1

I need to create folder if it does not exists, so I use:

bool mkdir_if_not_exist(const char *dir)
{
  bool ret = false;
  if (dir) {
     // first check if folder exists
     struct stat folder_info;
     if (stat(dir, &folder_info) != 0) {
    if (errno == ENOENT) { // create folder
        if (mkdir(dir, S_IRWXU | S_IXGRP | S_IRGRP | S_IROTH | S_IXOTH) ?!= 0) // 755
        perror("mkdir");
        else
        ret = true;
    } else
         perror("stat");
    } else
         ret = true; ?// dir exists
     }
     return ret;
 }

The folder is created only during first run of program - after that it is just a check. There is a suggestion to skipping the stat call and call mkdir and check errno against EEXIST. Does it give real benefits?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
eugene
  • 11
  • 2

3 Answers3

1

There's a slight benefit. Look up 'LBYL vs EAFP' or 'Look Before You Leap' vs 'Easier to Ask Forgiveness than Permission'.

The slight benefit is that the stat() system call has to parse the directory name and get to the inode - or the missing inode in this case - and then mkdir() has to do the same. Granted, the data needed by mkdir() is already in the kernel buffer pool, but it still involves two traversals of the path specified instead of one. So, in this case, it is slightly more efficient to use EAFP than to use LBYL as you do.

However, whether that is really a measurable effect in the average program is highly debatable. If you are doing nothing but create directories all over the place, then you might detect a benefit. But it is definitely a small effect, essentially unmeasurable, if you create a single directory at the start of a program.

You might need to deal with the case where strcmp(dir, "/some/where/or/another") == 0 but although "/some/where" exists, neither "/some/where/or" nor (of necessity) "/some/where/or/another" exist. Your current code does not handle missing directories in the middle of the path. It just reports the ENOENT that mkdir() would report. Your code that looks does not check that dir actually is a directory, either - it just assumes that if it exists, it is a directory. Handling these variations properly is trickier.

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
1

More important, with the stat + mkdir approach, there is a race condition: in between the stat and the mkdir another program could do the mkdir, so your mkdir could still fail with EEXIST.

andrewdski
  • 5,255
  • 2
  • 20
  • 20
0

Similar to Race condition with stat and mkdir in sequence, your solution is incorrect not only due to the race condition (as already pointed out by the other answers over here), but also because you never check whether the existing file is a directory or not.

When re-implementing functionality that's already widely available in existing command-line tools in UNIX, it always helps to see how it was implemented in those tools in the first place.

For example, take a look at how mkdir(1) -p option is implemented across the BSDs (bin/mkdir/mkdir.c#mkpath in OpenBSD and NetBSD), all of which, on mkdir(2)'s error, appear to immediately call stat(2) to subsequently run the S_ISDIR macro to ensure that the existing file is a directory, and not just any other type of a file.

Community
  • 1
  • 1
cnst
  • 25,870
  • 6
  • 90
  • 122