3

I found many examples of CreatingDirectory recursively, but not the one I was looking for.

here is the spec

Given input

  1. \\server\share\aa\bb\cc
  2. c:\aa\bb\cc

USING helper API

 CreateDirectory (char * path)
 returns true, if successful
 else
 FALSE

Condition: There should not be any parsing to distinguish if the path is Local or Server share.

Write a routine in C, or C++

LiraNuna
  • 64,916
  • 15
  • 117
  • 140
jacob
  • 31
  • 1
  • 1
  • 2
  • 1
    Is this a homework question? (It's not a problem if it is) – John Carter Oct 04 '09 at 23:19
  • 2
    In case it fails, wouldn't you like to know (and inform the caller) why it failed? Reasons for failing include: `no permission`, `file with same name already exists`, `no space on disk`. – pmg Oct 04 '09 at 23:28
  • Duplicate of http://stackoverflow.com/q/1530760/103167 except for not outright saying that `CreateDirectory` means the Win32 function (although most answers have assumed that it is) – Ben Voigt Apr 23 '15 at 16:23

8 Answers8

7

I think it's quite easier... here a version that works in every Windows version:

unsigned int pos = 0;
do
{
    pos = path.find_first_of("\\/", pos + 1);
    CreateDirectory(path.substr(0, pos).c_str(), NULL);
} while (pos != std::string::npos);

Unicode:

pos = path.find_first_of(L"\\/", pos + 1);

Regards,

Didac Perez Parera
  • 3,734
  • 3
  • 52
  • 87
3

This might be exactly what you want. It doesn't try to do any parsing to distinguish if the path is Local or Server share.

bool TryCreateDirectory(char *path){
    char *p;
    bool b;

    if(
        !(b=CreateDirectory(path))
        &&
        !(b=NULL==(p=strrchr(path, '\\')))
        ){
        size_t i;

        (p=strncpy((char *)malloc(1+i), path, i=p-path))[i]='\0';
        b=TryCreateDirectory(p);
        free(p);
        b=b?CreateDirectory(path):false;
    }

    return b;
}

The algorithm is quite simple, just pass the string of higher level directory recursively while creation of current level of directory fails until one success or there is no more higher level. When the inner call returns with succeed, create the current. This method do not parse to determ the local or server it self, it's according to the CreateDirectory. In WINAPI, CreateDirectory will never allows you to create "c:" or "\" when the path reaches that level, the method soon falls in to calling it self with path="" and this fails, too. It's the reason why Microsoft defines file sharing naming rule like this, for compatibility of DOS path rule and simplify the coding effort.

Ken Kin
  • 4,503
  • 3
  • 38
  • 76
  • 4
    +1 for the algorithm, but your coding style is terrible. And BTW, with MinGW (=gcc) you must compute `i` outside of the `strncpy` call. – Seki Feb 21 '12 at 17:08
1

Totally hackish and insecure and nothing you'd ever actually want to do in production code, but...

Warning: here be code that was typed in a browser:

int createDirectory(const char * path) {
  char * buffer = malloc((strlen(path) + 10) * sizeof(char));
  sprintf(buffer, "mkdir -p %s", path);
  int result = system(buffer);
  free(buffer);
  return result;
}
Dave DeLong
  • 242,470
  • 58
  • 448
  • 498
  • 1
    There are worse ways to do it. Once upon a few decades ago, it would have been necessary: in Version 7 Unix, `mkdir` was a SUID root program and there was no `mkdir()` system call (but neither was there a `-p` option to `mkdir`). – Jonathan Leffler Oct 05 '09 at 06:08
1

How about using MakeSureDirectoryPathExists() ?

Stefan
  • 43,293
  • 10
  • 75
  • 117
0

Just walk through each directory level in the path starting from the root, attempting to create the next level.

If any of the CreateDirectory calls fail then you can exit early, you're successful if you get to the end of the path without a failure.

This is assuming that calling CreateDirectory on a path that already exists has no ill effects.

John Carter
  • 53,924
  • 26
  • 111
  • 144
  • The only thing to watch is the different errors for 'lack of permission' vs 'directory already exists'. Attempting to create a directory that exists will just fail (unless you're on an antique version of NFS, when all sorts of odd-ball things could happen). – Jonathan Leffler Oct 05 '09 at 06:10
0

The requirement of not parsing the pathname for server names is interesting, as it seems to concede that parsing for / is required.

Perhaps the idea is to avoid building in hackish expressions for potentially complex syntax for hosts and mount points, which can have on some systems elaborate credentials encoded.

If it's homework, I may be giving away the algorithm you are supposed to think up, but it occurs to me that one way to meet those requirements is to start trying by attempting to mkdir the full pathname. If it fails, trim off the last directory and try again, if that fails, trim off another and try again... Eventually you should reach a root directory without needing to understand the server syntax, and then you will need to start adding pathname components back and making the subdirs one by one.

DigitalRoss
  • 143,651
  • 25
  • 248
  • 329
0
std::pair<bool, unsigned long> CreateDirectory(std::basic_string<_TCHAR> path)
{
    _ASSERT(!path.empty());
    typedef std::basic_string<_TCHAR> tstring;

    tstring::size_type pos = 0;

    while ((pos = path.find_first_of(_T("\\/"), pos + 1)) != tstring::npos)
    {
        ::CreateDirectory(path.substr(0, pos + 1).c_str(), nullptr);
    }

    if ((pos = path.find_first_of(_T("\\/"), path.length() - 1)) == tstring::npos)
    {
        path.append(_T("\\"));
    }

    ::CreateDirectory(path.c_str(), nullptr);

    return std::make_pair(
        ::GetFileAttributes(path.c_str()) != INVALID_FILE_ATTRIBUTES,
        ::GetLastError()
        );
}
jasnmoore
  • 13
  • 1
  • 4
-1
void createFolders(const std::string &s, char delim) {
std::stringstream ss(s);
std::string item;
char combinedName[50]={'\0'};
while (std::getline(ss, item, delim)) { 
  sprintf(combinedName,"%s%s%c",combinedName,item.c_str(),delim);          
  cout<<combinedName<<endl;
  struct stat st = {0};
  if (stat(combinedName,&st)==-1)
   { 
            #if REDHAT
                     mkdir(combinedName,0777);
            #else
                      CreateDirectory(combinedName,NULL);
            #endif
    }
 }
}
Awais Rafique
  • 466
  • 6
  • 17