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