Home | History | Annotate | Download | only in utils
      1 /* Copyright (C) 2007-2008 The Android Open Source Project
      2 **
      3 ** This software is licensed under the terms of the GNU General Public
      4 ** License version 2, as published by the Free Software Foundation, and
      5 ** may be copied, distributed, and modified under those terms.
      6 **
      7 ** This program is distributed in the hope that it will be useful,
      8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10 ** GNU General Public License for more details.
     11 */
     12 #include "android/utils/dirscanner.h"
     13 #include "android/utils/bufprint.h"
     14 #include "android/utils/system.h"
     15 #include "android/utils/path.h"
     16 #include <stddef.h>
     17 
     18 #define  DIRSCANNER_BASE     \
     19     char  root[PATH_MAX];    \
     20     int   rootLen;           \
     21     char  full[PATH_MAX];    \
     22 
     23 
     24 #if _WIN32
     25 
     26 #include <io.h>
     27 
     28 struct DirScanner {
     29     DIRSCANNER_BASE
     30     intptr_t            findIndex1;
     31     struct _finddata_t  findData;
     32 };
     33 
     34 /* note: findIndex1 contains the find index + 1
     35  *       so a value of 0 means 'invalid'
     36  */
     37 
     38 static int
     39 _dirScannerInit( DirScanner*  s )
     40 {
     41     char*  p   = s->root + s->rootLen;
     42     char*  end = s->root + sizeof s->root;
     43     int    ret;
     44 
     45     /* create file spec by appending \* to root */
     46     p = bufprint(p, end, "\\*");
     47     if (p >= end)
     48         return -1;
     49 
     50     ret = _findfirst(s->root, &s->findData);
     51 
     52     s->findIndex1 = ret+1;
     53     return ret;
     54 }
     55 
     56 static void
     57 _dirScanner_done( DirScanner*  s )
     58 {
     59     if (s->findIndex1 > 0) {
     60         _findclose(s->findIndex1-1);
     61         s->findIndex1 = 0;
     62     }
     63 }
     64 
     65 const char*
     66 dirScanner_next( DirScanner*  s )
     67 {
     68     char*  ret = NULL;
     69 
     70     if (!s || s->findIndex1 <= 0)
     71         return NULL;
     72 
     73     while (ret == NULL) {
     74         ret = s->findData.name;
     75 
     76         /* ignore special directories */
     77         if (!strcmp(ret, ".") || !strcmp(ret, "..")) {
     78             ret = NULL;
     79         }
     80         /* find next one */
     81         if (_findnext(s->findIndex1-1, &s->findData) < 0) {
     82             _dirScanner_done(s);
     83             break;
     84         }
     85     }
     86     return ret;
     87 }
     88 
     89 #else /* !_WIN32 */
     90 
     91 #include <dirent.h>
     92 struct DirScanner {
     93     DIRSCANNER_BASE
     94     DIR*            dir;
     95     struct dirent*  entry;
     96 };
     97 
     98 static int
     99 _dirScannerInit( DirScanner*  s )
    100 {
    101     s->dir = opendir(s->root);
    102 
    103     if (s->dir == NULL)
    104         return -1;
    105 
    106     s->entry = NULL;
    107     return 0;
    108 }
    109 
    110 static void
    111 _dirScanner_done( DirScanner*  s )
    112 {
    113     if (s->dir) {
    114         closedir(s->dir);
    115         s->dir = NULL;
    116     }
    117 }
    118 
    119 const char*
    120 dirScanner_next( DirScanner*  s )
    121 {
    122     char*  ret = NULL;
    123 
    124     if (!s || s->dir == NULL)
    125         return NULL;
    126 
    127     for (;;)
    128     {
    129         /* read new entry if needed */
    130         s->entry = readdir(s->dir);
    131         if (s->entry == NULL) {
    132             _dirScanner_done(s);
    133             break;
    134         }
    135 
    136         /* ignore special directories */
    137         ret = s->entry->d_name;
    138 
    139         if (!strcmp(ret,".") || !strcmp(ret,"..")) {
    140             ret = NULL;
    141             continue;
    142         }
    143         break;
    144     }
    145     return ret;
    146 }
    147 
    148 #endif /* !_WIN32 */
    149 
    150 DirScanner*
    151 dirScanner_new ( const char*  rootPath )
    152 {
    153     DirScanner*  s   = android_alloc0(sizeof *s);
    154     char*        p   = s->root;
    155     char*        end = p + sizeof s->root;
    156 
    157     p = bufprint(p, end, "%s", rootPath);
    158     if (p >= end)
    159         goto FAIL;
    160 
    161     s->rootLen = (p - s->root);
    162 
    163     if (_dirScannerInit(s) < 0)
    164         goto FAIL;
    165 
    166     return s;
    167 
    168 FAIL:
    169     dirScanner_free(s);
    170     return NULL;
    171 }
    172 
    173 
    174 void
    175 dirScanner_free( DirScanner*  s )
    176 {
    177     if (!s)
    178         return;
    179 
    180     _dirScanner_done(s);
    181     AFREE(s);
    182 }
    183 
    184 
    185 const char*
    186 dirScanner_nextFull( DirScanner*  s )
    187 {
    188     const char*  name = dirScanner_next(s);
    189     char*        p;
    190     char*        end;
    191 
    192     if (name == NULL)
    193         return NULL;
    194 
    195     p   = s->full;
    196     end = p + sizeof s->full;
    197 
    198     p = bufprint(p, end, "%.*s/%s", s->rootLen, s->root, name);
    199     if (p >= end) {
    200         /* ignore if the full name is too long */
    201         return dirScanner_nextFull(s);
    202     }
    203     return s->full;
    204 }
    205