views:

1721

answers:

5

After reading the mkdir(2) man page for the Unix system call with that name, it appears that the call doesn't create intermediate directories in a path, only the last directory in the path. Is there any way (or other function) to create all the directories in the path without resorting to manually parsing my directory string and individually creating each directory ?

+5  A: 

There is not a system call to do it for you, unfortunately. I'm guessing that's because there isn't a way to have really well-defined semantics for what should happen in error cases. Should it leave the directories that have already been created? Delete them? What if the deletions fail? And so on...

It is pretty easy to roll your own, however, and a quick google for 'recursive mkdir' turned up a number of solutions. Here's one that was near the top:

http://nion.modprobe.de/blog/archives/357-Recursive-directory-creation.html

Carl Norum
A: 

The actual question was

"Is there any way (or other function) to create all the directories in the path without resorting to manually parsing my directory string and individually creating each directory "

so mkdir(1) is another way! So down vote all you want, mkdir(1) is a valid answer.

MKDIR(1) BSD General Commands Manual MKDIR(1)

NAME
     mkdir -- make directories

SYNOPSIS
     mkdir [-pv] [-m mode] directory_name ...

DESCRIPTION
     The mkdir utility creates the directories named as operands, in the order
     specified, using mode rwxrwxrwx (0777) as modified by the current
     umask(2).

     The options are as follows:

     -p      Create intermediate directories as required.  If this option is
             not specified, the full path prefix of each operand must already
             exist.  On the other hand, with this option specified, no error
             will be reported if a directory given as an operand already
             exists.  Intermediate directories are created with permission
             bits of rwxrwxrwx (0777) as modified by the current umask, plus
             write and search permission for the owner.
fuzzy lollipop
OP is asking about the system call `mkdir(2)`, not the utility `mkdir(1)`.
Carl Norum
you can't do it with mkdir(2) so mkdir(1) is the only other solution
fuzzy lollipop
Yes you can, you just need to put it in a loop. Or, god forbid, actually do it recursively.
Carl Norum
A: 

The two other answers given are for mkdir(1) and not mkdir(2) like you ask for, but you can look at the source code for that program and see how it implements the -p options which calls mkdir(2) repeatedly as needed.

hlovdal
The actual question was "Is there any way (or other function) to create all the directories in the path without resorting to manually parsing my directory string and individually creating each directory " so mkdir(1) is another way!
fuzzy lollipop
+2  A: 

Apparently not, my two suggestions are:

char dirpath[80] = "/path/to/some/directory";
sprintf(mkcmd, "mkdir -p %s", dirpath);
system(mkcmd);

Or if you don't want to use system() try looking at the coreutils mkdir source code and see how they implemented the -p option.

SiegeX
I pretty much can't use the system command because I'm using a severely impaired (even for busybox) version of busybox. I can't assume that any command has all the standard arguments, or is even installed for that matter, because I'm working on an embedded system. I went with Carl Norum's answer because it works the best in my specific scenario, but your answer was good as well.
Alex Marshall
+1  A: 

Take a look at the bash source code here, and specifically look in examples/loadables/mkdir.c especially lines 136-210. If you don't want to do that, here's some of the source that deals with this (taken straight from the tar.gz that I've linked):

/* Make all the directories leading up to PATH, then create PATH.  Note that
   this changes the process's umask; make sure that all paths leading to a
   return reset it to ORIGINAL_UMASK */

static int
make_path (path, nmode, parent_mode)
     char *path;
     int nmode, parent_mode;
{
  int oumask;
  struct stat sb;
  char *p, *npath;

  if (stat (path, &sb) == 0)
    {
      if (S_ISDIR (sb.st_mode) == 0)
    {
      builtin_error ("`%s': file exists but is not a directory", path);
      return 1;
    }

      if (chmod (path, nmode))
        {
          builtin_error ("%s: %s", path, strerror (errno));
          return 1;
        }

      return 0;
    }

  oumask = umask (0);
  npath = savestring (path);    /* So we can write to it. */

  /* Check whether or not we need to do anything with intermediate dirs. */

  /* Skip leading slashes. */
  p = npath;
  while (*p == '/')
    p++;

  while (p = strchr (p, '/'))
    {
      *p = '\0';
      if (stat (npath, &sb) != 0)
    {
      if (mkdir (npath, parent_mode))
        {
          builtin_error ("cannot create directory `%s': %s", npath, strerror (errno));
          umask (original_umask);
          free (npath);
          return 1;
        }
    }
      else if (S_ISDIR (sb.st_mode) == 0)
        {
          builtin_error ("`%s': file exists but is not a directory", npath);
          umask (original_umask);
          free (npath);
          return 1;
        }

      *p++ = '/';   /* restore slash */
      while (*p == '/')
    p++;
    }

  /* Create the final directory component. */
  if (stat (npath, &sb) && mkdir (npath, nmode))
    {
      builtin_error ("cannot create directory `%s': %s", npath, strerror (errno));
      umask (original_umask);
      free (npath);
      return 1;
    }

  umask (original_umask);
  free (npath);
  return 0;
}

You can probably get away with a less general implementation.

Chinmay Kanchi