From: Junio C Hamano Date: Tue, 8 May 2012 16:43:40 +0000 (-0700) Subject: Merge branch 'rs/maint-dir-strbuf' into rs/dir-strbuf X-Git-Tag: v1.7.11-rc0~40^2 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/bef369219ae90097d187a8a12a82ab75f7f16638?ds=inline;hp=-c Merge branch 'rs/maint-dir-strbuf' into rs/dir-strbuf By René Scharfe * rs/maint-dir-strbuf: dir: convert to strbuf --- bef369219ae90097d187a8a12a82ab75f7f16638 diff --combined dir.c index e98760c72d,6d0ea9e70b..c6a98cc8dd --- a/dir.c +++ b/dir.c @@@ -34,54 -34,49 +34,54 @@@ int fnmatch_icase(const char *pattern, return fnmatch(pattern, string, flags | (ignore_case ? FNM_CASEFOLD : 0)); } -static int common_prefix(const char **pathspec) +static size_t common_prefix_len(const char **pathspec) { - const char *path, *slash, *next; - int prefix; + const char *n, *first; + size_t max = 0; if (!pathspec) - return 0; + return max; + + first = *pathspec; + while ((n = *pathspec++)) { + size_t i, len = 0; + for (i = 0; first == n || i < max; i++) { + char c = n[i]; + if (!c || c != first[i] || is_glob_special(c)) + break; + if (c == '/') + len = i + 1; + } + if (first == n || len < max) { + max = len; + if (!max) + break; + } + } + return max; +} - path = *pathspec; - slash = strrchr(path, '/'); - if (!slash) - return 0; +/* + * Returns a copy of the longest leading path common among all + * pathspecs. + */ +char *common_prefix(const char **pathspec) +{ + unsigned long len = common_prefix_len(pathspec); - /* - * The first 'prefix' characters of 'path' are common leading - * path components among the pathspecs we have seen so far, - * including the trailing slash. - */ - prefix = slash - path + 1; - while ((next = *++pathspec) != NULL) { - int len, last_matching_slash = -1; - for (len = 0; len < prefix && next[len] == path[len]; len++) - if (next[len] == '/') - last_matching_slash = len; - if (len == prefix) - continue; - if (last_matching_slash < 0) - return 0; - prefix = last_matching_slash + 1; - } - return prefix; + return len ? xmemdupz(*pathspec, len) : NULL; } int fill_directory(struct dir_struct *dir, const char **pathspec) { const char *path; - int len; + size_t len; /* * Calculate common prefix for the pathspec, and * use that to optimize the directory walk */ - len = common_prefix(pathspec); + len = common_prefix_len(pathspec); path = ""; if (len) @@@ -89,8 -84,6 +89,8 @@@ /* Read the directory and prune it */ read_directory(dir, path, len, pathspec); + if (*path) + free((char *)path); return len; } @@@ -873,14 -866,14 +873,14 @@@ enum path_treatment }; static enum path_treatment treat_one_path(struct dir_struct *dir, - char *path, int *len, + struct strbuf *path, const struct path_simplify *simplify, int dtype, struct dirent *de) { - int exclude = excluded(dir, path, &dtype); + int exclude = excluded(dir, path->buf, &dtype); if (exclude && (dir->flags & DIR_COLLECT_IGNORED) - && exclude_matches_pathspec(path, *len, simplify)) - dir_add_ignored(dir, path, *len); + && exclude_matches_pathspec(path->buf, path->len, simplify)) + dir_add_ignored(dir, path->buf, path->len); /* * Excluded? If we don't explicitly want to show @@@ -890,7 -883,7 +890,7 @@@ return path_ignored; if (dtype == DT_UNKNOWN) - dtype = get_dtype(de, path, *len); + dtype = get_dtype(de, path->buf, path->len); /* * Do we want to see just the ignored files? @@@ -907,9 -900,8 +907,8 @@@ default: return path_ignored; case DT_DIR: - memcpy(path + *len, "/", 2); - (*len)++; - switch (treat_directory(dir, path, *len, simplify)) { + strbuf_addch(path, '/'); + switch (treat_directory(dir, path->buf, path->len, simplify)) { case show_directory: if (exclude != !!(dir->flags & DIR_SHOW_IGNORED)) @@@ -930,26 -922,21 +929,21 @@@ static enum path_treatment treat_path(struct dir_struct *dir, struct dirent *de, - char *path, int path_max, + struct strbuf *path, int baselen, - const struct path_simplify *simplify, - int *len) + const struct path_simplify *simplify) { int dtype; if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git")) return path_ignored; - *len = strlen(de->d_name); - /* Ignore overly long pathnames! */ - if (*len + baselen + 8 > path_max) - return path_ignored; - memcpy(path + baselen, de->d_name, *len + 1); - *len += baselen; - if (simplify_away(path, *len, simplify)) + strbuf_setlen(path, baselen); + strbuf_addstr(path, de->d_name); + if (simplify_away(path->buf, path->len, simplify)) return path_ignored; dtype = DTYPE(de); - return treat_one_path(dir, path, len, simplify, dtype, de); + return treat_one_path(dir, path, simplify, dtype, de); } /* @@@ -968,34 -955,34 +962,35 @@@ static int read_directory_recursive(str { DIR *fdir = opendir(*base ? base : "."); int contents = 0; + struct dirent *de; - char path[PATH_MAX + 1]; ++ struct strbuf path = STRBUF_INIT; - if (fdir) { - struct dirent *de; - struct strbuf path = STRBUF_INIT; - - strbuf_add(&path, base, baselen); - - while ((de = readdir(fdir)) != NULL) { - switch (treat_path(dir, de, &path, baselen, simplify)) { - case path_recurse: - contents += read_directory_recursive - (dir, path.buf, path.len, 0, simplify); - continue; - case path_ignored: - continue; - case path_handled: - break; - } - contents++; - if (check_only) - goto exit_early; - else - dir_add_name(dir, path.buf, path.len); + if (!fdir) + return 0; + - memcpy(path, base, baselen); ++ strbuf_add(&path, base, baselen); + + while ((de = readdir(fdir)) != NULL) { - int len; - switch (treat_path(dir, de, path, sizeof(path), - baselen, simplify, &len)) { ++ switch (treat_path(dir, de, &path, baselen, simplify)) { + case path_recurse: - contents += read_directory_recursive(dir, path, len, 0, simplify); ++ contents += read_directory_recursive(dir, path.buf, ++ path.len, 0, ++ simplify); + continue; + case path_ignored: + continue; + case path_handled: + break; } -exit_early: - closedir(fdir); - strbuf_release(&path); + contents++; + if (check_only) + goto exit_early; + else - dir_add_name(dir, path, len); ++ dir_add_name(dir, path.buf, path.len); } +exit_early: + closedir(fdir); ++ strbuf_release(&path); return contents; } @@@ -1058,8 -1045,8 +1053,8 @@@ static int treat_leading_path(struct di const char *path, int len, const struct path_simplify *simplify) { - char pathbuf[PATH_MAX]; - int baselen, blen; + struct strbuf sb = STRBUF_INIT; + int baselen, rc = 0; const char *cp; while (len && path[len - 1] == '/') @@@ -1074,19 -1061,22 +1069,22 @@@ baselen = len; else baselen = cp - path; - memcpy(pathbuf, path, baselen); - pathbuf[baselen] = '\0'; - if (!is_directory(pathbuf)) - return 0; - if (simplify_away(pathbuf, baselen, simplify)) - return 0; - blen = baselen; - if (treat_one_path(dir, pathbuf, &blen, simplify, + strbuf_setlen(&sb, 0); + strbuf_add(&sb, path, baselen); + if (!is_directory(sb.buf)) + break; + if (simplify_away(sb.buf, sb.len, simplify)) + break; + if (treat_one_path(dir, &sb, simplify, DT_DIR, NULL) == path_ignored) - return 0; /* do not recurse into it */ - if (len <= baselen) - return 1; /* finished checking */ + break; /* do not recurse into it */ + if (len <= baselen) { + rc = 1; + break; /* finished checking */ + } } + strbuf_release(&sb); + return rc; } int read_directory(struct dir_struct *dir, const char *path, int len, const char **pathspec) @@@ -1172,32 -1162,22 +1170,32 @@@ int is_empty_dir(const char *path return ret; } -int remove_dir_recursively(struct strbuf *path, int flag) +static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up) { DIR *dir; struct dirent *e; - int ret = 0, original_len = path->len, len; + int ret = 0, original_len = path->len, len, kept_down = 0; int only_empty = (flag & REMOVE_DIR_EMPTY_ONLY); + int keep_toplevel = (flag & REMOVE_DIR_KEEP_TOPLEVEL); unsigned char submodule_head[20]; if ((flag & REMOVE_DIR_KEEP_NESTED_GIT) && - !resolve_gitlink_ref(path->buf, "HEAD", submodule_head)) + !resolve_gitlink_ref(path->buf, "HEAD", submodule_head)) { /* Do not descend and nuke a nested git work tree. */ + if (kept_up) + *kept_up = 1; return 0; + } + flag &= ~REMOVE_DIR_KEEP_TOPLEVEL; dir = opendir(path->buf); - if (!dir) - return rmdir(path->buf); + if (!dir) { + /* an empty dir could be removed even if it is unreadble */ + if (!keep_toplevel) + return rmdir(path->buf); + else + return -1; + } if (path->buf[original_len - 1] != '/') strbuf_addch(path, '/'); @@@ -1212,7 -1192,7 +1210,7 @@@ if (lstat(path->buf, &st)) ; /* fall thru */ else if (S_ISDIR(st.st_mode)) { - if (!remove_dir_recursively(path, only_empty)) + if (!remove_dir_recurse(path, flag, &kept_down)) continue; /* happy */ } else if (!only_empty && !unlink(path->buf)) continue; /* happy, too */ @@@ -1224,22 -1204,11 +1222,22 @@@ closedir(dir); strbuf_setlen(path, original_len); - if (!ret) + if (!ret && !keep_toplevel && !kept_down) ret = rmdir(path->buf); + else if (kept_up) + /* + * report the uplevel that it is not an error that we + * did not rmdir() our directory. + */ + *kept_up = !ret; return ret; } +int remove_dir_recursively(struct strbuf *path, int flag) +{ + return remove_dir_recurse(path, flag, NULL); +} + void setup_standard_excludes(struct dir_struct *dir) { const char *path;