[syslinux] fix Syslinux installation for some media

* Some disk devices, such as O2Micro PCI-E SD card readers, return ERROR_INVALID_PARAMETER
  when attempting to use ReadFile() on a volume against a non 8-byte aligned buffer.
* This patch ensures that the Syslinux buffers for sector patching are 16-byte aligned.
* HUGE THANKS to 424778940z, for the numerous testing that allowed to troubleshoot this issue.
* Closes #767
This commit is contained in:
Pete Batard 2016-06-09 17:49:58 +01:00
parent c0393aec08
commit 3fdf622933
4 changed files with 63 additions and 23 deletions

View File

@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 242, 376
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_ACCEPTFILES
CAPTION "Rufus 2.10.956"
CAPTION "Rufus 2.10.957"
FONT 8, "Segoe UI Symbol", 400, 0, 0x0
BEGIN
LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8
@ -320,8 +320,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,10,956,0
PRODUCTVERSION 2,10,956,0
FILEVERSION 2,10,957,0
PRODUCTVERSION 2,10,957,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -338,13 +338,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "2.10.956"
VALUE "FileVersion", "2.10.957"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2016 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "2.10.956"
VALUE "ProductVersion", "2.10.957"
END
END
BLOCK "VarFileInfo"

View File

@ -105,18 +105,19 @@ BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs_type)
const char* ldlinux_ext[3] = { "sys", "bss", "c32" };
const char* mboot_c32 = "mboot.c32";
char path[MAX_PATH], tmp[64];
const char *errmsg;
struct libfat_filesystem *fs;
libfat_sector_t s, *secp;
libfat_sector_t *sectors = NULL;
int ldlinux_sectors;
uint32_t ldlinux_cluster;
int i, nsectors;
int i, nsectors, sl_fs_stype;
int bt = (int)ComboBox_GetItemData(hBootType, ComboBox_GetCurSel(hBootType));
BOOL use_v5 = (bt == BT_SYSLINUX_V6) || ((bt == BT_ISO) && (SL_MAJOR(img_report.sl_version) >= 5));
PrintInfoDebug(0, MSG_234, (bt == BT_ISO)?img_report.sl_version_str:embedded_sl_version_str[use_v5?1:0]);
// 4K sector size workaround
/* 4K sector size workaround */
SECTOR_SHIFT = 0;
SECTOR_SIZE = SelectedDrive.SectorSize;
while (SECTOR_SIZE>>=1)
@ -126,10 +127,32 @@ BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs_type)
LIBFAT_SECTOR_SIZE = SECTOR_SIZE;
LIBFAT_SECTOR_MASK = SECTOR_SIZE - 1;
sectbuf = malloc(SECTOR_SIZE);
/* sectbuf should be aligned to at least 8 bytes - see github #767 */
sectbuf = _aligned_malloc(SECTOR_SIZE, 16);
if (sectbuf == NULL)
goto out;
/* First, reopen the volume (we already have a lock) */
d_handle = GetLogicalHandle(drive_index, TRUE, FALSE);
if ((d_handle == INVALID_HANDLE_VALUE) || (d_handle == NULL)) {
uprintf("Could open volume for Syslinux installation");
goto out;
}
/* Make sure we can read the boot sector (NB: Re-open already set us to offset 0) */
if (!ReadFile(d_handle, sectbuf, SECTOR_SIZE, &bytes_read, NULL)) {
uprintf("Could not read VBR");
goto out;
}
if (bytes_read != SECTOR_SIZE) {
uprintf("Could not read the whole VBR");
goto out;
}
if ((errmsg = syslinux_check_bootsect(sectbuf, &sl_fs_stype))) {
uprintf("Error: %s", errmsg);
goto out;
}
/* Initialize the ADV -- this should be smarter */
syslinux_reset_adv(syslinux_adv);
@ -201,13 +224,6 @@ BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs_type)
goto out;
}
/* Reopen the volume (we already have a lock) */
d_handle = GetLogicalHandle(drive_index, TRUE, FALSE);
if ((d_handle == INVALID_HANDLE_VALUE) || (d_handle == NULL)) {
uprintf("Could open volume for Syslinux installation");
goto out;
}
/* Map the file (is there a better way to do this?) */
ldlinux_sectors = (syslinux_ldlinux_len[0] + 2 * ADV_SIZE + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
sectors = (libfat_sector_t*) calloc(ldlinux_sectors, sizeof *sectors);
@ -366,7 +382,8 @@ BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs_type)
r = TRUE;
out:
safe_free(sectbuf);
if (sectbuf != NULL)
_aligned_free(sectbuf);
safe_free(syslinux_ldlinux[0]);
safe_free(syslinux_ldlinux[1]);
safe_free(sectors);

View File

@ -19,6 +19,20 @@
#include <stdlib.h>
#include "libfatint.h"
/*
* We need to align our sector buffers to at least the 8-byte mark, as some Windows
* disk devices, notably O2Micro PCI-E SD card readers, return ERROR_INVALID_PARAMETER
* when attempting to use ReadFile() against a non 8-byte aligned buffer.
* For good measure, we'll go further and align our buffers on a 16-byte boundary.
* 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.
*/
#if defined(__MINGW32__)
#define _aligned_malloc __mingw_aligned_malloc
#define _aligned_free __mingw_aligned_free
#endif
extern void _uprintf(const char *format, ...);
void *libfat_get_sector(struct libfat_filesystem *fs, libfat_sector_t n)
{
struct libfat_sector *ls;
@ -29,10 +43,10 @@ void *libfat_get_sector(struct libfat_filesystem *fs, libfat_sector_t n)
}
/* Not found in cache */
ls = malloc(sizeof(struct libfat_sector) + LIBFAT_SECTOR_SIZE);
ls = _aligned_malloc(sizeof(struct libfat_sector) + LIBFAT_SECTOR_SIZE, 16);
if (!ls) {
libfat_flush(fs);
ls = malloc(sizeof(struct libfat_sector) + LIBFAT_SECTOR_SIZE);
ls = _aligned_malloc(sizeof(struct libfat_sector) + LIBFAT_SECTOR_SIZE, 16);
if (!ls)
return NULL; /* Can't allocate memory */
@ -40,7 +54,7 @@ void *libfat_get_sector(struct libfat_filesystem *fs, libfat_sector_t n)
if (fs->read(fs->readptr, ls->data, LIBFAT_SECTOR_SIZE, n)
!= LIBFAT_SECTOR_SIZE) {
free(ls);
_aligned_free(ls);
return NULL; /* I/O error */
}
@ -60,6 +74,6 @@ void libfat_flush(struct libfat_filesystem *fs)
for (ls = lsnext; ls; ls = lsnext) {
lsnext = ls->next;
free(ls);
_aligned_free(ls);
}
}

View File

@ -22,10 +22,19 @@
#include "libfat.h"
#include "fat.h"
#if defined(__GNUC__)
#define ALIGN_START(m)
#define ALIGN_END(m) __attribute__ ((__aligned__(m)))
#elif defined(_MSC_VER)
#define ALIGN_START(m) __declspec(align(m))
#define ALIGN_END(m)
#endif
struct libfat_sector {
libfat_sector_t n; /* Sector number */
struct libfat_sector *next; /* Next in list */
char data[0];
libfat_sector_t n; /* Sector number */
struct libfat_sector *next; /* Next in list */
/* data[0] MUST be aligned to at least 8 bytes - see cache.c */
ALIGN_START(16) char data[0] ALIGN_END(16);
};
enum fat_type {