struct dir_entry *ent;
ent = xmalloc(sizeof(*ent) + len + 1);
- ent->ignored = ent->ignored_dir = 0;
ent->len = len;
memcpy(ent->name, pathname, len);
ent->name[len] = 0;
if (cache_name_pos(pathname, len) >= 0)
return NULL;
- ALLOC_GROW(dir->entries, dir->nr, dir->alloc);
+ 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)
+{
+ if (cache_name_pos(pathname, len) >= 0)
+ return NULL;
+
+ ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->ignored_alloc);
+ return dir->ignored[dir->ignored_nr++] = dir_entry_new(pathname, len);
+}
+
enum exist_status {
index_nonexistent = 0,
index_directory,
return 0;
}
+static int in_pathspec(const char *path, int len, const struct path_simplify *simplify)
+{
+ if (simplify) {
+ for (; simplify->path; simplify++) {
+ if (len == simplify->len
+ && !memcmp(path, simplify->path, len))
+ return 1;
+ }
+ }
+ return 0;
+}
+
/*
* Read a directory tree. We currently ignore anything but
* directories, regular files and symlinks. That's because git
continue;
exclude = excluded(dir, fullname);
+ if (exclude && dir->collect_ignored
+ && in_pathspec(fullname, baselen + len, simplify))
+ dir_add_ignored(dir, fullname, baselen + len);
if (exclude != dir->show_ignored) {
if (!dir->show_ignored || DTYPE(de) != DT_DIR) {
continue;
read_directory_recursive(dir, path, base, baselen, 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);
return dir->nr;
}
struct stat sb;
return stat(f, &sb) == 0;
}
+
+/*
+ * get_relative_cwd() gets the prefix of the current working directory
+ * relative to 'dir'. If we are not inside 'dir', it returns NULL.
+ *
+ * As a convenience, it also returns NULL if 'dir' is already NULL. The
+ * reason for this behaviour is that it is natural for functions returning
+ * directory names to return NULL to say "this directory does not exist"
+ * or "this directory is invalid". These cases are usually handled the
+ * same as if the cwd is not inside 'dir' at all, so get_relative_cwd()
+ * returns NULL for both of them.
+ *
+ * Most notably, get_relative_cwd(buffer, size, get_git_work_tree())
+ * unifies the handling of "outside work tree" with "no work tree at all".
+ */
+char *get_relative_cwd(char *buffer, int size, const char *dir)
+{
+ char *cwd = buffer;
+
+ if (!dir)
+ return NULL;
+ if (!getcwd(buffer, size))
+ die("can't find the current directory: %s", strerror(errno));
+
+ if (!is_absolute_path(dir))
+ dir = make_absolute_path(dir);
+
+ while (*dir && *dir == *cwd) {
+ dir++;
+ cwd++;
+ }
+ if (*dir)
+ return NULL;
+ if (*cwd == '/')
+ return cwd + 1;
+ return cwd;
+}
+
+int is_inside_dir(const char *dir)
+{
+ char buffer[PATH_MAX];
+ return get_relative_cwd(buffer, sizeof(buffer), dir) != NULL;
+}
+
+int remove_dir_recursively(struct strbuf *path, int only_empty)
+{
+ DIR *dir = opendir(path->buf);
+ struct dirent *e;
+ int ret = 0, original_len = path->len, len;
+
+ if (!dir)
+ return -1;
+ if (path->buf[original_len - 1] != '/')
+ strbuf_addch(path, '/');
+
+ len = path->len;
+ while ((e = readdir(dir)) != NULL) {
+ struct stat st;
+ if ((e->d_name[0] == '.') &&
+ ((e->d_name[1] == 0) ||
+ ((e->d_name[1] == '.') && e->d_name[2] == 0)))
+ continue; /* "." and ".." */
+
+ strbuf_setlen(path, len);
+ strbuf_addstr(path, e->d_name);
+ if (lstat(path->buf, &st))
+ ; /* fall thru */
+ else if (S_ISDIR(st.st_mode)) {
+ if (!remove_dir_recursively(path, only_empty))
+ continue; /* happy */
+ } else if (!only_empty && !unlink(path->buf))
+ continue; /* happy, too */
+
+ /* path too long, stat fails, or non-directory still exists */
+ ret = -1;
+ break;
+ }
+ closedir(dir);
+
+ strbuf_setlen(path, original_len);
+ if (!ret)
+ ret = rmdir(path->buf);
+ return ret;
+}