NT4/private/windows/base/client/filemisc.c
2020-09-30 17:12:29 +02:00

1327 lines
34 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
filemisc.c
Abstract:
Misc file operations for Win32
Author:
Mark Lucovsky (markl) 26-Sep-1990
Revision History:
--*/
#include <basedll.h>
NTSTATUS
BasepMoveFileDelayed(
IN PUNICODE_STRING OldFileName,
IN PUNICODE_STRING NewFileName
);
BOOL
APIENTRY
SetFileAttributesA(
LPCSTR lpFileName,
DWORD dwFileAttributes
)
/*++
Routine Description:
ANSI thunk to SetFileAttributesW
--*/
{
PUNICODE_STRING Unicode;
ANSI_STRING AnsiString;
NTSTATUS Status;
Unicode = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(&AnsiString,lpFileName);
Status = Basep8BitStringToUnicodeString(Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_BUFFER_OVERFLOW ) {
SetLastError(ERROR_FILENAME_EXCED_RANGE);
}
else {
BaseSetLastNTError(Status);
}
return FALSE;
}
return ( SetFileAttributesW(
(LPCWSTR)Unicode->Buffer,
dwFileAttributes
)
);
}
BOOL
APIENTRY
SetFileAttributesW(
LPCWSTR lpFileName,
DWORD dwFileAttributes
)
/*++
Routine Description:
The attributes of a file can be set using SetFileAttributes.
This API provides the same functionality as DOS (int 21h, function
43H with AL=1), and provides a subset of OS/2's DosSetFileInfo.
Arguments:
lpFileName - Supplies the file name of the file whose attributes are to
be set.
dwFileAttributes - Specifies the file attributes to be set for the
file. Any combination of flags is acceptable except that all
other flags override the normal file attribute,
FILE_ATTRIBUTE_NORMAL.
FileAttributes Flags:
FILE_ATTRIBUTE_NORMAL - A normal file should be created.
FILE_ATTRIBUTE_READONLY - A read-only file should be created.
FILE_ATTRIBUTE_HIDDEN - A hidden file should be created.
FILE_ATTRIBUTE_SYSTEM - A system file should be created.
FILE_ATTRIBUTE_ARCHIVE - The file should be marked so that it
will be archived.
Return Value:
TRUE - The operation was successful.
FALSE/NULL - The operation failed. Extended error status is available
using GetLastError.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE Handle;
UNICODE_STRING FileName;
IO_STATUS_BLOCK IoStatusBlock;
FILE_BASIC_INFORMATION BasicInfo;
BOOLEAN TranslationStatus;
RTL_RELATIVE_NAME RelativeName;
PVOID FreeBuffer;
TranslationStatus = RtlDosPathNameToNtPathName_U(
lpFileName,
&FileName,
NULL,
&RelativeName
);
if ( !TranslationStatus ) {
SetLastError(ERROR_PATH_NOT_FOUND);
return FALSE;
}
FreeBuffer = FileName.Buffer;
if ( RelativeName.RelativeName.Length ) {
FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
}
else {
RelativeName.ContainingDirectory = NULL;
}
InitializeObjectAttributes(
&Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
RelativeName.ContainingDirectory,
NULL
);
//
// Open the file
//
Status = NtOpenFile(
&Handle,
(ACCESS_MASK)FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT
);
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
//
// Set the attributes
//
RtlZeroMemory(&BasicInfo,sizeof(BasicInfo));
BasicInfo.FileAttributes = (dwFileAttributes & FILE_ATTRIBUTE_VALID_SET_FLAGS) | FILE_ATTRIBUTE_NORMAL;
Status = NtSetInformationFile(
Handle,
&IoStatusBlock,
&BasicInfo,
sizeof(BasicInfo),
FileBasicInformation
);
NtClose(Handle);
if ( NT_SUCCESS(Status) ) {
return TRUE;
}
else {
BaseSetLastNTError(Status);
return FALSE;
}
}
DWORD
APIENTRY
GetFileAttributesA(
LPCSTR lpFileName
)
/*++
Routine Description:
ANSI thunk to GetFileAttributesW
--*/
{
PUNICODE_STRING Unicode;
ANSI_STRING AnsiString;
NTSTATUS Status;
Unicode = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(&AnsiString,lpFileName);
Status = Basep8BitStringToUnicodeString(Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_BUFFER_OVERFLOW ) {
SetLastError(ERROR_FILENAME_EXCED_RANGE);
}
else {
BaseSetLastNTError(Status);
}
return (DWORD)-1;
}
return ( GetFileAttributesW((LPCWSTR)Unicode->Buffer) );
}
DWORD
APIENTRY
GetFileAttributesW(
LPCWSTR lpFileName
)
/*++
Routine Description:
The attributes of a file can be obtained using GetFileAttributes.
This API provides the same functionality as DOS (int 21h, function
43H with AL=0), and provides a subset of OS/2's DosQueryFileInfo.
Arguments:
lpFileName - Supplies the file name of the file whose attributes are to
be set.
Return Value:
Not -1 - Returns the attributes of the specified file. Valid
returned attributes are:
FILE_ATTRIBUTE_NORMAL - The file is a normal file.
FILE_ATTRIBUTE_READONLY - The file is marked read-only.
FILE_ATTRIBUTE_HIDDEN - The file is marked as hidden.
FILE_ATTRIBUTE_SYSTEM - The file is marked as a system file.
FILE_ATTRIBUTE_ARCHIVE - The file is marked for archive.
FILE_ATTRIBUTE_DIRECTORY - The file is marked as a directory.
FILE_ATTRIBUTE_VOLUME_LABEL - The file is marked as a volume lable.
0xffffffff - The operation failed. Extended error status is available
using GetLastError.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING FileName;
FILE_BASIC_INFORMATION BasicInfo;
BOOLEAN TranslationStatus;
RTL_RELATIVE_NAME RelativeName;
PVOID FreeBuffer;
TranslationStatus = RtlDosPathNameToNtPathName_U(
lpFileName,
&FileName,
NULL,
&RelativeName
);
if ( !TranslationStatus ) {
SetLastError(ERROR_PATH_NOT_FOUND);
return (DWORD)-1;
}
FreeBuffer = FileName.Buffer;
if ( RelativeName.RelativeName.Length ) {
FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
}
else {
RelativeName.ContainingDirectory = NULL;
}
InitializeObjectAttributes(
&Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
RelativeName.ContainingDirectory,
NULL
);
//
// Open the file
//
Status = NtQueryAttributesFile( &Obja, &BasicInfo );
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
if ( NT_SUCCESS(Status) ) {
return BasicInfo.FileAttributes;
}
else {
//
// Check for a device name.
//
if ( RtlIsDosDeviceName_U((PWSTR)lpFileName) ) {
return FILE_ATTRIBUTE_ARCHIVE;
}
BaseSetLastNTError(Status);
return (DWORD)-1;
}
}
BOOL
APIENTRY
GetFileAttributesExA(
LPCSTR lpFileName,
GET_FILEEX_INFO_LEVELS fInfoLevelId,
LPVOID lpFileInformation
)
/*++
Routine Description:
ANSI thunk to GetFileAttributesExW
--*/
{
PUNICODE_STRING Unicode;
ANSI_STRING AnsiString;
NTSTATUS Status;
Unicode = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(&AnsiString,lpFileName);
Status = Basep8BitStringToUnicodeString(Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_BUFFER_OVERFLOW ) {
SetLastError(ERROR_FILENAME_EXCED_RANGE);
}
else {
BaseSetLastNTError(Status);
}
return FALSE;
}
return ( GetFileAttributesExW((LPCWSTR)Unicode->Buffer,fInfoLevelId,lpFileInformation) );
}
BOOL
APIENTRY
GetFileAttributesExW(
LPCWSTR lpFileName,
GET_FILEEX_INFO_LEVELS fInfoLevelId,
LPVOID lpFileInformation
)
/*++
Routine Description:
The main attributes of a file can be obtained using GetFileAttributesEx.
Arguments:
lpFileName - Supplies the file name of the file whose attributes are to
be set.
fInfoLevelId - Supplies the info level indicating the information to be
returned about the file.
lpFileInformation - Supplies a buffer to receive the specified information
about the file.
Return Value:
TRUE - The operation was successful.
FALSE/NULL - The operation failed. Extended error status is available
using GetLastError.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING FileName;
FILE_NETWORK_OPEN_INFORMATION NetworkInfo;
LPWIN32_FILE_ATTRIBUTE_DATA AttributeData;
BOOLEAN TranslationStatus;
RTL_RELATIVE_NAME RelativeName;
PVOID FreeBuffer;
//
// Check the parameters. Note that for now there is only one info level,
// so there's no special code here to determine what to do.
//
if ( fInfoLevelId >= GetFileExMaxInfoLevel || fInfoLevelId < GetFileExInfoStandard ) {
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
TranslationStatus = RtlDosPathNameToNtPathName_U(
lpFileName,
&FileName,
NULL,
&RelativeName
);
if ( !TranslationStatus ) {
SetLastError(ERROR_PATH_NOT_FOUND);
return FALSE;
}
FreeBuffer = FileName.Buffer;
if ( RelativeName.RelativeName.Length ) {
FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
}
else {
RelativeName.ContainingDirectory = NULL;
}
InitializeObjectAttributes(
&Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
RelativeName.ContainingDirectory,
NULL
);
//
// Query the information about the file using the path-based NT service.
//
Status = NtQueryFullAttributesFile( &Obja, &NetworkInfo );
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
if ( NT_SUCCESS(Status) ) {
AttributeData = (LPWIN32_FILE_ATTRIBUTE_DATA)lpFileInformation;
AttributeData->dwFileAttributes = NetworkInfo.FileAttributes;
AttributeData->ftCreationTime = *(PFILETIME)&NetworkInfo.CreationTime;
AttributeData->ftLastAccessTime = *(PFILETIME)&NetworkInfo.LastAccessTime;
AttributeData->ftLastWriteTime = *(PFILETIME)&NetworkInfo.LastWriteTime;
AttributeData->nFileSizeHigh = NetworkInfo.EndOfFile.HighPart;
AttributeData->nFileSizeLow = (DWORD)NetworkInfo.EndOfFile.LowPart;
return TRUE;
}
else {
BaseSetLastNTError(Status);
return FALSE;
}
}
BOOL
APIENTRY
DeleteFileA(
LPCSTR lpFileName
)
/*++
Routine Description:
ANSI thunk to DeleteFileW
--*/
{
PUNICODE_STRING Unicode;
ANSI_STRING AnsiString;
NTSTATUS Status;
Unicode = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(&AnsiString,lpFileName);
Status = Basep8BitStringToUnicodeString(Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_BUFFER_OVERFLOW ) {
SetLastError(ERROR_FILENAME_EXCED_RANGE);
}
else {
BaseSetLastNTError(Status);
}
return FALSE;
}
return ( DeleteFileW((LPCWSTR)Unicode->Buffer) );
}
BOOL
APIENTRY
DeleteFileW(
LPCWSTR lpFileName
)
/*++
Routine Description:
An existing file can be deleted using DeleteFile.
This API provides the same functionality as DOS (int 21h, function 41H)
and OS/2's DosDelete.
Arguments:
lpFileName - Supplies the file name of the file to be deleted.
Return Value:
TRUE - The operation was successful.
FALSE/NULL - The operation failed. Extended error status is available
using GetLastError.
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE Handle;
UNICODE_STRING FileName;
IO_STATUS_BLOCK IoStatusBlock;
FILE_DISPOSITION_INFORMATION Disposition;
BOOLEAN TranslationStatus;
RTL_RELATIVE_NAME RelativeName;
PVOID FreeBuffer;
TranslationStatus = RtlDosPathNameToNtPathName_U(
lpFileName,
&FileName,
NULL,
&RelativeName
);
if ( !TranslationStatus ) {
SetLastError(ERROR_PATH_NOT_FOUND);
return FALSE;
}
FreeBuffer = FileName.Buffer;
if ( RelativeName.RelativeName.Length ) {
FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
}
else {
RelativeName.ContainingDirectory = NULL;
}
InitializeObjectAttributes(
&Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
RelativeName.ContainingDirectory,
NULL
);
//
// Open the file for delete access
//
Status = NtOpenFile(
&Handle,
(ACCESS_MASK)DELETE,
&Obja,
&IoStatusBlock,
FILE_SHARE_DELETE |
FILE_SHARE_READ |
FILE_SHARE_WRITE,
FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT
);
RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
//
// Delete the file
//
#undef DeleteFile
Disposition.DeleteFile = TRUE;
Status = NtSetInformationFile(
Handle,
&IoStatusBlock,
&Disposition,
sizeof(Disposition),
FileDispositionInformation
);
NtClose(Handle);
if ( NT_SUCCESS(Status) ) {
return TRUE;
}
else {
BaseSetLastNTError(Status);
return FALSE;
}
}
BOOL
APIENTRY
MoveFileA(
LPCSTR lpExistingFileName,
LPCSTR lpNewFileName
)
{
return MoveFileExA( lpExistingFileName, lpNewFileName, MOVEFILE_COPY_ALLOWED );
}
BOOL
APIENTRY
MoveFileW(
LPCWSTR lpExistingFileName,
LPCWSTR lpNewFileName
)
{
return MoveFileExW( lpExistingFileName, lpNewFileName, MOVEFILE_COPY_ALLOWED );
}
BOOL
APIENTRY
MoveFileExA(
LPCSTR lpExistingFileName,
LPCSTR lpNewFileName,
DWORD dwFlags
)
/*++
Routine Description:
ANSI thunk to MoveFileW
--*/
{
PUNICODE_STRING Unicode;
UNICODE_STRING UnicodeNewFileName;
ANSI_STRING AnsiString;
NTSTATUS Status;
BOOL ReturnValue;
Unicode = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(&AnsiString,lpExistingFileName);
Status = Basep8BitStringToUnicodeString(Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_BUFFER_OVERFLOW ) {
SetLastError(ERROR_FILENAME_EXCED_RANGE);
}
else {
BaseSetLastNTError(Status);
}
return FALSE;
}
if (ARGUMENT_PRESENT( lpNewFileName )) {
RtlInitAnsiString(&AnsiString,lpNewFileName);
Status = Basep8BitStringToUnicodeString(&UnicodeNewFileName,&AnsiString,TRUE);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
}
else {
UnicodeNewFileName.Buffer = NULL;
}
ReturnValue = MoveFileExW((LPCWSTR)Unicode->Buffer,(LPCWSTR)UnicodeNewFileName.Buffer,dwFlags);
if (UnicodeNewFileName.Buffer != NULL) {
RtlFreeUnicodeString(&UnicodeNewFileName);
}
return ReturnValue;
}
#ifdef _CAIRO_
#include "iofs.h"
#endif
typedef struct _HELPER_CONTEXT {
PVOID pObjectId;
DWORD dwFlags;
} HELPER_CONTEXT, *PHELPER_CONTEXT;
DWORD
APIENTRY
BasepCrossVolumeMoveHelper(
LARGE_INTEGER TotalFileSize,
LARGE_INTEGER TotalBytesTransferred,
LARGE_INTEGER StreamSize,
LARGE_INTEGER StreamBytesTransferred,
DWORD dwStreamNumber,
DWORD dwCallbackReason,
HANDLE SourceFile,
HANDLE DestinationFile,
LPVOID lpData OPTIONAL
)
{
PHELPER_CONTEXT Context = (PHELPER_CONTEXT)lpData;
if ( dwCallbackReason == CALLBACK_STREAM_SWITCH ) {
#ifdef _CAIRO_
OBJECTID *poid;
if ( poid = Context->pObjectId ) {
RtlSetObjectId(DestinationFile, poid);
Context->pObjectId = NULL;
}
#endif
if ( !(Context->dwFlags & MOVEFILE_WRITE_THROUGH) ) {
return PROGRESS_QUIET;
}
}
else if ( dwCallbackReason == CALLBACK_CHUNK_FINISHED ) {
if ( StreamBytesTransferred.QuadPart == StreamSize.QuadPart ) {
FlushFileBuffers(DestinationFile);
}
}
return PROGRESS_CONTINUE;
}
BOOL
APIENTRY
MoveFileExW(
LPCWSTR lpExistingFileName,
LPCWSTR lpNewFileName,
DWORD dwFlags
)
/*++
Routine Description:
An existing file can be renamed using MoveFile.
Arguments:
lpExistingFileName - Supplies the name of an existing file that is to be
renamed.
lpNewFileName - Supplies the new name for the existing file. The new
name must reside in the same file system/drive as the existing
file and must not already exist.
dwFlags - Supplies optional flag bits to control the behavior of the
rename. The following bits are currently defined:
MOVEFILE_REPLACE_EXISTING - if the new file name exists, replace
it by renaming the old file name on top of the new file name.
MOVEFILE_COPY_ALLOWED - if the new file name is on a different
volume than the old file name, and causes the rename operation
to fail, then setting this flag allows the MoveFileEx API
call to simulate the rename with a call to CopyFile followed
by a call to DeleteFile to the delete the old file if the
CopyFile was successful.
MOVEFILE_DELAY_UNTIL_REBOOT - dont actually do the rename now, but
instead queue the rename so that it will happen the next time
the system boots. If this flag is set, then the lpNewFileName
parameter may be NULL, in which case a delay DeleteFile of
the old file name will occur the next time the system is
booted.
The delay rename/delete operations occur immediately after
AUTOCHK is run, but prior to creating any paging files, so
it can be used to delete paging files from previous boots
before they are reused.
MOVEFILE_WRITE_THROUGH - perform the rename operation in such a
way that the file has actually been moved on the disk before
the API returns to the caller. Note that this flag causes a
flush at the end of a copy operation (if one were allowed and
necessary), and has no effect if the rename operation is
delayed until the next reboot.
Return Value:
TRUE - The operation was successful.
FALSE/NULL - The operation failed. Extended error status is available
using GetLastError.
--*/
{
NTSTATUS Status;
BOOLEAN ReplaceIfExists;
OBJECT_ATTRIBUTES Obja;
HANDLE Handle;
UNICODE_STRING OldFileName;
UNICODE_STRING NewFileName;
IO_STATUS_BLOCK IoStatusBlock;
PFILE_RENAME_INFORMATION NewName;
BOOLEAN TranslationStatus;
RTL_RELATIVE_NAME RelativeName;
PVOID FreeBuffer;
ULONG OpenFlags;
BOOLEAN fDoCrossVolumeMove;
BOOLEAN b;
#ifdef _CAIRO_
OBJECTID oid;
OBJECTID *poid; // only can be valid when fDoCrossVolumeMove = TRUE
#else
PVOID poid = NULL;
#endif
//
// if the target is a device, do not allow the rename !
//
if ( lpNewFileName ) {
if ( RtlIsDosDeviceName_U((PWSTR)lpNewFileName) ) {
SetLastError(ERROR_ALREADY_EXISTS);
return FALSE;
}
}
if (dwFlags & MOVEFILE_REPLACE_EXISTING) {
ReplaceIfExists = TRUE;
} else {
ReplaceIfExists = FALSE;
}
TranslationStatus = RtlDosPathNameToNtPathName_U(
lpExistingFileName,
&OldFileName,
NULL,
&RelativeName
);
if ( !TranslationStatus ) {
SetLastError(ERROR_PATH_NOT_FOUND);
return FALSE;
}
FreeBuffer = OldFileName.Buffer;
if (!(dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT)) {
if ( RelativeName.RelativeName.Length ) {
OldFileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
} else {
RelativeName.ContainingDirectory = NULL;
}
InitializeObjectAttributes(
&Obja,
&OldFileName,
OBJ_CASE_INSENSITIVE,
RelativeName.ContainingDirectory,
NULL
);
//
// Open the file for delete access
//
OpenFlags = FILE_SYNCHRONOUS_IO_NONALERT |
FILE_OPEN_FOR_BACKUP_INTENT |
(dwFlags & MOVEFILE_WRITE_THROUGH) ? FILE_WRITE_THROUGH : 0;
Status = NtOpenFile(
&Handle,
#ifdef _CAIRO_
FILE_READ_ATTRIBUTES |
#endif
(ACCESS_MASK)DELETE | SYNCHRONIZE,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
OpenFlags
);
if ( !NT_SUCCESS(Status) ) {
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
BaseSetLastNTError(Status);
return FALSE;
}
}
if (!(dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT) ||
(lpNewFileName != NULL)) {
TranslationStatus = RtlDosPathNameToNtPathName_U(
lpNewFileName,
&NewFileName,
NULL,
NULL
);
if ( !TranslationStatus ) {
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
SetLastError(ERROR_PATH_NOT_FOUND);
NtClose(Handle);
return FALSE;
}
} else {
RtlInitUnicodeString( &NewFileName, NULL );
}
if (dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT) {
//
// copy allowed is not permitted on delayed renames
//
//
// (typical stevewo hack, preserved for sentimental value)
//
// If ReplaceIfExists is TRUE, prepend an exclamation point
// to the new filename in order to pass this bit of data
// along to the session manager.
//
if (ReplaceIfExists &&
(NewFileName.Length != 0)) {
PWSTR NewBuffer;
NewBuffer = RtlAllocateHeap( RtlProcessHeap(),
MAKE_TAG( TMP_TAG ),
NewFileName.Length + sizeof(WCHAR) );
if (NewBuffer != NULL) {
NewBuffer[0] = L'!';
CopyMemory(&NewBuffer[1], NewFileName.Buffer, NewFileName.Length);
NewFileName.Length += sizeof(WCHAR);
NewFileName.MaximumLength += sizeof(WCHAR);
RtlFreeHeap(RtlProcessHeap(), 0, NewFileName.Buffer);
NewFileName.Buffer = NewBuffer;
}
}
if ( dwFlags & MOVEFILE_COPY_ALLOWED ) {
Status = STATUS_INVALID_PARAMETER;
} else {
Status = BasepMoveFileDelayed(&OldFileName, &NewFileName);
}
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
RtlFreeHeap(RtlProcessHeap(), 0, NewFileName.Buffer);
if (NT_SUCCESS(Status)) {
return(TRUE);
} else {
BaseSetLastNTError(Status);
return(FALSE);
}
}
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
FreeBuffer = NewFileName.Buffer;
NewName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), NewFileName.Length+sizeof(*NewName));
if (NewName != NULL) {
RtlMoveMemory( NewName->FileName, NewFileName.Buffer, NewFileName.Length );
NewName->ReplaceIfExists = ReplaceIfExists;
NewName->RootDirectory = NULL;
NewName->FileNameLength = NewFileName.Length;
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
Status = NtSetInformationFile(
Handle,
&IoStatusBlock,
NewName,
NewFileName.Length+sizeof(*NewName),
FileRenameInformation
);
RtlFreeHeap(RtlProcessHeap(), 0, NewName);
} else {
Status = STATUS_NO_MEMORY;
}
fDoCrossVolumeMove = (Status == STATUS_NOT_SAME_DEVICE) &&
(dwFlags & MOVEFILE_COPY_ALLOWED);
#ifdef _CAIRO_
if (fDoCrossVolumeMove)
{
// Get the object'd OBJECTID
poid = RtlQueryObjectId(Handle, &oid) == STATUS_SUCCESS ? &oid : NULL;
}
#endif
NtClose(Handle);
if ( NT_SUCCESS(Status) ) {
return TRUE;
} else if ( fDoCrossVolumeMove ) {
HELPER_CONTEXT Context;
Context.pObjectId = poid;
Context.dwFlags = dwFlags;
b = CopyFileExW(
lpExistingFileName,
lpNewFileName,
poid || dwFlags & MOVEFILE_WRITE_THROUGH ? BasepCrossVolumeMoveHelper : NULL,
&Context,
NULL,
ReplaceIfExists ? 0 : COPY_FILE_FAIL_IF_EXISTS
);
if ( b ) {
//
// the copy worked... Delete the source of the rename
// if it fails, try a set attributes and then a delete
//
if (!DeleteFileW( lpExistingFileName ) ) {
//
// If the delete fails, we will return true, but possibly
// leave the source dangling
//
SetFileAttributesW(lpExistingFileName,FILE_ATTRIBUTE_NORMAL);
DeleteFileW( lpExistingFileName );
}
return TRUE;
} else {
return FALSE;
}
} else {
BaseSetLastNTError(Status);
return FALSE;
}
}
NTSTATUS
BasepMoveFileDelayed(
IN PUNICODE_STRING OldFileName,
IN PUNICODE_STRING NewFileName
)
/*++
Routine Description:
Appends the given delayed move file operation to the registry
value that contains the list of move file operations to be
performed on the next boot.
Arguments:
OldFileName - Supplies the old file name
NewFileName - Supplies the new file name
Return Value:
NTSTATUS
--*/
{
OBJECT_ATTRIBUTES Obja;
UNICODE_STRING KeyName;
UNICODE_STRING ValueName;
HANDLE KeyHandle;
PWSTR ValueData, s;
PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
ULONG ValueLength = 1024;
ULONG ReturnedLength;
NTSTATUS Status;
RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager" );
RtlInitUnicodeString( &ValueName, L"PendingFileRenameOperations" );
InitializeObjectAttributes(
&Obja,
&KeyName,
OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtCreateKey( &KeyHandle,
GENERIC_READ | GENERIC_WRITE,
&Obja,
0,
NULL,
0,
NULL
);
if ( Status == STATUS_ACCESS_DENIED ) {
Status = NtCreateKey( &KeyHandle,
GENERIC_READ | GENERIC_WRITE,
&Obja,
0,
NULL,
REG_OPTION_BACKUP_RESTORE,
NULL
);
}
if (NT_SUCCESS( Status )) {
retry:
ValueInfo = RtlAllocateHeap(RtlProcessHeap(),
MAKE_TAG(TMP_TAG),
ValueLength + OldFileName->Length + sizeof(WCHAR) +
NewFileName->Length + 2*sizeof(WCHAR));
if (ValueInfo == NULL) {
NtClose(KeyHandle);
return(STATUS_NO_MEMORY);
}
//
// File rename operations are stored in the registry in a
// single MULTI_SZ value. This allows the renames to be
// performed in the same order that they were originally
// requested. Each rename operation consists of a pair of
// NULL-terminated strings.
//
Status = NtQueryValueKey(KeyHandle,
&ValueName,
KeyValuePartialInformation,
ValueInfo,
ValueLength,
&ReturnedLength);
if (Status == STATUS_BUFFER_OVERFLOW) {
//
// The existing value is too large for our buffer.
// Retry with a larger buffer.
//
ValueLength = ReturnedLength;
RtlFreeHeap(RtlProcessHeap(), 0, ValueInfo);
goto retry;
}
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
//
// The value does not currently exist. Create the
// value with our data.
//
s = ValueData = (PWSTR)ValueInfo;
} else if (NT_SUCCESS(Status)) {
//
// A value already exists, append our two strings to the
// MULTI_SZ.
//
ValueData = (PWSTR)(&ValueInfo->Data);
s = (PWSTR)((PCHAR)ValueData + ValueInfo->DataLength) - 1;
} else {
NtClose(KeyHandle);
RtlFreeHeap(RtlProcessHeap(), 0, ValueInfo);
return(Status);
}
CopyMemory(s, OldFileName->Buffer, OldFileName->Length);
s += (OldFileName->Length/sizeof(WCHAR));
*s++ = L'\0';
CopyMemory(s, NewFileName->Buffer, NewFileName->Length);
s += (NewFileName->Length/sizeof(WCHAR));
*s++ = L'\0';
*s++ = L'\0';
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_MULTI_SZ,
ValueData,
(s-ValueData)*sizeof(WCHAR));
NtClose(KeyHandle);
RtlFreeHeap(RtlProcessHeap(), 0, ValueInfo);
}
return(Status);
}
DWORD
WINAPI
GetCompressedFileSizeA(
LPCSTR lpFileName,
LPDWORD lpFileSizeHigh
)
{
PUNICODE_STRING Unicode;
ANSI_STRING AnsiString;
NTSTATUS Status;
Unicode = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(&AnsiString,lpFileName);
Status = Basep8BitStringToUnicodeString(Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_BUFFER_OVERFLOW ) {
SetLastError(ERROR_FILENAME_EXCED_RANGE);
}
else {
BaseSetLastNTError(Status);
}
return (DWORD)-1;
}
return ( GetCompressedFileSizeW((LPCWSTR)Unicode->Buffer,lpFileSizeHigh) );
return INVALID_FILE_SIZE;
}
DWORD
WINAPI
GetCompressedFileSizeW(
LPCWSTR lpFileName,
LPDWORD lpFileSizeHigh
)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES Obja;
HANDLE Handle;
UNICODE_STRING FileName;
IO_STATUS_BLOCK IoStatusBlock;
FILE_COMPRESSION_INFORMATION CompressionInfo;
BOOLEAN TranslationStatus;
RTL_RELATIVE_NAME RelativeName;
PVOID FreeBuffer;
DWORD FileSizeLow;
TranslationStatus = RtlDosPathNameToNtPathName_U(
lpFileName,
&FileName,
NULL,
&RelativeName
);
if ( !TranslationStatus ) {
SetLastError(ERROR_PATH_NOT_FOUND);
return (DWORD)-1;
}
FreeBuffer = FileName.Buffer;
if ( RelativeName.RelativeName.Length ) {
FileName = *(PUNICODE_STRING)&RelativeName.RelativeName;
}
else {
RelativeName.ContainingDirectory = NULL;
}
InitializeObjectAttributes(
&Obja,
&FileName,
OBJ_CASE_INSENSITIVE,
RelativeName.ContainingDirectory,
NULL
);
//
// Open the file
//
Status = NtOpenFile(
&Handle,
(ACCESS_MASK)FILE_READ_ATTRIBUTES,
&Obja,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN_FOR_BACKUP_INTENT
);
RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return (DWORD)-1;
}
//
// Get the compressed file size.
//
Status = NtQueryInformationFile(
Handle,
&IoStatusBlock,
&CompressionInfo,
sizeof(CompressionInfo),
FileCompressionInformation
);
if ( !NT_SUCCESS(Status) ) {
FileSizeLow = GetFileSize(Handle,lpFileSizeHigh);
NtClose(Handle);
return FileSizeLow;
}
NtClose(Handle);
if ( ARGUMENT_PRESENT(lpFileSizeHigh) ) {
*lpFileSizeHigh = (DWORD)CompressionInfo.CompressedFileSize.HighPart;
}
if (CompressionInfo.CompressedFileSize.LowPart == -1 ) {
SetLastError(0);
}
return CompressionInfo.CompressedFileSize.LowPart;
}