@@ -301,6 +301,140 @@ int hyper_create_file(const char *hyper_path)
301
301
return 0 ;
302
302
}
303
303
304
+ static char * hyper_resolve_link (char * path )
305
+ {
306
+ char buf [512 ];
307
+ int len ;
308
+
309
+ len = readlink (path , buf , sizeof (buf ));
310
+ if (len < 0 ) {
311
+ perror ("failed to read mkdir symlink" );
312
+ return NULL ;
313
+ } else if (len >= sizeof (buf )) {
314
+ errno = ENAMETOOLONG ;
315
+ return NULL ;
316
+ }
317
+
318
+ buf [len ] = '\0' ;
319
+ fprintf (stdout , "follow link %s\n" , buf );
320
+ return strdup (buf );
321
+ }
322
+
323
+ /**
324
+ * hyper_mkdir_follow_link - create directories recurrsively while resolving symlinks
325
+ * as if we were in a chroot jail.
326
+ *
327
+ * @root: chroot jail path.
328
+ * @parent: what's already created to the target directory.
329
+ * @path: target directory. It is always relative to @root even if it starts with /.
330
+ * @mode: directory mode.
331
+ * @link_max: max number of symlinks to follow.
332
+ * @depth: number of components resolved.
333
+ *
334
+ * Upon success, @parent is changed to point to resolved path name.
335
+ */
336
+ static int hyper_mkdir_follow_link (char * root , char * parent , char * path ,
337
+ mode_t mode , int * link_max , int * depth )
338
+ {
339
+ char * comp , * prev , * link , * dummy , * npath , * delim = "/" ;
340
+ struct stat st ;
341
+
342
+ npath = strdup (path );
343
+ if (npath == NULL )
344
+ goto out ;
345
+
346
+ comp = strtok_r (npath , delim , & dummy );
347
+ if (comp == NULL )
348
+ goto out ;
349
+
350
+ do {
351
+ if (!strcmp (comp , "." ))
352
+ continue ;
353
+
354
+ if (strlen (parent ) + strlen (comp ) + 1 >= 512 ) {
355
+ errno = ENAMETOOLONG ;
356
+ goto out ;
357
+ }
358
+ prev = & parent [strlen (parent )];
359
+ strcat (parent , "/" );
360
+ strcat (parent , comp );
361
+ if (!strcmp (comp , ".." )) {
362
+ if (-- (* depth ) <= 0 ) {
363
+ /* points to root */
364
+ sprintf (parent , "%s" , root );
365
+ * depth = 0 ;
366
+ }
367
+ /* no need to check parent directory */
368
+ continue ;
369
+ } else {
370
+ (* depth )++ ;
371
+ }
372
+
373
+ if (lstat (parent , & st ) >= 0 ) {
374
+ if (S_ISDIR (st .st_mode )) {
375
+ continue ;
376
+ } else if (S_ISLNK (st .st_mode )) {
377
+ if (-- (* link_max ) <= 0 ) {
378
+ errno = ELOOP ;
379
+ goto out ;
380
+ }
381
+ link = hyper_resolve_link (parent );
382
+ if (link == NULL )
383
+ goto out ;
384
+ if (link [0 ] == '/' ) {
385
+ sprintf (parent , "%s" , root );
386
+ * depth = 0 ;
387
+ } else {
388
+ * prev = '\0' ; /* drop current comp */
389
+ (* depth )-- ;
390
+ }
391
+ if (hyper_mkdir_follow_link (root , parent , link , mode , link_max , depth ) < 0 ) {
392
+ free (link );
393
+ goto out ;
394
+ }
395
+ free (link );
396
+ continue ;
397
+ } else {
398
+ errno = ENOTDIR ;
399
+ goto out ;
400
+ }
401
+ }
402
+
403
+ fprintf (stdout , "create directory %s\n" , parent );
404
+ if (mkdir (parent , mode ) < 0 && errno != EEXIST ) {
405
+ perror ("failed to create directory" );
406
+ goto out ;
407
+ }
408
+ } while ((comp = strtok_r (NULL , delim , & dummy )) != NULL );
409
+
410
+ /* reset errno to mark success */
411
+ errno = 0 ;
412
+ out :
413
+ free (npath );
414
+ printf ("parent is %s errno %d\n" , parent , errno );
415
+ return errno ? -1 : 0 ;
416
+ }
417
+
418
+ /*
419
+ * hyper_mkdir_at() is similar to hyper_mkdir() with the exception that
420
+ * when there are symlinks in the path components, it acts as if we created
421
+ * directories in a chroot jail. @path is always considered relative to root
422
+ * even if it starts with a leading stash ('/').
423
+ *
424
+ * Upon success, return symlink expanded result.
425
+ */
426
+ char * hyper_mkdir_at (char * root , char * path , mode_t mode )
427
+ {
428
+ char result [512 ];
429
+ int depth = 0 , max_link = 40 ;
430
+
431
+ sprintf (result , "%s" , root );
432
+ if (hyper_mkdir_follow_link (root , result , path , mode , & max_link , & depth ) < 0 )
433
+ return NULL ;
434
+
435
+ return strdup (result );
436
+ }
437
+
304
438
int hyper_mkdir (char * path , mode_t mode )
305
439
{
306
440
struct stat st ;
0 commit comments