Ignore:
File:
1 edited

Legend:

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

    rcfc3027 r19f857a  
    3838#include <dirent.h>
    3939#include <fcntl.h>
    40 #include <getopt.h>
    4140#include <sys/types.h>
    4241#include <sys/stat.h>
    4342#include <str.h>
    44 #include <sort.h>
    4543
    4644#include "errors.h"
     
    4846#include "util.h"
    4947#include "entry.h"
     48#include "ls.h"
    5049#include "cmds.h"
    51 
    52 /* Various values that can be returned by ls_scope() */
    53 #define LS_BOGUS 0
    54 #define LS_FILE  1
    55 #define LS_DIR   2
    56 
    57 /** Structure to represent a directory entry.
    58  *
    59  * Useful to keep together important information
    60  * for sorting directory entries.
    61  */
    62 struct dir_elem_t {
    63         char *name;
    64         struct stat s;
    65 };
    6650
    6751static const char *cmdname = "ls";
    6852
    69 static struct option const long_options[] = {
    70         { "help", no_argument, 0, 'h' },
    71         { "unsort", no_argument, 0, 'u' },
    72         { 0, 0, 0, 0 }
    73 };
     53static void ls_scan_dir(const char *d, DIR *dirp)
     54{
     55        struct dirent *dp;
     56        char *buff;
    7457
    75 /** Print an entry.
    76  *
    77  * ls_print currently does nothing more than print the entry.
    78  * In the future, we will likely pass the absolute path, and
     58        if (! dirp)
     59                return;
     60
     61        buff = (char *)malloc(PATH_MAX);
     62        if (NULL == buff) {
     63                cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
     64                return;
     65        }
     66
     67        while ((dp = readdir(dirp))) {
     68                memset(buff, 0, sizeof(buff));
     69                /* Don't worry if inserting a double slash, this will be fixed by
     70                 * absolutize() later with subsequent calls to open() or readdir() */
     71                snprintf(buff, PATH_MAX - 1, "%s/%s", d, dp->d_name);
     72                ls_print(dp->d_name, buff);
     73        }
     74
     75        free(buff);
     76
     77        return;
     78}
     79
     80/* ls_print currently does nothing more than print the entry.
     81 * in the future, we will likely pass the absolute path, and
    7982 * some sort of ls_options structure that controls how each
    8083 * entry is printed and what is printed about it.
    8184 *
    82  * Now we just print basic DOS style lists.
    83  *
    84  * @param de            Directory element.
    85  */
    86 static void ls_print(struct dir_elem_t *de)
     85 * Now we just print basic DOS style lists */
     86
     87static void ls_print(const char *name, const char *pathname)
    8788{
    88         if (de->s.is_file)
    89                 printf("%-40s\t%llu\n", de->name, (long long) de->s.size);
    90         else if (de->s.is_directory)
    91                 printf("%-40s\t<dir>\n", de->name);
    92         else
    93                 printf("%-40s\n", de->name);
    94 }
     89        struct stat s;
     90        int rc;
    9591
    96 
    97 /** Compare 2 directory elements.
    98  *
    99  * It compares 2 elements of a directory : a file is considered
    100  * as bigger than a directory, and if they have the same type,
    101  * they are compared alphabetically.
    102  *
    103  * @param a             Pointer to the structure of the first element.
    104  * @param b             Pointer to the structure of the second element.
    105  * @param arg           Pointer for an other and optionnal argument.
    106  *
    107  * @return              -1 if a < b, 1 otherwise.
    108  */
    109 static int ls_cmp(void *a, void *b, void *arg)
    110 {
    111         struct dir_elem_t *da = a;
    112         struct dir_elem_t *db = b;
    113        
    114         if ((da->s.is_directory && db->s.is_file) ||
    115             ((da->s.is_directory == db->s.is_directory) &&
    116             str_cmp(da->name, db->name) < 0))
    117                 return -1;
    118         else
    119                 return 1;
    120 }
    121 
    122 /** Scan a directory.
    123  *
    124  * Scan the content of a directory and print it.
    125  *
    126  * @param d             Name of the directory.
    127  * @param dirp  Directory stream.
    128  * @param sort  1 if the output must be sorted,
    129  *                              0 otherwise.
    130  */
    131 static void ls_scan_dir(const char *d, DIR *dirp, int sort)
    132 {
    133         int alloc_blocks = 20;
    134         int i;
    135         int nbdirs = 0;
    136         int rc;
    137         int len;
    138         char *buff;
    139         struct dir_elem_t *tmp;
    140         struct dir_elem_t *tosort;
    141         struct dirent *dp;
    142        
    143         if (!dirp)
    144                 return;
    145 
    146         buff = (char *) malloc(PATH_MAX);
    147         if (!buff) {
    148                 cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
     92        rc = stat(pathname, &s);
     93        if (rc != 0) {
     94                /* Odd chance it was deleted from the time readdir() found it */
     95                printf("ls: skipping bogus node %s\n", pathname);
     96                printf("rc=%d\n", rc);
    14997                return;
    15098        }
    15199       
    152         tosort = (struct dir_elem_t *) malloc(alloc_blocks * sizeof(*tosort));
    153         if (!tosort) {
    154                 cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
    155                 free(buff);
    156                 return;
    157         }
    158        
    159         while ((dp = readdir(dirp))) {
    160                 if (nbdirs + 1 > alloc_blocks) {
    161                         alloc_blocks += alloc_blocks;
    162                        
    163                         tmp = (struct dir_elem_t *) realloc(tosort,
    164                             alloc_blocks * sizeof(struct dir_elem_t));
    165                         if (!tmp) {
    166                                 cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
    167                                 goto out;
    168                         }
    169                         tosort = tmp;
    170                 }
    171                
    172                 /* fill the name field */
    173                 tosort[nbdirs].name = (char *) malloc(str_length(dp->d_name) + 1);
    174                 if (!tosort[nbdirs].name) {
    175                         cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
    176                         goto out;
    177                 }
    178                
    179                 str_cpy(tosort[nbdirs].name, str_length(dp->d_name) + 1, dp->d_name);
    180                 len = snprintf(buff, PATH_MAX - 1, "%s/%s", d, tosort[nbdirs].name);
    181                 buff[len] = '\0';
     100        if (s.is_file)
     101                printf("%-40s\t%llu\n", name, (long long) s.size);
     102        else if (s.is_directory)
     103                printf("%-40s\t<dir>\n", name);
     104        else
     105                printf("%-40s\n", name);
    182106
    183                 rc = stat(buff, &tosort[nbdirs++].s);
    184                 if (rc != 0) {
    185                         printf("ls: skipping bogus node %s\n", buff);
    186                         printf("rc=%d\n", rc);
    187                         goto out;
    188                 }
    189         }
    190        
    191         if (sort) {
    192                 if (!qsort(&tosort[0], nbdirs, sizeof(struct dir_elem_t),
    193                     ls_cmp, NULL)) {
    194                         printf("Sorting error.\n");
    195                 }
    196         }
    197        
    198         for (i = 0; i < nbdirs; i++)
    199                 ls_print(&tosort[i]);
    200        
    201 out:
    202         for(i = 0; i < nbdirs; i++)
    203                 free(tosort[i].name);
    204         free(tosort);
    205         free(buff);
     107        return;
    206108}
    207109
     
    212114        } else {
    213115                help_cmd_ls(HELP_SHORT);
    214                 printf(
    215                 "Usage:  %s [options] [path]\n"
    216                 "If not path is given, the current working directory is used.\n"
    217                 "Options:\n"
    218                 "  -h, --help       A short option summary\n"
    219                 "  -u, --unsort     Do not sort directory entries\n",
    220                 cmdname);
     116                printf("  `%s' [path], if no path is given the current "
     117                                "working directory is used.\n", cmdname);
    221118        }
    222119
     
    227124{
    228125        unsigned int argc;
    229         struct dir_elem_t de;
     126        struct stat s;
     127        char *buff;
    230128        DIR *dirp;
    231         int c, opt_ind;
    232         int sort = 1;
    233129
    234130        argc = cli_count_args(argv);
    235        
    236         for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
    237                 c = getopt_long(argc, argv, "hu", long_options, &opt_ind);
    238                 switch (c) {
    239                 case 'h':
    240                         help_cmd_ls(HELP_LONG);
    241                         return CMD_SUCCESS;
    242                 case 'u':
    243                         sort = 0;
    244                         break;
    245                 }
    246         }
    247        
    248         argc -= optind;
    249        
    250         de.name = (char *) malloc(PATH_MAX);
    251         if (!de.name) {
     131
     132        buff = (char *) malloc(PATH_MAX);
     133        if (NULL == buff) {
    252134                cli_error(CL_ENOMEM, "%s: ", cmdname);
    253135                return CMD_FAILURE;
    254136        }
    255         memset(de.name, 0, sizeof(PATH_MAX));
    256        
    257         if (argc == 0)
    258                 getcwd(de.name, PATH_MAX);
     137        memset(buff, 0, sizeof(buff));
     138
     139        if (argc == 1)
     140                getcwd(buff, PATH_MAX);
    259141        else
    260                 str_cpy(de.name, PATH_MAX, argv[optind]);
    261        
    262         if (stat(de.name, &de.s)) {
    263                 cli_error(CL_ENOENT, de.name);
    264                 free(de.name);
     142                str_cpy(buff, PATH_MAX, argv[1]);
     143
     144        if (stat(buff, &s)) {
     145                cli_error(CL_ENOENT, buff);
     146                free(buff);
    265147                return CMD_FAILURE;
    266148        }
    267149
    268         if (de.s.is_file) {
    269                 ls_print(&de);
     150        if (s.is_file) {
     151                ls_print(buff, buff);
    270152        } else {
    271                 dirp = opendir(de.name);
     153                dirp = opendir(buff);
    272154                if (!dirp) {
    273155                        /* May have been deleted between scoping it and opening it */
    274                         cli_error(CL_EFAIL, "Could not stat %s", de.name);
    275                         free(de.name);
     156                        cli_error(CL_EFAIL, "Could not stat %s", buff);
     157                        free(buff);
    276158                        return CMD_FAILURE;
    277159                }
    278                 ls_scan_dir(de.name, dirp, sort);
     160                ls_scan_dir(buff, dirp);
    279161                closedir(dirp);
    280162        }
    281163
    282         free(de.name);
     164        free(buff);
    283165
    284166        return CMD_SUCCESS;
Note: See TracChangeset for help on using the changeset viewer.