U0 CDate2Dos(U16 *t, U16 *d, CDate cdt) { CDateStruct ds; Date2Struct(&ds, cdt); *d = ds.day_of_mon + (ds.mon + (ds.year - 1980) << 4) << 5; *t = ds.sec >> 1 + (ds.min + ds.hour << 6) << 5; } CDate Dos2CDate(U16 t, U16 d) { CDateStruct ds; MemSet(&ds, 0, sizeof(CDateStruct)); ds.day_of_mon = d & 0x1F; d = d >> 5; ds.mon = d & 0xF; ds.year = d >> 4 + 1980; ds.sec = (t & 0x1F) * 2; t = t >> 5; ds.min = t & 0x3F; ds.hour = t >> 6; return Struct2Date(&ds); } U0 FAT32Init(CDrive *drive) { CFAT32Boot br32; Bool unlock; try { unlock = DriveLock(drive); drive->fs_type = FSt_FAT32; BlkRead(drive, &br32, drive->drv_offset, 1); drive->file_system_info_sect = drive->drv_offset + br32.file_system_info_sect; drive->fat1 = drive->drv_offset + br32.reserved_sects; drive->fat2 = drive->fat1 + br32.sects_per_fat; drive->data_area = drive->fat2 + br32.sects_per_fat - 2 * br32.sects_per_clus; //Starts at Clus 2 drive->spc = br32.sects_per_clus; drive->root_clus = br32.root_clus; DriveFATBlkAlloc(drive); Free(drive->fis); drive->fis = ZMAlloc(BLK_SIZE); BlkRead(drive, drive->fis, drive->file_system_info_sect, 1); if (unlock) DriveUnlock(drive); } catch if (unlock) DriveUnlock(drive); } U0 FAT32Format(U8 drv_let, Bool quick=TRUE) { CFAT32Boot *br = CAlloc(BLK_SIZE); CFAT32FileInfoSect *fis = CAlloc(BLK_SIZE); CDrive *drive = Letter2Drive(drv_let); I64 i, l; try { DriveLock(drive); DriveTypeSet(drv_let, FSt_FAT32); drive->fs_type = FSt_FAT32; br->jump_and_nop[0] = OC_JMP_REL8; br->jump_and_nop[1] = offset(CFAT32Boot.code) - 2; br->jump_and_nop[2] = OC_NOP; br->oem_name[0](I64) = 'MSWIN4.1'; br->bytes_per_sect = BLK_SIZE; if (drive->size <= 500000) br->sects_per_clus = 1; else if (drive->size <= 2000000) br->sects_per_clus = 2; else if (drive->size <= 6000000) br->sects_per_clus = 4; else if (drive->size <= 12000000) br->sects_per_clus = 8; else if (drive->size <= 33000000) br->sects_per_clus = 16; else if (drive->size <= 67000000) br->sects_per_clus = 32; else br->sects_per_clus = 64; br->reserved_sects = 32; br->copies_of_fat = 2; br->media_desc = 0xF8; br->sects = drive->size; l = (br->sects / br->sects_per_clus) >> (BLK_SIZE_BITS - 2) + 1; br->sects_per_fat = l; br->root_clus = 2; br->file_system_info_sect = 1; br->log_drive_num = 0x80; br->ext_signature = 0x29; br->serial_num = RandU32; MemCopy(br->vol_name, "NO NAME ", 11); br->fat_name[0](I64) = 'FAT32 '; br->signature = 0xAA55; fis->signature1 = 'RRaA'; fis->signature2 = 'rrAa'; fis->free_clus = -1; fis->most_recently_alloced = 0; fis->signature3 = 0xAA550000; if (quick) i = br->reserved_sects + 2 * l + 4 * br->sects_per_clus; else i = drive->size; BlkWriteZero(drive, drive->drv_offset, i); BlkWrite(drive, fis, drive->drv_offset + br->file_system_info_sect, 1); BlkWrite(drive, br, drive->drv_offset, 1); FAT32Init(drive); ClusAlloc(drive, 0, 1, FALSE); //Alloc #1 br->root_clus = ClusAlloc(drive, 0, 1, FALSE); BlkWrite(drive, br, drive->drv_offset, 1); FAT32Init(drive); DriveUnlock(drive); } catch DriveUnlock(drive); Free(br); Free(fis); } Bool FATNameTo(U8 *dst, U8 *src) { I64 i; MemSet(dst, CH_SPACE, 11); if (!FileNameCheck(src)) return FALSE; if (!StrCompare(src, "..")) { *dst = '.'; dst[1] = '.'; return TRUE; } else if (!StrCompare(src, ".")) { *dst = '.'; return TRUE; } i = 0; while (i < 8 && *src && *src != '.') dst[i++] = ToUpper(*src++); i = 8; if (*src == '.') src++; while (*src) if (*src != '.') dst[i++] = ToUpper(*src++); else src++; return TRUE; } I64 FATNameXSum(U8 *src) { I64 i, res = 0; for (i = 0; i < 11; i++) if (res & 1) res.u8[0] = 0x80 + res >> 1 + *src++; else res.u8[0] = res >> 1 + *src++; return res; } Bool FATFromName(U8 *dst, U8 *src) { I64 i, j, k = 0; for (j = 7; j >= 0 && src[j] == CH_SPACE; j--); for(i = 0; i <= j; i++) dst[k++] = src[i]; for (j = 10; j >= 8 && src[j] == CH_SPACE; j--); if (*src != '.' && j != 7) dst[k++] = '.'; for(i = 8; i <= j; i++) dst[k++] = src[i]; dst[k++] = 0; return FileNameCheck(dst); } U8 fat_long_name_map[13] = { offset(CFAT32DirEntryLong.name1), offset(CFAT32DirEntryLong.name1) + 2, offset(CFAT32DirEntryLong.name1) + 4, offset(CFAT32DirEntryLong.name1) + 6, offset(CFAT32DirEntryLong.name1) + 8, offset(CFAT32DirEntryLong.name2), offset(CFAT32DirEntryLong.name2) + 2, offset(CFAT32DirEntryLong.name2) + 4, offset(CFAT32DirEntryLong.name2) + 6, offset(CFAT32DirEntryLong.name2) + 8, offset(CFAT32DirEntryLong.name2) + 10, offset(CFAT32DirEntryLong.name3), offset(CFAT32DirEntryLong.name3) + 2 }; Bool DirLongNameFill(CDirEntry *tmpde, CFAT32DirEntryLong *de, I64 *xsum) { I64 i; U8 *ptr = de; if (de->ord & 0x40) { MemSet(tmpde, 0, sizeof(CDirEntry)); *xsum = de->xsum; } else if (de->type || de->zero || de->xsum != *xsum) { MemSet(tmpde, 0, sizeof(CDirEntry)); *xsum = 0; return FALSE; } switch (de->ord & 0x3F) { case 1: for (i = 0; i < 13; i++) if (!(tmpde->name[i] = ptr[fat_long_name_map[i]])) return TRUE; break; case 2: for (i = 0; i < 12; i++) if (!(tmpde->name[i + 13] = ptr[fat_long_name_map[i]])) return TRUE; break; } return TRUE; } Bool FAT32CDirFill(CDirEntry *tmpde, CFAT32DirEntry *de, CDate _local_time_offset) { Bool res; if (*tmpde->name) res = TRUE; else res = FATFromName(tmpde->name, de->name); tmpde->clus = de->clus_lo + de->clus_hi << 16; tmpde->size = de->size; tmpde->attr = de->attr; tmpde->datetime = Dos2CDate(de->WrtTime, de->WrtDate) - _local_time_offset; return res; } Bool FAT32DirFill(CFAT32DirEntry *de, CDirEntry *tmpde, I64 *_de_count, CDate _local_time_offset) {//Fill up to 3 entries and store count of entries. I64 de_count = 0, i, l, xsum, ord; U8 *ptr, dname[16]; CFAT32DirEntryLong *ld = de; Bool res; MemSet(de, 0, sizeof(CFAT32DirEntry)); res = FATNameTo(de->name, tmpde->name); FATFromName(dname, de->name); if (StrCompare(dname, tmpde->name)) { ord = 0x41; xsum = FATNameXSum(de->name); if ((l = StrLen(tmpde->name)) > 13) { ptr = &ld[de_count]; MemSet(ptr, 0, sizeof(CFAT32DirEntryLong)); ld[de_count].attr = RS_ATTR_LONG_NAME; ld[de_count].xsum = xsum; ld[de_count].ord = 0x42; for (i = 13; i < l; i++) ptr[fat_long_name_map[i - 13]] = tmpde->name[i]; i++; for (; i < 26; i++) ptr[fat_long_name_map[i - 13]](U16) = 0xFFFF; ord = 1; l = 13; de_count++; } ptr = &de[de_count]; MemSet(ptr, 0, sizeof(CFAT32DirEntryLong)); ld[de_count].attr = RS_ATTR_LONG_NAME; ld[de_count].xsum = xsum; ld[de_count].ord = ord; for (i = 0; i < l; i++) ptr[fat_long_name_map[i]] = tmpde->name[i]; i++; for (; i < 13; i++) ptr[fat_long_name_map[i]](U16) = 0xFFFF; de_count++; MemSet(&de[de_count], 0, sizeof(CFAT32DirEntry)); res = FATNameTo(de[de_count].name, tmpde->name); } de[de_count].clus_lo = tmpde->clus.u16[0]; de[de_count].clus_hi = tmpde->clus.u16[1]; if (!(tmpde->attr & RS_ATTR_DIR)) de[de_count].size = tmpde->size; de[de_count].attr = tmpde->attr; if (!tmpde->datetime) tmpde->datetime = Now; CDate2Dos(&de[de_count].WrtTime, &de[de_count].WrtDate, tmpde->datetime + _local_time_offset); if (_de_count) *_de_count = de_count + 1; return res; } Bool FAT32FileFind(CDrive *drive, I64 cur_dir_clus, U8 *name, CDirEntry *_res, I64 fuf_flags=0) {//FUF_JUST_DIRS, FUF_JUST_FILES Bool res = FALSE, unlock; CFAT32DirEntry *buf; I64 xsum = 0, attr, cur_dir_entry, entries_per_clus; U8 dname[CDIR_FILENAME_LEN], ch; CDirEntry long_name; if (fuf_flags & ~FUG_FILE_FIND) throw('FUF'); MemSet(_res, 0, sizeof(CDirEntry)); MemSet(&long_name, 0, sizeof(CDirEntry)); DriveCheck(drive); if (drive->fs_type != FSt_FAT32) PrintErr("Not FAT32 Drive\n"); else if (!CFileNameTo(dname, name)) PrintErr("Invalid FileName: \"%s\".\n", name); else try { unlock = DriveLock(drive); buf = MAlloc(BLK_SIZE * drive->spc); entries_per_clus = drive->spc << FAT32_ENTRIES_BITS; ClusRead(drive, buf, cur_dir_clus, 1); cur_dir_entry=0; while (ch = *buf[cur_dir_entry].name) { attr = buf[cur_dir_entry].attr; if (ch != 0xE5) { if (attr & RS_ATTR_LONG_NAME_MASK == RS_ATTR_LONG_NAME) DirLongNameFill(&long_name, &buf[cur_dir_entry], &xsum); else { if (!(attr & RS_ATTR_VOL_ID)) { if (xsum == FATNameXSum(buf[cur_dir_entry].name)) MemCopy(_res, &long_name, sizeof(CDirEntry)); else MemSet(_res, 0, sizeof(CDirEntry)); if (!(fuf_flags & FUF_JUST_DIRS && !(attr & RS_ATTR_DIR)) && !(fuf_flags & FUF_JUST_FILES && attr & RS_ATTR_DIR) && FAT32CDirFill(_res, &buf[cur_dir_entry], drive->fat32_local_time_offset) && !StrCompare(dname, _res->name)) { res = TRUE; goto fff_done; } } MemSet(&long_name, 0, sizeof(CDirEntry)); } } else MemSet(&long_name, 0, sizeof(CDirEntry)); if (++cur_dir_entry == entries_per_clus) { cur_dir_clus = ClusNumNext(drive, cur_dir_clus); if (!(0 < cur_dir_clus < 0x0FFFFFF8)) break; else { ClusRead(drive, buf, cur_dir_clus, 1); cur_dir_entry = 0; } } } MemSet(_res, 0, sizeof(CDirEntry)); fff_done: Free(buf); if (unlock) DriveUnlock(drive); } catch if (unlock) DriveUnlock(drive); return res; } U8 *FAT32FileRead(CDrive *drive, U8 *cur_dir, U8 *filename, I64 *_size, I64 *_attr) { U8 *buf = NULL; CDirEntry de; I64 c, blk_count, cur_dir_clus; DriveCheck(drive); *_size = 0; *_attr = 0; if (drive->fs_type != FSt_FAT32) PrintErr("Not FAT32 Drive\n"); else try { DriveLock(drive); cur_dir_clus = Name2DirClus(drive, cur_dir); if (FAT32FileFind(drive, cur_dir_clus, filename, &de, FUF_JUST_FILES)) { blk_count = (de.size + BLK_SIZE - 1) >> BLK_SIZE_BITS; buf = MAlloc(blk_count << BLK_SIZE_BITS + 1); c = de.clus; if (!(0 < c < 0x0FFFFFF8)) c = 0x0FFFFFFF; else c = ClusBlkRead(drive, buf, c, blk_count); buf[de.size] = 0; //Terminate *_size = de.size; *_attr = FileAttr(de.name, de.attr); } DriveUnlock(drive); } catch DriveUnlock(drive); return buf; } Bool FAT32Cd(U8 *name, I64 cur_dir_clus) { CDirEntry de; if (Fs->cur_dv->fs_type != FSt_FAT32) PrintErr("Not FAT32 Drive\n"); else if (FAT32FileFind(Fs->cur_dv, cur_dir_clus, name, &de, FUF_JUST_DIRS)) return TRUE; else PrintErr("File not found: \"%s\".\n", name); return FALSE; } U0 FAT32FreeClus(CDrive *drive, I64 c) { I64 next, saved_c = c; Bool unlock, unlock_break; DriveCheck(drive); if (!(0 < c < 0x0FFFFFF8)) return; if (drive->fs_type != FSt_FAT32) PrintErr("Not FAT32 Drive\n"); else try { unlock_break = BreakLock; unlock = DriveLock(drive); DriveFATBlkClean(drive); do { DriveFATBlkSet(drive, c, 0); next = drive->cur_fat_blk[c & (BLK_SIZE / 4 - 1)]; drive->cur_fat_blk[c & (BLK_SIZE / 4 - 1)] = 0; LBts(&drive->fat_blk_dirty, 0); c = next; } while (0 < c < 0x0FFFFFF8); DriveFATBlkClean(drive, 0); c = saved_c; do { DriveFATBlkSet(drive, c, 1); next = drive->cur_fat_blk[c & (BLK_SIZE / 4 - 1)]; drive->cur_fat_blk[c & (BLK_SIZE / 4 - 1)] = 0; LBts(&drive->fat_blk_dirty, 0); c = next; } while (0 < c < 0x0FFFFFF8); DriveFATBlkClean(drive, 1); if (unlock) DriveUnlock(drive); if (unlock_break) BreakUnlock; } catch { if (unlock) DriveUnlock(drive); if (unlock_break) BreakUnlock; } } I64 FAT32AllocClus(CDrive *drive, I64 c, I64 count) { Bool wrap_around = FALSE, unlock, unlock_break; I64 first = INVALID_CLUS, j, l; if (count <= 0) return 0x0FFFFFFF; try { unlock_break = BreakLock; unlock = DriveLock(drive); l = (drive->size + drive->drv_offset - drive->data_area) / drive->spc - 1; j = drive->fis->most_recently_alloced; while (count-- > 0) { while (TRUE) { j++; if (j < 1) j = 1; if (j >= l) { if (wrap_around) throw('Drive'); j = 1; wrap_around = TRUE; } DriveFATBlkSet(drive, j); if (!drive->cur_fat_blk[j & (BLK_SIZE / 4 - 1)]) break; } if (!(0 < first < 0x0FFFFFF8)) first = j; if (0 < c < l) { DriveFATBlkSet(drive, c); drive->cur_fat_blk[c & (BLK_SIZE / 4 - 1)] = j; LBts(&drive->fat_blk_dirty, 0); } c = j; } if (0 < c < l) { DriveFATBlkSet(drive, c); drive->cur_fat_blk[c & (BLK_SIZE / 4 - 1)] = 0x0FFFFFFF; LBts(&drive->fat_blk_dirty, 0); } DriveFATBlkClean(drive); drive->fis->most_recently_alloced = j; drive->fis->free_clus = -1; BlkWrite(drive, drive->fis, drive->file_system_info_sect, 1); } catch { if (unlock) DriveUnlock(drive); if (unlock_break) BreakUnlock; } if (unlock) DriveUnlock(drive); if (unlock_break) BreakUnlock; return first; } I64 FAT32AllocContiguousClus(CDrive *drive, I64 count) { I64 i, first = 1; Bool cont, unlock, unlock_break; if (count <= 0) return 0x0FFFFFFF; try { unlock_break = BreakLock; unlock = DriveLock(drive); while (TRUE) { first++; i = 0; cont = TRUE; while (cont && i < count) { if ((first + i + 1) * drive->spc + drive->data_area > drive->size + drive->drv_offset) throw('Drive'); DriveFATBlkSet(drive, first + i); if (drive->cur_fat_blk[(first + i) & (BLK_SIZE / 4 - 1)]) cont = FALSE; else i++; } if (!cont) first = first + i; else { DriveFATBlkClean(drive); for (i = 0; i < count; i++) { DriveFATBlkSet(drive, first + i, 0); if (i + 1 == count) drive->cur_fat_blk[(first + i) & (BLK_SIZE / 4 - 1)] = 0x0FFFFFFF; else drive->cur_fat_blk[(first + i) & (BLK_SIZE / 4 - 1)] = first + i + 1; LBts(&drive->fat_blk_dirty, 0); } DriveFATBlkClean(drive, 0); for (i = 0; i < count; i++) { DriveFATBlkSet(drive, first + i, 1); if (i + 1 == count) drive->cur_fat_blk[(first + i) & (BLK_SIZE / 4 - 1)] = 0x0FFFFFFF; else drive->cur_fat_blk[(first + i) & (BLK_SIZE / 4 - 1)] = first + i + 1; LBts(&drive->fat_blk_dirty, 0); } DriveFATBlkClean(drive, 1); break; } } } catch { if (unlock) DriveUnlock(drive); if (unlock_break) BreakUnlock; } if (unlock) DriveUnlock(drive); if (unlock_break) BreakUnlock; return first; } Bool FAT32DirNew(CDrive *drive, U8 *cur_dir, CDirEntry *tmpde, Bool free_old_chain) { //See ::/Doc/CutCorners.DD. CFAT32DirEntry *buf, *last_buf, *tmp_buf, de[3]; I64 i, attr, avail_count, de_count, c, cur_dir_entry, entries_per_clus, cur_dir_clus, xsum = 0, last_dir_clus = INVALID_CLUS; U8 ch; Bool written = FALSE, unlock, unlock_break; CDirEntry long_name; FAT32DirFill(&de, tmpde, &de_count, drive->fat32_local_time_offset); MemSet(&long_name, 0, sizeof(CDirEntry)); try { unlock_break = BreakLock; unlock = DriveLock(drive); cur_dir_clus = Name2DirClus(drive, cur_dir); buf = MAlloc(BLK_SIZE * drive->spc); last_buf = CAlloc(BLK_SIZE * drive->spc); entries_per_clus = drive->spc << FAT32_ENTRIES_BITS; ClusRead(drive, buf, cur_dir_clus, 1); cur_dir_entry = 0; while (ch = *buf[cur_dir_entry].name) { attr = buf[cur_dir_entry].attr; if (ch != 0xE5 && attr & RS_ATTR_LONG_NAME_MASK == RS_ATTR_LONG_NAME) DirLongNameFill(&long_name, &buf[cur_dir_entry], &xsum); else { avail_count = FAT32_ENTRIES_PER_BLK - cur_dir_entry & (FAT32_ENTRIES_PER_BLK - 1); for (i = 0; i < avail_count; i++) if (*buf[cur_dir_entry + i].name != 0xE5) { if (*buf[cur_dir_entry + i].name) avail_count = i; break; } if (ch == 0xE5 && !written && avail_count >= de_count) { MemCopy(&buf[cur_dir_entry], &de, de_count * sizeof(CFAT32DirEntry)); BlkWrite(drive, &buf[cur_dir_entry & -FAT32_ENTRIES_PER_BLK], drive->data_area + cur_dir_clus * drive->spc + cur_dir_entry >> FAT32_ENTRIES_BITS, 1); cur_dir_entry += de_count - 1; //gets inc'ed written = TRUE; } else if (ch != 0xE5 && !(attr & RS_ATTR_VOL_ID)) { if (xsum != FATNameXSum(buf[cur_dir_entry].name)) MemSet(&long_name, 0, sizeof(CDirEntry)); if (!*long_name.name) FATFromName(long_name.name, buf[cur_dir_entry].name); //Del old entry with same name if (!StrCompare(long_name.name, tmpde->name)) { if (free_old_chain) FAT32FreeClus(drive, buf[cur_dir_entry].clus_lo + buf[cur_dir_entry].clus_hi << 16); if (!written) { MemCopy(&buf[cur_dir_entry], &de[de_count - 1], sizeof(CFAT32DirEntry)); BlkWrite(drive, &buf[cur_dir_entry & -FAT32_ENTRIES_PER_BLK], drive->data_area + cur_dir_clus * drive->spc + cur_dir_entry >> FAT32_ENTRIES_BITS, 1); written = TRUE; } else { *buf[cur_dir_entry].name = 0xE5; i = 1; while (i <= cur_dir_entry && buf[cur_dir_entry - i].attr & RS_ATTR_LONG_NAME_MASK == RS_ATTR_LONG_NAME) *buf[cur_dir_entry-i++].name = 0xE5; i--; BlkWrite(drive, &buf[(cur_dir_entry - i) & -FAT32_ENTRIES_PER_BLK], drive->data_area + cur_dir_clus * drive->spc + (cur_dir_entry - i) >> FAT32_ENTRIES_BITS, (i + FAT32_ENTRIES_PER_BLK) >> FAT32_ENTRIES_BITS); if (i == cur_dir_entry && 0 < last_dir_clus < 0x0FFFFFF8) { i = 1; while (i <= entries_per_clus && last_buf[entries_per_clus - i].attr & RS_ATTR_LONG_NAME_MASK == RS_ATTR_LONG_NAME) *last_buf[entries_per_clus - i++].name = 0xE5; if (--i > 0) BlkWrite(drive, &buf[(entries_per_clus - i) & -FAT32_ENTRIES_PER_BLK], drive->data_area + last_dir_clus * drive->spc + (entries_per_clus - i) >> FAT32_ENTRIES_BITS, (i + FAT32_ENTRIES_PER_BLK - 1) >> FAT32_ENTRIES_BITS); } } break; } } MemSet(&long_name, 0, sizeof(CDirEntry)); } if (++cur_dir_entry == entries_per_clus) { last_dir_clus = cur_dir_clus; tmp_buf = buf; buf = last_buf; last_buf = tmp_buf; c=ClusNumNext(drive, cur_dir_clus); if (!(0 < c < 0x0FFFFFF8)) { c = ClusAlloc(drive, cur_dir_clus, 1, FALSE); MemSet(buf, 0, BLK_SIZE * drive->spc); ClusWrite(drive, buf, c, 1); } else ClusRead(drive, buf, c, 1); cur_dir_clus = c; cur_dir_entry = 0; } } if (!written) { avail_count = FAT32_ENTRIES_PER_BLK - cur_dir_entry & (FAT32_ENTRIES_PER_BLK - 1); if (avail_count < de_count) { for (i = 0; i < avail_count; i++) *buf[cur_dir_entry + i].name = 0xE5; BlkWrite(drive, &buf[cur_dir_entry & -FAT32_ENTRIES_PER_BLK], drive->data_area + cur_dir_clus * drive->spc + cur_dir_entry >> FAT32_ENTRIES_BITS, 1); cur_dir_entry += avail_count; if (cur_dir_entry == entries_per_clus) { last_dir_clus = cur_dir_clus; tmp_buf = buf; buf = last_buf; last_buf = tmp_buf; cur_dir_clus = ClusAlloc(drive, cur_dir_clus, 1); cur_dir_entry = 0; MemSet(buf, 0, BLK_SIZE * drive->spc); ClusWrite(drive, buf, cur_dir_clus, 1); } } MemCopy(&buf[cur_dir_entry], &de, de_count * sizeof(CFAT32DirEntry)); BlkWrite(drive, &buf[cur_dir_entry & -FAT32_ENTRIES_PER_BLK], drive->data_area + cur_dir_clus * drive->spc + cur_dir_entry >> FAT32_ENTRIES_BITS, 1); cur_dir_entry += de_count; if (cur_dir_entry == entries_per_clus) { cur_dir_clus = ClusAlloc(drive, cur_dir_clus, 1); MemSet(buf, 0, BLK_SIZE * drive->spc); ClusWrite(drive, buf, cur_dir_clus, 1); } else { MemSet(&buf[cur_dir_entry], 0, sizeof(CFAT32DirEntry)); BlkWrite(drive, &buf[cur_dir_entry & -FAT32_ENTRIES_PER_BLK], drive->data_area + cur_dir_clus * drive->spc + cur_dir_entry >> FAT32_ENTRIES_BITS, 1); } } Free(last_buf); Free(buf); if (unlock) DriveUnlock(drive); if (unlock_break) BreakUnlock; } catch { if (unlock) DriveUnlock(drive); if (unlock_break) BreakUnlock; } return FALSE; } I64 FAT32FilesDel(CDrive *drive, U8 *cur_dir, U8 *files_find_mask, I64 fuf_flags, Bool del_dir, Bool print_message) { CFAT32DirEntry *buf, *last_buf, *tmp_buf; I64 i, res = 0, attr, xsum = 0, last_dir_clus = INVALID_CLUS, cur_dir_entry, entries_per_clus, cur_dir_clus; U8 ch; Bool unlock_break; CDirEntry long_name; MemSet(&long_name, 0, sizeof(CDirEntry)); try { unlock_break = BreakLock; DriveLock(drive); cur_dir_clus = Name2DirClus(drive, cur_dir); buf = MAlloc(BLK_SIZE * drive->spc); last_buf = CAlloc(BLK_SIZE * drive->spc); entries_per_clus = drive->spc << FAT32_ENTRIES_BITS; ClusRead(drive, buf, cur_dir_clus, 1); cur_dir_entry = 0; while (ch = *buf[cur_dir_entry].name) { attr = buf[cur_dir_entry].attr; if (ch != 0xE5 && ch != '.') { if (attr & RS_ATTR_LONG_NAME_MASK == RS_ATTR_LONG_NAME) DirLongNameFill(&long_name, &buf[cur_dir_entry], &xsum); else { if (!(attr & RS_ATTR_VOL_ID) && (del_dir || !(attr & RS_ATTR_DIR))) { if (xsum != FATNameXSum(buf[cur_dir_entry].name)) MemSet(&long_name, 0, sizeof(CDirEntry)); if (!*long_name.name) FATFromName(long_name.name, buf[cur_dir_entry].name); if (FilesFindMatch(long_name.name, files_find_mask, fuf_flags)) { if (!(attr & RS_ATTR_DIR)) res++; if (print_message) "Del %s\n", long_name.name; *buf[cur_dir_entry].name = 0xE5; i = 1; while (i <= cur_dir_entry && buf[cur_dir_entry - i].attr & RS_ATTR_LONG_NAME_MASK == RS_ATTR_LONG_NAME) *buf[cur_dir_entry - i++].name = 0xE5; i--; BlkWrite(drive, &buf[(cur_dir_entry - i) & -FAT32_ENTRIES_PER_BLK], drive->data_area + cur_dir_clus * drive->spc + (cur_dir_entry - i) >> FAT32_ENTRIES_BITS, (i + FAT32_ENTRIES_PER_BLK) >> FAT32_ENTRIES_BITS); if (i == cur_dir_entry && last_dir_clus != INVALID_CLUS) { i = 1; while (i <= entries_per_clus && last_buf[entries_per_clus - i].attr & RS_ATTR_LONG_NAME_MASK == RS_ATTR_LONG_NAME) *last_buf[entries_per_clus - i++].name = 0xE5; if (--i > 0) BlkWrite(drive, &buf[(entries_per_clus - i) & -FAT32_ENTRIES_PER_BLK], drive->data_area + last_dir_clus * drive->spc + (entries_per_clus - i) >> FAT32_ENTRIES_BITS, (i + FAT32_ENTRIES_PER_BLK - 1) >> FAT32_ENTRIES_BITS); } FAT32FreeClus(drive, buf[cur_dir_entry].clus_lo + buf[cur_dir_entry].clus_hi << 16); } } MemSet(&long_name, 0, sizeof(CDirEntry)); } } else MemSet(&long_name, 0, sizeof(CDirEntry)); if (++cur_dir_entry == entries_per_clus) { last_dir_clus = cur_dir_clus; cur_dir_clus = ClusNumNext(drive, cur_dir_clus, 1); tmp_buf = buf; buf = last_buf; last_buf = tmp_buf; ClusRead(drive, buf, cur_dir_clus, 1); cur_dir_entry = 0; } } Free(buf); Free(last_buf); DriveUnlock(drive); if (unlock_break) BreakUnlock; } catch { DriveUnlock(drive); if (unlock_break) BreakUnlock; } return res; } I64 FAT32FileWrite(CDrive *drive, U8 *cur_dir, U8 *name, U8 *buf, I64 size, CDate cdt, I64 attr) { CDirEntry de; I64 c = 0, blk_count; Bool contiguous; MemSet(&de, 0, sizeof(CDirEntry)); if (size < 0) size = 0; if (drive->fs_type != FSt_FAT32) PrintErr("Not FAT32 Drive\n"); else if (!CFileNameTo(de.name, name)) PrintErr("Invalid FileName: \"%s\".\n", name); else { FAT32FilesDel(drive, cur_dir, de.name, 0, FALSE, FALSE); if (attr & RS_ATTR_CONTIGUOUS) contiguous = TRUE; else contiguous = FALSE; de.size = size; if (blk_count = (size + BLK_SIZE - 1) >> BLK_SIZE_BITS) c = ClusAlloc(drive, 0, (blk_count + drive->spc - 1) / drive->spc, contiguous); else c = 0x0FFFFFFF; de.clus = c; de.attr = attr; de.datetime = cdt; if (blk_count) ClusBlkWrite(drive, buf, c, blk_count); FAT32DirNew(drive, cur_dir, &de, TRUE); } return c; } CDirEntry *FAT32FilesFind(U8 *files_find_mask, I64 fuf_flags, CDirEntry *parent=NULL, I64 *_dir_size=NULL) { CDrive *drive = Fs->cur_dv; CFAT32DirEntry *buf; I64 attr, xsum = 0, dir_size = 0, sub_dir_size, cur_dir_clus, cur_dir_entry, entries_per_clus; U8 ch; CDirEntry *res = NULL, *tmpde, long_name; if (fuf_flags & ~FUG_FILES_FIND) throw('FUF'); try { MemSet(&long_name, 0, sizeof(CDirEntry)); DriveLock(drive); cur_dir_clus = Name2DirClus(drive, Fs->cur_dir); buf = MAlloc(BLK_SIZE * drive->spc); entries_per_clus = drive->spc << FAT32_ENTRIES_BITS; ClusRead(drive, buf, cur_dir_clus, 1); dir_size += drive->spc * BLK_SIZE; cur_dir_entry = 0; while (ch = *buf[cur_dir_entry].name) { attr = buf[cur_dir_entry].attr; if (ch != 0xE5) { if (attr & RS_ATTR_LONG_NAME_MASK == RS_ATTR_LONG_NAME) DirLongNameFill(&long_name, &buf[cur_dir_entry], &xsum); else { if (!(attr & RS_ATTR_VOL_ID)) { tmpde = MAlloc(sizeof(CDirEntry)); if (xsum == FATNameXSum(buf[cur_dir_entry].name)) MemCopy(tmpde, &long_name, sizeof(CDirEntry)); else MemSet(tmpde, 0, sizeof(CDirEntry)); if (FAT32CDirFill(tmpde, &buf[cur_dir_entry], drive->fat32_local_time_offset)) { tmpde->parent = parent; if (Bt(&fuf_flags, FUf_RECURSE) && attr & RS_ATTR_DIR && *tmpde->name != '.') { tmpde->next = res; res = tmpde; tmpde->full_name = DirNameAbs(tmpde->name); DriveUnlock(drive); if (Cd(tmpde->name)) { tmpde->sub=FAT32FilesFind(files_find_mask, fuf_flags, tmpde, &sub_dir_size); tmpde->size = sub_dir_size; Cd(".."); } DriveLock(drive); } else { tmpde->full_name = FileNameAbs(tmpde->name); if ((attr & RS_ATTR_DIR || !Bt(&fuf_flags, FUf_JUST_DIRS)) && !(Bt(&fuf_flags, FUf_RECURSE) && *tmpde->name == '.' && attr & RS_ATTR_DIR) && FilesFindMatch(tmpde->full_name, files_find_mask, fuf_flags)) { tmpde->next = res; res = tmpde; } else DirEntryDel(tmpde); } } else DirEntryDel(tmpde); } MemSet(&long_name, 0, sizeof(CDirEntry)); } } else MemSet(&long_name, 0, sizeof(CDirEntry)); if (++cur_dir_entry == entries_per_clus) { cur_dir_clus = ClusNumNext(drive, cur_dir_clus); if (cur_dir_clus == INVALID_CLUS) break; else { ClusRead(drive, buf, cur_dir_clus, 1); dir_size += drive->spc * BLK_SIZE; cur_dir_entry = 0; } } } Free(buf); DriveUnlock(drive); } catch DriveUnlock(drive); if (_dir_size) *_dir_size = dir_size; return res; } Bool FAT32MkDir(CDrive *drive, U8 *cur_dir, U8 *name, I64 entry_count) { I64 c, cur_dir_clus = Name2DirClus(drive, cur_dir), //Rough estimate of size size = CeilU64((entry_count + 2) << FAT32_ENTRIES_BITS, drive->spc << BLK_SIZE_BITS); U8 *buf = CAlloc(size); CDirEntry d_native; CFAT32DirEntry *dFAT = buf; Bool unlock_break; try { unlock_break = BreakLock; c = FileWrite(name, buf, size, 0, RS_ATTR_DIR); MemSet(&d_native, 0, sizeof(CDirEntry)); d_native.attr = RS_ATTR_DIR; *d_native.name = '.'; d_native.name[1] = 0; d_native.clus = c; d_native.size = 0; d_native.datetime = Now; FAT32DirFill(dFAT, &d_native, NULL, drive->fat32_local_time_offset); dFAT++; MemSet(&d_native, 0, sizeof(CDirEntry)); d_native.attr = RS_ATTR_DIR; *d_native.name = '.'; d_native.name[1] = '.'; d_native.name[2] = 0; d_native.clus = cur_dir_clus; d_native.size = 0; d_native.datetime = Now; FAT32DirFill(dFAT, &d_native, NULL, drive->fat32_local_time_offset); ClusWrite(drive, buf, c, 1); Free(buf); if (unlock_break) BreakUnlock; } catch if (unlock_break) BreakUnlock; return TRUE; }