[SETUP][USETUP][WELCOME] Improve the FILE header section. Brought to you by Adam...
[reactos.git] / reactos / 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: base/setup/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 BOOLEAN
134 IsValidPath(
135 PWCHAR InstallDir,
136 ULONG Length)
137 {
138 UINT i;
139
140 // TODO: Add check for 8.3 too.
141
142 /* Check for whitespaces */
143 for (i = 0; i < Length; i++)
144 {
145 if (isspace(InstallDir[i]))
146 return FALSE;
147 }
148
149 return TRUE;
150 }
151
152
153 NTSTATUS
154 SetupCreateDirectory(
155 PWCHAR PathName)
156 {
157 PWCHAR PathBuffer = NULL;
158 PWCHAR Ptr, EndPtr;
159 ULONG BackslashCount;
160 ULONG Size;
161 NTSTATUS Status = STATUS_SUCCESS;
162
163 Size = (wcslen(PathName) + 1) * sizeof(WCHAR);
164 PathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, Size);
165 if (PathBuffer == NULL)
166 return STATUS_INSUFFICIENT_RESOURCES;
167
168 wcscpy(PathBuffer, PathName);
169 EndPtr = PathBuffer + wcslen(PathName);
170
171 Ptr = PathBuffer;
172
173 /* Skip the '\Device\HarddiskX\PartitionY\ part */
174 BackslashCount = 0;
175 while (Ptr < EndPtr && BackslashCount < 4)
176 {
177 if (*Ptr == L'\\')
178 BackslashCount++;
179
180 Ptr++;
181 }
182
183 while (Ptr < EndPtr)
184 {
185 if (*Ptr == L'\\')
186 {
187 *Ptr = 0;
188
189 DPRINT("PathBuffer: %S\n", PathBuffer);
190 if (!DoesPathExist(PathBuffer))
191 {
192 DPRINT("Create: %S\n", PathBuffer);
193 Status = SetupCreateSingleDirectory(PathBuffer);
194 if (!NT_SUCCESS(Status))
195 goto done;
196 }
197
198 *Ptr = L'\\';
199 }
200
201 Ptr++;
202 }
203
204 if (!DoesPathExist(PathBuffer))
205 {
206 DPRINT("Create: %S\n", PathBuffer);
207 Status = SetupCreateSingleDirectory(PathBuffer);
208 if (!NT_SUCCESS(Status))
209 goto done;
210 }
211
212 done:
213 DPRINT("Done.\n");
214 if (PathBuffer != NULL)
215 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
216
217 return Status;
218 }
219
220
221 NTSTATUS
222 SetupCopyFile(
223 PWCHAR SourceFileName,
224 PWCHAR DestinationFileName)
225 {
226 OBJECT_ATTRIBUTES ObjectAttributes;
227 HANDLE FileHandleSource;
228 HANDLE FileHandleDest;
229 static IO_STATUS_BLOCK IoStatusBlock;
230 FILE_STANDARD_INFORMATION FileStandard;
231 FILE_BASIC_INFORMATION FileBasic;
232 ULONG RegionSize;
233 UNICODE_STRING FileName;
234 NTSTATUS Status;
235 PVOID SourceFileMap = 0;
236 HANDLE SourceFileSection;
237 SIZE_T SourceSectionSize = 0;
238 LARGE_INTEGER ByteOffset;
239
240 #ifdef __REACTOS__
241 RtlInitUnicodeString(&FileName,
242 SourceFileName);
243
244 InitializeObjectAttributes(&ObjectAttributes,
245 &FileName,
246 OBJ_CASE_INSENSITIVE,
247 NULL,
248 NULL);
249
250 Status = NtOpenFile(&FileHandleSource,
251 GENERIC_READ,
252 &ObjectAttributes,
253 &IoStatusBlock,
254 FILE_SHARE_READ,
255 FILE_SEQUENTIAL_ONLY);
256 if (!NT_SUCCESS(Status))
257 {
258 DPRINT1("NtOpenFile failed: %x, %wZ\n", Status, &FileName);
259 goto done;
260 }
261 #else
262 FileHandleSource = CreateFileW(SourceFileName,
263 GENERIC_READ,
264 FILE_SHARE_READ,
265 NULL,
266 OPEN_EXISTING,
267 0,
268 NULL);
269 if (FileHandleSource == INVALID_HANDLE_VALUE)
270 {
271 Status = STATUS_UNSUCCESSFUL;
272 goto done;
273 }
274 #endif
275
276 Status = NtQueryInformationFile(FileHandleSource,
277 &IoStatusBlock,
278 &FileStandard,
279 sizeof(FILE_STANDARD_INFORMATION),
280 FileStandardInformation);
281 if (!NT_SUCCESS(Status))
282 {
283 DPRINT1("NtQueryInformationFile failed: %x\n", Status);
284 goto closesrc;
285 }
286
287 Status = NtQueryInformationFile(FileHandleSource,
288 &IoStatusBlock,&FileBasic,
289 sizeof(FILE_BASIC_INFORMATION),
290 FileBasicInformation);
291 if (!NT_SUCCESS(Status))
292 {
293 DPRINT1("NtQueryInformationFile failed: %x\n", Status);
294 goto closesrc;
295 }
296
297 Status = NtCreateSection(&SourceFileSection,
298 SECTION_MAP_READ,
299 NULL,
300 NULL,
301 PAGE_READONLY,
302 SEC_COMMIT,
303 FileHandleSource);
304 if (!NT_SUCCESS(Status))
305 {
306 DPRINT1("NtCreateSection failed: %x, %S\n", Status, SourceFileName);
307 goto closesrc;
308 }
309
310 Status = NtMapViewOfSection(SourceFileSection,
311 NtCurrentProcess(),
312 &SourceFileMap,
313 0,
314 0,
315 NULL,
316 &SourceSectionSize,
317 ViewUnmap,
318 0,
319 PAGE_READONLY );
320 if (!NT_SUCCESS(Status))
321 {
322 DPRINT1("NtMapViewOfSection failed: %x, %S\n", Status, SourceFileName);
323 goto closesrcsec;
324 }
325
326 RtlInitUnicodeString(&FileName,
327 DestinationFileName);
328
329 InitializeObjectAttributes(&ObjectAttributes,
330 &FileName,
331 OBJ_CASE_INSENSITIVE,
332 NULL,
333 NULL);
334
335 Status = NtCreateFile(&FileHandleDest,
336 GENERIC_WRITE | SYNCHRONIZE,
337 &ObjectAttributes,
338 &IoStatusBlock,
339 NULL,
340 FILE_ATTRIBUTE_NORMAL,
341 0,
342 FILE_OVERWRITE_IF,
343 FILE_NO_INTERMEDIATE_BUFFERING |
344 FILE_SEQUENTIAL_ONLY |
345 FILE_SYNCHRONOUS_IO_NONALERT,
346 NULL,
347 0);
348 if (!NT_SUCCESS(Status))
349 {
350 DPRINT1("NtCreateFile failed: %x, %wZ\n", Status, &FileName);
351 goto unmapsrcsec;
352 }
353
354 RegionSize = (ULONG)PAGE_ROUND_UP(FileStandard.EndOfFile.u.LowPart);
355 IoStatusBlock.Status = 0;
356 ByteOffset.QuadPart = 0;
357 Status = NtWriteFile(FileHandleDest,
358 NULL,
359 NULL,
360 NULL,
361 &IoStatusBlock,
362 SourceFileMap,
363 RegionSize,
364 &ByteOffset,
365 NULL);
366 if (!NT_SUCCESS(Status))
367 {
368 DPRINT1("NtWriteFile failed: %x:%x, iosb: %p src: %p, size: %x\n", Status, IoStatusBlock.Status, &IoStatusBlock, SourceFileMap, RegionSize);
369 goto closedest;
370 }
371
372 /* Copy file date/time from source file */
373 Status = NtSetInformationFile(FileHandleDest,
374 &IoStatusBlock,
375 &FileBasic,
376 sizeof(FILE_BASIC_INFORMATION),
377 FileBasicInformation);
378 if (!NT_SUCCESS(Status))
379 {
380 DPRINT1("NtSetInformationFile failed: %x\n", Status);
381 goto closedest;
382 }
383
384 /* shorten the file back to it's real size after completing the write */
385 Status = NtSetInformationFile(FileHandleDest,
386 &IoStatusBlock,
387 &FileStandard.EndOfFile,
388 sizeof(FILE_END_OF_FILE_INFORMATION),
389 FileEndOfFileInformation);
390 if (!NT_SUCCESS(Status))
391 {
392 DPRINT1("NtSetInformationFile failed: %x\n", Status);
393 }
394
395 closedest:
396 NtClose(FileHandleDest);
397
398 unmapsrcsec:
399 NtUnmapViewOfSection(NtCurrentProcess(), SourceFileMap);
400
401 closesrcsec:
402 NtClose(SourceFileSection);
403
404 closesrc:
405 NtClose(FileHandleSource);
406
407 done:
408 return Status;
409 }
410
411 #ifdef __REACTOS__
412 NTSTATUS
413 SetupExtractFile(
414 PWCHAR CabinetFileName,
415 PWCHAR SourceFileName,
416 PWCHAR DestinationPathName)
417 {
418 ULONG CabStatus;
419
420 DPRINT("SetupExtractFile(CabinetFileName %S, SourceFileName %S, DestinationPathName %S)\n",
421 CabinetFileName, SourceFileName, DestinationPathName);
422
423 if (HasCurrentCabinet)
424 {
425 DPRINT("CurrentCabinetName: %S\n", CurrentCabinetName);
426 }
427
428 if ((HasCurrentCabinet) && (wcscmp(CabinetFileName, CurrentCabinetName) == 0))
429 {
430 DPRINT("Using same cabinet as last time\n");
431
432 /* Use our last location because the files should be sequential */
433 CabStatus = CabinetFindNextFileSequential(SourceFileName, &Search);
434 if (CabStatus != CAB_STATUS_SUCCESS)
435 {
436 DPRINT("Sequential miss on file: %S\n", SourceFileName);
437
438 /* Looks like we got unlucky */
439 CabStatus = CabinetFindFirst(SourceFileName, &Search);
440 }
441 }
442 else
443 {
444 DPRINT("Using new cabinet\n");
445
446 if (HasCurrentCabinet)
447 {
448 CabinetCleanup();
449 }
450
451 wcscpy(CurrentCabinetName, CabinetFileName);
452
453 CabinetInitialize();
454 CabinetSetEventHandlers(NULL, NULL, NULL);
455 CabinetSetCabinetName(CabinetFileName);
456
457 CabStatus = CabinetOpen();
458 if (CabStatus == CAB_STATUS_SUCCESS)
459 {
460 DPRINT("Opened cabinet %S\n", CabinetGetCabinetName());
461 HasCurrentCabinet = TRUE;
462 }
463 else
464 {
465 DPRINT("Cannot open cabinet (%d)\n", CabStatus);
466 return STATUS_UNSUCCESSFUL;
467 }
468
469 /* We have to start at the beginning here */
470 CabStatus = CabinetFindFirst(SourceFileName, &Search);
471 }
472
473 if (CabStatus != CAB_STATUS_SUCCESS)
474 {
475 DPRINT1("Unable to find '%S' in cabinet '%S'\n", SourceFileName, CabinetGetCabinetName());
476 return STATUS_UNSUCCESSFUL;
477 }
478
479 CabinetSetDestinationPath(DestinationPathName);
480 CabStatus = CabinetExtractFile(&Search);
481 if (CabStatus != CAB_STATUS_SUCCESS)
482 {
483 DPRINT("Cannot extract file %S (%d)\n", SourceFileName, CabStatus);
484 return STATUS_UNSUCCESSFUL;
485 }
486
487 return STATUS_SUCCESS;
488 }
489 #endif
490
491 BOOLEAN
492 DoesFileExist(
493 PWSTR PathName,
494 PWSTR FileName)
495 {
496 OBJECT_ATTRIBUTES ObjectAttributes;
497 IO_STATUS_BLOCK IoStatusBlock;
498 UNICODE_STRING Name;
499 WCHAR FullName[MAX_PATH];
500 HANDLE FileHandle;
501 NTSTATUS Status;
502
503 wcscpy(FullName, PathName);
504 if (FileName != NULL)
505 {
506 if (FileName[0] != L'\\')
507 wcscat(FullName, L"\\");
508 wcscat(FullName, FileName);
509 }
510
511 RtlInitUnicodeString(&Name,
512 FullName);
513
514 InitializeObjectAttributes(&ObjectAttributes,
515 &Name,
516 OBJ_CASE_INSENSITIVE,
517 NULL,
518 NULL);
519
520 Status = NtOpenFile(&FileHandle,
521 GENERIC_READ | SYNCHRONIZE,
522 &ObjectAttributes,
523 &IoStatusBlock,
524 0,
525 FILE_SYNCHRONOUS_IO_NONALERT);
526 if (!NT_SUCCESS(Status))
527 {
528 return FALSE;
529 }
530
531 NtClose(FileHandle);
532
533 return TRUE;
534 }
535
536 /* EOF */