00001
00002
00003
00004
00005
00006 #include "sysincludes.h"
00007 #include "msdos.h"
00008 #include "vfat.h"
00009 #include "mtools.h"
00010 #include "file.h"
00011 #include "mainloop.h"
00012 #include "fs.h"
00013 #include "codepage.h"
00014
00015 #ifdef TEST_SIZE
00016 #include "fsP.h"
00017 #endif
00018
00019 static int recursive;
00020 static int wide;
00021 static int all;
00022 static int concise;
00023 static int fast=0;
00024 #if 0
00025 static int testmode = 0;
00026 #endif
00027 static char *dirPath;
00028 static char *currentDrive;
00029 static Stream_t *currentDir;
00030
00031 static int filesInDir;
00032 static int filesOnDrive;
00033
00034 static int dirsOnDrive;
00035
00036 static int debug = 0;
00037
00038 static mt_size_t bytesInDir;
00039 static mt_size_t bytesOnDrive;
00040 static Stream_t *RootDir;
00041
00042
00043 static char shortname[13];
00044 static char longname[VBUFSIZE];
00045
00046
00047
00048
00049
00050 static inline void print_date(struct directory *dir)
00051 {
00052 char year[5];
00053 char day[3];
00054 char month[3];
00055 char *p;
00056
00057 sprintf(year, "%04d", DOS_YEAR(dir));
00058 sprintf(day, "%02d", DOS_DAY(dir));
00059 sprintf(month, "%02d", DOS_MONTH(dir));
00060
00061 for(p=mtools_date_string; *p; p++) {
00062 if(!strncasecmp(p, "yyyy", 4)) {
00063 printf("%04d", DOS_YEAR(dir));
00064 p+= 3;
00065 continue;
00066 } else if(!strncasecmp(p, "yy", 2)) {
00067 printf("%02d", DOS_YEAR(dir) % 100);
00068 p++;
00069 continue;
00070 } else if(!strncasecmp(p, "dd", 2)) {
00071 printf("%02d", DOS_DAY(dir));
00072 p++;
00073 continue;
00074 } else if(!strncasecmp(p, "mm", 2)) {
00075 printf("%02d", DOS_MONTH(dir));
00076 p++;
00077 continue;
00078 }
00079 putchar(*p);
00080 }
00081 }
00082
00083
00084
00085
00086 static inline void print_time(struct directory *dir)
00087 {
00088 char am_pm;
00089 int hour = DOS_HOUR(dir);
00090
00091 if(!mtools_twenty_four_hour_clock) {
00092 am_pm = (hour >= 12) ? 'p' : 'a';
00093 if (hour > 12)
00094 hour = hour - 12;
00095 if (hour == 0)
00096 hour = 12;
00097 } else
00098 am_pm = ' ';
00099
00100 printf("%2d:%02d%c", hour, DOS_MINUTE(dir), am_pm);
00101 }
00102
00103
00104
00105
00106 static const char *dotted_num(mt_size_t num, int width, char **buf)
00107 {
00108 int len;
00109 register char *srcp, *dstp;
00110 int size;
00111
00112 unsigned long numlo;
00113 unsigned long numhi;
00114
00115 if (num < 0) {
00116
00117 fprintf(stderr, "Invalid negative number\n");
00118 }
00119
00120 size = width + width;
00121 *buf = malloc(size+1);
00122
00123 if (*buf == NULL)
00124 return "";
00125
00126
00127
00128
00129
00130 numlo = num % 1000000000;
00131 numhi = num / 1000000000;
00132
00133 if(numhi && size > 9) {
00134 sprintf(*buf, "%.*lu%09lu", size-9, numhi, numlo);
00135 } else {
00136 sprintf(*buf, "%.*lu", size, numlo);
00137 }
00138
00139 for (srcp=*buf; srcp[1] != '\0'; ++srcp)
00140 if (srcp[0] == '0')
00141 srcp[0] = ' ';
00142 else
00143 break;
00144
00145 len = strlen(*buf);
00146 srcp = (*buf)+len;
00147 dstp = (*buf)+len+1;
00148
00149 for ( ; dstp >= (*buf)+4 && isdigit (srcp[-1]); ) {
00150 srcp -= 3;
00151 dstp -= 4;
00152 }
00153
00154
00155 while (dstp < (*buf) + len) {
00156 dstp[0] = srcp[0];
00157 dstp[1] = srcp[1];
00158 dstp[2] = srcp[2];
00159 if (dstp + 3 < (*buf) + len)
00160
00161
00162 dstp[3] = ' ';
00163 srcp += 3;
00164 dstp += 4;
00165 }
00166
00167 return (*buf) + len-width;
00168 }
00169
00170 static inline int print_volume_label(Stream_t *Dir, char *drive)
00171 {
00172 Stream_t *Stream = GetFs(Dir);
00173 direntry_t entry;
00174 DeclareThis(FsPublic_t);
00175 char shortname[13];
00176 char longname[VBUFSIZE];
00177 int r;
00178
00179 RootDir = OpenRoot(Stream);
00180 if(concise)
00181 return 0;
00182
00183
00184
00185 initializeDirentry(&entry, RootDir);
00186 if((r=vfat_lookup(&entry, 0, 0, ACCEPT_LABEL | MATCH_ANY,
00187 shortname, longname)) ) {
00188 if (r == -2) {
00189
00190 return -1;
00191 }
00192 printf(" Volume in drive %s has no label", drive);
00193 } else if (*longname)
00194 printf(" Volume in drive %s is %s (abbr=%s)",
00195 drive, longname, shortname);
00196 else
00197 printf(" Volume in drive %s is %s",
00198 drive, shortname);
00199 if(This->serialized)
00200 printf("\n Volume Serial Number is %04lX-%04lX",
00201 (This->serial_number >> 16) & 0xffff,
00202 This->serial_number & 0xffff);
00203 return 0;
00204 }
00205
00206
00207 static void printSummary(int files, mt_size_t bytes)
00208 {
00209 if(!filesInDir)
00210 printf("No files\n");
00211 else {
00212 char *s1;
00213 printf(" %3d file", files);
00214 if(files == 1)
00215 putchar(' ');
00216 else
00217 putchar('s');
00218 printf(" %s bytes\n",
00219 dotted_num(bytes, 13, &s1));
00220 if(s1)
00221 free(s1);
00222 }
00223 }
00224
00225 static void leaveDirectory(int haveError);
00226
00227 static void leaveDrive(int haveError)
00228 {
00229 if(!currentDrive)
00230 return;
00231 leaveDirectory(haveError);
00232 if(!concise && !haveError) {
00233 char *s1;
00234
00235 if(dirsOnDrive > 1) {
00236 printf("\nTotal files listed:\n");
00237 printSummary(filesOnDrive, bytesOnDrive);
00238 }
00239 if(RootDir && !fast) {
00240 mt_off_t bytes = getfree(RootDir);
00241 printf(" %s bytes free\n\n",
00242 dotted_num(bytes,17, &s1));
00243 #ifdef TEST_SIZE
00244 ((Fs_t*)GetFs(RootDir))->freeSpace = 0;
00245 bytes = getfree(RootDir);
00246 printf(" %s bytes free\n\n",
00247 dotted_num(bytes,17, &s1));
00248 #endif
00249 }
00250 if(s1)
00251 free(s1);
00252 }
00253 FREE(&RootDir);
00254 currentDrive = NULL;
00255 }
00256
00257
00258 static int enterDrive(Stream_t *Dir, char *drive)
00259 {
00260 int r;
00261 if(currentDrive != NULL && strcmp(currentDrive, drive) == 0)
00262 return 0;
00263
00264 leaveDrive(0);
00265 currentDrive = drive;
00266
00267 r = print_volume_label(Dir, drive);
00268 if (r)
00269 return r;
00270
00271
00272 bytesOnDrive = 0;
00273 filesOnDrive = 0;
00274 dirsOnDrive = 0;
00275 return 0;
00276 }
00277
00278 static char *emptyString="<out-of-memory>";
00279
00280 static void leaveDirectory(int haveError)
00281 {
00282 if(!currentDir)
00283 return;
00284
00285 if (!haveError) {
00286 if(dirPath && dirPath != emptyString)
00287 free(dirPath);
00288 if(wide)
00289 putchar('\n');
00290
00291 if(!concise)
00292 printSummary(filesInDir, bytesInDir);
00293 }
00294 FREE(¤tDir);
00295 }
00296
00297 static int enterDirectory(Stream_t *Dir)
00298 {
00299 int r;
00300 char *drive;
00301 char *slash;
00302
00303 if(currentDir == Dir)
00304 return 0;
00305
00306 leaveDirectory(0);
00307
00308 drive = getDrive(Dir);
00309 r=enterDrive(Dir, drive);
00310 if(r)
00311 return r;
00312 currentDir = COPY(Dir);
00313
00314 dirPath = getPwd(getDirentry(Dir));
00315 if(!dirPath)
00316 dirPath=emptyString;
00317 if(concise &&
00318 (slash = strrchr(dirPath, '/')) != NULL && slash[1] == '\0')
00319 *slash = '\0';
00320
00321
00322 if(!concise)
00323 printf("\nDirectory for %s\n", dirPath);
00324
00325 if(!wide && !concise)
00326 printf("\n");
00327
00328 dirsOnDrive++;
00329 bytesInDir = 0;
00330 filesInDir = 0;
00331 return 0;
00332 }
00333
00334 static int list_file(direntry_t *entry, MainParam_t *mp)
00335 {
00336 unsigned long size;
00337 int i;
00338 int Case;
00339 int r;
00340
00341 if(!all && (entry->dir.attr & 0x6))
00342 return 0;
00343
00344 if(concise && isSpecial(entry->name))
00345 return 0;
00346
00347 r=enterDirectory(entry->Dir);
00348 if (r)
00349 return ERROR_ONE;
00350 if (wide) {
00351 if(filesInDir % 5)
00352 putchar(' ');
00353 else
00354 putchar('\n');
00355 }
00356
00357 if(IS_DIR(entry)){
00358 size = 0;
00359 } else
00360 size = FILE_SIZE(&entry->dir);
00361
00362 Case = entry->dir.Case;
00363 if(!(Case & (BASECASE | EXTCASE)) &&
00364 mtools_ignore_short_case)
00365 Case |= BASECASE | EXTCASE;
00366
00367 if(Case & EXTCASE){
00368 for(i=0; i<3;i++)
00369 entry->dir.ext[i] = tolower(entry->dir.ext[i]);
00370 }
00371 to_unix(entry->dir.ext,3);
00372 if(Case & BASECASE){
00373 for(i=0; i<8;i++)
00374 entry->dir.name[i] = tolower(entry->dir.name[i]);
00375 }
00376 to_unix(entry->dir.name,8);
00377 if(wide){
00378 if(IS_DIR(entry))
00379 printf("[%s]%*s", shortname,
00380 (int) (15 - 2 - strlen(shortname)), "");
00381 else
00382 printf("%-15s", shortname);
00383 } else if(!concise) {
00384
00385 if(mtools_dotted_dir)
00386 printf("%-13s", shortname);
00387 else
00388 printf("%-8.8s %-3.3s ",
00389 entry->dir.name,
00390 entry->dir.ext);
00391 if(IS_DIR(entry))
00392 printf("<DIR> ");
00393 else
00394 printf(" %8ld", (long) size);
00395 printf(" ");
00396 print_date(&entry->dir);
00397 printf(" ");
00398 print_time(&entry->dir);
00399
00400 if(debug)
00401 printf(" %s %d ", entry->dir.name, START(&entry->dir));
00402
00403 if(*longname)
00404 printf(" %s", longname);
00405 printf("\n");
00406 } else {
00407 printf("%s/%s", dirPath, entry->name);
00408 if(IS_DIR(entry))
00409 putchar('/');
00410 putchar('\n');
00411 }
00412
00413 filesOnDrive++;
00414 filesInDir++;
00415
00416 bytesOnDrive += (mt_size_t) size;
00417 bytesInDir += (mt_size_t) size;
00418 return GOT_ONE;
00419 }
00420
00421 static int list_non_recurs_directory(direntry_t *entry, MainParam_t *mp)
00422 {
00423 int r;
00424
00425
00426
00427 if (mp->basenameHasWildcard) {
00428
00429 return list_file(entry, mp);
00430 } else {
00431
00432 MainParam_t subMp;
00433
00434 r=enterDirectory(mp->File);
00435 if(r)
00436 return ERROR_ONE;
00437
00438 subMp = *mp;
00439 subMp.dirCallback = subMp.callback;
00440 return mp->loop(mp->File, &subMp, "*") | GOT_ONE;
00441 }
00442 }
00443
00444
00445 static int list_recurs_directory(direntry_t *entry, MainParam_t *mp)
00446 {
00447 MainParam_t subMp;
00448 int ret;
00449
00450
00451 subMp = *mp;
00452 subMp.lookupflags = ACCEPT_DIR | ACCEPT_PLAIN;
00453 subMp.dirCallback = list_file;
00454 subMp.callback = list_file;
00455
00456 ret = mp->loop(mp->File, &subMp, "*");
00457
00458
00459 subMp = *mp;
00460 subMp.lookupflags = ACCEPT_DIR | NO_DOTS | NO_MSG | DO_OPEN;
00461 return ret | mp->loop(mp->File, &subMp, "*");
00462 }
00463
00464 #if 0
00465 static int test_directory(direntry_t *entry, MainParam_t *mp)
00466 {
00467 Stream_t *File=mp->File;
00468 Stream_t *Target;
00469 char errmsg[80];
00470
00471 if ((Target = SimpleFileOpen(0, 0, "-",
00472 O_WRONLY,
00473 errmsg, 0, 0, 0))) {
00474 copyfile(File, Target);
00475 FREE(&Target);
00476 }
00477 return GOT_ONE;
00478 }
00479 #endif
00480
00481 static void usage(void)
00482 {
00483 fprintf(stderr, "Mtools version %s, dated %s\n",
00484 mversion, mdate);
00485 fprintf(stderr, "Usage: %s: [-waXbfds/] msdosdirectory\n",
00486 progname);
00487 fprintf(stderr,
00488 " %s: [-waXbfds/] msdosfile [msdosfiles...]\n",
00489 progname);
00490 fprintf(stderr,
00491 "\t-w Wide listing\n"
00492 "\t-a All, including hidden files\n"
00493 "\t-b -X Concise listing\n"
00494 "\t-f Fast, no free space summary\n"
00495 "\t-d Debug mode\n"
00496 "\t-s -/ Recursive\n");
00497 exit(1);
00498 }
00499
00500
00501 void mdir(int argc, char **argv, int type)
00502 {
00503 int ret;
00504 MainParam_t mp;
00505 int faked;
00506 int c;
00507 char *fakedArgv[] = { "." };
00508
00509 concise = 0;
00510 recursive = 0;
00511 wide = all = 0;
00512
00513 while ((c = getopt(argc, argv, "waXbfds/")) != EOF) {
00514 switch(c) {
00515 case 'w':
00516 wide = 1;
00517 break;
00518 case 'a':
00519 all = 1;
00520 break;
00521 case 'b':
00522 case 'X':
00523 concise = 1;
00524
00525 break;
00526 case 's':
00527 case '/':
00528 recursive = 1;
00529 break;
00530 case 'f':
00531 fast = 1;
00532 break;
00533 case 'd':
00534 debug = 1;
00535 break;
00536 #if 0
00537 case 't':
00538 testmode = 1;
00539 break;
00540 #endif
00541 default:
00542 usage();
00543 }
00544 }
00545
00546
00547 faked = 0;
00548 if (optind == argc) {
00549 argv = fakedArgv;
00550 argc = 1;
00551 optind = 0;
00552 }
00553
00554 init_mp(&mp);
00555 currentDrive = '\0';
00556 currentDir = 0;
00557 RootDir = 0;
00558 dirPath = 0;
00559 #if 0
00560 if (testmode) {
00561 mp.lookupflags = ACCEPT_DIR | NO_DOTS;
00562 mp.dirCallback = test_directory;
00563 } else
00564 #endif
00565 if(recursive) {
00566 mp.lookupflags = ACCEPT_DIR | DO_OPEN_DIRS | NO_DOTS;
00567 mp.dirCallback = list_recurs_directory;
00568 } else {
00569 mp.lookupflags = ACCEPT_DIR | ACCEPT_PLAIN | DO_OPEN_DIRS;
00570 mp.dirCallback = list_non_recurs_directory;
00571 mp.callback = list_file;
00572 }
00573 mp.longname = longname;
00574 mp.shortname = shortname;
00575 ret=main_loop(&mp, argv + optind, argc - optind);
00576 leaveDirectory(ret);
00577 leaveDrive(ret);
00578 exit(ret);
00579 }