Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
  2. /* ftw() for DJGPP.
  3.  *
  4.  * Recursively descent the directory hierarchy rooted in DIR,
  5.  * calling FUNC for each object in the hierarchy.
  6.  *
  7.  * Copyright (c) 1995 Eli Zaretskii <eliz@is.elta.co.il>
  8.  *
  9.  * This software may be used freely as long as this copyright notice is
  10.  * left intact.  There is no warranty on this software.
  11.  *
  12.  */
  13.  
  14. #include <libc/stubs.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <errno.h>
  18. #include <ctype.h>
  19. #include <sys/stat.h>
  20. #include <dirent.h>
  21. #include <io.h>
  22. #include <ftw.h>
  23.  
  24. static int
  25. walk_dir(char *path, int (*func)(const char *, struct stat *, int))
  26. {
  27.   DIR *dp;
  28.   struct dirent *de;
  29.   struct stat stbuf;
  30.   int flag;
  31.   int e = errno;
  32.   int pathlen = strlen(path);
  33.  
  34.   if ((dp = opendir(path)) == 0)
  35.     return -1;
  36.  
  37.   for (errno = 0; (de = readdir(dp)) != 0; errno = 0)
  38.     {
  39.       int func_result;
  40.       char lastc = de->d_name[de->d_namlen - 1];
  41.  
  42.       /* Skip `.' and `..' entries.  Checking the last char is enough,
  43.          because readdir will never return a filename which ends with
  44.          a dot.  */
  45.       if (lastc == '.')
  46.         continue;
  47.  
  48.       /* Append found name to directory path.  */
  49.       if (pathlen + de->d_namlen + 1 > FILENAME_MAX)
  50.         {
  51.           (void)closedir(dp);
  52.           errno = ENAMETOOLONG;
  53.           return -1;
  54.         }
  55.       if (path[pathlen-1] == '/' || path[pathlen-1] == '\\')
  56.         pathlen--;
  57.       path[pathlen] = '/';
  58.       strcpy(path + pathlen + 1, de->d_name);
  59.  
  60.       if (stat(path, &stbuf) < 0)
  61.         flag = FTW_NS;
  62.       else if (S_ISDIR(stbuf.st_mode))
  63.         flag = FTW_D;
  64.       else if (S_ISLABEL(stbuf.st_mode))
  65.         flag = FTW_VL;
  66.       else
  67.         flag = FTW_F;
  68.  
  69.       /* Invoke FUNC() on this object.  */
  70.       errno = e;
  71.       if ((func_result = (*func)(path, &stbuf, flag)) != 0)
  72.         {
  73.           (void)closedir(dp);
  74.           return func_result;
  75.         }
  76.  
  77.       /* If this is a directory, walk its siblings.  */
  78.       if (flag == FTW_D)
  79.         {
  80.           int subwalk_result;
  81.  
  82.           errno = e;
  83.           if ((subwalk_result = walk_dir(path, func)) != 0)
  84.             {
  85.               (void)closedir(dp);
  86.               return subwalk_result;
  87.             }
  88.         }
  89.  
  90.       /* Erase D_NAME[] from PATH.  */
  91.       path[pathlen] = '\0';
  92.     }
  93.  
  94.   (void)closedir(dp);
  95.   if (errno == 0)   /* normal case: this subtree exhausted */
  96.     {
  97.       errno = e;/* restore errno from previous syscall */
  98.       return 0;
  99.     }
  100.   else
  101.     return -1;      /* with whatever errno was set by readdir() */
  102. }
  103.  
  104. int
  105. ftw(const char *dir, int (*func)(const char *, struct stat *, int),
  106.     int ignored)
  107. {
  108.   int flag;
  109.   unsigned char pathbuf[FILENAME_MAX];
  110.   int dirattr;
  111.   int len;
  112.   int e = errno;
  113.  
  114.   ignored = ignored;        /* pacify -Wall */
  115.  
  116.   if (dir == 0 || func == 0)
  117.     {
  118.       errno = EFAULT;
  119.       return -1;
  120.     }
  121.  
  122.   if (*dir == '\0')
  123.     {
  124.       errno = ENOENT;
  125.       return -1;
  126.     }
  127.  
  128.   strcpy(pathbuf, dir);
  129.   len = strlen(pathbuf);
  130.   if (pathbuf[len-1] == ':')
  131.     {
  132.       pathbuf[len++] = '.';
  133.       pathbuf[len] = '\0';
  134.     }
  135.  
  136.   /* Fail for non-directories.  */
  137.   errno = 0;
  138.   dirattr = _chmod(pathbuf, 0, 0);
  139.   if (errno == ENOENT)
  140.     return -1;
  141.   else if ((dirattr & 0x10) != 0x10)
  142.     {
  143.       errno = ENOTDIR;
  144.       return -1;
  145.     }
  146.   else
  147.     {
  148.       int func_result;
  149.       struct stat stbuf;
  150.  
  151.       if (stat(pathbuf, &stbuf) < 0)
  152.         flag = FTW_NS;
  153.       else
  154.         flag = FTW_D;
  155.       errno = e;
  156.       if ((func_result = (*func)(pathbuf, &stbuf, flag)) != 0)
  157.         return func_result;
  158.      
  159.       return walk_dir(pathbuf, func);
  160.     }
  161. }
  162.  
  163. #ifdef  TEST
  164.  
  165. #include <stdlib.h>
  166.  
  167. int
  168. ftw_walker(const char *path, struct stat *sb, int flag)
  169. {
  170.   char *base;
  171.  
  172.   printf("%s:\t%u\t", path, sb->st_size);
  173.   if (S_ISLABEL(sb->st_mode))
  174.     printf("V");
  175.   if (S_ISDIR(sb->st_mode))
  176.     printf("D");
  177.   if (S_ISCHR(sb->st_mode))
  178.     printf("C");
  179.   if (sb->st_mode & S_IRUSR)
  180.     printf("r");
  181.   if (sb->st_mode & S_IWUSR)
  182.     printf("w");
  183.   if (sb->st_mode & S_IXUSR)
  184.     printf("x");
  185.  
  186.   if (flag == FTW_NS)
  187.     printf("  !!no_stat!!");
  188.   printf("\n");
  189.  
  190.   base = strrchr(path, '/');
  191.   if (base == 0)
  192.     base = strrchr(path, '\\');
  193.   if (base == 0)
  194.     base = strrchr(path, ':');
  195.   if (strcmp(base == 0 ? path : base + 1, "xxxxx") == 0)
  196.     return 8;
  197.   return 0;
  198. }
  199.  
  200. int
  201. main(int argc, char *argv[])
  202. {
  203.   if (argc > 1)
  204.     {
  205.       char msg[80];
  206.  
  207.       sprintf(msg, "file_tree_walk: %d",
  208.                    ftw(argv[1], ftw_walker, 0));
  209.       if (errno)
  210.         perror(msg);
  211.       else
  212.         puts(msg);
  213.     }
  214.   else
  215.     printf("Usage: %s dir\n", argv[0]);
  216.  
  217.   return 0;
  218. }
  219.  
  220. #endif
  221.