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