@@ -277,10 +277,10 @@ int git_futils_mkdir(
277
277
mode_t mode ,
278
278
uint32_t flags )
279
279
{
280
- int error = -1 , verify_final ;
280
+ int error = -1 ;
281
281
git_buf make_path = GIT_BUF_INIT ;
282
282
ssize_t root = 0 , min_root_len ;
283
- char lastch , * tail ;
283
+ char lastch = '/' , * tail ;
284
284
struct stat st ;
285
285
286
286
/* build path and find "root" where we should start calling mkdir */
@@ -306,27 +306,32 @@ int git_futils_mkdir(
306
306
if ((flags & GIT_MKDIR_SKIP_LAST ) != 0 )
307
307
git_buf_rtruncate_at_char (& make_path , '/' );
308
308
309
+ /* if nothing left after truncation, then we're done! */
310
+ if (!make_path .size ) {
311
+ error = 0 ;
312
+ goto done ;
313
+ }
314
+
309
315
/* if we are not supposed to make the whole path, reset root */
310
316
if ((flags & GIT_MKDIR_PATH ) == 0 )
311
317
root = git_buf_rfind (& make_path , '/' );
312
318
319
+ /* advance root past drive name or network mount prefix */
320
+ min_root_len = git_path_root (make_path .ptr );
321
+ if (root < min_root_len )
322
+ root = min_root_len ;
323
+ while (make_path .ptr [root ] == '/' )
324
+ ++ root ;
325
+
313
326
/* clip root to make_path length */
314
- if (root >= (ssize_t )make_path .size )
315
- root = (ssize_t )make_path .size - 1 ;
327
+ if (root > (ssize_t )make_path .size )
328
+ root = (ssize_t )make_path .size ; /* i.e. NUL byte of string */
316
329
if (root < 0 )
317
330
root = 0 ;
318
331
319
- tail = & make_path .ptr [root ];
320
-
321
- /* is there any path to make? */
322
- verify_final = ((flags & GIT_MKDIR_VERIFY_DIR ) != 0 ) && (* tail != 0 );
332
+ /* walk down tail of path making each directory */
333
+ for (tail = & make_path .ptr [root ]; * tail ; * tail = lastch ) {
323
334
324
- /* make sure mkdir root is at least after filesystem root */
325
- min_root_len = git_path_root (make_path .ptr );
326
- if (root < min_root_len )
327
- tail = & make_path .ptr [min_root_len ];
328
-
329
- while (* tail ) {
330
335
/* advance tail to include next path component */
331
336
while (* tail == '/' )
332
337
tail ++ ;
@@ -345,45 +350,35 @@ int git_futils_mkdir(
345
350
/* ignore error if directory already exists */
346
351
if (p_stat (make_path .ptr , & st ) < 0 || !S_ISDIR (st .st_mode )) {
347
352
errno = tmp_errno ;
348
- giterr_set (GITERR_OS , "Failed to make directory '%s'" ,
349
- make_path .ptr );
353
+ giterr_set (GITERR_OS , "Failed to make directory '%s'" , make_path .ptr );
350
354
goto done ;
351
355
}
352
356
353
357
/* with exclusive create, existing dir is an error */
354
358
if ((flags & GIT_MKDIR_EXCL ) != 0 ) {
355
- giterr_set (GITERR_OS , "Directory already exists '%s'" ,
356
- make_path .ptr );
359
+ giterr_set (GITERR_OS , "Directory already exists '%s'" , make_path .ptr );
357
360
error = GIT_EEXISTS ;
358
361
goto done ;
359
362
}
360
363
}
361
364
362
365
/* chmod if requested and necessary */
363
- if ((flags & GIT_MKDIR_CHMOD_PATH ) != 0 ||
364
- (lastch == '\0' && (flags & GIT_MKDIR_CHMOD ) != 0 ))
365
- {
366
- if (st .st_mode != mode && p_chmod (make_path .ptr , mode ) < 0 ) {
367
- giterr_set (GITERR_OS , "Failed to set permissions on '%s'" ,
368
- make_path .ptr );
369
- goto done ;
370
- }
366
+ if (((flags & GIT_MKDIR_CHMOD_PATH ) != 0 ||
367
+ (lastch == '\0' && (flags & GIT_MKDIR_CHMOD ) != 0 )) &&
368
+ st .st_mode != mode &&
369
+ (error = p_chmod (make_path .ptr , mode )) < 0 ) {
370
+ giterr_set (GITERR_OS , "Failed to set permissions on '%s'" , make_path .ptr );
371
+ goto done ;
371
372
}
372
-
373
- /* if we made it to the end, then final isdir check is not needed */
374
- if (lastch == '\0' )
375
- verify_final = false;
376
-
377
- * tail = lastch ;
378
373
}
379
374
380
375
error = 0 ;
381
376
382
377
/* check that full path really is a directory if requested & needed */
383
- if (verify_final &&
378
+ if ((flags & GIT_MKDIR_VERIFY_DIR ) != 0 &&
379
+ lastch != '\0' &&
384
380
(p_stat (make_path .ptr , & st ) < 0 || !S_ISDIR (st .st_mode ))) {
385
- giterr_set (
386
- GITERR_OS , "Path is not a directory '%s'" , make_path .ptr );
381
+ giterr_set (GITERR_OS , "Path is not a directory '%s'" , make_path .ptr );
387
382
error = GIT_ENOTFOUND ;
388
383
}
389
384
0 commit comments