From 203623583739be8d41ed6a6f1efee64d1c16bbaf Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Thu, 24 Aug 2006 11:06:48 +0000 Subject: [PATCH] Dmitry Philippov: Implement SmProcessFileRenameList() svn path=/trunk/; revision=23684 --- reactos/base/system/smss/initmv.c | 473 +++++++++++++++++++++++++++--- 1 file changed, 438 insertions(+), 35 deletions(-) diff --git a/reactos/base/system/smss/initmv.c b/reactos/base/system/smss/initmv.c index d4e132334b5..315948edb68 100644 --- a/reactos/base/system/smss/initmv.c +++ b/reactos/base/system/smss/initmv.c @@ -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 + +/* 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 */