* Sync up to trunk head (r64829).
[reactos.git] / base / setup / usetup / filesup.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /* COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS text-mode setup
21 * FILE: subsys/system/usetup/filesup.c
22 * PURPOSE: File support functions
23 * PROGRAMMER: Eric Kohl
24 * Casper S. Hornstrup (chorns@users.sourceforge.net)
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include "usetup.h"
30
31 #define NDEBUG
32 #include <debug.h>
33
34 /* FUNCTIONS ****************************************************************/
35
36 static BOOLEAN HasCurrentCabinet = FALSE;
37 static WCHAR CurrentCabinetName[MAX_PATH];
38 static CAB_SEARCH Search;
39
40 static
41 NTSTATUS
42 SetupCreateSingleDirectory(
43 PWCHAR DirectoryName)
44 {
45 OBJECT_ATTRIBUTES ObjectAttributes;
46 IO_STATUS_BLOCK IoStatusBlock;
47 UNICODE_STRING PathName;
48 HANDLE DirectoryHandle;
49 NTSTATUS Status;
50
51 RtlCreateUnicodeString(&PathName,
52 DirectoryName);
53 if (PathName.Length > sizeof(WCHAR) &&
54 PathName.Buffer[PathName.Length / sizeof(WCHAR) - 2] == L'\\' &&
55 PathName.Buffer[PathName.Length / sizeof(WCHAR) - 1] == L'.')
56 {
57 PathName.Length -= sizeof(WCHAR);
58 PathName.Buffer[PathName.Length / sizeof(WCHAR)] = 0;
59 }
60
61 if (PathName.Length > sizeof(WCHAR) &&
62 PathName.Buffer[PathName.Length / sizeof(WCHAR) - 1] == L'\\')
63 {
64 PathName.Length -= sizeof(WCHAR);
65 PathName.Buffer[PathName.Length / sizeof(WCHAR)] = 0;
66 }
67
68 InitializeObjectAttributes(&ObjectAttributes,
69 &PathName,
70 OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
71 NULL,
72 NULL);
73
74 Status = NtCreateFile(&DirectoryHandle,
75 DIRECTORY_ALL_ACCESS,
76 &ObjectAttributes,
77 &IoStatusBlock,
78 NULL,
79 FILE_ATTRIBUTE_DIRECTORY,
80 FILE_SHARE_READ | FILE_SHARE_WRITE,
81 FILE_OPEN_IF,
82 FILE_DIRECTORY_FILE,
83 NULL,
84 0);
85 if (NT_SUCCESS(Status))
86 {
87 NtClose(DirectoryHandle);
88 }
89
90 RtlFreeUnicodeString(&PathName);
91
92 return Status;
93 }
94
95
96 static
97 BOOLEAN
98 DoesPathExist(
99 PWSTR PathName)
100 {
101 OBJECT_ATTRIBUTES ObjectAttributes;
102 IO_STATUS_BLOCK IoStatusBlock;
103 UNICODE_STRING Name;
104 HANDLE FileHandle;
105 NTSTATUS Status;
106
107 RtlInitUnicodeString(&Name,
108 PathName);
109
110 InitializeObjectAttributes(&ObjectAttributes,
111 &Name,
112 OBJ_CASE_INSENSITIVE,
113 NULL,
114 NULL);
115
116 Status = NtOpenFile(&FileHandle,
117 GENERIC_READ | SYNCHRONIZE,
118 &ObjectAttributes,
119 &IoStatusBlock,
120 0,
121 FILE_SYNCHRONOUS_IO_NONALERT);
122 if (!NT_SUCCESS(Status))
123 {
124 return FALSE;
125 }
126
127 NtClose(FileHandle);
128
129 return TRUE;
130 }
131
132
133 NTSTATUS
134 SetupCreateDirectory(
135 PWCHAR PathName)
136 {
137 PWCHAR PathBuffer = NULL;
138 PWCHAR Ptr, EndPtr;
139 ULONG BackslashCount;
140 ULONG Size;
141 NTSTATUS Status = STATUS_SUCCESS;
142
143 Size = (wcslen(PathName) + 1) * sizeof(WCHAR);
144 PathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, Size);
145 if (PathBuffer == NULL)
146 return STATUS_INSUFFICIENT_RESOURCES;
147
148 wcscpy(PathBuffer, PathName);
149 EndPtr = PathBuffer + wcslen(PathName);
150
151 Ptr = PathBuffer;
152
153 /* Skip the '\Device\HarddiskX\PartitionY\ part */
154 BackslashCount = 0;
155 while (Ptr < EndPtr && BackslashCount < 4)
156 {
157 if (*Ptr == L'\\')
158 BackslashCount++;
159
160 Ptr++;
161 }
162
163 while (Ptr < EndPtr)
164 {
165 if (*Ptr == L'\\')
166 {
167 *Ptr = 0;
168
169 DPRINT("PathBuffer: %S\n", PathBuffer);
170 if (!DoesPathExist(PathBuffer))
171 {
172 DPRINT("Create: %S\n", PathBuffer);
173 Status = SetupCreateSingleDirectory(PathBuffer);
174 if (!NT_SUCCESS(Status))
175 goto done;
176 }
177
178 *Ptr = L'\\';
179 }
180
181 Ptr++;
182 }
183
184 if (!DoesPathExist(PathBuffer))
185 {
186 DPRINT("Create: %S\n", PathBuffer);
187 Status = SetupCreateSingleDirectory(PathBuffer);
188 if (!NT_SUCCESS(Status))
189 goto done;
190 }
191
192 done:
193 DPRINT("Done.\n");
194 if (PathBuffer != NULL)
195 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
196
197 return Status;
198 }
199
200
201 NTSTATUS
202 SetupCopyFile(
203 PWCHAR SourceFileName,
204 PWCHAR DestinationFileName)
205 {
206 OBJECT_ATTRIBUTES ObjectAttributes;
207 HANDLE FileHandleSource;
208 HANDLE FileHandleDest;
209 static IO_STATUS_BLOCK IoStatusBlock;
210 FILE_STANDARD_INFORMATION FileStandard;
211 FILE_BASIC_INFORMATION FileBasic;
212 ULONG RegionSize;
213 UNICODE_STRING FileName;
214 NTSTATUS Status;
215 PVOID SourceFileMap = 0;
216 HANDLE SourceFileSection;
217 SIZE_T SourceSectionSize = 0;
218 LARGE_INTEGER ByteOffset;
219
220 #ifdef __REACTOS__
221 RtlInitUnicodeString(&FileName,
222 SourceFileName);
223
224 InitializeObjectAttributes(&ObjectAttributes,
225 &FileName,
226 OBJ_CASE_INSENSITIVE,
227 NULL,
228 NULL);
229
230 Status = NtOpenFile(&FileHandleSource,
231 GENERIC_READ,
232 &ObjectAttributes,
233 &IoStatusBlock,
234 FILE_SHARE_READ,
235 FILE_SEQUENTIAL_ONLY);
236 if (!NT_SUCCESS(Status))
237 {
238 DPRINT1("NtOpenFile failed: %x, %wZ\n", Status, &FileName);
239 goto done;
240 }
241 #else
242 FileHandleSource = CreateFileW(SourceFileName,
243 GENERIC_READ,
244 FILE_SHARE_READ,
245 NULL,
246 OPEN_EXISTING,
247 0,
248 NULL);
249 if (FileHandleSource == INVALID_HANDLE_VALUE)
250 {
251 Status = STATUS_UNSUCCESSFUL;
252 goto done;
253 }
254 #endif
255
256 Status = NtQueryInformationFile(FileHandleSource,
257 &IoStatusBlock,
258 &FileStandard,
259 sizeof(FILE_STANDARD_INFORMATION),
260 FileStandardInformation);
261 if (!NT_SUCCESS(Status))
262 {
263 DPRINT1("NtQueryInformationFile failed: %x\n", Status);
264 goto closesrc;
265 }
266
267 Status = NtQueryInformationFile(FileHandleSource,
268 &IoStatusBlock,&FileBasic,
269 sizeof(FILE_BASIC_INFORMATION),
270 FileBasicInformation);
271 if (!NT_SUCCESS(Status))
272 {
273 DPRINT1("NtQueryInformationFile failed: %x\n", Status);
274 goto closesrc;
275 }
276
277 Status = NtCreateSection(&SourceFileSection,
278 SECTION_MAP_READ,
279 NULL,
280 NULL,
281 PAGE_READONLY,
282 SEC_COMMIT,
283 FileHandleSource);
284 if (!NT_SUCCESS(Status))
285 {
286 DPRINT1("NtCreateSection failed: %x, %S\n", Status, SourceFileName);
287 goto closesrc;
288 }
289
290 Status = NtMapViewOfSection(SourceFileSection,
291 NtCurrentProcess(),
292 &SourceFileMap,
293 0,
294 0,
295 NULL,
296 &SourceSectionSize,
297 ViewUnmap,
298 0,
299 PAGE_READONLY );
300 if (!NT_SUCCESS(Status))
301 {
302 DPRINT1("NtMapViewOfSection failed: %x, %S\n", Status, SourceFileName);
303 goto closesrcsec;
304 }
305
306 RtlInitUnicodeString(&FileName,
307 DestinationFileName);
308
309 InitializeObjectAttributes(&ObjectAttributes,
310 &FileName,
311 OBJ_CASE_INSENSITIVE,
312 NULL,
313 NULL);
314
315 Status = NtCreateFile(&FileHandleDest,
316 GENERIC_WRITE | SYNCHRONIZE,
317 &ObjectAttributes,
318 &IoStatusBlock,
319 NULL,
320 FILE_ATTRIBUTE_NORMAL,
321 0,
322 FILE_OVERWRITE_IF,
323 FILE_NO_INTERMEDIATE_BUFFERING |
324 FILE_SEQUENTIAL_ONLY |
325 FILE_SYNCHRONOUS_IO_NONALERT,
326 NULL,
327 0);
328 if (!NT_SUCCESS(Status))
329 {
330 DPRINT1("NtCreateFile failed: %x\n", Status);
331 goto unmapsrcsec;
332 }
333
334 RegionSize = (ULONG)PAGE_ROUND_UP(FileStandard.EndOfFile.u.LowPart);
335 IoStatusBlock.Status = 0;
336 ByteOffset.QuadPart = 0;
337 Status = NtWriteFile(FileHandleDest,
338 NULL,
339 NULL,
340 NULL,
341 &IoStatusBlock,
342 SourceFileMap,
343 RegionSize,
344 &ByteOffset,
345 NULL);
346 if (!NT_SUCCESS(Status))
347 {
348 DPRINT1("NtWriteFile failed: %x:%x, iosb: %p src: %p, size: %x\n", Status, IoStatusBlock.Status, &IoStatusBlock, SourceFileMap, RegionSize);
349 goto closedest;
350 }
351
352 /* Copy file date/time from source file */
353 Status = NtSetInformationFile(FileHandleDest,
354 &IoStatusBlock,
355 &FileBasic,
356 sizeof(FILE_BASIC_INFORMATION),
357 FileBasicInformation);
358 if (!NT_SUCCESS(Status))
359 {
360 DPRINT1("NtSetInformationFile failed: %x\n", Status);
361 goto closedest;
362 }
363
364 /* shorten the file back to it's real size after completing the write */
365 Status = NtSetInformationFile(FileHandleDest,
366 &IoStatusBlock,
367 &FileStandard.EndOfFile,
368 sizeof(FILE_END_OF_FILE_INFORMATION),
369 FileEndOfFileInformation);
370 if (!NT_SUCCESS(Status))
371 {
372 DPRINT1("NtSetInformationFile failed: %x\n", Status);
373 }
374
375 closedest:
376 NtClose(FileHandleDest);
377
378 unmapsrcsec:
379 NtUnmapViewOfSection(NtCurrentProcess(), SourceFileMap);
380
381 closesrcsec:
382 NtClose(SourceFileSection);
383
384 closesrc:
385 NtClose(FileHandleSource);
386
387 done:
388 return Status;
389 }
390
391 #ifdef __REACTOS__
392 NTSTATUS
393 SetupExtractFile(
394 PWCHAR CabinetFileName,
395 PWCHAR SourceFileName,
396 PWCHAR DestinationPathName)
397 {
398 ULONG CabStatus;
399
400 DPRINT("SetupExtractFile(CabinetFileName %S, SourceFileName %S, DestinationPathName %S)\n",
401 CabinetFileName, SourceFileName, DestinationPathName);
402
403 if (HasCurrentCabinet)
404 {
405 DPRINT("CurrentCabinetName: %S\n", CurrentCabinetName);
406 }
407
408 if ((HasCurrentCabinet) && (wcscmp(CabinetFileName, CurrentCabinetName) == 0))
409 {
410 DPRINT("Using same cabinet as last time\n");
411
412 /* Use our last location because the files should be sequential */
413 CabStatus = CabinetFindNextFileSequential(SourceFileName, &Search);
414 if (CabStatus != CAB_STATUS_SUCCESS)
415 {
416 DPRINT("Sequential miss on file: %S\n", SourceFileName);
417
418 /* Looks like we got unlucky */
419 CabStatus = CabinetFindFirst(SourceFileName, &Search);
420 }
421 }
422 else
423 {
424 DPRINT("Using new cabinet\n");
425
426 if (HasCurrentCabinet)
427 {
428 CabinetCleanup();
429 }
430
431 wcscpy(CurrentCabinetName, CabinetFileName);
432
433 CabinetInitialize();
434 CabinetSetEventHandlers(NULL, NULL, NULL);
435 CabinetSetCabinetName(CabinetFileName);
436
437 CabStatus = CabinetOpen();
438 if (CabStatus == CAB_STATUS_SUCCESS)
439 {
440 DPRINT("Opened cabinet %S\n", CabinetGetCabinetName());
441 HasCurrentCabinet = TRUE;
442 }
443 else
444 {
445 DPRINT("Cannot open cabinet (%d)\n", CabStatus);
446 return STATUS_UNSUCCESSFUL;
447 }
448
449 /* We have to start at the beginning here */
450 CabStatus = CabinetFindFirst(SourceFileName, &Search);
451 }
452
453 if (CabStatus != CAB_STATUS_SUCCESS)
454 {
455 DPRINT1("Unable to find '%S' in cabinet '%S'\n", SourceFileName, CabinetGetCabinetName());
456 return STATUS_UNSUCCESSFUL;
457 }
458
459 CabinetSetDestinationPath(DestinationPathName);
460 CabStatus = CabinetExtractFile(&Search);
461 if (CabStatus != CAB_STATUS_SUCCESS)
462 {
463 DPRINT("Cannot extract file %S (%d)\n", SourceFileName, CabStatus);
464 return STATUS_UNSUCCESSFUL;
465 }
466
467 return STATUS_SUCCESS;
468 }
469 #endif
470
471 BOOLEAN
472 DoesFileExist(
473 PWSTR PathName,
474 PWSTR FileName)
475 {
476 OBJECT_ATTRIBUTES ObjectAttributes;
477 IO_STATUS_BLOCK IoStatusBlock;
478 UNICODE_STRING Name;
479 WCHAR FullName[MAX_PATH];
480 HANDLE FileHandle;
481 NTSTATUS Status;
482
483 wcscpy(FullName, PathName);
484 if (FileName != NULL)
485 {
486 if (FileName[0] != L'\\')
487 wcscat(FullName, L"\\");
488 wcscat(FullName, FileName);
489 }
490
491 RtlInitUnicodeString(&Name,
492 FullName);
493
494 InitializeObjectAttributes(&ObjectAttributes,
495 &Name,
496 OBJ_CASE_INSENSITIVE,
497 NULL,
498 NULL);
499
500 Status = NtOpenFile(&FileHandle,
501 GENERIC_READ | SYNCHRONIZE,
502 &ObjectAttributes,
503 &IoStatusBlock,
504 0,
505 FILE_SYNCHRONOUS_IO_NONALERT);
506 if (!NT_SUCCESS(Status))
507 {
508 return FALSE;
509 }
510
511 NtClose(FileHandle);
512
513 return TRUE;
514 }
515
516 /* EOF */