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