Sync with trunk r63647.
[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 NTSTATUS
41 SetupCreateDirectory(
42 PWCHAR DirectoryName)
43 {
44 OBJECT_ATTRIBUTES ObjectAttributes;
45 IO_STATUS_BLOCK IoStatusBlock;
46 UNICODE_STRING PathName;
47 HANDLE DirectoryHandle;
48 NTSTATUS Status;
49
50 RtlCreateUnicodeString(&PathName,
51 DirectoryName);
52 if (PathName.Length > sizeof(WCHAR) &&
53 PathName.Buffer[PathName.Length / sizeof(WCHAR) - 2] == L'\\' &&
54 PathName.Buffer[PathName.Length / sizeof(WCHAR) - 1] == L'.')
55 {
56 PathName.Length -= sizeof(WCHAR);
57 PathName.Buffer[PathName.Length / sizeof(WCHAR)] = 0;
58 }
59
60 if (PathName.Length > sizeof(WCHAR) &&
61 PathName.Buffer[PathName.Length / sizeof(WCHAR) - 1] == L'\\')
62 {
63 PathName.Length -= sizeof(WCHAR);
64 PathName.Buffer[PathName.Length / sizeof(WCHAR)] = 0;
65 }
66
67 InitializeObjectAttributes(&ObjectAttributes,
68 &PathName,
69 OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
70 NULL,
71 NULL);
72
73 Status = NtCreateFile(&DirectoryHandle,
74 DIRECTORY_ALL_ACCESS,
75 &ObjectAttributes,
76 &IoStatusBlock,
77 NULL,
78 FILE_ATTRIBUTE_DIRECTORY,
79 FILE_SHARE_READ | FILE_SHARE_WRITE,
80 FILE_OPEN_IF,
81 FILE_DIRECTORY_FILE,
82 NULL,
83 0);
84 if (NT_SUCCESS(Status))
85 {
86 NtClose(DirectoryHandle);
87 }
88
89 RtlFreeUnicodeString(&PathName);
90
91 return Status;
92 }
93
94
95 NTSTATUS
96 SetupCopyFile(
97 PWCHAR SourceFileName,
98 PWCHAR DestinationFileName)
99 {
100 OBJECT_ATTRIBUTES ObjectAttributes;
101 HANDLE FileHandleSource;
102 HANDLE FileHandleDest;
103 static IO_STATUS_BLOCK IoStatusBlock;
104 FILE_STANDARD_INFORMATION FileStandard;
105 FILE_BASIC_INFORMATION FileBasic;
106 ULONG RegionSize;
107 UNICODE_STRING FileName;
108 NTSTATUS Status;
109 PVOID SourceFileMap = 0;
110 HANDLE SourceFileSection;
111 SIZE_T SourceSectionSize = 0;
112 LARGE_INTEGER ByteOffset;
113
114 #ifdef __REACTOS__
115 RtlInitUnicodeString(&FileName,
116 SourceFileName);
117
118 InitializeObjectAttributes(&ObjectAttributes,
119 &FileName,
120 OBJ_CASE_INSENSITIVE,
121 NULL,
122 NULL);
123
124 Status = NtOpenFile(&FileHandleSource,
125 GENERIC_READ,
126 &ObjectAttributes,
127 &IoStatusBlock,
128 FILE_SHARE_READ,
129 FILE_SEQUENTIAL_ONLY);
130 if (!NT_SUCCESS(Status))
131 {
132 DPRINT1("NtOpenFile failed: %x, %wZ\n", Status, &FileName);
133 goto done;
134 }
135 #else
136 FileHandleSource = CreateFileW(SourceFileName,
137 GENERIC_READ,
138 FILE_SHARE_READ,
139 NULL,
140 OPEN_EXISTING,
141 0,
142 NULL);
143 if (FileHandleSource == INVALID_HANDLE_VALUE)
144 {
145 Status = STATUS_UNSUCCESSFUL;
146 goto done;
147 }
148 #endif
149
150 Status = NtQueryInformationFile(FileHandleSource,
151 &IoStatusBlock,
152 &FileStandard,
153 sizeof(FILE_STANDARD_INFORMATION),
154 FileStandardInformation);
155 if (!NT_SUCCESS(Status))
156 {
157 DPRINT1("NtQueryInformationFile failed: %x\n", Status);
158 goto closesrc;
159 }
160
161 Status = NtQueryInformationFile(FileHandleSource,
162 &IoStatusBlock,&FileBasic,
163 sizeof(FILE_BASIC_INFORMATION),
164 FileBasicInformation);
165 if (!NT_SUCCESS(Status))
166 {
167 DPRINT1("NtQueryInformationFile failed: %x\n", Status);
168 goto closesrc;
169 }
170
171 Status = NtCreateSection(&SourceFileSection,
172 SECTION_MAP_READ,
173 NULL,
174 NULL,
175 PAGE_READONLY,
176 SEC_COMMIT,
177 FileHandleSource);
178 if (!NT_SUCCESS(Status))
179 {
180 DPRINT1("NtCreateSection failed: %x, %S\n", Status, SourceFileName);
181 goto closesrc;
182 }
183
184 Status = NtMapViewOfSection(SourceFileSection,
185 NtCurrentProcess(),
186 &SourceFileMap,
187 0,
188 0,
189 NULL,
190 &SourceSectionSize,
191 ViewUnmap,
192 0,
193 PAGE_READONLY );
194 if (!NT_SUCCESS(Status))
195 {
196 DPRINT1("NtMapViewOfSection failed: %x, %S\n", Status, SourceFileName);
197 goto closesrcsec;
198 }
199
200 RtlInitUnicodeString(&FileName,
201 DestinationFileName);
202
203 InitializeObjectAttributes(&ObjectAttributes,
204 &FileName,
205 OBJ_CASE_INSENSITIVE,
206 NULL,
207 NULL);
208
209 Status = NtCreateFile(&FileHandleDest,
210 GENERIC_WRITE | SYNCHRONIZE,
211 &ObjectAttributes,
212 &IoStatusBlock,
213 NULL,
214 FILE_ATTRIBUTE_NORMAL,
215 0,
216 FILE_OVERWRITE_IF,
217 FILE_NO_INTERMEDIATE_BUFFERING |
218 FILE_SEQUENTIAL_ONLY |
219 FILE_SYNCHRONOUS_IO_NONALERT,
220 NULL,
221 0);
222 if (!NT_SUCCESS(Status))
223 {
224 DPRINT1("NtCreateFile failed: %x\n", Status);
225 goto unmapsrcsec;
226 }
227
228 RegionSize = (ULONG)PAGE_ROUND_UP(FileStandard.EndOfFile.u.LowPart);
229 IoStatusBlock.Status = 0;
230 ByteOffset.QuadPart = 0;
231 Status = NtWriteFile(FileHandleDest,
232 NULL,
233 NULL,
234 NULL,
235 &IoStatusBlock,
236 SourceFileMap,
237 RegionSize,
238 &ByteOffset,
239 NULL);
240 if (!NT_SUCCESS(Status))
241 {
242 DPRINT1("NtWriteFile failed: %x:%x, iosb: %p src: %p, size: %x\n", Status, IoStatusBlock.Status, &IoStatusBlock, SourceFileMap, RegionSize);
243 goto closedest;
244 }
245
246 /* Copy file date/time from source file */
247 Status = NtSetInformationFile(FileHandleDest,
248 &IoStatusBlock,
249 &FileBasic,
250 sizeof(FILE_BASIC_INFORMATION),
251 FileBasicInformation);
252 if (!NT_SUCCESS(Status))
253 {
254 DPRINT1("NtSetInformationFile failed: %x\n", Status);
255 goto closedest;
256 }
257
258 /* shorten the file back to it's real size after completing the write */
259 Status = NtSetInformationFile(FileHandleDest,
260 &IoStatusBlock,
261 &FileStandard.EndOfFile,
262 sizeof(FILE_END_OF_FILE_INFORMATION),
263 FileEndOfFileInformation);
264 if (!NT_SUCCESS(Status))
265 {
266 DPRINT1("NtSetInformationFile failed: %x\n", Status);
267 }
268
269 closedest:
270 NtClose(FileHandleDest);
271
272 unmapsrcsec:
273 NtUnmapViewOfSection(NtCurrentProcess(), SourceFileMap);
274
275 closesrcsec:
276 NtClose(SourceFileSection);
277
278 closesrc:
279 NtClose(FileHandleSource);
280
281 done:
282 return Status;
283 }
284
285 #ifdef __REACTOS__
286 NTSTATUS
287 SetupExtractFile(
288 PWCHAR CabinetFileName,
289 PWCHAR SourceFileName,
290 PWCHAR DestinationPathName)
291 {
292 ULONG CabStatus;
293
294 DPRINT("SetupExtractFile(CabinetFileName %S, SourceFileName %S, DestinationPathName %S)\n",
295 CabinetFileName, SourceFileName, DestinationPathName);
296
297 if (HasCurrentCabinet)
298 {
299 DPRINT("CurrentCabinetName: %S\n", CurrentCabinetName);
300 }
301
302 if ((HasCurrentCabinet) && (wcscmp(CabinetFileName, CurrentCabinetName) == 0))
303 {
304 DPRINT("Using same cabinet as last time\n");
305
306 /* Use our last location because the files should be sequential */
307 CabStatus = CabinetFindNextFileSequential(SourceFileName, &Search);
308 if (CabStatus != CAB_STATUS_SUCCESS)
309 {
310 DPRINT("Sequential miss on file: %S\n", SourceFileName);
311
312 /* Looks like we got unlucky */
313 CabStatus = CabinetFindFirst(SourceFileName, &Search);
314 }
315 }
316 else
317 {
318 DPRINT("Using new cabinet\n");
319
320 if (HasCurrentCabinet)
321 {
322 CabinetCleanup();
323 }
324
325 wcscpy(CurrentCabinetName, CabinetFileName);
326
327 CabinetInitialize();
328 CabinetSetEventHandlers(NULL, NULL, NULL);
329 CabinetSetCabinetName(CabinetFileName);
330
331 CabStatus = CabinetOpen();
332 if (CabStatus == CAB_STATUS_SUCCESS)
333 {
334 DPRINT("Opened cabinet %S\n", CabinetGetCabinetName());
335 HasCurrentCabinet = TRUE;
336 }
337 else
338 {
339 DPRINT("Cannot open cabinet (%d)\n", CabStatus);
340 return STATUS_UNSUCCESSFUL;
341 }
342
343 /* We have to start at the beginning here */
344 CabStatus = CabinetFindFirst(SourceFileName, &Search);
345 }
346
347 if (CabStatus != CAB_STATUS_SUCCESS)
348 {
349 DPRINT1("Unable to find '%S' in cabinet '%S'\n", SourceFileName, CabinetGetCabinetName());
350 return STATUS_UNSUCCESSFUL;
351 }
352
353 CabinetSetDestinationPath(DestinationPathName);
354 CabStatus = CabinetExtractFile(&Search);
355 if (CabStatus != CAB_STATUS_SUCCESS)
356 {
357 DPRINT("Cannot extract file %S (%d)\n", SourceFileName, CabStatus);
358 return STATUS_UNSUCCESSFUL;
359 }
360
361 return STATUS_SUCCESS;
362 }
363 #endif
364
365 BOOLEAN
366 DoesFileExist(
367 PWSTR PathName,
368 PWSTR FileName)
369 {
370 OBJECT_ATTRIBUTES ObjectAttributes;
371 IO_STATUS_BLOCK IoStatusBlock;
372 UNICODE_STRING Name;
373 WCHAR FullName[MAX_PATH];
374 HANDLE FileHandle;
375 NTSTATUS Status;
376
377 wcscpy(FullName, PathName);
378 if (FileName != NULL)
379 {
380 if (FileName[0] != L'\\')
381 wcscat(FullName, L"\\");
382 wcscat(FullName, FileName);
383 }
384
385 RtlInitUnicodeString(&Name,
386 FullName);
387
388 InitializeObjectAttributes(&ObjectAttributes,
389 &Name,
390 OBJ_CASE_INSENSITIVE,
391 NULL,
392 NULL);
393
394 Status = NtOpenFile(&FileHandle,
395 GENERIC_READ | SYNCHRONIZE,
396 &ObjectAttributes,
397 &IoStatusBlock,
398 0,
399 FILE_SYNCHRONOUS_IO_NONALERT);
400 if (!NT_SUCCESS(Status))
401 {
402 return FALSE;
403 }
404
405 NtClose(FileHandle);
406
407 return TRUE;
408 }
409
410 /* EOF */