3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/file/file.c
6 * PURPOSE: Directory functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
12 /* INCLUDES *****************************************************************/
17 #include "../include/debug.h"
19 /* GLOBALS *****************************************************************/
21 /* FUNCTIONS ****************************************************************/
24 AdjustFileAttributes (
25 LPCWSTR ExistingFileName
,
29 IO_STATUS_BLOCK IoStatusBlock
;
30 FILE_BASIC_INFORMATION ExistingInfo
,
37 hFile
= CreateFileW (ExistingFileName
,
38 FILE_READ_ATTRIBUTES
| FILE_WRITE_ATTRIBUTES
,
42 FILE_ATTRIBUTE_NORMAL
,
44 if (INVALID_HANDLE_VALUE
!= hFile
)
46 errCode
= NtQueryInformationFile (hFile
,
49 sizeof(FILE_BASIC_INFORMATION
),
50 FileBasicInformation
);
51 if (NT_SUCCESS (errCode
))
53 if (0 != (ExistingInfo
.FileAttributes
& FILE_ATTRIBUTE_READONLY
))
55 Attributes
= ExistingInfo
.FileAttributes
;
56 ExistingInfo
.FileAttributes
&= ~ FILE_ATTRIBUTE_READONLY
;
57 if (0 == (ExistingInfo
.FileAttributes
&
58 (FILE_ATTRIBUTE_HIDDEN
|
59 FILE_ATTRIBUTE_SYSTEM
|
60 FILE_ATTRIBUTE_ARCHIVE
)))
62 ExistingInfo
.FileAttributes
|= FILE_ATTRIBUTE_NORMAL
;
64 errCode
= NtSetInformationFile (hFile
,
67 sizeof(FILE_BASIC_INFORMATION
),
68 FileBasicInformation
);
69 if (!NT_SUCCESS(errCode
))
71 DPRINT("Removing READONLY attribute from source failed with status 0x%08x\n", errCode
);
73 ExistingInfo
.FileAttributes
= Attributes
;
77 if (NT_SUCCESS(errCode
))
79 hFile
= CreateFileW (NewFileName
,
80 FILE_READ_ATTRIBUTES
| FILE_WRITE_ATTRIBUTES
,
84 FILE_ATTRIBUTE_NORMAL
,
86 if (INVALID_HANDLE_VALUE
!= hFile
)
88 errCode
= NtQueryInformationFile(hFile
,
91 sizeof(FILE_BASIC_INFORMATION
),
92 FileBasicInformation
);
93 if (NT_SUCCESS(errCode
))
95 NewInfo
.FileAttributes
= (NewInfo
.FileAttributes
&
96 ~ (FILE_ATTRIBUTE_HIDDEN
|
97 FILE_ATTRIBUTE_SYSTEM
|
98 FILE_ATTRIBUTE_READONLY
|
99 FILE_ATTRIBUTE_NORMAL
)) |
100 (ExistingInfo
.FileAttributes
&
101 (FILE_ATTRIBUTE_HIDDEN
|
102 FILE_ATTRIBUTE_SYSTEM
|
103 FILE_ATTRIBUTE_READONLY
|
104 FILE_ATTRIBUTE_NORMAL
)) |
105 FILE_ATTRIBUTE_ARCHIVE
;
106 NewInfo
.CreationTime
= ExistingInfo
.CreationTime
;
107 NewInfo
.LastAccessTime
= ExistingInfo
.LastAccessTime
;
108 NewInfo
.LastWriteTime
= ExistingInfo
.LastWriteTime
;
109 errCode
= NtSetInformationFile (hFile
,
112 sizeof(FILE_BASIC_INFORMATION
),
113 FileBasicInformation
);
114 if (NT_SUCCESS(errCode
))
120 DPRINT("Setting attributes on dest file failed with status 0x%08x\n", errCode
);
125 DPRINT("Obtaining attributes from dest file failed with status 0x%08x\n", errCode
);
131 DPRINT("Opening dest file to set attributes failed with code %d\n", GetLastError());
137 DPRINT("Obtaining attributes from source file failed with status 0x%08x\n", errCode
);
143 DPRINT("Opening source file to obtain attributes failed with code %d\n", GetLastError());
155 MoveFileWithProgressW (
156 LPCWSTR lpExistingFileName
,
157 LPCWSTR lpNewFileName
,
158 LPPROGRESS_ROUTINE lpProgressRoutine
,
164 IO_STATUS_BLOCK IoStatusBlock
;
165 PFILE_RENAME_INFORMATION FileRename
;
168 UNICODE_STRING DstPathU
;
170 DPRINT("MoveFileWithProgressW()\n");
172 hFile
= CreateFileW (lpExistingFileName
,
174 FILE_SHARE_WRITE
|FILE_SHARE_READ
,
177 FILE_ATTRIBUTE_NORMAL
,
180 if (hFile
== INVALID_HANDLE_VALUE
)
185 /* validate & translate the filename */
186 if (!RtlDosPathNameToNtPathName_U ((LPWSTR
)lpNewFileName
,
191 DPRINT("Invalid destination path\n");
193 SetLastError(ERROR_PATH_NOT_FOUND
);
197 FileRename
= alloca(sizeof(FILE_RENAME_INFORMATION
) + DstPathU
.Length
);
198 if ((dwFlags
& MOVEFILE_REPLACE_EXISTING
) == MOVEFILE_REPLACE_EXISTING
)
199 FileRename
->ReplaceIfExists
= TRUE
;
201 FileRename
->ReplaceIfExists
= FALSE
;
203 memcpy(FileRename
->FileName
, DstPathU
.Buffer
, DstPathU
.Length
);
204 RtlFreeHeap (RtlGetProcessHeap (),
209 * Is the length the count of characters or the length of the buffer?
211 FileRename
->FileNameLength
= DstPathU
.Length
/ sizeof(WCHAR
);
212 errCode
= NtSetInformationFile (hFile
,
215 sizeof(FILE_RENAME_INFORMATION
) + DstPathU
.Length
,
216 FileRenameInformation
);
218 if (NT_SUCCESS(errCode
))
222 else if (STATUS_NOT_SAME_DEVICE
== errCode
&&
223 MOVEFILE_COPY_ALLOWED
== (dwFlags
& MOVEFILE_COPY_ALLOWED
))
225 Result
= CopyFileExW (lpExistingFileName
,
230 FileRename
->ReplaceIfExists
? 0 : COPY_FILE_FAIL_IF_EXISTS
);
233 /* Cleanup the source file */
234 AdjustFileAttributes(lpExistingFileName
, lpNewFileName
);
235 Result
= DeleteFileW (lpExistingFileName
);
239 /* FIXME file rename not yet implemented in all FSDs so it will always
240 * fail, even when the move is to the same device
242 else if (STATUS_NOT_IMPLEMENTED
== errCode
)
245 UNICODE_STRING SrcPathU
;
247 SrcPathU
.Buffer
= alloca(sizeof(WCHAR
) * MAX_PATH
);
248 SrcPathU
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
249 SrcPathU
.Length
= GetFullPathNameW(lpExistingFileName
, MAX_PATH
, SrcPathU
.Buffer
, NULL
);
250 if (SrcPathU
.Length
>= MAX_PATH
)
252 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
255 SrcPathU
.Length
*= sizeof(WCHAR
);
257 DstPathU
.Buffer
= alloca(sizeof(WCHAR
) * MAX_PATH
);
258 DstPathU
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
259 DstPathU
.Length
= GetFullPathNameW(lpNewFileName
, MAX_PATH
, DstPathU
.Buffer
, NULL
);
260 if (DstPathU
.Length
>= MAX_PATH
)
262 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
265 DstPathU
.Length
*= sizeof(WCHAR
);
267 if (0 == RtlCompareUnicodeString(&SrcPathU
, &DstPathU
, TRUE
))
269 /* Source and destination file are the same, nothing to do */
273 Result
= CopyFileExW (lpExistingFileName
,
278 FileRename
->ReplaceIfExists
? 0 : COPY_FILE_FAIL_IF_EXISTS
);
281 /* Cleanup the source file */
282 AdjustFileAttributes(lpExistingFileName
, lpNewFileName
);
283 Result
= DeleteFileW (lpExistingFileName
);
289 SetLastErrorByStatus (errCode
);
301 MoveFileWithProgressA (
302 LPCSTR lpExistingFileName
,
303 LPCSTR lpNewFileName
,
304 LPPROGRESS_ROUTINE lpProgressRoutine
,
309 UNICODE_STRING ExistingFileNameU
;
310 UNICODE_STRING NewFileNameU
;
311 ANSI_STRING ExistingFileName
;
312 ANSI_STRING NewFileName
;
315 RtlInitAnsiString (&ExistingFileName
,
316 (LPSTR
)lpExistingFileName
);
318 RtlInitAnsiString (&NewFileName
,
319 (LPSTR
)lpNewFileName
);
321 /* convert ansi (or oem) string to unicode */
324 RtlAnsiStringToUnicodeString (&ExistingFileNameU
,
327 RtlAnsiStringToUnicodeString (&NewFileNameU
,
333 RtlOemStringToUnicodeString (&ExistingFileNameU
,
336 RtlOemStringToUnicodeString (&NewFileNameU
,
341 Result
= MoveFileWithProgressW (ExistingFileNameU
.Buffer
,
347 RtlFreeHeap (RtlGetProcessHeap (),
349 ExistingFileNameU
.Buffer
);
350 RtlFreeHeap (RtlGetProcessHeap (),
352 NewFileNameU
.Buffer
);
364 LPCWSTR lpExistingFileName
,
365 LPCWSTR lpNewFileName
368 return MoveFileExW (lpExistingFileName
,
370 MOVEFILE_COPY_ALLOWED
);
380 LPCWSTR lpExistingFileName
,
381 LPCWSTR lpNewFileName
,
385 return MoveFileWithProgressW (lpExistingFileName
,
399 LPCSTR lpExistingFileName
,
403 return MoveFileExA (lpExistingFileName
,
405 MOVEFILE_COPY_ALLOWED
);
415 LPCSTR lpExistingFileName
,
416 LPCSTR lpNewFileName
,
420 return MoveFileWithProgressA (lpExistingFileName
,