/* * Copyright (c) 2008 Tim Post * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "errors.h" #include "util.h" #include "entry.h" #include "mkdir.h" #include "cmds.h" #define MKDIR_VERSION "0.0.1" static const char *cmdname = "mkdir"; static struct option const long_options[] = { { "parents", no_argument, 0, 'p' }, { "verbose", no_argument, 0, 'v' }, { "mode", required_argument, 0, 'm' }, { "help", no_argument, 0, 'h' }, { "version", no_argument, 0, 'V' }, { "follow", no_argument, 0, 'f' }, { 0, 0, 0, 0 } }; void help_cmd_mkdir(unsigned int level) { if (level == HELP_SHORT) { printf("`%s' creates a new directory\n", cmdname); } else { help_cmd_mkdir(HELP_SHORT); printf( "Usage: %s [options] \n" "Options:\n" " -h, --help A short option summary\n" " -V, --version Print version information and exit\n" " -p, --parents Create needed parents for \n" " -m, --mode Set permissions to [mode] (UNUSED)\n" " -v, --verbose Be extremely noisy about what is happening\n" " -f, --follow Go to the new directory once created\n" "Currently, %s is under development, some options don't work.\n", cmdname, cmdname); } return; } /* This is kind of clunky, but effective for now */ static unsigned int create_directory(const char *user_path, bool create_parents) { /* Ensure we would always work with absolute and canonified path. */ char *path = vfs_absolutize(user_path, NULL); if (path == NULL) { cli_error(CL_ENOMEM, "%s: path too big?", cmdname); return 1; } int ret = 0; errno_t rc; if (!create_parents) { rc = vfs_link_path(path, KIND_DIRECTORY, NULL); if (rc != EOK) { cli_error(CL_EFAIL, "%s: could not create %s (%s)", cmdname, path, str_error(rc)); ret = 1; } } else { /* Create the parent directories as well. */ size_t off = 0; while (true) { size_t prev_off = off; char32_t cur_char = str_decode(path, &off, STR_NO_LIMIT); if ((cur_char == 0) || (cur_char == U_SPECIAL)) { break; } if (cur_char != '/') { continue; } if (prev_off == 0) { continue; } /* * If we are here, it means that: * - we found / * - it is not the first / (no need to create root * directory) * * We would now overwrite the / with 0 to terminate the * string (that shall be okay because we are * overwriting at the beginning of UTF sequence). * That would allow us to create the directories * in correct nesting order. * * Notice that we ignore EEXIST errors as some of * the parent directories may already exist. */ char slash_char = path[prev_off]; path[prev_off] = 0; rc = vfs_link_path(path, KIND_DIRECTORY, NULL); if (rc != EOK && rc != EEXIST) { cli_error(CL_EFAIL, "%s: could not create %s (%s)", cmdname, path, str_error(rc)); ret = 1; goto leave; } path[prev_off] = slash_char; } /* Create the final directory. */ rc = vfs_link_path(path, KIND_DIRECTORY, NULL); if (rc != EOK) { cli_error(CL_EFAIL, "%s: could not create %s (%s)", cmdname, path, str_error(rc)); ret = 1; } } leave: free(path); return ret; } int cmd_mkdir(char **argv) { unsigned int argc, i, ret = 0; bool create_parents = false, follow = false, verbose = false; int c, opt_ind; argc = cli_count_args(argv); c = 0; optreset = 1; optind = 0; opt_ind = 0; while (c != -1) { c = getopt_long(argc, argv, "pvhVfm:", long_options, &opt_ind); switch (c) { case 'p': create_parents = true; break; case 'v': verbose = true; break; case 'h': help_cmd_mkdir(HELP_LONG); return CMD_SUCCESS; case 'V': printf("%s\n", MKDIR_VERSION); return CMD_SUCCESS; case 'f': follow = true; break; case 'm': printf("%s: [W] Ignoring mode %s\n", cmdname, optarg); break; } } argc -= optind; if (argc < 1) { printf("%s - incorrect number of arguments. Try `%s --help'\n", cmdname, cmdname); return CMD_FAILURE; } for (i = optind; argv[i] != NULL; i++) { if (verbose) printf("%s: creating %s%s\n", cmdname, argv[i], create_parents ? " (and all parents)" : ""); ret += create_directory(argv[i], create_parents); } if (follow && (argv[optind] != NULL)) { if (vfs_cwd_set(argv[optind]) != EOK) printf("%s: Error switching to directory.", cmdname); } if (ret) return CMD_FAILURE; else return CMD_SUCCESS; }