Subversion Repositories HelenOS

Rev

Rev 4377 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3294 post 1
/* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
2
 * All rights reserved.
3277 post 3
 *
3294 post 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
 */
3277 post 30
 
3294 post 31
 
3277 post 32
#include <stdio.h>
33
#include <stdlib.h>
3286 post 34
#include <dirent.h>
35
#include <fcntl.h>
36
#include <sys/types.h>
37
#include <sys/stat.h>
3353 post 38
#include <getopt.h>
39
#include <stdarg.h>
4692 svoboda 40
#include <string.h>
3286 post 41
 
42
#include "config.h"
43
#include "errors.h"
3353 post 44
#include "util.h"
3277 post 45
#include "entry.h"
46
#include "mkdir.h"
47
#include "cmds.h"
48
 
3353 post 49
#define MKDIR_VERSION "0.0.1"
50
 
3277 post 51
static char *cmdname = "mkdir";
52
 
3375 post 53
static struct option const long_options[] = {
3353 post 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
 
3413 post 64
void help_cmd_mkdir(unsigned int level)
3277 post 65
{
3286 post 66
    if (level == HELP_SHORT) {
67
        printf("`%s' creates a new directory\n", cmdname);
68
    } else {
69
        help_cmd_mkdir(HELP_SHORT);
3353 post 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);
3286 post 81
    }
82
 
3413 post 83
    return;
3277 post 84
}
85
 
3353 post 86
/* This is kind of clunky, but effective for now */
3364 post 87
static unsigned int
3353 post 88
create_directory(const char *path, unsigned int p)
3277 post 89
{
3286 post 90
    DIR *dirp;
3353 post 91
    char *tmp = NULL, *buff = NULL, *wdp = NULL;
92
    char *dirs[255];
93
    unsigned int absolute = 0, i = 0, ret = 0;
3277 post 94
 
3353 post 95
    /* Its a good idea to allocate path, plus we (may) need a copy of
96
     * path to tokenize if parents are specified */
4377 svoboda 97
    if (NULL == (tmp = str_dup(path))) {
3353 post 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 */
4377 svoboda 132
    dirs[i] = strtok(tmp, "/");
3353 post 133
    while (dirs[i] && i < 255)
4377 svoboda 134
        dirs[++i] = strtok(NULL, "/");
3353 post 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) {
3355 post 151
        /* Sometimes make or scripts conjoin odd paths. Account for something
152
         * like this: ../../foo/bar/../foo/foofoo/./bar */
4377 svoboda 153
        if (!str_cmp(dirs[i], "..") || !str_cmp(dirs[i], ".")) {
3353 post 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]);
3354 post 165
                ret ++;
3353 post 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
 
3413 post 185
int cmd_mkdir(char **argv)
3353 post 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
 
3376 post 192
    argc = cli_count_args(argv);
3277 post 193
 
3353 post 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",
3286 post 222
            cmdname, cmdname);
223
        return CMD_FAILURE;
224
    }
3277 post 225
 
3353 post 226
    if (NULL == (cwd = (char *) malloc(PATH_MAX))) {
227
        cli_error(CL_ENOMEM, "%s: could not allocate cwd", cmdname);
3286 post 228
        return CMD_FAILURE;
3277 post 229
    }
230
 
3353 post 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);
3286 post 240
    }
3277 post 241
 
3353 post 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;
3277 post 251
}
252