Exemplo n.º 1
0
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;
    }
}
Exemplo n.º 2
0
 /***********************************************************************
  *           GetTempFileNameW   (KERNEL32.@)
  */
UINT WINAPI
GetTempFileNameW(IN LPCWSTR lpPathName,
                 IN LPCWSTR lpPrefixString,
                 IN UINT uUnique,
                 OUT LPWSTR lpTempFileName)
{
    CHAR * Let;
    HANDLE TempFile;
    UINT ID, Num = 0;
    CHAR IDString[5];
    WCHAR * TempFileName;
    BASE_API_MESSAGE ApiMessage;
    PBASE_GET_TEMP_FILE GetTempFile = &ApiMessage.Data.GetTempFileRequest;
    DWORD FileAttributes, LastError;
    UNICODE_STRING PathNameString, PrefixString;
    static const WCHAR Ext[] = { L'.', 't', 'm', 'p', UNICODE_NULL };

    RtlInitUnicodeString(&PathNameString, lpPathName);
    if (PathNameString.Length == 0 || PathNameString.Buffer[(PathNameString.Length / sizeof(WCHAR)) - 1] != L'\\')
    {
        PathNameString.Length += sizeof(WCHAR);
    }

    /* lpTempFileName must be able to contain: PathName, Prefix (3), number(4), .tmp(4) & \0(1)
     * See: http://msdn.microsoft.com/en-us/library/aa364991%28v=vs.85%29.aspx
     */
    if (PathNameString.Length > (MAX_PATH - 3 - 4 - 4 - 1) * sizeof(WCHAR))
    {
        SetLastError(ERROR_BUFFER_OVERFLOW);
        return 0;
    }
 
    /* If PathName and TempFileName aren't the same buffer, move PathName to TempFileName */
    if (lpPathName != lpTempFileName)
    {
        memmove(lpTempFileName, PathNameString.Buffer, PathNameString.Length);
    }

    /* PathName MUST BE a path. Check it */
    lpTempFileName[(PathNameString.Length / sizeof(WCHAR)) - 1] = UNICODE_NULL;
    FileAttributes = GetFileAttributesW(lpTempFileName);
    if (FileAttributes == INVALID_FILE_ATTRIBUTES)
    {
        /* Append a '\' if necessary */
        lpTempFileName[(PathNameString.Length / sizeof(WCHAR)) - 1] = L'\\';
        lpTempFileName[PathNameString.Length / sizeof(WCHAR)] = UNICODE_NULL;
        FileAttributes = GetFileAttributesW(lpTempFileName);
        if (FileAttributes == INVALID_FILE_ATTRIBUTES)
        {
            SetLastError(ERROR_DIRECTORY);
            return 0;
        }
    }
    if (!(FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
    {
        SetLastError(ERROR_DIRECTORY);
        return 0;
    }
 
    /* Make sure not to mix path & prefix */
    lpTempFileName[(PathNameString.Length / sizeof(WCHAR)) - 1] = L'\\';
    RtlInitUnicodeString(&PrefixString, lpPrefixString);
    if (PrefixString.Length > 3 * sizeof(WCHAR))
    {
        PrefixString.Length = 3 * sizeof(WCHAR);
    }
 
    /* Append prefix to path */
    TempFileName = lpTempFileName + PathNameString.Length / sizeof(WCHAR);
    memmove(TempFileName, PrefixString.Buffer, PrefixString.Length);
    TempFileName += PrefixString.Length / sizeof(WCHAR);
 
    /* Then, generate filename */
    do
    {
        /* If user didn't gave any ID, ask Csrss to give one */
        if (!uUnique)
        {
            CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
                                NULL,
                                CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetTempFile),
                                sizeof(BASE_GET_TEMP_FILE));
            if (GetTempFile->UniqueID == 0)
            {
                Num++;
                continue;
            }
 
            ID = GetTempFile->UniqueID;
        }
        else
        {
            ID = uUnique;
        }
 
        /* Convert that ID to wchar */
        RtlIntegerToChar(ID, 0x10, sizeof(IDString), IDString);
        Let = IDString;
        do
        {
            *(TempFileName++) = RtlAnsiCharToUnicodeChar(&Let);
        } while (*Let != 0);
 
        /* Append extension & UNICODE_NULL */
        memmove(TempFileName, Ext, sizeof(Ext));

        /* If user provided its ID, just return */
        if (uUnique)
        {
            return uUnique;
        }

        /* Then, try to create file */
        if (!RtlIsDosDeviceName_U(lpTempFileName))
        {
            TempFile = CreateFileW(lpTempFileName,
                                   GENERIC_READ,
                                   0,
                                   NULL,
                                   CREATE_NEW,
                                   FILE_ATTRIBUTE_NORMAL,
                                   0);
            if (TempFile != INVALID_HANDLE_VALUE)
            {
                NtClose(TempFile);
                DPRINT("Temp file: %S\n", lpTempFileName);
                return ID;
            }

            LastError = GetLastError();
            /* There is no need to recover from those errors, they would hit next step */
            if (LastError == ERROR_INVALID_PARAMETER || LastError == ERROR_CANNOT_MAKE ||
                LastError == ERROR_WRITE_PROTECT || LastError == ERROR_NETWORK_ACCESS_DENIED ||
                LastError == ERROR_DISK_FULL || LastError == ERROR_INVALID_NAME ||
                LastError == ERROR_BAD_PATHNAME || LastError == ERROR_NO_INHERITANCE ||
                LastError == ERROR_DISK_CORRUPT ||
                (LastError == ERROR_ACCESS_DENIED && NtCurrentTeb()->LastStatusValue != STATUS_FILE_IS_A_DIRECTORY))
            {
                break;
            }
        }
        Num++;
    } while (Num & 0xFFFF);
 
    return 0;
}
Exemplo n.º 3
0
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;
        }
}
Exemplo n.º 4
0
Arquivo: move.c Projeto: RPG-7/reactos
/*
 * @implemented
 */
BOOL
WINAPI
MoveFileWithProgressW(IN LPCWSTR lpExistingFileName,
                      IN LPCWSTR lpNewFileName,
                      IN LPPROGRESS_ROUTINE lpProgressRoutine,
                      IN LPVOID lpData,
                      IN DWORD dwFlags)
{
    NTSTATUS Status;
    PWSTR NewBuffer;
    IO_STATUS_BLOCK IoStatusBlock;
    COPY_PROGRESS_CONTEXT CopyContext;
    OBJECT_ATTRIBUTES ObjectAttributes;
    PFILE_RENAME_INFORMATION RenameInfo;
    UNICODE_STRING NewPathU, ExistingPathU;
    FILE_ATTRIBUTE_TAG_INFORMATION FileAttrTagInfo;
    HANDLE SourceHandle = INVALID_HANDLE_VALUE, NewHandle, ExistingHandle;
    BOOL Ret = FALSE, ReplaceIfExists, DelayUntilReboot, AttemptReopenWithoutReparse;

    DPRINT("MoveFileWithProgressW(%S, %S, %p, %p, %x)\n", lpExistingFileName, lpNewFileName, lpProgressRoutine, lpData, dwFlags);

    NewPathU.Buffer = NULL;
    ExistingPathU.Buffer = NULL;

    _SEH2_TRY
    {
        /* Don't allow renaming to a disk */
        if (lpNewFileName && RtlIsDosDeviceName_U(lpNewFileName))
        {
            BaseSetLastNTError(STATUS_OBJECT_NAME_COLLISION);
            _SEH2_LEAVE;
        }

        ReplaceIfExists = !!(dwFlags & MOVEFILE_REPLACE_EXISTING);

        /* Get file path */
        if (!RtlDosPathNameToNtPathName_U(lpExistingFileName, &ExistingPathU, NULL, NULL))
        {
            BaseSetLastNTError(STATUS_OBJECT_PATH_NOT_FOUND);
            _SEH2_LEAVE;
        }

        /* Sanitize input */
        DelayUntilReboot = !!(dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT);
        if (DelayUntilReboot && (dwFlags & MOVEFILE_CREATE_HARDLINK))
        {
            BaseSetLastNTError(STATUS_INVALID_PARAMETER);
            _SEH2_LEAVE;
        }

        /* Unless we manage a proper opening, we'll attempt to reopen without reparse support */
        AttemptReopenWithoutReparse = TRUE;
        InitializeObjectAttributes(&ObjectAttributes,
                                   &ExistingPathU,
                                   OBJ_CASE_INSENSITIVE,
                                   NULL,
                                   NULL);
        /* Attempt to open source file */
        Status = NtOpenFile(&SourceHandle,
                            FILE_READ_ATTRIBUTES | DELETE | SYNCHRONIZE, 
                            &ObjectAttributes,
                            &IoStatusBlock,
                            FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                            FILE_OPEN_FOR_BACKUP_INTENT | ((dwFlags & MOVEFILE_WRITE_THROUGH) ? FILE_WRITE_THROUGH : 0));
        if (!NT_SUCCESS(Status))
        {
            /* If we failed and the file doesn't exist, don't attempt to reopen without reparse */
            if (DelayUntilReboot &&
                (Status == STATUS_SHARING_VIOLATION || Status == STATUS_OBJECT_NAME_NOT_FOUND || Status == STATUS_OBJECT_PATH_NOT_FOUND))
            {
                /* Here we don't fail completely, as we postpone the operation to reboot
                 * File might exist afterwards, and we don't need a handle here
                 */
                SourceHandle = INVALID_HANDLE_VALUE;
                AttemptReopenWithoutReparse = FALSE;
            }
            /* If we failed for any reason than unsupported reparse, fail completely */
            else if (Status != STATUS_INVALID_PARAMETER)
            {
                BaseSetLastNTError(Status);
                _SEH2_LEAVE;
            }
        }
        else
        {
            /* We managed to open, so query information */
            Status = NtQueryInformationFile(SourceHandle,
                                            &IoStatusBlock,
                                            &FileAttrTagInfo,
                                            sizeof(FILE_ATTRIBUTE_TAG_INFORMATION),
                                            FileAttributeTagInformation);
            if (!NT_SUCCESS(Status))
            {
                /* Do not tolerate any other error than something related to not supported operation */
                if (Status != STATUS_NOT_IMPLEMENTED && Status != STATUS_INVALID_PARAMETER)
                {
                    BaseSetLastNTError(Status);
                    _SEH2_LEAVE;
                }

                /* Not a reparse point, no need to reopen, it's fine */
                AttemptReopenWithoutReparse = FALSE;
            }
            /* Validate the reparse point (do we support it?) */
            else if (FileAttrTagInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT &&
                     FileAttrTagInfo.ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
            {
                NtClose(SourceHandle);
                SourceHandle = INVALID_HANDLE_VALUE;
            }
        }

        /* Simply reopen if required */
        if (AttemptReopenWithoutReparse)
        {
            Status = NtOpenFile(&SourceHandle,
                                DELETE | SYNCHRONIZE,
                                &ObjectAttributes,
                                &IoStatusBlock,
                                FILE_SHARE_READ | FILE_SHARE_WRITE,
                                ((dwFlags & MOVEFILE_WRITE_THROUGH) ? FILE_WRITE_THROUGH : 0));
            if (!NT_SUCCESS(Status))
            {
                BaseSetLastNTError(Status);
                _SEH2_LEAVE;
            }
        }

        /* Nullify string if we're to use it */
        if (DelayUntilReboot && !lpNewFileName)
        {
            RtlInitUnicodeString(&NewPathU, 0);
        }
        /* Check whether path exists */
        else if (!RtlDosPathNameToNtPathName_U(lpNewFileName, &NewPathU, 0, 0))
        {
            BaseSetLastNTError(STATUS_OBJECT_PATH_NOT_FOUND);
            _SEH2_LEAVE;
        }

        /* Handle postponed renaming */
        if (DelayUntilReboot)
        {
            /* If new file exists and we're allowed to replace, then mark the path with ! */
            if (ReplaceIfExists && NewPathU.Length)
            {
                NewBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NewPathU.Length + sizeof(WCHAR));
                if (NewBuffer == NULL)
                {
                    BaseSetLastNTError(STATUS_NO_MEMORY);
                    _SEH2_LEAVE;
                }

                NewBuffer[0] = L'!';
                RtlCopyMemory(&NewBuffer[1], NewPathU.Buffer, NewPathU.Length);
                NewPathU.Length += sizeof(WCHAR);
                NewPathU.MaximumLength += sizeof(WCHAR);
                RtlFreeHeap(RtlGetProcessHeap(), 0, NewPathU.Buffer);
                NewPathU.Buffer = NewBuffer;
            }

            /* Check whether 'copy' renaming is allowed if required */
            if (RtlDetermineDosPathNameType_U(lpExistingFileName) == RtlPathTypeUncAbsolute || dwFlags & MOVEFILE_COPY_ALLOWED)
            {
                Status = STATUS_INVALID_PARAMETER;
            }
            else
            {
                /* First, probe 2nd key to see whether it exists - if so, it will be appended there */
                Status = BasepMoveFileDelayed(&ExistingPathU, &NewPathU, 2, FALSE);
                if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
                {
                    /* If doesn't exist, append to first key first, creating it if it doesn't exist */
                    Status = BasepMoveFileDelayed(&ExistingPathU, &NewPathU, 1, TRUE);

                    if (Status == STATUS_INSUFFICIENT_RESOURCES)
                    {
                        /* If it failed because it's too big, then create 2nd key and put it there */
                        Status = BasepMoveFileDelayed(&ExistingPathU, &NewPathU, 2, TRUE);
                    }
                }
            }

            /* If we failed at some point, return the error */
            if (!NT_SUCCESS(Status))
            {
                BaseSetLastNTError(Status);
                _SEH2_LEAVE;
            }

            Ret = TRUE;
            _SEH2_LEAVE;
        }

        /* At that point, we MUST have a source handle */
        ASSERT(SourceHandle != INVALID_HANDLE_VALUE);

        /* Allocate renaming buffer and fill it */
        RenameInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, NewPathU.Length + sizeof(FILE_RENAME_INFORMATION));
        if (RenameInfo == NULL)
        {
            BaseSetLastNTError(STATUS_NO_MEMORY);
            _SEH2_LEAVE;
        }

        RtlCopyMemory(&RenameInfo->FileName, NewPathU.Buffer, NewPathU.Length);
        RenameInfo->ReplaceIfExists = ReplaceIfExists;
        RenameInfo->RootDirectory = 0;
        RenameInfo->FileNameLength = NewPathU.Length;

        /* Attempt to rename the file */
        Status = NtSetInformationFile(SourceHandle,
                                      &IoStatusBlock,
                                      RenameInfo,
                                      NewPathU.Length + sizeof(FILE_RENAME_INFORMATION),
                                      ((dwFlags & MOVEFILE_CREATE_HARDLINK) ? FileLinkInformation : FileRenameInformation));
        RtlFreeHeap(RtlGetProcessHeap(), 0, RenameInfo);
        if (NT_SUCCESS(Status))
        {
            /* If it succeed, all fine, quit */
            Ret = TRUE;
            _SEH2_LEAVE;
        }
        /* If we failed for any other reason than not the same device, fail
         * If we failed because of different devices, only allow renaming if user allowed copy
         */
        if (Status != STATUS_NOT_SAME_DEVICE || !(dwFlags & MOVEFILE_COPY_ALLOWED))
        {
            /* ReactOS hack! To be removed once all FSD have proper renaming support
             * Just leave status to error and leave 
             */
            if (Status == STATUS_NOT_IMPLEMENTED)
            {
                DPRINT1("Forcing copy, renaming not supported by FSD\n");
            }
            else
            {
                BaseSetLastNTError(Status);
                _SEH2_LEAVE;
            }
        }

        /* Close source file */
        NtClose(SourceHandle);
        SourceHandle = INVALID_HANDLE_VALUE;

        /* Issue the copy of the file */
        CopyContext.Flags = dwFlags;
        CopyContext.UserRoutine = lpProgressRoutine;
        CopyContext.UserData = lpData;
        NewHandle = INVALID_HANDLE_VALUE;
        ExistingHandle = INVALID_HANDLE_VALUE;

        Ret = BasepCopyFileExW(lpExistingFileName,
                               lpNewFileName,
                               BasepMoveFileCopyProgress,
                               &CopyContext,
                               NULL,
                               (ReplaceIfExists == 0) | COPY_FILE_OPEN_SOURCE_FOR_WRITE,
                               0,
                               &ExistingHandle,
                               &NewHandle);
        if (!Ret)
        {
            /* If it failed, don't leak any handle */
            if (ExistingHandle != INVALID_HANDLE_VALUE)
            {
                CloseHandle(ExistingHandle);
                ExistingHandle = INVALID_HANDLE_VALUE;
            }
        }
        else if (ExistingHandle != INVALID_HANDLE_VALUE)
        {
            if (NewHandle != INVALID_HANDLE_VALUE)
            {
                /* If copying succeed, notify */
                Status = BasepNotifyTrackingService(&ExistingHandle, &ObjectAttributes, NewHandle, &NewPathU);
                if (!NT_SUCCESS(Status))
                {
                    /* Fail in case it had to succeed */
                    if (dwFlags & MOVEFILE_FAIL_IF_NOT_TRACKABLE)
                    {
                        if (NewHandle != INVALID_HANDLE_VALUE)
                            CloseHandle(NewHandle);
                        NewHandle = INVALID_HANDLE_VALUE;
                        DeleteFileW(lpNewFileName);
                        Ret = FALSE;
                        BaseSetLastNTError(Status);
                    }
                }
            }

            CloseHandle(ExistingHandle);
            ExistingHandle = INVALID_HANDLE_VALUE;
        }

        /* In case copy worked, close file */
        if (NewHandle != INVALID_HANDLE_VALUE)
        {
            CloseHandle(NewHandle);
            NewHandle = INVALID_HANDLE_VALUE;
        }

        /* If it succeed, delete source file */
        if (Ret)
        {
            if (!DeleteFileW(lpExistingFileName))
            {
                /* Reset file attributes if required */
                SetFileAttributesW(lpExistingFileName, FILE_ATTRIBUTE_NORMAL);
                DeleteFileW(lpExistingFileName);
            }
        }
    }
    _SEH2_FINALLY
    {
        if (SourceHandle != INVALID_HANDLE_VALUE)
            NtClose(SourceHandle);

        RtlFreeHeap(RtlGetProcessHeap(), 0, ExistingPathU.Buffer);
        RtlFreeHeap(RtlGetProcessHeap(), 0, NewPathU.Buffer);
    }
    _SEH2_END;

    return Ret;
}