@@ -268,47 +268,6 @@ void hyper_filize(char *hyper_path)
268268 }
269269}
270270
271- static int hyper_create_parent_dir (const char * hyper_path )
272- {
273- char * p , * path = strdup (hyper_path );
274- int ret = 0 ;
275-
276- if (path == NULL )
277- return -1 ;
278- p = strrchr (path , '/' );
279- if (p != NULL && p != path ) {
280- * p = '\0' ;
281- ret = hyper_mkdir (path , 0777 );
282- }
283- free (path );
284-
285- return ret ;
286- }
287-
288- /* hyper_path must point to a file rather than a directory, e.g., having trailing '/' */
289- int hyper_create_file (const char * hyper_path )
290- {
291- int fd ;
292- struct stat stbuf ;
293-
294- if (stat (hyper_path , & stbuf ) >= 0 ) {
295- if (S_ISREG (stbuf .st_mode ))
296- return 0 ;
297- errno = S_ISDIR (stbuf .st_mode ) ? EISDIR : EINVAL ;
298- return -1 ;
299- }
300-
301- if (hyper_create_parent_dir (hyper_path ) < 0 )
302- return -1 ;
303-
304- fd = open (hyper_path , O_CREAT |O_WRONLY , 0666 );
305- if (fd < 0 )
306- return -1 ;
307- close (fd );
308- fprintf (stdout , "created file %s\n" , hyper_path );
309- return 0 ;
310- }
311-
312271static char * hyper_resolve_link (char * path )
313272{
314273 char buf [512 ];
@@ -333,19 +292,24 @@ static char *hyper_resolve_link(char *path)
333292 * as if we were in a chroot jail.
334293 *
335294 * @root: chroot jail path.
336- * @parent: what's already created to the target directory.
337295 * @path: target directory. It is always relative to @root even if it starts with /.
338- * @mode: directory mode .
296+ * @parent: what's already created to the target directory .
339297 * @link_max: max number of symlinks to follow.
340- * @depth: number of components resolved.
298+ * @create_file: create last component of @path as a normal file
341299 *
342300 * Upon success, @parent is changed to point to resolved path name.
343301 */
344- static int hyper_mkdir_follow_link (char * root , char * parent , char * path ,
345- mode_t mode , int * link_max , int * depth )
302+ static int hyper_mkdir_follow_link (const char * root , const char * path , char * parent ,
303+ int * link_max , bool create_file )
346304{
347- char * comp , * prev , * link , * dummy , * npath , * delim = "/" ;
305+ char * comp , * next , * prev , * last , * link , * dummy , * npath , * delim = "/" ;
348306 struct stat st ;
307+ int fd ;
308+
309+ if (strncmp (root , parent , strlen (root )) != 0 ) {
310+ errno = EINVAL ;
311+ return -1 ;
312+ }
349313
350314 npath = strdup (path );
351315 if (npath == NULL )
@@ -356,30 +320,40 @@ static int hyper_mkdir_follow_link(char *root, char *parent, char *path,
356320 goto out ;
357321
358322 do {
323+ last = comp ;
324+ next = strtok_r (NULL , delim , & dummy );
325+
359326 if (!strcmp (comp , "." ))
360327 continue ;
361328
329+ if (!strcmp (comp , ".." )) {
330+ /* *NOTE* this works iff:
331+ * 1. parent is initialized as root when entering for the first time.
332+ * 2. comp is never appended to parent with trailing '/'.
333+ * 3. comp is always appended to parent with *one* prefix '/'.
334+ */
335+ char * p = strrchr (parent , '/' );
336+ if (p == NULL ) {
337+ /* no comp appended, do nothing */
338+ } else if (p - parent >= strlen (root )) {
339+ /* go back one level */
340+ * p = '\0' ;
341+ }
342+ /* no need to check parent directory */
343+ continue ;
344+ }
345+
362346 if (strlen (parent ) + strlen (comp ) + 1 >= 512 ) {
363347 errno = ENAMETOOLONG ;
364348 goto out ;
365349 }
366350 prev = & parent [strlen (parent )];
367351 strcat (parent , "/" );
368352 strcat (parent , comp );
369- if (!strcmp (comp , ".." )) {
370- if (-- (* depth ) <= 0 ) {
371- /* points to root */
372- sprintf (parent , "%s" , root );
373- * depth = 0 ;
374- }
375- /* no need to check parent directory */
376- continue ;
377- } else {
378- (* depth )++ ;
379- }
380353
381354 if (lstat (parent , & st ) >= 0 ) {
382- if (S_ISDIR (st .st_mode )) {
355+ if ((S_ISDIR (st .st_mode ) && (next != NULL || !create_file )) ||
356+ (S_ISREG (st .st_mode ) && next == NULL && create_file )) {
383357 continue ;
384358 } else if (S_ISLNK (st .st_mode )) {
385359 if (-- (* link_max ) <= 0 ) {
@@ -391,12 +365,10 @@ static int hyper_mkdir_follow_link(char *root, char *parent, char *path,
391365 goto out ;
392366 if (link [0 ] == '/' ) {
393367 sprintf (parent , "%s" , root );
394- * depth = 0 ;
395368 } else {
396369 * prev = '\0' ; /* drop current comp */
397- (* depth )-- ;
398370 }
399- if (hyper_mkdir_follow_link (root , parent , link , mode , link_max , depth ) < 0 ) {
371+ if (hyper_mkdir_follow_link (root , link , parent , link_max , next == NULL && create_file ) < 0 ) {
400372 free (link );
401373 goto out ;
402374 }
@@ -408,39 +380,73 @@ static int hyper_mkdir_follow_link(char *root, char *parent, char *path,
408380 }
409381 }
410382
411- fprintf (stdout , "create directory %s\n" , parent );
412- if (mkdir (parent , mode ) < 0 && errno != EEXIST ) {
413- perror ("failed to create directory" );
414- goto out ;
383+ if (next == NULL && create_file ) {
384+ fprintf (stdout , "create file %s\n" , parent );
385+ fd = open (parent , O_CREAT |O_WRONLY , 0666 );
386+ if (fd < 0 )
387+ goto out ;
388+ close (fd );
389+ } else {
390+ fprintf (stdout , "create directory %s\n" , parent );
391+ if (mkdir (parent , 0755 ) < 0 && errno != EEXIST ) {
392+ perror ("failed to create directory" );
393+ goto out ;
394+ }
415395 }
416- } while ((comp = strtok_r ( NULL , delim , & dummy ) ) != NULL );
396+ } while ((comp = next ) != NULL );
417397
418- /* reset errno to mark success */
419- errno = 0 ;
398+ if (create_file && (!strcmp (last , "." ) || !strcmp (last , ".." )))
399+ errno = ENOTDIR ;
400+ else
401+ /* reset errno to mark success */
402+ errno = 0 ;
420403out :
421404 free (npath );
422- printf ("parent is %s errno %d\n" , parent , errno );
423405 return errno ? -1 : 0 ;
424406}
425407
408+ static int hyper_create_target_at (const char * root , char * hyper_path , int size , bool create_file )
409+ {
410+ char result [512 ];
411+ int max_link = 40 ;
412+
413+ sprintf (result , "%s" , root );
414+ if (hyper_mkdir_follow_link (root , hyper_path , result , & max_link , create_file ) < 0 )
415+ return -1 ;
416+
417+ if (strlen (result ) + 1 > size ) {
418+ errno = ENAMETOOLONG ;
419+ return -1 ;
420+ }
421+ sprintf (hyper_path , "%s" , result );
422+ return 0 ;
423+ }
424+
426425/*
427426 * hyper_mkdir_at() is similar to hyper_mkdir() with the exception that
428427 * when there are symlinks in the path components, it acts as if we created
429- * directories in a chroot jail. @path is always considered relative to root
430- * even if it starts with a leading stash ('/').
428+ * directories in a chroot jail. @hyper_path is always considered relative
429+ * to root even if it starts with a leading stash ('/').
431430 *
432- * Upon success, return symlink expanded result .
431+ * Upon success, @hyper_path is modified to save resolved path in chroot jail .
433432 */
434- char * hyper_mkdir_at (char * root , char * path , mode_t mode )
433+ int hyper_mkdir_at (const char * root , char * hyper_path , int size )
435434{
436- char result [512 ];
437- int depth = 0 , max_link = 40 ;
438-
439- sprintf (result , "%s" , root );
440- if (hyper_mkdir_follow_link (root , result , path , mode , & max_link , & depth ) < 0 )
441- return NULL ;
435+ return hyper_create_target_at (root , hyper_path , size , false);
436+ }
442437
443- return strdup (result );
438+ /**
439+ * hyper_create_file_at - create a file in @root chroot jail.
440+ *
441+ * @root: chroot jail path.
442+ * @hyper_path: must point to a file rather than a directory, e.g., having trailing '/'
443+ * @size: size of @hyper_path storage.
444+ *
445+ * Upon success, @hyper_path is modified to point to the path resolved in chroot jail.
446+ */
447+ int hyper_create_file_at (const char * root , char * hyper_path , int size )
448+ {
449+ return hyper_create_target_at (root , hyper_path , size , true);
444450}
445451
446452int hyper_mkdir (char * path , mode_t mode )
0 commit comments