kernel32: Move some file functions to kernelbase.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
e36a9c459d
commit
b6c9401882
|
@ -415,121 +415,6 @@ BOOL WINAPI KERNEL32_FlushFileBuffers( HANDLE file )
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* ReplaceFileW (KERNEL32.@)
|
|
||||||
* ReplaceFile (KERNEL32.@)
|
|
||||||
*/
|
|
||||||
BOOL WINAPI ReplaceFileW(LPCWSTR lpReplacedFileName, LPCWSTR lpReplacementFileName,
|
|
||||||
LPCWSTR lpBackupFileName, DWORD dwReplaceFlags,
|
|
||||||
LPVOID lpExclude, LPVOID lpReserved)
|
|
||||||
{
|
|
||||||
UNICODE_STRING nt_replaced_name, nt_replacement_name;
|
|
||||||
HANDLE hReplacement = NULL;
|
|
||||||
NTSTATUS status;
|
|
||||||
IO_STATUS_BLOCK io;
|
|
||||||
OBJECT_ATTRIBUTES attr;
|
|
||||||
FILE_BASIC_INFORMATION info;
|
|
||||||
|
|
||||||
TRACE("%s %s %s 0x%08x %p %p\n", debugstr_w(lpReplacedFileName),
|
|
||||||
debugstr_w(lpReplacementFileName), debugstr_w(lpBackupFileName),
|
|
||||||
dwReplaceFlags, lpExclude, lpReserved);
|
|
||||||
|
|
||||||
if (dwReplaceFlags)
|
|
||||||
FIXME("Ignoring flags %x\n", dwReplaceFlags);
|
|
||||||
|
|
||||||
/* First two arguments are mandatory */
|
|
||||||
if (!lpReplacedFileName || !lpReplacementFileName)
|
|
||||||
{
|
|
||||||
SetLastError(ERROR_INVALID_PARAMETER);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
attr.Length = sizeof(attr);
|
|
||||||
attr.RootDirectory = 0;
|
|
||||||
attr.Attributes = OBJ_CASE_INSENSITIVE;
|
|
||||||
attr.ObjectName = NULL;
|
|
||||||
attr.SecurityDescriptor = NULL;
|
|
||||||
attr.SecurityQualityOfService = NULL;
|
|
||||||
|
|
||||||
/* Open the "replaced" file for reading */
|
|
||||||
if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName, &nt_replaced_name, NULL, NULL)))
|
|
||||||
{
|
|
||||||
SetLastError( ERROR_PATH_NOT_FOUND );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
attr.ObjectName = &nt_replaced_name;
|
|
||||||
|
|
||||||
/* Replacement should fail if replaced is READ_ONLY */
|
|
||||||
status = NtQueryAttributesFile(&attr, &info);
|
|
||||||
RtlFreeUnicodeString(&nt_replaced_name);
|
|
||||||
if (status != STATUS_SUCCESS)
|
|
||||||
return set_ntstatus( status );
|
|
||||||
|
|
||||||
if (info.FileAttributes & FILE_ATTRIBUTE_READONLY)
|
|
||||||
{
|
|
||||||
SetLastError( ERROR_ACCESS_DENIED );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Open the replacement file for reading, writing, and deleting
|
|
||||||
* (writing and deleting are needed when finished)
|
|
||||||
*/
|
|
||||||
if (!(RtlDosPathNameToNtPathName_U(lpReplacementFileName, &nt_replacement_name, NULL, NULL)))
|
|
||||||
{
|
|
||||||
SetLastError( ERROR_PATH_NOT_FOUND );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
attr.ObjectName = &nt_replacement_name;
|
|
||||||
status = NtOpenFile(&hReplacement,
|
|
||||||
GENERIC_READ|GENERIC_WRITE|DELETE|WRITE_DAC|SYNCHRONIZE,
|
|
||||||
&attr, &io, 0,
|
|
||||||
FILE_SYNCHRONOUS_IO_NONALERT|FILE_NON_DIRECTORY_FILE);
|
|
||||||
RtlFreeUnicodeString(&nt_replacement_name);
|
|
||||||
if (status != STATUS_SUCCESS)
|
|
||||||
return set_ntstatus( status );
|
|
||||||
NtClose( hReplacement );
|
|
||||||
|
|
||||||
/* If the user wants a backup then that needs to be performed first */
|
|
||||||
if (lpBackupFileName)
|
|
||||||
{
|
|
||||||
if (!MoveFileExW( lpReplacedFileName, lpBackupFileName, MOVEFILE_REPLACE_EXISTING ))
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* ReplaceFile() can replace an open target. To do this, we need to move
|
|
||||||
* it out of the way first. */
|
|
||||||
static const WCHAR prefixW[] = {'r','f',0};
|
|
||||||
WCHAR temp_path[MAX_PATH], temp_file[MAX_PATH];
|
|
||||||
|
|
||||||
lstrcpynW( temp_path, lpReplacedFileName, ARRAY_SIZE( temp_path ) );
|
|
||||||
PathRemoveFileSpecW( temp_path );
|
|
||||||
if (!GetTempFileNameW( temp_path, prefixW, 0, temp_file )
|
|
||||||
|| !MoveFileExW( lpReplacedFileName, temp_file, MOVEFILE_REPLACE_EXISTING ))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
DeleteFileW( temp_file );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now that the backup has been performed (if requested), copy the replacement
|
|
||||||
* into place
|
|
||||||
*/
|
|
||||||
if (!MoveFileExW( lpReplacementFileName, lpReplacedFileName, 0 ))
|
|
||||||
{
|
|
||||||
/* on failure we need to indicate whether a backup was made */
|
|
||||||
if (!lpBackupFileName)
|
|
||||||
SetLastError( ERROR_UNABLE_TO_MOVE_REPLACEMENT );
|
|
||||||
else
|
|
||||||
SetLastError( ERROR_UNABLE_TO_MOVE_REPLACEMENT_2 );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* ReplaceFileA (KERNEL32.@)
|
* ReplaceFileA (KERNEL32.@)
|
||||||
*/
|
*/
|
||||||
|
@ -865,214 +750,3 @@ DWORD WINAPI K32GetDeviceDriverFileNameW(void *image_base, LPWSTR file_name, DWO
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* GetFinalPathNameByHandleW (KERNEL32.@)
|
|
||||||
*/
|
|
||||||
DWORD WINAPI GetFinalPathNameByHandleW(HANDLE file, LPWSTR path, DWORD charcount, DWORD flags)
|
|
||||||
{
|
|
||||||
WCHAR buffer[sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH + 1];
|
|
||||||
OBJECT_NAME_INFORMATION *info = (OBJECT_NAME_INFORMATION*)&buffer;
|
|
||||||
WCHAR drive_part[MAX_PATH];
|
|
||||||
DWORD drive_part_len = 0;
|
|
||||||
NTSTATUS status;
|
|
||||||
DWORD result = 0;
|
|
||||||
ULONG dummy;
|
|
||||||
WCHAR *ptr;
|
|
||||||
|
|
||||||
TRACE( "(%p,%p,%d,%x)\n", file, path, charcount, flags );
|
|
||||||
|
|
||||||
if (flags & ~(FILE_NAME_OPENED | VOLUME_NAME_GUID | VOLUME_NAME_NONE | VOLUME_NAME_NT))
|
|
||||||
{
|
|
||||||
WARN("Unknown flags: %x\n", flags);
|
|
||||||
SetLastError( ERROR_INVALID_PARAMETER );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get object name */
|
|
||||||
status = NtQueryObject( file, ObjectNameInformation, &buffer, sizeof(buffer) - sizeof(WCHAR), &dummy );
|
|
||||||
if (status != STATUS_SUCCESS)
|
|
||||||
{
|
|
||||||
SetLastError( RtlNtStatusToDosError( status ) );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (!info->Name.Buffer)
|
|
||||||
{
|
|
||||||
SetLastError( ERROR_INVALID_HANDLE );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (info->Name.Length < 4 * sizeof(WCHAR) || info->Name.Buffer[0] != '\\' ||
|
|
||||||
info->Name.Buffer[1] != '?' || info->Name.Buffer[2] != '?' || info->Name.Buffer[3] != '\\' )
|
|
||||||
{
|
|
||||||
FIXME("Unexpected object name: %s\n", debugstr_wn(info->Name.Buffer, info->Name.Length / sizeof(WCHAR)));
|
|
||||||
SetLastError( ERROR_GEN_FAILURE );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add terminating null character, remove "\\??\\" */
|
|
||||||
info->Name.Buffer[info->Name.Length / sizeof(WCHAR)] = 0;
|
|
||||||
info->Name.Length -= 4 * sizeof(WCHAR);
|
|
||||||
info->Name.Buffer += 4;
|
|
||||||
|
|
||||||
/* FILE_NAME_OPENED is not supported yet, and would require Wineserver changes */
|
|
||||||
if (flags & FILE_NAME_OPENED)
|
|
||||||
{
|
|
||||||
FIXME("FILE_NAME_OPENED not supported\n");
|
|
||||||
flags &= ~FILE_NAME_OPENED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get information required for VOLUME_NAME_NONE, VOLUME_NAME_GUID and VOLUME_NAME_NT */
|
|
||||||
if (flags == VOLUME_NAME_NONE || flags == VOLUME_NAME_GUID || flags == VOLUME_NAME_NT)
|
|
||||||
{
|
|
||||||
if (!GetVolumePathNameW( info->Name.Buffer, drive_part, MAX_PATH ))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
drive_part_len = strlenW(drive_part);
|
|
||||||
if (!drive_part_len || drive_part_len > strlenW(info->Name.Buffer) ||
|
|
||||||
drive_part[drive_part_len-1] != '\\' ||
|
|
||||||
strncmpiW( info->Name.Buffer, drive_part, drive_part_len ))
|
|
||||||
{
|
|
||||||
FIXME("Path %s returned by GetVolumePathNameW does not match file path %s\n",
|
|
||||||
debugstr_w(drive_part), debugstr_w(info->Name.Buffer));
|
|
||||||
SetLastError( ERROR_GEN_FAILURE );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags == VOLUME_NAME_NONE)
|
|
||||||
{
|
|
||||||
ptr = info->Name.Buffer + drive_part_len - 1;
|
|
||||||
result = strlenW(ptr);
|
|
||||||
if (result < charcount)
|
|
||||||
memcpy(path, ptr, (result + 1) * sizeof(WCHAR));
|
|
||||||
else result++;
|
|
||||||
}
|
|
||||||
else if (flags == VOLUME_NAME_GUID)
|
|
||||||
{
|
|
||||||
WCHAR volume_prefix[51];
|
|
||||||
|
|
||||||
/* GetVolumeNameForVolumeMountPointW sets error code on failure */
|
|
||||||
if (!GetVolumeNameForVolumeMountPointW( drive_part, volume_prefix, 50 ))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ptr = info->Name.Buffer + drive_part_len;
|
|
||||||
result = strlenW(volume_prefix) + strlenW(ptr);
|
|
||||||
if (result < charcount)
|
|
||||||
{
|
|
||||||
path[0] = 0;
|
|
||||||
strcatW(path, volume_prefix);
|
|
||||||
strcatW(path, ptr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
||||||
result++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (flags == VOLUME_NAME_NT)
|
|
||||||
{
|
|
||||||
WCHAR nt_prefix[MAX_PATH];
|
|
||||||
|
|
||||||
/* QueryDosDeviceW sets error code on failure */
|
|
||||||
drive_part[drive_part_len - 1] = 0;
|
|
||||||
if (!QueryDosDeviceW( drive_part, nt_prefix, MAX_PATH ))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ptr = info->Name.Buffer + drive_part_len - 1;
|
|
||||||
result = strlenW(nt_prefix) + strlenW(ptr);
|
|
||||||
if (result < charcount)
|
|
||||||
{
|
|
||||||
path[0] = 0;
|
|
||||||
strcatW(path, nt_prefix);
|
|
||||||
strcatW(path, ptr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
||||||
result++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (flags == VOLUME_NAME_DOS)
|
|
||||||
{
|
|
||||||
static const WCHAR dos_prefix[] = {'\\','\\','?','\\', '\0'};
|
|
||||||
|
|
||||||
result = strlenW(dos_prefix) + strlenW(info->Name.Buffer);
|
|
||||||
if (result < charcount)
|
|
||||||
{
|
|
||||||
path[0] = 0;
|
|
||||||
strcatW(path, dos_prefix);
|
|
||||||
strcatW(path, info->Name.Buffer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
||||||
result++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Windows crashes here, but we prefer returning ERROR_INVALID_PARAMETER */
|
|
||||||
WARN("Invalid combination of flags: %x\n", flags);
|
|
||||||
SetLastError( ERROR_INVALID_PARAMETER );
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* GetFinalPathNameByHandleA (KERNEL32.@)
|
|
||||||
*/
|
|
||||||
DWORD WINAPI GetFinalPathNameByHandleA(HANDLE file, LPSTR path, DWORD charcount, DWORD flags)
|
|
||||||
{
|
|
||||||
WCHAR *str;
|
|
||||||
DWORD result, len, cp;
|
|
||||||
|
|
||||||
TRACE( "(%p,%p,%d,%x)\n", file, path, charcount, flags);
|
|
||||||
|
|
||||||
len = GetFinalPathNameByHandleW(file, NULL, 0, flags);
|
|
||||||
if (len == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
|
||||||
if (!str)
|
|
||||||
{
|
|
||||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = GetFinalPathNameByHandleW(file, str, len, flags);
|
|
||||||
if (result != len - 1)
|
|
||||||
{
|
|
||||||
HeapFree(GetProcessHeap(), 0, str);
|
|
||||||
WARN("GetFinalPathNameByHandleW failed unexpectedly: %u\n", result);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
cp = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
|
|
||||||
|
|
||||||
len = WideCharToMultiByte(cp, 0, str, -1, NULL, 0, NULL, NULL);
|
|
||||||
if (!len)
|
|
||||||
{
|
|
||||||
HeapFree(GetProcessHeap(), 0, str);
|
|
||||||
WARN("Failed to get multibyte length\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (charcount < len)
|
|
||||||
{
|
|
||||||
HeapFree(GetProcessHeap(), 0, str);
|
|
||||||
return len - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = WideCharToMultiByte(cp, 0, str, -1, path, charcount, NULL, NULL);
|
|
||||||
if (!len)
|
|
||||||
{
|
|
||||||
HeapFree(GetProcessHeap(), 0, str);
|
|
||||||
WARN("WideCharToMultiByte failed\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
HeapFree(GetProcessHeap(), 0, str);
|
|
||||||
|
|
||||||
return len - 1;
|
|
||||||
}
|
|
||||||
|
|
|
@ -258,10 +258,10 @@
|
||||||
# @ stub CopyContext
|
# @ stub CopyContext
|
||||||
@ stdcall CopyFileA(str str long)
|
@ stdcall CopyFileA(str str long)
|
||||||
@ stdcall CopyFileExA (str str ptr ptr ptr long)
|
@ stdcall CopyFileExA (str str ptr ptr ptr long)
|
||||||
@ stdcall CopyFileExW (wstr wstr ptr ptr ptr long)
|
@ stdcall -import CopyFileExW(wstr wstr ptr ptr ptr long)
|
||||||
# @ stub CopyFileTransactedA
|
# @ stub CopyFileTransactedA
|
||||||
# @ stub CopyFileTransactedW
|
# @ stub CopyFileTransactedW
|
||||||
@ stdcall CopyFileW(wstr wstr long)
|
@ stdcall -import CopyFileW(wstr wstr long)
|
||||||
@ stdcall CopyLZFile(long long) LZCopy
|
@ stdcall CopyLZFile(long long) LZCopy
|
||||||
@ stdcall CreateActCtxA(ptr)
|
@ stdcall CreateActCtxA(ptr)
|
||||||
@ stdcall -import CreateActCtxW(ptr)
|
@ stdcall -import CreateActCtxW(ptr)
|
||||||
|
@ -287,10 +287,10 @@
|
||||||
@ stdcall -import CreateFileMappingNumaW(long ptr long long long wstr long)
|
@ stdcall -import CreateFileMappingNumaW(long ptr long long long wstr long)
|
||||||
@ stdcall -import CreateFileMappingW(long ptr long long long wstr)
|
@ stdcall -import CreateFileMappingW(long ptr long long long wstr)
|
||||||
@ stdcall -import CreateFileW(wstr long long ptr long long long)
|
@ stdcall -import CreateFileW(wstr long long ptr long long long)
|
||||||
@ stdcall CreateHardLinkA(str str ptr)
|
@ stdcall -import CreateHardLinkA(str str ptr)
|
||||||
@ stdcall CreateHardLinkTransactedA(str str ptr ptr)
|
@ stdcall CreateHardLinkTransactedA(str str ptr ptr)
|
||||||
@ stdcall CreateHardLinkTransactedW(wstr wstr ptr ptr)
|
@ stdcall CreateHardLinkTransactedW(wstr wstr ptr ptr)
|
||||||
@ stdcall CreateHardLinkW(wstr wstr ptr)
|
@ stdcall -import CreateHardLinkW(wstr wstr ptr)
|
||||||
@ stdcall -import CreateIoCompletionPort(long long long long)
|
@ stdcall -import CreateIoCompletionPort(long long long long)
|
||||||
@ stdcall CreateJobObjectA(ptr str)
|
@ stdcall CreateJobObjectA(ptr str)
|
||||||
@ stdcall CreateJobObjectW(ptr wstr)
|
@ stdcall CreateJobObjectW(ptr wstr)
|
||||||
|
@ -326,7 +326,7 @@
|
||||||
@ stdcall CreateSymbolicLinkA(str str long)
|
@ stdcall CreateSymbolicLinkA(str str long)
|
||||||
# @ stub CreateSymbolicLinkTransactedA
|
# @ stub CreateSymbolicLinkTransactedA
|
||||||
# @ stub CreateSymbolicLinkTransactedW
|
# @ stub CreateSymbolicLinkTransactedW
|
||||||
@ stdcall CreateSymbolicLinkW(wstr wstr long)
|
@ stdcall -import CreateSymbolicLinkW(wstr wstr long)
|
||||||
@ stdcall CreateTapePartition(long long long long)
|
@ stdcall CreateTapePartition(long long long long)
|
||||||
@ stdcall -import CreateThread(ptr long ptr long long ptr)
|
@ stdcall -import CreateThread(ptr long ptr long long ptr)
|
||||||
@ stdcall -import CreateThreadpool(ptr)
|
@ stdcall -import CreateThreadpool(ptr)
|
||||||
|
@ -684,8 +684,8 @@
|
||||||
@ stdcall -import GetFileSizeEx(long ptr)
|
@ stdcall -import GetFileSizeEx(long ptr)
|
||||||
@ stdcall -import GetFileTime(long ptr ptr ptr)
|
@ stdcall -import GetFileTime(long ptr ptr ptr)
|
||||||
@ stdcall -import GetFileType(long)
|
@ stdcall -import GetFileType(long)
|
||||||
@ stdcall GetFinalPathNameByHandleA(long ptr long long)
|
@ stdcall -import GetFinalPathNameByHandleA(long ptr long long)
|
||||||
@ stdcall GetFinalPathNameByHandleW(long ptr long long)
|
@ stdcall -import GetFinalPathNameByHandleW(long ptr long long)
|
||||||
@ stdcall GetFirmwareEnvironmentVariableA(str str ptr long)
|
@ stdcall GetFirmwareEnvironmentVariableA(str str ptr long)
|
||||||
@ stdcall GetFirmwareEnvironmentVariableW(wstr wstr ptr long)
|
@ stdcall GetFirmwareEnvironmentVariableW(wstr wstr ptr long)
|
||||||
@ stdcall -import GetFullPathNameA(str long ptr ptr)
|
@ stdcall -import GetFullPathNameA(str long ptr ptr)
|
||||||
|
@ -1091,12 +1091,12 @@
|
||||||
@ stdcall Module32NextW(long ptr)
|
@ stdcall Module32NextW(long ptr)
|
||||||
@ stdcall MoveFileA(str str)
|
@ stdcall MoveFileA(str str)
|
||||||
@ stdcall MoveFileExA(str str long)
|
@ stdcall MoveFileExA(str str long)
|
||||||
@ stdcall MoveFileExW(wstr wstr long)
|
@ stdcall -import MoveFileExW(wstr wstr long)
|
||||||
@ stdcall MoveFileTransactedA(str str ptr ptr long ptr)
|
@ stdcall MoveFileTransactedA(str str ptr ptr long ptr)
|
||||||
@ stdcall MoveFileTransactedW(wstr wstr ptr ptr long ptr)
|
@ stdcall MoveFileTransactedW(wstr wstr ptr ptr long ptr)
|
||||||
@ stdcall MoveFileW(wstr wstr)
|
@ stdcall MoveFileW(wstr wstr)
|
||||||
@ stdcall MoveFileWithProgressA(str str ptr ptr long)
|
@ stdcall MoveFileWithProgressA(str str ptr ptr long)
|
||||||
@ stdcall MoveFileWithProgressW(wstr wstr ptr ptr long)
|
@ stdcall -import MoveFileWithProgressW(wstr wstr ptr ptr long)
|
||||||
@ stdcall MulDiv(long long long)
|
@ stdcall MulDiv(long long long)
|
||||||
@ stdcall -import MultiByteToWideChar(long long str long ptr long)
|
@ stdcall -import MultiByteToWideChar(long long str long ptr long)
|
||||||
@ stdcall -import NeedCurrentDirectoryForExePathA(str)
|
@ stdcall -import NeedCurrentDirectoryForExePathA(str)
|
||||||
|
@ -1273,9 +1273,9 @@
|
||||||
@ stdcall RemoveVectoredContinueHandler(ptr) ntdll.RtlRemoveVectoredContinueHandler
|
@ stdcall RemoveVectoredContinueHandler(ptr) ntdll.RtlRemoveVectoredContinueHandler
|
||||||
@ stdcall RemoveVectoredExceptionHandler(ptr) ntdll.RtlRemoveVectoredExceptionHandler
|
@ stdcall RemoveVectoredExceptionHandler(ptr) ntdll.RtlRemoveVectoredExceptionHandler
|
||||||
@ stdcall -import ReOpenFile(ptr long long long) ReOpenFile
|
@ stdcall -import ReOpenFile(ptr long long long) ReOpenFile
|
||||||
@ stdcall ReplaceFile(wstr wstr wstr long ptr ptr) ReplaceFileW
|
@ stdcall -import ReplaceFile(wstr wstr wstr long ptr ptr) ReplaceFileW
|
||||||
@ stdcall ReplaceFileA(str str str long ptr ptr)
|
@ stdcall ReplaceFileA(str str str long ptr ptr)
|
||||||
@ stdcall ReplaceFileW(wstr wstr wstr long ptr ptr)
|
@ stdcall -import ReplaceFileW(wstr wstr wstr long ptr ptr)
|
||||||
# @ stub RemoveDirectoryTransactedA
|
# @ stub RemoveDirectoryTransactedA
|
||||||
# @ stub RemoveDirectoryTransactedW
|
# @ stub RemoveDirectoryTransactedW
|
||||||
@ stdcall -import RemoveDllDirectory(ptr)
|
@ stdcall -import RemoveDllDirectory(ptr)
|
||||||
|
|
|
@ -72,153 +72,6 @@ static DWORD copy_filename_WtoA( LPCWSTR nameW, LPSTR buffer, DWORD len )
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* add_boot_rename_entry
|
|
||||||
*
|
|
||||||
* Adds an entry to the registry that is loaded when windows boots and
|
|
||||||
* checks if there are some files to be removed or renamed/moved.
|
|
||||||
* <fn1> has to be valid and <fn2> may be NULL. If both pointers are
|
|
||||||
* non-NULL then the file is moved, otherwise it is deleted. The
|
|
||||||
* entry of the registry key is always appended with two zero
|
|
||||||
* terminated strings. If <fn2> is NULL then the second entry is
|
|
||||||
* simply a single 0-byte. Otherwise the second filename goes
|
|
||||||
* there. The entries are prepended with \??\ before the path and the
|
|
||||||
* second filename gets also a '!' as the first character if
|
|
||||||
* MOVEFILE_REPLACE_EXISTING is set. After the final string another
|
|
||||||
* 0-byte follows to indicate the end of the strings.
|
|
||||||
* i.e.:
|
|
||||||
* \??\D:\test\file1[0]
|
|
||||||
* !\??\D:\test\file1_renamed[0]
|
|
||||||
* \??\D:\Test|delete[0]
|
|
||||||
* [0] <- file is to be deleted, second string empty
|
|
||||||
* \??\D:\test\file2[0]
|
|
||||||
* !\??\D:\test\file2_renamed[0]
|
|
||||||
* [0] <- indicates end of strings
|
|
||||||
*
|
|
||||||
* or:
|
|
||||||
* \??\D:\test\file1[0]
|
|
||||||
* !\??\D:\test\file1_renamed[0]
|
|
||||||
* \??\D:\Test|delete[0]
|
|
||||||
* [0] <- file is to be deleted, second string empty
|
|
||||||
* [0] <- indicates end of strings
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static BOOL add_boot_rename_entry( LPCWSTR source, LPCWSTR dest, DWORD flags )
|
|
||||||
{
|
|
||||||
static const WCHAR ValueName[] = {'P','e','n','d','i','n','g',
|
|
||||||
'F','i','l','e','R','e','n','a','m','e',
|
|
||||||
'O','p','e','r','a','t','i','o','n','s',0};
|
|
||||||
static const WCHAR SessionW[] = {'\\','R','e','g','i','s','t','r','y','\\',
|
|
||||||
'M','a','c','h','i','n','e','\\',
|
|
||||||
'S','y','s','t','e','m','\\',
|
|
||||||
'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
|
|
||||||
'C','o','n','t','r','o','l','\\',
|
|
||||||
'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
|
|
||||||
static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
|
|
||||||
|
|
||||||
OBJECT_ATTRIBUTES attr;
|
|
||||||
UNICODE_STRING nameW, source_name, dest_name;
|
|
||||||
KEY_VALUE_PARTIAL_INFORMATION *info;
|
|
||||||
BOOL rc = FALSE;
|
|
||||||
HANDLE Reboot = 0;
|
|
||||||
DWORD len1, len2;
|
|
||||||
DWORD DataSize = 0;
|
|
||||||
BYTE *Buffer = NULL;
|
|
||||||
WCHAR *p;
|
|
||||||
|
|
||||||
if (!RtlDosPathNameToNtPathName_U( source, &source_name, NULL, NULL ))
|
|
||||||
{
|
|
||||||
SetLastError( ERROR_PATH_NOT_FOUND );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
dest_name.Buffer = NULL;
|
|
||||||
if (dest && !RtlDosPathNameToNtPathName_U( dest, &dest_name, NULL, NULL ))
|
|
||||||
{
|
|
||||||
RtlFreeUnicodeString( &source_name );
|
|
||||||
SetLastError( ERROR_PATH_NOT_FOUND );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
attr.Length = sizeof(attr);
|
|
||||||
attr.RootDirectory = 0;
|
|
||||||
attr.ObjectName = &nameW;
|
|
||||||
attr.Attributes = 0;
|
|
||||||
attr.SecurityDescriptor = NULL;
|
|
||||||
attr.SecurityQualityOfService = NULL;
|
|
||||||
RtlInitUnicodeString( &nameW, SessionW );
|
|
||||||
|
|
||||||
if (NtCreateKey( &Reboot, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
|
|
||||||
{
|
|
||||||
WARN("Error creating key for reboot management [%s]\n",
|
|
||||||
"SYSTEM\\CurrentControlSet\\Control\\Session Manager");
|
|
||||||
RtlFreeUnicodeString( &source_name );
|
|
||||||
RtlFreeUnicodeString( &dest_name );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
len1 = source_name.Length + sizeof(WCHAR);
|
|
||||||
if (dest)
|
|
||||||
{
|
|
||||||
len2 = dest_name.Length + sizeof(WCHAR);
|
|
||||||
if (flags & MOVEFILE_REPLACE_EXISTING)
|
|
||||||
len2 += sizeof(WCHAR); /* Plus 1 because of the leading '!' */
|
|
||||||
}
|
|
||||||
else len2 = sizeof(WCHAR); /* minimum is the 0 characters for the empty second string */
|
|
||||||
|
|
||||||
RtlInitUnicodeString( &nameW, ValueName );
|
|
||||||
|
|
||||||
/* First we check if the key exists and if so how many bytes it already contains. */
|
|
||||||
if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
|
|
||||||
NULL, 0, &DataSize ) == STATUS_BUFFER_TOO_SMALL)
|
|
||||||
{
|
|
||||||
if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
|
|
||||||
goto Quit;
|
|
||||||
if (NtQueryValueKey( Reboot, &nameW, KeyValuePartialInformation,
|
|
||||||
Buffer, DataSize, &DataSize )) goto Quit;
|
|
||||||
info = (KEY_VALUE_PARTIAL_INFORMATION *)Buffer;
|
|
||||||
if (info->Type != REG_MULTI_SZ) goto Quit;
|
|
||||||
if (DataSize > sizeof(info)) DataSize -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DataSize = info_size;
|
|
||||||
if (!(Buffer = HeapAlloc( GetProcessHeap(), 0, DataSize + len1 + len2 + sizeof(WCHAR) )))
|
|
||||||
goto Quit;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy( Buffer + DataSize, source_name.Buffer, len1 );
|
|
||||||
DataSize += len1;
|
|
||||||
p = (WCHAR *)(Buffer + DataSize);
|
|
||||||
if (dest)
|
|
||||||
{
|
|
||||||
if (flags & MOVEFILE_REPLACE_EXISTING)
|
|
||||||
*p++ = '!';
|
|
||||||
memcpy( p, dest_name.Buffer, len2 );
|
|
||||||
DataSize += len2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*p = 0;
|
|
||||||
DataSize += sizeof(WCHAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add final null */
|
|
||||||
p = (WCHAR *)(Buffer + DataSize);
|
|
||||||
*p = 0;
|
|
||||||
DataSize += sizeof(WCHAR);
|
|
||||||
|
|
||||||
rc = !NtSetValueKey(Reboot, &nameW, 0, REG_MULTI_SZ, Buffer + info_size, DataSize - info_size);
|
|
||||||
|
|
||||||
Quit:
|
|
||||||
RtlFreeUnicodeString( &source_name );
|
|
||||||
RtlFreeUnicodeString( &dest_name );
|
|
||||||
if (Reboot) NtClose(Reboot);
|
|
||||||
HeapFree( GetProcessHeap(), 0, Buffer );
|
|
||||||
return(rc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* GetShortPathNameA (KERNEL32.@)
|
* GetShortPathNameA (KERNEL32.@)
|
||||||
*/
|
*/
|
||||||
|
@ -244,26 +97,6 @@ DWORD WINAPI GetShortPathNameA( LPCSTR longpath, LPSTR shortpath, DWORD shortlen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static BOOL is_same_file(HANDLE h1, HANDLE h2)
|
|
||||||
{
|
|
||||||
FILE_ID_INFORMATION id1, id2;
|
|
||||||
IO_STATUS_BLOCK io;
|
|
||||||
|
|
||||||
return !NtQueryInformationFile( h1, &io, &id1, sizeof(id1), FileIdInformation )
|
|
||||||
&& !NtQueryInformationFile( h2, &io, &id2, sizeof(id2), FileIdInformation )
|
|
||||||
&& !memcmp( &id1, &id2, sizeof(FILE_ID_INFORMATION) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* CopyFileW (KERNEL32.@)
|
|
||||||
*/
|
|
||||||
BOOL WINAPI CopyFileW( LPCWSTR source, LPCWSTR dest, BOOL fail_if_exists )
|
|
||||||
{
|
|
||||||
return CopyFileExW( source, dest, NULL, NULL, NULL,
|
|
||||||
fail_if_exists ? COPY_FILE_FAIL_IF_EXISTS : 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* CopyFileA (KERNEL32.@)
|
* CopyFileA (KERNEL32.@)
|
||||||
*/
|
*/
|
||||||
|
@ -282,101 +115,6 @@ BOOL WINAPI CopyFileA( LPCSTR source, LPCSTR dest, BOOL fail_if_exists)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* CopyFileExW (KERNEL32.@)
|
|
||||||
*/
|
|
||||||
BOOL WINAPI CopyFileExW(LPCWSTR source, LPCWSTR dest,
|
|
||||||
LPPROGRESS_ROUTINE progress, LPVOID param,
|
|
||||||
LPBOOL cancel_ptr, DWORD flags)
|
|
||||||
{
|
|
||||||
static const int buffer_size = 65536;
|
|
||||||
HANDLE h1, h2;
|
|
||||||
BY_HANDLE_FILE_INFORMATION info;
|
|
||||||
DWORD count;
|
|
||||||
BOOL ret = FALSE;
|
|
||||||
char *buffer;
|
|
||||||
|
|
||||||
if (!source || !dest)
|
|
||||||
{
|
|
||||||
SetLastError(ERROR_INVALID_PARAMETER);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
if (!(buffer = HeapAlloc( GetProcessHeap(), 0, buffer_size )))
|
|
||||||
{
|
|
||||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE("%s -> %s, %x\n", debugstr_w(source), debugstr_w(dest), flags);
|
|
||||||
|
|
||||||
if ((h1 = CreateFileW(source, GENERIC_READ,
|
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
||||||
NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
WARN("Unable to open source %s\n", debugstr_w(source));
|
|
||||||
HeapFree( GetProcessHeap(), 0, buffer );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!GetFileInformationByHandle( h1, &info ))
|
|
||||||
{
|
|
||||||
WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
|
|
||||||
HeapFree( GetProcessHeap(), 0, buffer );
|
|
||||||
CloseHandle( h1 );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(flags & COPY_FILE_FAIL_IF_EXISTS))
|
|
||||||
{
|
|
||||||
BOOL same_file = FALSE;
|
|
||||||
h2 = CreateFileW( dest, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
|
||||||
OPEN_EXISTING, 0, 0);
|
|
||||||
if (h2 != INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
same_file = is_same_file( h1, h2 );
|
|
||||||
CloseHandle( h2 );
|
|
||||||
}
|
|
||||||
if (same_file)
|
|
||||||
{
|
|
||||||
HeapFree( GetProcessHeap(), 0, buffer );
|
|
||||||
CloseHandle( h1 );
|
|
||||||
SetLastError( ERROR_SHARING_VIOLATION );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
|
||||||
(flags & COPY_FILE_FAIL_IF_EXISTS) ? CREATE_NEW : CREATE_ALWAYS,
|
|
||||||
info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
WARN("Unable to open dest %s\n", debugstr_w(dest));
|
|
||||||
HeapFree( GetProcessHeap(), 0, buffer );
|
|
||||||
CloseHandle( h1 );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (ReadFile( h1, buffer, buffer_size, &count, NULL ) && count)
|
|
||||||
{
|
|
||||||
char *p = buffer;
|
|
||||||
while (count != 0)
|
|
||||||
{
|
|
||||||
DWORD res;
|
|
||||||
if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
|
|
||||||
p += res;
|
|
||||||
count -= res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret = TRUE;
|
|
||||||
done:
|
|
||||||
/* Maintain the timestamp of source file to destination file */
|
|
||||||
SetFileTime(h2, NULL, NULL, &info.ftLastWriteTime);
|
|
||||||
HeapFree( GetProcessHeap(), 0, buffer );
|
|
||||||
CloseHandle( h1 );
|
|
||||||
CloseHandle( h2 );
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* CopyFileExA (KERNEL32.@)
|
* CopyFileExA (KERNEL32.@)
|
||||||
*/
|
*/
|
||||||
|
@ -421,95 +159,6 @@ BOOL WINAPI MoveFileTransactedW(const WCHAR *source, const WCHAR *dest, LPPROGRE
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* MoveFileWithProgressW (KERNEL32.@)
|
|
||||||
*/
|
|
||||||
BOOL WINAPI MoveFileWithProgressW( LPCWSTR source, LPCWSTR dest,
|
|
||||||
LPPROGRESS_ROUTINE fnProgress,
|
|
||||||
LPVOID param, DWORD flag )
|
|
||||||
{
|
|
||||||
FILE_RENAME_INFORMATION *rename_info;
|
|
||||||
FILE_BASIC_INFORMATION info;
|
|
||||||
UNICODE_STRING nt_name;
|
|
||||||
OBJECT_ATTRIBUTES attr;
|
|
||||||
IO_STATUS_BLOCK io;
|
|
||||||
NTSTATUS status;
|
|
||||||
HANDLE source_handle = 0;
|
|
||||||
ULONG size;
|
|
||||||
|
|
||||||
TRACE("(%s,%s,%p,%p,%04x)\n",
|
|
||||||
debugstr_w(source), debugstr_w(dest), fnProgress, param, flag );
|
|
||||||
|
|
||||||
if (flag & MOVEFILE_DELAY_UNTIL_REBOOT)
|
|
||||||
return add_boot_rename_entry( source, dest, flag );
|
|
||||||
|
|
||||||
if (!dest)
|
|
||||||
return DeleteFileW( source );
|
|
||||||
|
|
||||||
/* check if we are allowed to rename the source */
|
|
||||||
|
|
||||||
if (!RtlDosPathNameToNtPathName_U( source, &nt_name, NULL, NULL ))
|
|
||||||
{
|
|
||||||
SetLastError( ERROR_PATH_NOT_FOUND );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
attr.Length = sizeof(attr);
|
|
||||||
attr.RootDirectory = 0;
|
|
||||||
attr.Attributes = OBJ_CASE_INSENSITIVE;
|
|
||||||
attr.ObjectName = &nt_name;
|
|
||||||
attr.SecurityDescriptor = NULL;
|
|
||||||
attr.SecurityQualityOfService = NULL;
|
|
||||||
|
|
||||||
status = NtOpenFile( &source_handle, DELETE | SYNCHRONIZE, &attr, &io,
|
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT );
|
|
||||||
RtlFreeUnicodeString( &nt_name );
|
|
||||||
if (status != STATUS_SUCCESS)
|
|
||||||
{
|
|
||||||
SetLastError( RtlNtStatusToDosError(status) );
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
status = NtQueryInformationFile( source_handle, &io, &info, sizeof(info), FileBasicInformation );
|
|
||||||
if (status != STATUS_SUCCESS)
|
|
||||||
{
|
|
||||||
SetLastError( RtlNtStatusToDosError(status) );
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!RtlDosPathNameToNtPathName_U( dest, &nt_name, NULL, NULL ))
|
|
||||||
{
|
|
||||||
SetLastError( ERROR_PATH_NOT_FOUND );
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
size = offsetof( FILE_RENAME_INFORMATION, FileName ) + nt_name.Length;
|
|
||||||
if (!(rename_info = HeapAlloc( GetProcessHeap(), 0, size )))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
rename_info->ReplaceIfExists = !!(flag & MOVEFILE_REPLACE_EXISTING);
|
|
||||||
rename_info->RootDirectory = NULL;
|
|
||||||
rename_info->FileNameLength = nt_name.Length;
|
|
||||||
memcpy( rename_info->FileName, nt_name.Buffer, nt_name.Length );
|
|
||||||
RtlFreeUnicodeString( &nt_name );
|
|
||||||
status = NtSetInformationFile( source_handle, &io, rename_info, size, FileRenameInformation );
|
|
||||||
HeapFree( GetProcessHeap(), 0, rename_info );
|
|
||||||
if (status == STATUS_NOT_SAME_DEVICE && (flag & MOVEFILE_COPY_ALLOWED))
|
|
||||||
{
|
|
||||||
NtClose( source_handle );
|
|
||||||
if (!CopyFileExW( source, dest, fnProgress, param, NULL,
|
|
||||||
flag & MOVEFILE_REPLACE_EXISTING ?
|
|
||||||
0 : COPY_FILE_FAIL_IF_EXISTS ))
|
|
||||||
return FALSE;
|
|
||||||
return DeleteFileW( source );
|
|
||||||
}
|
|
||||||
|
|
||||||
NtClose( source_handle );
|
|
||||||
return set_ntstatus( status );
|
|
||||||
|
|
||||||
error:
|
|
||||||
if (source_handle) NtClose( source_handle );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* MoveFileWithProgressA (KERNEL32.@)
|
* MoveFileWithProgressA (KERNEL32.@)
|
||||||
*/
|
*/
|
||||||
|
@ -533,14 +182,6 @@ BOOL WINAPI MoveFileWithProgressA( LPCSTR source, LPCSTR dest,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* MoveFileExW (KERNEL32.@)
|
|
||||||
*/
|
|
||||||
BOOL WINAPI MoveFileExW( LPCWSTR source, LPCWSTR dest, DWORD flag )
|
|
||||||
{
|
|
||||||
return MoveFileWithProgressW( source, dest, NULL, NULL, flag );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* MoveFileExA (KERNEL32.@)
|
* MoveFileExA (KERNEL32.@)
|
||||||
*/
|
*/
|
||||||
|
@ -570,87 +211,6 @@ BOOL WINAPI MoveFileA( LPCSTR source, LPCSTR dest )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
* CreateHardLinkW (KERNEL32.@)
|
|
||||||
*/
|
|
||||||
BOOL WINAPI CreateHardLinkW(LPCWSTR lpFileName, LPCWSTR lpExistingFileName,
|
|
||||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes)
|
|
||||||
{
|
|
||||||
UNICODE_STRING ntDest, ntSource;
|
|
||||||
FILE_LINK_INFORMATION *info = NULL;
|
|
||||||
OBJECT_ATTRIBUTES attr;
|
|
||||||
IO_STATUS_BLOCK io;
|
|
||||||
BOOL ret = FALSE;
|
|
||||||
HANDLE file;
|
|
||||||
ULONG size;
|
|
||||||
|
|
||||||
TRACE("(%s, %s, %p)\n", debugstr_w(lpFileName),
|
|
||||||
debugstr_w(lpExistingFileName), lpSecurityAttributes);
|
|
||||||
|
|
||||||
ntDest.Buffer = ntSource.Buffer = NULL;
|
|
||||||
if (!RtlDosPathNameToNtPathName_U( lpFileName, &ntDest, NULL, NULL ) ||
|
|
||||||
!RtlDosPathNameToNtPathName_U( lpExistingFileName, &ntSource, NULL, NULL ))
|
|
||||||
{
|
|
||||||
SetLastError( ERROR_PATH_NOT_FOUND );
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
size = offsetof( FILE_LINK_INFORMATION, FileName ) + ntDest.Length;
|
|
||||||
if (!(info = HeapAlloc( GetProcessHeap(), 0, size )))
|
|
||||||
{
|
|
||||||
SetLastError( ERROR_OUTOFMEMORY );
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
InitializeObjectAttributes( &attr, &ntSource, OBJ_CASE_INSENSITIVE, 0, NULL );
|
|
||||||
if (!(ret = set_ntstatus( NtOpenFile( &file, SYNCHRONIZE, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
||||||
FILE_SYNCHRONOUS_IO_NONALERT ) )))
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
info->ReplaceIfExists = FALSE;
|
|
||||||
info->RootDirectory = NULL;
|
|
||||||
info->FileNameLength = ntDest.Length;
|
|
||||||
memcpy( info->FileName, ntDest.Buffer, ntDest.Length );
|
|
||||||
ret = set_ntstatus( NtSetInformationFile( file, &io, info, size, FileLinkInformation ) );
|
|
||||||
|
|
||||||
NtClose( file );
|
|
||||||
|
|
||||||
err:
|
|
||||||
RtlFreeUnicodeString( &ntSource );
|
|
||||||
RtlFreeUnicodeString( &ntDest );
|
|
||||||
HeapFree( GetProcessHeap(), 0, info );
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
* CreateHardLinkA (KERNEL32.@)
|
|
||||||
*/
|
|
||||||
BOOL WINAPI CreateHardLinkA(LPCSTR lpFileName, LPCSTR lpExistingFileName,
|
|
||||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes)
|
|
||||||
{
|
|
||||||
WCHAR *sourceW, *destW;
|
|
||||||
BOOL res;
|
|
||||||
|
|
||||||
if (!(sourceW = FILE_name_AtoW( lpExistingFileName, TRUE )))
|
|
||||||
{
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
if (!(destW = FILE_name_AtoW( lpFileName, TRUE )))
|
|
||||||
{
|
|
||||||
HeapFree( GetProcessHeap(), 0, sourceW );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = CreateHardLinkW( destW, sourceW, lpSecurityAttributes );
|
|
||||||
|
|
||||||
HeapFree( GetProcessHeap(), 0, sourceW );
|
|
||||||
HeapFree( GetProcessHeap(), 0, destW );
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* CreateDirectoryExA (KERNEL32.@)
|
* CreateDirectoryExA (KERNEL32.@)
|
||||||
*/
|
*/
|
||||||
|
@ -820,15 +380,6 @@ WCHAR * CDECL wine_get_dos_file_name( LPCSTR str )
|
||||||
return nt_name.Buffer;
|
return nt_name.Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
* CreateSymbolicLinkW (KERNEL32.@)
|
|
||||||
*/
|
|
||||||
BOOLEAN WINAPI CreateSymbolicLinkW(LPCWSTR link, LPCWSTR target, DWORD flags)
|
|
||||||
{
|
|
||||||
FIXME("(%s %s %d): stub\n", debugstr_w(link), debugstr_w(target), flags);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* CreateSymbolicLinkA (KERNEL32.@)
|
* CreateSymbolicLinkA (KERNEL32.@)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "winioctl.h"
|
#include "winioctl.h"
|
||||||
#include "wincon.h"
|
#include "wincon.h"
|
||||||
#include "fileapi.h"
|
#include "fileapi.h"
|
||||||
|
#include "shlwapi.h"
|
||||||
#include "ddk/ntddk.h"
|
#include "ddk/ntddk.h"
|
||||||
#include "ddk/ntddser.h"
|
#include "ddk/ntddser.h"
|
||||||
|
|
||||||
|
@ -111,6 +112,136 @@ static inline BOOL contains_path( const WCHAR *name )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* add_boot_rename_entry
|
||||||
|
*
|
||||||
|
* Adds an entry to the registry that is loaded when windows boots and
|
||||||
|
* checks if there are some files to be removed or renamed/moved.
|
||||||
|
* <fn1> has to be valid and <fn2> may be NULL. If both pointers are
|
||||||
|
* non-NULL then the file is moved, otherwise it is deleted. The
|
||||||
|
* entry of the registry key is always appended with two zero
|
||||||
|
* terminated strings. If <fn2> is NULL then the second entry is
|
||||||
|
* simply a single 0-byte. Otherwise the second filename goes
|
||||||
|
* there. The entries are prepended with \??\ before the path and the
|
||||||
|
* second filename gets also a '!' as the first character if
|
||||||
|
* MOVEFILE_REPLACE_EXISTING is set. After the final string another
|
||||||
|
* 0-byte follows to indicate the end of the strings.
|
||||||
|
* i.e.:
|
||||||
|
* \??\D:\test\file1[0]
|
||||||
|
* !\??\D:\test\file1_renamed[0]
|
||||||
|
* \??\D:\Test|delete[0]
|
||||||
|
* [0] <- file is to be deleted, second string empty
|
||||||
|
* \??\D:\test\file2[0]
|
||||||
|
* !\??\D:\test\file2_renamed[0]
|
||||||
|
* [0] <- indicates end of strings
|
||||||
|
*
|
||||||
|
* or:
|
||||||
|
* \??\D:\test\file1[0]
|
||||||
|
* !\??\D:\test\file1_renamed[0]
|
||||||
|
* \??\D:\Test|delete[0]
|
||||||
|
* [0] <- file is to be deleted, second string empty
|
||||||
|
* [0] <- indicates end of strings
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static BOOL add_boot_rename_entry( LPCWSTR source, LPCWSTR dest, DWORD flags )
|
||||||
|
{
|
||||||
|
static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
|
||||||
|
|
||||||
|
OBJECT_ATTRIBUTES attr;
|
||||||
|
UNICODE_STRING nameW, source_name, dest_name;
|
||||||
|
KEY_VALUE_PARTIAL_INFORMATION *info;
|
||||||
|
BOOL rc = FALSE;
|
||||||
|
HANDLE key = 0;
|
||||||
|
DWORD len1, len2;
|
||||||
|
DWORD size = 0;
|
||||||
|
BYTE *buffer = NULL;
|
||||||
|
WCHAR *p;
|
||||||
|
|
||||||
|
if (!RtlDosPathNameToNtPathName_U( source, &source_name, NULL, NULL ))
|
||||||
|
{
|
||||||
|
SetLastError( ERROR_PATH_NOT_FOUND );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
dest_name.Buffer = NULL;
|
||||||
|
if (dest && !RtlDosPathNameToNtPathName_U( dest, &dest_name, NULL, NULL ))
|
||||||
|
{
|
||||||
|
RtlFreeUnicodeString( &source_name );
|
||||||
|
SetLastError( ERROR_PATH_NOT_FOUND );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
attr.Length = sizeof(attr);
|
||||||
|
attr.RootDirectory = 0;
|
||||||
|
attr.ObjectName = &nameW;
|
||||||
|
attr.Attributes = 0;
|
||||||
|
attr.SecurityDescriptor = NULL;
|
||||||
|
attr.SecurityQualityOfService = NULL;
|
||||||
|
RtlInitUnicodeString( &nameW, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager" );
|
||||||
|
|
||||||
|
if (NtCreateKey( &key, KEY_ALL_ACCESS, &attr, 0, NULL, 0, NULL ) != STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
RtlFreeUnicodeString( &source_name );
|
||||||
|
RtlFreeUnicodeString( &dest_name );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
len1 = source_name.Length + sizeof(WCHAR);
|
||||||
|
if (dest)
|
||||||
|
{
|
||||||
|
len2 = dest_name.Length + sizeof(WCHAR);
|
||||||
|
if (flags & MOVEFILE_REPLACE_EXISTING)
|
||||||
|
len2 += sizeof(WCHAR); /* Plus 1 because of the leading '!' */
|
||||||
|
}
|
||||||
|
else len2 = sizeof(WCHAR); /* minimum is the 0 characters for the empty second string */
|
||||||
|
|
||||||
|
RtlInitUnicodeString( &nameW, L"PendingFileRenameOperations" );
|
||||||
|
|
||||||
|
/* First we check if the key exists and if so how many bytes it already contains. */
|
||||||
|
if (NtQueryValueKey( key, &nameW, KeyValuePartialInformation,
|
||||||
|
NULL, 0, &size ) == STATUS_BUFFER_TOO_SMALL)
|
||||||
|
{
|
||||||
|
if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size + len1 + len2 + sizeof(WCHAR) ))) goto done;
|
||||||
|
if (NtQueryValueKey( key, &nameW, KeyValuePartialInformation, buffer, size, &size )) goto done;
|
||||||
|
info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
|
||||||
|
if (info->Type != REG_MULTI_SZ) goto done;
|
||||||
|
if (size > sizeof(info)) size -= sizeof(WCHAR); /* remove terminating null (will be added back later) */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size = info_size;
|
||||||
|
if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size + len1 + len2 + sizeof(WCHAR) ))) goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy( buffer + size, source_name.Buffer, len1 );
|
||||||
|
size += len1;
|
||||||
|
p = (WCHAR *)(buffer + size);
|
||||||
|
if (dest)
|
||||||
|
{
|
||||||
|
if (flags & MOVEFILE_REPLACE_EXISTING) *p++ = '!';
|
||||||
|
memcpy( p, dest_name.Buffer, len2 );
|
||||||
|
size += len2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*p = 0;
|
||||||
|
size += sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add final null */
|
||||||
|
p = (WCHAR *)(buffer + size);
|
||||||
|
*p = 0;
|
||||||
|
size += sizeof(WCHAR);
|
||||||
|
rc = !NtSetValueKey( key, &nameW, 0, REG_MULTI_SZ, buffer + info_size, size - info_size );
|
||||||
|
|
||||||
|
done:
|
||||||
|
RtlFreeUnicodeString( &source_name );
|
||||||
|
RtlFreeUnicodeString( &dest_name );
|
||||||
|
if (key) NtClose(key);
|
||||||
|
HeapFree( GetProcessHeap(), 0, buffer );
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* append_ext
|
* append_ext
|
||||||
*/
|
*/
|
||||||
|
@ -337,6 +468,20 @@ DWORD file_name_WtoA( LPCWSTR src, INT srclen, LPSTR dest, INT destlen )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* is_same_file
|
||||||
|
*/
|
||||||
|
static BOOL is_same_file( HANDLE h1, HANDLE h2 )
|
||||||
|
{
|
||||||
|
FILE_ID_INFORMATION id1, id2;
|
||||||
|
IO_STATUS_BLOCK io;
|
||||||
|
|
||||||
|
return !NtQueryInformationFile( h1, &io, &id1, sizeof(id1), FileIdInformation ) &&
|
||||||
|
!NtQueryInformationFile( h2, &io, &id2, sizeof(id2), FileIdInformation ) &&
|
||||||
|
!memcmp( &id1, &id2, sizeof(FILE_ID_INFORMATION) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* AreFileApisANSI (kernelbase.@)
|
* AreFileApisANSI (kernelbase.@)
|
||||||
*/
|
*/
|
||||||
|
@ -346,6 +491,107 @@ BOOL WINAPI DECLSPEC_HOTPATCH AreFileApisANSI(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* CopyFileExW (kernelbase.@)
|
||||||
|
*/
|
||||||
|
BOOL WINAPI CopyFileExW( const WCHAR *source, const WCHAR *dest, LPPROGRESS_ROUTINE progress,
|
||||||
|
void *param, BOOL *cancel_ptr, DWORD flags )
|
||||||
|
{
|
||||||
|
static const int buffer_size = 65536;
|
||||||
|
HANDLE h1, h2;
|
||||||
|
BY_HANDLE_FILE_INFORMATION info;
|
||||||
|
DWORD count;
|
||||||
|
BOOL ret = FALSE;
|
||||||
|
char *buffer;
|
||||||
|
|
||||||
|
if (!source || !dest)
|
||||||
|
{
|
||||||
|
SetLastError( ERROR_INVALID_PARAMETER );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if (!(buffer = HeapAlloc( GetProcessHeap(), 0, buffer_size )))
|
||||||
|
{
|
||||||
|
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("%s -> %s, %x\n", debugstr_w(source), debugstr_w(dest), flags);
|
||||||
|
|
||||||
|
if ((h1 = CreateFileW( source, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||||
|
NULL, OPEN_EXISTING, 0, 0 )) == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
WARN("Unable to open source %s\n", debugstr_w(source));
|
||||||
|
HeapFree( GetProcessHeap(), 0, buffer );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GetFileInformationByHandle( h1, &info ))
|
||||||
|
{
|
||||||
|
WARN("GetFileInformationByHandle returned error for %s\n", debugstr_w(source));
|
||||||
|
HeapFree( GetProcessHeap(), 0, buffer );
|
||||||
|
CloseHandle( h1 );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(flags & COPY_FILE_FAIL_IF_EXISTS))
|
||||||
|
{
|
||||||
|
BOOL same_file = FALSE;
|
||||||
|
h2 = CreateFileW( dest, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
|
||||||
|
if (h2 != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
same_file = is_same_file( h1, h2 );
|
||||||
|
CloseHandle( h2 );
|
||||||
|
}
|
||||||
|
if (same_file)
|
||||||
|
{
|
||||||
|
HeapFree( GetProcessHeap(), 0, buffer );
|
||||||
|
CloseHandle( h1 );
|
||||||
|
SetLastError( ERROR_SHARING_VIOLATION );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((h2 = CreateFileW( dest, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
||||||
|
(flags & COPY_FILE_FAIL_IF_EXISTS) ? CREATE_NEW : CREATE_ALWAYS,
|
||||||
|
info.dwFileAttributes, h1 )) == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
WARN("Unable to open dest %s\n", debugstr_w(dest));
|
||||||
|
HeapFree( GetProcessHeap(), 0, buffer );
|
||||||
|
CloseHandle( h1 );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (ReadFile( h1, buffer, buffer_size, &count, NULL ) && count)
|
||||||
|
{
|
||||||
|
char *p = buffer;
|
||||||
|
while (count != 0)
|
||||||
|
{
|
||||||
|
DWORD res;
|
||||||
|
if (!WriteFile( h2, p, count, &res, NULL ) || !res) goto done;
|
||||||
|
p += res;
|
||||||
|
count -= res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = TRUE;
|
||||||
|
done:
|
||||||
|
/* Maintain the timestamp of source file to destination file */
|
||||||
|
SetFileTime( h2, NULL, NULL, &info.ftLastWriteTime );
|
||||||
|
HeapFree( GetProcessHeap(), 0, buffer );
|
||||||
|
CloseHandle( h1 );
|
||||||
|
CloseHandle( h2 );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* CopyFileW (kernelbase.@)
|
||||||
|
*/
|
||||||
|
BOOL WINAPI DECLSPEC_HOTPATCH CopyFileW( const WCHAR *source, const WCHAR *dest, BOOL fail_if_exists )
|
||||||
|
{
|
||||||
|
return CopyFileExW( source, dest, NULL, NULL, NULL, fail_if_exists ? COPY_FILE_FAIL_IF_EXISTS : 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* CreateDirectoryA (kernelbase.@)
|
* CreateDirectoryA (kernelbase.@)
|
||||||
*/
|
*/
|
||||||
|
@ -622,6 +868,88 @@ HANDLE WINAPI DECLSPEC_HOTPATCH CreateFileW( LPCWSTR filename, DWORD access, DWO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* CreateHardLinkA (kernelbase.@)
|
||||||
|
*/
|
||||||
|
BOOL WINAPI DECLSPEC_HOTPATCH CreateHardLinkA( const char *dest, const char *source,
|
||||||
|
SECURITY_ATTRIBUTES *attr )
|
||||||
|
{
|
||||||
|
WCHAR *sourceW, *destW;
|
||||||
|
BOOL res;
|
||||||
|
|
||||||
|
if (!(sourceW = file_name_AtoW( source, TRUE ))) return FALSE;
|
||||||
|
if (!(destW = file_name_AtoW( dest, TRUE )))
|
||||||
|
{
|
||||||
|
HeapFree( GetProcessHeap(), 0, sourceW );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
res = CreateHardLinkW( destW, sourceW, attr );
|
||||||
|
HeapFree( GetProcessHeap(), 0, sourceW );
|
||||||
|
HeapFree( GetProcessHeap(), 0, destW );
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* CreateHardLinkW (kernelbase.@)
|
||||||
|
*/
|
||||||
|
BOOL WINAPI CreateHardLinkW( LPCWSTR dest, LPCWSTR source, SECURITY_ATTRIBUTES *sec_attr )
|
||||||
|
{
|
||||||
|
UNICODE_STRING ntDest, ntSource;
|
||||||
|
FILE_LINK_INFORMATION *info = NULL;
|
||||||
|
OBJECT_ATTRIBUTES attr;
|
||||||
|
IO_STATUS_BLOCK io;
|
||||||
|
BOOL ret = FALSE;
|
||||||
|
HANDLE file;
|
||||||
|
ULONG size;
|
||||||
|
|
||||||
|
TRACE( "(%s, %s, %p)\n", debugstr_w(dest), debugstr_w(source), sec_attr );
|
||||||
|
|
||||||
|
ntDest.Buffer = ntSource.Buffer = NULL;
|
||||||
|
if (!RtlDosPathNameToNtPathName_U( dest, &ntDest, NULL, NULL ) ||
|
||||||
|
!RtlDosPathNameToNtPathName_U( source, &ntSource, NULL, NULL ))
|
||||||
|
{
|
||||||
|
SetLastError( ERROR_PATH_NOT_FOUND );
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = offsetof( FILE_LINK_INFORMATION, FileName ) + ntDest.Length;
|
||||||
|
if (!(info = HeapAlloc( GetProcessHeap(), 0, size )))
|
||||||
|
{
|
||||||
|
SetLastError( ERROR_OUTOFMEMORY );
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
InitializeObjectAttributes( &attr, &ntSource, OBJ_CASE_INSENSITIVE, 0, NULL );
|
||||||
|
if (!(ret = set_ntstatus( NtOpenFile( &file, SYNCHRONIZE, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
FILE_SYNCHRONOUS_IO_NONALERT ) )))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
info->ReplaceIfExists = FALSE;
|
||||||
|
info->RootDirectory = NULL;
|
||||||
|
info->FileNameLength = ntDest.Length;
|
||||||
|
memcpy( info->FileName, ntDest.Buffer, ntDest.Length );
|
||||||
|
ret = set_ntstatus( NtSetInformationFile( file, &io, info, size, FileLinkInformation ) );
|
||||||
|
NtClose( file );
|
||||||
|
|
||||||
|
done:
|
||||||
|
RtlFreeUnicodeString( &ntSource );
|
||||||
|
RtlFreeUnicodeString( &ntDest );
|
||||||
|
HeapFree( GetProcessHeap(), 0, info );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* CreateSymbolicLinkW (kernelbase.@)
|
||||||
|
*/
|
||||||
|
BOOLEAN WINAPI /* DECLSPEC_HOTPATCH */ CreateSymbolicLinkW( LPCWSTR link, LPCWSTR target, DWORD flags )
|
||||||
|
{
|
||||||
|
FIXME( "(%s %s %d): stub\n", debugstr_w(link), debugstr_w(target), flags );
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* DeleteFileA (kernelbase.@)
|
* DeleteFileA (kernelbase.@)
|
||||||
*/
|
*/
|
||||||
|
@ -1331,6 +1659,185 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetFileAttributesExW( LPCWSTR name, GET_FILEEX_INF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* GetFinalPathNameByHandleA (kernelbase.@)
|
||||||
|
*/
|
||||||
|
DWORD WINAPI DECLSPEC_HOTPATCH GetFinalPathNameByHandleA( HANDLE file, LPSTR path,
|
||||||
|
DWORD count, DWORD flags )
|
||||||
|
{
|
||||||
|
WCHAR *str;
|
||||||
|
DWORD result, len;
|
||||||
|
|
||||||
|
TRACE( "(%p,%p,%d,%x)\n", file, path, count, flags);
|
||||||
|
|
||||||
|
len = GetFinalPathNameByHandleW(file, NULL, 0, flags);
|
||||||
|
if (len == 0) return 0;
|
||||||
|
|
||||||
|
str = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
||||||
|
if (!str)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = GetFinalPathNameByHandleW(file, str, len, flags);
|
||||||
|
if (result != len - 1)
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, str);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = file_name_WtoA( str, -1, NULL, 0 );
|
||||||
|
if (count < len)
|
||||||
|
{
|
||||||
|
HeapFree(GetProcessHeap(), 0, str);
|
||||||
|
return len - 1;
|
||||||
|
}
|
||||||
|
file_name_WtoA( str, -1, path, count );
|
||||||
|
HeapFree(GetProcessHeap(), 0, str);
|
||||||
|
return len - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* GetFinalPathNameByHandleW (kernelbase.@)
|
||||||
|
*/
|
||||||
|
DWORD WINAPI DECLSPEC_HOTPATCH GetFinalPathNameByHandleW( HANDLE file, LPWSTR path,
|
||||||
|
DWORD count, DWORD flags )
|
||||||
|
{
|
||||||
|
WCHAR buffer[sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH + 1];
|
||||||
|
OBJECT_NAME_INFORMATION *info = (OBJECT_NAME_INFORMATION*)&buffer;
|
||||||
|
WCHAR drive_part[MAX_PATH];
|
||||||
|
DWORD drive_part_len = 0;
|
||||||
|
NTSTATUS status;
|
||||||
|
DWORD result = 0;
|
||||||
|
ULONG dummy;
|
||||||
|
WCHAR *ptr;
|
||||||
|
|
||||||
|
TRACE( "(%p,%p,%d,%x)\n", file, path, count, flags );
|
||||||
|
|
||||||
|
if (flags & ~(FILE_NAME_OPENED | VOLUME_NAME_GUID | VOLUME_NAME_NONE | VOLUME_NAME_NT))
|
||||||
|
{
|
||||||
|
WARN("Unknown flags: %x\n", flags);
|
||||||
|
SetLastError( ERROR_INVALID_PARAMETER );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get object name */
|
||||||
|
status = NtQueryObject( file, ObjectNameInformation, &buffer, sizeof(buffer) - sizeof(WCHAR), &dummy );
|
||||||
|
if (!set_ntstatus( status )) return 0;
|
||||||
|
|
||||||
|
if (!info->Name.Buffer)
|
||||||
|
{
|
||||||
|
SetLastError( ERROR_INVALID_HANDLE );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (info->Name.Length < 4 * sizeof(WCHAR) || info->Name.Buffer[0] != '\\' ||
|
||||||
|
info->Name.Buffer[1] != '?' || info->Name.Buffer[2] != '?' || info->Name.Buffer[3] != '\\' )
|
||||||
|
{
|
||||||
|
FIXME("Unexpected object name: %s\n", debugstr_wn(info->Name.Buffer, info->Name.Length / sizeof(WCHAR)));
|
||||||
|
SetLastError( ERROR_GEN_FAILURE );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add terminating null character, remove "\\??\\" */
|
||||||
|
info->Name.Buffer[info->Name.Length / sizeof(WCHAR)] = 0;
|
||||||
|
info->Name.Length -= 4 * sizeof(WCHAR);
|
||||||
|
info->Name.Buffer += 4;
|
||||||
|
|
||||||
|
/* FILE_NAME_OPENED is not supported yet, and would require Wineserver changes */
|
||||||
|
if (flags & FILE_NAME_OPENED)
|
||||||
|
{
|
||||||
|
FIXME("FILE_NAME_OPENED not supported\n");
|
||||||
|
flags &= ~FILE_NAME_OPENED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get information required for VOLUME_NAME_NONE, VOLUME_NAME_GUID and VOLUME_NAME_NT */
|
||||||
|
if (flags == VOLUME_NAME_NONE || flags == VOLUME_NAME_GUID || flags == VOLUME_NAME_NT)
|
||||||
|
{
|
||||||
|
if (!GetVolumePathNameW( info->Name.Buffer, drive_part, MAX_PATH )) return 0;
|
||||||
|
drive_part_len = lstrlenW(drive_part);
|
||||||
|
if (!drive_part_len || drive_part_len > lstrlenW(info->Name.Buffer) ||
|
||||||
|
drive_part[drive_part_len-1] != '\\' ||
|
||||||
|
CompareStringOrdinal( info->Name.Buffer, drive_part_len, drive_part, drive_part_len, TRUE ) != CSTR_EQUAL)
|
||||||
|
{
|
||||||
|
FIXME( "Path %s returned by GetVolumePathNameW does not match file path %s\n",
|
||||||
|
debugstr_w(drive_part), debugstr_w(info->Name.Buffer) );
|
||||||
|
SetLastError( ERROR_GEN_FAILURE );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags == VOLUME_NAME_NONE)
|
||||||
|
{
|
||||||
|
ptr = info->Name.Buffer + drive_part_len - 1;
|
||||||
|
result = lstrlenW(ptr);
|
||||||
|
if (result < count) memcpy(path, ptr, (result + 1) * sizeof(WCHAR));
|
||||||
|
else result++;
|
||||||
|
}
|
||||||
|
else if (flags == VOLUME_NAME_GUID)
|
||||||
|
{
|
||||||
|
WCHAR volume_prefix[51];
|
||||||
|
|
||||||
|
/* GetVolumeNameForVolumeMountPointW sets error code on failure */
|
||||||
|
if (!GetVolumeNameForVolumeMountPointW( drive_part, volume_prefix, 50 )) return 0;
|
||||||
|
ptr = info->Name.Buffer + drive_part_len;
|
||||||
|
result = lstrlenW(volume_prefix) + lstrlenW(ptr);
|
||||||
|
if (result < count)
|
||||||
|
{
|
||||||
|
lstrcpyW(path, volume_prefix);
|
||||||
|
lstrcatW(path, ptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (flags == VOLUME_NAME_NT)
|
||||||
|
{
|
||||||
|
WCHAR nt_prefix[MAX_PATH];
|
||||||
|
|
||||||
|
/* QueryDosDeviceW sets error code on failure */
|
||||||
|
drive_part[drive_part_len - 1] = 0;
|
||||||
|
if (!QueryDosDeviceW( drive_part, nt_prefix, MAX_PATH )) return 0;
|
||||||
|
ptr = info->Name.Buffer + drive_part_len - 1;
|
||||||
|
result = lstrlenW(nt_prefix) + lstrlenW(ptr);
|
||||||
|
if (result < count)
|
||||||
|
{
|
||||||
|
lstrcpyW(path, nt_prefix);
|
||||||
|
lstrcatW(path, ptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (flags == VOLUME_NAME_DOS)
|
||||||
|
{
|
||||||
|
result = 4 + lstrlenW(info->Name.Buffer);
|
||||||
|
if (result < count)
|
||||||
|
{
|
||||||
|
lstrcpyW(path, L"\\\\?\\");
|
||||||
|
lstrcatW(path, info->Name.Buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Windows crashes here, but we prefer returning ERROR_INVALID_PARAMETER */
|
||||||
|
WARN("Invalid combination of flags: %x\n", flags);
|
||||||
|
SetLastError( ERROR_INVALID_PARAMETER );
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* GetFullPathNameA (kernelbase.@)
|
* GetFullPathNameA (kernelbase.@)
|
||||||
*/
|
*/
|
||||||
|
@ -1891,6 +2398,94 @@ UINT WINAPI DECLSPEC_HOTPATCH GetWindowsDirectoryW( LPWSTR path, UINT count )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* MoveFileExW (kernelbase.@)
|
||||||
|
*/
|
||||||
|
BOOL WINAPI MoveFileExW( const WCHAR *source, const WCHAR *dest, DWORD flag )
|
||||||
|
{
|
||||||
|
return MoveFileWithProgressW( source, dest, NULL, NULL, flag );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* MoveFileWithProgressW (kernelbase.@)
|
||||||
|
*/
|
||||||
|
BOOL WINAPI DECLSPEC_HOTPATCH MoveFileWithProgressW( const WCHAR *source, const WCHAR *dest,
|
||||||
|
LPPROGRESS_ROUTINE progress,
|
||||||
|
void *param, DWORD flag )
|
||||||
|
{
|
||||||
|
FILE_RENAME_INFORMATION *rename_info;
|
||||||
|
FILE_BASIC_INFORMATION info;
|
||||||
|
UNICODE_STRING nt_name;
|
||||||
|
OBJECT_ATTRIBUTES attr;
|
||||||
|
IO_STATUS_BLOCK io;
|
||||||
|
NTSTATUS status;
|
||||||
|
HANDLE source_handle = 0;
|
||||||
|
ULONG size;
|
||||||
|
|
||||||
|
TRACE( "(%s,%s,%p,%p,%04x)\n", debugstr_w(source), debugstr_w(dest), progress, param, flag );
|
||||||
|
|
||||||
|
if (flag & MOVEFILE_DELAY_UNTIL_REBOOT) return add_boot_rename_entry( source, dest, flag );
|
||||||
|
|
||||||
|
if (!dest) return DeleteFileW( source );
|
||||||
|
|
||||||
|
/* check if we are allowed to rename the source */
|
||||||
|
|
||||||
|
if (!RtlDosPathNameToNtPathName_U( source, &nt_name, NULL, NULL ))
|
||||||
|
{
|
||||||
|
SetLastError( ERROR_PATH_NOT_FOUND );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
attr.Length = sizeof(attr);
|
||||||
|
attr.RootDirectory = 0;
|
||||||
|
attr.Attributes = OBJ_CASE_INSENSITIVE;
|
||||||
|
attr.ObjectName = &nt_name;
|
||||||
|
attr.SecurityDescriptor = NULL;
|
||||||
|
attr.SecurityQualityOfService = NULL;
|
||||||
|
|
||||||
|
status = NtOpenFile( &source_handle, DELETE | SYNCHRONIZE, &attr, &io,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||||
|
FILE_SYNCHRONOUS_IO_NONALERT );
|
||||||
|
RtlFreeUnicodeString( &nt_name );
|
||||||
|
if (!set_ntstatus( status )) goto error;
|
||||||
|
|
||||||
|
status = NtQueryInformationFile( source_handle, &io, &info, sizeof(info), FileBasicInformation );
|
||||||
|
if (!set_ntstatus( status )) goto error;
|
||||||
|
|
||||||
|
if (!RtlDosPathNameToNtPathName_U( dest, &nt_name, NULL, NULL ))
|
||||||
|
{
|
||||||
|
SetLastError( ERROR_PATH_NOT_FOUND );
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
size = offsetof( FILE_RENAME_INFORMATION, FileName ) + nt_name.Length;
|
||||||
|
if (!(rename_info = HeapAlloc( GetProcessHeap(), 0, size ))) goto error;
|
||||||
|
|
||||||
|
rename_info->ReplaceIfExists = !!(flag & MOVEFILE_REPLACE_EXISTING);
|
||||||
|
rename_info->RootDirectory = NULL;
|
||||||
|
rename_info->FileNameLength = nt_name.Length;
|
||||||
|
memcpy( rename_info->FileName, nt_name.Buffer, nt_name.Length );
|
||||||
|
RtlFreeUnicodeString( &nt_name );
|
||||||
|
status = NtSetInformationFile( source_handle, &io, rename_info, size, FileRenameInformation );
|
||||||
|
HeapFree( GetProcessHeap(), 0, rename_info );
|
||||||
|
if (status == STATUS_NOT_SAME_DEVICE && (flag & MOVEFILE_COPY_ALLOWED))
|
||||||
|
{
|
||||||
|
NtClose( source_handle );
|
||||||
|
if (!CopyFileExW( source, dest, progress, param, NULL,
|
||||||
|
flag & MOVEFILE_REPLACE_EXISTING ? 0 : COPY_FILE_FAIL_IF_EXISTS ))
|
||||||
|
return FALSE;
|
||||||
|
return DeleteFileW( source );
|
||||||
|
}
|
||||||
|
|
||||||
|
NtClose( source_handle );
|
||||||
|
return set_ntstatus( status );
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (source_handle) NtClose( source_handle );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* NeedCurrentDirectoryForExePathA (kernelbase.@)
|
* NeedCurrentDirectoryForExePathA (kernelbase.@)
|
||||||
*/
|
*/
|
||||||
|
@ -1916,6 +2511,111 @@ BOOL WINAPI DECLSPEC_HOTPATCH NeedCurrentDirectoryForExePathW( LPCWSTR name )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* ReplaceFileW (kernelbase.@)
|
||||||
|
*/
|
||||||
|
BOOL WINAPI DECLSPEC_HOTPATCH ReplaceFileW( const WCHAR *replaced, const WCHAR *replacement,
|
||||||
|
const WCHAR *backup, DWORD flags,
|
||||||
|
void *exclude, void *reserved )
|
||||||
|
{
|
||||||
|
UNICODE_STRING nt_replaced_name, nt_replacement_name;
|
||||||
|
HANDLE hReplacement = NULL;
|
||||||
|
NTSTATUS status;
|
||||||
|
IO_STATUS_BLOCK io;
|
||||||
|
OBJECT_ATTRIBUTES attr;
|
||||||
|
FILE_BASIC_INFORMATION info;
|
||||||
|
|
||||||
|
TRACE( "%s %s %s 0x%08x %p %p\n", debugstr_w(replaced), debugstr_w(replacement), debugstr_w(backup),
|
||||||
|
flags, exclude, reserved );
|
||||||
|
|
||||||
|
if (flags) FIXME("Ignoring flags %x\n", flags);
|
||||||
|
|
||||||
|
/* First two arguments are mandatory */
|
||||||
|
if (!replaced || !replacement)
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
attr.Length = sizeof(attr);
|
||||||
|
attr.RootDirectory = 0;
|
||||||
|
attr.Attributes = OBJ_CASE_INSENSITIVE;
|
||||||
|
attr.ObjectName = NULL;
|
||||||
|
attr.SecurityDescriptor = NULL;
|
||||||
|
attr.SecurityQualityOfService = NULL;
|
||||||
|
|
||||||
|
/* Open the "replaced" file for reading */
|
||||||
|
if (!RtlDosPathNameToNtPathName_U( replaced, &nt_replaced_name, NULL, NULL ))
|
||||||
|
{
|
||||||
|
SetLastError( ERROR_PATH_NOT_FOUND );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
attr.ObjectName = &nt_replaced_name;
|
||||||
|
|
||||||
|
/* Replacement should fail if replaced is READ_ONLY */
|
||||||
|
status = NtQueryAttributesFile(&attr, &info);
|
||||||
|
RtlFreeUnicodeString(&nt_replaced_name);
|
||||||
|
if (!set_ntstatus( status )) return FALSE;
|
||||||
|
|
||||||
|
if (info.FileAttributes & FILE_ATTRIBUTE_READONLY)
|
||||||
|
{
|
||||||
|
SetLastError( ERROR_ACCESS_DENIED );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open the replacement file for reading, writing, and deleting
|
||||||
|
* (writing and deleting are needed when finished)
|
||||||
|
*/
|
||||||
|
if (!RtlDosPathNameToNtPathName_U( replacement, &nt_replacement_name, NULL, NULL ))
|
||||||
|
{
|
||||||
|
SetLastError( ERROR_PATH_NOT_FOUND );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
attr.ObjectName = &nt_replacement_name;
|
||||||
|
status = NtOpenFile( &hReplacement, GENERIC_READ | GENERIC_WRITE | DELETE | WRITE_DAC | SYNCHRONIZE,
|
||||||
|
&attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE );
|
||||||
|
RtlFreeUnicodeString(&nt_replacement_name);
|
||||||
|
if (!set_ntstatus( status )) return FALSE;
|
||||||
|
NtClose( hReplacement );
|
||||||
|
|
||||||
|
/* If the user wants a backup then that needs to be performed first */
|
||||||
|
if (backup)
|
||||||
|
{
|
||||||
|
if (!MoveFileExW( replaced, backup, MOVEFILE_REPLACE_EXISTING )) return FALSE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* ReplaceFile() can replace an open target. To do this, we need to move
|
||||||
|
* it out of the way first. */
|
||||||
|
WCHAR temp_path[MAX_PATH], temp_file[MAX_PATH];
|
||||||
|
|
||||||
|
lstrcpynW( temp_path, replaced, ARRAY_SIZE( temp_path ) );
|
||||||
|
PathRemoveFileSpecW( temp_path );
|
||||||
|
if (!GetTempFileNameW( temp_path, L"rf", 0, temp_file ) ||
|
||||||
|
!MoveFileExW( replaced, temp_file, MOVEFILE_REPLACE_EXISTING ))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
DeleteFileW( temp_file );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now that the backup has been performed (if requested), copy the replacement
|
||||||
|
* into place
|
||||||
|
*/
|
||||||
|
if (!MoveFileExW( replacement, replaced, 0 ))
|
||||||
|
{
|
||||||
|
/* on failure we need to indicate whether a backup was made */
|
||||||
|
if (!backup)
|
||||||
|
SetLastError( ERROR_UNABLE_TO_MOVE_REPLACEMENT );
|
||||||
|
else
|
||||||
|
SetLastError( ERROR_UNABLE_TO_MOVE_REPLACEMENT_2 );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* SearchPathA (kernelbase.@)
|
* SearchPathA (kernelbase.@)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -166,8 +166,8 @@
|
||||||
@ stdcall ConvertToAutoInheritPrivateObjectSecurity(ptr ptr ptr ptr long ptr)
|
@ stdcall ConvertToAutoInheritPrivateObjectSecurity(ptr ptr ptr ptr long ptr)
|
||||||
# @ stub CopyContext
|
# @ stub CopyContext
|
||||||
# @ stub CopyFile2
|
# @ stub CopyFile2
|
||||||
@ stdcall CopyFileExW(wstr wstr ptr ptr ptr long) kernel32.CopyFileExW
|
@ stdcall CopyFileExW(wstr wstr ptr ptr ptr long)
|
||||||
@ stdcall CopyFileW(wstr wstr long) kernel32.CopyFileW
|
@ stdcall CopyFileW(wstr wstr long)
|
||||||
# @ stub -arch=x86_64 CopyMemoryNonTemporal
|
# @ stub -arch=x86_64 CopyMemoryNonTemporal
|
||||||
@ stdcall CopySid(long ptr ptr)
|
@ stdcall CopySid(long ptr ptr)
|
||||||
# @ stub CouldMultiUserAppsBehaviorBePossibleForPackage
|
# @ stub CouldMultiUserAppsBehaviorBePossibleForPackage
|
||||||
|
@ -191,8 +191,8 @@
|
||||||
@ stdcall CreateFileMappingNumaW(long ptr long long long wstr long)
|
@ stdcall CreateFileMappingNumaW(long ptr long long long wstr long)
|
||||||
@ stdcall CreateFileMappingW(long ptr long long long wstr)
|
@ stdcall CreateFileMappingW(long ptr long long long wstr)
|
||||||
@ stdcall CreateFileW(wstr long long ptr long long long)
|
@ stdcall CreateFileW(wstr long long ptr long long long)
|
||||||
@ stdcall CreateHardLinkA(str str ptr) kernel32.CreateHardLinkA
|
@ stdcall CreateHardLinkA(str str ptr)
|
||||||
@ stdcall CreateHardLinkW(wstr wstr ptr) kernel32.CreateHardLinkW
|
@ stdcall CreateHardLinkW(wstr wstr ptr)
|
||||||
@ stdcall CreateIoCompletionPort(long long long long)
|
@ stdcall CreateIoCompletionPort(long long long long)
|
||||||
@ stdcall CreateMemoryResourceNotification(long)
|
@ stdcall CreateMemoryResourceNotification(long)
|
||||||
@ stdcall CreateMutexA(ptr long str)
|
@ stdcall CreateMutexA(ptr long str)
|
||||||
|
@ -221,7 +221,7 @@
|
||||||
# @ stub CreateStateContainer
|
# @ stub CreateStateContainer
|
||||||
# @ stub CreateStateLock
|
# @ stub CreateStateLock
|
||||||
# @ stub CreateStateSubcontainer
|
# @ stub CreateStateSubcontainer
|
||||||
@ stdcall CreateSymbolicLinkW(wstr wstr long) kernel32.CreateSymbolicLinkW
|
@ stdcall CreateSymbolicLinkW(wstr wstr long)
|
||||||
@ stdcall CreateThread(ptr long ptr long long ptr)
|
@ stdcall CreateThread(ptr long ptr long long ptr)
|
||||||
@ stdcall CreateThreadpool(ptr)
|
@ stdcall CreateThreadpool(ptr)
|
||||||
@ stdcall CreateThreadpoolCleanupGroup()
|
@ stdcall CreateThreadpoolCleanupGroup()
|
||||||
|
@ -524,8 +524,8 @@
|
||||||
@ stdcall GetFileVersionInfoSizeExW(long wstr ptr)
|
@ stdcall GetFileVersionInfoSizeExW(long wstr ptr)
|
||||||
@ stdcall GetFileVersionInfoSizeW(wstr ptr)
|
@ stdcall GetFileVersionInfoSizeW(wstr ptr)
|
||||||
@ stdcall GetFileVersionInfoW(wstr long long ptr)
|
@ stdcall GetFileVersionInfoW(wstr long long ptr)
|
||||||
@ stdcall GetFinalPathNameByHandleA(long ptr long long) kernel32.GetFinalPathNameByHandleA
|
@ stdcall GetFinalPathNameByHandleA(long ptr long long)
|
||||||
@ stdcall GetFinalPathNameByHandleW(long ptr long long) kernel32.GetFinalPathNameByHandleW
|
@ stdcall GetFinalPathNameByHandleW(long ptr long long)
|
||||||
@ stdcall GetFullPathNameA(str long ptr ptr)
|
@ stdcall GetFullPathNameA(str long ptr ptr)
|
||||||
@ stdcall GetFullPathNameW(wstr long ptr ptr)
|
@ stdcall GetFullPathNameW(wstr long ptr ptr)
|
||||||
# @ stub GetGPOListInternalA
|
# @ stub GetGPOListInternalA
|
||||||
|
@ -953,9 +953,9 @@
|
||||||
@ stdcall MapViewOfFileEx(long long long long long ptr)
|
@ stdcall MapViewOfFileEx(long long long long long ptr)
|
||||||
@ stdcall MapViewOfFileExNuma(long long long long long ptr long)
|
@ stdcall MapViewOfFileExNuma(long long long long long ptr long)
|
||||||
# @ stub MapViewOfFileFromApp
|
# @ stub MapViewOfFileFromApp
|
||||||
@ stdcall MoveFileExW(wstr wstr long) kernel32.MoveFileExW
|
@ stdcall MoveFileExW(wstr wstr long)
|
||||||
# @ stub MoveFileWithProgressTransactedW
|
# @ stub MoveFileWithProgressTransactedW
|
||||||
@ stdcall MoveFileWithProgressW(wstr wstr ptr ptr long) kernel32.MoveFileWithProgressW
|
@ stdcall MoveFileWithProgressW(wstr wstr ptr ptr long)
|
||||||
@ stdcall MulDiv(long long long) kernel32.MulDiv
|
@ stdcall MulDiv(long long long) kernel32.MulDiv
|
||||||
@ stdcall MultiByteToWideChar(long long str long ptr long)
|
@ stdcall MultiByteToWideChar(long long str long ptr long)
|
||||||
# @ stub NamedPipeEventEnum
|
# @ stub NamedPipeEventEnum
|
||||||
|
@ -1339,7 +1339,7 @@
|
||||||
@ stdcall RemoveVectoredContinueHandler(ptr) ntdll.RtlRemoveVectoredContinueHandler
|
@ stdcall RemoveVectoredContinueHandler(ptr) ntdll.RtlRemoveVectoredContinueHandler
|
||||||
@ stdcall RemoveVectoredExceptionHandler(ptr) ntdll.RtlRemoveVectoredExceptionHandler
|
@ stdcall RemoveVectoredExceptionHandler(ptr) ntdll.RtlRemoveVectoredExceptionHandler
|
||||||
# @ stub ReplaceFileExInternal
|
# @ stub ReplaceFileExInternal
|
||||||
@ stdcall ReplaceFileW(wstr wstr wstr long ptr ptr) kernel32.ReplaceFileW
|
@ stdcall ReplaceFileW(wstr wstr wstr long ptr ptr)
|
||||||
@ stdcall ResetEvent(long)
|
@ stdcall ResetEvent(long)
|
||||||
# @ stub ResetState
|
# @ stub ResetState
|
||||||
@ stdcall ResetWriteWatch(ptr long)
|
@ stdcall ResetWriteWatch(ptr long)
|
||||||
|
|
Loading…
Reference in New Issue