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