Dmitry Philippov: Implement SmProcessFileRenameList()

svn path=/trunk/; revision=23684
This commit is contained in:
Aleksey Bragin 2006-08-24 11:06:48 +00:00
parent 1b82756b34
commit 2036235837

View file

@ -1,52 +1,455 @@
/* $Id$
*
* initmv.c - Process the file rename list
*
* ReactOS Operating System
*
* --------------------------------------------------------------------
*
* This software is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING.LIB. If not, write
* to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
* MA 02139, USA.
*
* --------------------------------------------------------------------
* PROJECT: ReactOS Operating System
* LICENSE: GPL - See COPYING in the top level directory
* FILE: base/system/smss/initmv.c
* PURPOSE: Process the file rename list.
* PROGRAMMERS: Dmitry Philippov (shedon@mail.ru)
* UPDATE HISTORY:
* Created 13/08/2006
*/
/* INCLUDES ******************************************************************/
#include "smss.h"
#define NDEBUG
#include <debug.h>
/* FUNCTIONS *****************************************************************/
/*++
* @name SmpDeleteFile
*
* The SmpDeleteFile function deletes a specify file.
*
* @param lpFileName
* the name of a file which should be deleted
*
* @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
* othwerwise.
*
* @remarks
* This function is called by SmpMoveFilesQueryRoutine().
*
*
*--*/
NTSTATUS
SmProcessFileRenameList(VOID)
SmpDeleteFile( IN LPCWSTR lpFileName )
{
DPRINT("SmProcessFileRenameList() called\n");
FILE_DISPOSITION_INFORMATION FileDispInfo;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING FileNameU;
HANDLE FileHandle;
NTSTATUS Status;
/* FIXME: implement it! */
/*
* open HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\FileRenameOperations
* for each item in its value
* clone the old file in the new name,
* delete the source.
*
*/
DPRINT("SmpDeleteFile ( %S )\n", lpFileName);
DPRINT("SmProcessFileRenameList() done\n");
if( !lpFileName )
return (STATUS_INVALID_PARAMETER);
return(STATUS_SUCCESS);
RtlInitUnicodeString(&FileNameU, lpFileName);
InitializeObjectAttributes(&ObjectAttributes,
&FileNameU,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtCreateFile (&FileHandle,
DELETE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
RtlFreeUnicodeString(&FileNameU);
if( !NT_SUCCESS(Status) ) {
DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
return (Status);
}
FileDispInfo.DeleteFile = TRUE;
Status = NtSetInformationFile(
FileHandle,
&IoStatusBlock,
&FileDispInfo,
sizeof(FILE_DISPOSITION_INFORMATION),
FileDispositionInformation );
NtClose(FileHandle);
return (Status);
}
/*++
* @name SmpMoveFile
*
* The SmpMoveFile function deletes a specify file.
*
* @param lpExistingFileName
* the name of an existing file which should be removed
*
* @param lpNewFileName
* a new name of an existing file.
*
* @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
* othwerwise.
*
* @remarks
* This function called from the SmpMoveFilesQueryRoutine function.
*
*
*--*/
NTSTATUS
SmpMoveFile( IN LPCWSTR lpExistingFileName,
IN LPCWSTR lpNewFileName
)
{
PFILE_RENAME_INFORMATION FileRenameInfo;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
UNICODE_STRING ExistingFileNameU;
HANDLE FileHandle;
DWORD FileNameSize;
BOOLEAN ReplaceIfExists;
NTSTATUS Status;
if( !lpExistingFileName || !lpNewFileName )
return (STATUS_INVALID_PARAMETER);
DPRINT("SmpMoveFile (%S, %S)\n", lpExistingFileName, lpNewFileName);
RtlInitUnicodeString(&ExistingFileNameU, lpExistingFileName);
InitializeObjectAttributes(&ObjectAttributes,
&ExistingFileNameU,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtCreateFile (&FileHandle,
FILE_ALL_ACCESS,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if( !NT_SUCCESS(Status) ) {
DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
return (Status);
}
FileNameSize = wcslen(lpNewFileName)*sizeof(*lpNewFileName);
FileRenameInfo = RtlAllocateHeap(
RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(FILE_RENAME_INFORMATION)+FileNameSize);
if( !FileRenameInfo ) {
DPRINT("RtlAllocateHeap failed\n");
NtClose(FileHandle);
return (STATUS_NO_MEMORY);
}
if( L'!' == *lpNewFileName ) {
lpNewFileName++;
FileNameSize -= sizeof(*lpNewFileName);
ReplaceIfExists = TRUE;
}
else {
ReplaceIfExists = FALSE;
}
FileRenameInfo->RootDirectory = NULL;
FileRenameInfo->ReplaceIfExists = ReplaceIfExists;
FileRenameInfo->FileNameLength = FileNameSize;
RtlCopyMemory(FileRenameInfo->FileName, lpNewFileName, FileNameSize);
Status = NtSetInformationFile(
FileHandle,
&IoStatusBlock,
FileRenameInfo,
sizeof(FILE_RENAME_INFORMATION)+FileNameSize,
FileRenameInformation );
RtlFreeHeap(RtlGetProcessHeap(), 0, FileRenameInfo);
/* FIXME: After the FileRenameInformation parameter will be implemented into the fs driver
the following code can be removed */
if( STATUS_NOT_IMPLEMENTED == Status )
{
HANDLE FileHandleNew;
UNICODE_STRING NewFileNameU;
FILE_BASIC_INFORMATION FileBasicInfo;
UCHAR *lpBuffer = NULL;
SIZE_T RegionSize = 0x10000;
LARGE_INTEGER BytesCopied;
BOOL EndOfFileFound;
Status = NtQueryInformationFile(
FileHandle,
&IoStatusBlock,
&FileBasicInfo,
sizeof(FILE_BASIC_INFORMATION),
FileBasicInformation);
if( !NT_SUCCESS(Status) ) {
DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
NtClose(FileHandle);
return (Status);
}
RtlInitUnicodeString(&NewFileNameU, lpNewFileName);
InitializeObjectAttributes(&ObjectAttributes,
&NewFileNameU,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtCreateFile (&FileHandleNew,
FILE_ALL_ACCESS,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
ReplaceIfExists ? FILE_OVERWRITE_IF : FILE_CREATE,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if( !NT_SUCCESS(Status) ) {
DPRINT("NtCreateFile() failed (Status %lx)\n", Status);
NtClose(FileHandle);
return (Status);
}
Status = NtAllocateVirtualMemory(
NtCurrentProcess(),
(PVOID *)&lpBuffer,
2,
&RegionSize,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE);
if( !NT_SUCCESS(Status) ) {
DPRINT("NtAllocateVirtualMemory() failed (Status %lx)\n", Status);
NtClose(FileHandle);
SmpDeleteFile(lpNewFileName);
return (Status);
}
BytesCopied.QuadPart = 0;
EndOfFileFound = FALSE;
while( !EndOfFileFound
&& NT_SUCCESS(Status) )
{
Status = NtReadFile(FileHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
lpBuffer,
RegionSize,
NULL,
NULL);
if( NT_SUCCESS(Status) ) {
Status = NtWriteFile(FileHandleNew,
NULL,
NULL,
NULL,
&IoStatusBlock,
lpBuffer,
IoStatusBlock.Information,
NULL,
NULL);
if( NT_SUCCESS(Status) ) {
BytesCopied.QuadPart += IoStatusBlock.Information;
}
else {
DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
}
}
else {
if( STATUS_END_OF_FILE == Status ) {
EndOfFileFound = TRUE;
Status = STATUS_SUCCESS;
}
else {
DPRINT("NtWriteFile() failed (Status %lx)\n", Status);
}
}
}
NtFreeVirtualMemory(NtCurrentProcess(),
(PVOID *)&lpBuffer,
&RegionSize,
MEM_RELEASE);
Status = NtQueryInformationFile(
FileHandleNew,
&IoStatusBlock,
&FileBasicInfo,
sizeof(FILE_BASIC_INFORMATION),
FileBasicInformation);
if( !NT_SUCCESS(Status) ) {
DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status);
}
Status = NtSetInformationFile(FileHandleNew,
&IoStatusBlock,
&FileBasicInfo,
sizeof(FILE_BASIC_INFORMATION),
FileBasicInformation);
if( !NT_SUCCESS(Status) ) {
DPRINT("NtSetInformationFile() failed (Status %lx)\n", Status);
}
NtClose(FileHandleNew);
NtClose(FileHandle);
SmpDeleteFile(lpExistingFileName);
return (Status);
}
NtClose(FileHandle);
return (Status);
}
/*++
* @name SmpMoveFilesQueryRoutine
*
* The SmpMoveFilesQueryRoutine function processes registry entries.
*
* @param ValueName
* The name of the value.
*
* @param ValueType
* The type of the value.
*
* @param ValueData
* The null-terminated data for the value.
*
* @param ValueLength
* The length of ValueData.
*
* @param Context
* NULL
*
* @param EntryContext
* NULL
*
* @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
* othwerwise.
*
* @remarks
*
*
*
*--*/
static NTSTATUS STDCALL
SmpMoveFilesQueryRoutine(IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext)
{
NTSTATUS Status;
static LPWSTR FistFileName = NULL;
DPRINT("SmpMoveFilesQueryRoutine() called \n");
DPRINT("ValueData = %S \n", ValueData);
if( !FistFileName )
{
/* save a first file name */
FistFileName = ValueData;
Status = STATUS_SUCCESS;
}
else
{
if( 0 == *((LPWSTR)ValueData) ) {
/* delete if second file name is absent */
Status = SmpDeleteFile( FistFileName );
} else {
/* remove a file */
Status = SmpMoveFile( FistFileName, (LPCWSTR)ValueData );
}
FistFileName = NULL;
}
return Status;
}
/*++
* @name SmProcessFileRenameList
* @implemented
*
* The SmProcessFileRenameList function moves or deletes files thats have been added to the specify registry key for delayed moving.
*
* @param VOID
*
* @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
* othwerwise.
*
* @remarks
* This function reads the following registry value:
* HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\PendingFileRenameOperations
* This registry value is of type REG_MULTI_SZ. The each operation is specifed as two file names.
* A first name is a source file, a second name is a destination file.
* In the case of deleting operation a second file name must be the empty string.
* For exapmle:
* szxSrcFile\0szxDestFile\0\0 <-- the szxSrcFile file will be renamed to the szxDestFile file
* szxSomeFile\0\0\0 <-- the szxSomeFile file will be removed
* After it will be done, the registry value will be deleted.
*
*
*--*/
NTSTATUS
SmProcessFileRenameList( VOID )
{
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
NTSTATUS Status;
DPRINT("SmProcessFileRenameList() called\n");
RtlZeroMemory( &QueryTable, sizeof(QueryTable) );
QueryTable[0].Name = L"PendingFileRenameOperations";
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DELETE;
QueryTable[0].DefaultType = REG_NONE;
QueryTable[0].QueryRoutine = SmpMoveFilesQueryRoutine;
Status = RtlQueryRegistryValues(
RTL_REGISTRY_CONTROL,
L"\\Session Manager",
QueryTable,
NULL,
NULL);
if( !NT_SUCCESS(Status) ) {
DPRINT("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
}
/* FIXME: RtlQueryRegistryValues can return an error status if the PendingFileRenameOperations value
does not exist, in this case smss hungs, therefore we always return STATUS_SUCCESS */
return (STATUS_SUCCESS);
}
/* EOF */