Subversion Repositories HelenOS

Rev

Rev 3386 | Go to most recent revision | 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>
3286 post 40
 
41
#include "config.h"
42
#include "errors.h"
3353 post 43
#include "util.h"
3277 post 44
#include "entry.h"
45
#include "mkdir.h"
46
#include "cmds.h"
47
 
3353 post 48
#define MKDIR_VERSION "0.0.1"
49
 
3277 post 50
static char *cmdname = "mkdir";
51
 
3375 post 52
static struct option const long_options[] = {
3353 post 53
    {"parents", no_argument, 0, 'p'},
54
    {"verbose", no_argument, 0, 'v'},
55
    {"mode", required_argument, 0, 'm'},
56
    {"help", no_argument, 0, 'h'},
57
    {"version", no_argument, 0, 'V'},
58
    {"follow", no_argument, 0, 'f'},
59
    {0, 0, 0, 0}
60
};
61
 
62
 
4153 mejdrech 63
void help_cmd_mkdir(unsigned int level)
3277 post 64
{
3286 post 65
    if (level == HELP_SHORT) {
66
        printf("`%s' creates a new directory\n", cmdname);
67
    } else {
68
        help_cmd_mkdir(HELP_SHORT);
3353 post 69
        printf(
70
        "Usage:  %s [options] <path>\n"
71
        "Options:\n"
72
        "  -h, --help       A short option summary\n"
73
        "  -V, --version    Print version information and exit\n"
74
        "  -p, --parents    Create needed parents for <path>\n"
75
        "  -m, --mode       Set permissions to [mode] (UNUSED)\n"
76
        "  -v, --verbose    Be extremely noisy about what is happening\n"
77
        "  -f, --follow     Go to the new directory once created\n"
78
        "Currently, %s is under development, some options don't work.\n",
79
        cmdname, cmdname);
3286 post 80
    }
81
 
4153 mejdrech 82
    return;
3277 post 83
}
84
 
3353 post 85
/* This is kind of clunky, but effective for now */
3364 post 86
static unsigned int
3353 post 87
create_directory(const char *path, unsigned int p)
3277 post 88
{
3286 post 89
    DIR *dirp;
3353 post 90
    char *tmp = NULL, *buff = NULL, *wdp = NULL;
91
    char *dirs[255];
92
    unsigned int absolute = 0, i = 0, ret = 0;
3277 post 93
 
3353 post 94
    /* Its a good idea to allocate path, plus we (may) need a copy of
95
     * path to tokenize if parents are specified */
4153 mejdrech 96
    if (NULL == (tmp = strdup(path))) {
3353 post 97
        cli_error(CL_ENOMEM, "%s: path too big?", cmdname);
98
        return 1;
99
    }
100
 
101
    if (NULL == (wdp = (char *) malloc(PATH_MAX))) {
102
        cli_error(CL_ENOMEM, "%s: could not alloc cwd", cmdname);
103
        free(tmp);
104
        return 1;
105
    }
106
 
107
    /* The only reason for wdp is to be (optionally) verbose */
108
    getcwd(wdp, PATH_MAX);
109
 
110
    /* Typical use without specifying the creation of parents */
111
    if (p == 0) {
112
        dirp = opendir(tmp);
113
        if (dirp) {
114
            cli_error(CL_EEXISTS, "%s: can not create %s, try -p", cmdname, path);
115
            closedir(dirp);
116
            goto finit;
117
        }
118
        if (-1 == (mkdir(tmp, 0))) {
119
            cli_error(CL_EFAIL, "%s: could not create %s", cmdname, path);
120
            goto finit;
121
        }
122
    }
123
 
124
    /* Parents need to be created, path has to be broken up */
125
 
126
    /* See if path[0] is a slash, if so we have to remember to append it */
127
    if (tmp[0] == '/')
128
        absolute = 1;
129
 
130
    /* TODO: Canonify the path prior to tokenizing it, see below */
4153 mejdrech 131
    dirs[i] = strtok(tmp, "/");
3353 post 132
    while (dirs[i] && i < 255)
4153 mejdrech 133
        dirs[++i] = strtok(NULL, "/");
3353 post 134
 
135
    if (NULL == dirs[0])
136
        return 1;
137
 
138
    if (absolute == 1) {
139
        asprintf(&buff, "/%s", dirs[0]);
140
        mkdir(buff, 0);
141
        chdir(buff);
142
        free(buff);
143
        getcwd(wdp, PATH_MAX);
144
        i = 1;
145
    } else {
146
        i = 0;
147
    }
148
 
149
    while (dirs[i] != NULL) {
3355 post 150
        /* Sometimes make or scripts conjoin odd paths. Account for something
151
         * like this: ../../foo/bar/../foo/foofoo/./bar */
152
        if (!strcmp(dirs[i], "..") || !strcmp(dirs[i], ".")) {
3353 post 153
            if (0 != (chdir(dirs[i]))) {
154
                cli_error(CL_EFAIL, "%s: impossible path: %s",
155
                    cmdname, path);
156
                ret ++;
157
                goto finit;
158
            }
159
            getcwd(wdp, PATH_MAX);
160
        } else {
161
            if (-1 == (mkdir(dirs[i], 0))) {
162
                cli_error(CL_EFAIL,
163
                    "%s: failed at %s/%s", wdp, dirs[i]);
3354 post 164
                ret ++;
3353 post 165
                goto finit;
166
            }
167
            if (0 != (chdir(dirs[i]))) {
168
                cli_error(CL_EFAIL, "%s: failed creating %s\n",
169
                    cmdname, dirs[i]);
170
                ret ++;
171
                break;
172
            }
173
        }
174
        i++;
175
    }
176
    goto finit;
177
 
178
finit:
179
    free(wdp);
180
    free(tmp);
181
    return ret;
182
}
183
 
4153 mejdrech 184
int cmd_mkdir(char **argv)
3353 post 185
{
186
    unsigned int argc, create_parents = 0, i, ret = 0, follow = 0;
187
    unsigned int verbose = 0;
188
    int c, opt_ind;
189
    char *cwd;
190
 
3376 post 191
    argc = cli_count_args(argv);
3277 post 192
 
3353 post 193
    for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
194
        c = getopt_long(argc, argv, "pvhVfm:", long_options, &opt_ind);
195
        switch (c) {
196
        case 'p':
197
            create_parents = 1;
198
            break;
199
        case 'v':
200
            verbose = 1;
201
            break;
202
        case 'h':
203
            help_cmd_mkdir(HELP_LONG);
204
            return CMD_SUCCESS;
205
        case 'V':
206
            printf("%s\n", MKDIR_VERSION);
207
            return CMD_SUCCESS;
208
        case 'f':
209
            follow = 1;
210
            break;
211
        case 'm':
212
            printf("%s: [W] Ignoring mode %s\n", cmdname, optarg);
213
            break;
214
        }
215
    }
216
 
217
    argc -= optind;
218
 
219
    if (argc < 1) {
220
        printf("%s - incorrect number of arguments. Try `%s --help'\n",
3286 post 221
            cmdname, cmdname);
222
        return CMD_FAILURE;
223
    }
3277 post 224
 
3353 post 225
    if (NULL == (cwd = (char *) malloc(PATH_MAX))) {
226
        cli_error(CL_ENOMEM, "%s: could not allocate cwd", cmdname);
3286 post 227
        return CMD_FAILURE;
3277 post 228
    }
229
 
3353 post 230
    memset(cwd, 0, sizeof(cwd));
231
    getcwd(cwd, PATH_MAX);
232
 
233
    for (i = optind; argv[i] != NULL; i++) {
234
        if (verbose == 1)
235
            printf("%s: creating %s%s\n",
236
                cmdname, argv[i],
237
                create_parents ? " (and all parents)" : "");
238
        ret += create_directory(argv[i], create_parents);
3286 post 239
    }
3277 post 240
 
3353 post 241
    if (follow == 0)
242
        chdir(cwd);
243
 
244
    free(cwd);
245
 
246
    if (ret)
247
        return CMD_FAILURE;
248
    else
249
        return CMD_SUCCESS;
3277 post 250
}
251