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 DPRINT("Failed to open directory '%wZ', Status 0x%08lx\n", &Name
, Status
);
159 return NT_SUCCESS(Status
);
164 IN HANDLE RootDirectory OPTIONAL
,
165 IN PCWSTR PathNameToFile
)
168 UNICODE_STRING FileName
;
170 OBJECT_ATTRIBUTES ObjectAttributes
;
171 IO_STATUS_BLOCK IoStatusBlock
;
173 RtlInitUnicodeString(&FileName
, PathNameToFile
);
175 InitializeObjectAttributes(&ObjectAttributes
,
177 OBJ_CASE_INSENSITIVE
,
181 Status
= NtOpenFile(&FileHandle
,
182 FILE_GENERIC_READ
, // Contains SYNCHRONIZE
185 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
186 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
187 if (NT_SUCCESS(Status
))
190 DPRINT("Failed to open file '%wZ', Status 0x%08lx\n", &FileName
, Status
);
192 return NT_SUCCESS(Status
);
195 // FIXME: DEPRECATED! HACKish function that needs to be deprecated!
198 IN PCWSTR PathName OPTIONAL
,
201 WCHAR FullName
[MAX_PATH
];
202 CombinePaths(FullName
, ARRAYSIZE(FullName
), 2, PathName
, FileName
);
203 return DoesFileExist(NULL
, FullName
);
207 * The format of NtPath should be:
208 * \Device\HarddiskXXX\PartitionYYY[\path] ,
209 * where XXX and YYY respectively represent the hard disk and partition numbers,
210 * and [\path] represent an optional path (separated by '\\').
212 * If a NT path of such a form is correctly parsed, the function returns respectively:
213 * - in pDiskNumber: the hard disk number XXX,
214 * - in pPartNumber: the partition number YYY,
215 * - in PathComponent: pointer value (inside NtPath) to the beginning of \path.
217 * NOTE: The function does not accept leading whitespace.
220 NtPathToDiskPartComponents(
222 OUT PULONG pDiskNumber
,
223 OUT PULONG pPartNumber
,
224 OUT PCWSTR
* PathComponent OPTIONAL
)
226 ULONG DiskNumber
, PartNumber
;
231 if (PathComponent
) *PathComponent
= NULL
;
235 if (_wcsnicmp(Path
, L
"\\Device\\Harddisk", 16) != 0)
237 /* The NT path doesn't start with the prefix string, thus it cannot be a hard disk device path */
238 DPRINT1("'%S' : Not a possible hard disk device.\n", NtPath
);
244 /* A number must be present now */
245 if (!iswdigit(*Path
))
247 DPRINT1("'%S' : expected a number! Not a regular hard disk device.\n", Path
);
250 DiskNumber
= wcstoul(Path
, (PWSTR
*)&Path
, 10);
252 /* Either NULL termination, or a path separator must be present now */
253 if (*Path
&& *Path
!= OBJ_NAME_PATH_SEPARATOR
)
255 DPRINT1("'%S' : expected a path separator!\n", Path
);
261 DPRINT1("The path only specified a hard disk (and nothing else, like a partition...), so we stop there.\n");
265 /* Here, *Path == L'\\' */
267 if (_wcsnicmp(Path
, L
"\\Partition", 10) != 0)
269 /* Actually, \Partition is optional so, if we don't have it, we still return success. Or should we? */
270 DPRINT1("'%S' : unexpected format!\n", NtPath
);
276 /* A number must be present now */
277 if (!iswdigit(*Path
))
279 /* 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? */
280 DPRINT1("'%S' : expected a number!\n", Path
);
283 PartNumber
= wcstoul(Path
, (PWSTR
*)&Path
, 10);
285 /* Either NULL termination, or a path separator must be present now */
286 if (*Path
&& *Path
!= OBJ_NAME_PATH_SEPARATOR
)
288 /* We shouldn't fail here because it just means this part of path is actually not a partition specifier. Or should we? */
289 DPRINT1("'%S' : expected a path separator!\n", Path
);
293 /* OK, here we really have a partition specifier: return its number */
294 *pPartNumber
= PartNumber
;
297 /* Return the disk number */
298 *pDiskNumber
= DiskNumber
;
300 /* Return the path component also, if the user wants it */
301 if (PathComponent
) *PathComponent
= Path
;
308 IN HANDLE RootDirectory OPTIONAL
,
309 IN PCWSTR PathNameToFile
,
310 OUT PHANDLE FileHandle
, // IN OUT PHANDLE OPTIONAL
311 OUT PHANDLE SectionHandle
,
312 OUT PVOID
* BaseAddress
,
313 OUT PULONG FileSize OPTIONAL
,
314 IN BOOLEAN ReadWriteAccess
)
317 UNICODE_STRING FileName
;
318 OBJECT_ATTRIBUTES ObjectAttributes
;
319 IO_STATUS_BLOCK IoStatusBlock
;
320 ULONG SectionPageProtection
;
326 RtlInitUnicodeString(&FileName
, PathNameToFile
);
328 InitializeObjectAttributes(&ObjectAttributes
,
330 OBJ_CASE_INSENSITIVE
,
335 *SectionHandle
= NULL
;
337 Status
= NtOpenFile(FileHandle
,
338 FILE_GENERIC_READ
| // Contains SYNCHRONIZE
339 (ReadWriteAccess
? FILE_GENERIC_WRITE
: 0),
343 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
);
344 if (!NT_SUCCESS(Status
))
346 DPRINT1("Failed to open file '%wZ', Status 0x%08lx\n", &FileName
, Status
);
352 /* Query the file size */
353 FILE_STANDARD_INFORMATION FileInfo
;
354 Status
= NtQueryInformationFile(*FileHandle
,
358 FileStandardInformation
);
359 if (!NT_SUCCESS(Status
))
361 DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status
);
362 NtClose(*FileHandle
);
367 if (FileInfo
.EndOfFile
.HighPart
!= 0)
368 DPRINT1("WARNING!! The file '%wZ' is too large!\n", &FileName
);
370 *FileSize
= FileInfo
.EndOfFile
.LowPart
;
372 DPRINT("File size: %lu\n", *FileSize
);
375 /* Map the file in memory */
377 SectionPageProtection
= (ReadWriteAccess
? PAGE_READWRITE
: PAGE_READONLY
);
379 /* Create the section */
380 Status
= NtCreateSection(SectionHandle
,
381 STANDARD_RIGHTS_REQUIRED
| SECTION_QUERY
|
383 (ReadWriteAccess
? SECTION_MAP_WRITE
: 0),
386 SectionPageProtection
,
387 SEC_COMMIT
/* | SEC_IMAGE (_NO_EXECUTE) */,
389 if (!NT_SUCCESS(Status
))
391 DPRINT1("Failed to create a memory section for file '%wZ', Status 0x%08lx\n", &FileName
, Status
);
392 NtClose(*FileHandle
);
397 /* Map the section */
400 Status
= NtMapViewOfSection(*SectionHandle
,
408 SectionPageProtection
);
409 if (!NT_SUCCESS(Status
))
411 DPRINT1("Failed to map a view for file '%wZ', Status 0x%08lx\n", &FileName
, Status
);
412 NtClose(*SectionHandle
);
413 *SectionHandle
= NULL
;
414 NtClose(*FileHandle
);
419 *BaseAddress
= ViewBase
;
420 return STATUS_SUCCESS
;
425 IN HANDLE SectionHandle
,
426 IN PVOID BaseAddress
)
429 BOOLEAN Success
= TRUE
;
431 Status
= NtUnmapViewOfSection(NtCurrentProcess(), BaseAddress
);
432 if (!NT_SUCCESS(Status
))
434 DPRINT1("UnMapFile: NtUnmapViewOfSection(0x%p) failed with Status 0x%08lx\n",
435 BaseAddress
, Status
);
438 Status
= NtClose(SectionHandle
);
439 if (!NT_SUCCESS(Status
))
441 DPRINT1("UnMapFile: NtClose(0x%p) failed with Status 0x%08lx\n",
442 SectionHandle
, Status
);