4 #include "dir-iterator.h"
 
   6 struct dir_iterator_level {
 
  10          * The length of the directory part of path at this level
 
  11          * (including a trailing '/'):
 
  17  * The full data structure used to manage the internal directory
 
  18  * iteration state. It includes members that are not part of the
 
  21 struct dir_iterator_int {
 
  22         struct dir_iterator base;
 
  25          * The number of levels currently on the stack. After the first
 
  26          * call to dir_iterator_begin(), if it succeeds to open the
 
  27          * first level's dir, this will always be at least 1. Then,
 
  28          * when it comes to zero the iteration is ended and this
 
  33         /* The number of levels that have been allocated on the stack */
 
  37          * A stack of levels. levels[0] is the uppermost directory
 
  38          * that will be included in this iteration.
 
  40         struct dir_iterator_level *levels;
 
  42         /* Combination of flags for this dir-iterator */
 
  47  * Push a level in the iter stack and initialize it with information from
 
  48  * the directory pointed by iter->base->path. It is assumed that this
 
  49  * strbuf points to a valid directory path. Return 0 on success and -1
 
  50  * otherwise, setting errno accordingly and leaving the stack unchanged.
 
  52 static int push_level(struct dir_iterator_int *iter)
 
  54         struct dir_iterator_level *level;
 
  56         ALLOC_GROW(iter->levels, iter->levels_nr + 1, iter->levels_alloc);
 
  57         level = &iter->levels[iter->levels_nr++];
 
  59         if (!is_dir_sep(iter->base.path.buf[iter->base.path.len - 1]))
 
  60                 strbuf_addch(&iter->base.path, '/');
 
  61         level->prefix_len = iter->base.path.len;
 
  63         level->dir = opendir(iter->base.path.buf);
 
  65                 int saved_errno = errno;
 
  66                 if (errno != ENOENT) {
 
  67                         warning_errno("error opening directory '%s'",
 
  79  * Pop the top level on the iter stack, releasing any resources associated
 
  80  * with it. Return the new value of iter->levels_nr.
 
  82 static int pop_level(struct dir_iterator_int *iter)
 
  84         struct dir_iterator_level *level =
 
  85                 &iter->levels[iter->levels_nr - 1];
 
  87         if (level->dir && closedir(level->dir))
 
  88                 warning_errno("error closing directory '%s'",
 
  92         return --iter->levels_nr;
 
  96  * Populate iter->base with the necessary information on the next iteration
 
  97  * entry, represented by the given dirent de. Return 0 on success and -1
 
  98  * otherwise, setting errno accordingly.
 
 100 static int prepare_next_entry_data(struct dir_iterator_int *iter,
 
 103         int err, saved_errno;
 
 105         strbuf_addstr(&iter->base.path, de->d_name);
 
 107          * We have to reset these because the path strbuf might have
 
 108          * been realloc()ed at the previous strbuf_addstr().
 
 110         iter->base.relative_path = iter->base.path.buf +
 
 111                                    iter->levels[0].prefix_len;
 
 112         iter->base.basename = iter->base.path.buf +
 
 113                               iter->levels[iter->levels_nr - 1].prefix_len;
 
 115         if (iter->flags & DIR_ITERATOR_FOLLOW_SYMLINKS)
 
 116                 err = stat(iter->base.path.buf, &iter->base.st);
 
 118                 err = lstat(iter->base.path.buf, &iter->base.st);
 
 121         if (err && errno != ENOENT)
 
 122                 warning_errno("failed to stat '%s'", iter->base.path.buf);
 
 128 int dir_iterator_advance(struct dir_iterator *dir_iterator)
 
 130         struct dir_iterator_int *iter =
 
 131                 (struct dir_iterator_int *)dir_iterator;
 
 133         if (S_ISDIR(iter->base.st.st_mode) && push_level(iter)) {
 
 134                 if (errno != ENOENT && iter->flags & DIR_ITERATOR_PEDANTIC)
 
 136                 if (iter->levels_nr == 0)
 
 140         /* Loop until we find an entry that we can give back to the caller. */
 
 143                 struct dir_iterator_level *level =
 
 144                         &iter->levels[iter->levels_nr - 1];
 
 146                 strbuf_setlen(&iter->base.path, level->prefix_len);
 
 148                 de = readdir(level->dir);
 
 152                                 warning_errno("error reading directory '%s'",
 
 153                                               iter->base.path.buf);
 
 154                                 if (iter->flags & DIR_ITERATOR_PEDANTIC)
 
 156                         } else if (pop_level(iter) == 0) {
 
 157                                 return dir_iterator_abort(dir_iterator);
 
 162                 if (is_dot_or_dotdot(de->d_name))
 
 165                 if (prepare_next_entry_data(iter, de)) {
 
 166                         if (errno != ENOENT && iter->flags & DIR_ITERATOR_PEDANTIC)
 
 175         dir_iterator_abort(dir_iterator);
 
 179 int dir_iterator_abort(struct dir_iterator *dir_iterator)
 
 181         struct dir_iterator_int *iter = (struct dir_iterator_int *)dir_iterator;
 
 183         for (; iter->levels_nr; iter->levels_nr--) {
 
 184                 struct dir_iterator_level *level =
 
 185                         &iter->levels[iter->levels_nr - 1];
 
 187                 if (level->dir && closedir(level->dir)) {
 
 188                         int saved_errno = errno;
 
 189                         strbuf_setlen(&iter->base.path, level->prefix_len);
 
 191                         warning_errno("error closing directory '%s'",
 
 192                                       iter->base.path.buf);
 
 197         strbuf_release(&iter->base.path);
 
 202 struct dir_iterator *dir_iterator_begin(const char *path, unsigned int flags)
 
 204         struct dir_iterator_int *iter = xcalloc(1, sizeof(*iter));
 
 205         struct dir_iterator *dir_iterator = &iter->base;
 
 208         strbuf_init(&iter->base.path, PATH_MAX);
 
 209         strbuf_addstr(&iter->base.path, path);
 
 211         ALLOC_GROW(iter->levels, 10, iter->levels_alloc);
 
 216          * Note: stat already checks for NULL or empty strings and
 
 219         if (stat(iter->base.path.buf, &iter->base.st) < 0) {
 
 224         if (!S_ISDIR(iter->base.st.st_mode)) {
 
 225                 saved_errno = ENOTDIR;
 
 232         dir_iterator_abort(dir_iterator);