rugged 0.23.3 → 0.24.0b0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +1 -1
- data/ext/rugged/rugged.c +24 -0
- data/ext/rugged/rugged_config.c +65 -0
- data/ext/rugged/rugged_remote.c +22 -2
- data/ext/rugged/rugged_repo.c +10 -5
- data/ext/rugged/rugged_tree.c +4 -1
- data/lib/rugged/version.rb +1 -1
- data/vendor/libgit2/CMakeLists.txt +47 -2
- data/vendor/libgit2/include/git2/config.h +18 -0
- data/vendor/libgit2/include/git2/diff.h +25 -2
- data/vendor/libgit2/include/git2/errors.h +0 -12
- data/vendor/libgit2/include/git2/index.h +11 -0
- data/vendor/libgit2/include/git2/remote.h +12 -1
- data/vendor/libgit2/include/git2/sys/config.h +14 -0
- data/vendor/libgit2/include/git2/sys/filter.h +4 -1
- data/vendor/libgit2/include/git2/sys/odb_backend.h +4 -0
- data/vendor/libgit2/include/git2/sys/refdb_backend.h +5 -4
- data/vendor/libgit2/include/git2/sys/transport.h +27 -0
- data/vendor/libgit2/include/git2/transport.h +25 -21
- data/vendor/libgit2/include/git2/version.h +2 -2
- data/vendor/libgit2/libgit2.pc.in +3 -2
- data/vendor/libgit2/src/branch.c +1 -12
- data/vendor/libgit2/src/checkout.c +29 -20
- data/vendor/libgit2/src/clone.c +2 -2
- data/vendor/libgit2/src/common.h +13 -4
- data/vendor/libgit2/src/config.c +36 -0
- data/vendor/libgit2/src/config.h +15 -0
- data/vendor/libgit2/src/config_file.c +124 -20
- data/vendor/libgit2/src/config_file.h +10 -0
- data/vendor/libgit2/src/curl_stream.c +7 -7
- data/vendor/libgit2/src/diff.c +89 -27
- data/vendor/libgit2/src/diff_print.c +1 -1
- data/vendor/libgit2/src/errors.c +75 -40
- data/vendor/libgit2/src/filebuf.c +81 -3
- data/vendor/libgit2/src/fileops.c +176 -75
- data/vendor/libgit2/src/fileops.h +7 -10
- data/vendor/libgit2/src/filter.c +5 -2
- data/vendor/libgit2/src/global.c +25 -9
- data/vendor/libgit2/src/global.h +1 -0
- data/vendor/libgit2/src/idxmap.h +92 -0
- data/vendor/libgit2/src/ignore.c +9 -7
- data/vendor/libgit2/src/index.c +246 -46
- data/vendor/libgit2/src/index.h +2 -0
- data/vendor/libgit2/src/iterator.c +377 -118
- data/vendor/libgit2/src/iterator.h +28 -20
- data/vendor/libgit2/src/merge.c +26 -13
- data/vendor/libgit2/src/notes.c +1 -1
- data/vendor/libgit2/src/odb.c +1 -2
- data/vendor/libgit2/src/odb_loose.c +2 -2
- data/vendor/libgit2/src/odb_mempack.c +6 -2
- data/vendor/libgit2/src/oidmap.h +2 -0
- data/vendor/libgit2/src/openssl_stream.c +9 -3
- data/vendor/libgit2/src/path.c +37 -2
- data/vendor/libgit2/src/path.h +12 -1
- data/vendor/libgit2/src/pathspec.c +12 -12
- data/vendor/libgit2/src/push.c +2 -1
- data/vendor/libgit2/src/push.h +1 -0
- data/vendor/libgit2/src/refdb.c +2 -6
- data/vendor/libgit2/src/refdb_fs.c +13 -3
- data/vendor/libgit2/src/remote.c +44 -15
- data/vendor/libgit2/src/repository.c +28 -12
- data/vendor/libgit2/src/stash.c +17 -12
- data/vendor/libgit2/src/stransport_stream.c +1 -1
- data/vendor/libgit2/src/submodule.c +234 -152
- data/vendor/libgit2/src/sysdir.c +22 -8
- data/vendor/libgit2/src/transaction.c +41 -0
- data/vendor/libgit2/src/transaction.h +14 -0
- data/vendor/libgit2/src/transports/cred.c +8 -0
- data/vendor/libgit2/src/transports/http.c +6 -0
- data/vendor/libgit2/src/transports/smart.c +95 -0
- data/vendor/libgit2/src/transports/smart.h +1 -0
- data/vendor/libgit2/src/transports/smart_pkt.c +9 -2
- data/vendor/libgit2/src/transports/ssh.c +5 -3
- data/vendor/libgit2/src/transports/winhttp.c +19 -1
- data/vendor/libgit2/src/unix/posix.h +14 -1
- data/vendor/libgit2/src/util.c +56 -13
- data/vendor/libgit2/src/util.h +13 -5
- data/vendor/libgit2/src/win32/path_w32.c +15 -8
- data/vendor/libgit2/src/win32/posix_w32.c +11 -2
- data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.c +343 -0
- data/vendor/libgit2/src/win32/w32_crtdbg_stacktrace.h +93 -0
- data/vendor/libgit2/src/win32/w32_stack.c +192 -0
- data/vendor/libgit2/src/win32/w32_stack.h +138 -0
- data/vendor/libgit2/src/win32/w32_util.c +29 -5
- data/vendor/libgit2/src/win32/w32_util.h +13 -3
- metadata +11 -5
@@ -358,6 +358,7 @@ static int format_binary(
|
|
358
358
|
scan += chunk_len;
|
359
359
|
pi->line.num_lines++;
|
360
360
|
}
|
361
|
+
git_buf_putc(pi->buf, '\n');
|
361
362
|
|
362
363
|
return 0;
|
363
364
|
}
|
@@ -416,7 +417,6 @@ static int diff_print_patch_file_binary(
|
|
416
417
|
|
417
418
|
if ((error = format_binary(pi, binary->new_file.type, binary->new_file.data,
|
418
419
|
binary->new_file.datalen, binary->new_file.inflatedlen)) < 0 ||
|
419
|
-
(error = git_buf_putc(pi->buf, '\n')) < 0 ||
|
420
420
|
(error = format_binary(pi, binary->old_file.type, binary->old_file.data,
|
421
421
|
binary->old_file.datalen, binary->old_file.inflatedlen)) < 0) {
|
422
422
|
|
data/vendor/libgit2/src/errors.c
CHANGED
@@ -18,19 +18,30 @@ static git_error g_git_oom_error = {
|
|
18
18
|
GITERR_NOMEMORY
|
19
19
|
};
|
20
20
|
|
21
|
-
static void
|
21
|
+
static void set_error_from_buffer(int error_class)
|
22
22
|
{
|
23
23
|
git_error *error = &GIT_GLOBAL->error_t;
|
24
|
+
git_buf *buf = &GIT_GLOBAL->error_buf;
|
24
25
|
|
25
|
-
|
26
|
-
git__free(error->message);
|
27
|
-
|
28
|
-
error->message = string;
|
26
|
+
error->message = buf->ptr;
|
29
27
|
error->klass = error_class;
|
30
28
|
|
31
29
|
GIT_GLOBAL->last_error = error;
|
32
30
|
}
|
33
31
|
|
32
|
+
static void set_error(int error_class, char *string)
|
33
|
+
{
|
34
|
+
git_buf *buf = &GIT_GLOBAL->error_buf;
|
35
|
+
|
36
|
+
git_buf_clear(buf);
|
37
|
+
if (string) {
|
38
|
+
git_buf_puts(buf, string);
|
39
|
+
git__free(string);
|
40
|
+
}
|
41
|
+
|
42
|
+
set_error_from_buffer(error_class);
|
43
|
+
}
|
44
|
+
|
34
45
|
void giterr_set_oom(void)
|
35
46
|
{
|
36
47
|
GIT_GLOBAL->last_error = &g_git_oom_error;
|
@@ -38,27 +49,28 @@ void giterr_set_oom(void)
|
|
38
49
|
|
39
50
|
void giterr_set(int error_class, const char *string, ...)
|
40
51
|
{
|
41
|
-
git_buf buf = GIT_BUF_INIT;
|
42
52
|
va_list arglist;
|
43
53
|
#ifdef GIT_WIN32
|
44
54
|
DWORD win32_error_code = (error_class == GITERR_OS) ? GetLastError() : 0;
|
45
55
|
#endif
|
46
56
|
int error_code = (error_class == GITERR_OS) ? errno : 0;
|
57
|
+
git_buf *buf = &GIT_GLOBAL->error_buf;
|
47
58
|
|
59
|
+
git_buf_clear(buf);
|
48
60
|
if (string) {
|
49
61
|
va_start(arglist, string);
|
50
|
-
git_buf_vprintf(
|
62
|
+
git_buf_vprintf(buf, string, arglist);
|
51
63
|
va_end(arglist);
|
52
64
|
|
53
65
|
if (error_class == GITERR_OS)
|
54
|
-
git_buf_PUTS(
|
66
|
+
git_buf_PUTS(buf, ": ");
|
55
67
|
}
|
56
68
|
|
57
69
|
if (error_class == GITERR_OS) {
|
58
70
|
#ifdef GIT_WIN32
|
59
71
|
char * win32_error = git_win32_get_error_message(win32_error_code);
|
60
72
|
if (win32_error) {
|
61
|
-
git_buf_puts(
|
73
|
+
git_buf_puts(buf, win32_error);
|
62
74
|
git__free(win32_error);
|
63
75
|
|
64
76
|
SetLastError(0);
|
@@ -66,26 +78,29 @@ void giterr_set(int error_class, const char *string, ...)
|
|
66
78
|
else
|
67
79
|
#endif
|
68
80
|
if (error_code)
|
69
|
-
git_buf_puts(
|
81
|
+
git_buf_puts(buf, strerror(error_code));
|
70
82
|
|
71
83
|
if (error_code)
|
72
84
|
errno = 0;
|
73
85
|
}
|
74
86
|
|
75
|
-
if (!git_buf_oom(
|
76
|
-
|
87
|
+
if (!git_buf_oom(buf))
|
88
|
+
set_error_from_buffer(error_class);
|
77
89
|
}
|
78
90
|
|
79
91
|
void giterr_set_str(int error_class, const char *string)
|
80
92
|
{
|
81
|
-
|
93
|
+
git_buf *buf = &GIT_GLOBAL->error_buf;
|
82
94
|
|
83
95
|
assert(string);
|
84
96
|
|
85
|
-
|
97
|
+
if (!string)
|
98
|
+
return;
|
86
99
|
|
87
|
-
|
88
|
-
|
100
|
+
git_buf_clear(buf);
|
101
|
+
git_buf_puts(buf, string);
|
102
|
+
if (!git_buf_oom(buf))
|
103
|
+
set_error_from_buffer(error_class);
|
89
104
|
}
|
90
105
|
|
91
106
|
int giterr_set_regex(const regex_t *regex, int error_code)
|
@@ -116,45 +131,65 @@ void giterr_clear(void)
|
|
116
131
|
#endif
|
117
132
|
}
|
118
133
|
|
119
|
-
|
134
|
+
const git_error *giterr_last(void)
|
135
|
+
{
|
136
|
+
return GIT_GLOBAL->last_error;
|
137
|
+
}
|
138
|
+
|
139
|
+
int giterr_state_capture(git_error_state *state, int error_code)
|
120
140
|
{
|
121
141
|
git_error *error = GIT_GLOBAL->last_error;
|
142
|
+
git_buf *error_buf = &GIT_GLOBAL->error_buf;
|
122
143
|
|
123
|
-
|
144
|
+
memset(state, 0, sizeof(git_error_state));
|
124
145
|
|
125
|
-
if (!
|
126
|
-
return
|
146
|
+
if (!error_code)
|
147
|
+
return 0;
|
127
148
|
|
128
|
-
|
129
|
-
|
149
|
+
state->error_code = error_code;
|
150
|
+
state->oom = (error == &g_git_oom_error);
|
130
151
|
|
131
|
-
error
|
132
|
-
|
152
|
+
if (error) {
|
153
|
+
state->error_msg.klass = error->klass;
|
133
154
|
|
134
|
-
|
135
|
-
|
155
|
+
if (state->oom)
|
156
|
+
state->error_msg.message = g_git_oom_error.message;
|
157
|
+
else
|
158
|
+
state->error_msg.message = git_buf_detach(error_buf);
|
159
|
+
}
|
136
160
|
|
137
|
-
|
138
|
-
|
139
|
-
return GIT_GLOBAL->last_error;
|
161
|
+
giterr_clear();
|
162
|
+
return error_code;
|
140
163
|
}
|
141
164
|
|
142
|
-
int
|
165
|
+
int giterr_state_restore(git_error_state *state)
|
143
166
|
{
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
167
|
+
int ret = 0;
|
168
|
+
|
169
|
+
giterr_clear();
|
170
|
+
|
171
|
+
if (state && state->error_msg.message) {
|
172
|
+
if (state->oom)
|
173
|
+
giterr_set_oom();
|
174
|
+
else
|
175
|
+
set_error(state->error_msg.klass, state->error_msg.message);
|
176
|
+
|
177
|
+
ret = state->error_code;
|
178
|
+
memset(state, 0, sizeof(git_error_state));
|
179
|
+
}
|
180
|
+
|
181
|
+
return ret;
|
148
182
|
}
|
149
183
|
|
150
|
-
|
184
|
+
void giterr_state_free(git_error_state *state)
|
151
185
|
{
|
152
|
-
if (state
|
153
|
-
|
154
|
-
|
155
|
-
|
186
|
+
if (!state)
|
187
|
+
return;
|
188
|
+
|
189
|
+
if (!state->oom)
|
190
|
+
git__free(state->error_msg.message);
|
156
191
|
|
157
|
-
|
192
|
+
memset(state, 0, sizeof(git_error_state));
|
158
193
|
}
|
159
194
|
|
160
195
|
int giterr_system_last(void)
|
@@ -191,6 +191,81 @@ static int write_deflate(git_filebuf *file, void *source, size_t len)
|
|
191
191
|
return 0;
|
192
192
|
}
|
193
193
|
|
194
|
+
#define MAX_SYMLINK_DEPTH 5
|
195
|
+
|
196
|
+
static int resolve_symlink(git_buf *out, const char *path)
|
197
|
+
{
|
198
|
+
int i, error, root;
|
199
|
+
ssize_t ret;
|
200
|
+
struct stat st;
|
201
|
+
git_buf curpath = GIT_BUF_INIT, target = GIT_BUF_INIT;
|
202
|
+
|
203
|
+
if ((error = git_buf_grow(&target, GIT_PATH_MAX + 1)) < 0 ||
|
204
|
+
(error = git_buf_puts(&curpath, path)) < 0)
|
205
|
+
return error;
|
206
|
+
|
207
|
+
for (i = 0; i < MAX_SYMLINK_DEPTH; i++) {
|
208
|
+
error = p_lstat(curpath.ptr, &st);
|
209
|
+
if (error < 0 && errno == ENOENT) {
|
210
|
+
error = git_buf_puts(out, curpath.ptr);
|
211
|
+
goto cleanup;
|
212
|
+
}
|
213
|
+
|
214
|
+
if (error < 0) {
|
215
|
+
giterr_set(GITERR_OS, "failed to stat '%s'", curpath.ptr);
|
216
|
+
error = -1;
|
217
|
+
goto cleanup;
|
218
|
+
}
|
219
|
+
|
220
|
+
if (!S_ISLNK(st.st_mode)) {
|
221
|
+
error = git_buf_puts(out, curpath.ptr);
|
222
|
+
goto cleanup;
|
223
|
+
}
|
224
|
+
|
225
|
+
ret = p_readlink(curpath.ptr, target.ptr, GIT_PATH_MAX);
|
226
|
+
if (ret < 0) {
|
227
|
+
giterr_set(GITERR_OS, "failed to read symlink '%s'", curpath.ptr);
|
228
|
+
error = -1;
|
229
|
+
goto cleanup;
|
230
|
+
}
|
231
|
+
|
232
|
+
if (ret == GIT_PATH_MAX) {
|
233
|
+
giterr_set(GITERR_INVALID, "symlink target too long");
|
234
|
+
error = -1;
|
235
|
+
goto cleanup;
|
236
|
+
}
|
237
|
+
|
238
|
+
/* readlink(2) won't NUL-terminate for us */
|
239
|
+
target.ptr[ret] = '\0';
|
240
|
+
target.size = ret;
|
241
|
+
|
242
|
+
root = git_path_root(target.ptr);
|
243
|
+
if (root >= 0) {
|
244
|
+
if ((error = git_buf_puts(&curpath, target.ptr)) < 0)
|
245
|
+
goto cleanup;
|
246
|
+
} else {
|
247
|
+
git_buf dir = GIT_BUF_INIT;
|
248
|
+
|
249
|
+
if ((error = git_path_dirname_r(&dir, curpath.ptr)) < 0)
|
250
|
+
goto cleanup;
|
251
|
+
|
252
|
+
git_buf_swap(&curpath, &dir);
|
253
|
+
git_buf_free(&dir);
|
254
|
+
|
255
|
+
if ((error = git_path_apply_relative(&curpath, target.ptr)) < 0)
|
256
|
+
goto cleanup;
|
257
|
+
}
|
258
|
+
}
|
259
|
+
|
260
|
+
giterr_set(GITERR_INVALID, "maximum symlink depth reached");
|
261
|
+
error = -1;
|
262
|
+
|
263
|
+
cleanup:
|
264
|
+
git_buf_free(&curpath);
|
265
|
+
git_buf_free(&target);
|
266
|
+
return error;
|
267
|
+
}
|
268
|
+
|
194
269
|
int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode)
|
195
270
|
{
|
196
271
|
int compression, error = -1;
|
@@ -265,11 +340,14 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode
|
|
265
340
|
file->path_lock = git_buf_detach(&tmp_path);
|
266
341
|
GITERR_CHECK_ALLOC(file->path_lock);
|
267
342
|
} else {
|
268
|
-
|
343
|
+
git_buf resolved_path = GIT_BUF_INIT;
|
344
|
+
|
345
|
+
if ((error = resolve_symlink(&resolved_path, path)) < 0)
|
346
|
+
goto cleanup;
|
269
347
|
|
270
348
|
/* Save the original path of the file */
|
271
|
-
|
272
|
-
|
349
|
+
path_len = resolved_path.size;
|
350
|
+
file->path_original = git_buf_detach(&resolved_path);
|
273
351
|
|
274
352
|
/* create the locking path by appending ".lock" to the original */
|
275
353
|
GITERR_CHECK_ALLOC_ADD(&alloc_len, path_len, GIT_FILELOCK_EXTLENGTH);
|
@@ -18,7 +18,7 @@ GIT__USE_STRMAP
|
|
18
18
|
int git_futils_mkpath2file(const char *file_path, const mode_t mode)
|
19
19
|
{
|
20
20
|
return git_futils_mkdir(
|
21
|
-
file_path,
|
21
|
+
file_path, mode,
|
22
22
|
GIT_MKDIR_PATH | GIT_MKDIR_SKIP_LAST | GIT_MKDIR_VERIFY_DIR);
|
23
23
|
}
|
24
24
|
|
@@ -289,97 +289,230 @@ void git_futils_mmap_free(git_map *out)
|
|
289
289
|
p_munmap(out);
|
290
290
|
}
|
291
291
|
|
292
|
-
GIT_INLINE(int)
|
293
|
-
const char *
|
292
|
+
GIT_INLINE(int) mkdir_validate_dir(
|
293
|
+
const char *path,
|
294
294
|
struct stat *st,
|
295
295
|
mode_t mode,
|
296
296
|
uint32_t flags,
|
297
|
-
struct
|
297
|
+
struct git_futils_mkdir_options *opts)
|
298
298
|
{
|
299
|
+
/* with exclusive create, existing dir is an error */
|
300
|
+
if ((flags & GIT_MKDIR_EXCL) != 0) {
|
301
|
+
giterr_set(GITERR_FILESYSTEM,
|
302
|
+
"Failed to make directory '%s': directory exists", path);
|
303
|
+
return GIT_EEXISTS;
|
304
|
+
}
|
305
|
+
|
299
306
|
if ((S_ISREG(st->st_mode) && (flags & GIT_MKDIR_REMOVE_FILES)) ||
|
300
307
|
(S_ISLNK(st->st_mode) && (flags & GIT_MKDIR_REMOVE_SYMLINKS))) {
|
301
|
-
if (p_unlink(
|
308
|
+
if (p_unlink(path) < 0) {
|
302
309
|
giterr_set(GITERR_OS, "Failed to remove %s '%s'",
|
303
|
-
S_ISLNK(st->st_mode) ? "symlink" : "file",
|
310
|
+
S_ISLNK(st->st_mode) ? "symlink" : "file", path);
|
304
311
|
return GIT_EEXISTS;
|
305
312
|
}
|
306
313
|
|
307
|
-
perfdata
|
314
|
+
opts->perfdata.mkdir_calls++;
|
308
315
|
|
309
|
-
if (p_mkdir(
|
310
|
-
giterr_set(GITERR_OS, "Failed to make directory '%s'",
|
316
|
+
if (p_mkdir(path, mode) < 0) {
|
317
|
+
giterr_set(GITERR_OS, "Failed to make directory '%s'", path);
|
311
318
|
return GIT_EEXISTS;
|
312
319
|
}
|
313
320
|
}
|
314
321
|
|
315
322
|
else if (S_ISLNK(st->st_mode)) {
|
316
323
|
/* Re-stat the target, make sure it's a directory */
|
317
|
-
perfdata
|
324
|
+
opts->perfdata.stat_calls++;
|
318
325
|
|
319
|
-
if (p_stat(
|
320
|
-
giterr_set(GITERR_OS, "Failed to make directory '%s'",
|
326
|
+
if (p_stat(path, st) < 0) {
|
327
|
+
giterr_set(GITERR_OS, "Failed to make directory '%s'", path);
|
321
328
|
return GIT_EEXISTS;
|
322
329
|
}
|
323
330
|
}
|
324
331
|
|
325
332
|
else if (!S_ISDIR(st->st_mode)) {
|
326
333
|
giterr_set(GITERR_FILESYSTEM,
|
327
|
-
"Failed to make directory '%s': directory exists",
|
334
|
+
"Failed to make directory '%s': directory exists", path);
|
328
335
|
return GIT_EEXISTS;
|
329
336
|
}
|
330
337
|
|
331
338
|
return 0;
|
332
339
|
}
|
333
340
|
|
334
|
-
int
|
341
|
+
GIT_INLINE(int) mkdir_validate_mode(
|
335
342
|
const char *path,
|
336
|
-
|
343
|
+
struct stat *st,
|
344
|
+
bool terminal_path,
|
337
345
|
mode_t mode,
|
338
346
|
uint32_t flags,
|
339
347
|
struct git_futils_mkdir_options *opts)
|
340
348
|
{
|
341
|
-
|
342
|
-
|
343
|
-
ssize_t root = 0, min_root_len, root_len;
|
344
|
-
char lastch = '/', *tail;
|
345
|
-
struct stat st;
|
349
|
+
if (((terminal_path && (flags & GIT_MKDIR_CHMOD) != 0) ||
|
350
|
+
(flags & GIT_MKDIR_CHMOD_PATH) != 0) && st->st_mode != mode) {
|
346
351
|
|
347
|
-
|
348
|
-
if (git_path_join_unrooted(&make_path, path, base, &root) < 0)
|
349
|
-
return -1;
|
352
|
+
opts->perfdata.chmod_calls++;
|
350
353
|
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
+
if (p_chmod(path, mode) < 0) {
|
355
|
+
giterr_set(GITERR_OS, "failed to set permissions on '%s'", path);
|
356
|
+
return -1;
|
357
|
+
}
|
358
|
+
}
|
359
|
+
|
360
|
+
return 0;
|
361
|
+
}
|
362
|
+
|
363
|
+
GIT_INLINE(int) mkdir_canonicalize(
|
364
|
+
git_buf *path,
|
365
|
+
uint32_t flags)
|
366
|
+
{
|
367
|
+
ssize_t root_len;
|
368
|
+
|
369
|
+
if (path->size == 0) {
|
370
|
+
giterr_set(GITERR_OS, "attempt to create empty path");
|
371
|
+
return -1;
|
354
372
|
}
|
355
373
|
|
356
374
|
/* Trim trailing slashes (except the root) */
|
357
|
-
if ((root_len = git_path_root(
|
375
|
+
if ((root_len = git_path_root(path->ptr)) < 0)
|
358
376
|
root_len = 0;
|
359
377
|
else
|
360
378
|
root_len++;
|
361
379
|
|
362
|
-
while (
|
363
|
-
|
364
|
-
make_path.ptr[--make_path.size] = '\0';
|
380
|
+
while (path->size > (size_t)root_len && path->ptr[path->size - 1] == '/')
|
381
|
+
path->ptr[--path->size] = '\0';
|
365
382
|
|
366
383
|
/* if we are not supposed to made the last element, truncate it */
|
367
384
|
if ((flags & GIT_MKDIR_SKIP_LAST2) != 0) {
|
368
|
-
git_path_dirname_r(
|
385
|
+
git_path_dirname_r(path, path->ptr);
|
369
386
|
flags |= GIT_MKDIR_SKIP_LAST;
|
370
387
|
}
|
371
388
|
if ((flags & GIT_MKDIR_SKIP_LAST) != 0) {
|
372
|
-
git_path_dirname_r(
|
389
|
+
git_path_dirname_r(path, path->ptr);
|
373
390
|
}
|
374
391
|
|
375
392
|
/* We were either given the root path (or trimmed it to
|
376
|
-
|
393
|
+
* the root), we don't have anything to do.
|
394
|
+
*/
|
395
|
+
if (path->size <= (size_t)root_len)
|
396
|
+
git_buf_clear(path);
|
397
|
+
|
398
|
+
return 0;
|
399
|
+
}
|
400
|
+
|
401
|
+
int git_futils_mkdir(
|
402
|
+
const char *path,
|
403
|
+
mode_t mode,
|
404
|
+
uint32_t flags)
|
405
|
+
{
|
406
|
+
git_buf make_path = GIT_BUF_INIT, parent_path = GIT_BUF_INIT;
|
407
|
+
const char *relative;
|
408
|
+
struct git_futils_mkdir_options opts = { 0 };
|
409
|
+
struct stat st;
|
410
|
+
size_t depth = 0;
|
411
|
+
int len = 0, root_len, error;
|
412
|
+
|
413
|
+
if ((error = git_buf_puts(&make_path, path)) < 0 ||
|
414
|
+
(error = mkdir_canonicalize(&make_path, flags)) < 0 ||
|
415
|
+
(error = git_buf_puts(&parent_path, make_path.ptr)) < 0 ||
|
416
|
+
make_path.size == 0)
|
417
|
+
goto done;
|
418
|
+
|
419
|
+
root_len = git_path_root(make_path.ptr);
|
420
|
+
|
421
|
+
/* find the first parent directory that exists. this will be used
|
422
|
+
* as the base to dirname_relative.
|
377
423
|
*/
|
378
|
-
|
379
|
-
error =
|
424
|
+
for (relative = make_path.ptr; parent_path.size; ) {
|
425
|
+
error = p_lstat(parent_path.ptr, &st);
|
426
|
+
|
427
|
+
if (error == 0) {
|
428
|
+
break;
|
429
|
+
} else if (errno != ENOENT) {
|
430
|
+
giterr_set(GITERR_OS, "failed to stat '%s'", parent_path.ptr);
|
431
|
+
goto done;
|
432
|
+
}
|
433
|
+
|
434
|
+
depth++;
|
435
|
+
|
436
|
+
/* examine the parent of the current path */
|
437
|
+
if ((len = git_path_dirname_r(&parent_path, parent_path.ptr)) < 0) {
|
438
|
+
error = len;
|
439
|
+
goto done;
|
440
|
+
}
|
441
|
+
|
442
|
+
assert(len);
|
443
|
+
|
444
|
+
/* we've walked all the given path's parents and it's either relative
|
445
|
+
* or rooted. either way, give up and make the entire path.
|
446
|
+
*/
|
447
|
+
if ((len == 1 && parent_path.ptr[0] == '.') || len == root_len+1) {
|
448
|
+
relative = make_path.ptr;
|
449
|
+
break;
|
450
|
+
}
|
451
|
+
|
452
|
+
relative = make_path.ptr + len + 1;
|
453
|
+
|
454
|
+
/* not recursive? just make this directory relative to its parent. */
|
455
|
+
if ((flags & GIT_MKDIR_PATH) == 0)
|
456
|
+
break;
|
457
|
+
}
|
458
|
+
|
459
|
+
/* we found an item at the location we're trying to create,
|
460
|
+
* validate it.
|
461
|
+
*/
|
462
|
+
if (depth == 0) {
|
463
|
+
error = mkdir_validate_dir(make_path.ptr, &st, mode, flags, &opts);
|
464
|
+
|
465
|
+
if (!error)
|
466
|
+
error = mkdir_validate_mode(
|
467
|
+
make_path.ptr, &st, true, mode, flags, &opts);
|
468
|
+
|
380
469
|
goto done;
|
381
470
|
}
|
382
471
|
|
472
|
+
/* we already took `SKIP_LAST` and `SKIP_LAST2` into account when
|
473
|
+
* canonicalizing `make_path`.
|
474
|
+
*/
|
475
|
+
flags &= ~(GIT_MKDIR_SKIP_LAST2 | GIT_MKDIR_SKIP_LAST);
|
476
|
+
|
477
|
+
error = git_futils_mkdir_relative(relative,
|
478
|
+
parent_path.size ? parent_path.ptr : NULL, mode, flags, &opts);
|
479
|
+
|
480
|
+
done:
|
481
|
+
git_buf_free(&make_path);
|
482
|
+
git_buf_free(&parent_path);
|
483
|
+
return error;
|
484
|
+
}
|
485
|
+
|
486
|
+
int git_futils_mkdir_r(const char *path, const mode_t mode)
|
487
|
+
{
|
488
|
+
return git_futils_mkdir(path, mode, GIT_MKDIR_PATH);
|
489
|
+
}
|
490
|
+
|
491
|
+
int git_futils_mkdir_relative(
|
492
|
+
const char *relative_path,
|
493
|
+
const char *base,
|
494
|
+
mode_t mode,
|
495
|
+
uint32_t flags,
|
496
|
+
struct git_futils_mkdir_options *opts)
|
497
|
+
{
|
498
|
+
git_buf make_path = GIT_BUF_INIT;
|
499
|
+
ssize_t root = 0, min_root_len;
|
500
|
+
char lastch = '/', *tail;
|
501
|
+
struct stat st;
|
502
|
+
struct git_futils_mkdir_options empty_opts = {0};
|
503
|
+
int error;
|
504
|
+
|
505
|
+
if (!opts)
|
506
|
+
opts = &empty_opts;
|
507
|
+
|
508
|
+
/* build path and find "root" where we should start calling mkdir */
|
509
|
+
if (git_path_join_unrooted(&make_path, relative_path, base, &root) < 0)
|
510
|
+
return -1;
|
511
|
+
|
512
|
+
if ((error = mkdir_canonicalize(&make_path, flags)) < 0 ||
|
513
|
+
make_path.size == 0)
|
514
|
+
goto done;
|
515
|
+
|
383
516
|
/* if we are not supposed to make the whole path, reset root */
|
384
517
|
if ((flags & GIT_MKDIR_PATH) == 0)
|
385
518
|
root = git_buf_rfind(&make_path, '/');
|
@@ -437,32 +570,15 @@ retry_lstat:
|
|
437
570
|
goto done;
|
438
571
|
}
|
439
572
|
} else {
|
440
|
-
|
441
|
-
|
442
|
-
giterr_set(GITERR_FILESYSTEM, "Failed to make directory '%s': directory exists", make_path.ptr);
|
443
|
-
error = GIT_EEXISTS;
|
573
|
+
if ((error = mkdir_validate_dir(
|
574
|
+
make_path.ptr, &st, mode, flags, opts)) < 0)
|
444
575
|
goto done;
|
445
|
-
}
|
446
|
-
|
447
|
-
if ((error = validate_existing(
|
448
|
-
make_path.ptr, &st, mode, flags, &opts->perfdata)) < 0)
|
449
|
-
goto done;
|
450
576
|
}
|
451
577
|
|
452
578
|
/* chmod if requested and necessary */
|
453
|
-
if ((
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
opts->perfdata.chmod_calls++;
|
458
|
-
|
459
|
-
if ((error = p_chmod(make_path.ptr, mode)) < 0 &&
|
460
|
-
lastch == '\0') {
|
461
|
-
giterr_set(GITERR_OS, "Failed to set permissions on '%s'",
|
462
|
-
make_path.ptr);
|
463
|
-
goto done;
|
464
|
-
}
|
465
|
-
}
|
579
|
+
if ((error = mkdir_validate_mode(
|
580
|
+
make_path.ptr, &st, (lastch == '\0'), mode, flags, opts)) < 0)
|
581
|
+
goto done;
|
466
582
|
|
467
583
|
if (opts->dir_map && opts->pool) {
|
468
584
|
char *cache_path;
|
@@ -501,21 +617,6 @@ done:
|
|
501
617
|
return error;
|
502
618
|
}
|
503
619
|
|
504
|
-
int git_futils_mkdir(
|
505
|
-
const char *path,
|
506
|
-
const char *base,
|
507
|
-
mode_t mode,
|
508
|
-
uint32_t flags)
|
509
|
-
{
|
510
|
-
struct git_futils_mkdir_options options = {0};
|
511
|
-
return git_futils_mkdir_ext(path, base, mode, flags, &options);
|
512
|
-
}
|
513
|
-
|
514
|
-
int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode)
|
515
|
-
{
|
516
|
-
return git_futils_mkdir(path, base, mode, GIT_MKDIR_PATH);
|
517
|
-
}
|
518
|
-
|
519
620
|
typedef struct {
|
520
621
|
const char *base;
|
521
622
|
size_t baselen;
|
@@ -777,7 +878,7 @@ static int _cp_r_mkdir(cp_r_info *info, git_buf *from)
|
|
777
878
|
/* create root directory the first time we need to create a directory */
|
778
879
|
if ((info->flags & GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT) == 0) {
|
779
880
|
error = git_futils_mkdir(
|
780
|
-
info->to_root,
|
881
|
+
info->to_root, info->dirmode,
|
781
882
|
(info->flags & GIT_CPDIR_CHMOD_DIRS) ? GIT_MKDIR_CHMOD : 0);
|
782
883
|
|
783
884
|
info->flags |= GIT_CPDIR__MKDIR_DONE_FOR_TO_ROOT;
|
@@ -785,9 +886,9 @@ static int _cp_r_mkdir(cp_r_info *info, git_buf *from)
|
|
785
886
|
|
786
887
|
/* create directory with root as base to prevent excess chmods */
|
787
888
|
if (!error)
|
788
|
-
error =
|
889
|
+
error = git_futils_mkdir_relative(
|
789
890
|
from->ptr + info->from_prefix, info->to_root,
|
790
|
-
info->dirmode, info->mkdir_flags);
|
891
|
+
info->dirmode, info->mkdir_flags, NULL);
|
791
892
|
|
792
893
|
return error;
|
793
894
|
}
|