summaryrefslogtreecommitdiffstats
path: root/dir-iterator.h
blob: e3b6ff28007366568d981631d5b312bd849486c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#ifndef DIR_ITERATOR_H
#define DIR_ITERATOR_H

#include "strbuf.h"

/*
 * Iterate over a directory tree.
 *
 * Iterate over a directory tree, recursively, including paths of all
 * types and hidden paths. Skip "." and ".." entries and don't follow
 * symlinks except for the original path. Note that the original path
 * is not included in the iteration.
 *
 * Every time dir_iterator_advance() is called, update the members of
 * the dir_iterator structure to reflect the next path in the
 * iteration. The order that paths are iterated over within a
 * directory is undefined, directory paths are always given before
 * their contents.
 *
 * A typical iteration looks like this:
 *
 *     int ok;
 *     unsigned int flags = DIR_ITERATOR_PEDANTIC;
 *     struct dir_iterator *iter = dir_iterator_begin(path, flags);
 *
 *     if (!iter)
 *             goto error_handler;
 *
 *     while ((ok = dir_iterator_advance(iter)) == ITER_OK) {
 *             if (want_to_stop_iteration()) {
 *                     ok = dir_iterator_abort(iter);
 *                     break;
 *             }
 *
 *             // Access information about the current path:
 *             if (S_ISDIR(iter->st.st_mode))
 *                     printf("%s is a directory\n", iter->relative_path);
 *     }
 *
 *     if (ok != ITER_DONE)
 *             handle_error();
 *
 * Callers are allowed to modify iter->path while they are working,
 * but they must restore it to its original contents before calling
 * dir_iterator_advance() again.
 */

/*
 * Flags for dir_iterator_begin:
 *
 * - DIR_ITERATOR_PEDANTIC: override dir-iterator's default behavior
 *   in case of an error at dir_iterator_advance(), which is to keep
 *   looking for a next valid entry. With this flag, resources are freed
 *   and ITER_ERROR is returned immediately. In both cases, a meaningful
 *   warning is emitted. Note: ENOENT errors are always ignored so that
 *   the API users may remove files during iteration.
 *
 * - DIR_ITERATOR_FOLLOW_SYMLINKS: make dir-iterator follow symlinks.
 *   i.e., linked directories' contents will be iterated over and
 *   iter->base.st will contain information on the referred files,
 *   not the symlinks themselves, which is the default behavior. Broken
 *   symlinks are ignored.
 *
 *   Note: setting DIR_ITERATOR_FOLLOW_SYMLINKS affects resolving the
 *   starting path as well (e.g., attempting to iterate starting at a
 *   symbolic link pointing to a directory without FOLLOW_SYMLINKS will
 *   result in an error).
 *
 * Warning: circular symlinks are also followed when
 * DIR_ITERATOR_FOLLOW_SYMLINKS is set. The iteration may end up with
 * an ELOOP if they happen and DIR_ITERATOR_PEDANTIC is set.
 */
#define DIR_ITERATOR_PEDANTIC (1 << 0)
#define DIR_ITERATOR_FOLLOW_SYMLINKS (1 << 1)

struct dir_iterator {
	/* The current path: */
	struct strbuf path;

	/*
	 * The current path relative to the starting path. This part
	 * of the path always uses "/" characters to separate path
	 * components:
	 */
	const char *relative_path;

	/* The current basename: */
	const char *basename;

	/*
	 * The result of calling lstat() on path; or stat(), if the
	 * DIR_ITERATOR_FOLLOW_SYMLINKS flag was set at
	 * dir_iterator's initialization.
	 */
	struct stat st;
};

/*
 * Start a directory iteration over path with the combination of
 * options specified by flags. On success, return a dir_iterator
 * that holds the internal state of the iteration. In case of
 * failure, return NULL and set errno accordingly.
 *
 * The iteration includes all paths under path, not including path
 * itself and not including "." or ".." entries.
 *
 * Parameters are:
 *  - path is the starting directory. An internal copy will be made.
 *  - flags is a combination of the possible flags to initialize a
 *    dir-iterator or 0 for default behavior.
 */
struct dir_iterator *dir_iterator_begin(const char *path, unsigned int flags);

/*
 * Advance the iterator to the first or next item and return ITER_OK.
 * If the iteration is exhausted, free the dir_iterator and any
 * resources associated with it and return ITER_DONE.
 *
 * It is a bug to use iterator or call this function again after it
 * has returned ITER_DONE or ITER_ERROR (which may be returned iff
 * the DIR_ITERATOR_PEDANTIC flag was set).
 */
int dir_iterator_advance(struct dir_iterator *iterator);

/*
 * End the iteration before it has been exhausted. Free the
 * dir_iterator and any associated resources and return ITER_DONE. On
 * error, free the dir_iterator and return ITER_ERROR.
 */
int dir_iterator_abort(struct dir_iterator *iterator);

#endif