Code

Merge branch 'jk/maint-rmdir-fix' into maint-1.6.6
authorJunio C Hamano <gitster@pobox.com>
Sun, 7 Mar 2010 22:53:50 +0000 (14:53 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sun, 7 Mar 2010 22:53:50 +0000 (14:53 -0800)
* jk/maint-rmdir-fix:
  rm: fix bug in recursive subdirectory removal

1  2 
dir.c

diff --combined dir.c
index d0999ba055367c31571b251fb34bb46ed6c7051d,fdc0a2ede1b679d31570edd6f6334b7f29800c06..5d0a3084dbe1e7a23f7863f6c206914fbbfc0bf6
--- 1/dir.c
--- 2/dir.c
+++ b/dir.c
@@@ -14,11 -14,12 +14,11 @@@ struct path_simplify 
        const char *path;
  };
  
 -static int read_directory_recursive(struct dir_struct *dir,
 -      const char *path, const char *base, int baselen,
 +static int read_directory_recursive(struct dir_struct *dir, const char *path, int len,
        int check_only, const struct path_simplify *simplify);
 -static int get_dtype(struct dirent *de, const char *path);
 +static int get_dtype(struct dirent *de, const char *path, int len);
  
 -int common_prefix(const char **pathspec)
 +static int common_prefix(const char **pathspec)
  {
        const char *path, *slash, *next;
        int prefix;
        return prefix;
  }
  
 +int fill_directory(struct dir_struct *dir, const char **pathspec)
 +{
 +      const char *path;
 +      int len;
 +
 +      /*
 +       * Calculate common prefix for the pathspec, and
 +       * use that to optimize the directory walk
 +       */
 +      len = common_prefix(pathspec);
 +      path = "";
 +
 +      if (len)
 +              path = xmemdupz(*pathspec, len);
 +
 +      /* Read the directory and prune it */
 +      read_directory(dir, path, len, pathspec);
 +      return len;
 +}
 +
  /*
   * Does 'match' match the given name?
   * A match is found if
@@@ -326,7 -307,7 +326,7 @@@ static int excluded_1(const char *pathn
  
                        if (x->flags & EXC_FLAG_MUSTBEDIR) {
                                if (*dtype == DT_UNKNOWN)
 -                                      *dtype = get_dtype(NULL, pathname);
 +                                      *dtype = get_dtype(NULL, pathname, pathlen);
                                if (*dtype != DT_DIR)
                                        continue;
                        }
@@@ -415,7 -396,7 +415,7 @@@ static struct dir_entry *dir_add_name(s
  
  static struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len)
  {
 -      if (cache_name_pos(pathname, len) >= 0)
 +      if (!cache_name_is_other(pathname, len))
                return NULL;
  
        ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->ignored_alloc);
@@@ -524,7 -505,7 +524,7 @@@ static enum directory_treatment treat_d
        /* This is the "show_other_directories" case */
        if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
                return show_directory;
 -      if (!read_directory_recursive(dir, dirname, dirname, len, 1, simplify))
 +      if (!read_directory_recursive(dir, dirname, len, 1, simplify))
                return ignore_directory;
        return show_directory;
  }
@@@ -566,52 -547,11 +566,52 @@@ static int in_pathspec(const char *path
        return 0;
  }
  
 -static int get_dtype(struct dirent *de, const char *path)
 +static int get_index_dtype(const char *path, int len)
 +{
 +      int pos;
 +      struct cache_entry *ce;
 +
 +      ce = cache_name_exists(path, len, 0);
 +      if (ce) {
 +              if (!ce_uptodate(ce))
 +                      return DT_UNKNOWN;
 +              if (S_ISGITLINK(ce->ce_mode))
 +                      return DT_DIR;
 +              /*
 +               * Nobody actually cares about the
 +               * difference between DT_LNK and DT_REG
 +               */
 +              return DT_REG;
 +      }
 +
 +      /* Try to look it up as a directory */
 +      pos = cache_name_pos(path, len);
 +      if (pos >= 0)
 +              return DT_UNKNOWN;
 +      pos = -pos-1;
 +      while (pos < active_nr) {
 +              ce = active_cache[pos++];
 +              if (strncmp(ce->name, path, len))
 +                      break;
 +              if (ce->name[len] > '/')
 +                      break;
 +              if (ce->name[len] < '/')
 +                      continue;
 +              if (!ce_uptodate(ce))
 +                      break;  /* continue? */
 +              return DT_DIR;
 +      }
 +      return DT_UNKNOWN;
 +}
 +
 +static int get_dtype(struct dirent *de, 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);
        if (dtype != DT_UNKNOWN)
                return dtype;
        if (lstat(path, &st))
   * Also, we ignore the name ".git" (even if it is not a directory).
   * That likely will not change.
   */
 -static int read_directory_recursive(struct dir_struct *dir, const char *path, const char *base, int baselen, int check_only, const struct path_simplify *simplify)
 +static int read_directory_recursive(struct dir_struct *dir, const char *base, int baselen, int check_only, const struct path_simplify *simplify)
  {
 -      DIR *fdir = opendir(path);
 +      DIR *fdir = opendir(*base ? base : ".");
        int contents = 0;
  
        if (fdir) {
                struct dirent *de;
 -              char fullname[PATH_MAX + 1];
 -              memcpy(fullname, base, baselen);
 +              char path[PATH_MAX + 1];
 +              memcpy(path, base, baselen);
  
                while ((de = readdir(fdir)) != NULL) {
                        int len, dtype;
                                continue;
                        len = strlen(de->d_name);
                        /* Ignore overly long pathnames! */
 -                      if (len + baselen + 8 > sizeof(fullname))
 +                      if (len + baselen + 8 > sizeof(path))
                                continue;
 -                      memcpy(fullname + baselen, de->d_name, len+1);
 -                      if (simplify_away(fullname, baselen + len, simplify))
 +                      memcpy(path + baselen, de->d_name, len+1);
 +                      len = baselen + len;
 +                      if (simplify_away(path, len, simplify))
                                continue;
  
                        dtype = DTYPE(de);
 -                      exclude = excluded(dir, fullname, &dtype);
 +                      exclude = excluded(dir, path, &dtype);
                        if (exclude && (dir->flags & DIR_COLLECT_IGNORED)
 -                          && in_pathspec(fullname, baselen + len, simplify))
 -                              dir_add_ignored(dir, fullname, baselen + len);
 +                          && in_pathspec(path, len, simplify))
 +                              dir_add_ignored(dir, path,len);
  
                        /*
                         * Excluded? If we don't explicitly want to show
                                continue;
  
                        if (dtype == DT_UNKNOWN)
 -                              dtype = get_dtype(de, fullname);
 +                              dtype = get_dtype(de, path, len);
  
                        /*
                         * Do we want to see just the ignored files?
                        default:
                                continue;
                        case DT_DIR:
 -                              memcpy(fullname + baselen + len, "/", 2);
 +                              memcpy(path + len, "/", 2);
                                len++;
 -                              switch (treat_directory(dir, fullname, baselen + len, simplify)) {
 +                              switch (treat_directory(dir, path, len, simplify)) {
                                case show_directory:
                                        if (exclude != !!(dir->flags
                                                        & DIR_SHOW_IGNORED))
                                        break;
                                case recurse_into_directory:
                                        contents += read_directory_recursive(dir,
 -                                              fullname, fullname, baselen + len, 0, simplify);
 +                                              path, len, 0, simplify);
                                        continue;
                                case ignore_directory:
                                        continue;
                        if (check_only)
                                goto exit_early;
                        else
 -                              dir_add_name(dir, fullname, baselen + len);
 +                              dir_add_name(dir, path, len);
                }
  exit_early:
                closedir(fdir);
@@@ -778,15 -717,15 +778,15 @@@ static void free_simplify(struct path_s
        free(simplify);
  }
  
 -int read_directory(struct dir_struct *dir, const char *path, const char *base, int baselen, const char **pathspec)
 +int read_directory(struct dir_struct *dir, const char *path, int len, const char **pathspec)
  {
        struct path_simplify *simplify;
  
 -      if (has_symlink_leading_path(path, strlen(path)))
 +      if (has_symlink_leading_path(path, len))
                return dir->nr;
  
        simplify = create_simplify(pathspec);
 -      read_directory_recursive(dir, path, base, baselen, 0, simplify);
 +      read_directory_recursive(dir, path, len, 0, simplify);
        free_simplify(simplify);
        qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);
        qsort(dir->ignored, dir->ignored_nr, sizeof(struct dir_entry *), cmp_name);
@@@ -820,7 -759,7 +820,7 @@@ char *get_relative_cwd(char *buffer, in
        if (!dir)
                return NULL;
        if (!getcwd(buffer, size))
 -              die("can't find the current directory: %s", strerror(errno));
 +              die_errno("can't find the current directory");
  
        if (!is_absolute_path(dir))
                dir = make_absolute_path(dir);
@@@ -861,20 -800,12 +861,20 @@@ int is_empty_dir(const char *path
        return ret;
  }
  
 -int remove_dir_recursively(struct strbuf *path, int only_empty)
 +int remove_dir_recursively(struct strbuf *path, int flag)
  {
 -      DIR *dir = opendir(path->buf);
 +      DIR *dir;
        struct dirent *e;
        int ret = 0, original_len = path->len, len;
 +      int only_empty = (flag & REMOVE_DIR_EMPTY_ONLY);
 +      unsigned char submodule_head[20];
 +
 +      if ((flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
 +          !resolve_gitlink_ref(path->buf, "HEAD", submodule_head))
 +              /* Do not descend and nuke a nested git work tree. */
 +              return 0;
  
 +      dir = opendir(path->buf);
        if (!dir)
                return -1;
        if (path->buf[original_len - 1] != '/')
@@@ -933,7 -864,7 +933,7 @@@ int remove_path(const char *name
                slash = dirs + (slash - name);
                do {
                        *slash = '\0';
-               } while (rmdir(dirs) && (slash = strrchr(dirs, '/')));
+               } while (rmdir(dirs) == 0 && (slash = strrchr(dirs, '/')));
                free(dirs);
        }
        return 0;