https://github.com/git/git
Revision a36df79a37c7c643177905ce725dca8e9bd092d3 authored by Jeff King on 09 August 2021, 22:48:39 UTC, committed by Johannes Schindelin on 12 March 2023, 19:31:55 UTC
When parsing our buffer of output from git-log, we have a
find_end_of_line() helper that finds the next newline, and gives us the
number of bytes to move past it, or the size of the whole remaining
buffer if there is no newline.

But trying to handle both those cases leads to some oddities:

  - we try to overwrite the newline with NUL in the caller, by writing
    over line[len-1]. This is at best redundant, since the helper will
    already have done so if it saw a newline. But if it didn't see a
    newline, it's actively wrong; we'll overwrite the byte at the end of
    the (unterminated) line.

    We could solve this just dropping the extra NUL assignment in the
    caller and just letting the helper do the right thing. But...

  - if we see a "diff --git" line, we'll restore the newline on top of
    the NUL byte, so we can pass the string to parse_git_diff_header().
    But if there was no newline in the first place, we can't do this.
    There's no place to put it (the current code writes a newline
    over whatever byte we obliterated earlier). The best we can do is
    feed the complete remainder of the buffer to the function (which is,
    in fact, a string, by virtue of being a strbuf).

To solve this, the caller needs to know whether we actually found a
newline or not. We could modify find_end_of_line() to return that
information, but we can further observe that it has only one caller.
So let's just inline it in that caller.

Nobody seems to have noticed this case, probably because git-log would
never produce input that doesn't end with a newline. Arguably we could
just return an error as soon as we see that the output does not end in a
newline. But the code to do so actually ends up _longer_, mostly because
of the cleanup we have to do in handling the error.

Signed-off-by: Jeff King <peff@peff.net>
Acked-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 18bc8eb
Raw File
Tip revision: a36df79a37c7c643177905ce725dca8e9bd092d3 authored by Jeff King on 09 August 2021, 22:48:39 UTC
range-diff: handle unterminated lines in read_patches()
Tip revision: a36df79
worktree.h
#ifndef WORKTREE_H
#define WORKTREE_H

#include "cache.h"
#include "refs.h"

struct strbuf;

struct worktree {
	char *path;
	char *id;
	char *head_ref;		/* NULL if HEAD is broken or detached */
	char *lock_reason;	/* private - use worktree_lock_reason */
	struct object_id head_oid;
	int is_detached;
	int is_bare;
	int is_current;
	int lock_reason_valid; /* private */
};

/*
 * Get the worktrees.  The primary worktree will always be the first returned,
 * and linked worktrees will follow in no particular order.
 *
 * The caller is responsible for freeing the memory from the returned
 * worktrees by calling free_worktrees().
 */
struct worktree **get_worktrees(void);

/*
 * Returns 1 if linked worktrees exist, 0 otherwise.
 */
int submodule_uses_worktrees(const char *path);

/*
 * Return git dir of the worktree. Note that the path may be relative.
 * If wt is NULL, git dir of current worktree is returned.
 */
const char *get_worktree_git_dir(const struct worktree *wt);

/*
 * Search for the worktree identified unambiguously by `arg` -- typically
 * supplied by the user via the command-line -- which may be a pathname or some
 * shorthand uniquely identifying a worktree, thus making it convenient for the
 * user to specify a worktree with minimal typing. For instance, if the last
 * component (say, "foo") of a worktree's pathname is unique among worktrees
 * (say, "work/foo" and "work/bar"), it can be used to identify the worktree
 * unambiguously.
 *
 * `prefix` should be the `prefix` handed to top-level Git commands along with
 * `argc` and `argv`.
 *
 * Return the worktree identified by `arg`, or NULL if not found.
 */
struct worktree *find_worktree(struct worktree **list,
			       const char *prefix,
			       const char *arg);

/*
 * Return the worktree corresponding to `path`, or NULL if no such worktree
 * exists.
 */
struct worktree *find_worktree_by_path(struct worktree **, const char *path);

/*
 * Return true if the given worktree is the main one.
 */
int is_main_worktree(const struct worktree *wt);

/*
 * Return the reason string if the given worktree is locked or NULL
 * otherwise.
 */
const char *worktree_lock_reason(struct worktree *wt);

#define WT_VALIDATE_WORKTREE_MISSING_OK (1 << 0)

/*
 * Return zero if the worktree is in good condition. Error message is
 * returned if "errmsg" is not NULL.
 */
int validate_worktree(const struct worktree *wt,
		      struct strbuf *errmsg,
		      unsigned flags);

/*
 * Update worktrees/xxx/gitdir with the new path.
 */
void update_worktree_location(struct worktree *wt,
			      const char *path_);

typedef void (* worktree_repair_fn)(int iserr, const char *path,
				    const char *msg, void *cb_data);

/*
 * Visit each registered linked worktree and repair corruptions. For each
 * repair made or error encountered while attempting a repair, the callback
 * function, if non-NULL, is called with the path of the worktree and a
 * description of the repair or error, along with the callback user-data.
 */
void repair_worktrees(worktree_repair_fn, void *cb_data);

/*
 * Repair administrative files corresponding to the worktree at the given path.
 * The worktree's .git file pointing at the repository must be intact for the
 * repair to succeed. Useful for re-associating an orphaned worktree with the
 * repository if the worktree has been moved manually (without using "git
 * worktree move"). For each repair made or error encountered while attempting
 * a repair, the callback function, if non-NULL, is called with the path of the
 * worktree and a description of the repair or error, along with the callback
 * user-data.
 */
void repair_worktree_at_path(const char *, worktree_repair_fn, void *cb_data);

/*
 * Free up the memory for worktree(s)
 */
void free_worktrees(struct worktree **);

/*
 * Check if a per-worktree symref points to a ref in the main worktree
 * or any linked worktree, and return the worktree that holds the ref,
 * or NULL otherwise. The result may be destroyed by the next call.
 */
const struct worktree *find_shared_symref(const char *symref,
					  const char *target);

/*
 * Similar to head_ref() for all HEADs _except_ one from the current
 * worktree, which is covered by head_ref().
 */
int other_head_refs(each_ref_fn fn, void *cb_data);

int is_worktree_being_rebased(const struct worktree *wt, const char *target);
int is_worktree_being_bisected(const struct worktree *wt, const char *target);

/*
 * Similar to git_path() but can produce paths for a specified
 * worktree instead of current one
 */
const char *worktree_git_path(const struct worktree *wt,
			      const char *fmt, ...)
	__attribute__((format (printf, 2, 3)));

/*
 * Parse a worktree ref (i.e. with prefix main-worktree/ or
 * worktrees/) and return the position of the worktree's name and
 * length (or NULL and zero if it's main worktree), and ref.
 *
 * All name, name_length and ref arguments could be NULL.
 */
int parse_worktree_ref(const char *worktree_ref, const char **name,
		       int *name_length, const char **ref);

/*
 * Return a refname suitable for access from the current ref store.
 */
void strbuf_worktree_ref(const struct worktree *wt,
			 struct strbuf *sb,
			 const char *refname);

#endif
back to top