blob: 3a2f9e3efa4fd9a28848802cef27161953b734e3 [file] [log] [blame]
Alistair Delvabeaee832021-02-24 11:27:23 -08001/* Copyright 1996-2006,2008,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
Yi Kong39bbd962022-01-09 19:41:38 +080018
Alistair Delvabeaee832021-02-24 11:27:23 -080019#include "sysincludes.h"
20#include "msdos.h"
21#include "stream.h"
22#include "mtools.h"
23#include "fsP.h"
24#include "file_name.h"
25
26#ifdef HAVE_LONG_LONG
27typedef long long fatBitMask;
28#else
29typedef long fatBitMask;
30#endif
31
32typedef struct FatMap_t {
33 unsigned char *data;
34 fatBitMask dirty;
35 fatBitMask valid;
36} FatMap_t;
37
38#define SECT_PER_ENTRY (sizeof(fatBitMask)*8)
39#define ONE ((fatBitMask) 1)
40
Yi Kong39bbd962022-01-09 19:41:38 +080041static __inline__ ssize_t readSector(Fs_t *This, char *buf, unsigned int off,
42 size_t size)
Alistair Delvabeaee832021-02-24 11:27:23 -080043{
Yi Kong39bbd962022-01-09 19:41:38 +080044 return PREADS(This->head.Next, buf, sectorsToBytes(This, off),
45 size << This->sectorShift);
Alistair Delvabeaee832021-02-24 11:27:23 -080046}
47
48
Yi Kong39bbd962022-01-09 19:41:38 +080049static __inline__ ssize_t forceReadSector(Fs_t *This, char *buf,
50 unsigned int off, size_t size)
Alistair Delvabeaee832021-02-24 11:27:23 -080051{
Yi Kong39bbd962022-01-09 19:41:38 +080052 return force_pread(This->head.Next, buf, sectorsToBytes(This, off),
53 size << This->sectorShift);
Alistair Delvabeaee832021-02-24 11:27:23 -080054}
55
56
Yi Kong39bbd962022-01-09 19:41:38 +080057static __inline__ ssize_t forceWriteSector(Fs_t *This, char *buf, unsigned int off,
58 size_t size)
Alistair Delvabeaee832021-02-24 11:27:23 -080059{
Yi Kong39bbd962022-01-09 19:41:38 +080060 return force_pwrite(This->head.Next, buf, sectorsToBytes(This, off),
61 size << This->sectorShift);
Alistair Delvabeaee832021-02-24 11:27:23 -080062}
63
64
65static FatMap_t *GetFatMap(Fs_t *Stream)
66{
67 size_t nr_entries;
68 size_t i;
69 FatMap_t *map;
70
71 Stream->fat_error = 0;
72 nr_entries = (Stream->fat_len + SECT_PER_ENTRY - 1) / SECT_PER_ENTRY;
73 map = NewArray(nr_entries, FatMap_t);
74 if(!map)
75 return 0;
76
77 for(i=0; i< nr_entries; i++) {
78 map[i].data = 0;
79 map[i].valid = 0;
80 map[i].dirty = 0;
81 }
82
83 return map;
84}
85
Yi Kong39bbd962022-01-09 19:41:38 +080086static __inline__ int locate(Fs_t *Stream, uint32_t offset,
87 uint32_t *slot, uint32_t *bit)
Alistair Delvabeaee832021-02-24 11:27:23 -080088{
89 if(offset >= Stream->fat_len)
90 return -1;
91 *slot = offset / SECT_PER_ENTRY;
92 *bit = offset % SECT_PER_ENTRY;
93 return 0;
94}
95
Yi Kong39bbd962022-01-09 19:41:38 +080096static __inline__ ssize_t fatReadSector(Fs_t *This,
97 unsigned int sector,
98 unsigned int slot,
99 unsigned int bit, unsigned int dupe,
100 fatBitMask bitmap)
Alistair Delvabeaee832021-02-24 11:27:23 -0800101{
Yi Kong39bbd962022-01-09 19:41:38 +0800102 unsigned int fat_start;
103 ssize_t ret;
104 unsigned int nr_sectors;
Alistair Delvabeaee832021-02-24 11:27:23 -0800105
106 dupe = (dupe + This->primaryFat) % This->num_fat;
107 fat_start = This->fat_start + This->fat_len * dupe;
Yi Kong39bbd962022-01-09 19:41:38 +0800108
Alistair Delvabeaee832021-02-24 11:27:23 -0800109 if(bitmap == 0) {
110 nr_sectors = SECT_PER_ENTRY - bit%SECT_PER_ENTRY;
111 } else {
112 nr_sectors = 1;
113 }
114
115 /* first, read as much as the buffer can give us */
116 ret = readSector(This,
117 (char *)(This->FatMap[slot].data+(bit<<This->sectorShift)),
118 fat_start+sector,
119 nr_sectors);
120 if(ret < 0)
121 return 0;
122
Yi Kong39bbd962022-01-09 19:41:38 +0800123 if((size_t) ret < This->sector_size) {
Alistair Delvabeaee832021-02-24 11:27:23 -0800124 /* if we got less than one sector's worth, insist to get at
125 * least one sector */
126 ret = forceReadSector(This,
Yi Kong39bbd962022-01-09 19:41:38 +0800127 (char *) (This->FatMap[slot].data +
Alistair Delvabeaee832021-02-24 11:27:23 -0800128 (bit << This->sectorShift)),
129 fat_start+sector, 1);
130 if(ret < (int) This->sector_size)
131 return 0;
132 return 1;
133 }
134
135 return ret >> This->sectorShift;
136}
137
138
Yi Kong39bbd962022-01-09 19:41:38 +0800139static ssize_t fatWriteSector(Fs_t *This,
140 unsigned int sector,
141 unsigned int slot,
142 unsigned int bit,
143 unsigned int dupe)
Alistair Delvabeaee832021-02-24 11:27:23 -0800144{
Yi Kong39bbd962022-01-09 19:41:38 +0800145 unsigned int fat_start;
Alistair Delvabeaee832021-02-24 11:27:23 -0800146
147 dupe = (dupe + This->primaryFat) % This->num_fat;
148 if(dupe && !This->writeAllFats)
149 return This->sector_size;
150
151 fat_start = This->fat_start + This->fat_len * dupe;
152
153 return forceWriteSector(This,
Yi Kong39bbd962022-01-09 19:41:38 +0800154 (char *)
Alistair Delvabeaee832021-02-24 11:27:23 -0800155 (This->FatMap[slot].data + bit * This->sector_size),
156 fat_start+sector, 1);
157}
158
159static unsigned char *loadSector(Fs_t *This,
160 unsigned int sector, fatAccessMode_t mode,
161 int recurs)
162{
Yi Kong39bbd962022-01-09 19:41:38 +0800163 uint32_t slot, bit;
164 ssize_t ret;
Alistair Delvabeaee832021-02-24 11:27:23 -0800165
166 if(locate(This,sector, &slot, &bit) < 0)
167 return 0;
168#if 0
169 if (((This->fat_len + SECT_PER_ENTRY - 1) / SECT_PER_ENTRY) <= slot) {
170 fprintf(stderr,"This should not happen\n");
171 fprintf(stderr, "fat_len = %d\n", This->fat_len);
172 fprintf(stderr, "SECT_PER_ENTRY=%d\n", (int)SECT_PER_ENTRY);
Yi Kong39bbd962022-01-09 19:41:38 +0800173 fprintf(stderr, "sector = %d slot = %d bit=%d\n",
Alistair Delvabeaee832021-02-24 11:27:23 -0800174 sector, slot, bit);
175 fprintf(stderr, "left = %d",(int)
176 ((This->fat_len+SECT_PER_ENTRY-1) / SECT_PER_ENTRY));
177 return 0;
178 }
179#endif
180 if(!This->FatMap[slot].data) {
181 /* allocate the storage space */
Yi Kong39bbd962022-01-09 19:41:38 +0800182 This->FatMap[slot].data =
Alistair Delvabeaee832021-02-24 11:27:23 -0800183 malloc(This->sector_size * SECT_PER_ENTRY);
184 if(!This->FatMap[slot].data)
185 return 0;
186 memset(This->FatMap[slot].data, 0xee,
187 This->sector_size * SECT_PER_ENTRY);
188 }
189
190 if(! (This->FatMap[slot].valid & (ONE << bit))) {
191 unsigned int i;
192 ret = -1;
193 for(i=0; i< This->num_fat; i++) {
194 /* read the sector */
195 ret = fatReadSector(This, sector, slot, bit, i,
196 This->FatMap[slot].valid);
197
198 if(ret == 0) {
199 fprintf(stderr,
200 "Error reading fat number %d\n", i);
201 continue;
202 }
203 if(This->FatMap[slot].valid)
204 /* Set recurs if there have already been
205 * sectors loaded in this bitmap long
206 */
207 recurs = 1;
208 break;
209 }
210
211 /* all copies bad. Return error */
212 if(ret == 0)
213 return 0;
214
215 for(i=0; (int) i < ret; i++)
216 This->FatMap[slot].valid |= ONE << (bit + i);
217
218 if(!recurs && ret == 1)
219 /* do some prefetching, if we happened to only
220 * get one sector */
221 loadSector(This, sector+1, mode, 1);
222 if(!recurs && batchmode)
223 for(i=0; i < 1024; i++)
224 loadSector(This, sector+i, mode, 1);
225 }
226
227 if(mode == FAT_ACCESS_WRITE) {
228 This->FatMap[slot].dirty |= ONE << bit;
229 This->fat_dirty = 1;
230 }
231 return This->FatMap[slot].data + (bit << This->sectorShift);
232}
233
234
235static unsigned char *getAddress(Fs_t *Stream,
236 unsigned int num, fatAccessMode_t mode)
237{
238 unsigned char *ret;
Yi Kong39bbd962022-01-09 19:41:38 +0800239 unsigned int sector;
240 unsigned int offset;
Alistair Delvabeaee832021-02-24 11:27:23 -0800241
242 sector = num >> Stream->sectorShift;
243 ret = 0;
244 if(sector == Stream->lastFatSectorNr &&
245 Stream->lastFatAccessMode >= mode)
246 ret = Stream->lastFatSectorData;
Yi Kong39bbd962022-01-09 19:41:38 +0800247 if(!ret) {
Alistair Delvabeaee832021-02-24 11:27:23 -0800248 ret = loadSector(Stream, sector, mode, 0);
249 if(!ret)
250 return 0;
251 Stream->lastFatSectorNr = sector;
252 Stream->lastFatSectorData = ret;
253 Stream->lastFatAccessMode = mode;
254 }
255 offset = num & Stream->sectorMask;
256 return ret+offset;
257}
258
259
Yi Kong39bbd962022-01-09 19:41:38 +0800260static int readByte(Fs_t *Stream, unsigned int start)
Alistair Delvabeaee832021-02-24 11:27:23 -0800261{
262 unsigned char *address;
Yi Kong39bbd962022-01-09 19:41:38 +0800263
Alistair Delvabeaee832021-02-24 11:27:23 -0800264 address = getAddress(Stream, start, FAT_ACCESS_READ);
265 if(!address)
266 return -1;
267 return *address;
268}
269
270
271/*
272 * Fat 12 encoding:
273 * | byte n | byte n+1 | byte n+2 |
274 * |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
275 * | | | | | | | | | | | | | | | | | | | | | | | | |
276 * | n+0.0 | n+0.5 | n+1.0 | n+1.5 | n+2.0 | n+2.5 |
277 * \_____ \____ \______/________/_____ /
278 * ____\______\________/ _____/ ____\_/
279 * / \ \ / / \
280 * | n+1.5 | n+0.0 | n+0.5 | n+2.0 | n+2.5 | n+1.0 |
281 * | FAT entry k | FAT entry k+1 |
282 */
Yi Kong39bbd962022-01-09 19:41:38 +0800283
Alistair Delvabeaee832021-02-24 11:27:23 -0800284 /*
285 * Get and decode a FAT (file allocation table) entry. Returns the cluster
286 * number on success or 1 on failure.
287 */
288
289static unsigned int fat12_decode(Fs_t *Stream, unsigned int num)
290{
291 unsigned int start = num * 3 / 2;
292 int byte0 = readByte(Stream, start);
293 int byte1 = readByte(Stream, start+1);
Yi Kong39bbd962022-01-09 19:41:38 +0800294
Alistair Delvabeaee832021-02-24 11:27:23 -0800295 if (num < 2 || byte0 < 0 || byte1 < 0 || num > Stream->num_clus+1) {
296 fprintf(stderr,"[1] Bad address %d\n", num);
297 return 1;
298 }
299
300 if (num & 1)
Yi Kong39bbd962022-01-09 19:41:38 +0800301 return ((uint32_t)byte1 << 4) | (((uint32_t)byte0 & 0xf0)>>4);
Alistair Delvabeaee832021-02-24 11:27:23 -0800302 else
Yi Kong39bbd962022-01-09 19:41:38 +0800303 return (((uint32_t)byte1 & 0xf) << 8) | (uint32_t)byte0;
Alistair Delvabeaee832021-02-24 11:27:23 -0800304}
305
306
307/*
308 * Puts a code into the FAT table. Is the opposite of fat_decode(). No
309 * sanity checking is done on the code. Returns a 1 on error.
310 */
311static void fat12_encode(Fs_t *Stream, unsigned int num, unsigned int code)
312{
Yi Kong39bbd962022-01-09 19:41:38 +0800313 unsigned int start = num * 3 / 2;
Alistair Delvabeaee832021-02-24 11:27:23 -0800314 unsigned char *address0 = getAddress(Stream, start, FAT_ACCESS_WRITE);
315 unsigned char *address1 = getAddress(Stream, start+1, FAT_ACCESS_WRITE);
316
317 if (num & 1) {
318 /* (odd) not on byte boundary */
319 *address0 = (*address0 & 0x0f) | ((code << 4) & 0xf0);
320 *address1 = (code >> 4) & 0xff;
321 } else {
322 /* (even) on byte boundary */
323 *address0 = code & 0xff;
324 *address1 = (*address1 & 0xf0) | ((code >> 8) & 0x0f);
325 }
326}
327
328
329/*
330 * Fat 16 encoding:
331 * | byte n | byte n+1 |
332 * |7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
333 * | | | | | | | | | | | | | | | | |
334 * | FAT entry k |
335 */
336
337static unsigned int fat16_decode(Fs_t *Stream, unsigned int num)
338{
339 unsigned char *address = getAddress(Stream, num << 1, FAT_ACCESS_READ);
340 if(!address)
341 return 1;
342 return _WORD(address);
343}
344
345static void fat16_encode(Fs_t *Stream, unsigned int num, unsigned int code)
Yi Kong39bbd962022-01-09 19:41:38 +0800346{
347 if(code > UINT16_MAX) {
348 fprintf(stderr, "FAT16 code %x too big\n", code);
349 exit(1);
350 }
Alistair Delvabeaee832021-02-24 11:27:23 -0800351 unsigned char *address = getAddress(Stream, num << 1, FAT_ACCESS_WRITE);
Yi Kong39bbd962022-01-09 19:41:38 +0800352 set_word(address, (uint16_t) code);
Alistair Delvabeaee832021-02-24 11:27:23 -0800353}
354
355
Yi Kong39bbd962022-01-09 19:41:38 +0800356#pragma GCC diagnostic push
357#pragma GCC diagnostic ignored "-Wcast-align"
358/* Ignore alignment warnings about casting to type with higher
359 * alignment requirement. Requirement is met, as initial pointer is an
360 * even offset into a buffer allocated by malloc, which according to
361 * manpage is "suitably aligned for any built-in type */
Alistair Delvabeaee832021-02-24 11:27:23 -0800362static unsigned int fast_fat16_decode(Fs_t *Stream, unsigned int num)
363{
Yi Kong39bbd962022-01-09 19:41:38 +0800364 unsigned short *address =
365 (unsigned short *) getAddress(Stream, num << 1,
Alistair Delvabeaee832021-02-24 11:27:23 -0800366 FAT_ACCESS_READ);
367 if(!address)
368 return 1;
369 return *address;
370}
371
372static void fast_fat16_encode(Fs_t *Stream, unsigned int num, unsigned int code)
Yi Kong39bbd962022-01-09 19:41:38 +0800373{
374 unsigned short *address =
375 (unsigned short *) getAddress(Stream, num << 1,
Alistair Delvabeaee832021-02-24 11:27:23 -0800376 FAT_ACCESS_WRITE);
Yi Kong39bbd962022-01-09 19:41:38 +0800377 if(code > UINT16_MAX) {
378 fprintf(stderr, "FAT16 code %x too big\n", code);
379 exit(1);
380 }
381 *address = (uint16_t) code;
Alistair Delvabeaee832021-02-24 11:27:23 -0800382}
Yi Kong39bbd962022-01-09 19:41:38 +0800383#pragma GCC diagnostic pop
Alistair Delvabeaee832021-02-24 11:27:23 -0800384
385
386
387/*
388 * Fat 32 encoding
389 */
390#define FAT32_HIGH 0xf0000000
391#define FAT32_ADDR 0x0fffffff
392
393static unsigned int fat32_decode(Fs_t *Stream, unsigned int num)
394{
395 unsigned char *address = getAddress(Stream, num << 2, FAT_ACCESS_READ);
396 if(!address)
397 return 1;
398 return _DWORD(address) & FAT32_ADDR;
399}
400
401static void fat32_encode(Fs_t *Stream, unsigned int num, unsigned int code)
Yi Kong39bbd962022-01-09 19:41:38 +0800402{
Alistair Delvabeaee832021-02-24 11:27:23 -0800403 unsigned char *address = getAddress(Stream, num << 2, FAT_ACCESS_WRITE);
404 set_dword(address,(code&FAT32_ADDR) | (_DWORD(address)&FAT32_HIGH));
405}
406
Yi Kong39bbd962022-01-09 19:41:38 +0800407#pragma GCC diagnostic push
408#pragma GCC diagnostic ignored "-Wcast-align"
Alistair Delvabeaee832021-02-24 11:27:23 -0800409static unsigned int fast_fat32_decode(Fs_t *Stream, unsigned int num)
410{
Yi Kong39bbd962022-01-09 19:41:38 +0800411 unsigned int *address =
412 (unsigned int *) getAddress(Stream, num << 2,
Alistair Delvabeaee832021-02-24 11:27:23 -0800413 FAT_ACCESS_READ);
414 if(!address)
415 return 1;
416 return (*address) & FAT32_ADDR;
417}
418
419static void fast_fat32_encode(Fs_t *Stream, unsigned int num, unsigned int code)
Yi Kong39bbd962022-01-09 19:41:38 +0800420{
421 unsigned int *address =
422 (unsigned int *) getAddress(Stream, num << 2,
Alistair Delvabeaee832021-02-24 11:27:23 -0800423 FAT_ACCESS_WRITE);
424 *address = (*address & FAT32_HIGH) | (code & FAT32_ADDR);
425}
Yi Kong39bbd962022-01-09 19:41:38 +0800426#pragma GCC diagnostic pop
Alistair Delvabeaee832021-02-24 11:27:23 -0800427
428/*
429 * Write the FAT table to the disk. Up to now the FAT manipulation has
430 * been done in memory. All errors are fatal. (Might not be too smart
431 * to wait till the end of the program to write the table. Oh well...)
432 */
433
434void fat_write(Fs_t *This)
435{
436 unsigned int i, j, dups, bit, slot;
Yi Kong39bbd962022-01-09 19:41:38 +0800437 ssize_t ret;
Alistair Delvabeaee832021-02-24 11:27:23 -0800438
439 /*fprintf(stderr, "Fat write\n");*/
440
441 if (!This->fat_dirty)
442 return;
443
444 dups = This->num_fat;
445 if (This->fat_error)
446 dups = 1;
447
448
449 for(i=0; i<dups; i++){
450 j = 0;
451 for(slot=0;j<This->fat_len;slot++) {
452 if(!This->FatMap[slot].dirty) {
453 j += SECT_PER_ENTRY;
454 continue;
455 }
Yi Kong39bbd962022-01-09 19:41:38 +0800456 for(bit=0;
Alistair Delvabeaee832021-02-24 11:27:23 -0800457 bit < SECT_PER_ENTRY && j<This->fat_len;
458 bit++,j++) {
459 if(!(This->FatMap[slot].dirty & (ONE << bit)))
460 continue;
461 ret = fatWriteSector(This,j,slot, bit, i);
462 if (ret < (int) This->sector_size){
463 if (ret < 0 ){
464 perror("error in fat_write");
465 exit(1);
466 } else {
467 fprintf(stderr,
468 "end of file in fat_write\n");
469 exit(1);
470 }
471 }
472 /* if last dupe, zero it out */
473 if(i==dups-1)
474 This->FatMap[slot].dirty &= ~(ONE<<bit);
475 }
476 }
477 }
478 /* write the info sector, if any */
479 if(This->infoSectorLoc && This->infoSectorLoc != MAX32) {
480 /* initialize info sector */
481 InfoSector_t *infoSector;
482 infoSector = (InfoSector_t *) safe_malloc(This->sector_size);
483 if(forceReadSector(This, (char *)infoSector,
484 This->infoSectorLoc, 1) !=
485 (signed int) This->sector_size) {
486 fprintf(stderr,"Trouble reading the info sector\n");
487 memset(infoSector->filler1, 0, sizeof(infoSector->filler1));
488 memset(infoSector->filler2, 0, sizeof(infoSector->filler2));
489 }
490 set_dword(infoSector->signature1, INFOSECT_SIGNATURE1);
491 set_dword(infoSector->signature2, INFOSECT_SIGNATURE2);
492 set_dword(infoSector->pos, This->last);
493 set_dword(infoSector->count, This->freeSpace);
494 set_word(infoSector->signature3, 0xaa55);
495 if(forceWriteSector(This, (char *)infoSector, This->infoSectorLoc, 1) !=
496 (signed int) This->sector_size)
497 fprintf(stderr,"Trouble writing the info sector\n");
498 free(infoSector);
499 }
500 This->fat_dirty = 0;
501 This->lastFatAccessMode = FAT_ACCESS_READ;
502}
503
504
505
506/*
507 * Zero-Fat
508 * Used by mformat.
509 */
Yi Kong39bbd962022-01-09 19:41:38 +0800510int zero_fat(Fs_t *Stream, uint8_t media_descriptor)
Alistair Delvabeaee832021-02-24 11:27:23 -0800511{
512 unsigned int i, j;
513 unsigned int fat_start;
514 unsigned char *buf;
515
516 buf = malloc(Stream->sector_size);
517 if(!buf) {
518 perror("alloc fat sector buffer");
519 return -1;
520 }
521 for(i=0; i< Stream->num_fat; i++) {
522 fat_start = Stream->fat_start + i*Stream->fat_len;
523 for(j = 0; j < Stream->fat_len; j++) {
524 if(j <= 1)
525 memset(buf, 0, Stream->sector_size);
526 if(!j) {
527 buf[0] = media_descriptor;
528 buf[2] = buf[1] = 0xff;
529 if(Stream->fat_bits > 12)
530 buf[3] = 0xff;
531 if(Stream->fat_bits > 16) {
532 buf[4] = 0xff;
533 buf[5] = 0xff;
534 buf[6] = 0xff;
535 buf[7] = 0x0f;
536 }
537 }
538
539 if(forceWriteSector(Stream, (char *)buf,
540 fat_start + j, 1) !=
541 (signed int) Stream->sector_size) {
542 fprintf(stderr,
543 "Trouble initializing a FAT sector\n");
544 free(buf);
545 return -1;
546 }
547 }
548 }
Yi Kong39bbd962022-01-09 19:41:38 +0800549
Alistair Delvabeaee832021-02-24 11:27:23 -0800550 free(buf);
551 Stream->FatMap = GetFatMap(Stream);
552 if (Stream->FatMap == NULL) {
553 perror("alloc fat map");
554 return -1;
555 }
556 return 0;
557}
558
559
Yi Kong39bbd962022-01-09 19:41:38 +0800560static void set_fat12(Fs_t *This)
Alistair Delvabeaee832021-02-24 11:27:23 -0800561{
562 This->fat_bits = 12;
563 This->end_fat = 0xfff;
564 This->last_fat = 0xff6;
565 This->fat_decode = fat12_decode;
566 This->fat_encode = fat12_encode;
567}
568
Yi Kong39bbd962022-01-09 19:41:38 +0800569static uint16_t word_endian_test = 0x1234;
Alistair Delvabeaee832021-02-24 11:27:23 -0800570
Yi Kong39bbd962022-01-09 19:41:38 +0800571static void set_fat16(Fs_t *This)
Alistair Delvabeaee832021-02-24 11:27:23 -0800572{
Yi Kong39bbd962022-01-09 19:41:38 +0800573 uint8_t *t = (uint8_t *) &word_endian_test;
Alistair Delvabeaee832021-02-24 11:27:23 -0800574 This->fat_bits = 16;
575 This->end_fat = 0xffff;
576 This->last_fat = 0xfff6;
577
Yi Kong39bbd962022-01-09 19:41:38 +0800578 if(t[0] == 0x34 && t[1] == 0x12) {
Alistair Delvabeaee832021-02-24 11:27:23 -0800579 This->fat_decode = fast_fat16_decode;
580 This->fat_encode = fast_fat16_encode;
581 } else {
582 This->fat_decode = fat16_decode;
583 This->fat_encode = fat16_encode;
584 }
585}
586
Yi Kong39bbd962022-01-09 19:41:38 +0800587static uint32_t dword_endian_test = 0x12345678;
Alistair Delvabeaee832021-02-24 11:27:23 -0800588
Yi Kong39bbd962022-01-09 19:41:38 +0800589static void set_fat32(Fs_t *This)
Alistair Delvabeaee832021-02-24 11:27:23 -0800590{
Yi Kong39bbd962022-01-09 19:41:38 +0800591 uint8_t *t = (uint8_t *) &dword_endian_test;
Alistair Delvabeaee832021-02-24 11:27:23 -0800592 This->fat_bits = 32;
593 This->end_fat = 0xfffffff;
594 This->last_fat = 0xffffff6;
Yi Kong39bbd962022-01-09 19:41:38 +0800595
596 if(t[0] == 0x78 && t[1] == 0x56 && t[2] == 0x34 && t[3] == 0x12) {
Alistair Delvabeaee832021-02-24 11:27:23 -0800597 This->fat_decode = fast_fat32_decode;
598 This->fat_encode = fast_fat32_encode;
599 } else {
600 This->fat_decode = fat32_decode;
601 This->fat_encode = fat32_encode;
602 }
603}
604
Yi Kong39bbd962022-01-09 19:41:38 +0800605void set_fat(Fs_t *This) {
606 if(This->num_clus < FAT12)
607 set_fat12(This);
608 else if(This->num_clus < FAT16)
609 set_fat16(This);
610 else
611 set_fat32(This);
612}
Alistair Delvabeaee832021-02-24 11:27:23 -0800613
614static int check_fat(Fs_t *This)
615{
Yi Kong39bbd962022-01-09 19:41:38 +0800616 /*
Alistair Delvabeaee832021-02-24 11:27:23 -0800617 * This is only a sanity check. For disks with really big FATs,
618 * there is no point in checking the whole FAT.
619 */
620
621 unsigned int i, f;
622 unsigned int tocheck;
623 if(mtools_skip_check)
624 return 0;
625
626 /* too few sectors in the FAT */
Yi Kong39bbd962022-01-09 19:41:38 +0800627 if(This->fat_len < NEEDED_FAT_SIZE(This)) {
628 fprintf(stderr, "Too few sectors in FAT\n");
Alistair Delvabeaee832021-02-24 11:27:23 -0800629 return -1;
Yi Kong39bbd962022-01-09 19:41:38 +0800630 }
Alistair Delvabeaee832021-02-24 11:27:23 -0800631 /* we do not warn about too much sectors in FAT, which may
632 * happen when a partition has been shrunk using FIPS, or on
633 * other occurrences */
Yi Kong39bbd962022-01-09 19:41:38 +0800634
Alistair Delvabeaee832021-02-24 11:27:23 -0800635 tocheck = This->num_clus;
636 if (tocheck + 1 >= This->last_fat) {
637 fprintf(stderr, "Too many clusters in FAT\n");
638 return -1;
639 }
640
641 if(tocheck > 4096)
642 tocheck = 4096;
643
644 for ( i= 3 ; i < tocheck; i++){
645 f = This->fat_decode(This,i);
646 if (f == 1 || (f < This->last_fat && f > This->num_clus)){
647 fprintf(stderr,
648 "Cluster # at %d too big(%#x)\n", i,f);
649 fprintf(stderr,"Probably non MS-DOS disk\n");
650 return -1;
651 }
652 }
653 return 0;
654}
655
656
657/*
658 * Read the first sector of FAT table into memory. Crude error detection on
659 * wrong FAT encoding scheme.
660 */
Yi Kong39bbd962022-01-09 19:41:38 +0800661static int check_media_type(Fs_t *This, union bootsector *boot)
Alistair Delvabeaee832021-02-24 11:27:23 -0800662{
663 unsigned char *address;
664
Alistair Delvabeaee832021-02-24 11:27:23 -0800665 This->FatMap = GetFatMap(This);
666 if (This->FatMap == NULL) {
667 perror("alloc fat map");
668 return -1;
669 }
670
671 address = getAddress(This, 0, FAT_ACCESS_READ);
672 if(!address) {
673 fprintf(stderr,
674 "Could not read first FAT sector\n");
675 return -1;
676 }
677
678 if(mtools_skip_check)
679 return 0;
680
681 if(!address[0] && !address[1] && !address[2])
682 /* Some Atari disks have zeroes where Dos has media descriptor
683 * and 0xff. Do not consider this as an error */
684 return 0;
Yi Kong39bbd962022-01-09 19:41:38 +0800685
Alistair Delvabeaee832021-02-24 11:27:23 -0800686 if((address[0] != boot->boot.descr && boot->boot.descr >= 0xf0 &&
Yi Kong39bbd962022-01-09 19:41:38 +0800687 ((address[0] != 0xf9 && address[0] != 0xf7)
Alistair Delvabeaee832021-02-24 11:27:23 -0800688 || boot->boot.descr != 0xf0)) || address[0] < 0xf0) {
689 fprintf(stderr,
Yi Kong39bbd962022-01-09 19:41:38 +0800690 "Bad media types %02x/%02x, probably non-MSDOS disk\n",
Alistair Delvabeaee832021-02-24 11:27:23 -0800691 address[0],
692 boot->boot.descr);
693 return -1;
694 }
695
696 if(address[1] != 0xff || address[2] != 0xff){
Yi Kong39bbd962022-01-09 19:41:38 +0800697 fprintf(stderr,"Initial bytes of fat is not 0xff\n");
Alistair Delvabeaee832021-02-24 11:27:23 -0800698 return -1;
699 }
700
701 return 0;
702}
703
Yi Kong39bbd962022-01-09 19:41:38 +0800704static int fat_32_read(Fs_t *This, union bootsector *boot)
Alistair Delvabeaee832021-02-24 11:27:23 -0800705{
706 size_t size;
707
708 This->fat_len = DWORD(ext.fat32.bigFat);
709 This->writeAllFats = !(boot->boot.ext.fat32.extFlags[0] & 0x80);
710 This->primaryFat = boot->boot.ext.fat32.extFlags[0] & 0xf;
711 This->rootCluster = DWORD(ext.fat32.rootCluster);
712 This->clus_start = This->fat_start + This->num_fat * This->fat_len;
713
714 /* read the info sector */
715 size = This->sector_size;
716 This->infoSectorLoc = WORD(ext.fat32.infoSector);
717 if(This->sector_size >= 512 &&
718 This->infoSectorLoc && This->infoSectorLoc != MAX32) {
719 InfoSector_t *infoSector;
720 infoSector = (InfoSector_t *) safe_malloc(size);
721 if(forceReadSector(This, (char *)infoSector,
Yi Kong39bbd962022-01-09 19:41:38 +0800722 This->infoSectorLoc, 1) ==
Alistair Delvabeaee832021-02-24 11:27:23 -0800723 (signed int) This->sector_size &&
724 _DWORD(infoSector->signature1) == INFOSECT_SIGNATURE1 &&
725 _DWORD(infoSector->signature2) == INFOSECT_SIGNATURE2) {
726 This->freeSpace = _DWORD(infoSector->count);
727 This->last = _DWORD(infoSector->pos);
728 }
729 free(infoSector);
730 }
Yi Kong39bbd962022-01-09 19:41:38 +0800731
732 return(check_media_type(This, boot) || check_fat(This));
Alistair Delvabeaee832021-02-24 11:27:23 -0800733}
734
735
Yi Kong39bbd962022-01-09 19:41:38 +0800736static int old_fat_read(Fs_t *This, union bootsector *boot, int nodups)
Alistair Delvabeaee832021-02-24 11:27:23 -0800737{
738 This->writeAllFats = 1;
739 This->primaryFat = 0;
740 This->dir_start = This->fat_start + This->num_fat * This->fat_len;
Alistair Delvabeaee832021-02-24 11:27:23 -0800741 This->infoSectorLoc = MAX32;
742
743 if(nodups)
744 This->num_fat = 1;
745
Yi Kong39bbd962022-01-09 19:41:38 +0800746 if(check_media_type(This, boot))
Alistair Delvabeaee832021-02-24 11:27:23 -0800747 return -1;
748
Yi Kong39bbd962022-01-09 19:41:38 +0800749 if(This->num_clus >= FAT12)
Alistair Delvabeaee832021-02-24 11:27:23 -0800750 /* third FAT byte must be 0xff */
751 if(!mtools_skip_check && readByte(This, 3) != 0xff)
752 return -1;
Alistair Delvabeaee832021-02-24 11:27:23 -0800753
754 return check_fat(This);
755}
756
757/*
Yi Kong39bbd962022-01-09 19:41:38 +0800758 * Read the first sector of the FAT table into memory and initialize
Alistair Delvabeaee832021-02-24 11:27:23 -0800759 * structures.
760 */
Yi Kong39bbd962022-01-09 19:41:38 +0800761int fat_read(Fs_t *This, union bootsector *boot, int nodups)
Alistair Delvabeaee832021-02-24 11:27:23 -0800762{
763 This->fat_error = 0;
764 This->fat_dirty = 0;
765 This->last = MAX32;
766 This->freeSpace = MAX32;
767 This->lastFatSectorNr = 0;
768 This->lastFatSectorData = 0;
769
Yi Kong39bbd962022-01-09 19:41:38 +0800770 if(This->num_clus < FAT16)
771 return old_fat_read(This, boot, nodups);
Alistair Delvabeaee832021-02-24 11:27:23 -0800772 else
Yi Kong39bbd962022-01-09 19:41:38 +0800773 return fat_32_read(This, boot);
Alistair Delvabeaee832021-02-24 11:27:23 -0800774}
775
776
777unsigned int fatDecode(Fs_t *This, unsigned int pos)
778{
779 unsigned int ret;
780
781 ret = This->fat_decode(This, pos);
782 if(ret && (ret < 2 || ret > This->num_clus+1) && ret < This->last_fat) {
783 fprintf(stderr, "Bad FAT entry %d at %d\n", ret, pos);
784 This->fat_error++;
785 }
786 return ret;
787}
788
789/* append a new cluster */
790void fatAppend(Fs_t *This, unsigned int pos, unsigned int newpos)
791{
792 This->fat_encode(This, pos, newpos);
793 This->fat_encode(This, newpos, This->end_fat);
794 if(This->freeSpace != MAX32)
795 This->freeSpace--;
796}
797
798/* de-allocates the given cluster */
799void fatDeallocate(Fs_t *This, unsigned int pos)
800{
801 This->fat_encode(This, pos, 0);
802 if(This->freeSpace != MAX32)
803 This->freeSpace++;
804}
805
806/* allocate a new cluster */
807void fatAllocate(Fs_t *This, unsigned int pos, unsigned int value)
808{
809 This->fat_encode(This, pos, value);
810 if(This->freeSpace != MAX32)
811 This->freeSpace--;
812}
813
814void fatEncode(Fs_t *This, unsigned int pos, unsigned int value)
815{
816 unsigned int oldvalue = This->fat_decode(This, pos);
817 This->fat_encode(This, pos, value);
818 if(This->freeSpace != MAX32) {
819 if(oldvalue)
820 This->freeSpace++;
821 if(value)
822 This->freeSpace--;
823 }
824}
825
826unsigned int get_next_free_cluster(Fs_t *This, unsigned int last)
827{
828 unsigned int i;
829
830 if(This->last != MAX32)
831 last = This->last;
832
833 if (last < 2 ||
834 last >= This->num_clus+1)
835 last = 1;
836
837 for (i=last+1; i< This->num_clus+2; i++) {
838 unsigned int r = fatDecode(This, i);
839 if(r == 1)
840 goto exit_0;
841 if (!r) {
842 This->last = i;
843 return i;
844 }
845 }
846
847 for(i=2; i < last+1; i++) {
848 unsigned int r = fatDecode(This, i);
849 if(r == 1)
850 goto exit_0;
851 if (!r) {
852 This->last = i;
853 return i;
854 }
855 }
856
857
858 fprintf(stderr,"No free cluster %d %d\n", This->preallocatedClusters,
859 This->last);
860 return 1;
861 exit_0:
862 fprintf(stderr, "FAT error\n");
863 return 1;
864}
865
Yi Kong39bbd962022-01-09 19:41:38 +0800866bool getSerialized(Fs_t *Fs) {
867 return Fs->serialized;
868}
869
870unsigned long getSerialNumber(Fs_t *Fs) {
871 return Fs->serial_number;
872}
873
874uint32_t getClusterBytes(Fs_t *Fs) {
875 return Fs->cluster_size * Fs->sector_size;
876}
877
Alistair Delvabeaee832021-02-24 11:27:23 -0800878int fat_error(Stream_t *Dir)
879{
880 Stream_t *Stream = GetFs(Dir);
881 DeclareThis(Fs_t);
882
883 if(This->fat_error)
884 fprintf(stderr,"Fat error detected\n");
885
886 return This->fat_error;
887}
888
Yi Kong39bbd962022-01-09 19:41:38 +0800889uint32_t fat32RootCluster(Stream_t *Dir)
Alistair Delvabeaee832021-02-24 11:27:23 -0800890{
891 Stream_t *Stream = GetFs(Dir);
892 DeclareThis(Fs_t);
Yi Kong39bbd962022-01-09 19:41:38 +0800893
Alistair Delvabeaee832021-02-24 11:27:23 -0800894 if(This->fat_bits == 32)
895 return This->rootCluster;
896 else
897 return 0;
898}
899
900
901/*
902 * Get the amount of free space on the diskette
903 */
Yi Kong39bbd962022-01-09 19:41:38 +0800904mt_off_t getfree(Stream_t *Dir)
Alistair Delvabeaee832021-02-24 11:27:23 -0800905{
906 Stream_t *Stream = GetFs(Dir);
907 DeclareThis(Fs_t);
908
909 if(This->freeSpace == MAX32 || This->freeSpace == 0) {
910 register unsigned int i;
Yi Kong39bbd962022-01-09 19:41:38 +0800911 uint32_t total;
Alistair Delvabeaee832021-02-24 11:27:23 -0800912
913 total = 0L;
914 for (i = 2; i < This->num_clus + 2; i++) {
915 unsigned int r = fatDecode(This,i);
916 if(r == 1) {
917 return -1;
918 }
919 if (!r)
920 total++;
921 }
922 This->freeSpace = total;
923 }
Yi Kong39bbd962022-01-09 19:41:38 +0800924 return sectorsToBytes(This,
925 This->freeSpace * This->cluster_size);
Alistair Delvabeaee832021-02-24 11:27:23 -0800926}
927
928
929/*
930 * Ensure that there is a minimum of total sectors free
931 */
Yi Kong39bbd962022-01-09 19:41:38 +0800932int getfreeMinClusters(Stream_t *Dir, uint32_t size)
Alistair Delvabeaee832021-02-24 11:27:23 -0800933{
934 Stream_t *Stream = GetFs(Dir);
935 DeclareThis(Fs_t);
936 register unsigned int i, last;
937 size_t total;
938
939 if(batchmode && This->freeSpace == MAX32)
940 getfree(Stream);
941
942 if(This->freeSpace != MAX32) {
943 if(This->freeSpace >= size)
944 return 1;
945 else {
946 fprintf(stderr, "Disk full\n");
947 got_signal = 1;
948 return 0;
949 }
950 }
951
952 total = 0L;
953
954 /* we start at the same place where we'll start later to actually
955 * allocate the sectors. That way, the same sectors of the FAT, which
Yi Kong39bbd962022-01-09 19:41:38 +0800956 * are already loaded during getfreeMin will be able to be reused
Alistair Delvabeaee832021-02-24 11:27:23 -0800957 * during get_next_free_cluster */
958 last = This->last;
Yi Kong39bbd962022-01-09 19:41:38 +0800959
Alistair Delvabeaee832021-02-24 11:27:23 -0800960 if ( last < 2 || last >= This->num_clus + 2)
961 last = 1;
962 for (i=last+1; i< This->num_clus+2; i++){
963 unsigned int r = fatDecode(This, i);
964 if(r == 1) {
965 goto exit_0;
966 }
967 if (!r)
968 total++;
969 if(total >= size)
Yi Kong39bbd962022-01-09 19:41:38 +0800970 return 1;
Alistair Delvabeaee832021-02-24 11:27:23 -0800971 }
972 for(i=2; i < last+1; i++){
Yi Kong39bbd962022-01-09 19:41:38 +0800973 unsigned int r = fatDecode(This, i);
Alistair Delvabeaee832021-02-24 11:27:23 -0800974 if(r == 1) {
975 goto exit_0;
976 }
977 if (!r)
978 total++;
979 if(total >= size)
980 return 1;
981 }
982 fprintf(stderr, "Disk full\n");
983 got_signal = 1;
984 return 0;
985 exit_0:
986 fprintf(stderr, "FAT error\n");
987 return 0;
988}
989
990
Yi Kong39bbd962022-01-09 19:41:38 +0800991int getfreeMinBytes(Stream_t *Dir, mt_off_t size)
Alistair Delvabeaee832021-02-24 11:27:23 -0800992{
993 Stream_t *Stream = GetFs(Dir);
994 DeclareThis(Fs_t);
Yi Kong39bbd962022-01-09 19:41:38 +0800995 mt_off_t size2;
Alistair Delvabeaee832021-02-24 11:27:23 -0800996
997 size2 = size / (This->sector_size * This->cluster_size);
998 if(size % (This->sector_size * This->cluster_size))
999 size2++;
Yi Kong39bbd962022-01-09 19:41:38 +08001000 if((smt_off_t)size2 > UINT32_MAX) {
1001 fprintf(stderr, "Requested size too big\n");
1002 exit(1);
1003 }
1004 return getfreeMinClusters(Dir, (uint32_t) size2);
Alistair Delvabeaee832021-02-24 11:27:23 -08001005}
1006
1007
Yi Kong39bbd962022-01-09 19:41:38 +08001008uint32_t getStart(Stream_t *Dir, struct directory *dir)
Alistair Delvabeaee832021-02-24 11:27:23 -08001009{
1010 Stream_t *Stream = GetFs(Dir);
Yi Kong39bbd962022-01-09 19:41:38 +08001011 uint32_t first;
Alistair Delvabeaee832021-02-24 11:27:23 -08001012
1013 first = START(dir);
Yi Kong39bbd962022-01-09 19:41:38 +08001014 if(fat32RootCluster(Stream)) {
1015 first |= (uint32_t) STARTHI(dir) << 16;
1016 }
Alistair Delvabeaee832021-02-24 11:27:23 -08001017 return first;
1018}
1019
1020int fs_free(Stream_t *Stream)
1021{
1022 DeclareThis(Fs_t);
1023
1024 if(This->FatMap) {
1025 int i, nr_entries;
Yi Kong39bbd962022-01-09 19:41:38 +08001026 nr_entries = (This->fat_len + SECT_PER_ENTRY - 1) /
Alistair Delvabeaee832021-02-24 11:27:23 -08001027 SECT_PER_ENTRY;
1028 for(i=0; i< nr_entries; i++)
1029 if(This->FatMap[i].data)
Yi Kong39bbd962022-01-09 19:41:38 +08001030 free(This->FatMap[i].data);
Alistair Delvabeaee832021-02-24 11:27:23 -08001031 free(This->FatMap);
1032 }
1033 if(This->cp)
1034 cp_close(This->cp);
1035 return 0;
1036}