4 * Copyright © 2005-2020 Rich Felker, et al.
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 /* Pull in _STDIO_WITH_THREAD_CANCELLATION_SUPPORT */
35 #include "../stdio/local.h"
39 struct history
*chain
;
47 #define dirfd(d) (*(int *)d)
49 static int do_nftw(char *path
, int (*fn
)(const char *, const struct stat
*, int, struct FTW
*), int fd_limit
, int flags
, struct history
*h
)
51 size_t l
= strlen(path
), j
= l
&& path
[l
-1]=='/' ? l
-1 : l
;
58 if ((flags
& FTW_PHYS
) ? lstat(path
, &st
) : stat(path
, &st
) < 0) {
59 if (!(flags
& FTW_PHYS
) && errno
==ENOENT
&& !lstat(path
, &st
))
61 else if (errno
!= EACCES
) return -1;
63 } else if (S_ISDIR(st
.st_mode
)) {
64 if (access(path
, R_OK
) < 0) type
= FTW_DNR
;
65 else if (flags
& FTW_DEPTH
) type
= FTW_DP
;
67 } else if (S_ISLNK(st
.st_mode
)) {
68 if (flags
& FTW_PHYS
) type
= FTW_SL
;
74 if ((flags
& FTW_MOUNT
) && h
&& st
.st_dev
!= h
->dev
)
80 new.level
= h
? h
->level
+1 : 0;
83 lev
.level
= new.level
;
88 for (k
=j
; k
&& path
[k
]=='/'; k
--);
89 for (; k
&& path
[k
-1]!='/'; k
--);
93 if (!(flags
& FTW_DEPTH
) && (r
=fn(path
, &st
, type
, &lev
)))
96 for (; h
; h
= h
->chain
)
97 if (h
->dev
== st
.st_dev
&& h
->ino
== st
.st_ino
)
100 if ((type
== FTW_D
|| type
== FTW_DP
) && fd_limit
) {
101 DIR *d
= opendir(path
);
104 while ((de
= readdir(d
))) {
105 if (de
->d_name
[0] == '.'
107 || (de
->d_name
[1]=='.'
108 && !de
->d_name
[2]))) continue;
109 if (strlen(de
->d_name
) >= PATH_MAX
-l
) {
110 errno
= ENAMETOOLONG
;
115 strcpy(path
+j
+1, de
->d_name
);
116 if ((r
=do_nftw(path
, fn
, fd_limit
-1, flags
, &new))) {
122 } else if (errno
!= EACCES
) {
128 if ((flags
& FTW_DEPTH
) && (r
=fn(path
, &st
, type
, &lev
)))
134 int nftw(const char *path
, int (*fn
)(const char *, const struct stat
*, int, struct FTW
*), int fd_limit
, int flags
)
138 char pathbuf
[PATH_MAX
+1];
140 if (fd_limit
<= 0) return 0;
144 errno
= ENAMETOOLONG
;
147 memcpy(pathbuf
, path
, l
+1);
149 #ifdef _STDIO_WITH_THREAD_CANCELLATION_SUPPORT
150 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE
, &cs
);
152 r
= do_nftw(pathbuf
, fn
, fd_limit
, flags
, NULL
);
153 #ifdef _STDIO_WITH_THREAD_CANCELLATION_SUPPORT
154 pthread_setcancelstate(cs
, 0);
159 #endif /* ! HAVE_OPENDIR */