From c5412c58d2dd6c89e4b03c7c446d69a6b01e7a3f Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Thu, 3 Apr 2008 16:11:31 +0000 Subject: Re-implemented Path::createDirectoryOnDisk (for Unix). This method allows one to create a directory, and optionally create all parent directories that do not exist. The original implementation would require that *all* directories along a path are writable by the user, including directories that already exist. For example, suppose we wanted to create the directory "/tmp/foo/bar", and the directory "/tmp" already exists, but not "/tmp/foo". Since "/tmp" is writable by all users, the original implementation would work, and create "/tmp/foo", followed by "/tmp/bar". A problem occurred, however if one wanted to created the directory "/Users/myuser/bar" (or equivalently "/home/myuser/bar"), and "/Users/myuser" already existed and is writable by the current user. The directory "/User/myuser" is writable by the user, but "/User" is not. The original implementation of createDirectoryOnDisk would return with failure since "/User" is not writable, even though "/User/mysuser" is writable. The new implementation works by recursively creating parents as needed, and thus doesn't need to check the permissions on every directory in a path. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@49162 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/System/Unix/Path.inc | 71 ++++++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 32 deletions(-) (limited to 'lib/System') diff --git a/lib/System/Unix/Path.inc b/lib/System/Unix/Path.inc index 2f24b89..c3d06a3 100644 --- a/lib/System/Unix/Path.inc +++ b/lib/System/Unix/Path.inc @@ -527,6 +527,34 @@ Path::eraseSuffix() { return false; } +static bool createDirectoryHelper(char* beg, char* end, bool create_parents) { + + if (access(beg, F_OK | R_OK | W_OK) == 0) + return false; + + if (create_parents) { + + char* c = end; + + for (; c != beg; --c) + if (*c == '/') { + + // Recurse to handling the parent directory. + *c = '\0'; + bool x = createDirectoryHelper(beg, c, create_parents); + *c = '/'; + + // Return if we encountered an error. + if (x) + return true; + + break; + } + } + + return mkdir(beg, S_IRWXU | S_IRWXG) != 0; +} + bool Path::createDirectoryOnDisk( bool create_parents, std::string* ErrMsg ) { // Get a writeable copy of the path name @@ -534,38 +562,17 @@ Path::createDirectoryOnDisk( bool create_parents, std::string* ErrMsg ) { path.copy(pathname,MAXPATHLEN); // Null-terminate the last component - int lastchar = path.length() - 1 ; - if (pathname[lastchar] == '/') - pathname[lastchar] = 0; - else - pathname[lastchar+1] = 0; - - // If we're supposed to create intermediate directories - if ( create_parents ) { - // Find the end of the initial name component - char * next = strchr(pathname,'/'); - if ( pathname[0] == '/') - next = strchr(&pathname[1],'/'); - - // Loop through the directory components until we're done - while ( next != 0 ) { - *next = 0; - if (0 != access(pathname, F_OK | R_OK | W_OK)) - if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) { - return MakeErrMsg(ErrMsg, - std::string(pathname) + ": can't create directory"); - } - char* save = next; - next = strchr(next+1,'/'); - *save = '/'; - } - } - - if (0 != access(pathname, F_OK | R_OK)) - if (0 != mkdir(pathname, S_IRWXU | S_IRWXG)) { - return MakeErrMsg(ErrMsg, - std::string(pathname) + ": can't create directory"); - } + int lastchar = path.length() - 1 ; + + if (pathname[lastchar] != '/') + ++lastchar; + + pathname[lastchar] = 0; + + if (createDirectoryHelper(pathname, pathname+lastchar, create_parents)) + return MakeErrMsg(ErrMsg, + std::string(pathname) + ": can't create directory"); + return false; } -- cgit v1.1