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