mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
Some fixes to CreateDirectoryEx:
- properly copy the directory attributes - add basic support to handle reparse points and add fallback code if the file system doesn't support them svn path=/trunk/; revision=18158
This commit is contained in:
parent
cd88496c7a
commit
a83c2a2bb4
1 changed files with 213 additions and 70 deletions
|
@ -116,7 +116,8 @@ CreateDirectoryW (
|
||||||
(lpSecurityAttributes ? lpSecurityAttributes->lpSecurityDescriptor : NULL));
|
(lpSecurityAttributes ? lpSecurityAttributes->lpSecurityDescriptor : NULL));
|
||||||
|
|
||||||
Status = NtCreateFile (&DirectoryHandle,
|
Status = NtCreateFile (&DirectoryHandle,
|
||||||
GENERIC_READ,
|
FILE_LIST_DIRECTORY | SYNCHRONIZE |
|
||||||
|
FILE_OPEN_FOR_BACKUP_INTENT,
|
||||||
&ObjectAttributes,
|
&ObjectAttributes,
|
||||||
&IoStatusBlock,
|
&IoStatusBlock,
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -157,17 +158,28 @@ CreateDirectoryExW (
|
||||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
IO_STATUS_BLOCK IoStatusBlock;
|
IO_STATUS_BLOCK IoStatusBlock;
|
||||||
UNICODE_STRING NtPathU, NtTemplatePathU;
|
UNICODE_STRING NtPathU, NtTemplatePathU;
|
||||||
HANDLE DirectoryHandle, TemplateHandle;
|
HANDLE DirectoryHandle = NULL;
|
||||||
|
HANDLE TemplateHandle = NULL;
|
||||||
FILE_EA_INFORMATION EaInformation;
|
FILE_EA_INFORMATION EaInformation;
|
||||||
|
FILE_BASIC_INFORMATION FileBasicInfo;
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
|
ULONG OpenOptions, CreateOptions;
|
||||||
|
ACCESS_MASK DesiredAccess;
|
||||||
|
BOOLEAN ReparsePoint = FALSE;
|
||||||
PVOID EaBuffer = NULL;
|
PVOID EaBuffer = NULL;
|
||||||
ULONG EaLength = 0;
|
ULONG EaLength = 0;
|
||||||
|
|
||||||
|
OpenOptions = FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT |
|
||||||
|
FILE_OPEN_FOR_BACKUP_INTENT;
|
||||||
|
CreateOptions = FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT;
|
||||||
|
DesiredAccess = FILE_LIST_DIRECTORY | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES |
|
||||||
|
FILE_READ_ATTRIBUTES;
|
||||||
|
|
||||||
DPRINT ("lpTemplateDirectory %S lpNewDirectory %S lpSecurityAttributes %p\n",
|
DPRINT ("lpTemplateDirectory %ws lpNewDirectory %ws lpSecurityAttributes %p\n",
|
||||||
lpTemplateDirectory, lpNewDirectory, lpSecurityAttributes);
|
lpTemplateDirectory, lpNewDirectory, lpSecurityAttributes);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read the extended attributes from the template directory
|
* Translate the template directory path
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpTemplateDirectory,
|
if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpTemplateDirectory,
|
||||||
|
@ -179,31 +191,107 @@ CreateDirectoryExW (
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
|
&NtPathU,
|
||||||
|
OBJ_CASE_INSENSITIVE,
|
||||||
|
NULL,
|
||||||
|
(lpSecurityAttributes ? lpSecurityAttributes->lpSecurityDescriptor : NULL));
|
||||||
|
|
||||||
InitializeObjectAttributes(&ObjectAttributes,
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
&NtTemplatePathU,
|
&NtTemplatePathU,
|
||||||
OBJ_CASE_INSENSITIVE,
|
OBJ_CASE_INSENSITIVE,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
Status = NtCreateFile (&TemplateHandle,
|
/*
|
||||||
GENERIC_READ,
|
* Open the template directory
|
||||||
&ObjectAttributes,
|
*/
|
||||||
&IoStatusBlock,
|
|
||||||
NULL,
|
OpenTemplateDir:
|
||||||
0,
|
Status = NtOpenFile (&TemplateHandle,
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | FILE_READ_EA,
|
||||||
FILE_OPEN,
|
&ObjectAttributes,
|
||||||
FILE_DIRECTORY_FILE,
|
&IoStatusBlock,
|
||||||
NULL,
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
0);
|
OpenOptions);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
RtlFreeHeap (RtlGetProcessHeap (),
|
if (Status == STATUS_INVALID_PARAMETER &&
|
||||||
0,
|
(OpenOptions & FILE_OPEN_REPARSE_POINT))
|
||||||
NtTemplatePathU.Buffer);
|
{
|
||||||
SetLastErrorByStatus (Status);
|
/* Some FSs (FAT) don't support reparse points, try opening
|
||||||
return FALSE;
|
the directory without FILE_OPEN_REPARSE_POINT */
|
||||||
|
OpenOptions &= ~FILE_OPEN_REPARSE_POINT;
|
||||||
|
|
||||||
|
DPRINT("Reparse points not supported, try with less options\n");
|
||||||
|
|
||||||
|
/* try again */
|
||||||
|
goto OpenTemplateDir;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DPRINT1("Failed to open the template directory: 0x%x\n", Status);
|
||||||
|
goto CleanupNoNtPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Translate the new directory path and check if they're the same
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpNewDirectory,
|
||||||
|
&NtPathU,
|
||||||
|
NULL,
|
||||||
|
NULL))
|
||||||
|
{
|
||||||
|
Status = STATUS_OBJECT_PATH_NOT_FOUND;
|
||||||
|
goto CleanupNoNtPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RtlEqualUnicodeString(&NtPathU,
|
||||||
|
&NtTemplatePathU,
|
||||||
|
TRUE))
|
||||||
|
{
|
||||||
|
DPRINT1("Both directory paths are the same!\n");
|
||||||
|
Status = STATUS_OBJECT_NAME_INVALID;
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Query the basic file attributes from the template directory
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Make sure FILE_ATTRIBUTE_NORMAL is used in case the information
|
||||||
|
isn't set by the FS */
|
||||||
|
FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
||||||
|
Status = NtQueryInformationFile(TemplateHandle,
|
||||||
|
&IoStatusBlock,
|
||||||
|
&FileBasicInfo,
|
||||||
|
sizeof(FILE_BASIC_INFORMATION),
|
||||||
|
FileBasicInformation);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
DPRINT1("Failed to query the basic directory attributes\n");
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* clear the reparse point attribute if present. We're going to set the
|
||||||
|
reparse point later which will cause the attribute to be set */
|
||||||
|
if (FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
|
||||||
|
{
|
||||||
|
FileBasicInfo.FileAttributes &= ~FILE_ATTRIBUTE_REPARSE_POINT;
|
||||||
|
|
||||||
|
/* writing the extended attributes requires the FILE_WRITE_DATA
|
||||||
|
access right */
|
||||||
|
DesiredAccess |= FILE_WRITE_DATA;
|
||||||
|
|
||||||
|
CreateOptions |= FILE_OPEN_REPARSE_POINT;
|
||||||
|
ReparsePoint = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read the Extended Attributes if present
|
||||||
|
*/
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
@ -261,65 +349,121 @@ CreateDirectoryExW (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NtClose(TemplateHandle);
|
|
||||||
|
|
||||||
RtlFreeHeap (RtlGetProcessHeap (),
|
|
||||||
0,
|
|
||||||
NtTemplatePathU.Buffer);
|
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
/* free the he extended attributes buffer */
|
DPRINT1("Querying the EA data failed: 0x%x\n", Status);
|
||||||
if (EaBuffer != NULL)
|
goto Cleanup;
|
||||||
{
|
|
||||||
RtlFreeHeap (RtlGetProcessHeap (),
|
|
||||||
0,
|
|
||||||
EaBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
SetLastErrorByStatus (Status);
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the new directory and copy over the extended attributes if
|
* Create the new directory
|
||||||
* needed
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpNewDirectory,
|
|
||||||
&NtPathU,
|
|
||||||
NULL,
|
|
||||||
NULL))
|
|
||||||
{
|
|
||||||
/* free the he extended attributes buffer */
|
|
||||||
if (EaBuffer != NULL)
|
|
||||||
{
|
|
||||||
RtlFreeHeap (RtlGetProcessHeap (),
|
|
||||||
0,
|
|
||||||
EaBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
SetLastError(ERROR_PATH_NOT_FOUND);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
InitializeObjectAttributes(&ObjectAttributes,
|
|
||||||
&NtPathU,
|
|
||||||
OBJ_CASE_INSENSITIVE,
|
|
||||||
NULL,
|
|
||||||
(lpSecurityAttributes ? lpSecurityAttributes->lpSecurityDescriptor : NULL));
|
|
||||||
|
|
||||||
Status = NtCreateFile (&DirectoryHandle,
|
Status = NtCreateFile (&DirectoryHandle,
|
||||||
GENERIC_READ,
|
DesiredAccess,
|
||||||
&ObjectAttributes,
|
&ObjectAttributes,
|
||||||
&IoStatusBlock,
|
&IoStatusBlock,
|
||||||
NULL,
|
NULL,
|
||||||
FILE_ATTRIBUTE_NORMAL,
|
FileBasicInfo.FileAttributes,
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
FILE_CREATE,
|
FILE_CREATE,
|
||||||
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
|
CreateOptions,
|
||||||
EaBuffer,
|
EaBuffer,
|
||||||
EaLength);
|
EaLength);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
if (ReparsePoint &&
|
||||||
|
(Status == STATUS_INVALID_PARAMETER || Status == STATUS_ACCESS_DENIED))
|
||||||
|
{
|
||||||
|
/* The FS doesn't seem to support reparse points... */
|
||||||
|
DPRINT1("Cannot copy the hardlink, destination doesn\'t support reparse points!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReparsePoint)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Copy the reparse point
|
||||||
|
*/
|
||||||
|
|
||||||
|
PREPARSE_GUID_DATA_BUFFER ReparseDataBuffer =
|
||||||
|
(PREPARSE_GUID_DATA_BUFFER)RtlAllocateHeap(RtlGetProcessHeap(),
|
||||||
|
0,
|
||||||
|
MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
|
||||||
|
|
||||||
|
if (ReparseDataBuffer == NULL)
|
||||||
|
{
|
||||||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* query the size of the reparse data buffer structure */
|
||||||
|
Status = NtFsControlFile(TemplateHandle,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&IoStatusBlock,
|
||||||
|
FSCTL_GET_REPARSE_POINT,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
ReparseDataBuffer,
|
||||||
|
MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* write the reparse point */
|
||||||
|
Status = NtFsControlFile(DirectoryHandle,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&IoStatusBlock,
|
||||||
|
FSCTL_SET_REPARSE_POINT,
|
||||||
|
ReparseDataBuffer,
|
||||||
|
MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
RtlFreeHeap(RtlGetProcessHeap(),
|
||||||
|
0,
|
||||||
|
ReparseDataBuffer);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
/* fail, we were unable to read the reparse point data! */
|
||||||
|
DPRINT1("Querying or setting the reparse point failed: 0x%x\n", Status);
|
||||||
|
goto Cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Copy alternate file streams, if existing
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* FIXME - enumerate and copy the file streams */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We successfully created the directory and copied all information
|
||||||
|
* from the template directory
|
||||||
|
*/
|
||||||
|
Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
Cleanup:
|
||||||
|
RtlFreeHeap (RtlGetProcessHeap (),
|
||||||
|
0,
|
||||||
|
NtPathU.Buffer);
|
||||||
|
|
||||||
|
CleanupNoNtPath:
|
||||||
|
if (TemplateHandle != NULL)
|
||||||
|
{
|
||||||
|
NtClose(TemplateHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
RtlFreeHeap (RtlGetProcessHeap (),
|
||||||
|
0,
|
||||||
|
NtTemplatePathU.Buffer);
|
||||||
|
|
||||||
/* free the he extended attributes buffer */
|
/* free the he extended attributes buffer */
|
||||||
if (EaBuffer != NULL)
|
if (EaBuffer != NULL)
|
||||||
|
@ -329,9 +473,10 @@ CreateDirectoryExW (
|
||||||
EaBuffer);
|
EaBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
RtlFreeHeap (RtlGetProcessHeap (),
|
if (DirectoryHandle != NULL)
|
||||||
0,
|
{
|
||||||
NtPathU.Buffer);
|
NtClose(DirectoryHandle);
|
||||||
|
}
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
|
@ -339,8 +484,6 @@ CreateDirectoryExW (
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
NtClose (DirectoryHandle);
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue