]> git.sesse.net Git - plocate/commitdiff
Make updatedb understand DT_UNKNOWN.
authorSteinar H. Gunderson <steinar+nageru@gunderson.no>
Sun, 21 Mar 2021 14:48:55 +0000 (15:48 +0100)
committerSteinar H. Gunderson <steinar+nageru@gunderson.no>
Sun, 21 Mar 2021 14:48:55 +0000 (15:48 +0100)
Some filesystems don't know from getdents() whether an entry is a file
or a directory without a stat(). I had assumed this was only an issue
for obscure operating systems, so I removed it (mlocate's updatedb
supported it), but evidently older versions of XFS has this issue, too,
so add back checking.

Reported by Marcel Partap.

updatedb.cpp

index 895b0715b05afce634a8916f576ccdf833230654..8d524c6872038b4c72829de3d12cbb354f6fc760 100644 (file)
@@ -628,7 +628,23 @@ int scan(const string &path, int fd, dev_t parent_dev, dir_time modified, dir_ti
 
                        entry e;
                        e.name = de->d_name;
-                       e.is_directory = (de->d_type == DT_DIR);
+                       if (de->d_type == DT_UNKNOWN) {
+                               // Evidently some file systems, like older versions of XFS
+                               // (mkfs.xfs -m crc=0 -n ftype=0), can return this,
+                               // and we need a stat(). If we wanted to optimize for this,
+                               // we could probably defer it to later (we're stat-ing directories
+                               // when recursing), but this is rare, and not really worth it --
+                               // the second stat() will be cached anyway.
+                               struct stat buf;
+                               if (fstatat(fd, de->d_name, &buf, AT_SYMLINK_NOFOLLOW) == 0 &&
+                                   S_ISDIR(buf.st_mode)) {
+                                       e.is_directory = true;
+                               } else {
+                                       e.is_directory = false;
+                               }
+                       } else {
+                               e.is_directory = (de->d_type == DT_DIR);
+                       }
 
                        if (conf_verbose) {
                                printf("%s/%s\n", path.c_str(), de->d_name);