mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
[core] add full extraction support for efi.img
* Also, Solus distro maintainers, I hate you!
This commit is contained in:
parent
dd9f9ce1e9
commit
f02fbe3acc
13 changed files with 327 additions and 77 deletions
|
@ -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" />
|
||||
|
|
|
@ -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
206
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 <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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
10
src/rufus.rc
10
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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
126
src/syslinux/libfat/dumpdir.c
Normal file
126
src/syslinux/libfat/dumpdir.c
Normal 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);
|
||||
}
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue