branch update for HEAD-2003021201
[reactos.git] / 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 <kernel32/kernel32.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         WINBOOL                 *pbCancel,
32         WINBOOL                 *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    WINBOOL 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         TIME 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 = LastWriteTime;
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 WINBOOL
194 STDCALL
195 CopyFileExW (
196         LPCWSTR                 lpExistingFileName,
197         LPCWSTR                 lpNewFileName,
198         LPPROGRESS_ROUTINE      lpProgressRoutine,
199         LPVOID                  lpData,
200         WINBOOL                 *pbCancel,
201         DWORD                   dwCopyFlags
202         )
203 {
204    NTSTATUS errCode;
205    HANDLE FileHandleSource, FileHandleDest;
206    IO_STATUS_BLOCK IoStatusBlock;
207    FILE_STANDARD_INFORMATION FileStandard;
208    FILE_BASIC_INFORMATION FileBasic;
209    FILE_DISPOSITION_INFORMATION FileDispInfo;
210    WINBOOL RC = FALSE;
211    WINBOOL KeepDestOnError = FALSE;
212    DWORD SystemError;
213
214    FileHandleSource = CreateFileW(lpExistingFileName,
215                                   GENERIC_READ,
216                                   FILE_SHARE_READ,
217                                   NULL,
218                                   OPEN_EXISTING,
219                                   FILE_ATTRIBUTE_NORMAL|FILE_FLAG_NO_BUFFERING,
220                                   NULL);
221    if (INVALID_HANDLE_VALUE != FileHandleSource)
222      {
223         errCode = NtQueryInformationFile(FileHandleSource,
224                                          &IoStatusBlock,
225                                          &FileStandard,
226                                          sizeof(FILE_STANDARD_INFORMATION),
227                                          FileStandardInformation);
228         if (!NT_SUCCESS(errCode))
229           {
230              DPRINT("Status 0x%08x obtaining FileStandardInformation for source\n", errCode);
231              SetLastErrorByStatus(errCode);
232           }
233         else
234           {
235              errCode = NtQueryInformationFile(FileHandleSource,
236                                               &IoStatusBlock,&FileBasic,
237                                               sizeof(FILE_BASIC_INFORMATION),
238                                               FileBasicInformation);
239              if (!NT_SUCCESS(errCode))
240                {
241                   DPRINT("Status 0x%08x obtaining FileBasicInformation for source\n", errCode);
242                   SetLastErrorByStatus(errCode);
243                }
244              else
245                {
246                   FileHandleDest = CreateFileW(lpNewFileName,
247                                                GENERIC_WRITE,
248                                                FILE_SHARE_WRITE,
249                                                NULL,
250                                                dwCopyFlags ? CREATE_NEW : CREATE_ALWAYS,
251                                                FileBasic.FileAttributes,
252                                                NULL);
253                   if (INVALID_HANDLE_VALUE != FileHandleDest)
254                     {
255                        errCode = CopyLoop(FileHandleSource,
256                                           FileHandleDest,
257                                           FileStandard.EndOfFile,
258                                           lpProgressRoutine,
259                                           lpData,
260                                           pbCancel,
261                                           &KeepDestOnError);
262                        if (!NT_SUCCESS(errCode))
263                          {
264                             SetLastErrorByStatus(errCode);
265                          }
266                        else
267                          {
268                             errCode = SetLastWriteTime(FileHandleDest,
269                                                        FileBasic.LastWriteTime);
270                             if (!NT_SUCCESS(errCode))
271                               {
272                                  SetLastErrorByStatus(errCode);
273                               }
274                             else
275                               {
276                                  RC = TRUE;
277                               }
278                          }
279                        NtClose(FileHandleDest);
280                        if (! RC && ! KeepDestOnError)
281                          {
282                             SystemError = GetLastError();
283                             SetFileAttributesW(lpNewFileName, FILE_ATTRIBUTE_NORMAL);
284                             DeleteFileW(lpNewFileName);
285                             SetLastError(SystemError);
286                          }
287                     }
288                   else
289                     {
290                     DPRINT("Error %d during opening of dest file\n", GetLastError());
291                     }
292                }
293           }
294         NtClose(FileHandleSource);
295      }
296    else
297      {
298      DPRINT("Error %d during opening of source file\n", GetLastError());
299      }
300
301    return RC;
302 }
303
304
305 WINBOOL
306 STDCALL
307 CopyFileExA (
308         LPCSTR                  lpExistingFileName,
309         LPCSTR                  lpNewFileName,
310         LPPROGRESS_ROUTINE      lpProgressRoutine,
311         LPVOID                  lpData,
312         WINBOOL                 *pbCancel,
313         DWORD                   dwCopyFlags
314         )
315 {
316         UNICODE_STRING ExistingFileNameU;
317         UNICODE_STRING NewFileNameU;
318         ANSI_STRING ExistingFileName;
319         ANSI_STRING NewFileName;
320         WINBOOL Result;
321
322         RtlInitAnsiString (&ExistingFileName,
323                            (LPSTR)lpExistingFileName);
324
325         RtlInitAnsiString (&NewFileName,
326                            (LPSTR)lpNewFileName);
327
328         /* convert ansi (or oem) string to unicode */
329         if (bIsFileApiAnsi)
330         {
331                 RtlAnsiStringToUnicodeString (&ExistingFileNameU,
332                                               &ExistingFileName,
333                                               TRUE);
334                 RtlAnsiStringToUnicodeString (&NewFileNameU,
335                                               &NewFileName,
336                                               TRUE);
337         }
338         else
339         {
340                 RtlOemStringToUnicodeString (&ExistingFileNameU,
341                                              &ExistingFileName,
342                                              TRUE);
343                 RtlOemStringToUnicodeString (&NewFileNameU,
344                                              &NewFileName,
345                                              TRUE);
346         }
347
348         Result = CopyFileExW (ExistingFileNameU.Buffer,
349                               NewFileNameU.Buffer,
350                               lpProgressRoutine,
351                               lpData,
352                               pbCancel,
353                               dwCopyFlags);
354
355         RtlFreeHeap (RtlGetProcessHeap (),
356                      0,
357                      ExistingFileNameU.Buffer);
358         RtlFreeHeap (RtlGetProcessHeap (),
359                      0,
360                      NewFileNameU.Buffer);
361
362         return Result;
363 }
364
365
366 WINBOOL
367 STDCALL
368 CopyFileA (
369         LPCSTR  lpExistingFileName,
370         LPCSTR  lpNewFileName,
371         WINBOOL bFailIfExists
372         )
373 {
374         return CopyFileExA (lpExistingFileName,
375                             lpNewFileName,
376                             NULL,
377                             NULL,
378                             NULL,
379                             bFailIfExists);
380 }
381
382
383 WINBOOL
384 STDCALL
385 CopyFileW (
386         LPCWSTR lpExistingFileName,
387         LPCWSTR lpNewFileName,
388         WINBOOL bFailIfExists
389         )
390 {
391         return CopyFileExW (lpExistingFileName,
392                             lpNewFileName,
393                             NULL,
394                             NULL,
395                             NULL,
396                             bFailIfExists);
397 }
398
399 /* EOF */