@@ -301,6 +301,140 @@ int hyper_create_file(const char *hyper_path)
301301 return 0 ;
302302}
303303
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+
304438int hyper_mkdir (char * path , mode_t mode )
305439{
306440 struct stat st ;
0 commit comments