Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/bdsh/cmds/modules/mkdir/mkdir.c

    r36ab7c7 r738b549  
    3636#include <stdarg.h>
    3737#include <str.h>
     38#include <errno.h>
     39#include <str_error.h>
     40#include <vfs/vfs.h>
    3841
    3942#include "config.h"
     
    8386/* This is kind of clunky, but effective for now */
    8487static unsigned int
    85 create_directory(const char *path, unsigned int p)
     88create_directory(const char *user_path, bool create_parents)
    8689{
    87         DIR *dirp;
    88         char *tmp = NULL, *buff = NULL, *wdp = NULL;
    89         char *dirs[255];
    90         unsigned int absolute = 0, i = 0, ret = 0;
    91 
    92         /* Its a good idea to allocate path, plus we (may) need a copy of
    93          * path to tokenize if parents are specified */
    94         if (NULL == (tmp = str_dup(path))) {
     90        /* Ensure we would always work with absolute and canonified path. */
     91        char *path = absolutize(user_path, NULL);
     92        if (path == NULL) {
    9593                cli_error(CL_ENOMEM, "%s: path too big?", cmdname);
    9694                return 1;
    9795        }
    9896
    99         if (NULL == (wdp = (char *) malloc(PATH_MAX))) {
    100                 cli_error(CL_ENOMEM, "%s: could not alloc cwd", cmdname);
    101                 free(tmp);
    102                 return 1;
    103         }
    104 
    105         /* The only reason for wdp is to be (optionally) verbose */
    106         getcwd(wdp, PATH_MAX);
    107 
    108         /* Typical use without specifying the creation of parents */
    109         if (p == 0) {
    110                 dirp = opendir(tmp);
    111                 if (dirp) {
    112                         cli_error(CL_EEXISTS, "%s: can not create %s, try -p", cmdname, path);
    113                         closedir(dirp);
    114                         goto finit;
    115                 }
    116                 if (-1 == (mkdir(tmp, 0))) {
    117                         cli_error(CL_EFAIL, "%s: could not create %s", cmdname, path);
    118                         goto finit;
    119                 }
    120         }
    121 
    122         /* Parents need to be created, path has to be broken up */
    123 
    124         /* See if path[0] is a slash, if so we have to remember to append it */
    125         if (tmp[0] == '/')
    126                 absolute = 1;
    127 
    128         /* TODO: Canonify the path prior to tokenizing it, see below */
    129         dirs[i] = strtok(tmp, "/");
    130         while (dirs[i] && i < 255)
    131                 dirs[++i] = strtok(NULL, "/");
    132 
    133         if (NULL == dirs[0])
    134                 return 1;
    135 
    136         if (absolute == 1) {
    137                 asprintf(&buff, "/%s", dirs[0]);
    138                 mkdir(buff, 0);
    139                 chdir(buff);
    140                 free(buff);
    141                 getcwd(wdp, PATH_MAX);
    142                 i = 1;
     97        int rc;
     98        int ret = 0;
     99
     100        if (!create_parents) {
     101                rc = mkdir(path, 0);
     102                if (rc != EOK) {
     103                        cli_error(CL_EFAIL, "%s: could not create %s (%s)",
     104                            cmdname, path, str_error(rc));
     105                        ret = 1;
     106                }
    143107        } else {
    144                 i = 0;
    145         }
    146 
    147         while (dirs[i] != NULL) {
    148                 /* Sometimes make or scripts conjoin odd paths. Account for something
    149                  * like this: ../../foo/bar/../foo/foofoo/./bar */
    150                 if (!str_cmp(dirs[i], "..") || !str_cmp(dirs[i], ".")) {
    151                         if (0 != (chdir(dirs[i]))) {
    152                                 cli_error(CL_EFAIL, "%s: impossible path: %s",
    153                                         cmdname, path);
    154                                 ret ++;
    155                                 goto finit;
    156                         }
    157                         getcwd(wdp, PATH_MAX);
    158                 } else {
    159                         if (-1 == (mkdir(dirs[i], 0))) {
    160                                 cli_error(CL_EFAIL,
    161                                         "%s: failed at %s/%s", wdp, dirs[i]);
    162                                 ret ++;
    163                                 goto finit;
    164                         }
    165                         if (0 != (chdir(dirs[i]))) {
    166                                 cli_error(CL_EFAIL, "%s: failed creating %s\n",
    167                                         cmdname, dirs[i]);
    168                                 ret ++;
     108                /* Create the parent directories as well. */
     109                size_t off = 0;
     110                while (1) {
     111                        size_t prev_off = off;
     112                        wchar_t cur_char = str_decode(path, &off, STR_NO_LIMIT);
     113                        if ((cur_char == 0) || (cur_char == U_SPECIAL)) {
    169114                                break;
    170115                        }
    171                 }
    172                 i++;
    173         }
    174         goto finit;
    175 
    176 finit:
    177         free(wdp);
    178         free(tmp);
     116                        if (cur_char != '/') {
     117                                continue;
     118                        }
     119                        if (prev_off == 0) {
     120                                continue;
     121                        }
     122                        /*
     123                         * If we are here, it means that:
     124                         * - we found /
     125                         * - it is not the first / (no need to create root
     126                         *   directory)
     127                         *
     128                         * We would now overwrite the / with 0 to terminate the
     129                         * string (that shall be okay because we are
     130                         * overwriting at the beginning of UTF sequence).
     131                         * That would allow us to create the directories
     132                         * in correct nesting order.
     133                         *
     134                         * Notice that we ignore EEXIST errors as some of
     135                         * the parent directories may already exist.
     136                         */
     137                        char slash_char = path[prev_off];
     138                        path[prev_off] = 0;
     139                        rc = mkdir(path, 0);
     140                        if (rc == EEXIST) {
     141                                rc = EOK;
     142                        }
     143
     144                        if (rc != EOK) {
     145                                cli_error(CL_EFAIL, "%s: could not create %s (%s)",
     146                                    cmdname, path, str_error(rc));
     147                                ret = 1;
     148                                goto leave;
     149                        }
     150
     151                        path[prev_off] = slash_char;
     152                }
     153                /* Create the final directory. */
     154                rc = mkdir(path, 0);
     155                if (rc != EOK) {
     156                        cli_error(CL_EFAIL, "%s: could not create %s (%s)",
     157                            cmdname, path, str_error(rc));
     158                        ret = 1;
     159                }
     160        }
     161
     162leave:
     163        free(path);
    179164        return ret;
    180165}
     
    182167int cmd_mkdir(char **argv)
    183168{
    184         unsigned int argc, create_parents = 0, i, ret = 0, follow = 0;
    185         unsigned int verbose = 0;
     169        unsigned int argc, i, ret = 0;
     170        bool create_parents = false, follow = false, verbose = false;
    186171        int c, opt_ind;
    187         char *cwd;
    188172
    189173        argc = cli_count_args(argv);
     
    193177                switch (c) {
    194178                case 'p':
    195                         create_parents = 1;
     179                        create_parents = true;
    196180                        break;
    197181                case 'v':
    198                         verbose = 1;
     182                        verbose = true;
    199183                        break;
    200184                case 'h':
     
    205189                        return CMD_SUCCESS;
    206190                case 'f':
    207                         follow = 1;
     191                        follow = true;
    208192                        break;
    209193                case 'm':
     
    221205        }
    222206
    223         if (NULL == (cwd = (char *) malloc(PATH_MAX))) {
    224                 cli_error(CL_ENOMEM, "%s: could not allocate cwd", cmdname);
    225                 return CMD_FAILURE;
    226         }
    227 
    228         memset(cwd, 0, sizeof(cwd));
    229         getcwd(cwd, PATH_MAX);
    230 
    231207        for (i = optind; argv[i] != NULL; i++) {
    232                 if (verbose == 1)
     208                if (verbose)
    233209                        printf("%s: creating %s%s\n",
    234210                                cmdname, argv[i],
     
    237213        }
    238214
    239         if (follow == 0)
    240                 chdir(cwd);
    241 
    242         free(cwd);
     215        if (follow && (argv[optind] != NULL)) {
     216                chdir(argv[optind]);
     217        }
    243218
    244219        if (ret)
Note: See TracChangeset for help on using the changeset viewer.