Michael Haggerty | 0fe5043 | 2016-06-18 06:15:18 +0200 | [diff] [blame] | 1 | #ifndef DIR_ITERATOR_H |
| 2 | #define DIR_ITERATOR_H |
| 3 | |
Elijah Newren | ef3ca95 | 2018-08-15 10:54:05 -0700 | [diff] [blame] | 4 | #include "strbuf.h" |
| 5 | |
Michael Haggerty | 0fe5043 | 2016-06-18 06:15:18 +0200 | [diff] [blame] | 6 | /* |
| 7 | * Iterate over a directory tree. |
| 8 | * |
| 9 | * Iterate over a directory tree, recursively, including paths of all |
| 10 | * types and hidden paths. Skip "." and ".." entries and don't follow |
Matheus Tavares | 3012397 | 2019-07-10 20:58:59 -0300 | [diff] [blame] | 11 | * symlinks except for the original path. Note that the original path |
| 12 | * is not included in the iteration. |
Michael Haggerty | 0fe5043 | 2016-06-18 06:15:18 +0200 | [diff] [blame] | 13 | * |
| 14 | * Every time dir_iterator_advance() is called, update the members of |
| 15 | * the dir_iterator structure to reflect the next path in the |
| 16 | * iteration. The order that paths are iterated over within a |
Matheus Tavares | 3012397 | 2019-07-10 20:58:59 -0300 | [diff] [blame] | 17 | * directory is undefined, directory paths are always given before |
| 18 | * their contents. |
Michael Haggerty | 0fe5043 | 2016-06-18 06:15:18 +0200 | [diff] [blame] | 19 | * |
| 20 | * A typical iteration looks like this: |
| 21 | * |
| 22 | * int ok; |
Matheus Tavares | fa1da7d | 2019-07-10 20:59:00 -0300 | [diff] [blame] | 23 | * unsigned int flags = DIR_ITERATOR_PEDANTIC; |
| 24 | * struct dir_iterator *iter = dir_iterator_begin(path, flags); |
Matheus Tavares | 3012397 | 2019-07-10 20:58:59 -0300 | [diff] [blame] | 25 | * |
| 26 | * if (!iter) |
| 27 | * goto error_handler; |
Michael Haggerty | 0fe5043 | 2016-06-18 06:15:18 +0200 | [diff] [blame] | 28 | * |
| 29 | * while ((ok = dir_iterator_advance(iter)) == ITER_OK) { |
| 30 | * if (want_to_stop_iteration()) { |
| 31 | * ok = dir_iterator_abort(iter); |
| 32 | * break; |
| 33 | * } |
| 34 | * |
| 35 | * // Access information about the current path: |
| 36 | * if (S_ISDIR(iter->st.st_mode)) |
| 37 | * printf("%s is a directory\n", iter->relative_path); |
| 38 | * } |
| 39 | * |
| 40 | * if (ok != ITER_DONE) |
| 41 | * handle_error(); |
| 42 | * |
| 43 | * Callers are allowed to modify iter->path while they are working, |
| 44 | * but they must restore it to its original contents before calling |
| 45 | * dir_iterator_advance() again. |
| 46 | */ |
| 47 | |
Matheus Tavares | fa1da7d | 2019-07-10 20:59:00 -0300 | [diff] [blame] | 48 | /* |
| 49 | * Flags for dir_iterator_begin: |
| 50 | * |
| 51 | * - DIR_ITERATOR_PEDANTIC: override dir-iterator's default behavior |
| 52 | * in case of an error at dir_iterator_advance(), which is to keep |
| 53 | * looking for a next valid entry. With this flag, resources are freed |
| 54 | * and ITER_ERROR is returned immediately. In both cases, a meaningful |
| 55 | * warning is emitted. Note: ENOENT errors are always ignored so that |
| 56 | * the API users may remove files during iteration. |
| 57 | * |
| 58 | * - DIR_ITERATOR_FOLLOW_SYMLINKS: make dir-iterator follow symlinks. |
| 59 | * i.e., linked directories' contents will be iterated over and |
| 60 | * iter->base.st will contain information on the referred files, |
| 61 | * not the symlinks themselves, which is the default behavior. Broken |
| 62 | * symlinks are ignored. |
| 63 | * |
| 64 | * Warning: circular symlinks are also followed when |
| 65 | * DIR_ITERATOR_FOLLOW_SYMLINKS is set. The iteration may end up with |
| 66 | * an ELOOP if they happen and DIR_ITERATOR_PEDANTIC is set. |
| 67 | */ |
| 68 | #define DIR_ITERATOR_PEDANTIC (1 << 0) |
| 69 | #define DIR_ITERATOR_FOLLOW_SYMLINKS (1 << 1) |
| 70 | |
Michael Haggerty | 0fe5043 | 2016-06-18 06:15:18 +0200 | [diff] [blame] | 71 | struct dir_iterator { |
| 72 | /* The current path: */ |
| 73 | struct strbuf path; |
| 74 | |
| 75 | /* |
| 76 | * The current path relative to the starting path. This part |
| 77 | * of the path always uses "/" characters to separate path |
| 78 | * components: |
| 79 | */ |
| 80 | const char *relative_path; |
| 81 | |
| 82 | /* The current basename: */ |
| 83 | const char *basename; |
| 84 | |
Matheus Tavares | fa1da7d | 2019-07-10 20:59:00 -0300 | [diff] [blame] | 85 | /* |
| 86 | * The result of calling lstat() on path; or stat(), if the |
| 87 | * DIR_ITERATOR_FOLLOW_SYMLINKS flag was set at |
| 88 | * dir_iterator's initialization. |
| 89 | */ |
Michael Haggerty | 0fe5043 | 2016-06-18 06:15:18 +0200 | [diff] [blame] | 90 | struct stat st; |
| 91 | }; |
| 92 | |
| 93 | /* |
Matheus Tavares | fa1da7d | 2019-07-10 20:59:00 -0300 | [diff] [blame] | 94 | * Start a directory iteration over path with the combination of |
| 95 | * options specified by flags. On success, return a dir_iterator |
| 96 | * that holds the internal state of the iteration. In case of |
| 97 | * failure, return NULL and set errno accordingly. |
Michael Haggerty | 0fe5043 | 2016-06-18 06:15:18 +0200 | [diff] [blame] | 98 | * |
| 99 | * The iteration includes all paths under path, not including path |
| 100 | * itself and not including "." or ".." entries. |
| 101 | * |
Matheus Tavares | fa1da7d | 2019-07-10 20:59:00 -0300 | [diff] [blame] | 102 | * Parameters are: |
| 103 | * - path is the starting directory. An internal copy will be made. |
| 104 | * - flags is a combination of the possible flags to initialize a |
| 105 | * dir-iterator or 0 for default behavior. |
Michael Haggerty | 0fe5043 | 2016-06-18 06:15:18 +0200 | [diff] [blame] | 106 | */ |
Matheus Tavares | fa1da7d | 2019-07-10 20:59:00 -0300 | [diff] [blame] | 107 | struct dir_iterator *dir_iterator_begin(const char *path, unsigned int flags); |
Michael Haggerty | 0fe5043 | 2016-06-18 06:15:18 +0200 | [diff] [blame] | 108 | |
| 109 | /* |
| 110 | * Advance the iterator to the first or next item and return ITER_OK. |
| 111 | * If the iteration is exhausted, free the dir_iterator and any |
Matheus Tavares | fa1da7d | 2019-07-10 20:59:00 -0300 | [diff] [blame] | 112 | * resources associated with it and return ITER_DONE. |
| 113 | * |
| 114 | * It is a bug to use iterator or call this function again after it |
| 115 | * has returned ITER_DONE or ITER_ERROR (which may be returned iff |
| 116 | * the DIR_ITERATOR_PEDANTIC flag was set). |
Michael Haggerty | 0fe5043 | 2016-06-18 06:15:18 +0200 | [diff] [blame] | 117 | */ |
| 118 | int dir_iterator_advance(struct dir_iterator *iterator); |
| 119 | |
| 120 | /* |
| 121 | * End the iteration before it has been exhausted. Free the |
| 122 | * dir_iterator and any associated resources and return ITER_DONE. On |
| 123 | * error, free the dir_iterator and return ITER_ERROR. |
| 124 | */ |
| 125 | int dir_iterator_abort(struct dir_iterator *iterator); |
| 126 | |
| 127 | #endif |