https://git.reactos.org/?p=reactos.git;a=commitdiff;h=3ddb05d44326c189e67e1…
commit 3ddb05d44326c189e67e1d71298e236048b2146a
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Wed Oct 23 15:20:46 2024 +0200
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Wed Oct 23 23:19:58 2024 +0200
[SETUPLIB] GetSourcePaths(): Fix determination of the installation source path.
Refine the algorithm introduced in commit c560342f08 (r75667, r75676),
whereby the installation source path is based on the full image file path
of the installer program, and of the \SystemRoot symlink.
Also reverts commit 6f389a35db "Add a workaround for installing from USB drives"
CORE-17818
+ SAL2-annotate and add Doxygen comments.
----
In case the \SystemRoot full path prefixes the image file path,
use the resolved \SystemRoot as the installation source path.
Otherwise, use the image file path.
The \SystemRoot symlink target resolution needs full path reparsing,
because it can reference other symlinks. This is what happens, for
example when booting the installation from a removable hard-disk.
We can have:
\SystemRoot ---> \Device\Harddisk1\Partition1\ReactOS
and: \Device\Harddisk1\Partition1 ---> \Device\HarddiskVolume2
etc.
and we wish to resolve \SystemRoot to: \Device\HarddiskVolume2\ReactOS
instead of keeping the former version (using Harddisk1\Partition1).
We then verify whether it prefixes the image file path, which is
a fully reparsed path.
---
base/setup/lib/setuplib.c | 194 +++++++++++++++++++++++++++++-----------------
base/setup/lib/setuplib.h | 6 +-
2 files changed, 124 insertions(+), 76 deletions(-)
diff --git a/base/setup/lib/setuplib.c b/base/setup/lib/setuplib.c
index f8a961ab3c1..632db24ec29 100644
--- a/base/setup/lib/setuplib.c
+++ b/base/setup/lib/setuplib.c
@@ -378,29 +378,48 @@ Quit:
#endif
}
+/**
+ * @brief
+ * Determine the installation source path and isolate its useful
+ * path components (root path and source sub-directory).
+ *
+ * The installation source path is based either on the installer's
+ * image file path, or on the \SystemRoot full path.
+ *
+ * In case the \SystemRoot full path prefixes the image file path,
+ * use the resolved \SystemRoot as the installation source path.
+ * Otherwise, use the image file path.
+ *
+ * The returned strings are allocated with RtlCreateUnicodeString(),
+ * and need to be freed with RtlFreeUnicodeString() after being used.
+ *
+ * Example of output:
+ * SourcePath: '\Device\CdRom0\I386'
+ * SourceRootPath: '\Device\CdRom0'
+ * SourceRootDir: '\I386'
+ **/
NTSTATUS
GetSourcePaths(
- OUT PUNICODE_STRING SourcePath,
- OUT PUNICODE_STRING SourceRootPath,
- OUT PUNICODE_STRING SourceRootDir)
+ _Out_ PUNICODE_STRING SourcePath,
+ _Out_ PUNICODE_STRING SourceRootPath,
+ _Out_ PUNICODE_STRING SourceRootDir)
{
NTSTATUS Status;
- HANDLE LinkHandle;
- OBJECT_ATTRIBUTES ObjectAttributes;
- UCHAR ImageFileBuffer[sizeof(UNICODE_STRING) + MAX_PATH * sizeof(WCHAR)];
- PUNICODE_STRING InstallSourcePath = (PUNICODE_STRING)&ImageFileBuffer;
- WCHAR SystemRootBuffer[MAX_PATH] = L"";
- UNICODE_STRING SystemRootPath = RTL_CONSTANT_STRING(L"\\SystemRoot");
ULONG BufferSize;
PWCHAR Ptr;
+ HANDLE LinkHandle;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+ struct { OBJECT_NAME_INFORMATION; WCHAR Buffer[MAX_PATH]; } ImageFileBuffer;
+ PUNICODE_STRING InstallSourcePath = &ImageFileBuffer.Name;
+ struct { OBJECT_NAME_INFORMATION; WCHAR Buffer[MAX_PATH]; } SystemRootBuffer;
+ PUNICODE_STRING SystemRootPath = &SystemRootBuffer.Name;
+ const UNICODE_STRING SystemRoot = RTL_CONSTANT_STRING(L"\\SystemRoot");
- // FIXME: commented out to allow installation from USB
-#if 0
- /* Determine the installation source path via the full path of the installer */
+ /* Retrieve the installer's full image file path */
RtlInitEmptyUnicodeString(InstallSourcePath,
- (PWSTR)((ULONG_PTR)ImageFileBuffer + sizeof(UNICODE_STRING)),
- sizeof(ImageFileBuffer) - sizeof(UNICODE_STRING)
- /* Reserve space for a NULL terminator */ - sizeof(UNICODE_NULL));
+ ImageFileBuffer.Buffer,
+ sizeof(ImageFileBuffer.Buffer));
BufferSize = sizeof(ImageFileBuffer);
Status = NtQueryInformationProcess(NtCurrentProcess(),
ProcessImageFileName,
@@ -410,75 +429,114 @@ GetSourcePaths(
// STATUS_INFO_LENGTH_MISMATCH or STATUS_BUFFER_TOO_SMALL ?
if (!NT_SUCCESS(Status))
return Status;
-
- /* Manually NULL-terminate */
+ ASSERT(InstallSourcePath->Length < InstallSourcePath->MaximumLength);
+
+ /* Go to the beginning of the path component, stop at the separator */
+ Ptr = ImageFileBuffer.Buffer + (InstallSourcePath->Length / sizeof(WCHAR));
+ while ((Ptr > ImageFileBuffer.Buffer) && (*Ptr != OBJ_NAME_PATH_SEPARATOR))
+ --Ptr;
+ /* Strip the trailing file name (at the separator or beginning of buffer)
+ * and manually NULL-terminate */
+ InstallSourcePath->Length = (ULONG_PTR)Ptr - (ULONG_PTR)ImageFileBuffer.Buffer;
InstallSourcePath->Buffer[InstallSourcePath->Length / sizeof(WCHAR)] = UNICODE_NULL;
- /* Strip the trailing file name */
- Ptr = wcsrchr(InstallSourcePath->Buffer, OBJ_NAME_PATH_SEPARATOR);
- if (Ptr)
- *Ptr = UNICODE_NULL;
- InstallSourcePath->Length = wcslen(InstallSourcePath->Buffer) * sizeof(WCHAR);
-#endif
/*
- * Now resolve the full path to \SystemRoot. In case it prefixes
- * the installation source path determined from the full path of
- * the installer, we use instead the resolved \SystemRoot as the
- * installation source path.
- * Otherwise, we use instead the path from the full installer path.
+ * Now, resolve the \SystemRoot symlink target full path.
+ *
+ * The symlink target path resolution requires reparsing, because it
+ * can reference other symlinks. This is what happens, for example when
+ * booting the installation from a removable hard-disk. We can have:
+ *
+ * \SystemRoot ---> \Device\Harddisk1\Partition1\ReactOS
+ * and: \Device\Harddisk1\Partition1 ---> \Device\HarddiskVolume2
+ * etc.
+ * and we wish to resolve \SystemRoot to: \Device\HarddiskVolume2\ReactOS
+ *
+ * We then verify whether it prefixes the image file path obtained
+ * from the step above, which is a fully reparsed path.
+ *
+ * - Using NtOpenSymbolicLinkObject(SYMBOLIC_LINK_QUERY) followed by
+ * NtQuerySymbolicLinkObject() would only resolve the first symlink
+ * but not the others (\Device\Harddisk1\Partition1 left as is).
+ *
+ * - Since \SystemRoot has to point to a directory, we try opening
+ * the directory itself: NtOpenFile(..., FILE_DIRECTORY_FILE).
+ *
+ * - A call to NtQueryInformationFile(FileNameInformation) alone on
+ * the obtained handle would only retrieve the FS directory name,
+ * i.e. \ReactOS , but not the whole NT path.
+ *
+ * - We therefore use NtQueryObject(), which allows retrieving the
+ * full resolved NT path (device name + FS directory name).
*/
InitializeObjectAttributes(&ObjectAttributes,
- &SystemRootPath,
+ (PUNICODE_STRING)&SystemRoot,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
- Status = NtOpenSymbolicLinkObject(&LinkHandle,
- SYMBOLIC_LINK_QUERY,
- &ObjectAttributes);
- if (!NT_SUCCESS(Status))
- {
- /*
- * We failed at opening the \SystemRoot link (usually due to wrong
- * access rights). Do not consider this as a fatal error, but use
- * instead the image file path as the installation source path.
- */
- DPRINT1("NtOpenSymbolicLinkObject(%wZ) failed with Status 0x%08lx\n",
- &SystemRootPath, Status);
- goto InitPaths;
- }
-
- RtlInitEmptyUnicodeString(&SystemRootPath,
- SystemRootBuffer,
- sizeof(SystemRootBuffer));
-
- /* Resolve the link and close its handle */
- Status = NtQuerySymbolicLinkObject(LinkHandle,
- &SystemRootPath,
- &BufferSize);
- NtClose(LinkHandle);
+ RtlInitEmptyUnicodeString(SystemRootPath,
+ SystemRootBuffer.Buffer,
+ sizeof(SystemRootBuffer.Buffer));
+ Status = NtOpenFile(&LinkHandle,
+ SYNCHRONIZE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
+ /*| FILE_OPEN_FOR_BACKUP_INTENT*/);
+ if (NT_SUCCESS(Status))
+ {
+ /* Resolve the path and close its handle */
+ Status = NtQueryObject(LinkHandle,
+ ObjectNameInformation,
+ &SystemRootBuffer,
+ sizeof(SystemRootBuffer),
+ &BufferSize);
+ NtClose(LinkHandle);
+ }
+ /* If any of the calls above failed, try to naively resolve the symlink */
if (!NT_SUCCESS(Status))
- return Status; // Unexpected error
-
- /* Check whether the resolved \SystemRoot is a prefix of the image file path */
- // FIXME: commented out to allow installation from USB
- // if (RtlPrefixUnicodeString(&SystemRootPath, InstallSourcePath, TRUE))
{
- /* Yes it is, so we use instead SystemRoot as the installation source path */
- InstallSourcePath = &SystemRootPath;
+ RtlInitEmptyUnicodeString(SystemRootPath,
+ SystemRootBuffer.Buffer,
+ sizeof(SystemRootBuffer.Buffer));
+
+ Status = NtOpenSymbolicLinkObject(&LinkHandle,
+ SYMBOLIC_LINK_QUERY,
+ &ObjectAttributes);
+ if (NT_SUCCESS(Status))
+ {
+ /* Resolve the link and close its handle */
+ Status = NtQuerySymbolicLinkObject(LinkHandle,
+ SystemRootPath,
+ &BufferSize);
+ NtClose(LinkHandle);
+ }
}
+ ASSERT(SystemRootPath->Length < SystemRootPath->MaximumLength);
+
+ /*
+ * If the resolved \SystemRoot is a prefix of the image file path,
+ * use \SystemRoot instead as the installation source path.
+ *
+ * If opening the \SystemRoot link failed (usually due to wrong
+ * access rights), do not consider this as a fatal error, and
+ * use the image file path as the installation source path.
+ */
+ if (NT_SUCCESS(Status) && RtlPrefixUnicodeString(SystemRootPath, InstallSourcePath, TRUE))
+ InstallSourcePath = SystemRootPath;
-InitPaths:
/*
- * Retrieve the different source path components
+ * Retrieve the different source path components.
*/
RtlCreateUnicodeString(SourcePath, InstallSourcePath->Buffer);
- /* Strip trailing directory */
+ /* Isolate and strip the trailing (source root) directory */
Ptr = wcsrchr(InstallSourcePath->Buffer, OBJ_NAME_PATH_SEPARATOR);
if (Ptr)
{
@@ -986,10 +1044,6 @@ InitializeSetup(
NTSTATUS Status;
/* Get the source path and source root path */
- //
- // NOTE: Sometimes the source path may not be in SystemRoot !!
- // (and this is the case when using the 1st-stage GUI setup!)
- //
Status = GetSourcePaths(&pSetupData->SourcePath,
&pSetupData->SourceRootPath,
&pSetupData->SourceRootDir);
@@ -998,12 +1052,6 @@ InitializeSetup(
DPRINT1("GetSourcePaths() failed (Status 0x%08lx)\n", Status);
return ERROR_NO_SOURCE_DRIVE;
}
- /*
- * Example of output:
- * SourcePath: '\Device\CdRom0\I386'
- * SourceRootPath: '\Device\CdRom0'
- * SourceRootDir: '\I386'
- */
DPRINT1("SourcePath (1): '%wZ'\n", &pSetupData->SourcePath);
DPRINT1("SourceRootPath (1): '%wZ'\n", &pSetupData->SourceRootPath);
DPRINT1("SourceRootDir (1): '%wZ'\n", &pSetupData->SourceRootDir);
diff --git a/base/setup/lib/setuplib.h b/base/setup/lib/setuplib.h
index 93edbebad14..a69f7bba877 100644
--- a/base/setup/lib/setuplib.h
+++ b/base/setup/lib/setuplib.h
@@ -171,9 +171,9 @@ InstallSetupInfFile(
NTSTATUS
GetSourcePaths(
- OUT PUNICODE_STRING SourcePath,
- OUT PUNICODE_STRING SourceRootPath,
- OUT PUNICODE_STRING SourceRootDir);
+ _Out_ PUNICODE_STRING SourcePath,
+ _Out_ PUNICODE_STRING SourceRootPath,
+ _Out_ PUNICODE_STRING SourceRootDir);
ERROR_NUMBER
LoadSetupInf(
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=cf955094b47aaf8aa18e1…
commit cf955094b47aaf8aa18e108825ae59fb919ced24
Author: Tomáš Veselý <turican0(a)gmail.com>
AuthorDate: Tue Oct 22 17:10:34 2024 +0200
Commit: GitHub <noreply(a)github.com>
CommitDate: Tue Oct 22 18:10:34 2024 +0300
[NTUSER] IntSetTimer(): Use timer IDs range [256,32767] as on Windows (#7277)
Based on the Doug Lyons' test in #7087, I found that my previous fix stopped working partially. Or rather, it would only work until the 32767 indexes were exhausted. It seems to me that the behavior of the bitfield has changed, because when I published the previous patch, it passed my tests.
- Bit array generates free ID cyclically, in the previous code after 32767 indexes expired the same index was returned, because of this the previous fix would stop working after expiration, so change the logic of calculating the next index.
- Change the index range to 256-32767 to match Windows, indexes 0-255 can theoretically be used as reserved for system purposes.
Addendum to fd327db20ff. CORE-9141
---
win32ss/user/ntuser/timer.c | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/win32ss/user/ntuser/timer.c b/win32ss/user/ntuser/timer.c
index db029cc039d..051cf07cc1e 100644
--- a/win32ss/user/ntuser/timer.c
+++ b/win32ss/user/ntuser/timer.c
@@ -17,7 +17,9 @@ static LIST_ENTRY TimersListHead;
static LONG TimeLast = 0;
/* Windows 2000 has room for 32768 window-less timers */
-#define NUM_WINDOW_LESS_TIMERS 32768
+/* These values give timer IDs [256,32767], same as on Windows */
+#define MAX_WINDOW_LESS_TIMER_ID (32768 - 1)
+#define NUM_WINDOW_LESS_TIMERS (32768 - 256)
#define HINTINDEX_BEGIN_VALUE 0
@@ -78,11 +80,12 @@ RemoveTimer(PTIMER pTmr)
RemoveEntryList(&pTmr->ptmrList);
if ((pTmr->pWnd == NULL) && (!(pTmr->flags & TMRF_SYSTEM))) // System timers are reusable.
{
- UINT_PTR IDEvent;
+ ULONG ulBitmapIndex;
- IDEvent = NUM_WINDOW_LESS_TIMERS - pTmr->nID;
+ ASSERT(pTmr->nID <= MAX_WINDOW_LESS_TIMER_ID);
+ ulBitmapIndex = (ULONG)(MAX_WINDOW_LESS_TIMER_ID - pTmr->nID);
IntLockWindowlessTimerBitmap();
- RtlClearBit(&WindowLessTimersBitMap, IDEvent);
+ RtlClearBit(&WindowLessTimersBitMap, ulBitmapIndex);
IntUnlockWindowlessTimerBitmap();
}
UserDereferenceObject(pTmr);
@@ -222,12 +225,8 @@ IntSetTimer( PWND Window,
{
IntLockWindowlessTimerBitmap();
- ulBitmapIndex = RtlFindClearBitsAndSet(&WindowLessTimersBitMap, 1, HintIndex++);
- if (ulBitmapIndex == ULONG_MAX)
- {
- HintIndex = HINTINDEX_BEGIN_VALUE;
- ulBitmapIndex = RtlFindClearBitsAndSet(&WindowLessTimersBitMap, 1, HintIndex++);
- }
+ ulBitmapIndex = RtlFindClearBitsAndSet(&WindowLessTimersBitMap, 1, HintIndex);
+ HintIndex = (ulBitmapIndex + 1) % NUM_WINDOW_LESS_TIMERS;
if (ulBitmapIndex == ULONG_MAX)
{
IntUnlockWindowlessTimerBitmap();
@@ -237,7 +236,7 @@ IntSetTimer( PWND Window,
}
ASSERT(ulBitmapIndex < NUM_WINDOW_LESS_TIMERS);
- IDEvent = NUM_WINDOW_LESS_TIMERS - ulBitmapIndex;
+ IDEvent = MAX_WINDOW_LESS_TIMER_ID - ulBitmapIndex;
Ret = IDEvent;
IntUnlockWindowlessTimerBitmap();