Hi,
I am trying to rename a file (move to recycler managed by us) whenever
user deletes the file. I went through this post and also article on OSR:
http://www.osronline.com/showThread.cfm?link=15483
http://www.osronline.com/showThread.cfm?link=53443
My Rename is failing with STATUS_OBJECT_NAME_INVALID. If I try simple name
(setting both FileObject and RootDirectory NULL) then it works fine. How can
I find out which object name is invalid - Source object, Target Directory or
Filename. I cannot use Zw function as it causes to post
IRP_MJ_SET_INFORMATION back to my driver which interferes with our own logic
to disallow user to manage our recycler. So we use IRP_MJ call to send the
request down.
There was other thing which I notice in OSR article - When getting full
target path for Relative Name, we first get directory object using handle
passed in RootHandle but according to MSDN documentation, the target
directory file object is passed in IRP:
*IrpSp->Parameters.SetFile.FileObject*For rename or link operations. If *
Irp->AssociatedIrp.SystemBuffer->FileName* contains a fully qualified file
name, or if *Irp->AssociatedIrp.SystemBuffer->RootDirectory* is non-NULL,
this member is a file object pointer for the parent directory of the file
that is the target of the operation. Otherwise it is NULL.
So why we need to explicitly get FileObject of the directory object ??
Here is the code I am using to do a Rename using IRP.
swprintf(pFullFileName,
L"\DosDevices\F:\DxLogs\Recycler\Rename");
RtlInitUnicodeString(&uFullFileName, pFullFileName);
DbgPrint(“Unicode String Buffer %ws Length : %d Max Length : %d\n”,
uFullFileName.Buffer, uFullFileName.Length, uFullFileName.MaximumLength);
InitializeObjectAttributes(&ObjectAttr, &uFullFileName,
OBJ_CASE_INSENSITIVE, NULL, NULL );
Status = IoCreateFileSpecifyDeviceObjectHint( &Handle, 0,
&ObjectAttr, &IoStatus, NULL, 0, 0, FILE_OPEN_IF,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_WRITE_THROUGH,
NULL, 0,
CreateFileTypeNone, NULL, 0, pDO );
if ( NT_SUCCESS(Status) )
Status = ObReferenceObjectByHandle(Handle, SYNCHRONIZE, *IoFileObjectType,
KernelMode, (PVOID *)ppFO, NULL);
I am doing a Relative Rename where I pass the handle obtained above and just
the filename of the target filename. Here is how I setup my File Rename
Structure.
wcscpy(pNameInfo->FileName, “Target.txt”);
pNameInfo->FileNameLength =
(wcslen(pNameInfo->FileName)*sizeof(WCHAR)); //filename
pNameInfo->ReplaceIfExists = TRUE;
pNameInfo->RootDirectory = Handle;
Here is how I create a IRP
Length = sizeof(FILE_RENAME_INFORMATION)+pNameInfo->FileNameLength;
irp = IoAllocateIrp( pDO->StackSize, FALSE );
irp->Tail.Overlay.OriginalFileObject = pFO;
irp->Tail.Overlay.Thread = PsGetCurrentThread();
irp->RequestorMode = KernelMode;
irp->UserEvent = &event;
irp->Flags = IRP_SYNCHRONOUS_API | IRP_BUFFERED_IO;
irp->UserIosb = &IoStatus;
irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE)
NULL;
irp->AssociatedIrp.SystemBuffer = pNameInfo;
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->FileObject = pFO;
irpSp->DeviceObject = pDO;
irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
irpSp->Parameters.SetFile.Length = Length;
irpSp->Parameters.SetFile.FileInformationClass =
FileRenameInformation;
irpSp->Parameters.SetFile.AdvanceOnly = FALSE;
irpSp->Parameters.SetFile.FileObject = *ppFO;
IoSetCompletionRoutine( irp,
SetFileInfoCompletionRoutine,
0,
TRUE,
TRUE,
TRUE );
status = IoCallDriver( pDO, irp );
Any help ?
Thanks
Ash