source: trunk/minix/commands/i386/mtools-3.9.7/mdir.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 11.1 KB
Line 
1/*
2 * mdir.c:
3 * Display an MSDOS directory
4 */
5
6#include "sysincludes.h"
7#include "msdos.h"
8#include "vfat.h"
9#include "mtools.h"
10#include "file.h"
11#include "mainloop.h"
12#include "fs.h"
13#include "codepage.h"
14
15#ifdef TEST_SIZE
16#include "fsP.h"
17#endif
18
19static int recursive;
20static int wide;
21static int all;
22static int concise;
23static int fast=0;
24#if 0
25static int testmode = 0;
26#endif
27static char *dirPath;
28static char *currentDrive;
29static Stream_t *currentDir;
30
31static int filesInDir; /* files in current dir */
32static int filesOnDrive; /* files on drive */
33
34static int dirsOnDrive; /* number of listed directories on this drive */
35
36static int debug = 0; /* debug mode */
37
38static mt_size_t bytesInDir;
39static mt_size_t bytesOnDrive;
40static Stream_t *RootDir;
41
42
43static char shortname[13];
44static char longname[VBUFSIZE];
45
46
47/*
48 * Print an MSDOS directory date stamp.
49 */
50static inline void print_date(struct directory *dir)
51{
52 char year[5];
53 char day[3];
54 char month[3];
55 char *p;
56
57 sprintf(year, "%04d", DOS_YEAR(dir));
58 sprintf(day, "%02d", DOS_DAY(dir));
59 sprintf(month, "%02d", DOS_MONTH(dir));
60
61 for(p=mtools_date_string; *p; p++) {
62 if(!strncasecmp(p, "yyyy", 4)) {
63 printf("%04d", DOS_YEAR(dir));
64 p+= 3;
65 continue;
66 } else if(!strncasecmp(p, "yy", 2)) {
67 printf("%02d", DOS_YEAR(dir) % 100);
68 p++;
69 continue;
70 } else if(!strncasecmp(p, "dd", 2)) {
71 printf("%02d", DOS_DAY(dir));
72 p++;
73 continue;
74 } else if(!strncasecmp(p, "mm", 2)) {
75 printf("%02d", DOS_MONTH(dir));
76 p++;
77 continue;
78 }
79 putchar(*p);
80 }
81}
82
83/*
84 * Print an MSDOS directory time stamp.
85 */
86static inline void print_time(struct directory *dir)
87{
88 char am_pm;
89 int hour = DOS_HOUR(dir);
90
91 if(!mtools_twenty_four_hour_clock) {
92 am_pm = (hour >= 12) ? 'p' : 'a';
93 if (hour > 12)
94 hour = hour - 12;
95 if (hour == 0)
96 hour = 12;
97 } else
98 am_pm = ' ';
99
100 printf("%2d:%02d%c", hour, DOS_MINUTE(dir), am_pm);
101}
102
103/*
104 * Return a number in dotted notation
105 */
106static const char *dotted_num(mt_size_t num, int width, char **buf)
107{
108 int len;
109 register char *srcp, *dstp;
110 int size;
111
112 unsigned long numlo;
113 unsigned long numhi;
114
115 if (num < 0) {
116 /* warn about negative numbers here. They should not occur */
117 fprintf(stderr, "Invalid negative number\n");
118 }
119
120 size = width + width;
121 *buf = malloc(size+1);
122
123 if (*buf == NULL)
124 return "";
125
126 /* Create the number in maximum width; make sure that the string
127 * length is not exceeded (in %6ld, the result can be longer than 6!)
128 */
129
130 numlo = num % 1000000000;
131 numhi = num / 1000000000;
132
133 if(numhi && size > 9) {
134 sprintf(*buf, "%.*lu%09lu", size-9, numhi, numlo);
135 } else {
136 sprintf(*buf, "%.*lu", size, numlo);
137 }
138
139 for (srcp=*buf; srcp[1] != '\0'; ++srcp)
140 if (srcp[0] == '0')
141 srcp[0] = ' ';
142 else
143 break;
144
145 len = strlen(*buf);
146 srcp = (*buf)+len;
147 dstp = (*buf)+len+1;
148
149 for ( ; dstp >= (*buf)+4 && isdigit (srcp[-1]); ) {
150 srcp -= 3; /* from here we copy three digits */
151 dstp -= 4; /* that's where we put these 3 digits */
152 }
153
154 /* now finally copy the 3-byte blocks to their new place */
155 while (dstp < (*buf) + len) {
156 dstp[0] = srcp[0];
157 dstp[1] = srcp[1];
158 dstp[2] = srcp[2];
159 if (dstp + 3 < (*buf) + len)
160 /* use spaces instead of dots: they please both
161 * Americans and Europeans */
162 dstp[3] = ' ';
163 srcp += 3;
164 dstp += 4;
165 }
166
167 return (*buf) + len-width;
168}
169
170static inline int print_volume_label(Stream_t *Dir, char *drive)
171{
172 Stream_t *Stream = GetFs(Dir);
173 direntry_t entry;
174 DeclareThis(FsPublic_t);
175 char shortname[13];
176 char longname[VBUFSIZE];
177 int r;
178
179 RootDir = OpenRoot(Stream);
180 if(concise)
181 return 0;
182
183 /* find the volume label */
184
185 initializeDirentry(&entry, RootDir);
186 if((r=vfat_lookup(&entry, 0, 0, ACCEPT_LABEL | MATCH_ANY,
187 shortname, longname)) ) {
188 if (r == -2) {
189 /* I/O Error */
190 return -1;
191 }
192 printf(" Volume in drive %s has no label", drive);
193 } else if (*longname)
194 printf(" Volume in drive %s is %s (abbr=%s)",
195 drive, longname, shortname);
196 else
197 printf(" Volume in drive %s is %s",
198 drive, shortname);
199 if(This->serialized)
200 printf("\n Volume Serial Number is %04lX-%04lX",
201 (This->serial_number >> 16) & 0xffff,
202 This->serial_number & 0xffff);
203 return 0;
204}
205
206
207static void printSummary(int files, mt_size_t bytes)
208{
209 if(!filesInDir)
210 printf("No files\n");
211 else {
212 char *s1;
213 printf(" %3d file", files);
214 if(files == 1)
215 putchar(' ');
216 else
217 putchar('s');
218 printf(" %s bytes\n",
219 dotted_num(bytes, 13, &s1));
220 if(s1)
221 free(s1);
222 }
223}
224
225static void leaveDirectory(int haveError);
226
227static void leaveDrive(int haveError)
228{
229 if(!currentDrive)
230 return;
231 leaveDirectory(haveError);
232 if(!concise && !haveError) {
233 char *s1;
234
235 if(dirsOnDrive > 1) {
236 printf("\nTotal files listed:\n");
237 printSummary(filesOnDrive, bytesOnDrive);
238 }
239 if(RootDir && !fast) {
240 mt_off_t bytes = getfree(RootDir);
241 printf(" %s bytes free\n\n",
242 dotted_num(bytes,17, &s1));
243#ifdef TEST_SIZE
244 ((Fs_t*)GetFs(RootDir))->freeSpace = 0;
245 bytes = getfree(RootDir);
246 printf(" %s bytes free\n\n",
247 dotted_num(bytes,17, &s1));
248#endif
249 }
250 if(s1)
251 free(s1);
252 }
253 FREE(&RootDir);
254 currentDrive = NULL;
255}
256
257
258static int enterDrive(Stream_t *Dir, char *drive)
259{
260 int r;
261 if(currentDrive != NULL && strcmp(currentDrive, drive) == 0)
262 return 0; /* still the same */
263
264 leaveDrive(0);
265 currentDrive = drive;
266
267 r = print_volume_label(Dir, drive);
268 if (r)
269 return r;
270
271
272 bytesOnDrive = 0;
273 filesOnDrive = 0;
274 dirsOnDrive = 0;
275 return 0;
276}
277
278static char *emptyString="<out-of-memory>";
279
280static void leaveDirectory(int haveError)
281{
282 if(!currentDir)
283 return;
284
285 if (!haveError) {
286 if(dirPath && dirPath != emptyString)
287 free(dirPath);
288 if(wide)
289 putchar('\n');
290
291 if(!concise)
292 printSummary(filesInDir, bytesInDir);
293 }
294 FREE(&currentDir);
295}
296
297static int enterDirectory(Stream_t *Dir)
298{
299 int r;
300 char *drive;
301 char *slash;
302
303 if(currentDir == Dir)
304 return 0; /* still the same directory */
305
306 leaveDirectory(0);
307
308 drive = getDrive(Dir);
309 r=enterDrive(Dir, drive);
310 if(r)
311 return r;
312 currentDir = COPY(Dir);
313
314 dirPath = getPwd(getDirentry(Dir));
315 if(!dirPath)
316 dirPath=emptyString;
317 if(concise &&
318 (slash = strrchr(dirPath, '/')) != NULL && slash[1] == '\0')
319 *slash = '\0';
320
321 /* print directory title */
322 if(!concise)
323 printf("\nDirectory for %s\n", dirPath);
324
325 if(!wide && !concise)
326 printf("\n");
327
328 dirsOnDrive++;
329 bytesInDir = 0;
330 filesInDir = 0;
331 return 0;
332}
333
334static int list_file(direntry_t *entry, MainParam_t *mp)
335{
336 unsigned long size;
337 int i;
338 int Case;
339 int r;
340
341 if(!all && (entry->dir.attr & 0x6))
342 return 0;
343
344 if(concise && isSpecial(entry->name))
345 return 0;
346
347 r=enterDirectory(entry->Dir);
348 if (r)
349 return ERROR_ONE;
350 if (wide) {
351 if(filesInDir % 5)
352 putchar(' ');
353 else
354 putchar('\n');
355 }
356
357 if(IS_DIR(entry)){
358 size = 0;
359 } else
360 size = FILE_SIZE(&entry->dir);
361
362 Case = entry->dir.Case;
363 if(!(Case & (BASECASE | EXTCASE)) &&
364 mtools_ignore_short_case)
365 Case |= BASECASE | EXTCASE;
366
367 if(Case & EXTCASE){
368 for(i=0; i<3;i++)
369 entry->dir.ext[i] = tolower(entry->dir.ext[i]);
370 }
371 to_unix(entry->dir.ext,3);
372 if(Case & BASECASE){
373 for(i=0; i<8;i++)
374 entry->dir.name[i] = tolower(entry->dir.name[i]);
375 }
376 to_unix(entry->dir.name,8);
377 if(wide){
378 if(IS_DIR(entry))
379 printf("[%s]%*s", shortname,
380 (int) (15 - 2 - strlen(shortname)), "");
381 else
382 printf("%-15s", shortname);
383 } else if(!concise) {
384 /* is a subdirectory */
385 if(mtools_dotted_dir)
386 printf("%-13s", shortname);
387 else
388 printf("%-8.8s %-3.3s ",
389 entry->dir.name,
390 entry->dir.ext);
391 if(IS_DIR(entry))
392 printf("<DIR> ");
393 else
394 printf(" %8ld", (long) size);
395 printf(" ");
396 print_date(&entry->dir);
397 printf(" ");
398 print_time(&entry->dir);
399
400 if(debug)
401 printf(" %s %d ", entry->dir.name, START(&entry->dir));
402
403 if(*longname)
404 printf(" %s", longname);
405 printf("\n");
406 } else {
407 printf("%s/%s", dirPath, entry->name);
408 if(IS_DIR(entry))
409 putchar('/');
410 putchar('\n');
411 }
412
413 filesOnDrive++;
414 filesInDir++;
415
416 bytesOnDrive += (mt_size_t) size;
417 bytesInDir += (mt_size_t) size;
418 return GOT_ONE;
419}
420
421static int list_non_recurs_directory(direntry_t *entry, MainParam_t *mp)
422{
423 int r;
424 /* list top-level directory
425 * If this was matched by wildcard in the basename, list it as
426 * file, otherwise, list it as directory */
427 if (mp->basenameHasWildcard) {
428 /* wildcard, list it as file */
429 return list_file(entry, mp);
430 } else {
431 /* no wildcard, list it as directory */
432 MainParam_t subMp;
433
434 r=enterDirectory(mp->File);
435 if(r)
436 return ERROR_ONE;
437
438 subMp = *mp;
439 subMp.dirCallback = subMp.callback;
440 return mp->loop(mp->File, &subMp, "*") | GOT_ONE;
441 }
442}
443
444
445static int list_recurs_directory(direntry_t *entry, MainParam_t *mp)
446{
447 MainParam_t subMp;
448 int ret;
449
450 /* first list the files */
451 subMp = *mp;
452 subMp.lookupflags = ACCEPT_DIR | ACCEPT_PLAIN;
453 subMp.dirCallback = list_file;
454 subMp.callback = list_file;
455
456 ret = mp->loop(mp->File, &subMp, "*");
457
458 /* then list subdirectories */
459 subMp = *mp;
460 subMp.lookupflags = ACCEPT_DIR | NO_DOTS | NO_MSG | DO_OPEN;
461 return ret | mp->loop(mp->File, &subMp, "*");
462}
463
464#if 0
465static int test_directory(direntry_t *entry, MainParam_t *mp)
466{
467 Stream_t *File=mp->File;
468 Stream_t *Target;
469 char errmsg[80];
470
471 if ((Target = SimpleFileOpen(0, 0, "-",
472 O_WRONLY,
473 errmsg, 0, 0, 0))) {
474 copyfile(File, Target);
475 FREE(&Target);
476 }
477 return GOT_ONE;
478}
479#endif
480
481static void usage(void)
482{
483 fprintf(stderr, "Mtools version %s, dated %s\n",
484 mversion, mdate);
485 fprintf(stderr, "Usage: %s: [-waXbfds/] msdosdirectory\n",
486 progname);
487 fprintf(stderr,
488 " %s: [-waXbfds/] msdosfile [msdosfiles...]\n",
489 progname);
490 fprintf(stderr,
491 "\t-w Wide listing\n"
492 "\t-a All, including hidden files\n"
493 "\t-b -X Concise listing\n"
494 "\t-f Fast, no free space summary\n"
495 "\t-d Debug mode\n"
496 "\t-s -/ Recursive\n");
497 exit(1);
498}
499
500
501void mdir(int argc, char **argv, int type)
502{
503 int ret;
504 MainParam_t mp;
505 int faked;
506 int c;
507 char *fakedArgv[] = { "." };
508
509 concise = 0;
510 recursive = 0;
511 wide = all = 0;
512 /* first argument */
513 while ((c = getopt(argc, argv, "waXbfds/")) != EOF) {
514 switch(c) {
515 case 'w':
516 wide = 1;
517 break;
518 case 'a':
519 all = 1;
520 break;
521 case 'b':
522 case 'X':
523 concise = 1;
524 /*recursive = 1;*/
525 break;
526 case 's':
527 case '/':
528 recursive = 1;
529 break;
530 case 'f':
531 fast = 1;
532 break;
533 case 'd':
534 debug = 1;
535 break;
536#if 0
537 case 't': /* test mode */
538 testmode = 1;
539 break;
540#endif
541 default:
542 usage();
543 }
544 }
545
546 /* fake an argument */
547 faked = 0;
548 if (optind == argc) {
549 argv = fakedArgv;
550 argc = 1;
551 optind = 0;
552 }
553
554 init_mp(&mp);
555 currentDrive = '\0';
556 currentDir = 0;
557 RootDir = 0;
558 dirPath = 0;
559#if 0
560 if (testmode) {
561 mp.lookupflags = ACCEPT_DIR | NO_DOTS;
562 mp.dirCallback = test_directory;
563 } else
564#endif
565 if(recursive) {
566 mp.lookupflags = ACCEPT_DIR | DO_OPEN_DIRS | NO_DOTS;
567 mp.dirCallback = list_recurs_directory;
568 } else {
569 mp.lookupflags = ACCEPT_DIR | ACCEPT_PLAIN | DO_OPEN_DIRS;
570 mp.dirCallback = list_non_recurs_directory;
571 mp.callback = list_file;
572 }
573 mp.longname = longname;
574 mp.shortname = shortname;
575 ret=main_loop(&mp, argv + optind, argc - optind);
576 leaveDirectory(ret);
577 leaveDrive(ret);
578 exit(ret);
579}
Note: See TracBrowser for help on using the repository browser.