2 * COPYRIGHT: GNU GENERAL PUBLIC LICENSE VERSION 2
3 * PROJECT: ReiserFs file system driver for Windows NT/2000/XP/Vista.
6 * PROGRAMMER: Mark Piper, Matt Wu, Bo Brantén.
11 /* INCLUDES *****************************************************************/
15 // TODO: turn off (turns off warning about returning without return value, so I could easily disable code sections)
17 #pragma warning(disable : 4716)
20 /* GLOBALS ***************************************************************/
22 extern PRFSD_GLOBAL RfsdGlobal
;
24 /* DEFINITIONS *************************************************************/
27 #pragma alloc_text(PAGE, RfsdLoadSuper)
28 #pragma alloc_text(PAGE, RfsdSaveSuper)
30 #pragma alloc_text(PAGE, RfsdLoadGroup)
31 #pragma alloc_text(PAGE, RfsdSaveGroup)
33 #pragma alloc_text(PAGE, RfsdLoadInode)
34 #pragma alloc_text(PAGE, RfsdSaveInode)
36 #pragma alloc_text(PAGE, RfsdLoadBlock)
37 #pragma alloc_text(PAGE, RfsdSaveBlock)
39 #pragma alloc_text(PAGE, RfsdSaveBuffer)
41 #pragma alloc_text(PAGE, RfsdGetBlock)
42 #pragma alloc_text(PAGE, RfsdBlockMap)
44 #pragma alloc_text(PAGE, RfsdBuildBDL)
45 #pragma alloc_text(PAGE, RfsdBuildBDL2)
47 #pragma alloc_text(PAGE, RfsdNewBlock)
48 #pragma alloc_text(PAGE, RfsdFreeBlock)
50 #pragma alloc_text(PAGE, RfsdExpandBlock)
51 #pragma alloc_text(PAGE, RfsdExpandInode)
53 #pragma alloc_text(PAGE, RfsdNewInode)
54 #pragma alloc_text(PAGE, RfsdFreeInode)
56 #pragma alloc_text(PAGE, RfsdAddEntry)
57 #pragma alloc_text(PAGE, RfsdRemoveEntry)
59 #pragma alloc_text(PAGE, RfsdTruncateBlock)
60 #pragma alloc_text(PAGE, RfsdTruncateInode)
62 #pragma alloc_text(PAGE, RfsdAddMcbEntry)
63 #pragma alloc_text(PAGE, RfsdRemoveMcbEntry)
64 #pragma alloc_text(PAGE, RfsdLookupMcbEntry)
66 #pragma alloc_text(PAGE, SuperblockContainsMagicKey)
67 #pragma alloc_text(PAGE, DetermineOnDiskKeyFormat)
68 #pragma alloc_text(PAGE, FillInMemoryKey)
69 #pragma alloc_text(PAGE, CompareShortKeys)
70 #pragma alloc_text(PAGE, CompareKeysWithoutOffset)
71 #pragma alloc_text(PAGE, CompareKeys)
72 #pragma alloc_text(PAGE, NavigateToLeafNode)
73 #pragma alloc_text(PAGE, _NavigateToLeafNode)
74 #pragma alloc_text(PAGE, RfsdParseFilesystemTree)
77 /* FUNCTIONS ***************************************************************/
80 RfsdLoadSuper(IN PRFSD_VCB Vcb
,
84 PRFSD_SUPER_BLOCK RfsdSb
= NULL
;
88 RfsdSb
= (PRFSD_SUPER_BLOCK
) ExAllocatePoolWithTag(PagedPool
,
89 SUPER_BLOCK_SIZE
, RFSD_POOL_TAG
);
94 Status
= RfsdReadDisk(
96 (ULONGLONG
) SUPER_BLOCK_OFFSET
,
101 if (!NT_SUCCESS(Status
)) {
103 RfsdPrint((DBG_ERROR
, "RfsdReadDisk: Read Block Device error.\n"));
115 RfsdSaveSuper( IN PRFSD_IRP_CONTEXT IrpContext
,
123 Offset
= (LONGLONG
) SUPER_BLOCK_OFFSET
;
125 bRet
= RfsdSaveBuffer( IrpContext
,
131 if (IsFlagOn(Vcb
->Flags
, VCB_FLOPPY_DISK
)) {
132 RfsdStartFloppyFlushDpc(Vcb
, NULL
, NULL
);
141 RfsdLoadGroup(IN PRFSD_VCB Vcb
)
148 PRFSD_SUPER_BLOCK sb
;
150 sb
= Vcb
->SuperBlock
;
152 Vcb
->BlockSize
= RFSD_MIN_BLOCK
<< sb
->s_log_block_size
;
153 Vcb
->SectorBits
= RfsdLog2(SECTOR_SIZE
);
154 ASSERT(BLOCK_BITS
== RfsdLog2(BLOCK_SIZE
));
156 Vcb
->NumOfGroups
= (sb
->s_blocks_count
- sb
->s_first_data_block
+
157 sb
->s_blocks_per_group
- 1) / sb
->s_blocks_per_group
;
159 Size
= sizeof(RFSD_GROUP_DESC
) * Vcb
->NumOfGroups
;
161 if (Vcb
->BlockSize
== RFSD_MIN_BLOCK
) {
162 Lba
= (LONGLONG
)2 * Vcb
->BlockSize
;
165 if (Vcb
->BlockSize
> RFSD_MIN_BLOCK
) {
166 Lba
= (LONGLONG
) (Vcb
->BlockSize
);
173 Buffer
= ExAllocatePoolWithTag(PagedPool
, Size
, RFSD_POOL_TAG
);
175 RfsdPrint((DBG_ERROR
, "RfsdLoadSuper: no enough memory.\n"));
179 RfsdPrint((DBG_USER
, "RfsdLoadGroup: Lba=%I64xh Size=%xh\n", Lba
, Size
));
181 Status
= RfsdReadDisk( Vcb
,
187 if (!NT_SUCCESS(Status
)) {
200 &(Vcb->GroupDescBcb),
205 Vcb->GroupDesc = NULL;
210 Vcb
->GroupDesc
= (PRFSD_GROUP_DESC
) Buffer
;
216 RfsdSaveGroup( IN PRFSD_IRP_CONTEXT IrpContext
,
223 if (Vcb
->BlockSize
== RFSD_MIN_BLOCK
) {
225 Offset
= (LONGLONG
) (2 * Vcb
->BlockSize
);
229 Offset
= (LONGLONG
) (Vcb
->BlockSize
);
232 Offset
+= ((LONGLONG
) sizeof(struct rfsd_group_desc
) * Group
);
234 bRet
= RfsdSaveBuffer(
238 sizeof(struct rfsd_group_desc
),
239 &(Vcb
->GroupDesc
[Group
]) );
241 if (IsFlagOn(Vcb
->Flags
, VCB_FLOPPY_DISK
)) {
242 RfsdStartFloppyFlushDpc(Vcb
, NULL
, NULL
);
251 /** Reads an inode structure off disk into the Inode object (which has been allocated, but not filled with any data) */
253 RfsdLoadInode (IN PRFSD_VCB Vcb
,
254 IN PRFSD_KEY_IN_MEMORY pKey
,
255 IN OUT PRFSD_INODE Inode
)
259 PRFSD_ITEM_HEAD pItemHeader
= NULL
;
260 PUCHAR pItemBuffer
= NULL
;
261 PUCHAR pBlockBuffer
= NULL
;
263 // Crate the target key for the stat item (stat items always have an offset of 0)
264 RFSD_KEY_IN_MEMORY TargetKey
;
269 TargetKey
.k_offset
= 0x0;
270 TargetKey
.k_type
= RFSD_KEY_TYPE_v2_STAT_DATA
;
272 RfsdPrint((DBG_FUNC
, /*__FUNCTION__*/ "on %i, %i\n", TargetKey
.k_dir_id
, TargetKey
.k_objectid
));
275 Status
= RfsdLoadItem(Vcb
, &TargetKey
,
276 &(pItemHeader
), &(pItemBuffer
), &(pBlockBuffer
), NULL
, //<
279 if (!NT_SUCCESS(Status
))
280 { if (pBlockBuffer
) {ExFreePool(pBlockBuffer
);} return FALSE
; }
282 // Copy the item into the inode / stat data structure
283 RtlCopyMemory(Inode
, pItemBuffer
, sizeof(RFSD_INODE
));
287 ExFreePool(pBlockBuffer
);
295 RfsdSaveInode ( IN PRFSD_IRP_CONTEXT IrpContext
,
298 IN PRFSD_INODE RfsdInode
)
303 LARGE_INTEGER CurrentTime
;
306 KeQuerySystemTime(&CurrentTime
);
307 RfsdInode
->i_mtime
= RfsdInode
->i_atime
=
308 (ULONG
)(RfsdInodeTime(CurrentTime
));
310 RfsdPrint((DBG_INFO
, "RfsdSaveInode: Saving Inode %xh: Mode=%xh Size=%xh\n",
311 Inode
, RfsdInode
->i_mode
, RfsdInode
->i_size
));
313 if (!RfsdGetInodeLba(Vcb
, Inode
, &Offset
)) {
314 RfsdPrint((DBG_ERROR
, "RfsdSaveInode: error get inode(%xh)'s addr.\n", Inode
));
318 bRet
= RfsdSaveBuffer(IrpContext
, Vcb
, Offset
, sizeof(RFSD_INODE
), RfsdInode
);
320 if (IsFlagOn(Vcb
->Flags
, VCB_FLOPPY_DISK
)) {
321 RfsdStartFloppyFlushDpc(Vcb
, NULL
, NULL
);
330 /** Just reads a block into a buffer */
334 IN ULONG dwBlk
, // A disk block ptr (a disk block number)
335 IN OUT PVOID Buffer
) // A buffer, which must be allocated to contain at least Vcb->BlockSize
337 IO_STATUS_BLOCK IoStatus
;
342 Offset
= (LONGLONG
) dwBlk
;
343 Offset
= Offset
* Vcb
->BlockSize
;
347 (PLARGE_INTEGER
)&Offset
,
355 if (!NT_SUCCESS(IoStatus
.Status
)) {
365 RfsdSaveBlock ( IN PRFSD_IRP_CONTEXT IrpContext
,
375 Offset
= (LONGLONG
) dwBlk
;
376 Offset
= Offset
* Vcb
->BlockSize
;
378 bRet
= RfsdSaveBuffer(IrpContext
, Vcb
, Offset
, Vcb
->BlockSize
, Buf
);
380 if (IsFlagOn(Vcb
->Flags
, VCB_FLOPPY_DISK
)) {
381 RfsdStartFloppyFlushDpc(Vcb
, NULL
, NULL
);
389 RfsdSaveBuffer( IN PRFSD_IRP_CONTEXT IrpContext
,
401 if( !CcPinRead( Vcb
->StreamObj
,
402 (PLARGE_INTEGER
) (&Offset
),
408 RfsdPrint((DBG_ERROR
, "RfsdSaveBuffer: PinReading error ...\n"));
414 RtlCopyMemory(Buffer
, Buf
, Size
);
415 CcSetDirtyPinnedData(Bcb
, NULL
);
416 RfsdRepinBcb(IrpContext
, Bcb
);
418 SetFlag(Vcb
->StreamObj
->Flags
, FO_FILE_MODIFIED
);
420 RfsdAddMcbEntry(Vcb
, Offset
, (LONGLONG
)Size
);
426 if (AbnormalTermination()) {
440 IN PRFSD_IRP_CONTEXT IrpContext
,
442 IN ULONG dwContent
, // A ptr to a disk block (disk block number)
451 NTSTATUS Status
= STATUS_SUCCESS
;
453 ULONG i
= 0, j
= 0, temp
= 1;
461 } else if (Layer
<= 3) {
463 /* allocate memory for pData to contain the block */
464 pData
= (ULONG
*) ExAllocatePoolWithTag(NonPagedPool
, Vcb
->BlockSize
, RFSD_POOL_TAG
);
466 RfsdPrint((DBG_ERROR
, "RfsdGetBlock: no enough memory.\n"));
467 Status
= STATUS_INSUFFICIENT_RESOURCES
;
471 /* load the block dwContext into pData buffer */
472 if (!RfsdLoadBlock(Vcb
, dwContent
, pData
)) {
474 Status
= STATUS_INSUFFICIENT_RESOURCES
;
478 temp
= 1 << ((BLOCK_BITS
- 2) * (Layer
- 1));
485 #if DISABLED // WRITE MODE ONLY
492 /* we need allocate new block: dwBlk */
494 Status
= RfsdNewBlock(
502 if (!NT_SUCCESS(Status
)) {
507 /* we need save pData now */
510 /* save the block first, before next call */
511 if (!RfsdSaveBlock( IrpContext
, Vcb
,
514 /* error occurs when saving the block */
515 Status
= STATUS_INSUFFICIENT_RESOURCES
;
517 /* we need free newly allocated block */
518 RfsdFreeBlock(IrpContext
, Vcb
, dwBlk
);
520 /* free the memory of pData */
528 /* free the memory of pData */
536 /* free the memory of pData */
539 /* transfer to next recursion call */
540 Status
= RfsdGetBlock(
550 if (!NT_SUCCESS(Status
)) {
563 /** I think this means it maps the blocks into the cache.
564 Basically, it goes through and calls GetBlock for each block.
568 IN PRFSD_IRP_CONTEXT IrpContext
,
571 IN PRFSD_INODE Inode
,
572 IN ULONG Index
, // Ordinal index of this block in the BDL
573 IN BOOLEAN bAlloc
, // FALSE
574 OUT PULONG pBlock
// <
581 ULONG dwSizes
[RFSD_BLOCK_TYPES
];
582 NTSTATUS Status
= STATUS_SUCCESS
;;
586 for (i
= 0; i
< RFSD_BLOCK_TYPES
; i
++) {
587 dwSizes
[i
] = Vcb
->dwData
[i
];
590 for (i
= 0; i
< RFSD_BLOCK_TYPES
; i
++) {
592 if (Index
< dwSizes
[i
]) {
597 // dwBlk will get the ptr to a block.
598 dwBlk
= Inode
->i_block
[i
==0 ? (Index
):(i
+ RFSD_NDIR_BLOCKS
- 1)];
600 #if DISABLED // WRITE MODE ONLY
611 /* we need allocate new block: dwBlk */
612 Status
= RfsdNewBlock(
615 (InodeNo
- 1) / BLOCKS_PER_GROUP
,
620 if (!NT_SUCCESS(Status
)) {
624 /* save the it into inode*/
625 Inode
->i_block
[i
==0 ? (Index
):(i
+ RFSD_NDIR_BLOCKS
- 1)] = dwBlk
;
628 if (!RfsdSaveInode( IrpContext
,
633 Status
= STATUS_UNSUCCESSFUL
;
635 RfsdFreeBlock(IrpContext
, Vcb
, dwBlk
);
642 Status
= RfsdGetBlock(
652 RfsdPrint((DBG_INFO
, "RfsdBlockMap: i=%xh index=%xh dwBlk=%xh (%xh)\n",
653 i
, Index
, dwRet
, dwBlk
));
655 if (NT_SUCCESS(Status
)) {
673 // NOTE: ReiserFS starts it byte offsets at 1, as opposed to 0 (which is used for the buffer -- and therefore, the BDL is also 0-based).
677 IN PRFSD_KEY_IN_MEMORY pKey
,
678 IN PRFSD_INODE pInode
,
679 OUT PULONG out_Count
,
680 OUT PRFSD_BDL
* out_ppBdl
)
682 NTSTATUS Status
= STATUS_SUCCESS
;
683 BOOLEAN done
= FALSE
;
685 RFSD_KEY_IN_MEMORY CurrentTargetKey
= *pKey
;
686 ULONGLONG CurrentOffset
= 0;
688 PRFSD_ITEM_HEAD pItemHeader
= NULL
; // The temporary storage for retrieving items from disk
689 PUCHAR pItemBuffer
= NULL
;
690 PUCHAR pBlockBuffer
= NULL
;
692 ULONG idxCurrentBD
= 0;
693 PRFSD_BDL pBdl
= NULL
; // The block descriptor list, which will be allocated, filled, and assigned to out_Bdl
697 // Allocate the BDL for the maximum number of block descriptors that will be needed (including the tail)
698 // FUTURE: sd_blocks DEFINITELY is not the number of blocks consumed by a file. (at least not the number of 4096-byte blocks)
699 // However, I'm unsure of how to calculate the number of blocks. Perhaps I should consider using a linked list instead?
700 KdPrint(("## Allocating %i BD's\n", pInode
->i_size
/ Vcb
->BlockSize
+ 3));
701 pBdl
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(RFSD_BDL
) * (SIZE_T
) (pInode
->i_size
/ Vcb
->BlockSize
+ 3), RFSD_POOL_TAG
);
702 if (!pBdl
) { Status
= STATUS_INSUFFICIENT_RESOURCES
; goto errorout
; }
703 //RtlZeroMemory(pBdl, sizeof(RFSD_BDL) * (pInode->sd_blocks + 1));
704 RtlZeroMemory(pBdl
, sizeof(RFSD_BDL
) * (SIZE_T
) (pInode
->i_size
/ Vcb
->BlockSize
+ 3));
707 // Build descriptors for all of the indirect items associated with the file
710 // Search for an indirect item, corresponding to CurrentOffset...
712 // Create the key to search for (note that the key always start with offset 1, even though it is for byte 0)
713 CurrentTargetKey
.k_offset
= CurrentOffset
+ 1;
714 CurrentTargetKey
.k_type
= RFSD_KEY_TYPE_v2_INDIRECT
;
716 // Perform the search
717 Status
= RfsdLoadItem(
718 Vcb
, &CurrentTargetKey
,
719 &(pItemHeader
), &(pItemBuffer
), &(pBlockBuffer
), NULL
,
723 // If there was no such indirect item...
724 if (Status
== STATUS_NO_SUCH_MEMBER
) { Status
= STATUS_SUCCESS
; break; }
725 if (!NT_SUCCESS(Status
)) { goto errorout
; }
727 // Otherwise, create a block descriptor for each pointer in the indirect item
729 ULONG countBlockRefs
= pItemHeader
->ih_item_len
/ sizeof(ULONG
);
732 for (idxBlockRef
= 0; idxBlockRef
< countBlockRefs
; idxBlockRef
++)
734 PULONG BlockRef
= (PULONG
) ((PUCHAR
) pItemBuffer
+ sizeof(ULONG
) * idxBlockRef
);
736 // Build a block descriptor for this block reference
737 pBdl
[idxCurrentBD
].Lba
= (LONGLONG
) *BlockRef
* (LONGLONG
) Vcb
->BlockSize
;
738 pBdl
[idxCurrentBD
].Length
= Vcb
->BlockSize
;
739 pBdl
[idxCurrentBD
].Offset
= CurrentOffset
;
741 // If this is the last reference in the indirect item, subtract the free space from the end
742 // TODO: this may not work, because the ih_free_space_reserved seems to be wrong / not there!
743 if (idxBlockRef
== (countBlockRefs
- 1))
744 pBdl
[idxCurrentBD
].Length
-= pItemHeader
->u
.ih_free_space_reserved
;
746 // Advance to the next block reference
747 CurrentOffset
+= Vcb
->BlockSize
;
751 if (countBlockRefs
<= 0) { done
= TRUE
; }
754 if (pBlockBuffer
) { ExFreePool(pBlockBuffer
); pBlockBuffer
= NULL
; }
757 // Cleanup the last remaining block buffer, from the indirect items
758 if (pBlockBuffer
) { ExFreePool(pBlockBuffer
); pBlockBuffer
= NULL
; }
760 // Search for the tail of the file (its optional direct item), corresponding to CurrentOffset...
762 ULONG BlockNumber
= 0;
764 // Create the key to search for
765 CurrentTargetKey
.k_offset
= CurrentOffset
+ 1;
766 CurrentTargetKey
.k_type
= RFSD_KEY_TYPE_v2_DIRECT
;
768 // Perform the search
769 Status
= RfsdLoadItem(
770 Vcb
, &CurrentTargetKey
,
771 &(pItemHeader
), &(pItemBuffer
), &(pBlockBuffer
), &(BlockNumber
),
775 if (Status
== STATUS_SUCCESS
)
777 // If there was a tail, then build a block descriptor for it
778 pBdl
[idxCurrentBD
].Lba
= (LONGLONG
) BlockNumber
* (LONGLONG
) Vcb
->BlockSize
+ pItemHeader
->ih_item_location
;
779 pBdl
[idxCurrentBD
].Length
= pItemHeader
->ih_item_len
;
780 pBdl
[idxCurrentBD
].Offset
= CurrentOffset
;
782 // Advance to the next block reference
783 CurrentOffset
+= pItemHeader
->ih_item_len
;
788 if (Status
== STATUS_NO_SUCH_MEMBER
) { Status
= STATUS_SUCCESS
; goto errorout
; } // If there wasn't a tail, it's fine
789 else { goto errorout
; } // But if there was some other problem, let's report it.
793 if (pBlockBuffer
) { ExFreePool(pBlockBuffer
); pBlockBuffer
= NULL
; }
795 // Search for the second part of the tail of the file (its optional second direct item), corresponding to CurrentOffset...
797 ULONG BlockNumber
= 0;
799 // Create the key to search for
800 CurrentTargetKey
.k_offset
= CurrentOffset
+ 1;
801 CurrentTargetKey
.k_type
= RFSD_KEY_TYPE_v2_DIRECT
;
803 // Perform the search
804 Status
= RfsdLoadItem(
805 Vcb
, &CurrentTargetKey
,
806 &(pItemHeader
), &(pItemBuffer
), &(pBlockBuffer
), &(BlockNumber
),
810 if (Status
== STATUS_SUCCESS
)
812 // If there was a second part of the tail, then build a block descriptor for it
813 pBdl
[idxCurrentBD
].Lba
= (LONGLONG
) BlockNumber
* (LONGLONG
) Vcb
->BlockSize
+ pItemHeader
->ih_item_location
;
814 pBdl
[idxCurrentBD
].Length
= pItemHeader
->ih_item_len
;
815 pBdl
[idxCurrentBD
].Offset
= CurrentOffset
;
821 if (Status
== STATUS_NO_SUCH_MEMBER
) { Status
= STATUS_SUCCESS
; } // If there wasn't a second part of the tail, it's fine
822 else { goto errorout
; } // But if there was some other problem, let's report it.
827 if (pBlockBuffer
) { ExFreePool(pBlockBuffer
); pBlockBuffer
= NULL
; }
830 *out_Count
= idxCurrentBD
;
838 PRFSD_IRP_CONTEXT IrpContext
,
846 RTL_BITMAP BlockBitmap
;
847 LARGE_INTEGER Offset
;
853 ULONG Group
= 0, dwBlk
, dwHint
= 0;
858 if (GroupHint
> Vcb
->NumOfGroups
)
859 GroupHint
= Vcb
->NumOfGroups
- 1;
861 if (BlockHint
!= 0) {
862 GroupHint
= (BlockHint
- RFSD_FIRST_DATA_BLOCK
) / BLOCKS_PER_GROUP
;
863 dwHint
= (BlockHint
- RFSD_FIRST_DATA_BLOCK
) % BLOCKS_PER_GROUP
;
868 // Perform Prefered Group
869 if (Vcb
->GroupDesc
[GroupHint
].bg_free_blocks_count
) {
871 Offset
.QuadPart
= (LONGLONG
) Vcb
->BlockSize
;
872 Offset
.QuadPart
= Offset
.QuadPart
*
873 Vcb
->GroupDesc
[GroupHint
].bg_block_bitmap
;
875 if (GroupHint
== Vcb
->NumOfGroups
- 1) {
877 Length
= TOTAL_BLOCKS
% BLOCKS_PER_GROUP
;
879 /* s_blocks_count is integer multiple of s_blocks_per_group */
881 Length
= BLOCKS_PER_GROUP
;
884 Length
= BLOCKS_PER_GROUP
;
887 if (!CcPinRead( Vcb
->StreamObj
,
894 RfsdPrint((DBG_ERROR
, "RfsdNewBlock: PinReading error ...\n"));
895 return STATUS_INSUFFICIENT_RESOURCES
;
898 RtlInitializeBitMap( &BlockBitmap
,
904 if (RtlCheckBit(&BlockBitmap
, dwHint
) == 0) {
907 dwBlk
= RtlFindClearBits(&BlockBitmap
, 1, dwHint
);
910 // We could not get new block in the prefered group.
911 if (dwBlk
== 0xFFFFFFFF) {
913 CcUnpinData(BitmapBcb
);
917 RtlZeroMemory(&BlockBitmap
, sizeof(RTL_BITMAP
));
921 if (dwBlk
== 0xFFFFFFFF) {
923 for(Group
= 0; Group
< Vcb
->NumOfGroups
; Group
++)
924 if (Vcb
->GroupDesc
[Group
].bg_free_blocks_count
) {
925 if (Group
== GroupHint
)
928 Offset
.QuadPart
= (LONGLONG
) Vcb
->BlockSize
;
929 Offset
.QuadPart
= Offset
.QuadPart
* Vcb
->GroupDesc
[Group
].bg_block_bitmap
;
931 if (Vcb
->NumOfGroups
== 1) {
932 Length
= TOTAL_BLOCKS
;
934 if (Group
== Vcb
->NumOfGroups
- 1) {
936 Length
= TOTAL_BLOCKS
% BLOCKS_PER_GROUP
;
938 /* s_blocks_count is integer multiple of s_blocks_per_group */
940 Length
= BLOCKS_PER_GROUP
;
943 Length
= BLOCKS_PER_GROUP
;
947 if (!CcPinRead( Vcb
->StreamObj
,
953 RfsdPrint((DBG_ERROR
, "RfsdNewBlock: PinReading error ...\n"));
954 return STATUS_INSUFFICIENT_RESOURCES
;
957 RtlInitializeBitMap( &BlockBitmap
,
961 dwBlk
= RtlFindClearBits(&BlockBitmap
, 1, 0);
963 if (dwBlk
!= 0xFFFFFFFF) {
968 CcUnpinData(BitmapBcb
);
972 RtlZeroMemory(&BlockBitmap
, sizeof(RTL_BITMAP
));
977 if (dwBlk
< Length
) {
979 RtlSetBits(&BlockBitmap
, dwBlk
, 1);
981 CcSetDirtyPinnedData(BitmapBcb
, NULL
);
983 RfsdRepinBcb(IrpContext
, BitmapBcb
);
985 CcUnpinData(BitmapBcb
);
987 RfsdAddMcbEntry(Vcb
, Offset
.QuadPart
, (LONGLONG
)Vcb
->BlockSize
);
989 *dwRet
= dwBlk
+ RFSD_FIRST_DATA_BLOCK
+ Group
* BLOCKS_PER_GROUP
;
991 //Updating Group Desc / Superblock
992 Vcb
->GroupDesc
[Group
].bg_free_blocks_count
--;
993 RfsdSaveGroup(IrpContext
, Vcb
, Group
);
995 Vcb
->SuperBlock
->s_free_blocks_count
--;
996 RfsdSaveSuper(IrpContext
, Vcb
);
1000 for (i
=0; i
< Vcb
->NumOfGroups
; i
++)
1002 if ((Vcb
->GroupDesc
[i
].bg_block_bitmap
== *dwRet
) ||
1003 (Vcb
->GroupDesc
[i
].bg_inode_bitmap
== *dwRet
) ||
1004 (Vcb
->GroupDesc
[i
].bg_inode_table
== *dwRet
) ) {
1012 return STATUS_SUCCESS
;
1015 return STATUS_DISK_FULL
;
1021 PRFSD_IRP_CONTEXT IrpContext
,
1028 RTL_BITMAP BlockBitmap
;
1029 LARGE_INTEGER Offset
;
1036 BOOLEAN bModified
= FALSE
;
1038 if ( Block
< RFSD_FIRST_DATA_BLOCK
||
1039 (Block
/ BLOCKS_PER_GROUP
) >= Vcb
->NumOfGroups
) {
1042 return STATUS_INVALID_PARAMETER
;
1045 RfsdPrint((DBG_INFO
, "RfsdFreeBlock: Block %xh to be freed.\n", Block
));
1047 Group
= (Block
- RFSD_FIRST_DATA_BLOCK
) / BLOCKS_PER_GROUP
;
1049 dwBlk
= (Block
- RFSD_FIRST_DATA_BLOCK
) % BLOCKS_PER_GROUP
;
1052 Offset
.QuadPart
= (LONGLONG
) Vcb
->BlockSize
;
1053 Offset
.QuadPart
= Offset
.QuadPart
* Vcb
->GroupDesc
[Group
].bg_block_bitmap
;
1055 if (Group
== Vcb
->NumOfGroups
- 1) {
1057 Length
= TOTAL_BLOCKS
% BLOCKS_PER_GROUP
;
1059 /* s_blocks_count is integer multiple of s_blocks_per_group */
1061 Length
= BLOCKS_PER_GROUP
;
1065 Length
= BLOCKS_PER_GROUP
;
1068 if (!CcPinRead( Vcb
->StreamObj
,
1075 RfsdPrint((DBG_ERROR
, "RfsdDeleteBlock: PinReading error ...\n"));
1076 return STATUS_INSUFFICIENT_RESOURCES
;
1079 RtlInitializeBitMap( &BlockBitmap
,
1083 if (RtlCheckBit(&BlockBitmap
, dwBlk
) == 0) {
1086 RtlClearBits(&BlockBitmap
, dwBlk
, 1);
1092 CcUnpinData(BitmapBcb
);
1096 RtlZeroMemory(&BlockBitmap
, sizeof(RTL_BITMAP
));
1102 CcSetDirtyPinnedData(BitmapBcb
, NULL
);
1104 RfsdRepinBcb(IrpContext
, BitmapBcb
);
1106 CcUnpinData(BitmapBcb
);
1108 RfsdAddMcbEntry(Vcb
, Offset
.QuadPart
, (LONGLONG
)Vcb
->BlockSize
);
1110 //Updating Group Desc / Superblock
1111 Vcb
->GroupDesc
[Group
].bg_free_blocks_count
++;
1112 RfsdSaveGroup(IrpContext
, Vcb
, Group
);
1114 Vcb
->SuperBlock
->s_free_blocks_count
++;
1115 RfsdSaveSuper(IrpContext
, Vcb
);
1117 return STATUS_SUCCESS
;
1120 return STATUS_UNSUCCESSFUL
;
1126 PRFSD_IRP_CONTEXT IrpContext
,
1138 ULONG
*pData
= NULL
;
1139 ULONG i
= 0, j
= 0, temp
= 1;
1140 ULONG dwNewBlk
= 0, dwBlk
= 0;
1141 BOOLEAN bDirty
= FALSE
;
1142 NTSTATUS Status
= STATUS_SUCCESS
;
1144 PRFSD_INODE Inode
= Fcb
->Inode
;
1145 PRFSD_SUPER_BLOCK RfsdSb
= Vcb
->SuperBlock
;
1147 pData
= (ULONG
*) ExAllocatePoolWithTag(PagedPool
, Vcb
->BlockSize
, RFSD_POOL_TAG
);
1150 return STATUS_INSUFFICIENT_RESOURCES
;
1153 RtlZeroMemory(pData
, Vcb
->BlockSize
);
1159 if (IsDirectory(Fcb
)) {
1161 PRFSD_DIR_ENTRY2 pEntry
;
1163 pEntry
= (PRFSD_DIR_ENTRY2
) pData
;
1164 pEntry
->rec_len
= (USHORT
)(Vcb
->BlockSize
);
1166 if (!RfsdSaveBlock(IrpContext
, Vcb
, dwContent
, (PVOID
)pData
)) {
1168 Status
= STATUS_UNSUCCESSFUL
;
1174 LARGE_INTEGER Offset
;
1176 Offset
.QuadPart
= (LONGLONG
) dwContent
;
1177 Offset
.QuadPart
= Offset
.QuadPart
* Vcb
->BlockSize
;
1179 RfsdRemoveMcbEntry(Vcb
, Offset
.QuadPart
, (LONGLONG
)Vcb
->BlockSize
);
1183 if (!RfsdSaveBlock(IrpContext
, Vcb
, dwContent
, (PVOID
)pData
)) {
1185 Status
= STATUS_UNSUCCESSFUL
;
1193 dwNewBlk
= dwContent
;
1195 } else if (layer
<= 3) {
1199 if (!RfsdLoadBlock(Vcb
, dwContent
, (void *)pData
)) {
1201 Status
= STATUS_UNSUCCESSFUL
;
1206 temp
= 1 << ((BLOCK_BITS
- 2) * (layer
- 1));
1215 Status
= RfsdNewBlock(
1221 if (!NT_SUCCESS(Status
)) {
1223 RfsdPrint((DBG_ERROR
, "RfsdExpandBlock: get new block error.\n"));
1227 Inode
->i_blocks
+= (Vcb
->BlockSize
/ SECTOR_SIZE
);
1233 Status
= RfsdExpandBlock(
1241 if (!NT_SUCCESS(Status
))
1243 RfsdPrint((DBG_ERROR
, "RfsdExpandBlockk: ... error recuise...\n"));
1249 RfsdSaveBlock( IrpContext
,
1260 if (NT_SUCCESS(Status
) && dwRet
)
1269 IN PRFSD_IRP_CONTEXT IrpContext
,
1278 ULONG dwSizes
[RFSD_BLOCK_TYPES
];
1281 ULONG dwBlk
= 0, dwNewBlk
= 0;
1283 NTSTATUS Status
= STATUS_SUCCESS
;
1284 BOOLEAN bNewBlock
= FALSE
;
1286 PRFSD_INODE Inode
= Fcb
->Inode
;
1288 Index
= (ULONG
)(Fcb
->Header
.AllocationSize
.QuadPart
>> BLOCK_BITS
);
1290 for (i
= 0; i
< RFSD_BLOCK_TYPES
; i
++) {
1291 dwSizes
[i
] = Vcb
->dwData
[i
];
1292 dwTotal
+= dwSizes
[i
];
1295 if (Index
>= dwTotal
) {
1297 RfsdPrint((DBG_ERROR
, "RfsdExpandInode: beyond the maxinum size of an inode.\n"));
1298 return STATUS_UNSUCCESSFUL
;
1301 for (i
= 0; i
< RFSD_BLOCK_TYPES
; i
++) {
1303 if (Index
< dwSizes
[i
]) {
1305 dwBlk
= Inode
->i_block
[i
==0 ? (Index
):(i
+ RFSD_NDIR_BLOCKS
- 1)];
1309 Status
= RfsdNewBlock(
1312 Fcb
->BlkHint
? 0 : ((Fcb
->RfsdMcb
->Inode
- 1) / INODES_PER_GROUP
),
1316 if (!NT_SUCCESS(Status
) ) {
1317 RfsdPrint((DBG_ERROR
, "RfsdExpandInode: get new block error.\n"));
1321 Inode
->i_block
[i
==0 ? (Index
):(i
+ RFSD_NDIR_BLOCKS
- 1)] = dwBlk
;
1323 Inode
->i_blocks
+= (Vcb
->BlockSize
/ SECTOR_SIZE
);
1328 Status
= RfsdExpandBlock (
1335 if (NT_SUCCESS(Status
)) {
1336 Fcb
->Header
.AllocationSize
.QuadPart
+= Vcb
->BlockSize
;
1342 Index
-= dwSizes
[i
];
1345 RfsdSaveInode(IrpContext
, Vcb
, Fcb
->RfsdMcb
->Inode
, Inode
);
1347 if (NT_SUCCESS(Status
)) {
1350 Fcb
->BlkHint
= dwNewBlk
+1;
1353 RfsdPrint((DBG_INFO
, "RfsdExpandInode: %S (%xh) i=%2.2xh Index=%8.8xh New Block=%8.8xh\n",
1354 Fcb
->RfsdMcb
->ShortName
.Buffer
, Fcb
->RfsdMcb
->Inode
, i
, Index
, dwNewBlk
));
1358 Status
= STATUS_UNSUCCESSFUL
;
1368 PRFSD_IRP_CONTEXT IrpContext
,
1377 RTL_BITMAP InodeBitmap
;
1382 ULONG Average
, Length
;
1383 LARGE_INTEGER Offset
;
1387 *Inode
= dwInode
= 0XFFFFFFFF;
1393 if (Type
== RFSD_FT_DIR
) {
1395 Average
= Vcb
->SuperBlock
->s_free_inodes_count
/ Vcb
->NumOfGroups
;
1397 for (j
= 0; j
< Vcb
->NumOfGroups
; j
++) {
1399 i
= (j
+ GroupHint
) % (Vcb
->NumOfGroups
);
1401 if ((Vcb
->GroupDesc
[i
].bg_used_dirs_count
<< 8) <
1402 Vcb
->GroupDesc
[i
].bg_free_inodes_count
) {
1410 for (j
= 0; j
< Vcb
->NumOfGroups
; j
++) {
1412 if (Vcb
->GroupDesc
[j
].bg_free_inodes_count
>= Average
) {
1413 if (!Group
|| (Vcb
->GroupDesc
[j
].bg_free_blocks_count
>
1414 Vcb
->GroupDesc
[Group
].bg_free_blocks_count
))
1423 * Try to place the inode in its parent directory (GroupHint)
1426 if (Vcb
->GroupDesc
[GroupHint
].bg_free_inodes_count
) {
1428 Group
= GroupHint
+ 1;
1435 * Use a quadratic hash to find a group with a
1439 for (j
= 1; j
< Vcb
->NumOfGroups
; j
<<= 1) {
1442 if (i
> Vcb
->NumOfGroups
)
1443 i
-= Vcb
->NumOfGroups
;
1445 if (Vcb
->GroupDesc
[i
].bg_free_inodes_count
) {
1454 * That failed: try linear search for a free inode
1457 for (j
= 2; j
< Vcb
->NumOfGroups
; j
++) {
1458 if (++i
>= Vcb
->NumOfGroups
) i
= 0;
1460 if (Vcb
->GroupDesc
[i
].bg_free_inodes_count
) {
1468 // Could not find a proper group.
1471 return STATUS_DISK_FULL
;
1477 Offset
.QuadPart
= (LONGLONG
) Vcb
->BlockSize
;
1478 Offset
.QuadPart
= Offset
.QuadPart
* Vcb
->GroupDesc
[Group
].bg_inode_bitmap
;
1480 if (Vcb
->NumOfGroups
== 1) {
1481 Length
= INODES_COUNT
;
1483 if (Group
== Vcb
->NumOfGroups
- 1) {
1484 Length
= INODES_COUNT
% INODES_PER_GROUP
;
1486 /* INODES_COUNT is integer multiple of INODES_PER_GROUP */
1487 Length
= INODES_PER_GROUP
;
1490 Length
= INODES_PER_GROUP
;
1494 if (!CcPinRead( Vcb
->StreamObj
,
1501 RfsdPrint((DBG_ERROR
, "RfsdNewInode: PinReading error ...\n"));
1503 return STATUS_UNSUCCESSFUL
;
1506 RtlInitializeBitMap( &InodeBitmap
,
1510 dwInode
= RtlFindClearBits(&InodeBitmap
, 1, 0);
1512 if (dwInode
== 0xFFFFFFFF) {
1513 CcUnpinData(BitmapBcb
);
1517 RtlZeroMemory(&InodeBitmap
, sizeof(RTL_BITMAP
));
1521 if (dwInode
== 0xFFFFFFFF || dwInode
>= Length
) {
1523 if (Vcb
->GroupDesc
[Group
].bg_free_inodes_count
!= 0) {
1525 Vcb
->GroupDesc
[Group
].bg_free_inodes_count
= 0;
1527 RfsdSaveGroup(IrpContext
, Vcb
, Group
);
1534 RtlSetBits(&InodeBitmap
, dwInode
, 1);
1536 CcSetDirtyPinnedData(BitmapBcb
, NULL
);
1538 RfsdRepinBcb(IrpContext
, BitmapBcb
);
1540 CcUnpinData(BitmapBcb
);
1542 RfsdAddMcbEntry(Vcb
, Offset
.QuadPart
, (LONGLONG
)Vcb
->BlockSize
);
1544 *Inode
= dwInode
+ 1 + Group
* INODES_PER_GROUP
;
1546 //Updating Group Desc / Superblock
1547 Vcb
->GroupDesc
[Group
].bg_free_inodes_count
--;
1548 if (Type
== RFSD_FT_DIR
) {
1549 Vcb
->GroupDesc
[Group
].bg_used_dirs_count
++;
1552 RfsdSaveGroup(IrpContext
, Vcb
, Group
);
1554 Vcb
->SuperBlock
->s_free_inodes_count
--;
1555 RfsdSaveSuper(IrpContext
, Vcb
);
1557 return STATUS_SUCCESS
;
1560 return STATUS_DISK_FULL
;
1567 PRFSD_IRP_CONTEXT IrpContext
,
1575 RTL_BITMAP InodeBitmap
;
1581 LARGE_INTEGER Offset
;
1584 BOOLEAN bModified
= FALSE
;
1587 Group
= (Inode
- 1) / INODES_PER_GROUP
;
1588 dwIno
= (Inode
- 1) % INODES_PER_GROUP
;
1590 RfsdPrint((DBG_INFO
, "RfsdFreeInode: Inode: %xh (Group/Off = %xh/%xh)\n",
1591 Inode
, Group
, dwIno
));
1594 Offset
.QuadPart
= (LONGLONG
) Vcb
->BlockSize
;
1595 Offset
.QuadPart
= Offset
.QuadPart
* Vcb
->GroupDesc
[Group
].bg_inode_bitmap
;
1596 if (Group
== Vcb
->NumOfGroups
- 1) {
1598 Length
= INODES_COUNT
% INODES_PER_GROUP
;
1600 /* s_inodes_count is integer multiple of s_inodes_per_group */
1601 Length
= INODES_PER_GROUP
;
1604 Length
= INODES_PER_GROUP
;
1607 if (!CcPinRead( Vcb
->StreamObj
,
1613 RfsdPrint((DBG_ERROR
, "RfsdFreeInode: PinReading error ...\n"));
1617 RtlInitializeBitMap( &InodeBitmap
,
1621 if (RtlCheckBit(&InodeBitmap
, dwIno
) == 0) {
1624 RtlClearBits(&InodeBitmap
, dwIno
, 1);
1630 CcUnpinData(BitmapBcb
);
1634 RtlZeroMemory(&InodeBitmap
, sizeof(RTL_BITMAP
));
1640 CcSetDirtyPinnedData(BitmapBcb
, NULL
);
1642 RfsdRepinBcb(IrpContext
, BitmapBcb
);
1644 CcUnpinData(BitmapBcb
);
1646 RfsdAddMcbEntry(Vcb
, Offset
.QuadPart
, (LONGLONG
)Vcb
->BlockSize
);
1648 //Updating Group Desc / Superblock
1649 if (Type
== RFSD_FT_DIR
) {
1650 Vcb
->GroupDesc
[Group
].bg_used_dirs_count
--;
1653 Vcb
->GroupDesc
[Group
].bg_free_inodes_count
++;
1654 RfsdSaveGroup(IrpContext
, Vcb
, Group
);
1656 Vcb
->SuperBlock
->s_free_inodes_count
++;
1657 RfsdSaveSuper(IrpContext
, Vcb
);
1669 IN PRFSD_IRP_CONTEXT IrpContext
,
1674 IN PUNICODE_STRING FileName
)
1678 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1680 PRFSD_DIR_ENTRY2 pDir
= NULL
;
1681 PRFSD_DIR_ENTRY2 pNewDir
= NULL
;
1682 PRFSD_DIR_ENTRY2 pTarget
= NULL
;
1687 BOOLEAN bFound
= FALSE
;
1688 BOOLEAN bAdding
= FALSE
;
1690 BOOLEAN MainResourceAcquired
= FALSE
;
1694 if (!IsDirectory(Dcb
)) {
1696 return STATUS_NOT_A_DIRECTORY
;
1699 MainResourceAcquired
= ExAcquireResourceExclusiveLite(&Dcb
->MainResource
, TRUE
);
1703 Dcb
->ReferenceCount
++;
1705 pDir
= (PRFSD_DIR_ENTRY2
) ExAllocatePoolWithTag(PagedPool
,
1706 RFSD_DIR_REC_LEN(RFSD_NAME_LEN
), RFSD_POOL_TAG
);
1708 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1712 pTarget
= (PRFSD_DIR_ENTRY2
) ExAllocatePoolWithTag(PagedPool
,
1713 2 * RFSD_DIR_REC_LEN(RFSD_NAME_LEN
), RFSD_POOL_TAG
);
1716 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1720 #if DISABLED // disabled in FFS too
1721 if (IsFlagOn( SUPER_BLOCK
->s_feature_incompat
,
1722 RFSD_FEATURE_INCOMPAT_FILETYPE
)) {
1723 pDir
->file_type
= (UCHAR
) FileType
;
1727 pDir
->file_type
= 0;
1732 OemName
.Buffer
= pDir
->name
;
1733 OemName
.MaximumLength
= RFSD_NAME_LEN
;
1736 Status
= RfsdUnicodeToOEM(&OemName
, FileName
);
1738 if (!NT_SUCCESS(Status
)) {
1742 pDir
->name_len
= (CCHAR
) OemName
.Length
;
1745 pDir
->inode
= Inode
;
1746 pDir
->rec_len
= (USHORT
) (RFSD_DIR_REC_LEN(pDir
->name_len
));
1752 while ((LONGLONG
)dwBytes
< Dcb
->Header
.AllocationSize
.QuadPart
) {
1754 RtlZeroMemory(pTarget
, RFSD_DIR_REC_LEN(RFSD_NAME_LEN
));
1756 // Reading the DCB contents
1757 Status
= RfsdReadInode(
1760 Dcb
->RfsdMcb
->Inode
,
1764 RFSD_DIR_REC_LEN(RFSD_NAME_LEN
),
1767 if (!NT_SUCCESS(Status
)) {
1768 RfsdPrint((DBG_ERROR
, "RfsdAddDirectory: Reading Directory Content error.\n"));
1772 if (((pTarget
->inode
== 0) && pTarget
->rec_len
>= pDir
->rec_len
) ||
1773 (pTarget
->rec_len
>= RFSD_DIR_REC_LEN(pTarget
->name_len
) + pDir
->rec_len
)) {
1775 if (pTarget
->inode
) {
1777 RtlZeroMemory(pTarget
, 2 * RFSD_DIR_REC_LEN(RFSD_NAME_LEN
));
1779 // Reading the DCB contents
1780 Status
= RfsdReadInode(
1783 Dcb
->RfsdMcb
->Inode
,
1787 2 * RFSD_DIR_REC_LEN(RFSD_NAME_LEN
),
1790 if (!NT_SUCCESS(Status
)) {
1791 RfsdPrint((DBG_ERROR
, "RfsdAddDirectory: Reading Directory Content error.\n"));
1795 Length
= RFSD_DIR_REC_LEN(pTarget
->name_len
);
1797 pNewDir
= (PRFSD_DIR_ENTRY2
) ((PUCHAR
)pTarget
+ RFSD_DIR_REC_LEN(pTarget
->name_len
));
1799 pNewDir
->rec_len
= pTarget
->rec_len
- RFSD_DIR_REC_LEN(pTarget
->name_len
);
1801 pTarget
->rec_len
= RFSD_DIR_REC_LEN(pTarget
->name_len
);
1809 pNewDir
->file_type
= pDir
->file_type
;
1810 pNewDir
->inode
= pDir
->inode
;
1811 pNewDir
->name_len
= pDir
->name_len
;
1812 memcpy(pNewDir
->name
, pDir
->name
, pDir
->name_len
);
1813 Length
+= RFSD_DIR_REC_LEN(pDir
->name_len
);
1819 dwBytes
+= pTarget
->rec_len
;
1826 if ( FileType
==RFSD_FT_DIR
) {
1828 if(((pDir
->name_len
== 1) && (pDir
->name
[0] == '.')) ||
1829 ((pDir
->name_len
== 2) && (pDir
->name
[0] == '.') && (pDir
->name
[1] == '.')) ) {
1831 Dcb
->Inode
->i_links_count
++;
1835 Status
= RfsdWriteInode(
1838 Dcb
->RfsdMcb
->Inode
,
1847 // We should expand the size of the dir inode
1852 Status
= RfsdExpandInode(IrpContext
, Vcb
, Dcb
, &dwRet
);
1854 if (NT_SUCCESS(Status
)) {
1856 Dcb
->Inode
->i_size
= Dcb
->Header
.AllocationSize
.LowPart
;
1858 RfsdSaveInode(IrpContext
, Vcb
, Dcb
->RfsdMcb
->Inode
, Dcb
->Inode
);
1860 Dcb
->Header
.FileSize
= Dcb
->Header
.AllocationSize
;
1869 } else { // Something must be error!
1876 Dcb
->ReferenceCount
--;
1878 if(MainResourceAcquired
) {
1879 ExReleaseResourceForThreadLite(
1881 ExGetCurrentResourceThread());
1884 if (pTarget
!= NULL
) {
1885 ExFreePool(pTarget
);
1899 IN PRFSD_IRP_CONTEXT IrpContext
,
1907 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1909 PRFSD_DIR_ENTRY2 pTarget
= NULL
;
1910 PRFSD_DIR_ENTRY2 pPrevDir
= NULL
;
1912 USHORT PrevRecLen
= 0;
1917 BOOLEAN MainResourceAcquired
= FALSE
;
1921 if (!IsDirectory(Dcb
)) {
1922 return STATUS_NOT_A_DIRECTORY
;
1925 MainResourceAcquired
=
1926 ExAcquireResourceExclusiveLite(&Dcb
->MainResource
, TRUE
);
1930 Dcb
->ReferenceCount
++;
1932 pTarget
= (PRFSD_DIR_ENTRY2
) ExAllocatePoolWithTag(PagedPool
,
1933 RFSD_DIR_REC_LEN(RFSD_NAME_LEN
), RFSD_POOL_TAG
);
1936 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1940 pPrevDir
= (PRFSD_DIR_ENTRY2
) ExAllocatePoolWithTag(PagedPool
,
1941 RFSD_DIR_REC_LEN(RFSD_NAME_LEN
), RFSD_POOL_TAG
);
1943 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1949 while ((LONGLONG
)dwBytes
< Dcb
->Header
.AllocationSize
.QuadPart
) {
1951 RtlZeroMemory(pTarget
, RFSD_DIR_REC_LEN(RFSD_NAME_LEN
));
1953 Status
= RfsdReadInode(
1956 Dcb
->RfsdMcb
->Inode
,
1960 RFSD_DIR_REC_LEN(RFSD_NAME_LEN
),
1963 if (!NT_SUCCESS(Status
)) {
1965 RfsdPrint((DBG_ERROR
, "RfsdRemoveEntry: Reading Directory Content error.\n"));
1970 // Find it ! Then remove the entry from Dcb ...
1973 if (pTarget
->inode
== Inode
) {
1977 BOOLEAN bAcross
= FALSE
;
1979 if (((ULONG
)PrevRecLen
+ pTarget
->rec_len
) > BLOCK_SIZE
) {
1983 dwRet
= (dwBytes
- PrevRecLen
) & (~(BLOCK_SIZE
- 1));
1984 if (dwRet
!= (dwBytes
& (~(BLOCK_SIZE
- 1))))
1992 pPrevDir
->rec_len
+= pTarget
->rec_len
;
1994 RecLen
= RFSD_DIR_REC_LEN(pTarget
->name_len
);
1996 RtlZeroMemory(pTarget
, RecLen
);
1998 Status
= RfsdWriteInode(
2001 Dcb
->RfsdMcb
->Inode
,
2003 dwBytes
- PrevRecLen
,
2010 ASSERT(NT_SUCCESS(Status
));
2012 Status
= RfsdWriteInode(
2015 Dcb
->RfsdMcb
->Inode
,
2024 ASSERT(NT_SUCCESS(Status
));
2028 RecLen
= (ULONG
)pTarget
->rec_len
;
2029 if (RecLen
> RFSD_DIR_REC_LEN(RFSD_NAME_LEN
)) {
2031 RtlZeroMemory(pTarget
, RFSD_DIR_REC_LEN(RFSD_NAME_LEN
));
2033 pTarget
->rec_len
= (USHORT
)RecLen
;
2035 Status
= RfsdWriteInode(
2038 Dcb
->RfsdMcb
->Inode
,
2042 RFSD_DIR_REC_LEN(RFSD_NAME_LEN
),
2047 ASSERT(NT_SUCCESS(Status
));
2051 RtlZeroMemory(pTarget
, RecLen
);
2052 pTarget
->rec_len
= (USHORT
)RecLen
;
2054 Status
= RfsdWriteInode(
2057 Dcb
->RfsdMcb
->Inode
,
2066 ASSERT(NT_SUCCESS(Status
));
2071 // Error if it's the entry of dot or dot-dot or drop the parent's refer link
2074 if (FileType
== RFSD_FT_DIR
) {
2076 if(((pTarget
->name_len
== 1) && (pTarget
->name
[0] == '.')) ||
2077 ((pTarget
->name_len
== 2) && (pTarget
->name
[0] == '.') && (pTarget
->name
[1] == '.')) ) {
2081 Dcb
->Inode
->i_links_count
--;
2086 // Update at least mtime/atime if !RFSD_FT_DIR.
2089 if ( !RfsdSaveInode(
2092 Dcb
->RfsdMcb
->Inode
,
2095 Status
= STATUS_UNSUCCESSFUL
;
2102 RtlCopyMemory(pPrevDir
, pTarget
, RFSD_DIR_REC_LEN(RFSD_NAME_LEN
));
2103 PrevRecLen
= pTarget
->rec_len
;
2106 dwBytes
+= pTarget
->rec_len
;
2111 Dcb
->ReferenceCount
--;
2113 if(MainResourceAcquired
)
2114 ExReleaseResourceForThreadLite(
2116 ExGetCurrentResourceThread());
2118 if (pTarget
!= NULL
) {
2119 ExFreePool(pTarget
);
2122 if (pPrevDir
!= NULL
) {
2123 ExFreePool(pPrevDir
);
2132 RfsdSetParentEntry (
2133 IN PRFSD_IRP_CONTEXT IrpContext
,
2137 IN ULONG NewParent
)
2141 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
2143 PRFSD_DIR_ENTRY2 pSelf
= NULL
;
2144 PRFSD_DIR_ENTRY2 pParent
= NULL
;
2148 BOOLEAN MainResourceAcquired
= FALSE
;
2152 if (!IsDirectory(Dcb
)) {
2153 return STATUS_NOT_A_DIRECTORY
;
2156 MainResourceAcquired
=
2157 ExAcquireResourceExclusiveLite(&Dcb
->MainResource
, TRUE
);
2161 Dcb
->ReferenceCount
++;
2163 pSelf
= (PRFSD_DIR_ENTRY2
) ExAllocatePoolWithTag(PagedPool
,
2164 RFSD_DIR_REC_LEN(1) + RFSD_DIR_REC_LEN(2), RFSD_POOL_TAG
);
2166 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2173 // Reading the DCB contents
2176 Status
= RfsdReadInode(
2179 Dcb
->RfsdMcb
->Inode
,
2183 RFSD_DIR_REC_LEN(1) + RFSD_DIR_REC_LEN(2),
2186 if (!NT_SUCCESS(Status
)) {
2187 RfsdPrint((DBG_ERROR
, "RfsdSetParentEntry: Reading Directory Content error.\n"));
2191 ASSERT(dwBytes
== RFSD_DIR_REC_LEN(1) + RFSD_DIR_REC_LEN(2));
2193 pParent
= (PRFSD_DIR_ENTRY2
)((PUCHAR
)pSelf
+ pSelf
->rec_len
);
2195 if (pParent
->inode
!= OldParent
) {
2199 pParent
->inode
= NewParent
;
2201 Status
= RfsdWriteInode(
2204 Dcb
->RfsdMcb
->Inode
,
2214 Dcb
->ReferenceCount
--;
2216 if(MainResourceAcquired
) {
2217 ExReleaseResourceForThreadLite(
2219 ExGetCurrentResourceThread());
2234 IN PRFSD_IRP_CONTEXT IrpContext
,
2240 OUT BOOLEAN
*bFreed
)
2245 ULONG
*pData
= NULL
;
2246 ULONG i
= 0, j
= 0, temp
= 1;
2247 BOOLEAN bDirty
= FALSE
;
2254 NTSTATUS Status
= STATUS_SUCCESS
;
2256 PRFSD_INODE Inode
= Fcb
->Inode
;
2262 if ( dwContent
> 0 && (dwContent
/ BLOCKS_PER_GROUP
) < Vcb
->NumOfGroups
) {
2264 Status
= RfsdFreeBlock(IrpContext
, Vcb
, dwContent
);
2266 if (NT_SUCCESS(Status
)) {
2268 ASSERT(Inode
->i_blocks
>= (Vcb
->BlockSize
/ SECTOR_SIZE
));
2269 Inode
->i_blocks
-= (Vcb
->BlockSize
/ SECTOR_SIZE
);
2273 } else if (dwContent
== 0) {
2274 Status
= STATUS_SUCCESS
;
2277 Status
= STATUS_INVALID_PARAMETER
;
2280 } else if (layer
<= 3) {
2282 Offset
= (LONGLONG
) dwContent
;
2283 Offset
= Offset
* Vcb
->BlockSize
;
2285 if (!CcPinRead( Vcb
->StreamObj
,
2286 (PLARGE_INTEGER
) (&Offset
),
2292 RfsdPrint((DBG_ERROR
, "RfsdSaveBuffer: PinReading error ...\n"));
2293 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2297 temp
= 1 << ((BLOCK_BITS
- 2) * (layer
- 1));
2306 Status
= RfsdTruncateBlock(
2316 if(!NT_SUCCESS(Status
)) {
2325 if (i
== 0 && j
== 0) {
2330 Status
= RfsdFreeBlock(IrpContext
, Vcb
, dwContent
);
2332 if (NT_SUCCESS(Status
)) {
2333 ASSERT(Inode
->i_blocks
>= (Vcb
->BlockSize
/ SECTOR_SIZE
));
2334 Inode
->i_blocks
-= (Vcb
->BlockSize
/ SECTOR_SIZE
);
2342 CcSetDirtyPinnedData(Bcb
, NULL
);
2343 RfsdRepinBcb(IrpContext
, Bcb
);
2345 RfsdAddMcbEntry(Vcb
, Offset
, (LONGLONG
)Vcb
->BlockSize
);
2363 IN PRFSD_IRP_CONTEXT IrpContext
,
2370 ULONG dwSizes
[RFSD_BLOCK_TYPES
];
2376 NTSTATUS Status
= STATUS_SUCCESS
;
2377 BOOLEAN bFreed
= FALSE
;
2379 PRFSD_INODE Inode
= Fcb
->Inode
;
2381 Index
= (ULONG
)(Fcb
->Header
.AllocationSize
.QuadPart
>> BLOCK_BITS
);
2389 for (i
= 0; i
< RFSD_BLOCK_TYPES
; i
++) {
2390 dwSizes
[i
] = Vcb
->dwData
[i
];
2391 dwTotal
+= dwSizes
[i
];
2394 if (Index
>= dwTotal
) {
2395 RfsdPrint((DBG_ERROR
, "RfsdTruncateInode: beyond the maxinum size of an inode.\n"));
2399 for (i
= 0; i
< RFSD_BLOCK_TYPES
; i
++) {
2401 if (Index
< dwSizes
[i
]) {
2403 dwBlk
= Inode
->i_block
[i
==0 ? (Index
):(i
+ RFSD_NDIR_BLOCKS
- 1)];
2407 Status
= RfsdTruncateBlock(IrpContext
, Vcb
, Fcb
, dwBlk
, Index
, i
, &bFreed
);
2410 if (NT_SUCCESS(Status
)) {
2412 Fcb
->Header
.AllocationSize
.QuadPart
-= Vcb
->BlockSize
;
2415 Inode
->i_block
[i
==0 ? (Index
):(i
+ RFSD_NDIR_BLOCKS
- 1)] = 0;
2422 Index
-= dwSizes
[i
];
2426 // Inode struct saving is done externally.
2429 RfsdSaveInode(IrpContext
, Vcb
, Fcb
->RfsdMcb
->Inode
, Inode
);
2437 RfsdAddMcbEntry ( // Mcb = map control block (maps file-relative block offsets to disk-relative block offsets)
2445 BOOLEAN bRet
= FALSE
;
2455 Offset
= Lba
& (~((LONGLONG
)BLOCK_SIZE
- 1));
2457 Length
= (Length
+ Lba
- Offset
+ BLOCK_SIZE
- 1) &
2458 (~((LONGLONG
)BLOCK_SIZE
- 1));
2460 ASSERT ((Offset
& (BLOCK_SIZE
- 1)) == 0);
2461 ASSERT ((Length
& (BLOCK_SIZE
- 1)) == 0);
2463 Offset
= (Offset
>> BLOCK_BITS
) + 1;
2464 Length
= (Length
>> BLOCK_BITS
);
2466 ExAcquireResourceExclusiveLite(
2467 &(Vcb
->McbResource
),
2470 RfsdPrint((DBG_INFO
, "RfsdAddMcbEntry: Lba=%I64xh Length=%I64xh\n",
2474 bRet
= FsRtlLookupLargeMcbEntry(
2483 if (bRet
&& DirtyLba
== Offset
&& DirtyLen
>= Length
) {
2485 RfsdPrint((DBG_INFO
, "RfsdAddMcbEntry: this run already exists.\n"));
2491 bRet
= FsRtlAddLargeMcbEntry(
2496 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
2505 BOOLEAN bFound
= FALSE
;
2510 bFound
= FsRtlLookupLargeMcbEntry(
2519 if ((!bFound
) || (DirtyLba
== -1) ||
2520 (DirtyLba
!= Offset
) || (DirtyLen
< Length
)) {
2523 LONGLONG DirtyLength
;
2528 FsRtlGetNextLargeMcbEntry( &(Vcb
->DirtyMcbs
),
2535 RfsdPrint((DBG_INFO
, "Index = %xh\n", Index
));
2536 RfsdPrint((DBG_INFO
, "DirtyVba = %I64xh\n", DirtyVba
));
2537 RfsdPrint((DBG_INFO
, "DirtyLba = %I64xh\n", DirtyLba
));
2538 RfsdPrint((DBG_INFO
, "DirtyLen = %I64xh\n\n", DirtyLength
));
2544 ExReleaseResourceForThreadLite(
2545 &(Vcb
->McbResource
),
2546 ExGetCurrentResourceThread() );
2554 RfsdRemoveMcbEntry (
2564 Offset
= Lba
& (~((LONGLONG
)BLOCK_SIZE
- 1));
2566 Length
= (Length
+ Lba
- Offset
+ BLOCK_SIZE
- 1) &
2567 (~((LONGLONG
)BLOCK_SIZE
- 1));
2569 ASSERT(Offset
== Lba
);
2571 ASSERT ((Offset
& (BLOCK_SIZE
- 1)) == 0);
2572 ASSERT ((Length
& (BLOCK_SIZE
- 1)) == 0);
2574 Offset
= (Offset
>> BLOCK_BITS
) + 1;
2575 Length
= (Length
>> BLOCK_BITS
);
2577 RfsdPrint((DBG_INFO
, "RfsdRemoveMcbEntry: Lba=%I64xh Length=%I64xh\n",
2580 ExAcquireResourceExclusiveLite(
2581 &(Vcb
->McbResource
),
2585 FsRtlRemoveLargeMcbEntry(
2589 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
2595 BOOLEAN bFound
= FALSE
;
2596 LONGLONG DirtyLba
, DirtyLen
;
2598 bFound
= FsRtlLookupLargeMcbEntry(
2607 if (bFound
&&( DirtyLba
!= -1)) {
2613 ExReleaseResourceForThreadLite(
2614 &(Vcb
->McbResource
),
2615 ExGetCurrentResourceThread() );
2620 RfsdLookupMcbEntry (
2624 OUT PLONGLONG pLength
,
2625 OUT PLONGLONG RunStart
,
2626 OUT PLONGLONG RunLength
,
2636 Offset
= Lba
& (~((LONGLONG
)BLOCK_SIZE
- 1));
2637 ASSERT ((Offset
& (BLOCK_SIZE
- 1)) == 0);
2639 ASSERT(Lba
== Offset
);
2641 Offset
= (Offset
>> BLOCK_BITS
) + 1;
2643 ExAcquireResourceExclusiveLite(
2644 &(Vcb
->McbResource
),
2647 bRet
= FsRtlLookupLargeMcbEntry(
2656 ExReleaseResourceForThreadLite(
2657 &(Vcb
->McbResource
),
2658 ExGetCurrentResourceThread() );
2662 if (pLba
&& ((*pLba
) != -1)) {
2664 ASSERT((*pLba
) > 0);
2666 (*pLba
) = (((*pLba
) - 1) << BLOCK_BITS
);
2667 (*pLba
) += ((Lba
) & ((LONGLONG
)BLOCK_SIZE
- 1));
2672 (*pLength
) <<= BLOCK_BITS
;
2673 (*pLength
) -= ((Lba
) & ((LONGLONG
)BLOCK_SIZE
- 1));
2676 if (RunStart
&& (*RunStart
!= -1)) {
2677 (*RunStart
) = (((*RunStart
) - 1) << BLOCK_BITS
);
2681 (*RunLength
) <<= BLOCK_BITS
;
2692 ///////////////////////////////////////////////////
2693 ///////////////////////////////////////////////////
2696 Invoked by FSCTL.c on mount volume
2698 BOOLEAN
SuperblockContainsMagicKey(PRFSD_SUPER_BLOCK sb
)
2700 #define MAGIC_KEY_LENGTH 9
2702 UCHAR sz_MagicKey
[] = REISER2FS_SUPER_MAGIC_STRING
;
2704 BOOLEAN b_KeyMatches
= TRUE
;
2711 // If any characters read from disk don't match the expected magic key, we don't have a ReiserFS volume.
2712 for (i
= 0; i
< MAGIC_KEY_LENGTH
; i
++)
2714 currentChar
= sb
->s_magic
[i
];
2715 if (currentChar
!= sz_MagicKey
[i
])
2725 ______________________________________________________________________________
2727 | |/ /___ _ _ | | | | |_(_) |___
2728 | ' // _ \ | | | | | | | __| | / __|
2729 | . \ __/ |_| | | |_| | |_| | \__ \
2730 |_|\_\___|\__, | \___/ \__|_|_|___/
2732 ______________________________________________________________________________
2737 Guess whether a key is v1, or v2, by investigating its type field.
2738 NOTE: I based this off Florian Buchholz's code snippet, which is from reisefs lib.
2740 Old keys (on i386) have k_offset_v2.k_type == 15 (direct and indirect) or == 0 (dir items and stat data).
2743 RFSD_KEY_VERSION
DetermineOnDiskKeyFormat(const PRFSD_KEY_ON_DISK key
)
2745 int type
= (int) key
->u
.k_offset_v2
.k_type
;
2749 if ( type
== 0x0 || type
== 0xF )
2750 return RFSD_KEY_VERSION_1
;
2752 return RFSD_KEY_VERSION_2
;
2756 /** Given the uniqueness value from a version 1 KEY_ON_DISK, convert that to the v2 equivalent type (which is used for the KEY_IN_MEMORY structures) */
2758 ConvertKeyTypeUniqueness(__u32 k_uniqueness
)
2760 switch (k_uniqueness
)
2762 case RFSD_KEY_TYPE_v1_STAT_DATA
: return RFSD_KEY_TYPE_v2_STAT_DATA
;
2763 case RFSD_KEY_TYPE_v1_INDIRECT
: return RFSD_KEY_TYPE_v2_INDIRECT
;
2764 case RFSD_KEY_TYPE_v1_DIRECT
: return RFSD_KEY_TYPE_v2_DIRECT
;
2765 case RFSD_KEY_TYPE_v1_DIRENTRY
: return RFSD_KEY_TYPE_v2_DIRENTRY
;
2768 RfsdPrint((DBG_ERROR
, "Unexpected uniqueness value %i", k_uniqueness
));
2769 // NOTE: If above value is 555, it's the 'any' value, which I'd be surprised to see on disk.
2771 return 0xF; // We'll return v2 'any', just to see what happens...
2775 /** Fills an in-memory key structure with equivalent data as that given by an on-disk key, converting any older v1 information ito the new v2 formats. */
2778 IN PRFSD_KEY_ON_DISK pKeyOnDisk
,
2779 IN RFSD_KEY_VERSION KeyVersion
,
2780 IN OUT PRFSD_KEY_IN_MEMORY pKeyInMemory
)
2784 // Sanity check that the input and output locations exist
2785 if (!pKeyOnDisk
|| !pKeyInMemory
) { DbgBreak(); return; }
2787 // Copy over the fields that are compatible between keys
2788 pKeyInMemory
->k_dir_id
= pKeyOnDisk
->k_dir_id
;
2789 pKeyInMemory
->k_objectid
= pKeyOnDisk
->k_objectid
;
2791 if (KeyVersion
== RFSD_KEY_VERSION_UNKNOWN
)
2792 { KeyVersion
= DetermineOnDiskKeyFormat(pKeyOnDisk
); }
2794 // Copy over the fields that are incompatible between keys, converting older type fields to the v2 format
2797 case RFSD_KEY_VERSION_1
:
2798 pKeyInMemory
->k_offset
= pKeyOnDisk
->u
.k_offset_v1
.k_offset
;
2799 pKeyInMemory
->k_type
= ConvertKeyTypeUniqueness( pKeyOnDisk
->u
.k_offset_v1
.k_uniqueness
);
2802 case RFSD_KEY_VERSION_2
:
2803 pKeyInMemory
->k_offset
= pKeyOnDisk
->u
.k_offset_v2
.k_offset
;
2804 pKeyInMemory
->k_type
= (__u32
) pKeyOnDisk
->u
.k_offset_v2
.k_type
;
2809 /** Compares two in memory keys, returning KEY_SMALLER, KEY_LARGER, or KEYS_MATCH relative to the first key given. */
2812 IN PRFSD_KEY_IN_MEMORY a
,
2813 IN PRFSD_KEY_IN_MEMORY b
)
2817 // compare 1. integer
2818 if( a
->k_dir_id
< b
->k_dir_id
) return RFSD_KEY_SMALLER
;
2819 if( a
->k_dir_id
> b
->k_dir_id
) return RFSD_KEY_LARGER
;
2821 // compare 2. integer
2822 if( a
->k_objectid
< b
->k_objectid
) return RFSD_KEY_SMALLER
;
2823 if( a
->k_objectid
> b
->k_objectid
) return RFSD_KEY_LARGER
;
2825 return RFSD_KEYS_MATCH
;
2829 /** Compares two in memory keys, returning KEY_SMALLER, KEY_LARGER, or KEYS_MATCH relative to the first key given. */
2831 CompareKeysWithoutOffset(
2832 IN PRFSD_KEY_IN_MEMORY a
,
2833 IN PRFSD_KEY_IN_MEMORY b
)
2837 // compare 1. integer
2838 if( a
->k_dir_id
< b
->k_dir_id
) return RFSD_KEY_SMALLER
;
2839 if( a
->k_dir_id
> b
->k_dir_id
) return RFSD_KEY_LARGER
;
2841 // compare 2. integer
2842 if( a
->k_objectid
< b
->k_objectid
) return RFSD_KEY_SMALLER
;
2843 if( a
->k_objectid
> b
->k_objectid
) return RFSD_KEY_LARGER
;
2845 // compare 4. integer
2846 // NOTE: Buchholz says that if we get to here in navigating the file tree, something has gone wrong...
2847 if( a
->k_type
< b
->k_type
) return RFSD_KEY_SMALLER
;
2848 if( a
->k_type
> b
->k_type
) return RFSD_KEY_LARGER
;
2850 return RFSD_KEYS_MATCH
;
2854 /** Compares two in memory keys, returning KEY_SMALLER, KEY_LARGER, or KEYS_MATCH relative to the first key given. */
2857 IN PRFSD_KEY_IN_MEMORY a
,
2858 IN PRFSD_KEY_IN_MEMORY b
)
2862 // compare 1. integer
2863 if( a
->k_dir_id
< b
->k_dir_id
) return RFSD_KEY_SMALLER
;
2864 if( a
->k_dir_id
> b
->k_dir_id
) return RFSD_KEY_LARGER
;
2866 // compare 2. integer
2867 if( a
->k_objectid
< b
->k_objectid
) return RFSD_KEY_SMALLER
;
2868 if( a
->k_objectid
> b
->k_objectid
) return RFSD_KEY_LARGER
;
2870 // compare 3. integer
2871 if( a
->k_offset
< b
->k_offset
) return RFSD_KEY_SMALLER
;
2872 if( a
->k_offset
> b
->k_offset
) return RFSD_KEY_LARGER
;
2874 // compare 4. integer
2875 // NOTE: Buchholz says that if we get to here in navigating the file tree, something has gone wrong...
2876 if( a
->k_type
< b
->k_type
) return RFSD_KEY_SMALLER
;
2877 if( a
->k_type
> b
->k_type
) return RFSD_KEY_LARGER
;
2879 return RFSD_KEYS_MATCH
;
2885 ______________________________________________________________________________
2887 |_ _| __ ___ ___ | \ | | __ ___ _(_) __ _ __ _| |_(_) ___ _ __
2888 | || '__/ _ \/ _ \ | \| |/ _` \ \ / / |/ _` |/ _` | __| |/ _ \| '_ \
2889 | || | | __/ __/ | |\ | (_| |\ V /| | (_| | (_| | |_| | (_) | | | |
2890 |_||_| \___|\___| |_| \_|\__,_| \_/ |_|\__, |\__,_|\__|_|\___/|_| |_|
2892 ______________________________________________________________________________
2898 IN PRFSD_KEY_IN_MEMORY Key
, // Key to search for.
2899 IN ULONG StartingBlockNumber
, // Block number of an internal or leaf node, to start the search from
2900 OUT PULONG out_NextBlockNumber
// Block number of the leaf node that contains Key
2905 return _NavigateToLeafNode(Vcb
, Key
, StartingBlockNumber
, out_NextBlockNumber
, TRUE
, &CompareKeys
, NULL
, NULL
);
2909 RfsdParseFilesystemTree(
2911 IN PRFSD_KEY_IN_MEMORY Key
, // Key to search for.
2912 IN ULONG StartingBlockNumber
, // Block number of an internal or leaf node, to start the search from
2913 IN
RFSD_CALLBACK(fpDirectoryCallback
), // A function ptr to trigger on hitting a matching leaf block
2914 IN PVOID pContext
// This context item will simply be passed through to the callback when invoked
2921 return _NavigateToLeafNode(Vcb
, Key
, StartingBlockNumber
, &out
, FALSE
, &CompareShortKeys
, fpDirectoryCallback
, pContext
);
2926 Returns the block number of the leaf node that should contain key (if that key exists at all within the disk tree).
2928 STATUS_INVALID_HANDLE if a block or block header could not be read
2929 STATUS_INSUFFICIENT_RESOURCES if processing was terminated due to a failure of memory allocation
2930 STATUS_SUCCESS on success
2931 NOTE: the return value can also be anything defined by the invoked callback
2934 _NavigateToLeafNode(
2936 IN PRFSD_KEY_IN_MEMORY Key
, // Key to search for.
2937 IN ULONG StartingBlockNumber
, // Block number of an internal or leaf node, to start the search from
2938 OUT PULONG out_NextBlockNumber
, // Block number of the leaf node that contains Key (when a callback is in use, this is typically ignored -- it returns the block number at which the callback was last triggered)
2939 IN BOOLEAN ReturnOnFirstMatch
, // Whether or not the function should return upon finding the first leaf node containing the Key
2940 IN
RFSD_KEY_COMPARISON (*fpComparisonFunction
)(PRFSD_KEY_IN_MEMORY
, PRFSD_KEY_IN_MEMORY
),
2941 RFSD_CALLBACK(fpDirectoryCallback
), // A function ptr to trigger on hitting a matching leaf block
2942 IN PVOID pContext
// This context item will simply be passed through to the callback when invoked
2947 NTSTATUS Status
= STATUS_SUCCESS
;
2948 ULONG leafNodeBlockNumber
; // The result to be calculated
2949 PRFSD_DISK_NODE_REF pTargetDiskNodeReference
= NULL
; //
2951 // Read in this disk node's data
2952 PUCHAR pBlockBuffer
= RfsdAllocateAndLoadBlock(Vcb
, StartingBlockNumber
);
2954 // Read the block header
2955 PRFSD_BLOCK_HEAD pBlockHeader
= (PRFSD_BLOCK_HEAD
) pBlockBuffer
;
2959 // Sanity check that we could read the block and the header is there
2960 if (!pBlockBuffer
) { return STATUS_INVALID_HANDLE
; }
2962 // If this block is a leaf, just return it (or invoke the given callback on the leaf block)
2963 if (pBlockHeader
->blk_level
== RFSD_LEAF_BLOCK_LEVEL
)
2965 NTSTATUS CallbackStatus
;
2967 ExFreePool(pBlockBuffer
);
2969 *out_NextBlockNumber
= StartingBlockNumber
;
2971 // If a callback should be invoked on finding a matching leaf node, do so...
2972 if (fpDirectoryCallback
) return (*fpDirectoryCallback
)(StartingBlockNumber
, pContext
);
2973 else return STATUS_SUCCESS
;
2976 // Otherwise, find the next node down in the tree, by obtaining pTargetDiskNodeReference
2978 ULONG idxRightKey
= 0;
2979 PRFSD_KEY_ON_DISK pLeftKeyOnDisk
= NULL
;
2980 PRFSD_KEY_ON_DISK pRightKeyOnDisk
= NULL
;
2982 RFSD_KEY_IN_MEMORY LeftKeyInMemory
, RightKeyInMemory
;
2983 RFSD_KEY_COMPARISON leftComparison
, rightComparison
;
2985 RightKeyInMemory
.k_dir_id
= 0; // (Dummy statement to prevent needless warning aboujt using RightKeyInMemory before being initialized)
2987 // Search (within the increasing list of target Keys), for the target key that Key is <= to.
2988 for (idxRightKey
= 0; idxRightKey
<= pBlockHeader
->blk_nr_item
; idxRightKey
++)
2990 // Advance the left key to become what was the right key, and the right key to become the next key
2991 pLeftKeyOnDisk
= pRightKeyOnDisk
;
2992 pRightKeyOnDisk
= (idxRightKey
== pBlockHeader
->blk_nr_item
) ?
2993 (PRFSD_KEY_ON_DISK
) NULL
:
2994 (PRFSD_KEY_ON_DISK
) (pBlockBuffer
+ sizeof(RFSD_BLOCK_HEAD
) + (idxRightKey
* sizeof(RFSD_KEY_ON_DISK
)));
2996 LeftKeyInMemory
= RightKeyInMemory
;
2997 if (pRightKeyOnDisk
)
2998 FillInMemoryKey(pRightKeyOnDisk
, RFSD_KEY_VERSION_UNKNOWN
, &(RightKeyInMemory
));
3001 // Find if the target key falls in the range in between the left and right keys...
3003 // We must be smaller than the right key (if it exists). However, we will allow the key to match if short key comparisons are in use.
3004 rightComparison
= pRightKeyOnDisk
? ((*fpComparisonFunction
)(Key
, &RightKeyInMemory
)) : RFSD_KEY_SMALLER
;
3005 if (fpComparisonFunction
== &CompareShortKeys
)
3006 { if (rightComparison
== RFSD_KEY_LARGER
) continue; }
3008 { if (rightComparison
!= RFSD_KEY_SMALLER
) continue; }
3010 // And larger than or equal to the left key.
3011 leftComparison
= pLeftKeyOnDisk
? ((*fpComparisonFunction
)(Key
, &LeftKeyInMemory
)) : RFSD_KEY_LARGER
;
3012 if ( (leftComparison
== RFSD_KEY_LARGER
) || (leftComparison
== RFSD_KEYS_MATCH
) )
3014 // The target range has been found. Read the reference to the disk node child, lower in the tree.
3015 // This returns the pointer preceding the righthand key.
3016 pTargetDiskNodeReference
= (PRFSD_DISK_NODE_REF
) (pBlockBuffer
3017 + sizeof(RFSD_BLOCK_HEAD
) + (pBlockHeader
->blk_nr_item
* sizeof(RFSD_KEY_ON_DISK
)) + (idxRightKey
* sizeof(RFSD_DISK_NODE_REF
)));
3019 // Continue recursion downwards; eventually a leaf node will be returned.
3020 Status
= _NavigateToLeafNode(
3021 Vcb
, Key
, pTargetDiskNodeReference
->dc_block_number
,
3022 &(leafNodeBlockNumber
),
3023 ReturnOnFirstMatch
, fpComparisonFunction
, fpDirectoryCallback
, pContext
); // <
3025 if (ReturnOnFirstMatch
|| Status
== STATUS_EVENT_DONE
|| // Success cases
3026 Status
== STATUS_INSUFFICIENT_RESOURCES
|| Status
== STATUS_INVALID_HANDLE
) // Error cases
3027 { goto return_results
; }
3035 ExFreePool(pBlockBuffer
);
3036 *out_NextBlockNumber
= leafNodeBlockNumber
;