Author: fireball
Date: Thu Aug 24 15:06:48 2006
New Revision: 23684
URL:
http://svn.reactos.org/svn/reactos?rev=23684&view=rev
Log:
Dmitry Philippov: Implement SmProcessFileRenameList()
Modified:
trunk/reactos/base/system/smss/initmv.c
Modified: trunk/reactos/base/system/smss/initmv.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/smss/initmv.c?…
==============================================================================
--- trunk/reactos/base/system/smss/initmv.c (original)
+++ trunk/reactos/base/system/smss/initmv.c Thu Aug 24 15:06:48 2006
@@ -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(a)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");
-
- /* 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("SmProcessFileRenameList() done\n");
-
- return(STATUS_SUCCESS);
+ FILE_DISPOSITION_INFORMATION FileDispInfo;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK IoStatusBlock;
+ UNICODE_STRING FileNameU;
+ HANDLE FileHandle;
+ NTSTATUS Status;
+
+ DPRINT("SmpDeleteFile ( %S )\n", lpFileName);
+
+ if( !lpFileName )
+ return (STATUS_INVALID_PARAMETER);
+
+ 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 */