@@ -329,16 +329,20 @@ static char *hyper_resolve_link(char *path)
329329 * @path: target directory. It is always relative to @root even if it starts with /.
330330 * @mode: directory mode.
331331 * @link_max: max number of symlinks to follow.
332- * @depth: number of components resolved.
333332 *
334333 * Upon success, @parent is changed to point to resolved path name.
335334 */
336335static int hyper_mkdir_follow_link (char * root , char * parent , char * path ,
337- mode_t mode , int * link_max , int * depth )
336+ mode_t mode , int * link_max )
338337{
339338 char * comp , * prev , * link , * dummy , * npath , * delim = "/" ;
340339 struct stat st ;
341340
341+ if (strncmp (root , parent , strlen (root )) != 0 ) {
342+ errno = EINVAL ;
343+ return -1 ;
344+ }
345+
342346 npath = strdup (path );
343347 if (npath == NULL )
344348 goto out ;
@@ -351,24 +355,30 @@ static int hyper_mkdir_follow_link(char *root, char *parent, char *path,
351355 if (!strcmp (comp , "." ))
352356 continue ;
353357
358+ if (!strcmp (comp , ".." )) {
359+ /* *NOTE* this works iff:
360+ * 1. parent is initialized as root when entering for the first time.
361+ * 2. comp is never appended to parent with trailing '/'.
362+ * 3. comp is always appended to parent with *one* prefix '/'.
363+ */
364+ char * p = strrchr (parent , '/' );
365+ if (p == NULL ) {
366+ /* no comp appended, do nothing */
367+ } else if (p - parent >= strlen (root )) {
368+ /* go back one level */
369+ * p = '\0' ;
370+ }
371+ /* no need to check parent directory */
372+ continue ;
373+ }
374+
354375 if (strlen (parent ) + strlen (comp ) + 1 >= 512 ) {
355376 errno = ENAMETOOLONG ;
356377 goto out ;
357378 }
358379 prev = & parent [strlen (parent )];
359380 strcat (parent , "/" );
360381 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- }
372382
373383 if (lstat (parent , & st ) >= 0 ) {
374384 if (S_ISDIR (st .st_mode )) {
@@ -383,12 +393,10 @@ static int hyper_mkdir_follow_link(char *root, char *parent, char *path,
383393 goto out ;
384394 if (link [0 ] == '/' ) {
385395 sprintf (parent , "%s" , root );
386- * depth = 0 ;
387396 } else {
388397 * prev = '\0' ; /* drop current comp */
389- (* depth )-- ;
390398 }
391- if (hyper_mkdir_follow_link (root , parent , link , mode , link_max , depth ) < 0 ) {
399+ if (hyper_mkdir_follow_link (root , parent , link , mode , link_max ) < 0 ) {
392400 free (link );
393401 goto out ;
394402 }
@@ -411,7 +419,6 @@ static int hyper_mkdir_follow_link(char *root, char *parent, char *path,
411419 errno = 0 ;
412420out :
413421 free (npath );
414- printf ("parent is %s errno %d\n" , parent , errno );
415422 return errno ? -1 : 0 ;
416423}
417424
@@ -426,10 +433,10 @@ static int hyper_mkdir_follow_link(char *root, char *parent, char *path,
426433char * hyper_mkdir_at (char * root , char * path , mode_t mode )
427434{
428435 char result [512 ];
429- int depth = 0 , max_link = 40 ;
436+ int max_link = 40 ;
430437
431438 sprintf (result , "%s" , root );
432- if (hyper_mkdir_follow_link (root , result , path , mode , & max_link , & depth ) < 0 )
439+ if (hyper_mkdir_follow_link (root , result , path , mode , & max_link ) < 0 )
433440 return NULL ;
434441
435442 return strdup (result );
0 commit comments