Bring back ext2 code from branch
[reactos.git] / reactos / drivers / filesystems / ext2 / src / metadata.c
1 /*************************************************************************
2 *
3 * File: metadata.c
4 *
5 * Module: Ext2 File System Driver (Kernel mode execution only)
6 *
7 * Description:
8 * Should contain code to handle Ext2 Metadata.
9 *
10 * Author: Manoj Paul Joseph
11 *
12 *
13 *************************************************************************/
14
15 #include "ext2fsd.h"
16
17 #define EXT2_BUG_CHECK_ID EXT2_FILE_METADATA_IO
18
19 #define DEBUG_LEVEL ( DEBUG_TRACE_METADATA )
20
21 extern Ext2Data Ext2GlobalData;
22
23 /*************************************************************************
24 *
25 * Function: Ext2ReadInode()
26 *
27 * Description:
28 *
29 * The functions will read in the specifiec inode and return it in a buffer
30 *
31 *
32 * Expected Interrupt Level (for execution) :
33 *
34 * IRQL_PASSIVE_LEVEL
35 *
36 *
37 * Arguements:
38 *
39 *
40 *
41 * Return Value: The Status of the Read IO
42 *
43 *************************************************************************/
44
45 NTSTATUS Ext2ReadInode (
46 PtrExt2VCB PtrVcb, // the Volume Control Block
47 uint32 InodeNo, // The Inode no
48 PEXT2_INODE PtrInode // The Inode Buffer
49 )
50 {
51 // The Status to be returned...
52 NTSTATUS RC = STATUS_SUCCESS;
53
54 // The Read Buffer Pointer
55 BYTE * PtrPinnedReadBuffer = NULL;
56
57 PEXT2_INODE PtrTempInode;
58
59 // Buffer Control Block
60 PBCB PtrBCB = NULL;
61
62 LARGE_INTEGER VolumeByteOffset, TempOffset;
63
64 ULONG LogicalBlockSize = 0;
65
66 ULONG NumberOfBytesToRead = 0;
67 ULONG Difference = 0;
68
69 ULONG GroupNo;
70 int Index;
71
72 try
73 {
74 ASSERT(PtrVcb);
75 ASSERT(PtrVcb->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB);
76
77 // Inode numbers start at 1 and not from 0
78 // Hence 1 is subtracted from InodeNo to get a zero based index...
79 GroupNo = ( InodeNo - 1 ) / PtrVcb->InodesPerGroup;
80
81 if( GroupNo >= PtrVcb->NoOfGroups )
82 {
83 DebugTrace(DEBUG_TRACE_MISC, "&&&&&& Invalid Inode no. Group no %d - too big", GroupNo );
84 DebugTrace(DEBUG_TRACE_MISC, "Only %d groups available on disk", PtrVcb->NoOfGroups );
85 RC = STATUS_UNSUCCESSFUL;
86 try_return( RC );
87 }
88
89 //if( PtrVcb->InodeTableBlock[ GroupNo ] == 0 )
90 if( PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock == 0 )
91 {
92 DebugTrace(DEBUG_TRACE_MISC, "&&&&&& Inode Table Group Invalid - Group no %d ", GroupNo );
93 RC = STATUS_UNSUCCESSFUL;
94 try_return( RC );
95 }
96
97 // Inode numbers start at 1 and not from 0
98 // Hence 1 is subtracted from InodeNo to get a zero based index...
99 Index = ( InodeNo - 1 ) - ( GroupNo * PtrVcb->InodesPerGroup );
100
101 LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVcb->LogBlockSize;
102 NumberOfBytesToRead = sizeof(EXT2_INODE); // LogicalBlockSize;
103
104 VolumeByteOffset.QuadPart = PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock
105 * LogicalBlockSize + Index * sizeof(EXT2_INODE);
106 //VolumeByteOffset.QuadPart = PtrVcb->InodeTableBlock[ GroupNo ] * LogicalBlockSize +
107 // Index * sizeof(EXT2_INODE);
108
109 TempOffset.QuadPart = Ext2Align64( VolumeByteOffset.QuadPart, LogicalBlockSize );
110 if( TempOffset.QuadPart != VolumeByteOffset.QuadPart )
111 {
112 // TempOffset.QuadPart -= LogicalBlockSize;
113 Difference = (LONG) (VolumeByteOffset.QuadPart - TempOffset.QuadPart + LogicalBlockSize );
114 VolumeByteOffset.QuadPart -= Difference;
115 NumberOfBytesToRead += Difference;
116 }
117
118 NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
119
120 if( NumberOfBytesToRead > LogicalBlockSize )
121 {
122 // Multiple blocks being read in...
123 // Can cause overlap
124 // Watch out!!!!
125 Ext2BreakPoint();
126 }
127
128
129
130 if (!CcMapData( PtrVcb->PtrStreamFileObject,
131 &VolumeByteOffset,
132 NumberOfBytesToRead,
133 TRUE,
134 &PtrBCB,
135 (PVOID*)&PtrPinnedReadBuffer ))
136 {
137 RC = STATUS_UNSUCCESSFUL;
138 try_return( RC );
139 }
140 else
141 {
142 PtrTempInode = (PEXT2_INODE) ( PtrPinnedReadBuffer + Difference );
143 RtlCopyMemory( PtrInode, PtrTempInode , sizeof(EXT2_INODE) );
144 }
145
146 try_exit: NOTHING;
147 }
148 finally
149 {
150 if( PtrBCB )
151 {
152 CcUnpinData( PtrBCB );
153 PtrBCB = NULL;
154 }
155
156 }
157 return RC;
158 }
159
160 /*************************************************************************
161 *
162 * Function: Ext2InitializeFCBInodeInfo()
163 *
164 * Description:
165 * The functions will initialize the FCB with its i-node info
166 * provided it hasn't been initialized as yet...
167 *
168 * Expected Interrupt Level (for execution) :
169 * IRQL_PASSIVE_LEVEL
170 *
171 * Arguements:
172 * Pointer to FCB
173 *
174 * Return Value: None
175 *
176 *************************************************************************/
177 void Ext2InitializeFCBInodeInfo (
178 PtrExt2FCB PtrFCB )
179 {
180 PtrExt2VCB PtrVCB = NULL;
181 EXT2_INODE Inode;
182 int i;
183 ULONG LogicalBlockSize;
184
185 PtrVCB = PtrFCB->PtrVCB;
186
187 LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
188
189 if( !Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED ) )
190 {
191 DebugTrace(DEBUG_TRACE_MISC, "Reading in the i-node no %d", PtrFCB->INodeNo );
192
193 Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode );
194
195 for( i = 0; i < EXT2_N_BLOCKS ; i++ )
196 {
197 PtrFCB->IBlock[i] = Inode.i_block[ i ];
198 }
199
200 PtrFCB->CreationTime.QuadPart = ( __int64 )Inode.i_ctime * 10000000;
201 PtrFCB->CreationTime.QuadPart += Ext2GlobalData.TimeDiff.QuadPart;
202 PtrFCB->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) Inode.i_atime * 10000000);
203 PtrFCB->LastWriteTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) Inode.i_mtime * 10000000);
204
205
206 PtrFCB->LinkCount = Inode.i_links_count;
207
208 // Getting the file type...
209 if( ! Ext2IsModeRegularFile( Inode.i_mode ) )
210 {
211 // Not a reqular file...
212 if( Ext2IsModeDirectory( Inode.i_mode) )
213 {
214 // Directory...
215 Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY );
216 }
217 else
218 {
219 // Special File...
220 // Treated with respect... ;)
221 //
222 Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_SPECIAL_FILE );
223 }
224
225 }
226 if( Ext2IsModeHidden( Inode.i_mode ) )
227 {
228 Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_HIDDEN_FILE );
229 }
230 if( Ext2IsModeReadOnly( Inode.i_mode ) )
231 {
232 Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_READ_ONLY );
233 }
234
235
236 PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart = Inode.i_size;
237 Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED );
238 PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart = Inode.i_blocks * 512;
239
240 if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] )
241 {
242 PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart -= LogicalBlockSize / 512;
243 }
244 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [metadata]", Inode );
245 }
246 }
247
248 /*************************************************************************
249 *
250 * Function: Ext2AllocInode()
251 *
252 * Description:
253 * The functions will allocate a new on-disk i-node
254 *
255 * Expected Interrupt Level (for execution) :
256 * IRQL_PASSIVE_LEVEL
257 *
258 *
259 * Arguements:
260 * Parent Inode no
261 *
262 * Return Value: The new i-node no or zero
263 *
264 *************************************************************************/
265 ULONG Ext2AllocInode(
266 PtrExt2IrpContext PtrIrpContext,
267 PtrExt2VCB PtrVCB,
268 ULONG ParentINodeNo )
269 {
270 ULONG InodeNo = 0;
271
272 // Buffer Control Block
273 PBCB PtrBitmapBCB = NULL;
274 BYTE * PtrBitmapBuffer = NULL;
275
276 LARGE_INTEGER VolumeByteOffset;
277 ULONG LogicalBlockSize = 0;
278 ULONG NumberOfBytesToRead = 0;
279
280 if( PtrVCB->FreeInodesCount == 0)
281 {
282 //
283 // No Free Inodes left...
284 // Fail request...
285 //
286 return 0;
287 }
288
289 try
290 {
291 // unsigned int DescIndex ;
292 BOOLEAN Found = FALSE;
293 ULONG Block;
294 ULONG GroupNo;
295
296 LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
297
298 for( GroupNo = 0; PtrVCB->NoOfGroups; GroupNo++ )
299 {
300 if( PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount )
301 break;
302 }
303
304 VolumeByteOffset.QuadPart =
305 PtrVCB->PtrGroupDescriptors[ GroupNo ].InodeBitmapBlock * LogicalBlockSize;
306
307 NumberOfBytesToRead = PtrVCB->InodesCount / PtrVCB->NoOfGroups;
308
309 if( NumberOfBytesToRead % 8 )
310 {
311 NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) + 1;
312 }
313 else
314 {
315 NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) ;
316 }
317
318 for( Block = 0; !Found && Block < Ext2Align( NumberOfBytesToRead , LogicalBlockSize );
319 Block += LogicalBlockSize, VolumeByteOffset.QuadPart += LogicalBlockSize)
320 {
321 //
322 // Read in the bitmap block...
323 //
324 ULONG i, j;
325 BYTE Bitmap;
326
327 if( !CcPinRead( PtrVCB->PtrStreamFileObject,
328 &VolumeByteOffset,
329 LogicalBlockSize, //NumberOfBytesToRead,
330 TRUE,
331 &PtrBitmapBCB,
332 (PVOID*)&PtrBitmapBuffer ) )
333 {
334 DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0);
335 return 0;
336 }
337
338 //
339 // Is there a free inode...
340 //
341 for( i = 0; !Found && i < LogicalBlockSize &&
342 i + (Block * LogicalBlockSize) < NumberOfBytesToRead; i++ )
343 {
344 Bitmap = PtrBitmapBuffer[i];
345 if( Bitmap != 0xff )
346 {
347 //
348 // Found a free inode...
349 for( j = 0; !Found && j < 8; j++ )
350 {
351 if( ( Bitmap & 0x01 ) == 0 )
352 {
353 //
354 // Found...
355 Found = TRUE;
356
357 // Inode numbers start at 1 and not from 0
358 // Hence 1 is addded to j
359 InodeNo = ( ( ( Block * LogicalBlockSize) + i ) * 8) + j + 1 +
360 ( GroupNo * PtrVCB->InodesPerGroup );
361
362 // Update the inode on the disk...
363 Bitmap = 1 << j;
364 PtrBitmapBuffer[i] |= Bitmap;
365
366 CcSetDirtyPinnedData( PtrBitmapBCB, NULL );
367 Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject );
368
369 //
370 // Should update the bitmaps in the other groups too...
371 //
372 break;
373 }
374 Bitmap = Bitmap >> 1;
375 }
376 }
377 }
378 //
379 // Unpin the BCB...
380 //
381 if( PtrBitmapBCB )
382 {
383 CcUnpinData( PtrBitmapBCB );
384 PtrBitmapBCB = NULL;
385 }
386 }
387
388 {
389 //
390 // Updating the Inode count in the Group Descriptor...
391 //
392 PBCB PtrDescriptorBCB = NULL;
393 PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL;
394
395 PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount--;
396
397 if( PtrVCB->LogBlockSize )
398 {
399 // First block contains the descriptors...
400 VolumeByteOffset.QuadPart = LogicalBlockSize;
401 }
402 else
403 {
404 // Second block contains the descriptors...
405 VolumeByteOffset.QuadPart = LogicalBlockSize * 2;
406 }
407 NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc );
408 NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
409
410 if (!CcPinRead( PtrVCB->PtrStreamFileObject,
411 &VolumeByteOffset,
412 NumberOfBytesToRead,
413 TRUE,
414 &PtrDescriptorBCB ,
415 (PVOID*)&PtrGroupDescriptor ))
416 {
417 DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0);
418 //
419 // Ignore this error...
420 // Not fatal...
421 }
422 else
423 {
424 PtrGroupDescriptor[ GroupNo ].bg_free_inodes_count =
425 PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount;
426 //
427 // Not synchronously flushing this information...
428 // Lazy writing will do...
429 //
430 CcSetDirtyPinnedData( PtrDescriptorBCB, NULL );
431 CcUnpinData( PtrDescriptorBCB );
432 PtrDescriptorBCB = NULL;
433 }
434 }
435
436
437 //
438 // Update the Inode count...
439 // in the Super Block...
440 //
441 {
442 // Ext2 Super Block information...
443 PEXT2_SUPER_BLOCK PtrSuperBlock = NULL;
444 PBCB PtrSuperBlockBCB = NULL;
445
446 PtrVCB->FreeInodesCount--;
447 // Reading in the super block...
448 VolumeByteOffset.QuadPart = 1024;
449
450 // THis shouldn't be more than a block in size...
451 NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize );
452
453 if( !CcPinRead( PtrVCB->PtrStreamFileObject,
454 &VolumeByteOffset,
455 NumberOfBytesToRead,
456 TRUE,
457 &PtrSuperBlockBCB,
458 (PVOID*)&PtrSuperBlock ) )
459 {
460 DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0);
461 }
462 else
463 {
464 PtrSuperBlock->s_free_inodes_count = PtrVCB->FreeInodesCount;
465 CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL );
466 Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject );
467 if( PtrSuperBlockBCB )
468 {
469 CcUnpinData( PtrSuperBlockBCB );
470 PtrSuperBlockBCB = NULL;
471 }
472
473 }
474 }
475
476 try_exit: NOTHING;
477 }
478 finally
479 {
480 if( PtrBitmapBCB )
481 {
482 CcUnpinData( PtrBitmapBCB );
483 PtrBitmapBCB = NULL;
484 }
485 }
486 DebugTrace( DEBUG_TRACE_SPECIAL, " Allocating an inode - I-Node no : %ld", InodeNo );
487
488 return InodeNo;
489
490 }
491
492 /*************************************************************************
493 *
494 * Function: Ext2DeallocInode()
495 *
496 * Description:
497 * The functions will deallocate an i-node
498 *
499 * Expected Interrupt Level (for execution) :
500 * IRQL_PASSIVE_LEVEL
501 *
502 * Return Value: Success / Failure...
503 *
504 *************************************************************************/
505 BOOLEAN Ext2DeallocInode(
506 PtrExt2IrpContext PtrIrpContext,
507 PtrExt2VCB PtrVCB,
508 ULONG INodeNo )
509 {
510 BOOLEAN RC = TRUE;
511
512 // Buffer Control Block
513 PBCB PtrBitmapBCB = NULL;
514 BYTE * PtrBitmapBuffer = NULL;
515
516 LARGE_INTEGER VolumeByteOffset;
517 ULONG LogicalBlockSize = 0;
518
519 DebugTrace( DEBUG_TRACE_SPECIAL, " Deallocating an inode - I-Node no : %ld", INodeNo );
520
521 try
522 {
523 ULONG BlockIndex ;
524 ULONG BitmapIndex;
525 ULONG GroupNo;
526 BYTE Bitmap;
527
528 LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
529
530 GroupNo = INodeNo / PtrVCB->InodesPerGroup;
531 INodeNo = INodeNo % PtrVCB->InodesPerGroup;
532
533 BitmapIndex = (INodeNo-1) / 8;
534 Bitmap = 1 << ( (INodeNo-1) % 8 );
535 BlockIndex = BitmapIndex / LogicalBlockSize;
536 // Adjusting to index into the Logical block that contains the bitmap
537 BitmapIndex = BitmapIndex - ( BlockIndex * LogicalBlockSize );
538
539 VolumeByteOffset.QuadPart =
540 ( PtrVCB->PtrGroupDescriptors[ GroupNo ].InodeBitmapBlock + BlockIndex )
541 * LogicalBlockSize;
542
543 //
544 // Read in the bitmap block...
545 //
546 if( !CcPinRead( PtrVCB->PtrStreamFileObject,
547 &VolumeByteOffset,
548 LogicalBlockSize, // Just the block that contains the bitmap will do...
549 TRUE, // Can Wait...
550 &PtrBitmapBCB,
551 (PVOID*)&PtrBitmapBuffer ) )
552 {
553 // Unable to Pin the data into the cache...
554 try_return (RC = FALSE);
555 }
556
557 //
558 // Locate the inode...
559 // This inode is in the byte PtrBitmapBuffer[ BitmapIndex ]
560 if( ( PtrBitmapBuffer[ BitmapIndex ] & Bitmap ) == 0)
561 {
562 // This shouldn't have been so...
563 // The inode was never allocated!
564 // How to deallocate something that hasn't been allocated?
565 // Hmmm... ;)
566 // Ignore this error...
567 try_return (RC = TRUE);
568 }
569
570
571 // Setting the bit for the inode...
572 PtrBitmapBuffer[ BitmapIndex ] &= (~Bitmap);
573
574 // Update the cache...
575 CcSetDirtyPinnedData( PtrBitmapBCB, NULL );
576
577 // Save up the BCB for forcing a synchronous write...
578 // Before completing the IRP...
579 Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject );
580
581
582 if( PtrBitmapBCB )
583 {
584 CcUnpinData( PtrBitmapBCB );
585 PtrBitmapBCB = NULL;
586 }
587
588 {
589 //
590 // Updating the Inode count in the Group Descriptor...
591 //
592 PBCB PtrDescriptorBCB = NULL;
593 PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL;
594 ULONG NumberOfBytesToRead = 0;
595
596 PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount++;
597
598 if( PtrVCB->LogBlockSize )
599 {
600 // First block contains the descriptors...
601 VolumeByteOffset.QuadPart = LogicalBlockSize;
602 }
603 else
604 {
605 // Second block contains the descriptors...
606 VolumeByteOffset.QuadPart = LogicalBlockSize * 2;
607 }
608 NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc );
609 NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
610
611 if (!CcPinRead( PtrVCB->PtrStreamFileObject,
612 &VolumeByteOffset,
613 NumberOfBytesToRead,
614 TRUE,
615 &PtrDescriptorBCB ,
616 (PVOID*)&PtrGroupDescriptor ))
617 {
618 DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0);
619 //
620 // Ignore this error...
621 // Not fatal...
622 }
623 else
624 {
625 PtrGroupDescriptor[ GroupNo ].bg_free_inodes_count =
626 PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount;
627 //
628 // Not synchronously flushing this information...
629 // Lazy writing will do...
630 //
631 CcSetDirtyPinnedData( PtrDescriptorBCB, NULL );
632 CcUnpinData( PtrDescriptorBCB );
633 PtrDescriptorBCB = NULL;
634 }
635 }
636
637
638 //
639 // Update the Inode count...
640 // in the Super Block
641 // and in the VCB
642 //
643 {
644 // Ext2 Super Block information...
645 PEXT2_SUPER_BLOCK PtrSuperBlock = NULL;
646 PBCB PtrSuperBlockBCB = NULL;
647 ULONG NumberOfBytesToRead = 0;
648
649 PtrVCB->FreeInodesCount++;
650
651 // Reading in the super block...
652 VolumeByteOffset.QuadPart = 1024;
653 NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize );
654
655 if( !CcPinRead( PtrVCB->PtrStreamFileObject,
656 &VolumeByteOffset,
657 NumberOfBytesToRead,
658 TRUE,
659 &PtrSuperBlockBCB,
660 (PVOID*)&PtrSuperBlock ) )
661 {
662 DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0);
663 }
664 else
665 {
666 PtrSuperBlock->s_free_inodes_count = PtrVCB->FreeInodesCount;
667 CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL );
668 Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject );
669 if( PtrSuperBlockBCB )
670 {
671 CcUnpinData( PtrSuperBlockBCB );
672 PtrSuperBlockBCB = NULL;
673 }
674
675 }
676 }
677 try_exit: NOTHING;
678 }
679 finally
680 {
681 if( PtrBitmapBCB )
682 {
683 CcUnpinData( PtrBitmapBCB );
684 PtrBitmapBCB = NULL;
685 }
686 }
687 return RC;
688 }
689
690 /*************************************************************************
691 *
692 * Function: Ext2WriteInode()
693 *
694 * Description:
695 * The functions will write an i-node to disk
696 *
697 * Expected Interrupt Level (for execution) :
698 * IRQL_PASSIVE_LEVEL
699 *
700 *
701 * Return Value: Success / Failure...
702 *
703 *************************************************************************/
704 NTSTATUS Ext2WriteInode(
705 PtrExt2IrpContext PtrIrpContext,
706 PtrExt2VCB PtrVcb, // the Volume Control Block
707 uint32 InodeNo, // The Inode no
708 PEXT2_INODE PtrInode // The Inode Buffer
709 )
710 {
711 // The Status to be returned...
712 NTSTATUS RC = STATUS_SUCCESS;
713
714 // The Read Buffer Pointer
715 BYTE * PtrPinnedBuffer = NULL;
716
717 PEXT2_INODE PtrTempInode;
718
719 // Buffer Control Block
720 PBCB PtrBCB = NULL;
721
722 LARGE_INTEGER VolumeByteOffset, TempOffset;
723
724 ULONG LogicalBlockSize = 0;
725 ULONG NumberOfBytesToRead = 0;
726 ULONG Difference = 0;
727 ULONG GroupNo;
728 int Index;
729
730 try
731 {
732 DebugTrace( DEBUG_TRACE_SPECIAL, "Writing and updating an inode - I-Node no : %ld", InodeNo );
733
734 ASSERT(PtrVcb);
735 ASSERT(PtrVcb->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB);
736 GroupNo = InodeNo / PtrVcb->InodesPerGroup;
737
738 if( GroupNo >= PtrVcb->NoOfGroups )
739 {
740 DebugTrace(DEBUG_TRACE_MISC, "&&&&&& Invalid Inode no. Group no %d - too big", GroupNo );
741 DebugTrace(DEBUG_TRACE_MISC, "Only %d groups available on disk", PtrVcb->NoOfGroups );
742 RC = STATUS_UNSUCCESSFUL;
743 try_return( RC );
744 }
745
746 if( PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock == 0 )
747 {
748 DebugTrace(DEBUG_TRACE_MISC, "&&&&&& Inode Table Group Invalid - Group no %d ", GroupNo );
749 RC = STATUS_UNSUCCESSFUL;
750 try_return( RC );
751 }
752
753 Index = ( InodeNo - 1 ) - ( GroupNo * PtrVcb->InodesPerGroup );
754
755 LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVcb->LogBlockSize;
756 NumberOfBytesToRead = sizeof(EXT2_INODE);
757
758 VolumeByteOffset.QuadPart = PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock
759 * LogicalBlockSize + Index * sizeof(EXT2_INODE);
760
761 TempOffset.QuadPart = Ext2Align64( VolumeByteOffset.QuadPart, LogicalBlockSize );
762 if( TempOffset.QuadPart != VolumeByteOffset.QuadPart )
763 {
764 // TempOffset.QuadPart -= LogicalBlockSize;
765 Difference = (LONG) (VolumeByteOffset.QuadPart - TempOffset.QuadPart + LogicalBlockSize );
766 VolumeByteOffset.QuadPart -= Difference;
767 NumberOfBytesToRead += Difference;
768 }
769
770 NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
771
772 if( NumberOfBytesToRead > LogicalBlockSize )
773 {
774 // Multiple blocks being read in...
775 // Can cause overlap
776 // Watch out!!!!
777 Ext2BreakPoint();
778 }
779
780 if( !CcPinRead( PtrVcb->PtrStreamFileObject,
781 &VolumeByteOffset,
782 NumberOfBytesToRead,
783 TRUE, // Can Wait...
784 &PtrBCB,
785 (PVOID*)&PtrPinnedBuffer ) )
786 {
787 RC = STATUS_UNSUCCESSFUL;
788 try_return( RC );
789 }
790 else
791 {
792 RtlCopyMemory( PtrPinnedBuffer + Difference, PtrInode, sizeof(EXT2_INODE) );
793 CcSetDirtyPinnedData( PtrBCB, NULL );
794 Ext2SaveBCB( PtrIrpContext, PtrBCB, PtrVcb->PtrStreamFileObject );
795 }
796
797 try_exit: NOTHING;
798 }
799 finally
800 {
801 if( PtrBCB )
802 {
803 CcUnpinData( PtrBCB );
804 PtrBCB = NULL;
805 }
806
807 }
808 return RC;
809 }
810
811
812 /*************************************************************************
813 *
814 * Function: Ext2MakeNewDirectoryEntry()
815 *
816 * Description:
817 * The functions will make a new directory entry in a directory file...
818 *
819 * Expected Interrupt Level (for execution) :
820 * IRQL_PASSIVE_LEVEL
821 *
822 *
823 * Return Value: Success / Failure...
824 *
825 *************************************************************************/
826 BOOLEAN Ext2MakeNewDirectoryEntry(
827 PtrExt2IrpContext PtrIrpContext, // The Irp context
828 PtrExt2FCB PtrParentFCB, // Parent Folder FCB
829 PFILE_OBJECT PtrFileObject, // Parent Folder Object
830 PUNICODE_STRING PtrName, // New entry's name
831 ULONG Type, // The type of the new entry
832 ULONG NewInodeNo) // The inode no of the new entry...
833 {
834 PBCB PtrLastBlockBCB = NULL;
835 BYTE * PtrLastBlock = NULL;
836 EXT2_DIR_ENTRY DirEntry;
837 PEXT2_DIR_ENTRY PtrTempDirEntry;
838
839 ULONG BlockNo = 0;
840 ULONG i;
841 PtrExt2VCB PtrVCB;
842 LARGE_INTEGER VolumeByteOffset;
843 unsigned long LogicalBlockSize = 0;
844 unsigned long NumberOfBytesToRead = 0;
845 BOOLEAN RC = FALSE;
846
847 USHORT HeaderLength = sizeof( EXT2_DIR_ENTRY );
848 USHORT NewEntryLength = 0;
849 USHORT MinLength = 0;
850 #define ActualLength (PtrTempDirEntry->rec_len)
851 #define NameLength (PtrTempDirEntry->name_len)
852
853 try
854 {
855 ASSERT( PtrFileObject );
856
857 DebugTrace( DEBUG_TRACE_SPECIAL, "Making directory entry: %S", PtrName->Buffer );
858
859 PtrVCB = PtrParentFCB->PtrVCB;
860 AssertVCB( PtrVCB);
861
862 HeaderLength = sizeof( EXT2_DIR_ENTRY ) -
863 (sizeof( char ) * EXT2_NAME_LEN);
864 // 1. Setting up the entry...
865 NewEntryLength = sizeof( EXT2_DIR_ENTRY ) - ( sizeof( char ) * ( EXT2_NAME_LEN - (PtrName->Length / 2) ) );
866 // Length should be a multiplicant of 4
867 NewEntryLength = ((NewEntryLength + 3 ) & 0xfffffffc);
868
869 RtlZeroMemory( &DirEntry, sizeof( EXT2_DIR_ENTRY ) );
870
871 DirEntry.file_type = (BYTE) Type;
872 DirEntry.inode = NewInodeNo;
873 DirEntry.name_len = (BYTE)(PtrName->Length / 2 ); // Does not include a NULL
874
875 // DirEntry.rec_len = (USHORT) NewEntryLength;
876
877 for( i = 0; ; i++ )
878 {
879 if( i < (ULONG)( PtrName->Length / 2 ) )
880 {
881 DirEntry.name[i] = (CHAR) PtrName->Buffer[i];
882 }
883 else
884 {
885 //DirEntry.name[i] = 0; // Entry need not be zero terminated...
886 break;
887 }
888 }
889
890 //
891 // 2. Read the block in the directory...
892 // Initiate Caching...
893 if ( PtrFileObject->PrivateCacheMap == NULL )
894 {
895 CcInitializeCacheMap(
896 PtrFileObject,
897 (PCC_FILE_SIZES)(&(PtrParentFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)),
898 TRUE, // We utilize pin access for directories
899 &(Ext2GlobalData.CacheMgrCallBacks), // callbacks
900 PtrParentFCB ); // The context used in callbacks
901 }
902
903 LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
904 if( PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart > 0 )
905 {
906 BlockNo = (ULONG) ( (PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) / LogicalBlockSize) ;
907 }
908 else
909 {
910 // This directory doesn't have any data blocks...
911 // Allocate a new block...
912 if( !Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrParentFCB, PtrFileObject, TRUE ) )
913 {
914 try_return( RC = FALSE );
915 }
916 else
917 {
918 // Bring in the newly allocated block to the cache...
919 VolumeByteOffset.QuadPart = 0;
920
921 if( !CcPreparePinWrite(
922 PtrFileObject,
923 &VolumeByteOffset,
924 LogicalBlockSize,
925 TRUE, // Zero out the block...
926 TRUE, // Can Wait...
927 &PtrLastBlockBCB,
928 (PVOID*)&PtrLastBlock ) )
929 {
930 try_return( RC = FALSE );
931 }
932
933 DirEntry.rec_len = (USHORT)LogicalBlockSize;
934 RtlCopyBytes( PtrLastBlock, &DirEntry, NewEntryLength);
935 CcSetDirtyPinnedData( PtrLastBlockBCB, NULL );
936 Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject );
937 try_return( RC = TRUE );
938 }
939 }
940
941 VolumeByteOffset.QuadPart = BlockNo * LogicalBlockSize;
942 CcMapData( PtrFileObject,
943 &VolumeByteOffset,
944 LogicalBlockSize,
945 TRUE,
946 &PtrLastBlockBCB,
947 (PVOID*)&PtrLastBlock );
948
949 for( i = 0 ; i < LogicalBlockSize; )
950 {
951 PtrTempDirEntry = (PEXT2_DIR_ENTRY) &PtrLastBlock[ i ];
952
953 MinLength = HeaderLength + NameLength;
954 MinLength = ( HeaderLength + NameLength + 3 ) & 0xfffffffc;
955
956
957 if( PtrTempDirEntry->rec_len == 0 )
958 {
959 if( i == 0 )
960 {
961 // Must be an empty Block...
962 // Insert here...
963 // ---------------->>>
964
965 CcPinMappedData( PtrFileObject,
966 &VolumeByteOffset,
967 LogicalBlockSize,
968 TRUE,
969 &PtrLastBlockBCB );
970
971 DirEntry.rec_len = (USHORT)LogicalBlockSize;
972
973 RtlCopyBytes( PtrLastBlock, &DirEntry, NewEntryLength);
974 CcSetDirtyPinnedData( PtrLastBlockBCB, NULL );
975 Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject );
976 try_return( RC = TRUE );
977 }
978 else
979 {
980 // This shouldn't be so...
981 // Something is wrong...
982 // Fail this request...
983 try_return( RC = FALSE );
984 }
985 }
986 if( ActualLength - MinLength >= NewEntryLength )
987 {
988 // Insert here...
989 // ---------------->
990
991 // Getting ready for updation...
992 CcPinMappedData( PtrFileObject,
993 &VolumeByteOffset,
994 LogicalBlockSize,
995 TRUE,
996 &PtrLastBlockBCB );
997
998
999 DirEntry.rec_len = ActualLength - MinLength;
1000
1001 // Updating the current last entry
1002 PtrTempDirEntry->rec_len = MinLength;
1003 i += PtrTempDirEntry->rec_len;
1004
1005 // Making the new entry...
1006 RtlCopyBytes( (PtrLastBlock + i) , &DirEntry, NewEntryLength);
1007 CcSetDirtyPinnedData( PtrLastBlockBCB, NULL );
1008 Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject );
1009 try_return( RC = TRUE );
1010
1011 }
1012 i += PtrTempDirEntry->rec_len;
1013 }
1014
1015 // Will have to allocate a new block...
1016 // Old block does not have enough space..
1017 if( !Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrParentFCB, PtrFileObject, TRUE ) )
1018 {
1019 try_return( RC = FALSE );
1020 }
1021 else
1022 {
1023 // unpin the previously pinned block
1024 CcUnpinData( PtrLastBlockBCB );
1025 PtrLastBlockBCB = NULL;
1026
1027 // Bring in the newly allocated block to the cache...
1028 VolumeByteOffset.QuadPart += LogicalBlockSize;
1029 if( !CcPreparePinWrite(
1030 PtrFileObject,
1031 &VolumeByteOffset,
1032 LogicalBlockSize,
1033 TRUE, // Zero out the block...
1034 TRUE, // Can Wait...
1035 &PtrLastBlockBCB,
1036 (PVOID*)&PtrLastBlock ) )
1037 {
1038 try_return( RC = FALSE );
1039 }
1040
1041 DirEntry.rec_len = (USHORT)LogicalBlockSize;
1042 RtlCopyBytes( PtrLastBlock, &DirEntry, NewEntryLength);
1043 CcSetDirtyPinnedData( PtrLastBlockBCB, NULL );
1044 Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject );
1045 try_return( RC = TRUE );
1046 }
1047 try_exit: NOTHING;
1048 }
1049 finally
1050 {
1051 if( PtrLastBlockBCB )
1052 {
1053 CcUnpinData( PtrLastBlockBCB );
1054 PtrLastBlockBCB = NULL;
1055 }
1056 }
1057 if( RC == FALSE )
1058 {
1059 DebugTrace( DEBUG_TRACE_ERROR, "Failed to making directory entry: %S", PtrName->Buffer );
1060 }
1061 return RC;
1062 }
1063
1064
1065 BOOLEAN Ext2FreeDirectoryEntry(
1066 PtrExt2IrpContext PtrIrpContext,
1067 PtrExt2FCB PtrParentFCB,
1068 PUNICODE_STRING PtrName)
1069 {
1070
1071 PBCB PtrDataBlockBCB = NULL;
1072 BYTE * PtrDataBlock = NULL;
1073 PFILE_OBJECT PtrFileObject = NULL;
1074 PEXT2_DIR_ENTRY PtrTempDirEntry;
1075 LONGLONG ByteOffset = 0;
1076 PtrExt2VCB PtrVCB;
1077 LARGE_INTEGER VolumeByteOffset;
1078 unsigned long LogicalBlockSize = 0;
1079 BOOLEAN RC = FALSE;
1080
1081
1082 try
1083 {
1084 DebugTrace( DEBUG_TRACE_SPECIAL, "Freeing directory entry: %S", PtrName->Buffer );
1085
1086 PtrVCB = PtrParentFCB->PtrVCB;
1087 AssertVCB( PtrVCB);
1088
1089 LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
1090
1091 PtrFileObject = PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject;
1092 if( PtrFileObject == NULL )
1093 {
1094 return FALSE;
1095 }
1096
1097
1098 //
1099 // 1. Read the block in the directory...
1100 // Initiate Caching...
1101 if ( PtrFileObject->PrivateCacheMap == NULL )
1102 {
1103 CcInitializeCacheMap(
1104 PtrFileObject,
1105 (PCC_FILE_SIZES)(&(PtrParentFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)),
1106 TRUE, // We utilize pin access for directories
1107 &(Ext2GlobalData.CacheMgrCallBacks), // callbacks
1108 PtrParentFCB ); // The context used in callbacks
1109 }
1110
1111 for( ByteOffset = 0;
1112 ByteOffset < PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart;
1113 ByteOffset += LogicalBlockSize )
1114 {
1115 ULONG Index = 0;
1116 PEXT2_DIR_ENTRY PtrDirEntry = NULL;
1117
1118
1119 VolumeByteOffset.QuadPart = ByteOffset;
1120
1121 CcPinRead( PtrFileObject,
1122 &VolumeByteOffset,
1123 LogicalBlockSize,
1124 TRUE,
1125 &PtrDataBlockBCB,
1126 (PVOID*)&PtrDataBlock );
1127 while( Index < LogicalBlockSize )
1128 {
1129 ULONG i;
1130 // Parse...
1131 PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrDataBlock[ Index ];
1132 Index += PtrDirEntry->rec_len;
1133
1134 if( PtrDirEntry->inode == 0 )
1135 {
1136 // This is a deleted entry...
1137 continue;
1138 }
1139 if( ( PtrName->Length/2 ) != PtrDirEntry->name_len )
1140 continue;
1141 for( i = 0; ; i++ )
1142 {
1143 if( PtrDirEntry->name_len == i )
1144 {
1145 // Remove the entry by setting the inode no to zero
1146 PtrDirEntry->inode = 0;
1147
1148 // Update the disk
1149 CcSetDirtyPinnedData( PtrDataBlockBCB , NULL );
1150 Ext2SaveBCB( PtrIrpContext, PtrDataBlockBCB, PtrFileObject );
1151 CcUnpinData( PtrDataBlockBCB );
1152 PtrDataBlockBCB = NULL;
1153
1154 // Return to caller...
1155 try_return( RC = TRUE );
1156 }
1157 if( PtrName->Buffer[i] != PtrDirEntry->name[i] )
1158 {
1159 break;
1160 }
1161 }
1162 }
1163 CcUnpinData( PtrDataBlockBCB );
1164 PtrDataBlockBCB = NULL;
1165 }
1166 try_return( RC = FALSE );
1167
1168 try_exit: NOTHING;
1169 }
1170 finally
1171 {
1172 if( PtrDataBlockBCB )
1173 {
1174 CcUnpinData( PtrDataBlockBCB );
1175 PtrDataBlockBCB = NULL;
1176 }
1177 }
1178 return RC;
1179 }
1180
1181 /*************************************************************************
1182 *
1183 * Function: Ext2AddBlockToFile()
1184 *
1185 * Description:
1186 * The functions will add a block to a file...
1187 * It will update the allocation size but not the file size...
1188 *
1189 * Expected Interrupt Level (for execution) :
1190 * IRQL_PASSIVE_LEVEL
1191 *
1192 *
1193 * Return Value: Success / Failure...
1194 *
1195 *************************************************************************/
1196 BOOLEAN Ext2AddBlockToFile(
1197 PtrExt2IrpContext PtrIrpContext,
1198 PtrExt2VCB PtrVCB,
1199 PtrExt2FCB PtrFCB,
1200 PFILE_OBJECT PtrFileObject,
1201 BOOLEAN UpdateFileSize)
1202 {
1203 BOOLEAN RC = TRUE;
1204
1205 ULONG NewBlockNo = 0;
1206 LARGE_INTEGER VolumeByteOffset;
1207 ULONG LogicalBlockSize = 0;
1208 ULONG NoOfBlocks = 0;
1209 EXT2_INODE Inode;
1210
1211 ULONG DirectBlocks = 0;
1212 ULONG SingleIndirectBlocks = 0;
1213 ULONG DoubleIndirectBlocks = 0;
1214 ULONG TripleIndirectBlocks = 0;
1215
1216 ULONG *PtrSIBBuffer = NULL;
1217 PBCB PtrSIBBCB = NULL;
1218 ULONG *PtrDIBBuffer = NULL;
1219 PBCB PtrDIBBCB = NULL;
1220
1221
1222 LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
1223 DirectBlocks = EXT2_NDIR_BLOCKS ;
1224 SingleIndirectBlocks = LogicalBlockSize / sizeof( ULONG );
1225 DoubleIndirectBlocks = SingleIndirectBlocks * LogicalBlockSize / sizeof( ULONG );
1226 TripleIndirectBlocks = DoubleIndirectBlocks * LogicalBlockSize / sizeof( ULONG );
1227
1228 try
1229 {
1230 if( PtrFCB && PtrFCB->FCBName->ObjectName.Length )
1231 {
1232 DebugTrace( DEBUG_TRACE_SPECIAL, "Adding Blocks to file %S", PtrFCB->FCBName->ObjectName.Buffer );
1233 }
1234
1235 Ext2InitializeFCBInodeInfo( PtrFCB );
1236
1237 // Allocate a block...
1238 NewBlockNo = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 );
1239
1240 if( NewBlockNo == 0 )
1241 {
1242 try_return (RC = FALSE );
1243 }
1244
1245 // No of blocks CURRENTLY allocated...
1246 NoOfBlocks = (ULONG) PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart / LogicalBlockSize;
1247
1248
1249 if( NoOfBlocks < EXT2_NDIR_BLOCKS )
1250 {
1251 //
1252 // A direct data block will do...
1253 //
1254
1255 PtrFCB->IBlock[ NoOfBlocks ] = NewBlockNo;
1256
1257 // Update the inode...
1258 Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode );
1259 Inode.i_block[ NoOfBlocks ] = NewBlockNo;
1260 Inode.i_blocks += ( LogicalBlockSize / 512 );
1261 PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize;
1262 if( UpdateFileSize )
1263 {
1264 Inode.i_size += LogicalBlockSize;
1265 PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize;
1266 }
1267
1268
1269 if( PtrFileObject->PrivateCacheMap != NULL)
1270 {
1271 //
1272 // Caching has been initiated...
1273 // Let the Cache manager in on these changes...
1274 //
1275 CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize));
1276 }
1277
1278
1279 // Updating the inode...
1280 if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
1281 {
1282 try_return (RC = TRUE);
1283 }
1284 else
1285 {
1286 try_return (RC = FALSE );
1287 }
1288
1289 }
1290 else if( NoOfBlocks < (DirectBlocks + SingleIndirectBlocks) )
1291 {
1292 //
1293 // A single indirect data block will do...
1294 Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode );
1295
1296 if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] == 0 )
1297 {
1298 // A Single Indirect block should be allocated as well!!
1299 PtrFCB->IBlock[ EXT2_IND_BLOCK ] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 );
1300 if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] == 0 )
1301 {
1302 try_return (RC = FALSE );
1303 }
1304 Inode.i_blocks += ( LogicalBlockSize / 512 );
1305
1306 // Bring in the new block to the cache
1307 // Zero it out
1308 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize;
1309
1310 if( !CcPreparePinWrite(
1311 PtrVCB->PtrStreamFileObject,
1312 &VolumeByteOffset,
1313 LogicalBlockSize,
1314 TRUE, // Zero out the block...
1315 TRUE, // Can Wait...
1316 &PtrSIBBCB,
1317 (PVOID*)&PtrSIBBuffer ) )
1318 {
1319 try_return( RC = FALSE );
1320 }
1321 }
1322 else
1323 {
1324 // Just bring in the SIB to the cache
1325
1326 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize;
1327
1328 if( !CcPinRead( PtrVCB->PtrStreamFileObject,
1329 &VolumeByteOffset,
1330 LogicalBlockSize,
1331 TRUE, // Can Wait...
1332 &PtrSIBBCB,
1333 (PVOID*)&PtrSIBBuffer ) )
1334 {
1335 try_return( RC = FALSE );
1336 }
1337 }
1338
1339 // Update the inode...
1340
1341 Inode.i_block[ EXT2_IND_BLOCK ] = PtrFCB->IBlock[ EXT2_IND_BLOCK ];
1342 Inode.i_blocks += ( LogicalBlockSize / 512 );
1343 PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize;
1344 if( UpdateFileSize )
1345 {
1346 Inode.i_size += LogicalBlockSize;
1347 PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize;
1348 }
1349 if( PtrFileObject->PrivateCacheMap != NULL)
1350 {
1351 //
1352 // Caching has been initiated...
1353 // Let the Cache manager in on these changes...
1354 //
1355 CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize));
1356 }
1357
1358 if( !NT_SUCCESS( Ext2WriteInode(
1359 PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
1360 {
1361 try_return (RC = FALSE );
1362 }
1363
1364
1365 // Update the SIB...
1366 PtrSIBBuffer[ NoOfBlocks - DirectBlocks ] = NewBlockNo;
1367 CcSetDirtyPinnedData( PtrSIBBCB, NULL );
1368 Ext2SaveBCB( PtrIrpContext, PtrSIBBCB, PtrVCB->PtrStreamFileObject );
1369
1370 try_return (RC = TRUE);
1371
1372 }
1373 else if( NoOfBlocks < (DirectBlocks + SingleIndirectBlocks + DoubleIndirectBlocks ) )
1374 {
1375 //
1376 // A double indirect block will do...
1377 //
1378 ULONG SBlockNo;
1379 ULONG BlockNo;
1380
1381 Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode );
1382
1383 if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] == 0 )
1384 {
1385 // A double indirect pointer block should be allocated as well!!
1386 PtrFCB->IBlock[ EXT2_DIND_BLOCK ] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 );
1387 if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] == 0 )
1388 {
1389 try_return (RC = FALSE );
1390 }
1391 Inode.i_blocks += ( LogicalBlockSize / 512 );
1392
1393 // Bring in the new block to the cache
1394 // Zero it out
1395 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
1396
1397 if( !CcPreparePinWrite(
1398 PtrVCB->PtrStreamFileObject,
1399 &VolumeByteOffset,
1400 LogicalBlockSize,
1401 TRUE, // Zero out the block...
1402 TRUE, // Can Wait...
1403 &PtrDIBBCB,
1404 (PVOID*)&PtrDIBBuffer ) )
1405 {
1406 try_return( RC = FALSE );
1407 }
1408 }
1409 else
1410 {
1411 // Just bring in the DIB to the cache
1412
1413 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
1414
1415 if( !CcPinRead( PtrVCB->PtrStreamFileObject,
1416 &VolumeByteOffset,
1417 LogicalBlockSize,
1418 TRUE, // Can Wait...
1419 &PtrDIBBCB,
1420 (PVOID*)&PtrDIBBuffer ) )
1421 {
1422 try_return( RC = FALSE );
1423 }
1424 }
1425
1426 // See if a single indirect 'pointer' block
1427 // should also be allocated...
1428 BlockNo = ( NoOfBlocks - DirectBlocks - SingleIndirectBlocks );
1429 SBlockNo = BlockNo / SingleIndirectBlocks;
1430 if( BlockNo % SingleIndirectBlocks )
1431 {
1432 // A single indirect 'pointer' block
1433 // should also be allocated...
1434 PtrDIBBuffer[SBlockNo] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 );
1435 CcSetDirtyPinnedData( PtrDIBBCB, NULL );
1436 VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize;
1437
1438 Inode.i_blocks += ( LogicalBlockSize / 512 );
1439
1440 if( !CcPreparePinWrite(
1441 PtrVCB->PtrStreamFileObject,
1442 &VolumeByteOffset,
1443 LogicalBlockSize,
1444 TRUE, // Zero out the block...
1445 TRUE, // Can Wait...
1446 &PtrSIBBCB,
1447 (PVOID*)&PtrSIBBuffer ) )
1448 {
1449 try_return( RC = FALSE );
1450 }
1451 }
1452 else
1453 {
1454 VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize;
1455 if( !CcPinRead( PtrVCB->PtrStreamFileObject,
1456 &VolumeByteOffset,
1457 LogicalBlockSize,
1458 TRUE, // Can Wait...
1459 &PtrSIBBCB,
1460 (PVOID*)&PtrSIBBuffer ) )
1461 {
1462 try_return( RC = FALSE );
1463 }
1464 }
1465 BlockNo = BlockNo % SingleIndirectBlocks;
1466
1467 // Update the inode...
1468
1469 Inode.i_block[ EXT2_DIND_BLOCK ] = PtrFCB->IBlock[ EXT2_DIND_BLOCK ];
1470 Inode.i_blocks += ( LogicalBlockSize / 512 );
1471 PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize;
1472 if( UpdateFileSize )
1473 {
1474 Inode.i_size += LogicalBlockSize;
1475 PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize;
1476 }
1477 if( PtrFileObject->PrivateCacheMap != NULL)
1478 {
1479 //
1480 // Caching has been initiated...
1481 // Let the Cache manager in on these changes...
1482 //
1483 CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize));
1484 }
1485
1486 if( !NT_SUCCESS( Ext2WriteInode(
1487 PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
1488 {
1489 try_return (RC = FALSE );
1490 }
1491
1492
1493 // Update the SIB...
1494 PtrSIBBuffer[ BlockNo ] = NewBlockNo;
1495 CcSetDirtyPinnedData( PtrSIBBCB, NULL );
1496 Ext2SaveBCB( PtrIrpContext, PtrSIBBCB, PtrVCB->PtrStreamFileObject );
1497 Ext2SaveBCB( PtrIrpContext, PtrDIBBCB, PtrVCB->PtrStreamFileObject );
1498
1499 try_return (RC = TRUE);
1500
1501 }
1502 else
1503 {
1504 //
1505 // A Triple Indirect block is required
1506 //
1507 ULONG SBlockNo;
1508 ULONG BlockNo;
1509
1510 // This is not supported as yet...
1511 try_return (RC = FALSE);
1512
1513 Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode );
1514
1515 if( PtrFCB->IBlock[ EXT2_TIND_BLOCK ] == 0 )
1516 {
1517 // A double indirect pointer block should be allocated as well!!
1518 PtrFCB->IBlock[ EXT2_DIND_BLOCK ] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 );
1519 if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] == 0 )
1520 {
1521 try_return (RC = FALSE );
1522 }
1523 Inode.i_blocks += ( LogicalBlockSize / 512 );
1524
1525 // Bring in the new block to the cache
1526 // Zero it out
1527 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
1528
1529 if( !CcPreparePinWrite(
1530 PtrVCB->PtrStreamFileObject,
1531 &VolumeByteOffset,
1532 LogicalBlockSize,
1533 TRUE, // Zero out the block...
1534 TRUE, // Can Wait...
1535 &PtrDIBBCB,
1536 (PVOID*)&PtrDIBBuffer ) )
1537 {
1538 try_return( RC = FALSE );
1539 }
1540 }
1541 else
1542 {
1543 // Just bring in the DIB to the cache
1544
1545 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
1546
1547 if( !CcPinRead( PtrVCB->PtrStreamFileObject,
1548 &VolumeByteOffset,
1549 LogicalBlockSize,
1550 TRUE, // Can Wait...
1551 &PtrDIBBCB,
1552 (PVOID*)&PtrDIBBuffer ) )
1553 {
1554 try_return( RC = FALSE );
1555 }
1556 }
1557
1558 // See if a single indirect 'pointer' block
1559 // should also be allocated...
1560 BlockNo = ( NoOfBlocks - DirectBlocks - SingleIndirectBlocks );
1561 SBlockNo = BlockNo / SingleIndirectBlocks;
1562 if( BlockNo % SingleIndirectBlocks )
1563 {
1564 // A single indirect 'pointer' block
1565 // should also be allocated...
1566 PtrDIBBuffer[SBlockNo] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 );
1567 CcSetDirtyPinnedData( PtrDIBBCB, NULL );
1568 VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize;
1569
1570 Inode.i_blocks += ( LogicalBlockSize / 512 );
1571
1572 if( !CcPreparePinWrite(
1573 PtrVCB->PtrStreamFileObject,
1574 &VolumeByteOffset,
1575 LogicalBlockSize,
1576 TRUE, // Zero out the block...
1577 TRUE, // Can Wait...
1578 &PtrSIBBCB,
1579 (PVOID*)&PtrSIBBuffer ) )
1580 {
1581 try_return( RC = FALSE );
1582 }
1583 }
1584 else
1585 {
1586 VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize;
1587 if( !CcPinRead( PtrVCB->PtrStreamFileObject,
1588 &VolumeByteOffset,
1589 LogicalBlockSize,
1590 TRUE, // Can Wait...
1591 &PtrSIBBCB,
1592 (PVOID*)&PtrSIBBuffer ) )
1593 {
1594 try_return( RC = FALSE );
1595 }
1596 }
1597 BlockNo = BlockNo % SingleIndirectBlocks;
1598
1599 // Update the inode...
1600
1601 Inode.i_block[ EXT2_DIND_BLOCK ] = PtrFCB->IBlock[ EXT2_DIND_BLOCK ];
1602 Inode.i_blocks += ( LogicalBlockSize / 512 );
1603 PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize;
1604 if( UpdateFileSize )
1605 {
1606 Inode.i_size += LogicalBlockSize;
1607 PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize;
1608 }
1609 if( PtrFileObject->PrivateCacheMap != NULL)
1610 {
1611 //
1612 // Caching has been initiated...
1613 // Let the Cache manager in on these changes...
1614 //
1615 CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize));
1616 }
1617
1618 if( !NT_SUCCESS( Ext2WriteInode(
1619 PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
1620 {
1621 try_return (RC = FALSE );
1622 }
1623
1624
1625 // Update the SIB...
1626 PtrSIBBuffer[ BlockNo ] = NewBlockNo;
1627 CcSetDirtyPinnedData( PtrSIBBCB, NULL );
1628 Ext2SaveBCB( PtrIrpContext, PtrSIBBCB, PtrVCB->PtrStreamFileObject );
1629 Ext2SaveBCB( PtrIrpContext, PtrDIBBCB, PtrVCB->PtrStreamFileObject );
1630
1631 try_return (RC = TRUE);
1632
1633 }
1634
1635 try_exit: NOTHING;
1636 }
1637 finally
1638 {
1639 if( PtrSIBBCB )
1640 {
1641 CcUnpinData( PtrSIBBCB );
1642 PtrSIBBCB = NULL;
1643 }
1644 if( PtrDIBBCB )
1645 {
1646 CcUnpinData( PtrDIBBCB );
1647 PtrDIBBCB = NULL;
1648 }
1649 }
1650 return RC;
1651 }
1652
1653 /*************************************************************************
1654 *
1655 * Function: Ext2AllocBlock()
1656 *
1657 * Description:
1658 * The functions will allocate a new block
1659 *
1660 * Expected Interrupt Level (for execution) :
1661 * IRQL_PASSIVE_LEVEL
1662 *
1663 *
1664 * Return Value: Success / Failure...
1665 *
1666 *************************************************************************/
1667 ULONG Ext2AllocBlock(
1668 PtrExt2IrpContext PtrIrpContext,
1669 PtrExt2VCB PtrVCB,
1670 ULONG Count)
1671 {
1672 // Buffer Control Block
1673 PBCB PtrBitmapBCB = NULL;
1674 BYTE * PtrBitmapBuffer = NULL;
1675 ULONG BlockNo = 0;
1676 LARGE_INTEGER VolumeByteOffset;
1677 ULONG LogicalBlockSize = 0;
1678 ULONG NumberOfBytesToRead = 0;
1679
1680 if( PtrVCB->FreeBlocksCount == 0 )
1681 {
1682 //
1683 // No Free Block left...
1684 // Fail request...
1685 //
1686 return 0;
1687 }
1688
1689 try
1690 {
1691 BOOLEAN Found = FALSE;
1692 ULONG Block;
1693 ULONG GroupNo;
1694 LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
1695
1696 for( GroupNo = 0; PtrVCB->NoOfGroups; GroupNo++ )
1697 {
1698 if( PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount )
1699 break;
1700 }
1701
1702 VolumeByteOffset.QuadPart =
1703 PtrVCB->PtrGroupDescriptors[ GroupNo ].BlockBitmapBlock * LogicalBlockSize;
1704
1705 NumberOfBytesToRead = PtrVCB->BlocksCount / PtrVCB->NoOfGroups;
1706
1707 if( NumberOfBytesToRead % 8 )
1708 {
1709 NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) + 1;
1710 }
1711 else
1712 {
1713 NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) ;
1714 }
1715
1716
1717 for( Block = 0; !Found && Block < Ext2Align( NumberOfBytesToRead , LogicalBlockSize );
1718 Block += LogicalBlockSize, VolumeByteOffset.QuadPart += LogicalBlockSize)
1719 {
1720 //
1721 // Read in the block bitmap block...
1722 ULONG i, j;
1723 BYTE Bitmap;
1724
1725 if( !CcPinRead( PtrVCB->PtrStreamFileObject,
1726 &VolumeByteOffset,
1727 LogicalBlockSize, // NumberOfBytesToRead,
1728 TRUE,
1729 &PtrBitmapBCB,
1730 (PVOID*)&PtrBitmapBuffer ) )
1731 {
1732 DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0);
1733 try_return( BlockNo = 0 );
1734 }
1735
1736 //
1737 // Is there a free block...
1738 //
1739 for( i = 0; !Found && i < LogicalBlockSize &&
1740 i + (Block * LogicalBlockSize) < NumberOfBytesToRead; i++ )
1741 {
1742 Bitmap = PtrBitmapBuffer[i];
1743 if( Bitmap != 0xff )
1744 {
1745 //
1746 // Found a free block...
1747 for( j = 0; !Found && j < 8; j++ )
1748 {
1749 if( ( Bitmap & 0x01 ) == 0 )
1750 {
1751 //
1752 // Found...
1753 Found = TRUE;
1754 BlockNo = ( ( ( Block * LogicalBlockSize) + i ) * 8) + j + 1
1755 + ( GroupNo * PtrVCB->BlocksPerGroup );
1756
1757 Bitmap = 1 << j;
1758 PtrBitmapBuffer[i] |= Bitmap;
1759
1760 CcSetDirtyPinnedData( PtrBitmapBCB, NULL );
1761 Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject );
1762 //
1763 // Should update the bitmaps in the other groups too...
1764 //
1765 break;
1766 }
1767 Bitmap = Bitmap >> 1;
1768 }
1769 }
1770 }
1771 //
1772 // Unpin the BCB...
1773 //
1774 if( PtrBitmapBCB )
1775 {
1776 CcUnpinData( PtrBitmapBCB );
1777 PtrBitmapBCB = NULL;
1778 }
1779
1780 }
1781
1782 //
1783 // Updating the Free Block count in the Group Descriptor...
1784 //
1785
1786 {
1787 PBCB PtrDescriptorBCB = NULL;
1788 PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL;
1789 //
1790 // Updating the Free Blocks count in the Group Descriptor...
1791 //
1792 PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount--;
1793
1794 if( PtrVCB->LogBlockSize )
1795 {
1796 // First block contains the descriptors...
1797 VolumeByteOffset.QuadPart = LogicalBlockSize;
1798 }
1799 else
1800 {
1801 // Second block contains the descriptors...
1802 VolumeByteOffset.QuadPart = LogicalBlockSize * 2;
1803 }
1804 NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc );
1805 NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
1806
1807 if (!CcPinRead( PtrVCB->PtrStreamFileObject,
1808 &VolumeByteOffset,
1809 NumberOfBytesToRead,
1810 TRUE,
1811 &PtrDescriptorBCB ,
1812 (PVOID*)&PtrGroupDescriptor ))
1813 {
1814 DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0);
1815 //
1816 // Ignore this error...
1817 // Not fatal...
1818 }
1819 else
1820 {
1821 PtrGroupDescriptor[ GroupNo ].bg_free_blocks_count=
1822 PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount;
1823
1824 //
1825 // Not synchronously flushing this information...
1826 // Lazy writing will do...
1827 //
1828 CcSetDirtyPinnedData( PtrDescriptorBCB, NULL );
1829 CcUnpinData( PtrDescriptorBCB );
1830 PtrDescriptorBCB = NULL;
1831 }
1832 }
1833
1834 //
1835 // Update the Block count
1836 // in the super block and in the VCB
1837 //
1838 {
1839 // Ext2 Super Block information...
1840 PEXT2_SUPER_BLOCK PtrSuperBlock = NULL;
1841 PBCB PtrSuperBlockBCB = NULL;
1842
1843 PtrVCB->FreeBlocksCount--;
1844
1845 // Reading in the super block...
1846 VolumeByteOffset.QuadPart = 1024;
1847 NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize );
1848
1849 if( !CcPinRead( PtrVCB->PtrStreamFileObject,
1850 &VolumeByteOffset,
1851 NumberOfBytesToRead,
1852 TRUE,
1853 &PtrSuperBlockBCB,
1854 (PVOID*)&PtrSuperBlock ) )
1855 {
1856 DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0);
1857 }
1858 else
1859 {
1860 PtrSuperBlock->s_free_blocks_count = PtrVCB->FreeBlocksCount;
1861 CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL );
1862 Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject );
1863 if( PtrSuperBlockBCB )
1864 {
1865 CcUnpinData( PtrSuperBlockBCB );
1866 PtrSuperBlockBCB = NULL;
1867 }
1868 }
1869 }
1870
1871 try_exit: NOTHING;
1872 }
1873 finally
1874 {
1875 if( PtrBitmapBCB )
1876 {
1877 CcUnpinData( PtrBitmapBCB );
1878 PtrBitmapBCB = NULL;
1879 }
1880 DebugTrace( DEBUG_TRACE_SPECIAL, " Allocating a block - Block no : %ld", BlockNo );
1881 }
1882 return BlockNo;
1883 }
1884
1885 /*************************************************************************
1886 *
1887 * Function: Ext2DeallocBlock()
1888 *
1889 * Description:
1890 * The functions will deallocate a data block
1891 *
1892 * Expected Interrupt Level (for execution) :
1893 * IRQL_PASSIVE_LEVEL
1894 *
1895 * Return Value: Success / Failure...
1896 *
1897 *************************************************************************/
1898 BOOLEAN Ext2DeallocBlock(
1899 PtrExt2IrpContext PtrIrpContext,
1900 PtrExt2VCB PtrVCB,
1901 ULONG BlockNo )
1902 {
1903 // Buffer Control Block
1904 PBCB PtrBitmapBCB = NULL;
1905 BYTE * PtrBitmapBuffer = NULL;
1906 BOOLEAN RC = TRUE;
1907 LARGE_INTEGER VolumeByteOffset;
1908 ULONG LogicalBlockSize = 0;
1909 // ULONG NumberOfBytesToRead = 0;
1910
1911 DebugTrace( DEBUG_TRACE_SPECIAL, " Deallocating a block - Block no : %ld", BlockNo );
1912
1913 try
1914 {
1915 ULONG GroupNo;
1916 ULONG BlockIndex;
1917 ULONG BitmapIndex;
1918 BYTE Bitmap;
1919
1920 LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
1921
1922 GroupNo = BlockNo / PtrVCB->BlocksPerGroup;
1923 BlockNo = BlockNo % PtrVCB->BlocksPerGroup;
1924
1925 Bitmap = 1 << ( (BlockNo-1) % 8 );
1926 BitmapIndex = (BlockNo-1) / 8;
1927 BlockIndex = BitmapIndex / LogicalBlockSize;
1928 // Adjusting to index into the Logical block that contains the bitmap
1929 BitmapIndex = BitmapIndex - ( BlockIndex * LogicalBlockSize );
1930
1931 VolumeByteOffset.QuadPart =
1932 ( PtrVCB->PtrGroupDescriptors[ GroupNo ].BlockBitmapBlock + BlockIndex )
1933 * LogicalBlockSize;
1934
1935 //
1936 // Read in the bitmap block...
1937 //
1938 if( !CcPinRead( PtrVCB->PtrStreamFileObject,
1939 &VolumeByteOffset,
1940 LogicalBlockSize,
1941 TRUE, // Can Wait...
1942 &PtrBitmapBCB,
1943 (PVOID*)&PtrBitmapBuffer ) )
1944 {
1945 // Unable to Pin the data into the cache...
1946 try_return (RC = FALSE);
1947 }
1948
1949 //
1950 // Locate the block 'bit'...
1951 // This block 'bit' is in the byte PtrBitmapBuffer[ BitmapIndex ]
1952 if( ( PtrBitmapBuffer[ BitmapIndex ] & Bitmap ) == 0)
1953 {
1954 // This shouldn't have been so...
1955 // The block was never allocated!
1956 // How to deallocate something that hasn't been allocated?
1957 // Hmmm... ;)
1958 // Ignore this error...
1959 try_return (RC = TRUE);
1960 }
1961
1962 // Setting the bit for the inode...
1963 PtrBitmapBuffer[ BitmapIndex ] &= (~Bitmap);
1964
1965 // Update the cache...
1966 CcSetDirtyPinnedData( PtrBitmapBCB, NULL );
1967
1968 // Save up the BCB for forcing a synchronous write...
1969 // Before completing the IRP...
1970 Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject );
1971
1972
1973 if( PtrBitmapBCB )
1974 {
1975 CcUnpinData( PtrBitmapBCB );
1976 PtrBitmapBCB = NULL;
1977 }
1978
1979 //
1980 // Updating the Block count in the Group Descriptor...
1981 //
1982
1983 {
1984 PBCB PtrDescriptorBCB = NULL;
1985 PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor = NULL;
1986 ULONG NumberOfBytesToRead = 0;
1987 //
1988 // Updating the Free Blocks count in the Group Descriptor...
1989 //
1990 PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount++;
1991
1992 if( PtrVCB->LogBlockSize )
1993 {
1994 // First block contains the descriptors...
1995 VolumeByteOffset.QuadPart = LogicalBlockSize;
1996 }
1997 else
1998 {
1999 // Second block contains the descriptors...
2000 VolumeByteOffset.QuadPart = LogicalBlockSize * 2;
2001 }
2002 NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc );
2003 NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
2004
2005 if (!CcPinRead( PtrVCB->PtrStreamFileObject,
2006 &VolumeByteOffset,
2007 NumberOfBytesToRead,
2008 TRUE,
2009 &PtrDescriptorBCB ,
2010 (PVOID*)&PtrGroupDescriptor ))
2011 {
2012 DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0);
2013 //
2014 // Ignore this error...
2015 // Not fatal...
2016 }
2017 else
2018 {
2019 PtrGroupDescriptor[ GroupNo ].bg_free_blocks_count=
2020 PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount;
2021
2022 //
2023 // Not synchronously flushing this information...
2024 // Lazy writing will do...
2025 //
2026 CcSetDirtyPinnedData( PtrDescriptorBCB, NULL );
2027 CcUnpinData( PtrDescriptorBCB );
2028 PtrDescriptorBCB = NULL;
2029 }
2030 }
2031
2032 //
2033 // Update the Block count
2034 // in the super block and in the VCB
2035 //
2036 {
2037 // Ext2 Super Block information...
2038 PEXT2_SUPER_BLOCK PtrSuperBlock = NULL;
2039 PBCB PtrSuperBlockBCB = NULL;
2040 ULONG NumberOfBytesToRead = 0;
2041
2042 PtrVCB->FreeBlocksCount++;
2043
2044 // Reading in the super block...
2045 VolumeByteOffset.QuadPart = 1024;
2046 NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize );
2047
2048 if( !CcPinRead( PtrVCB->PtrStreamFileObject,
2049 &VolumeByteOffset,
2050 NumberOfBytesToRead,
2051 TRUE,
2052 &PtrSuperBlockBCB,
2053 (PVOID*)&PtrSuperBlock ) )
2054 {
2055 DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0);
2056 }
2057 else
2058 {
2059 PtrSuperBlock->s_free_blocks_count = PtrVCB->FreeBlocksCount;
2060 CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL );
2061 Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject );
2062 CcUnpinData( PtrSuperBlockBCB );
2063 PtrSuperBlockBCB = NULL;
2064 }
2065 }
2066 try_exit: NOTHING;
2067 }
2068 finally
2069 {
2070 if( PtrBitmapBCB )
2071 {
2072 CcUnpinData( PtrBitmapBCB );
2073 PtrBitmapBCB = NULL;
2074 }
2075 }
2076 return RC;
2077 }
2078
2079 BOOLEAN Ext2UpdateFileSize(
2080 PtrExt2IrpContext PtrIrpContext,
2081 PFILE_OBJECT PtrFileObject,
2082 PtrExt2FCB PtrFCB)
2083 {
2084 EXT2_INODE Inode;
2085 PtrExt2VCB PtrVCB = PtrFCB->PtrVCB;
2086
2087 if( PtrFileObject->PrivateCacheMap )
2088 {
2089 CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize));
2090 }
2091 // Now update the size on the disk...
2092 // Read in the inode...
2093 if( ! NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
2094 {
2095 return FALSE;
2096 }
2097
2098 Inode.i_size = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart;
2099 // Update time also???
2100
2101 // Updating the inode...
2102 if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
2103 {
2104 return TRUE;
2105 }
2106 else
2107 {
2108 return FALSE;
2109 }
2110 }
2111
2112 /*************************************************************************
2113 *
2114 * Function: Ext2DeleteFile()
2115 *
2116 * Description:
2117 * The functions will delete a file
2118 *
2119 * Expected Interrupt Level (for execution) :
2120 * IRQL_PASSIVE_LEVEL
2121 *
2122 * Return Value: Success / Failure...
2123 *
2124 *************************************************************************/
2125 BOOLEAN Ext2DeleteFile(
2126 PtrExt2FCB PtrFCB,
2127 PtrExt2IrpContext PtrIrpContext)
2128 {
2129 EXT2_INODE Inode;
2130 PtrExt2FCB PtrParentFCB = NULL;
2131 PtrExt2VCB PtrVCB = PtrFCB->PtrVCB;
2132
2133 //
2134 // Get the Parent Directory...
2135 PtrParentFCB = Ext2LocateFCBInCore( PtrVCB, PtrFCB->ParentINodeNo );
2136 Ext2InitializeFCBInodeInfo( PtrFCB );
2137
2138 // 1.
2139 // Free up the directory entry...
2140 if( !Ext2FreeDirectoryEntry( PtrIrpContext,
2141 PtrParentFCB, &PtrFCB->FCBName->ObjectName ) )
2142 {
2143 return FALSE;
2144 }
2145
2146 // 2.
2147 // Decrement Link count...
2148 if( !NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
2149 {
2150 return FALSE;
2151 }
2152
2153 ASSERT( Inode.i_links_count == PtrFCB->LinkCount );
2154
2155 Inode.i_links_count--;
2156 PtrFCB->LinkCount = Inode.i_links_count;
2157
2158 if( !Inode.i_links_count )
2159 {
2160 //
2161 // Setting the deletion time field in the inode...
2162 //
2163 ULONG Time;
2164 Time = Ext2GetCurrentTime();
2165 Inode.i_dtime = Time ;
2166 }
2167
2168 // 3.
2169 // Updating the inode...
2170
2171 if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
2172 {
2173 if( Inode.i_links_count )
2174 {
2175 // Some more links to the same file are available...
2176 // So we won't deallocate the data blocks...
2177 return TRUE;
2178 }
2179 }
2180 else
2181 {
2182 return FALSE;
2183 }
2184
2185 // 4.
2186 // Free up the inode...
2187 Ext2DeallocInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo );
2188
2189 // 5.
2190 // Release the data blocks...
2191 Ext2ReleaseDataBlocks( PtrFCB, PtrIrpContext);
2192
2193 return TRUE;
2194 }
2195
2196
2197 /*************************************************************************
2198 *
2199 * Function: Ext2ReleaseDataBlocks()
2200 *
2201 * Description:
2202 * The functions will release all the data blocks in a file
2203 * It does NOT update the file inode...
2204 *
2205 * Expected Interrupt Level (for execution) :
2206 * IRQL_PASSIVE_LEVEL
2207 *
2208 * Return Value: Success / Failure...
2209 *
2210 *************************************************************************/
2211 BOOLEAN Ext2ReleaseDataBlocks(
2212 PtrExt2FCB PtrFCB,
2213 PtrExt2IrpContext PtrIrpContext)
2214 {
2215 PtrExt2VCB PtrVCB = PtrFCB->PtrVCB;
2216 ULONG LogicalBlockSize;
2217 ULONG i;
2218
2219
2220 LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
2221
2222 // Release the data blocks...
2223
2224 // 1.
2225 // Free up the triple indirect blocks...
2226 if( PtrFCB->IBlock[ EXT2_TIND_BLOCK ] )
2227 {
2228
2229 PBCB PtrSIBCB = NULL;
2230 PBCB PtrDIBCB = NULL;
2231 PBCB PtrTIBCB = NULL;
2232
2233 ULONG * PtrPinnedSIndirectBlock = NULL;
2234 ULONG * PtrPinnedDIndirectBlock = NULL;
2235 ULONG * PtrPinnedTIndirectBlock = NULL;
2236
2237 LARGE_INTEGER VolumeByteOffset;
2238 ULONG TIndex, DIndex, SIndex;
2239
2240 // Pin the Double Indirect Pointer Block...
2241 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_TIND_BLOCK ] * LogicalBlockSize;
2242 if (!CcMapData( PtrVCB->PtrStreamFileObject,
2243 &VolumeByteOffset,
2244 LogicalBlockSize,
2245 TRUE,
2246 &PtrTIBCB,
2247 (PVOID*)&PtrPinnedTIndirectBlock ))
2248 {
2249 return FALSE;
2250 }
2251
2252 // Read the Block numbers off the Triple Indirect Pointer Block...
2253 for( TIndex = 0; TIndex < (LogicalBlockSize/sizeof(ULONG)); TIndex++ )
2254 {
2255 if( PtrPinnedTIndirectBlock[ TIndex ] )
2256 {
2257 VolumeByteOffset.QuadPart = PtrPinnedTIndirectBlock[TIndex] * LogicalBlockSize;
2258 if (!CcMapData( PtrVCB->PtrStreamFileObject,
2259 &VolumeByteOffset,
2260 LogicalBlockSize,
2261 TRUE,
2262 &PtrDIBCB,
2263 (PVOID*)&PtrPinnedDIndirectBlock ))
2264 {
2265 return FALSE;
2266 }
2267
2268 // Read the Block numbers off the Double Indirect Pointer Blocks...
2269 for( DIndex = 0; DIndex < (LogicalBlockSize/sizeof(ULONG)); DIndex++ )
2270 {
2271 if( PtrPinnedDIndirectBlock[DIndex] )
2272 {
2273 VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[DIndex] * LogicalBlockSize;
2274 if (!CcMapData( PtrVCB->PtrStreamFileObject,
2275 &VolumeByteOffset,
2276 LogicalBlockSize,
2277 TRUE,
2278 &PtrSIBCB,
2279 (PVOID*)&PtrPinnedSIndirectBlock ))
2280 {
2281 return FALSE;
2282 }
2283
2284 // Read the Block numbers off the Single Indirect Pointer Blocks and
2285 // free the data blocks
2286 for( SIndex = 0; SIndex < (LogicalBlockSize/sizeof(ULONG)); SIndex++ )
2287 {
2288 if( PtrPinnedSIndirectBlock[ SIndex ] )
2289 {
2290 Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[SIndex] );
2291 }
2292 else
2293 {
2294 break;
2295 }
2296 }
2297 CcUnpinData( PtrSIBCB );
2298
2299 // Deallocating
2300 // Single Indirect Pointer Block
2301 Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedDIndirectBlock[DIndex] );
2302 }
2303 else
2304 {
2305 break;
2306 }
2307 }
2308 }
2309 else
2310 {
2311 break;
2312 }
2313 }
2314 CcUnpinData( PtrTIBCB );
2315 // Deallocating Triple Indirect Pointer Blocks
2316 Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_TIND_BLOCK ] );
2317 }
2318
2319 // 2.
2320 // Free up the double indirect blocks...
2321 if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] )
2322 {
2323 PBCB PtrDIBCB = NULL;
2324 PBCB PtrSIBCB = NULL;
2325 ULONG * PtrPinnedSIndirectBlock = NULL;
2326 ULONG * PtrPinnedDIndirectBlock = NULL;
2327
2328 LARGE_INTEGER VolumeByteOffset;
2329 ULONG DIndex, SIndex;
2330
2331 // Pin the Double Indirect Pointer Block...
2332 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
2333 if (!CcMapData( PtrVCB->PtrStreamFileObject,
2334 &VolumeByteOffset,
2335 LogicalBlockSize,
2336 TRUE,
2337 &PtrDIBCB,
2338 (PVOID*)&PtrPinnedDIndirectBlock ))
2339 {
2340 return FALSE;
2341 }
2342
2343 // Read the Block numbers off the Double Indirect Pointer Block...
2344 for( DIndex = 0; DIndex < (LogicalBlockSize/sizeof(ULONG)); DIndex++ )
2345 {
2346 if( PtrPinnedDIndirectBlock[DIndex] )
2347 {
2348 VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[DIndex] * LogicalBlockSize;
2349 if (!CcMapData( PtrVCB->PtrStreamFileObject,
2350 &VolumeByteOffset,
2351 LogicalBlockSize,
2352 TRUE,
2353 &PtrSIBCB,
2354 (PVOID*)&PtrPinnedSIndirectBlock ))
2355 {
2356 return FALSE;
2357 }
2358
2359 // Read the Block numbers off the Single Indirect Pointer Blocks and
2360 // free the data blocks
2361 for( SIndex = 0; SIndex < (LogicalBlockSize/sizeof(ULONG)); SIndex++ )
2362 {
2363 if( PtrPinnedSIndirectBlock[ SIndex ] )
2364 {
2365 Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[SIndex] );
2366 }
2367 else
2368 {
2369 break;
2370 }
2371 }
2372 CcUnpinData( PtrSIBCB );
2373
2374 // Deallocating
2375 // Single Indirect Pointer Block
2376 Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedDIndirectBlock[DIndex] );
2377 }
2378 else
2379 {
2380 break;
2381 }
2382 }
2383 CcUnpinData( PtrDIBCB );
2384 // Deallocating Double Indirect Pointer Blocks
2385 Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_DIND_BLOCK ] );
2386 }
2387
2388 // 3.
2389 // Free up the single indirect blocks...
2390 if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] )
2391 {
2392 PBCB PtrBCB = NULL;
2393 ULONG * PtrPinnedSIndirectBlock = NULL;
2394 LARGE_INTEGER VolumeByteOffset;
2395 ULONG Index;
2396
2397 // Pin the Single Indirect Pointer Block...
2398 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize;
2399 if (!CcMapData( PtrVCB->PtrStreamFileObject,
2400 &VolumeByteOffset,
2401 LogicalBlockSize,
2402 TRUE,
2403 &PtrBCB,
2404 (PVOID*)&PtrPinnedSIndirectBlock ))
2405 {
2406 return FALSE;
2407 }
2408
2409 // Read the Block numbers off the Indirect Pointer Block and
2410 // free the data blocks
2411 for( Index = 0; Index < (LogicalBlockSize/sizeof(ULONG)); Index++ )
2412 {
2413 if( PtrPinnedSIndirectBlock[Index] )
2414 {
2415 Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[Index] );
2416 }
2417 else
2418 {
2419 break;
2420 }
2421 }
2422 CcUnpinData( PtrBCB );
2423 Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_IND_BLOCK ] );
2424 }
2425
2426 // 4.
2427 // Free up the direct blocks...
2428 for( i = 0; i < EXT2_NDIR_BLOCKS; i++ )
2429 {
2430 if( PtrFCB->IBlock[ i ] )
2431 {
2432 Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ i ] );
2433 }
2434 else
2435 {
2436 break;
2437 }
2438 }
2439 return TRUE;
2440 }
2441
2442
2443 BOOLEAN Ext2TruncateFileAllocationSize(
2444 PtrExt2IrpContext PtrIrpContext,
2445 PtrExt2FCB PtrFCB,
2446 PFILE_OBJECT PtrFileObject,
2447 PLARGE_INTEGER PtrAllocationSize )
2448 {
2449 PtrExt2VCB PtrVCB = PtrFCB->PtrVCB;
2450 ULONG LogicalBlockSize;
2451 ULONG i;
2452
2453 ULONG NoOfBlocksToBeLeft= 0;
2454 ULONG CurrentBlockNo = 0;
2455
2456 //
2457 // This function has not been tested...
2458 //
2459 Ext2BreakPoint();
2460
2461 LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
2462 NoOfBlocksToBeLeft = (ULONG) (PtrAllocationSize->QuadPart / LogicalBlockSize);
2463
2464
2465
2466 // Release the data blocks...
2467
2468 // 1.
2469 // Free up the direct blocks...
2470 for( i = NoOfBlocksToBeLeft; i < EXT2_NDIR_BLOCKS; i++ )
2471 {
2472 if( PtrFCB->IBlock[ i ] )
2473 {
2474 Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ i ] );
2475 PtrFCB->IBlock[ i ] = 0;
2476 }
2477 else
2478 {
2479 break;
2480 }
2481 }
2482
2483 // 2.
2484 // Free up the single indirect blocks...
2485 CurrentBlockNo = EXT2_NDIR_BLOCKS;
2486
2487 if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] )
2488 {
2489 PBCB PtrBCB = NULL;
2490 ULONG * PtrPinnedSIndirectBlock = NULL;
2491 LARGE_INTEGER VolumeByteOffset;
2492 ULONG Index;
2493
2494 // Pin the Single Indirect Pointer Block...
2495 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize;
2496 if (!CcMapData( PtrVCB->PtrStreamFileObject,
2497 &VolumeByteOffset,
2498 LogicalBlockSize,
2499 TRUE,
2500 &PtrBCB,
2501 (PVOID*)&PtrPinnedSIndirectBlock ))
2502 {
2503 return FALSE;
2504 }
2505
2506 // Read the Block numbers off the Indirect Pointer Block and
2507 // free the data blocks
2508 for( Index = 0; Index < (LogicalBlockSize/sizeof(ULONG));
2509 Index++, CurrentBlockNo++ )
2510 {
2511 if( CurrentBlockNo >= NoOfBlocksToBeLeft )
2512 {
2513 if( PtrPinnedSIndirectBlock[Index] )
2514 {
2515 Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[Index] );
2516 }
2517 else
2518 {
2519 break;
2520 }
2521 }
2522 else if( !PtrPinnedSIndirectBlock[Index] )
2523 {
2524 break;
2525 }
2526 }
2527 if( NoOfBlocksToBeLeft <= EXT2_NDIR_BLOCKS )
2528 {
2529 Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_IND_BLOCK ] );
2530 PtrFCB->IBlock[ EXT2_IND_BLOCK ] = 0;
2531 }
2532
2533 CcUnpinData( PtrBCB );
2534 }
2535
2536 // 3.
2537 // Free up the double indirect blocks...
2538 if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] )
2539 {
2540
2541 }
2542
2543 // 4.
2544 // Free up the triple indirect blocks...
2545 if( PtrFCB->IBlock[ EXT2_TIND_BLOCK ] )
2546 {
2547
2548 }
2549
2550 return TRUE;
2551 }
2552
2553 BOOLEAN Ext2IsDirectoryEmpty(
2554 PtrExt2FCB PtrFCB,
2555 PtrExt2CCB PtrCCB,
2556 PtrExt2IrpContext PtrIrpContext)
2557 {
2558
2559 PFILE_OBJECT PtrFileObject = NULL;
2560
2561 if( !Ext2IsFlagOn(PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY) )
2562 {
2563 return FALSE;
2564 }
2565
2566 // 1.
2567 // Initialize the Blocks in the FCB...
2568 //
2569 Ext2InitializeFCBInodeInfo( PtrFCB );
2570
2571
2572 // 2.
2573 // Get hold of the file object...
2574 //
2575 PtrFileObject = PtrCCB->PtrFileObject;
2576
2577
2578 // 3.
2579 // Now initiating Caching, pinned access to be precise ...
2580 //
2581 if (PtrFileObject->PrivateCacheMap == NULL)
2582 {
2583 CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)),
2584 TRUE, // We utilize pin access for directories
2585 &(Ext2GlobalData.CacheMgrCallBacks), // callbacks
2586 PtrFCB ); // The context used in callbacks
2587 }
2588
2589 // 4.
2590 // Getting down to the real business now... ;)
2591 // Read in the directory contents and do a search
2592 //
2593 {
2594 LARGE_INTEGER StartBufferOffset;
2595 ULONG PinBufferLength;
2596 ULONG BufferIndex;
2597 PBCB PtrBCB = NULL;
2598 BYTE * PtrPinnedBlockBuffer = NULL;
2599 PEXT2_DIR_ENTRY PtrDirEntry = NULL;
2600 BOOLEAN Found = FALSE;
2601 int i;
2602
2603
2604
2605 StartBufferOffset.QuadPart = 0;
2606
2607 //
2608 // Read in the whole directory
2609 // **Bad programming**
2610 // Will do for now.
2611 //
2612 PinBufferLength = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart;
2613 if (!CcMapData( PtrFileObject,
2614 &StartBufferOffset,
2615 PinBufferLength,
2616 TRUE,
2617 &PtrBCB,
2618 (PVOID*)&PtrPinnedBlockBuffer ) )
2619 {
2620 return FALSE;
2621 }
2622
2623 //
2624 // Walking through now...
2625 //
2626 for( BufferIndex = 0, Found = FALSE; !Found && BufferIndex < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; BufferIndex += PtrDirEntry->rec_len )
2627 {
2628 PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ BufferIndex ];
2629 if( PtrDirEntry->inode == 0)
2630 {
2631 // Deleted entry...
2632 // Ignore...
2633 continue;
2634 }
2635 if( PtrDirEntry->name[0] == '.' )
2636 {
2637 if( PtrDirEntry->name_len == 1 ||
2638 ( PtrDirEntry->name_len == 2 && PtrDirEntry->name[1] == '.' ) )
2639 {
2640 continue;
2641 }
2642 }
2643 Found = TRUE;
2644 }
2645 CcUnpinData( PtrBCB );
2646 PtrBCB = NULL;
2647
2648 return !Found;
2649 }
2650 }
2651
2652
2653 NTSTATUS Ext2RenameOrLinkFile(
2654 PtrExt2FCB PtrSourceFCB,
2655 PFILE_OBJECT PtrSourceFileObject,
2656 PtrExt2IrpContext PtrIrpContext,
2657 PIRP PtrIrp,
2658 PFILE_RENAME_INFORMATION PtrRenameInfo)
2659 {
2660 PtrExt2FCB PtrParentFCB = NULL;
2661 PtrExt2VCB PtrSourceVCB = PtrSourceFCB->PtrVCB;
2662
2663 PtrExt2FCB PtrTargetFCB = NULL;
2664 PtrExt2CCB PtrTargetCCB = NULL;
2665 PtrExt2VCB PtrTargetVCB = NULL;
2666
2667
2668 FILE_INFORMATION_CLASS FunctionalityRequested;
2669 PIO_STACK_LOCATION PtrIoStackLocation = NULL;
2670 PFILE_OBJECT TargetFileObject = NULL;
2671 BOOLEAN ReplaceExistingFile = FALSE;
2672 BOOLEAN Found = FALSE;
2673
2674 PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp);
2675 FunctionalityRequested = PtrIoStackLocation->Parameters.SetFile.FileInformationClass;
2676 TargetFileObject = PtrIoStackLocation->Parameters.SetFile.FileObject;
2677 ReplaceExistingFile = PtrIoStackLocation->Parameters.SetFile.ReplaceIfExists;
2678
2679 // Get the FCB and CCB pointers
2680 Ext2GetFCB_CCB_VCB_FromFileObject (
2681 TargetFileObject , &PtrTargetFCB, &PtrTargetCCB, &PtrTargetVCB);
2682
2683 if( !PtrTargetCCB )
2684 {
2685 return STATUS_ACCESS_DENIED;
2686 }
2687 if( PtrTargetVCB != PtrSourceVCB )
2688 {
2689 // Cannot rename across volumes...
2690 return STATUS_ACCESS_DENIED;
2691 }
2692 if ( !Ext2IsFlagOn( PtrTargetFCB->FCBFlags, EXT2_FCB_DIRECTORY ) )
2693 {
2694 // Target has to be a folder...
2695 return STATUS_ACCESS_DENIED;
2696 }
2697
2698 // 1.
2699 // Open the parent folder...
2700 PtrParentFCB = Ext2LocateFCBInCore( PtrSourceVCB, PtrSourceFCB->ParentINodeNo );
2701 if( !PtrParentFCB )
2702 {
2703 // Get the folder from the disk
2704 // Use the inode no PtrSourceFCB->ParentINodeNo
2705 //
2706 // For now...
2707 return STATUS_ACCESS_DENIED;
2708 }
2709
2710 // 2.
2711 // Check if the file exists in the TargetFolder...
2712 {
2713 LARGE_INTEGER StartBufferOffset;
2714 ULONG PinBufferLength;
2715 ULONG BufferIndex;
2716 PBCB PtrBCB = NULL;
2717 BYTE * PtrPinnedBlockBuffer = NULL;
2718 PEXT2_DIR_ENTRY PtrDirEntry = NULL;
2719 int i;
2720
2721 StartBufferOffset.QuadPart = 0;
2722
2723 //
2724 // Read in the whole directory
2725 //
2726 if ( TargetFileObject->PrivateCacheMap == NULL )
2727 {
2728 CcInitializeCacheMap(
2729 TargetFileObject,
2730 (PCC_FILE_SIZES)(&(PtrTargetFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)),
2731 TRUE, // We utilize pin access for directories
2732 &(Ext2GlobalData.CacheMgrCallBacks), // callbacks
2733 PtrTargetCCB ); // The context used in callbacks
2734 }
2735
2736 PinBufferLength = PtrTargetFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart;
2737 if (!CcMapData( TargetFileObject,
2738 &StartBufferOffset,
2739 PinBufferLength,
2740 TRUE,
2741 &PtrBCB,
2742 (PVOID*)&PtrPinnedBlockBuffer ) )
2743 {
2744 return FALSE;
2745 }
2746
2747 //
2748 // Walking through now...
2749 //
2750 for( BufferIndex = 0, Found = FALSE; !Found && BufferIndex < ( PtrTargetFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; BufferIndex += PtrDirEntry->rec_len )
2751 {
2752 PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ BufferIndex ];
2753 if( PtrDirEntry->inode == 0)
2754 {
2755 // Deleted entry...
2756 // Ignore...
2757 continue;
2758 }
2759 if( PtrDirEntry->name_len == (PtrTargetCCB->RenameLinkTargetFileName.Length/2) )
2760 {
2761 Found = TRUE;
2762 for( i =0; i < PtrDirEntry->name_len ; i++ )
2763 {
2764 if( PtrDirEntry->name[i] != PtrTargetCCB->RenameLinkTargetFileName.Buffer[i] )
2765 {
2766 Found = FALSE;
2767 break;
2768 }
2769 }
2770 }
2771 }
2772 CcUnpinData( PtrBCB );
2773 PtrBCB = NULL;
2774 }
2775
2776 // 3.
2777 // If the file exists, delete it if requested..
2778 if( Found )
2779 {
2780 if( !ReplaceExistingFile )
2781 {
2782 return STATUS_OBJECT_NAME_COLLISION;
2783 }
2784 // Delete the file...
2785 // Reject this for now...
2786 return STATUS_ACCESS_DENIED;
2787 }
2788
2789
2790 {
2791 ULONG Type = EXT2_FT_REG_FILE;
2792 if( Ext2IsFlagOn( PtrSourceFCB->FCBFlags, EXT2_FCB_DIRECTORY ) )
2793 {
2794 Type = EXT2_FT_DIR;
2795 }
2796
2797 ASSERT( TargetFileObject );
2798
2799 // 4.
2800 // Remove the old entry...
2801 Ext2FreeDirectoryEntry( PtrIrpContext, PtrParentFCB,
2802 &PtrSourceFCB->FCBName->ObjectName);
2803
2804 // 5.
2805 // Create a new entry...
2806 Ext2MakeNewDirectoryEntry(
2807 PtrIrpContext, // This IRP Context
2808 PtrTargetFCB, // Parent Folder FCB
2809 TargetFileObject, // Parent Folder Object
2810 &PtrTargetCCB->RenameLinkTargetFileName, // New entry's name
2811 Type, // The type of the new entry
2812 PtrSourceFCB->INodeNo ); // The inode no of the new entry...
2813
2814 }
2815
2816 // 6.
2817 // Update the PtrSourceFCB...
2818 {
2819
2820 PtrExt2ObjectName PtrObjectName;
2821 if( PtrSourceFCB->FCBName )
2822 {
2823 Ext2ReleaseObjectName( PtrSourceFCB->FCBName );
2824 }
2825 PtrObjectName = Ext2AllocateObjectName();
2826 Ext2CopyUnicodeString( &PtrObjectName->ObjectName, &PtrTargetCCB->RenameLinkTargetFileName );
2827 PtrSourceFCB->FCBName = PtrObjectName;
2828 PtrSourceFCB->ParentINodeNo = PtrTargetFCB->INodeNo;
2829 }
2830
2831 if( PtrTargetCCB->RenameLinkTargetFileName.Length )
2832 {
2833 Ext2DeallocateUnicodeString( &PtrTargetCCB->RenameLinkTargetFileName );
2834 }
2835
2836 return STATUS_SUCCESS;
2837 }