2 * reactos Cache Manager mapper emulation of libcaptive
3 * Copyright (C) 2002 Jan Kratochvil <project-captive@jankratochvil.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; exactly version 2 of June 1991 is required
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "reactos/ddk/ccfuncs.h" /* self */
23 #include <glib/gmessages.h>
24 #include <glib/ghash.h>
25 #include <glib/gmem.h>
27 #include "reactos/ddk/mmfuncs.h" /* for MmCreateMdl() */
28 #include "reactos/ddk/kefuncs.h" /* for KeInitializeEvent() */
29 #include "reactos/ddk/iofuncs.h" /* for IoPageRead() */
30 #include "captive/macros.h"
31 #include <sys/types.h>
34 #include <glib/glist.h>
35 #include "reactos/internal/io.h" /* for IoSynchronousPageWrite() */
36 #include <glib/garray.h>
37 #include <glib/gmain.h>
42 #define CAPTIVE_PUBLIC_BCB_NODETYPECODE 0xDE45 /* FIXME: unknown, undocumented */
45 static gboolean validate_Bcb(const PUBLIC_BCB *PublicBcb)
47 g_return_val_if_fail(PublicBcb!=NULL,FALSE);
48 g_return_val_if_fail(PublicBcb->NodeTypeCode==CAPTIVE_PUBLIC_BCB_NODETYPECODE,FALSE);
49 g_return_val_if_fail(PublicBcb->NodeByteSize==sizeof(*PublicBcb),FALSE);
50 g_return_val_if_fail(PublicBcb->MappedLength>0,FALSE);
51 g_return_val_if_fail(PublicBcb->MappedFileOffset.QuadPart>=0,FALSE);
57 /* position in file */
58 struct page_position {
59 FILE_OBJECT *FileObject;
60 LARGE_INTEGER FileOffset; /* always PAGE_SIZE aligned */
62 GList *privbcb_list; /* each mapped page has its one private_bcb */
65 /* map: (struct page_position *)pagepos -> (struct page_position *)pagepos */
66 static GHashTable *page_position_hash;
68 static gboolean validate_page_position(const struct page_position *pagepos)
71 struct shmid_ds shmid_ds;
73 g_return_val_if_fail(pagepos!=NULL,FALSE);
74 g_return_val_if_fail(pagepos->FileObject!=NULL,FALSE);
75 g_return_val_if_fail(pagepos->FileOffset.QuadPart>=0,FALSE);
76 g_return_val_if_fail(0==CAPTIVE_ROUND_DOWN_EXCEEDING64(pagepos->FileOffset.QuadPart,PAGE_SIZE),FALSE);
77 /* 'pagepos->shmid' may be -1 */
78 /* 'pagepos->privbcb_list' may be empty */
79 g_return_val_if_fail((pagepos->shmid==-1)==(pagepos->privbcb_list==NULL),FALSE); /* either deleted or alive */
81 if (pagepos->shmid!=-1) {
82 errint=shmctl(pagepos->shmid,
85 g_return_val_if_fail(errint==0,FALSE);
87 g_return_val_if_fail(shmid_ds.shm_perm.uid==geteuid(),FALSE);
88 g_return_val_if_fail(shmid_ds.shm_perm.gid==getegid(),FALSE);
89 g_return_val_if_fail(shmid_ds.shm_perm.cuid==geteuid(),FALSE);
90 g_return_val_if_fail(shmid_ds.shm_perm.cgid==getegid(),FALSE);
91 /* 'shm_perm.mode' was seen with sticky bit 01000: */
92 g_return_val_if_fail((shmid_ds.shm_perm.mode&0777)==0600,FALSE);
93 g_return_val_if_fail(shmid_ds.shm_segsz==PAGE_SIZE,FALSE);
94 g_return_val_if_fail(shmid_ds.shm_cpid==getpid(),FALSE);
95 g_return_val_if_fail(shmid_ds.shm_lpid==getpid(),FALSE);
96 g_return_val_if_fail(shmid_ds.shm_nattch==g_list_length(pagepos->privbcb_list),FALSE);
102 static guint page_position_hash_hash_func(const struct page_position *key)
104 g_return_val_if_fail(validate_page_position(key),0);
106 return ((guint)key->FileObject)^(key->FileOffset.QuadPart);
109 static gboolean page_position_hash_key_equal_func(const struct page_position *a,const struct page_position *b)
111 g_return_val_if_fail(validate_page_position(a),FALSE);
112 g_return_val_if_fail(validate_page_position(b),FALSE);
114 return (a->FileObject==b->FileObject && a->FileOffset.QuadPart==b->FileOffset.QuadPart);
117 static void page_position_hash_key_destroy_func(struct page_position *key)
119 g_return_if_fail(validate_page_position(key));
120 g_assert(key->privbcb_list==NULL);
121 g_assert(key->shmid==-1);
126 static void page_position_hash_init(void)
128 if (page_position_hash)
130 page_position_hash=g_hash_table_new_full(
131 (GHashFunc)page_position_hash_hash_func, /* hash_func */
132 (GEqualFunc)page_position_hash_key_equal_func, /* key_equal_func */
133 (GDestroyNotify)page_position_hash_key_destroy_func, /* key_destroy_func */
134 NULL); /* value_destroy_func */
139 PUBLIC_BCB *PublicBcb; /* ->MappedLength, ->MappedFileOffset */
140 FILE_OBJECT *FileObject;
142 gboolean idle_func_pending;
143 /* we save it here as 'PublicBcb' may be already destroyed in private_bcb_hash_value_destroy_func(): */
144 ULONG MappedLength; /* It is the real requested size; it is not PAGE_SIZE aligned. */
145 /* we save it here as 'PublicBcb' may be already destroyed in private_bcb_hash_value_destroy_func(): */
146 LARGE_INTEGER MappedFileOffset; /* It is the real requested offset; it is not PAGE_SIZE aligned. */
147 gpointer base; /* It is the pointer corresponding to MappedFileOffset; it is not PAGE_SIZE aligned. */
149 LARGE_INTEGER lsn; gboolean lsn_valid;
152 /* map: (PUBLIC_BCB *)PublicBcb -> (struct private_bcb *)privbcb */
153 static GHashTable *private_bcb_hash;
155 static void private_bcb_hash_key_destroy_func(PUBLIC_BCB *key)
157 g_return_if_fail(validate_Bcb(key));
162 static void private_bcb_hash_value_destroy_func(struct private_bcb *value)
164 struct page_position pagepos_local;
168 gpointer base_aligned;
170 g_return_if_fail(value!=NULL);
171 /* We cannot do 'validate_Bcb(value->PublicBcb)' here as 'value->PublicBcb'
172 * may got already destroyed by 'private_bcb_hash_key_destroy_func(key)'
174 g_return_if_fail(value->PublicBcb!=NULL);
175 g_return_if_fail(value->FileObject!=NULL);
176 g_return_if_fail(value->ref_count==0);
177 g_return_if_fail(value->MappedLength>0);
178 g_return_if_fail(value->MappedFileOffset.QuadPart>=0);
179 g_return_if_fail(value->base!=NULL);
180 g_return_if_fail(value->dirty==FALSE);
182 page_position_hash_init();
184 base_aligned=((char *)value->base)-CAPTIVE_ROUND_DOWN_EXCEEDING64(value->MappedFileOffset.QuadPart,PAGE_SIZE);
186 pagepos_local.FileObject=value->FileObject;
187 pagepos_local.privbcb_list=NULL;
188 pagepos_local.shmid=-1;
191 offset<value->MappedLength;
193 struct page_position *pagepos;
195 pagepos_local.FileOffset.QuadPart=CAPTIVE_ROUND_DOWN64(value->MappedFileOffset.QuadPart+offset,PAGE_SIZE);
196 pagepos=g_hash_table_lookup(page_position_hash,&pagepos_local);
197 g_assert(validate_page_position(pagepos));
198 g_assert(pagepos->privbcb_list!=NULL);
199 errint=shmdt(((char *)base_aligned)+offset);
202 g_assert(g_list_find(pagepos->privbcb_list,value)!=NULL);
203 pagepos->privbcb_list=g_list_remove(pagepos->privbcb_list,value);
204 g_assert(g_list_find(pagepos->privbcb_list,value)==NULL);
206 if (!pagepos->privbcb_list) {
207 /* It should be destroyed automatically as IPC_RMID should be pending from its foundation. */
209 errbool=g_hash_table_remove(page_position_hash,&pagepos_local);
210 g_assert(errbool==TRUE);
213 g_assert(validate_page_position(pagepos));
219 static void private_bcb_hash_init(void)
221 if (private_bcb_hash)
223 private_bcb_hash=g_hash_table_new_full(
224 g_direct_hash, /* hash_func */
225 g_direct_equal, /* key_equal_func */
226 (GDestroyNotify)private_bcb_hash_key_destroy_func, /* key_destroy_func */
227 (GDestroyNotify)private_bcb_hash_value_destroy_func); /* value_destroy_func */
231 static ULONG captive_Cc_IoPageRead(FILE_OBJECT *FileObject,gpointer address,ULONG length,LARGE_INTEGER *FileOffset)
235 IO_STATUS_BLOCK IoStatus;
238 g_return_val_if_fail(FileObject!=NULL,0);
239 g_return_val_if_fail(address!=0,0);
240 g_return_val_if_fail(length!=0,0);
241 g_return_val_if_fail(FileOffset!=NULL,0);
243 /* VolumeRead on ext2fsd.sys will return IoStatus.Information==0 although it
244 * successfuly read the data. Workaround it - preclear (not postclear) the
245 * buffer and do not make any other assumptions about the data read.
247 memset(address,0,PAGE_SIZE); /* pre-clear the buffer */
248 Mdl=MmCreateMdl(NULL,address,PAGE_SIZE); /* FIXME: Deprecated in favor of IoAllocateMdl() */
250 KeInitializeEvent(&Event,NotificationEvent,FALSE);
251 /* FIXME: read/write should be possible after CcSetDirtyPinnedData() etc. */
252 IoStatus.Information=0; /* preventive pre-clear for buggy filesystems */
253 err=IoPageRead(FileObject,Mdl,FileOffset,&Event,&IoStatus);
254 g_assert(NT_SUCCESS(err));
255 g_assert(NT_SUCCESS(IoStatus.Status));
256 /* It is not == as the file may be shorter than requested */
257 g_assert(IoStatus.Information<=length);
260 /* Forbidden, see the comment above about ext2fsd.sys.
261 * memset(((char *)address)+IoStatus.Information,0,(length-IoStatus.Information));
264 return IoStatus.Information; /* may be shorter than real! */
268 static struct private_bcb *captive_privbcb_find(IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER FileOffset,IN ULONG Length,
269 PUBLIC_BCB *Bcb_find)
271 struct page_position pagepos_local,*pagepos;
272 struct private_bcb *privbcb,*privbcb_listitem;
275 g_return_val_if_fail(FileObject!=NULL,NULL);
276 g_return_val_if_fail(FileOffset!=NULL,NULL);
277 /* 'Bcb_find' may be NULL */
279 page_position_hash_init();
281 pagepos_local.FileObject=FileObject;
282 pagepos_local.FileOffset.QuadPart=CAPTIVE_ROUND_DOWN64(FileOffset->QuadPart,PAGE_SIZE);
283 pagepos_local.privbcb_list=NULL;
284 pagepos_local.shmid=-1;
285 if (!(pagepos=g_hash_table_lookup(page_position_hash,&pagepos_local)))
287 g_assert(validate_page_position(pagepos));
288 g_assert(pagepos->privbcb_list!=NULL);
291 for (privbcb_list=pagepos->privbcb_list;privbcb_list;privbcb_list=privbcb_list->next) {
292 privbcb_listitem=privbcb_list->data;
294 && privbcb_listitem->MappedFileOffset.QuadPart==FileOffset->QuadPart
295 && privbcb_listitem->MappedLength==Length
296 && (!Bcb_find || Bcb_find==privbcb_listitem->PublicBcb)) {
297 g_assert(privbcb==NULL); /* appropriate 'Bcb_find'-matching privbcb found twice */
298 privbcb=privbcb_listitem;
306 /* Sanity check 'privbcb': */
307 g_return_val_if_fail(FileObject==privbcb->FileObject,FALSE);
315 * @FileObject: Initialized open #FileObject to map.
316 * %NULL value is forbidden.
317 * @FileOffset: The @FileObject file offset from where to map the region from.
318 * Negative value is forbidden.
319 * @Length: Requested length of the region to map from @FileObject.
320 * FIXME: Value %0 is currently forbidden by libcaptive; it should be allowed.
321 * @Flags: %MAP_WAIT means whether disk waiting is permitted for this function.
322 * %MAP_NO_READ currently ignored; we map the data always.
323 * Value without %MAP_WAIT is currently forbidden by libcaptive as we have no on-demand loading implemented.
324 * @Bcb: Returns initialized #PUBLIC_BCB to refer to the mapped region.
325 * The memory region can be larger than requested as it is %PAGE_SIZE aligned.
326 * %NULL pointer is forbidden.
327 * @Buffer: Returns the mapped memory region start address.
328 * This address may not be %PAGE_SIZE aligned.
329 * %NULL pointer is forbidden.
331 * Maps the specified region of @FileObject to automatically chosen address space.
332 * FIXME: No on-demand loading implemented yet - the whole region is read at the time of this function call.
334 * WARNING: If you modify the data in the returned @Buffer you must call some CcPinMappedData()
335 * or CcPinRead() afterwards. W32 docs say you should never modify the data in any way from this function
336 * but W32 filesystems apparently do not conform to it. :-) If you do not take care of the
337 * modified data by some dirty-marking facility such data will be carelessly dropped without
338 * their commit to the disk.
340 * Every call to this function must be matched by a one corresponding CcUnpinData() call.
342 * We can be called as full CcMapData() (e.g. CcPinRead() from fastfat.sys)
343 * even if such mapping for such file already exists.
344 * We should probably create a new #Bcb for the same space,
345 * at least ntfs.sys of NT-5.1sp1 appears to expect it. Bleech.
347 * Returns: %TRUE if the region was successfuly mapped.
348 * @Bcb with the initialized new memory region.
349 * @Buffer with the address of the exact byte specified by @FileOffset.
351 BOOLEAN CcMapData(IN PFILE_OBJECT FileObject,
352 IN PLARGE_INTEGER FileOffset,IN ULONG Length,IN ULONG Flags,OUT PVOID *Bcb,OUT PVOID *Buffer)
354 PUBLIC_BCB **PublicBcbp,*PublicBcb;
355 struct page_position pagepos_local,*pagepos;
356 LARGE_INTEGER FileOffset_bottom,FileOffset_top;
357 gpointer base_aligned;
358 size_t offset,length_mapped_aligned;
361 struct private_bcb *privbcb;
362 gboolean after_eof=FALSE; /* Did we reached the end of file already? */
363 GPtrArray *read_array;
365 g_return_val_if_fail(FileObject!=NULL,FALSE);
366 g_return_val_if_fail(FileOffset!=NULL,FALSE);
367 g_return_val_if_fail(FileOffset->QuadPart>=0,FALSE);
368 g_return_val_if_fail(Length>0,FALSE); /* FIXME: not handled below; 0 should be allowed */
369 g_return_val_if_fail(Flags&MAP_WAIT,FALSE); /* FIXME: on-demand loading not yet implemented */
370 g_return_val_if_fail(!(Flags&~(MAP_WAIT|MAP_NO_READ)),FALSE); /* unknown flags? */
371 g_return_val_if_fail(Bcb!=NULL,FALSE);
372 g_return_val_if_fail(Buffer!=NULL,FALSE);
374 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: FileObject=%p,FileOffset=0x%llX,Length=0x%lX,Flags=0x%lX",G_STRLOC,
375 FileObject,(guint64)FileOffset->QuadPart,(gulong)Length,(gulong)Flags);
377 g_return_val_if_fail(FileObject->SectionObjectPointers!=NULL,FALSE);
378 g_return_val_if_fail(FileObject->DeviceObject!=NULL,FALSE);
379 /* Is PAGE_SIZE aligned with 'FileObject->DeviceObject->SectorSize'?
380 * 'SectorSize' may not yet be initialized during mount operation
381 * and 'FileObject->DeviceObject->Vpb' may exist in such case.
383 g_return_val_if_fail(0
384 || FileObject->DeviceObject->SectorSize==0 /* prevent division by 0 */
385 || 0==CAPTIVE_ROUND_DOWN_EXCEEDING(PAGE_SIZE,FileObject->DeviceObject->SectorSize),
388 page_position_hash_init();
389 private_bcb_hash_init();
391 PublicBcbp=(PUBLIC_BCB **)Bcb;
392 /* extend 'FileOffset' and 'Length' to page boundaries */
393 FileOffset_bottom.QuadPart=CAPTIVE_ROUND_DOWN64(FileOffset->QuadPart,PAGE_SIZE);
394 FileOffset_top.QuadPart=CAPTIVE_ROUND_UP64(FileOffset->QuadPart+Length,PAGE_SIZE);
395 length_mapped_aligned=(FileOffset_top.QuadPart-FileOffset_bottom.QuadPart);
397 /* We can be called as full CcMapData() (e.g. CcPinRead() from fastfat.sys)
398 * even if such mapping for such file already exists.
399 * We should probably create a new Bcb for the same space,
400 * at least ntfs.sys of NT-5.1sp1 appears to expect it. Bleech.
402 if ((privbcb=captive_privbcb_find(FileObject,FileOffset,Length,NULL)))
403 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: FileObject=%p,FileOffset=0x%llX,Length=0x%lX already mapped by privbcb %p",
404 G_STRLOC,FileObject,(guint64)FileOffset->QuadPart,(gulong)Length,privbcb);
406 /* Create 'base_aligned'; referenced as unaligned by 'privbcb'. */
407 /* TODO: on-demand loading */
408 /* Although we do zeroed-page mapping here we just reserve the linears
409 * space by it - all the page will be overriden by shmat(2) afterwards anyway.
413 length_mapped_aligned, /* length */
414 PROT_READ|PROT_WRITE, /* prot; read/write must be possible although write is not guaranteed to be flushed yet */
415 MAP_PRIVATE|MAP_ANONYMOUS, /* flags */
416 -1, /* fd; ignored due to MAP_ANONYMOUS */
417 0); /* offset; ignored due to MAP_ANONYMOUS */
418 g_assert(base_aligned!=NULL);
420 /* Create 'PublicBcb'; referenced by 'privbcb'. */
421 captive_new(PublicBcb);
422 PublicBcb->NodeTypeCode=CAPTIVE_PUBLIC_BCB_NODETYPECODE;
423 PublicBcb->NodeByteSize=sizeof(*PublicBcb); /* we have no extensions there */
424 PublicBcb->MappedLength=Length;
425 PublicBcb->MappedFileOffset=*FileOffset;
427 /* Create 'privbcb'; referenced by created 'pagepos'es. */
428 captive_new(privbcb);
429 privbcb->PublicBcb=PublicBcb;
430 privbcb->FileObject=FileObject;
431 privbcb->ref_count=1;
432 privbcb->idle_func_pending=FALSE;
433 privbcb->MappedLength=PublicBcb->MappedLength;
434 privbcb->MappedFileOffset=PublicBcb->MappedFileOffset;
435 privbcb->base=base_aligned+CAPTIVE_ROUND_DOWN_EXCEEDING64(FileOffset->QuadPart,PAGE_SIZE);
436 privbcb->dirty=FALSE;
437 privbcb->lsn_valid=FALSE;
438 g_hash_table_insert(private_bcb_hash,
440 privbcb); /* value */
442 /* We MUST NOT call captive_Cc_IoPageRead() inside our pagepos filling loop
443 * below as captive_Cc_IoPageRead() has very big consequences as it calls
444 * the filesystem code and we may get reentrancy.
445 * Therefore we store all missing page read requests to 'read_array' and we
446 * fill them when all the memory structures are in consistent state.
447 * We can also coalescence the requests more easily this way.
449 read_array=g_ptr_array_new();
451 pagepos_local.FileObject=FileObject;
452 pagepos_local.shmid=-1;
453 pagepos_local.privbcb_list=NULL;
456 offset<length_mapped_aligned;
460 pagepos_local.FileOffset.QuadPart=FileOffset_bottom.QuadPart+offset;
461 if (!(pagepos=g_hash_table_lookup(page_position_hash,&pagepos_local))) {
462 captive_new(pagepos);
463 /* FIXME: Reference 'FileObject' to not to leave broken references to it here */
464 *pagepos=pagepos_local;
465 pagepos->shmid=shmget(IPC_PRIVATE,PAGE_SIZE,IPC_CREAT|IPC_CREAT|0600);
466 pagepos->privbcb_list=NULL;
467 g_ptr_array_add(read_array,pagepos); /* enlist this 'pagepos' as todo read item */
470 g_assert(pagepos->privbcb_list!=NULL);
471 g_assert(pagepos->shmid!=-1);
472 pageaddr=(gpointer)(((char *)base_aligned)+offset);
473 /* It appears as shmat(2) cannot override previously mmap(2)ed memory;
474 * mmap(2) is still needed to get linear block of memory assignment.
476 /* TODO:thread; munmap()..shmat() window */
477 errint=munmap(pageaddr,PAGE_SIZE);
479 errptr=shmat(pagepos->shmid,
480 pageaddr, /* shmaddr */
481 0); /* shmflg; !SHM_RDONLY==r/w FIXME: read/write should be possible after CcSetDirtyPinnedData() etc. */
482 g_assert(errptr==pageaddr);
484 g_assert(g_list_find(pagepos->privbcb_list,privbcb)==NULL);
485 pagepos->privbcb_list=g_list_prepend(pagepos->privbcb_list,privbcb); /* order not important */
486 g_assert(g_list_find(pagepos->privbcb_list,privbcb)!=NULL);
487 if (pagepos->privbcb_list->next==NULL) { /* exactly one item (we just added it now) */
489 errint=shmctl(pagepos->shmid,
493 g_hash_table_insert(page_position_hash,
495 pagepos); /* value */
497 g_assert(validate_page_position(pagepos));
500 /* Fill in the missing pages content todo-list stored in 'read_array': */
501 while (read_array->len && (pagepos=g_ptr_array_remove_index(read_array,
505 struct pagepos *pagepos_next;
506 gpointer pageaddr,pageaddr_next;
508 pageaddr=(gpointer)(((char *)base_aligned)+(pagepos->FileOffset.QuadPart-FileOffset_bottom.QuadPart));
510 /* Coalescence of the requests */
511 while (read_array->len) {
512 pagepos_next=g_ptr_array_index(read_array,
514 pageaddr_next=(gpointer)(((char *)base_aligned)+(pagepos->FileOffset.QuadPart-FileOffset_bottom.QuadPart));
515 if (pageaddr_next!=((char *)pageaddr)+read_size)
517 read_size+=PAGE_SIZE;
518 g_assert(pagepos_next==g_ptr_array_remove_index(read_array,
521 /* Read the range content: */
522 got=captive_Cc_IoPageRead(FileObject,pageaddr,read_size,&pagepos->FileOffset);
526 g_assert(got<=PAGE_SIZE);
527 after_eof=(got<PAGE_SIZE);
529 g_ptr_array_free(read_array,
530 TRUE); /* free_seg; free the array of gpointer(==struct pagepos *) items */
532 /* offset _into_ page, may not be PAGE_SIZE aligned: */
533 *Buffer=privbcb->base;
534 *PublicBcbp=PublicBcb;
535 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,
536 "%s: result: privbcb->base=%p,privbcb->base+privbcb->MappedLength=%p,privbcb->MappedLength=0x%lX",
537 G_STRLOC,privbcb->base,((char *)privbcb->base)+privbcb->MappedLength,(unsigned long)privbcb->MappedLength);
538 g_assert(validate_Bcb(PublicBcb)==TRUE);
539 if (!FileObject->SectionObjectPointers->SharedCacheMap)
540 FileObject->SectionObjectPointers->SharedCacheMap=PublicBcb;
542 /* FIXME: (NOTE*1) Weird but it appears as fastfat.sys during make_directory()
543 * can pass us an already cached 'FileObject' (with different offset/size).
544 * We must not CcUnpinData() it as its BCB is still referenced (CcUnpinData()ed) by fastfat.sys.
546 FileObject->SectionObjectPointers->SharedCacheMap=NULL;
548 FileObject->SectionObjectPointers->SharedCacheMap=PublicBcb;
556 * @FileObject: Initialized open #FileObject to map.
557 * %NULL value is forbidden.
558 * @MappedFileOffset: The @FileObject file offset from where to map the region from.
559 * Negative value is forbidden.
560 * @MappedLength: Requested length of the region to map from @FileObject.
561 * FIXME: Value %0 is currently forbidden by libcaptive; it should be allowed.
562 * @Wait: Whether disk waiting is permitted for this function.
563 * Value currently ignored by libcaptive as the data must have been mapped by CcMapData() already anyway.
564 * @Flags: %PIN_WAIT means whether disk waiting is permitted for this function.
565 * Value without %PIN_WAIT is currently permtted by libcaptive as the data must have been mapped by CcMapData() already anyway.
566 * %PIN_NO_READ currently ignored; we map the data always.
567 * FIXME: %PIN_EXCLUSIVE for exclusive @Bcb access is now ignored by libcaptive.
568 * %PIN_IF_BCB if @Bcb should never be created; function is successful only if @Bcb already exists.
569 * @Bcb: Returns initialized #PUBLIC_BCB to refer to the mapped region.
570 * The memory region can be larger than requested as it is %PAGE_SIZE aligned.
571 * %NULL pointer is forbidden.
572 * @Buffer: Returns the mapped memory region start address.
573 * This address may not be %PAGE_SIZE aligned.
574 * %NULL pointer is forbidden.
576 * This function will allow you to modify the data mapped by CcMapData().
577 * libcaptive does not differentiate this function with CcMapData().
579 * NEVER re-read any memory from FileObject here!
580 * at least fastfat.sys directory create relies on the fact of CcPinRead()
581 * with already modified buffers to be left intact.
583 * This call will proceed as CcPinRead() if such #Bcb does not yet exist.
584 * This is IMO just a bug workaround for a peruse by fastfat.sys FatLocateVolumeLabel().
586 * Every call to this function must be matched by a one corresponding CcUnpinData() call.
588 * Returns: %TRUE if the region was successfuly mapped.
589 * @Bcb with the initialized new memory region.
590 * @Buffer with the address of the exact byte specified by @FileOffset.
592 BOOLEAN CcPinMappedData
593 (IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER FileOffset,IN ULONG Length,IN ULONG Flags,OUT PVOID *Bcb)
595 struct private_bcb *privbcb;
597 g_return_val_if_fail(FileObject!=NULL,FALSE);
598 g_return_val_if_fail(FileOffset!=NULL,FALSE);
599 g_return_val_if_fail(FileOffset->QuadPart>=0,FALSE);
600 g_return_val_if_fail(Length>0,FALSE); /* FIXME: not handled below; 0 should be allowed */
601 /* 'Flags&PIN_WAIT' ignored as we already must have the data mapped */
602 g_return_val_if_fail(!(Flags&~(PIN_WAIT|PIN_EXCLUSIVE|PIN_NO_READ|PIN_IF_BCB)),FALSE); /* unknown flags? */
603 g_return_val_if_fail(Bcb!=NULL,FALSE);
605 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: FileObject=%p,FileOffset=0x%llX,Length=0x%lX,Flags=0x%lX",G_STRLOC,
606 FileObject,(guint64)FileOffset->QuadPart,(gulong)Length,(gulong)Flags);
608 privbcb=captive_privbcb_find(FileObject,FileOffset,Length,NULL);
609 if (!privbcb && (Flags & PIN_IF_BCB)) /* BCB does not exist */
611 /* Appropriate privbcb not found.
612 * This IMO should not happen and it is a bug in the client.
613 * Unfortuantely fastfat.sys FatLocateVolumeLabel() will CcPinMappedData()
614 * the volume label dirent without any previous CcMapData() or CcPinRead() !
628 /* NEVER re-read any memory from FileObject here! */
630 privbcb->ref_count++;
632 /* Memory already mapped by CcMapData(). */
633 *Bcb=privbcb->PublicBcb;
640 * @FileObject: Initialized open #FileObject to map.
641 * %NULL value is forbidden.
642 * @FileOffset: The @FileObject file offset from where to map the region from.
643 * Negative value is forbidden.
644 * @Length: Requested length of the region to map from @FileObject.
645 * FIXME: Value %0 is currently forbidden by libcaptive; it should be allowed.
646 * @Flags: %PIN_WAIT means whether disk waiting is permitted for this function.
647 * Value without %PIN_WAIT is currently permtted by libcaptive as the data must have been mapped by CcMapData() already anyway.
648 * %PIN_NO_READ currently ignored; we map the data always.
649 * FIXME: %PIN_EXCLUSIVE for exclusive @Bcb access is now ignored by libcaptive.
650 * %PIN_IF_BCB if @Bcb should never be created; function is successful only if @Bcb already exists.
651 * @Bcb: Returns initialized #PUBLIC_BCB to refer to the mapped region.
652 * The memory region can be larger than requested as it is %PAGE_SIZE aligned.
653 * %NULL pointer is forbidden.
654 * @Buffer: Returns the mapped memory region start address.
655 * This address may not be %PAGE_SIZE aligned.
656 * %NULL pointer is forbidden.
658 * Merely a shortcut call for CcMapData() and CcPinMappedData() afterwards.
659 * See these two functions for the details. It has a difference to subsequent
660 * calling of CcMapData() and CcPinMappedData() instead as this call counts
661 * only as one function for a corresponding CcUnpinData() call.
663 * Every call to this function must be matched by a one corresponding CcUnpinData() call.
665 * Returns: %TRUE if the region was successfuly mapped.
666 * @Bcb with the initialized new memory region.
667 * @Buffer with the address of the exact byte specified by @FileOffset.
669 BOOLEAN CcPinRead(IN PFILE_OBJECT FileObject,
670 IN PLARGE_INTEGER FileOffset,IN ULONG Length,IN ULONG Flags,OUT PVOID *Bcb,OUT PVOID *Buffer)
672 PVOID Bcb_CcPinMappedData;
674 gboolean count_CcMapData;
675 struct private_bcb *privbcb;
677 g_return_val_if_fail(FileObject!=NULL,FALSE);
678 g_return_val_if_fail(FileOffset!=NULL,FALSE);
679 g_return_val_if_fail(FileOffset->QuadPart>=0,FALSE);
680 g_return_val_if_fail(Length>0,FALSE); /* FIXME: not handled below; 0 should be allowed */
681 /* 'Flags&PIN_WAIT' ignored as we already must have the data mapped */
682 g_return_val_if_fail(!(Flags&~(PIN_WAIT|PIN_EXCLUSIVE|PIN_NO_READ|PIN_IF_BCB)),FALSE); /* unknown flags? */
683 g_return_val_if_fail(Bcb!=NULL,FALSE);
684 g_return_val_if_fail(Buffer!=NULL,FALSE);
686 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: FileObject=%p,FileOffset=0x%llX,Length=0x%lX,Flags=0x%lX",G_STRLOC,
687 FileObject,(guint64)FileOffset->QuadPart,(gulong)Length,(gulong)Flags);
689 if (!(Flags&PIN_IF_BCB)) {
690 errbool=CcMapData(FileObject,FileOffset,Length,
692 | (Flags&PIN_WAIT ? MAP_WAIT : 0),
694 g_return_val_if_fail(errbool==TRUE,FALSE);
695 count_CcMapData=TRUE;
698 count_CcMapData=FALSE;
700 errbool=CcPinMappedData(FileObject,FileOffset,Length,Flags,&Bcb_CcPinMappedData);
701 if (!(Flags&PIN_IF_BCB)) {
702 g_return_val_if_fail(errbool==TRUE,FALSE);
703 g_return_val_if_fail(Bcb_CcPinMappedData==*Bcb,FALSE);
706 if (errbool==FALSE) /* FALSE permitted; We may fail if Bcb does not exist yet. */
708 *Bcb=Bcb_CcPinMappedData;
711 privbcb=captive_privbcb_find(FileObject,FileOffset,Length,*Bcb);
712 g_assert(privbcb!=NULL);
713 g_assert(privbcb->ref_count>=1);
714 g_assert(privbcb->PublicBcb==*Bcb);
715 if (count_CcMapData) {
716 /* CcPinRead() must always reference-count only by 1 despite any sub-called functions! */
717 g_assert(privbcb->ref_count>=2);
718 privbcb->ref_count--;
725 static void logging_notify_privbcb_flush(struct private_bcb *privbcb);
727 static void captive_privbcb_flush(struct private_bcb *privbcb)
731 IO_STATUS_BLOCK IoStatus;
733 gpointer base_sectoraligned;
734 gsize length_sectoraligned;
735 LARGE_INTEGER FileOffset_sectoraligned;
741 logging_notify_privbcb_flush(privbcb);
743 g_assert(privbcb->FileObject->DeviceObject!=NULL);
745 /* We can get 0=='privbcb->FileObject->DeviceObject->SectorSize' during mount of ext2fsd.sys.
746 * FIXME: We are unable to find the correct sectorsize for a filesystem as
747 * even the 'CommonFcb' below contains invalid information.
748 * As we need to have 'sectorsize' <=filesystem_blocksize at least for ext2fsd.sys
749 * we choose PAGE_SIZE - the maximum libcaptive can with its design and also the maximum
750 * size ever needed for ext2fsd.sys (PAGE_SIZE is the maximum ext2 block size).
752 sectorsize=PAGE_SIZE;
754 sectorsize=privbcb->FileObject->DeviceObject->SectorSize;
755 if (privbcb->FileObject->FsContext) {
756 REACTOS_COMMON_FCB_HEADER *CommonFcb=(REACTOS_COMMON_FCB_HEADER *)privbcb->FileObject->FsContext;
758 /* FIXME: Check CommonFcb->Type */
759 /* 'AllocationSize' can be less than 'sectorsize' if the total file length is smaller.
760 * Observed with ext2fsd.sys volume-file.
762 if (sectorsize<CommonFcb->AllocationSize.QuadPart)
763 sectorsize=CommonFcb->AllocationSize.QuadPart;
767 /* Is PAGE_SIZE aligned with 'privbcb->FileObject->DeviceObject->SectorSize'? */
768 g_assert(sectorsize>0);
769 g_assert(0==CAPTIVE_ROUND_DOWN_EXCEEDING(PAGE_SIZE,sectorsize));
770 /* We align here directly the 'privbcb->base' which is not correct.
771 * We should rather aligned according to 'privbcb->MappedOffset' but
772 * as 'privbcb->base' with PAGE_SIZE alignment is just a possibly
773 * better alignment than 'privbcb->FileObject->DeviceObject->SectorSize' it must the same operation.
775 g_assert(CAPTIVE_ROUND_DOWN_EXCEEDING(privbcb->base,sectorsize)
776 ==CAPTIVE_ROUND_DOWN_EXCEEDING64(privbcb->MappedFileOffset.QuadPart,sectorsize));
777 base_sectoraligned =CAPTIVE_ROUND_DOWN(privbcb->base,sectorsize);
778 length_sectoraligned=CAPTIVE_ROUND_UP(((char *)privbcb->base)+privbcb->MappedLength,sectorsize)
779 -((char *)base_sectoraligned);
780 g_assert(0==CAPTIVE_ROUND_DOWN_EXCEEDING(length_sectoraligned,sectorsize));
781 FileOffset_sectoraligned.QuadPart=CAPTIVE_ROUND_DOWN64(privbcb->MappedFileOffset.QuadPart,sectorsize);
783 Mdl=MmCreateMdl(NULL,base_sectoraligned,length_sectoraligned);
786 KeInitializeEvent(&Event,NotificationEvent,FALSE);
788 /* FIXME: read/write should be possible after CcSetDirtyPinnedData() etc. */
789 /* Use rather IoSynchronousPageWrite() than IoPageWrite() to prevent STATUS_PENDING. */
790 err=IoSynchronousPageWrite(privbcb->FileObject,Mdl,&FileOffset_sectoraligned,&Event,&IoStatus);
791 g_assert(NT_SUCCESS(err));
792 g_assert(NT_SUCCESS(IoStatus.Status));
793 /* We should write at least the unaligned mapped data although we
794 * do not need to successfuly write the whole aligned amount.
795 * FIXME: Also we can get just value 0 if the write is considered 'not dirty'
796 * during FAT write by fastfat.sys.
798 g_assert(IoStatus.Information==0 || IoStatus.Information>=CAPTIVE_ROUND_DOWN_EXCEEDING(privbcb->base,sectorsize)
799 +privbcb->MappedLength);
800 g_assert(IoStatus.Information<=length_sectoraligned);
802 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: 'dirty' flush: FileObject=%p,MappedFileOffset=0x%llX,MappedLength=0x%lX,base=%p"
803 "; base_sectoraligned=%p,FileOffset_sectoraligned=0x%llX,length_sectoraligned=0x%lX; ->Information=0x%lX",G_STRLOC,
804 privbcb->FileObject,(guint64)privbcb->MappedFileOffset.QuadPart,(gulong)privbcb->MappedLength,privbcb->base,
805 base_sectoraligned,(guint64)FileOffset_sectoraligned.QuadPart,(gulong)length_sectoraligned,
806 (gulong)IoStatus.Information);
808 privbcb->dirty=FALSE;
812 static gboolean CcUnpinData_idle_func(struct private_bcb *privbcb /*data*/)
816 g_return_val_if_fail(privbcb!=NULL,FALSE); /* remove-me */
817 g_return_val_if_fail(privbcb->PublicBcb!=NULL,FALSE); /* remove-me */
819 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,
820 "%s: privbcb->FileObject=%p,privbcb->MappedFileOffset=0x%llX,privbcb->MappedLength=0x%lX,privbcb->ref_count=%d"
821 ",privbcb->idle_func_pending=%d",G_STRLOC,
822 privbcb->FileObject,(guint64)privbcb->MappedFileOffset.QuadPart,(gulong)privbcb->MappedLength,(int)privbcb->ref_count,
823 (int)privbcb->idle_func_pending);
825 g_assert(privbcb->idle_func_pending==TRUE);
826 privbcb->idle_func_pending=FALSE;
828 g_assert(privbcb->ref_count>0);
830 if (--privbcb->ref_count)
831 return FALSE; /* remove-me */
833 /* We were called as CcUnpinData()->captive_privbcb_flush()->CcUnpinData()->CcUnpinData_idle_func()
835 if (privbcb->dirty) {
836 privbcb->ref_count++;
837 return FALSE; /* remove-me */
840 errbool=g_hash_table_remove(private_bcb_hash,privbcb->PublicBcb);
841 g_assert(errbool==TRUE);
843 return FALSE; /* remove-me */
848 * @Bcb: Initialized #PUBLIC_BCB structure.
849 * %NULL value is forbidden.
851 * Dereferences @Bcb with the possible cleanup operations if you were the last owner.
853 VOID CcUnpinData(IN PVOID Bcb)
855 PUBLIC_BCB *PublicBcb;
856 struct private_bcb *privbcb;
858 g_return_if_fail(validate_Bcb(Bcb));
860 private_bcb_hash_init();
862 PublicBcb=(PUBLIC_BCB *)Bcb;
863 privbcb=g_hash_table_lookup(private_bcb_hash,PublicBcb);
864 g_return_if_fail(privbcb!=NULL);
866 g_assert(privbcb->FileObject->SectionObjectPointers!=NULL);
867 /* It may not 'privbcb->FileObject->SectionObjectPointers->SharedCacheMap==PublicBcb'; see (NOTE*1) */
869 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,
870 "%s: privbcb->FileObject=%p,privbcb->MappedFileOffset=0x%llX,privbcb->MappedLength=0x%lX,privbcb->ref_count=%d"
871 ",privbcb->idle_func_pending=%d",G_STRLOC,
872 privbcb->FileObject,(guint64)privbcb->MappedFileOffset.QuadPart,(gulong)privbcb->MappedLength,(int)privbcb->ref_count,
873 (int)privbcb->idle_func_pending);
876 g_assert(privbcb->ref_count>0);
877 /* Do not write back the contents if this is not the final unpin.
878 * FIXME: Is it correct?
880 if (--privbcb->ref_count) {
881 /* CcUnpinData() end of the cycle for the second time while CcUnpinData_idle_func()
882 * was not yet invoked.
884 if (privbcb->ref_count==1 && privbcb->idle_func_pending) {
885 captive_privbcb_flush(privbcb);
890 privbcb->ref_count++; /* it will get decreased again in CcUnpinData_idle_func() */
892 captive_privbcb_flush(privbcb);
894 g_assert(privbcb->FileObject->SectionObjectPointers!=NULL);
895 /* It may not 'privbcb->FileObject->SectionObjectPointers->SharedCacheMap==PublicBcb'; see (NOTE*1) */
896 if (privbcb->FileObject->SectionObjectPointers->SharedCacheMap==PublicBcb)
897 privbcb->FileObject->SectionObjectPointers->SharedCacheMap=NULL;
899 /* Caboom: lfs (log file system) of ntfs.sys-NT5.1sp1 will do:
900 * CcPinRead(); CcUnpinData(); access Buffer (wanna-crash);
901 * Therefore we must postpone the buffer unmapping to some idle function...
902 * I expect it a bug in ntfs.sys.
904 if (!privbcb->idle_func_pending) {
905 privbcb->idle_func_pending=TRUE;
907 G_PRIORITY_DEFAULT_IDLE, /* priority */
908 (GSourceFunc)CcUnpinData_idle_func, /* function */
915 VOID CcRepinBcb(IN PVOID Bcb)
917 PUBLIC_BCB *PublicBcb;
918 struct private_bcb *privbcb;
920 g_return_if_fail(validate_Bcb(Bcb));
922 private_bcb_hash_init();
924 PublicBcb=(PUBLIC_BCB *)Bcb;
925 privbcb=g_hash_table_lookup(private_bcb_hash,PublicBcb);
926 g_return_if_fail(privbcb!=NULL);
928 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: Bcb=%p; privbcb->FileObject=%p",G_STRLOC,
929 Bcb,privbcb->FileObject);
931 privbcb->ref_count++;
935 VOID CcUnpinRepinnedBcb(IN PVOID Bcb,IN BOOLEAN WriteThrough,IN PIO_STATUS_BLOCK IoStatus)
937 PUBLIC_BCB *PublicBcb;
938 struct private_bcb *privbcb;
940 g_return_if_fail(validate_Bcb(Bcb));
941 g_return_if_fail(IoStatus!=NULL);
943 private_bcb_hash_init();
945 PublicBcb=(PUBLIC_BCB *)Bcb;
946 privbcb=g_hash_table_lookup(private_bcb_hash,PublicBcb);
947 g_return_if_fail(privbcb!=NULL);
949 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: Bcb=%p,WriteThrough=%d,IoStatus=%p; privbcb->FileObject=%p",G_STRLOC,
950 Bcb,(gint)WriteThrough,IoStatus,privbcb->FileObject);
952 IoStatus->Status=STATUS_SUCCESS;
953 IoStatus->Information=privbcb->MappedLength;
959 VOID CcSetDirtyPinnedData(IN PVOID Bcb,IN PLARGE_INTEGER Lsn OPTIONAL)
961 PUBLIC_BCB *PublicBcb;
962 struct private_bcb *privbcb;
964 g_return_if_fail(validate_Bcb(Bcb));
966 private_bcb_hash_init();
968 PublicBcb=(PUBLIC_BCB *)Bcb;
969 privbcb=g_hash_table_lookup(private_bcb_hash,PublicBcb);
970 g_return_if_fail(privbcb!=NULL);
972 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: Bcb=%p,Lsn=0x%llX; privbcb->FileObject=%p",G_STRLOC,
973 Bcb,(guint64)(!Lsn ? -1 : Lsn->QuadPart),privbcb->FileObject);
975 /* 'privbcb->ref_count' not to be increased by this function. */
979 privbcb->lsn_valid=TRUE;
988 * @FileObject: Initialized open #FileObject to update file sizes of.
989 * %NULL value is forbidden.
990 * @FileSizes: New file sizes to update cache to.
991 * %NULL value is forbidden.
993 * Update cache properties after file sizes were updated.
994 * Probably only the exceeding pages need to be unmapped and BCBs updated
995 * if FileSizes->AllocationSize gets shrunk.
997 * FIXME: Currently a NOP with no effect by libcaptive.
999 VOID CcSetFileSizes(IN PFILE_OBJECT FileObject,IN PCC_FILE_SIZES FileSizes)
1001 g_return_if_fail(FileObject!=NULL);
1002 g_return_if_fail(FileSizes!=NULL);
1004 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: FileObject=%p,"
1005 "FileSizes->AllocationSize=0x%llX,FileSizes->FileSize=0x%llX,FileSizes->ValidDataLength=0x%llX",G_STRLOC,
1006 FileObject,(guint64)FileSizes->AllocationSize.QuadPart,(guint64)FileSizes->FileSize.QuadPart,
1007 (guint64)FileSizes->ValidDataLength.QuadPart);
1009 /* FIXME: check BCB && 'struct page_position' invalidities */
1014 * CcPurgeCacheSection:
1015 * @SectionObjectPointer: Pointer specifying file to purge;
1016 * %NULL value is forbidden.
1017 * libcaptive interprets only #SharedCacheMap field as #PUBLIC_BCB pointer.
1018 * Field #SharedCacheMap value %NULL is permitted; libcaptive does a NOP with %FALSE return code in such case.
1019 * @FileOffset: Starting offset of the ranger to purge.
1020 * %NULL pointer is permitted and it means to purge the whole whole.
1021 * FIXME: Non %NULL pointer is NOT IMPLEMENTED YET by libcaptive.
1022 * @Length: Length of the range to purge. Ignored if @FileOffset==NULL.
1023 * @UninitializeCacheMaps: Purge also private cache maps (FIXME: ???).
1025 * Drop any caching for shrunken file which is not being deleted.
1026 * libcaptive will no longer consider such #BCB as dirty.
1028 * Returns: %TRUE if the range was purged successfuly.
1030 BOOLEAN CcPurgeCacheSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
1031 IN PLARGE_INTEGER FileOffset OPTIONAL,IN ULONG Length,IN BOOLEAN UninitializeCacheMaps)
1033 PUBLIC_BCB *PublicBcb;
1034 struct private_bcb *privbcb;
1036 g_return_val_if_fail(SectionObjectPointer!=NULL,FALSE);
1037 if (SectionObjectPointer->SharedCacheMap==NULL)
1038 return FALSE; /* failed - nothing to purge */
1039 g_return_val_if_fail(FileOffset==NULL,FALSE); /* NOT IMPLEMENTED YET */
1041 PublicBcb=SectionObjectPointer->SharedCacheMap;
1042 g_return_val_if_fail(validate_Bcb(PublicBcb),FALSE);
1044 private_bcb_hash_init();
1046 privbcb=g_hash_table_lookup(private_bcb_hash,PublicBcb);
1047 g_return_val_if_fail(privbcb!=NULL,FALSE);
1049 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: SectionObjectPointer=%p(Bcb=%p,privbcb=%p,privbcb->FileObject=%p),"
1050 "FileOffset=0x%llX,Length=0x%lX,UninitializeCacheMaps=%d",G_STRLOC,
1051 SectionObjectPointer,PublicBcb,privbcb,privbcb->FileObject,
1052 (guint64)(!FileOffset ? -1 : FileOffset->QuadPart),(gulong)Length,(gint)UninitializeCacheMaps);
1054 privbcb->dirty=FALSE; /* purge it */
1062 * @FileObject: Initialized open #FileObject to map.
1063 * %NULL value is forbidden.
1064 * @FileOffset: The @FileObject file offset from where to map the region from.
1065 * Negative value is forbidden.
1066 * @Length: Requested length of the region to map from @FileObject.
1067 * Value %0 is permitted (no effect of this function call).
1068 * @Wait: Whether disk waiting is permitted for this function.
1069 * Value %FALSE is currently forbidden by libcaptive as we have no on-demand loading implemented.
1070 * @Buffer: Address of memory region with already allocated memory of size @Length.
1071 * This address may not be %PAGE_SIZE aligned.
1072 * %NULL pointer is forbidden.
1073 * @IoStatus: #PIO_STATUS_BLOCK to return status of this operation.
1074 * %NULL pointer is forbidden.
1076 * Reads the specified region of @FileObject to the given @Buffer.
1077 * No on-demand loading is in effect.
1079 * Returns: %TRUE if the region was successfuly filled with @Length bytes.
1080 * @IoStatus.Status initialized by %STATUS_SUCCESS if successful.
1081 * @IoStatus.Information initialized by @Length if successful.
1083 BOOLEAN CcCopyRead(IN PFILE_OBJECT FileObject,
1084 IN PLARGE_INTEGER FileOffset,IN ULONG Length,IN BOOLEAN Wait,OUT PVOID Buffer,OUT PIO_STATUS_BLOCK IoStatus)
1090 g_return_val_if_fail(FileObject!=NULL,FALSE);
1091 g_return_val_if_fail(FileOffset!=NULL,FALSE);
1092 g_return_val_if_fail(Buffer!=NULL,FALSE);
1093 g_return_val_if_fail(IoStatus!=NULL,FALSE);
1095 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: FileObject=%p,FileOffset=0x%llX,Length=0x%lX,Wait=%d",G_STRLOC,
1096 FileObject,(guint64)FileOffset->QuadPart,(gulong)Length,(gint)Wait);
1098 IoStatus->Status=STATUS_UNSUCCESSFUL;
1099 IoStatus->Information=0;
1103 FileObject, /* FileObject */
1104 FileOffset, /* FileOffset */
1105 Length, /* Length */
1107 &MappedBcb, /* Bcb */
1108 &MappedBuffer); /* Buffer */
1109 g_return_val_if_fail(errbool==TRUE,FALSE);
1111 memcpy(Buffer,MappedBuffer,Length);
1113 CcUnpinData(MappedBcb); /* no error code */
1116 IoStatus->Status=STATUS_SUCCESS;
1117 IoStatus->Information=Length;
1125 * @FileObject: Initialized open #FileObject to map.
1126 * %NULL value is forbidden.
1127 * @FileOffset: The @FileObject file offset from where to map the region from.
1128 * Negative value is forbidden.
1129 * @Length: Requested length of the region to map from @FileObject.
1130 * Value %0 is permitted (no effect of this function call).
1131 * @Wait: Whether disk waiting is permitted for this function.
1132 * Value %FALSE is currently forbidden by libcaptive as we have no on-demand loading implemented.
1133 * @Buffer: Address of memory region with already allocated memory of size @Length.
1134 * This address may not be %PAGE_SIZE aligned.
1135 * %NULL pointer is forbidden.
1137 * Writes the specified region of the given @Buffer to @FileObject.
1139 * Returns: %TRUE if the region was successfuly written with @Length bytes.
1141 BOOLEAN CcCopyWrite(IN PFILE_OBJECT FileObject,
1142 IN PLARGE_INTEGER FileOffset,IN ULONG Length,IN BOOLEAN Wait,IN PVOID Buffer)
1148 g_return_val_if_fail(FileObject!=NULL,FALSE);
1149 g_return_val_if_fail(FileOffset!=NULL,FALSE);
1150 g_return_val_if_fail(Buffer!=NULL,FALSE);
1152 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: FileObject=%p,FileOffset=0x%llX,Length=0x%lX,Wait=%d",G_STRLOC,
1153 FileObject,(guint64)FileOffset->QuadPart,(gulong)Length,(gint)Wait);
1157 FileObject, /* FileObject */
1158 FileOffset, /* FileOffset */
1159 Length, /* Length */
1161 &MappedBcb, /* Bcb */
1162 &MappedBuffer); /* Buffer */
1163 g_return_val_if_fail(errbool==TRUE,FALSE);
1165 memcpy(MappedBuffer,Buffer,Length);
1167 CcSetDirtyPinnedData(
1168 MappedBcb, /* Bcb */
1170 CcUnpinData(MappedBcb); /* no error code */
1179 * @FileObject: Initialized open #FileObject to map.
1180 * %NULL value is forbidden.
1181 * @BytesToWrite: Amount of data to be asked whether it will be accepted.
1182 * Value %0 is permitted.
1183 * @Wait: Whether disk waiting would be permitted during the forthcoming write call.
1184 * @Retrying: Use %TRUE iff calling this function for the second and further times for one request.
1186 * Asks cache manager if it would currently accept write request to @FileObject
1187 * of @BytesToWrite bytes with @Wait condition.
1188 * libcaptive will always accept any writes. This function is a NOP.
1190 * Returns: libcaptive always returns %TRUE.
1192 BOOLEAN CcCanIWrite(IN PFILE_OBJECT FileObject,IN ULONG BytesToWrite,IN BOOLEAN Wait,IN BOOLEAN Retrying)
1194 g_return_val_if_fail(FileObject!=NULL,FALSE);
1196 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: FileObject=%p,BytesToWrite=0x%lX,Wait=%d,Retrying=%d",G_STRLOC,
1197 FileObject,(gulong)BytesToWrite,(gint)Wait,(gint)Retrying);
1204 * CcSetReadAheadGranularity:
1205 * @FileObject: Initialized open #FileObject to map.
1206 * %NULL value is forbidden.
1207 * @Granularity: Suggested size of the cache element.
1208 * Value must be larger or requal to %PAGE_SIZE and it must be even power of two.
1210 * libcaptive does not implement any caching and therefore this function
1213 VOID CcSetReadAheadGranularity(IN PFILE_OBJECT FileObject,IN ULONG Granularity)
1215 g_return_if_fail(FileObject!=NULL);
1216 g_return_if_fail(Granularity>=PAGE_SIZE);
1217 g_return_if_fail((Granularity&(Granularity-1))==0); /* Power of two */
1219 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: FileObject=%p,Granularity=0x%lX",G_STRLOC,
1220 FileObject,(gulong)Granularity);
1222 /* NOP; no caching by libcaptive */
1228 * @SectionObjectPointer: Pointer specifying file to flush;
1229 * %NULL value is forbidden.
1230 * libcaptive interprets only #SharedCacheMap field as #PUBLIC_BCB pointer.
1231 * Field #SharedCacheMap value %NULL is permitted; libcaptive does a NOP in such case.
1232 * @FileOffset: Optional starting point of the range to flush.
1233 * %NULL value is permitted.
1234 * @Length: Length of the range to flush. Ignored if @FileOffset is %NULL.
1235 * @IoStatus: Optionally returns the resulting operation status.
1236 * #Information field will contain the number of bytes flushed.
1237 * %NULL value is permitted.
1239 * Flushes out any pending dirty data in cache manager BCB mapping.
1240 * FIXME: libcaptive currently always flushes the full file ignoring any @FileOffset or @Length.
1242 VOID CcFlushCache(IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
1243 IN PLARGE_INTEGER FileOffset OPTIONAL,IN ULONG Length,OUT PIO_STATUS_BLOCK IoStatus OPTIONAL)
1245 PUBLIC_BCB *PublicBcb;
1246 struct private_bcb *privbcb;
1247 IO_STATUS_BLOCK IoStatus_CcUnpinRepinnedBcb_local;
1249 g_return_if_fail(SectionObjectPointer!=NULL);
1251 if (SectionObjectPointer->SharedCacheMap==NULL) {
1254 IoStatus->Status=STATUS_SUCCESS;
1255 IoStatus->Information=0;
1260 PublicBcb=SectionObjectPointer->SharedCacheMap;
1261 g_return_if_fail(validate_Bcb(PublicBcb));
1263 private_bcb_hash_init();
1265 privbcb=g_hash_table_lookup(private_bcb_hash,PublicBcb);
1266 g_return_if_fail(privbcb!=NULL);
1268 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: SectionObjectPointer=%p(Bcb=%p,privbcb=%p,privbcb->FileObject=%p),"
1269 "FileOffset=0x%llX,Length=0x%lX,IoStatus=%p",G_STRLOC,
1270 SectionObjectPointer,PublicBcb,privbcb,privbcb->FileObject,
1271 (guint64)(!FileOffset ? -1 : FileOffset->QuadPart),(gulong)Length,IoStatus);
1274 if (FileOffset->QuadPart >=privbcb->MappedFileOffset.QuadPart+privbcb->MappedLength)
1276 if (FileOffset->QuadPart+Length<=privbcb->MappedFileOffset.QuadPart)
1280 /* We may find some 'privbcb' being already sheduled to be destroyed.
1281 * We need to reference it to not to loose it in the middle of our flush operation.
1283 CcRepinBcb(PublicBcb);
1285 /* FIXME: Flush just FileOffset..FileOfset+Length part */
1286 captive_privbcb_flush(privbcb);
1289 PublicBcb, /* Bcb */
1290 TRUE, /* WriteThrough; ignored by libcaptive */
1291 &IoStatus_CcUnpinRepinnedBcb_local); /* IoStatus; ignored here */
1294 IoStatus->Status=STATUS_SUCCESS;
1295 IoStatus->Information=(FileOffset && Length ? MIN(privbcb->MappedLength,Length) : privbcb->MappedLength);
1300 static gboolean captive_FileObject_ZeroData(PFILE_OBJECT FileObject,guint64 window_bottom,guint64 window_top)
1304 gpointer zerobuffer;
1305 LARGE_INTEGER window_bottom_LargeInteger;
1307 IO_STATUS_BLOCK IoStatus;
1309 g_return_val_if_fail(FileObject!=NULL,FALSE);
1310 g_return_val_if_fail(window_bottom<=window_top,FALSE);
1312 if (window_bottom==window_top) /* trivia */
1315 g_return_val_if_fail(FileObject->DeviceObject!=NULL,FALSE);
1317 /* Such requirement is W32 documented for CcZeroData()
1318 * and it is really a requirement at least for the underlying fastfat.sys.
1320 g_assert(0==CAPTIVE_ROUND_DOWN_EXCEEDING64(window_bottom,FileObject->DeviceObject->SectorSize));
1321 g_assert(0==CAPTIVE_ROUND_DOWN_EXCEEDING64(window_top ,FileObject->DeviceObject->SectorSize));
1323 zerobuffer=g_malloc0(window_top-window_bottom);
1324 window_bottom_LargeInteger.QuadPart=window_bottom;
1326 Mdl=MmCreateMdl(NULL,zerobuffer,window_top-window_bottom);
1327 g_assert(Mdl!=NULL);
1329 KeInitializeEvent(&Event,NotificationEvent,FALSE);
1331 /* FIXME: Notify logging subsystem by LSNs? */
1333 /* Use rather IoSynchronousPageWrite() than IoPageWrite() to prevent STATUS_PENDING. */
1334 err=IoSynchronousPageWrite(FileObject,Mdl,&window_bottom_LargeInteger,&Event,&IoStatus);
1335 g_assert(NT_SUCCESS(err));
1336 g_assert(NT_SUCCESS(IoStatus.Status));
1337 /* We should write up to the last sector touched by the range although we
1338 * do not need to successfuly write the whole aligned amount.
1339 * FIXME: Also we can get just value 0 if the write is considered 'not dirty'
1340 * during FAT write by fastfat.sys.
1342 g_assert(IoStatus.Information==0
1343 || (window_top-window_bottom)==CAPTIVE_ROUND_UP(IoStatus.Information,FileObject->DeviceObject->SectorSize));
1344 g_assert(IoStatus.Information<=window_top-window_bottom); /* redundant */
1352 BOOLEAN CcZeroData(IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER StartOffset,IN PLARGE_INTEGER EndOffset,IN BOOLEAN Wait)
1354 guint64 window_lower_bottom,window_lower_top;
1355 guint64 window_higher_bottom,window_higher_top;
1357 g_return_val_if_fail(FileObject!=NULL,FALSE);
1358 g_return_val_if_fail(StartOffset!=NULL,FALSE);
1359 g_return_val_if_fail(EndOffset!=NULL,FALSE);
1360 g_return_val_if_fail(StartOffset->QuadPart<=EndOffset->QuadPart,FALSE);
1362 g_return_val_if_fail(FileObject->SectionObjectPointers!=NULL,FALSE);
1364 window_lower_bottom=StartOffset->QuadPart;
1365 window_lower_top=EndOffset->QuadPart;
1366 window_higher_bottom=window_higher_top=0;
1368 if (FileObject->SectionObjectPointers->SharedCacheMap!=NULL) {
1369 PUBLIC_BCB *PublicBcb;
1370 struct private_bcb *privbcb;
1371 guint64 window_cached_bottom,window_cached_top;
1373 PublicBcb=FileObject->SectionObjectPointers->SharedCacheMap;
1374 g_return_val_if_fail(validate_Bcb(PublicBcb),FALSE);
1376 private_bcb_hash_init();
1378 privbcb=g_hash_table_lookup(private_bcb_hash,PublicBcb);
1379 g_return_val_if_fail(privbcb!=NULL,FALSE);
1381 window_cached_bottom=MAX(StartOffset->QuadPart,privbcb->MappedFileOffset.QuadPart);
1382 window_cached_top=MIN(EndOffset->QuadPart,privbcb->MappedFileOffset.QuadPart+privbcb->MappedLength);
1384 if (window_cached_bottom<window_cached_top) {
1385 memset(((char *)privbcb->base)+window_cached_bottom-privbcb->MappedFileOffset.QuadPart,0,window_cached_top-window_cached_bottom);
1386 privbcb->dirty=TRUE;
1387 window_higher_top=window_lower_top;
1388 window_lower_top=window_cached_bottom;
1389 window_higher_bottom=window_cached_top;
1392 if (window_lower_bottom<window_lower_top) {
1393 g_return_val_if_fail(Wait==TRUE,FALSE);
1394 if (!captive_FileObject_ZeroData(FileObject,window_lower_bottom,window_lower_top))
1395 g_return_val_if_reached(FALSE);
1397 if (window_higher_bottom<window_higher_top) {
1398 g_return_val_if_fail(Wait==TRUE,FALSE);
1399 if (!captive_FileObject_ZeroData(FileObject,window_higher_bottom,window_higher_top))
1400 g_return_val_if_reached(FALSE);
1407 /* map (PVOID LogHandle) -> (GList (of FILE_OBJECT *) *FileObject_list) */
1408 static GHashTable *log_handle_hash;
1410 static void log_handle_hash_init(void)
1412 if (log_handle_hash)
1414 log_handle_hash=g_hash_table_new(
1415 g_direct_hash, /* hash_func */
1416 g_direct_equal); /* key_equal_func */
1419 /* map (FILE_OBJECT *FileObject) -> (struct FileObject_logging *) */
1420 struct FileObject_logging {
1422 PFLUSH_TO_LSN FlushToLsnRoutine;
1425 static GHashTable *FileObject_logging_hash;
1427 static void FileObject_logging_hash_init(void)
1429 if (FileObject_logging_hash)
1431 FileObject_logging_hash=g_hash_table_new(
1432 g_direct_hash, /* hash_func */
1433 g_direct_equal); /* key_equal_func */
1436 static void logging_notify_privbcb_flush(struct private_bcb *privbcb)
1438 struct FileObject_logging *FileObject_logging;
1440 g_return_if_fail(privbcb!=NULL);
1442 if (!privbcb->lsn_valid) /* nothing to report anyway */
1445 FileObject_logging_hash_init();
1447 if (!(FileObject_logging=g_hash_table_lookup(FileObject_logging_hash,privbcb->FileObject)))
1449 (*FileObject_logging->FlushToLsnRoutine)(FileObject_logging->LogHandle,privbcb->lsn);
1452 VOID CcSetLogHandleForFile(IN PFILE_OBJECT FileObject,IN PVOID LogHandle,IN PFLUSH_TO_LSN FlushToLsnRoutine)
1454 GList *LogHandle_list;
1455 struct FileObject_logging *FileObject_logging;
1457 g_return_if_fail(FileObject!=NULL);
1458 /* 'LogHandle' may be NULL */
1459 g_return_if_fail(FlushToLsnRoutine!=NULL);
1461 log_handle_hash_init();
1462 FileObject_logging_hash_init();
1464 if (!(FileObject_logging=g_hash_table_lookup(
1465 FileObject_logging_hash,FileObject))) {
1466 captive_new(FileObject_logging);
1467 g_hash_table_insert(FileObject_logging_hash,
1468 FileObject,FileObject_logging);
1471 LogHandle_list=g_hash_table_lookup(log_handle_hash,FileObject_logging->LogHandle);
1472 g_assert(NULL!=g_list_find(LogHandle_list,FileObject));
1473 LogHandle_list=g_list_remove(LogHandle_list,FileObject);
1474 g_assert(NULL==g_list_find(LogHandle_list,FileObject));
1475 g_hash_table_insert(log_handle_hash,FileObject_logging->LogHandle,LogHandle_list);
1478 FileObject_logging->LogHandle=LogHandle;
1479 FileObject_logging->FlushToLsnRoutine=FlushToLsnRoutine;
1481 LogHandle_list=g_hash_table_lookup(log_handle_hash,LogHandle);
1482 LogHandle_list=g_list_prepend(LogHandle_list,FileObject);
1483 g_hash_table_insert(log_handle_hash,LogHandle,LogHandle_list);
1487 struct CcGetDirtyPages_param {
1488 PDIRTY_PAGE_ROUTINE DirtyPageRoutine; /* arg of CcGetDirtyPages() */
1489 IN PVOID Context1; /* arg of CcGetDirtyPages() */
1490 IN PVOID Context2; /* arg of CcGetDirtyPages() */
1491 FILE_OBJECT *FileObject; /* search through 'page_position_hash' for 'FileObject' */
1492 LARGE_INTEGER OldestLsn; gboolean OldestLsn_found; /* intermediate return value of CcGetDirtyPages() */
1495 static void CcGetDirtyPages_page_position_hash_foreach(
1496 struct page_position *pagepos, /* key */
1497 struct page_position *pagepos2, /* value */
1498 struct CcGetDirtyPages_param *CcGetDirtyPages_param) /* user_data */
1500 LARGE_INTEGER FileOffset_local;
1501 LARGE_INTEGER OldestLsn,NewestLsn;
1502 LARGE_INTEGER OldestLsn_check,NewestLsn_check;
1503 gboolean lsn_found=FALSE;
1504 GList *privbcb_list;
1506 g_return_if_fail(pagepos!=NULL);
1507 g_return_if_fail(pagepos==pagepos2);
1508 g_return_if_fail(CcGetDirtyPages_param!=NULL);
1510 FileOffset_local=pagepos->FileOffset;
1513 privbcb_list=pagepos->privbcb_list;
1515 privbcb_list=privbcb_list->next) {
1516 struct private_bcb *privbcb=privbcb_list->data;
1518 if (!privbcb->lsn_valid)
1521 OldestLsn=NewestLsn=privbcb->lsn;
1524 OldestLsn.QuadPart=MIN(OldestLsn.QuadPart,privbcb->lsn.QuadPart);
1525 NewestLsn.QuadPart=MAX(NewestLsn.QuadPart,privbcb->lsn.QuadPart);
1531 if (!CcGetDirtyPages_param->OldestLsn_found) {
1532 CcGetDirtyPages_param->OldestLsn=OldestLsn;
1533 CcGetDirtyPages_param->OldestLsn_found=TRUE;
1536 CcGetDirtyPages_param->OldestLsn.QuadPart=MIN(CcGetDirtyPages_param->OldestLsn.QuadPart,OldestLsn.QuadPart);
1538 OldestLsn_check=OldestLsn;
1539 NewestLsn_check=NewestLsn;
1541 (*CcGetDirtyPages_param->DirtyPageRoutine)(
1542 pagepos->FileObject, /* FileObject */
1543 &FileOffset_local, /* FileOffset */
1544 PAGE_SIZE, /* Length */
1545 &OldestLsn, /* OldestLsn */
1546 &NewestLsn, /* NewestLsn */
1547 CcGetDirtyPages_param->Context1, /* Context1 */
1548 CcGetDirtyPages_param->Context2); /* Context2 */
1550 /* just unconfirmed sanity: */
1551 g_assert(FileOffset_local.QuadPart==pagepos->FileOffset.QuadPart); /* check for possible corruption */
1552 g_assert(OldestLsn_check.QuadPart==OldestLsn.QuadPart);
1553 g_assert(NewestLsn_check.QuadPart==NewestLsn.QuadPart);
1556 /* libcaptive must return #gint64 instead of the official #LARGE_INTEGER
1557 * as W32 expects it as value in EAX:EDX but GCC returns the structure address in EAX.
1559 gint64 /* instead of LARGE_INTEGER */ CcGetDirtyPages(IN PVOID LogHandle,
1560 IN PDIRTY_PAGE_ROUTINE DirtyPageRoutine,IN PVOID Context1,IN PVOID Context2)
1562 GList *LogHandle_list;
1563 struct CcGetDirtyPages_param CcGetDirtyPages_param;
1565 /* 'LogHandle' may be NULL */
1566 g_return_val_if_fail(DirtyPageRoutine!=NULL,0);
1568 log_handle_hash_init();
1569 page_position_hash_init();
1571 CcGetDirtyPages_param.DirtyPageRoutine=DirtyPageRoutine;
1572 CcGetDirtyPages_param.Context1=Context1;
1573 CcGetDirtyPages_param.Context2=Context2;
1574 CcGetDirtyPages_param.OldestLsn_found=FALSE;
1577 LogHandle_list=g_hash_table_lookup(log_handle_hash,LogHandle);
1579 LogHandle_list=LogHandle_list->next) {
1580 CcGetDirtyPages_param.FileObject=LogHandle_list->data;
1581 g_hash_table_foreach(
1582 page_position_hash, /* hash_table */
1583 (GHFunc)CcGetDirtyPages_page_position_hash_foreach, /* func */
1584 &CcGetDirtyPages_param); /* user_data */
1587 if (!CcGetDirtyPages_param.OldestLsn_found)
1589 return CcGetDirtyPages_param.OldestLsn.QuadPart;
1594 * CcSetAdditionalCacheAttributes:
1595 * @FileObject: Initialized open #FileObject to map.
1596 * %NULL value is forbidden.
1597 * @DisableReadAhead: Read-ahead should not be done by Cache Manager.
1598 * @DisableWriteBehind: Write-behind should not be done by Cache Manager.
1600 * libcaptive does not implement any caching and therefore this function
1603 VOID CcSetAdditionalCacheAttributes(IN PFILE_OBJECT FileObject,IN BOOLEAN DisableReadAhead,IN BOOLEAN DisableWriteBehind)
1605 g_return_if_fail(FileObject!=NULL);
1607 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: FileObject=%p,DisableReadAhead=%s,DisableWriteBehind=%s",G_STRLOC,
1608 FileObject,(DisableReadAhead ? "TRUE" : "FALSE"),(DisableWriteBehind ? "TRUE" : "FALSE"));
1610 /* NOP; no caching by libcaptive */
1615 * CcSetBcbOwnerPointer:
1616 * @Bcb: Initialized #PUBLIC_BCB structure.
1617 * %NULL value is forbidden.
1618 * @Owner: Thread-specific pointer (FIXME: Is it KeGetCurrentThread()?).
1619 * %NULL value is forbidden (FIXME: is it W32 compliant?).
1621 * Set thread-specific pointer for a pinned @Bcb. Use CcUnpinDataForThread()
1622 * when @Bcb is no longer needed. CcUnpinDataForThread() is NOT a reverse
1623 * operation for this single call CcSetBcbOwnerPointer(), see CcUnpinDataForThread().
1625 * libcaptive implements this function as no-operation as it does not yet
1626 * support any threading.
1628 VOID CcSetBcbOwnerPointer(IN PVOID Bcb,IN PVOID Owner)
1630 g_return_if_fail(Bcb!=NULL);
1631 g_return_if_fail(Owner!=NULL);
1633 /* FIXME:thread; NOP if no threads present */
1638 * CcUnpinDataForThread:
1639 * @Bcb: Initialized #PUBLIC_BCB structure.
1640 * %NULL value is forbidden.
1641 * @ResourceThreadId: Thread-specific pointer (FIXME: Is it KeGetCurrentThread()?).
1642 * This pointer had to be passed to CcSetBcbOwnerPointer() #Owner parameter previously.
1643 * %NULL value is forbidden (FIXME: is it W32 compliant?).
1645 * CcUnpinData() for a thread specified by @ResourceThreadId.
1646 * Reverse operation for a pair of CcMapData() and CcSetBcbOwnerPointer().
1648 * libcaptive implements this function as a simple pass to CcUnpinData() as it does not yet
1649 * support any threading.
1651 VOID CcUnpinDataForThread(IN PVOID Bcb,IN ERESOURCE_THREAD ResourceThreadId)
1653 g_return_if_fail(Bcb!=NULL);
1654 g_return_if_fail(ResourceThreadId!=0);
1664 * @Bcb: Initialized #PUBLIC_BCB structure.
1665 * %NULL value is forbidden.
1667 * Create a copy of @Bcb for the exactly same file contents as is @Bcb.
1668 * The returned copy has the same attributes as the result of CcMapData()
1669 * notwithstanding the current state of input @Bcb, therefore it is only
1670 * for read/only access etc.
1672 * libcaptive calls CcMapData() internally with @Bcb parameters.
1674 * Returns: Copy of @Bcb. This _pointer_ never equals to @Bcb.
1675 * It should be some different
1676 * #PUBLIC_BCB structure according to W32 doc.
1678 PVOID CcRemapBcb(IN PVOID Bcb)
1681 PVOID Buffer_unused;
1683 PUBLIC_BCB *PublicBcb;
1684 struct private_bcb *privbcb;
1686 g_return_val_if_fail(validate_Bcb(Bcb),NULL);
1688 private_bcb_hash_init();
1690 PublicBcb=(PUBLIC_BCB *)Bcb;
1691 privbcb=g_hash_table_lookup(private_bcb_hash,PublicBcb);
1692 g_return_val_if_fail(privbcb!=NULL,NULL);
1694 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,
1695 "%s: privbcb->FileObject=%p,privbcb->MappedFileOffset=0x%llX,privbcb->MappedLength=0x%lX,privbcb->ref_count=%d",G_STRLOC,
1696 privbcb->FileObject,(guint64)privbcb->MappedFileOffset.QuadPart,(gulong)privbcb->MappedLength,(int)privbcb->ref_count);
1699 privbcb->FileObject, /* FileObject */
1700 &privbcb->MappedFileOffset, /* FileOffset */
1701 privbcb->MappedLength, /* Length */
1702 MAP_WAIT, /* Flags; && !MAP_NO_READ */
1704 &Buffer_unused); /* Buffer */
1705 g_return_val_if_fail(errbool==TRUE,NULL);
1706 g_return_val_if_fail(r!=NULL,NULL);
1707 g_return_val_if_fail(Buffer_unused!=NULL,NULL);
1715 * CcPreparePinWrite:
1716 * @FileObject: Initialized open #FileObject to map.
1717 * %NULL value is forbidden.
1718 * @FileOffset: The @FileObject file offset from where to map the region from.
1719 * Negative value is forbidden.
1720 * @Length: Requested length of the region to map from @FileObject.
1721 * FIXME: Value %0 is currently forbidden by libcaptive; it should be allowed.
1722 * @Zero: %TRUE if the area of @FileOffset...@FileOffset+@Length should be cleared.
1723 * @Flags: %PIN_WAIT means whether disk waiting is permitted for this function.
1724 * Value without %PIN_WAIT is currently permtted by libcaptive as the data must have been mapped by CcMapData() already anyway.
1725 * %PIN_NO_READ currently ignored; we map the data always.
1726 * FIXME: %PIN_EXCLUSIVE for exclusive @Bcb access is now ignored by libcaptive.
1727 * %PIN_IF_BCB if @Bcb should never be created; function is successful only if @Bcb already exists.
1728 * @Bcb: Returns initialized #PUBLIC_BCB to refer to the mapped region.
1729 * The memory region can be larger than requested as it is %PAGE_SIZE aligned.
1730 * %NULL pointer is forbidden.
1731 * @Buffer: Returns the mapped memory region start address.
1732 * This address may not be %PAGE_SIZE aligned.
1733 * %NULL pointer is forbidden.
1735 * Wrapper for a pair of CcPinRead() and CcSetDirtyPinnedData().
1736 * The mapped range can be also optionally cleared if @Zero is specified.
1737 * See CcPinRead() for a more detailed documentation.
1739 * FIXME: libcaptive will read even the file pages completely not need
1740 * in the case @Zero was specified.
1742 * Returns: %TRUE if the mapping was successful.
1744 BOOLEAN CcPreparePinWrite(IN PFILE_OBJECT FileObject,
1745 IN PLARGE_INTEGER FileOffset,IN ULONG Length,IN BOOLEAN Zero,IN ULONG Flags,OUT PVOID *Bcb,OUT PVOID *Buffer)
1749 g_return_val_if_fail(FileObject!=NULL,FALSE);
1750 g_return_val_if_fail(FileOffset!=NULL,FALSE);
1751 g_return_val_if_fail(FileOffset->QuadPart>=0,FALSE);
1752 g_return_val_if_fail(Length>0,FALSE); /* FIXME: not handled below; 0 should be allowed */
1753 /* 'Flags' passed to CcPinRead() */
1754 g_return_val_if_fail(Bcb!=NULL,FALSE);
1755 g_return_val_if_fail(Buffer!=NULL,FALSE);
1757 errbool=CcPinRead(FileObject,FileOffset,Length,Flags,Bcb,Buffer);
1758 g_return_val_if_fail(errbool==TRUE,FALSE);
1760 CcSetDirtyPinnedData(
1762 NULL); /* Lsn; OPTIONAL */
1765 memset(*Buffer,0,Length);