IoStatus->Information=(FileOffset && Length ? MIN(privbcb->MappedLength,Length) : privbcb->MappedLength);
}
}
+
+
+static gboolean captive_FileObject_ZeroData(PFILE_OBJECT FileObject,guint64 window_bottom,guint64 window_top)
+{
+MDL *Mdl;
+KEVENT Event;
+gpointer zerobuffer;
+LARGE_INTEGER window_bottom_LargeInteger;
+NTSTATUS err;
+IO_STATUS_BLOCK IoStatus;
+
+ g_return_val_if_fail(FileObject!=NULL,FALSE);
+ g_return_val_if_fail(window_bottom<=window_top,FALSE);
+
+ if (window_bottom==window_top) /* trivia */
+ return TRUE;
+
+ g_return_val_if_fail(FileObject->DeviceObject!=NULL,FALSE);
+
+ /* Such requirement is W32 documented for CcZeroData()
+ * and it is really a requirement at least for the underlying fastfat.sys.
+ */
+ g_assert(0==CAPTIVE_ROUND_DOWN_EXCEEDING64(window_bottom,FileObject->DeviceObject->SectorSize));
+ g_assert(0==CAPTIVE_ROUND_DOWN_EXCEEDING64(window_top ,FileObject->DeviceObject->SectorSize));
+
+ zerobuffer=g_malloc0(window_top-window_bottom);
+ window_bottom_LargeInteger.QuadPart=window_bottom;
+
+ Mdl=MmCreateMdl(NULL,zerobuffer,window_top-window_bottom);
+ g_assert(Mdl!=NULL);
+
+ KeInitializeEvent(&Event,NotificationEvent,FALSE);
+
+ /* Use rather IoSynchronousPageWrite() than IoPageWrite() to prevent STATUS_PENDING. */
+ err=IoSynchronousPageWrite(FileObject,Mdl,&window_bottom_LargeInteger,&Event,&IoStatus);
+ g_assert(NT_SUCCESS(err));
+ g_assert(NT_SUCCESS(IoStatus.Status));
+ /* We should write up to the last sector touched by the range although we
+ * do not need to successfuly write the whole aligned amount.
+ * FIXME: Also we can get just value 0 if the write is considered 'not dirty'
+ * during FAT write by fastfat.sys.
+ */
+ g_assert(IoStatus.Information==0
+ || (window_top-window_bottom)==CAPTIVE_ROUND_UP(IoStatus.Information,FileObject->DeviceObject->SectorSize));
+ g_assert(IoStatus.Information<=window_top-window_bottom); /* redundant */
+
+ g_free(zerobuffer);
+
+ return TRUE;
+}
+
+
+BOOLEAN CcZeroData(IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER StartOffset,IN PLARGE_INTEGER EndOffset,IN BOOLEAN Wait)
+{
+guint64 window_lower_bottom,window_lower_top;
+guint64 window_higher_bottom,window_higher_top;
+
+ g_return_val_if_fail(FileObject!=NULL,FALSE);
+ g_return_val_if_fail(StartOffset!=NULL,FALSE);
+ g_return_val_if_fail(EndOffset!=NULL,FALSE);
+ g_return_val_if_fail(StartOffset->QuadPart<=EndOffset->QuadPart,FALSE);
+
+ g_return_val_if_fail(FileObject->SectionObjectPointers!=NULL,FALSE);
+
+ window_lower_bottom=StartOffset->QuadPart;
+ window_lower_top=EndOffset->QuadPart;
+ window_higher_bottom=window_higher_top=0;
+
+ if (FileObject->SectionObjectPointers->SharedCacheMap!=NULL) {
+PUBLIC_BCB *PublicBcb;
+struct private_bcb *privbcb;
+guint64 window_cached_bottom,window_cached_top;
+
+ PublicBcb=FileObject->SectionObjectPointers->SharedCacheMap;
+ g_return_val_if_fail(validate_Bcb(PublicBcb),FALSE);
+
+ private_bcb_hash_init();
+
+ privbcb=g_hash_table_lookup(private_bcb_hash,PublicBcb);
+ g_return_val_if_fail(privbcb!=NULL,FALSE);
+
+ window_cached_bottom=MAX(StartOffset->QuadPart,privbcb->MappedFileOffset.QuadPart);
+ window_cached_top=MIN(EndOffset->QuadPart,privbcb->MappedFileOffset.QuadPart+privbcb->MappedLength);
+
+ if (window_cached_bottom<window_cached_top) {
+ memset(((char *)privbcb->base)+window_cached_bottom-privbcb->MappedFileOffset.QuadPart,0,window_cached_top-window_cached_bottom);
+ privbcb->dirty=TRUE;
+ window_higher_top=window_lower_top;
+ window_lower_top=window_cached_bottom;
+ window_higher_bottom=window_cached_top;
+ }
+ }
+ if (window_lower_bottom<window_lower_top) {
+ g_return_val_if_fail(Wait==TRUE,FALSE);
+ if (!captive_FileObject_ZeroData(FileObject,window_lower_bottom,window_lower_top))
+ g_return_val_if_reached(FALSE);
+ }
+ if (window_higher_bottom<window_higher_top) {
+ g_return_val_if_fail(Wait==TRUE,FALSE);
+ if (!captive_FileObject_ZeroData(FileObject,window_higher_bottom,window_higher_top))
+ g_return_val_if_reached(FALSE);
+ }
+
+ return TRUE;
+}