~martin-decky/helenos/rcu

« back to all changes in this revision

Viewing changes to uspace/app/bdsh/cmds/modules/ls/ls.c

MergeĀ mainlineĀ changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
41
41
#include <str.h>
42
42
#include <sort.h>
43
43
 
 
44
#include "ls.h"
44
45
#include "errors.h"
45
46
#include "config.h"
46
47
#include "util.h"
47
48
#include "entry.h"
48
49
#include "cmds.h"
49
50
 
50
 
/* Various values that can be returned by ls_scope() */
51
 
#define LS_BOGUS 0
52
 
#define LS_FILE  1
53
 
#define LS_DIR   2
54
 
 
55
 
/** Structure to represent a directory entry.
56
 
 *
57
 
 * Useful to keep together important information
58
 
 * for sorting directory entries.
59
 
 */
60
 
struct dir_elem_t {
61
 
        char *name;
62
 
        struct stat s;
63
 
};
64
 
 
65
51
static const char *cmdname = "ls";
66
52
 
 
53
static ls_job_t ls;
 
54
 
67
55
static struct option const long_options[] = {
68
56
        { "help", no_argument, 0, 'h' },
69
57
        { "unsort", no_argument, 0, 'u' },
 
58
        { "recursive", no_argument, 0, 'r' },
70
59
        { 0, 0, 0, 0 }
71
60
};
72
61
 
 
62
/* Prototypes for the ls command, excluding entry points. */
 
63
static unsigned int ls_start(ls_job_t *);
 
64
static void ls_print(struct dir_elem_t *);
 
65
static int ls_cmp(void *, void *, void *);
 
66
static signed int ls_scan_dir(const char *, DIR *, struct dir_elem_t **);
 
67
static unsigned int ls_recursive(const char *, DIR *);
 
68
static unsigned int ls_scope(const char *, struct dir_elem_t *);
 
69
 
 
70
static unsigned int ls_start(ls_job_t *ls)
 
71
{
 
72
        ls->recursive = 0;
 
73
        ls->sort = 1;
 
74
 
 
75
        return 1;
 
76
}
 
77
 
73
78
/** Print an entry.
74
79
 *
75
80
 * ls_print currently does nothing more than print the entry.
91
96
                printf("%-40s\n", de->name);
92
97
}
93
98
 
94
 
 
95
99
/** Compare 2 directory elements.
96
100
 *
97
101
 * It compares 2 elements of a directory : a file is considered
126
130
 * @param sort  1 if the output must be sorted,
127
131
 *                              0 otherwise.
128
132
 */
129
 
static void ls_scan_dir(const char *d, DIR *dirp, int sort)
 
133
static signed int ls_scan_dir(const char *d, DIR *dirp, 
 
134
    struct dir_elem_t **dir_list_ptr)
130
135
{
131
136
        int alloc_blocks = 20;
132
137
        int i;
139
144
        struct dirent *dp;
140
145
        
141
146
        if (!dirp)
142
 
                return;
 
147
                return -1;
143
148
 
144
149
        buff = (char *) malloc(PATH_MAX);
145
150
        if (!buff) {
146
151
                cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
147
 
                return;
 
152
                return -1;
148
153
        }
149
154
        
150
155
        tosort = (struct dir_elem_t *) malloc(alloc_blocks * sizeof(*tosort));
151
156
        if (!tosort) {
152
157
                cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
153
158
                free(buff);
154
 
                return;
 
159
                return -1;
155
160
        }
156
161
        
157
162
        while ((dp = readdir(dirp))) {
186
191
                }
187
192
        }
188
193
        
189
 
        if (sort) {
 
194
        if (ls.sort) {
190
195
                if (!qsort(&tosort[0], nbdirs, sizeof(struct dir_elem_t),
191
196
                    ls_cmp, NULL)) {
192
197
                        printf("Sorting error.\n");
195
200
        
196
201
        for (i = 0; i < nbdirs; i++)
197
202
                ls_print(&tosort[i]);
 
203
 
 
204
        /* Populate the directory list. */
 
205
        if (ls.recursive) {
 
206
                tmp = (struct dir_elem_t *) realloc(*dir_list_ptr, 
 
207
                    nbdirs * sizeof(struct dir_elem_t));
 
208
                if (!tmp) {
 
209
                        cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
 
210
                        goto out;
 
211
                } 
 
212
                *dir_list_ptr = tmp;
 
213
 
 
214
                for (i = 0; i < nbdirs; i++) {
 
215
                        (*dir_list_ptr)[i].name = str_dup(tosort[i].name);
 
216
                        if (!(*dir_list_ptr)[i].name) {
 
217
                                cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
 
218
                                goto out;
 
219
                        }
 
220
                }
 
221
        }
198
222
        
199
223
out:
200
224
        for(i = 0; i < nbdirs; i++)
201
225
                free(tosort[i].name);
202
226
        free(tosort);
203
227
        free(buff);
 
228
 
 
229
        return nbdirs;
 
230
}
 
231
 
 
232
/** Visit a directory recursively.
 
233
 *
 
234
 * ls_recursive visits all the subdirectories recursively and
 
235
 * prints the files and directories in them.
 
236
 *
 
237
 * @param path  Path the current directory being visited.
 
238
 * @param dirp  Directory stream.
 
239
 */
 
240
static unsigned int ls_recursive(const char *path, DIR *dirp)
 
241
{
 
242
        int i, nbdirs, ret;
 
243
        unsigned int scope;
 
244
        char *subdir_path;
 
245
        DIR *subdirp;
 
246
        struct dir_elem_t *dir_list;
 
247
        
 
248
        const char * const trailing_slash = "/";
 
249
 
 
250
        nbdirs = 0;
 
251
        dir_list = (struct dir_elem_t *) malloc(sizeof(struct dir_elem_t));
 
252
 
 
253
        printf("\n%s:\n", path);
 
254
 
 
255
        subdir_path = (char *) malloc(PATH_MAX);
 
256
        if (!subdir_path) {
 
257
                ret = CMD_FAILURE;
 
258
                goto out;
 
259
        }
 
260
 
 
261
        nbdirs = ls_scan_dir(path, dirp, &dir_list); 
 
262
        if (nbdirs == -1) {
 
263
                ret = CMD_FAILURE;
 
264
                goto out;
 
265
        }
 
266
 
 
267
        for (i = 0; i < nbdirs; ++i) {
 
268
                memset(subdir_path, 0, PATH_MAX);
 
269
 
 
270
                if (str_size(subdir_path) + str_size(path) + 1 <= PATH_MAX)
 
271
                        str_append(subdir_path, PATH_MAX, path);
 
272
                if (path[str_size(path)-1] != '/' &&
 
273
                    str_size(subdir_path) + str_size(trailing_slash) + 1 <= PATH_MAX)
 
274
                        str_append(subdir_path, PATH_MAX, trailing_slash);
 
275
                if (str_size(subdir_path) +
 
276
                    str_size(dir_list[i].name) + 1 <= PATH_MAX)
 
277
                        str_append(subdir_path, PATH_MAX, dir_list[i].name);
 
278
 
 
279
                scope = ls_scope(subdir_path, &dir_list[i]);
 
280
                switch (scope) {
 
281
                case LS_FILE:
 
282
                        break;
 
283
                case LS_DIR:
 
284
                        subdirp = opendir(subdir_path);
 
285
                        if (!subdirp) {
 
286
                                /* May have been deleted between scoping it and opening it */
 
287
                                cli_error(CL_EFAIL, "Could not stat %s", dir_list[i].name);
 
288
                                ret = CMD_FAILURE;
 
289
                                goto out;
 
290
                        }
 
291
 
 
292
                        ret = ls_recursive(subdir_path, subdirp);
 
293
                        closedir(subdirp);
 
294
                        if (ret == CMD_FAILURE)
 
295
                                goto out;
 
296
                        break;
 
297
                case LS_BOGUS:
 
298
                        ret = CMD_FAILURE;
 
299
                        goto out;
 
300
                }       
 
301
        }
 
302
   
 
303
        ret = CMD_SUCCESS; 
 
304
 
 
305
out:
 
306
        for (i = 0; i < nbdirs; i++)
 
307
                free(dir_list[i].name);
 
308
        free(dir_list);
 
309
        free(subdir_path);
 
310
 
 
311
        return ret;
 
312
}
 
313
 
 
314
static unsigned int ls_scope(const char *path, struct dir_elem_t *de)
 
315
{
 
316
        if (stat(path, &de->s)) {
 
317
                cli_error(CL_ENOENT, path);
 
318
                return LS_BOGUS;
 
319
        }
 
320
 
 
321
        if (de->s.is_file)
 
322
                return LS_FILE;
 
323
        else if (de->s.is_directory)
 
324
                return LS_DIR;
 
325
 
 
326
        return LS_BOGUS;
204
327
}
205
328
 
206
329
void help_cmd_ls(unsigned int level)
214
337
                "If not path is given, the current working directory is used.\n"
215
338
                "Options:\n"
216
339
                "  -h, --help       A short option summary\n"
217
 
                "  -u, --unsort     Do not sort directory entries\n",
 
340
                "  -u, --unsort     Do not sort directory entries\n"
 
341
                "  -r, --recursive  List subdirectories recursively\n",
218
342
                cmdname);
219
343
        }
220
344
 
227
351
        struct dir_elem_t de;
228
352
        DIR *dirp;
229
353
        int c, opt_ind;
230
 
        int sort = 1;
 
354
        int ret = 0;
 
355
        unsigned int scope;
 
356
 
 
357
        if (!ls_start(&ls)) {
 
358
                cli_error(CL_EFAIL, "%s: Could not initialize", cmdname);
 
359
                return CMD_FAILURE;
 
360
        }
231
361
 
232
362
        argc = cli_count_args(argv);
233
363
        
234
364
        for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
235
 
                c = getopt_long(argc, argv, "hu", long_options, &opt_ind);
 
365
                c = getopt_long(argc, argv, "hur", long_options, &opt_ind);
236
366
                switch (c) {
237
367
                case 'h':
238
368
                        help_cmd_ls(HELP_LONG);
239
369
                        return CMD_SUCCESS;
240
370
                case 'u':
241
 
                        sort = 0;
 
371
                        ls.sort = 0;
 
372
                        break;
 
373
                case 'r':
 
374
                        ls.recursive = 1;
242
375
                        break;
243
376
                }
244
377
        }
250
383
                cli_error(CL_ENOMEM, "%s: ", cmdname);
251
384
                return CMD_FAILURE;
252
385
        }
253
 
        memset(de.name, 0, sizeof(PATH_MAX));
 
386
        memset(de.name, 0, PATH_MAX);
254
387
        
255
388
        if (argc == 0)
256
389
                getcwd(de.name, PATH_MAX);
257
390
        else
258
391
                str_cpy(de.name, PATH_MAX, argv[optind]);
259
 
        
260
 
        if (stat(de.name, &de.s)) {
261
 
                cli_error(CL_ENOENT, de.name);
262
 
                free(de.name);
263
 
                return CMD_FAILURE;
264
 
        }
265
392
 
266
 
        if (de.s.is_file) {
 
393
        scope = ls_scope(de.name, &de);
 
394
        switch (scope) {
 
395
        case LS_FILE:
267
396
                ls_print(&de);
268
 
        } else {
 
397
                break;
 
398
        case LS_DIR:
269
399
                dirp = opendir(de.name);
270
400
                if (!dirp) {
271
401
                        /* May have been deleted between scoping it and opening it */
273
403
                        free(de.name);
274
404
                        return CMD_FAILURE;
275
405
                }
276
 
                ls_scan_dir(de.name, dirp, sort);
 
406
                if (ls.recursive)
 
407
                        ret = ls_recursive(de.name, dirp);
 
408
                else  
 
409
                        ret = ls_scan_dir(de.name, dirp, NULL);
 
410
 
277
411
                closedir(dirp);
 
412
                break;
 
413
        case LS_BOGUS:
 
414
                return CMD_FAILURE;
278
415
        }
279
416
 
280
417
        free(de.name);
281
418
 
282
 
        return CMD_SUCCESS;
 
419
        if (ret == -1 || ret == CMD_FAILURE)
 
420
                return CMD_FAILURE;
 
421
        else
 
422
                return CMD_SUCCESS;
283
423
}
284
424