mirror of
https://github.com/GerbilSoft/rom-properties.git
synced 2025-06-18 19:45:41 -04:00
[rp-download] SetFileOriginInfo_win32.cpp: Use NTDLL to write the Alternate Data Stream with just the file handle.
Note that we have to use NtWriteFile(). Using WriteFile() results in ERROR_BAD_COMMAND. If the ADS write fails, it will be deleted with NtDeleteFile(). NOTE: Unicode only! ANSI builds won't write the ADS anymore. ANSI builds (if they even work at all) should only be used on Win9x, which doesn't support ADS anyway. TODO: Convert NTSTATUS to POSIX error codes?
This commit is contained in:
parent
a19815f744
commit
f157be4a97
@ -110,6 +110,11 @@ TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME}
|
|||||||
IF(WIN32)
|
IF(WIN32)
|
||||||
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PRIVATE win32common rptext-noi18n)
|
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PRIVATE win32common rptext-noi18n)
|
||||||
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PRIVATE wininet advapi32)
|
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PRIVATE wininet advapi32)
|
||||||
|
# NTDLL is used to open Alternate Data Streams without requiring the original filename.
|
||||||
|
# NOTE: Only works in Unicode builds. Non-Unicode builds would be for Win9x, which
|
||||||
|
# doesn't support Alternate Data Streams, anyway.
|
||||||
|
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PRIVATE ntdll)
|
||||||
|
|
||||||
# Delay-load shell32.dll and ole32.dll to prevent a performance penalty due to gdi32.dll.
|
# Delay-load shell32.dll and ole32.dll to prevent a performance penalty due to gdi32.dll.
|
||||||
# Reference: https://randomascii.wordpress.com/2018/12/03/a-not-called-function-can-cause-a-5x-slowdown/
|
# Reference: https://randomascii.wordpress.com/2018/12/03/a-not-called-function-can-cause-a-5x-slowdown/
|
||||||
# This is also needed when disabling direct Win32k syscalls,
|
# This is also needed when disabling direct Win32k syscalls,
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* ROM Properties Page shell extension. (rp-download) *
|
* ROM Properties Page shell extension. (rp-download) *
|
||||||
* SetFileOriginInfo.hpp: setFileOriginInfo() function. *
|
* SetFileOriginInfo.hpp: setFileOriginInfo() function. *
|
||||||
* *
|
* *
|
||||||
* Copyright (c) 2016-2023 by David Korth. *
|
* Copyright (c) 2016-2025 by David Korth. *
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later *
|
* SPDX-License-Identifier: GPL-2.0-or-later *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
@ -19,29 +19,14 @@
|
|||||||
|
|
||||||
namespace RpDownload {
|
namespace RpDownload {
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
/**
|
/**
|
||||||
* Set the file origin info.
|
* Set the file origin info.
|
||||||
* This uses xattrs on Linux and ADS on Windows.
|
* This uses xattrs on Linux and ADS on Windows.
|
||||||
* @param file Open file. (Must be writable.)
|
* @param file Open file (Must be writable)
|
||||||
* @param url Origin URL.
|
* @param url Origin URL
|
||||||
* @param mtime If >= 0, this value is set as the mtime.
|
* @param mtime If >= 0, this value is set as the mtime.
|
||||||
* @return 0 on success; negative POSIX error code on error.
|
* @return 0 on success; negative POSIX error code on error.
|
||||||
*/
|
*/
|
||||||
int setFileOriginInfo(FILE *file, const TCHAR *url, time_t mtime);
|
int setFileOriginInfo(FILE *file, const TCHAR *url, time_t mtime);
|
||||||
#endif /* !_WIN32 */
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
/**
|
|
||||||
* Set the file origin info.
|
|
||||||
* This uses xattrs on Linux and ADS on Windows.
|
|
||||||
* @param file Open file. (Must be writable.)
|
|
||||||
* @param filename Filename. [FIXME: Make it so we don't need this on Windows.]
|
|
||||||
* @param url Origin URL.
|
|
||||||
* @param mtime If >= 0, this value is set as the mtime.
|
|
||||||
* @return 0 on success; negative POSIX error code on error.
|
|
||||||
*/
|
|
||||||
int setFileOriginInfo(FILE *file, const TCHAR *filename, const TCHAR *url, time_t mtime);
|
|
||||||
#endif /* _WIN32 */
|
|
||||||
|
|
||||||
} //namespace RpDownload
|
} //namespace RpDownload
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* ROM Properties Page shell extension. (rp-download) *
|
* ROM Properties Page shell extension. (rp-download) *
|
||||||
* SetFileOriginInfo_win32.cpp: setFileOriginInfo() function. (Win32 version) *
|
* SetFileOriginInfo_win32.cpp: setFileOriginInfo() function. (Win32 version) *
|
||||||
* *
|
* *
|
||||||
* Copyright (c) 2016-2024 by David Korth. *
|
* Copyright (c) 2016-2025 by David Korth. *
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later *
|
* SPDX-License-Identifier: GPL-2.0-or-later *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
@ -29,6 +29,39 @@
|
|||||||
using std::string;
|
using std::string;
|
||||||
using std::tstring;
|
using std::tstring;
|
||||||
|
|
||||||
|
#ifdef UNICODE
|
||||||
|
// NTDLL function calls
|
||||||
|
#include <io.h>
|
||||||
|
#include <winternl.h>
|
||||||
|
|
||||||
|
// FIXME: RTL_CONSTANT_STRING macro is in ntdef.h,
|
||||||
|
// but #include'ing it breaks things.
|
||||||
|
// This version is from MinGW-w64 12.0.0.
|
||||||
|
#define RTL_CONSTANT_STRING(s) { sizeof(s)-sizeof((s)[0]), sizeof(s), const_cast<PWSTR>(s) }
|
||||||
|
|
||||||
|
// NTDLL functions not declared in winternl.h.
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
__kernel_entry NTSYSCALLAPI NTSTATUS NtWriteFile(
|
||||||
|
HANDLE FileHandle,
|
||||||
|
HANDLE Event,
|
||||||
|
PIO_APC_ROUTINE ApcRoutine,
|
||||||
|
PVOID ApcContext,
|
||||||
|
PIO_STATUS_BLOCK IoStatusBlock,
|
||||||
|
PVOID Buffer,
|
||||||
|
ULONG Length,
|
||||||
|
PLARGE_INTEGER ByteOffset,
|
||||||
|
PULONG Key
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef const OBJECT_ATTRIBUTES *PCOBJECT_ATTRIBUTES;
|
||||||
|
__kernel_entry NTSYSCALLAPI NTSTATUS NtDeleteFile(
|
||||||
|
PCOBJECT_ATTRIBUTES ObjectAttributes
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif /* UNICODE */
|
||||||
|
|
||||||
namespace RpDownload {
|
namespace RpDownload {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -75,13 +108,12 @@ static bool getStoreFileOriginInfo(void)
|
|||||||
/**
|
/**
|
||||||
* Set the file origin info.
|
* Set the file origin info.
|
||||||
* This uses xattrs on Linux and ADS on Windows.
|
* This uses xattrs on Linux and ADS on Windows.
|
||||||
* @param file Open file. (Must be writable.)
|
* @param file Open file (Must be writable)
|
||||||
* @param filename Filename. [FIXME: Make it so we don't need this on Windows.]
|
* @param url Origin URL
|
||||||
* @param url Origin URL.
|
|
||||||
* @param mtime If >= 0, this value is set as the mtime.
|
* @param mtime If >= 0, this value is set as the mtime.
|
||||||
* @return 0 on success; negative POSIX error code on error.
|
* @return 0 on success; negative POSIX error code on error.
|
||||||
*/
|
*/
|
||||||
int setFileOriginInfo(FILE *file, const TCHAR *filename, const TCHAR *url, time_t mtime)
|
int setFileOriginInfo(FILE *file, const TCHAR *url, time_t mtime)
|
||||||
{
|
{
|
||||||
// NOTE: Even if one of the xattr functions fails, we'll
|
// NOTE: Even if one of the xattr functions fails, we'll
|
||||||
// continue with others and setting mtime. The first error
|
// continue with others and setting mtime. The first error
|
||||||
@ -94,6 +126,7 @@ int setFileOriginInfo(FILE *file, const TCHAR *filename, const TCHAR *url, time_
|
|||||||
# error 32-bit time_t is not supported. Get a newer compiler.
|
# error 32-bit time_t is not supported. Get a newer compiler.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef UNICODE
|
||||||
// Check if storeFileOriginInfo is enabled.
|
// Check if storeFileOriginInfo is enabled.
|
||||||
const bool storeFileOriginInfo = getStoreFileOriginInfo();
|
const bool storeFileOriginInfo = getStoreFileOriginInfo();
|
||||||
if (storeFileOriginInfo) do {
|
if (storeFileOriginInfo) do {
|
||||||
@ -102,25 +135,34 @@ int setFileOriginInfo(FILE *file, const TCHAR *filename, const TCHAR *url, time_
|
|||||||
// - https://cqureacademy.com/blog/alternate-data-streams
|
// - https://cqureacademy.com/blog/alternate-data-streams
|
||||||
// - https://stackoverflow.com/questions/46141321/open-alternate-data-stream-ads-from-file-handle-or-file-id
|
// - https://stackoverflow.com/questions/46141321/open-alternate-data-stream-ads-from-file-handle-or-file-id
|
||||||
// - https://stackoverflow.com/a/46141949
|
// - https://stackoverflow.com/a/46141949
|
||||||
// FIXME: NtCreateFile() seems to have issues, and we end up
|
HANDLE hFile = reinterpret_cast<HANDLE>(_get_osfhandle(fileno(file)));
|
||||||
// getting STATUS_INVALID_PARAMETER (0xC000000D).
|
IO_STATUS_BLOCK iosb;
|
||||||
// We'll use a regular CreateFile() call for now.
|
UNICODE_STRING ObjectName = RTL_CONSTANT_STRING(L":Zone.Identifier");
|
||||||
tstring tfilename = filename;
|
|
||||||
tfilename += _T(":Zone.Identifier");
|
OBJECT_ATTRIBUTES oa;
|
||||||
HANDLE hAds = CreateFile(
|
InitializeObjectAttributes(&oa, &ObjectName, 0, hFile, nullptr);
|
||||||
tfilename.c_str(), // lpFileName
|
|
||||||
GENERIC_WRITE, // dwDesiredAccess
|
HANDLE hAds = nullptr;
|
||||||
FILE_SHARE_READ, // dwShareMode
|
NTSTATUS status = NtCreateFile(
|
||||||
nullptr, // lpSecurityAttributes
|
&hAds, // FileHandle
|
||||||
CREATE_ALWAYS, // dwCreationDisposition
|
FILE_GENERIC_WRITE, // DesiredAccess
|
||||||
FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes
|
&oa, // ObjectAttributes
|
||||||
nullptr); // hTemplateFile
|
&iosb, // IoStatusBlock
|
||||||
if (!hAds || hAds == INVALID_HANDLE_VALUE) {
|
nullptr, // AllocationSize
|
||||||
|
FILE_ATTRIBUTE_NORMAL, // FileAttributes
|
||||||
|
FILE_SHARE_READ, // ShareAccess
|
||||||
|
FILE_OVERWRITE_IF, // CreateDisposition
|
||||||
|
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, // CreateOptions
|
||||||
|
nullptr, // EaBuffer
|
||||||
|
0); // EaLength
|
||||||
|
if (status < 0) {
|
||||||
// Error opening the ADS.
|
// Error opening the ADS.
|
||||||
err = w32err_to_posix(GetLastError());
|
// TODO: Convert NTSTATUS to POSIX?
|
||||||
|
/*err = w32err_to_posix(GetLastError());
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
err = EIO;
|
err = EIO;
|
||||||
}
|
}*/
|
||||||
|
err = EIO;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,19 +177,28 @@ int setFileOriginInfo(FILE *file, const TCHAR *filename, const TCHAR *url, time_
|
|||||||
s_zoneID += T2U8(url);
|
s_zoneID += T2U8(url);
|
||||||
s_zoneID += "\r\n";
|
s_zoneID += "\r\n";
|
||||||
|
|
||||||
DWORD dwBytesWritten = 0;
|
status = NtWriteFile(
|
||||||
BOOL bRet = WriteFile(hAds, s_zoneID.data(), static_cast<DWORD>(s_zoneID.size()),
|
hAds, // FileHandle
|
||||||
&dwBytesWritten, nullptr);
|
nullptr, // Event
|
||||||
if ((!bRet || dwBytesWritten != static_cast<DWORD>(s_zoneID.size())) && err == 0) {
|
nullptr, // ApcRoutine
|
||||||
// Some error occurred...
|
nullptr, // ApcContext
|
||||||
err = w32err_to_posix(GetLastError());
|
&iosb, // IoStatusBlock
|
||||||
if (err == 0) {
|
s_zoneID.data(), // Buffer
|
||||||
err = EIO;
|
static_cast<DWORD>(s_zoneID.size()), // Length
|
||||||
}
|
nullptr, // ByteOffset
|
||||||
}
|
nullptr); // Key
|
||||||
|
NtClose(hAds);
|
||||||
|
|
||||||
CloseHandle(hAds);
|
if (status < 0) {
|
||||||
|
// Error writing the stream data.
|
||||||
|
// Delete the stream.
|
||||||
|
NtDeleteFile(&oa);
|
||||||
|
|
||||||
|
// TODO: Convert NTSTATUS to Win32?
|
||||||
|
err = -EIO;
|
||||||
|
}
|
||||||
} while (0);
|
} while (0);
|
||||||
|
#endif /* UNICODE */
|
||||||
|
|
||||||
if (mtime >= 0) {
|
if (mtime >= 0) {
|
||||||
// TODO: 100ns timestamp precision for access time?
|
// TODO: 100ns timestamp precision for access time?
|
||||||
|
@ -610,12 +610,7 @@ int RP_C_API _tmain(int argc, TCHAR *argv[])
|
|||||||
fflush(f_out);
|
fflush(f_out);
|
||||||
|
|
||||||
// Save the file origin information.
|
// Save the file origin information.
|
||||||
#ifdef _WIN32
|
|
||||||
// TODO: Figure out how to setFileOriginInfo() on Windows using an open file handle.
|
|
||||||
setFileOriginInfo(f_out, cache_filename.c_str(), full_url.c_str(), downloader.mtime());
|
|
||||||
#else /* !_WIN32 */
|
|
||||||
setFileOriginInfo(f_out, full_url.c_str(), downloader.mtime());
|
setFileOriginInfo(f_out, full_url.c_str(), downloader.mtime());
|
||||||
#endif /* _WIN32 */
|
|
||||||
fclose(f_out);
|
fclose(f_out);
|
||||||
|
|
||||||
// Success.
|
// Success.
|
||||||
|
Loading…
Reference in New Issue
Block a user