Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / drivers / filesystems / reiserfs / src / rfsdblock.c
1 /*
2 * COPYRIGHT: GNU GENERAL PUBLIC LICENSE VERSION 2
3 * PROJECT: ReiserFs file system driver for Windows NT/2000/XP/Vista.
4 * FILE: rfsdblock.c
5 * PURPOSE: Disk block operations that are specific to ReiserFS.
6 * PROGRAMMER: Mark Piper, Matt Wu, Bo Brantén.
7 * HOMEPAGE:
8 * UPDATE HISTORY:
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include "rfsd.h"
14
15 /* GLOBALS ***************************************************************/
16
17 extern PRFSD_GLOBAL RfsdGlobal;
18
19 /* DEFINITIONS *************************************************************/
20
21 #ifdef ALLOC_PRAGMA
22 #pragma alloc_text(PAGE, RfsdAllocateAndLoadBlock)
23 #pragma alloc_text(PAGE, RfsdFindItemHeaderInBlock)
24 #pragma alloc_text(PAGE, RfsdLoadItem)
25 #endif
26
27 /* FUNCTIONS *************************************************************/
28
29 /**
30 Returns the address of an allocated buffer (WHICH THE CALLER WILL BE RESPONSIBLE FOR FREEING!), filled with the contents of the given block number on disk.
31 (This is really just an alternative interface to LoadBlock)
32 */
33 PUCHAR
34 RfsdAllocateAndLoadBlock(
35 IN PRFSD_VCB Vcb,
36 IN ULONG BlockIndex) // The ordinal block number to read
37 {
38 // Allocate the return buffer (the caller will be responsible for freeing this!)
39 PUCHAR pReturnBuffer = ExAllocatePoolWithTag(NonPagedPool, Vcb->BlockSize, RFSD_POOL_TAG); // NOTE: for now, I'm switching this to non-paged, because i was getting crashes
40
41 PAGED_CODE();
42
43 if (!pReturnBuffer)
44 { DbgBreak(); return NULL; }
45
46 // Read the block in from disk, or from cache.
47 if (!RfsdLoadBlock(Vcb, BlockIndex, pReturnBuffer))
48 { DbgBreak(); ExFreePool(pReturnBuffer); return NULL; }
49
50 // Return the result to the caller.
51 return pReturnBuffer;
52 }
53
54 /**
55 Finds the item header inside a given leaf node block that matches a given key.
56
57 STATUS_INVALID_HANDLE if the block given to search is invalid
58 STATUS_NO_SUCH_MEMBER if the key is not found in the block given
59 */
60 NTSTATUS
61 RfsdFindItemHeaderInBlock(
62 IN PRFSD_VCB Vcb,
63 IN PRFSD_KEY_IN_MEMORY pTargetKey, // The key to match against
64 IN PUCHAR pBlockBuffer, // A filled disk block, provided by the caller
65 OUT PRFSD_ITEM_HEAD* ppMatchingItemHeader, // A pointer to a PRFSD_ITEM_HEAD. The PRFSD_ITEM_HEAD will point to the item head matching Key, or NULL if there was no such item head in the given block.
66 IN RFSD_KEY_COMPARISON (*fpComparisonFunction)(PRFSD_KEY_IN_MEMORY, PRFSD_KEY_IN_MEMORY)
67 )
68 {
69 // Read the block header
70 PRFSD_BLOCK_HEAD pBlockHeader = (PRFSD_BLOCK_HEAD) pBlockBuffer;
71 PUCHAR pItemHeaderListBuffer = (PUCHAR) pBlockBuffer + sizeof(RFSD_BLOCK_HEAD);
72
73 PAGED_CODE();
74
75 *ppMatchingItemHeader = NULL;
76
77 // Sanity check that the block (and therefore its header) is there
78 if (!pBlockHeader) { return STATUS_INVALID_HANDLE; }
79 ASSERT(pBlockHeader->blk_level == 1);
80
81 // Search through the item headers to find one with a key matching pTargetKey
82 {
83 ULONG idxCurrentItemHeader = 0;
84 PRFSD_ITEM_HEAD pCurrentItemHeader = NULL;
85 RFSD_KEY_IN_MEMORY CurrentItemKey;
86
87 for(idxCurrentItemHeader = 0; idxCurrentItemHeader < pBlockHeader->blk_nr_item; idxCurrentItemHeader++)
88 {
89 // Grab the item header, and its key
90 pCurrentItemHeader = (PRFSD_ITEM_HEAD) (pItemHeaderListBuffer + idxCurrentItemHeader * sizeof(RFSD_ITEM_HEAD));
91
92 FillInMemoryKey(
93 &( pCurrentItemHeader->ih_key ), pCurrentItemHeader->ih_version,
94 &( CurrentItemKey ) ); // <
95
96 // Check if this item is the one being searched for
97 if ( RFSD_KEYS_MATCH == (*fpComparisonFunction)( pTargetKey , &CurrentItemKey ) )
98 {
99 *ppMatchingItemHeader = pCurrentItemHeader;
100 return STATUS_SUCCESS;
101 }
102 }
103
104 // If a matching key was never found, simply return
105 return STATUS_NO_SUCH_MEMBER;
106 }
107 }
108
109 /**
110 Given an item's key, load the block, the item header, and the item buffer associated with the key.
111
112 STATUS_INTERNAL_ERROR if leaf node could not be reached
113 STATUS_NO_SUCH_MEMBER if the item header could not be located
114 STATUS_INSUFFICIENT_RESOURCES if the leaf node buffer could not be allocated
115
116 */
117 NTSTATUS
118 RfsdLoadItem(
119 IN PRFSD_VCB Vcb,
120 IN PRFSD_KEY_IN_MEMORY pItemKey, // The key of the item to find
121 OUT PRFSD_ITEM_HEAD* ppMatchingItemHeader,
122 OUT PUCHAR* ppItemBuffer,
123 OUT PUCHAR* ppBlockBuffer, // Block buffer, which backs the other output data structures. The caller must free this (even in the case of an error)!
124 OPTIONAL OUT PULONG pBlockNumber, // The ordinal disk block number at which the item was found
125 IN RFSD_KEY_COMPARISON (*fpComparisonFunction)(PRFSD_KEY_IN_MEMORY, PRFSD_KEY_IN_MEMORY)
126 )
127 {
128 NTSTATUS Status;
129 ULONG LeafNodeBlockNumber;
130
131 PAGED_CODE();
132
133 // Clear the output pointers
134 *ppItemBuffer = *ppBlockBuffer = NULL;
135 *ppMatchingItemHeader = NULL;
136 if (pBlockNumber) *pBlockNumber = 0;
137
138
139 // Find the block number of the leaf node bock (on disk), that should contain the item w/ pItemKey
140 Status = NavigateToLeafNode(
141 Vcb, pItemKey, Vcb->SuperBlock->s_root_block,
142 &(LeafNodeBlockNumber)
143 );
144 if (!NT_SUCCESS(Status)){ DbgBreak(); return STATUS_INTERNAL_ERROR; }
145 if (pBlockNumber) *pBlockNumber = LeafNodeBlockNumber;
146
147
148 // Load the block (which the caller must later free)
149 *ppBlockBuffer = RfsdAllocateAndLoadBlock(Vcb, LeafNodeBlockNumber);
150 if (!*ppBlockBuffer) { return STATUS_INSUFFICIENT_RESOURCES; }
151
152
153 // Get the item header and its information
154 Status = RfsdFindItemHeaderInBlock(
155 Vcb, pItemKey, *ppBlockBuffer,
156 ( ppMatchingItemHeader ), //<
157 fpComparisonFunction
158 );
159 if (Status == STATUS_NO_SUCH_MEMBER) { return STATUS_NO_SUCH_MEMBER; }
160 if (!*ppMatchingItemHeader) { return STATUS_INTERNAL_ERROR; }
161
162 // Setup the item buffer
163 *ppItemBuffer = (PUCHAR) *ppBlockBuffer + (*ppMatchingItemHeader)->ih_item_location;
164
165 return STATUS_SUCCESS;
166 }