Author: pschweitzer
Date: Wed Sep 20 16:13:15 2017
New Revision: 75914
URL:
http://svn.reactos.org/svn/reactos?rev=75914&view=rev
Log:
[KERNEL32]
Rewrite SetFileAttributesW() to make it W2K3 compliant.
Notable improvements:
- Supports reparse points
- Doesn't query attributes to set them (speedup!)
This fixes a few failures in tests committed in r75236.
CORE-13495
Modified:
trunk/reactos/dll/win32/kernel32/client/file/fileinfo.c
Modified: trunk/reactos/dll/win32/kernel32/client/file/fileinfo.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/client/…
==============================================================================
--- trunk/reactos/dll/win32/kernel32/client/file/fileinfo.c [iso-8859-1] (original)
+++ trunk/reactos/dll/win32/kernel32/client/file/fileinfo.c [iso-8859-1] Wed Sep 20
16:13:15 2017
@@ -897,81 +897,104 @@
/*
* @implemented
*/
-BOOL WINAPI
+BOOL
+WINAPI
SetFileAttributesW(LPCWSTR lpFileName,
- DWORD dwFileAttributes)
-{
- FILE_BASIC_INFORMATION FileInformation;
- OBJECT_ATTRIBUTES ObjectAttributes;
- IO_STATUS_BLOCK IoStatusBlock;
- UNICODE_STRING FileName;
- HANDLE FileHandle;
- NTSTATUS Status;
-
- TRACE ("SetFileAttributeW(%S, 0x%lx) called\n", lpFileName,
dwFileAttributes);
-
- /* Validate and translate the filename */
- if (!RtlDosPathNameToNtPathName_U (lpFileName,
- &FileName,
- NULL,
- NULL))
- {
- WARN ("Invalid path\n");
- SetLastError (ERROR_BAD_PATHNAME);
- return FALSE;
- }
- TRACE ("FileName: \'%wZ\'\n", &FileName);
-
- /* build the object attributes */
- InitializeObjectAttributes (&ObjectAttributes,
- &FileName,
- OBJ_CASE_INSENSITIVE,
- NULL,
- NULL);
-
- /* Open the file */
- Status = NtOpenFile (&FileHandle,
- SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
- &ObjectAttributes,
- &IoStatusBlock,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- FILE_SYNCHRONOUS_IO_NONALERT);
- RtlFreeUnicodeString (&FileName);
- if (!NT_SUCCESS (Status))
- {
- WARN ("NtOpenFile() failed (Status %lx)\n", Status);
- BaseSetLastNTError (Status);
- return FALSE;
- }
-
- Status = NtQueryInformationFile(FileHandle,
- &IoStatusBlock,
- &FileInformation,
- sizeof(FILE_BASIC_INFORMATION),
- FileBasicInformation);
- if (!NT_SUCCESS(Status))
- {
- WARN ("SetFileAttributes NtQueryInformationFile failed with status
0x%08x\n", Status);
- NtClose (FileHandle);
- BaseSetLastNTError (Status);
- return FALSE;
- }
-
- FileInformation.FileAttributes = dwFileAttributes;
- Status = NtSetInformationFile(FileHandle,
- &IoStatusBlock,
- &FileInformation,
- sizeof(FILE_BASIC_INFORMATION),
- FileBasicInformation);
- NtClose (FileHandle);
- if (!NT_SUCCESS(Status))
- {
- WARN ("SetFileAttributes NtSetInformationFile failed with status
0x%08x\n", Status);
- BaseSetLastNTError (Status);
- return FALSE;
- }
-
- return TRUE;
+ DWORD dwFileAttributes)
+{
+ NTSTATUS Status;
+ PWSTR PathUBuffer;
+ HANDLE FileHandle;
+ UNICODE_STRING NtPathU;
+ IO_STATUS_BLOCK IoStatusBlock;
+ RTL_RELATIVE_NAME_U RelativeName;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ FILE_BASIC_INFORMATION FileInformation;
+
+ /* Get relative name */
+ if (!RtlDosPathNameToRelativeNtPathName_U(lpFileName, &NtPathU, NULL,
&RelativeName))
+ {
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ return FALSE;
+ }
+
+ /* Save buffer to allow later freeing */
+ PathUBuffer = NtPathU.Buffer;
+
+ /* If we have relative name (and root dir), use them instead */
+ if (RelativeName.RelativeName.Length != 0)
+ {
+ NtPathU.Length = RelativeName.RelativeName.Length;
+ NtPathU.MaximumLength = RelativeName.RelativeName.MaximumLength;
+ NtPathU.Buffer = RelativeName.RelativeName.Buffer;
+ }
+ else
+ {
+ RelativeName.ContainingDirectory = NULL;
+ }
+
+ /* Prepare the object attribute for opening the file */
+ InitializeObjectAttributes(&ObjectAttributes, &NtPathU,
+ OBJ_CASE_INSENSITIVE,
+ RelativeName.ContainingDirectory, NULL);
+
+ /* Attempt to open the file, while supporting reparse point */
+ Status = NtOpenFile(&FileHandle, FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
+ &ObjectAttributes, &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT |
FILE_SYNCHRONOUS_IO_NONALERT);
+ /* If opening failed, check whether it was because of reparse point support */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Nope, just quit */
+ if (Status != STATUS_INVALID_PARAMETER)
+ {
+ RtlReleaseRelativeName(&RelativeName);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
+ BaseSetLastNTError(Status);
+
+ return FALSE;
+ }
+
+ /* Yes, retry without */
+ Status = NtOpenFile(&FileHandle, FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
+ &ObjectAttributes, &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT);
+ if (!NT_SUCCESS(Status))
+ {
+ RtlReleaseRelativeName(&RelativeName);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
+ BaseSetLastNTError(Status);
+
+ return FALSE;
+ }
+ }
+
+ /* We don't need strings anylonger */
+ RtlReleaseRelativeName(&RelativeName);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
+
+ /* Zero our structure, we'll only set file attributes */
+ ZeroMemory(&FileInformation, sizeof(FileInformation));
+ /* Set the attributes, filtering only allowed attributes, and forcing normal
attribute */
+ FileInformation.FileAttributes = (dwFileAttributes &
FILE_ATTRIBUTE_VALID_SET_FLAGS) | FILE_ATTRIBUTE_NORMAL;
+
+ /* Finally, set the attributes */
+ Status = NtSetInformationFile(FileHandle, &IoStatusBlock, &FileInformation,
+ sizeof(FILE_BASIC_INFORMATION), FileBasicInformation);
+ /* Close the file */
+ NtClose(FileHandle);
+
+ /* If it failed, set the error and fail */
+ if (!NT_SUCCESS(Status))
+ {
+ BaseSetLastNTError(Status);
+
+ return FALSE;
+ }
+
+ return TRUE;
}
/*