static enum path_treatment treat_one_path(struct dir_struct *dir, char *path, int *len, const struct path_simplify *simplify, int dtype, struct dirent *de) { int exclude = excluded(dir, path, &dtype); if (exclude && (dir->flags & DIR_COLLECT_IGNORED) && exclude_matches_pathspec(path, *len, simplify)) dir_add_ignored(dir, path, *len); /* * Excluded? If we don't explicitly want to show * ignored files, ignore it */ if (exclude && !(dir->flags & DIR_SHOW_IGNORED)) return path_ignored; if (dtype == DT_UNKNOWN) dtype = get_dtype(de, path, *len); /* * Do we want to see just the ignored files? * We still need to recurse into directories, * even if we don't ignore them, since the * directory may contain files that we do.. */ if (!exclude && (dir->flags & DIR_SHOW_IGNORED)) { if (dtype != DT_DIR) return path_ignored; } switch (dtype) { default: return path_ignored; case DT_DIR: memcpy(path + *len, "/", 2); (*len)++; switch (treat_directory(dir, path, *len, simplify)) { case show_directory: if (exclude != !!(dir->flags & DIR_SHOW_IGNORED)) return path_ignored; break; case recurse_into_directory: return path_recurse; case ignore_directory: return path_ignored; } break; case DT_REG: case DT_LNK: break; } return path_handled; }
/* * Read a directory tree. We currently ignore anything but * directories, regular files and symlinks. That's because git * doesn't handle them at all yet. Maybe that will change some * day. * * Also, we ignore the name ".git" (even if it is not a directory). * That likely will not change. * * Returns the most significant path_treatment value encountered in the scan. */ static enum path_treatment read_directory_recursive(struct dir_struct *dir, const char *base, int baselen, int check_only, const struct path_simplify *simplify) { DIR *fdir; enum path_treatment state, subdir_state, dir_state = path_none; struct dirent *de; struct strbuf path = STRBUF_INIT; strbuf_add(&path, base, baselen); fdir = opendir(path.len ? path.buf : "."); if (!fdir) goto out; while ((de = readdir(fdir)) != NULL) { /* check how the file or directory should be treated */ state = treat_path(dir, de, &path, baselen, simplify); if (state > dir_state) dir_state = state; /* recurse into subdir if instructed by treat_path */ if (state == path_recurse) { subdir_state = read_directory_recursive(dir, path.buf, path.len, check_only, simplify); if (subdir_state > dir_state) dir_state = subdir_state; } if (check_only) { /* abort early if maximum state has been reached */ if (dir_state == path_untracked) break; /* skip the dir_add_* part */ continue; } /* add the path to the appropriate result list */ switch (state) { case path_excluded: if (dir->flags & DIR_SHOW_IGNORED) dir_add_name(dir, path.buf, path.len); else if ((dir->flags & DIR_SHOW_IGNORED_TOO) || ((dir->flags & DIR_COLLECT_IGNORED) && exclude_matches_pathspec(path.buf, path.len, simplify))) dir_add_ignored(dir, path.buf, path.len); break; case path_untracked: if (!(dir->flags & DIR_SHOW_IGNORED)) dir_add_name(dir, path.buf, path.len); break; default: break; } } closedir(fdir); out: strbuf_release(&path); return dir_state; }