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…
	
	Add table
		Add a link
		
	
		Reference in a new issue