-
-
Notifications
You must be signed in to change notification settings - Fork 63
/
fat16.h
761 lines (702 loc) · 20.6 KB
/
fat16.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
/**
* @file filesystems/fat16.h
* @version 7.0.0
*
* @section License
* Copyright (C) 2009, William Greiman (Arduino Fat16 Library)
* Copyright (C) 2013-2015, Mikael Patel (Cosa, Refactoring)
* Copyright (C) 2015-2016, Erik Moqvist (written in c)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* This file is part of the Simba project.
*/
#ifndef __FILESYSTEMS_FAT16_H__
#define __FILESYSTEMS_FAT16_H__
#include "simba.h"
/*
* FAT16 file structures.
*
* @section Acknowledgement
* Refactoring of Arduino Fat16 Library, Copyright (C) 2009 by William Greiman
*
* @section References
* 1. http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
* 2. http://code.google.com/p/fat16lib/
* 3. https://github.com/mikaelpatel/Cosa/tree/master/libraries/FAT16
*/
/**
* The offset is relative to the start of the file.
*/
#define FAT16_SEEK_SET 0
/**
* The offset is relative to the current position indicator.
*/
#define FAT16_SEEK_CUR 1
/**
* The offset is relative to the end of the file.
*/
#define FAT16_SEEK_END 2
/**
* End of file indicator.
*/
#define FAT16_EOF -1
/**
* Open for reading.
*/
#define O_READ 0x01
/**
* Same as O_READ.
*/
#define O_RDONLY O_READ
/**
* Open for write.
*/
#define O_WRITE 0x02
/**
* Same as O_WRITE.
*/
#define O_WRONLY O_WRITE
/**
* Open for reading and writing.
*/
#define O_RDWR (O_READ | O_WRITE)
/**
* The file position indicator shall be set to the end of the file
* prior to each write.
*/
#define O_APPEND 0x04
/**
* Synchronous writes.
*/
#define O_SYNC 0x08
/**
* Create the file if non-existent.
*/
#define O_CREAT 0x10
/**
* If O_CREAT and O_EXCL are set, file open shall fail if the file
* exists.
*/
#define O_EXCL 0x20
/**
* Truncate the file to zero length.
*/
#define O_TRUNC 0x40
/**
* File is read-only.
*/
#define DIR_ATTR_READ_ONLY 0x01
/**
* File should hidden in directory listings.
*/
#define DIR_ATTR_HIDDEN 0x02
/**
* Entry is for a system file.
*/
#define DIR_ATTR_SYSTEM 0x04
/**
* Directory entry contains the volume label.
*/
#define DIR_ATTR_VOLUME_ID 0x08
/**
* Entry is for a directory.
*/
#define DIR_ATTR_DIRECTORY 0x10
/**
* Old DOS archive bit for backup support.
*/
#define DIR_ATTR_ARCHIVE 0x20
/**
* Block read function callback.
*/
typedef ssize_t (*fat16_read_t)(void *arg_p,
void *dst_p,
uint32_t src_block);
/**
* Block write function callback.
*/
typedef ssize_t (*fat16_write_t)(void *arg_p,
uint32_t dst_block,
const void *src_p);
/**
* A FAT entry.
*/
typedef uint16_t fat_t;
/**
* FAT Time Format. A FAT directory entry time stamp is a 16-bit
* field that has a granularity of 2 seconds. Here is the format
* (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
* 16-bit word).
*
* Bits 0-4: 2-second count, valid value range 0-29 inclusive
* (0-58 seconds).
* Bits 5-10: Minutes, valid value range 0-59 inclusive.
* Bits 11-15: Hours, valid value range 0-23 inclusive.
*
* The valid time range is from Midnight 00:00:00 to 23:59:58.
*/
union fat16_time_t {
uint16_t as_uint16;
struct {
uint16_t seconds : 5;
uint16_t minutes : 6;
uint16_t hours : 5;
} bits;
};
/**
* FAT date representation support
* Date Format. A FAT directory entry date stamp is a 16-bit field
* that is basically a date relative to the MS-DOS epoch of
* 01/01/1980. Here is the format (bit 0 is the LSB of the 16-bit
* word, bit 15 is the MSB of the 16-bit word):
*
* Bits 0-4: Day of month, valid value range 1-31 inclusive.
* Bits 5-8: Month of year, 1 = January, valid value range 1-12
* inclusive.
* Bits 9-15: Count of years from 1980, valid value range 0-127
* inclusive (1980-2107).
*/
union fat16_date_t {
uint16_t as_uint16;
struct {
uint16_t day : 5;
uint16_t month : 4;
uint16_t year : 7;
} bits;
};
/**
* MBR partition table entry. A partition table entry for a MBR
* formatted storage device. The MBR partition table has four entries.
*/
struct part_t {
/**
* Boot Indicator. Indicates whether the volume is the active
* partition. Legal values include: 0x00. Do not use for booting.
* 0x80 Active partition.
*/
uint8_t boot;
/**
* Head part of Cylinder-head-sector address of the first block in
* the partition. Legal values are 0-255. Only used in old PC BIOS.
*/
uint8_t begin_head;
/**
* Sector part of Cylinder-head-sector address of the first block in
* the partition. Legal values are 1-63. Only used in old PC BIOS.
*/
unsigned begin_sector : 6;
/**
* High bits cylinder for first block in partition.
*/
unsigned begin_cylinder_high : 2;
/**
* Combine beginCylinderLow with beginCylinderHigh. Legal values
* are 0-1023. Only used in old PC BIOS.
*/
uint8_t begin_cylinder_low;
/**
* Partition type. See defines that begin with PART_TYPE_ for
* some Microsoft partition types.
*/
uint8_t type;
/**
* head part of cylinder-head-sector address of the last sector in the
* partition. Legal values are 0-255. Only used in old PC BIOS.
*/
uint8_t end_head;
/**
* Sector part of cylinder-head-sector address of the last sector in
* the partition. Legal values are 1-63. Only used in old PC BIOS.
*/
unsigned end_sector : 6;
/**
* High bits of end cylinder
*/
unsigned end_cylinder_high : 2;
/**
* Combine endCylinderLow with endCylinderHigh. Legal values
* are 0-1023. Only used in old PC BIOS.
*/
uint8_t end_cylinder_low;
/**
* Logical block address of the first block in the partition.
*/
uint32_t first_sector;
/**
* Length of the partition, in blocks.
*/
uint32_t total_sectors;
} PACKED;
/**
* BIOS parameter block; The BIOS parameter block describes the
* physical layout of a FAT volume.
*/
struct bpb_t {
/**
* Count of bytes per sector. This value may take on only the
* following values: 512, 1024, 2048 or 4096
*/
uint16_t bytes_per_sector;
/**
* Number of sectors per allocation unit. This value must be a
* power of 2 that is greater than 0. The legal values are
* 1, 2, 4, 8, 16, 32, 64, and 128.
*/
uint8_t sectors_per_cluster;
/**
* Number of sectors before the first FAT. This value must not be
* zero.
*/
uint16_t reserved_sector_count;
/**
* The count of FAT data structures on the volume. This field
* should always contain the value 2 for any FAT volume of any
* type.
*/
uint8_t fat_count;
/**
* For FAT12 and FAT16 volumes, this field contains the count of
* 32-byte directory entries in the root directory. For FAT32 volumes,
* this field must be set to 0. For FAT12 and FAT16 volumes, this
* value should always specify a count that when multiplied by 32
* results in a multiple of bytesPerSector. FAT16 volumes should
* use the value 512.
*/
uint16_t root_dir_entry_count;
/**
* This field is the old 16-bit total count of sectors on the volume.
* This count includes the count of all sectors in all four regions
* of the volume. This field can be 0; if it is 0, then totalSectors32
* must be non-zero. For FAT32 volumes, this field must be 0. For
* FAT12 and FAT16 volumes, this field contains the sector count, and
* totalSectors32 is 0 if the total sector count fits
* (is less than 0x10000).
*/
uint16_t total_sectors_small;
/**
* This dates back to the old MS-DOS 1.x media determination and is
* no longer usually used for anything. 0xf8 is the standard value
* for fixed (non-removable) media. For removable media, 0xf0 is
* frequently used. Legal values are 0xf0 or 0xf8-0xff.
*/
uint8_t media_type;
/**
* Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
* On FAT32 volumes this field must be 0, and sectorsPerFat32
* contains the FAT size count.
*/
uint16_t sectors_per_fat;
/**
* Sectors per track for interrupt 0x13. Not used otherwise.
*/
uint16_t sectors_per_track;
/**
* Number of heads for interrupt 0x13. Not used otherwise.
*/
uint16_t head_count;
/**
* Count of hidden sectors preceding the partition that contains this
* FAT volume. This field is generally only relevant for media
* visible on interrupt 0x13.
*/
uint32_t hiddden_sectors;
/**
* This field is the new 32-bit total count of sectors on the volume.
* This count includes the count of all sectors in all four regions
* of the volume. This field can be 0; if it is 0, then
* totalSectors16 must be non-zero.
*/
uint32_t total_sectors_large;
} PACKED;
/**
* Boot sector for a FAT16 or FAT32 volume.
*/
struct fbs_t {
/**
* X86 jmp to boot program
*/
uint8_t jmp_to_boot_code[3];
/**
* Informational only - don't depend on it
*/
char oem_name[8];
/**
* BIOS Parameter Block
*/
struct bpb_t bpb;
/**
* For int0x13 use value 0x80 for hard drive
*/
uint8_t drive_number;
/**
* Used by Windows NT - should be zero for FAT
*/
uint8_t reserved1;
/**
* 0x29 if next three fields are valid
*/
uint8_t boot_signature;
/**
* Usually generated by combining date and time
*/
uint32_t volume_serial_number;
/**
* Should match volume label in root dir
*/
char volume_label[11];
/**
* Informational only - don't depend on it
*/
char file_system_type[8];
/**
* X86 boot code
*/
uint8_t boot_code[448];
/**
* Must be 0x55AA
*/
uint16_t boot_sector_sig;
} PACKED;
/**
* Master Boot Record. The first block of a storage device that is
* formatted with a MBR.
*/
struct mbr_t {
/**
* Code Area for master boot program.
*/
uint8_t codeArea[440];
/**
* Optional WindowsNT disk signature. May contain more boot code.
*/
uint32_t diskSignature;
/**
* Usually zero but may be more boot code.
*/
uint16_t usuallyZero;
/**
* Partition tables.
*/
struct part_t part[4];
/**
* First MBR signature byte. Must be 0x55
*/
uint16_t mbr_sig;
} PACKED;
/**
* FAT short directory entry. Short means short 8.3 name, not the
* entry size.
*/
struct dir_t {
/**
* Short 8.3 name.
* The first eight bytes contain the file name with blank fill.
* The last three bytes contain the file extension with blank fill.
*/
uint8_t name[11];
/**
* Entry attributes. The upper two bits of the attribute byte are
* reserved and should always be set to 0 when a file is created
* and never modified or looked at after that. See defines that
* begin with DIR_ATT_.
*/
uint8_t attributes;
/**
* Reserved for use by Windows NT. Set value to 0 when a file is
* created and never modify or look at it after that.
*/
uint8_t reserved1;
/**
* The granularity of the seconds part of creationTime is 2 seconds
* so this field is a count of tenths of a second and its valid
* value range is 0-199 inclusive. (WHG note - seems to be hundredths)
*/
uint8_t creation_time_tenths;
/**
* Time file was created.
*/
uint16_t creation_time;
/**
* Date file was created.
*/
uint16_t creation_date;
/**
* Last access date. Note that there is no last access time, only
* a date. This is the date of last read or write. In the case of
* a write, this should be set to the same date as lastWriteDate.
*/
uint16_t last_access_date;
/**
* High word of this entry's first cluster number (always 0 for a
* FAT12 or FAT16 volume).
*/
uint16_t first_cluster_high;
/**
* Time of last write. File creation is considered a write.
*/
uint16_t last_write_time;
/**
* Date of last write. File creation is considered a write.
*/
uint16_t last_write_date;
/**
* Low word of this entry's first cluster number.
*/
uint16_t first_cluster_low;
/**
* 32-bit unsigned holding this file's size in bytes.
*/
uint32_t file_size;
} PACKED;
union fat16_cache16_t {
/* Used to access cached file data blocks. */
uint8_t data[512];
/* Used to access cached FAT entries. */
fat_t fat[256];
/* Used to access cached directory entries. */
struct dir_t dir[16];
/* Used to access a cached Master Boot Record. */
struct mbr_t mbr;
/* Used to access to a cached FAT16 boot sector. */
struct fbs_t fbs;
};
struct fat16_cache_t {
uint32_t block_number; /* Logical number of block in the cache */
uint8_t dirty; /* cacheFlush() will write block if true */
uint32_t mirror_block; /* mirror block for second FAT */
union fat16_cache16_t buffer; /* 512 byte cache for raw blocks */
};
struct fat16_t {
/* Data block read and wrte functions. */
fat16_read_t read;
fat16_write_t write;
void *arg_p;
unsigned int partition;
/* Volume info */
uint8_t fat_count; /* number of FATs */
uint8_t blocks_per_cluster; /* must be power of 2 */
uint16_t root_dir_entry_count; /* should be 512 for FAT16 */
fat_t blocks_per_fat; /* number of blocks in one FAT */
fat_t cluster_count; /* total clusters in volume */
uint32_t volume_start_block; /* start of volume */
uint32_t fat_start_block; /* start of first FAT */
uint32_t root_dir_start_block; /* start of root dir */
uint32_t data_start_block; /* start of data clusters */
/* block cache */
struct fat16_cache_t cache;
};
struct fat16_file_t {
struct fat16_t *fat16_p; /* file system that contains this file */
uint8_t flags; /* see above for bit definitions */
int16_t dir_entry_block; /* block of directory entry for open file */
int16_t dir_entry_index; /* index of directory entry for open file */
fat_t first_cluster; /* first cluster of file */
size_t file_size; /* fileSize */
fat_t cur_cluster; /* current cluster */
size_t cur_position; /* current byte offset */
};
struct fat16_dir_t {
int16_t root_index;
struct fat16_file_t file; /* use the file datastructure to
reresent a directory */
};
struct fat16_dir_entry_t {
char name[256];
int is_dir;
size_t size;
struct date_t latest_mod_date;
};
/**
* Initialize a FAT16 volume.
*
* @param[in,out] self_p FAT16 object to initialize.
* @param[in] read Callback function used to read blocks of data.
* @param[in] write Callback function used to write blocks of data.
* @param[in] arg_p Argument passed as the first arguemtn to read()
* and write().
* @param[in] partition Partition to be used. Legal values for a
* partition are 1-4 to use the corresponding
* partition on a device formatted with a MBR,
* Master Boot Record, or zero if the device is
* formatted as a super floppy with the FAT boot
* sector in block zero.
*
* @return zero(0) or negative error code.
*/
int fat16_init(struct fat16_t *self_p,
fat16_read_t read,
fat16_write_t write,
void *arg_p,
unsigned int partition);
/**
* Mount given FAT16 volume.
*
* @param[in] self_p FAT16 object.
*
* @return zero(0) or negative error code.
*/
int fat16_mount(struct fat16_t *self_p);
/**
* Unmount given FAT16 volume.
*
* @param[in] self_p FAT16 object.
*
* @return zero(0) or negative error code.
*/
int fat16_unmount(struct fat16_t *self_p);
/**
* Create an empty FAT16 file system on the device.
*
* @param[in] self_p FAT16 object.
*/
int fat16_format(struct fat16_t *self_p);
/**
* Print volume information to given channel.
*
* @param[in] self_p FAT16 object.
* @param[in] chan_p Output channel.
*
* @return zero(0) or negative error code.
*/
int fat16_print(struct fat16_t *self_p, chan_t *chan_p);
/**
* Open a file by file path and mode flags.
*
* @param[in] self_p FAT16 object.
* @param[in,out] file_p File object to be initialized.
* @param[in] path_p A valid 8.3 DOS name for a file path.
* @param[in] oflag mode of file open (create, read, write, etc).
*
* @return zero(0) or negative error code.
*/
int fat16_file_open(struct fat16_t *self_p,
struct fat16_file_t *file_p,
const char *path_p,
int oflag);
/**
* Close a file and force cached data and directory information to be
* written to the media.
*
* @param[in] file_p File object.
*
* @return zero(0) or negative error code.
*/
int fat16_file_close(struct fat16_file_t *file_p);
/**
* Read data to given buffer with given size from the file.
*
* @param[in] file_p File object.
* @param[in] buf_p Buffer to read into.
* @param[in] size number of bytes to read.
*
* @return number of bytes read or EOF(-1).
*/
ssize_t fat16_file_read(struct fat16_file_t *file_p,
void *buf_p,
size_t size);
/**
* Write data from buffer with given size to the file.
*
* @param[in] file_p File object.
* @param[in] buf_p Buffer to write.
* @param[in] size number of bytes to write.
*
* @return Number of bytes written or EOF(-1).
*/
ssize_t fat16_file_write(struct fat16_file_t *file_p,
const void *buf_p,
size_t size);
/**
* Sets the file's read/write position relative to mode.
*
* @param[in] file_p File object.
* @param[in] pos New position in bytes from given mode.
* @param[in] whence Absolute, relative or from end.
*
* @return zero(0) or negative error code.
*/
int fat16_file_seek(struct fat16_file_t *file_p,
size_t pos,
int whence);
/**
* Return current position in the file.
*
* @param[in] file_p File object.
*
* @return Current position or negative error code.
*/
ssize_t fat16_file_tell(struct fat16_file_t *file_p);
/**
* Truncate given file to a size of precisly `size` bytes.
*
* If the file previously was larger than this size, the extra data is
* lost. If the file previously was shorter, it is extended, and the
* extended part reads as null bytes ('\0').
*
* @param[in] file_p File object.
* @param[in] size New size of the file in bytes.
*
* @return zero(0) or negative error code.
*/
int fat16_file_truncate(struct fat16_file_t *file_p,
size_t size);
/**
* Return number of bytes in the file.
*
* @param[in] file_p File object.
*
* @return File size in bytes or negative error code.
*/
ssize_t fat16_file_size(struct fat16_file_t *file_p);
/**
* Causes all modified data and directory fields to be written to the
* storage device.
*
* @param[in] file_p File object.
*
* @return zero(0) or negative error code.
*/
int fat16_file_sync(struct fat16_file_t *file_p);
/**
* Open a directory by directory path and mode flags.
*
* @param[in] self_p FAT16 object.
* @param[in,out] dir_p Directory object to be initialized.
* @param[in] path_p A valid 8.3 DOS name for a directory path.
* @param[in] oflag mode of the directory to open (create, read, etc).
*
* @return zero(0) or negative error code.
*/
int fat16_dir_open(struct fat16_t *self_p,
struct fat16_dir_t *dir_p,
const char *path_p,
int oflag);
/**
* Close given directory.
*
* @param[in] dir_p Directory object.
*
* @return zero(0) or negative error code.
*/
int fat16_dir_close(struct fat16_dir_t *dir_p);
/**
* Read the next file or directory within the opened directory.
*
* @param[in] dir_p Directory object.
* @param[out] entry_p Read entry.
*
* @return true(1) if an entry was read or false(0) if no entry could
* be read, otherwise negative error code.
*/
int fat16_dir_read(struct fat16_dir_t *dir_p,
struct fat16_dir_entry_t *entry_p);
#endif