ls.c

00001 /* Copyright (c) 2008, Tim Post <tinkertim@gmail.com>
00002  * All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions are met:
00006  *
00007  * Redistributions of source code must retain the above copyright notice, this
00008  * list of conditions and the following disclaimer.
00009  *
00010  * Redistributions in binary form must reproduce the above copyright notice,
00011  * this list of conditions and the following disclaimer in the documentation
00012  * and/or other materials provided with the distribution.
00013  *
00014  * Neither the name of the original program's authors nor the names of its
00015  * contributors may be used to endorse or promote products derived from this
00016  * software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028  * POSSIBILITY OF SUCH DAMAGE.
00029  */
00030 
00031 /* NOTE:
00032  * This is a bit of an ugly hack, working around the absence of fstat / etc.
00033  * As more stuff is completed and exposed in libc, this will improve */
00034 
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <unistd.h>
00038 #include <dirent.h>
00039 #include <fcntl.h>
00040 #include <getopt.h>
00041 #include <sys/types.h>
00042 #include <sys/stat.h>
00043 #include <str.h>
00044 #include <sort.h>
00045 
00046 #include "errors.h"
00047 #include "config.h"
00048 #include "util.h"
00049 #include "entry.h"
00050 #include "cmds.h"
00051 
00052 /* Various values that can be returned by ls_scope() */
00053 #define LS_BOGUS 0
00054 #define LS_FILE  1
00055 #define LS_DIR   2
00056 
00062 struct dir_elem_t {
00063         char *name;
00064         struct stat s;
00065 };
00066 
00067 static const char *cmdname = "ls";
00068 
00069 static struct option const long_options[] = {
00070         { "help", no_argument, 0, 'h' },
00071         { "unsort", no_argument, 0, 'u' },
00072         { 0, 0, 0, 0 }
00073 };
00074 
00086 static void ls_print(struct dir_elem_t *de)
00087 {
00088         if (de->s.is_file)
00089                 printf("%-40s\t%llu\n", de->name, (long long) de->s.size);
00090         else if (de->s.is_directory)
00091                 printf("%-40s\t<dir>\n", de->name);
00092         else
00093                 printf("%-40s\n", de->name);
00094 }
00095 
00096 
00109 static int ls_cmp(void *a, void *b, void *arg)
00110 {
00111         struct dir_elem_t *da = a;
00112         struct dir_elem_t *db = b;
00113         
00114         if ((da->s.is_directory && db->s.is_file) ||
00115             ((da->s.is_directory == db->s.is_directory) &&
00116             str_cmp(da->name, db->name) < 0))
00117                 return -1;
00118         else
00119                 return 1;
00120 }
00121 
00131 static void ls_scan_dir(const char *d, DIR *dirp, int sort)
00132 {
00133         int alloc_blocks = 20;
00134         int i;
00135         int nbdirs = 0;
00136         int rc;
00137         int len;
00138         char *buff;
00139         struct dir_elem_t *tmp;
00140         struct dir_elem_t *tosort;
00141         struct dirent *dp;
00142         
00143         if (!dirp)
00144                 return;
00145 
00146         buff = (char *) malloc(PATH_MAX);
00147         if (!buff) {
00148                 cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
00149                 return;
00150         }
00151         
00152         tosort = (struct dir_elem_t *) malloc(alloc_blocks * sizeof(*tosort));
00153         if (!tosort) {
00154                 cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
00155                 free(buff);
00156                 return;
00157         }
00158         
00159         while ((dp = readdir(dirp))) {
00160                 if (nbdirs + 1 > alloc_blocks) {
00161                         alloc_blocks += alloc_blocks;
00162                         
00163                         tmp = (struct dir_elem_t *) realloc(tosort,
00164                             alloc_blocks * sizeof(struct dir_elem_t));
00165                         if (!tmp) {
00166                                 cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
00167                                 goto out;
00168                         }
00169                         tosort = tmp;
00170                 }
00171                 
00172                 /* fill the name field */
00173                 tosort[nbdirs].name = (char *) malloc(str_length(dp->d_name) + 1);
00174                 if (!tosort[nbdirs].name) {
00175                         cli_error(CL_ENOMEM, "ls: failed to scan %s", d);
00176                         goto out;
00177                 }
00178                 
00179                 str_cpy(tosort[nbdirs].name, str_length(dp->d_name) + 1, dp->d_name);
00180                 len = snprintf(buff, PATH_MAX - 1, "%s/%s", d, tosort[nbdirs].name);
00181                 buff[len] = '\0';
00182 
00183                 rc = stat(buff, &tosort[nbdirs++].s);
00184                 if (rc != 0) {
00185                         printf("ls: skipping bogus node %s\n", buff);
00186                         printf("rc=%d\n", rc);
00187                         goto out;
00188                 }
00189         }
00190         
00191         if (sort) {
00192                 if (!qsort(&tosort[0], nbdirs, sizeof(struct dir_elem_t),
00193                     ls_cmp, NULL)) {
00194                         printf("Sorting error.\n");
00195                 }
00196         }
00197         
00198         for (i = 0; i < nbdirs; i++)
00199                 ls_print(&tosort[i]);
00200         
00201 out:
00202         for(i = 0; i < nbdirs; i++)
00203                 free(tosort[i].name);
00204         free(tosort);
00205         free(buff);
00206 }
00207 
00208 void help_cmd_ls(unsigned int level)
00209 {
00210         if (level == HELP_SHORT) {
00211                 printf("`%s' lists files and directories.\n", cmdname);
00212         } else {
00213                 help_cmd_ls(HELP_SHORT);
00214                 printf(
00215                 "Usage:  %s [options] [path]\n"
00216                 "If not path is given, the current working directory is used.\n"
00217                 "Options:\n"
00218                 "  -h, --help       A short option summary\n"
00219                 "  -u, --unsort     Do not sort directory entries\n",
00220                 cmdname);
00221         }
00222 
00223         return;
00224 }
00225 
00226 int cmd_ls(char **argv)
00227 {
00228         unsigned int argc;
00229         struct dir_elem_t de;
00230         DIR *dirp;
00231         int c, opt_ind;
00232         int sort = 1;
00233 
00234         argc = cli_count_args(argv);
00235         
00236         for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
00237                 c = getopt_long(argc, argv, "hu", long_options, &opt_ind);
00238                 switch (c) {
00239                 case 'h':
00240                         help_cmd_ls(HELP_LONG);
00241                         return CMD_SUCCESS;
00242                 case 'u':
00243                         sort = 0;
00244                         break;
00245                 }
00246         }
00247         
00248         argc -= optind;
00249         
00250         de.name = (char *) malloc(PATH_MAX);
00251         if (!de.name) {
00252                 cli_error(CL_ENOMEM, "%s: ", cmdname);
00253                 return CMD_FAILURE;
00254         }
00255         memset(de.name, 0, sizeof(PATH_MAX));
00256         
00257         if (argc == 0)
00258                 getcwd(de.name, PATH_MAX);
00259         else
00260                 str_cpy(de.name, PATH_MAX, argv[optind]);
00261         
00262         if (stat(de.name, &de.s)) {
00263                 cli_error(CL_ENOENT, de.name);
00264                 free(de.name);
00265                 return CMD_FAILURE;
00266         }
00267 
00268         if (de.s.is_file) {
00269                 ls_print(&de);
00270         } else {
00271                 dirp = opendir(de.name);
00272                 if (!dirp) {
00273                         /* May have been deleted between scoping it and opening it */
00274                         cli_error(CL_EFAIL, "Could not stat %s", de.name);
00275                         free(de.name);
00276                         return CMD_FAILURE;
00277                 }
00278                 ls_scan_dir(de.name, dirp, sort);
00279                 closedir(dirp);
00280         }
00281 
00282         free(de.name);
00283 
00284         return CMD_SUCCESS;
00285 }
00286 

Generated on Thu Jun 2 07:45:41 2011 for HelenOS/USB by  doxygen 1.4.7