xref: /aosp_15_r20/external/mtools/mdir.c (revision d5c9a868b113e0ec0db2f27bc2ce8a253e77c4b0)
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(&currentDir);
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