Data->Iopb->Parameters.Write.ByteOffset invalid in funtion of how user app manages the file written.

Hi all.

I’m trying to develop a minifilter to control the writes of a user application in a file. I am controling each write operation in PreWrite callback. The minifilter sends all data received to another user application using FltSendMessage function before the data is written in the file.

I have develop a test user application to write in the file continously (one line each 1 second, for example), and the data received in the minifilter is different in funtion on how this test application manages this file.

If this app is develop in C, and uses for example, log4cplus to write the file, each write operation is duplicated in the minifilter, allways duplicated. But the Data->Iopb->Parameters.Write.ByteOffset said me that the two PreWrite calls are for the same file line (the offset is the same for both PreWrite calls). So I can use this ByteOffset to discart the second one (I save each PreWrite offset in a variable and compare the last offset saved with the new offset received, if both are the same, the second line is not sent with FltSendMessage because is duplicated.

if this test app is develop in Java, with a FileWriter object, the PreWrite calls are not duplicated an the offset is allways -1. This offset never changes.

Reading about this ByteOffset parameter, I thought this parameter indicated the position of the data within the file. So, why is it received allways with -1 value? The data is written in the file in the correct position, so I don’t understand this behaviour.

Another thing I have test is to check Data->Iopb->Parameters.Write.Key of each PreWrite call. But it is always received with 0 value.

Does anyone have any idea how to solve this?

Thanks!!

Doing some investigation I have discover that -1 in ByteOffset means to write at the end of the file, without specifying a exact file position. So, now I need to understand why some preWrite calls are executed for the same write data. Any idea?
This is my preWrite function:

FLT_PREOP_CALLBACK_STATUS CFilCtrlDrvFilter::PreWrite(__inout PFLT_CALLBACK_DATA Data,
	__in PCFLT_RELATED_OBJECTS FltObjects,
	__deref_opt_out PVOID*     CompletionContext) {

	UNREFERENCED_PARAMETER(FltObjects);
	UNREFERENCED_PARAMETER(CompletionContext);
	UNREFERENCED_PARAMETER( Data);

	
	//If there is no config object, do nothing.
	if(!m_Config) {
		return FLT_PREOP_SUCCESS_NO_CALLBACK;
	}

	//If the filter is activated (my own registry parameter to filter or not filter).
	if(!m_Config->FilterActivated()) {
		return FLT_PREOP_SUCCESS_NO_CALLBACK;
	}

	// Check we are managing the right IRP
	NT_ASSERT(Data->Iopb->MajorFunction == IRP_MJ_WRITE);

	
	if(FlagOn( Data->Iopb->IrpFlags, IRP_NOCACHE))//IRP_WRITE_OPERATION))
		return FLT_PREOP_SUCCESS_NO_CALLBACK;
	

	// Get filename information
	PFLT_FILE_NAME_INFORMATION FileNameInfo = GetFileNameInfoWrite(Data);
	if(!FileNameInfo)
		return FLT_PREOP_SUCCESS_NO_CALLBACK;
	
	//If the file to write is not in the path configured, no nothing.
	CWString strFilePath(FileNameInfo->ParentDir);
	if(strFilePath != m_Config->GetMonitorizeFilePath()) {
		return FLT_PREOP_SUCCESS_NO_CALLBACK;
	}

	CWString strFinalComponent(FileNameInfo->FinalComponent);
	//KdPrint(("FILCtrl-PreWrite: Final: %wZ.\n", &FileNameInfo->FinalComponent));

	PWCHAR lpwFinalComponent = NULL;
	strFinalComponent >> lpwFinalComponent;
	
	PWCHAR lpwMonitorizeFile = NULL;
	m_Config->GetMonitorizeFileName() >> lpwMonitorizeFile;

        //Check if file name matches my configuration (regular expresions)
	int result = wslre_match(lpwMonitorizeFile , lpwFinalComponent, (int)wcslen(lpwFinalComponent), NULL, 0, 0);
	//If matches
	if( result >= 0) {

		LARGE_INTEGER lOffset = Data->Iopb->Parameters.Write.ByteOffset;
		KdPrint(( "FILCtrl-PreWrite: Offset: %i %i.\n", Data->Iopb->Parameters.Write.ByteOffset.u.HighPart, Data->Iopb->Parameters.Write.ByteOffset.u.LowPart));

		char *ioBuffer = NULL;
		PMDL MdlAddress = Data->Iopb->Parameters.Write.MdlAddress;
		ULONG Length = (ULONG)Data->Iopb->Parameters.Write.Length;
		if(MdlAddress != NULL) {
			ASSERT( MdlAddress->Next == NULL);
			ioBuffer = (char*) MmGetSystemAddressForMdlSafe( MdlAddress, NormalPagePriority);
			
		} else {
			__try {
				ioBuffer = (char*)Data->Iopb->Parameters.Write.WriteBuffer;
				if(Data->RequestorMode != KernelMode) {
					ProbeForRead(ioBuffer, Data->Iopb->Parameters.Write.Length, 1);
				}
			}__except(EXCEPTION_EXECUTE_HANDLER) {
				KdPrint(("FILCtrl-PreWrite: Exception ProbeForRead.\n"));
				ioBuffer = NULL;
			}
			
		}

		if( ioBuffer != NULL) {
			
			if(lOffset.u.HighPart == -1 && lOffset.u.LowPart == -1) {
				KdPrint(("FILCtrl-PreWrite: Offset -1. Writing %ld.\n", Length));
                                //Send data to client app using FltSendMessage 
				sendDataToClient(ioBuffer, Length);
			} else {
				//Compare this offset with the last preWrite executions offset.
                                if(differentOffset(&lOffset)) {
					KdPrint(("FILCtrl-PreWrite: Offset different. Writing %ld.\n", Length));
                                        //Send data to client app using FltSendMessage 
					sendDataToClient(ioBuffer, Length);
                                        //Safe this preWrite offset to compare with the next preWrite offset.
					saveNewOffset(&lOffset);
				}
				else {
					KdPrint(("FILCtrl-PreWrite: Same offset.\n"));
				}
			}
		}
	}
	
	FltReleaseFileNameInformation(FileNameInfo);
	FileNameInfo = NULL;
	
	return FLT_PREOP_SUCCESS_NO_CALLBACK;

}

So, why is it received allways with -1 value? The data is written in the file in the correct position, so I don’t understand this behaviour.
That would be FILE_WRITE_TO_END_OF_FILE

@rod_widdowson said:

So, why is it received allways with -1 value? The data is written in the file in the correct position, so I don’t understand this behaviour.
That would be FILE_WRITE_TO_END_OF_FILE

Yes, I now know the -1 meaning, so my develop is not valid because I assumed that the offset should be always different. If the offset received in one PreWrite is the same than the last PreWrite offset, I could discard this data because I had already processed it in the previous call.

If the offset is not valid for me, the only possibility is to know why some times the minifilter receives more than one PreWrite for the same data. I think that some of this repeated PreWrite must be discarted in my minifilter before processed the data, but I don’t know how to identify this callbacks.