summaryrefslogtreecommitdiff
path: root/dir.c
diff options
context:
space:
mode:
Diffstat (limited to 'dir.c')
-rw-r--r--dir.c198
1 files changed, 107 insertions, 91 deletions
diff --git a/dir.c b/dir.c
index a71331af18..9e09bcbd02 100644
--- a/dir.c
+++ b/dir.c
@@ -53,24 +53,16 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir,
int check_only, const struct path_simplify *simplify);
static int get_dtype(struct dirent *de, const char *path, int len);
-/* helper string functions with support for the ignore_case flag */
-int strcmp_icase(const char *a, const char *b)
+int fspathcmp(const char *a, const char *b)
{
return ignore_case ? strcasecmp(a, b) : strcmp(a, b);
}
-int strncmp_icase(const char *a, const char *b, size_t count)
+int fspathncmp(const char *a, const char *b, size_t count)
{
return ignore_case ? strncasecmp(a, b, count) : strncmp(a, b, count);
}
-int fnmatch_icase(const char *pattern, const char *string, int flags)
-{
- return wildmatch(pattern, string,
- flags | (ignore_case ? WM_CASEFOLD : 0),
- NULL);
-}
-
int git_fnmatch(const struct pathspec_item *item,
const char *pattern, const char *string,
int prefix)
@@ -457,7 +449,7 @@ int no_wildcard(const char *string)
void parse_exclude_pattern(const char **pattern,
int *patternlen,
- int *flags,
+ unsigned *flags,
int *nowildcardlen)
{
const char *p = *pattern;
@@ -498,17 +490,12 @@ void add_exclude(const char *string, const char *base,
{
struct exclude *x;
int patternlen;
- int flags;
+ unsigned flags;
int nowildcardlen;
parse_exclude_pattern(&string, &patternlen, &flags, &nowildcardlen);
if (flags & EXC_FLAG_MUSTBEDIR) {
- char *s;
- x = xmalloc(sizeof(*x) + patternlen + 1);
- s = (char *)(x+1);
- memcpy(s, string, patternlen);
- s[patternlen] = '\0';
- x->pattern = s;
+ FLEXPTR_ALLOC_MEM(x, pattern, string, patternlen);
} else {
x = xmalloc(sizeof(*x));
x->pattern = string;
@@ -538,7 +525,7 @@ static void *read_skip_worktree_file_from_index(const char *path, size_t *size,
return NULL;
if (!ce_skip_worktree(active_cache[pos]))
return NULL;
- data = read_sha1_file(active_cache[pos]->sha1, &type, &sz);
+ data = read_sha1_file(active_cache[pos]->oid.hash, &type, &sz);
if (!data || type != OBJ_BLOB) {
free(data);
return NULL;
@@ -546,7 +533,7 @@ static void *read_skip_worktree_file_from_index(const char *path, size_t *size,
*size = xsize_t(sz);
if (sha1_stat) {
memset(&sha1_stat->stat, 0, sizeof(sha1_stat->stat));
- hashcpy(sha1_stat->sha1, active_cache[pos]->sha1);
+ hashcpy(sha1_stat->sha1, active_cache[pos]->oid.hash);
}
return data;
}
@@ -564,9 +551,7 @@ void clear_exclude_list(struct exclude_list *el)
free(el->excludes);
free(el->filebuf);
- el->nr = 0;
- el->excludes = NULL;
- el->filebuf = NULL;
+ memset(el, 0, sizeof(*el));
}
static void trim_trailing_spaces(char *buf)
@@ -627,10 +612,7 @@ static struct untracked_cache_dir *lookup_untracked(struct untracked_cache *uc,
}
uc->dir_created++;
- d = xmalloc(sizeof(*d) + len + 1);
- memset(d, 0, sizeof(*d));
- memcpy(d->name, name, len);
- d->name[len] = '\0';
+ FLEX_ALLOC_MEM(d, name, name, len);
ALLOC_GROW(dir->dirs, dir->dirs_nr + 1, dir->dirs_alloc);
memmove(dir->dirs + first + 1, dir->dirs + first,
@@ -699,7 +681,7 @@ static int add_excludes(const char *fname, const char *base, int baselen,
return 0;
}
if (buf[size-1] != '\n') {
- buf = xrealloc(buf, size+1);
+ buf = xrealloc(buf, st_add(size, 1));
buf[size++] = '\n';
}
} else {
@@ -713,7 +695,7 @@ static int add_excludes(const char *fname, const char *base, int baselen,
close(fd);
return 0;
}
- buf = xmalloc(size+1);
+ buf = xmallocz(size);
if (read_in_full(fd, buf, size) != size) {
free(buf);
close(fd);
@@ -731,7 +713,8 @@ static int add_excludes(const char *fname, const char *base, int baselen,
!ce_stage(active_cache[pos]) &&
ce_uptodate(active_cache[pos]) &&
!would_convert_to_git(fname))
- hashcpy(sha1_stat->sha1, active_cache[pos]->sha1);
+ hashcpy(sha1_stat->sha1,
+ active_cache[pos]->oid.hash);
else
hash_sha1_file(buf, size, "blob", sha1_stat->sha1);
fill_stat_data(&sha1_stat->stat, &st);
@@ -808,16 +791,16 @@ void add_excludes_from_file(struct dir_struct *dir, const char *fname)
int match_basename(const char *basename, int basenamelen,
const char *pattern, int prefix, int patternlen,
- int flags)
+ unsigned flags)
{
if (prefix == patternlen) {
if (patternlen == basenamelen &&
- !strncmp_icase(pattern, basename, basenamelen))
+ !fspathncmp(pattern, basename, basenamelen))
return 1;
} else if (flags & EXC_FLAG_ENDSWITH) {
/* "*literal" matching against "fooliteral" */
if (patternlen - 1 <= basenamelen &&
- !strncmp_icase(pattern + 1,
+ !fspathncmp(pattern + 1,
basename + basenamelen - (patternlen - 1),
patternlen - 1))
return 1;
@@ -833,7 +816,7 @@ int match_basename(const char *basename, int basenamelen,
int match_pathname(const char *pathname, int pathlen,
const char *base, int baselen,
const char *pattern, int prefix, int patternlen,
- int flags)
+ unsigned flags)
{
const char *name;
int namelen;
@@ -854,7 +837,7 @@ int match_pathname(const char *pathname, int pathlen,
*/
if (pathlen < baselen + 1 ||
(baselen && pathname[baselen] != '/') ||
- strncmp_icase(pathname, base, baselen))
+ fspathncmp(pathname, base, baselen))
return 0;
namelen = baselen ? pathlen - baselen - 1 : pathlen;
@@ -868,7 +851,7 @@ int match_pathname(const char *pathname, int pathlen,
if (prefix > namelen)
return 0;
- if (strncmp_icase(pattern, name, prefix))
+ if (fspathncmp(pattern, name, prefix))
return 0;
pattern += prefix;
patternlen -= prefix;
@@ -901,6 +884,7 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,
int *dtype,
struct exclude_list *el)
{
+ struct exclude *exc = NULL; /* undecided */
int i;
if (!el->nr)
@@ -922,18 +906,22 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,
if (match_basename(basename,
pathlen - (basename - pathname),
exclude, prefix, x->patternlen,
- x->flags))
- return x;
+ x->flags)) {
+ exc = x;
+ break;
+ }
continue;
}
assert(x->baselen == 0 || x->base[x->baselen - 1] == '/');
if (match_pathname(pathname, pathlen,
x->base, x->baselen ? x->baselen - 1 : 0,
- exclude, prefix, x->patternlen, x->flags))
- return x;
+ exclude, prefix, x->patternlen, x->flags)) {
+ exc = x;
+ break;
+ }
}
- return NULL; /* undecided */
+ return exc;
}
/*
@@ -1164,10 +1152,8 @@ static struct dir_entry *dir_entry_new(const char *pathname, int len)
{
struct dir_entry *ent;
- ent = xmalloc(sizeof(*ent) + len + 1);
+ FLEX_ALLOC_MEM(ent, name, pathname, len);
ent->len = len;
- memcpy(ent->name, pathname, len);
- ent->name[len] = 0;
return ent;
}
@@ -1202,29 +1188,15 @@ enum exist_status {
*/
static enum exist_status directory_exists_in_index_icase(const char *dirname, int len)
{
- const struct cache_entry *ce = cache_dir_exists(dirname, len);
- unsigned char endchar;
-
- if (!ce)
- return index_nonexistent;
- endchar = ce->name[len];
+ struct cache_entry *ce;
- /*
- * The cache_entry structure returned will contain this dirname
- * and possibly additional path components.
- */
- if (endchar == '/')
+ if (cache_dir_exists(dirname, len))
return index_directory;
- /*
- * If there are no additional path components, then this cache_entry
- * represents a submodule. Submodules, despite being directories,
- * are stored in the cache without a closing slash.
- */
- if (!endchar && S_ISGITLINK(ce->ce_mode))
+ ce = cache_file_exists(dirname, len, ignore_case);
+ if (ce && S_ISGITLINK(ce->ce_mode))
return index_gitdir;
- /* This should never be hit, but it exists just in case. */
return index_nonexistent;
}
@@ -1519,8 +1491,7 @@ static enum path_treatment treat_path_fast(struct dir_struct *dir,
}
strbuf_addstr(path, cdir->ucd->name);
/* treat_one_path() does this before it calls treat_directory() */
- if (path->buf[path->len - 1] != '/')
- strbuf_addch(path, '/');
+ strbuf_complete(path, '/');
if (cdir->ucd->check_only)
/*
* check_only is set as a result of treat_directory() getting
@@ -1851,31 +1822,67 @@ static const char *get_ident_string(void)
return sb.buf;
if (uname(&uts) < 0)
die_errno(_("failed to get kernel name and information"));
- strbuf_addf(&sb, "Location %s, system %s %s %s", get_git_work_tree(),
- uts.sysname, uts.release, uts.version);
+ strbuf_addf(&sb, "Location %s, system %s", get_git_work_tree(),
+ uts.sysname);
return sb.buf;
}
static int ident_in_untracked(const struct untracked_cache *uc)
{
- const char *end = uc->ident.buf + uc->ident.len;
- const char *p = uc->ident.buf;
+ /*
+ * Previous git versions may have saved many NUL separated
+ * strings in the "ident" field, but it is insane to manage
+ * many locations, so just take care of the first one.
+ */
- for (p = uc->ident.buf; p < end; p += strlen(p) + 1)
- if (!strcmp(p, get_ident_string()))
- return 1;
- return 0;
+ return !strcmp(uc->ident.buf, get_ident_string());
}
-void add_untracked_ident(struct untracked_cache *uc)
+static void set_untracked_ident(struct untracked_cache *uc)
{
- if (ident_in_untracked(uc))
- return;
+ strbuf_reset(&uc->ident);
strbuf_addstr(&uc->ident, get_ident_string());
- /* this strbuf contains a list of strings, save NUL too */
+
+ /*
+ * This strbuf used to contain a list of NUL separated
+ * strings, so save NUL too for backward compatibility.
+ */
strbuf_addch(&uc->ident, 0);
}
+static void new_untracked_cache(struct index_state *istate)
+{
+ struct untracked_cache *uc = xcalloc(1, sizeof(*uc));
+ strbuf_init(&uc->ident, 100);
+ uc->exclude_per_dir = ".gitignore";
+ /* should be the same flags used by git-status */
+ uc->dir_flags = DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
+ set_untracked_ident(uc);
+ istate->untracked = uc;
+ istate->cache_changed |= UNTRACKED_CHANGED;
+}
+
+void add_untracked_cache(struct index_state *istate)
+{
+ if (!istate->untracked) {
+ new_untracked_cache(istate);
+ } else {
+ if (!ident_in_untracked(istate->untracked)) {
+ free_untracked_cache(istate->untracked);
+ new_untracked_cache(istate);
+ }
+ }
+}
+
+void remove_untracked_cache(struct index_state *istate)
+{
+ if (istate->untracked) {
+ free_untracked_cache(istate->untracked);
+ istate->untracked = NULL;
+ istate->cache_changed |= UNTRACKED_CHANGED;
+ }
+}
+
static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *dir,
int base_len,
const struct pathspec *pathspec)
@@ -1933,7 +1940,7 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
return NULL;
if (!ident_in_untracked(dir->untracked)) {
- warning(_("Untracked cache is disabled on this system."));
+ warning(_("Untracked cache is disabled on this system or location."));
return NULL;
}
@@ -2030,6 +2037,15 @@ int file_exists(const char *f)
return lstat(f, &sb) == 0;
}
+static int cmp_icase(char a, char b)
+{
+ if (a == b)
+ return 0;
+ if (ignore_case)
+ return toupper(a) - toupper(b);
+ return a - b;
+}
+
/*
* Given two normalized paths (a trailing slash is ok), if subdir is
* outside dir, return -1. Otherwise return the offset in subdir that
@@ -2041,7 +2057,7 @@ int dir_inside_of(const char *subdir, const char *dir)
assert(dir && subdir && *dir && *subdir);
- while (*dir && *subdir && *dir == *subdir) {
+ while (*dir && *subdir && !cmp_icase(*dir, *subdir)) {
dir++;
subdir++;
offset++;
@@ -2126,8 +2142,7 @@ static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up)
else
return -1;
}
- if (path->buf[original_len - 1] != '/')
- strbuf_addch(path, '/');
+ strbuf_complete(path, '/');
len = path->len;
while ((e = readdir(dir)) != NULL) {
@@ -2176,6 +2191,8 @@ int remove_dir_recursively(struct strbuf *path, int flag)
return remove_dir_recurse(path, flag, NULL);
}
+static GIT_PATH_FUNC(git_path_info_exclude, "info/exclude")
+
void setup_standard_excludes(struct dir_struct *dir)
{
const char *path;
@@ -2190,7 +2207,7 @@ void setup_standard_excludes(struct dir_struct *dir)
dir->untracked ? &dir->ss_excludes_file : NULL);
/* per repository user preference */
- path = git_path("info/exclude");
+ path = git_path_info_exclude();
if (!access_or_warn(path, R_OK, 0))
add_excludes_from_file_1(dir, path,
dir->untracked ? &dir->ss_info_exclude : NULL);
@@ -2336,20 +2353,19 @@ void write_untracked_extension(struct strbuf *out, struct untracked_cache *untra
struct ondisk_untracked_cache *ouc;
struct write_data wd;
unsigned char varbuf[16];
- int len = 0, varint_len;
- if (untracked->exclude_per_dir)
- len = strlen(untracked->exclude_per_dir);
- ouc = xmalloc(sizeof(*ouc) + len + 1);
+ int varint_len;
+ size_t len = strlen(untracked->exclude_per_dir);
+
+ FLEX_ALLOC_MEM(ouc, exclude_per_dir, untracked->exclude_per_dir, len);
stat_data_to_disk(&ouc->info_exclude_stat, &untracked->ss_info_exclude.stat);
stat_data_to_disk(&ouc->excludes_file_stat, &untracked->ss_excludes_file.stat);
hashcpy(ouc->info_exclude_sha1, untracked->ss_info_exclude.sha1);
hashcpy(ouc->excludes_file_sha1, untracked->ss_excludes_file.sha1);
ouc->dir_flags = htonl(untracked->dir_flags);
- memcpy(ouc->exclude_per_dir, untracked->exclude_per_dir, len + 1);
varint_len = encode_varint(untracked->ident.len, varbuf);
strbuf_add(out, varbuf, varint_len);
- strbuf_add(out, untracked->ident.buf, untracked->ident.len);
+ strbuf_addbuf(out, &untracked->ident);
strbuf_add(out, ouc, ouc_size(len));
free(ouc);
@@ -2450,21 +2466,21 @@ static int read_one_dir(struct untracked_cache_dir **untracked_,
ud.untracked_alloc = value;
ud.untracked_nr = value;
if (ud.untracked_nr)
- ud.untracked = xmalloc(sizeof(*ud.untracked) * ud.untracked_nr);
+ ALLOC_ARRAY(ud.untracked, ud.untracked_nr);
data = next;
next = data;
ud.dirs_alloc = ud.dirs_nr = decode_varint(&next);
if (next > end)
return -1;
- ud.dirs = xmalloc(sizeof(*ud.dirs) * ud.dirs_nr);
+ ALLOC_ARRAY(ud.dirs, ud.dirs_nr);
data = next;
len = strlen((const char *)data);
next = data + len + 1;
if (next > rd->end)
return -1;
- *untracked_ = untracked = xmalloc(sizeof(*untracked) + len);
+ *untracked_ = untracked = xmalloc(st_add(sizeof(*untracked), len));
memcpy(untracked, &ud, sizeof(ud));
memcpy(untracked->name, data, len + 1);
data = next;
@@ -2577,7 +2593,7 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long
rd.data = next;
rd.end = end;
rd.index = 0;
- rd.ucd = xmalloc(sizeof(*rd.ucd) * len);
+ ALLOC_ARRAY(rd.ucd, len);
if (read_one_dir(&uc->root, &rd) || rd.index != len)
goto done;