]> git.ipfire.org Git - thirdparty/git.git/blob - dir.h
sparse-checkout: improve OS ls compatibility
[thirdparty/git.git] / dir.h
1 #ifndef DIR_H
2 #define DIR_H
3
4 /* See Documentation/technical/api-directory-listing.txt */
5
6 #include "cache.h"
7 #include "hashmap.h"
8 #include "strbuf.h"
9
10 struct dir_entry {
11 unsigned int len;
12 char name[FLEX_ARRAY]; /* more */
13 };
14
15 #define PATTERN_FLAG_NODIR 1
16 #define PATTERN_FLAG_ENDSWITH 4
17 #define PATTERN_FLAG_MUSTBEDIR 8
18 #define PATTERN_FLAG_NEGATIVE 16
19
20 struct path_pattern {
21 /*
22 * This allows callers of last_matching_pattern() etc.
23 * to determine the origin of the matching pattern.
24 */
25 struct pattern_list *pl;
26
27 const char *pattern;
28 int patternlen;
29 int nowildcardlen;
30 const char *base;
31 int baselen;
32 unsigned flags; /* PATTERN_FLAG_* */
33
34 /*
35 * Counting starts from 1 for line numbers in ignore files,
36 * and from -1 decrementing for patterns from CLI args.
37 */
38 int srcpos;
39 };
40
41 /* used for hashmaps for cone patterns */
42 struct pattern_entry {
43 struct hashmap_entry ent;
44 char *pattern;
45 size_t patternlen;
46 };
47
48 /*
49 * Each excludes file will be parsed into a fresh exclude_list which
50 * is appended to the relevant exclude_list_group (either EXC_DIRS or
51 * EXC_FILE). An exclude_list within the EXC_CMDL exclude_list_group
52 * can also be used to represent the list of --exclude values passed
53 * via CLI args.
54 */
55 struct pattern_list {
56 int nr;
57 int alloc;
58
59 /* remember pointer to exclude file contents so we can free() */
60 char *filebuf;
61
62 /* origin of list, e.g. path to filename, or descriptive string */
63 const char *src;
64
65 struct path_pattern **patterns;
66
67 /*
68 * While scanning the excludes, we attempt to match the patterns
69 * with a more restricted set that allows us to use hashsets for
70 * matching logic, which is faster than the linear lookup in the
71 * excludes array above. If non-zero, that check succeeded.
72 */
73 unsigned use_cone_patterns;
74 unsigned full_cone;
75
76 /*
77 * Stores paths where everything starting with those paths
78 * is included.
79 */
80 struct hashmap recursive_hashmap;
81
82 /*
83 * Used to check single-level parents of blobs.
84 */
85 struct hashmap parent_hashmap;
86 };
87
88 /*
89 * The contents of the per-directory exclude files are lazily read on
90 * demand and then cached in memory, one per exclude_stack struct, in
91 * order to avoid opening and parsing each one every time that
92 * directory is traversed.
93 */
94 struct exclude_stack {
95 struct exclude_stack *prev; /* the struct exclude_stack for the parent directory */
96 int baselen;
97 int exclude_ix; /* index of exclude_list within EXC_DIRS exclude_list_group */
98 struct untracked_cache_dir *ucd;
99 };
100
101 struct exclude_list_group {
102 int nr, alloc;
103 struct pattern_list *pl;
104 };
105
106 struct oid_stat {
107 struct stat_data stat;
108 struct object_id oid;
109 int valid;
110 };
111
112 /*
113 * Untracked cache
114 *
115 * The following inputs are sufficient to determine what files in a
116 * directory are excluded:
117 *
118 * - The list of files and directories of the directory in question
119 * - The $GIT_DIR/index
120 * - dir_struct flags
121 * - The content of $GIT_DIR/info/exclude
122 * - The content of core.excludesfile
123 * - The content (or the lack) of .gitignore of all parent directories
124 * from $GIT_WORK_TREE
125 * - The check_only flag in read_directory_recursive (for
126 * DIR_HIDE_EMPTY_DIRECTORIES)
127 *
128 * The first input can be checked using directory mtime. In many
129 * filesystems, directory mtime (stat_data field) is updated when its
130 * files or direct subdirs are added or removed.
131 *
132 * The second one can be hooked from cache_tree_invalidate_path().
133 * Whenever a file (or a submodule) is added or removed from a
134 * directory, we invalidate that directory.
135 *
136 * The remaining inputs are easy, their SHA-1 could be used to verify
137 * their contents (exclude_sha1[], info_exclude_sha1[] and
138 * excludes_file_sha1[])
139 */
140 struct untracked_cache_dir {
141 struct untracked_cache_dir **dirs;
142 char **untracked;
143 struct stat_data stat_data;
144 unsigned int untracked_alloc, dirs_nr, dirs_alloc;
145 unsigned int untracked_nr;
146 unsigned int check_only : 1;
147 /* all data except 'dirs' in this struct are good */
148 unsigned int valid : 1;
149 unsigned int recurse : 1;
150 /* null object ID means this directory does not have .gitignore */
151 struct object_id exclude_oid;
152 char name[FLEX_ARRAY];
153 };
154
155 struct untracked_cache {
156 struct oid_stat ss_info_exclude;
157 struct oid_stat ss_excludes_file;
158 const char *exclude_per_dir;
159 struct strbuf ident;
160 /*
161 * dir_struct#flags must match dir_flags or the untracked
162 * cache is ignored.
163 */
164 unsigned dir_flags;
165 struct untracked_cache_dir *root;
166 /* Statistics */
167 int dir_created;
168 int gitignore_invalidated;
169 int dir_invalidated;
170 int dir_opened;
171 /* fsmonitor invalidation data */
172 unsigned int use_fsmonitor : 1;
173 };
174
175 struct dir_struct {
176 int nr, alloc;
177 int ignored_nr, ignored_alloc;
178 enum {
179 DIR_SHOW_IGNORED = 1<<0,
180 DIR_SHOW_OTHER_DIRECTORIES = 1<<1,
181 DIR_HIDE_EMPTY_DIRECTORIES = 1<<2,
182 DIR_NO_GITLINKS = 1<<3,
183 DIR_COLLECT_IGNORED = 1<<4,
184 DIR_SHOW_IGNORED_TOO = 1<<5,
185 DIR_COLLECT_KILLED_ONLY = 1<<6,
186 DIR_KEEP_UNTRACKED_CONTENTS = 1<<7,
187 DIR_SHOW_IGNORED_TOO_MODE_MATCHING = 1<<8,
188 DIR_SKIP_NESTED_GIT = 1<<9
189 } flags;
190 struct dir_entry **entries;
191 struct dir_entry **ignored;
192
193 /* Exclude info */
194 const char *exclude_per_dir;
195
196 /*
197 * We maintain three groups of exclude pattern lists:
198 *
199 * EXC_CMDL lists patterns explicitly given on the command line.
200 * EXC_DIRS lists patterns obtained from per-directory ignore files.
201 * EXC_FILE lists patterns from fallback ignore files, e.g.
202 * - .git/info/exclude
203 * - core.excludesfile
204 *
205 * Each group contains multiple exclude lists, a single list
206 * per source.
207 */
208 #define EXC_CMDL 0
209 #define EXC_DIRS 1
210 #define EXC_FILE 2
211 struct exclude_list_group exclude_list_group[3];
212
213 /*
214 * Temporary variables which are used during loading of the
215 * per-directory exclude lists.
216 *
217 * exclude_stack points to the top of the exclude_stack, and
218 * basebuf contains the full path to the current
219 * (sub)directory in the traversal. Exclude points to the
220 * matching exclude struct if the directory is excluded.
221 */
222 struct exclude_stack *exclude_stack;
223 struct path_pattern *pattern;
224 struct strbuf basebuf;
225
226 /* Enable untracked file cache if set */
227 struct untracked_cache *untracked;
228 struct oid_stat ss_info_exclude;
229 struct oid_stat ss_excludes_file;
230 unsigned unmanaged_exclude_files;
231 };
232
233 /*Count the number of slashes for string s*/
234 int count_slashes(const char *s);
235
236 /*
237 * The ordering of these constants is significant, with
238 * higher-numbered match types signifying "closer" (i.e. more
239 * specific) matches which will override lower-numbered match types
240 * when populating the seen[] array.
241 */
242 #define MATCHED_RECURSIVELY 1
243 #define MATCHED_RECURSIVELY_LEADING_PATHSPEC 2
244 #define MATCHED_FNMATCH 3
245 #define MATCHED_EXACTLY 4
246 int simple_length(const char *match);
247 int no_wildcard(const char *string);
248 char *common_prefix(const struct pathspec *pathspec);
249 int match_pathspec(const struct index_state *istate,
250 const struct pathspec *pathspec,
251 const char *name, int namelen,
252 int prefix, char *seen, int is_dir);
253 int report_path_error(const char *ps_matched, const struct pathspec *pathspec);
254 int within_depth(const char *name, int namelen, int depth, int max_depth);
255
256 int fill_directory(struct dir_struct *dir,
257 struct index_state *istate,
258 const struct pathspec *pathspec);
259 int read_directory(struct dir_struct *, struct index_state *istate,
260 const char *path, int len,
261 const struct pathspec *pathspec);
262
263 enum pattern_match_result {
264 UNDECIDED = -1,
265 NOT_MATCHED = 0,
266 MATCHED = 1,
267 MATCHED_RECURSIVE = 2,
268 };
269
270 /*
271 * Scan the list of patterns to determine if the ordered list
272 * of patterns matches on 'pathname'.
273 *
274 * Return 1 for a match, 0 for not matched and -1 for undecided.
275 */
276 enum pattern_match_result path_matches_pattern_list(const char *pathname,
277 int pathlen,
278 const char *basename, int *dtype,
279 struct pattern_list *pl,
280 struct index_state *istate);
281 struct dir_entry *dir_add_ignored(struct dir_struct *dir,
282 struct index_state *istate,
283 const char *pathname, int len);
284
285 /*
286 * these implement the matching logic for dir.c:excluded_from_list and
287 * attr.c:path_matches()
288 */
289 int match_basename(const char *, int,
290 const char *, int, int, unsigned);
291 int match_pathname(const char *, int,
292 const char *, int,
293 const char *, int, int, unsigned);
294
295 struct path_pattern *last_matching_pattern(struct dir_struct *dir,
296 struct index_state *istate,
297 const char *name, int *dtype);
298
299 int is_excluded(struct dir_struct *dir,
300 struct index_state *istate,
301 const char *name, int *dtype);
302
303 int pl_hashmap_cmp(const void *unused_cmp_data,
304 const struct hashmap_entry *a,
305 const struct hashmap_entry *b,
306 const void *key);
307 int hashmap_contains_parent(struct hashmap *map,
308 const char *path,
309 struct strbuf *buffer);
310 struct pattern_list *add_pattern_list(struct dir_struct *dir,
311 int group_type, const char *src);
312 int add_patterns_from_file_to_list(const char *fname, const char *base, int baselen,
313 struct pattern_list *pl, struct index_state *istate);
314 void add_patterns_from_file(struct dir_struct *, const char *fname);
315 int add_patterns_from_blob_to_list(struct object_id *oid,
316 const char *base, int baselen,
317 struct pattern_list *pl);
318 void parse_path_pattern(const char **string, int *patternlen, unsigned *flags, int *nowildcardlen);
319 void add_pattern(const char *string, const char *base,
320 int baselen, struct pattern_list *pl, int srcpos);
321 void clear_pattern_list(struct pattern_list *pl);
322 void clear_directory(struct dir_struct *dir);
323
324 int repo_file_exists(struct repository *repo, const char *path);
325 int file_exists(const char *);
326
327 int is_inside_dir(const char *dir);
328 int dir_inside_of(const char *subdir, const char *dir);
329
330 static inline int is_dot_or_dotdot(const char *name)
331 {
332 return (name[0] == '.' &&
333 (name[1] == '\0' ||
334 (name[1] == '.' && name[2] == '\0')));
335 }
336
337 int is_empty_dir(const char *dir);
338
339 void setup_standard_excludes(struct dir_struct *dir);
340
341
342 /* Constants for remove_dir_recursively: */
343
344 /*
345 * If a non-directory is found within path, stop and return an error.
346 * (In this case some empty directories might already have been
347 * removed.)
348 */
349 #define REMOVE_DIR_EMPTY_ONLY 01
350
351 /*
352 * If any Git work trees are found within path, skip them without
353 * considering it an error.
354 */
355 #define REMOVE_DIR_KEEP_NESTED_GIT 02
356
357 /* Remove the contents of path, but leave path itself. */
358 #define REMOVE_DIR_KEEP_TOPLEVEL 04
359
360 /*
361 * Remove path and its contents, recursively. flags is a combination
362 * of the above REMOVE_DIR_* constants. Return 0 on success.
363 *
364 * This function uses path as temporary scratch space, but restores it
365 * before returning.
366 */
367 int remove_dir_recursively(struct strbuf *path, int flag);
368
369 /* tries to remove the path with empty directories along it, ignores ENOENT */
370 int remove_path(const char *path);
371
372 int fspathcmp(const char *a, const char *b);
373 int fspathncmp(const char *a, const char *b, size_t count);
374
375 /*
376 * The prefix part of pattern must not contains wildcards.
377 */
378 struct pathspec_item;
379 int git_fnmatch(const struct pathspec_item *item,
380 const char *pattern, const char *string,
381 int prefix);
382
383 int submodule_path_match(const struct index_state *istate,
384 const struct pathspec *ps,
385 const char *submodule_name,
386 char *seen);
387
388 static inline int ce_path_match(const struct index_state *istate,
389 const struct cache_entry *ce,
390 const struct pathspec *pathspec,
391 char *seen)
392 {
393 return match_pathspec(istate, pathspec, ce->name, ce_namelen(ce), 0, seen,
394 S_ISDIR(ce->ce_mode) || S_ISGITLINK(ce->ce_mode));
395 }
396
397 static inline int dir_path_match(const struct index_state *istate,
398 const struct dir_entry *ent,
399 const struct pathspec *pathspec,
400 int prefix, char *seen)
401 {
402 int has_trailing_dir = ent->len && ent->name[ent->len - 1] == '/';
403 int len = has_trailing_dir ? ent->len - 1 : ent->len;
404 return match_pathspec(istate, pathspec, ent->name, len, prefix, seen,
405 has_trailing_dir);
406 }
407
408 int cmp_dir_entry(const void *p1, const void *p2);
409 int check_dir_entry_contains(const struct dir_entry *out, const struct dir_entry *in);
410
411 void untracked_cache_invalidate_path(struct index_state *, const char *, int safe_path);
412 void untracked_cache_remove_from_index(struct index_state *, const char *);
413 void untracked_cache_add_to_index(struct index_state *, const char *);
414
415 void free_untracked_cache(struct untracked_cache *);
416 struct untracked_cache *read_untracked_extension(const void *data, unsigned long sz);
417 void write_untracked_extension(struct strbuf *out, struct untracked_cache *untracked);
418 void add_untracked_cache(struct index_state *istate);
419 void remove_untracked_cache(struct index_state *istate);
420
421 /*
422 * Connect a worktree to a git directory by creating (or overwriting) a
423 * '.git' file containing the location of the git directory. In the git
424 * directory set the core.worktree setting to indicate where the worktree is.
425 * When `recurse_into_nested` is set, recurse into any nested submodules,
426 * connecting them as well.
427 */
428 void connect_work_tree_and_git_dir(const char *work_tree,
429 const char *git_dir,
430 int recurse_into_nested);
431 void relocate_gitdir(const char *path,
432 const char *old_git_dir,
433 const char *new_git_dir);
434 #endif