00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
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
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
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
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