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