[USETUP] Move Setup[Delete|Copy|Move]File() from usetup code into the setuplib's...
[reactos.git] / base / setup / usetup / filesup.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS text-mode setup
4 * FILE: base/setup/usetup/filesup.c
5 * PURPOSE: File support functions
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include "usetup.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 /* FUNCTIONS ****************************************************************/
17
18 static BOOLEAN HasCurrentCabinet = FALSE;
19 static WCHAR CurrentCabinetName[MAX_PATH];
20 static CAB_SEARCH Search;
21
22 static
23 NTSTATUS
24 SetupCreateSingleDirectory(
25 PWCHAR DirectoryName)
26 {
27 OBJECT_ATTRIBUTES ObjectAttributes;
28 IO_STATUS_BLOCK IoStatusBlock;
29 UNICODE_STRING PathName;
30 HANDLE DirectoryHandle;
31 NTSTATUS Status;
32
33 if (!RtlCreateUnicodeString(&PathName, DirectoryName))
34 return STATUS_NO_MEMORY;
35
36 if (PathName.Length > sizeof(WCHAR) &&
37 PathName.Buffer[PathName.Length / sizeof(WCHAR) - 2] == L'\\' &&
38 PathName.Buffer[PathName.Length / sizeof(WCHAR) - 1] == L'.')
39 {
40 PathName.Length -= sizeof(WCHAR);
41 PathName.Buffer[PathName.Length / sizeof(WCHAR)] = 0;
42 }
43
44 if (PathName.Length > sizeof(WCHAR) &&
45 PathName.Buffer[PathName.Length / sizeof(WCHAR) - 1] == L'\\')
46 {
47 PathName.Length -= sizeof(WCHAR);
48 PathName.Buffer[PathName.Length / sizeof(WCHAR)] = 0;
49 }
50
51 InitializeObjectAttributes(&ObjectAttributes,
52 &PathName,
53 OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
54 NULL,
55 NULL);
56
57 Status = NtCreateFile(&DirectoryHandle,
58 FILE_LIST_DIRECTORY | SYNCHRONIZE,
59 &ObjectAttributes,
60 &IoStatusBlock,
61 NULL,
62 FILE_ATTRIBUTE_DIRECTORY,
63 FILE_SHARE_READ | FILE_SHARE_WRITE,
64 FILE_OPEN_IF,
65 FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE,
66 NULL,
67 0);
68 if (NT_SUCCESS(Status))
69 {
70 NtClose(DirectoryHandle);
71 }
72
73 RtlFreeUnicodeString(&PathName);
74
75 return Status;
76 }
77
78 NTSTATUS
79 SetupCreateDirectory(
80 PWCHAR PathName)
81 {
82 PWCHAR PathBuffer = NULL;
83 PWCHAR Ptr, EndPtr;
84 ULONG BackslashCount;
85 ULONG Size;
86 NTSTATUS Status = STATUS_SUCCESS;
87
88 Size = (wcslen(PathName) + 1) * sizeof(WCHAR);
89 PathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, Size);
90 if (PathBuffer == NULL)
91 return STATUS_INSUFFICIENT_RESOURCES;
92
93 wcscpy(PathBuffer, PathName);
94 EndPtr = PathBuffer + wcslen(PathName);
95
96 Ptr = PathBuffer;
97
98 /* Skip the '\Device\HarddiskX\PartitionY\ part */
99 BackslashCount = 0;
100 while (Ptr < EndPtr && BackslashCount < 4)
101 {
102 if (*Ptr == L'\\')
103 BackslashCount++;
104
105 Ptr++;
106 }
107
108 while (Ptr < EndPtr)
109 {
110 if (*Ptr == L'\\')
111 {
112 *Ptr = 0;
113
114 DPRINT("PathBuffer: %S\n", PathBuffer);
115 if (!DoesPathExist(NULL, PathBuffer))
116 {
117 DPRINT("Create: %S\n", PathBuffer);
118 Status = SetupCreateSingleDirectory(PathBuffer);
119 if (!NT_SUCCESS(Status))
120 goto done;
121 }
122
123 *Ptr = L'\\';
124 }
125
126 Ptr++;
127 }
128
129 if (!DoesPathExist(NULL, PathBuffer))
130 {
131 DPRINT("Create: %S\n", PathBuffer);
132 Status = SetupCreateSingleDirectory(PathBuffer);
133 if (!NT_SUCCESS(Status))
134 goto done;
135 }
136
137 done:
138 DPRINT("Done.\n");
139 if (PathBuffer != NULL)
140 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
141
142 return Status;
143 }
144
145 NTSTATUS
146 SetupExtractFile(
147 PWCHAR CabinetFileName,
148 PWCHAR SourceFileName,
149 PWCHAR DestinationPathName)
150 {
151 ULONG CabStatus;
152
153 DPRINT("SetupExtractFile(CabinetFileName %S, SourceFileName %S, DestinationPathName %S)\n",
154 CabinetFileName, SourceFileName, DestinationPathName);
155
156 if (HasCurrentCabinet)
157 {
158 DPRINT("CurrentCabinetName: %S\n", CurrentCabinetName);
159 }
160
161 if ((HasCurrentCabinet) && (wcscmp(CabinetFileName, CurrentCabinetName) == 0))
162 {
163 DPRINT("Using same cabinet as last time\n");
164
165 /* Use our last location because the files should be sequential */
166 CabStatus = CabinetFindNextFileSequential(SourceFileName, &Search);
167 if (CabStatus != CAB_STATUS_SUCCESS)
168 {
169 DPRINT("Sequential miss on file: %S\n", SourceFileName);
170
171 /* Looks like we got unlucky */
172 CabStatus = CabinetFindFirst(SourceFileName, &Search);
173 }
174 }
175 else
176 {
177 DPRINT("Using new cabinet\n");
178
179 if (HasCurrentCabinet)
180 {
181 CabinetCleanup();
182 }
183
184 wcscpy(CurrentCabinetName, CabinetFileName);
185
186 CabinetInitialize();
187 CabinetSetEventHandlers(NULL, NULL, NULL);
188 CabinetSetCabinetName(CabinetFileName);
189
190 CabStatus = CabinetOpen();
191 if (CabStatus == CAB_STATUS_SUCCESS)
192 {
193 DPRINT("Opened cabinet %S\n", CabinetGetCabinetName());
194 HasCurrentCabinet = TRUE;
195 }
196 else
197 {
198 DPRINT("Cannot open cabinet (%d)\n", CabStatus);
199 return STATUS_UNSUCCESSFUL;
200 }
201
202 /* We have to start at the beginning here */
203 CabStatus = CabinetFindFirst(SourceFileName, &Search);
204 }
205
206 if (CabStatus != CAB_STATUS_SUCCESS)
207 {
208 DPRINT1("Unable to find '%S' in cabinet '%S'\n", SourceFileName, CabinetGetCabinetName());
209 return STATUS_UNSUCCESSFUL;
210 }
211
212 CabinetSetDestinationPath(DestinationPathName);
213 CabStatus = CabinetExtractFile(&Search);
214 if (CabStatus != CAB_STATUS_SUCCESS)
215 {
216 DPRINT("Cannot extract file %S (%d)\n", SourceFileName, CabStatus);
217 return STATUS_UNSUCCESSFUL;
218 }
219
220 return STATUS_SUCCESS;
221 }
222
223 BOOLEAN
224 IsValidPath(
225 IN PCWSTR InstallDir)
226 {
227 UINT i, Length;
228
229 Length = wcslen(InstallDir);
230
231 // TODO: Add check for 8.3 too.
232
233 /* Path must be at least 2 characters long */
234 // if (Length < 2)
235 // return FALSE;
236
237 /* Path must start with a backslash */
238 // if (InstallDir[0] != L'\\')
239 // return FALSE;
240
241 /* Path must not end with a backslash */
242 if (InstallDir[Length - 1] == L'\\')
243 return FALSE;
244
245 /* Path must not contain whitespace characters */
246 for (i = 0; i < Length; i++)
247 {
248 if (iswspace(InstallDir[i]))
249 return FALSE;
250 }
251
252 /* Path component must not end with a dot */
253 for (i = 0; i < Length; i++)
254 {
255 if (InstallDir[i] == L'\\' && i > 0)
256 {
257 if (InstallDir[i - 1] == L'.')
258 return FALSE;
259 }
260 }
261
262 if (InstallDir[Length - 1] == L'.')
263 return FALSE;
264
265 return TRUE;
266 }
267
268 /* EOF */