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