2 * PROJECT: ReactOS Setup Library
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: File support functions.
5 * COPYRIGHT: Copyright 2017-2018 Hermes Belusca-Maito
8 /* INCLUDES *****************************************************************/
15 /* FUNCTIONS ****************************************************************/
19 IN OUT PWSTR PathBuffer
,
20 IN SIZE_T cchPathSize
,
21 IN ULONG NumberOfPathComponents
,
22 IN
va_list PathComponentsList
)
24 NTSTATUS Status
= STATUS_SUCCESS
;
29 return STATUS_SUCCESS
;
31 while (NumberOfPathComponents
--)
33 PathComponent
= va_arg(PathComponentsList
, PCWSTR
);
37 cchPathLen
= min(cchPathSize
, wcslen(PathBuffer
));
38 if (cchPathLen
>= cchPathSize
)
39 return STATUS_BUFFER_OVERFLOW
;
41 if (PathComponent
[0] != OBJ_NAME_PATH_SEPARATOR
&&
42 cchPathLen
> 0 && PathBuffer
[cchPathLen
-1] != OBJ_NAME_PATH_SEPARATOR
)
44 /* PathComponent does not start with '\' and PathBuffer does not end with '\' */
45 Status
= RtlStringCchCatW(PathBuffer
, cchPathSize
, L
"\\");
46 if (!NT_SUCCESS(Status
))
49 else if (PathComponent
[0] == OBJ_NAME_PATH_SEPARATOR
&&
50 cchPathLen
> 0 && PathBuffer
[cchPathLen
-1] == OBJ_NAME_PATH_SEPARATOR
)
52 /* PathComponent starts with '\' and PathBuffer ends with '\' */
53 while (*PathComponent
== OBJ_NAME_PATH_SEPARATOR
)
54 ++PathComponent
; // Skip any backslash
56 Status
= RtlStringCchCatW(PathBuffer
, cchPathSize
, PathComponent
);
57 if (!NT_SUCCESS(Status
))
67 IN SIZE_T cchPathSize
,
68 IN ULONG NumberOfPathComponents
,
69 IN
va_list PathComponentsList
)
72 return STATUS_SUCCESS
;
74 *PathBuffer
= UNICODE_NULL
;
75 return ConcatPathsV(PathBuffer
, cchPathSize
,
76 NumberOfPathComponents
,
82 IN OUT PWSTR PathBuffer
,
83 IN SIZE_T cchPathSize
,
84 IN ULONG NumberOfPathComponents
,
88 va_list PathComponentsList
;
91 return STATUS_SUCCESS
;
93 va_start(PathComponentsList
, NumberOfPathComponents
);
94 Status
= ConcatPathsV(PathBuffer
, cchPathSize
,
95 NumberOfPathComponents
,
97 va_end(PathComponentsList
);
104 OUT PWSTR PathBuffer
,
105 IN SIZE_T cchPathSize
,
106 IN ULONG NumberOfPathComponents
,
110 va_list PathComponentsList
;
113 return STATUS_SUCCESS
;
115 *PathBuffer
= UNICODE_NULL
;
117 va_start(PathComponentsList
, NumberOfPathComponents
);
118 Status
= CombinePathsV(PathBuffer
, cchPathSize
,
119 NumberOfPathComponents
,
121 va_end(PathComponentsList
);
127 // NOTE: It may be possible to merge both DoesPathExist and DoesFileExist...
131 IN HANDLE RootDirectory OPTIONAL
,
136 OBJECT_ATTRIBUTES ObjectAttributes
;
137 IO_STATUS_BLOCK IoStatusBlock
;
140 RtlInitUnicodeString(&Name
, PathName
);
142 InitializeObjectAttributes(&ObjectAttributes
,
144 OBJ_CASE_INSENSITIVE
,
148 Status
= NtOpenFile(&FileHandle
,
149 FILE_LIST_DIRECTORY
| SYNCHRONIZE
,
152 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
153 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_DIRECTORY_FILE
);
154 if (NT_SUCCESS(Status
))
157 DPRINT1("Failed to open directory %wZ, Status 0x%08lx\n", &Name
, Status
);
159 return NT_SUCCESS(Status
);
164 IN HANDLE RootDirectory OPTIONAL
,
165 IN PCWSTR PathName OPTIONAL
,
170 OBJECT_ATTRIBUTES ObjectAttributes
;
171 IO_STATUS_BLOCK IoStatusBlock
;
173 WCHAR FullName
[MAX_PATH
];
175 CombinePaths(FullName
, ARRAYSIZE(FullName
), 2, PathName
, FileName
);
176 RtlInitUnicodeString(&Name
, FullName
);
178 InitializeObjectAttributes(&ObjectAttributes
,
180 OBJ_CASE_INSENSITIVE
,
184 Status
= NtOpenFile(&FileHandle
,
185 GENERIC_READ
| SYNCHRONIZE
,
188 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
189 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
190 if (NT_SUCCESS(Status
))
193 DPRINT1("Failed to open file %wZ, Status 0x%08lx\n", &Name
, Status
);
195 return NT_SUCCESS(Status
);
199 * The format of NtPath should be:
200 * \Device\HarddiskXXX\PartitionYYY[\path] ,
201 * where XXX and YYY respectively represent the hard disk and partition numbers,
202 * and [\path] represent an optional path (separated by '\\').
204 * If a NT path of such a form is correctly parsed, the function returns respectively:
205 * - in pDiskNumber: the hard disk number XXX,
206 * - in pPartNumber: the partition number YYY,
207 * - in PathComponent: pointer value (inside NtPath) to the beginning of \path.
209 * NOTE: The function does not accept leading whitespace.
212 NtPathToDiskPartComponents(
214 OUT PULONG pDiskNumber
,
215 OUT PULONG pPartNumber
,
216 OUT PCWSTR
* PathComponent OPTIONAL
)
218 ULONG DiskNumber
, PartNumber
;
223 if (PathComponent
) *PathComponent
= NULL
;
227 if (_wcsnicmp(Path
, L
"\\Device\\Harddisk", 16) != 0)
229 /* The NT path doesn't start with the prefix string, thus it cannot be a hard disk device path */
230 DPRINT1("'%S' : Not a possible hard disk device.\n", NtPath
);
236 /* A number must be present now */
237 if (!iswdigit(*Path
))
239 DPRINT1("'%S' : expected a number! Not a regular hard disk device.\n", Path
);
242 DiskNumber
= wcstoul(Path
, (PWSTR
*)&Path
, 10);
244 /* Either NULL termination, or a path separator must be present now */
245 if (*Path
&& *Path
!= OBJ_NAME_PATH_SEPARATOR
)
247 DPRINT1("'%S' : expected a path separator!\n", Path
);
253 DPRINT1("The path only specified a hard disk (and nothing else, like a partition...), so we stop there.\n");
257 /* Here, *Path == L'\\' */
259 if (_wcsnicmp(Path
, L
"\\Partition", 10) != 0)
261 /* Actually, \Partition is optional so, if we don't have it, we still return success. Or should we? */
262 DPRINT1("'%S' : unexpected format!\n", NtPath
);
268 /* A number must be present now */
269 if (!iswdigit(*Path
))
271 /* If we don't have a number it means this part of path is actually not a partition specifier, so we shouldn't fail either. Or should we? */
272 DPRINT1("'%S' : expected a number!\n", Path
);
275 PartNumber
= wcstoul(Path
, (PWSTR
*)&Path
, 10);
277 /* Either NULL termination, or a path separator must be present now */
278 if (*Path
&& *Path
!= OBJ_NAME_PATH_SEPARATOR
)
280 /* We shouldn't fail here because it just means this part of path is actually not a partition specifier. Or should we? */
281 DPRINT1("'%S' : expected a path separator!\n", Path
);
285 /* OK, here we really have a partition specifier: return its number */
286 *pPartNumber
= PartNumber
;
289 /* Return the disk number */
290 *pDiskNumber
= DiskNumber
;
292 /* Return the path component also, if the user wants it */
293 if (PathComponent
) *PathComponent
= Path
;
300 IN HANDLE RootDirectory OPTIONAL
,
301 IN PCWSTR PathName OPTIONAL
,
302 IN PCWSTR FileName
, // OPTIONAL
303 OUT PHANDLE FileHandle
, // IN OUT PHANDLE OPTIONAL
304 OUT PHANDLE SectionHandle
,
305 OUT PVOID
* BaseAddress
,
306 OUT PULONG FileSize OPTIONAL
)
309 OBJECT_ATTRIBUTES ObjectAttributes
;
310 IO_STATUS_BLOCK IoStatusBlock
;
314 WCHAR FullName
[MAX_PATH
];
316 CombinePaths(FullName
, ARRAYSIZE(FullName
), 2, PathName
, FileName
);
317 RtlInitUnicodeString(&Name
, FullName
);
319 InitializeObjectAttributes(&ObjectAttributes
,
321 OBJ_CASE_INSENSITIVE
,
326 *SectionHandle
= NULL
;
328 Status
= NtOpenFile(FileHandle
,
329 GENERIC_READ
| SYNCHRONIZE
,
333 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
334 if (!NT_SUCCESS(Status
))
336 DPRINT1("Failed to open file '%wZ', Status 0x%08lx\n", &Name
, Status
);
342 /* Query the file size */
343 FILE_STANDARD_INFORMATION FileInfo
;
344 Status
= NtQueryInformationFile(*FileHandle
,
348 FileStandardInformation
);
349 if (!NT_SUCCESS(Status
))
351 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status
);
352 NtClose(*FileHandle
);
357 if (FileInfo
.EndOfFile
.HighPart
!= 0)
358 DPRINT1("WARNING!! The file '%wZ' is too large!\n", &Name
);
360 *FileSize
= FileInfo
.EndOfFile
.LowPart
;
362 DPRINT("File size: %lu\n", *FileSize
);
365 /* Map the file in memory */
367 /* Create the section */
368 Status
= NtCreateSection(SectionHandle
,
373 SEC_COMMIT
/* | SEC_IMAGE (_NO_EXECUTE) */,
375 if (!NT_SUCCESS(Status
))
377 DPRINT1("Failed to create a memory section for file '%wZ', Status 0x%08lx\n", &Name
, Status
);
378 NtClose(*FileHandle
);
383 /* Map the section */
386 Status
= NtMapViewOfSection(*SectionHandle
,
395 if (!NT_SUCCESS(Status
))
397 DPRINT1("Failed to map a view for file %wZ, Status 0x%08lx\n", &Name
, Status
);
398 NtClose(*SectionHandle
);
399 *SectionHandle
= NULL
;
400 NtClose(*FileHandle
);
405 *BaseAddress
= ViewBase
;
406 return STATUS_SUCCESS
;
411 IN HANDLE SectionHandle
,
412 IN PVOID BaseAddress
)
415 BOOLEAN Success
= TRUE
;
417 Status
= NtUnmapViewOfSection(NtCurrentProcess(), BaseAddress
);
418 if (!NT_SUCCESS(Status
))
420 DPRINT1("UnMapFile: NtUnmapViewOfSection(0x%p) failed with Status 0x%08lx\n",
421 BaseAddress
, Status
);
424 Status
= NtClose(SectionHandle
);
425 if (!NT_SUCCESS(Status
))
427 DPRINT1("UnMapFile: NtClose(0x%p) failed with Status 0x%08lx\n",
428 SectionHandle
, Status
);