line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
/* |
2
|
|
|
|
|
|
|
* Copyright (C) the libgit2 contributors. All rights reserved. |
3
|
|
|
|
|
|
|
* |
4
|
|
|
|
|
|
|
* This file is part of libgit2, distributed under the GNU GPL v2 with |
5
|
|
|
|
|
|
|
* a Linking Exception. For full terms see the included COPYING file. |
6
|
|
|
|
|
|
|
*/ |
7
|
|
|
|
|
|
|
#ifndef INCLUDE_fs_path_h__ |
8
|
|
|
|
|
|
|
#define INCLUDE_fs_path_h__ |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
#include "git2_util.h" |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
#include "posix.h" |
13
|
|
|
|
|
|
|
#include "str.h" |
14
|
|
|
|
|
|
|
#include "vector.h" |
15
|
|
|
|
|
|
|
#include "utf8.h" |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
/** |
18
|
|
|
|
|
|
|
* Path manipulation utils |
19
|
|
|
|
|
|
|
* |
20
|
|
|
|
|
|
|
* These are path utilities that munge paths without actually |
21
|
|
|
|
|
|
|
* looking at the real filesystem. |
22
|
|
|
|
|
|
|
*/ |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
/* |
25
|
|
|
|
|
|
|
* The dirname() function shall take a pointer to a character string |
26
|
|
|
|
|
|
|
* that contains a pathname, and return a pointer to a string that is a |
27
|
|
|
|
|
|
|
* pathname of the parent directory of that file. Trailing '/' characters |
28
|
|
|
|
|
|
|
* in the path are not counted as part of the path. |
29
|
|
|
|
|
|
|
* |
30
|
|
|
|
|
|
|
* If path does not contain a '/', then dirname() shall return a pointer to |
31
|
|
|
|
|
|
|
* the string ".". If path is a null pointer or points to an empty string, |
32
|
|
|
|
|
|
|
* dirname() shall return a pointer to the string "." . |
33
|
|
|
|
|
|
|
* |
34
|
|
|
|
|
|
|
* The `git_fs_path_dirname` implementation is thread safe. The returned |
35
|
|
|
|
|
|
|
* string must be manually free'd. |
36
|
|
|
|
|
|
|
* |
37
|
|
|
|
|
|
|
* The `git_fs_path_dirname_r` implementation writes the dirname to a `git_str` |
38
|
|
|
|
|
|
|
* if the buffer pointer is not NULL. |
39
|
|
|
|
|
|
|
* It returns an error code < 0 if there is an allocation error, otherwise |
40
|
|
|
|
|
|
|
* the length of the dirname (which will be > 0). |
41
|
|
|
|
|
|
|
*/ |
42
|
|
|
|
|
|
|
extern char *git_fs_path_dirname(const char *path); |
43
|
|
|
|
|
|
|
extern int git_fs_path_dirname_r(git_str *buffer, const char *path); |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
/* |
46
|
|
|
|
|
|
|
* This function returns the basename of the file, which is the last |
47
|
|
|
|
|
|
|
* part of its full name given by fname, with the drive letter and |
48
|
|
|
|
|
|
|
* leading directories stripped off. For example, the basename of |
49
|
|
|
|
|
|
|
* c:/foo/bar/file.ext is file.ext, and the basename of a:foo is foo. |
50
|
|
|
|
|
|
|
* |
51
|
|
|
|
|
|
|
* Trailing slashes and backslashes are significant: the basename of |
52
|
|
|
|
|
|
|
* c:/foo/bar/ is an empty string after the rightmost slash. |
53
|
|
|
|
|
|
|
* |
54
|
|
|
|
|
|
|
* The `git_fs_path_basename` implementation is thread safe. The returned |
55
|
|
|
|
|
|
|
* string must be manually free'd. |
56
|
|
|
|
|
|
|
* |
57
|
|
|
|
|
|
|
* The `git_fs_path_basename_r` implementation writes the basename to a `git_str`. |
58
|
|
|
|
|
|
|
* It returns an error code < 0 if there is an allocation error, otherwise |
59
|
|
|
|
|
|
|
* the length of the basename (which will be >= 0). |
60
|
|
|
|
|
|
|
*/ |
61
|
|
|
|
|
|
|
extern char *git_fs_path_basename(const char *path); |
62
|
|
|
|
|
|
|
extern int git_fs_path_basename_r(git_str *buffer, const char *path); |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
/* Return the offset of the start of the basename. Unlike the other |
65
|
|
|
|
|
|
|
* basename functions, this returns 0 if the path is empty. |
66
|
|
|
|
|
|
|
*/ |
67
|
|
|
|
|
|
|
extern size_t git_fs_path_basename_offset(git_str *buffer); |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
/** |
70
|
|
|
|
|
|
|
* Find offset to root of path if path has one. |
71
|
|
|
|
|
|
|
* |
72
|
|
|
|
|
|
|
* This will return a number >= 0 which is the offset to the start of the |
73
|
|
|
|
|
|
|
* path, if the path is rooted (i.e. "/rooted/path" returns 0 and |
74
|
|
|
|
|
|
|
* "c:/windows/rooted/path" returns 2). If the path is not rooted, this |
75
|
|
|
|
|
|
|
* returns -1. |
76
|
|
|
|
|
|
|
*/ |
77
|
|
|
|
|
|
|
extern int git_fs_path_root(const char *path); |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
/** |
80
|
|
|
|
|
|
|
* Ensure path has a trailing '/'. |
81
|
|
|
|
|
|
|
*/ |
82
|
|
|
|
|
|
|
extern int git_fs_path_to_dir(git_str *path); |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
/** |
85
|
|
|
|
|
|
|
* Ensure string has a trailing '/' if there is space for it. |
86
|
|
|
|
|
|
|
*/ |
87
|
|
|
|
|
|
|
extern void git_fs_path_string_to_dir(char *path, size_t size); |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
/** |
90
|
|
|
|
|
|
|
* Taken from git.git; returns nonzero if the given path is "." or "..". |
91
|
|
|
|
|
|
|
*/ |
92
|
3050
|
|
|
|
|
|
GIT_INLINE(int) git_fs_path_is_dot_or_dotdot(const char *name) |
93
|
|
|
|
|
|
|
{ |
94
|
4031
|
100
|
|
|
|
|
return (name[0] == '.' && |
|
|
100
|
|
|
|
|
|
95
|
981
|
100
|
|
|
|
|
(name[1] == '\0' || |
96
|
780
|
50
|
|
|
|
|
(name[1] == '.' && name[2] == '\0'))); |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
#ifdef GIT_WIN32 |
100
|
|
|
|
|
|
|
GIT_INLINE(int) git_fs_path_is_dot_or_dotdotW(const wchar_t *name) |
101
|
|
|
|
|
|
|
{ |
102
|
|
|
|
|
|
|
return (name[0] == L'.' && |
103
|
|
|
|
|
|
|
(name[1] == L'\0' || |
104
|
|
|
|
|
|
|
(name[1] == L'.' && name[2] == L'\0'))); |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
#define git_fs_path_is_absolute(p) \ |
108
|
|
|
|
|
|
|
(git__isalpha((p)[0]) && (p)[1] == ':' && ((p)[2] == '\\' || (p)[2] == '/')) |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
#define git_fs_path_is_dirsep(p) \ |
111
|
|
|
|
|
|
|
((p) == '/' || (p) == '\\') |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
/** |
114
|
|
|
|
|
|
|
* Convert backslashes in path to forward slashes. |
115
|
|
|
|
|
|
|
*/ |
116
|
|
|
|
|
|
|
GIT_INLINE(void) git_fs_path_mkposix(char *path) |
117
|
|
|
|
|
|
|
{ |
118
|
|
|
|
|
|
|
while (*path) { |
119
|
|
|
|
|
|
|
if (*path == '\\') |
120
|
|
|
|
|
|
|
*path = '/'; |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
path++; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
#else |
126
|
|
|
|
|
|
|
# define git_fs_path_mkposix(p) /* blank */ |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
#define git_fs_path_is_absolute(p) \ |
129
|
|
|
|
|
|
|
((p)[0] == '/') |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
#define git_fs_path_is_dirsep(p) \ |
132
|
|
|
|
|
|
|
((p) == '/') |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
#endif |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
/** |
137
|
|
|
|
|
|
|
* Check if string is a relative path (i.e. starts with "./" or "../") |
138
|
|
|
|
|
|
|
*/ |
139
|
|
|
|
|
|
|
GIT_INLINE(int) git_fs_path_is_relative(const char *p) |
140
|
|
|
|
|
|
|
{ |
141
|
|
|
|
|
|
|
return (p[0] == '.' && (p[1] == '/' || (p[1] == '.' && p[2] == '/'))); |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
/** |
145
|
|
|
|
|
|
|
* Check if string is at end of path segment (i.e. looking at '/' or '\0') |
146
|
|
|
|
|
|
|
*/ |
147
|
|
|
|
|
|
|
GIT_INLINE(int) git_fs_path_at_end_of_segment(const char *p) |
148
|
|
|
|
|
|
|
{ |
149
|
|
|
|
|
|
|
return !*p || *p == '/'; |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
extern int git__percent_decode(git_str *decoded_out, const char *input); |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
/** |
155
|
|
|
|
|
|
|
* Extract path from file:// URL. |
156
|
|
|
|
|
|
|
*/ |
157
|
|
|
|
|
|
|
extern int git_fs_path_fromurl(git_str *local_path_out, const char *file_url); |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
/** |
161
|
|
|
|
|
|
|
* Path filesystem utils |
162
|
|
|
|
|
|
|
* |
163
|
|
|
|
|
|
|
* These are path utilities that actually access the filesystem. |
164
|
|
|
|
|
|
|
*/ |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
/** |
167
|
|
|
|
|
|
|
* Check if a file exists and can be accessed. |
168
|
|
|
|
|
|
|
* @return true or false |
169
|
|
|
|
|
|
|
*/ |
170
|
|
|
|
|
|
|
extern bool git_fs_path_exists(const char *path); |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
/** |
173
|
|
|
|
|
|
|
* Check if the given path points to a directory. |
174
|
|
|
|
|
|
|
* @return true or false |
175
|
|
|
|
|
|
|
*/ |
176
|
|
|
|
|
|
|
extern bool git_fs_path_isdir(const char *path); |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
/** |
179
|
|
|
|
|
|
|
* Check if the given path points to a regular file. |
180
|
|
|
|
|
|
|
* @return true or false |
181
|
|
|
|
|
|
|
*/ |
182
|
|
|
|
|
|
|
extern bool git_fs_path_isfile(const char *path); |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
/** |
185
|
|
|
|
|
|
|
* Check if the given path points to a symbolic link. |
186
|
|
|
|
|
|
|
* @return true or false |
187
|
|
|
|
|
|
|
*/ |
188
|
|
|
|
|
|
|
extern bool git_fs_path_islink(const char *path); |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
/** |
191
|
|
|
|
|
|
|
* Check if the given path is a directory, and is empty. |
192
|
|
|
|
|
|
|
*/ |
193
|
|
|
|
|
|
|
extern bool git_fs_path_is_empty_dir(const char *path); |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
/** |
196
|
|
|
|
|
|
|
* Stat a file and/or link and set error if needed. |
197
|
|
|
|
|
|
|
*/ |
198
|
|
|
|
|
|
|
extern int git_fs_path_lstat(const char *path, struct stat *st); |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
/** |
201
|
|
|
|
|
|
|
* Check if the parent directory contains the item. |
202
|
|
|
|
|
|
|
* |
203
|
|
|
|
|
|
|
* @param dir Directory to check. |
204
|
|
|
|
|
|
|
* @param item Item that might be in the directory. |
205
|
|
|
|
|
|
|
* @return 0 if item exists in directory, <0 otherwise. |
206
|
|
|
|
|
|
|
*/ |
207
|
|
|
|
|
|
|
extern bool git_fs_path_contains(git_str *dir, const char *item); |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
/** |
210
|
|
|
|
|
|
|
* Check if the given path contains the given subdirectory. |
211
|
|
|
|
|
|
|
* |
212
|
|
|
|
|
|
|
* @param parent Directory path that might contain subdir |
213
|
|
|
|
|
|
|
* @param subdir Subdirectory name to look for in parent |
214
|
|
|
|
|
|
|
* @return true if subdirectory exists, false otherwise. |
215
|
|
|
|
|
|
|
*/ |
216
|
|
|
|
|
|
|
extern bool git_fs_path_contains_dir(git_str *parent, const char *subdir); |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
/** |
219
|
|
|
|
|
|
|
* Determine the common directory length between two paths, including |
220
|
|
|
|
|
|
|
* the final path separator. For example, given paths 'a/b/c/1.txt |
221
|
|
|
|
|
|
|
* and 'a/b/c/d/2.txt', the common directory is 'a/b/c/', and this |
222
|
|
|
|
|
|
|
* will return the length of the string 'a/b/c/', which is 6. |
223
|
|
|
|
|
|
|
* |
224
|
|
|
|
|
|
|
* @param one The first path |
225
|
|
|
|
|
|
|
* @param two The second path |
226
|
|
|
|
|
|
|
* @return The length of the common directory |
227
|
|
|
|
|
|
|
*/ |
228
|
|
|
|
|
|
|
extern size_t git_fs_path_common_dirlen(const char *one, const char *two); |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
/** |
231
|
|
|
|
|
|
|
* Make the path relative to the given parent path. |
232
|
|
|
|
|
|
|
* |
233
|
|
|
|
|
|
|
* @param path The path to make relative |
234
|
|
|
|
|
|
|
* @param parent The parent path to make path relative to |
235
|
|
|
|
|
|
|
* @return 0 if path was made relative, GIT_ENOTFOUND |
236
|
|
|
|
|
|
|
* if there was not common root between the paths, |
237
|
|
|
|
|
|
|
* or <0. |
238
|
|
|
|
|
|
|
*/ |
239
|
|
|
|
|
|
|
extern int git_fs_path_make_relative(git_str *path, const char *parent); |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
/** |
242
|
|
|
|
|
|
|
* Check if the given path contains the given file. |
243
|
|
|
|
|
|
|
* |
244
|
|
|
|
|
|
|
* @param dir Directory path that might contain file |
245
|
|
|
|
|
|
|
* @param file File name to look for in parent |
246
|
|
|
|
|
|
|
* @return true if file exists, false otherwise. |
247
|
|
|
|
|
|
|
*/ |
248
|
|
|
|
|
|
|
extern bool git_fs_path_contains_file(git_str *dir, const char *file); |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
/** |
251
|
|
|
|
|
|
|
* Prepend base to unrooted path or just copy path over. |
252
|
|
|
|
|
|
|
* |
253
|
|
|
|
|
|
|
* This will optionally return the index into the path where the "root" |
254
|
|
|
|
|
|
|
* is, either the end of the base directory prefix or the path root. |
255
|
|
|
|
|
|
|
*/ |
256
|
|
|
|
|
|
|
extern int git_fs_path_join_unrooted( |
257
|
|
|
|
|
|
|
git_str *path_out, const char *path, const char *base, ssize_t *root_at); |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
/** |
260
|
|
|
|
|
|
|
* Removes multiple occurrences of '/' in a row, squashing them into a |
261
|
|
|
|
|
|
|
* single '/'. |
262
|
|
|
|
|
|
|
*/ |
263
|
|
|
|
|
|
|
extern void git_fs_path_squash_slashes(git_str *path); |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
/** |
266
|
|
|
|
|
|
|
* Clean up path, prepending base if it is not already rooted. |
267
|
|
|
|
|
|
|
*/ |
268
|
|
|
|
|
|
|
extern int git_fs_path_prettify(git_str *path_out, const char *path, const char *base); |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
/** |
271
|
|
|
|
|
|
|
* Clean up path, prepending base if it is not already rooted and |
272
|
|
|
|
|
|
|
* appending a slash. |
273
|
|
|
|
|
|
|
*/ |
274
|
|
|
|
|
|
|
extern int git_fs_path_prettify_dir(git_str *path_out, const char *path, const char *base); |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
/** |
277
|
|
|
|
|
|
|
* Get a directory from a path. |
278
|
|
|
|
|
|
|
* |
279
|
|
|
|
|
|
|
* If path is a directory, this acts like `git_fs_path_prettify_dir` |
280
|
|
|
|
|
|
|
* (cleaning up path and appending a '/'). If path is a normal file, |
281
|
|
|
|
|
|
|
* this prettifies it, then removed the filename a la dirname and |
282
|
|
|
|
|
|
|
* appends the trailing '/'. If the path does not exist, it is |
283
|
|
|
|
|
|
|
* treated like a regular filename. |
284
|
|
|
|
|
|
|
*/ |
285
|
|
|
|
|
|
|
extern int git_fs_path_find_dir(git_str *dir); |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
/** |
288
|
|
|
|
|
|
|
* Resolve relative references within a path. |
289
|
|
|
|
|
|
|
* |
290
|
|
|
|
|
|
|
* This eliminates "./" and "../" relative references inside a path, |
291
|
|
|
|
|
|
|
* as well as condensing multiple slashes into single ones. It will |
292
|
|
|
|
|
|
|
* not touch the path before the "ceiling" length. |
293
|
|
|
|
|
|
|
* |
294
|
|
|
|
|
|
|
* Additionally, this will recognize an "c:/" drive prefix or a "xyz://" URL |
295
|
|
|
|
|
|
|
* prefix and not touch that part of the path. |
296
|
|
|
|
|
|
|
*/ |
297
|
|
|
|
|
|
|
extern int git_fs_path_resolve_relative(git_str *path, size_t ceiling); |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
/** |
300
|
|
|
|
|
|
|
* Apply a relative path to base path. |
301
|
|
|
|
|
|
|
* |
302
|
|
|
|
|
|
|
* Note that the base path could be a filename or a URL and this |
303
|
|
|
|
|
|
|
* should still work. The relative path is walked segment by segment |
304
|
|
|
|
|
|
|
* with three rules: series of slashes will be condensed to a single |
305
|
|
|
|
|
|
|
* slash, "." will be eaten with no change, and ".." will remove a |
306
|
|
|
|
|
|
|
* segment from the base path. |
307
|
|
|
|
|
|
|
*/ |
308
|
|
|
|
|
|
|
extern int git_fs_path_apply_relative(git_str *target, const char *relpath); |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
enum { |
311
|
|
|
|
|
|
|
GIT_FS_PATH_DIR_IGNORE_CASE = (1u << 0), |
312
|
|
|
|
|
|
|
GIT_FS_PATH_DIR_PRECOMPOSE_UNICODE = (1u << 1), |
313
|
|
|
|
|
|
|
GIT_FS_PATH_DIR_INCLUDE_DOT_AND_DOTDOT = (1u << 2), |
314
|
|
|
|
|
|
|
}; |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
/** |
317
|
|
|
|
|
|
|
* Walk each directory entry, except '.' and '..', calling fn(state). |
318
|
|
|
|
|
|
|
* |
319
|
|
|
|
|
|
|
* @param pathbuf Buffer the function reads the initial directory |
320
|
|
|
|
|
|
|
* path from, and updates with each successive entry's name. |
321
|
|
|
|
|
|
|
* @param flags Combination of GIT_FS_PATH_DIR flags. |
322
|
|
|
|
|
|
|
* @param callback Callback for each entry. Passed the `payload` and each |
323
|
|
|
|
|
|
|
* successive path inside the directory as a full path. This may |
324
|
|
|
|
|
|
|
* safely append text to the pathbuf if needed. Return non-zero to |
325
|
|
|
|
|
|
|
* cancel iteration (and return value will be propagated back). |
326
|
|
|
|
|
|
|
* @param payload Passed to callback as first argument. |
327
|
|
|
|
|
|
|
* @return 0 on success or error code from OS error or from callback |
328
|
|
|
|
|
|
|
*/ |
329
|
|
|
|
|
|
|
extern int git_fs_path_direach( |
330
|
|
|
|
|
|
|
git_str *pathbuf, |
331
|
|
|
|
|
|
|
uint32_t flags, |
332
|
|
|
|
|
|
|
int (*callback)(void *payload, git_str *path), |
333
|
|
|
|
|
|
|
void *payload); |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
/** |
336
|
|
|
|
|
|
|
* Sort function to order two paths |
337
|
|
|
|
|
|
|
*/ |
338
|
|
|
|
|
|
|
extern int git_fs_path_cmp( |
339
|
|
|
|
|
|
|
const char *name1, size_t len1, int isdir1, |
340
|
|
|
|
|
|
|
const char *name2, size_t len2, int isdir2, |
341
|
|
|
|
|
|
|
int (*compare)(const char *, const char *, size_t)); |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
/** |
344
|
|
|
|
|
|
|
* Invoke callback up path directory by directory until the ceiling is |
345
|
|
|
|
|
|
|
* reached (inclusive of a final call at the root_path). |
346
|
|
|
|
|
|
|
* |
347
|
|
|
|
|
|
|
* Returning anything other than 0 from the callback function |
348
|
|
|
|
|
|
|
* will stop the iteration and propagate the error to the caller. |
349
|
|
|
|
|
|
|
* |
350
|
|
|
|
|
|
|
* @param pathbuf Buffer the function reads the directory from and |
351
|
|
|
|
|
|
|
* and updates with each successive name. |
352
|
|
|
|
|
|
|
* @param ceiling Prefix of path at which to stop walking up. If NULL, |
353
|
|
|
|
|
|
|
* this will walk all the way up to the root. If not a prefix of |
354
|
|
|
|
|
|
|
* pathbuf, the callback will be invoked a single time on the |
355
|
|
|
|
|
|
|
* original input path. |
356
|
|
|
|
|
|
|
* @param callback Function to invoke on each path. Passed the `payload` |
357
|
|
|
|
|
|
|
* and the buffer containing the current path. The path should not |
358
|
|
|
|
|
|
|
* be modified in any way. Return non-zero to stop iteration. |
359
|
|
|
|
|
|
|
* @param payload Passed to fn as the first ath. |
360
|
|
|
|
|
|
|
*/ |
361
|
|
|
|
|
|
|
extern int git_fs_path_walk_up( |
362
|
|
|
|
|
|
|
git_str *pathbuf, |
363
|
|
|
|
|
|
|
const char *ceiling, |
364
|
|
|
|
|
|
|
int (*callback)(void *payload, const char *path), |
365
|
|
|
|
|
|
|
void *payload); |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
enum { |
369
|
|
|
|
|
|
|
GIT_FS_PATH_NOTEQUAL = 0, |
370
|
|
|
|
|
|
|
GIT_FS_PATH_EQUAL = 1, |
371
|
|
|
|
|
|
|
GIT_FS_PATH_PREFIX = 2 |
372
|
|
|
|
|
|
|
}; |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
/* |
375
|
|
|
|
|
|
|
* Determines if a path is equal to or potentially a child of another. |
376
|
|
|
|
|
|
|
* @param parent The possible parent |
377
|
|
|
|
|
|
|
* @param child The possible child |
378
|
|
|
|
|
|
|
*/ |
379
|
51
|
|
|
|
|
|
GIT_INLINE(int) git_fs_path_equal_or_prefixed( |
380
|
|
|
|
|
|
|
const char *parent, |
381
|
|
|
|
|
|
|
const char *child, |
382
|
|
|
|
|
|
|
ssize_t *prefixlen) |
383
|
|
|
|
|
|
|
{ |
384
|
51
|
|
|
|
|
|
const char *p = parent, *c = child; |
385
|
51
|
|
|
|
|
|
int lastslash = 0; |
386
|
|
|
|
|
|
|
|
387
|
2409
|
100
|
|
|
|
|
while (*p && *c) { |
|
|
50
|
|
|
|
|
|
388
|
2358
|
|
|
|
|
|
lastslash = (*p == '/'); |
389
|
|
|
|
|
|
|
|
390
|
2358
|
50
|
|
|
|
|
if (*p++ != *c++) |
391
|
0
|
|
|
|
|
|
return GIT_FS_PATH_NOTEQUAL; |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
|
394
|
51
|
50
|
|
|
|
|
if (*p != '\0') |
395
|
0
|
|
|
|
|
|
return GIT_FS_PATH_NOTEQUAL; |
396
|
|
|
|
|
|
|
|
397
|
51
|
50
|
|
|
|
|
if (*c == '\0') { |
398
|
0
|
0
|
|
|
|
|
if (prefixlen) |
399
|
0
|
|
|
|
|
|
*prefixlen = p - parent; |
400
|
|
|
|
|
|
|
|
401
|
0
|
|
|
|
|
|
return GIT_FS_PATH_EQUAL; |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
51
|
50
|
|
|
|
|
if (*c == '/' || lastslash) { |
|
|
50
|
|
|
|
|
|
405
|
51
|
50
|
|
|
|
|
if (prefixlen) |
406
|
51
|
|
|
|
|
|
*prefixlen = (p - parent) - lastslash; |
407
|
|
|
|
|
|
|
|
408
|
51
|
|
|
|
|
|
return GIT_FS_PATH_PREFIX; |
409
|
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
|
411
|
0
|
|
|
|
|
|
return GIT_FS_PATH_NOTEQUAL; |
412
|
|
|
|
|
|
|
} |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
/* translate errno to libgit2 error code and set error message */ |
415
|
|
|
|
|
|
|
extern int git_fs_path_set_error( |
416
|
|
|
|
|
|
|
int errno_value, const char *path, const char *action); |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
/* check if non-ascii characters are present in filename */ |
419
|
|
|
|
|
|
|
extern bool git_fs_path_has_non_ascii(const char *path, size_t pathlen); |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
#define GIT_PATH_REPO_ENCODING "UTF-8" |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
#ifdef __APPLE__ |
424
|
|
|
|
|
|
|
#define GIT_PATH_NATIVE_ENCODING "UTF-8-MAC" |
425
|
|
|
|
|
|
|
#else |
426
|
|
|
|
|
|
|
#define GIT_PATH_NATIVE_ENCODING "UTF-8" |
427
|
|
|
|
|
|
|
#endif |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
#ifdef GIT_USE_ICONV |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
#include |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
typedef struct { |
434
|
|
|
|
|
|
|
iconv_t map; |
435
|
|
|
|
|
|
|
git_str buf; |
436
|
|
|
|
|
|
|
} git_fs_path_iconv_t; |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
#define GIT_PATH_ICONV_INIT { (iconv_t)-1, GIT_STR_INIT } |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
/* Init iconv data for converting decomposed UTF-8 to precomposed */ |
441
|
|
|
|
|
|
|
extern int git_fs_path_iconv_init_precompose(git_fs_path_iconv_t *ic); |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
/* Clear allocated iconv data */ |
444
|
|
|
|
|
|
|
extern void git_fs_path_iconv_clear(git_fs_path_iconv_t *ic); |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
/* |
447
|
|
|
|
|
|
|
* Rewrite `in` buffer using iconv map if necessary, replacing `in` |
448
|
|
|
|
|
|
|
* pointer internal iconv buffer if rewrite happened. The `in` pointer |
449
|
|
|
|
|
|
|
* will be left unchanged if no rewrite was needed. |
450
|
|
|
|
|
|
|
*/ |
451
|
|
|
|
|
|
|
extern int git_fs_path_iconv(git_fs_path_iconv_t *ic, const char **in, size_t *inlen); |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
#endif /* GIT_USE_ICONV */ |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
extern bool git_fs_path_does_decompose_unicode(const char *root); |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
typedef struct git_fs_path_diriter git_fs_path_diriter; |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
#if defined(GIT_WIN32) && !defined(__MINGW32__) |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
struct git_fs_path_diriter |
463
|
|
|
|
|
|
|
{ |
464
|
|
|
|
|
|
|
git_win32_path path; |
465
|
|
|
|
|
|
|
size_t parent_len; |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
git_str path_utf8; |
468
|
|
|
|
|
|
|
size_t parent_utf8_len; |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
HANDLE handle; |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
unsigned int flags; |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
WIN32_FIND_DATAW current; |
475
|
|
|
|
|
|
|
unsigned int needs_next; |
476
|
|
|
|
|
|
|
}; |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
#define GIT_FS_PATH_DIRITER_INIT { {0}, 0, GIT_STR_INIT, 0, INVALID_HANDLE_VALUE } |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
#else |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
struct git_fs_path_diriter |
483
|
|
|
|
|
|
|
{ |
484
|
|
|
|
|
|
|
git_str path; |
485
|
|
|
|
|
|
|
size_t parent_len; |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
unsigned int flags; |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
DIR *dir; |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
#ifdef GIT_USE_ICONV |
492
|
|
|
|
|
|
|
git_fs_path_iconv_t ic; |
493
|
|
|
|
|
|
|
#endif |
494
|
|
|
|
|
|
|
}; |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
#define GIT_FS_PATH_DIRITER_INIT { GIT_STR_INIT } |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
#endif |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
/** |
501
|
|
|
|
|
|
|
* Initialize a directory iterator. |
502
|
|
|
|
|
|
|
* |
503
|
|
|
|
|
|
|
* @param diriter Pointer to a diriter structure that will be setup. |
504
|
|
|
|
|
|
|
* @param path The path that will be iterated over |
505
|
|
|
|
|
|
|
* @param flags Directory reader flags |
506
|
|
|
|
|
|
|
* @return 0 or an error code |
507
|
|
|
|
|
|
|
*/ |
508
|
|
|
|
|
|
|
extern int git_fs_path_diriter_init( |
509
|
|
|
|
|
|
|
git_fs_path_diriter *diriter, |
510
|
|
|
|
|
|
|
const char *path, |
511
|
|
|
|
|
|
|
unsigned int flags); |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
/** |
514
|
|
|
|
|
|
|
* Advance the directory iterator. Will return GIT_ITEROVER when |
515
|
|
|
|
|
|
|
* the iteration has completed successfully. |
516
|
|
|
|
|
|
|
* |
517
|
|
|
|
|
|
|
* @param diriter The directory iterator |
518
|
|
|
|
|
|
|
* @return 0, GIT_ITEROVER, or an error code |
519
|
|
|
|
|
|
|
*/ |
520
|
|
|
|
|
|
|
extern int git_fs_path_diriter_next(git_fs_path_diriter *diriter); |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
/** |
523
|
|
|
|
|
|
|
* Returns the file name of the current item in the iterator. |
524
|
|
|
|
|
|
|
* |
525
|
|
|
|
|
|
|
* @param out Pointer to store the path in |
526
|
|
|
|
|
|
|
* @param out_len Pointer to store the length of the path in |
527
|
|
|
|
|
|
|
* @param diriter The directory iterator |
528
|
|
|
|
|
|
|
* @return 0 or an error code |
529
|
|
|
|
|
|
|
*/ |
530
|
|
|
|
|
|
|
extern int git_fs_path_diriter_filename( |
531
|
|
|
|
|
|
|
const char **out, |
532
|
|
|
|
|
|
|
size_t *out_len, |
533
|
|
|
|
|
|
|
git_fs_path_diriter *diriter); |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
/** |
536
|
|
|
|
|
|
|
* Returns the full path of the current item in the iterator; that |
537
|
|
|
|
|
|
|
* is the current filename plus the path of the directory that the |
538
|
|
|
|
|
|
|
* iterator was constructed with. |
539
|
|
|
|
|
|
|
* |
540
|
|
|
|
|
|
|
* @param out Pointer to store the path in |
541
|
|
|
|
|
|
|
* @param out_len Pointer to store the length of the path in |
542
|
|
|
|
|
|
|
* @param diriter The directory iterator |
543
|
|
|
|
|
|
|
* @return 0 or an error code |
544
|
|
|
|
|
|
|
*/ |
545
|
|
|
|
|
|
|
extern int git_fs_path_diriter_fullpath( |
546
|
|
|
|
|
|
|
const char **out, |
547
|
|
|
|
|
|
|
size_t *out_len, |
548
|
|
|
|
|
|
|
git_fs_path_diriter *diriter); |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
/** |
551
|
|
|
|
|
|
|
* Performs an `lstat` on the current item in the iterator. |
552
|
|
|
|
|
|
|
* |
553
|
|
|
|
|
|
|
* @param out Pointer to store the stat data in |
554
|
|
|
|
|
|
|
* @param diriter The directory iterator |
555
|
|
|
|
|
|
|
* @return 0 or an error code |
556
|
|
|
|
|
|
|
*/ |
557
|
|
|
|
|
|
|
extern int git_fs_path_diriter_stat(struct stat *out, git_fs_path_diriter *diriter); |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
/** |
560
|
|
|
|
|
|
|
* Closes the directory iterator. |
561
|
|
|
|
|
|
|
* |
562
|
|
|
|
|
|
|
* @param diriter The directory iterator |
563
|
|
|
|
|
|
|
*/ |
564
|
|
|
|
|
|
|
extern void git_fs_path_diriter_free(git_fs_path_diriter *diriter); |
565
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
/** |
567
|
|
|
|
|
|
|
* Load all directory entries (except '.' and '..') into a vector. |
568
|
|
|
|
|
|
|
* |
569
|
|
|
|
|
|
|
* For cases where `git_fs_path_direach()` is not appropriate, this |
570
|
|
|
|
|
|
|
* allows you to load the filenames in a directory into a vector |
571
|
|
|
|
|
|
|
* of strings. That vector can then be sorted, iterated, or whatever. |
572
|
|
|
|
|
|
|
* Remember to free alloc of the allocated strings when you are done. |
573
|
|
|
|
|
|
|
* |
574
|
|
|
|
|
|
|
* @param contents Vector to fill with directory entry names. |
575
|
|
|
|
|
|
|
* @param path The directory to read from. |
576
|
|
|
|
|
|
|
* @param prefix_len When inserting entries, the trailing part of path |
577
|
|
|
|
|
|
|
* will be prefixed after this length. I.e. given path "/a/b" and |
578
|
|
|
|
|
|
|
* prefix_len 3, the entries will look like "b/e1", "b/e2", etc. |
579
|
|
|
|
|
|
|
* @param flags Combination of GIT_FS_PATH_DIR flags. |
580
|
|
|
|
|
|
|
*/ |
581
|
|
|
|
|
|
|
extern int git_fs_path_dirload( |
582
|
|
|
|
|
|
|
git_vector *contents, |
583
|
|
|
|
|
|
|
const char *path, |
584
|
|
|
|
|
|
|
size_t prefix_len, |
585
|
|
|
|
|
|
|
uint32_t flags); |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
/* Used for paths to repositories on the filesystem */ |
589
|
|
|
|
|
|
|
extern bool git_fs_path_is_local_file_url(const char *file_url); |
590
|
|
|
|
|
|
|
extern int git_fs_path_from_url_or_path(git_str *local_path_out, const char *url_or_path); |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
/* Flags to determine path validity in `git_fs_path_isvalid` */ |
593
|
|
|
|
|
|
|
#define GIT_FS_PATH_REJECT_EMPTY_COMPONENT (1 << 0) |
594
|
|
|
|
|
|
|
#define GIT_FS_PATH_REJECT_TRAVERSAL (1 << 1) |
595
|
|
|
|
|
|
|
#define GIT_FS_PATH_REJECT_SLASH (1 << 2) |
596
|
|
|
|
|
|
|
#define GIT_FS_PATH_REJECT_BACKSLASH (1 << 3) |
597
|
|
|
|
|
|
|
#define GIT_FS_PATH_REJECT_TRAILING_DOT (1 << 4) |
598
|
|
|
|
|
|
|
#define GIT_FS_PATH_REJECT_TRAILING_SPACE (1 << 5) |
599
|
|
|
|
|
|
|
#define GIT_FS_PATH_REJECT_TRAILING_COLON (1 << 6) |
600
|
|
|
|
|
|
|
#define GIT_FS_PATH_REJECT_DOS_PATHS (1 << 7) |
601
|
|
|
|
|
|
|
#define GIT_FS_PATH_REJECT_NT_CHARS (1 << 8) |
602
|
|
|
|
|
|
|
#define GIT_FS_PATH_REJECT_LONG_PATHS (1 << 9) |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
#define GIT_FS_PATH_REJECT_MAX (1 << 9) |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
/* Default path safety for writing files to disk: since we use the |
607
|
|
|
|
|
|
|
* Win32 "File Namespace" APIs ("\\?\") we need to protect from |
608
|
|
|
|
|
|
|
* paths that the normal Win32 APIs would not write. |
609
|
|
|
|
|
|
|
*/ |
610
|
|
|
|
|
|
|
#ifdef GIT_WIN32 |
611
|
|
|
|
|
|
|
# define GIT_FS_PATH_REJECT_FILESYSTEM_DEFAULTS \ |
612
|
|
|
|
|
|
|
GIT_FS_PATH_REJECT_EMPTY_COMPONENT | \ |
613
|
|
|
|
|
|
|
GIT_FS_PATH_REJECT_TRAVERSAL | \ |
614
|
|
|
|
|
|
|
GIT_FS_PATH_REJECT_BACKSLASH | \ |
615
|
|
|
|
|
|
|
GIT_FS_PATH_REJECT_TRAILING_DOT | \ |
616
|
|
|
|
|
|
|
GIT_FS_PATH_REJECT_TRAILING_SPACE | \ |
617
|
|
|
|
|
|
|
GIT_FS_PATH_REJECT_TRAILING_COLON | \ |
618
|
|
|
|
|
|
|
GIT_FS_PATH_REJECT_DOS_PATHS | \ |
619
|
|
|
|
|
|
|
GIT_FS_PATH_REJECT_NT_CHARS |
620
|
|
|
|
|
|
|
#else |
621
|
|
|
|
|
|
|
# define GIT_FS_PATH_REJECT_FILESYSTEM_DEFAULTS \ |
622
|
|
|
|
|
|
|
GIT_FS_PATH_REJECT_EMPTY_COMPONENT | \ |
623
|
|
|
|
|
|
|
GIT_FS_PATH_REJECT_TRAVERSAL |
624
|
|
|
|
|
|
|
#endif |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
/** |
627
|
|
|
|
|
|
|
* Validate a filesystem path; with custom callbacks per-character and |
628
|
|
|
|
|
|
|
* per-path component. |
629
|
|
|
|
|
|
|
*/ |
630
|
|
|
|
|
|
|
extern bool git_fs_path_str_is_valid_ext( |
631
|
|
|
|
|
|
|
const git_str *path, |
632
|
|
|
|
|
|
|
unsigned int flags, |
633
|
|
|
|
|
|
|
bool (*validate_char_cb)(char ch, void *payload), |
634
|
|
|
|
|
|
|
bool (*validate_component_cb)(const char *component, size_t len, void *payload), |
635
|
|
|
|
|
|
|
bool (*validate_length_cb)(const char *component, size_t len, size_t utf8_char_len), |
636
|
|
|
|
|
|
|
void *payload); |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
GIT_INLINE(bool) git_fs_path_is_valid_ext( |
639
|
|
|
|
|
|
|
const char *path, |
640
|
|
|
|
|
|
|
unsigned int flags, |
641
|
|
|
|
|
|
|
bool (*validate_char_cb)(char ch, void *payload), |
642
|
|
|
|
|
|
|
bool (*validate_component_cb)(const char *component, size_t len, void *payload), |
643
|
|
|
|
|
|
|
bool (*validate_length_cb)(const char *component, size_t len, size_t utf8_char_len), |
644
|
|
|
|
|
|
|
void *payload) |
645
|
|
|
|
|
|
|
{ |
646
|
|
|
|
|
|
|
const git_str str = GIT_STR_INIT_CONST(path, SIZE_MAX); |
647
|
|
|
|
|
|
|
return git_fs_path_str_is_valid_ext( |
648
|
|
|
|
|
|
|
&str, |
649
|
|
|
|
|
|
|
flags, |
650
|
|
|
|
|
|
|
validate_char_cb, |
651
|
|
|
|
|
|
|
validate_component_cb, |
652
|
|
|
|
|
|
|
validate_length_cb, |
653
|
|
|
|
|
|
|
payload); |
654
|
|
|
|
|
|
|
} |
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
/** |
657
|
|
|
|
|
|
|
* Validate a filesystem path. This ensures that the given path is legal |
658
|
|
|
|
|
|
|
* and does not contain any "unsafe" components like path traversal ('.' |
659
|
|
|
|
|
|
|
* or '..'), characters that are inappropriate for lesser filesystems |
660
|
|
|
|
|
|
|
* (trailing ' ' or ':' characters), or filenames ("component names") |
661
|
|
|
|
|
|
|
* that are not supported ('AUX', 'COM1"). |
662
|
|
|
|
|
|
|
*/ |
663
|
|
|
|
|
|
|
GIT_INLINE(bool) git_fs_path_is_valid( |
664
|
|
|
|
|
|
|
const char *path, |
665
|
|
|
|
|
|
|
unsigned int flags) |
666
|
|
|
|
|
|
|
{ |
667
|
|
|
|
|
|
|
const git_str str = GIT_STR_INIT_CONST(path, SIZE_MAX); |
668
|
|
|
|
|
|
|
return git_fs_path_str_is_valid_ext(&str, flags, NULL, NULL, NULL, NULL); |
669
|
|
|
|
|
|
|
} |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
/** Validate a filesystem path in a `git_str`. */ |
672
|
|
|
|
|
|
|
GIT_INLINE(bool) git_fs_path_str_is_valid( |
673
|
|
|
|
|
|
|
const git_str *path, |
674
|
|
|
|
|
|
|
unsigned int flags) |
675
|
|
|
|
|
|
|
{ |
676
|
|
|
|
|
|
|
return git_fs_path_str_is_valid_ext(path, flags, NULL, NULL, NULL, NULL); |
677
|
|
|
|
|
|
|
} |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
extern int git_fs_path_validate_str_length_with_suffix( |
680
|
|
|
|
|
|
|
git_str *path, |
681
|
|
|
|
|
|
|
size_t suffix_len); |
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
/** |
684
|
|
|
|
|
|
|
* Validate an on-disk path, taking into account that it will have a |
685
|
|
|
|
|
|
|
* suffix appended (eg, `.lock`). |
686
|
|
|
|
|
|
|
*/ |
687
|
|
|
|
|
|
|
GIT_INLINE(int) git_fs_path_validate_filesystem_with_suffix( |
688
|
|
|
|
|
|
|
const char *path, |
689
|
|
|
|
|
|
|
size_t path_len, |
690
|
|
|
|
|
|
|
size_t suffix_len) |
691
|
|
|
|
|
|
|
{ |
692
|
|
|
|
|
|
|
#ifdef GIT_WIN32 |
693
|
|
|
|
|
|
|
size_t path_chars, total_chars; |
694
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
path_chars = git_utf8_char_length(path, path_len); |
696
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
if (GIT_ADD_SIZET_OVERFLOW(&total_chars, path_chars, suffix_len) || |
698
|
|
|
|
|
|
|
total_chars > MAX_PATH) { |
699
|
|
|
|
|
|
|
git_error_set(GIT_ERROR_FILESYSTEM, "path too long: '%s'", path); |
700
|
|
|
|
|
|
|
return -1; |
701
|
|
|
|
|
|
|
} |
702
|
|
|
|
|
|
|
return 0; |
703
|
|
|
|
|
|
|
#else |
704
|
|
|
|
|
|
|
GIT_UNUSED(path); |
705
|
|
|
|
|
|
|
GIT_UNUSED(path_len); |
706
|
|
|
|
|
|
|
GIT_UNUSED(suffix_len); |
707
|
|
|
|
|
|
|
return 0; |
708
|
|
|
|
|
|
|
#endif |
709
|
|
|
|
|
|
|
} |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
/** |
712
|
|
|
|
|
|
|
* Validate an path on the filesystem. This ensures that the given |
713
|
|
|
|
|
|
|
* path is valid for the operating system/platform; for example, this |
714
|
|
|
|
|
|
|
* will ensure that the given absolute path is smaller than MAX_PATH on |
715
|
|
|
|
|
|
|
* Windows. |
716
|
|
|
|
|
|
|
* |
717
|
|
|
|
|
|
|
* For paths within the working directory, you should use ensure that |
718
|
|
|
|
|
|
|
* `core.longpaths` is obeyed. Use `git_fs_path_validate_workdir`. |
719
|
|
|
|
|
|
|
*/ |
720
|
|
|
|
|
|
|
GIT_INLINE(int) git_fs_path_validate_filesystem( |
721
|
|
|
|
|
|
|
const char *path, |
722
|
|
|
|
|
|
|
size_t path_len) |
723
|
|
|
|
|
|
|
{ |
724
|
|
|
|
|
|
|
return git_fs_path_validate_filesystem_with_suffix(path, path_len, 0); |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
/** |
728
|
|
|
|
|
|
|
* Convert any backslashes into slashes |
729
|
|
|
|
|
|
|
*/ |
730
|
|
|
|
|
|
|
int git_fs_path_normalize_slashes(git_str *out, const char *path); |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
bool git_fs_path_supports_symlinks(const char *dir); |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
typedef enum { |
735
|
|
|
|
|
|
|
GIT_FS_PATH_OWNER_NONE = 0, |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
/** The file must be owned by the current user. */ |
738
|
|
|
|
|
|
|
GIT_FS_PATH_OWNER_CURRENT_USER = (1 << 0), |
739
|
|
|
|
|
|
|
|
740
|
|
|
|
|
|
|
/** The file must be owned by the system account. */ |
741
|
|
|
|
|
|
|
GIT_FS_PATH_OWNER_ADMINISTRATOR = (1 << 1), |
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
/** |
744
|
|
|
|
|
|
|
* The file may be owned by a system account if the current |
745
|
|
|
|
|
|
|
* user is in an administrator group. Windows only; this is |
746
|
|
|
|
|
|
|
* a noop on non-Windows systems. |
747
|
|
|
|
|
|
|
*/ |
748
|
|
|
|
|
|
|
GIT_FS_PATH_USER_IS_ADMINISTRATOR = (1 << 2), |
749
|
|
|
|
|
|
|
|
750
|
|
|
|
|
|
|
/** |
751
|
|
|
|
|
|
|
* The file is owned by the current user, who is running `sudo`. |
752
|
|
|
|
|
|
|
*/ |
753
|
|
|
|
|
|
|
GIT_FS_PATH_OWNER_RUNNING_SUDO = (1 << 3), |
754
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
/** The file may be owned by another user. */ |
756
|
|
|
|
|
|
|
GIT_FS_PATH_OWNER_OTHER = (1 << 4) |
757
|
|
|
|
|
|
|
} git_fs_path_owner_t; |
758
|
|
|
|
|
|
|
|
759
|
|
|
|
|
|
|
/** |
760
|
|
|
|
|
|
|
* Sets the mock ownership for files; subsequent calls to |
761
|
|
|
|
|
|
|
* `git_fs_path_owner_is_*` functions will return this data until |
762
|
|
|
|
|
|
|
* cleared with `GIT_FS_PATH_OWNER_NONE`. |
763
|
|
|
|
|
|
|
*/ |
764
|
|
|
|
|
|
|
void git_fs_path__set_owner(git_fs_path_owner_t owner); |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
/** Verify that the file in question is owned by the given owner. */ |
767
|
|
|
|
|
|
|
int git_fs_path_owner_is( |
768
|
|
|
|
|
|
|
bool *out, |
769
|
|
|
|
|
|
|
const char *path, |
770
|
|
|
|
|
|
|
git_fs_path_owner_t owner_type); |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
/** |
773
|
|
|
|
|
|
|
* Verify that the file in question is owned by an administrator or system |
774
|
|
|
|
|
|
|
* account. |
775
|
|
|
|
|
|
|
*/ |
776
|
|
|
|
|
|
|
int git_fs_path_owner_is_system(bool *out, const char *path); |
777
|
|
|
|
|
|
|
|
778
|
|
|
|
|
|
|
/** |
779
|
|
|
|
|
|
|
* Verify that the file in question is owned by the current user; |
780
|
|
|
|
|
|
|
*/ |
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
int git_fs_path_owner_is_current_user(bool *out, const char *path); |
783
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
/** |
785
|
|
|
|
|
|
|
* Search the current PATH for the given executable, returning the full |
786
|
|
|
|
|
|
|
* path if it is found. |
787
|
|
|
|
|
|
|
*/ |
788
|
|
|
|
|
|
|
int git_fs_path_find_executable(git_str *fullpath, const char *executable); |
789
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
#endif |