diff options
Diffstat (limited to 'dir.c')
-rw-r--r-- | dir.c | 198 |
1 files changed, 107 insertions, 91 deletions
@@ -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; |