Serenity Operating System
at master 95 lines 3.0 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2020-2021, Linus Groh <linusg@serenityos.org> 4 * Copyright (c) 2021, Xavier Defrang <xavier.defrang@gmail.com> 5 * 6 * SPDX-License-Identifier: BSD-2-Clause 7 */ 8 9#include <AK/LexicalPath.h> 10#include <AK/StringBuilder.h> 11#include <LibCore/ArgsParser.h> 12#include <LibCore/FilePermissionsMask.h> 13#include <LibCore/System.h> 14#include <LibMain/Main.h> 15#include <errno.h> 16#include <sys/stat.h> 17#include <unistd.h> 18 19ErrorOr<int> serenity_main(Main::Arguments arguments) 20{ 21 TRY(Core::System::pledge("stdio cpath rpath")); 22 23 bool create_parents = false; 24 DeprecatedString mode_string; 25 Vector<DeprecatedString> directories; 26 27 Core::ArgsParser args_parser; 28 args_parser.add_option(create_parents, "Create parent directories if they don't exist", "parents", 'p'); 29 args_parser.add_option(mode_string, "Set new directory permissions", "mode", 'm', "mode"); 30 args_parser.add_positional_argument(directories, "Directories to create", "directories"); 31 args_parser.parse(arguments); 32 33 mode_t const default_mode = 0755; 34 mode_t const mask_reference_mode = 0777; 35 36 Core::FilePermissionsMask mask; 37 38 if (mode_string.is_empty()) { 39 mask.assign_permissions(default_mode); 40 } else { 41 mask = TRY(Core::FilePermissionsMask::parse(mode_string)); 42 } 43 44 bool has_errors = false; 45 46 for (auto& directory : directories) { 47 LexicalPath lexical_path(directory); 48 if (!create_parents) { 49 if (mkdir(lexical_path.string().characters(), mask.apply(mask_reference_mode)) < 0) { 50 perror("mkdir"); 51 has_errors = true; 52 } 53 continue; 54 } 55 StringBuilder path_builder; 56 if (lexical_path.is_absolute()) 57 path_builder.append('/'); 58 59 auto& parts = lexical_path.parts_view(); 60 size_t num_parts = parts.size(); 61 62 for (size_t idx = 0; idx < num_parts; ++idx) { 63 auto& part = parts[idx]; 64 65 path_builder.append(part); 66 auto path = path_builder.to_deprecated_string(); 67 68 struct stat st; 69 if (stat(path.characters(), &st) < 0) { 70 if (errno != ENOENT) { 71 perror("stat"); 72 has_errors = true; 73 break; 74 } 75 76 bool is_final = (idx == (num_parts - 1)); 77 mode_t mode = is_final ? mask.apply(mask_reference_mode) : default_mode; 78 79 if (mkdir(path.characters(), mode) < 0) { 80 perror("mkdir"); 81 has_errors = true; 82 break; 83 } 84 } else { 85 if (!S_ISDIR(st.st_mode)) { 86 warnln("mkdir: cannot create directory '{}': not a directory", path); 87 has_errors = true; 88 break; 89 } 90 } 91 path_builder.append('/'); 92 } 93 } 94 return has_errors ? 1 : 0; 95}