#include #include #include #include extern EFI_SYSTEM_TABLE *ST; #pragma pack(push, 1) struct BPB { UINT8 jmpBoot[3]; UINT8 OEMName[8]; UINT16 BytsPerSec; UINT8 SecPerClus; UINT16 RsvdSecCnt; UINT8 NumFATs; UINT16 RootEntCnt; UINT16 TotSec16; UINT8 Media; UINT16 FATSz16; UINT16 SecPerTrk; UINT16 NumHeads; UINT32 HiddSec; UINT32 TotSec32; UINT32 FATSz32; UINT16 ExtFlags; UINT16 FSVer; UINT32 RootClus; UINT16 FSInfo; UINT16 BkBootSec; UINT8 Reserved[12]; UINT8 DrvNum; UINT8 Reserved1; UINT8 BootSig; UINT32 VolID; UINT8 VolLab[11]; UINT8 FilSysType[8]; }; struct GPTHeader { UINT64 Signature; UINT32 Revision; UINT32 HeaderSize; UINT32 HeaderCRC32; UINT32 Reserved; UINT64 MyLBA; UINT64 AlternateLBA; UINT64 FirstUsableLBA; UINT64 LastUsableLBA; EFI_GUID DiskGUID; UINT64 PartitionEntryLBA; UINT32 NumPartitionEntries; UINT32 SizeOfPartitionEntry; UINT32 PartitionEntryArrayCRC32; }; struct GPTEntry { EFI_GUID PartitionTypeGUID; EFI_GUID UniquePartitionGUID; UINT64 StartingLBA; UINT64 EndingLBA; UINT64 Attributes; CHAR16 PartitionName[36]; }; struct MBRPart { UINT8 Status; UINT8 CHSStart[3]; UINT8 Type; UINT8 CHSEnd[3]; UINT32 LBABegin; UINT32 NumSectors; }; #pragma pack(pop) #define GPT_SIGNATURE_VAL 0x5452415020494645ULL #define MBR_SIGNATURE 0xAA55 #define MBR_TYPE_FAT12 0x01 #define MBR_TYPE_FAT16 0x04 #define MBR_TYPE_FAT16B 0x06 #define MBR_TYPE_FAT32 0x0B #define MBR_TYPE_FAT32LBA 0x0C #define MBR_TYPE_FAT16LBA 0x0E #define MBR_TYPE_ESP 0xEF // ---- GUID helpers ---- static BOOLEAN guid_is_zero(EFI_GUID *g) { return g->Data1 == 0 && g->Data2 == 0 && g->Data3 == 0 && g->Data4[0] == 0 && g->Data4[1] == 0 && g->Data4[2] == 0 && g->Data4[3] == 0 && g->Data4[4] == 0 && g->Data4[5] == 0 && g->Data4[6] == 0 && g->Data4[7] == 0; } static BOOLEAN guid_eq(EFI_GUID *a, EFI_GUID *b) { return a->Data1 == b->Data1 && a->Data2 == b->Data2 && a->Data3 == b->Data3 && a->Data4[0] == b->Data4[0] && a->Data4[1] == b->Data4[1] && a->Data4[2] == b->Data4[2] && a->Data4[3] == b->Data4[3] && a->Data4[4] == b->Data4[4] && a->Data4[5] == b->Data4[5] && a->Data4[6] == b->Data4[6] && a->Data4[7] == b->Data4[7]; } // ---- Block I/O ---- struct block_dev { EFI_BLOCK_IO_PROTOCOL *Bio; UINT32 BlockSize; }; static EFI_STATUS blk_init(struct block_dev *dev) { EFI_GUID g = EFI_BLOCK_IO_PROTOCOL_GUID; EFI_HANDLE *Handles = NULL; UINTN NoHandles = 0; EFI_STATUS st = uefi_call_wrapper(ST->BootServices->LocateHandleBuffer, 5, ByProtocol, &g, NULL, &NoHandles, &Handles); if (EFI_ERROR(st) || NoHandles == 0) return EFI_NOT_FOUND; EFI_BLOCK_IO_PROTOCOL *Bio = NULL; for (UINTN i = 0; i < NoHandles; i++) { EFI_BLOCK_IO_PROTOCOL *b = NULL; st = uefi_call_wrapper(ST->BootServices->HandleProtocol, 3, Handles[i], &g, (void**)&b); if (EFI_ERROR(st)) continue; if (b->Media->MediaPresent) { Bio = b; break; } if (!Bio) Bio = b; } uefi_call_wrapper(ST->BootServices->FreePool, 1, Handles); if (!Bio) return EFI_NOT_FOUND; dev->Bio = Bio; dev->BlockSize = Bio->Media->BlockSize; return EFI_SUCCESS; } static EFI_STATUS blk_read(struct block_dev *dev, UINT64 LBA, UINTN Sectors, void *Buf) { return uefi_call_wrapper(dev->Bio->ReadBlocks, 5, dev->Bio, dev->Bio->Media->MediaId, LBA, Sectors * dev->BlockSize, Buf); } // ---- Partition detection ---- static EFI_STATUS find_gpt_partition(struct block_dev *dev, UINT64 *StartLBA) { UINT8 *Buf = (UINT8*)kmalloc(dev->BlockSize); if (!Buf) return EFI_OUT_OF_RESOURCES; EFI_STATUS st = blk_read(dev, 1, 1, Buf); if (EFI_ERROR(st)) { kfree(Buf); return st; } struct GPTHeader *Hdr = (struct GPTHeader*)Buf; if (Hdr->Signature != GPT_SIGNATURE_VAL) { kfree(Buf); return EFI_NOT_FOUND; } // Read partition entries UINTN EntrySz = Hdr->SizeOfPartitionEntry; UINTN NumEnt = Hdr->NumPartitionEntries; UINTN Total = EntrySz * NumEnt; UINTN Secs = (Total + dev->BlockSize - 1) / dev->BlockSize; UINT8 *EntBuf = (UINT8*)kmalloc(Secs * dev->BlockSize); if (!EntBuf) { kfree(Buf); return EFI_OUT_OF_RESOURCES; } st = blk_read(dev, Hdr->PartitionEntryLBA, Secs, EntBuf); if (EFI_ERROR(st)) { kfree(Buf); kfree(EntBuf); return st; } // EFI System Partition GUID EFI_GUID esp = { 0xC12A7328, 0xF81F, 0x11D2, {0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B} }; // Basic data partition GUID (FAT) EFI_GUID basic = { 0xEBD0A0A2, 0xB9E5, 0x4433, {0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7} }; BOOLEAN found = FALSE; for (UINTN i = 0; i < NumEnt; i++) { struct GPTEntry *E = (struct GPTEntry*)(EntBuf + i * EntrySz); if (guid_is_zero(&E->PartitionTypeGUID)) continue; if (guid_eq(&E->PartitionTypeGUID, &esp) || guid_eq(&E->PartitionTypeGUID, &basic)) { *StartLBA = E->StartingLBA; found = TRUE; break; } } if (!found) { // Fallback: first non-empty partition for (UINTN i = 0; i < NumEnt; i++) { struct GPTEntry *E = (struct GPTEntry*)(EntBuf + i * EntrySz); if (!guid_is_zero(&E->PartitionTypeGUID)) { *StartLBA = E->StartingLBA; found = TRUE; break; } } } kfree(Buf); kfree(EntBuf); return found ? EFI_SUCCESS : EFI_NOT_FOUND; } static EFI_STATUS find_mbr_partition(struct block_dev *dev, UINT64 *StartLBA) { UINT8 *Buf = (UINT8*)kmalloc(dev->BlockSize); if (!Buf) return EFI_OUT_OF_RESOURCES; EFI_STATUS st = blk_read(dev, 0, 1, Buf); if (EFI_ERROR(st)) { kfree(Buf); return st; } if (*(UINT16*)(Buf + 510) != MBR_SIGNATURE) { kfree(Buf); return EFI_NOT_FOUND; } struct MBRPart *Parts = (struct MBRPart*)(Buf + 446); // Verify at least one non-zero partition entry exists BOOLEAN has_part = FALSE; for (SSINT32 i = 0; i < 4; i++) { if (Parts[i].Type != 0x00 && Parts[i].Type != 0xEE) { has_part = TRUE; break; } } if (!has_part) { kfree(Buf); return EFI_NOT_FOUND; } for (SSINT32 i = 0; i < 4; i++) { UINT8 t = Parts[i].Type; if (t == 0x00 || t == 0xEE) continue; if (t == MBR_TYPE_FAT12 || t == MBR_TYPE_FAT16 || t == MBR_TYPE_FAT16B || t == MBR_TYPE_FAT32 || t == MBR_TYPE_FAT32LBA || t == MBR_TYPE_FAT16LBA || t == MBR_TYPE_ESP) { *StartLBA = Parts[i].LBABegin; kfree(Buf); return EFI_SUCCESS; } } // Fallback: first non-empty partition for (SSINT32 i = 0; i < 4; i++) { if (Parts[i].Type != 0x00) { *StartLBA = Parts[i].LBABegin; kfree(Buf); return EFI_SUCCESS; } } kfree(Buf); return EFI_NOT_FOUND; } // ---- FAT driver ---- struct fat_fs { struct block_dev *Dev; UINT64 PartLBA; UINT16 BytsPerSec; UINT8 SecPerClus; UINT16 RsvdSecCnt; UINT8 NumFATs; UINT32 FATSz; UINT32 RootClus; UINT32 TotClus; UINT16 RootEntCnt; BOOLEAN IsFAT32; UINT32 ClusSize; void *FatBuf; // cached FAT UINT32 FATEntries; UINT32 *FAT32; UINT16 *FAT16; }; static UINT64 clus_to_lba(struct fat_fs *fs, UINT32 Clus) { UINT32 RootSecs = fs->IsFAT32 ? 0 : ((fs->RootEntCnt * 32) + fs->BytsPerSec - 1) / fs->BytsPerSec; UINT32 FirstDataSec = fs->RsvdSecCnt + fs->NumFATs * fs->FATSz + RootSecs; return fs->PartLBA + FirstDataSec + (UINT64)(Clus - 2) * fs->SecPerClus; } static UINT32 fat_next(struct fat_fs *fs, UINT32 Clus) { if (fs->IsFAT32) { if (Clus >= fs->FATEntries) return 0x0FFFFFF8; UINT32 v = fs->FAT32[Clus] & 0x0FFFFFFF; if (v == 0x00000000) return 0; if (v >= 0x0FFFFFF8) return 0x0FFFFFF8; return v; } else { if (Clus >= fs->FATEntries) return 0xFFF8; UINT16 v = fs->FAT16[Clus]; if (v == 0x0000) return 0; if (v >= 0xFFF8) return 0x0FFFFFF8; return v; } } static EFI_STATUS fat_init(struct fat_fs *fs, struct block_dev *dev, UINT64 PartLBA) { fs->Dev = dev; fs->PartLBA = PartLBA; UINT8 *Buf = (UINT8*)kmalloc(dev->BlockSize); if (!Buf) return EFI_OUT_OF_RESOURCES; EFI_STATUS st = blk_read(dev, PartLBA, 1, Buf); if (EFI_ERROR(st)) { kfree(Buf); return st; } if (*(UINT16*)(Buf + 510) != MBR_SIGNATURE) { kfree(Buf); return EFI_UNSUPPORTED; } struct BPB *bpb = (struct BPB*)Buf; fs->BytsPerSec = bpb->BytsPerSec; fs->SecPerClus = bpb->SecPerClus; fs->RsvdSecCnt = bpb->RsvdSecCnt; fs->NumFATs = bpb->NumFATs; fs->RootEntCnt = bpb->RootEntCnt; UINT32 TotSec = bpb->TotSec16 ? bpb->TotSec16 : bpb->TotSec32; UINT32 RootSecs = ((fs->RootEntCnt * 32) + fs->BytsPerSec - 1) / fs->BytsPerSec; UINT32 FATSz = bpb->FATSz16 ? bpb->FATSz16 : bpb->FATSz32; fs->FATSz = FATSz; UINT32 FirstDataSec = fs->RsvdSecCnt + fs->NumFATs * FATSz + RootSecs; fs->TotClus = (TotSec - FirstDataSec) / fs->SecPerClus; if (fs->TotClus < 4085) { serial_write("Sylva: FS: FAT12 unsupported\n"); kfree(Buf); return EFI_UNSUPPORTED; } else if (fs->TotClus < 65525) { fs->IsFAT32 = FALSE; fs->FATEntries = FATSz * fs->BytsPerSec / 2; } else { fs->IsFAT32 = TRUE; fs->RootClus = bpb->RootClus; fs->FATEntries = FATSz * fs->BytsPerSec / 4; } fs->ClusSize = fs->BytsPerSec * fs->SecPerClus; // Cache FAT UINTN FATBytes = FATSz * fs->BytsPerSec; fs->FatBuf = kmalloc(FATBytes); if (!fs->FatBuf) { kfree(Buf); return EFI_OUT_OF_RESOURCES; } st = blk_read(dev, PartLBA + fs->RsvdSecCnt, FATSz, fs->FatBuf); if (EFI_ERROR(st)) { kfree(Buf); kfree(fs->FatBuf); return st; } if (fs->IsFAT32) { fs->FAT32 = (UINT32*)fs->FatBuf; fs->FAT16 = NULL; } else { fs->FAT16 = (UINT16*)fs->FatBuf; fs->FAT32 = NULL; } kfree(Buf); return EFI_SUCCESS; } // ---- LFN helpers ---- static UINT8 lfn_checksum(const UINT8 *SFN) { UINT8 sum = 0; for (SSINT32 i = 0; i < 11; i++) sum = ((sum & 1) ? 0x80 : 0) + (sum >> 1) + SFN[i]; return sum; } #define LFN_MAX_FRAGS 20 #define LFN_FRAG_SIZE 13 struct lfn_state { CHAR16 frags[LFN_MAX_FRAGS][LFN_FRAG_SIZE + 1]; UINTN count; }; static void lfn_reset(struct lfn_state *lfn) { lfn->count = 0; } static void lfn_add(struct lfn_state *lfn, const UINT8 *E) { if (lfn->count >= LFN_MAX_FRAGS) return; UINTN pos = 0; for (SSINT32 i = 0; i < 5 && pos < LFN_FRAG_SIZE; i++) { CHAR16 c = *(const UINT16*)(E + 1 + i * 2); if (c == 0x0000 || c == 0xFFFF) { lfn->frags[lfn->count][pos] = 0; return; } lfn->frags[lfn->count][pos++] = c; } for (SSINT32 i = 0; i < 6 && pos < LFN_FRAG_SIZE; i++) { CHAR16 c = *(const UINT16*)(E + 14 + i * 2); if (c == 0x0000 || c == 0xFFFF) { lfn->frags[lfn->count][pos] = 0; return; } lfn->frags[lfn->count][pos++] = c; } for (SSINT32 i = 0; i < 2 && pos < LFN_FRAG_SIZE; i++) { CHAR16 c = *(const UINT16*)(E + 28 + i * 2); if (c == 0x0000 || c == 0xFFFF) { lfn->frags[lfn->count][pos] = 0; return; } lfn->frags[lfn->count][pos++] = c; } lfn->frags[lfn->count][pos] = 0; lfn->count++; } // Fragments arrive in reverse order (seq=N first, seq=1 last). // Concatenate from last to first to get correct name order. static void lfn_build(struct lfn_state *lfn, CHAR16 *out, UINTN out_size) { UINTN pos = 0; for (UINTN i = lfn->count; i > 0; i--) { for (UINTN j = 0; lfn->frags[i - 1][j] && pos < out_size - 1; j++) out[pos++] = lfn->frags[i - 1][j]; } out[pos] = 0; } static void sfn_to_name(const UINT8 *E, CHAR16 *out, UINTN out_size) { UINTN pos = 0; for (SSINT32 i = 0; i < 8 && pos < out_size - 1; i++) if (E[i] != ' ') out[pos++] = E[i]; UINTN ext_start = pos; BOOLEAN has_ext = FALSE; for (SSINT32 i = 8; i < 11 && pos < out_size - 1; i++) { if (E[i] != ' ') { if (!has_ext) { out[pos++] = '.'; has_ext = TRUE; ext_start = pos; } out[pos++] = E[i]; } } // If extension is empty but we added a dot, remove it if (has_ext && pos == ext_start) pos--; out[pos] = 0; } // ---- Directory reading ---- typedef void (*dir_cb)(void *Ctx, const CHAR16 *Name, UINT8 Attr, UINT32 Size, UINT32 FirstClus); // Returns TRUE when end-of-directory reached static BOOLEAN process_sector(struct fat_fs *fs, UINT8 *Buf, struct lfn_state *lfn, dir_cb Callback, void *Ctx) { for (UINTN off = 0; off < fs->BytsPerSec; off += 32) { UINT8 *E = Buf + off; if (E[0] == 0x00) return TRUE; if (E[0] == 0xE5) { lfn_reset(lfn); continue; } UINT8 Attr = E[11]; if (Attr == 0x0F) { if (E[0] & 0x40) lfn_reset(lfn); lfn_add(lfn, E); continue; } // SFN entry CHAR16 Name[256]; BOOLEAN use_lfn = FALSE; if (lfn->count > 0 && lfn_checksum(E) == E[13]) { lfn_build(lfn, Name, 256); use_lfn = TRUE; } if (!use_lfn) sfn_to_name(E, Name, 256); // Skip . and .. if (E[0] == 0x2E) { lfn_reset(lfn); continue; } UINT32 Size = *(const UINT32*)(E + 28); UINT32 FirstClus; if (fs->IsFAT32) FirstClus = ((UINT32)*(const UINT16*)(E + 20) << 16) | *(const UINT16*)(E + 26); else FirstClus = *(const UINT16*)(E + 26); Callback(Ctx, Name, Attr, Size, FirstClus); lfn_reset(lfn); } return FALSE; } static void read_directory(struct fat_fs *fs, UINT32 Cluster, dir_cb Callback, void *Ctx) { UINT8 *Buf = (UINT8*)kmalloc(fs->BytsPerSec); if (!Buf) return; struct lfn_state lfn; lfn_reset(&lfn); if (fs->IsFAT32) { UINT32 Clus = Cluster; while (Clus >= 2 && Clus < 0x0FFFFFF8) { UINT64 BaseLBA = clus_to_lba(fs, Clus); for (UINTN s = 0; s < fs->SecPerClus; s++) { if (EFI_ERROR(blk_read(fs->Dev, BaseLBA + s, 1, Buf))) goto done; if (process_sector(fs, Buf, &lfn, Callback, Ctx)) goto done; } Clus = fat_next(fs, Clus); } } else if (Cluster == 0) { UINT32 RootSecs = ((fs->RootEntCnt * 32) + fs->BytsPerSec - 1) / fs->BytsPerSec; UINT64 RootLBA = fs->PartLBA + fs->RsvdSecCnt + fs->NumFATs * fs->FATSz; for (UINTN s = 0; s < RootSecs; s++) { if (EFI_ERROR(blk_read(fs->Dev, RootLBA + s, 1, Buf))) goto done; if (process_sector(fs, Buf, &lfn, Callback, Ctx)) goto done; } } else { UINT32 Clus = Cluster; while (Clus >= 2 && Clus < 0x0FFFFFF8) { UINT64 BaseLBA = clus_to_lba(fs, Clus); for (UINTN s = 0; s < fs->SecPerClus; s++) { if (EFI_ERROR(blk_read(fs->Dev, BaseLBA + s, 1, Buf))) goto done; if (process_sector(fs, Buf, &lfn, Callback, Ctx)) goto done; } Clus = fat_next(fs, Clus); } } done: kfree(Buf); } // ---- Public API ---- static struct fat_fs g_fs; static BOOLEAN g_fs_inited = FALSE; // Recursive listing support struct list_ctx { struct fat_fs *fs; SSINT32 depth; }; static void name_to_ascii(const CHAR16 *Name, char *Ascii, UINTN ascii_sz) { wstr_to_ascii(Ascii, (WString)Name, ascii_sz); } static void list_callback(void *ctx, const CHAR16 *Name, UINT8 Attr, UINT32 Size, UINT32 FirstClus) { struct list_ctx *lc = (struct list_ctx*)ctx; for (SSINT32 i = 0; i < lc->depth; i++) serial_write(" "); serial_write(Attr & 0x10 ? "[DIR] " : "[FILE] "); char ascii[256]; name_to_ascii(Name, ascii, sizeof(ascii)); serial_write(ascii); if (!(Attr & 0x10)) { serial_write(" ("); serial_write_hex(Size); serial_write(" bytes)"); } serial_write("\n"); if ((Attr & 0x10) && lc->depth < 8) { struct list_ctx sub = { lc->fs, lc->depth + 1 }; read_directory(lc->fs, FirstClus, list_callback, &sub); } } EFI_STATUS fs_init() { serial_write("Sylva: FS: init block...\n"); static struct block_dev dev; EFI_STATUS st = blk_init(&dev); if (EFI_ERROR(st)) { serial_write("Sylva: FS: no block device!\n"); return st; } serial_write("Sylva: FS: block size = "); serial_write_hex(dev.BlockSize); serial_write("\n"); UINT64 PartLBA = 0; st = find_gpt_partition(&dev, &PartLBA); if (EFI_ERROR(st)) { serial_write("Sylva: FS: no GPT, trying MBR...\n"); st = find_mbr_partition(&dev, &PartLBA); } if (EFI_ERROR(st)) { serial_write("Sylva: FS: no partition table, assuming super-floppy...\n"); PartLBA = 0; } serial_write("Sylva: FS: partition LBA = "); serial_write_hex(PartLBA); serial_write("\n"); st = fat_init(&g_fs, &dev, PartLBA); if (EFI_ERROR(st)) { serial_write("Sylva: FS: FAT init failed!\n"); return st; } serial_write("Sylva: FS: FAT"); serial_write(g_fs.IsFAT32 ? "32" : "16"); serial_write(" ready, cluster size = "); serial_write_hex(g_fs.ClusSize); serial_write("\n"); g_fs_inited = TRUE; return EFI_SUCCESS; } void fs_list() { if (!g_fs_inited) { serial_write("FS not initialized\n"); return; } UINT32 Root = g_fs.IsFAT32 ? g_fs.RootClus : 0; struct list_ctx lc = { &g_fs, 0 }; read_directory(&g_fs, Root, list_callback, &lc); } // ---- File reading ---- struct find_ctx { const CHAR16 *Target; BOOLEAN Found; UINT32 Cluster; UINT32 Size; UINT8 Attr; }; static BOOLEAN name_match(const CHAR16 *a, const CHAR16 *b) { return wstr_eq((WString)a, (WString)b); } static void find_callback(void *ctx, const CHAR16 *Name, UINT8 Attr, UINT32 Size, UINT32 FirstClus) { struct find_ctx *fc = (struct find_ctx*)ctx; if (fc->Found) return; if (name_match(fc->Target, Name)) { fc->Found = TRUE; fc->Cluster = FirstClus; fc->Size = Size; fc->Attr = Attr; } } EFI_STATUS fs_read(WString Path, void **Buffer, UINTN *Size) { if (!g_fs_inited) return EFI_NOT_READY; const CHAR16 *p = Path; while (*p == L'\\') p++; UINT32 CurClus = g_fs.IsFAT32 ? g_fs.RootClus : 0; CHAR16 Comp[256]; while (*p) { UINTN ci = 0; while (*p && *p != L'\\' && ci < 255) Comp[ci++] = *p++; Comp[ci] = 0; while (*p == L'\\') p++; struct find_ctx fc; fc.Target = Comp; fc.Found = FALSE; read_directory(&g_fs, CurClus, find_callback, &fc); if (!fc.Found) return EFI_NOT_FOUND; if (*p == 0 && !(fc.Attr & 0x10)) { UINT32 FileSz = fc.Size; void *Buf = kmalloc(FileSz ? FileSz : 1); if (!Buf) return EFI_OUT_OF_RESOURCES; if (FileSz > 0) { UINT32 Clus = fc.Cluster; UINTN Offset = 0; UINTN ClusBytes = g_fs.ClusSize; while (Clus >= 2 && Clus < 0x0FFFFFF8 && Offset < FileSz) { UINT64 LBA = clus_to_lba(&g_fs, Clus); for (UINTN s = 0; s < g_fs.SecPerClus && Offset < FileSz; s++) { UINTN Part = g_fs.BytsPerSec; if (Part > FileSz - Offset) Part = FileSz - Offset; EFI_STATUS st = blk_read(g_fs.Dev, LBA + s, 1, (UINT8*)Buf + Offset); if (EFI_ERROR(st)) { kfree(Buf); return st; } Offset += Part; } Clus = fat_next(&g_fs, Clus); } } *Buffer = Buf; *Size = FileSz; return EFI_SUCCESS; } if (!(fc.Attr & 0x10)) return EFI_NOT_FOUND; CurClus = fc.Cluster; } return EFI_NOT_FOUND; }