17
const char *path;
18
};
19
20
-static int read_directory_recursive(struct dir_struct *dir, const char *path, int len,
20
+/*
21
+ * Tells read_directory_recursive how a file or directory should be treated.
22
+ * Values are ordered by significance, e.g. if a directory contains both
23
+ * excluded and untracked files, it is listed as untracked because
24
+ * path_untracked > path_excluded.
25
+ */
26
+enum path_treatment {
27
+ path_none = 0,
28
+ path_recurse,
29
+ path_excluded,
30
+ path_untracked
31
+};
32
+
33
+static enum path_treatment read_directory_recursive(struct dir_struct *dir,
34
+ const char *path, int len,
35
int check_only, const struct path_simplify *simplify);
36
static int get_dtype(struct dirent *de, const char *path, int len);
37
1016
*
1017
* (a) if "show_other_directories" is true, we show it as
1018
* just a directory, unless "hide_empty_directories" is
1005
- * also true and the directory is empty, in which case
1006
- * we just ignore it entirely.
1007
- * if we are looking for ignored directories, look if it
1008
- * contains only ignored files to decide if it must be shown as
1009
- * ignored or not.
1019
+ * also true, in which case we need to check if it contains any
1020
+ * untracked and / or ignored files.
1021
* (b) if it looks like a git directory, and we don't have
1022
* 'no_gitlinks' set we treat it as a gitlink, and show it
1023
* as a directory.
1024
* (c) otherwise, we recurse into it.
1025
*/
1015
-enum directory_treatment {
1016
- show_directory,
1017
- ignore_directory,
1018
- recurse_into_directory
1019
-};
1020
-
1021
-static enum directory_treatment treat_directory(struct dir_struct *dir,
1026
+static enum path_treatment treat_directory(struct dir_struct *dir,
1027
const char *dirname, int len, int exclude,
1028
const struct path_simplify *simplify)
1029
{
1030
/* The "len-1" is to strip the final '/' */
1031
switch (directory_exists_in_index(dirname, len-1)) {
1032
case index_directory:
1028
- return recurse_into_directory;
1033
+ return path_recurse;
1034
1035
case index_gitdir:
1036
if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES)
1032
- return ignore_directory;
1033
- return show_directory;
1037
+ return path_none;
1038
+ return path_untracked;
1039
1040
case index_nonexistent:
1041
if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES)
1043
if (!(dir->flags & DIR_NO_GITLINKS)) {
1044
unsigned char sha1[20];
1045
if (resolve_gitlink_ref(dirname, "HEAD", sha1) == 0)
1041
- return show_directory;
1046
+ return path_untracked;
1047
}
1043
- return recurse_into_directory;
1048
+ return path_recurse;
1049
}
1050
1051
/* This is the "show_other_directories" case */
1052
1048
- /*
1049
- * We are looking for ignored files and our directory is not ignored,
1050
- * check if it contains untracked files (i.e. is listed as untracked)
1051
- */
1052
- if ((dir->flags & DIR_SHOW_IGNORED) && !exclude) {
1053
- int ignored;
1054
- dir->flags &= ~DIR_SHOW_IGNORED;
1055
- ignored = read_directory_recursive(dir, dirname, len, 1, simplify);
1056
- dir->flags |= DIR_SHOW_IGNORED;
1057
-
1058
- if (ignored)
1059
- return ignore_directory;
1060
- }
1061
-
1053
if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
1063
- return show_directory;
1064
- if (!read_directory_recursive(dir, dirname, len, 1, simplify))
1065
- return ignore_directory;
1066
- return show_directory;
1054
+ return exclude ? path_excluded : path_untracked;
1055
+
1056
+ return read_directory_recursive(dir, dirname, len, 1, simplify);
1057
}
1058
1059
/*
1168
return dtype;
1169
}
1170
1181
-enum path_treatment {
1182
- path_ignored,
1183
- path_handled,
1184
- path_recurse
1185
-};
1186
-
1171
static enum path_treatment treat_one_path(struct dir_struct *dir,
1172
struct strbuf *path,
1173
const struct path_simplify *simplify,
1180
/* Always exclude indexed files */
1181
if (dtype != DT_DIR &&
1182
cache_name_exists(path->buf, path->len, ignore_case))
1199
- return path_ignored;
1183
+ return path_none;
1184
1185
exclude = is_excluded(dir, path->buf, &dtype);
1186
if (exclude && (dir->flags & DIR_COLLECT_IGNORED)
1192
* ignored files, ignore it
1193
*/
1194
if (exclude && !(dir->flags & DIR_SHOW_IGNORED))
1211
- return path_ignored;
1195
+ return path_excluded;
1196
1197
switch (dtype) {
1198
default:
1215
- return path_ignored;
1199
+ return path_none;
1200
case DT_DIR:
1201
strbuf_addch(path, '/');
1218
- switch (treat_directory(dir, path->buf, path->len, exclude, simplify)) {
1219
- case show_directory:
1220
- break;
1221
- case recurse_into_directory:
1222
- return path_recurse;
1223
- case ignore_directory:
1224
- return path_ignored;
1225
- }
1226
- break;
1202
+ return treat_directory(dir, path->buf, path->len, exclude,
1203
+ simplify);
1204
case DT_REG:
1205
case DT_LNK:
1229
- if (exclude == !(dir->flags & DIR_SHOW_IGNORED))
1230
- return path_ignored;
1231
- break;
1206
+ return exclude ? path_excluded : path_untracked;
1207
}
1233
- return path_handled;
1208
}
1209
1210
static enum path_treatment treat_path(struct dir_struct *dir,
1216
int dtype;
1217
1218
if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git"))
1245
- return path_ignored;
1219
+ return path_none;
1220
strbuf_setlen(path, baselen);
1221
strbuf_addstr(path, de->d_name);
1222
if (simplify_away(path->buf, path->len, simplify))
1249
- return path_ignored;
1223
+ return path_none;
1224
1225
dtype = DTYPE(de);
1226
return treat_one_path(dir, path, simplify, dtype, de);
1234
*
1235
* Also, we ignore the name ".git" (even if it is not a directory).
1236
* That likely will not change.
1237
+ *
1238
+ * Returns the most significant path_treatment value encountered in the scan.
1239
*/
1264
-static int read_directory_recursive(struct dir_struct *dir,
1240
+static enum path_treatment read_directory_recursive(struct dir_struct *dir,
1241
const char *base, int baselen,
1242
int check_only,
1243
const struct path_simplify *simplify)
1244
{
1245
DIR *fdir;
1270
- int contents = 0;
1246
+ enum path_treatment state, subdir_state, dir_state = path_none;
1247
struct dirent *de;
1248
struct strbuf path = STRBUF_INIT;
1249
1254
goto out;
1255
1256
while ((de = readdir(fdir)) != NULL) {
1281
- switch (treat_path(dir, de, &path, baselen, simplify)) {
1282
- case path_recurse:
1283
- contents += read_directory_recursive(dir, path.buf,
1257
+ /* check how the file or directory should be treated */
1258
+ state = treat_path(dir, de, &path, baselen, simplify);
1259
+ if (state > dir_state)
1260
+ dir_state = state;
1261
+
1262
+ /* recurse into subdir if instructed by treat_path */
1263
+ if (state == path_recurse) {
1264
+ subdir_state = read_directory_recursive(dir, path.buf,
1265
path.len, check_only, simplify);
1266
+ if (subdir_state > dir_state)
1267
+ dir_state = subdir_state;
1268
+ }
1269
+
1270
+ if (check_only) {
1271
+ /* abort early if maximum state has been reached */
1272
+ if (dir_state == path_untracked)
1273
+ break;
1274
+ /* skip the dir_add_* part */
1275
continue;
1286
- case path_ignored:
1287
- continue;
1288
- case path_handled:
1289
- break;
1276
}
1291
- contents++;
1292
- if (check_only)
1277
+
1278
+ /* add the path to the appropriate result list */
1279
+ switch (state) {
1280
+ case path_excluded:
1281
+ if (dir->flags & DIR_SHOW_IGNORED)
1282
+ dir_add_name(dir, path.buf, path.len);
1283
+ break;
1284
+
1285
+ case path_untracked:
1286
+ if (!(dir->flags & DIR_SHOW_IGNORED))
1287
+ dir_add_name(dir, path.buf, path.len);
1288
break;
1294
- dir_add_name(dir, path.buf, path.len);
1289
+
1290
+ default:
1291
+ break;
1292
+ }
1293
}
1294
closedir(fdir);
1295
out:
1296
strbuf_release(&path);
1297
1300
- return contents;
1298
+ return dir_state;
1299
}
1300
1301
static int cmp_name(const void *p1, const void *p2)
1366
if (simplify_away(sb.buf, sb.len, simplify))
1367
break;
1368
if (treat_one_path(dir, &sb, simplify,
1371
- DT_DIR, NULL) == path_ignored)
1369
+ DT_DIR, NULL) == path_none)
1370
break; /* do not recurse into it */
1371
if (len <= baselen) {
1372
rc = 1;