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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
|
/* SPDX-License-Identifier: LGPL-3.0-or-later */
/*
* dir_iterator.h
*
* Copyright (C) 2023 David Oberhollenzer <goliath@infraroot.at>
*/
#ifndef IO_DIR_ITERATOR_H
#define IO_DIR_ITERATOR_H
#include "io/dir_entry.h"
#include "sqfs/predef.h"
/**
* @interface dir_iterator_t
*
* @brief An iterator over entries in a filesystem directory.
*/
typedef struct dir_iterator_t {
sqfs_object_t obj;
/**
* @brief Read the next entry and update internal state relating to it
*
* @param it A pointer to the iterator itself
* @param out Returns a pointer to an entry on success
*
* @return Zero on success, postivie value if the end of the list was
* reached, negative @ref SQFS_ERROR value on failure.
*/
int (*next)(struct dir_iterator_t *it, dir_entry_t **out);
/**
* @brief If the last entry was a symlink, extract the target path
*
* @param it A pointer to the iterator itself.
* @param out Returns a pointer to a string on success. Has to be
* released with free().
*
* @return Zero on success, negative @ref SQFS_ERROR value on failure.
*/
int (*read_link)(struct dir_iterator_t *it, char **out);
/**
* @brief If the last entry was a directory, open it.
*
* If next() returned a directory, this can be used to create a brand
* new dir_iterator_t for it, that is independent of the current one
* and returns the sub-directories entries.
*
* @param it A pointer to the iterator itself.
* @param out Returns a pointer to a directory iterator on success.
*
* @return Zero on success, negative @ref SQFS_ERROR value on failure.
*/
int (*open_subdir)(struct dir_iterator_t *it,
struct dir_iterator_t **out);
/**
* @brief Skip a sub-hierarchy on a stacked iterator
*
* If an iterator would ordinarily recurse into a sub-directory,
* tell it to skip those entries. On simple, flag iterators like the
* one returned by @ref dir_iterator_create, this has no effect.
*
* @param it A pointer to the iterator itself.
*/
void (*ignore_subdir)(struct dir_iterator_t *it);
/**
* @brief If the last entry was a regular file, open it.
*
* If next() returned a file, this can be used to create an istream
* to read from it.
*
* @param it A pointer to the iterator itself.
* @param out Returns a pointer to a @ref sqfs_istream_t on success.
*
* @return Zero on success, negative @ref SQFS_ERROR value on failure.
*/
int (*open_file_ro)(struct dir_iterator_t *it, sqfs_istream_t **out);
/**
* @brief Read extended attributes associated with the current entry
*
* @param it A pointer to the iterator itself.
* @param out Returns a linked list of xattr entries.
*
* @return Zero on success, negative @ref SQFS_ERROR value on failure.
*/
int (*read_xattr)(struct dir_iterator_t *it, sqfs_xattr_t **out);
} dir_iterator_t;
enum {
DIR_SCAN_NO_SOCK = 0x0001,
DIR_SCAN_NO_SLINK = 0x0002,
DIR_SCAN_NO_FILE = 0x0004,
DIR_SCAN_NO_BLK = 0x0008,
DIR_SCAN_NO_DIR = 0x0010,
DIR_SCAN_NO_CHR = 0x0020,
DIR_SCAN_NO_FIFO = 0x0040,
DIR_SCAN_KEEP_TIME = 0x0100,
DIR_SCAN_KEEP_UID = 0x0200,
DIR_SCAN_KEEP_GID = 0x0400,
DIR_SCAN_KEEP_MODE = 0x0800,
DIR_SCAN_ONE_FILESYSTEM = 0x1000,
DIR_SCAN_NO_RECURSION = 0x2000,
DIR_SCAN_MATCH_FULL_PATH = 0x4000,
};
typedef struct {
sqfs_u32 flags;
sqfs_u32 def_uid;
sqfs_u32 def_gid;
sqfs_u32 def_mode;
sqfs_s64 def_mtime;
/**
* @brief A prefix to attach to all returend paths
*
* If not null, this string and an additional "/" are prepended to
* all entries returned by the iterator.
*/
const char *prefix;
/**
* @brief A glob pattern that either the name must match
*
* If this is not NULL, only paths that match this globbing pattern
* are returned. If the flag DIR_SCAN_MATCH_FULL_PATH is set, the
* entire path must match, slashes cannot match wild card characters.
* If not set, only the last part of the path is tested. The iterator
* still recurses into directories, it simply doesn't report them if
* they don't match.
*/
const char *name_pattern;
} dir_tree_cfg_t;
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Construct a simple directory iterator given a path
*
* On systems with encoding aware file I/O (like Windows), the path is
* interpreted to be UTF-8 encoded and converted to the native system API
* encoding to open the directory. For each directory entry, the name in
* the native encoding is converted back to UTF-8 when reading.
*
* The implementation returned by this is simple, non-recursive, reporting
* directory contents as returned by the OS native API, i.e. not sorted,
* and including the "." and ".." entries.
*
* @param path A path to a directory on the file system.
*
* @return A pointer to a dir_iterator_t implementation on success,
* NULL on error (message is printed to stderr).
*/
SQFS_INTERNAL dir_iterator_t *dir_iterator_create(const char *path);
/**
* @brief Create a stacked, recursive directory tree iterator
*
* The underlying implementation automatically recurses into sub directories
* and returns a flattened list of entries, where each entry represents a full
* path. Advanced filtering, path pre-fixing et cetera can be configured.
* The typical "." and ".." entries are filtered out as well.
*
* @param path A path to a directory on the file system.
* @param cfg A @ref dir_tree_cfg_t filtering configuration.
*
* @return A pointer to a dir_iterator_t implementation on success,
* NULL on error (message is printed to stderr).
*/
SQFS_INTERNAL
dir_iterator_t *dir_tree_iterator_create(const char *path,
const dir_tree_cfg_t *cfg);
#ifdef __cplusplus
}
#endif
#endif /* IO_DIR_ITERATOR_H */
|