diff options
| author | Romain GARBAGE <romain.garbage@inria.fr> | 2025-09-12 16:57:59 +0200 |
|---|---|---|
| committer | Ludovic Courtès <ludo@gnu.org> | 2025-10-17 12:23:54 +0200 |
| commit | 4ce3a53ae5ee832aa92e0345f15780bc7da060d7 (patch) | |
| tree | 58c31f7bd40591dc75c3738d2564af3d4cea3b6e /gnu | |
| parent | 228d687fbe60aa61945f69733fefcfb56a592756 (diff) | |
pack: Address DT_UNKNOWN case for exotic filesystems.
In some filesystems, the d_type field in the dirent struct returned by
readdir(3) is not properly filled. According to readdir(3), "All applications
must properly handle a return of DT_UNKNOWN". This patch addresses the issue.
* gnu/packages/aux-files/run-in-namespace.c: Handle DT_UNKNOWN case.
Change-Id: I128b0b88add1e9990e4fbf316ee03c3d19d4e0fc
Signed-off-by: Ludovic Courtès <ludo@gnu.org>
Diffstat (limited to 'gnu')
| -rw-r--r-- | gnu/packages/aux-files/run-in-namespace.c | 22 |
1 files changed, 16 insertions, 6 deletions
diff --git a/gnu/packages/aux-files/run-in-namespace.c b/gnu/packages/aux-files/run-in-namespace.c index 074befde461..0ba017cec38 100644 --- a/gnu/packages/aux-files/run-in-namespace.c +++ b/gnu/packages/aux-files/run-in-namespace.c | |||
| @@ -160,24 +160,34 @@ mirror_directory (const char *source, const char *target, | |||
| 160 | int (* firmlink) (const char *, const struct dirent *, | 160 | int (* firmlink) (const char *, const struct dirent *, |
| 161 | const char *)) | 161 | const char *)) |
| 162 | { | 162 | { |
| 163 | DIR *stream = opendir (source); | 163 | int dir_fd = open (source, O_DIRECTORY | O_RDONLY | O_CLOEXEC); |
| 164 | DIR *stream = fdopendir (dir_fd); | ||
| 164 | 165 | ||
| 165 | for (struct dirent *entry = readdir (stream); | 166 | for (struct dirent *entry = readdir (stream); |
| 166 | entry != NULL; | 167 | entry != NULL; |
| 167 | entry = readdir (stream)) | 168 | entry = readdir (stream)) |
| 168 | { | 169 | { |
| 169 | /* XXX: Some file systems may not report a useful 'd_type'. Ignore them | ||
| 170 | for now. */ | ||
| 171 | assert (entry->d_type != DT_UNKNOWN); | ||
| 172 | |||
| 173 | if (strcmp (entry->d_name, ".") == 0 | 170 | if (strcmp (entry->d_name, ".") == 0 |
| 174 | || strcmp (entry->d_name, "..") == 0) | 171 | || strcmp (entry->d_name, "..") == 0) |
| 175 | continue; | 172 | continue; |
| 176 | 173 | ||
| 174 | int is_link = 0; | ||
| 175 | if (entry->d_type == DT_UNKNOWN) | ||
| 176 | { | ||
| 177 | struct stat statbuf; | ||
| 178 | if (fstatat (dir_fd, entry->d_name, &statbuf, | ||
| 179 | AT_SYMLINK_NOFOLLOW) < 0) | ||
| 180 | assert_perror (errno); | ||
| 181 | if ((statbuf.st_mode & S_IFMT) == S_IFLNK) | ||
| 182 | is_link = 1; | ||
| 183 | } | ||
| 184 | else if (entry->d_type == DT_LNK) | ||
| 185 | is_link = 1; | ||
| 186 | |||
| 177 | char *abs_source = concat (source, entry->d_name); | 187 | char *abs_source = concat (source, entry->d_name); |
| 178 | char *new_entry = concat (target, entry->d_name); | 188 | char *new_entry = concat (target, entry->d_name); |
| 179 | 189 | ||
| 180 | if (entry->d_type == DT_LNK) | 190 | if (is_link) |
| 181 | { | 191 | { |
| 182 | char target[PATH_MAX]; | 192 | char target[PATH_MAX]; |
| 183 | 193 | ||
