[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

New version of function mkdirhier()



Hi,

I'm currently creating a patch to make libtar build and stumbled on the
function mkdirhier() in util.c. Since that function use not recommended
and potentially dangerous functions like strlcpy and strsep I rewrote
and generalized it using strchr and strncat.

Attached is the new function together with some test strings in main.
Have I missed some corner case, or is there a design flaw somewhere? If
you happen find the time to review the new function that would be
appreciated.

Thanks!
/*
** mkdirhier() - create all directories in a given path
** returns:
**      0                       success
**      1                       all directories already exist
**      -1 (and sets errno)     error
*/
int
mkdirhier(char *path)
{
        char src[MAXPATHLEN], dst[MAXPATHLEN] = "";
        char *dirp, *nextp = src;
        int retval = 1;

        if (strlcpy(src, path, sizeof(src)) > sizeof(src))
        {
                errno = ENAMETOOLONG;
                return -1;
        }

        if (path[0] == '/')
                strcpy(dst, "/");
        while ((dirp = strsep(&nextp, "/")) != NULL)
        {
                if (*dirp == '\0')
                        continue;

                if (dst[0] != '\0')
                        strcat(dst, "/");
                strcat(dst, dirp);

                if (mkdir(dst, 0777) == -1)
                {
                        if (errno != EEXIST)
                                return -1;
                }
                else
                        retval = 0;
        }

        return retval;
}
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

/*
** mkdirhier() - create all directories in a given path
** returns:
**      0                       success
**      1                       all directories already exist
**      -1 (and sets errno)     error
*/
int
mkdirhier(char *path)
{
  char *src, *dst = "";
  char *dirp;
  int retval = 1, len = 0;

  src = path;
  if ((dst = calloc (0, strlen (src))) == NULL)
    {
      errno = ENOMEM;
      return -1;
    }

  /* Absolute path: Leading '/' */
  if (path[0] == '/')
    {
    strncpy(dst, "/", 1);
    src++;
    }

  while ((dirp = strchr(src, '/')) != NULL)
    {
      len = dirp - src;
      if (len == 0)
	{
	  src++;
	  continue;
	}
      if (len == 1 && src[0] == '.')
	{
	  src++;
	  continue;
	}
      if (len == 2 && src[0] == '.' && src[1] == '.')
	{
	  strncat(dst, src, len);
	  src = dirp + 1;
	  strncat(dst, "/", 1);
	  continue;
	} 
      if (len > 0)
	{
	  strncat(dst, src, len);
	  src = dirp + 1;
	  if (mkdir(dst, 0777) == -1)
	    {
	      if (errno != EEXIST)
		{
		  free(dst);
		  return -1;
		}
	    }
	  else
	    retval = 0;
	  strncat(dst, "/", 1);
	}
    }

  /* Create dir after last '/' or no '/' in path */
  if ((dirp = strchr(src, '\0')) != NULL)
    {
      len = dirp - src;
      if (len == 0)
	{
	  return retval;
	}
      if (len == 1 && src[0] == '.')
	{
	  return retval;
	}
      if (len == 2 && src[0] == '.' && src[1] == '.')
	{
	  return retval;
	} 
      if (len > 0) {
	strncat(dst, src, len);
	if (mkdir(dst, 0777) == -1)
	  {
	    if (errno != EEXIST)
	      {
		free(dst);
		return -1;
	      }
	  }
	else
	  retval = 0;
      }
    }
  free(dst);
  return retval;
}

void main(void)
{
  char *path[32]={".", "./", ".//", "..", "../", "..//",
		  "/tmp", "/tmp/test", "//tmp/test", "/tmp/test//",
		  "da", "da/", "./da", "./da/", ".//da", "./da//",
		  ".da", ".da/", "./.da", ".da/", "././/da", "./../da//",
		  "da/b", "da/b/", "da/b//", "./da", "../da", "../da/",
		  "da/b/c", "da/b/c//", "da//b//c/ddee/f/", "da/b/c/ddee/f"};
  int result = 0, i;

  printf("main\n======================\n");
  for (i=0; i<32; i++) {
    printf ("%i) path = %s\n", i, path[i]);
    result = mkdirhier(path[i]);
    if (result == 1)
      printf ("all directories exist\n");
    else if (result == 0)
      printf ("all directories created\n");
    else
      printf ("error\n");
    printf("======================\n");
  }
}

Reply to: