mdir.c

Go to the documentation of this file.
00001 /*
00002  * mdir.c:
00003  * Display an MSDOS directory
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; /* files in current dir */
00032 static int filesOnDrive; /* files on drive */
00033         
00034 static int dirsOnDrive; /* number of listed directories on this drive */
00035 
00036 static int debug = 0; /* debug mode */
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  * Print an MSDOS directory date stamp.
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  * Print an MSDOS directory time stamp.
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  * Return a number in dotted notation
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             /* warn about negative numbers here.  They should not occur */
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         /* Create the number in maximum width; make sure that the string
00127          * length is not exceeded (in %6ld, the result can be longer than 6!)
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;  /* from here we copy three digits */
00151                 dstp -= 4;  /* that's where we put these 3 digits */
00152         }
00153 
00154         /* now finally copy the 3-byte blocks to their new place */
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                         /* use spaces instead of dots: they please both
00161                          * Americans and Europeans */
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         /* find the volume label */
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                         /* I/O Error */
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; /* still the same */
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(&currentDir);
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; /* still the same directory */
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         /* print directory title */
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                 /* is a subdirectory */
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         /* list top-level directory
00425          *   If this was matched by wildcard in the basename, list it as
00426          *   file, otherwise, list it as directory */
00427         if (mp->basenameHasWildcard) {
00428                 /* wildcard, list it as file */
00429                 return list_file(entry, mp);
00430         } else {
00431                 /* no wildcard, list it as directory */
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         /* first list the files */
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         /* then list subdirectories */
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                                         /* first argument */
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                                 /*recursive = 1;*/
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': /* test mode */
00538                                 testmode = 1;
00539                                 break;
00540 #endif
00541                         default:
00542                                 usage();
00543                 }
00544         }
00545 
00546         /* fake an argument */
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 }

Generated on Fri Apr 14 22:56:55 2006 for minix by  doxygen 1.4.6