Commit a47330a24a002793ebfd33553aeb80a98f940755

Stefan Sperling 2022-01-27T22:32:09

fix 'got status' reporting all directories on NFS mounts as unversioned Problem found and fix tested by Ted Bullock. ok millert, naddy

diff --git a/lib/fileindex.c b/lib/fileindex.c
index 71a058b..6ea3dea 100644
--- a/lib/fileindex.c
+++ b/lib/fileindex.c
@@ -1022,28 +1022,15 @@ walk_dir(struct got_pathlist_entry **next, struct got_fileindex *fileindex,
 	struct dirent *de = dle->data;
 	DIR *subdir = NULL;
 	int subdirfd = -1;
-	int type;
 
 	*next = NULL;
 
-	if (de->d_type == DT_UNKNOWN) {
-		/* Occurs on NFS mounts without "readdir plus" RPC. */
-		char *dir_path;
-		if (asprintf(&dir_path, "%s/%s", rootpath, path) == -1)
-			return got_error_from_errno("asprintf");
-		err = got_path_dirent_type(&type, dir_path, de);
-		free(dir_path);
-		if (err)
-			return err;
-	} else
-		type = de->d_type;
-
 	/* Must traverse ignored directories if they contain tracked files. */
-	if (type == DT_DIR && ignore &&
+	if (de->d_type == DT_DIR && ignore &&
 	    have_tracked_file_in_dir(fileindex, path))
 		ignore = 0;
 
-	if (type == DT_DIR && !ignore) {
+	if (de->d_type == DT_DIR && !ignore) {
 		char *subpath;
 		char *subdirpath;
 		struct got_pathlist_head subdirlist;
@@ -1099,6 +1086,28 @@ walk_dir(struct got_pathlist_entry **next, struct got_fileindex *fileindex,
 }
 
 static const struct got_error *
+dirent_type_fixup(struct dirent *de, const char *rootpath, const char *path)
+{
+	const struct got_error *err;
+	char *dir_path;
+	int type;
+
+	if (de->d_type != DT_UNKNOWN)
+		return NULL;
+
+	/* DT_UNKNOWN occurs on NFS mounts without "readdir plus" RPC. */
+	if (asprintf(&dir_path, "%s/%s", rootpath, path) == -1)
+		return got_error_from_errno("asprintf");
+	err = got_path_dirent_type(&type, dir_path, de);
+	free(dir_path);
+	if (err)
+		return err;
+
+	de->d_type = type;
+	return NULL;
+}
+
+static const struct got_error *
 diff_fileindex_dir(struct got_fileindex *fileindex,
     struct got_fileindex_entry **ie, struct got_pathlist_head *dirlist,
     int dirfd, const char *rootpath, const char *path,
@@ -1123,6 +1132,9 @@ diff_fileindex_dir(struct got_fileindex *fileindex,
 			char *de_path;
 			int cmp;
 			de = dle->data;
+			err = dirent_type_fixup(de, rootpath, path);
+			if (err)
+				break;
 			if (asprintf(&de_path, "%s/%s", path,
 			    de->d_name) == -1) {
 				err = got_error_from_errno("asprintf");
@@ -1162,6 +1174,9 @@ diff_fileindex_dir(struct got_fileindex *fileindex,
 			*ie = walk_fileindex(fileindex, *ie);
 		} else if (dle) {
 			de = dle->data;
+			err = dirent_type_fixup(de, rootpath, path);
+			if (err)
+				break;
 			err = cb->diff_new(&ignore, cb_arg, de, path, dirfd);
 			if (err)
 				break;