Browse Source

mkdir: Add -p option to create parent directories

Linus Groh 5 years ago
parent
commit
8f2300afb5
2 changed files with 49 additions and 6 deletions
  1. 6 2
      Base/usr/share/man/man1/mkdir.md
  2. 43 4
      Userland/mkdir.cpp

+ 6 - 2
Base/usr/share/man/man1/mkdir.md

@@ -5,17 +5,21 @@ mkdir - create directories
 ## Synopsis
 
 ```**sh
-$ mkdir directories...
+$ mkdir [ options...] directories...
 ```
 
 ## Description
 
 Create a new empty directory for each of the given *directories*.
 
+## Options
+
+* `-p`, `--parents`: Create parent directories if they don't exist
+
 ## Examples
 
 ```sh
-$ mkdir /tmp/foo
+$ mkdir -p /tmp/foo/bar
 ```
 
 ## See also

+ 43 - 4
Userland/mkdir.cpp

@@ -25,28 +25,67 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <AK/FileSystemPath.h>
+#include <AK/StringBuilder.h>
 #include <LibCore/ArgsParser.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
 int main(int argc, char** argv)
 {
-    if (pledge("stdio cpath", nullptr) < 0) {
+    if (pledge("stdio cpath rpath", nullptr) < 0) {
         perror("pledge");
         return 1;
     }
 
+    bool create_parents = false;
     Vector<const char*> directories;
 
     Core::ArgsParser args_parser;
+    args_parser.add_option(create_parents, "Create parent directories if they don't exist", "parents", 'p');
     args_parser.add_positional_argument(directories, "Directories to create", "directories");
     args_parser.parse(argc, argv);
 
+    // FIXME: Support -m/--mode option
+    mode_t mode = 0755;
+
     bool has_errors = false;
+
     for (auto& directory : directories) {
-        if (mkdir(directory, 0755) < 0) {
-            perror("mkdir");
-            has_errors = true;
+        FileSystemPath canonical_path(directory);
+        if (!create_parents) {
+            if (mkdir(canonical_path.string().characters(), mode) < 0) {
+                perror("mkdir");
+                has_errors = true;
+            }
+            continue;
+        }
+        StringBuilder path_builder;
+        if (canonical_path.is_absolute())
+            path_builder.append("/");
+        for (auto& part : canonical_path.parts()) {
+            path_builder.append(part);
+            auto path = path_builder.build();
+            struct stat st;
+            if (stat(path.characters(), &st) < 0) {
+                if (errno != ENOENT) {
+                    perror("stat");
+                    has_errors = true;
+                    break;
+                }
+                if (mkdir(path.characters(), mode) < 0) {
+                    perror("mkdir");
+                    has_errors = true;
+                    break;
+                }
+            } else {
+                if (!S_ISDIR(st.st_mode)) {
+                    fprintf(stderr, "mkdir: cannot create directory '%s': not a directory\n", path.characters());
+                    has_errors = true;
+                    break;
+                }
+            }
+            path_builder.append("/");
         }
     }
     return has_errors ? 1 : 0;