Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / drivers / filesystems / reiserfs / src / rfsd.c
1 /*
2 * COPYRIGHT: GNU GENERAL PUBLIC LICENSE VERSION 2
3 * PROJECT: ReiserFs file system driver for Windows NT/2000/XP/Vista.
4 * FILE: rfsd.c
5 * PURPOSE:
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 // TODO: turn off (turns off warning about returning without return value, so I could easily disable code sections)
16 #ifdef _MSC_VER
17 #pragma warning(disable : 4716)
18 #endif
19
20 /* GLOBALS ***************************************************************/
21
22 extern PRFSD_GLOBAL RfsdGlobal;
23
24 /* DEFINITIONS *************************************************************/
25
26 #ifdef ALLOC_PRAGMA
27 #pragma alloc_text(PAGE, RfsdLoadSuper)
28 #pragma alloc_text(PAGE, RfsdSaveSuper)
29
30 #pragma alloc_text(PAGE, RfsdLoadGroup)
31 #pragma alloc_text(PAGE, RfsdSaveGroup)
32
33 #pragma alloc_text(PAGE, RfsdLoadInode)
34 #pragma alloc_text(PAGE, RfsdSaveInode)
35
36 #pragma alloc_text(PAGE, RfsdLoadBlock)
37 #pragma alloc_text(PAGE, RfsdSaveBlock)
38
39 #pragma alloc_text(PAGE, RfsdSaveBuffer)
40
41 #pragma alloc_text(PAGE, RfsdGetBlock)
42 #pragma alloc_text(PAGE, RfsdBlockMap)
43
44 #pragma alloc_text(PAGE, RfsdBuildBDL)
45 #pragma alloc_text(PAGE, RfsdBuildBDL2)
46
47 #pragma alloc_text(PAGE, RfsdNewBlock)
48 #pragma alloc_text(PAGE, RfsdFreeBlock)
49
50 #pragma alloc_text(PAGE, RfsdExpandBlock)
51 #pragma alloc_text(PAGE, RfsdExpandInode)
52
53 #pragma alloc_text(PAGE, RfsdNewInode)
54 #pragma alloc_text(PAGE, RfsdFreeInode)
55
56 #pragma alloc_text(PAGE, RfsdAddEntry)
57 #pragma alloc_text(PAGE, RfsdRemoveEntry)
58
59 #pragma alloc_text(PAGE, RfsdTruncateBlock)
60 #pragma alloc_text(PAGE, RfsdTruncateInode)
61
62 #pragma alloc_text(PAGE, RfsdAddMcbEntry)
63 #pragma alloc_text(PAGE, RfsdRemoveMcbEntry)
64 #pragma alloc_text(PAGE, RfsdLookupMcbEntry)
65
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)
75 #endif
76
77 /* FUNCTIONS ***************************************************************/
78
79 PRFSD_SUPER_BLOCK
80 RfsdLoadSuper(IN PRFSD_VCB Vcb,
81 IN BOOLEAN bVerify )
82 {
83 NTSTATUS Status;
84 PRFSD_SUPER_BLOCK RfsdSb = NULL;
85
86 PAGED_CODE();
87
88 RfsdSb = (PRFSD_SUPER_BLOCK) ExAllocatePoolWithTag(PagedPool,
89 SUPER_BLOCK_SIZE, RFSD_POOL_TAG);
90 if (!RfsdSb) {
91 return NULL;
92 }
93
94 Status = RfsdReadDisk(
95 Vcb,
96 (ULONGLONG) SUPER_BLOCK_OFFSET,
97 SUPER_BLOCK_SIZE,
98 (PVOID) RfsdSb,
99 bVerify );
100
101 if (!NT_SUCCESS(Status)) {
102
103 RfsdPrint((DBG_ERROR, "RfsdReadDisk: Read Block Device error.\n"));
104
105 ExFreePool(RfsdSb);
106 return NULL;
107 }
108
109 return RfsdSb;
110 }
111
112 #if 0
113
114 BOOLEAN
115 RfsdSaveSuper( IN PRFSD_IRP_CONTEXT IrpContext,
116 IN PRFSD_VCB Vcb )
117 {
118 DbgBreak();
119 #if DISABLED
120 LONGLONG Offset;
121 BOOLEAN bRet;
122
123 Offset = (LONGLONG) SUPER_BLOCK_OFFSET;
124
125 bRet = RfsdSaveBuffer( IrpContext,
126 Vcb,
127 Offset,
128 SUPER_BLOCK_SIZE,
129 Vcb->SuperBlock );
130
131 if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
132 RfsdStartFloppyFlushDpc(Vcb, NULL, NULL);
133 }
134
135 return bRet;
136 #endif
137 }
138
139 #if DISABLED
140 BOOLEAN
141 RfsdLoadGroup(IN PRFSD_VCB Vcb)
142 {
143 ULONG Size;
144 PVOID Buffer;
145 LONGLONG Lba;
146 NTSTATUS Status;
147
148 PRFSD_SUPER_BLOCK sb;
149
150 sb = Vcb->SuperBlock;
151
152 Vcb->BlockSize = RFSD_MIN_BLOCK << sb->s_log_block_size;
153 Vcb->SectorBits = RfsdLog2(SECTOR_SIZE);
154 ASSERT(BLOCK_BITS == RfsdLog2(BLOCK_SIZE));
155
156 Vcb->NumOfGroups = (sb->s_blocks_count - sb->s_first_data_block +
157 sb->s_blocks_per_group - 1) / sb->s_blocks_per_group;
158
159 Size = sizeof(RFSD_GROUP_DESC) * Vcb->NumOfGroups;
160
161 if (Vcb->BlockSize == RFSD_MIN_BLOCK) {
162 Lba = (LONGLONG)2 * Vcb->BlockSize;
163 }
164
165 if (Vcb->BlockSize > RFSD_MIN_BLOCK) {
166 Lba = (LONGLONG) (Vcb->BlockSize);
167 }
168
169 if (Lba == 0) {
170 return FALSE;
171 }
172
173 Buffer = ExAllocatePoolWithTag(PagedPool, Size, RFSD_POOL_TAG);
174 if (!Buffer) {
175 RfsdPrint((DBG_ERROR, "RfsdLoadSuper: no enough memory.\n"));
176 return FALSE;
177 }
178
179 RfsdPrint((DBG_USER, "RfsdLoadGroup: Lba=%I64xh Size=%xh\n", Lba, Size));
180
181 Status = RfsdReadDisk( Vcb,
182 Lba,
183 Size,
184 Buffer,
185 FALSE );
186
187 if (!NT_SUCCESS(Status)) {
188 ExFreePool(Buffer);
189 Buffer = NULL;
190
191 return FALSE;
192 }
193
194 /*
195 bPinned = CcPinRead(
196 Vcb->StreamObj,
197 Lba,
198 Size,
199 PIN_WAIT,
200 &(Vcb->GroupDescBcb),
201 &(Buffer));
202
203 if (!bPinned)
204 {
205 Vcb->GroupDesc = NULL;
206 return FALSE;
207 }
208 */
209
210 Vcb->GroupDesc = (PRFSD_GROUP_DESC) Buffer;
211
212 return TRUE;
213 }
214
215 BOOLEAN
216 RfsdSaveGroup( IN PRFSD_IRP_CONTEXT IrpContext,
217 IN PRFSD_VCB Vcb,
218 IN ULONG Group )
219 {
220 LONGLONG Offset;
221 BOOLEAN bRet;
222
223 if (Vcb->BlockSize == RFSD_MIN_BLOCK) {
224
225 Offset = (LONGLONG) (2 * Vcb->BlockSize);
226
227 } else {
228
229 Offset = (LONGLONG) (Vcb->BlockSize);
230 }
231
232 Offset += ((LONGLONG) sizeof(struct rfsd_group_desc) * Group);
233
234 bRet = RfsdSaveBuffer(
235 IrpContext,
236 Vcb,
237 Offset,
238 sizeof(struct rfsd_group_desc),
239 &(Vcb->GroupDesc[Group]) );
240
241 if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
242 RfsdStartFloppyFlushDpc(Vcb, NULL, NULL);
243 }
244
245 return bRet;
246 }
247 #endif
248
249 #endif // 0
250
251 /** Reads an inode structure off disk into the Inode object (which has been allocated, but not filled with any data) */
252 BOOLEAN
253 RfsdLoadInode (IN PRFSD_VCB Vcb,
254 IN PRFSD_KEY_IN_MEMORY pKey,
255 IN OUT PRFSD_INODE Inode)
256 {
257 NTSTATUS Status;
258
259 PRFSD_ITEM_HEAD pItemHeader = NULL;
260 PUCHAR pItemBuffer = NULL;
261 PUCHAR pBlockBuffer = NULL;
262
263 // Crate the target key for the stat item (stat items always have an offset of 0)
264 RFSD_KEY_IN_MEMORY TargetKey;
265
266 PAGED_CODE();
267
268 TargetKey = *pKey;
269 TargetKey.k_offset = 0x0;
270 TargetKey.k_type = RFSD_KEY_TYPE_v2_STAT_DATA;
271
272 RfsdPrint((DBG_FUNC, /*__FUNCTION__*/ "on %i, %i\n", TargetKey.k_dir_id, TargetKey.k_objectid));
273
274 //Load the stat data
275 Status = RfsdLoadItem(Vcb, &TargetKey,
276 &(pItemHeader), &(pItemBuffer), &(pBlockBuffer), NULL, //<
277 &CompareKeys
278 );
279 if (!NT_SUCCESS(Status))
280 { if (pBlockBuffer) {ExFreePool(pBlockBuffer);} return FALSE; }
281
282 // Copy the item into the inode / stat data structure
283 RtlCopyMemory(Inode, pItemBuffer, sizeof(RFSD_INODE));
284
285 // Cleanup
286 if (pBlockBuffer)
287 ExFreePool(pBlockBuffer);
288
289 return TRUE;
290 }
291
292 #if 0
293
294 BOOLEAN
295 RfsdSaveInode ( IN PRFSD_IRP_CONTEXT IrpContext,
296 IN PRFSD_VCB Vcb,
297 IN ULONG Inode,
298 IN PRFSD_INODE RfsdInode)
299 {
300 DbgBreak();
301 #if DISABLED
302 LONGLONG Offset = 0;
303 LARGE_INTEGER CurrentTime;
304 BOOLEAN bRet;
305
306 KeQuerySystemTime(&CurrentTime);
307 RfsdInode->i_mtime = RfsdInode->i_atime =
308 (ULONG)(RfsdInodeTime(CurrentTime));
309
310 RfsdPrint((DBG_INFO, "RfsdSaveInode: Saving Inode %xh: Mode=%xh Size=%xh\n",
311 Inode, RfsdInode->i_mode, RfsdInode->i_size));
312
313 if (!RfsdGetInodeLba(Vcb, Inode, &Offset)) {
314 RfsdPrint((DBG_ERROR, "RfsdSaveInode: error get inode(%xh)'s addr.\n", Inode));
315 return FALSE;
316 }
317
318 bRet = RfsdSaveBuffer(IrpContext, Vcb, Offset, sizeof(RFSD_INODE), RfsdInode);
319
320 if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
321 RfsdStartFloppyFlushDpc(Vcb, NULL, NULL);
322 }
323
324 return bRet;
325 #endif
326 }
327
328 #endif // 0
329
330 /** Just reads a block into a buffer */
331 BOOLEAN
332 RfsdLoadBlock (
333 IN PRFSD_VCB Vcb,
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
336 {
337 IO_STATUS_BLOCK IoStatus;
338 LONGLONG Offset;
339
340 PAGED_CODE();
341
342 Offset = (LONGLONG) dwBlk;
343 Offset = Offset * Vcb->BlockSize;
344
345 if (!RfsdCopyRead(
346 Vcb->StreamObj,
347 (PLARGE_INTEGER)&Offset,
348 Vcb->BlockSize,
349 PIN_WAIT,
350 Buffer,
351 &IoStatus )) {
352 return FALSE;
353 }
354
355 if (!NT_SUCCESS(IoStatus.Status)) {
356 return FALSE;
357 }
358
359 return TRUE;
360 }
361
362 #if 0
363
364 BOOLEAN
365 RfsdSaveBlock ( IN PRFSD_IRP_CONTEXT IrpContext,
366 IN PRFSD_VCB Vcb,
367 IN ULONG dwBlk,
368 IN PVOID Buf )
369 {
370 DbgBreak();
371 #if DISABLED
372 LONGLONG Offset;
373 BOOLEAN bRet;
374
375 Offset = (LONGLONG) dwBlk;
376 Offset = Offset * Vcb->BlockSize;
377
378 bRet = RfsdSaveBuffer(IrpContext, Vcb, Offset, Vcb->BlockSize, Buf);
379
380 if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
381 RfsdStartFloppyFlushDpc(Vcb, NULL, NULL);
382 }
383
384 return bRet;
385 #endif
386 }
387
388 BOOLEAN
389 RfsdSaveBuffer( IN PRFSD_IRP_CONTEXT IrpContext,
390 IN PRFSD_VCB Vcb,
391 IN LONGLONG Offset,
392 IN ULONG Size,
393 IN PVOID Buf )
394 {
395 PBCB Bcb;
396 PVOID Buffer;
397 BOOLEAN bRet;
398
399 PAGED_CODE();
400
401 if( !CcPinRead( Vcb->StreamObj,
402 (PLARGE_INTEGER) (&Offset),
403 Size,
404 PIN_WAIT,
405 &Bcb,
406 &Buffer )) {
407
408 RfsdPrint((DBG_ERROR, "RfsdSaveBuffer: PinReading error ...\n"));
409 return FALSE;
410 }
411
412 _SEH2_TRY {
413
414 RtlCopyMemory(Buffer, Buf, Size);
415 CcSetDirtyPinnedData(Bcb, NULL );
416 RfsdRepinBcb(IrpContext, Bcb);
417
418 SetFlag(Vcb->StreamObj->Flags, FO_FILE_MODIFIED);
419
420 RfsdAddMcbEntry(Vcb, Offset, (LONGLONG)Size);
421
422 bRet = TRUE;
423
424 } _SEH2_FINALLY {
425
426 if (AbnormalTermination()) {
427
428 CcUnpinData(Bcb);
429 bRet = FALSE;
430 }
431 } _SEH2_END;
432
433 CcUnpinData(Bcb);
434
435 return bRet;
436 }
437
438 NTSTATUS
439 RfsdGetBlock(
440 IN PRFSD_IRP_CONTEXT IrpContext,
441 IN PRFSD_VCB Vcb,
442 IN ULONG dwContent, // A ptr to a disk block (disk block number)
443 IN ULONG Index,
444 IN ULONG Layer,
445 IN BOOLEAN bAlloc,
446 OUT PULONG pBlock
447 )
448 {
449 DbgBreak();
450 #if DISABLED
451 NTSTATUS Status = STATUS_SUCCESS;
452 ULONG *pData = NULL;
453 ULONG i = 0, j = 0, temp = 1;
454 ULONG dwRet = 0;
455 ULONG dwBlk = 0;
456
457 if (Layer == 0) {
458
459 dwRet = dwContent;
460
461 } else if (Layer <= 3) {
462
463 /* allocate memory for pData to contain the block */
464 pData = (ULONG *) ExAllocatePoolWithTag(NonPagedPool, Vcb->BlockSize, RFSD_POOL_TAG);
465 if (!pData) {
466 RfsdPrint((DBG_ERROR, "RfsdGetBlock: no enough memory.\n"));
467 Status = STATUS_INSUFFICIENT_RESOURCES;
468 goto errorout;
469 }
470
471 /* load the block dwContext into pData buffer */
472 if (!RfsdLoadBlock(Vcb, dwContent, pData)) {
473 ExFreePool(pData);
474 Status = STATUS_INSUFFICIENT_RESOURCES;
475 goto errorout;
476 }
477
478 temp = 1 << ((BLOCK_BITS - 2) * (Layer - 1));
479
480 i = Index / temp;
481 j = Index % temp;
482
483 dwBlk = pData[i];
484
485 #if DISABLED // WRITE MODE ONLY
486 if (dwBlk ==0 ) {
487
488 if (bAlloc) {
489
490 DbgBreak();
491
492 /* we need allocate new block: dwBlk */
493
494 Status = RfsdNewBlock(
495 IrpContext,
496 Vcb,
497 0,
498 dwContent,
499 &dwBlk
500 );
501
502 if (!NT_SUCCESS(Status)) {
503 ExFreePool(pData);
504 goto errorout;
505 }
506
507 /* we need save pData now */
508 pData[i] = dwBlk;
509
510 /* save the block first, before next call */
511 if (!RfsdSaveBlock( IrpContext, Vcb,
512 dwContent, pData)) {
513
514 /* error occurs when saving the block */
515 Status = STATUS_INSUFFICIENT_RESOURCES;
516
517 /* we need free newly allocated block */
518 RfsdFreeBlock(IrpContext, Vcb, dwBlk);
519
520 /* free the memory of pData */
521 ExFreePool(pData);
522
523 goto errorout;
524 }
525
526 } else {
527
528 /* free the memory of pData */
529 ExFreePool(pData);
530
531 goto errorout;
532 }
533 }
534 #endif
535
536 /* free the memory of pData */
537 ExFreePool(pData);
538
539 /* transfer to next recursion call */
540 Status = RfsdGetBlock(
541 IrpContext,
542 Vcb,
543 dwBlk,
544 j,
545 Layer - 1,
546 bAlloc,
547 &dwRet
548 );
549
550 if (!NT_SUCCESS(Status)) {
551 dwRet = 0;
552 }
553 }
554
555 errorout:
556
557 *pBlock = dwRet;
558
559 return Status;
560 #endif
561 }
562
563 /** I think this means it maps the blocks into the cache.
564 Basically, it goes through and calls GetBlock for each block.
565 */
566 NTSTATUS
567 RfsdBlockMap(
568 IN PRFSD_IRP_CONTEXT IrpContext,
569 IN PRFSD_VCB Vcb,
570 IN ULONG InodeNo,
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 // <
575 )
576 {
577 DbgBreak();
578 #if DISABLED
579 ULONG i;
580
581 ULONG dwSizes[RFSD_BLOCK_TYPES];
582 NTSTATUS Status = STATUS_SUCCESS;;
583
584 *pBlock = 0;
585
586 for (i = 0; i < RFSD_BLOCK_TYPES; i++) {
587 dwSizes[i] = Vcb->dwData[i];
588 }
589
590 for (i = 0; i < RFSD_BLOCK_TYPES; i++) {
591
592 if (Index < dwSizes[i]) {
593
594 ULONG dwRet = 0;
595 ULONG dwBlk = 0;
596
597 // dwBlk will get the ptr to a block.
598 dwBlk = Inode->i_block[i==0 ? (Index):(i + RFSD_NDIR_BLOCKS - 1)];
599
600 #if DISABLED // WRITE MODE ONLY
601 if (dwBlk == 0) {
602
603 if (!bAlloc) {
604
605 goto errorout;
606
607 } else {
608
609 DbgBreak();
610
611 /* we need allocate new block: dwBlk */
612 Status = RfsdNewBlock(
613 IrpContext,
614 Vcb,
615 (InodeNo - 1) / BLOCKS_PER_GROUP,
616 0,
617 &dwBlk
618 );
619
620 if (!NT_SUCCESS(Status)) {
621 goto errorout;
622 }
623
624 /* save the it into inode*/
625 Inode->i_block[i==0 ? (Index):(i + RFSD_NDIR_BLOCKS - 1)] = dwBlk;
626
627 /* save the inode */
628 if (!RfsdSaveInode( IrpContext,
629 Vcb,
630 InodeNo,
631 Inode)) {
632
633 Status = STATUS_UNSUCCESSFUL;
634
635 RfsdFreeBlock(IrpContext, Vcb, dwBlk);
636
637 goto errorout;
638 }
639 }
640 }
641 #endif
642 Status = RfsdGetBlock(
643 IrpContext,
644 Vcb,
645 dwBlk,
646 Index,
647 i,
648 bAlloc,
649 &dwRet //<
650 );
651
652 RfsdPrint((DBG_INFO, "RfsdBlockMap: i=%xh index=%xh dwBlk=%xh (%xh)\n",
653 i, Index, dwRet, dwBlk));
654
655 if (NT_SUCCESS(Status)) {
656 *pBlock = dwRet;
657 }
658
659 break;
660 }
661
662 Index -= dwSizes[i];
663 }
664
665 errorout:
666
667 return Status;
668 #endif
669 }
670
671 #endif // 0
672
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).
674 NTSTATUS
675 RfsdBuildBDL2(
676 IN PRFSD_VCB Vcb,
677 IN PRFSD_KEY_IN_MEMORY pKey,
678 IN PRFSD_INODE pInode,
679 OUT PULONG out_Count,
680 OUT PRFSD_BDL* out_ppBdl )
681 {
682 NTSTATUS Status = STATUS_SUCCESS;
683 BOOLEAN done = FALSE;
684
685 RFSD_KEY_IN_MEMORY CurrentTargetKey = *pKey;
686 ULONGLONG CurrentOffset = 0;
687
688 PRFSD_ITEM_HEAD pItemHeader = NULL; // The temporary storage for retrieving items from disk
689 PUCHAR pItemBuffer = NULL;
690 PUCHAR pBlockBuffer = NULL;
691
692 ULONG idxCurrentBD = 0;
693 PRFSD_BDL pBdl = NULL; // The block descriptor list, which will be allocated, filled, and assigned to out_Bdl
694
695 PAGED_CODE();
696
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));
705
706
707 // Build descriptors for all of the indirect items associated with the file
708 while (!done)
709 {
710 // Search for an indirect item, corresponding to CurrentOffset...
711
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;
715
716 // Perform the search
717 Status = RfsdLoadItem(
718 Vcb, &CurrentTargetKey,
719 &(pItemHeader), &(pItemBuffer), &(pBlockBuffer), NULL,
720 &CompareKeys
721 );
722
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; }
726
727 // Otherwise, create a block descriptor for each pointer in the indirect item
728 {
729 ULONG countBlockRefs = pItemHeader->ih_item_len / sizeof(ULONG);
730 ULONG idxBlockRef;
731
732 for (idxBlockRef = 0; idxBlockRef < countBlockRefs; idxBlockRef++)
733 {
734 PULONG BlockRef = (PULONG) ((PUCHAR) pItemBuffer + sizeof(ULONG) * idxBlockRef);
735
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;
740
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;
745
746 // Advance to the next block reference
747 CurrentOffset += Vcb->BlockSize;
748 idxCurrentBD++;
749 }
750
751 if (countBlockRefs <= 0) { done = TRUE; }
752 }
753
754 if (pBlockBuffer) { ExFreePool(pBlockBuffer); pBlockBuffer = NULL; }
755 }
756
757 // Cleanup the last remaining block buffer, from the indirect items
758 if (pBlockBuffer) { ExFreePool(pBlockBuffer); pBlockBuffer = NULL; }
759
760 // Search for the tail of the file (its optional direct item), corresponding to CurrentOffset...
761 {
762 ULONG BlockNumber = 0;
763
764 // Create the key to search for
765 CurrentTargetKey.k_offset = CurrentOffset + 1;
766 CurrentTargetKey.k_type = RFSD_KEY_TYPE_v2_DIRECT;
767
768 // Perform the search
769 Status = RfsdLoadItem(
770 Vcb, &CurrentTargetKey,
771 &(pItemHeader), &(pItemBuffer), &(pBlockBuffer), &(BlockNumber),
772 &CompareKeys
773 );
774
775 if (Status == STATUS_SUCCESS)
776 {
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;
781
782 // Advance to the next block reference
783 CurrentOffset += pItemHeader->ih_item_len;
784 idxCurrentBD++;
785 }
786 else
787 {
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.
790 }
791 }
792
793 if (pBlockBuffer) { ExFreePool(pBlockBuffer); pBlockBuffer = NULL; }
794
795 // Search for the second part of the tail of the file (its optional second direct item), corresponding to CurrentOffset...
796 {
797 ULONG BlockNumber = 0;
798
799 // Create the key to search for
800 CurrentTargetKey.k_offset = CurrentOffset + 1;
801 CurrentTargetKey.k_type = RFSD_KEY_TYPE_v2_DIRECT;
802
803 // Perform the search
804 Status = RfsdLoadItem(
805 Vcb, &CurrentTargetKey,
806 &(pItemHeader), &(pItemBuffer), &(pBlockBuffer), &(BlockNumber),
807 &CompareKeys
808 );
809
810 if (Status == STATUS_SUCCESS)
811 {
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;
816
817 idxCurrentBD++;
818 }
819 else
820 {
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.
823 }
824 }
825
826 errorout:
827 if (pBlockBuffer) { ExFreePool(pBlockBuffer); pBlockBuffer = NULL; }
828
829 *out_ppBdl = pBdl;
830 *out_Count = idxCurrentBD;
831 return Status;
832 }
833
834 #if 0
835
836 NTSTATUS
837 RfsdNewBlock(
838 PRFSD_IRP_CONTEXT IrpContext,
839 PRFSD_VCB Vcb,
840 ULONG GroupHint,
841 ULONG BlockHint,
842 PULONG dwRet )
843 {
844 DbgBreak();
845 #if DISABLED
846 RTL_BITMAP BlockBitmap;
847 LARGE_INTEGER Offset;
848 ULONG Length;
849
850 PBCB BitmapBcb;
851 PVOID BitmapCache;
852
853 ULONG Group = 0, dwBlk, dwHint = 0;
854
855 *dwRet = 0;
856 dwBlk = 0XFFFFFFFF;
857
858 if (GroupHint > Vcb->NumOfGroups)
859 GroupHint = Vcb->NumOfGroups - 1;
860
861 if (BlockHint != 0) {
862 GroupHint = (BlockHint - RFSD_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
863 dwHint = (BlockHint - RFSD_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
864 }
865
866 ScanBitmap:
867
868 // Perform Prefered Group
869 if (Vcb->GroupDesc[GroupHint].bg_free_blocks_count) {
870
871 Offset.QuadPart = (LONGLONG) Vcb->BlockSize;
872 Offset.QuadPart = Offset.QuadPart *
873 Vcb->GroupDesc[GroupHint].bg_block_bitmap;
874
875 if (GroupHint == Vcb->NumOfGroups - 1) {
876
877 Length = TOTAL_BLOCKS % BLOCKS_PER_GROUP;
878
879 /* s_blocks_count is integer multiple of s_blocks_per_group */
880 if (Length == 0) {
881 Length = BLOCKS_PER_GROUP;
882 }
883 } else {
884 Length = BLOCKS_PER_GROUP;
885 }
886
887 if (!CcPinRead( Vcb->StreamObj,
888 &Offset,
889 Vcb->BlockSize,
890 PIN_WAIT,
891 &BitmapBcb,
892 &BitmapCache ) ) {
893
894 RfsdPrint((DBG_ERROR, "RfsdNewBlock: PinReading error ...\n"));
895 return STATUS_INSUFFICIENT_RESOURCES;
896 }
897
898 RtlInitializeBitMap( &BlockBitmap,
899 BitmapCache,
900 Length );
901
902 Group = GroupHint;
903
904 if (RtlCheckBit(&BlockBitmap, dwHint) == 0) {
905 dwBlk = dwHint;
906 } else {
907 dwBlk = RtlFindClearBits(&BlockBitmap, 1, dwHint);
908 }
909
910 // We could not get new block in the prefered group.
911 if (dwBlk == 0xFFFFFFFF) {
912
913 CcUnpinData(BitmapBcb);
914 BitmapBcb = NULL;
915 BitmapCache = NULL;
916
917 RtlZeroMemory(&BlockBitmap, sizeof(RTL_BITMAP));
918 }
919 }
920
921 if (dwBlk == 0xFFFFFFFF) {
922
923 for(Group = 0; Group < Vcb->NumOfGroups; Group++)
924 if (Vcb->GroupDesc[Group].bg_free_blocks_count) {
925 if (Group == GroupHint)
926 continue;
927
928 Offset.QuadPart = (LONGLONG) Vcb->BlockSize;
929 Offset.QuadPart = Offset.QuadPart * Vcb->GroupDesc[Group].bg_block_bitmap;
930
931 if (Vcb->NumOfGroups == 1) {
932 Length = TOTAL_BLOCKS;
933 } else {
934 if (Group == Vcb->NumOfGroups - 1) {
935
936 Length = TOTAL_BLOCKS % BLOCKS_PER_GROUP;
937
938 /* s_blocks_count is integer multiple of s_blocks_per_group */
939 if (Length == 0) {
940 Length = BLOCKS_PER_GROUP;
941 }
942 } else {
943 Length = BLOCKS_PER_GROUP;
944 }
945 }
946
947 if (!CcPinRead( Vcb->StreamObj,
948 &Offset,
949 Vcb->BlockSize,
950 PIN_WAIT,
951 &BitmapBcb,
952 &BitmapCache ) ) {
953 RfsdPrint((DBG_ERROR, "RfsdNewBlock: PinReading error ...\n"));
954 return STATUS_INSUFFICIENT_RESOURCES;
955 }
956
957 RtlInitializeBitMap( &BlockBitmap,
958 BitmapCache,
959 Length );
960
961 dwBlk = RtlFindClearBits(&BlockBitmap, 1, 0);
962
963 if (dwBlk != 0xFFFFFFFF) {
964 break;
965
966 } else {
967
968 CcUnpinData(BitmapBcb);
969 BitmapBcb = NULL;
970 BitmapCache = NULL;
971
972 RtlZeroMemory(&BlockBitmap, sizeof(RTL_BITMAP));
973 }
974 }
975 }
976
977 if (dwBlk < Length) {
978
979 RtlSetBits(&BlockBitmap, dwBlk, 1);
980
981 CcSetDirtyPinnedData(BitmapBcb, NULL );
982
983 RfsdRepinBcb(IrpContext, BitmapBcb);
984
985 CcUnpinData(BitmapBcb);
986
987 RfsdAddMcbEntry(Vcb, Offset.QuadPart, (LONGLONG)Vcb->BlockSize);
988
989 *dwRet = dwBlk + RFSD_FIRST_DATA_BLOCK + Group * BLOCKS_PER_GROUP;
990
991 //Updating Group Desc / Superblock
992 Vcb->GroupDesc[Group].bg_free_blocks_count--;
993 RfsdSaveGroup(IrpContext, Vcb, Group);
994
995 Vcb->SuperBlock->s_free_blocks_count--;
996 RfsdSaveSuper(IrpContext, Vcb);
997
998 {
999 ULONG i=0;
1000 for (i=0; i < Vcb->NumOfGroups; i++)
1001 {
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) ) {
1005 DbgBreak();
1006 GroupHint = Group;
1007 goto ScanBitmap;
1008 }
1009 }
1010 }
1011
1012 return STATUS_SUCCESS;
1013 }
1014
1015 return STATUS_DISK_FULL;
1016 #endif
1017 }
1018
1019 NTSTATUS
1020 RfsdFreeBlock(
1021 PRFSD_IRP_CONTEXT IrpContext,
1022 PRFSD_VCB Vcb,
1023 ULONG Block )
1024 {
1025 DbgBreak();
1026 #if DISABLED
1027
1028 RTL_BITMAP BlockBitmap;
1029 LARGE_INTEGER Offset;
1030 ULONG Length;
1031
1032 PBCB BitmapBcb;
1033 PVOID BitmapCache;
1034
1035 ULONG Group, dwBlk;
1036 BOOLEAN bModified = FALSE;
1037
1038 if ( Block < RFSD_FIRST_DATA_BLOCK ||
1039 (Block / BLOCKS_PER_GROUP) >= Vcb->NumOfGroups) {
1040
1041 DbgBreak();
1042 return STATUS_INVALID_PARAMETER;
1043 }
1044
1045 RfsdPrint((DBG_INFO, "RfsdFreeBlock: Block %xh to be freed.\n", Block));
1046
1047 Group = (Block - RFSD_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
1048
1049 dwBlk = (Block - RFSD_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
1050
1051 {
1052 Offset.QuadPart = (LONGLONG) Vcb->BlockSize;
1053 Offset.QuadPart = Offset.QuadPart * Vcb->GroupDesc[Group].bg_block_bitmap;
1054
1055 if (Group == Vcb->NumOfGroups - 1) {
1056
1057 Length = TOTAL_BLOCKS % BLOCKS_PER_GROUP;
1058
1059 /* s_blocks_count is integer multiple of s_blocks_per_group */
1060 if (Length == 0) {
1061 Length = BLOCKS_PER_GROUP;
1062 }
1063
1064 } else {
1065 Length = BLOCKS_PER_GROUP;
1066 }
1067
1068 if (!CcPinRead( Vcb->StreamObj,
1069 &Offset,
1070 Vcb->BlockSize,
1071 PIN_WAIT,
1072 &BitmapBcb,
1073 &BitmapCache ) ) {
1074
1075 RfsdPrint((DBG_ERROR, "RfsdDeleteBlock: PinReading error ...\n"));
1076 return STATUS_INSUFFICIENT_RESOURCES;
1077 }
1078
1079 RtlInitializeBitMap( &BlockBitmap,
1080 BitmapCache,
1081 Length );
1082
1083 if (RtlCheckBit(&BlockBitmap, dwBlk) == 0) {
1084
1085 } else {
1086 RtlClearBits(&BlockBitmap, dwBlk, 1);
1087 bModified = TRUE;
1088 }
1089
1090 if (!bModified) {
1091
1092 CcUnpinData(BitmapBcb);
1093 BitmapBcb = NULL;
1094 BitmapCache = NULL;
1095
1096 RtlZeroMemory(&BlockBitmap, sizeof(RTL_BITMAP));
1097 }
1098 }
1099
1100 if (bModified) {
1101
1102 CcSetDirtyPinnedData(BitmapBcb, NULL );
1103
1104 RfsdRepinBcb(IrpContext, BitmapBcb);
1105
1106 CcUnpinData(BitmapBcb);
1107
1108 RfsdAddMcbEntry(Vcb, Offset.QuadPart, (LONGLONG)Vcb->BlockSize);
1109
1110 //Updating Group Desc / Superblock
1111 Vcb->GroupDesc[Group].bg_free_blocks_count++;
1112 RfsdSaveGroup(IrpContext, Vcb, Group);
1113
1114 Vcb->SuperBlock->s_free_blocks_count++;
1115 RfsdSaveSuper(IrpContext, Vcb);
1116
1117 return STATUS_SUCCESS;
1118 }
1119
1120 return STATUS_UNSUCCESSFUL;
1121 #endif
1122 }
1123
1124 NTSTATUS
1125 RfsdExpandBlock(
1126 PRFSD_IRP_CONTEXT IrpContext,
1127 PRFSD_VCB Vcb,
1128 PRFSD_FCB Fcb,
1129 ULONG dwContent,
1130 ULONG Index,
1131 ULONG layer,
1132 BOOLEAN bNew,
1133 ULONG *dwRet )
1134 {
1135 DbgBreak();
1136 #if DISABLED
1137
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;
1143
1144 PRFSD_INODE Inode = Fcb->Inode;
1145 PRFSD_SUPER_BLOCK RfsdSb = Vcb->SuperBlock;
1146
1147 pData = (ULONG *) ExAllocatePoolWithTag(PagedPool, Vcb->BlockSize, RFSD_POOL_TAG);
1148
1149 if (!pData) {
1150 return STATUS_INSUFFICIENT_RESOURCES;
1151 }
1152
1153 RtlZeroMemory(pData, Vcb->BlockSize);
1154
1155 if (bNew) {
1156
1157 if (layer == 0) {
1158
1159 if (IsDirectory(Fcb)) {
1160
1161 PRFSD_DIR_ENTRY2 pEntry;
1162
1163 pEntry = (PRFSD_DIR_ENTRY2) pData;
1164 pEntry->rec_len = (USHORT)(Vcb->BlockSize);
1165
1166 if (!RfsdSaveBlock(IrpContext, Vcb, dwContent, (PVOID)pData)) {
1167
1168 Status = STATUS_UNSUCCESSFUL;
1169 goto errorout;
1170 }
1171
1172 } else {
1173
1174 LARGE_INTEGER Offset;
1175
1176 Offset.QuadPart = (LONGLONG) dwContent;
1177 Offset.QuadPart = Offset.QuadPart * Vcb->BlockSize;
1178
1179 RfsdRemoveMcbEntry(Vcb, Offset.QuadPart, (LONGLONG)Vcb->BlockSize);
1180 }
1181 } else {
1182
1183 if (!RfsdSaveBlock(IrpContext, Vcb, dwContent, (PVOID)pData)) {
1184
1185 Status = STATUS_UNSUCCESSFUL;
1186 goto errorout;
1187 }
1188 }
1189 }
1190
1191 if (layer == 0) {
1192
1193 dwNewBlk = dwContent;
1194
1195 } else if (layer <= 3) {
1196
1197 if (!bNew) {
1198
1199 if (!RfsdLoadBlock(Vcb, dwContent, (void *)pData)) {
1200
1201 Status = STATUS_UNSUCCESSFUL;
1202 goto errorout;
1203 }
1204 }
1205
1206 temp = 1 << ((BLOCK_BITS - 2) * (layer - 1));
1207
1208 i = Index / temp;
1209 j = Index % temp;
1210
1211 dwBlk = pData[i];
1212
1213 if (dwBlk == 0) {
1214
1215 Status = RfsdNewBlock(
1216 IrpContext,
1217 Vcb, 0,
1218 dwContent,
1219 &dwBlk);
1220
1221 if (!NT_SUCCESS(Status)) {
1222
1223 RfsdPrint((DBG_ERROR, "RfsdExpandBlock: get new block error.\n"));
1224 goto errorout;
1225 }
1226
1227 Inode->i_blocks += (Vcb->BlockSize / SECTOR_SIZE);
1228
1229 pData[i] = dwBlk;
1230 bDirty = TRUE;
1231 }
1232
1233 Status = RfsdExpandBlock(
1234 IrpContext,
1235 Vcb, Fcb,
1236 dwBlk, j,
1237 layer - 1,
1238 bDirty,
1239 &dwNewBlk );
1240
1241 if (!NT_SUCCESS(Status))
1242 {
1243 RfsdPrint((DBG_ERROR, "RfsdExpandBlockk: ... error recuise...\n"));
1244 goto errorout;
1245 }
1246
1247 if (bDirty)
1248 {
1249 RfsdSaveBlock( IrpContext,
1250 Vcb, dwContent,
1251 (void *)pData );
1252 }
1253 }
1254
1255 errorout:
1256
1257 if (pData)
1258 ExFreePool(pData);
1259
1260 if (NT_SUCCESS(Status) && dwRet)
1261 *dwRet = dwNewBlk;
1262
1263 return Status;
1264 #endif
1265 }
1266
1267 NTSTATUS
1268 RfsdExpandInode(
1269 IN PRFSD_IRP_CONTEXT IrpContext,
1270 IN PRFSD_VCB Vcb,
1271 IN PRFSD_FCB Fcb,
1272 OUT PULONG dwRet
1273 )
1274 {
1275 DbgBreak();
1276 #if DISABLED
1277
1278 ULONG dwSizes[RFSD_BLOCK_TYPES];
1279 ULONG Index = 0;
1280 ULONG dwTotal = 0;
1281 ULONG dwBlk = 0, dwNewBlk = 0;
1282 ULONG i;
1283 NTSTATUS Status = STATUS_SUCCESS;
1284 BOOLEAN bNewBlock = FALSE;
1285
1286 PRFSD_INODE Inode = Fcb->Inode;
1287
1288 Index = (ULONG)(Fcb->Header.AllocationSize.QuadPart >> BLOCK_BITS);
1289
1290 for (i = 0; i < RFSD_BLOCK_TYPES; i++) {
1291 dwSizes[i] = Vcb->dwData[i];
1292 dwTotal += dwSizes[i];
1293 }
1294
1295 if (Index >= dwTotal) {
1296
1297 RfsdPrint((DBG_ERROR, "RfsdExpandInode: beyond the maxinum size of an inode.\n"));
1298 return STATUS_UNSUCCESSFUL;
1299 }
1300
1301 for (i = 0; i < RFSD_BLOCK_TYPES; i++) {
1302
1303 if (Index < dwSizes[i]) {
1304
1305 dwBlk = Inode->i_block[i==0 ? (Index):(i + RFSD_NDIR_BLOCKS - 1)];
1306
1307 if (dwBlk == 0) {
1308
1309 Status = RfsdNewBlock(
1310 IrpContext,
1311 Vcb,
1312 Fcb->BlkHint ? 0 : ((Fcb->RfsdMcb->Inode - 1) / INODES_PER_GROUP),
1313 Fcb->BlkHint,
1314 &dwBlk );
1315
1316 if (!NT_SUCCESS(Status) ) {
1317 RfsdPrint((DBG_ERROR, "RfsdExpandInode: get new block error.\n"));
1318 break;
1319 }
1320
1321 Inode->i_block[i==0 ? (Index):(i + RFSD_NDIR_BLOCKS - 1)] = dwBlk;
1322
1323 Inode->i_blocks += (Vcb->BlockSize / SECTOR_SIZE);
1324
1325 bNewBlock = TRUE;
1326 }
1327
1328 Status = RfsdExpandBlock (
1329 IrpContext,
1330 Vcb, Fcb,
1331 dwBlk, Index,
1332 i, bNewBlock,
1333 &dwNewBlk );
1334
1335 if (NT_SUCCESS(Status)) {
1336 Fcb->Header.AllocationSize.QuadPart += Vcb->BlockSize;
1337 }
1338
1339 break;
1340 }
1341
1342 Index -= dwSizes[i];
1343 }
1344
1345 RfsdSaveInode(IrpContext, Vcb, Fcb->RfsdMcb->Inode, Inode);
1346
1347 if (NT_SUCCESS(Status)) {
1348 if (dwNewBlk) {
1349 if (dwRet) {
1350 Fcb->BlkHint = dwNewBlk+1;
1351 *dwRet = dwNewBlk;
1352
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));
1355 }
1356 } else {
1357 DbgBreak();
1358 Status = STATUS_UNSUCCESSFUL;
1359 }
1360 }
1361
1362 return Status;
1363 #endif
1364 }
1365
1366 NTSTATUS
1367 RfsdNewInode(
1368 PRFSD_IRP_CONTEXT IrpContext,
1369 PRFSD_VCB Vcb,
1370 ULONG GroupHint,
1371 ULONG Type,
1372 PULONG Inode )
1373 {
1374 DbgBreak();
1375 #if DISABLED
1376
1377 RTL_BITMAP InodeBitmap;
1378 PVOID BitmapCache;
1379 PBCB BitmapBcb;
1380
1381 ULONG Group, i, j;
1382 ULONG Average, Length;
1383 LARGE_INTEGER Offset;
1384
1385 ULONG dwInode;
1386
1387 *Inode = dwInode = 0XFFFFFFFF;
1388
1389 repeat:
1390
1391 Group = i = 0;
1392
1393 if (Type == RFSD_FT_DIR) {
1394
1395 Average = Vcb->SuperBlock->s_free_inodes_count / Vcb->NumOfGroups;
1396
1397 for (j = 0; j < Vcb->NumOfGroups; j++) {
1398
1399 i = (j + GroupHint) % (Vcb->NumOfGroups);
1400
1401 if ((Vcb->GroupDesc[i].bg_used_dirs_count << 8) <
1402 Vcb->GroupDesc[i].bg_free_inodes_count ) {
1403 Group = i + 1;
1404 break;
1405 }
1406 }
1407
1408 if (!Group) {
1409
1410 for (j = 0; j < Vcb->NumOfGroups; j++) {
1411
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 ))
1415 Group = j + 1;
1416 }
1417 }
1418 }
1419
1420 } else {
1421
1422 /*
1423 * Try to place the inode in its parent directory (GroupHint)
1424 */
1425
1426 if (Vcb->GroupDesc[GroupHint].bg_free_inodes_count) {
1427
1428 Group = GroupHint + 1;
1429
1430 } else {
1431
1432 i = GroupHint;
1433
1434 /*
1435 * Use a quadratic hash to find a group with a
1436 * free inode
1437 */
1438
1439 for (j = 1; j < Vcb->NumOfGroups; j <<= 1) {
1440
1441 i += j;
1442 if (i > Vcb->NumOfGroups)
1443 i -= Vcb->NumOfGroups;
1444
1445 if (Vcb->GroupDesc[i].bg_free_inodes_count) {
1446 Group = i + 1;
1447 break;
1448 }
1449 }
1450 }
1451
1452 if (!Group) {
1453 /*
1454 * That failed: try linear search for a free inode
1455 */
1456 i = GroupHint + 1;
1457 for (j = 2; j < Vcb->NumOfGroups; j++) {
1458 if (++i >= Vcb->NumOfGroups) i = 0;
1459
1460 if (Vcb->GroupDesc[i].bg_free_inodes_count) {
1461 Group = i + 1;
1462 break;
1463 }
1464 }
1465 }
1466 }
1467
1468 // Could not find a proper group.
1469 if (!Group) {
1470
1471 return STATUS_DISK_FULL;
1472
1473 } else {
1474
1475 Group--;
1476
1477 Offset.QuadPart = (LONGLONG) Vcb->BlockSize;
1478 Offset.QuadPart = Offset.QuadPart * Vcb->GroupDesc[Group].bg_inode_bitmap;
1479
1480 if (Vcb->NumOfGroups == 1) {
1481 Length = INODES_COUNT;
1482 } else {
1483 if (Group == Vcb->NumOfGroups - 1) {
1484 Length = INODES_COUNT % INODES_PER_GROUP;
1485 if (!Length) {
1486 /* INODES_COUNT is integer multiple of INODES_PER_GROUP */
1487 Length = INODES_PER_GROUP;
1488 }
1489 } else {
1490 Length = INODES_PER_GROUP;
1491 }
1492 }
1493
1494 if (!CcPinRead( Vcb->StreamObj,
1495 &Offset,
1496 Vcb->BlockSize,
1497 PIN_WAIT,
1498 &BitmapBcb,
1499 &BitmapCache ) ) {
1500
1501 RfsdPrint((DBG_ERROR, "RfsdNewInode: PinReading error ...\n"));
1502
1503 return STATUS_UNSUCCESSFUL;
1504 }
1505
1506 RtlInitializeBitMap( &InodeBitmap,
1507 BitmapCache,
1508 Length );
1509
1510 dwInode = RtlFindClearBits(&InodeBitmap, 1, 0);
1511
1512 if (dwInode == 0xFFFFFFFF) {
1513 CcUnpinData(BitmapBcb);
1514 BitmapBcb = NULL;
1515 BitmapCache = NULL;
1516
1517 RtlZeroMemory(&InodeBitmap, sizeof(RTL_BITMAP));
1518 }
1519 }
1520
1521 if (dwInode == 0xFFFFFFFF || dwInode >= Length) {
1522
1523 if (Vcb->GroupDesc[Group].bg_free_inodes_count != 0) {
1524
1525 Vcb->GroupDesc[Group].bg_free_inodes_count = 0;
1526
1527 RfsdSaveGroup(IrpContext, Vcb, Group);
1528 }
1529
1530 goto repeat;
1531
1532 } else {
1533
1534 RtlSetBits(&InodeBitmap, dwInode, 1);
1535
1536 CcSetDirtyPinnedData(BitmapBcb, NULL );
1537
1538 RfsdRepinBcb(IrpContext, BitmapBcb);
1539
1540 CcUnpinData(BitmapBcb);
1541
1542 RfsdAddMcbEntry(Vcb, Offset.QuadPart, (LONGLONG)Vcb->BlockSize);
1543
1544 *Inode = dwInode + 1 + Group * INODES_PER_GROUP;
1545
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++;
1550 }
1551
1552 RfsdSaveGroup(IrpContext, Vcb, Group);
1553
1554 Vcb->SuperBlock->s_free_inodes_count--;
1555 RfsdSaveSuper(IrpContext, Vcb);
1556
1557 return STATUS_SUCCESS;
1558 }
1559
1560 return STATUS_DISK_FULL;
1561
1562 #endif
1563 }
1564
1565 BOOLEAN
1566 RfsdFreeInode(
1567 PRFSD_IRP_CONTEXT IrpContext,
1568 PRFSD_VCB Vcb,
1569 ULONG Inode,
1570 ULONG Type )
1571 {
1572 DbgBreak();
1573 #if DISABLED
1574
1575 RTL_BITMAP InodeBitmap;
1576 PVOID BitmapCache;
1577 PBCB BitmapBcb;
1578
1579 ULONG Group;
1580 ULONG Length;
1581 LARGE_INTEGER Offset;
1582
1583 ULONG dwIno;
1584 BOOLEAN bModified = FALSE;
1585
1586
1587 Group = (Inode - 1) / INODES_PER_GROUP;
1588 dwIno = (Inode - 1) % INODES_PER_GROUP;
1589
1590 RfsdPrint((DBG_INFO, "RfsdFreeInode: Inode: %xh (Group/Off = %xh/%xh)\n",
1591 Inode, Group, dwIno));
1592
1593 {
1594 Offset.QuadPart = (LONGLONG) Vcb->BlockSize;
1595 Offset.QuadPart = Offset.QuadPart * Vcb->GroupDesc[Group].bg_inode_bitmap;
1596 if (Group == Vcb->NumOfGroups - 1) {
1597
1598 Length = INODES_COUNT % INODES_PER_GROUP;
1599 if (!Length) {
1600 /* s_inodes_count is integer multiple of s_inodes_per_group */
1601 Length = INODES_PER_GROUP;
1602 }
1603 } else {
1604 Length = INODES_PER_GROUP;
1605 }
1606
1607 if (!CcPinRead( Vcb->StreamObj,
1608 &Offset,
1609 Vcb->BlockSize,
1610 PIN_WAIT,
1611 &BitmapBcb,
1612 &BitmapCache ) ) {
1613 RfsdPrint((DBG_ERROR, "RfsdFreeInode: PinReading error ...\n"));
1614 return FALSE;
1615 }
1616
1617 RtlInitializeBitMap( &InodeBitmap,
1618 BitmapCache,
1619 Length );
1620
1621 if (RtlCheckBit(&InodeBitmap, dwIno) == 0) {
1622 DbgBreak();
1623 } else {
1624 RtlClearBits(&InodeBitmap, dwIno, 1);
1625 bModified = TRUE;
1626 }
1627
1628 if (!bModified) {
1629
1630 CcUnpinData(BitmapBcb);
1631 BitmapBcb = NULL;
1632 BitmapCache = NULL;
1633
1634 RtlZeroMemory(&InodeBitmap, sizeof(RTL_BITMAP));
1635 }
1636 }
1637
1638 if (bModified) {
1639
1640 CcSetDirtyPinnedData(BitmapBcb, NULL );
1641
1642 RfsdRepinBcb(IrpContext, BitmapBcb);
1643
1644 CcUnpinData(BitmapBcb);
1645
1646 RfsdAddMcbEntry(Vcb, Offset.QuadPart, (LONGLONG)Vcb->BlockSize);
1647
1648 //Updating Group Desc / Superblock
1649 if (Type == RFSD_FT_DIR) {
1650 Vcb->GroupDesc[Group].bg_used_dirs_count--;
1651 }
1652
1653 Vcb->GroupDesc[Group].bg_free_inodes_count++;
1654 RfsdSaveGroup(IrpContext, Vcb, Group);
1655
1656 Vcb->SuperBlock->s_free_inodes_count++;
1657 RfsdSaveSuper(IrpContext, Vcb);
1658
1659 return TRUE;
1660 }
1661
1662 return FALSE;
1663
1664 #endif
1665 }
1666
1667 NTSTATUS
1668 RfsdAddEntry (
1669 IN PRFSD_IRP_CONTEXT IrpContext,
1670 IN PRFSD_VCB Vcb,
1671 IN PRFSD_FCB Dcb,
1672 IN ULONG FileType,
1673 IN ULONG Inode,
1674 IN PUNICODE_STRING FileName )
1675 {
1676 DbgBreak();
1677 #if DISABLED
1678 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1679
1680 PRFSD_DIR_ENTRY2 pDir = NULL;
1681 PRFSD_DIR_ENTRY2 pNewDir = NULL;
1682 PRFSD_DIR_ENTRY2 pTarget = NULL;
1683
1684 ULONG Length = 0;
1685 ULONG dwBytes = 0;
1686
1687 BOOLEAN bFound = FALSE;
1688 BOOLEAN bAdding = FALSE;
1689
1690 BOOLEAN MainResourceAcquired = FALSE;
1691
1692 ULONG dwRet;
1693
1694 if (!IsDirectory(Dcb)) {
1695 DbgBreak();
1696 return STATUS_NOT_A_DIRECTORY;
1697 }
1698
1699 MainResourceAcquired = ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
1700
1701 _SEH2_TRY {
1702
1703 Dcb->ReferenceCount++;
1704
1705 pDir = (PRFSD_DIR_ENTRY2) ExAllocatePoolWithTag(PagedPool,
1706 RFSD_DIR_REC_LEN(RFSD_NAME_LEN), RFSD_POOL_TAG);
1707 if (!pDir) {
1708 Status = STATUS_INSUFFICIENT_RESOURCES;
1709 _SEH2_LEAVE;
1710 }
1711
1712 pTarget = (PRFSD_DIR_ENTRY2) ExAllocatePoolWithTag(PagedPool,
1713 2 * RFSD_DIR_REC_LEN(RFSD_NAME_LEN), RFSD_POOL_TAG);
1714 if (!pTarget) {
1715
1716 Status = STATUS_INSUFFICIENT_RESOURCES;
1717 _SEH2_LEAVE;
1718 }
1719
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;
1724 } else
1725 #endif
1726 {
1727 pDir->file_type = 0;
1728 }
1729
1730 {
1731 OEM_STRING OemName;
1732 OemName.Buffer = pDir->name;
1733 OemName.MaximumLength = RFSD_NAME_LEN;
1734 OemName.Length = 0;
1735
1736 Status = RfsdUnicodeToOEM(&OemName, FileName);
1737
1738 if (!NT_SUCCESS(Status)) {
1739 _SEH2_LEAVE;
1740 }
1741
1742 pDir->name_len = (CCHAR) OemName.Length;
1743 }
1744
1745 pDir->inode = Inode;
1746 pDir->rec_len = (USHORT) (RFSD_DIR_REC_LEN(pDir->name_len));
1747
1748 dwBytes = 0;
1749
1750 Repeat:
1751
1752 while ((LONGLONG)dwBytes < Dcb->Header.AllocationSize.QuadPart) {
1753
1754 RtlZeroMemory(pTarget, RFSD_DIR_REC_LEN(RFSD_NAME_LEN));
1755
1756 // Reading the DCB contents
1757 Status = RfsdReadInode(
1758 NULL,
1759 Vcb,
1760 Dcb->RfsdMcb->Inode,
1761 Dcb->Inode,
1762 dwBytes,
1763 (PVOID)pTarget,
1764 RFSD_DIR_REC_LEN(RFSD_NAME_LEN),
1765 &dwRet);
1766
1767 if (!NT_SUCCESS(Status)) {
1768 RfsdPrint((DBG_ERROR, "RfsdAddDirectory: Reading Directory Content error.\n"));
1769 _SEH2_LEAVE;
1770 }
1771
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)) {
1774
1775 if (pTarget->inode) {
1776
1777 RtlZeroMemory(pTarget, 2 * RFSD_DIR_REC_LEN(RFSD_NAME_LEN));
1778
1779 // Reading the DCB contents
1780 Status = RfsdReadInode(
1781 NULL,
1782 Vcb,
1783 Dcb->RfsdMcb->Inode,
1784 Dcb->Inode,
1785 dwBytes,
1786 (PVOID)pTarget,
1787 2 * RFSD_DIR_REC_LEN(RFSD_NAME_LEN),
1788 &dwRet);
1789
1790 if (!NT_SUCCESS(Status)) {
1791 RfsdPrint((DBG_ERROR, "RfsdAddDirectory: Reading Directory Content error.\n"));
1792 _SEH2_LEAVE;
1793 }
1794
1795 Length = RFSD_DIR_REC_LEN(pTarget->name_len);
1796
1797 pNewDir = (PRFSD_DIR_ENTRY2) ((PUCHAR)pTarget + RFSD_DIR_REC_LEN(pTarget->name_len));
1798
1799 pNewDir->rec_len = pTarget->rec_len - RFSD_DIR_REC_LEN(pTarget->name_len);
1800
1801 pTarget->rec_len = RFSD_DIR_REC_LEN(pTarget->name_len);
1802
1803 } else {
1804
1805 Length = 0;
1806 pNewDir = pTarget;
1807 }
1808
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);
1814
1815 bFound = TRUE;
1816 break;
1817 }
1818
1819 dwBytes += pTarget->rec_len;
1820 }
1821
1822 if (bFound) {
1823
1824 ULONG dwRet;
1825
1826 if ( FileType==RFSD_FT_DIR ) {
1827
1828 if(((pDir->name_len == 1) && (pDir->name[0] == '.')) ||
1829 ((pDir->name_len == 2) && (pDir->name[0] == '.') && (pDir->name[1] == '.')) ) {
1830 } else {
1831 Dcb->Inode->i_links_count++;
1832 }
1833 }
1834
1835 Status = RfsdWriteInode(
1836 IrpContext,
1837 Vcb,
1838 Dcb->RfsdMcb->Inode,
1839 Dcb->Inode,
1840 (ULONGLONG)dwBytes,
1841 pTarget,
1842 Length,
1843 FALSE,
1844 &dwRet );
1845 } else {
1846
1847 // We should expand the size of the dir inode
1848 if (!bAdding) {
1849
1850 ULONG dwRet;
1851
1852 Status = RfsdExpandInode(IrpContext, Vcb, Dcb, &dwRet);
1853
1854 if (NT_SUCCESS(Status)) {
1855
1856 Dcb->Inode->i_size = Dcb->Header.AllocationSize.LowPart;
1857
1858 RfsdSaveInode(IrpContext, Vcb, Dcb->RfsdMcb->Inode, Dcb->Inode);
1859
1860 Dcb->Header.FileSize = Dcb->Header.AllocationSize;
1861
1862 bAdding = TRUE;
1863
1864 goto Repeat;
1865 }
1866
1867 _SEH2_LEAVE;
1868
1869 } else { // Something must be error!
1870 _SEH2_LEAVE;
1871 }
1872 }
1873
1874 } _SEH2_FINALLY {
1875
1876 Dcb->ReferenceCount--;
1877
1878 if(MainResourceAcquired) {
1879 ExReleaseResourceForThreadLite(
1880 &Dcb->MainResource,
1881 ExGetCurrentResourceThread());
1882 }
1883
1884 if (pTarget != NULL) {
1885 ExFreePool(pTarget);
1886 }
1887
1888 if (pDir) {
1889 ExFreePool(pDir);
1890 }
1891 } _SEH2_END;
1892
1893 return Status;
1894 #endif
1895 }
1896
1897 NTSTATUS
1898 RfsdRemoveEntry (
1899 IN PRFSD_IRP_CONTEXT IrpContext,
1900 IN PRFSD_VCB Vcb,
1901 IN PRFSD_FCB Dcb,
1902 IN ULONG FileType,
1903 IN ULONG Inode )
1904 {
1905 DbgBreak();
1906 #if DISABLED
1907 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1908
1909 PRFSD_DIR_ENTRY2 pTarget = NULL;
1910 PRFSD_DIR_ENTRY2 pPrevDir = NULL;
1911
1912 USHORT PrevRecLen = 0;
1913
1914 ULONG Length = 0;
1915 ULONG dwBytes = 0;
1916
1917 BOOLEAN MainResourceAcquired = FALSE;
1918
1919 ULONG dwRet;
1920
1921 if (!IsDirectory(Dcb)) {
1922 return STATUS_NOT_A_DIRECTORY;
1923 }
1924
1925 MainResourceAcquired =
1926 ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
1927
1928 _SEH2_TRY {
1929
1930 Dcb->ReferenceCount++;
1931
1932 pTarget = (PRFSD_DIR_ENTRY2) ExAllocatePoolWithTag(PagedPool,
1933 RFSD_DIR_REC_LEN(RFSD_NAME_LEN), RFSD_POOL_TAG);
1934 if (!pTarget) {
1935
1936 Status = STATUS_INSUFFICIENT_RESOURCES;
1937 _SEH2_LEAVE;
1938 }
1939
1940 pPrevDir = (PRFSD_DIR_ENTRY2) ExAllocatePoolWithTag(PagedPool,
1941 RFSD_DIR_REC_LEN(RFSD_NAME_LEN), RFSD_POOL_TAG);
1942 if (!pPrevDir) {
1943 Status = STATUS_INSUFFICIENT_RESOURCES;
1944 _SEH2_LEAVE;
1945 }
1946
1947 dwBytes = 0;
1948
1949 while ((LONGLONG)dwBytes < Dcb->Header.AllocationSize.QuadPart) {
1950
1951 RtlZeroMemory(pTarget, RFSD_DIR_REC_LEN(RFSD_NAME_LEN));
1952
1953 Status = RfsdReadInode(
1954 NULL,
1955 Vcb,
1956 Dcb->RfsdMcb->Inode,
1957 Dcb->Inode,
1958 dwBytes,
1959 (PVOID)pTarget,
1960 RFSD_DIR_REC_LEN(RFSD_NAME_LEN),
1961 &dwRet);
1962
1963 if (!NT_SUCCESS(Status)) {
1964
1965 RfsdPrint((DBG_ERROR, "RfsdRemoveEntry: Reading Directory Content error.\n"));
1966 _SEH2_LEAVE;
1967 }
1968
1969 //
1970 // Find it ! Then remove the entry from Dcb ...
1971 //
1972
1973 if (pTarget->inode == Inode) {
1974
1975 ULONG RecLen;
1976
1977 BOOLEAN bAcross = FALSE;
1978
1979 if (((ULONG)PrevRecLen + pTarget->rec_len) > BLOCK_SIZE) {
1980 bAcross = TRUE;
1981 } else {
1982
1983 dwRet = (dwBytes - PrevRecLen) & (~(BLOCK_SIZE - 1));
1984 if (dwRet != (dwBytes & (~(BLOCK_SIZE - 1))))
1985 {
1986 bAcross = TRUE;
1987 }
1988 }
1989
1990 if (!bAcross) {
1991
1992 pPrevDir->rec_len += pTarget->rec_len;
1993
1994 RecLen = RFSD_DIR_REC_LEN(pTarget->name_len);
1995
1996 RtlZeroMemory(pTarget, RecLen);
1997
1998 Status = RfsdWriteInode(
1999 IrpContext,
2000 Vcb,
2001 Dcb->RfsdMcb->Inode,
2002 Dcb->Inode,
2003 dwBytes - PrevRecLen,
2004 pPrevDir,
2005 8,
2006 FALSE,
2007 &dwRet
2008 );
2009
2010 ASSERT(NT_SUCCESS(Status));
2011
2012 Status = RfsdWriteInode(
2013 IrpContext,
2014 Vcb,
2015 Dcb->RfsdMcb->Inode,
2016 Dcb->Inode,
2017 dwBytes,
2018 pTarget,
2019 RecLen,
2020 FALSE,
2021 &dwRet
2022 );
2023
2024 ASSERT(NT_SUCCESS(Status));
2025
2026 } else {
2027
2028 RecLen = (ULONG)pTarget->rec_len;
2029 if (RecLen > RFSD_DIR_REC_LEN(RFSD_NAME_LEN)) {
2030
2031 RtlZeroMemory(pTarget, RFSD_DIR_REC_LEN(RFSD_NAME_LEN));
2032
2033 pTarget->rec_len = (USHORT)RecLen;
2034
2035 Status = RfsdWriteInode(
2036 IrpContext,
2037 Vcb,
2038 Dcb->RfsdMcb->Inode,
2039 Dcb->Inode,
2040 dwBytes,
2041 pTarget,
2042 RFSD_DIR_REC_LEN(RFSD_NAME_LEN),
2043 FALSE,
2044 &dwRet
2045 );
2046
2047 ASSERT(NT_SUCCESS(Status));
2048
2049 } else {
2050
2051 RtlZeroMemory(pTarget, RecLen);
2052 pTarget->rec_len = (USHORT)RecLen;
2053
2054 Status = RfsdWriteInode(
2055 IrpContext,
2056 Vcb,
2057 Dcb->RfsdMcb->Inode,
2058 Dcb->Inode,
2059 dwBytes,
2060 pTarget,
2061 RecLen,
2062 FALSE,
2063 &dwRet
2064 );
2065
2066 ASSERT(NT_SUCCESS(Status));
2067 }
2068 }
2069
2070 //
2071 // Error if it's the entry of dot or dot-dot or drop the parent's refer link
2072 //
2073
2074 if (FileType == RFSD_FT_DIR) {
2075
2076 if(((pTarget->name_len == 1) && (pTarget->name[0] == '.')) ||
2077 ((pTarget->name_len == 2) && (pTarget->name[0] == '.') && (pTarget->name[1] == '.')) ) {
2078
2079 DbgBreak();
2080 } else {
2081 Dcb->Inode->i_links_count--;
2082 }
2083 }
2084
2085 //
2086 // Update at least mtime/atime if !RFSD_FT_DIR.
2087 //
2088
2089 if ( !RfsdSaveInode(
2090 IrpContext,
2091 Vcb,
2092 Dcb->RfsdMcb->Inode,
2093 Dcb->Inode
2094 ) ) {
2095 Status = STATUS_UNSUCCESSFUL;
2096 }
2097
2098 break;
2099
2100 } else {
2101
2102 RtlCopyMemory(pPrevDir, pTarget, RFSD_DIR_REC_LEN(RFSD_NAME_LEN));
2103 PrevRecLen = pTarget->rec_len;
2104 }
2105
2106 dwBytes += pTarget->rec_len;
2107 }
2108
2109 } _SEH2_FINALLY {
2110
2111 Dcb->ReferenceCount--;
2112
2113 if(MainResourceAcquired)
2114 ExReleaseResourceForThreadLite(
2115 &Dcb->MainResource,
2116 ExGetCurrentResourceThread());
2117
2118 if (pTarget != NULL) {
2119 ExFreePool(pTarget);
2120 }
2121
2122 if (pPrevDir != NULL) {
2123 ExFreePool(pPrevDir);
2124 }
2125 } _SEH2_END;
2126
2127 return Status;
2128 #endif
2129 }
2130
2131 NTSTATUS
2132 RfsdSetParentEntry (
2133 IN PRFSD_IRP_CONTEXT IrpContext,
2134 IN PRFSD_VCB Vcb,
2135 IN PRFSD_FCB Dcb,
2136 IN ULONG OldParent,
2137 IN ULONG NewParent )
2138 {
2139 DbgBreak();
2140 #if DISABLED
2141 NTSTATUS Status = STATUS_UNSUCCESSFUL;
2142
2143 PRFSD_DIR_ENTRY2 pSelf = NULL;
2144 PRFSD_DIR_ENTRY2 pParent = NULL;
2145
2146 ULONG dwBytes = 0;
2147
2148 BOOLEAN MainResourceAcquired = FALSE;
2149
2150 ULONG Offset = 0;
2151
2152 if (!IsDirectory(Dcb)) {
2153 return STATUS_NOT_A_DIRECTORY;
2154 }
2155
2156 MainResourceAcquired =
2157 ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
2158
2159 _SEH2_TRY {
2160
2161 Dcb->ReferenceCount++;
2162
2163 pSelf = (PRFSD_DIR_ENTRY2) ExAllocatePoolWithTag(PagedPool,
2164 RFSD_DIR_REC_LEN(1) + RFSD_DIR_REC_LEN(2), RFSD_POOL_TAG);
2165 if (!pSelf) {
2166 Status = STATUS_INSUFFICIENT_RESOURCES;
2167 _SEH2_LEAVE;
2168 }
2169
2170 dwBytes = 0;
2171
2172 //
2173 // Reading the DCB contents
2174 //
2175
2176 Status = RfsdReadInode(
2177 NULL,
2178 Vcb,
2179 Dcb->RfsdMcb->Inode,
2180 Dcb->Inode,
2181 Offset,
2182 (PVOID)pSelf,
2183 RFSD_DIR_REC_LEN(1) + RFSD_DIR_REC_LEN(2),
2184 &dwBytes );
2185
2186 if (!NT_SUCCESS(Status)) {
2187 RfsdPrint((DBG_ERROR, "RfsdSetParentEntry: Reading Directory Content error.\n"));
2188 _SEH2_LEAVE;
2189 }
2190
2191 ASSERT(dwBytes == RFSD_DIR_REC_LEN(1) + RFSD_DIR_REC_LEN(2));
2192
2193 pParent = (PRFSD_DIR_ENTRY2)((PUCHAR)pSelf + pSelf->rec_len);
2194
2195 if (pParent->inode != OldParent) {
2196 DbgBreak();
2197 }
2198
2199 pParent->inode = NewParent;
2200
2201 Status = RfsdWriteInode(
2202 IrpContext,
2203 Vcb,
2204 Dcb->RfsdMcb->Inode,
2205 Dcb->Inode,
2206 Offset,
2207 pSelf,
2208 dwBytes,
2209 FALSE,
2210 &dwBytes );
2211
2212 } _SEH2_FINALLY {
2213
2214 Dcb->ReferenceCount--;
2215
2216 if(MainResourceAcquired) {
2217 ExReleaseResourceForThreadLite(
2218 &Dcb->MainResource,
2219 ExGetCurrentResourceThread());
2220 }
2221
2222 if (pSelf) {
2223 ExFreePool(pSelf);
2224 }
2225 } _SEH2_END;
2226
2227 return Status;
2228 #endif
2229 { return 1; }
2230 }
2231
2232 NTSTATUS
2233 RfsdTruncateBlock(
2234 IN PRFSD_IRP_CONTEXT IrpContext,
2235 IN PRFSD_VCB Vcb,
2236 IN PRFSD_FCB Fcb,
2237 IN ULONG dwContent,
2238 IN ULONG Index,
2239 IN ULONG layer,
2240 OUT BOOLEAN *bFreed )
2241 {
2242 DbgBreak();
2243 #if DISABLED
2244
2245 ULONG *pData = NULL;
2246 ULONG i = 0, j = 0, temp = 1;
2247 BOOLEAN bDirty = FALSE;
2248 ULONG dwBlk;
2249
2250 LONGLONG Offset;
2251
2252 PBCB Bcb;
2253
2254 NTSTATUS Status = STATUS_SUCCESS;
2255
2256 PRFSD_INODE Inode = Fcb->Inode;
2257
2258 *bFreed = FALSE;
2259
2260 if (layer == 0) {
2261
2262 if ( dwContent > 0 && (dwContent / BLOCKS_PER_GROUP) < Vcb->NumOfGroups) {
2263
2264 Status = RfsdFreeBlock(IrpContext, Vcb, dwContent);
2265
2266 if (NT_SUCCESS(Status)) {
2267
2268 ASSERT(Inode->i_blocks >= (Vcb->BlockSize / SECTOR_SIZE));
2269 Inode->i_blocks -= (Vcb->BlockSize / SECTOR_SIZE);
2270 *bFreed = TRUE;
2271 }
2272
2273 } else if (dwContent == 0) {
2274 Status = STATUS_SUCCESS;
2275 } else {
2276 DbgBreak();
2277 Status = STATUS_INVALID_PARAMETER;
2278 }
2279
2280 } else if (layer <= 3) {
2281
2282 Offset = (LONGLONG) dwContent;
2283 Offset = Offset * Vcb->BlockSize;
2284
2285 if (!CcPinRead( Vcb->StreamObj,
2286 (PLARGE_INTEGER) (&Offset),
2287 Vcb->BlockSize,
2288 PIN_WAIT,
2289 &Bcb,
2290 &pData )) {
2291
2292 RfsdPrint((DBG_ERROR, "RfsdSaveBuffer: PinReading error ...\n"));
2293 Status = STATUS_INSUFFICIENT_RESOURCES;
2294 goto errorout;
2295 }
2296
2297 temp = 1 << ((BLOCK_BITS - 2) * (layer - 1));
2298
2299 i = Index / temp;
2300 j = Index % temp;
2301
2302 dwBlk = pData[i];
2303
2304 if (dwBlk) {
2305
2306 Status = RfsdTruncateBlock(
2307 IrpContext,
2308 Vcb,
2309 Fcb,
2310 dwBlk,
2311 j,
2312 layer - 1,
2313 &bDirty
2314 );
2315
2316 if(!NT_SUCCESS(Status)) {
2317 goto errorout;
2318 }
2319
2320 if (bDirty) {
2321 pData[i] = 0;
2322 }
2323 }
2324
2325 if (i == 0 && j == 0) {
2326
2327 CcUnpinData(Bcb);
2328 pData = NULL;
2329
2330 Status = RfsdFreeBlock(IrpContext, Vcb, dwContent);
2331
2332 if (NT_SUCCESS(Status)) {
2333 ASSERT(Inode->i_blocks >= (Vcb->BlockSize / SECTOR_SIZE));
2334 Inode->i_blocks -= (Vcb->BlockSize / SECTOR_SIZE);
2335
2336 *bFreed = TRUE;
2337 }
2338
2339 } else {
2340
2341 if (bDirty) {
2342 CcSetDirtyPinnedData(Bcb, NULL );
2343 RfsdRepinBcb(IrpContext, Bcb);
2344
2345 RfsdAddMcbEntry(Vcb, Offset, (LONGLONG)Vcb->BlockSize);
2346 }
2347 }
2348 }
2349
2350 errorout:
2351
2352 if (pData) {
2353 CcUnpinData(Bcb);
2354 }
2355
2356 return Status;
2357
2358 #endif
2359 }
2360
2361 NTSTATUS
2362 RfsdTruncateInode(
2363 IN PRFSD_IRP_CONTEXT IrpContext,
2364 IN PRFSD_VCB Vcb,
2365 IN PRFSD_FCB Fcb )
2366 {
2367 DbgBreak();
2368 #if DISABLED
2369
2370 ULONG dwSizes[RFSD_BLOCK_TYPES];
2371 ULONG Index = 0;
2372 ULONG dwTotal = 0;
2373 ULONG dwBlk = 0;
2374
2375 ULONG i;
2376 NTSTATUS Status = STATUS_SUCCESS;
2377 BOOLEAN bFreed = FALSE;
2378
2379 PRFSD_INODE Inode = Fcb->Inode;
2380
2381 Index = (ULONG)(Fcb->Header.AllocationSize.QuadPart >> BLOCK_BITS);
2382
2383 if (Index > 0) {
2384 Index--;
2385 } else {
2386 return Status;
2387 }
2388
2389 for (i = 0; i < RFSD_BLOCK_TYPES; i++) {
2390 dwSizes[i] = Vcb->dwData[i];
2391 dwTotal += dwSizes[i];
2392 }
2393
2394 if (Index >= dwTotal) {
2395 RfsdPrint((DBG_ERROR, "RfsdTruncateInode: beyond the maxinum size of an inode.\n"));
2396 return Status;
2397 }
2398
2399 for (i = 0; i < RFSD_BLOCK_TYPES; i++) {
2400
2401 if (Index < dwSizes[i]) {
2402
2403 dwBlk = Inode->i_block[i==0 ? (Index):(i + RFSD_NDIR_BLOCKS - 1)];
2404
2405 if (dwBlk) {
2406
2407 Status = RfsdTruncateBlock(IrpContext, Vcb, Fcb, dwBlk, Index , i, &bFreed);
2408 }
2409
2410 if (NT_SUCCESS(Status)) {
2411
2412 Fcb->Header.AllocationSize.QuadPart -= Vcb->BlockSize;
2413
2414 if (bFreed) {
2415 Inode->i_block[i==0 ? (Index):(i + RFSD_NDIR_BLOCKS - 1)] = 0;
2416 }
2417 }
2418
2419 break;
2420 }
2421
2422 Index -= dwSizes[i];
2423 }
2424
2425 //
2426 // Inode struct saving is done externally.
2427 //
2428
2429 RfsdSaveInode(IrpContext, Vcb, Fcb->RfsdMcb->Inode, Inode);
2430
2431
2432 return Status;
2433 #endif
2434 }
2435
2436 BOOLEAN
2437 RfsdAddMcbEntry ( // Mcb = map control block (maps file-relative block offsets to disk-relative block offsets)
2438 IN PRFSD_VCB Vcb,
2439 IN LONGLONG Lba,
2440 IN LONGLONG Length)
2441 {
2442 DbgBreak();
2443 #if DISABLED
2444
2445 BOOLEAN bRet = FALSE;
2446
2447 LONGLONG Offset;
2448
2449 #if DBG
2450 LONGLONG DirtyLba;
2451 LONGLONG DirtyLen;
2452 #endif
2453
2454
2455 Offset = Lba & (~((LONGLONG)BLOCK_SIZE - 1));
2456
2457 Length = (Length + Lba - Offset + BLOCK_SIZE - 1) &
2458 (~((LONGLONG)BLOCK_SIZE - 1));
2459
2460 ASSERT ((Offset & (BLOCK_SIZE - 1)) == 0);
2461 ASSERT ((Length & (BLOCK_SIZE - 1)) == 0);
2462
2463 Offset = (Offset >> BLOCK_BITS) + 1;
2464 Length = (Length >> BLOCK_BITS);
2465
2466 ExAcquireResourceExclusiveLite(
2467 &(Vcb->McbResource),
2468 TRUE );
2469
2470 RfsdPrint((DBG_INFO, "RfsdAddMcbEntry: Lba=%I64xh Length=%I64xh\n",
2471 Offset, Length ));
2472
2473 #if DBG
2474 bRet = FsRtlLookupLargeMcbEntry(
2475 &(Vcb->DirtyMcbs),
2476 Offset,
2477 &DirtyLba,
2478 &DirtyLen,
2479 NULL,
2480 NULL,
2481 NULL );
2482
2483 if (bRet && DirtyLba == Offset && DirtyLen >= Length) {
2484
2485 RfsdPrint((DBG_INFO, "RfsdAddMcbEntry: this run already exists.\n"));
2486 }
2487 #endif
2488
2489 _SEH2_TRY {
2490
2491 bRet = FsRtlAddLargeMcbEntry(
2492 &(Vcb->DirtyMcbs),
2493 Offset, Offset,
2494 Length );
2495
2496 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
2497
2498 DbgBreak();
2499 bRet = FALSE;
2500 } _SEH2_END;
2501
2502 #if DBG
2503 if (bRet) {
2504
2505 BOOLEAN bFound = FALSE;
2506 LONGLONG RunStart;
2507 LONGLONG RunLength;
2508 ULONG Index;
2509
2510 bFound = FsRtlLookupLargeMcbEntry(
2511 &(Vcb->DirtyMcbs),
2512 Offset,
2513 &DirtyLba,
2514 &DirtyLen,
2515 &RunStart,
2516 &RunLength,
2517 &Index );
2518
2519 if ((!bFound) || (DirtyLba == -1) ||
2520 (DirtyLba != Offset) || (DirtyLen < Length)) {
2521 LONGLONG DirtyVba;
2522 LONGLONG DirtyLba;
2523 LONGLONG DirtyLength;
2524
2525 DbgBreak();
2526
2527 for ( Index = 0;
2528 FsRtlGetNextLargeMcbEntry( &(Vcb->DirtyMcbs),
2529 Index,
2530 &DirtyVba,
2531 &DirtyLba,
2532 &DirtyLength);
2533 Index++ ) {
2534
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));
2539 }
2540 }
2541 }
2542 #endif
2543
2544 ExReleaseResourceForThreadLite(
2545 &(Vcb->McbResource),
2546 ExGetCurrentResourceThread() );
2547
2548 return bRet;
2549 #endif
2550
2551 }
2552
2553 VOID
2554 RfsdRemoveMcbEntry (
2555 IN PRFSD_VCB Vcb,
2556 IN LONGLONG Lba,
2557 IN LONGLONG Length)
2558 {
2559 DbgBreak();
2560 #if DISABLED
2561
2562 LONGLONG Offset;
2563
2564 Offset = Lba & (~((LONGLONG)BLOCK_SIZE - 1));
2565
2566 Length = (Length + Lba - Offset + BLOCK_SIZE - 1) &
2567 (~((LONGLONG)BLOCK_SIZE - 1));
2568
2569 ASSERT(Offset == Lba);
2570
2571 ASSERT ((Offset & (BLOCK_SIZE - 1)) == 0);
2572 ASSERT ((Length & (BLOCK_SIZE - 1)) == 0);
2573
2574 Offset = (Offset >> BLOCK_BITS) + 1;
2575 Length = (Length >> BLOCK_BITS);
2576
2577 RfsdPrint((DBG_INFO, "RfsdRemoveMcbEntry: Lba=%I64xh Length=%I64xh\n",
2578 Offset, Length ));
2579
2580 ExAcquireResourceExclusiveLite(
2581 &(Vcb->McbResource),
2582 TRUE );
2583
2584 _SEH2_TRY {
2585 FsRtlRemoveLargeMcbEntry(
2586 &(Vcb->DirtyMcbs),
2587 Offset, Length );
2588
2589 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
2590 DbgBreak();
2591 } _SEH2_END;
2592
2593 #if DBG
2594 {
2595 BOOLEAN bFound = FALSE;
2596 LONGLONG DirtyLba, DirtyLen;
2597
2598 bFound = FsRtlLookupLargeMcbEntry(
2599 &(Vcb->DirtyMcbs),
2600 Offset,
2601 &DirtyLba,
2602 &DirtyLen,
2603 NULL,
2604 NULL,
2605 NULL );
2606
2607 if (bFound &&( DirtyLba != -1)) {
2608 DbgBreak();
2609 }
2610 }
2611 #endif
2612
2613 ExReleaseResourceForThreadLite(
2614 &(Vcb->McbResource),
2615 ExGetCurrentResourceThread() );
2616 #endif
2617 }
2618
2619 BOOLEAN
2620 RfsdLookupMcbEntry (
2621 IN PRFSD_VCB Vcb,
2622 IN LONGLONG Lba,
2623 OUT PLONGLONG pLba,
2624 OUT PLONGLONG pLength,
2625 OUT PLONGLONG RunStart,
2626 OUT PLONGLONG RunLength,
2627 OUT PULONG Index)
2628 {
2629 DbgBreak();
2630 #if DISABLED
2631
2632 BOOLEAN bRet;
2633 LONGLONG Offset;
2634
2635
2636 Offset = Lba & (~((LONGLONG)BLOCK_SIZE - 1));
2637 ASSERT ((Offset & (BLOCK_SIZE - 1)) == 0);
2638
2639 ASSERT(Lba == Offset);
2640
2641 Offset = (Offset >> BLOCK_BITS) + 1;
2642
2643 ExAcquireResourceExclusiveLite(
2644 &(Vcb->McbResource),
2645 TRUE );
2646
2647 bRet = FsRtlLookupLargeMcbEntry(
2648 &(Vcb->DirtyMcbs),
2649 Offset,
2650 pLba,
2651 pLength,
2652 RunStart,
2653 RunLength,
2654 Index );
2655
2656 ExReleaseResourceForThreadLite(
2657 &(Vcb->McbResource),
2658 ExGetCurrentResourceThread() );
2659
2660 if (bRet) {
2661
2662 if (pLba && ((*pLba) != -1)) {
2663
2664 ASSERT((*pLba) > 0);
2665
2666 (*pLba) = (((*pLba) - 1) << BLOCK_BITS);
2667 (*pLba) += ((Lba) & ((LONGLONG)BLOCK_SIZE - 1));
2668 }
2669
2670 if (pLength) {
2671
2672 (*pLength) <<= BLOCK_BITS;
2673 (*pLength) -= ((Lba) & ((LONGLONG)BLOCK_SIZE - 1));
2674 }
2675
2676 if (RunStart && (*RunStart != -1)) {
2677 (*RunStart) = (((*RunStart) - 1) << BLOCK_BITS);
2678 }
2679
2680 if (RunLength) {
2681 (*RunLength) <<= BLOCK_BITS;
2682 }
2683 }
2684
2685 return bRet;
2686
2687 #endif
2688 }
2689
2690 #endif // 0
2691
2692 ///////////////////////////////////////////////////
2693 ///////////////////////////////////////////////////
2694
2695 /**
2696 Invoked by FSCTL.c on mount volume
2697 */
2698 BOOLEAN SuperblockContainsMagicKey(PRFSD_SUPER_BLOCK sb)
2699 {
2700 #define MAGIC_KEY_LENGTH 9
2701
2702 UCHAR sz_MagicKey[] = REISER2FS_SUPER_MAGIC_STRING;
2703 #ifndef __REACTOS__
2704 BOOLEAN b_KeyMatches = TRUE;
2705 #endif
2706 UCHAR currentChar;
2707 int i;
2708
2709 PAGED_CODE();
2710
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++)
2713 {
2714 currentChar = sb->s_magic[i];
2715 if (currentChar != sz_MagicKey[i])
2716 { return FALSE; }
2717 }
2718
2719 return TRUE;
2720 }
2721
2722
2723
2724 /*
2725 ______________________________________________________________________________
2726 _ __ _ _ _ _ _
2727 | |/ /___ _ _ | | | | |_(_) |___
2728 | ' // _ \ | | | | | | | __| | / __|
2729 | . \ __/ |_| | | |_| | |_| | \__ \
2730 |_|\_\___|\__, | \___/ \__|_|_|___/
2731 |___/
2732 ______________________________________________________________________________
2733 */
2734
2735
2736 /**
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.
2739
2740 Old keys (on i386) have k_offset_v2.k_type == 15 (direct and indirect) or == 0 (dir items and stat data).
2741 */
2742
2743 RFSD_KEY_VERSION DetermineOnDiskKeyFormat(const PRFSD_KEY_ON_DISK key)
2744 {
2745 int type = (int) key->u.k_offset_v2.k_type;
2746
2747 PAGED_CODE();
2748
2749 if ( type == 0x0 || type == 0xF )
2750 return RFSD_KEY_VERSION_1;
2751
2752 return RFSD_KEY_VERSION_2;
2753 }
2754
2755
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) */
2757 __u32
2758 ConvertKeyTypeUniqueness(__u32 k_uniqueness)
2759 {
2760 switch (k_uniqueness)
2761 {
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;
2766
2767 default:
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.
2770 DbgBreak();
2771 return 0xF; // We'll return v2 'any', just to see what happens...
2772 }
2773 }
2774
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. */
2776 void
2777 FillInMemoryKey(
2778 IN PRFSD_KEY_ON_DISK pKeyOnDisk,
2779 IN RFSD_KEY_VERSION KeyVersion,
2780 IN OUT PRFSD_KEY_IN_MEMORY pKeyInMemory )
2781 {
2782 PAGED_CODE();
2783
2784 // Sanity check that the input and output locations exist
2785 if (!pKeyOnDisk || !pKeyInMemory) { DbgBreak(); return; }
2786
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;
2790
2791 if (KeyVersion == RFSD_KEY_VERSION_UNKNOWN)
2792 { KeyVersion = DetermineOnDiskKeyFormat(pKeyOnDisk); }
2793
2794 // Copy over the fields that are incompatible between keys, converting older type fields to the v2 format
2795 switch (KeyVersion)
2796 {
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 );
2800 break;
2801
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;
2805 break;
2806 }
2807 }
2808
2809 /** Compares two in memory keys, returning KEY_SMALLER, KEY_LARGER, or KEYS_MATCH relative to the first key given. */
2810 RFSD_KEY_COMPARISON
2811 CompareShortKeys(
2812 IN PRFSD_KEY_IN_MEMORY a,
2813 IN PRFSD_KEY_IN_MEMORY b )
2814 {
2815 PAGED_CODE();
2816
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;
2820
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;
2824
2825 return RFSD_KEYS_MATCH;
2826 }
2827
2828
2829 /** Compares two in memory keys, returning KEY_SMALLER, KEY_LARGER, or KEYS_MATCH relative to the first key given. */
2830 RFSD_KEY_COMPARISON
2831 CompareKeysWithoutOffset(
2832 IN PRFSD_KEY_IN_MEMORY a,
2833 IN PRFSD_KEY_IN_MEMORY b )
2834 {
2835 PAGED_CODE();
2836
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;
2840
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;
2844
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;
2849
2850 return RFSD_KEYS_MATCH;
2851 }
2852
2853
2854 /** Compares two in memory keys, returning KEY_SMALLER, KEY_LARGER, or KEYS_MATCH relative to the first key given. */
2855 RFSD_KEY_COMPARISON
2856 CompareKeys(
2857 IN PRFSD_KEY_IN_MEMORY a,
2858 IN PRFSD_KEY_IN_MEMORY b )
2859 {
2860 PAGED_CODE();
2861
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;
2865
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;
2869
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;
2873
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;
2878
2879 return RFSD_KEYS_MATCH;
2880 }
2881
2882
2883
2884 /*
2885 ______________________________________________________________________________
2886 _____ _ _ _ _ _
2887 |_ _| __ ___ ___ | \ | | __ ___ _(_) __ _ __ _| |_(_) ___ _ __
2888 | || '__/ _ \/ _ \ | \| |/ _` \ \ / / |/ _` |/ _` | __| |/ _ \| '_ \
2889 | || | | __/ __/ | |\ | (_| |\ V /| | (_| | (_| | |_| | (_) | | | |
2890 |_||_| \___|\___| |_| \_|\__,_| \_/ |_|\__, |\__,_|\__|_|\___/|_| |_|
2891 |___/
2892 ______________________________________________________________________________
2893 */
2894
2895 NTSTATUS
2896 NavigateToLeafNode(
2897 IN PRFSD_VCB Vcb,
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
2901 )
2902 {
2903 PAGED_CODE();
2904
2905 return _NavigateToLeafNode(Vcb, Key, StartingBlockNumber, out_NextBlockNumber, TRUE, &CompareKeys, NULL, NULL);
2906 }
2907
2908 NTSTATUS
2909 RfsdParseFilesystemTree(
2910 IN PRFSD_VCB Vcb,
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
2915 )
2916 {
2917 ULONG out = 0;
2918
2919 PAGED_CODE();
2920
2921 return _NavigateToLeafNode(Vcb, Key, StartingBlockNumber, &out, FALSE, &CompareShortKeys, fpDirectoryCallback, pContext);
2922 }
2923
2924
2925 /**
2926 Returns the block number of the leaf node that should contain key (if that key exists at all within the disk tree).
2927
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
2932 **/
2933 NTSTATUS
2934 _NavigateToLeafNode(
2935 IN PRFSD_VCB Vcb,
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
2943
2944
2945 )
2946 {
2947 NTSTATUS Status = STATUS_SUCCESS;
2948 ULONG leafNodeBlockNumber; // The result to be calculated
2949 PRFSD_DISK_NODE_REF pTargetDiskNodeReference = NULL; //
2950
2951 // Read in this disk node's data
2952 PUCHAR pBlockBuffer = RfsdAllocateAndLoadBlock(Vcb, StartingBlockNumber);
2953
2954 // Read the block header
2955 PRFSD_BLOCK_HEAD pBlockHeader = (PRFSD_BLOCK_HEAD) pBlockBuffer;
2956
2957 PAGED_CODE();
2958
2959 // Sanity check that we could read the block and the header is there
2960 if (!pBlockBuffer) { return STATUS_INVALID_HANDLE; }
2961
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)
2964 {
2965 NTSTATUS CallbackStatus;
2966
2967 ExFreePool(pBlockBuffer);
2968
2969 *out_NextBlockNumber = StartingBlockNumber;
2970
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;
2974 }
2975
2976 // Otherwise, find the next node down in the tree, by obtaining pTargetDiskNodeReference
2977 {
2978 ULONG idxRightKey = 0;
2979 PRFSD_KEY_ON_DISK pLeftKeyOnDisk = NULL;
2980 PRFSD_KEY_ON_DISK pRightKeyOnDisk = NULL;
2981
2982 RFSD_KEY_IN_MEMORY LeftKeyInMemory, RightKeyInMemory;
2983 RFSD_KEY_COMPARISON leftComparison, rightComparison;
2984
2985 RightKeyInMemory.k_dir_id = 0; // (Dummy statement to prevent needless warning aboujt using RightKeyInMemory before being initialized)
2986
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++)
2989 {
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)));
2995
2996 LeftKeyInMemory = RightKeyInMemory;
2997 if (pRightKeyOnDisk)
2998 FillInMemoryKey(pRightKeyOnDisk, RFSD_KEY_VERSION_UNKNOWN, &(RightKeyInMemory));
2999
3000
3001 // Find if the target key falls in the range in between the left and right keys...
3002 {
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; }
3007 else
3008 { if (rightComparison != RFSD_KEY_SMALLER) continue; }
3009
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) )
3013 {
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)));
3018
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); // <
3024
3025 if (ReturnOnFirstMatch || Status == STATUS_EVENT_DONE || // Success cases
3026 Status == STATUS_INSUFFICIENT_RESOURCES || Status == STATUS_INVALID_HANDLE) // Error cases
3027 { goto return_results; }
3028 }
3029 }
3030 }
3031 }
3032
3033 return_results:
3034
3035 ExFreePool(pBlockBuffer);
3036 *out_NextBlockNumber = leafNodeBlockNumber;
3037 return Status;
3038 }