mirror of
https://github.com/reactos/reactos.git
synced 2024-07-02 02:34:53 +00:00
[KERNEL32]
- Halfplement BasepGetComputerNameFromNtPath() which allows querying the computer name given a handle & an NT path - Implement BasepNotifyTrackingService() which issues a FileTrackingInformation on file move svn path=/trunk/; revision=67355
This commit is contained in:
parent
4c58fa556c
commit
7576c6a523
|
@ -178,16 +178,312 @@ BasepMoveFileDelayed(IN PUNICODE_STRING ExistingPath,
|
|||
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
* @implemented
|
||||
*/
|
||||
DWORD
|
||||
WINAPI
|
||||
BasepGetComputerNameFromNtPath(IN PUNICODE_STRING NewPath,
|
||||
IN HANDLE NewHandle,
|
||||
OUT PWSTR ComputerName,
|
||||
IN OUT PULONG ComputerNameLength)
|
||||
{
|
||||
BOOL Query = FALSE;
|
||||
WCHAR Letter;
|
||||
PWSTR AbsolutePath, EndOfName;
|
||||
USHORT AbsolutePathLength, NameLength;
|
||||
WCHAR TargetDevice[0x105];
|
||||
WCHAR DeviceName[] = {'A', ':', '\0'}; /* Init to something, will be set later */
|
||||
UNICODE_STRING UncString = RTL_CONSTANT_STRING(L"\\??\\UNC\\");
|
||||
UNICODE_STRING GlobalString = RTL_CONSTANT_STRING(L"\\??\\");
|
||||
|
||||
DPRINT("BasepGetComputerNameFromNtPath(%wZ, %p, %p, %lu)\n", NewPath, NewHandle, ComputerName, ComputerNameLength);
|
||||
|
||||
/* If it's an UNC path */
|
||||
if (RtlPrefixUnicodeString(&UncString, NewPath, TRUE))
|
||||
{
|
||||
/* Check for broken caller */
|
||||
if (NewPath->Length <= UncString.Length)
|
||||
{
|
||||
return ERROR_BAD_PATHNAME;
|
||||
}
|
||||
|
||||
/* Skip UNC prefix */
|
||||
AbsolutePath = &NewPath->Buffer[UncString.Length / sizeof(WCHAR)];
|
||||
AbsolutePathLength = NewPath->Length - UncString.Length;
|
||||
|
||||
/* And query DFS */
|
||||
Query = TRUE;
|
||||
}
|
||||
/* Otherwise, we have to be in global (NT path!), with drive letter */
|
||||
else if (RtlPrefixUnicodeString(&GlobalString, NewPath, TRUE) && NewPath->Buffer[5] == ':')
|
||||
{
|
||||
/* Path is like that: \??\C:\Complete Path\To File.ext */
|
||||
/* Get the letter and upcase it if required */
|
||||
Letter = NewPath->Buffer[4];
|
||||
if (Letter >= 'a' && Letter <= 'z')
|
||||
{
|
||||
Letter -= ('a' - 'A');
|
||||
}
|
||||
DeviceName[0] = Letter;
|
||||
|
||||
/* Query the associated DOS device */
|
||||
if (!QueryDosDeviceW(DeviceName, TargetDevice, ARRAYSIZE(TargetDevice)))
|
||||
{
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
/* If that's a network share */
|
||||
if (TargetDevice == wcsstr(TargetDevice, L"\\Device\\LanmanRedirector\\;"))
|
||||
{
|
||||
/* Path is like that: \Device\LanmanRedirector\;C:0000000000000000\Complete Path\To File.ext */
|
||||
/* Check we have the correct drive letter */
|
||||
if (TargetDevice[26] == DeviceName[0] &&
|
||||
TargetDevice[27] == ':')
|
||||
{
|
||||
/* Check for the path begin, computer name is before */
|
||||
PWSTR Path = wcschr(&TargetDevice[28], '\\');
|
||||
if (Path == NULL)
|
||||
{
|
||||
return ERROR_BAD_PATHNAME;
|
||||
}
|
||||
|
||||
AbsolutePath = Path + 1;
|
||||
AbsolutePathLength = sizeof(WCHAR) * (ARRAYSIZE(TargetDevice) - (AbsolutePath - TargetDevice));
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_BAD_PATHNAME;
|
||||
}
|
||||
}
|
||||
/* If it's a local device */
|
||||
else if (TargetDevice == wcsstr(TargetDevice, L"\\Device\\Harddisk")
|
||||
|| TargetDevice == wcsstr(TargetDevice, L"\\Device\\CdRom")
|
||||
|| TargetDevice == wcsstr(TargetDevice, L"\\Device\\Floppy"))
|
||||
{
|
||||
/* Just query the computer name */
|
||||
if (!GetComputerNameW(ComputerName, ComputerNameLength))
|
||||
{
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
/* If it's a DFS share */
|
||||
else if (TargetDevice == wcsstr(TargetDevice, L"\\Device\\WinDfs\\"))
|
||||
{
|
||||
/* Obviously, query DFS */
|
||||
Query = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_BAD_PATHNAME;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return ERROR_BAD_PATHNAME;
|
||||
}
|
||||
|
||||
/* Query DFS, currently not implemented - shouldn't be missing in ReactOS yet ;-) */
|
||||
if (Query)
|
||||
{
|
||||
UNIMPLEMENTED_DBGBREAK("Querying DFS not implemented!\n");
|
||||
AbsolutePath = NULL;
|
||||
AbsolutePathLength = 0;
|
||||
}
|
||||
|
||||
/* Now, properly extract the computer name from the full path */
|
||||
EndOfName = AbsolutePath;
|
||||
if (AbsolutePathLength)
|
||||
{
|
||||
for (NameLength = 0; NameLength < AbsolutePathLength; NameLength += sizeof(WCHAR))
|
||||
{
|
||||
/* Look for the next \, it will be the end of computer name */
|
||||
if (EndOfName[0] == '\\')
|
||||
{
|
||||
break;
|
||||
}
|
||||
/* Computer name cannot contain ., if we get to that point, something went wrong... */
|
||||
else if (EndOfName[0] == '.')
|
||||
{
|
||||
return ERROR_BAD_PATHNAME;
|
||||
}
|
||||
|
||||
++EndOfName;
|
||||
}
|
||||
}
|
||||
|
||||
NameLength = EndOfName - AbsolutePath;
|
||||
/* Check we didn't overflow and that our computer name isn't ill-formed */
|
||||
if (NameLength >= AbsolutePathLength || NameLength >= MAX_COMPUTERNAME_LENGTH * sizeof(WCHAR))
|
||||
{
|
||||
return ERROR_BAD_PATHNAME;
|
||||
}
|
||||
|
||||
/* Check we can fit */
|
||||
if (NameLength + sizeof(UNICODE_NULL) > *ComputerNameLength * sizeof(WCHAR))
|
||||
{
|
||||
return ERROR_BUFFER_OVERFLOW;
|
||||
}
|
||||
|
||||
/* Write, zero and done! */
|
||||
RtlCopyMemory(ComputerName, AbsolutePath, NameLength);
|
||||
*ComputerNameLength = NameLength / sizeof(WCHAR);
|
||||
ComputerName[NameLength / sizeof(WCHAR)] = UNICODE_NULL;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS
|
||||
WINAPI
|
||||
BasepNotifyTrackingService(IN PHANDLE ExistingHandle,
|
||||
BasepNotifyTrackingService(IN OUT PHANDLE ExistingHandle,
|
||||
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
IN HANDLE NewHandle,
|
||||
IN PUNICODE_STRING NewPath)
|
||||
{
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
NTSTATUS Status;
|
||||
ULONG ComputerNameLength, FileAttributes;
|
||||
WCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 1];
|
||||
OEM_STRING ComputerNameStringA;
|
||||
CHAR ComputerNameStringBuffer[0x105];
|
||||
UNICODE_STRING ComputerNameStringW;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
FILE_BASIC_INFORMATION FileBasicInfo;
|
||||
HANDLE hFullWrite;
|
||||
struct
|
||||
{
|
||||
FILE_TRACKING_INFORMATION;
|
||||
CHAR Buffer[(MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR)];
|
||||
} FileTrackingInfo;
|
||||
|
||||
DPRINT("BasepNotifyTrackingService(%p, %p, %p, %wZ)\n", *ExistingHandle, ObjectAttributes, NewHandle, NewPath);
|
||||
|
||||
Status = STATUS_SUCCESS;
|
||||
ComputerNameLength = ARRAYSIZE(ComputerName);
|
||||
|
||||
/* Attempt to get computer name of target handle */
|
||||
if (BasepGetComputerNameFromNtPath(NewPath, NewHandle, ComputerName, &ComputerNameLength))
|
||||
{
|
||||
/* If we failed to get it, we will just notify with the handle */
|
||||
FileTrackingInfo.ObjectInformationLength = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Convert the retrieved computer name to ANSI and attach it to the notification */
|
||||
ComputerNameStringA.Length = 0;
|
||||
ComputerNameStringA.MaximumLength = ARRAYSIZE(ComputerNameStringBuffer);
|
||||
ComputerNameStringA.Buffer = ComputerNameStringBuffer;
|
||||
|
||||
RtlInitUnicodeString(&ComputerNameStringW, ComputerName);
|
||||
Status = RtlUnicodeStringToOemString(&ComputerNameStringA, &ComputerNameStringW, 0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
RtlCopyMemory(FileTrackingInfo.ObjectInformation, ComputerNameStringA.Buffer, ComputerNameStringA.Length);
|
||||
FileTrackingInfo.ObjectInformation[ComputerNameStringA.Length] = 0;
|
||||
FileTrackingInfo.ObjectInformationLength = ComputerNameStringA.Length + 1;
|
||||
}
|
||||
|
||||
/* Attach the handle we moved */
|
||||
FileTrackingInfo.DestinationFile = NewHandle;
|
||||
|
||||
/* Final, notify */
|
||||
Status = NtSetInformationFile(*ExistingHandle,
|
||||
&IoStatusBlock,
|
||||
&FileTrackingInfo,
|
||||
sizeof(FileTrackingInfo),
|
||||
FileTrackingInformation);
|
||||
if (Status != STATUS_ACCESS_DENIED)
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* If we get here, we got access denied error, this comes from a
|
||||
* read-only flag. So, close the file, in order to reopen it with enough
|
||||
* rights to remove said flag and reattempt notification
|
||||
*/
|
||||
CloseHandle(*ExistingHandle);
|
||||
|
||||
/* Reopen it, to be able to change the destination file attributes */
|
||||
Status = NtOpenFile(ExistingHandle,
|
||||
SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
|
||||
ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
*ExistingHandle = INVALID_HANDLE_VALUE;
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Get the file attributes */
|
||||
Status = NtQueryInformationFile(*ExistingHandle,
|
||||
&IoStatusBlock,
|
||||
&FileBasicInfo,
|
||||
sizeof(FileBasicInfo),
|
||||
FileBasicInformation);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Get rid of the read only flag */
|
||||
FileAttributes = FileBasicInfo.FileAttributes & ~FILE_ATTRIBUTE_READONLY;
|
||||
RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo));
|
||||
FileBasicInfo.FileAttributes = FileAttributes;
|
||||
|
||||
/* Attempt... */
|
||||
Status = NtSetInformationFile(*ExistingHandle,
|
||||
&IoStatusBlock,
|
||||
&FileBasicInfo,
|
||||
sizeof(FileBasicInfo),
|
||||
FileBasicInformation);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Now, reopen with maximum accesses to notify */
|
||||
Status = NtOpenFile(&hFullWrite,
|
||||
GENERIC_WRITE | SYNCHRONIZE,
|
||||
ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
FILE_SYNCHRONOUS_IO_NONALERT);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
NtClose(*ExistingHandle);
|
||||
*ExistingHandle = hFullWrite;
|
||||
|
||||
/* Full success, notify! */
|
||||
Status = NtSetInformationFile(*ExistingHandle,
|
||||
&IoStatusBlock,
|
||||
&FileTrackingInfo,
|
||||
sizeof(FileTrackingInfo),
|
||||
FileTrackingInformation);
|
||||
}
|
||||
|
||||
/* If opening with full access failed or if notify failed, restore read-only */
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
FileBasicInfo.FileAttributes |= FILE_ATTRIBUTE_READONLY;
|
||||
|
||||
Status = NtSetInformationFile(*ExistingHandle,
|
||||
&IoStatusBlock,
|
||||
&FileBasicInfo,
|
||||
sizeof(FileBasicInfo),
|
||||
FileBasicInformation);
|
||||
}
|
||||
|
||||
/* We're done */
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue