[llvm-commits] [llvm] r49162 - /llvm/trunk/lib/System/Unix/Path.inc

Ted Kremenek kremenek at apple.com
Thu Apr 3 09:11:39 PDT 2008


Author: kremenek
Date: Thu Apr  3 11:11:31 2008
New Revision: 49162

URL: http://llvm.org/viewvc/llvm-project?rev=49162&view=rev
Log:
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.

Modified:
    llvm/trunk/lib/System/Unix/Path.inc

Modified: llvm/trunk/lib/System/Unix/Path.inc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/System/Unix/Path.inc?rev=49162&r1=49161&r2=49162&view=diff

==============================================================================
--- llvm/trunk/lib/System/Unix/Path.inc (original)
+++ llvm/trunk/lib/System/Unix/Path.inc Thu Apr  3 11:11:31 2008
@@ -527,6 +527,34 @@
   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.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;
 }
 





More information about the llvm-commits mailing list