2

I am completing cs50x (the edX (free) version of the Harvard cs50) course and am trying to be a bit tricky/lazy/test myself.

I am trying to use a C program to create all the directories I will need for my psets.

I have looked online and found that <sys/stat.h> includes the mkdir() function and therefore tried creating some nested loops to create all the necessary folders by doing something similar to mkdir {pset1,pset1/{standard,hacker},pset2,pset2{standard... to give me a directory structure like this:

pset1/Standard
pset1/Hacker
pset2/Standard

etc...

I came up with this:

#include <cs50.h>
#include <stdio.h>
#include <sys/stat.h>

int main(int argc, string argv[])
{
    for(int i = 1; i <=8; i++)
    {
        string dir = argv[1];
        sprintf(dir,"%s%i", argv[1], i);
        mkdir(dir, 0777);
        for(int j = 0; j<2; j++)
        {
            string subDir[] = {"Standard","Hacker"};
            sprintf(dir,"%s%i/%s", argv[1], i, subDir[j]);
            mkdir(dir, 0777);
        }
    }
}

However, the program only creates pset1 and completes, there are no subfolders, no pset2 etc.

3
  • 1
    You'll have to build a string to pass with sprintf(). Commented Mar 5, 2015 at 8:39
  • There is no string in C, you seem to be using C++. Very confusing. Commented Mar 5, 2015 at 9:26
  • 1
    The cs50 header i include on line 1 creates this function, it just makes things easier to understand in the future i guess, and I havent completed enough of the lectures to learn what it is that the string function actually does. Commented Mar 5, 2015 at 10:12

3 Answers 3

1

To create a full path you can call mkdir() recursivly like this:

#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

int mkdirr(const char * path, const mode_t mode, const int fail_on_exist)
{
  int result = 0;
  char * dir = NULL;

  do
  {
    if (NULL == path)
    {
      errno = EINVAL;
      result = -1;
      break;
    }

    if ((dir = strrchr(path, '/'))) 
    {
      *dir = '\0';
      result = mkdirr(path, mode, fail_on_exist);
      *dir = '/';

      if (result)
      {
        break;
      }
    }

    if (strlen(path))
    {
      if ((result = mkdir(path, mode)))
      {
        char s[PATH_MAX];
        sprintf(s, "mkdir() failed for '%s'", path);
        perror(s);

        if ((EEXIST == result) && (0 == fail_on_exist))
        {
          result = 0;
        }
        else
        {
          break;
        }
      }
    }
  } while (0);

  return result;
}

And then call mkdirr() like this;

int main(void)
{
  char p[] = "test/1/2/3";
  if (-1 == mkdirr(p, 0777, 0))
  {
    perror("mkdirr() failed()");
  }

  return 0;
}
Sign up to request clarification or add additional context in comments.

1 Comment

The code that does if ((dir = strrchr(path, '/'))) { *dir = '\0'; is dire because you stated that your code would not modify path when you used const char *path but this code proceeds to modify it. It may well fail horribly if passed a string literal.
0

Yes, you're being lazy since you seem to have very little knowledge of C, yet try to program in it. :)

C is not Python, there is no string interpolation/formatting operator. You have to call a function, specificially snprintf(). Read that manual page.

Also, you can't create a bunch of nested directories with a single call to mkdir(). Read the manual page.

To create nested directories, you're either going to have to build each's absolute path (i.e. each successive time you call mkdir() the path will be longer than the previous time), or actually enter each directory as you create it, and go from there.

3 Comments

I realise that, thats why I wrote code to create the base directory prior to creating the nested directories specifically
@mistamadd001 OK: I failed to understand that part of your code, and also the part of the question where you describe the desired directory structure. It would probably help if you spelled it out more clearly.
Updated original post with new code and outcome, also gave example of directory structure
0
/*
* Creates nested directory
* len -> path string length
* path -> directory to be created
* example path-> /usr/local/apat/10/test/ , in this case it will check if all 
* diretories like /usr, /usr/local, /usr/local/apat, /usr/local/apat/10 and 
* /usr/local/apat/10/test are present or not. If not present then created.
*/ 
bool create_nested_directories(char *path, int len)
{
    int index = 1;
    bool ret = false;
    struct stat stats;
    bool checkfordir = true;
    char *lpath = (char *)malloc(len+1);
    
    if(path == NULL) goto end;
    if(len <= 0) goto end;
    
    strcpy(lpath, path);
    while(index < len)
    {
        if(lpath[index] == '/')
        {
            lpath[index] = 0x0;
            
            if(checkfordir == true)
            {
                if(!(stat(lpath, &stats) == 0 && S_ISDIR(stats.st_mode)))
                {
                    checkfordir = false; //once check retruns false, always will be flase for res of the lpath
                    mkdir(lpath, 0755);
                }
            }
            else
            {
                mkdir(lpath, 0755);
            }
            lpath[index] = '/';
        }

        index++;
    }

end:  
    free(lpath);
    return ret;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.