[KERNEL32]
[reactos.git] / reactos / dll / win32 / kernel32 / client / file / copy.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/file/copy.c
5 * PURPOSE: Copying files
6 * PROGRAMMER: Ariadne (ariadne@xs4all.nl)
7 * UPDATE HISTORY:
8 * 01/11/98 Created
9 * 07/02/99 Moved to seperate file
10 */
11
12 /* INCLUDES ****************************************************************/
13
14 #include <k32.h>
15 #define NDEBUG
16 #include <debug.h>
17
18 #if DBG
19 DEBUG_CHANNEL(kernel32file);
20 #endif
21
22 /* FUNCTIONS ****************************************************************/
23
24
25 static NTSTATUS
26 CopyLoop (
27 HANDLE FileHandleSource,
28 HANDLE FileHandleDest,
29 LARGE_INTEGER SourceFileSize,
30 LPPROGRESS_ROUTINE lpProgressRoutine,
31 LPVOID lpData,
32 BOOL *pbCancel,
33 BOOL *KeepDest
34 )
35 {
36 NTSTATUS errCode;
37 IO_STATUS_BLOCK IoStatusBlock;
38 UCHAR *lpBuffer = NULL;
39 SIZE_T RegionSize = 0x10000;
40 LARGE_INTEGER BytesCopied;
41 DWORD CallbackReason;
42 DWORD ProgressResult;
43 BOOL EndOfFileFound;
44
45 *KeepDest = FALSE;
46 errCode = NtAllocateVirtualMemory(NtCurrentProcess(),
47 (PVOID *)&lpBuffer,
48 0,
49 &RegionSize,
50 MEM_RESERVE | MEM_COMMIT,
51 PAGE_READWRITE);
52
53 if (NT_SUCCESS(errCode))
54 {
55 BytesCopied.QuadPart = 0;
56 EndOfFileFound = FALSE;
57 CallbackReason = CALLBACK_STREAM_SWITCH;
58 while (! EndOfFileFound &&
59 NT_SUCCESS(errCode) &&
60 (NULL == pbCancel || ! *pbCancel))
61 {
62 if (NULL != lpProgressRoutine)
63 {
64 ProgressResult = (*lpProgressRoutine)(SourceFileSize,
65 BytesCopied,
66 SourceFileSize,
67 BytesCopied,
68 0,
69 CallbackReason,
70 FileHandleSource,
71 FileHandleDest,
72 lpData);
73 switch (ProgressResult)
74 {
75 case PROGRESS_CANCEL:
76 TRACE("Progress callback requested cancel\n");
77 errCode = STATUS_REQUEST_ABORTED;
78 break;
79 case PROGRESS_STOP:
80 TRACE("Progress callback requested stop\n");
81 errCode = STATUS_REQUEST_ABORTED;
82 *KeepDest = TRUE;
83 break;
84 case PROGRESS_QUIET:
85 lpProgressRoutine = NULL;
86 break;
87 case PROGRESS_CONTINUE:
88 default:
89 break;
90 }
91 CallbackReason = CALLBACK_CHUNK_FINISHED;
92 }
93 if (NT_SUCCESS(errCode))
94 {
95 errCode = NtReadFile(FileHandleSource,
96 NULL,
97 NULL,
98 NULL,
99 (PIO_STATUS_BLOCK)&IoStatusBlock,
100 lpBuffer,
101 RegionSize,
102 NULL,
103 NULL);
104 if (NT_SUCCESS(errCode) && (NULL == pbCancel || ! *pbCancel))
105 {
106 errCode = NtWriteFile(FileHandleDest,
107 NULL,
108 NULL,
109 NULL,
110 (PIO_STATUS_BLOCK)&IoStatusBlock,
111 lpBuffer,
112 IoStatusBlock.Information,
113 NULL,
114 NULL);
115 if (NT_SUCCESS(errCode))
116 {
117 BytesCopied.QuadPart += IoStatusBlock.Information;
118 }
119 else
120 {
121 WARN("Error 0x%08x reading writing to dest\n", errCode);
122 }
123 }
124 else if (!NT_SUCCESS(errCode))
125 {
126 if (STATUS_END_OF_FILE == errCode)
127 {
128 EndOfFileFound = TRUE;
129 errCode = STATUS_SUCCESS;
130 }
131 else
132 {
133 WARN("Error 0x%08x reading from source\n", errCode);
134 }
135 }
136 }
137 }
138
139 if (! EndOfFileFound && (NULL != pbCancel && *pbCancel))
140 {
141 TRACE("User requested cancel\n");
142 errCode = STATUS_REQUEST_ABORTED;
143 }
144
145 NtFreeVirtualMemory(NtCurrentProcess(),
146 (PVOID *)&lpBuffer,
147 &RegionSize,
148 MEM_RELEASE);
149 }
150 else
151 {
152 TRACE("Error 0x%08x allocating buffer of %lu bytes\n", errCode, RegionSize);
153 }
154
155 return errCode;
156 }
157
158 static NTSTATUS
159 SetLastWriteTime(
160 HANDLE FileHandle,
161 LARGE_INTEGER LastWriteTime
162 )
163 {
164 NTSTATUS errCode = STATUS_SUCCESS;
165 IO_STATUS_BLOCK IoStatusBlock;
166 FILE_BASIC_INFORMATION FileBasic;
167
168 errCode = NtQueryInformationFile (FileHandle,
169 &IoStatusBlock,
170 &FileBasic,
171 sizeof(FILE_BASIC_INFORMATION),
172 FileBasicInformation);
173 if (!NT_SUCCESS(errCode))
174 {
175 WARN("Error 0x%08x obtaining FileBasicInformation\n", errCode);
176 }
177 else
178 {
179 FileBasic.LastWriteTime.QuadPart = LastWriteTime.QuadPart;
180 errCode = NtSetInformationFile (FileHandle,
181 &IoStatusBlock,
182 &FileBasic,
183 sizeof(FILE_BASIC_INFORMATION),
184 FileBasicInformation);
185 if (!NT_SUCCESS(errCode))
186 {
187 WARN("Error 0x%0x setting LastWriteTime\n", errCode);
188 }
189 }
190
191 return errCode;
192 }
193
194
195 /*
196 * @implemented
197 */
198 BOOL
199 WINAPI
200 CopyFileExW (
201 LPCWSTR lpExistingFileName,
202 LPCWSTR lpNewFileName,
203 LPPROGRESS_ROUTINE lpProgressRoutine,
204 LPVOID lpData,
205 BOOL *pbCancel,
206 DWORD dwCopyFlags
207 )
208 {
209 NTSTATUS errCode;
210 HANDLE FileHandleSource, FileHandleDest;
211 IO_STATUS_BLOCK IoStatusBlock;
212 FILE_STANDARD_INFORMATION FileStandard;
213 FILE_BASIC_INFORMATION FileBasic;
214 BOOL RC = FALSE;
215 BOOL KeepDestOnError = FALSE;
216 DWORD SystemError;
217
218 FileHandleSource = CreateFileW(lpExistingFileName,
219 GENERIC_READ,
220 FILE_SHARE_READ | FILE_SHARE_WRITE,
221 NULL,
222 OPEN_EXISTING,
223 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_NO_BUFFERING,
224 NULL);
225 if (INVALID_HANDLE_VALUE != FileHandleSource)
226 {
227 errCode = NtQueryInformationFile(FileHandleSource,
228 &IoStatusBlock,
229 &FileStandard,
230 sizeof(FILE_STANDARD_INFORMATION),
231 FileStandardInformation);
232 if (!NT_SUCCESS(errCode))
233 {
234 TRACE("Status 0x%08x obtaining FileStandardInformation for source\n", errCode);
235 BaseSetLastNTError(errCode);
236 }
237 else
238 {
239 errCode = NtQueryInformationFile(FileHandleSource,
240 &IoStatusBlock,&FileBasic,
241 sizeof(FILE_BASIC_INFORMATION),
242 FileBasicInformation);
243 if (!NT_SUCCESS(errCode))
244 {
245 TRACE("Status 0x%08x obtaining FileBasicInformation for source\n", errCode);
246 BaseSetLastNTError(errCode);
247 }
248 else
249 {
250 FileHandleDest = CreateFileW(lpNewFileName,
251 GENERIC_WRITE,
252 FILE_SHARE_WRITE,
253 NULL,
254 dwCopyFlags ? CREATE_NEW : CREATE_ALWAYS,
255 FileBasic.FileAttributes,
256 NULL);
257 if (INVALID_HANDLE_VALUE != FileHandleDest)
258 {
259 errCode = CopyLoop(FileHandleSource,
260 FileHandleDest,
261 FileStandard.EndOfFile,
262 lpProgressRoutine,
263 lpData,
264 pbCancel,
265 &KeepDestOnError);
266 if (!NT_SUCCESS(errCode))
267 {
268 BaseSetLastNTError(errCode);
269 }
270 else
271 {
272 LARGE_INTEGER t;
273
274 t.QuadPart = FileBasic.LastWriteTime.QuadPart;
275 errCode = SetLastWriteTime(FileHandleDest, t);
276 if (!NT_SUCCESS(errCode))
277 {
278 BaseSetLastNTError(errCode);
279 }
280 else
281 {
282 RC = TRUE;
283 }
284 }
285 NtClose(FileHandleDest);
286 if (! RC && ! KeepDestOnError)
287 {
288 SystemError = GetLastError();
289 SetFileAttributesW(lpNewFileName, FILE_ATTRIBUTE_NORMAL);
290 DeleteFileW(lpNewFileName);
291 SetLastError(SystemError);
292 }
293 }
294 else
295 {
296 WARN("Error %lu during opening of dest file\n", GetLastError());
297 }
298 }
299 }
300 NtClose(FileHandleSource);
301 }
302 else
303 {
304 WARN("Error %lu during opening of source file\n", GetLastError());
305 }
306
307 return RC;
308 }
309
310
311 /*
312 * @implemented
313 */
314 BOOL
315 WINAPI
316 CopyFileExA(IN LPCSTR lpExistingFileName,
317 IN LPCSTR lpNewFileName,
318 IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL,
319 IN LPVOID lpData OPTIONAL,
320 IN LPBOOL pbCancel OPTIONAL,
321 IN DWORD dwCopyFlags)
322 {
323 BOOL Result = FALSE;
324 UNICODE_STRING lpNewFileNameW;
325 PUNICODE_STRING lpExistingFileNameW;
326
327 lpExistingFileNameW = Basep8BitStringToStaticUnicodeString(lpExistingFileName);
328 if (!lpExistingFileNameW)
329 {
330 return FALSE;
331 }
332
333 if (Basep8BitStringToDynamicUnicodeString(&lpNewFileNameW, lpNewFileName))
334 {
335 Result = CopyFileExW(lpExistingFileNameW->Buffer,
336 lpNewFileNameW.Buffer,
337 lpProgressRoutine,
338 lpData,
339 pbCancel,
340 dwCopyFlags);
341
342 RtlFreeUnicodeString(&lpNewFileNameW);
343 }
344
345 return Result;
346 }
347
348
349 /*
350 * @implemented
351 */
352 BOOL
353 WINAPI
354 CopyFileA(IN LPCSTR lpExistingFileName,
355 IN LPCSTR lpNewFileName,
356 IN BOOL bFailIfExists)
357 {
358 BOOL Result = FALSE;
359 UNICODE_STRING lpNewFileNameW;
360 PUNICODE_STRING lpExistingFileNameW;
361
362 lpExistingFileNameW = Basep8BitStringToStaticUnicodeString(lpExistingFileName);
363 if (!lpExistingFileNameW)
364 {
365 return FALSE;
366 }
367
368 if (Basep8BitStringToDynamicUnicodeString(&lpNewFileNameW, lpNewFileName))
369 {
370 Result = CopyFileExW(lpExistingFileNameW->Buffer,
371 lpNewFileNameW.Buffer,
372 NULL,
373 NULL,
374 NULL,
375 (bFailIfExists ? COPY_FILE_FAIL_IF_EXISTS : 0));
376
377 RtlFreeUnicodeString(&lpNewFileNameW);
378 }
379
380 return Result;
381 }
382
383
384 /*
385 * @implemented
386 */
387 BOOL
388 WINAPI
389 CopyFileW(IN LPCWSTR lpExistingFileName,
390 IN LPCWSTR lpNewFileName,
391 IN BOOL bFailIfExists)
392 {
393 return CopyFileExW(lpExistingFileName,
394 lpNewFileName,
395 NULL,
396 NULL,
397 NULL,
398 (bFailIfExists ? COPY_FILE_FAIL_IF_EXISTS : 0));
399 }
400
401
402 /*
403 * @implemented
404 */
405 BOOL
406 WINAPI
407 PrivCopyFileExW (
408 LPCWSTR lpExistingFileName,
409 LPCWSTR lpNewFileName,
410 LPPROGRESS_ROUTINE lpProgressRoutine,
411 LPVOID lpData,
412 BOOL *pbCancel,
413 DWORD dwCopyFlags
414 )
415 {
416 UNIMPLEMENTED;
417 return FALSE;
418 }
419
420 /* EOF */