diff --git a/.vs/syslinux-libfat.vcxproj b/.vs/syslinux-libfat.vcxproj
index 6b8714ef..246a0240 100644
--- a/.vs/syslinux-libfat.vcxproj
+++ b/.vs/syslinux-libfat.vcxproj
@@ -42,6 +42,7 @@
+
diff --git a/.vs/syslinux-libfat.vcxproj.filters b/.vs/syslinux-libfat.vcxproj.filters
index 717f809c..514c11eb 100644
--- a/.vs/syslinux-libfat.vcxproj.filters
+++ b/.vs/syslinux-libfat.vcxproj.filters
@@ -37,5 +37,8 @@
Source Files
+
+ Source Files
+
\ No newline at end of file
diff --git a/src/iso.c b/src/iso.c
index 3e49943c..5a336787 100644
--- a/src/iso.c
+++ b/src/iso.c
@@ -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
.
- * If is NULL, returns TRUE if an EFI bootloader exists in the img.
- * If 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));
diff --git a/src/msapi_utf8.h b/src/msapi_utf8.h
index 617226c9..67c3648d 100644
--- a/src/msapi_utf8.h
+++ b/src/msapi_utf8.h
@@ -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;
diff --git a/src/process.h b/src/process.h
index fee9f99f..fd506fae 100644
--- a/src/process.h
+++ b/src/process.h
@@ -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];
diff --git a/src/rufus.c b/src/rufus.c
index 52ddfaa7..7f00cb71 100755
--- a/src/rufus.c
+++ b/src/rufus.c
@@ -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
diff --git a/src/rufus.h b/src/rufus.h
index 7f767d80..843758b2 100644
--- a/src/rufus.h
+++ b/src/rufus.h
@@ -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);
diff --git a/src/rufus.rc b/src/rufus.rc
index e6cdcf74..88d250c7 100644
--- a/src/rufus.rc
+++ b/src/rufus.rc
@@ -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"
diff --git a/src/syslinux/libfat/Makefile.am b/src/syslinux/libfat/Makefile.am
index d39ccf38..26a31d92 100644
--- a/src/syslinux/libfat/Makefile.am
+++ b/src/syslinux/libfat/Makefile.am
@@ -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)
diff --git a/src/syslinux/libfat/Makefile.in b/src/syslinux/libfat/Makefile.in
index 0d843711..2dc1d313 100644
--- a/src/syslinux/libfat/Makefile.in
+++ b/src/syslinux/libfat/Makefile.in
@@ -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
diff --git a/src/syslinux/libfat/cache.c b/src/syslinux/libfat/cache.c
index 5b989765..51f1f007 100644
--- a/src/syslinux/libfat/cache.c
+++ b/src/syslinux/libfat/cache.c
@@ -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;
diff --git a/src/syslinux/libfat/dumpdir.c b/src/syslinux/libfat/dumpdir.c
new file mode 100644
index 00000000..bc037189
--- /dev/null
+++ b/src/syslinux/libfat/dumpdir.c
@@ -0,0 +1,126 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2019 Pete Batard
+ *
+ * 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
+#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);
+}
diff --git a/src/syslinux/libfat/libfat.h b/src/syslinux/libfat/libfat.h
index 0357510a..d2968822 100644
--- a/src/syslinux/libfat/libfat.h
+++ b/src/syslinux/libfat/libfat.h
@@ -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 */