char *old_name = *name;
if (!old_name)
return;
- *name = xstrdup(prefix_filename(state->prefix, state->prefix_length, *name));
+ *name = prefix_filename(state->prefix, *name);
free(old_name);
}
return 0;
return EXISTS_IN_WORKTREE;
- } else if ((errno != ENOENT) && (errno != ENOTDIR)) {
+ } else if (!is_missing_file_error(errno)) {
return error_errno("%s", new_name);
}
return 0;
res = write_locked_index(&result, &lock, COMMIT_LOCK);
discard_index(&result);
- if (res)
- return error(_("could not write temporary index to %s"),
- state->fake_ancestor);
+ if (res)
+ return error(_("could not write temporary index to %s"),
+ state->fake_ancestor);
- return 0;
- }
+ return 0;
+}
- static void stat_patch_list(struct apply_state *state, struct patch *patch)
- {
- int files, adds, dels;
+static void stat_patch_list(struct apply_state *state, struct patch *patch)
+{
+ int files, adds, dels;
- for (files = adds = dels = 0 ; patch ; patch = patch->next) {
- files++;
- adds += patch->lines_added;
- dels += patch->lines_deleted;
- show_stats(state, patch);
- }
+ for (files = adds = dels = 0 ; patch ; patch = patch->next) {
+ files++;
+ adds += patch->lines_added;
+ dels += patch->lines_deleted;
+ show_stats(state, patch);
+ }
- print_stat_summary(stdout, files, adds, dels);
- }
+ print_stat_summary(stdout, files, adds, dels);
+}
- static void numstat_patch_list(struct apply_state *state,
- struct patch *patch)
- {
- for ( ; patch; patch = patch->next) {
- const char *name;
- name = patch->new_name ? patch->new_name : patch->old_name;
- if (patch->is_binary)
- printf("-\t-\t");
- else
- printf("%d\t%d\t", patch->lines_added, patch->lines_deleted);
- write_name_quoted(name, stdout, state->line_termination);
- }
- }
-
- static void show_file_mode_name(const char *newdelete, unsigned int mode, const char *name)
- {
- if (mode)
- printf(" %s mode %06o %s\n", newdelete, mode, name);
- else
- printf(" %s %s\n", newdelete, name);
- }
-
- static void show_mode_change(struct patch *p, int show_name)
- {
- if (p->old_mode && p->new_mode && p->old_mode != p->new_mode) {
- if (show_name)
- printf(" mode change %06o => %06o %s\n",
- p->old_mode, p->new_mode, p->new_name);
- else
- printf(" mode change %06o => %06o\n",
- p->old_mode, p->new_mode);
- }
- }
-
- static void show_rename_copy(struct patch *p)
- {
- const char *renamecopy = p->is_rename ? "rename" : "copy";
- const char *old, *new;
-
- /* Find common prefix */
- old = p->old_name;
- new = p->new_name;
- while (1) {
- const char *slash_old, *slash_new;
- slash_old = strchr(old, '/');
- slash_new = strchr(new, '/');
- if (!slash_old ||
- !slash_new ||
- slash_old - old != slash_new - new ||
- memcmp(old, new, slash_new - new))
- break;
- old = slash_old + 1;
- new = slash_new + 1;
- }
- /* p->old_name thru old is the common prefix, and old and new
- * through the end of names are renames
- */
- if (old != p->old_name)
- printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
- (int)(old - p->old_name), p->old_name,
- old, new, p->score);
- else
- printf(" %s %s => %s (%d%%)\n", renamecopy,
- p->old_name, p->new_name, p->score);
- show_mode_change(p, 0);
- }
-
- static void summary_patch_list(struct patch *patch)
- {
- struct patch *p;
-
- for (p = patch; p; p = p->next) {
- if (p->is_new)
- show_file_mode_name("create", p->new_mode, p->new_name);
- else if (p->is_delete)
- show_file_mode_name("delete", p->old_mode, p->old_name);
- else {
- if (p->is_rename || p->is_copy)
- show_rename_copy(p);
- else {
- if (p->score) {
- printf(" rewrite %s (%d%%)\n",
- p->new_name, p->score);
- show_mode_change(p, 0);
- }
- else
- show_mode_change(p, 1);
- }
- }
- }
- }
-
- static void patch_stats(struct apply_state *state, struct patch *patch)
- {
- int lines = patch->lines_added + patch->lines_deleted;
-
- if (lines > state->max_change)
- state->max_change = lines;
- if (patch->old_name) {
- int len = quote_c_style(patch->old_name, NULL, NULL, 0);
- if (!len)
- len = strlen(patch->old_name);
- if (len > state->max_len)
- state->max_len = len;
- }
- if (patch->new_name) {
- int len = quote_c_style(patch->new_name, NULL, NULL, 0);
- if (!len)
- len = strlen(patch->new_name);
- if (len > state->max_len)
- state->max_len = len;
- }
- }
-
- static int remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty)
- {
- if (state->update_index) {
- if (remove_file_from_cache(patch->old_name) < 0)
- return error(_("unable to remove %s from index"), patch->old_name);
- }
- if (!state->cached) {
- if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) {
- remove_path(patch->old_name);
- }
- }
- return 0;
- }
-
- static int add_index_file(struct apply_state *state,
- const char *path,
- unsigned mode,
- void *buf,
- unsigned long size)
- {
- struct stat st;
- struct cache_entry *ce;
- int namelen = strlen(path);
- unsigned ce_size = cache_entry_size(namelen);
-
- if (!state->update_index)
- return 0;
-
- ce = xcalloc(1, ce_size);
- memcpy(ce->name, path, namelen);
- ce->ce_mode = create_ce_mode(mode);
- ce->ce_flags = create_ce_flags(0);
- ce->ce_namelen = namelen;
- if (S_ISGITLINK(mode)) {
- const char *s;
-
- if (!skip_prefix(buf, "Subproject commit ", &s) ||
- get_oid_hex(s, &ce->oid)) {
+static void numstat_patch_list(struct apply_state *state,
+ struct patch *patch)
+{
+ for ( ; patch; patch = patch->next) {
+ const char *name;
+ name = patch->new_name ? patch->new_name : patch->old_name;
+ if (patch->is_binary)
+ printf("-\t-\t");
+ else
+ printf("%d\t%d\t", patch->lines_added, patch->lines_deleted);
+ write_name_quoted(name, stdout, state->line_termination);
+ }
+}
+
+static void show_file_mode_name(const char *newdelete, unsigned int mode, const char *name)
+{
+ if (mode)
+ printf(" %s mode %06o %s\n", newdelete, mode, name);
+ else
+ printf(" %s %s\n", newdelete, name);
+}
+
+static void show_mode_change(struct patch *p, int show_name)
+{
+ if (p->old_mode && p->new_mode && p->old_mode != p->new_mode) {
+ if (show_name)
+ printf(" mode change %06o => %06o %s\n",
+ p->old_mode, p->new_mode, p->new_name);
+ else
+ printf(" mode change %06o => %06o\n",
+ p->old_mode, p->new_mode);
+ }
+}
+
+static void show_rename_copy(struct patch *p)
+{
+ const char *renamecopy = p->is_rename ? "rename" : "copy";
+ const char *old, *new;
+
+ /* Find common prefix */
+ old = p->old_name;
+ new = p->new_name;
+ while (1) {
+ const char *slash_old, *slash_new;
+ slash_old = strchr(old, '/');
+ slash_new = strchr(new, '/');
+ if (!slash_old ||
+ !slash_new ||
+ slash_old - old != slash_new - new ||
+ memcmp(old, new, slash_new - new))
+ break;
+ old = slash_old + 1;
+ new = slash_new + 1;
+ }
+ /* p->old_name thru old is the common prefix, and old and new
+ * through the end of names are renames
+ */
+ if (old != p->old_name)
+ printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
+ (int)(old - p->old_name), p->old_name,
+ old, new, p->score);
+ else
+ printf(" %s %s => %s (%d%%)\n", renamecopy,
+ p->old_name, p->new_name, p->score);
+ show_mode_change(p, 0);
+}
+
+static void summary_patch_list(struct patch *patch)
+{
+ struct patch *p;
+
+ for (p = patch; p; p = p->next) {
+ if (p->is_new)
+ show_file_mode_name("create", p->new_mode, p->new_name);
+ else if (p->is_delete)
+ show_file_mode_name("delete", p->old_mode, p->old_name);
+ else {
+ if (p->is_rename || p->is_copy)
+ show_rename_copy(p);
+ else {
+ if (p->score) {
+ printf(" rewrite %s (%d%%)\n",
+ p->new_name, p->score);
+ show_mode_change(p, 0);
+ }
+ else
+ show_mode_change(p, 1);
+ }
+ }
+ }
+}
+
+static void patch_stats(struct apply_state *state, struct patch *patch)
+{
+ int lines = patch->lines_added + patch->lines_deleted;
+
+ if (lines > state->max_change)
+ state->max_change = lines;
+ if (patch->old_name) {
+ int len = quote_c_style(patch->old_name, NULL, NULL, 0);
+ if (!len)
+ len = strlen(patch->old_name);
+ if (len > state->max_len)
+ state->max_len = len;
+ }
+ if (patch->new_name) {
+ int len = quote_c_style(patch->new_name, NULL, NULL, 0);
+ if (!len)
+ len = strlen(patch->new_name);
+ if (len > state->max_len)
+ state->max_len = len;
+ }
+}
+
+static int remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty)
+{
+ if (state->update_index) {
+ if (remove_file_from_cache(patch->old_name) < 0)
+ return error(_("unable to remove %s from index"), patch->old_name);
+ }
+ if (!state->cached) {
+ if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) {
+ remove_path(patch->old_name);
+ }
+ }
+ return 0;
+}
+
+static int add_index_file(struct apply_state *state,
+ const char *path,
+ unsigned mode,
+ void *buf,
+ unsigned long size)
+{
+ struct stat st;
+ struct cache_entry *ce;
+ int namelen = strlen(path);
+ unsigned ce_size = cache_entry_size(namelen);
+
+ if (!state->update_index)
+ return 0;
+
+ ce = xcalloc(1, ce_size);
+ memcpy(ce->name, path, namelen);
+ ce->ce_mode = create_ce_mode(mode);
+ ce->ce_flags = create_ce_flags(0);
+ ce->ce_namelen = namelen;
+ if (S_ISGITLINK(mode)) {
+ const char *s;
+
+ if (!skip_prefix(buf, "Subproject commit ", &s) ||
+ get_oid_hex(s, &ce->oid)) {
free(ce);
- return error(_("corrupt patch for submodule %s"), path);
+ return error(_("corrupt patch for submodule %s"), path);
}
} else {
if (!state->cached) {
for (i = 0; i < argc; i++) {
const char *arg = argv[i];
+ char *to_free = NULL;
int fd;
if (!strcmp(arg, "-")) {
errs |= res;
read_stdin = 0;
continue;
- } else if (0 < state->prefix_length)
- arg = prefix_filename(state->prefix,
- state->prefix_length,
- arg);
+ } else
+ arg = to_free = prefix_filename(state->prefix, arg);
fd = open(arg, O_RDONLY);
if (fd < 0) {
error(_("can't open patch '%s': %s"), arg, strerror(errno));
res = -128;
+ free(to_free);
goto end;
}
read_stdin = 0;
set_default_whitespace_mode(state);
res = apply_patch(state, fd, arg, options);
close(fd);
+ free(to_free);
if (res < 0)
goto end;
errs |= res;
ce = active_cache[pos];
if (lstat(ce->name, &st) < 0) {
- if (errno != ENOENT && errno != ENOTDIR)
+ if (!is_missing_file_error(errno))
warning_errno(_("failed to stat '%s'"), ce->name);
/* It already vanished from the working tree */
continue;
die(_("index file corrupt"));
parse_pathspec(&pathspec, 0,
- PATHSPEC_PREFER_CWD |
- PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
+ PATHSPEC_PREFER_CWD,
prefix, argv);
refresh_index(&the_index, REFRESH_QUIET, &pathspec, NULL, NULL);
struct stat st;
struct stat_data base;
int fd, ret = 0;
+ char *cwd;
strbuf_addstr(&mtime_dir, "mtime-test-XXXXXX");
if (!mkdtemp(mtime_dir.buf))
die_errno("Could not make temporary directory");
- fprintf(stderr, _("Testing mtime in '%s' "), xgetcwd());
+ cwd = xgetcwd();
+ fprintf(stderr, _("Testing mtime in '%s' "), cwd);
+ free(cwd);
+
atexit(remove_test_directory);
xstat_mtime_dir(&st);
fill_stat_data(&base, &st);
*/
static int process_lstat_error(const char *path, int err)
{
- if (err == ENOENT || err == ENOTDIR)
+ if (is_missing_file_error(err))
return remove_one_path(path);
return error("lstat(\"%s\"): %s", path, strerror(err));
}
}
if (split_index > 0) {
- init_split_index(&the_index);
- the_index.cache_changed |= SPLIT_INDEX_ORDERED;
- } else if (!split_index && the_index.split_index) {
- /*
- * can't discard_split_index(&the_index); because that
- * will destroy split_index->base->cache[], which may
- * be shared with the_index.cache[]. So yeah we're
- * leaking a bit here.
- */
- the_index.split_index = NULL;
- the_index.cache_changed |= SOMETHING_CHANGED;
+ if (git_config_get_split_index() == 0)
+ warning(_("core.splitIndex is set to false; "
+ "remove or change it, if you really want to "
+ "enable split index"));
+ if (the_index.split_index)
+ the_index.cache_changed |= SPLIT_INDEX_ORDERED;
+ else
+ add_split_index(&the_index);
+ } else if (!split_index) {
+ if (git_config_get_split_index() == 1)
+ warning(_("core.splitIndex is set to true; "
+ "remove or change it, if you really want to "
+ "disable split index"));
+ remove_split_index(&the_index);
}
switch (untracked_cache) {
static int check_removed(const struct cache_entry *ce, struct stat *st)
{
if (lstat(ce->name, st) < 0) {
- if (errno != ENOENT && errno != ENOTDIR)
+ if (!is_missing_file_error(errno))
return -1;
return 1;
}
}
static int diff_cache(struct rev_info *revs,
- const unsigned char *tree_sha1,
+ const struct object_id *tree_oid,
const char *tree_name,
int cached)
{
struct tree_desc t;
struct unpack_trees_options opts;
- tree = parse_tree_indirect(tree_sha1);
+ tree = parse_tree_indirect(tree_oid);
if (!tree)
return error("bad tree object %s",
- tree_name ? tree_name : sha1_to_hex(tree_sha1));
+ tree_name ? tree_name : oid_to_hex(tree_oid));
memset(&opts, 0, sizeof(opts));
opts.head_idx = 1;
opts.index_only = cached;
struct object_array_entry *ent;
ent = revs->pending.objects;
- if (diff_cache(revs, ent->item->oid.hash, ent->name, cached))
+ if (diff_cache(revs, &ent->item->oid, ent->name, cached))
exit(128);
diff_set_mnemonic_prefix(&revs->diffopt, "c/", cached ? "i/" : "w/");
return 0;
}
-int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)
+int do_diff_cache(const struct object_id *tree_oid, struct diff_options *opt)
{
struct rev_info revs;
copy_pathspec(&revs.prune_data, &opt->pathspec);
revs.diffopt = *opt;
- if (diff_cache(&revs, tree_sha1, NULL, 1))
+ if (diff_cache(&revs, tree_oid, NULL, 1))
exit(128);
return 0;
}
* Copyright (C) Linus Torvalds, 2005-2006
* Junio Hamano, 2005-2006
*/
+#define NO_THE_INDEX_COMPATIBILITY_MACROS
#include "cache.h"
#include "dir.h"
+#include "attr.h"
#include "refs.h"
#include "wildmatch.h"
#include "pathspec.h"
};
static enum path_treatment read_directory_recursive(struct dir_struct *dir,
- const char *path, int len, struct untracked_cache_dir *untracked,
+ struct index_state *istate, const char *path, int len,
+ struct untracked_cache_dir *untracked,
int check_only, const struct pathspec *pathspec);
-static int get_dtype(struct dirent *de, const char *path, int len);
+static int get_dtype(struct dirent *de, struct index_state *istate,
+ const char *path, int len);
int fspathcmp(const char *a, const char *b)
{
PATHSPEC_LITERAL |
PATHSPEC_GLOB |
PATHSPEC_ICASE |
- PATHSPEC_EXCLUDE);
+ PATHSPEC_EXCLUDE |
+ PATHSPEC_ATTR);
for (n = 0; n < pathspec->nr; n++) {
size_t i = 0, len = 0, item_len;
return len ? xmemdupz(pathspec->items[0].match, len) : NULL;
}
-int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)
+int fill_directory(struct dir_struct *dir,
+ struct index_state *istate,
+ const struct pathspec *pathspec)
{
const char *prefix;
size_t prefix_len;
prefix = prefix_len ? pathspec->items[0].match : "";
/* Read the directory and prune it */
- read_directory(dir, prefix, prefix_len, pathspec);
+ read_directory(dir, istate, prefix, prefix_len, pathspec);
return prefix_len;
}
#define DO_MATCH_DIRECTORY (1<<1)
#define DO_MATCH_SUBMODULE (1<<2)
+static int match_attrs(const char *name, int namelen,
+ const struct pathspec_item *item)
+{
+ int i;
+
+ git_check_attr(name, item->attr_check);
+ for (i = 0; i < item->attr_match_nr; i++) {
+ const char *value;
+ int matched;
+ enum attr_match_mode match_mode;
+
+ value = item->attr_check->items[i].value;
+ match_mode = item->attr_match[i].match_mode;
+
+ if (ATTR_TRUE(value))
+ matched = (match_mode == MATCH_SET);
+ else if (ATTR_FALSE(value))
+ matched = (match_mode == MATCH_UNSET);
+ else if (ATTR_UNSET(value))
+ matched = (match_mode == MATCH_UNSPECIFIED);
+ else
+ matched = (match_mode == MATCH_VALUE &&
+ !strcmp(item->attr_match[i].value, value));
+ if (!matched)
+ return 0;
+ }
+
+ return 1;
+}
+
/*
* Does 'match' match the given name?
* A match is found if
strncmp(item->match, name - prefix, item->prefix))
return 0;
+ if (item->attr_match_nr && !match_attrs(name, namelen, item))
+ return 0;
+
/* If the match was just the prefix, we matched */
if (!*match)
return MATCHED_RECURSIVELY;
PATHSPEC_LITERAL |
PATHSPEC_GLOB |
PATHSPEC_ICASE |
- PATHSPEC_EXCLUDE);
+ PATHSPEC_EXCLUDE |
+ PATHSPEC_ATTR);
if (!ps->nr) {
if (!ps->recursive ||
x->el = el;
}
-static void *read_skip_worktree_file_from_index(const char *path, size_t *size,
+static void *read_skip_worktree_file_from_index(const struct index_state *istate,
+ const char *path, size_t *size,
struct sha1_stat *sha1_stat)
{
int pos, len;
void *data;
len = strlen(path);
- pos = cache_name_pos(path, len);
+ pos = index_name_pos(istate, path, len);
if (pos < 0)
return NULL;
- if (!ce_skip_worktree(active_cache[pos]))
+ if (!ce_skip_worktree(istate->cache[pos]))
return NULL;
- data = read_sha1_file(active_cache[pos]->oid.hash, &type, &sz);
+ data = read_sha1_file(istate->cache[pos]->oid.hash, &type, &sz);
if (!data || type != OBJ_BLOB) {
free(data);
return NULL;
*size = xsize_t(sz);
if (sha1_stat) {
memset(&sha1_stat->stat, 0, sizeof(sha1_stat->stat));
- hashcpy(sha1_stat->sha1, active_cache[pos]->oid.hash);
+ hashcpy(sha1_stat->sha1, istate->cache[pos]->oid.hash);
}
return data;
}
/*
* Given a file with name "fname", read it (either from disk, or from
- * the index if "check_index" is non-zero), parse it and store the
+ * an index if 'istate' is non-null), parse it and store the
* exclude rules in "el".
*
* If "ss" is not NULL, compute SHA-1 of the exclude file and fill
* ss_valid is non-zero, "ss" must contain good value as input.
*/
static int add_excludes(const char *fname, const char *base, int baselen,
- struct exclude_list *el, int check_index,
+ struct exclude_list *el,
+ struct index_state *istate,
struct sha1_stat *sha1_stat)
{
struct stat st;
warn_on_inaccessible(fname);
if (0 <= fd)
close(fd);
- if (!check_index ||
- (buf = read_skip_worktree_file_from_index(fname, &size, sha1_stat)) == NULL)
+ if (!istate ||
+ (buf = read_skip_worktree_file_from_index(istate, fname, &size, sha1_stat)) == NULL)
return -1;
if (size == 0) {
free(buf);
if (sha1_stat) {
int pos;
if (sha1_stat->valid &&
- !match_stat_data_racy(&the_index, &sha1_stat->stat, &st))
+ !match_stat_data_racy(istate, &sha1_stat->stat, &st))
; /* no content change, ss->sha1 still good */
- else if (check_index &&
- (pos = cache_name_pos(fname, strlen(fname))) >= 0 &&
- !ce_stage(active_cache[pos]) &&
- ce_uptodate(active_cache[pos]) &&
+ else if (istate &&
+ (pos = index_name_pos(istate, fname, strlen(fname))) >= 0 &&
+ !ce_stage(istate->cache[pos]) &&
+ ce_uptodate(istate->cache[pos]) &&
!would_convert_to_git(fname))
hashcpy(sha1_stat->sha1,
- active_cache[pos]->oid.hash);
+ istate->cache[pos]->oid.hash);
else
hash_sha1_file(buf, size, "blob", sha1_stat->sha1);
fill_stat_data(&sha1_stat->stat, &st);
int add_excludes_from_file_to_list(const char *fname, const char *base,
int baselen, struct exclude_list *el,
- int check_index)
+ struct index_state *istate)
{
- return add_excludes(fname, base, baselen, el, check_index, NULL);
+ return add_excludes(fname, base, baselen, el, istate, NULL);
}
struct exclude_list *add_exclude_list(struct dir_struct *dir,
if (!dir->untracked)
dir->unmanaged_exclude_files++;
el = add_exclude_list(dir, EXC_FILE, fname);
- if (add_excludes(fname, "", 0, el, 0, sha1_stat) < 0)
+ if (add_excludes(fname, "", 0, el, NULL, sha1_stat) < 0)
die("cannot use %s as an exclude file", fname);
}
int pathlen,
const char *basename,
int *dtype,
- struct exclude_list *el)
+ struct exclude_list *el,
+ struct index_state *istate)
{
struct exclude *exc = NULL; /* undecided */
int i;
if (x->flags & EXC_FLAG_MUSTBEDIR) {
if (*dtype == DT_UNKNOWN)
- *dtype = get_dtype(NULL, pathname, pathlen);
+ *dtype = get_dtype(NULL, istate, pathname, pathlen);
if (*dtype != DT_DIR)
continue;
}
*/
int is_excluded_from_list(const char *pathname,
int pathlen, const char *basename, int *dtype,
- struct exclude_list *el)
+ struct exclude_list *el, struct index_state *istate)
{
struct exclude *exclude;
- exclude = last_exclude_matching_from_list(pathname, pathlen, basename, dtype, el);
+ exclude = last_exclude_matching_from_list(pathname, pathlen, basename,
+ dtype, el, istate);
if (exclude)
return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
return -1; /* undecided */
}
static struct exclude *last_exclude_matching_from_lists(struct dir_struct *dir,
+ struct index_state *istate,
const char *pathname, int pathlen, const char *basename,
int *dtype_p)
{
for (j = group->nr - 1; j >= 0; j--) {
exclude = last_exclude_matching_from_list(
pathname, pathlen, basename, dtype_p,
- &group->el[j]);
+ &group->el[j], istate);
if (exclude)
return exclude;
}
* Loads the per-directory exclude list for the substring of base
* which has a char length of baselen.
*/
-static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
+static void prep_exclude(struct dir_struct *dir,
+ struct index_state *istate,
+ const char *base, int baselen)
{
struct exclude_list_group *group;
struct exclude_list *el;
int dt = DT_DIR;
dir->basebuf.buf[stk->baselen - 1] = 0;
dir->exclude = last_exclude_matching_from_lists(dir,
+ istate,
dir->basebuf.buf, stk->baselen - 1,
dir->basebuf.buf + current, &dt);
dir->basebuf.buf[stk->baselen - 1] = '/';
strbuf_addbuf(&sb, &dir->basebuf);
strbuf_addstr(&sb, dir->exclude_per_dir);
el->src = strbuf_detach(&sb, NULL);
- add_excludes(el->src, el->src, stk->baselen, el, 1,
+ add_excludes(el->src, el->src, stk->baselen, el, istate,
untracked ? &sha1_stat : NULL);
}
/*
* undecided.
*/
struct exclude *last_exclude_matching(struct dir_struct *dir,
- const char *pathname,
- int *dtype_p)
+ struct index_state *istate,
+ const char *pathname,
+ int *dtype_p)
{
int pathlen = strlen(pathname);
const char *basename = strrchr(pathname, '/');
basename = (basename) ? basename+1 : pathname;
- prep_exclude(dir, pathname, basename-pathname);
+ prep_exclude(dir, istate, pathname, basename-pathname);
if (dir->exclude)
return dir->exclude;
- return last_exclude_matching_from_lists(dir, pathname, pathlen,
+ return last_exclude_matching_from_lists(dir, istate, pathname, pathlen,
basename, dtype_p);
}
* scans all exclude lists to determine whether pathname is excluded.
* Returns 1 if true, otherwise 0.
*/
-int is_excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
+int is_excluded(struct dir_struct *dir, struct index_state *istate,
+ const char *pathname, int *dtype_p)
{
struct exclude *exclude =
- last_exclude_matching(dir, pathname, dtype_p);
+ last_exclude_matching(dir, istate, pathname, dtype_p);
if (exclude)
return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
return 0;
return ent;
}
-static struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)
+static struct dir_entry *dir_add_name(struct dir_struct *dir,
+ struct index_state *istate,
+ const char *pathname, int len)
{
- if (cache_file_exists(pathname, len, ignore_case))
+ if (index_file_exists(istate, pathname, len, ignore_case))
return NULL;
ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc);
return dir->entries[dir->nr++] = dir_entry_new(pathname, len);
}
-struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len)
+struct dir_entry *dir_add_ignored(struct dir_struct *dir,
+ struct index_state *istate,
+ const char *pathname, int len)
{
- if (!cache_name_is_other(pathname, len))
+ if (!index_name_is_other(istate, pathname, len))
return NULL;
ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->ignored_alloc);
* the directory name; instead, use the case insensitive
* directory hash.
*/
-static enum exist_status directory_exists_in_index_icase(const char *dirname, int len)
+static enum exist_status directory_exists_in_index_icase(struct index_state *istate,
+ const char *dirname, int len)
{
struct cache_entry *ce;
- if (cache_dir_exists(dirname, len))
+ if (index_dir_exists(istate, dirname, len))
return index_directory;
- ce = cache_file_exists(dirname, len, ignore_case);
+ ce = index_file_exists(istate, dirname, len, ignore_case);
if (ce && S_ISGITLINK(ce->ce_mode))
return index_gitdir;
* the files it contains) will sort with the '/' at the
* end.
*/
-static enum exist_status directory_exists_in_index(const char *dirname, int len)
+static enum exist_status directory_exists_in_index(struct index_state *istate,
+ const char *dirname, int len)
{
int pos;
if (ignore_case)
- return directory_exists_in_index_icase(dirname, len);
+ return directory_exists_in_index_icase(istate, dirname, len);
- pos = cache_name_pos(dirname, len);
+ pos = index_name_pos(istate, dirname, len);
if (pos < 0)
pos = -pos-1;
- while (pos < active_nr) {
- const struct cache_entry *ce = active_cache[pos++];
+ while (pos < istate->cache_nr) {
+ const struct cache_entry *ce = istate->cache[pos++];
unsigned char endchar;
if (strncmp(ce->name, dirname, len))
* (c) otherwise, we recurse into it.
*/
static enum path_treatment treat_directory(struct dir_struct *dir,
+ struct index_state *istate,
struct untracked_cache_dir *untracked,
const char *dirname, int len, int baselen, int exclude,
const struct pathspec *pathspec)
{
/* The "len-1" is to strip the final '/' */
- switch (directory_exists_in_index(dirname, len-1)) {
+ switch (directory_exists_in_index(istate, dirname, len-1)) {
case index_directory:
return path_recurse;
untracked = lookup_untracked(dir->untracked, untracked,
dirname + baselen, len - baselen);
- return read_directory_recursive(dir, dirname, len,
+ return read_directory_recursive(dir, istate, dirname, len,
untracked, 1, pathspec);
}
PATHSPEC_LITERAL |
PATHSPEC_GLOB |
PATHSPEC_ICASE |
- PATHSPEC_EXCLUDE);
+ PATHSPEC_EXCLUDE |
+ PATHSPEC_ATTR);
for (i = 0; i < pathspec->nr; i++) {
const struct pathspec_item *item = &pathspec->items[i];
return 0;
}
-static int get_index_dtype(const char *path, int len)
+static int get_index_dtype(struct index_state *istate,
+ const char *path, int len)
{
int pos;
const struct cache_entry *ce;
- ce = cache_file_exists(path, len, 0);
+ ce = index_file_exists(istate, path, len, 0);
if (ce) {
if (!ce_uptodate(ce))
return DT_UNKNOWN;
}
/* Try to look it up as a directory */
- pos = cache_name_pos(path, len);
+ pos = index_name_pos(istate, path, len);
if (pos >= 0)
return DT_UNKNOWN;
pos = -pos-1;
- while (pos < active_nr) {
- ce = active_cache[pos++];
+ while (pos < istate->cache_nr) {
+ ce = istate->cache[pos++];
if (strncmp(ce->name, path, len))
break;
if (ce->name[len] > '/')
return DT_UNKNOWN;
}
-static int get_dtype(struct dirent *de, const char *path, int len)
+static int get_dtype(struct dirent *de, struct index_state *istate,
+ const char *path, int len)
{
int dtype = de ? DTYPE(de) : DT_UNKNOWN;
struct stat st;
if (dtype != DT_UNKNOWN)
return dtype;
- dtype = get_index_dtype(path, len);
+ dtype = get_index_dtype(istate, path, len);
if (dtype != DT_UNKNOWN)
return dtype;
if (lstat(path, &st))
static enum path_treatment treat_one_path(struct dir_struct *dir,
struct untracked_cache_dir *untracked,
+ struct index_state *istate,
struct strbuf *path,
int baselen,
const struct pathspec *pathspec,
int dtype, struct dirent *de)
{
int exclude;
- int has_path_in_index = !!cache_file_exists(path->buf, path->len, ignore_case);
+ int has_path_in_index = !!index_file_exists(istate, path->buf, path->len, ignore_case);
if (dtype == DT_UNKNOWN)
- dtype = get_dtype(de, path->buf, path->len);
+ dtype = get_dtype(de, istate, path->buf, path->len);
/* Always exclude indexed files */
if (dtype != DT_DIR && has_path_in_index)
if ((dir->flags & DIR_COLLECT_KILLED_ONLY) &&
(dtype == DT_DIR) &&
!has_path_in_index &&
- (directory_exists_in_index(path->buf, path->len) == index_nonexistent))
+ (directory_exists_in_index(istate, path->buf, path->len) == index_nonexistent))
return path_none;
- exclude = is_excluded(dir, path->buf, &dtype);
+ exclude = is_excluded(dir, istate, path->buf, &dtype);
/*
* Excluded? If we don't explicitly want to show
return path_none;
case DT_DIR:
strbuf_addch(path, '/');
- return treat_directory(dir, untracked, path->buf, path->len,
+ return treat_directory(dir, istate, untracked, path->buf, path->len,
baselen, exclude, pathspec);
case DT_REG:
case DT_LNK:
static enum path_treatment treat_path_fast(struct dir_struct *dir,
struct untracked_cache_dir *untracked,
struct cached_dir *cdir,
+ struct index_state *istate,
struct strbuf *path,
int baselen,
const struct pathspec *pathspec)
* to its bottom. Verify again the same set of directories
* with check_only set.
*/
- return read_directory_recursive(dir, path->buf, path->len,
+ return read_directory_recursive(dir, istate, path->buf, path->len,
cdir->ucd, 1, pathspec);
/*
* We get path_recurse in the first run when
static enum path_treatment treat_path(struct dir_struct *dir,
struct untracked_cache_dir *untracked,
struct cached_dir *cdir,
+ struct index_state *istate,
struct strbuf *path,
int baselen,
const struct pathspec *pathspec)
struct dirent *de = cdir->de;
if (!de)
- return treat_path_fast(dir, untracked, cdir, path,
+ return treat_path_fast(dir, untracked, cdir, istate, path,
baselen, pathspec);
if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git"))
return path_none;
return path_none;
dtype = DTYPE(de);
- return treat_one_path(dir, untracked, path, baselen, pathspec, dtype, de);
+ return treat_one_path(dir, untracked, istate, path, baselen, pathspec, dtype, de);
}
static void add_untracked(struct untracked_cache_dir *dir, const char *name)
static int valid_cached_dir(struct dir_struct *dir,
struct untracked_cache_dir *untracked,
+ struct index_state *istate,
struct strbuf *path,
int check_only)
{
return 0;
}
if (!untracked->valid ||
- match_stat_data_racy(&the_index, &untracked->stat_data, &st)) {
+ match_stat_data_racy(istate, &untracked->stat_data, &st)) {
if (untracked->valid)
invalidate_directory(dir->untracked, untracked);
fill_stat_data(&untracked->stat_data, &st);
*/
if (path->len && path->buf[path->len - 1] != '/') {
strbuf_addch(path, '/');
- prep_exclude(dir, path->buf, path->len);
+ prep_exclude(dir, istate, path->buf, path->len);
strbuf_setlen(path, path->len - 1);
} else
- prep_exclude(dir, path->buf, path->len);
+ prep_exclude(dir, istate, path->buf, path->len);
/* hopefully prep_exclude() haven't invalidated this entry... */
return untracked->valid;
static int open_cached_dir(struct cached_dir *cdir,
struct dir_struct *dir,
struct untracked_cache_dir *untracked,
+ struct index_state *istate,
struct strbuf *path,
int check_only)
{
memset(cdir, 0, sizeof(*cdir));
cdir->untracked = untracked;
- if (valid_cached_dir(dir, untracked, path, check_only))
+ if (valid_cached_dir(dir, untracked, istate, path, check_only))
return 0;
cdir->fdir = opendir(path->len ? path->buf : ".");
if (dir->untracked)
* Returns the most significant path_treatment value encountered in the scan.
*/
static enum path_treatment read_directory_recursive(struct dir_struct *dir,
- const char *base, int baselen,
- struct untracked_cache_dir *untracked, int check_only,
- const struct pathspec *pathspec)
+ struct index_state *istate, const char *base, int baselen,
+ struct untracked_cache_dir *untracked, int check_only,
+ const struct pathspec *pathspec)
{
struct cached_dir cdir;
enum path_treatment state, subdir_state, dir_state = path_none;
strbuf_add(&path, base, baselen);
- if (open_cached_dir(&cdir, dir, untracked, &path, check_only))
+ if (open_cached_dir(&cdir, dir, untracked, istate, &path, check_only))
goto out;
if (untracked)
while (!read_cached_dir(&cdir)) {
/* check how the file or directory should be treated */
- state = treat_path(dir, untracked, &cdir, &path,
+ state = treat_path(dir, untracked, &cdir, istate, &path,
baselen, pathspec);
if (state > dir_state)
dir_state = state;
/* recurse into subdir if instructed by treat_path */
- if (state == path_recurse) {
+ if ((state == path_recurse) ||
+ ((state == path_untracked) &&
+ (dir->flags & DIR_SHOW_IGNORED_TOO) &&
+ (get_dtype(cdir.de, istate, path.buf, path.len) == DT_DIR))) {
struct untracked_cache_dir *ud;
ud = lookup_untracked(dir->untracked, untracked,
path.buf + baselen,
path.len - baselen);
subdir_state =
- read_directory_recursive(dir, path.buf,
+ read_directory_recursive(dir, istate, path.buf,
path.len, ud,
check_only, pathspec);
if (subdir_state > dir_state)
switch (state) {
case path_excluded:
if (dir->flags & DIR_SHOW_IGNORED)
- dir_add_name(dir, path.buf, path.len);
+ dir_add_name(dir, istate, path.buf, path.len);
else if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||
((dir->flags & DIR_COLLECT_IGNORED) &&
exclude_matches_pathspec(path.buf, path.len,
pathspec)))
- dir_add_ignored(dir, path.buf, path.len);
+ dir_add_ignored(dir, istate, path.buf, path.len);
break;
case path_untracked:
if (dir->flags & DIR_SHOW_IGNORED)
break;
- dir_add_name(dir, path.buf, path.len);
+ dir_add_name(dir, istate, path.buf, path.len);
if (cdir.fdir)
add_untracked(untracked, path.buf + baselen);
break;
return dir_state;
}
-static int cmp_name(const void *p1, const void *p2)
+int cmp_dir_entry(const void *p1, const void *p2)
{
const struct dir_entry *e1 = *(const struct dir_entry **)p1;
const struct dir_entry *e2 = *(const struct dir_entry **)p2;
return name_compare(e1->name, e1->len, e2->name, e2->len);
}
+/* check if *out lexically strictly contains *in */
+int check_dir_entry_contains(const struct dir_entry *out, const struct dir_entry *in)
+{
+ return (out->len < in->len) &&
+ (out->name[out->len - 1] == '/') &&
+ !memcmp(out->name, in->name, out->len);
+}
+
static int treat_leading_path(struct dir_struct *dir,
+ struct index_state *istate,
const char *path, int len,
const struct pathspec *pathspec)
{
break;
if (simplify_away(sb.buf, sb.len, pathspec))
break;
- if (treat_one_path(dir, NULL, &sb, baselen, pathspec,
+ if (treat_one_path(dir, NULL, istate, &sb, baselen, pathspec,
DT_DIR, NULL) == path_none)
break; /* do not recurse into it */
if (len <= baselen) {
return root;
}
-int read_directory(struct dir_struct *dir, const char *path,
- int len, const struct pathspec *pathspec)
+int read_directory(struct dir_struct *dir, struct index_state *istate,
+ const char *path, int len, const struct pathspec *pathspec)
{
struct untracked_cache_dir *untracked;
* e.g. prep_exclude()
*/
dir->untracked = NULL;
- if (!len || treat_leading_path(dir, path, len, pathspec))
- read_directory_recursive(dir, path, len, untracked, 0, pathspec);
- QSORT(dir->entries, dir->nr, cmp_name);
- QSORT(dir->ignored, dir->ignored_nr, cmp_name);
+ if (!len || treat_leading_path(dir, istate, path, len, pathspec))
+ read_directory_recursive(dir, istate, path, len, untracked, 0, pathspec);
+ QSORT(dir->entries, dir->nr, cmp_dir_entry);
+ QSORT(dir->ignored, dir->ignored_nr, cmp_dir_entry);
+
+ /*
+ * If DIR_SHOW_IGNORED_TOO is set, read_directory_recursive() will
+ * also pick up untracked contents of untracked dirs; by default
+ * we discard these, but given DIR_KEEP_UNTRACKED_CONTENTS we do not.
+ */
+ if ((dir->flags & DIR_SHOW_IGNORED_TOO) &&
+ !(dir->flags & DIR_KEEP_UNTRACKED_CONTENTS)) {
+ int i, j;
+
+ /* remove from dir->entries untracked contents of untracked dirs */
+ for (i = j = 0; j < dir->nr; j++) {
+ if (i &&
+ check_dir_entry_contains(dir->entries[i - 1], dir->entries[j])) {
+ free(dir->entries[j]);
+ dir->entries[j] = NULL;
+ } else {
+ dir->entries[i++] = dir->entries[j];
+ }
+ }
+
+ dir->nr = i;
+ }
+
if (dir->untracked) {
static struct trace_key trace_untracked_stats = TRACE_KEY_INIT(UNTRACKED_STATS);
trace_printf_key(&trace_untracked_stats,
dir->untracked->gitignore_invalidated,
dir->untracked->dir_invalidated,
dir->untracked->dir_opened);
- if (dir->untracked == the_index.untracked &&
+ if (dir->untracked == istate->untracked &&
(dir->untracked->dir_opened ||
dir->untracked->gitignore_invalidated ||
dir->untracked->dir_invalidated))
- the_index.cache_changed |= UNTRACKED_CHANGED;
- if (dir->untracked != the_index.untracked) {
+ istate->cache_changed |= UNTRACKED_CHANGED;
+ if (dir->untracked != istate->untracked) {
free(dir->untracked);
dir->untracked = NULL;
}
{
char *slash;
- if (unlink(name) && errno != ENOENT && errno != ENOTDIR)
+ if (unlink(name) && !is_missing_file_error(errno))
return -1;
slash = strrchr(name, '/');
/* Update gitfile and core.worktree setting to connect work tree and git dir */
void connect_work_tree_and_git_dir(const char *work_tree_, const char *git_dir_)
{
- struct strbuf file_name = STRBUF_INIT;
+ struct strbuf gitfile_sb = STRBUF_INIT;
+ struct strbuf cfg_sb = STRBUF_INIT;
struct strbuf rel_path = STRBUF_INIT;
- char *git_dir = real_pathdup(git_dir_, 1);
- char *work_tree = real_pathdup(work_tree_, 1);
+ char *git_dir, *work_tree;
- /* Update gitfile */
- strbuf_addf(&file_name, "%s/.git", work_tree);
- write_file(file_name.buf, "gitdir: %s",
- relative_path(git_dir, work_tree, &rel_path));
+ /* Prepare .git file */
+ strbuf_addf(&gitfile_sb, "%s/.git", work_tree_);
+ if (safe_create_leading_directories_const(gitfile_sb.buf))
+ die(_("could not create directories for %s"), gitfile_sb.buf);
+
+ /* Prepare config file */
+ strbuf_addf(&cfg_sb, "%s/config", git_dir_);
+ if (safe_create_leading_directories_const(cfg_sb.buf))
+ die(_("could not create directories for %s"), cfg_sb.buf);
+ git_dir = real_pathdup(git_dir_, 1);
+ work_tree = real_pathdup(work_tree_, 1);
+
+ /* Write .git file */
+ write_file(gitfile_sb.buf, "gitdir: %s",
+ relative_path(git_dir, work_tree, &rel_path));
/* Update core.worktree setting */
- strbuf_reset(&file_name);
- strbuf_addf(&file_name, "%s/config", git_dir);
- git_config_set_in_file(file_name.buf, "core.worktree",
+ git_config_set_in_file(cfg_sb.buf, "core.worktree",
relative_path(work_tree, git_dir, &rel_path));
- strbuf_release(&file_name);
+ strbuf_release(&gitfile_sb);
+ strbuf_release(&cfg_sb);
strbuf_release(&rel_path);
free(work_tree);
free(git_dir);
#define PRIo32 "o"
#endif
+typedef uintmax_t timestamp_t;
+#define PRItime PRIuMAX
+#define parse_timestamp strtoumax
+#define TIME_MAX UINTMAX_MAX
+
#ifndef PATH_SEP
#define PATH_SEP ':'
#endif
extern void set_warn_routine(void (*routine)(const char *warn, va_list params));
extern void (*get_warn_routine(void))(const char *warn, va_list params);
extern void set_die_is_recursing_routine(int (*routine)(void));
-extern void set_error_handle(FILE *);
extern int starts_with(const char *str, const char *prefix);
#endif
#define DEFAULT_PACKED_GIT_LIMIT \
- ((1024L * 1024L) * (size_t)(sizeof(void*) >= 8 ? 8192 : 256))
+ ((1024L * 1024L) * (size_t)(sizeof(void*) >= 8 ? (32 * 1024L * 1024L) : 256))
#ifdef NO_PREAD
#define pread git_pread
__attribute__((format (printf, 3, 4)))
extern int xsnprintf(char *dst, size_t max, const char *fmt, ...);
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 256
+#endif
+
+extern int xgethostname(char *buf, size_t len);
+
/* in ctype.c, for kwset users */
extern const unsigned char tolower_trans_tbl[256];
#define HAVE_VARIADIC_MACROS 1
#endif
+#ifdef HAVE_VARIADIC_MACROS
+__attribute__((format (printf, 3, 4))) NORETURN
+void BUG_fl(const char *file, int line, const char *fmt, ...);
+#define BUG(...) BUG_fl(__FILE__, __LINE__, __VA_ARGS__)
+#else
+__attribute__((format (printf, 1, 2))) NORETURN
+void BUG(const char *fmt, ...);
+#endif
+
/*
* Preserves errno, prints a message, but gives no warning for ENOENT.
* Returns 0 on success, which includes trying to unlink an object that does
#define getc_unlocked(fh) getc(fh)
#endif
+ /*
+ * Our code often opens a path to an optional file, to work on its
+ * contents when we can successfully open it. We can ignore a failure
+ * to open if such an optional file does not exist, but we do want to
+ * report a failure in opening for other reasons (e.g. we got an I/O
+ * error, or the file is there, but we lack the permission to open).
+ *
+ * Call this function after seeing an error from open() or fopen() to
+ * see if the errno indicates a missing file that we can safely ignore.
+ */
+ static inline int is_missing_file_error(int errno_)
+ {
+ return (errno_ == ENOENT || errno_ == ENOTDIR);
+ }
+
extern int cmd_main(int, const char **);
#endif
int check_filename(const char *prefix, const char *arg)
{
const char *name;
+ char *to_free = NULL;
struct stat st;
if (starts_with(arg, ":/")) {
return 1;
name = arg + 2;
} else if (prefix)
- name = prefix_filename(prefix, strlen(prefix), arg);
+ name = to_free = prefix_filename(prefix, arg);
else
name = arg;
- if (!lstat(name, &st))
+ if (!lstat(name, &st)) {
+ free(to_free);
return 1; /* file exists */
- if (is_missing_file_error(errno))
+ }
- if (errno == ENOENT || errno == ENOTDIR) {
++ if (is_missing_file_error(errno)) {
+ free(to_free);
return 0; /* file does not exist */
+ }
die_errno("failed to stat '%s'", arg);
}
ssize_t len;
if (stat(path, &st)) {
+ /* NEEDSWORK: discern between ENOENT vs other errors */
error_code = READ_GITFILE_ERR_STAT_FAILED;
goto cleanup_return;
}
/* --work-tree is set without --git-dir; use discovered one */
if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
+ char *to_free = NULL;
+ const char *ret;
+
if (offset != cwd->len && !is_absolute_path(gitdir))
- gitdir = real_pathdup(gitdir, 1);
+ gitdir = to_free = real_pathdup(gitdir, 1);
if (chdir(cwd->buf))
die_errno("Could not come back to cwd");
- return setup_explicit_git_dir(gitdir, cwd, nongit_ok);
+ ret = setup_explicit_git_dir(gitdir, cwd, nongit_ok);
+ free(to_free);
+ return ret;
}
/* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
if (offset == cwd->len)
return NULL;
- /* Make "offset" point to past the '/', and add a '/' at the end */
- offset++;
+ /* Make "offset" point past the '/' (already the case for root dirs) */
+ if (offset != offset_1st_component(cwd->buf))
+ offset++;
+ /* Add a '/' at the end */
strbuf_addch(cwd, '/');
return cwd->buf + offset;
}
/* --work-tree is set without --git-dir; use discovered one */
if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
- const char *gitdir;
+ static const char *gitdir;
gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset);
if (chdir(cwd->buf))
}
}
+enum discovery_result {
+ GIT_DIR_NONE = 0,
+ GIT_DIR_EXPLICIT,
+ GIT_DIR_DISCOVERED,
+ GIT_DIR_BARE,
+ /* these are errors */
+ GIT_DIR_HIT_CEILING = -1,
+ GIT_DIR_HIT_MOUNT_POINT = -2,
+ GIT_DIR_INVALID_GITFILE = -3
+};
+
/*
* We cannot decide in this function whether we are in the work tree or
* not, since the config can only be read _after_ this function was called.
+ *
+ * Also, we avoid changing any global state (such as the current working
+ * directory) to allow early callers.
+ *
+ * The directory where the search should start needs to be passed in via the
+ * `dir` parameter; upon return, the `dir` buffer will contain the path of
+ * the directory where the search ended, and `gitdir` will contain the path of
+ * the discovered .git/ directory, if any. If `gitdir` is not absolute, it
+ * is relative to `dir` (i.e. *not* necessarily the cwd).
*/
-static const char *setup_git_directory_gently_1(int *nongit_ok)
+static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
+ struct strbuf *gitdir,
+ int die_on_error)
{
const char *env_ceiling_dirs = getenv(CEILING_DIRECTORIES_ENVIRONMENT);
struct string_list ceiling_dirs = STRING_LIST_INIT_DUP;
- static struct strbuf cwd = STRBUF_INIT;
- const char *gitdirenv, *ret;
- char *gitfile;
- int offset, offset_parent, ceil_offset = -1;
+ const char *gitdirenv;
+ int ceil_offset = -1, min_offset = has_dos_drive_prefix(dir->buf) ? 3 : 1;
dev_t current_device = 0;
int one_filesystem = 1;
- /*
- * We may have read an incomplete configuration before
- * setting-up the git directory. If so, clear the cache so
- * that the next queries to the configuration reload complete
- * configuration (including the per-repo config file that we
- * ignored previously).
- */
- git_config_clear();
-
- /*
- * Let's assume that we are in a git repository.
- * If it turns out later that we are somewhere else, the value will be
- * updated accordingly.
- */
- if (nongit_ok)
- *nongit_ok = 0;
-
- if (strbuf_getcwd(&cwd))
- die_errno(_("Unable to read current working directory"));
- offset = cwd.len;
-
/*
* If GIT_DIR is set explicitly, we're not going
* to do any discovery, but we still do repository
* validation.
*/
gitdirenv = getenv(GIT_DIR_ENVIRONMENT);
- if (gitdirenv)
- return setup_explicit_git_dir(gitdirenv, &cwd, nongit_ok);
+ if (gitdirenv) {
+ strbuf_addstr(gitdir, gitdirenv);
+ return GIT_DIR_EXPLICIT;
+ }
if (env_ceiling_dirs) {
int empty_entry_found = 0;
string_list_split(&ceiling_dirs, env_ceiling_dirs, PATH_SEP, -1);
filter_string_list(&ceiling_dirs, 0,
canonicalize_ceiling_entry, &empty_entry_found);
- ceil_offset = longest_ancestor_length(cwd.buf, &ceiling_dirs);
+ ceil_offset = longest_ancestor_length(dir->buf, &ceiling_dirs);
string_list_clear(&ceiling_dirs, 0);
}
- if (ceil_offset < 0 && has_dos_drive_prefix(cwd.buf))
- ceil_offset = 1;
+ if (ceil_offset < 0)
+ ceil_offset = min_offset - 2;
/*
- * Test in the following order (relative to the cwd):
+ * Test in the following order (relative to the dir):
* - .git (file containing "gitdir: <path>")
* - .git/
* - ./ (bare)
*/
one_filesystem = !git_env_bool("GIT_DISCOVERY_ACROSS_FILESYSTEM", 0);
if (one_filesystem)
- current_device = get_device_or_die(".", NULL, 0);
+ current_device = get_device_or_die(dir->buf, NULL, 0);
for (;;) {
- gitfile = (char*)read_gitfile(DEFAULT_GIT_DIR_ENVIRONMENT);
- if (gitfile)
- gitdirenv = gitfile = xstrdup(gitfile);
- else {
- if (is_git_directory(DEFAULT_GIT_DIR_ENVIRONMENT))
- gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT;
+ int offset = dir->len, error_code = 0;
+
+ if (offset > min_offset)
+ strbuf_addch(dir, '/');
+ strbuf_addstr(dir, DEFAULT_GIT_DIR_ENVIRONMENT);
+ gitdirenv = read_gitfile_gently(dir->buf, die_on_error ?
+ NULL : &error_code);
+ if (!gitdirenv) {
+ if (die_on_error ||
+ error_code == READ_GITFILE_ERR_NOT_A_FILE) {
+ /* NEEDSWORK: fail if .git is not file nor dir */
+ if (is_git_directory(dir->buf))
+ gitdirenv = DEFAULT_GIT_DIR_ENVIRONMENT;
+ } else if (error_code != READ_GITFILE_ERR_STAT_FAILED)
+ return GIT_DIR_INVALID_GITFILE;
}
-
+ strbuf_setlen(dir, offset);
if (gitdirenv) {
- ret = setup_discovered_git_dir(gitdirenv,
- &cwd, offset,
- nongit_ok);
- free(gitfile);
- return ret;
+ strbuf_addstr(gitdir, gitdirenv);
+ return GIT_DIR_DISCOVERED;
}
- free(gitfile);
- if (is_git_directory("."))
- return setup_bare_git_dir(&cwd, offset, nongit_ok);
-
- offset_parent = offset;
- while (--offset_parent > ceil_offset && cwd.buf[offset_parent] != '/');
- if (offset_parent <= ceil_offset)
- return setup_nongit(cwd.buf, nongit_ok);
- if (one_filesystem) {
- dev_t parent_device = get_device_or_die("..", cwd.buf,
- offset);
- if (parent_device != current_device) {
- if (nongit_ok) {
- if (chdir(cwd.buf))
- die_errno(_("Cannot come back to cwd"));
- *nongit_ok = 1;
- return NULL;
- }
- strbuf_setlen(&cwd, offset);
- die(_("Not a git repository (or any parent up to mount point %s)\n"
- "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)."),
- cwd.buf);
- }
- }
- if (chdir("..")) {
- strbuf_setlen(&cwd, offset);
- die_errno(_("Cannot change to '%s/..'"), cwd.buf);
+ if (is_git_directory(dir->buf)) {
+ strbuf_addstr(gitdir, ".");
+ return GIT_DIR_BARE;
}
- offset = offset_parent;
+
+ if (offset <= min_offset)
+ return GIT_DIR_HIT_CEILING;
+
+ while (--offset > ceil_offset && !is_dir_sep(dir->buf[offset]))
+ ; /* continue */
+ if (offset <= ceil_offset)
+ return GIT_DIR_HIT_CEILING;
+
+ strbuf_setlen(dir, offset > min_offset ? offset : min_offset);
+ if (one_filesystem &&
+ current_device != get_device_or_die(dir->buf, NULL, offset))
+ return GIT_DIR_HIT_MOUNT_POINT;
+ }
+}
+
+const char *discover_git_directory(struct strbuf *gitdir)
+{
+ struct strbuf dir = STRBUF_INIT, err = STRBUF_INIT;
+ size_t gitdir_offset = gitdir->len, cwd_len;
+ struct repository_format candidate;
+
+ if (strbuf_getcwd(&dir))
+ return NULL;
+
+ cwd_len = dir.len;
+ if (setup_git_directory_gently_1(&dir, gitdir, 0) <= 0) {
+ strbuf_release(&dir);
+ return NULL;
+ }
+
+ /*
+ * The returned gitdir is relative to dir, and if dir does not reflect
+ * the current working directory, we simply make the gitdir absolute.
+ */
+ if (dir.len < cwd_len && !is_absolute_path(gitdir->buf + gitdir_offset)) {
+ /* Avoid a trailing "/." */
+ if (!strcmp(".", gitdir->buf + gitdir_offset))
+ strbuf_setlen(gitdir, gitdir_offset);
+ else
+ strbuf_addch(&dir, '/');
+ strbuf_insert(gitdir, gitdir_offset, dir.buf, dir.len);
}
+
+ strbuf_reset(&dir);
+ strbuf_addf(&dir, "%s/config", gitdir->buf + gitdir_offset);
+ read_repository_format(&candidate, dir.buf);
+ strbuf_release(&dir);
+
+ if (verify_repository_format(&candidate, &err) < 0) {
+ warning("ignoring git dir '%s': %s",
+ gitdir->buf + gitdir_offset, err.buf);
+ strbuf_release(&err);
+ return NULL;
+ }
+
+ return gitdir->buf + gitdir_offset;
}
const char *setup_git_directory_gently(int *nongit_ok)
{
- const char *prefix;
+ static struct strbuf cwd = STRBUF_INIT;
+ struct strbuf dir = STRBUF_INIT, gitdir = STRBUF_INIT;
+ const char *prefix, *env_prefix;
+
+ /*
+ * We may have read an incomplete configuration before
+ * setting-up the git directory. If so, clear the cache so
+ * that the next queries to the configuration reload complete
+ * configuration (including the per-repo config file that we
+ * ignored previously).
+ */
+ git_config_clear();
+
+ /*
+ * Let's assume that we are in a git repository.
+ * If it turns out later that we are somewhere else, the value will be
+ * updated accordingly.
+ */
+ if (nongit_ok)
+ *nongit_ok = 0;
+
+ if (strbuf_getcwd(&cwd))
+ die_errno(_("Unable to read current working directory"));
+ strbuf_addbuf(&dir, &cwd);
+
+ switch (setup_git_directory_gently_1(&dir, &gitdir, 1)) {
+ case GIT_DIR_NONE:
+ prefix = NULL;
+ break;
+ case GIT_DIR_EXPLICIT:
+ prefix = setup_explicit_git_dir(gitdir.buf, &cwd, nongit_ok);
+ break;
+ case GIT_DIR_DISCOVERED:
+ if (dir.len < cwd.len && chdir(dir.buf))
+ die(_("Cannot change to '%s'"), dir.buf);
+ prefix = setup_discovered_git_dir(gitdir.buf, &cwd, dir.len,
+ nongit_ok);
+ break;
+ case GIT_DIR_BARE:
+ if (dir.len < cwd.len && chdir(dir.buf))
+ die(_("Cannot change to '%s'"), dir.buf);
+ prefix = setup_bare_git_dir(&cwd, dir.len, nongit_ok);
+ break;
+ case GIT_DIR_HIT_CEILING:
+ prefix = setup_nongit(cwd.buf, nongit_ok);
+ break;
+ case GIT_DIR_HIT_MOUNT_POINT:
+ if (nongit_ok) {
+ *nongit_ok = 1;
+ strbuf_release(&cwd);
+ strbuf_release(&dir);
+ return NULL;
+ }
+ die(_("Not a git repository (or any parent up to mount point %s)\n"
+ "Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)."),
+ dir.buf);
+ default:
+ die("BUG: unhandled setup_git_directory_1() result");
+ }
+
+ env_prefix = getenv(GIT_TOPLEVEL_PREFIX_ENVIRONMENT);
+ if (env_prefix)
+ prefix = env_prefix;
- prefix = setup_git_directory_gently_1(nongit_ok);
if (prefix)
setenv(GIT_PREFIX_ENVIRONMENT, prefix, 1);
else
startup_info->have_repository = !nongit_ok || !*nongit_ok;
startup_info->prefix = prefix;
+ strbuf_release(&dir);
+ strbuf_release(&gitdir);
+
return prefix;
}
static int get_sha1_oneline(const char *, unsigned char *, struct commit_list *);
-typedef int (*disambiguate_hint_fn)(const unsigned char *, void *);
+typedef int (*disambiguate_hint_fn)(const struct object_id *, void *);
struct disambiguate_state {
int len; /* length of prefix in hex chars */
- char hex_pfx[GIT_SHA1_HEXSZ + 1];
- unsigned char bin_pfx[GIT_SHA1_RAWSZ];
+ char hex_pfx[GIT_MAX_HEXSZ + 1];
+ struct object_id bin_pfx;
disambiguate_hint_fn fn;
void *cb_data;
- unsigned char candidate[GIT_SHA1_RAWSZ];
+ struct object_id candidate;
unsigned candidate_exists:1;
unsigned candidate_checked:1;
unsigned candidate_ok:1;
unsigned always_call_fn:1;
};
-static void update_candidates(struct disambiguate_state *ds, const unsigned char *current)
+static void update_candidates(struct disambiguate_state *ds, const struct object_id *current)
{
if (ds->always_call_fn) {
ds->ambiguous = ds->fn(current, ds->cb_data) ? 1 : 0;
}
if (!ds->candidate_exists) {
/* this is the first candidate */
- hashcpy(ds->candidate, current);
+ oidcpy(&ds->candidate, current);
ds->candidate_exists = 1;
return;
- } else if (!hashcmp(ds->candidate, current)) {
+ } else if (!oidcmp(&ds->candidate, current)) {
/* the same as what we already have seen */
return;
}
}
if (!ds->candidate_checked) {
- ds->candidate_ok = ds->fn(ds->candidate, ds->cb_data);
+ ds->candidate_ok = ds->fn(&ds->candidate, ds->cb_data);
ds->disambiguate_fn_used = 1;
ds->candidate_checked = 1;
}
if (!ds->candidate_ok) {
/* discard the candidate; we know it does not satisfy fn */
- hashcpy(ds->candidate, current);
+ oidcpy(&ds->candidate, current);
ds->candidate_checked = 0;
return;
}
static void find_short_object_filename(struct disambiguate_state *ds)
{
struct alternate_object_database *alt;
- char hex[GIT_SHA1_HEXSZ];
+ char hex[GIT_MAX_HEXSZ];
static struct alternate_object_database *fakeent;
if (!fakeent) {
continue;
while (!ds->ambiguous && (de = readdir(dir)) != NULL) {
- unsigned char sha1[20];
+ struct object_id oid;
- if (strlen(de->d_name) != 38)
+ if (strlen(de->d_name) != GIT_SHA1_HEXSZ - 2)
continue;
if (memcmp(de->d_name, ds->hex_pfx + 2, ds->len - 2))
continue;
- memcpy(hex + 2, de->d_name, 38);
- if (!get_sha1_hex(hex, sha1))
- update_candidates(ds, sha1);
+ memcpy(hex + 2, de->d_name, GIT_SHA1_HEXSZ - 2);
+ if (!get_oid_hex(hex, &oid))
+ update_candidates(ds, &oid);
}
closedir(dir);
}
struct disambiguate_state *ds)
{
uint32_t num, last, i, first = 0;
- const unsigned char *current = NULL;
+ const struct object_id *current = NULL;
open_pack_index(p);
num = p->num_objects;
int cmp;
current = nth_packed_object_sha1(p, mid);
- cmp = hashcmp(ds->bin_pfx, current);
+ cmp = hashcmp(ds->bin_pfx.hash, current);
if (!cmp) {
first = mid;
break;
* 0, 1 or more objects that actually match(es).
*/
for (i = first; i < num && !ds->ambiguous; i++) {
- current = nth_packed_object_sha1(p, i);
- if (!match_sha(ds->len, ds->bin_pfx, current))
+ struct object_id oid;
+ current = nth_packed_object_oid(&oid, p, i);
+ if (!match_sha(ds->len, ds->bin_pfx.hash, current->hash))
break;
update_candidates(ds, current);
}
* same repository!
*/
ds->candidate_ok = (!ds->disambiguate_fn_used ||
- ds->fn(ds->candidate, ds->cb_data));
+ ds->fn(&ds->candidate, ds->cb_data));
if (!ds->candidate_ok)
return SHORT_NAME_AMBIGUOUS;
- hashcpy(sha1, ds->candidate);
+ hashcpy(sha1, ds->candidate.hash);
return 0;
}
-static int disambiguate_commit_only(const unsigned char *sha1, void *cb_data_unused)
+static int disambiguate_commit_only(const struct object_id *oid, void *cb_data_unused)
{
- int kind = sha1_object_info(sha1, NULL);
+ int kind = sha1_object_info(oid->hash, NULL);
return kind == OBJ_COMMIT;
}
-static int disambiguate_committish_only(const unsigned char *sha1, void *cb_data_unused)
+static int disambiguate_committish_only(const struct object_id *oid, void *cb_data_unused)
{
struct object *obj;
int kind;
- kind = sha1_object_info(sha1, NULL);
+ kind = sha1_object_info(oid->hash, NULL);
if (kind == OBJ_COMMIT)
return 1;
if (kind != OBJ_TAG)
return 0;
/* We need to do this the hard way... */
- obj = deref_tag(parse_object(sha1), NULL, 0);
+ obj = deref_tag(parse_object(oid), NULL, 0);
if (obj && obj->type == OBJ_COMMIT)
return 1;
return 0;
}
-static int disambiguate_tree_only(const unsigned char *sha1, void *cb_data_unused)
+static int disambiguate_tree_only(const struct object_id *oid, void *cb_data_unused)
{
- int kind = sha1_object_info(sha1, NULL);
+ int kind = sha1_object_info(oid->hash, NULL);
return kind == OBJ_TREE;
}
-static int disambiguate_treeish_only(const unsigned char *sha1, void *cb_data_unused)
+static int disambiguate_treeish_only(const struct object_id *oid, void *cb_data_unused)
{
struct object *obj;
int kind;
- kind = sha1_object_info(sha1, NULL);
+ kind = sha1_object_info(oid->hash, NULL);
if (kind == OBJ_TREE || kind == OBJ_COMMIT)
return 1;
if (kind != OBJ_TAG)
return 0;
/* We need to do this the hard way... */
- obj = deref_tag(parse_object(sha1), NULL, 0);
+ obj = deref_tag(parse_object(oid), NULL, 0);
if (obj && (obj->type == OBJ_TREE || obj->type == OBJ_COMMIT))
return 1;
return 0;
}
-static int disambiguate_blob_only(const unsigned char *sha1, void *cb_data_unused)
+static int disambiguate_blob_only(const struct object_id *oid, void *cb_data_unused)
{
- int kind = sha1_object_info(sha1, NULL);
+ int kind = sha1_object_info(oid->hash, NULL);
return kind == OBJ_BLOB;
}
ds->hex_pfx[i] = c;
if (!(i & 1))
val <<= 4;
- ds->bin_pfx[i >> 1] |= val;
+ ds->bin_pfx.hash[i >> 1] |= val;
}
ds->len = len;
return 0;
}
-static int show_ambiguous_object(const unsigned char *sha1, void *data)
+static int show_ambiguous_object(const struct object_id *oid, void *data)
{
const struct disambiguate_state *ds = data;
struct strbuf desc = STRBUF_INIT;
int type;
- if (ds->fn && !ds->fn(sha1, ds->cb_data))
+
+ if (ds->fn && !ds->fn(oid, ds->cb_data))
return 0;
- type = sha1_object_info(sha1, NULL);
+ type = sha1_object_info(oid->hash, NULL);
if (type == OBJ_COMMIT) {
- struct commit *commit = lookup_commit(sha1);
+ struct commit *commit = lookup_commit(oid);
if (commit) {
struct pretty_print_context pp = {0};
pp.date_mode.type = DATE_SHORT;
format_commit_message(commit, " %ad - %s", &desc, &pp);
}
} else if (type == OBJ_TAG) {
- struct tag *tag = lookup_tag(sha1);
+ struct tag *tag = lookup_tag(oid);
if (!parse_tag(tag) && tag->tag)
strbuf_addf(&desc, " %s", tag->tag);
}
advise(" %s %s%s",
- find_unique_abbrev(sha1, DEFAULT_ABBREV),
+ find_unique_abbrev(oid->hash, DEFAULT_ABBREV),
typename(type) ? typename(type) : "unknown type",
desc.buf);
return status;
}
-static int collect_ambiguous(const unsigned char *sha1, void *data)
+static int collect_ambiguous(const struct object_id *oid, void *data)
{
- sha1_array_append(data, sha1);
+ oid_array_append(data, oid);
return 0;
}
int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)
{
- struct sha1_array collect = SHA1_ARRAY_INIT;
+ struct oid_array collect = OID_ARRAY_INIT;
struct disambiguate_state ds;
int ret;
find_short_object_filename(&ds);
find_short_packed_object(&ds);
- ret = sha1_array_for_each_unique(&collect, fn, cb_data);
- sha1_array_clear(&collect);
+ ret = oid_array_for_each_unique(&collect, fn, cb_data);
+ oid_array_clear(&collect);
return ret;
}
const char *find_unique_abbrev(const unsigned char *sha1, int len)
{
static int bufno;
- static char hexbuffer[4][GIT_SHA1_HEXSZ + 1];
+ static char hexbuffer[4][GIT_MAX_HEXSZ + 1];
char *hex = hexbuffer[bufno];
bufno = (bufno + 1) % ARRAY_SIZE(hexbuffer);
find_unique_abbrev_r(hex, sha1, len);
for (i = 0; i < nr; i++) {
int suffix_len = strlen(suffix[i]);
if (suffix_len <= len
- && !memcmp(string, suffix[i], suffix_len))
+ && !strncasecmp(string, suffix[i], suffix_len))
return suffix_len;
}
return 0;
if (reflog_len) {
int nth, i;
- unsigned long at_time;
- unsigned long co_time;
+ timestamp_t at_time;
+ timestamp_t co_time;
int co_tz, co_cnt;
/* Is it asking for N-th entry, or approxidate? */
static int get_parent(const char *name, int len,
unsigned char *result, int idx)
{
- unsigned char sha1[20];
- int ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH);
+ struct object_id oid;
+ int ret = get_sha1_1(name, len, oid.hash, GET_SHA1_COMMITTISH);
struct commit *commit;
struct commit_list *p;
if (ret)
return ret;
- commit = lookup_commit_reference(sha1);
+ commit = lookup_commit_reference(&oid);
if (parse_commit(commit))
return -1;
if (!idx) {
static int get_nth_ancestor(const char *name, int len,
unsigned char *result, int generation)
{
- unsigned char sha1[20];
+ struct object_id oid;
struct commit *commit;
int ret;
- ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH);
+ ret = get_sha1_1(name, len, oid.hash, GET_SHA1_COMMITTISH);
if (ret)
return ret;
- commit = lookup_commit_reference(sha1);
+ commit = lookup_commit_reference(&oid);
if (!commit)
return -1;
if (name && !namelen)
namelen = strlen(name);
while (1) {
- if (!o || (!o->parsed && !parse_object(o->oid.hash)))
+ if (!o || (!o->parsed && !parse_object(&o->oid)))
return NULL;
if (expected_type == OBJ_ANY || o->type == expected_type)
return o;
static int peel_onion(const char *name, int len, unsigned char *sha1,
unsigned lookup_flags)
{
- unsigned char outer[20];
+ struct object_id outer;
const char *sp;
unsigned int expected_type = 0;
struct object *o;
else if (expected_type == OBJ_TREE)
lookup_flags |= GET_SHA1_TREEISH;
- if (get_sha1_1(name, sp - name - 2, outer, lookup_flags))
+ if (get_sha1_1(name, sp - name - 2, outer.hash, lookup_flags))
return -1;
- o = parse_object(outer);
+ o = parse_object(&outer);
if (!o)
return -1;
if (!expected_type) {
o = deref_tag(o, name, sp - name - 2);
- if (!o || (!o->parsed && !parse_object(o->oid.hash)))
+ if (!o || (!o->parsed && !parse_object(&o->oid)))
return -1;
hashcpy(sha1, o->oid.hash);
return 0;
int flag, void *cb_data)
{
struct commit_list **list = cb_data;
- struct object *object = parse_object(oid->hash);
+ struct object *object = parse_object(oid);
if (!object)
return 0;
if (object->type == OBJ_TAG) {
int matches;
commit = pop_most_recent_commit(&list, ONELINE_SEEN);
- if (!parse_object(commit->object.oid.hash))
+ if (!parse_object(&commit->object.oid))
continue;
buf = get_commit_buffer(commit, NULL);
p = strstr(buf, "\n\n");
struct strbuf buf;
};
-static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
- const char *email, unsigned long timestamp, int tz,
+static int grab_nth_branch_switch(struct object_id *ooid, struct object_id *noid,
+ const char *email, timestamp_t timestamp, int tz,
const char *message, void *cb_data)
{
struct grab_nth_branch_switch_cbdata *cb = cb_data;
}
if (st)
return st;
- one = lookup_commit_reference_gently(oid_tmp.hash, 0);
+ one = lookup_commit_reference_gently(&oid_tmp, 0);
if (!one)
return -1;
if (get_sha1_committish(dots[3] ? (dots + 3) : "HEAD", oid_tmp.hash))
return -1;
- two = lookup_commit_reference_gently(oid_tmp.hash, 0);
+ two = lookup_commit_reference_gently(&oid_tmp, 0);
if (!two)
return -1;
mbs = get_merge_bases(one, two);
if (file_exists(filename))
die("Path '%s' exists on disk, but not in '%.*s'.",
filename, object_name_len, object_name);
- if (errno == ENOENT || errno == ENOTDIR) {
+ if (is_missing_file_error(errno)) {
char *fullname = xstrfmt("%s%s", prefix, filename);
if (!get_tree_entry(tree_sha1, fullname,
if (file_exists(filename))
die("Path '%s' exists on disk, but not in the index.", filename);
- if (errno == ENOENT || errno == ENOTDIR)
+ if (is_missing_file_error(errno))
die("Path '%s' does not exist (neither on disk nor in the index).",
filename);
memset(oc, 0, sizeof(*oc));
oc->mode = S_IFINVALID;
+ strbuf_init(&oc->symlink_path, 0);
ret = get_sha1_1(name, namelen, sha1, flags);
if (!ret)
return ret;
namelen = strlen(cp);
}
- strlcpy(oc->path, cp, sizeof(oc->path));
+ if (flags & GET_SHA1_RECORD_PATH)
+ oc->path = xstrdup(cp);
if (!active_cache)
read_cache();
}
}
hashcpy(oc->tree, tree_sha1);
- strlcpy(oc->path, filename, sizeof(oc->path));
+ if (flags & GET_SHA1_RECORD_PATH)
+ oc->path = xstrdup(filename);
free(new_filename);
return ret;
get_sha1_with_context_1(name, GET_SHA1_ONLY_TO_DIE, prefix, sha1, &oc);
}
-int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc)
+int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *oc)
{
if (flags & GET_SHA1_FOLLOW_SYMLINKS && flags & GET_SHA1_ONLY_TO_DIE)
die("BUG: incompatible flags for get_sha1_with_context");
- return get_sha1_with_context_1(str, flags, NULL, sha1, orc);
+ return get_sha1_with_context_1(str, flags, NULL, sha1, oc);
}
static int access_error_is_ok(int err, unsigned flag)
{
- return err == ENOENT || err == ENOTDIR ||
- ((flag & ACCESS_EACCES_OK) && err == EACCES);
+ return (is_missing_file_error(err) ||
+ ((flag & ACCESS_EACCES_OK) && err == EACCES));
}
int access_or_warn(const char *path, int mode, unsigned flag)
{
poll(NULL, 0, millisec);
}
+
+int xgethostname(char *buf, size_t len)
+{
+ /*
+ * If the full hostname doesn't fit in buf, POSIX does not
+ * specify whether the buffer will be null-terminated, so to
+ * be safe, do it ourselves.
+ */
+ int ret = gethostname(buf, len);
+ if (!ret)
+ buf[len - 1] = 0;
+ return ret;
+}