source: trunk/src/ole32/stg_bigblockfile.c@ 5087

Last change on this file since 5087 was 5026, checked in by sandervl, 25 years ago

Wine resync

File size: 21.3 KB
Line 
1/******************************************************************************
2 *
3 * BigBlockFile
4 *
5 * This is the implementation of a file that consists of blocks of
6 * a predetermined size.
7 * This class is used in the Compound File implementation of the
8 * IStorage and IStream interfaces. It provides the functionality
9 * to read and write any blocks in the file as well as setting and
10 * obtaining the size of the file.
11 * The blocks are indexed sequentially from the start of the file
12 * starting with -1.
13 *
14 * TODO:
15 * - Support for a transacted mode
16 *
17 * Copyright 1999 Thuy Nguyen
18 *
19 */
20
21#ifdef __WIN32OS2__
22#define WINE_LARGE_INTEGER
23#define inline
24
25#include <odin.h>
26#include "ole32.h"
27#include "heapstring.h"
28
29#endif
30
31#include <assert.h>
32#include <stdlib.h>
33#include <stdio.h>
34#include <string.h>
35#include <limits.h>
36
37#include "winbase.h"
38#include "winerror.h"
39#include "wine/obj_base.h"
40#include "wine/obj_storage.h"
41#include "ole2.h"
42
43#include "storage32.h"
44
45#include "debugtools.h"
46
47DEFAULT_DEBUG_CHANNEL(storage);
48
49/***********************************************************
50 * Data structures used internally by the BigBlockFile
51 * class.
52 */
53
54/* We map in PAGE_SIZE-sized chunks. Must be a multiple of 4096. */
55#define PAGE_SIZE 131072
56
57#define BLOCKS_PER_PAGE (PAGE_SIZE / BIG_BLOCK_SIZE)
58
59/* We keep a list of recently-discarded pages. This controls the
60 * size of that list. */
61#define MAX_VICTIM_PAGES 16
62
63/* This structure provides one bit for each block in a page.
64 * Use BIGBLOCKFILE_{Test,Set,Clear}Bit to manipulate it. */
65typedef struct
66{
67 unsigned int bits[BLOCKS_PER_PAGE / (CHAR_BIT * sizeof(unsigned int))];
68} BlockBits;
69
70/***
71 * This structure identifies the paged that are mapped
72 * from the file and their position in memory. It is
73 * also used to hold a reference count to those pages.
74 *
75 * page_index identifies which PAGE_SIZE chunk from the
76 * file this mapping represents. (The mappings are always
77 * PAGE_SIZE-aligned.)
78 */
79struct MappedPage
80{
81 MappedPage *next;
82 MappedPage *prev;
83
84 DWORD page_index;
85 LPVOID lpBytes;
86 LONG refcnt;
87
88 BlockBits readable_blocks;
89 BlockBits writable_blocks;
90};
91
92/***********************************************************
93 * Prototypes for private methods
94 */
95static void* BIGBLOCKFILE_GetMappedView(LPBIGBLOCKFILE This,
96 DWORD page_index);
97static void BIGBLOCKFILE_ReleaseMappedPage(LPBIGBLOCKFILE This,
98 MappedPage *page);
99static void BIGBLOCKFILE_FreeAllMappedPages(LPBIGBLOCKFILE This);
100static void BIGBLOCKFILE_UnmapAllMappedPages(LPBIGBLOCKFILE This);
101static void BIGBLOCKFILE_RemapAllMappedPages(LPBIGBLOCKFILE This);
102static void* BIGBLOCKFILE_GetBigBlockPointer(LPBIGBLOCKFILE This,
103 ULONG index,
104 DWORD desired_access);
105static MappedPage* BIGBLOCKFILE_GetPageFromPointer(LPBIGBLOCKFILE This,
106 void* pBlock);
107static MappedPage* BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE This,
108 ULONG page_index);
109static DWORD BIGBLOCKFILE_GetProtectMode(DWORD openFlags);
110static BOOL BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This, HANDLE hFile);
111static BOOL BIGBLOCKFILE_MemInit(LPBIGBLOCKFILE This, ILockBytes* plkbyt);
112
113/* Note that this evaluates a and b multiple times, so don't
114 * pass expressions with side effects. */
115#define ROUND_UP(a, b) ((((a) + (b) - 1)/(b))*(b))
116
117/***********************************************************
118 * Blockbits functions.
119 */
120static inline BOOL BIGBLOCKFILE_TestBit(const BlockBits *bb,
121 unsigned int index)
122{
123 unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int));
124 unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int));
125
126 return bb->bits[array_index] & (1 << bit_index);
127}
128
129static inline void BIGBLOCKFILE_SetBit(BlockBits *bb, unsigned int index)
130{
131 unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int));
132 unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int));
133
134 bb->bits[array_index] |= (1 << bit_index);
135}
136
137static inline void BIGBLOCKFILE_ClearBit(BlockBits *bb, unsigned int index)
138{
139 unsigned int array_index = index / (CHAR_BIT * sizeof(unsigned int));
140 unsigned int bit_index = index % (CHAR_BIT * sizeof(unsigned int));
141
142 bb->bits[array_index] &= ~(1 << bit_index);
143}
144
145static inline void BIGBLOCKFILE_Zero(BlockBits *bb)
146{
147 memset(bb->bits, 0, sizeof(bb->bits));
148}
149
150/******************************************************************************
151 * BIGBLOCKFILE_Construct
152 *
153 * Construct a big block file. Create the file mapping object.
154 * Create the read only mapped pages list, the writable mapped page list
155 * and the blocks in use list.
156 */
157BigBlockFile * BIGBLOCKFILE_Construct(
158 HANDLE hFile,
159 ILockBytes* pLkByt,
160 DWORD openFlags,
161 ULONG blocksize,
162 BOOL fileBased)
163{
164 LPBIGBLOCKFILE This;
165
166 This = (LPBIGBLOCKFILE)HeapAlloc(GetProcessHeap(), 0, sizeof(BigBlockFile));
167
168 if (This == NULL)
169 return NULL;
170
171 This->fileBased = fileBased;
172
173 This->flProtect = BIGBLOCKFILE_GetProtectMode(openFlags);
174
175 This->blocksize = blocksize;
176
177 This->maplist = NULL;
178 This->victimhead = NULL;
179 This->victimtail = NULL;
180 This->num_victim_pages = 0;
181
182 if (This->fileBased)
183 {
184 if (!BIGBLOCKFILE_FileInit(This, hFile))
185 {
186 HeapFree(GetProcessHeap(), 0, This);
187 return NULL;
188 }
189 }
190 else
191 {
192 if (!BIGBLOCKFILE_MemInit(This, pLkByt))
193 {
194 HeapFree(GetProcessHeap(), 0, This);
195 return NULL;
196 }
197 }
198
199 return This;
200}
201
202/******************************************************************************
203 * BIGBLOCKFILE_FileInit
204 *
205 * Initialize a big block object supported by a file.
206 */
207static BOOL BIGBLOCKFILE_FileInit(LPBIGBLOCKFILE This, HANDLE hFile)
208{
209 This->pLkbyt = NULL;
210 This->hbytearray = 0;
211 This->pbytearray = NULL;
212
213 This->hfile = hFile;
214
215 if (This->hfile == INVALID_HANDLE_VALUE)
216 return FALSE;
217
218 /* create the file mapping object
219 */
220 This->hfilemap = CreateFileMappingA(This->hfile,
221 NULL,
222 This->flProtect,
223 0, 0,
224 NULL);
225
226 if (!This->hfilemap)
227 {
228 CloseHandle(This->hfile);
229 return FALSE;
230 }
231
232 This->filesize.s.LowPart = GetFileSize(This->hfile,
233 &This->filesize.s.HighPart);
234
235 This->maplist = NULL;
236
237 TRACE("file len %lu\n", This->filesize.s.LowPart);
238
239 return TRUE;
240}
241
242/******************************************************************************
243 * BIGBLOCKFILE_MemInit
244 *
245 * Initialize a big block object supported by an ILockBytes on HGLOABL.
246 */
247static BOOL BIGBLOCKFILE_MemInit(LPBIGBLOCKFILE This, ILockBytes* plkbyt)
248{
249 This->hfile = 0;
250 This->hfilemap = 0;
251
252 /*
253 * Retrieve the handle to the byte array from the LockByte object.
254 */
255 if (GetHGlobalFromILockBytes(plkbyt, &(This->hbytearray)) != S_OK)
256 {
257 FIXME("May not be an ILockBytes on HGLOBAL\n");
258 return FALSE;
259 }
260
261 This->pLkbyt = plkbyt;
262
263 /*
264 * Increment the reference count of the ILockByte object since
265 * we're keeping a reference to it.
266 */
267 ILockBytes_AddRef(This->pLkbyt);
268
269 This->filesize.s.LowPart = GlobalSize(This->hbytearray);
270 This->filesize.s.HighPart = 0;
271
272 This->pbytearray = GlobalLock(This->hbytearray);
273
274 TRACE("mem on %p len %lu\n", This->pbytearray, This->filesize.s.LowPart);
275
276 return TRUE;
277}
278
279/******************************************************************************
280 * BIGBLOCKFILE_Destructor
281 *
282 * Destructor. Clean up, free memory.
283 */
284void BIGBLOCKFILE_Destructor(
285 LPBIGBLOCKFILE This)
286{
287 BIGBLOCKFILE_FreeAllMappedPages(This);
288
289 if (This->fileBased)
290 {
291 CloseHandle(This->hfilemap);
292 CloseHandle(This->hfile);
293 }
294 else
295 {
296 GlobalUnlock(This->hbytearray);
297 ILockBytes_Release(This->pLkbyt);
298 }
299
300 /* destroy this
301 */
302 HeapFree(GetProcessHeap(), 0, This);
303}
304
305/******************************************************************************
306 * BIGBLOCKFILE_GetROBigBlock
307 *
308 * Returns the specified block in read only mode.
309 * Will return NULL if the block doesn't exists.
310 */
311void* BIGBLOCKFILE_GetROBigBlock(
312 LPBIGBLOCKFILE This,
313 ULONG index)
314{
315 /*
316 * block index starts at -1
317 * translate to zero based index
318 */
319 if (index == 0xffffffff)
320 index = 0;
321 else
322 index++;
323
324 /*
325 * validate the block index
326 *
327 */
328 if (This->blocksize * (index + 1)
329 > ROUND_UP(This->filesize.s.LowPart, This->blocksize))
330 {
331 TRACE("out of range %lu vs %lu\n", This->blocksize * (index + 1),
332 This->filesize.s.LowPart);
333 return NULL;
334 }
335
336 return BIGBLOCKFILE_GetBigBlockPointer(This, index, FILE_MAP_READ);
337}
338
339/******************************************************************************
340 * BIGBLOCKFILE_GetBigBlock
341 *
342 * Returns the specified block.
343 * Will grow the file if necessary.
344 */
345void* BIGBLOCKFILE_GetBigBlock(LPBIGBLOCKFILE This, ULONG index)
346{
347 /*
348 * block index starts at -1
349 * translate to zero based index
350 */
351 if (index == 0xffffffff)
352 index = 0;
353 else
354 index++;
355
356 /*
357 * make sure that the block physically exists
358 */
359 if ((This->blocksize * (index + 1)) > This->filesize.s.LowPart)
360 {
361 ULARGE_INTEGER newSize;
362
363 newSize.s.HighPart = 0;
364 newSize.s.LowPart = This->blocksize * (index + 1);
365
366 BIGBLOCKFILE_SetSize(This, newSize);
367 }
368
369 return BIGBLOCKFILE_GetBigBlockPointer(This, index, FILE_MAP_WRITE);
370}
371
372/******************************************************************************
373 * BIGBLOCKFILE_ReleaseBigBlock
374 *
375 * Releases the specified block.
376 */
377void BIGBLOCKFILE_ReleaseBigBlock(LPBIGBLOCKFILE This, void *pBlock)
378{
379 MappedPage *page;
380
381 if (pBlock == NULL)
382 return;
383
384 page = BIGBLOCKFILE_GetPageFromPointer(This, pBlock);
385
386 if (page == NULL)
387 return;
388
389 BIGBLOCKFILE_ReleaseMappedPage(This, page);
390}
391
392/******************************************************************************
393 * BIGBLOCKFILE_SetSize
394 *
395 * Sets the size of the file.
396 *
397 */
398void BIGBLOCKFILE_SetSize(LPBIGBLOCKFILE This, ULARGE_INTEGER newSize)
399{
400 if (This->filesize.s.LowPart == newSize.s.LowPart)
401 return;
402
403 TRACE("from %lu to %lu\n", This->filesize.s.LowPart, newSize.s.LowPart);
404 /*
405 * unmap all views, must be done before call to SetEndFile
406 */
407 BIGBLOCKFILE_UnmapAllMappedPages(This);
408
409 if (This->fileBased)
410 {
411 char buf[10];
412
413 /*
414 * close file-mapping object, must be done before call to SetEndFile
415 */
416 CloseHandle(This->hfilemap);
417 This->hfilemap = 0;
418
419 /*
420 * BEGIN HACK
421 * This fixes a bug when saving through smbfs.
422 * smbmount a Windows shared directory, save a structured storage file
423 * to that dir: crash.
424 *
425 * The problem is that the SetFilePointer-SetEndOfFile combo below
426 * doesn't always succeed. The file is not grown. It seems like the
427 * operation is cached. By doing the WriteFile, the file is actually
428 * grown on disk.
429 * This hack is only needed when saving to smbfs.
430 */
431 memset(buf, '0', 10);
432 SetFilePointer(This->hfile, newSize.s.LowPart, NULL, FILE_BEGIN);
433 WriteFile(This->hfile, buf, 10, NULL, NULL);
434 /*
435 * END HACK
436 */
437
438 /*
439 * set the new end of file
440 */
441 SetFilePointer(This->hfile, newSize.s.LowPart, NULL, FILE_BEGIN);
442 SetEndOfFile(This->hfile);
443
444 /*
445 * re-create the file mapping object
446 */
447 This->hfilemap = CreateFileMappingA(This->hfile,
448 NULL,
449 This->flProtect,
450 0, 0,
451 NULL);
452 }
453 else
454 {
455 GlobalUnlock(This->hbytearray);
456
457 /*
458 * Resize the byte array object.
459 */
460 ILockBytes_SetSize(This->pLkbyt, newSize);
461
462 /*
463 * Re-acquire the handle, it may have changed.
464 */
465 GetHGlobalFromILockBytes(This->pLkbyt, &This->hbytearray);
466 This->pbytearray = GlobalLock(This->hbytearray);
467 }
468
469 This->filesize.s.LowPart = newSize.s.LowPart;
470 This->filesize.s.HighPart = newSize.s.HighPart;
471
472 BIGBLOCKFILE_RemapAllMappedPages(This);
473}
474
475/******************************************************************************
476 * BIGBLOCKFILE_GetSize
477 *
478 * Returns the size of the file.
479 *
480 */
481ULARGE_INTEGER BIGBLOCKFILE_GetSize(LPBIGBLOCKFILE This)
482{
483 return This->filesize;
484}
485
486/******************************************************************************
487 * BIGBLOCKFILE_AccessCheck [PRIVATE]
488 *
489 * block_index is the index within the page.
490 */
491static BOOL BIGBLOCKFILE_AccessCheck(MappedPage *page, ULONG block_index,
492 DWORD desired_access)
493{
494 assert(block_index < BLOCKS_PER_PAGE);
495
496 if (desired_access == FILE_MAP_READ)
497 {
498 if (BIGBLOCKFILE_TestBit(&page->writable_blocks, block_index))
499 return FALSE;
500
501 BIGBLOCKFILE_SetBit(&page->readable_blocks, block_index);
502 }
503 else
504 {
505 assert(desired_access == FILE_MAP_WRITE);
506
507 if (BIGBLOCKFILE_TestBit(&page->readable_blocks, block_index))
508 return FALSE;
509
510 BIGBLOCKFILE_SetBit(&page->writable_blocks, block_index);
511 }
512
513 return TRUE;
514}
515
516/******************************************************************************
517 * BIGBLOCKFILE_GetBigBlockPointer [PRIVATE]
518 *
519 * Returns a pointer to the specified block.
520 */
521static void* BIGBLOCKFILE_GetBigBlockPointer(
522 LPBIGBLOCKFILE This,
523 ULONG block_index,
524 DWORD desired_access)
525{
526 DWORD page_index = block_index / BLOCKS_PER_PAGE;
527 DWORD block_on_page = block_index % BLOCKS_PER_PAGE;
528
529 MappedPage *page = BIGBLOCKFILE_GetMappedView(This, page_index);
530 if (!page || !page->lpBytes) return NULL;
531
532 if (!BIGBLOCKFILE_AccessCheck(page, block_on_page, desired_access))
533 {
534 BIGBLOCKFILE_ReleaseMappedPage(This, page);
535 return NULL;
536 }
537
538 return (LPBYTE)page->lpBytes + (block_on_page * This->blocksize);
539}
540
541/******************************************************************************
542 * BIGBLOCKFILE_GetMappedPageFromPointer [PRIVATE]
543 *
544 * pBlock is a pointer to a block on a page.
545 * The page has to be on the in-use list. (As oppsed to the victim list.)
546 *
547 * Does not increment the usage count.
548 */
549static MappedPage *BIGBLOCKFILE_GetPageFromPointer(LPBIGBLOCKFILE This,
550 void *pBlock)
551{
552 MappedPage *page;
553
554 for (page = This->maplist; page != NULL; page = page->next)
555 {
556 if ((LPBYTE)pBlock >= (LPBYTE)page->lpBytes
557 && (LPBYTE)pBlock <= (LPBYTE)page->lpBytes + PAGE_SIZE)
558 break;
559
560 }
561
562 return page;
563}
564
565/******************************************************************************
566 * BIGBLOCKFILE_FindPageInList [PRIVATE]
567 *
568 */
569static MappedPage *BIGBLOCKFILE_FindPageInList(MappedPage *head,
570 ULONG page_index)
571{
572 for (; head != NULL; head = head->next)
573 {
574 if (head->page_index == page_index)
575 {
576 InterlockedIncrement(&head->refcnt);
577 break;
578 }
579 }
580
581 return head;
582
583}
584
585static void BIGBLOCKFILE_UnlinkPage(MappedPage *page)
586{
587 if (page->next) page->next->prev = page->prev;
588 if (page->prev) page->prev->next = page->next;
589}
590
591static void BIGBLOCKFILE_LinkHeadPage(MappedPage **head, MappedPage *page)
592{
593 if (*head) (*head)->prev = page;
594 page->next = *head;
595 page->prev = NULL;
596 *head = page;
597}
598
599/******************************************************************************
600 * BIGBLOCKFILE_GetMappedView [PRIVATE]
601 *
602 * Gets the page requested if it is already mapped.
603 * If it's not already mapped, this method will map it
604 */
605static void * BIGBLOCKFILE_GetMappedView(
606 LPBIGBLOCKFILE This,
607 DWORD page_index)
608{
609 MappedPage *page;
610
611 page = BIGBLOCKFILE_FindPageInList(This->maplist, page_index);
612 if (!page)
613 {
614 page = BIGBLOCKFILE_FindPageInList(This->victimhead, page_index);
615 if (page)
616 {
617 This->num_victim_pages--;
618
619 BIGBLOCKFILE_Zero(&page->readable_blocks);
620 BIGBLOCKFILE_Zero(&page->writable_blocks);
621 }
622 }
623
624 if (page)
625 {
626 /* If the page is not already at the head of the list, move
627 * it there. (Also moves pages from victim to main list.) */
628 if (This->maplist != page)
629 {
630 if (This->victimhead == page) This->victimhead = page->next;
631 if (This->victimtail == page) This->victimtail = page->prev;
632
633 BIGBLOCKFILE_UnlinkPage(page);
634
635 BIGBLOCKFILE_LinkHeadPage(&This->maplist, page);
636 }
637
638 return page;
639 }
640
641 page = BIGBLOCKFILE_CreatePage(This, page_index);
642 if (!page) return NULL;
643
644 BIGBLOCKFILE_LinkHeadPage(&This->maplist, page);
645
646 return page;
647}
648
649static BOOL BIGBLOCKFILE_MapPage(LPBIGBLOCKFILE This, MappedPage *page)
650{
651 DWORD lowoffset = PAGE_SIZE * page->page_index;
652
653 if (This->fileBased)
654 {
655 DWORD numBytesToMap;
656 DWORD desired_access;
657
658 if (lowoffset + PAGE_SIZE > This->filesize.s.LowPart)
659 numBytesToMap = This->filesize.s.LowPart - lowoffset;
660 else
661 numBytesToMap = PAGE_SIZE;
662
663 if (This->flProtect == PAGE_READONLY)
664 desired_access = FILE_MAP_READ;
665 else
666 desired_access = FILE_MAP_WRITE;
667
668 page->lpBytes = MapViewOfFile(This->hfilemap, desired_access, 0,
669 lowoffset, numBytesToMap);
670 }
671 else
672 {
673 page->lpBytes = (LPBYTE)This->pbytearray + lowoffset;
674 }
675
676 TRACE("mapped page %lu to %p\n", page->page_index, page->lpBytes);
677
678 return page->lpBytes != NULL;
679}
680
681static MappedPage *BIGBLOCKFILE_CreatePage(LPBIGBLOCKFILE This,
682 ULONG page_index)
683{
684 MappedPage *page;
685
686 page = HeapAlloc(GetProcessHeap(), 0, sizeof(MappedPage));
687 if (page == NULL)
688 return NULL;
689
690 page->page_index = page_index;
691 page->refcnt = 1;
692
693 page->next = NULL;
694 page->prev = NULL;
695
696 BIGBLOCKFILE_MapPage(This, page);
697
698 BIGBLOCKFILE_Zero(&page->readable_blocks);
699 BIGBLOCKFILE_Zero(&page->writable_blocks);
700
701 return page;
702}
703
704static void BIGBLOCKFILE_UnmapPage(LPBIGBLOCKFILE This, MappedPage *page)
705{
706 TRACE("%ld at %p\n", page->page_index, page->lpBytes);
707 if (page->refcnt > 0)
708 ERR("unmapping inuse page %p\n", page->lpBytes);
709
710 if (This->fileBased && page->lpBytes)
711 UnmapViewOfFile(page->lpBytes);
712
713 page->lpBytes = NULL;
714}
715
716static void BIGBLOCKFILE_DeletePage(LPBIGBLOCKFILE This, MappedPage *page)
717{
718 BIGBLOCKFILE_UnmapPage(This, page);
719
720 HeapFree(GetProcessHeap(), 0, page);
721}
722
723/******************************************************************************
724 * BIGBLOCKFILE_ReleaseMappedPage [PRIVATE]
725 *
726 * Decrements the reference count of the mapped page.
727 */
728static void BIGBLOCKFILE_ReleaseMappedPage(
729 LPBIGBLOCKFILE This,
730 MappedPage *page)
731{
732 assert(This != NULL);
733 assert(page != NULL);
734
735 /* If the page is no longer refenced, move it to the victim list.
736 * If the victim list is too long, kick somebody off. */
737 if (!InterlockedDecrement(&page->refcnt))
738 {
739 if (This->maplist == page) This->maplist = page->next;
740
741 BIGBLOCKFILE_UnlinkPage(page);
742
743 if (MAX_VICTIM_PAGES > 0)
744 {
745 if (This->num_victim_pages >= MAX_VICTIM_PAGES)
746 {
747 MappedPage *victim = This->victimtail;
748 if (victim)
749 {
750 This->victimtail = victim->prev;
751 if (This->victimhead == victim)
752 This->victimhead = victim->next;
753
754 BIGBLOCKFILE_UnlinkPage(victim);
755 BIGBLOCKFILE_DeletePage(This, victim);
756 }
757 }
758 else This->num_victim_pages++;
759
760 BIGBLOCKFILE_LinkHeadPage(&This->victimhead, page);
761 if (This->victimtail == NULL) This->victimtail = page;
762 }
763 else
764 BIGBLOCKFILE_DeletePage(This, page);
765 }
766}
767
768static void BIGBLOCKFILE_DeleteList(LPBIGBLOCKFILE This, MappedPage *list)
769{
770 while (list != NULL)
771 {
772 MappedPage *next = list->next;
773
774 BIGBLOCKFILE_DeletePage(This, list);
775
776 list = next;
777 }
778}
779
780/******************************************************************************
781 * BIGBLOCKFILE_FreeAllMappedPages [PRIVATE]
782 *
783 * Unmap all currently mapped pages.
784 * Empty mapped pages list.
785 */
786static void BIGBLOCKFILE_FreeAllMappedPages(
787 LPBIGBLOCKFILE This)
788{
789 BIGBLOCKFILE_DeleteList(This, This->maplist);
790 BIGBLOCKFILE_DeleteList(This, This->victimhead);
791
792 This->maplist = NULL;
793 This->victimhead = NULL;
794 This->victimtail = NULL;
795 This->num_victim_pages = 0;
796}
797
798static void BIGBLOCKFILE_UnmapList(LPBIGBLOCKFILE This, MappedPage *list)
799{
800 for (; list != NULL; list = list->next)
801 {
802 BIGBLOCKFILE_UnmapPage(This, list);
803 }
804}
805
806static void BIGBLOCKFILE_UnmapAllMappedPages(LPBIGBLOCKFILE This)
807{
808 BIGBLOCKFILE_UnmapList(This, This->maplist);
809 BIGBLOCKFILE_UnmapList(This, This->victimhead);
810}
811
812static void BIGBLOCKFILE_RemapList(LPBIGBLOCKFILE This, MappedPage *list)
813{
814 while (list != NULL)
815 {
816 MappedPage *next = list->next;
817
818 if (list->page_index * PAGE_SIZE > This->filesize.s.LowPart)
819 {
820 TRACE("discarding %lu\n", list->page_index);
821
822 /* page is entirely outside of the file, delete it */
823 BIGBLOCKFILE_UnlinkPage(list);
824 BIGBLOCKFILE_DeletePage(This, list);
825 }
826 else
827 {
828 /* otherwise, remap it */
829 BIGBLOCKFILE_MapPage(This, list);
830 }
831
832 list = next;
833 }
834}
835
836static void BIGBLOCKFILE_RemapAllMappedPages(LPBIGBLOCKFILE This)
837{
838 BIGBLOCKFILE_RemapList(This, This->maplist);
839 BIGBLOCKFILE_RemapList(This, This->victimhead);
840}
841
842/****************************************************************************
843 * BIGBLOCKFILE_GetProtectMode
844 *
845 * This function will return a protection mode flag for a file-mapping object
846 * from the open flags of a file.
847 */
848static DWORD BIGBLOCKFILE_GetProtectMode(DWORD openFlags)
849{
850 if (openFlags & (STGM_WRITE | STGM_READWRITE))
851 return PAGE_READWRITE;
852 else
853 return PAGE_READONLY;
854}
Note: See TracBrowser for help on using the repository browser.