[core] add full extraction support for efi.img

* Also, Solus distro maintainers, I hate you!
This commit is contained in:
Pete Batard 2019-04-04 19:12:48 +01:00
parent dd9f9ce1e9
commit f02fbe3acc
No known key found for this signature in database
GPG Key ID: 38E0CF5E69EDD671
13 changed files with 327 additions and 77 deletions

View File

@ -42,6 +42,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\syslinux\libfat\cache.c" />
<ClCompile Include="..\src\syslinux\libfat\dumpdir.c" />
<ClCompile Include="..\src\syslinux\libfat\fatchain.c" />
<ClCompile Include="..\src\syslinux\libfat\open.c" />
<ClCompile Include="..\src\syslinux\libfat\searchdir.c" />

View File

@ -37,5 +37,8 @@
<ClCompile Include="..\src\syslinux\libfat\searchdir.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\src\syslinux\libfat\dumpdir.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

206
src/iso.c
View File

@ -59,6 +59,7 @@ uint32_t GetInstallWimVersion(const char* iso);
typedef struct {
BOOLEAN is_cfg;
BOOLEAN is_conf;
BOOLEAN is_syslinux_cfg;
BOOLEAN is_grub_cfg;
BOOLEAN is_old_c32[NB_OLD_C32];
@ -291,11 +292,11 @@ static void fix_config(const char* psz_fullpath, const char* psz_path, const cha
// Workaround for config files requiring an ISO label for kernel append that may be
// different from our USB label. Oh, and these labels must have spaces converted to \x20.
if (props->is_cfg) {
if ((props->is_cfg) || (props->is_conf)) {
iso_label = replace_char(img_report.label, ' ', "\\x20");
usb_label = replace_char(img_report.usb_label, ' ', "\\x20");
if ((iso_label != NULL) && (usb_label != NULL)) {
if (replace_in_token_data(src, (props->is_grub_cfg) ? "linuxefi" : "append",
if (replace_in_token_data(src, (props->is_grub_cfg) ? "linuxefi" : ((props->is_conf) ? "options" : "append"),
iso_label, usb_label, TRUE) != NULL)
uprintf(" Patched %s: '%s' ➔ '%s'\n", src, iso_label, usb_label);
}
@ -881,7 +882,7 @@ out:
img_report.sl_version_str);
}
}
if (!IS_EFI_BOOTABLE(img_report) && HAS_EFI_IMG(img_report) && ExtractEfiImgFiles(NULL)) {
if (!IS_EFI_BOOTABLE(img_report) && HAS_EFI_IMG(img_report) && HasEfiImgBootLoaders()) {
img_report.has_efi = 0x80;
}
if (HAS_WINPE(img_report)) {
@ -932,9 +933,9 @@ out:
StrArrayDestroy(&isolinux_path);
SendMessage(hMainDialog, UM_PROGRESS_EXIT, 0, 0);
} else {
// For Debian live ISOs, that only provide EFI boot files in a FAT efi.img
// Solus and other ISOs only provide EFI boot files in a FAT efi.img
if (img_report.has_efi == 0x80)
ExtractEfiImgFiles(dest_dir);
DumpFatDir(dest_dir, 0);
if (HAS_SYSLINUX(img_report)) {
static_sprintf(path, "%s\\syslinux.cfg", dest_dir);
// Create a /syslinux.cfg (if none exists) that points to the existing isolinux cfg
@ -1187,26 +1188,19 @@ int iso9660_readfat(intptr_t pp, void *buf, size_t secsize, libfat_sector_t sec)
}
/*
* Extract EFI bootloaders files from an ISO-9660 FAT img file into directory <dir>.
* If <dir> is NULL, returns TRUE if an EFI bootloader exists in the img.
* If <dir> is not NULL, returns TRUE if any if the bootloaders was properly written.
* Returns TRUE if an EFI bootloader exists in the img.
*/
BOOL ExtractEfiImgFiles(const char* dir)
BOOL HasEfiImgBootLoaders(void)
{
BOOL ret = FALSE;
HANDLE handle;
DWORD size, file_size, written;
iso9660_t* p_iso = NULL;
iso9660_stat_t* p_statbuf = NULL;
iso9660_readfat_private* p_private = NULL;
libfat_sector_t s;
int32_t dc, c;
struct libfat_filesystem *lf_fs = NULL;
struct libfat_direntry direntry;
char name[12] = { 0 };
char path[64];
int i, j, k;
void* buf;
if ((image_path == NULL) || !HAS_EFI_IMG(img_report))
return FALSE;
@ -1261,57 +1255,10 @@ BOOL ExtractEfiImgFiles(const char* dir)
}
c = libfat_searchdir(lf_fs, dc, name, &direntry);
if (c > 0) {
if (dir == NULL) {
if (!ret)
uprintf(" Detected EFI bootloader(s) (from '%s'):", img_report.efi_img_path);
uprintf(" ● '%s'", efi_bootname[i]);
ret = TRUE;
} else {
file_size = direntry.entry[28] + (direntry.entry[29] << 8) + (direntry.entry[30] << 16) +
(direntry.entry[31] << 24);
// Sanity check
if (file_size > 64 * MB) {
uprintf("Warning: File size is larger than 64 MB => not extracted");
continue;
}
static_sprintf(path, "%s\\efi", dir);
if (!CreateDirectoryA(path, 0) && (GetLastError() != ERROR_ALREADY_EXISTS)) {
uprintf("Could not create directory '%s': %s\n", path, WindowsErrorString());
continue;
}
static_strcat(path, "\\boot");
if (!CreateDirectoryA(path, 0) && (GetLastError() != ERROR_ALREADY_EXISTS)) {
uprintf("Could not create directory '%s': %s\n", path, WindowsErrorString());
continue;
}
static_strcat(path, "\\");
static_strcat(path, efi_bootname[i]);
uprintf("Extracting: %s (from '%s', %s)", path, img_report.efi_img_path,
SizeToHumanReadable(file_size, FALSE, FALSE));
handle = CreateFileA(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle == INVALID_HANDLE_VALUE) {
uprintf("Unable to create '%s': %s", path, WindowsErrorString());
continue;
}
written = 0;
s = libfat_clustertosector(lf_fs, c);
while ((s != 0) && (s < 0xFFFFFFFFULL) && (written < file_size)) {
buf = libfat_get_sector(lf_fs, s);
size = MIN(LIBFAT_SECTOR_SIZE, file_size - written);
if (!WriteFileWithRetry(handle, buf, size, &size, WRITE_RETRIES) ||
(size != MIN(LIBFAT_SECTOR_SIZE, file_size - written))) {
uprintf("Error writing '%s': %s", path, WindowsErrorString());
CloseHandle(handle);
continue;
}
written += size;
s = libfat_nextsector(lf_fs, s);
}
CloseHandle(handle);
ret = TRUE;
}
if (!ret)
uprintf(" Detected EFI bootloader(s) (from '%s'):", img_report.efi_img_path);
uprintf(" ● '%s'", efi_bootname[i]);
ret = TRUE;
}
}
@ -1327,6 +1274,135 @@ out:
return ret;
}
BOOL DumpFatDir(const char* path, int32_t cluster)
{
// We don't have concurrent calls to this function, so a static lf_fs is fine
static struct libfat_filesystem *lf_fs = NULL;
void* buf;
char *target = NULL, *name = NULL;
BOOL ret = FALSE;
HANDLE handle;
DWORD size, written;
libfat_diritem_t diritem = { 0 };
libfat_dirpos_t dirpos = { cluster, -1, 0 };
libfat_sector_t s;
iso9660_t* p_iso = NULL;
iso9660_stat_t* p_statbuf = NULL;
iso9660_readfat_private* p_private = NULL;
if (path == NULL)
return -1;
if (cluster == 0) {
// Root dir => Perform init stuff
if (image_path == NULL)
return FALSE;
p_iso = iso9660_open(image_path);
if (p_iso == NULL) {
uprintf("Could not open image '%s' as an ISO-9660 file system", image_path);
goto out;
}
p_statbuf = iso9660_ifs_stat_translate(p_iso, img_report.efi_img_path);
if (p_statbuf == NULL) {
uprintf("Could not get ISO-9660 file information for file %s\n", img_report.efi_img_path);
goto out;
}
p_private = malloc(sizeof(iso9660_readfat_private));
if (p_private == NULL)
goto out;
p_private->p_iso = p_iso;
p_private->lsn = p_statbuf->lsn[0]; // Image should be small enough not to use multiextents
p_private->sec_start = 0;
// Populate our intial buffer
if (iso9660_iso_seek_read(p_private->p_iso, p_private->buf, p_private->lsn, ISO_NB_BLOCKS) != ISO_NB_BLOCKS * ISO_BLOCKSIZE) {
uprintf("Error reading ISO-9660 file %s at LSN %lu\n", img_report.efi_img_path, (long unsigned int)p_private->lsn);
goto out;
}
lf_fs = libfat_open(iso9660_readfat, (intptr_t)p_private);
if (lf_fs == NULL) {
uprintf("FAT access error");
goto out;
}
}
do {
dirpos.cluster = libfat_dumpdir(lf_fs, &dirpos, &diritem);
if (dirpos.cluster >= 0) {
name = wchar_to_utf8(diritem.name);
target = malloc(strlen(path) + safe_strlen(name) + 2);
if ((name == NULL) || (target == NULL)) {
uprintf("Could not allocate buffer");
safe_free(name);
goto out;
}
strcpy(target, path);
strcat(target, "\\");
strcat(target, name);
if (diritem.attributes & 0x10) {
// Directory => Create directory
if (!CreateDirectoryU(target, 0) && (GetLastError() != ERROR_ALREADY_EXISTS)) {
uprintf("Could not create directory '%s': %s\n", target, WindowsErrorString());
continue;
}
if (!DumpFatDir(target, dirpos.cluster))
goto out;
} else {
// Need to figure out if it's a .conf file (Damn you Solus!!)
EXTRACT_PROPS props = { 0 };
size_t len = strlen(name);
props.is_conf = ((len > 4) && (stricmp(&name[len - 5], ".conf") == 0));
uprintf("Extracting: %s (from '%s', %s)", target, img_report.efi_img_path,
SizeToHumanReadable(diritem.size, FALSE, FALSE));
handle = CreateFileU(target, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
NULL, CREATE_ALWAYS, diritem.attributes, NULL);
if (handle == INVALID_HANDLE_VALUE) {
uprintf("Unable to create '%s': %s", target, WindowsErrorString());
continue;
}
written = 0;
s = libfat_clustertosector(lf_fs, dirpos.cluster);
while ((s != 0) && (s < 0xFFFFFFFFULL) && (written < diritem.size)) {
if (FormatStatus) goto out;
buf = libfat_get_sector(lf_fs, s);
size = MIN(LIBFAT_SECTOR_SIZE, diritem.size - written);
if (!WriteFileWithRetry(handle, buf, size, &size, WRITE_RETRIES) ||
(size != MIN(LIBFAT_SECTOR_SIZE, diritem.size - written))) {
uprintf("Error writing '%s': %s", target, WindowsErrorString());
CloseHandle(handle);
continue;
}
written += size;
s = libfat_nextsector(lf_fs, s);
// Trust me, you *REALLY* want to invoke libfat_flush() here
libfat_flush(lf_fs);
}
CloseHandle(handle);
if (props.is_conf)
fix_config(target, NULL, NULL, &props);
}
safe_free(target);
safe_free(name);
}
} while (dirpos.cluster >= 0);
ret = TRUE;
out:
if (cluster == 0) {
if (lf_fs != NULL) {
libfat_close(lf_fs);
lf_fs = NULL;
}
if (p_statbuf != NULL)
safe_free(p_statbuf->rr.psz_symlink);
safe_free(p_statbuf);
safe_free(p_private);
if (p_iso != NULL)
iso9660_close(p_iso);
}
return ret;
}
// VirtDisk API Prototypes - Only available for Windows 8 or later
PF_TYPE_DECL(WINAPI, DWORD, OpenVirtualDisk, (PVIRTUAL_STORAGE_TYPE, PCWSTR,
VIRTUAL_DISK_ACCESS_MASK, OPEN_VIRTUAL_DISK_FLAG, POPEN_VIRTUAL_DISK_PARAMETERS, PHANDLE));

View File

@ -452,7 +452,7 @@ static __inline DWORD CharUpperBuffU(char* lpString, DWORD len)
static __inline HANDLE CreateFileU(const char* lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
{
HANDLE ret = INVALID_HANDLE_VALUE;
DWORD err = ERROR_INVALID_DATA;
@ -465,6 +465,18 @@ static __inline HANDLE CreateFileU(const char* lpFileName, DWORD dwDesiredAccess
return ret;
}
static __inline BOOL CreateDirectoryU(const char* lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
{
BOOL ret = FALSE;
DWORD err = ERROR_INVALID_DATA;
wconvert(lpPathName);
ret = CreateDirectoryW(wlpPathName, lpSecurityAttributes);
err = GetLastError();
wfree(lpPathName);
SetLastError(err);
return ret;
}
static __inline BOOL CopyFileU(const char* lpExistingFileName, const char* lpNewFileName, BOOL bFailIfExists)
{
BOOL ret = FALSE;

View File

@ -121,7 +121,7 @@ typedef struct _OBJECT_TYPES_INFORMATION
typedef struct _PROCESS_BASIC_INFORMATION_WOW64
{
PVOID Reserved1[2];
// MinGW32 screws us with a sizeof(PVOID64) of 4 instead of 8 => Use an ULONGLONG instead
// MinGW32 screws us with a sizeof(PVOID64) of 4 instead of 8 => Use ULONGLONG instead
ULONGLONG PebBaseAddress;
PVOID Reserved2[4];
ULONG_PTR UniqueProcessId[2];

View File

@ -1886,6 +1886,10 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
case WM_COMMAND:
#ifdef RUFUS_TEST
if (LOWORD(wParam) == IDC_TEST) {
image_path = "C:\\Downloads\\fat.iso";
strcpy(img_report.efi_img_path, "efi.img");
DumpFatDir("C:\\tmp", 0);
image_path = NULL;
break;
}
#endif

View File

@ -503,7 +503,8 @@ extern BOOL ExtractAppIcon(const char* filename, BOOL bSilent);
extern BOOL ExtractDOS(const char* path);
extern BOOL ExtractISO(const char* src_iso, const char* dest_dir, BOOL scan);
extern int64_t ExtractISOFile(const char* iso, const char* iso_file, const char* dest_file, DWORD attributes);
extern BOOL ExtractEfiImgFiles(const char* dir);
extern BOOL HasEfiImgBootLoaders(void);
extern BOOL DumpFatDir(const char* path, int32_t cluster);
extern char* MountISO(const char* path);
extern void UnMountISO(void);
extern BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs);

View File

@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 232, 326
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_ACCEPTFILES
CAPTION "Rufus 3.6.1506"
CAPTION "Rufus 3.6.1507"
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
BEGIN
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
@ -394,8 +394,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 3,6,1506,0
PRODUCTVERSION 3,6,1506,0
FILEVERSION 3,6,1507,0
PRODUCTVERSION 3,6,1507,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -413,13 +413,13 @@ BEGIN
VALUE "Comments", "https://akeo.ie"
VALUE "CompanyName", "Akeo Consulting"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "3.6.1506"
VALUE "FileVersion", "3.6.1507"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2019 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "https://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus-3.6.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "3.6.1506"
VALUE "ProductVersion", "3.6.1507"
END
END
BLOCK "VarFileInfo"

View File

@ -1,4 +1,4 @@
noinst_LIBRARIES = libfat.a
libfat_a_SOURCES = cache.c fatchain.c open.c searchdir.c
libfat_a_SOURCES = cache.c fatchain.c open.c searchdir.c dumpdir.c
libfat_a_CFLAGS = $(AM_CFLAGS)

View File

@ -95,7 +95,7 @@ libfat_a_AR = $(AR) $(ARFLAGS)
libfat_a_LIBADD =
am_libfat_a_OBJECTS = libfat_a-cache.$(OBJEXT) \
libfat_a-fatchain.$(OBJEXT) libfat_a-open.$(OBJEXT) \
libfat_a-searchdir.$(OBJEXT)
libfat_a-searchdir.$(OBJEXT) libfat_a-dumpdir.$(OBJEXT)
libfat_a_OBJECTS = $(am_libfat_a_OBJECTS)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@ -243,7 +243,7 @@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
noinst_LIBRARIES = libfat.a
libfat_a_SOURCES = cache.c fatchain.c open.c searchdir.c
libfat_a_SOURCES = cache.c fatchain.c open.c searchdir.c dumpdir.c
libfat_a_CFLAGS = $(AM_CFLAGS)
all: all-am
@ -324,6 +324,12 @@ libfat_a-searchdir.o: searchdir.c
libfat_a-searchdir.obj: searchdir.c
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfat_a_CFLAGS) $(CFLAGS) -c -o libfat_a-searchdir.obj `if test -f 'searchdir.c'; then $(CYGPATH_W) 'searchdir.c'; else $(CYGPATH_W) '$(srcdir)/searchdir.c'; fi`
libfat_a-dumpdir.o: dumpdir.c
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfat_a_CFLAGS) $(CFLAGS) -c -o libfat_a-dumpdir.o `test -f 'dumpdir.c' || echo '$(srcdir)/'`dumpdir.c
libfat_a-dumpdir.obj: dumpdir.c
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libfat_a_CFLAGS) $(CFLAGS) -c -o libfat_a-dumpdir.obj `if test -f 'dumpdir.c'; then $(CYGPATH_W) 'dumpdir.c'; else $(CYGPATH_W) '$(srcdir)/dumpdir.c'; fi`
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am

View File

@ -28,7 +28,6 @@
* Also, since struct libfat_sector's data[0] is our buffer, this means we must BOTH
* align that member in the struct declaration, and use aligned malloc/free.
*/
extern void _uprintf(const char *format, ...);
void *libfat_get_sector(struct libfat_filesystem *fs, libfat_sector_t n)
{
struct libfat_sector *ls;

View File

@ -0,0 +1,126 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 2019 Pete Batard <pete@akeo.ie>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, Inc., 53 Temple Place Ste 330,
* Boston MA 02111-1307, USA; either version 2 of the License, or
* (at your option) any later version; incorporated herein by reference.
*
* ----------------------------------------------------------------------- */
/*
* dumpdir.c
*
* Returns all files and directory items from a FAT directory.
*/
#include <string.h>
#include "libfatint.h"
static struct fat_dirent* get_next_dirent(struct libfat_filesystem *fs,
libfat_sector_t *sector, int *offset)
{
struct fat_dirent *dep;
*offset += sizeof(struct fat_dirent);
if (*offset >= LIBFAT_SECTOR_SIZE) {
*offset = 0;
*sector = libfat_nextsector(fs, *sector);
if ((*sector == 0) || (*sector == (libfat_sector_t)-1))
return NULL;
}
dep = libfat_get_sector(fs, *sector);
if (!dep)
return NULL;
dep = (struct fat_dirent*) &((char*)dep)[*offset];
return dep;
}
static void fill_utf16(wchar_t *name, unsigned char *entry)
{
int i;
for (i=0; i<5; i++)
name[i] = read16((le16_t*)&entry[1 + 2*i]);
for (i=5; i<11; i++)
name[i] = read16((le16_t*)&entry[4 + 2*i]);
for (i=11; i<12; i++)
name[i] = read16((le16_t*)&entry[6 + 2*i]);
}
int libfat_dumpdir(struct libfat_filesystem *fs, libfat_dirpos_t *dp,
libfat_diritem_t *di)
{
int i, j;
struct fat_dirent *dep;
memset(di->name, 0, sizeof(di->name));
di->size = 0;
di->attributes = 0;
if (dp->offset < 0) {
/* First entry */
dp->offset = 0;
dp->sector = libfat_clustertosector(fs, dp->cluster);
if ((dp->sector == 0) || (dp->sector == (libfat_sector_t)-1))
return -1;
dep = libfat_get_sector(fs, dp->sector);
} else {
dep = get_next_dirent(fs, &dp->sector, &dp->offset);
}
if (!dep)
return -1; /* Read error */
/* Ignore volume labels, deleted entries as well as '.' and '..' entries */
while ((dep->attribute == 0x08) || (dep->name[0] == 0xe5) ||
((dep->name[0] == '.') && (dep->name[2] == ' ') &&
((dep->name[1] == ' ') || (dep->name[1] == '.')))) {
dep = get_next_dirent(fs, &dp->sector, &dp->offset);
if (!dep)
return -1;
}
if (dep->name[0] == 0)
return -2; /* Last entry */
/* Build UCS-2 name */
j = -1;
while (dep->attribute == 0x0F) { /* LNF (Long File Name) entry */
i = dep->name[0];
if ((j < 0) && ((i & 0xF0) != 0x40)) /* End of LFN marker was not found */
break;
/* Isolate and check the sequence number, which should be decrementing */
i = (i & 0x0F) - 1;
if ((j >= 0) && (i != j - 1))
return -3;
j = i;
fill_utf16(&di->name[13 * i], dep->name);
dep = get_next_dirent(fs, &dp->sector, &dp->offset);
if (!dep)
return -1;
}
if (di->name[0] == 0) {
for (i = 0, j = 0; i < 12; i++) {
if ((i >= 8) && (dep->name[i] == ' '))
break;
if (i == 8)
di->name[j++] = '.';
if (dep->name[i] == ' ')
continue;
di->name[j] = dep->name[i];
/* Caseflags: bit 3 = lowercase basename, bit 4 = lowercase extension */
if ((di->name[j] >= 'A') && (di->name[j] <= 'Z')) {
if ((dep->caseflags & 0x02) && (i < 8))
di->name[j] += 0x20;
if ((dep->caseflags & 0x04) && (i >= 8))
di->name[j] += 0x20;
}
j++;
}
}
di->attributes = dep->attribute & 0x37;
di->size = read32(&dep->size);
return read16(&dep->clustlo) + (read16(&dep->clusthi) << 16);
}

View File

@ -39,6 +39,18 @@ struct libfat_direntry {
unsigned char entry[32];
};
typedef struct libfat_dirpos {
int32_t cluster;
int32_t offset;
libfat_sector_t sector;
} libfat_dirpos_t;
typedef struct libfat_diritem {
wchar_t name[256];
uint32_t size;
uint8_t attributes; /* [--ad-shr] */
} libfat_diritem_t;
/*
* Open the filesystem. The readfunc is the function to read
* sectors, in the format:
@ -86,4 +98,14 @@ void *libfat_get_sector(struct libfat_filesystem *fs, libfat_sector_t n);
int32_t libfat_searchdir(struct libfat_filesystem *fs, int32_t dirclust,
const void *name, struct libfat_direntry *direntry);
/*
* Return all the files and directory items from a FAT directory.
* Initial call must set dp->offset to negative and dp->cluster to the cluster
* that contains the directory data. After that each subsequent call must use
* the same dp.
* Return value is the cluster for the corresponding item or negative on error.
*/
int libfat_dumpdir(struct libfat_filesystem *fs, libfat_dirpos_t *dp,
libfat_diritem_t *di);
#endif /* LIBFAT_H */