예제 #1
0
/**
 * Loads plugins from the default plugins directory.
 */
VOID PhLoadPlugins(
    VOID
    )
{
    HANDLE pluginsDirectoryHandle;
    PPH_STRING pluginsDirectory;

    pluginsDirectory = PhGetStringSetting(L"PluginsDirectory");

    if (RtlDetermineDosPathNameType_U(pluginsDirectory->Buffer) == RtlPathTypeRelative)
    {
        // Not absolute. Make sure it is.
        PluginsDirectory = PhConcatStrings(4, PhApplicationDirectory->Buffer, L"\\", pluginsDirectory->Buffer, L"\\");
        PhDereferenceObject(pluginsDirectory);
    }
    else
    {
        PluginsDirectory = pluginsDirectory;
    }

    if (NT_SUCCESS(PhCreateFileWin32(
        &pluginsDirectoryHandle,
        PluginsDirectory->Buffer,
        FILE_GENERIC_READ,
        0,
        FILE_SHARE_READ,
        FILE_OPEN,
        FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
        )))
    {
        UNICODE_STRING pattern = RTL_CONSTANT_STRING(L"*.dll");

        PhEnumDirectoryFile(pluginsDirectoryHandle, &pattern, EnumPluginsDirectoryCallback, NULL);
        NtClose(pluginsDirectoryHandle);
    }

    // When we loaded settings before, we didn't know about plugin settings, so they
    // went into the ignored settings list. Now that they've had a chance to add
    // settings, we should scan the ignored settings list and move the settings to
    // the right places.
    if (PhSettingsFileName)
        PhConvertIgnoredSettings();

    PhpExecuteCallbackForAllPlugins(PluginCallbackLoad);
}
예제 #2
0
파일: vista.c 프로젝트: hoangduit/reactos
/*
 * @implemented
 */
BOOLEAN
WINAPI
CreateSymbolicLinkW(IN LPCWSTR lpSymlinkFileName,
                    IN LPCWSTR lpTargetFileName,
                    IN DWORD dwFlags)
{
    IO_STATUS_BLOCK IoStatusBlock;
    OBJECT_ATTRIBUTES ObjectAttributes;
    HANDLE hSymlink = NULL;
    UNICODE_STRING SymlinkFileName = { 0, 0, NULL };
    UNICODE_STRING TargetFileName = { 0, 0, NULL };
    BOOLEAN bAllocatedTarget = FALSE, bRelativePath = FALSE;
    LPWSTR lpTargetFullFileName = NULL;
    SIZE_T cbPrintName;
    SIZE_T cbReparseData;
    PREPARSE_DATA_BUFFER pReparseData = NULL;
    PBYTE pBufTail;
    NTSTATUS Status;
    ULONG dwCreateOptions;
    DWORD dwErr;

    if(!lpSymlinkFileName || !lpTargetFileName || (dwFlags | SYMBOLIC_LINK_FLAG_DIRECTORY) != SYMBOLIC_LINK_FLAG_DIRECTORY)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }

    if(dwFlags & SYMBOLIC_LINK_FLAG_DIRECTORY)
        dwCreateOptions = FILE_DIRECTORY_FILE;
    else
        dwCreateOptions = FILE_NON_DIRECTORY_FILE;

    switch(RtlDetermineDosPathNameType_U(lpTargetFileName))
    {
    case RtlPathTypeUnknown:
    case RtlPathTypeRooted:
    case RtlPathTypeRelative:
        bRelativePath = TRUE;
        RtlInitUnicodeString(&TargetFileName, lpTargetFileName);
        break;

    case RtlPathTypeDriveRelative:
        {
            LPWSTR FilePart;
            SIZE_T cchTargetFullFileName;

            cchTargetFullFileName = GetFullPathNameW(lpTargetFileName, 0, NULL, &FilePart);

            if(cchTargetFullFileName == 0)
            {
                dwErr = GetLastError();
                goto Cleanup;
            }

            lpTargetFullFileName = RtlAllocateHeap(RtlGetProcessHeap(), 0, cchTargetFullFileName * sizeof(WCHAR));

            if(lpTargetFullFileName == NULL)
            {
                dwErr = ERROR_NOT_ENOUGH_MEMORY;
                goto Cleanup;
            }

            if(GetFullPathNameW(lpTargetFileName, cchTargetFullFileName, lpTargetFullFileName, &FilePart) == 0)
            {
                dwErr = GetLastError();
                goto Cleanup;
            }
        }

        lpTargetFileName = lpTargetFullFileName;

        // fallthrough

    case RtlPathTypeUncAbsolute:
    case RtlPathTypeDriveAbsolute:
    case RtlPathTypeLocalDevice:
    case RtlPathTypeRootLocalDevice:
    default:
        if(!RtlDosPathNameToNtPathName_U(lpTargetFileName, &TargetFileName, NULL, NULL))
        {
            bAllocatedTarget = TRUE;
            dwErr = ERROR_INVALID_PARAMETER;
            goto Cleanup;
        }
    }

    cbPrintName = wcslen(lpTargetFileName) * sizeof(WCHAR);
    cbReparseData = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + TargetFileName.Length + cbPrintName;
    pReparseData = RtlAllocateHeap(RtlGetProcessHeap(), 0, cbReparseData);

    if(pReparseData == NULL)
    {
        dwErr = ERROR_NOT_ENOUGH_MEMORY;
        goto Cleanup;
    }

    pBufTail = (PBYTE)(pReparseData->SymbolicLinkReparseBuffer.PathBuffer);

    pReparseData->ReparseTag = (ULONG)IO_REPARSE_TAG_SYMLINK;
    pReparseData->ReparseDataLength = (USHORT)cbReparseData - REPARSE_DATA_BUFFER_HEADER_SIZE;
    pReparseData->Reserved = 0;

    pReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
    pReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength = TargetFileName.Length;
    pBufTail += pReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset;
    RtlCopyMemory(pBufTail, TargetFileName.Buffer, TargetFileName.Length);

    pReparseData->SymbolicLinkReparseBuffer.PrintNameOffset = pReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
    pReparseData->SymbolicLinkReparseBuffer.PrintNameLength = (USHORT)cbPrintName;
    pBufTail += pReparseData->SymbolicLinkReparseBuffer.PrintNameOffset;
    RtlCopyMemory(pBufTail, lpTargetFileName, cbPrintName);

    pReparseData->SymbolicLinkReparseBuffer.Flags = 0;

    if(bRelativePath)
        pReparseData->SymbolicLinkReparseBuffer.Flags |= 1; // TODO! give this lone flag a name

    if(!RtlDosPathNameToNtPathName_U(lpSymlinkFileName, &SymlinkFileName, NULL, NULL))
    {
        dwErr = ERROR_PATH_NOT_FOUND;
        goto Cleanup;
    }

    InitializeObjectAttributes(&ObjectAttributes, &SymlinkFileName, OBJ_CASE_INSENSITIVE, NULL, NULL);

    Status = NtCreateFile
    (
        &hSymlink,
        FILE_WRITE_ATTRIBUTES | DELETE | SYNCHRONIZE,
        &ObjectAttributes,
        &IoStatusBlock,
        NULL,
        FILE_ATTRIBUTE_NORMAL,
        0,
        FILE_CREATE,
        FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT | dwCreateOptions,
        NULL,
        0
    );

    if(!NT_SUCCESS(Status))
    {
        dwErr = RtlNtStatusToDosError(Status);
        goto Cleanup;
    }

    Status = NtFsControlFile
    (
        hSymlink,
        NULL,
        NULL,
        NULL,
        &IoStatusBlock,
        FSCTL_SET_REPARSE_POINT,
        pReparseData,
        cbReparseData,
        NULL,
        0
    );

    if(!NT_SUCCESS(Status))
    {
        FILE_DISPOSITION_INFORMATION DispInfo;
        DispInfo.DeleteFile = TRUE;
        NtSetInformationFile(hSymlink, &IoStatusBlock, &DispInfo, sizeof(DispInfo), FileDispositionInformation);

        dwErr = RtlNtStatusToDosError(Status);
        goto Cleanup;
    }

    dwErr = NO_ERROR;

Cleanup:
    if(hSymlink)
        NtClose(hSymlink);

    RtlFreeUnicodeString(&SymlinkFileName);
    if (bAllocatedTarget)
    {
        RtlFreeHeap(RtlGetProcessHeap(),
                    0,
                    TargetFileName.Buffer);
    }

    if(lpTargetFullFileName)
        RtlFreeHeap(RtlGetProcessHeap(), 0, lpTargetFullFileName);

    if(pReparseData)
        RtlFreeHeap(RtlGetProcessHeap(), 0, pReparseData);

    if(dwErr)
    {
        SetLastError(dwErr);
        return FALSE;
    }

    return TRUE;
}
예제 #3
0
파일: npipe.c 프로젝트: RareHare/reactos
/*
 * @implemented
 */
BOOL
WINAPI
WaitNamedPipeW(LPCWSTR lpNamedPipeName,
               DWORD nTimeOut)
{
    UNICODE_STRING NamedPipeName, NewName, DevicePath, PipePrefix;
    ULONG NameLength;
    ULONG i;
    PWCHAR p;
    ULONG Type;
    OBJECT_ATTRIBUTES ObjectAttributes;
    NTSTATUS Status;
    HANDLE FileHandle;
    IO_STATUS_BLOCK IoStatusBlock;
    ULONG WaitPipeInfoSize;
    PFILE_PIPE_WAIT_FOR_BUFFER WaitPipeInfo;

    /* Start by making a unicode string of the name */
    TRACE("Sent path: %S\n", lpNamedPipeName);
    RtlCreateUnicodeString(&NamedPipeName, lpNamedPipeName);
    NameLength = NamedPipeName.Length / sizeof(WCHAR);

    /* All slashes must become backslashes */
    for (i = 0; i < NameLength; i++)
    {
        /* Check and convert */
        if (NamedPipeName.Buffer[i] == L'/') NamedPipeName.Buffer[i] = L'\\';
    }

    /* Find the path type of the name we were given */
    NewName = NamedPipeName;
    Type = RtlDetermineDosPathNameType_U(lpNamedPipeName);

    /* Check if this was a device path, ie : "\\.\pipe\name" */
    if (Type == RtlPathTypeLocalDevice)
    {
        /* Make sure it's a valid prefix */
        RtlInitUnicodeString(&PipePrefix, L"\\\\.\\pipe\\");
        RtlPrefixString((PANSI_STRING)&PipePrefix, (PANSI_STRING)&NewName, TRUE);

        /* Move past it */
        NewName.Buffer += 9;
        NewName.Length -= 9 * sizeof(WCHAR);

        /* Initialize the Dos Devices name */
        TRACE("NewName: %wZ\n", &NewName);
        RtlInitUnicodeString(&DevicePath, L"\\DosDevices\\pipe\\");
    }
    else if (Type == RtlPathTypeRootLocalDevice)
    {
        /* The path is \\server\\pipe\name; find the pipename itself */
        p = &NewName.Buffer[2];

        /* First loop to get past the server name */
        do
        {
            /* Check if this is a backslash */
            if (*p == L'\\') break;

            /* Check next */
            p++;
        } while (*p);

        /* Now make sure the full name contains "pipe\" */
        if ((*p) && !(_wcsnicmp(p + 1, L"pipe\\", sizeof("pipe\\"))))
        {
            /* Get to the pipe name itself now */
            p += sizeof("pipe\\") - 1;
        }
        else
        {
            /* The name is invalid */
            WARN("Invalid name!\n");
            BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD);
            return FALSE;
        }

        /* FIXME: Open \DosDevices\Unc\Server\Pipe\Name */
    }
    else
    {
        WARN("Invalid path type\n");
        BaseSetLastNTError(STATUS_OBJECT_PATH_SYNTAX_BAD);
        return FALSE;
    }

    /* Now calculate the total length of the structure and allocate it */
    WaitPipeInfoSize = FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name[0]) +
                       NewName.Length;
    WaitPipeInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, WaitPipeInfoSize);
    if (WaitPipeInfo == NULL)
    {
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
        return FALSE;
    }

    /* Initialize the object attributes */
    TRACE("Opening: %wZ\n", &DevicePath);
    InitializeObjectAttributes(&ObjectAttributes,
                               &DevicePath,
                               OBJ_CASE_INSENSITIVE,
                               NULL,
                               NULL);

    /* Open the path */
    Status = NtOpenFile(&FileHandle,
                        FILE_READ_ATTRIBUTES | SYNCHRONIZE,
                        &ObjectAttributes,
                        &IoStatusBlock,
                        FILE_SHARE_READ | FILE_SHARE_WRITE,
                        FILE_SYNCHRONOUS_IO_NONALERT);
    if (!NT_SUCCESS(Status))
    {
        /* Fail; couldn't open */
        WARN("Status: %lx\n", Status);
        BaseSetLastNTError(Status);
        RtlFreeUnicodeString(&NamedPipeName);
        RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo);
        return FALSE;
    }

    /* Check what timeout we got */
    if (nTimeOut == NMPWAIT_USE_DEFAULT_WAIT)
    {
        /* Don't use a timeout */
        WaitPipeInfo->TimeoutSpecified = FALSE;
    }
    else
    {
        /* Check if we should wait forever */
        if (nTimeOut == NMPWAIT_WAIT_FOREVER)
        {
            /* Set the max */
            WaitPipeInfo->Timeout.LowPart = 0;
            WaitPipeInfo->Timeout.HighPart = 0x80000000;
        }
        else
        {
            /* Convert to NT format */
            WaitPipeInfo->Timeout.QuadPart = UInt32x32To64(-10000, nTimeOut);
        }

        /* In both cases, we do have a timeout */
        WaitPipeInfo->TimeoutSpecified = TRUE;
    }

    /* Set the length and copy the name */
    WaitPipeInfo->NameLength = NewName.Length;
    RtlCopyMemory(WaitPipeInfo->Name, NewName.Buffer, NewName.Length);

    /* Get rid of the full name */
    RtlFreeUnicodeString(&NamedPipeName);

    /* Let NPFS know of our request */
    Status = NtFsControlFile(FileHandle,
                             NULL,
                             NULL,
                             NULL,
                             &IoStatusBlock,
                             FSCTL_PIPE_WAIT,
                             WaitPipeInfo,
                             WaitPipeInfoSize,
                             NULL,
                             0);

    /* Free our pipe info data and close the handle */
    RtlFreeHeap(RtlGetProcessHeap(), 0, WaitPipeInfo);
    NtClose(FileHandle);

    /* Check the status */
    if (!NT_SUCCESS(Status))
    {
        /* Failure to wait on the pipe */
        WARN("Status: %lx\n", Status);
        BaseSetLastNTError (Status);
        return FALSE;
     }

    /* Success */
    return TRUE;
}
예제 #4
0
BOOLEAN PhaGetProcessKnownCommandLine(
    __in PPH_STRING CommandLine,
    __in PH_KNOWN_PROCESS_TYPE KnownProcessType,
    __out PPH_KNOWN_PROCESS_COMMAND_LINE KnownCommandLine
    )
{
    switch (KnownProcessType & KnownProcessTypeMask)
    {
    case ServiceHostProcessType:
        {
            // svchost.exe -k <GroupName>

            static PH_COMMAND_LINE_OPTION options[] =
            {
                { 1, L"k", MandatoryArgumentType }
            };

            KnownCommandLine->ServiceHost.GroupName = NULL;

            PhParseCommandLine(
                &CommandLine->sr,
                options,
                sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION),
                PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS,
                PhpSvchostCommandLineCallback,
                KnownCommandLine
                );

            if (KnownCommandLine->ServiceHost.GroupName)
            {
                PhaDereferenceObject(KnownCommandLine->ServiceHost.GroupName);
                return TRUE;
            }
            else
            {
                return FALSE;
            }
        }
        break;
    case RunDllAsAppProcessType:
        {
            // rundll32.exe <DllName>,<ProcedureName> ...

            SIZE_T i;
            ULONG_PTR lastIndexOfComma;
            PPH_STRING dllName;
            PPH_STRING procedureName;

            i = 0;

            // Get the rundll32.exe part.

            dllName = PhParseCommandLinePart(&CommandLine->sr, &i);

            if (!dllName)
                return FALSE;

            PhDereferenceObject(dllName);

            // Get the DLL name part.

            while (i < CommandLine->Length / 2 && CommandLine->Buffer[i] == ' ')
                i++;

            dllName = PhParseCommandLinePart(&CommandLine->sr, &i);

            if (!dllName)
                return FALSE;

            PhaDereferenceObject(dllName);

            // The procedure name begins after the last comma.

            lastIndexOfComma = PhFindLastCharInString(dllName, 0, ',');

            if (lastIndexOfComma == -1)
                return FALSE;

            procedureName = PhaSubstring(
                dllName,
                lastIndexOfComma + 1,
                dllName->Length / 2 - lastIndexOfComma - 1
                );
            dllName = PhaSubstring(dllName, 0, lastIndexOfComma);

            // If the DLL name isn't an absolute path, assume it's in system32.
            // TODO: Use a proper search function.

            if (RtlDetermineDosPathNameType_U(dllName->Buffer) == RtlPathTypeRelative)
            {
                dllName = PhaConcatStrings(
                    3,
                    ((PPH_STRING)PHA_DEREFERENCE(PhGetSystemDirectory()))->Buffer,
                    L"\\",
                    dllName->Buffer
                    );
            }

            KnownCommandLine->RunDllAsApp.FileName = dllName;
            KnownCommandLine->RunDllAsApp.ProcedureName = procedureName;
        }
        break;
    case ComSurrogateProcessType:
        {
            // dllhost.exe /processid:<Guid>

            static PH_STRINGREF inprocServer32Name = PH_STRINGREF_INIT(L"InprocServer32");

            SIZE_T i;
            ULONG_PTR indexOfProcessId;
            PPH_STRING argPart;
            PPH_STRING guidString;
            UNICODE_STRING guidStringUs;
            GUID guid;
            HANDLE clsidKeyHandle;
            HANDLE inprocServer32KeyHandle;
            PPH_STRING fileName;

            i = 0;

            // Get the dllhost.exe part.

            argPart = PhParseCommandLinePart(&CommandLine->sr, &i);

            if (!argPart)
                return FALSE;

            PhDereferenceObject(argPart);

            // Get the argument part.

            while (i < (ULONG)CommandLine->Length / 2 && CommandLine->Buffer[i] == ' ')
                i++;

            argPart = PhParseCommandLinePart(&CommandLine->sr, &i);

            if (!argPart)
                return FALSE;

            PhaDereferenceObject(argPart);

            // Find "/processid:"; the GUID is just after that.

            PhUpperString(argPart);
            indexOfProcessId = PhFindStringInString(argPart, 0, L"/PROCESSID:");

            if (indexOfProcessId == -1)
                return FALSE;

            guidString = PhaSubstring(
                argPart,
                indexOfProcessId + 11,
                (ULONG)argPart->Length / 2 - indexOfProcessId - 11
                );
            PhStringRefToUnicodeString(&guidString->sr, &guidStringUs);

            if (!NT_SUCCESS(RtlGUIDFromString(
                &guidStringUs,
                &guid
                )))
                return FALSE;

            KnownCommandLine->ComSurrogate.Guid = guid;
            KnownCommandLine->ComSurrogate.Name = NULL;
            KnownCommandLine->ComSurrogate.FileName = NULL;

            // Lookup the GUID in the registry to determine the name and file name.

            if (NT_SUCCESS(PhOpenKey(
                &clsidKeyHandle,
                KEY_READ,
                PH_KEY_CLASSES_ROOT,
                &PhaConcatStrings2(L"CLSID\\", guidString->Buffer)->sr,
                0
                )))
            {
                KnownCommandLine->ComSurrogate.Name =
                    PHA_DEREFERENCE(PhQueryRegistryString(clsidKeyHandle, NULL));

                if (NT_SUCCESS(PhOpenKey(
                    &inprocServer32KeyHandle,
                    KEY_READ,
                    clsidKeyHandle,
                    &inprocServer32Name,
                    0
                    )))
                {
                    KnownCommandLine->ComSurrogate.FileName =
                        PHA_DEREFERENCE(PhQueryRegistryString(inprocServer32KeyHandle, NULL));

                    if (fileName = PHA_DEREFERENCE(PhExpandEnvironmentStrings(
                        &KnownCommandLine->ComSurrogate.FileName->sr
                        )))
                    {
                        KnownCommandLine->ComSurrogate.FileName = fileName;
                    }

                    NtClose(inprocServer32KeyHandle);
                }

                NtClose(clsidKeyHandle);
            }
        }
        break;
    default:
        return FALSE;
    }

    return TRUE;
}
예제 #5
0
/**
 * Loads plugins from the default plugins directory.
 */
VOID PhLoadPlugins(
    VOID
    )
{
    HANDLE pluginsDirectoryHandle;
    PPH_STRING pluginsDirectory;

    pluginsDirectory = PhGetStringSetting(L"PluginsDirectory");

    if (RtlDetermineDosPathNameType_U(pluginsDirectory->Buffer) == RtlPathTypeRelative)
    {
        // Not absolute. Make sure it is.
        PluginsDirectory = PhConcatStrings(4, PhApplicationDirectory->Buffer, L"\\", pluginsDirectory->Buffer, L"\\");
        PhDereferenceObject(pluginsDirectory);
    }
    else
    {
        PluginsDirectory = pluginsDirectory;
    }

    if (NT_SUCCESS(PhCreateFileWin32(
        &pluginsDirectoryHandle,
        PluginsDirectory->Buffer,
        FILE_GENERIC_READ,
        0,
        FILE_SHARE_READ,
        FILE_OPEN,
        FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT
        )))
    {
        UNICODE_STRING pattern = RTL_CONSTANT_STRING(L"*.dll");

        PhEnumDirectoryFile(pluginsDirectoryHandle, &pattern, EnumPluginsDirectoryCallback, NULL);
        NtClose(pluginsDirectoryHandle);
    }

    // Handle load errors.
    // In certain startup modes we want to ignore all plugin load errors.
    if (LoadErrors && LoadErrors->Count != 0 && !PhStartupParameters.PhSvc)
    {
        PH_STRING_BUILDER sb;
        ULONG i;
        PPHP_PLUGIN_LOAD_ERROR loadError;
        PPH_STRING baseName;

        PhInitializeStringBuilder(&sb, 100);
        PhAppendStringBuilder2(&sb, L"Unable to load the following plugin(s):\n\n");

        for (i = 0; i < LoadErrors->Count; i++)
        {
            loadError = LoadErrors->Items[i];
            baseName = PhGetBaseName(loadError->FileName);
            PhAppendFormatStringBuilder(&sb, L"%s: %s\n",
                baseName->Buffer, PhGetStringOrDefault(loadError->ErrorMessage, L"An unknown error occurred."));
            PhDereferenceObject(baseName);
        }

        PhAppendStringBuilder2(&sb, L"\nDo you want to disable the above plugin(s)?");

        if (PhShowMessage(
            NULL,
            MB_ICONERROR | MB_YESNO,
            sb.String->Buffer
            ) == IDYES)
        {
            ULONG i;

            for (i = 0; i < LoadErrors->Count; i++)
            {
                loadError = LoadErrors->Items[i];
                baseName = PhGetBaseName(loadError->FileName);
                PhSetPluginDisabled(&baseName->sr, TRUE);
                PhDereferenceObject(baseName);
            }
        }

        PhDeleteStringBuilder(&sb);
    }

    // When we loaded settings before, we didn't know about plugin settings, so they
    // went into the ignored settings list. Now that they've had a chance to add
    // settings, we should scan the ignored settings list and move the settings to
    // the right places.
    if (PhSettingsFileName)
        PhConvertIgnoredSettings();

    PhpExecuteCallbackForAllPlugins(PluginCallbackLoad, TRUE);
}
예제 #6
0
파일: move.c 프로젝트: 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;
}