25 #if defined(MEGA65_BUILD) || !defined(XEMU_BUILD) || (defined(XEMU_BUILD) && defined(SD_CONTENT_SUPPORT))
28 # define FDISK_SUPPORT
34 # define FATDEBUG DEBUG
35 # define FATDEBUGPRINT DEBUGPRINT
38 # define FATDEBUG printf
39 # define FATDEBUGPRINT printf
40 # define FATAL(...) do { fprintf(stderr, "FATAL: "); fprintf(stderr, __VA_ARGS__); exit(1); } while(0)
41 # define ERROR_WINDOW(...) do { fprintf(stderr, "ERROR: "); fprintf(stderr, __VA_ARGS__); } while(0)
42 # define OFF_T_ERROR ((off_t)-1)
44 typedef unsigned long int Uint32;
45 typedef unsigned int Uint16;
46 typedef unsigned char Uint8 ;
56 #include <sys/types.h>
66 #define FS_MINIMAL_SIZE_IN_BLOCKS 10
83 if (
block >= disk.blocks) {
84 FATDEBUGPRINT(
"FATFS: WARNING: Host FS: reading outside of the device" NL);
91 if (
block >= disk.blocks) {
92 FATDEBUGPRINT(
"FATFS: WARNING: Host FS: writing outside of the device" NL);
101 FATDEBUGPRINT(
"FATFS: WARNING: read partition block: invalid partition is selected" NL);
105 FATDEBUGPRINT(
"FATFS: WARNING: read partition block: trying to read block outside of partition!" NL);
113 FATDEBUGPRINT(
"FATFS: WARNING: write partition block: invalid partition is selected" NL);
117 FATDEBUGPRINT(
"FATFS: WARNING: write partition block: trying to read block outside of partition!" NL);
131 FATDEBUGPRINT(
"FATFS: WARNING: read cluster: invalid in-cluster-block data %d" NL, block_in_cluster);
144 FATDEBUGPRINT(
"FATFS: WARNING: write cluster: invalid in-cluster-block data %d" NL, block_in_cluster);
150 #define AS_WORD(p,o) (p[o] + (p[o+1] << 8))
151 #define AS_DWORD(p,o) (p[o] + (p[o+1] << 8) + (p[o+2] << 16) + (p[o+3] << 24))
163 static int mfat_flush_fat_cache (
void )
165 if (fat_cache.dirty) {
166 if (mfat_write_part_blk(fat_cache.block, fat_cache.buf))
173 mfat_write_part_blk(fat_cache.block + fat2_offset, fat_cache.buf);
180 static int cluster_was_free;
196 fat_cache.ofs = (
cluster & 127) << 2;
197 if (
block != fat_cache.block) {
198 mfat_flush_fat_cache();
199 if (mfat_read_part_blk(
block, fat_cache.buf))
201 fat_cache.block =
block;
206 FATDEBUG(
"FATFS: DEBUG: mfat_read_chain: got cluster: $%08X" NL,
AS_DWORD(fat_cache.buf, fat_cache.ofs));
215 cluster_was_free = (
cluster == 0);
241 int ret = mfat_read_fat_chain(
cluster);
244 for (
int a = fat_cache.ofs; a < fat_cache.ofs + 4; a++, next >>= 8) {
259 if (next_cluster == 1)
261 if (mfat_write_fat_chain(
cluster, 1))
265 if (mfat_flush_fat_cache())
269 mfat_flush_fat_cache();
282 FATDEBUG(
"FATFS: DEBUG: %s() is about seeking for free linear chunk in FAT for %u bytes size object" NL, __func__,
size);
290 if (
next == 0 && cluster_was_free) {
293 len = cluster_byte_size;
296 len += cluster_byte_size;
300 FATDEBUG(
"FATFS: DEBUG: %s() founds %u sized free linear chunk in FAT at cluster %u" NL, __func__,
size, first);
301 for (
Uint32 a = 0; a < seq; a++) {
302 if (mfat_write_fat_chain(first + a, a != seq - 1 ? first + a + 1 : 0)) {
306 mfat_free_fat_chain(first);
310 mfat_flush_fat_cache();
316 FATDEBUG(
"FATFS: DEBUG: %s() could not found %d sized free linear chunk in FAT ..." NL, __func__,
size);
327 disk.blocks = device_size;
329 fat_cache.block = -1;
341 int first_valid = -1;
342 Uint8 cache[512], *p;
344 mfat_flush_fat_cache();
345 fat_cache.block = -1;
348 if (mfat_read_DEVICE_blk(0, cache))
353 for (
int a = 0; a < 4; a++, p += 16) {
362 (p[4] == 0xB || p[4] == 0xC) &&
370 FATDEBUG(
"FATFS: Part#%d: %08X - %08X (size=%08X), type = %02X, valid=%d size=%d Mbytes" NL,
386 static void hexdump (
Uint8 *p,
int lines,
const char *title )
390 for (
int b = 0 ; b < lines ; b ++) {
392 for (
int a = 0; a < 32; a++)
394 for (
int a = 0; a < 32; a++)
395 FATDEBUG(
"%c", p[a] >=32 && p[a] < 127 ? p[a] :
'?');
408 int previous_part = disk.part;
410 mfat_flush_fat_cache();
411 fat_cache.block = -1;
421 if (mfat_read_part_blk(0, cache))
424 if (
AS_WORD(cache, 0xB) != 512) {
425 FATDEBUGPRINT(
"FATFS: WARNING: Only 512 bytes / logical sector is supported!" NL);
428 FATDEBUG(
"FATFS: INFO: Logical sectors per cluster: %d (cluster size = %d bytes)" NL, cache[0xD], cache[0xD] * 512);
429 if (cache[0xD] == 0) {
430 FATDEBUGPRINT(
"FATFS: WARNING: Invalid logical sectors per cluster information!" NL);
435 FATDEBUG(
"FATFS: INFO: FAT copies: %d" NL, cache[0x10]);
436 if (cache[0x10] != 2) {
444 FATDEBUG(
"FATFS: INFO: FS information sector at block: %d" NL,
AS_WORD(cache, 0x30));
453 FATDEBUG(
"FATFS: INFO: Number of clusters from FAT size: %d" NL,
AS_DWORD(cache, 0x24) * 128);
477 if (mfat_read_cluster(a, b, cache)) {
481 FATDEBUG(
"FATFS: INFO: Root directory, cluster=%d/block=%d" NL, a, b);
482 hexdump(cache, 16, NULL);
483 for (
int c = 0; c < 512; c += 32) {
484 if (cache[c] >= 32 && cache[c] != 0xE5 && (cache[c + 0xB] & 8)) {
486 FATDEBUG(
"FATFS: INFO: VOLUME is: \"%s\"" NL, cache + c);
489 goto end_of_directory;
492 a = mfat_read_fat_chain(a);
505 hexdump(cache, 16,
"FS information sector");
506 FATDEBUG(
"FATFS: INFO: FS info signature @0=$%08X @1E4=$%08X @1FC=$%08X" NL,
509 if (
AS_DWORD(cache, 0) != 0x41615252 ||
AS_DWORD(cache, 0x1E4) != 0x61417272 ||
AS_DWORD(cache, 0x1FC) != 0xAA550000U) {
521 disk.part = previous_part;
566 while (
cluster >= 2 && cluster < p->partition->clusters) {
569 if (next_cluster == 1)
571 if (next_cluster >= 2 && next_cluster != (
cluster + 1) && fragmented)
605 if (p->
cluster != stream_cache.cluster || p->
in_cluster_block != stream_cache.cluster_block || disk.part != stream_cache.part) {
608 stream_cache.cluster = p->
cluster;
610 stream_cache.part = disk.part;
612 FATDEBUG(
"FATFS: INFO: WOW, data block has been cached for cluster %d, block %d within cluster" NL, stream_cache.cluster, stream_cache.cluster_block);
636 FATAL(
"FATFS: in_block_pos is greater than 512");
654 static Uint8 cache[512];
655 static Uint32 cached_cluster;
656 static int cached_cluster_block = -1;
669 FATDEBUG(
"WOW, data block has been cached for cluster %d, block %d within cluster" NL, cached_cluster, cached_cluster_block);
693 FATAL(
"FATFS: in_block_pos is greater than 512");
726 FATDEBUG(
"FATFS: INFO: %s getting ret %d" NL, __func__, ret);
730 FATAL(
"FATFS: dirent read 32 is not 32" NL);
733 FATDEBUG(
"FATFS: INFO: %s end of stream" NL, __func__);
738 ((
buf[0xB] & 0x0F) == 0x0F) ||
739 (
buf[0x0] <= 0x20) ||
740 (
buf[0x0] & 0x80) ||
752 while (
buf[i] != 0x20 && i < 8)
754 if (
buf[8] != 0x20) {
757 while (
buf[8 + i] != 0x20 && i < 3)
758 *d++ =
buf[8 + (i++)];
771 time.tm_hour = (
AS_WORD(
buf, 0x16) >> 11) & 31;
774 time.tm_year = (
AS_WORD(
buf, 0x18) >> 9) + 80;
778 p->
time = mktime(&time);
789 char normalized_search_name[8 + 1 + 3 + 1];
798 FATDEBUG(
"FATFS: INFO: %s considering file [%s] as [%s]" NL, __func__, p->
name,
name ? normalized_search_name :
"<first>");
802 if (!strcmp(p->
name, normalized_search_name))
805 FATDEBUG(
"FATFS: INFO: %s returns because of ret being %d" NL, __func__, ret);
815 char fat_name[8 + 3 + 1];
817 int write_null_entry = 0;
823 ERROR_WINDOW(
"Problem: file %s already exists as a directory on the image\nNot possible to overwrite with a file\nSource file: %s", dirent->
name,
name);
829 mfat_free_fat_chain(dirent->
cluster);
830 }
else if (ret == 0) {
833 write_null_entry = 1;
834 }
else if (ret == -1) {
838 FATAL(
"Unknown error code of %d in %s", ret, __func__);
842 repos_cur_dirent(&dirent->
stream);
851 mfat_write_cluster(stream_cache.cluster, stream_cache.cluster_block, stream_cache.buf);
854 memcpy(p, fat_name, 8 + 3);
855 p[0x1A] = dirent->
cluster & 0xFF;
856 p[0x1B] = (dirent->
cluster >> 8) & 0xFF;
857 p[0x14] = (dirent->
cluster >> 16) & 0xFF;
858 p[0x15] = (dirent->
cluster >> 24) & 0xFF;
859 p[0x1C] =
size & 0xFF;
860 p[0x1D] = (
size >> 8) & 0xFF;
861 p[0x1E] = (
size >> 16) & 0xFF;
862 p[0x1F] = (
size >> 24) & 0xFF;
864 time_t ts = time(NULL);
866 struct tm *tm = localtime(&ts);
868 p[0x16] = (tm->tm_sec >> 1) + ((tm->tm_min & 0xF) << 5);
869 p[0x17] = (tm->tm_min >> 3) + (tm->tm_hour << 3);
870 p[0x18] = tm->tm_mday + (((tm->tm_mon + 1) & 7) << 5);
871 p[0x19] = ((tm->tm_mon + 1) >> 3) + ((tm->tm_year - 80) << 1);
872 memcpy(p + 0x0E, p + 0x16, 4);
875 if (mfat_write_cluster(stream_cache.cluster, stream_cache.cluster_block, stream_cache.buf)) {
892 if (!(p->
type & (0x10|0x08|0x40|0x80)))
915 static const char *allowed_dos_name_chars =
"!#$%&'()-@^_`{}~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
918 static char fat_dirent_name[8 + 3 + 1];
927 memset(d, 0x20, 8 + 3);
933 }
else if (c ==
'.') {
943 if (c >=
'a' && c <=
'z')
945 if (!strchr(allowed_dos_name_chars, c))
966 }
else if (c ==
'.') {
976 if (c >=
'a' && c <=
'z')
978 if (!strchr(allowed_dos_name_chars, c))
998 if (lseek(fd,
ofs, SEEK_SET) !=
ofs) {
999 perror(
"Host seek error");
1002 if (read(fd,
buf, 512) != 512) {
1003 perror(
"Host read error");
1012 static const char default_fn[] =
"hyppo.disk";
1013 const char *
fn = (argc > 1) ? argv[1] : default_fn;
1015 fd = open(
fn, O_RDONLY);
1017 perror(
"Open disk image");
1020 off_t devsize = lseek(fd, 0, SEEK_END);
1022 perror(
"Host lseek to get device size");
1026 if (devsize & 511) {
1027 FATDEBUGPRINT(
"FATFS: WARNING: Host size error: size is not 512 byte aligned" NL);
1031 if (devsize < 16*1024*1024) {
1032 FATDEBUGPRINT(
"FATFS: WARNING: Host size error: image is too small (<16Mbytes)" NL);
1037 if (devsize > 0x2000000) {
1038 FATDEBUGPRINT(
"FATFS: WARNING: Host size error: image is too large (>16Gbytes)" NL);
1045 FATDEBUGPRINT(
"FATFS: WARNING: No partition could be detected in MBR for usage" NL);
1062 FATDEBUG(
"GET REAL SIZE = %d, fragmented = %d" NL, ret, fragmented);
1065 for (
int x = 0;
x < 2;
x++) {
1079 FATDEBUG(
"RESULT of searching file : %d" NL, ret);
1081 FATDEBUG(
"RESULT of searching file (AGAIN!): %d" NL, ret);