URI: 
       dirread.c - 9base - revived minimalist port of Plan 9 userland to Unix
  HTML git clone git://git.suckless.org/9base
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       dirread.c (3712B)
       ---
            1 #include <u.h>
            2 #define NOPLAN9DEFINES
            3 #include <libc.h>
            4 #include <sys/stat.h>
            5 #include <dirent.h>
            6 
            7 #if defined (__linux__)
            8 # include <sys/syscall.h>
            9 # if defined (_LARGEFILE64_SOURCE)
           10 #  define getdents SYS_getdents64
           11 # else
           12 #  define getdents SYS_getdents
           13 # endif
           14 #endif
           15 
           16 extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
           17 
           18 #if defined(__linux__)
           19 static int
           20 mygetdents(int fd, struct dirent *buf, int n) {
           21   return syscall (getdents, fd, (void*) buf, n);
           22 }
           23 #elif defined(__APPLE__) || defined(__FreeBSD__)
           24 static int
           25 mygetdents(int fd, struct dirent *buf, int n)
           26 {
           27         long off;
           28         return getdirentries(fd, (void*)buf, n, &off);
           29 }
           30 #elif defined(__OpenBSD__)
           31 #include <sys/param.h>
           32 # if OpenBSD < 201405 /* for OpenBSD 5.4 and earlier */
           33 static int
           34 mygetdents(int fd, struct dirent *buf, int n)
           35 {
           36         off_t off;
           37         return getdirentries(fd, (void*)buf, n, &off);
           38 }
           39 # else
           40 static int
           41 mygetdents(int fd, struct dirent *buf, int n)
           42 {
           43         return getdents(fd, (void*)buf, n);
           44 }
           45 # endif
           46 #elif defined(__sun__) || defined(__NetBSD__)
           47 static int
           48 mygetdents(int fd, struct dirent *buf, int n)
           49 {
           50         return getdents(fd, (void*)buf, n);
           51 }
           52 #elif defined(__AIX__)
           53 static int
           54 mygetdents(int fd, struct dirent *buf, int n)
           55 {
           56         return getdirent(fd, (void*)buf, n);
           57 }
           58 #endif
           59 
           60 static int
           61 countde(char *p, int n)
           62 {
           63         char *e;
           64         int m;
           65         struct dirent *de;
           66 
           67         e = p+n;
           68         m = 0;
           69         while(p < e){
           70                 de = (struct dirent*)p;
           71                 if(de->d_reclen <= 4+2+2+1 || p+de->d_reclen > e)
           72                         break;
           73                 if(de->d_name[0]=='.' && de->d_name[1]==0)
           74                         de->d_name[0] = 0;
           75                 else if(de->d_name[0]=='.' && de->d_name[1]=='.' && de->d_name[2]==0)
           76                         de->d_name[0] = 0;
           77                 m++;
           78                 p += de->d_reclen;
           79         }
           80         return m;
           81 }
           82 
           83 static int
           84 dirpackage(int fd, char *buf, int n, Dir **dp)
           85 {
           86         int oldwd;
           87         char *p, *str, *estr;
           88         int i, nstr, m;
           89         struct dirent *de;
           90         struct stat st, lst;
           91         Dir *d;
           92 
           93         n = countde(buf, n);
           94         if(n <= 0)
           95                 return n;
           96 
           97         if((oldwd = open(".", O_RDONLY)) < 0)
           98                 return -1;
           99         if(fchdir(fd) < 0)
          100                 return -1;
          101                 
          102         p = buf;
          103         nstr = 0;
          104 
          105         for(i=0; i<n; i++){
          106                 de = (struct dirent*)p;
          107                 memset(&lst, 0, sizeof lst);
          108                 if(de->d_name[0] == 0)
          109                         /* nothing */ {}
          110                 else if(lstat(de->d_name, &lst) < 0)
          111                         de->d_name[0] = 0;
          112                 else{
          113                         st = lst;
          114                         if(S_ISLNK(lst.st_mode))
          115                                 stat(de->d_name, &st);
          116                         nstr += _p9dir(&lst, &st, de->d_name, nil, nil, nil);
          117                 }
          118                 p += de->d_reclen;
          119         }
          120 
          121         d = malloc(sizeof(Dir)*n+nstr);
          122         if(d == nil){
          123                 fchdir(oldwd);
          124                 close(oldwd);
          125                 return -1;
          126         }
          127         str = (char*)&d[n];
          128         estr = str+nstr;
          129 
          130         p = buf;
          131         m = 0;
          132         for(i=0; i<n; i++){
          133                 de = (struct dirent*)p;
          134                 if(de->d_name[0] != 0 && lstat(de->d_name, &lst) >= 0){
          135                         st = lst;
          136                         if((lst.st_mode&S_IFMT) == S_IFLNK)
          137                                 stat(de->d_name, &st);
          138                         _p9dir(&lst, &st, de->d_name, &d[m++], &str, estr);
          139                 }
          140                 p += de->d_reclen;
          141         }
          142 
          143         fchdir(oldwd);
          144         close(oldwd);
          145         *dp = d;
          146         return m;
          147 }
          148 
          149 long
          150 dirread(int fd, Dir **dp)
          151 {
          152         char *buf;
          153         struct stat st;
          154         int n;
          155 
          156         *dp = 0;
          157 
          158         if(fstat(fd, &st) < 0)
          159                 return -1;
          160 
          161         if(st.st_blksize < 8192)
          162                 st.st_blksize = 8192;
          163 
          164         buf = malloc(st.st_blksize);
          165         if(buf == nil)
          166                 return -1;
          167 
          168         n = mygetdents(fd, (void*)buf, st.st_blksize);
          169         if(n < 0){
          170                 free(buf);
          171                 return -1;
          172         }
          173         n = dirpackage(fd, buf, n, dp);
          174         free(buf);
          175         return n;
          176 }
          177 
          178 
          179 long
          180 dirreadall(int fd, Dir **d)
          181 {
          182         uchar *buf, *nbuf;
          183         long n, ts;
          184         struct stat st;
          185 
          186         if(fstat(fd, &st) < 0)
          187                 return -1;
          188 
          189         if(st.st_blksize < 8192)
          190                 st.st_blksize = 8192;
          191 
          192         buf = nil;
          193         ts = 0;
          194         for(;;){
          195                 nbuf = realloc(buf, ts+st.st_blksize);
          196                 if(nbuf == nil){
          197                         free(buf);
          198                         return -1;
          199                 }
          200                 buf = nbuf;
          201                 n = mygetdents(fd, (void*)(buf+ts), st.st_blksize);
          202                 if(n <= 0)
          203                         break;
          204                 ts += n;
          205         }
          206         if(ts >= 0)
          207                 ts = dirpackage(fd, (char*)buf, ts, d);
          208         free(buf);
          209         if(ts == 0 && n < 0)
          210                 return -1;
          211         return ts;
          212 }