mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
[iso] add symlink support for target file systems that support it
* For now that means only NTFS. And we only do that for ISO-9660/Rock Ridge images.
This commit is contained in:
parent
0bd38abd4e
commit
e9d588a6e0
3 changed files with 87 additions and 45 deletions
112
src/iso.c
112
src/iso.c
|
@ -122,7 +122,7 @@ static const char* stupid_antivirus = " NOTE: This is usually caused by a poorl
|
||||||
const char* old_c32_name[NB_OLD_C32] = OLD_C32_NAMES;
|
const char* old_c32_name[NB_OLD_C32] = OLD_C32_NAMES;
|
||||||
static const int64_t old_c32_threshold[NB_OLD_C32] = OLD_C32_THRESHOLD;
|
static const int64_t old_c32_threshold[NB_OLD_C32] = OLD_C32_THRESHOLD;
|
||||||
static uint8_t joliet_level = 0;
|
static uint8_t joliet_level = 0;
|
||||||
static uint64_t total_blocks, nb_blocks;
|
static uint64_t total_blocks, extra_blocks, nb_blocks;
|
||||||
static BOOL scan_only = FALSE;
|
static BOOL scan_only = FALSE;
|
||||||
static StrArray config_path, isolinux_path, modified_path;
|
static StrArray config_path, isolinux_path, modified_path;
|
||||||
static char symlinked_syslinux[MAX_PATH];
|
static char symlinked_syslinux[MAX_PATH];
|
||||||
|
@ -311,20 +311,20 @@ static BOOL check_iso_props(const char* psz_dirname, int64_t file_length, const
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for PE (XP) specific files in "/i386", "/amd64" or "/minint"
|
// Check for PE (XP) specific files in "/i386", "/amd64" or "/minint"
|
||||||
for (i=0; i<ARRAYSIZE(pe_dirname); i++)
|
for (i = 0; i < ARRAYSIZE(pe_dirname); i++)
|
||||||
if (safe_stricmp(psz_dirname, pe_dirname[i]) == 0)
|
if (safe_stricmp(psz_dirname, pe_dirname[i]) == 0)
|
||||||
for (j=0; j<ARRAYSIZE(pe_file); j++)
|
for (j=0; j<ARRAYSIZE(pe_file); j++)
|
||||||
if (safe_stricmp(psz_basename, pe_file[j]) == 0)
|
if (safe_stricmp(psz_basename, pe_file[j]) == 0)
|
||||||
img_report.winpe |= (1<<j)<<(ARRAYSIZE(pe_dirname)*i);
|
img_report.winpe |= (1<<j)<<(ARRAYSIZE(pe_dirname)*i);
|
||||||
|
|
||||||
for (i=0; i<ARRAYSIZE(isolinux_bin); i++) {
|
for (i = 0; i < ARRAYSIZE(isolinux_bin); i++) {
|
||||||
if (safe_stricmp(psz_basename, isolinux_bin[i]) == 0) {
|
if (safe_stricmp(psz_basename, isolinux_bin[i]) == 0) {
|
||||||
// Maintain a list of all the isolinux.bin files found
|
// Maintain a list of all the isolinux.bin files found
|
||||||
StrArrayAdd(&isolinux_path, psz_fullpath, TRUE);
|
StrArrayAdd(&isolinux_path, psz_fullpath, TRUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; i<NB_OLD_C32; i++) {
|
for (i = 0; i < NB_OLD_C32; i++) {
|
||||||
if (props->is_old_c32[i])
|
if (props->is_old_c32[i])
|
||||||
img_report.has_old_c32[i] = TRUE;
|
img_report.has_old_c32[i] = TRUE;
|
||||||
}
|
}
|
||||||
|
@ -706,7 +706,7 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path)
|
||||||
HANDLE file_handle = NULL;
|
HANDLE file_handle = NULL;
|
||||||
DWORD buf_size, wr_size, err;
|
DWORD buf_size, wr_size, err;
|
||||||
EXTRACT_PROPS props;
|
EXTRACT_PROPS props;
|
||||||
BOOL is_symlink, is_identical, free_p_statbuf = FALSE;
|
BOOL is_symlink, is_identical, create_file, free_p_statbuf = FALSE;
|
||||||
int length, r = 1;
|
int length, r = 1;
|
||||||
char psz_fullpath[MAX_PATH], *psz_basename = NULL, *psz_sanpath = NULL;
|
char psz_fullpath[MAX_PATH], *psz_basename = NULL, *psz_sanpath = NULL;
|
||||||
char tmp[128], target_path[256];
|
char tmp[128], target_path[256];
|
||||||
|
@ -798,7 +798,7 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path)
|
||||||
static_sprintf(target_path, "%s/%s", psz_path, p_statbuf->rr.psz_symlink);
|
static_sprintf(target_path, "%s/%s", psz_path, p_statbuf->rr.psz_symlink);
|
||||||
iso9660_stat_t *p_statbuf2 = iso9660_ifs_stat_translate(p_iso, target_path);
|
iso9660_stat_t *p_statbuf2 = iso9660_ifs_stat_translate(p_iso, target_path);
|
||||||
if (p_statbuf2 != NULL) {
|
if (p_statbuf2 != NULL) {
|
||||||
total_blocks += (p_statbuf2->total_size + ISO_BLOCKSIZE - 1) / ISO_BLOCKSIZE;
|
extra_blocks += (p_statbuf2->total_size + ISO_BLOCKSIZE - 1) / ISO_BLOCKSIZE;
|
||||||
iso9660_stat_free(p_statbuf2);
|
iso9660_stat_free(p_statbuf2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -821,8 +821,26 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path)
|
||||||
psz_sanpath = sanitize_filename(psz_fullpath, &is_identical);
|
psz_sanpath = sanitize_filename(psz_fullpath, &is_identical);
|
||||||
if (!is_identical)
|
if (!is_identical)
|
||||||
uprintf(" File name sanitized to '%s'", psz_sanpath);
|
uprintf(" File name sanitized to '%s'", psz_sanpath);
|
||||||
|
create_file = TRUE;
|
||||||
if (is_symlink) {
|
if (is_symlink) {
|
||||||
if (file_length == 0) {
|
if (fs_type == FS_NTFS) {
|
||||||
|
// Replicate symlinks if NTFS is being used
|
||||||
|
static_sprintf(target_path, "%s/%s", psz_path, p_statbuf->rr.psz_symlink);
|
||||||
|
iso9660_stat_t* p_statbuf2 = iso9660_ifs_stat_translate(p_iso, target_path);
|
||||||
|
if (p_statbuf2 != NULL) {
|
||||||
|
to_windows_path(psz_fullpath);
|
||||||
|
to_windows_path(p_statbuf->rr.psz_symlink);
|
||||||
|
uprintf("Symlinking: %s%s ➔ %s", psz_fullpath,
|
||||||
|
(p_statbuf2->type == _STAT_DIR) ? "\\" : "", p_statbuf->rr.psz_symlink);
|
||||||
|
if (!CreateSymbolicLinkU(psz_fullpath, p_statbuf->rr.psz_symlink,
|
||||||
|
(p_statbuf2->type == _STAT_DIR) ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0))
|
||||||
|
uprintf(" Could not create symlink: %s", WindowsErrorString());
|
||||||
|
to_unix_path(p_statbuf->rr.psz_symlink);
|
||||||
|
to_unix_path(psz_fullpath);
|
||||||
|
iso9660_stat_free(p_statbuf2);
|
||||||
|
create_file = FALSE;
|
||||||
|
}
|
||||||
|
} else if (file_length == 0) {
|
||||||
if ((safe_stricmp(p_statbuf->filename, "syslinux") == 0) &&
|
if ((safe_stricmp(p_statbuf->filename, "syslinux") == 0) &&
|
||||||
// Special handling for ISOs that have a syslinux → isolinux symbolic link (e.g. Knoppix)
|
// Special handling for ISOs that have a syslinux → isolinux symbolic link (e.g. Knoppix)
|
||||||
(safe_stricmp(p_statbuf->rr.psz_symlink, "isolinux") == 0)) {
|
(safe_stricmp(p_statbuf->rr.psz_symlink, "isolinux") == 0)) {
|
||||||
|
@ -846,45 +864,58 @@ static int iso_extract_files(iso9660_t* p_iso, const char *psz_path)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO: Ideally, we'd want to create a text file that contains the target link
|
print_extracted_file(psz_fullpath, safe_strlen(p_statbuf->rr.psz_symlink));
|
||||||
print_extracted_file(psz_fullpath, file_length);
|
|
||||||
uprintf(" Ignoring Rock Ridge symbolic link to '%s'", p_statbuf->rr.psz_symlink);
|
uprintf(" Ignoring Rock Ridge symbolic link to '%s'", p_statbuf->rr.psz_symlink);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
uuprintf("Unexpected symlink length: %d", file_length);
|
||||||
|
create_file = FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
file_handle = CreatePreallocatedFile(psz_sanpath, GENERIC_READ | GENERIC_WRITE,
|
if (create_file) {
|
||||||
FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, file_length);
|
file_handle = CreatePreallocatedFile(psz_sanpath, GENERIC_READ | GENERIC_WRITE,
|
||||||
if (file_handle == INVALID_HANDLE_VALUE) {
|
FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, file_length);
|
||||||
err = GetLastError();
|
if (file_handle == INVALID_HANDLE_VALUE) {
|
||||||
uprintf(" Unable to create file: %s", WindowsErrorString());
|
err = GetLastError();
|
||||||
if (((err == ERROR_ACCESS_DENIED) || (err == ERROR_INVALID_HANDLE)) &&
|
uprintf(" Unable to create file: %s", WindowsErrorString());
|
||||||
(safe_strcmp(&psz_sanpath[3], autorun_name) == 0))
|
if (((err == ERROR_ACCESS_DENIED) || (err == ERROR_INVALID_HANDLE)) &&
|
||||||
uprintf(stupid_antivirus);
|
(safe_strcmp(&psz_sanpath[3], autorun_name) == 0))
|
||||||
else
|
uprintf(stupid_antivirus);
|
||||||
goto out;
|
else
|
||||||
} else for (i = 0; file_length > 0; i++) {
|
goto out;
|
||||||
if (FormatStatus) goto out;
|
} else if (is_symlink) {
|
||||||
memset(buf, 0, ISO_BLOCKSIZE);
|
// Create a text file that contains the target link
|
||||||
lsn = p_statbuf->lsn + (lsn_t)i;
|
ISO_BLOCKING(r = WriteFileWithRetry(file_handle, p_statbuf->rr.psz_symlink,
|
||||||
if (iso9660_iso_seek_read(p_iso, buf, lsn, 1) != ISO_BLOCKSIZE) {
|
(DWORD)safe_strlen(p_statbuf->rr.psz_symlink), &wr_size, WRITE_RETRIES));
|
||||||
uprintf(" Error reading ISO9660 file %s at LSN %lu",
|
if (!r) {
|
||||||
psz_iso_name, (long unsigned int)lsn);
|
uprintf(" Error writing file: %s", WindowsErrorString());
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
} else for (i = 0; file_length > 0; i++) {
|
||||||
|
if (FormatStatus) goto out;
|
||||||
|
memset(buf, 0, ISO_BLOCKSIZE);
|
||||||
|
lsn = p_statbuf->lsn + (lsn_t)i;
|
||||||
|
if (iso9660_iso_seek_read(p_iso, buf, lsn, 1) != ISO_BLOCKSIZE) {
|
||||||
|
uprintf(" Error reading ISO9660 file %s at LSN %lu",
|
||||||
|
psz_iso_name, (long unsigned int)lsn);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
buf_size = (DWORD)MIN(file_length, ISO_BLOCKSIZE);
|
||||||
|
ISO_BLOCKING(r = WriteFileWithRetry(file_handle, buf, buf_size, &wr_size, WRITE_RETRIES));
|
||||||
|
if (!r) {
|
||||||
|
uprintf(" Error writing file: %s", WindowsErrorString());
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
file_length -= ISO_BLOCKSIZE;
|
||||||
|
if (nb_blocks++ % PROGRESS_THRESHOLD == 0)
|
||||||
|
UpdateProgressWithInfo(OP_FILE_COPY, MSG_231, nb_blocks, total_blocks +
|
||||||
|
((fs_type != FS_NTFS) ? extra_blocks : 0));
|
||||||
}
|
}
|
||||||
buf_size = (DWORD)MIN(file_length, ISO_BLOCKSIZE);
|
if (preserve_timestamps) {
|
||||||
ISO_BLOCKING(r = WriteFileWithRetry(file_handle, buf, buf_size, &wr_size, WRITE_RETRIES));
|
LPFILETIME ft = to_filetime(mktime(&p_statbuf->tm));
|
||||||
if (!r) {
|
if (!SetFileTime(file_handle, ft, ft, ft))
|
||||||
uprintf(" Error writing file: %s", WindowsErrorString());
|
uprintf(" Could not set timestamp: %s", WindowsErrorString());
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
file_length -= ISO_BLOCKSIZE;
|
|
||||||
if (nb_blocks++ % PROGRESS_THRESHOLD == 0)
|
|
||||||
UpdateProgressWithInfo(OP_FILE_COPY, MSG_231, nb_blocks, total_blocks);
|
|
||||||
}
|
|
||||||
if (preserve_timestamps) {
|
|
||||||
LPFILETIME ft = to_filetime(mktime(&p_statbuf->tm));
|
|
||||||
if (!SetFileTime(file_handle, ft, ft, ft))
|
|
||||||
uprintf(" Could not set timestamp: %s", WindowsErrorString());
|
|
||||||
}
|
}
|
||||||
if (free_p_statbuf)
|
if (free_p_statbuf)
|
||||||
iso9660_stat_free(p_statbuf);
|
iso9660_stat_free(p_statbuf);
|
||||||
|
@ -1014,6 +1045,7 @@ BOOL ExtractISO(const char* src_iso, const char* dest_dir, BOOL scan)
|
||||||
uprintf("ISO analysis:");
|
uprintf("ISO analysis:");
|
||||||
SendMessage(hMainDialog, UM_PROGRESS_INIT, PBS_MARQUEE, 0);
|
SendMessage(hMainDialog, UM_PROGRESS_INIT, PBS_MARQUEE, 0);
|
||||||
total_blocks = 0;
|
total_blocks = 0;
|
||||||
|
extra_blocks = 0;
|
||||||
has_ldlinux_c32 = FALSE;
|
has_ldlinux_c32 = FALSE;
|
||||||
// String array of all isolinux/syslinux locations
|
// String array of all isolinux/syslinux locations
|
||||||
StrArrayCreate(&config_path, 8);
|
StrArrayCreate(&config_path, 8);
|
||||||
|
|
|
@ -1233,6 +1233,16 @@ static __inline BOOL MoveFileExU(const char* lpExistingFileName, const char* lpN
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static __inline BOOL CreateSymbolicLinkU(const char* lpSymlinkFileName, const char* lpTargetFileName, DWORD dwFlags)
|
||||||
|
{
|
||||||
|
wconvert(lpSymlinkFileName);
|
||||||
|
wconvert(lpTargetFileName);
|
||||||
|
BOOL ret = CreateSymbolicLinkW(wlpSymlinkFileName, wlpTargetFileName, dwFlags);
|
||||||
|
wfree(lpTargetFileName);
|
||||||
|
wfree(lpSymlinkFileName);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
// The following expects PropertyBuffer to contain a single Unicode string
|
// The following expects PropertyBuffer to contain a single Unicode string
|
||||||
static __inline BOOL SetupDiGetDeviceRegistryPropertyU(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData,
|
static __inline BOOL SetupDiGetDeviceRegistryPropertyU(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData,
|
||||||
DWORD Property, PDWORD PropertyRegDataType, PBYTE PropertyBuffer, DWORD PropertyBufferSize, PDWORD RequiredSize)
|
DWORD Property, PDWORD PropertyRegDataType, PBYTE PropertyBuffer, DWORD PropertyBufferSize, PDWORD RequiredSize)
|
||||||
|
|
10
src/rufus.rc
10
src/rufus.rc
|
@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
||||||
IDD_DIALOG DIALOGEX 12, 12, 232, 326
|
IDD_DIALOG DIALOGEX 12, 12, 232, 326
|
||||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||||
EXSTYLE WS_EX_ACCEPTFILES
|
EXSTYLE WS_EX_ACCEPTFILES
|
||||||
CAPTION "Rufus 4.3.2086"
|
CAPTION "Rufus 4.3.2087"
|
||||||
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
|
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
|
||||||
BEGIN
|
BEGIN
|
||||||
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
|
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
|
||||||
|
@ -392,8 +392,8 @@ END
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 4,3,2086,0
|
FILEVERSION 4,3,2087,0
|
||||||
PRODUCTVERSION 4,3,2086,0
|
PRODUCTVERSION 4,3,2087,0
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -411,13 +411,13 @@ BEGIN
|
||||||
VALUE "Comments", "https://rufus.ie"
|
VALUE "Comments", "https://rufus.ie"
|
||||||
VALUE "CompanyName", "Akeo Consulting"
|
VALUE "CompanyName", "Akeo Consulting"
|
||||||
VALUE "FileDescription", "Rufus"
|
VALUE "FileDescription", "Rufus"
|
||||||
VALUE "FileVersion", "4.3.2086"
|
VALUE "FileVersion", "4.3.2087"
|
||||||
VALUE "InternalName", "Rufus"
|
VALUE "InternalName", "Rufus"
|
||||||
VALUE "LegalCopyright", "© 2011-2023 Pete Batard (GPL v3)"
|
VALUE "LegalCopyright", "© 2011-2023 Pete Batard (GPL v3)"
|
||||||
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
|
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
|
||||||
VALUE "OriginalFilename", "rufus-4.3.exe"
|
VALUE "OriginalFilename", "rufus-4.3.exe"
|
||||||
VALUE "ProductName", "Rufus"
|
VALUE "ProductName", "Rufus"
|
||||||
VALUE "ProductVersion", "4.3.2086"
|
VALUE "ProductVersion", "4.3.2087"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
Loading…
Reference in a new issue