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: