Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 1 | /* Copyright 1997-2003,2006,2007,2009 Alain Knaff. |
| 2 | * This file is part of mtools. |
| 3 | * |
| 4 | * Mtools is free software: you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU General Public License as published by |
| 6 | * the Free Software Foundation, either version 3 of the License, or |
| 7 | * (at your option) any later version. |
| 8 | * |
| 9 | * Mtools is distributed in the hope that it will be useful, |
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | * GNU General Public License for more details. |
| 13 | * |
| 14 | * You should have received a copy of the GNU General Public License |
| 15 | * along with Mtools. If not, see <http://www.gnu.org/licenses/>. |
| 16 | * |
| 17 | * mlabel.c |
| 18 | * Make an MSDOS volume label |
| 19 | */ |
| 20 | |
| 21 | #include "sysincludes.h" |
| 22 | #include "msdos.h" |
| 23 | #include "mainloop.h" |
| 24 | #include "vfat.h" |
| 25 | #include "mtools.h" |
| 26 | #include "nameclash.h" |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 27 | #include "fsP.h" |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 28 | |
| 29 | static void usage(int ret) NORETURN; |
| 30 | static void usage(int ret) |
| 31 | { |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 32 | fprintf(stderr, |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 33 | "Mtools version %s, dated %s\n", mversion, mdate); |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 34 | fprintf(stderr, |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 35 | "Usage: %s [-v] drive\n", progname); |
| 36 | exit(ret); |
| 37 | } |
| 38 | |
| 39 | |
| 40 | static void displayInfosector(Stream_t *Stream, union bootsector *boot) |
| 41 | { |
| 42 | InfoSector_t *infosec; |
| 43 | |
| 44 | if(WORD(ext.fat32.infoSector) == MAX16) |
| 45 | return; |
| 46 | |
| 47 | infosec = (InfoSector_t *) safe_malloc(WORD(secsiz)); |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 48 | force_pread(Stream, (char *) infosec, |
| 49 | (mt_off_t) WORD(secsiz) * WORD(ext.fat32.infoSector), |
| 50 | WORD(secsiz)); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 51 | printf("\nInfosector:\n"); |
| 52 | printf("signature=0x%08x\n", _DWORD(infosec->signature1)); |
| 53 | if(_DWORD(infosec->count) != MAX32) |
| 54 | printf("free clusters=%u\n", _DWORD(infosec->count)); |
| 55 | if(_DWORD(infosec->pos) != MAX32) |
| 56 | printf("last allocated cluster=%u\n", _DWORD(infosec->pos)); |
| 57 | } |
| 58 | |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 59 | /* |
| 60 | * Number of hidden sector is only a 4 byte quantity if number of sectors is |
| 61 | */ |
| 62 | static uint32_t getHidden(union bootsector *boot) { |
| 63 | return WORD(psect) ? WORD(nhs) : DWORD(nhs); |
| 64 | } |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 65 | |
| 66 | static void displayBPB(Stream_t *Stream, union bootsector *boot) { |
| 67 | struct label_blk_t *labelBlock; |
| 68 | |
| 69 | printf("bootsector information\n"); |
| 70 | printf("======================\n"); |
| 71 | printf("banner:\"%.8s\"\n", boot->boot.banner); |
| 72 | printf("sector size: %d bytes\n", WORD(secsiz)); |
| 73 | printf("cluster size: %d sectors\n", boot->boot.clsiz); |
| 74 | printf("reserved (boot) sectors: %d\n", WORD(nrsvsect)); |
| 75 | printf("fats: %d\n", boot->boot.nfat); |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 76 | printf("max available root directory slots: %d\n", |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 77 | WORD(dirents)); |
| 78 | printf("small size: %d sectors\n", WORD(psect)); |
| 79 | printf("media descriptor byte: 0x%x\n", boot->boot.descr); |
| 80 | printf("sectors per fat: %d\n", WORD(fatlen)); |
| 81 | printf("sectors per track: %d\n", WORD(nsect)); |
| 82 | printf("heads: %d\n", WORD(nheads)); |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 83 | printf("hidden sectors: %d\n", getHidden(boot)); |
| 84 | if(!WORD(psect)) |
| 85 | printf("big size: %u sectors\n", DWORD(bigsect)); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 86 | |
| 87 | if(WORD(fatlen)) { |
| 88 | labelBlock = &boot->boot.ext.old.labelBlock; |
| 89 | } else { |
| 90 | labelBlock = &boot->boot.ext.fat32.labelBlock; |
| 91 | } |
| 92 | |
| 93 | if(has_BPB4) { |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 94 | printf("physical drive id: 0x%x\n", |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 95 | labelBlock->physdrive); |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 96 | printf("reserved=0x%x\n", |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 97 | labelBlock->reserved); |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 98 | printf("dos4=0x%x\n", |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 99 | labelBlock->dos4); |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 100 | printf("serial number: %08X\n", |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 101 | _DWORD(labelBlock->serial)); |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 102 | printf("disk label=\"%11.11s\"\n", |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 103 | labelBlock->label); |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 104 | printf("disk type=\"%8.8s\"\n", |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 105 | labelBlock->fat_type); |
| 106 | } |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 107 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 108 | if(!WORD(fatlen)){ |
| 109 | printf("Big fatlen=%u\n", |
| 110 | DWORD(ext.fat32.bigFat)); |
| 111 | printf("Extended flags=0x%04x\n", |
| 112 | WORD(ext.fat32.extFlags)); |
| 113 | printf("FS version=0x%04x\n", |
| 114 | WORD(ext.fat32.fsVersion)); |
| 115 | printf("rootCluster=%u\n", |
| 116 | DWORD(ext.fat32.rootCluster)); |
| 117 | if(WORD(ext.fat32.infoSector) != MAX16) |
| 118 | printf("infoSector location=%d\n", |
| 119 | WORD(ext.fat32.infoSector)); |
| 120 | if(WORD(ext.fat32.backupBoot) != MAX16) |
| 121 | printf("backup boot sector=%d\n", |
| 122 | WORD(ext.fat32.backupBoot)); |
| 123 | displayInfosector(Stream, boot); |
| 124 | } |
| 125 | } |
| 126 | |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 127 | static int try(uint32_t tot_sectors, Fs_t *masterFs, Fs_t *tryFs, |
| 128 | struct device *master_dev, struct device *try_dev, |
| 129 | uint8_t *bootDescr) { |
| 130 | *tryFs = *masterFs; |
| 131 | *try_dev = *master_dev; |
| 132 | return calc_fs_parameters(try_dev, 0, tot_sectors, |
| 133 | tryFs, bootDescr); |
| 134 | } |
| 135 | |
| 136 | static void print_mformat_commandline(const char *imgFile, |
| 137 | char drive, |
| 138 | struct device *dev, |
| 139 | union bootsector *boot, |
| 140 | int media, |
| 141 | int haveBPB) { |
| 142 | uint8_t size_code; |
| 143 | uint32_t sect_per_track; |
| 144 | uint32_t hidden; |
| 145 | uint32_t tot_sectors; |
| 146 | int tracks_match=0; |
| 147 | Fs_t masterFs, tryFs, actual; |
| 148 | struct device used_dev; |
| 149 | uint8_t tryMedia; |
| 150 | int bad; |
| 151 | |
| 152 | sect_per_track = dev->sectors * dev->heads; |
| 153 | if(sect_per_track == 0) |
| 154 | return; |
| 155 | |
| 156 | tot_sectors = parseFsParams(&actual, boot, |
| 157 | media | (haveBPB ? 0x100:0), |
| 158 | sect_per_track); |
| 159 | if(tot_sectors == 0) |
| 160 | return; |
| 161 | |
| 162 | printf("mformat command line:\n mformat "); |
| 163 | |
| 164 | if(haveBPB) { |
| 165 | if(media == 0xf0) |
| 166 | hidden = getHidden(boot); |
| 167 | else |
| 168 | hidden = 0; |
| 169 | size_code = (uint8_t) actual.sectorShift-7; |
| 170 | } else { |
| 171 | size_code=2; |
| 172 | hidden = 0; |
| 173 | } |
| 174 | |
| 175 | if(tot_sectors == |
| 176 | dev->tracks * sect_per_track - hidden % sect_per_track) { |
| 177 | tracks_match=1; |
| 178 | printf("-t %d ", dev->tracks); |
| 179 | } else { |
| 180 | printf("-T %d ", tot_sectors); |
| 181 | } |
| 182 | printf ("-h %d -s %d ", dev->heads, dev->sectors); |
| 183 | if(haveBPB && (hidden || !tracks_match)) |
| 184 | printf("-H %d ", hidden); |
| 185 | used_dev=*dev; |
| 186 | if(size_code != 2) { |
| 187 | printf("-S %d ",size_code); |
| 188 | used_dev.ssize = size_code; |
| 189 | } |
| 190 | |
| 191 | initFsForFormat(&masterFs); |
| 192 | setFsSectorSize(&masterFs, &used_dev, 0); |
| 193 | |
| 194 | if(actual.num_fat != 2) { |
| 195 | masterFs.num_fat = actual.num_fat; |
| 196 | printf("-d %d ", actual.num_fat); |
| 197 | } |
| 198 | |
| 199 | bad=try(tot_sectors, &masterFs, &tryFs, dev , &used_dev, &tryMedia); |
| 200 | |
| 201 | if(bad || actual.dir_len != tryFs.dir_len) { |
| 202 | masterFs.dir_len = actual.dir_len; |
| 203 | printf("-r %d ", actual.dir_len); |
| 204 | bad = try(tot_sectors, |
| 205 | &masterFs, &tryFs, dev , &used_dev, |
| 206 | &tryMedia); |
| 207 | } |
| 208 | |
| 209 | if(bad || actual.cluster_size != tryFs.cluster_size) { |
| 210 | masterFs.cluster_size = actual.cluster_size; |
| 211 | printf("-c %d ", actual.cluster_size); |
| 212 | bad = try(tot_sectors, |
| 213 | &masterFs, &tryFs, dev , &used_dev, |
| 214 | &tryMedia); |
| 215 | } |
| 216 | |
| 217 | if(bad || actual.fat_start != tryFs.fat_start) { |
| 218 | masterFs.fat_start = actual.fat_start; |
| 219 | printf("-R %d ", actual.fat_start); |
| 220 | bad = try(tot_sectors, |
| 221 | &masterFs, &tryFs, dev , &used_dev, |
| 222 | &tryMedia); |
| 223 | } |
| 224 | |
| 225 | if(bad || actual.fat_len != tryFs.fat_len) { |
| 226 | masterFs.fat_len = actual.fat_len; |
| 227 | printf("-L %d ", actual.fat_len); |
| 228 | bad = try(tot_sectors, |
| 229 | &masterFs, &tryFs, dev , &used_dev, |
| 230 | &tryMedia); |
| 231 | } |
| 232 | #ifdef HAVE_ASSERT_H |
| 233 | assert(!bad); |
| 234 | #endif |
| 235 | if((media & 0xff) != (tryMedia & 0xff)) |
| 236 | printf("-m %d ", (media & 0xff)); |
| 237 | |
| 238 | if(actual.fat_bits == 32) { |
| 239 | if(actual.backupBoot != tryFs.backupBoot) |
| 240 | printf("-K %d ", actual.backupBoot); |
| 241 | } |
| 242 | |
| 243 | if(imgFile != NULL) |
| 244 | printf("-i \"%s\" ", imgFile); |
| 245 | printf("%c:\n", ch_tolower(drive)); |
| 246 | printf("\n"); |
| 247 | } |
| 248 | |
| 249 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 250 | void minfo(int argc, char **argv, int type UNUSEDP) NORETURN; |
| 251 | void minfo(int argc, char **argv, int type UNUSEDP) |
| 252 | { |
| 253 | union bootsector boot; |
| 254 | |
| 255 | char name[EXPAND_BUF]; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 256 | struct device dev; |
| 257 | char drive; |
| 258 | int verbose=0; |
| 259 | int c; |
| 260 | Stream_t *Stream; |
| 261 | int have_drive = 0; |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 262 | int ex=0; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 263 | char *imgFile=NULL; |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 264 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 265 | if(helpFlag(argc, argv)) |
| 266 | usage(0); |
| 267 | while ((c = getopt(argc, argv, "i:vh")) != EOF) { |
| 268 | switch (c) { |
| 269 | case 'i': |
| 270 | set_cmd_line_image(optarg); |
| 271 | imgFile=optarg; |
| 272 | break; |
| 273 | case 'v': |
| 274 | verbose = 1; |
| 275 | break; |
| 276 | case 'h': |
| 277 | usage(0); |
| 278 | default: |
| 279 | usage(1); |
| 280 | } |
| 281 | } |
| 282 | |
| 283 | for(;optind <= argc; optind++) { |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 284 | int media; |
| 285 | int haveBPB; |
| 286 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 287 | if(optind == argc) { |
| 288 | if(have_drive) |
| 289 | break; |
| 290 | drive = get_default_drive(); |
| 291 | } else { |
| 292 | if(!argv[optind][0] || argv[optind][1] != ':') |
| 293 | usage(1); |
| 294 | drive = ch_toupper(argv[optind][0]); |
| 295 | } |
| 296 | have_drive = 1; |
| 297 | |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 298 | if(! (Stream = find_device(drive, O_RDONLY, &dev, &boot, |
| 299 | name, &media, 0, NULL))) { |
| 300 | fprintf(stderr, "Could not open drive %c:\n", drive); |
| 301 | ex=1; |
| 302 | continue; |
| 303 | } |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 304 | |
| 305 | haveBPB = media >= 0x100; |
| 306 | media = media & 0xff; |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 307 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 308 | printf("device information:\n"); |
| 309 | printf("===================\n"); |
| 310 | printf("filename=\"%s\"\n", name); |
| 311 | printf("sectors per track: %d\n", dev.sectors); |
| 312 | printf("heads: %d\n", dev.heads); |
| 313 | printf("cylinders: %d\n\n", dev.tracks); |
| 314 | printf("media byte: %02x\n\n", media & 0xff); |
| 315 | |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 316 | print_mformat_commandline(imgFile, drive, |
| 317 | &dev, &boot, media, haveBPB); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 318 | |
| 319 | if(haveBPB || verbose) |
| 320 | displayBPB(Stream, &boot); |
| 321 | |
| 322 | if(verbose) { |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 323 | uint16_t size; |
| 324 | ssize_t ssize; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 325 | unsigned char *buf; |
| 326 | |
| 327 | printf("\n"); |
| 328 | size = WORD_S(secsiz); |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 329 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 330 | buf = (unsigned char *) malloc(size); |
| 331 | if(!buf) { |
| 332 | fprintf(stderr, "Out of memory error\n"); |
| 333 | exit(1); |
| 334 | } |
| 335 | |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 336 | ssize = PREADS(Stream, buf, 0, size); |
| 337 | if(ssize < 0) { |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 338 | perror("read boot sector"); |
| 339 | exit(1); |
| 340 | } |
| 341 | |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 342 | print_sector("Boot sector hexdump", buf, (uint16_t)ssize); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 343 | } |
| 344 | } |
| 345 | FREE(&Stream); |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 346 | exit(ex); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 347 | } |