mkdir.c

00001 /* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
00002  * All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions are met:
00006  *
00007  * Redistributions of source code must retain the above copyright notice, this
00008  * list of conditions and the following disclaimer.
00009  *
00010  * Redistributions in binary form must reproduce the above copyright notice,
00011  * this list of conditions and the following disclaimer in the documentation
00012  * and/or other materials provided with the distribution.
00013  *
00014  * Neither the name of the original program's authors nor the names of its
00015  * contributors may be used to endorse or promote products derived from this
00016  * software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028  * POSSIBILITY OF SUCH DAMAGE.
00029  */
00030 
00031 
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <dirent.h>
00035 #include <fcntl.h>
00036 #include <sys/types.h>
00037 #include <sys/stat.h>
00038 #include <getopt.h>
00039 #include <stdarg.h>
00040 #include <str.h>
00041 
00042 #include "config.h"
00043 #include "errors.h"
00044 #include "util.h"
00045 #include "entry.h"
00046 #include "mkdir.h"
00047 #include "cmds.h"
00048 
00049 #define MKDIR_VERSION "0.0.1"
00050 
00051 static const char *cmdname = "mkdir";
00052 
00053 static struct option const long_options[] = {
00054         {"parents", no_argument, 0, 'p'},
00055         {"verbose", no_argument, 0, 'v'},
00056         {"mode", required_argument, 0, 'm'},
00057         {"help", no_argument, 0, 'h'},
00058         {"version", no_argument, 0, 'V'},
00059         {"follow", no_argument, 0, 'f'},
00060         {0, 0, 0, 0}
00061 };
00062 
00063 
00064 void help_cmd_mkdir(unsigned int level)
00065 {
00066         if (level == HELP_SHORT) {
00067                 printf("`%s' creates a new directory\n", cmdname);
00068         } else {
00069                 help_cmd_mkdir(HELP_SHORT);
00070                 printf(
00071                 "Usage:  %s [options] <path>\n"
00072                 "Options:\n"
00073                 "  -h, --help       A short option summary\n"
00074                 "  -V, --version    Print version information and exit\n"
00075                 "  -p, --parents    Create needed parents for <path>\n"
00076                 "  -m, --mode       Set permissions to [mode] (UNUSED)\n"
00077                 "  -v, --verbose    Be extremely noisy about what is happening\n"
00078                 "  -f, --follow     Go to the new directory once created\n"
00079                 "Currently, %s is under development, some options don't work.\n",
00080                 cmdname, cmdname);
00081         }
00082 
00083         return;
00084 }
00085 
00086 /* This is kind of clunky, but effective for now */
00087 static unsigned int
00088 create_directory(const char *path, unsigned int p)
00089 {
00090         DIR *dirp;
00091         char *tmp = NULL, *buff = NULL, *wdp = NULL;
00092         char *dirs[255];
00093         unsigned int absolute = 0, i = 0, ret = 0;
00094 
00095         /* Its a good idea to allocate path, plus we (may) need a copy of
00096          * path to tokenize if parents are specified */
00097         if (NULL == (tmp = str_dup(path))) {
00098                 cli_error(CL_ENOMEM, "%s: path too big?", cmdname);
00099                 return 1;
00100         }
00101 
00102         if (NULL == (wdp = (char *) malloc(PATH_MAX))) {
00103                 cli_error(CL_ENOMEM, "%s: could not alloc cwd", cmdname);
00104                 free(tmp);
00105                 return 1;
00106         }
00107 
00108         /* The only reason for wdp is to be (optionally) verbose */
00109         getcwd(wdp, PATH_MAX);
00110 
00111         /* Typical use without specifying the creation of parents */
00112         if (p == 0) {
00113                 dirp = opendir(tmp);
00114                 if (dirp) {
00115                         cli_error(CL_EEXISTS, "%s: can not create %s, try -p", cmdname, path);
00116                         closedir(dirp);
00117                         goto finit;
00118                 }
00119                 if (-1 == (mkdir(tmp, 0))) {
00120                         cli_error(CL_EFAIL, "%s: could not create %s", cmdname, path);
00121                         goto finit;
00122                 }
00123         }
00124 
00125         /* Parents need to be created, path has to be broken up */
00126 
00127         /* See if path[0] is a slash, if so we have to remember to append it */
00128         if (tmp[0] == '/')
00129                 absolute = 1;
00130 
00131         /* TODO: Canonify the path prior to tokenizing it, see below */
00132         dirs[i] = strtok(tmp, "/");
00133         while (dirs[i] && i < 255)
00134                 dirs[++i] = strtok(NULL, "/");
00135 
00136         if (NULL == dirs[0])
00137                 return 1;
00138 
00139         if (absolute == 1) {
00140                 asprintf(&buff, "/%s", dirs[0]);
00141                 mkdir(buff, 0);
00142                 chdir(buff);
00143                 free(buff);
00144                 getcwd(wdp, PATH_MAX);
00145                 i = 1;
00146         } else {
00147                 i = 0;
00148         }
00149 
00150         while (dirs[i] != NULL) {
00151                 /* Sometimes make or scripts conjoin odd paths. Account for something
00152                  * like this: ../../foo/bar/../foo/foofoo/./bar */
00153                 if (!str_cmp(dirs[i], "..") || !str_cmp(dirs[i], ".")) {
00154                         if (0 != (chdir(dirs[i]))) {
00155                                 cli_error(CL_EFAIL, "%s: impossible path: %s",
00156                                         cmdname, path);
00157                                 ret ++;
00158                                 goto finit;
00159                         }
00160                         getcwd(wdp, PATH_MAX);
00161                 } else {
00162                         if (-1 == (mkdir(dirs[i], 0))) {
00163                                 cli_error(CL_EFAIL,
00164                                         "%s: failed at %s/%s", wdp, dirs[i]);
00165                                 ret ++;
00166                                 goto finit;
00167                         }
00168                         if (0 != (chdir(dirs[i]))) {
00169                                 cli_error(CL_EFAIL, "%s: failed creating %s\n",
00170                                         cmdname, dirs[i]);
00171                                 ret ++;
00172                                 break;
00173                         }
00174                 }
00175                 i++;
00176         }
00177         goto finit;
00178 
00179 finit:
00180         free(wdp);
00181         free(tmp);
00182         return ret;
00183 }
00184 
00185 int cmd_mkdir(char **argv)
00186 {
00187         unsigned int argc, create_parents = 0, i, ret = 0, follow = 0;
00188         unsigned int verbose = 0;
00189         int c, opt_ind;
00190         char *cwd;
00191 
00192         argc = cli_count_args(argv);
00193 
00194         for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
00195                 c = getopt_long(argc, argv, "pvhVfm:", long_options, &opt_ind);
00196                 switch (c) {
00197                 case 'p':
00198                         create_parents = 1;
00199                         break;
00200                 case 'v':
00201                         verbose = 1;
00202                         break;
00203                 case 'h':
00204                         help_cmd_mkdir(HELP_LONG);
00205                         return CMD_SUCCESS;
00206                 case 'V':
00207                         printf("%s\n", MKDIR_VERSION);
00208                         return CMD_SUCCESS;
00209                 case 'f':
00210                         follow = 1;
00211                         break;
00212                 case 'm':
00213                         printf("%s: [W] Ignoring mode %s\n", cmdname, optarg);
00214                         break;
00215                 }
00216         }
00217 
00218         argc -= optind;
00219 
00220         if (argc < 1) {
00221                 printf("%s - incorrect number of arguments. Try `%s --help'\n",
00222                         cmdname, cmdname);
00223                 return CMD_FAILURE;
00224         }
00225 
00226         if (NULL == (cwd = (char *) malloc(PATH_MAX))) {
00227                 cli_error(CL_ENOMEM, "%s: could not allocate cwd", cmdname);
00228                 return CMD_FAILURE;
00229         }
00230 
00231         memset(cwd, 0, sizeof(cwd));
00232         getcwd(cwd, PATH_MAX);
00233 
00234         for (i = optind; argv[i] != NULL; i++) {
00235                 if (verbose == 1)
00236                         printf("%s: creating %s%s\n",
00237                                 cmdname, argv[i],
00238                                 create_parents ? " (and all parents)" : "");
00239                 ret += create_directory(argv[i], create_parents);
00240         }
00241 
00242         if (follow == 0)
00243                 chdir(cwd);
00244 
00245         free(cwd);
00246 
00247         if (ret)
00248                 return CMD_FAILURE;
00249         else
00250                 return CMD_SUCCESS;
00251 }
00252 

Generated on Thu Jun 2 07:45:41 2011 for HelenOS/USB by  doxygen 1.4.7