Subversion Repositories HelenOS

Rev

Rev 4266 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
  2.  * All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions are met:
  6.  *
  7.  * Redistributions of source code must retain the above copyright notice, this
  8.  * list of conditions and the following disclaimer.
  9.  *
  10.  * Redistributions in binary form must reproduce the above copyright notice,
  11.  * this list of conditions and the following disclaimer in the documentation
  12.  * and/or other materials provided with the distribution.
  13.  *
  14.  * Neither the name of the original program's authors nor the names of its
  15.  * contributors may be used to endorse or promote products derived from this
  16.  * software without specific prior written permission.
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  19.  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21.  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  22.  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  23.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  24.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  25.  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  26.  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  27.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28.  * POSSIBILITY OF SUCH DAMAGE.
  29.  */
  30.  
  31.  
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <dirent.h>
  35. #include <fcntl.h>
  36. #include <sys/types.h>
  37. #include <sys/stat.h>
  38. #include <getopt.h>
  39. #include <stdarg.h>
  40. #include <string.h>
  41.  
  42. #include "config.h"
  43. #include "errors.h"
  44. #include "util.h"
  45. #include "entry.h"
  46. #include "mkdir.h"
  47. #include "cmds.h"
  48.  
  49. #define MKDIR_VERSION "0.0.1"
  50.  
  51. static char *cmdname = "mkdir";
  52.  
  53. static struct option const long_options[] = {
  54.     {"parents", no_argument, 0, 'p'},
  55.     {"verbose", no_argument, 0, 'v'},
  56.     {"mode", required_argument, 0, 'm'},
  57.     {"help", no_argument, 0, 'h'},
  58.     {"version", no_argument, 0, 'V'},
  59.     {"follow", no_argument, 0, 'f'},
  60.     {0, 0, 0, 0}
  61. };
  62.  
  63.  
  64. void help_cmd_mkdir(unsigned int level)
  65. {
  66.     if (level == HELP_SHORT) {
  67.         printf("`%s' creates a new directory\n", cmdname);
  68.     } else {
  69.         help_cmd_mkdir(HELP_SHORT);
  70.         printf(
  71.         "Usage:  %s [options] <path>\n"
  72.         "Options:\n"
  73.         "  -h, --help       A short option summary\n"
  74.         "  -V, --version    Print version information and exit\n"
  75.         "  -p, --parents    Create needed parents for <path>\n"
  76.         "  -m, --mode       Set permissions to [mode] (UNUSED)\n"
  77.         "  -v, --verbose    Be extremely noisy about what is happening\n"
  78.         "  -f, --follow     Go to the new directory once created\n"
  79.         "Currently, %s is under development, some options don't work.\n",
  80.         cmdname, cmdname);
  81.     }
  82.  
  83.     return;
  84. }
  85.  
  86. /* This is kind of clunky, but effective for now */
  87. static unsigned int
  88. create_directory(const char *path, unsigned int p)
  89. {
  90.     DIR *dirp;
  91.     char *tmp = NULL, *buff = NULL, *wdp = NULL;
  92.     char *dirs[255];
  93.     unsigned int absolute = 0, i = 0, ret = 0;
  94.  
  95.     /* Its a good idea to allocate path, plus we (may) need a copy of
  96.      * path to tokenize if parents are specified */
  97.     if (NULL == (tmp = str_dup(path))) {
  98.         cli_error(CL_ENOMEM, "%s: path too big?", cmdname);
  99.         return 1;
  100.     }
  101.  
  102.     if (NULL == (wdp = (char *) malloc(PATH_MAX))) {
  103.         cli_error(CL_ENOMEM, "%s: could not alloc cwd", cmdname);
  104.         free(tmp);
  105.         return 1;
  106.     }
  107.  
  108.     /* The only reason for wdp is to be (optionally) verbose */
  109.     getcwd(wdp, PATH_MAX);
  110.  
  111.     /* Typical use without specifying the creation of parents */
  112.     if (p == 0) {
  113.         dirp = opendir(tmp);
  114.         if (dirp) {
  115.             cli_error(CL_EEXISTS, "%s: can not create %s, try -p", cmdname, path);
  116.             closedir(dirp);
  117.             goto finit;
  118.         }
  119.         if (-1 == (mkdir(tmp, 0))) {
  120.             cli_error(CL_EFAIL, "%s: could not create %s", cmdname, path);
  121.             goto finit;
  122.         }
  123.     }
  124.  
  125.     /* Parents need to be created, path has to be broken up */
  126.  
  127.     /* See if path[0] is a slash, if so we have to remember to append it */
  128.     if (tmp[0] == '/')
  129.         absolute = 1;
  130.  
  131.     /* TODO: Canonify the path prior to tokenizing it, see below */
  132.     dirs[i] = strtok(tmp, "/");
  133.     while (dirs[i] && i < 255)
  134.         dirs[++i] = strtok(NULL, "/");
  135.  
  136.     if (NULL == dirs[0])
  137.         return 1;
  138.  
  139.     if (absolute == 1) {
  140.         asprintf(&buff, "/%s", dirs[0]);
  141.         mkdir(buff, 0);
  142.         chdir(buff);
  143.         free(buff);
  144.         getcwd(wdp, PATH_MAX);
  145.         i = 1;
  146.     } else {
  147.         i = 0;
  148.     }
  149.  
  150.     while (dirs[i] != NULL) {
  151.         /* Sometimes make or scripts conjoin odd paths. Account for something
  152.          * like this: ../../foo/bar/../foo/foofoo/./bar */
  153.         if (!str_cmp(dirs[i], "..") || !str_cmp(dirs[i], ".")) {
  154.             if (0 != (chdir(dirs[i]))) {
  155.                 cli_error(CL_EFAIL, "%s: impossible path: %s",
  156.                     cmdname, path);
  157.                 ret ++;
  158.                 goto finit;
  159.             }
  160.             getcwd(wdp, PATH_MAX);
  161.         } else {
  162.             if (-1 == (mkdir(dirs[i], 0))) {
  163.                 cli_error(CL_EFAIL,
  164.                     "%s: failed at %s/%s", wdp, dirs[i]);
  165.                 ret ++;
  166.                 goto finit;
  167.             }
  168.             if (0 != (chdir(dirs[i]))) {
  169.                 cli_error(CL_EFAIL, "%s: failed creating %s\n",
  170.                     cmdname, dirs[i]);
  171.                 ret ++;
  172.                 break;
  173.             }
  174.         }
  175.         i++;
  176.     }
  177.     goto finit;
  178.  
  179. finit:
  180.     free(wdp);
  181.     free(tmp);
  182.     return ret;
  183. }
  184.  
  185. int cmd_mkdir(char **argv)
  186. {
  187.     unsigned int argc, create_parents = 0, i, ret = 0, follow = 0;
  188.     unsigned int verbose = 0;
  189.     int c, opt_ind;
  190.     char *cwd;
  191.  
  192.     argc = cli_count_args(argv);
  193.  
  194.     for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
  195.         c = getopt_long(argc, argv, "pvhVfm:", long_options, &opt_ind);
  196.         switch (c) {
  197.         case 'p':
  198.             create_parents = 1;
  199.             break;
  200.         case 'v':
  201.             verbose = 1;
  202.             break;
  203.         case 'h':
  204.             help_cmd_mkdir(HELP_LONG);
  205.             return CMD_SUCCESS;
  206.         case 'V':
  207.             printf("%s\n", MKDIR_VERSION);
  208.             return CMD_SUCCESS;
  209.         case 'f':
  210.             follow = 1;
  211.             break;
  212.         case 'm':
  213.             printf("%s: [W] Ignoring mode %s\n", cmdname, optarg);
  214.             break;
  215.         }
  216.     }
  217.  
  218.     argc -= optind;
  219.  
  220.     if (argc < 1) {
  221.         printf("%s - incorrect number of arguments. Try `%s --help'\n",
  222.             cmdname, cmdname);
  223.         return CMD_FAILURE;
  224.     }
  225.  
  226.     if (NULL == (cwd = (char *) malloc(PATH_MAX))) {
  227.         cli_error(CL_ENOMEM, "%s: could not allocate cwd", cmdname);
  228.         return CMD_FAILURE;
  229.     }
  230.  
  231.     memset(cwd, 0, sizeof(cwd));
  232.     getcwd(cwd, PATH_MAX);
  233.  
  234.     for (i = optind; argv[i] != NULL; i++) {
  235.         if (verbose == 1)
  236.             printf("%s: creating %s%s\n",
  237.                 cmdname, argv[i],
  238.                 create_parents ? " (and all parents)" : "");
  239.         ret += create_directory(argv[i], create_parents);
  240.     }
  241.  
  242.     if (follow == 0)
  243.         chdir(cwd);
  244.  
  245.     free(cwd);
  246.  
  247.     if (ret)
  248.         return CMD_FAILURE;
  249.     else
  250.         return CMD_SUCCESS;
  251. }
  252.  
  253.