nftw.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. #include <ftw.h>
  2. #include <dirent.h>
  3. #include <sys/stat.h>
  4. #include <errno.h>
  5. #include <unistd.h>
  6. #include <string.h>
  7. #include <limits.h>
  8. #include <pthread.h>
  9. #include "libc.h"
  10. struct history
  11. {
  12. struct history *chain;
  13. dev_t dev;
  14. ino_t ino;
  15. int level;
  16. int base;
  17. };
  18. #undef dirfd
  19. #define dirfd(d) (*(int *)d)
  20. static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, struct FTW *), int fd_limit, int flags, struct history *h)
  21. {
  22. size_t l = strlen(path), j = l && path[l-1]=='/' ? l-1 : l;
  23. struct stat st;
  24. struct history new;
  25. int type;
  26. int r;
  27. struct FTW lev;
  28. if ((flags & FTW_PHYS) ? lstat(path, &st) : stat(path, &st) < 0) {
  29. if (!(flags & FTW_PHYS) && errno==ENOENT && !lstat(path, &st))
  30. type = FTW_SLN;
  31. else if (errno != EACCES) return -1;
  32. else type = FTW_NS;
  33. } else if (S_ISDIR(st.st_mode)) {
  34. if (access(path, R_OK) < 0) type = FTW_DNR;
  35. else if (flags & FTW_DEPTH) type = FTW_DP;
  36. else type = FTW_D;
  37. } else if (S_ISLNK(st.st_mode)) {
  38. if (flags & FTW_PHYS) type = FTW_SL;
  39. else type = FTW_SLN;
  40. } else {
  41. type = FTW_F;
  42. }
  43. if ((flags & FTW_MOUNT) && h && st.st_dev != h->dev)
  44. return 0;
  45. new.chain = h;
  46. new.dev = st.st_dev;
  47. new.ino = st.st_ino;
  48. new.level = h ? h->level+1 : 0;
  49. new.base = j+1;
  50. lev.level = new.level;
  51. if (h) {
  52. lev.base = h->base;
  53. } else {
  54. size_t k;
  55. for (k=j; k && path[k]=='/'; k--);
  56. for (; k && path[k-1]!='/'; k--);
  57. lev.base = k;
  58. }
  59. if (!(flags & FTW_DEPTH) && (r=fn(path, &st, type, &lev)))
  60. return r;
  61. for (; h; h = h->chain)
  62. if (h->dev == st.st_dev && h->ino == st.st_ino)
  63. return 0;
  64. if ((type == FTW_D || type == FTW_DP) && fd_limit) {
  65. DIR *d = opendir(path);
  66. if (d) {
  67. struct dirent *de;
  68. while ((de = readdir(d))) {
  69. if (de->d_name[0] == '.'
  70. && (!de->d_name[1]
  71. || (de->d_name[1]=='.'
  72. && !de->d_name[2]))) continue;
  73. if (strlen(de->d_name) >= PATH_MAX-l) {
  74. errno = ENAMETOOLONG;
  75. closedir(d);
  76. return -1;
  77. }
  78. path[j]='/';
  79. strcpy(path+j+1, de->d_name);
  80. if ((r=do_nftw(path, fn, fd_limit-1, flags, &new))) {
  81. closedir(d);
  82. return r;
  83. }
  84. }
  85. closedir(d);
  86. } else if (errno != EACCES) {
  87. return -1;
  88. }
  89. }
  90. path[l] = 0;
  91. if ((flags & FTW_DEPTH) && (r=fn(path, &st, type, &lev)))
  92. return r;
  93. return 0;
  94. }
  95. int nftw(const char *path, int (*fn)(const char *, const struct stat *, int, struct FTW *), int fd_limit, int flags)
  96. {
  97. int r, cs;
  98. size_t l;
  99. char pathbuf[PATH_MAX+1];
  100. if (fd_limit <= 0) return 0;
  101. l = strlen(path);
  102. if (l > PATH_MAX) {
  103. errno = ENAMETOOLONG;
  104. return -1;
  105. }
  106. memcpy(pathbuf, path, l+1);
  107. pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
  108. r = do_nftw(pathbuf, fn, fd_limit, flags, NULL);
  109. pthread_setcancelstate(cs, 0);
  110. return r;
  111. }
  112. LFS64(nftw);