1 /*************************************************************************
5 * Module: Ext2 File System Driver (Kernel mode execution only)
8 * Should contain code to handle Ext2 Metadata.
10 * Author: Manoj Paul Joseph
13 *************************************************************************/
17 #define EXT2_BUG_CHECK_ID EXT2_FILE_METADATA_IO
19 #define DEBUG_LEVEL ( DEBUG_TRACE_METADATA )
21 extern Ext2Data Ext2GlobalData
;
23 /*************************************************************************
25 * Function: Ext2ReadInode()
29 * The functions will read in the specifiec inode and return it in a buffer
32 * Expected Interrupt Level (for execution) :
41 * Return Value: The Status of the Read IO
43 *************************************************************************/
45 NTSTATUS
Ext2ReadInode (
46 PtrExt2VCB PtrVcb
, // the Volume Control Block
47 uint32 InodeNo
, // The Inode no
48 PEXT2_INODE PtrInode
// The Inode Buffer
51 // The Status to be returned...
52 NTSTATUS RC
= STATUS_SUCCESS
;
54 // The Read Buffer Pointer
55 BYTE
* PtrPinnedReadBuffer
= NULL
;
57 PEXT2_INODE PtrTempInode
;
59 // Buffer Control Block
62 LARGE_INTEGER VolumeByteOffset
, TempOffset
;
64 ULONG LogicalBlockSize
= 0;
66 ULONG NumberOfBytesToRead
= 0;
75 ASSERT(PtrVcb
->NodeIdentifier
.NodeType
== EXT2_NODE_TYPE_VCB
);
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
;
81 if( GroupNo
>= PtrVcb
->NoOfGroups
)
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
;
89 //if( PtrVcb->InodeTableBlock[ GroupNo ] == 0 )
90 if( PtrVcb
->PtrGroupDescriptors
[ GroupNo
].InodeTablesBlock
== 0 )
92 DebugTrace(DEBUG_TRACE_MISC
, "&&&&&& Inode Table Group Invalid - Group no %d ", GroupNo
);
93 RC
= STATUS_UNSUCCESSFUL
;
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
);
101 LogicalBlockSize
= EXT2_MIN_BLOCK_SIZE
<< PtrVcb
->LogBlockSize
;
102 NumberOfBytesToRead
= sizeof(EXT2_INODE
); // LogicalBlockSize;
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);
109 TempOffset
.QuadPart
= Ext2Align64( VolumeByteOffset
.QuadPart
, LogicalBlockSize
);
110 if( TempOffset
.QuadPart
!= VolumeByteOffset
.QuadPart
)
112 // TempOffset.QuadPart -= LogicalBlockSize;
113 Difference
= (LONG
) (VolumeByteOffset
.QuadPart
- TempOffset
.QuadPart
+ LogicalBlockSize
);
114 VolumeByteOffset
.QuadPart
-= Difference
;
115 NumberOfBytesToRead
+= Difference
;
118 NumberOfBytesToRead
= Ext2Align( NumberOfBytesToRead
, LogicalBlockSize
);
120 if( NumberOfBytesToRead
> LogicalBlockSize
)
122 // Multiple blocks being read in...
130 if (!CcMapData( PtrVcb
->PtrStreamFileObject
,
135 (PVOID
*)&PtrPinnedReadBuffer
))
137 RC
= STATUS_UNSUCCESSFUL
;
142 PtrTempInode
= (PEXT2_INODE
) ( PtrPinnedReadBuffer
+ Difference
);
143 RtlCopyMemory( PtrInode
, PtrTempInode
, sizeof(EXT2_INODE
) );
152 CcUnpinData( PtrBCB
);
160 /*************************************************************************
162 * Function: Ext2InitializeFCBInodeInfo()
165 * The functions will initialize the FCB with its i-node info
166 * provided it hasn't been initialized as yet...
168 * Expected Interrupt Level (for execution) :
176 *************************************************************************/
177 void Ext2InitializeFCBInodeInfo (
180 PtrExt2VCB PtrVCB
= NULL
;
183 ULONG LogicalBlockSize
;
185 PtrVCB
= PtrFCB
->PtrVCB
;
187 LogicalBlockSize
= EXT2_MIN_BLOCK_SIZE
<< PtrVCB
->LogBlockSize
;
189 if( !Ext2IsFlagOn( PtrFCB
->FCBFlags
, EXT2_FCB_BLOCKS_INITIALIZED
) )
191 DebugTrace(DEBUG_TRACE_MISC
, "Reading in the i-node no %d", PtrFCB
->INodeNo
);
193 Ext2ReadInode( PtrVCB
, PtrFCB
->INodeNo
, &Inode
);
195 for( i
= 0; i
< EXT2_N_BLOCKS
; i
++ )
197 PtrFCB
->IBlock
[i
] = Inode
.i_block
[ i
];
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);
206 PtrFCB
->LinkCount
= Inode
.i_links_count
;
208 // Getting the file type...
209 if( ! Ext2IsModeRegularFile( Inode
.i_mode
) )
211 // Not a reqular file...
212 if( Ext2IsModeDirectory( Inode
.i_mode
) )
215 Ext2SetFlag( PtrFCB
->FCBFlags
, EXT2_FCB_DIRECTORY
);
220 // Treated with respect... ;)
222 Ext2SetFlag( PtrFCB
->FCBFlags
, EXT2_FCB_SPECIAL_FILE
);
226 if( Ext2IsModeHidden( Inode
.i_mode
) )
228 Ext2SetFlag( PtrFCB
->FCBFlags
, EXT2_FCB_HIDDEN_FILE
);
230 if( Ext2IsModeReadOnly( Inode
.i_mode
) )
232 Ext2SetFlag( PtrFCB
->FCBFlags
, EXT2_FCB_READ_ONLY
);
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;
240 if( PtrFCB
->IBlock
[ EXT2_IND_BLOCK
] )
242 PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.AllocationSize
.QuadPart
-= LogicalBlockSize
/ 512;
244 DebugTrace( DEBUG_TRACE_FREE
, "Freeing = %lX [metadata]", Inode
);
248 /*************************************************************************
250 * Function: Ext2AllocInode()
253 * The functions will allocate a new on-disk i-node
255 * Expected Interrupt Level (for execution) :
262 * Return Value: The new i-node no or zero
264 *************************************************************************/
265 ULONG
Ext2AllocInode(
266 PtrExt2IrpContext PtrIrpContext
,
268 ULONG ParentINodeNo
)
272 // Buffer Control Block
273 PBCB PtrBitmapBCB
= NULL
;
274 BYTE
* PtrBitmapBuffer
= NULL
;
276 LARGE_INTEGER VolumeByteOffset
;
277 ULONG LogicalBlockSize
= 0;
278 ULONG NumberOfBytesToRead
= 0;
280 if( PtrVCB
->FreeInodesCount
== 0)
283 // No Free Inodes left...
291 // unsigned int DescIndex ;
292 BOOLEAN Found
= FALSE
;
296 LogicalBlockSize
= EXT2_MIN_BLOCK_SIZE
<< PtrVCB
->LogBlockSize
;
298 for( GroupNo
= 0; PtrVCB
->NoOfGroups
; GroupNo
++ )
300 if( PtrVCB
->PtrGroupDescriptors
[ GroupNo
].FreeInodesCount
)
304 VolumeByteOffset
.QuadPart
=
305 PtrVCB
->PtrGroupDescriptors
[ GroupNo
].InodeBitmapBlock
* LogicalBlockSize
;
307 NumberOfBytesToRead
= PtrVCB
->InodesCount
/ PtrVCB
->NoOfGroups
;
309 if( NumberOfBytesToRead
% 8 )
311 NumberOfBytesToRead
= ( NumberOfBytesToRead
/ 8 ) + 1;
315 NumberOfBytesToRead
= ( NumberOfBytesToRead
/ 8 ) ;
318 for( Block
= 0; !Found
&& Block
< Ext2Align( NumberOfBytesToRead
, LogicalBlockSize
);
319 Block
+= LogicalBlockSize
, VolumeByteOffset
.QuadPart
+= LogicalBlockSize
)
322 // Read in the bitmap block...
327 if( !CcPinRead( PtrVCB
->PtrStreamFileObject
,
329 LogicalBlockSize
, //NumberOfBytesToRead,
332 (PVOID
*)&PtrBitmapBuffer
) )
334 DebugTrace(DEBUG_TRACE_ERROR
, "Cache read failiure while reading in volume meta data", 0);
339 // Is there a free inode...
341 for( i
= 0; !Found
&& i
< LogicalBlockSize
&&
342 i
+ (Block
* LogicalBlockSize
) < NumberOfBytesToRead
; i
++ )
344 Bitmap
= PtrBitmapBuffer
[i
];
348 // Found a free inode...
349 for( j
= 0; !Found
&& j
< 8; j
++ )
351 if( ( Bitmap
& 0x01 ) == 0 )
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
);
362 // Update the inode on the disk...
364 PtrBitmapBuffer
[i
] |= Bitmap
;
366 CcSetDirtyPinnedData( PtrBitmapBCB
, NULL
);
367 Ext2SaveBCB( PtrIrpContext
, PtrBitmapBCB
, PtrVCB
->PtrStreamFileObject
);
370 // Should update the bitmaps in the other groups too...
374 Bitmap
= Bitmap
>> 1;
383 CcUnpinData( PtrBitmapBCB
);
390 // Updating the Inode count in the Group Descriptor...
392 PBCB PtrDescriptorBCB
= NULL
;
393 PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor
= NULL
;
395 PtrVCB
->PtrGroupDescriptors
[ GroupNo
].FreeInodesCount
--;
397 if( PtrVCB
->LogBlockSize
)
399 // First block contains the descriptors...
400 VolumeByteOffset
.QuadPart
= LogicalBlockSize
;
404 // Second block contains the descriptors...
405 VolumeByteOffset
.QuadPart
= LogicalBlockSize
* 2;
407 NumberOfBytesToRead
= PtrVCB
->NoOfGroups
* sizeof( struct ext2_group_desc
);
408 NumberOfBytesToRead
= Ext2Align( NumberOfBytesToRead
, LogicalBlockSize
);
410 if (!CcPinRead( PtrVCB
->PtrStreamFileObject
,
415 (PVOID
*)&PtrGroupDescriptor
))
417 DebugTrace(DEBUG_TRACE_ERROR
, "Cache read failiure while reading in volume meta data", 0);
419 // Ignore this error...
424 PtrGroupDescriptor
[ GroupNo
].bg_free_inodes_count
=
425 PtrVCB
->PtrGroupDescriptors
[ GroupNo
].FreeInodesCount
;
427 // Not synchronously flushing this information...
428 // Lazy writing will do...
430 CcSetDirtyPinnedData( PtrDescriptorBCB
, NULL
);
431 CcUnpinData( PtrDescriptorBCB
);
432 PtrDescriptorBCB
= NULL
;
438 // Update the Inode count...
439 // in the Super Block...
442 // Ext2 Super Block information...
443 PEXT2_SUPER_BLOCK PtrSuperBlock
= NULL
;
444 PBCB PtrSuperBlockBCB
= NULL
;
446 PtrVCB
->FreeInodesCount
--;
447 // Reading in the super block...
448 VolumeByteOffset
.QuadPart
= 1024;
450 // THis shouldn't be more than a block in size...
451 NumberOfBytesToRead
= Ext2Align( sizeof( EXT2_SUPER_BLOCK
), LogicalBlockSize
);
453 if( !CcPinRead( PtrVCB
->PtrStreamFileObject
,
458 (PVOID
*)&PtrSuperBlock
) )
460 DebugTrace(DEBUG_TRACE_ERROR
, "Cache read failiure while reading in volume meta data", 0);
464 PtrSuperBlock
->s_free_inodes_count
= PtrVCB
->FreeInodesCount
;
465 CcSetDirtyPinnedData( PtrSuperBlockBCB
, NULL
);
466 Ext2SaveBCB( PtrIrpContext
, PtrSuperBlockBCB
, PtrVCB
->PtrStreamFileObject
);
467 if( PtrSuperBlockBCB
)
469 CcUnpinData( PtrSuperBlockBCB
);
470 PtrSuperBlockBCB
= NULL
;
482 CcUnpinData( PtrBitmapBCB
);
486 DebugTrace( DEBUG_TRACE_SPECIAL
, " Allocating an inode - I-Node no : %ld", InodeNo
);
492 /*************************************************************************
494 * Function: Ext2DeallocInode()
497 * The functions will deallocate an i-node
499 * Expected Interrupt Level (for execution) :
502 * Return Value: Success / Failure...
504 *************************************************************************/
505 BOOLEAN
Ext2DeallocInode(
506 PtrExt2IrpContext PtrIrpContext
,
512 // Buffer Control Block
513 PBCB PtrBitmapBCB
= NULL
;
514 BYTE
* PtrBitmapBuffer
= NULL
;
516 LARGE_INTEGER VolumeByteOffset
;
517 ULONG LogicalBlockSize
= 0;
519 DebugTrace( DEBUG_TRACE_SPECIAL
, " Deallocating an inode - I-Node no : %ld", INodeNo
);
528 LogicalBlockSize
= EXT2_MIN_BLOCK_SIZE
<< PtrVCB
->LogBlockSize
;
530 GroupNo
= INodeNo
/ PtrVCB
->InodesPerGroup
;
531 INodeNo
= INodeNo
% PtrVCB
->InodesPerGroup
;
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
);
539 VolumeByteOffset
.QuadPart
=
540 ( PtrVCB
->PtrGroupDescriptors
[ GroupNo
].InodeBitmapBlock
+ BlockIndex
)
544 // Read in the bitmap block...
546 if( !CcPinRead( PtrVCB
->PtrStreamFileObject
,
548 LogicalBlockSize
, // Just the block that contains the bitmap will do...
551 (PVOID
*)&PtrBitmapBuffer
) )
553 // Unable to Pin the data into the cache...
554 try_return (RC
= FALSE
);
558 // Locate the inode...
559 // This inode is in the byte PtrBitmapBuffer[ BitmapIndex ]
560 if( ( PtrBitmapBuffer
[ BitmapIndex
] & Bitmap
) == 0)
562 // This shouldn't have been so...
563 // The inode was never allocated!
564 // How to deallocate something that hasn't been allocated?
566 // Ignore this error...
567 try_return (RC
= TRUE
);
571 // Setting the bit for the inode...
572 PtrBitmapBuffer
[ BitmapIndex
] &= (~Bitmap
);
574 // Update the cache...
575 CcSetDirtyPinnedData( PtrBitmapBCB
, NULL
);
577 // Save up the BCB for forcing a synchronous write...
578 // Before completing the IRP...
579 Ext2SaveBCB( PtrIrpContext
, PtrBitmapBCB
, PtrVCB
->PtrStreamFileObject
);
584 CcUnpinData( PtrBitmapBCB
);
590 // Updating the Inode count in the Group Descriptor...
592 PBCB PtrDescriptorBCB
= NULL
;
593 PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor
= NULL
;
594 ULONG NumberOfBytesToRead
= 0;
596 PtrVCB
->PtrGroupDescriptors
[ GroupNo
].FreeInodesCount
++;
598 if( PtrVCB
->LogBlockSize
)
600 // First block contains the descriptors...
601 VolumeByteOffset
.QuadPart
= LogicalBlockSize
;
605 // Second block contains the descriptors...
606 VolumeByteOffset
.QuadPart
= LogicalBlockSize
* 2;
608 NumberOfBytesToRead
= PtrVCB
->NoOfGroups
* sizeof( struct ext2_group_desc
);
609 NumberOfBytesToRead
= Ext2Align( NumberOfBytesToRead
, LogicalBlockSize
);
611 if (!CcPinRead( PtrVCB
->PtrStreamFileObject
,
616 (PVOID
*)&PtrGroupDescriptor
))
618 DebugTrace(DEBUG_TRACE_ERROR
, "Cache read failiure while reading in volume meta data", 0);
620 // Ignore this error...
625 PtrGroupDescriptor
[ GroupNo
].bg_free_inodes_count
=
626 PtrVCB
->PtrGroupDescriptors
[ GroupNo
].FreeInodesCount
;
628 // Not synchronously flushing this information...
629 // Lazy writing will do...
631 CcSetDirtyPinnedData( PtrDescriptorBCB
, NULL
);
632 CcUnpinData( PtrDescriptorBCB
);
633 PtrDescriptorBCB
= NULL
;
639 // Update the Inode count...
640 // in the Super Block
644 // Ext2 Super Block information...
645 PEXT2_SUPER_BLOCK PtrSuperBlock
= NULL
;
646 PBCB PtrSuperBlockBCB
= NULL
;
647 ULONG NumberOfBytesToRead
= 0;
649 PtrVCB
->FreeInodesCount
++;
651 // Reading in the super block...
652 VolumeByteOffset
.QuadPart
= 1024;
653 NumberOfBytesToRead
= Ext2Align( sizeof( EXT2_SUPER_BLOCK
), LogicalBlockSize
);
655 if( !CcPinRead( PtrVCB
->PtrStreamFileObject
,
660 (PVOID
*)&PtrSuperBlock
) )
662 DebugTrace(DEBUG_TRACE_ERROR
, "Cache read failiure while reading in volume meta data", 0);
666 PtrSuperBlock
->s_free_inodes_count
= PtrVCB
->FreeInodesCount
;
667 CcSetDirtyPinnedData( PtrSuperBlockBCB
, NULL
);
668 Ext2SaveBCB( PtrIrpContext
, PtrSuperBlockBCB
, PtrVCB
->PtrStreamFileObject
);
669 if( PtrSuperBlockBCB
)
671 CcUnpinData( PtrSuperBlockBCB
);
672 PtrSuperBlockBCB
= NULL
;
683 CcUnpinData( PtrBitmapBCB
);
690 /*************************************************************************
692 * Function: Ext2WriteInode()
695 * The functions will write an i-node to disk
697 * Expected Interrupt Level (for execution) :
701 * Return Value: Success / Failure...
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
711 // The Status to be returned...
712 NTSTATUS RC
= STATUS_SUCCESS
;
714 // The Read Buffer Pointer
715 BYTE
* PtrPinnedBuffer
= NULL
;
717 PEXT2_INODE PtrTempInode
;
719 // Buffer Control Block
722 LARGE_INTEGER VolumeByteOffset
, TempOffset
;
724 ULONG LogicalBlockSize
= 0;
725 ULONG NumberOfBytesToRead
= 0;
726 ULONG Difference
= 0;
732 DebugTrace( DEBUG_TRACE_SPECIAL
, "Writing and updating an inode - I-Node no : %ld", InodeNo
);
735 ASSERT(PtrVcb
->NodeIdentifier
.NodeType
== EXT2_NODE_TYPE_VCB
);
736 GroupNo
= InodeNo
/ PtrVcb
->InodesPerGroup
;
738 if( GroupNo
>= PtrVcb
->NoOfGroups
)
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
;
746 if( PtrVcb
->PtrGroupDescriptors
[ GroupNo
].InodeTablesBlock
== 0 )
748 DebugTrace(DEBUG_TRACE_MISC
, "&&&&&& Inode Table Group Invalid - Group no %d ", GroupNo
);
749 RC
= STATUS_UNSUCCESSFUL
;
753 Index
= ( InodeNo
- 1 ) - ( GroupNo
* PtrVcb
->InodesPerGroup
);
755 LogicalBlockSize
= EXT2_MIN_BLOCK_SIZE
<< PtrVcb
->LogBlockSize
;
756 NumberOfBytesToRead
= sizeof(EXT2_INODE
);
758 VolumeByteOffset
.QuadPart
= PtrVcb
->PtrGroupDescriptors
[ GroupNo
].InodeTablesBlock
759 * LogicalBlockSize
+ Index
* sizeof(EXT2_INODE
);
761 TempOffset
.QuadPart
= Ext2Align64( VolumeByteOffset
.QuadPart
, LogicalBlockSize
);
762 if( TempOffset
.QuadPart
!= VolumeByteOffset
.QuadPart
)
764 // TempOffset.QuadPart -= LogicalBlockSize;
765 Difference
= (LONG
) (VolumeByteOffset
.QuadPart
- TempOffset
.QuadPart
+ LogicalBlockSize
);
766 VolumeByteOffset
.QuadPart
-= Difference
;
767 NumberOfBytesToRead
+= Difference
;
770 NumberOfBytesToRead
= Ext2Align( NumberOfBytesToRead
, LogicalBlockSize
);
772 if( NumberOfBytesToRead
> LogicalBlockSize
)
774 // Multiple blocks being read in...
780 if( !CcPinRead( PtrVcb
->PtrStreamFileObject
,
785 (PVOID
*)&PtrPinnedBuffer
) )
787 RC
= STATUS_UNSUCCESSFUL
;
792 RtlCopyMemory( PtrPinnedBuffer
+ Difference
, PtrInode
, sizeof(EXT2_INODE
) );
793 CcSetDirtyPinnedData( PtrBCB
, NULL
);
794 Ext2SaveBCB( PtrIrpContext
, PtrBCB
, PtrVcb
->PtrStreamFileObject
);
803 CcUnpinData( PtrBCB
);
812 /*************************************************************************
814 * Function: Ext2MakeNewDirectoryEntry()
817 * The functions will make a new directory entry in a directory file...
819 * Expected Interrupt Level (for execution) :
823 * Return Value: Success / Failure...
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...
834 PBCB PtrLastBlockBCB
= NULL
;
835 BYTE
* PtrLastBlock
= NULL
;
836 EXT2_DIR_ENTRY DirEntry
;
837 PEXT2_DIR_ENTRY PtrTempDirEntry
;
842 LARGE_INTEGER VolumeByteOffset
;
843 unsigned long LogicalBlockSize
= 0;
844 unsigned long NumberOfBytesToRead
= 0;
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)
855 ASSERT( PtrFileObject
);
857 DebugTrace( DEBUG_TRACE_SPECIAL
, "Making directory entry: %S", PtrName
->Buffer
);
859 PtrVCB
= PtrParentFCB
->PtrVCB
;
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);
869 RtlZeroMemory( &DirEntry
, sizeof( EXT2_DIR_ENTRY
) );
871 DirEntry
.file_type
= (BYTE
) Type
;
872 DirEntry
.inode
= NewInodeNo
;
873 DirEntry
.name_len
= (BYTE
)(PtrName
->Length
/ 2 ); // Does not include a NULL
875 // DirEntry.rec_len = (USHORT) NewEntryLength;
879 if( i
< (ULONG
)( PtrName
->Length
/ 2 ) )
881 DirEntry
.name
[i
] = (CHAR
) PtrName
->Buffer
[i
];
885 //DirEntry.name[i] = 0; // Entry need not be zero terminated...
891 // 2. Read the block in the directory...
892 // Initiate Caching...
893 if ( PtrFileObject
->PrivateCacheMap
== NULL
)
895 CcInitializeCacheMap(
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
903 LogicalBlockSize
= EXT2_MIN_BLOCK_SIZE
<< PtrVCB
->LogBlockSize
;
904 if( PtrParentFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.QuadPart
> 0 )
906 BlockNo
= (ULONG
) ( (PtrParentFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.QuadPart
- 1) / LogicalBlockSize
) ;
910 // This directory doesn't have any data blocks...
911 // Allocate a new block...
912 if( !Ext2AddBlockToFile( PtrIrpContext
, PtrVCB
, PtrParentFCB
, PtrFileObject
, TRUE
) )
914 try_return( RC
= FALSE
);
918 // Bring in the newly allocated block to the cache...
919 VolumeByteOffset
.QuadPart
= 0;
921 if( !CcPreparePinWrite(
925 TRUE
, // Zero out the block...
928 (PVOID
*)&PtrLastBlock
) )
930 try_return( RC
= FALSE
);
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
);
941 VolumeByteOffset
.QuadPart
= BlockNo
* LogicalBlockSize
;
942 CcMapData( PtrFileObject
,
947 (PVOID
*)&PtrLastBlock
);
949 for( i
= 0 ; i
< LogicalBlockSize
; )
951 PtrTempDirEntry
= (PEXT2_DIR_ENTRY
) &PtrLastBlock
[ i
];
953 MinLength
= HeaderLength
+ NameLength
;
954 MinLength
= ( HeaderLength
+ NameLength
+ 3 ) & 0xfffffffc;
957 if( PtrTempDirEntry
->rec_len
== 0 )
961 // Must be an empty Block...
963 // ---------------->>>
965 CcPinMappedData( PtrFileObject
,
971 DirEntry
.rec_len
= (USHORT
)LogicalBlockSize
;
973 RtlCopyBytes( PtrLastBlock
, &DirEntry
, NewEntryLength
);
974 CcSetDirtyPinnedData( PtrLastBlockBCB
, NULL
);
975 Ext2SaveBCB( PtrIrpContext
, PtrLastBlockBCB
, PtrFileObject
);
976 try_return( RC
= TRUE
);
980 // This shouldn't be so...
981 // Something is wrong...
982 // Fail this request...
983 try_return( RC
= FALSE
);
986 if( ActualLength
- MinLength
>= NewEntryLength
)
991 // Getting ready for updation...
992 CcPinMappedData( PtrFileObject
,
999 DirEntry
.rec_len
= ActualLength
- MinLength
;
1001 // Updating the current last entry
1002 PtrTempDirEntry
->rec_len
= MinLength
;
1003 i
+= PtrTempDirEntry
->rec_len
;
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
);
1012 i
+= PtrTempDirEntry
->rec_len
;
1015 // Will have to allocate a new block...
1016 // Old block does not have enough space..
1017 if( !Ext2AddBlockToFile( PtrIrpContext
, PtrVCB
, PtrParentFCB
, PtrFileObject
, TRUE
) )
1019 try_return( RC
= FALSE
);
1023 // unpin the previously pinned block
1024 CcUnpinData( PtrLastBlockBCB
);
1025 PtrLastBlockBCB
= NULL
;
1027 // Bring in the newly allocated block to the cache...
1028 VolumeByteOffset
.QuadPart
+= LogicalBlockSize
;
1029 if( !CcPreparePinWrite(
1033 TRUE
, // Zero out the block...
1034 TRUE
, // Can Wait...
1036 (PVOID
*)&PtrLastBlock
) )
1038 try_return( RC
= FALSE
);
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
);
1051 if( PtrLastBlockBCB
)
1053 CcUnpinData( PtrLastBlockBCB
);
1054 PtrLastBlockBCB
= NULL
;
1059 DebugTrace( DEBUG_TRACE_ERROR
, "Failed to making directory entry: %S", PtrName
->Buffer
);
1065 BOOLEAN
Ext2FreeDirectoryEntry(
1066 PtrExt2IrpContext PtrIrpContext
,
1067 PtrExt2FCB PtrParentFCB
,
1068 PUNICODE_STRING PtrName
)
1071 PBCB PtrDataBlockBCB
= NULL
;
1072 BYTE
* PtrDataBlock
= NULL
;
1073 PFILE_OBJECT PtrFileObject
= NULL
;
1074 PEXT2_DIR_ENTRY PtrTempDirEntry
;
1075 LONGLONG ByteOffset
= 0;
1077 LARGE_INTEGER VolumeByteOffset
;
1078 unsigned long LogicalBlockSize
= 0;
1084 DebugTrace( DEBUG_TRACE_SPECIAL
, "Freeing directory entry: %S", PtrName
->Buffer
);
1086 PtrVCB
= PtrParentFCB
->PtrVCB
;
1089 LogicalBlockSize
= EXT2_MIN_BLOCK_SIZE
<< PtrVCB
->LogBlockSize
;
1091 PtrFileObject
= PtrParentFCB
->DcbFcb
.Dcb
.PtrDirFileObject
;
1092 if( PtrFileObject
== NULL
)
1099 // 1. Read the block in the directory...
1100 // Initiate Caching...
1101 if ( PtrFileObject
->PrivateCacheMap
== NULL
)
1103 CcInitializeCacheMap(
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
1111 for( ByteOffset
= 0;
1112 ByteOffset
< PtrParentFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.QuadPart
;
1113 ByteOffset
+= LogicalBlockSize
)
1116 PEXT2_DIR_ENTRY PtrDirEntry
= NULL
;
1119 VolumeByteOffset
.QuadPart
= ByteOffset
;
1121 CcPinRead( PtrFileObject
,
1126 (PVOID
*)&PtrDataBlock
);
1127 while( Index
< LogicalBlockSize
)
1131 PtrDirEntry
= (PEXT2_DIR_ENTRY
) &PtrDataBlock
[ Index
];
1132 Index
+= PtrDirEntry
->rec_len
;
1134 if( PtrDirEntry
->inode
== 0 )
1136 // This is a deleted entry...
1139 if( ( PtrName
->Length
/2 ) != PtrDirEntry
->name_len
)
1143 if( PtrDirEntry
->name_len
== i
)
1145 // Remove the entry by setting the inode no to zero
1146 PtrDirEntry
->inode
= 0;
1149 CcSetDirtyPinnedData( PtrDataBlockBCB
, NULL
);
1150 Ext2SaveBCB( PtrIrpContext
, PtrDataBlockBCB
, PtrFileObject
);
1151 CcUnpinData( PtrDataBlockBCB
);
1152 PtrDataBlockBCB
= NULL
;
1154 // Return to caller...
1155 try_return( RC
= TRUE
);
1157 if( PtrName
->Buffer
[i
] != PtrDirEntry
->name
[i
] )
1163 CcUnpinData( PtrDataBlockBCB
);
1164 PtrDataBlockBCB
= NULL
;
1166 try_return( RC
= FALSE
);
1172 if( PtrDataBlockBCB
)
1174 CcUnpinData( PtrDataBlockBCB
);
1175 PtrDataBlockBCB
= NULL
;
1181 /*************************************************************************
1183 * Function: Ext2AddBlockToFile()
1186 * The functions will add a block to a file...
1187 * It will update the allocation size but not the file size...
1189 * Expected Interrupt Level (for execution) :
1190 * IRQL_PASSIVE_LEVEL
1193 * Return Value: Success / Failure...
1195 *************************************************************************/
1196 BOOLEAN
Ext2AddBlockToFile(
1197 PtrExt2IrpContext PtrIrpContext
,
1200 PFILE_OBJECT PtrFileObject
,
1201 BOOLEAN UpdateFileSize
)
1205 ULONG NewBlockNo
= 0;
1206 LARGE_INTEGER VolumeByteOffset
;
1207 ULONG LogicalBlockSize
= 0;
1208 ULONG NoOfBlocks
= 0;
1211 ULONG DirectBlocks
= 0;
1212 ULONG SingleIndirectBlocks
= 0;
1213 ULONG DoubleIndirectBlocks
= 0;
1214 ULONG TripleIndirectBlocks
= 0;
1216 ULONG
*PtrSIBBuffer
= NULL
;
1217 PBCB PtrSIBBCB
= NULL
;
1218 ULONG
*PtrDIBBuffer
= NULL
;
1219 PBCB PtrDIBBCB
= NULL
;
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
);
1230 if( PtrFCB
&& PtrFCB
->FCBName
->ObjectName
.Length
)
1232 DebugTrace( DEBUG_TRACE_SPECIAL
, "Adding Blocks to file %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
1235 Ext2InitializeFCBInodeInfo( PtrFCB
);
1237 // Allocate a block...
1238 NewBlockNo
= Ext2AllocBlock( PtrIrpContext
, PtrVCB
, 1 );
1240 if( NewBlockNo
== 0 )
1242 try_return (RC
= FALSE
);
1245 // No of blocks CURRENTLY allocated...
1246 NoOfBlocks
= (ULONG
) PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.AllocationSize
.QuadPart
/ LogicalBlockSize
;
1249 if( NoOfBlocks
< EXT2_NDIR_BLOCKS
)
1252 // A direct data block will do...
1255 PtrFCB
->IBlock
[ NoOfBlocks
] = NewBlockNo
;
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
)
1264 Inode
.i_size
+= LogicalBlockSize
;
1265 PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.QuadPart
+= LogicalBlockSize
;
1269 if( PtrFileObject
->PrivateCacheMap
!= NULL
)
1272 // Caching has been initiated...
1273 // Let the Cache manager in on these changes...
1275 CcSetFileSizes( PtrFileObject
, (PCC_FILE_SIZES
)&(PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.AllocationSize
));
1279 // Updating the inode...
1280 if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext
, PtrVCB
, PtrFCB
->INodeNo
, &Inode
) ) )
1282 try_return (RC
= TRUE
);
1286 try_return (RC
= FALSE
);
1290 else if( NoOfBlocks
< (DirectBlocks
+ SingleIndirectBlocks
) )
1293 // A single indirect data block will do...
1294 Ext2ReadInode( PtrVCB
, PtrFCB
->INodeNo
, &Inode
);
1296 if( PtrFCB
->IBlock
[ EXT2_IND_BLOCK
] == 0 )
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 )
1302 try_return (RC
= FALSE
);
1304 Inode
.i_blocks
+= ( LogicalBlockSize
/ 512 );
1306 // Bring in the new block to the cache
1308 VolumeByteOffset
.QuadPart
= PtrFCB
->IBlock
[ EXT2_IND_BLOCK
] * LogicalBlockSize
;
1310 if( !CcPreparePinWrite(
1311 PtrVCB
->PtrStreamFileObject
,
1314 TRUE
, // Zero out the block...
1315 TRUE
, // Can Wait...
1317 (PVOID
*)&PtrSIBBuffer
) )
1319 try_return( RC
= FALSE
);
1324 // Just bring in the SIB to the cache
1326 VolumeByteOffset
.QuadPart
= PtrFCB
->IBlock
[ EXT2_IND_BLOCK
] * LogicalBlockSize
;
1328 if( !CcPinRead( PtrVCB
->PtrStreamFileObject
,
1331 TRUE
, // Can Wait...
1333 (PVOID
*)&PtrSIBBuffer
) )
1335 try_return( RC
= FALSE
);
1339 // Update the inode...
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
)
1346 Inode
.i_size
+= LogicalBlockSize
;
1347 PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.QuadPart
+= LogicalBlockSize
;
1349 if( PtrFileObject
->PrivateCacheMap
!= NULL
)
1352 // Caching has been initiated...
1353 // Let the Cache manager in on these changes...
1355 CcSetFileSizes( PtrFileObject
, (PCC_FILE_SIZES
)&(PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.AllocationSize
));
1358 if( !NT_SUCCESS( Ext2WriteInode(
1359 PtrIrpContext
, PtrVCB
, PtrFCB
->INodeNo
, &Inode
) ) )
1361 try_return (RC
= FALSE
);
1365 // Update the SIB...
1366 PtrSIBBuffer
[ NoOfBlocks
- DirectBlocks
] = NewBlockNo
;
1367 CcSetDirtyPinnedData( PtrSIBBCB
, NULL
);
1368 Ext2SaveBCB( PtrIrpContext
, PtrSIBBCB
, PtrVCB
->PtrStreamFileObject
);
1370 try_return (RC
= TRUE
);
1373 else if( NoOfBlocks
< (DirectBlocks
+ SingleIndirectBlocks
+ DoubleIndirectBlocks
) )
1376 // A double indirect block will do...
1381 Ext2ReadInode( PtrVCB
, PtrFCB
->INodeNo
, &Inode
);
1383 if( PtrFCB
->IBlock
[ EXT2_DIND_BLOCK
] == 0 )
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 )
1389 try_return (RC
= FALSE
);
1391 Inode
.i_blocks
+= ( LogicalBlockSize
/ 512 );
1393 // Bring in the new block to the cache
1395 VolumeByteOffset
.QuadPart
= PtrFCB
->IBlock
[ EXT2_DIND_BLOCK
] * LogicalBlockSize
;
1397 if( !CcPreparePinWrite(
1398 PtrVCB
->PtrStreamFileObject
,
1401 TRUE
, // Zero out the block...
1402 TRUE
, // Can Wait...
1404 (PVOID
*)&PtrDIBBuffer
) )
1406 try_return( RC
= FALSE
);
1411 // Just bring in the DIB to the cache
1413 VolumeByteOffset
.QuadPart
= PtrFCB
->IBlock
[ EXT2_DIND_BLOCK
] * LogicalBlockSize
;
1415 if( !CcPinRead( PtrVCB
->PtrStreamFileObject
,
1418 TRUE
, // Can Wait...
1420 (PVOID
*)&PtrDIBBuffer
) )
1422 try_return( RC
= FALSE
);
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
)
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
;
1438 Inode
.i_blocks
+= ( LogicalBlockSize
/ 512 );
1440 if( !CcPreparePinWrite(
1441 PtrVCB
->PtrStreamFileObject
,
1444 TRUE
, // Zero out the block...
1445 TRUE
, // Can Wait...
1447 (PVOID
*)&PtrSIBBuffer
) )
1449 try_return( RC
= FALSE
);
1454 VolumeByteOffset
.QuadPart
= PtrDIBBuffer
[SBlockNo
] * LogicalBlockSize
;
1455 if( !CcPinRead( PtrVCB
->PtrStreamFileObject
,
1458 TRUE
, // Can Wait...
1460 (PVOID
*)&PtrSIBBuffer
) )
1462 try_return( RC
= FALSE
);
1465 BlockNo
= BlockNo
% SingleIndirectBlocks
;
1467 // Update the inode...
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
)
1474 Inode
.i_size
+= LogicalBlockSize
;
1475 PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.QuadPart
+= LogicalBlockSize
;
1477 if( PtrFileObject
->PrivateCacheMap
!= NULL
)
1480 // Caching has been initiated...
1481 // Let the Cache manager in on these changes...
1483 CcSetFileSizes( PtrFileObject
, (PCC_FILE_SIZES
)&(PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.AllocationSize
));
1486 if( !NT_SUCCESS( Ext2WriteInode(
1487 PtrIrpContext
, PtrVCB
, PtrFCB
->INodeNo
, &Inode
) ) )
1489 try_return (RC
= FALSE
);
1493 // Update the SIB...
1494 PtrSIBBuffer
[ BlockNo
] = NewBlockNo
;
1495 CcSetDirtyPinnedData( PtrSIBBCB
, NULL
);
1496 Ext2SaveBCB( PtrIrpContext
, PtrSIBBCB
, PtrVCB
->PtrStreamFileObject
);
1497 Ext2SaveBCB( PtrIrpContext
, PtrDIBBCB
, PtrVCB
->PtrStreamFileObject
);
1499 try_return (RC
= TRUE
);
1505 // A Triple Indirect block is required
1510 // This is not supported as yet...
1511 try_return (RC
= FALSE
);
1513 Ext2ReadInode( PtrVCB
, PtrFCB
->INodeNo
, &Inode
);
1515 if( PtrFCB
->IBlock
[ EXT2_TIND_BLOCK
] == 0 )
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 )
1521 try_return (RC
= FALSE
);
1523 Inode
.i_blocks
+= ( LogicalBlockSize
/ 512 );
1525 // Bring in the new block to the cache
1527 VolumeByteOffset
.QuadPart
= PtrFCB
->IBlock
[ EXT2_DIND_BLOCK
] * LogicalBlockSize
;
1529 if( !CcPreparePinWrite(
1530 PtrVCB
->PtrStreamFileObject
,
1533 TRUE
, // Zero out the block...
1534 TRUE
, // Can Wait...
1536 (PVOID
*)&PtrDIBBuffer
) )
1538 try_return( RC
= FALSE
);
1543 // Just bring in the DIB to the cache
1545 VolumeByteOffset
.QuadPart
= PtrFCB
->IBlock
[ EXT2_DIND_BLOCK
] * LogicalBlockSize
;
1547 if( !CcPinRead( PtrVCB
->PtrStreamFileObject
,
1550 TRUE
, // Can Wait...
1552 (PVOID
*)&PtrDIBBuffer
) )
1554 try_return( RC
= FALSE
);
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
)
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
;
1570 Inode
.i_blocks
+= ( LogicalBlockSize
/ 512 );
1572 if( !CcPreparePinWrite(
1573 PtrVCB
->PtrStreamFileObject
,
1576 TRUE
, // Zero out the block...
1577 TRUE
, // Can Wait...
1579 (PVOID
*)&PtrSIBBuffer
) )
1581 try_return( RC
= FALSE
);
1586 VolumeByteOffset
.QuadPart
= PtrDIBBuffer
[SBlockNo
] * LogicalBlockSize
;
1587 if( !CcPinRead( PtrVCB
->PtrStreamFileObject
,
1590 TRUE
, // Can Wait...
1592 (PVOID
*)&PtrSIBBuffer
) )
1594 try_return( RC
= FALSE
);
1597 BlockNo
= BlockNo
% SingleIndirectBlocks
;
1599 // Update the inode...
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
)
1606 Inode
.i_size
+= LogicalBlockSize
;
1607 PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.QuadPart
+= LogicalBlockSize
;
1609 if( PtrFileObject
->PrivateCacheMap
!= NULL
)
1612 // Caching has been initiated...
1613 // Let the Cache manager in on these changes...
1615 CcSetFileSizes( PtrFileObject
, (PCC_FILE_SIZES
)&(PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.AllocationSize
));
1618 if( !NT_SUCCESS( Ext2WriteInode(
1619 PtrIrpContext
, PtrVCB
, PtrFCB
->INodeNo
, &Inode
) ) )
1621 try_return (RC
= FALSE
);
1625 // Update the SIB...
1626 PtrSIBBuffer
[ BlockNo
] = NewBlockNo
;
1627 CcSetDirtyPinnedData( PtrSIBBCB
, NULL
);
1628 Ext2SaveBCB( PtrIrpContext
, PtrSIBBCB
, PtrVCB
->PtrStreamFileObject
);
1629 Ext2SaveBCB( PtrIrpContext
, PtrDIBBCB
, PtrVCB
->PtrStreamFileObject
);
1631 try_return (RC
= TRUE
);
1641 CcUnpinData( PtrSIBBCB
);
1646 CcUnpinData( PtrDIBBCB
);
1653 /*************************************************************************
1655 * Function: Ext2AllocBlock()
1658 * The functions will allocate a new block
1660 * Expected Interrupt Level (for execution) :
1661 * IRQL_PASSIVE_LEVEL
1664 * Return Value: Success / Failure...
1666 *************************************************************************/
1667 ULONG
Ext2AllocBlock(
1668 PtrExt2IrpContext PtrIrpContext
,
1672 // Buffer Control Block
1673 PBCB PtrBitmapBCB
= NULL
;
1674 BYTE
* PtrBitmapBuffer
= NULL
;
1676 LARGE_INTEGER VolumeByteOffset
;
1677 ULONG LogicalBlockSize
= 0;
1678 ULONG NumberOfBytesToRead
= 0;
1680 if( PtrVCB
->FreeBlocksCount
== 0 )
1683 // No Free Block left...
1691 BOOLEAN Found
= FALSE
;
1694 LogicalBlockSize
= EXT2_MIN_BLOCK_SIZE
<< PtrVCB
->LogBlockSize
;
1696 for( GroupNo
= 0; PtrVCB
->NoOfGroups
; GroupNo
++ )
1698 if( PtrVCB
->PtrGroupDescriptors
[ GroupNo
].FreeBlocksCount
)
1702 VolumeByteOffset
.QuadPart
=
1703 PtrVCB
->PtrGroupDescriptors
[ GroupNo
].BlockBitmapBlock
* LogicalBlockSize
;
1705 NumberOfBytesToRead
= PtrVCB
->BlocksCount
/ PtrVCB
->NoOfGroups
;
1707 if( NumberOfBytesToRead
% 8 )
1709 NumberOfBytesToRead
= ( NumberOfBytesToRead
/ 8 ) + 1;
1713 NumberOfBytesToRead
= ( NumberOfBytesToRead
/ 8 ) ;
1717 for( Block
= 0; !Found
&& Block
< Ext2Align( NumberOfBytesToRead
, LogicalBlockSize
);
1718 Block
+= LogicalBlockSize
, VolumeByteOffset
.QuadPart
+= LogicalBlockSize
)
1721 // Read in the block bitmap block...
1725 if( !CcPinRead( PtrVCB
->PtrStreamFileObject
,
1727 LogicalBlockSize
, // NumberOfBytesToRead,
1730 (PVOID
*)&PtrBitmapBuffer
) )
1732 DebugTrace(DEBUG_TRACE_ERROR
, "Cache read failiure while reading in volume meta data", 0);
1733 try_return( BlockNo
= 0 );
1737 // Is there a free block...
1739 for( i
= 0; !Found
&& i
< LogicalBlockSize
&&
1740 i
+ (Block
* LogicalBlockSize
) < NumberOfBytesToRead
; i
++ )
1742 Bitmap
= PtrBitmapBuffer
[i
];
1743 if( Bitmap
!= 0xff )
1746 // Found a free block...
1747 for( j
= 0; !Found
&& j
< 8; j
++ )
1749 if( ( Bitmap
& 0x01 ) == 0 )
1754 BlockNo
= ( ( ( Block
* LogicalBlockSize
) + i
) * 8) + j
+ 1
1755 + ( GroupNo
* PtrVCB
->BlocksPerGroup
);
1758 PtrBitmapBuffer
[i
] |= Bitmap
;
1760 CcSetDirtyPinnedData( PtrBitmapBCB
, NULL
);
1761 Ext2SaveBCB( PtrIrpContext
, PtrBitmapBCB
, PtrVCB
->PtrStreamFileObject
);
1763 // Should update the bitmaps in the other groups too...
1767 Bitmap
= Bitmap
>> 1;
1776 CcUnpinData( PtrBitmapBCB
);
1777 PtrBitmapBCB
= NULL
;
1783 // Updating the Free Block count in the Group Descriptor...
1787 PBCB PtrDescriptorBCB
= NULL
;
1788 PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor
= NULL
;
1790 // Updating the Free Blocks count in the Group Descriptor...
1792 PtrVCB
->PtrGroupDescriptors
[ GroupNo
].FreeBlocksCount
--;
1794 if( PtrVCB
->LogBlockSize
)
1796 // First block contains the descriptors...
1797 VolumeByteOffset
.QuadPart
= LogicalBlockSize
;
1801 // Second block contains the descriptors...
1802 VolumeByteOffset
.QuadPart
= LogicalBlockSize
* 2;
1804 NumberOfBytesToRead
= PtrVCB
->NoOfGroups
* sizeof( struct ext2_group_desc
);
1805 NumberOfBytesToRead
= Ext2Align( NumberOfBytesToRead
, LogicalBlockSize
);
1807 if (!CcPinRead( PtrVCB
->PtrStreamFileObject
,
1809 NumberOfBytesToRead
,
1812 (PVOID
*)&PtrGroupDescriptor
))
1814 DebugTrace(DEBUG_TRACE_ERROR
, "Cache read failiure while reading in volume meta data", 0);
1816 // Ignore this error...
1821 PtrGroupDescriptor
[ GroupNo
].bg_free_blocks_count
=
1822 PtrVCB
->PtrGroupDescriptors
[ GroupNo
].FreeBlocksCount
;
1825 // Not synchronously flushing this information...
1826 // Lazy writing will do...
1828 CcSetDirtyPinnedData( PtrDescriptorBCB
, NULL
);
1829 CcUnpinData( PtrDescriptorBCB
);
1830 PtrDescriptorBCB
= NULL
;
1835 // Update the Block count
1836 // in the super block and in the VCB
1839 // Ext2 Super Block information...
1840 PEXT2_SUPER_BLOCK PtrSuperBlock
= NULL
;
1841 PBCB PtrSuperBlockBCB
= NULL
;
1843 PtrVCB
->FreeBlocksCount
--;
1845 // Reading in the super block...
1846 VolumeByteOffset
.QuadPart
= 1024;
1847 NumberOfBytesToRead
= Ext2Align( sizeof( EXT2_SUPER_BLOCK
), LogicalBlockSize
);
1849 if( !CcPinRead( PtrVCB
->PtrStreamFileObject
,
1851 NumberOfBytesToRead
,
1854 (PVOID
*)&PtrSuperBlock
) )
1856 DebugTrace(DEBUG_TRACE_ERROR
, "Cache read failiure while reading in volume meta data", 0);
1860 PtrSuperBlock
->s_free_blocks_count
= PtrVCB
->FreeBlocksCount
;
1861 CcSetDirtyPinnedData( PtrSuperBlockBCB
, NULL
);
1862 Ext2SaveBCB( PtrIrpContext
, PtrSuperBlockBCB
, PtrVCB
->PtrStreamFileObject
);
1863 if( PtrSuperBlockBCB
)
1865 CcUnpinData( PtrSuperBlockBCB
);
1866 PtrSuperBlockBCB
= NULL
;
1877 CcUnpinData( PtrBitmapBCB
);
1878 PtrBitmapBCB
= NULL
;
1880 DebugTrace( DEBUG_TRACE_SPECIAL
, " Allocating a block - Block no : %ld", BlockNo
);
1885 /*************************************************************************
1887 * Function: Ext2DeallocBlock()
1890 * The functions will deallocate a data block
1892 * Expected Interrupt Level (for execution) :
1893 * IRQL_PASSIVE_LEVEL
1895 * Return Value: Success / Failure...
1897 *************************************************************************/
1898 BOOLEAN
Ext2DeallocBlock(
1899 PtrExt2IrpContext PtrIrpContext
,
1903 // Buffer Control Block
1904 PBCB PtrBitmapBCB
= NULL
;
1905 BYTE
* PtrBitmapBuffer
= NULL
;
1907 LARGE_INTEGER VolumeByteOffset
;
1908 ULONG LogicalBlockSize
= 0;
1909 // ULONG NumberOfBytesToRead = 0;
1911 DebugTrace( DEBUG_TRACE_SPECIAL
, " Deallocating a block - Block no : %ld", BlockNo
);
1920 LogicalBlockSize
= EXT2_MIN_BLOCK_SIZE
<< PtrVCB
->LogBlockSize
;
1922 GroupNo
= BlockNo
/ PtrVCB
->BlocksPerGroup
;
1923 BlockNo
= BlockNo
% PtrVCB
->BlocksPerGroup
;
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
);
1931 VolumeByteOffset
.QuadPart
=
1932 ( PtrVCB
->PtrGroupDescriptors
[ GroupNo
].BlockBitmapBlock
+ BlockIndex
)
1936 // Read in the bitmap block...
1938 if( !CcPinRead( PtrVCB
->PtrStreamFileObject
,
1941 TRUE
, // Can Wait...
1943 (PVOID
*)&PtrBitmapBuffer
) )
1945 // Unable to Pin the data into the cache...
1946 try_return (RC
= FALSE
);
1950 // Locate the block 'bit'...
1951 // This block 'bit' is in the byte PtrBitmapBuffer[ BitmapIndex ]
1952 if( ( PtrBitmapBuffer
[ BitmapIndex
] & Bitmap
) == 0)
1954 // This shouldn't have been so...
1955 // The block was never allocated!
1956 // How to deallocate something that hasn't been allocated?
1958 // Ignore this error...
1959 try_return (RC
= TRUE
);
1962 // Setting the bit for the inode...
1963 PtrBitmapBuffer
[ BitmapIndex
] &= (~Bitmap
);
1965 // Update the cache...
1966 CcSetDirtyPinnedData( PtrBitmapBCB
, NULL
);
1968 // Save up the BCB for forcing a synchronous write...
1969 // Before completing the IRP...
1970 Ext2SaveBCB( PtrIrpContext
, PtrBitmapBCB
, PtrVCB
->PtrStreamFileObject
);
1975 CcUnpinData( PtrBitmapBCB
);
1976 PtrBitmapBCB
= NULL
;
1980 // Updating the Block count in the Group Descriptor...
1984 PBCB PtrDescriptorBCB
= NULL
;
1985 PEXT2_GROUP_DESCRIPTOR PtrGroupDescriptor
= NULL
;
1986 ULONG NumberOfBytesToRead
= 0;
1988 // Updating the Free Blocks count in the Group Descriptor...
1990 PtrVCB
->PtrGroupDescriptors
[ GroupNo
].FreeBlocksCount
++;
1992 if( PtrVCB
->LogBlockSize
)
1994 // First block contains the descriptors...
1995 VolumeByteOffset
.QuadPart
= LogicalBlockSize
;
1999 // Second block contains the descriptors...
2000 VolumeByteOffset
.QuadPart
= LogicalBlockSize
* 2;
2002 NumberOfBytesToRead
= PtrVCB
->NoOfGroups
* sizeof( struct ext2_group_desc
);
2003 NumberOfBytesToRead
= Ext2Align( NumberOfBytesToRead
, LogicalBlockSize
);
2005 if (!CcPinRead( PtrVCB
->PtrStreamFileObject
,
2007 NumberOfBytesToRead
,
2010 (PVOID
*)&PtrGroupDescriptor
))
2012 DebugTrace(DEBUG_TRACE_ERROR
, "Cache read failiure while reading in volume meta data", 0);
2014 // Ignore this error...
2019 PtrGroupDescriptor
[ GroupNo
].bg_free_blocks_count
=
2020 PtrVCB
->PtrGroupDescriptors
[ GroupNo
].FreeBlocksCount
;
2023 // Not synchronously flushing this information...
2024 // Lazy writing will do...
2026 CcSetDirtyPinnedData( PtrDescriptorBCB
, NULL
);
2027 CcUnpinData( PtrDescriptorBCB
);
2028 PtrDescriptorBCB
= NULL
;
2033 // Update the Block count
2034 // in the super block and in the VCB
2037 // Ext2 Super Block information...
2038 PEXT2_SUPER_BLOCK PtrSuperBlock
= NULL
;
2039 PBCB PtrSuperBlockBCB
= NULL
;
2040 ULONG NumberOfBytesToRead
= 0;
2042 PtrVCB
->FreeBlocksCount
++;
2044 // Reading in the super block...
2045 VolumeByteOffset
.QuadPart
= 1024;
2046 NumberOfBytesToRead
= Ext2Align( sizeof( EXT2_SUPER_BLOCK
), LogicalBlockSize
);
2048 if( !CcPinRead( PtrVCB
->PtrStreamFileObject
,
2050 NumberOfBytesToRead
,
2053 (PVOID
*)&PtrSuperBlock
) )
2055 DebugTrace(DEBUG_TRACE_ERROR
, "Cache read failiure while reading in volume meta data", 0);
2059 PtrSuperBlock
->s_free_blocks_count
= PtrVCB
->FreeBlocksCount
;
2060 CcSetDirtyPinnedData( PtrSuperBlockBCB
, NULL
);
2061 Ext2SaveBCB( PtrIrpContext
, PtrSuperBlockBCB
, PtrVCB
->PtrStreamFileObject
);
2062 CcUnpinData( PtrSuperBlockBCB
);
2063 PtrSuperBlockBCB
= NULL
;
2072 CcUnpinData( PtrBitmapBCB
);
2073 PtrBitmapBCB
= NULL
;
2079 BOOLEAN
Ext2UpdateFileSize(
2080 PtrExt2IrpContext PtrIrpContext
,
2081 PFILE_OBJECT PtrFileObject
,
2085 PtrExt2VCB PtrVCB
= PtrFCB
->PtrVCB
;
2087 if( PtrFileObject
->PrivateCacheMap
)
2089 CcSetFileSizes( PtrFileObject
, (PCC_FILE_SIZES
)&(PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.AllocationSize
));
2091 // Now update the size on the disk...
2092 // Read in the inode...
2093 if( ! NT_SUCCESS( Ext2ReadInode( PtrVCB
, PtrFCB
->INodeNo
, &Inode
) ) )
2098 Inode
.i_size
= PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.LowPart
;
2099 // Update time also???
2101 // Updating the inode...
2102 if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext
, PtrVCB
, PtrFCB
->INodeNo
, &Inode
) ) )
2112 /*************************************************************************
2114 * Function: Ext2DeleteFile()
2117 * The functions will delete a file
2119 * Expected Interrupt Level (for execution) :
2120 * IRQL_PASSIVE_LEVEL
2122 * Return Value: Success / Failure...
2124 *************************************************************************/
2125 BOOLEAN
Ext2DeleteFile(
2127 PtrExt2IrpContext PtrIrpContext
)
2130 PtrExt2FCB PtrParentFCB
= NULL
;
2131 PtrExt2VCB PtrVCB
= PtrFCB
->PtrVCB
;
2134 // Get the Parent Directory...
2135 PtrParentFCB
= Ext2LocateFCBInCore( PtrVCB
, PtrFCB
->ParentINodeNo
);
2136 Ext2InitializeFCBInodeInfo( PtrFCB
);
2139 // Free up the directory entry...
2140 if( !Ext2FreeDirectoryEntry( PtrIrpContext
,
2141 PtrParentFCB
, &PtrFCB
->FCBName
->ObjectName
) )
2147 // Decrement Link count...
2148 if( !NT_SUCCESS( Ext2ReadInode( PtrVCB
, PtrFCB
->INodeNo
, &Inode
) ) )
2153 ASSERT( Inode
.i_links_count
== PtrFCB
->LinkCount
);
2155 Inode
.i_links_count
--;
2156 PtrFCB
->LinkCount
= Inode
.i_links_count
;
2158 if( !Inode
.i_links_count
)
2161 // Setting the deletion time field in the inode...
2164 Time
= Ext2GetCurrentTime();
2165 Inode
.i_dtime
= Time
;
2169 // Updating the inode...
2171 if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext
, PtrVCB
, PtrFCB
->INodeNo
, &Inode
) ) )
2173 if( Inode
.i_links_count
)
2175 // Some more links to the same file are available...
2176 // So we won't deallocate the data blocks...
2186 // Free up the inode...
2187 Ext2DeallocInode( PtrIrpContext
, PtrVCB
, PtrFCB
->INodeNo
);
2190 // Release the data blocks...
2191 Ext2ReleaseDataBlocks( PtrFCB
, PtrIrpContext
);
2197 /*************************************************************************
2199 * Function: Ext2ReleaseDataBlocks()
2202 * The functions will release all the data blocks in a file
2203 * It does NOT update the file inode...
2205 * Expected Interrupt Level (for execution) :
2206 * IRQL_PASSIVE_LEVEL
2208 * Return Value: Success / Failure...
2210 *************************************************************************/
2211 BOOLEAN
Ext2ReleaseDataBlocks(
2213 PtrExt2IrpContext PtrIrpContext
)
2215 PtrExt2VCB PtrVCB
= PtrFCB
->PtrVCB
;
2216 ULONG LogicalBlockSize
;
2220 LogicalBlockSize
= EXT2_MIN_BLOCK_SIZE
<< PtrVCB
->LogBlockSize
;
2222 // Release the data blocks...
2225 // Free up the triple indirect blocks...
2226 if( PtrFCB
->IBlock
[ EXT2_TIND_BLOCK
] )
2229 PBCB PtrSIBCB
= NULL
;
2230 PBCB PtrDIBCB
= NULL
;
2231 PBCB PtrTIBCB
= NULL
;
2233 ULONG
* PtrPinnedSIndirectBlock
= NULL
;
2234 ULONG
* PtrPinnedDIndirectBlock
= NULL
;
2235 ULONG
* PtrPinnedTIndirectBlock
= NULL
;
2237 LARGE_INTEGER VolumeByteOffset
;
2238 ULONG TIndex
, DIndex
, SIndex
;
2240 // Pin the Double Indirect Pointer Block...
2241 VolumeByteOffset
.QuadPart
= PtrFCB
->IBlock
[ EXT2_TIND_BLOCK
] * LogicalBlockSize
;
2242 if (!CcMapData( PtrVCB
->PtrStreamFileObject
,
2247 (PVOID
*)&PtrPinnedTIndirectBlock
))
2252 // Read the Block numbers off the Triple Indirect Pointer Block...
2253 for( TIndex
= 0; TIndex
< (LogicalBlockSize
/sizeof(ULONG
)); TIndex
++ )
2255 if( PtrPinnedTIndirectBlock
[ TIndex
] )
2257 VolumeByteOffset
.QuadPart
= PtrPinnedTIndirectBlock
[TIndex
] * LogicalBlockSize
;
2258 if (!CcMapData( PtrVCB
->PtrStreamFileObject
,
2263 (PVOID
*)&PtrPinnedDIndirectBlock
))
2268 // Read the Block numbers off the Double Indirect Pointer Blocks...
2269 for( DIndex
= 0; DIndex
< (LogicalBlockSize
/sizeof(ULONG
)); DIndex
++ )
2271 if( PtrPinnedDIndirectBlock
[DIndex
] )
2273 VolumeByteOffset
.QuadPart
= PtrPinnedDIndirectBlock
[DIndex
] * LogicalBlockSize
;
2274 if (!CcMapData( PtrVCB
->PtrStreamFileObject
,
2279 (PVOID
*)&PtrPinnedSIndirectBlock
))
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
++ )
2288 if( PtrPinnedSIndirectBlock
[ SIndex
] )
2290 Ext2DeallocBlock( PtrIrpContext
, PtrVCB
, PtrPinnedSIndirectBlock
[SIndex
] );
2297 CcUnpinData( PtrSIBCB
);
2300 // Single Indirect Pointer Block
2301 Ext2DeallocBlock( PtrIrpContext
, PtrVCB
, PtrPinnedDIndirectBlock
[DIndex
] );
2314 CcUnpinData( PtrTIBCB
);
2315 // Deallocating Triple Indirect Pointer Blocks
2316 Ext2DeallocBlock( PtrIrpContext
, PtrVCB
, PtrFCB
->IBlock
[ EXT2_TIND_BLOCK
] );
2320 // Free up the double indirect blocks...
2321 if( PtrFCB
->IBlock
[ EXT2_DIND_BLOCK
] )
2323 PBCB PtrDIBCB
= NULL
;
2324 PBCB PtrSIBCB
= NULL
;
2325 ULONG
* PtrPinnedSIndirectBlock
= NULL
;
2326 ULONG
* PtrPinnedDIndirectBlock
= NULL
;
2328 LARGE_INTEGER VolumeByteOffset
;
2329 ULONG DIndex
, SIndex
;
2331 // Pin the Double Indirect Pointer Block...
2332 VolumeByteOffset
.QuadPart
= PtrFCB
->IBlock
[ EXT2_DIND_BLOCK
] * LogicalBlockSize
;
2333 if (!CcMapData( PtrVCB
->PtrStreamFileObject
,
2338 (PVOID
*)&PtrPinnedDIndirectBlock
))
2343 // Read the Block numbers off the Double Indirect Pointer Block...
2344 for( DIndex
= 0; DIndex
< (LogicalBlockSize
/sizeof(ULONG
)); DIndex
++ )
2346 if( PtrPinnedDIndirectBlock
[DIndex
] )
2348 VolumeByteOffset
.QuadPart
= PtrPinnedDIndirectBlock
[DIndex
] * LogicalBlockSize
;
2349 if (!CcMapData( PtrVCB
->PtrStreamFileObject
,
2354 (PVOID
*)&PtrPinnedSIndirectBlock
))
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
++ )
2363 if( PtrPinnedSIndirectBlock
[ SIndex
] )
2365 Ext2DeallocBlock( PtrIrpContext
, PtrVCB
, PtrPinnedSIndirectBlock
[SIndex
] );
2372 CcUnpinData( PtrSIBCB
);
2375 // Single Indirect Pointer Block
2376 Ext2DeallocBlock( PtrIrpContext
, PtrVCB
, PtrPinnedDIndirectBlock
[DIndex
] );
2383 CcUnpinData( PtrDIBCB
);
2384 // Deallocating Double Indirect Pointer Blocks
2385 Ext2DeallocBlock( PtrIrpContext
, PtrVCB
, PtrFCB
->IBlock
[ EXT2_DIND_BLOCK
] );
2389 // Free up the single indirect blocks...
2390 if( PtrFCB
->IBlock
[ EXT2_IND_BLOCK
] )
2393 ULONG
* PtrPinnedSIndirectBlock
= NULL
;
2394 LARGE_INTEGER VolumeByteOffset
;
2397 // Pin the Single Indirect Pointer Block...
2398 VolumeByteOffset
.QuadPart
= PtrFCB
->IBlock
[ EXT2_IND_BLOCK
] * LogicalBlockSize
;
2399 if (!CcMapData( PtrVCB
->PtrStreamFileObject
,
2404 (PVOID
*)&PtrPinnedSIndirectBlock
))
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
++ )
2413 if( PtrPinnedSIndirectBlock
[Index
] )
2415 Ext2DeallocBlock( PtrIrpContext
, PtrVCB
, PtrPinnedSIndirectBlock
[Index
] );
2422 CcUnpinData( PtrBCB
);
2423 Ext2DeallocBlock( PtrIrpContext
, PtrVCB
, PtrFCB
->IBlock
[ EXT2_IND_BLOCK
] );
2427 // Free up the direct blocks...
2428 for( i
= 0; i
< EXT2_NDIR_BLOCKS
; i
++ )
2430 if( PtrFCB
->IBlock
[ i
] )
2432 Ext2DeallocBlock( PtrIrpContext
, PtrVCB
, PtrFCB
->IBlock
[ i
] );
2443 BOOLEAN
Ext2TruncateFileAllocationSize(
2444 PtrExt2IrpContext PtrIrpContext
,
2446 PFILE_OBJECT PtrFileObject
,
2447 PLARGE_INTEGER PtrAllocationSize
)
2449 PtrExt2VCB PtrVCB
= PtrFCB
->PtrVCB
;
2450 ULONG LogicalBlockSize
;
2453 ULONG NoOfBlocksToBeLeft
= 0;
2454 ULONG CurrentBlockNo
= 0;
2457 // This function has not been tested...
2461 LogicalBlockSize
= EXT2_MIN_BLOCK_SIZE
<< PtrVCB
->LogBlockSize
;
2462 NoOfBlocksToBeLeft
= (ULONG
) (PtrAllocationSize
->QuadPart
/ LogicalBlockSize
);
2466 // Release the data blocks...
2469 // Free up the direct blocks...
2470 for( i
= NoOfBlocksToBeLeft
; i
< EXT2_NDIR_BLOCKS
; i
++ )
2472 if( PtrFCB
->IBlock
[ i
] )
2474 Ext2DeallocBlock( PtrIrpContext
, PtrVCB
, PtrFCB
->IBlock
[ i
] );
2475 PtrFCB
->IBlock
[ i
] = 0;
2484 // Free up the single indirect blocks...
2485 CurrentBlockNo
= EXT2_NDIR_BLOCKS
;
2487 if( PtrFCB
->IBlock
[ EXT2_IND_BLOCK
] )
2490 ULONG
* PtrPinnedSIndirectBlock
= NULL
;
2491 LARGE_INTEGER VolumeByteOffset
;
2494 // Pin the Single Indirect Pointer Block...
2495 VolumeByteOffset
.QuadPart
= PtrFCB
->IBlock
[ EXT2_IND_BLOCK
] * LogicalBlockSize
;
2496 if (!CcMapData( PtrVCB
->PtrStreamFileObject
,
2501 (PVOID
*)&PtrPinnedSIndirectBlock
))
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
++ )
2511 if( CurrentBlockNo
>= NoOfBlocksToBeLeft
)
2513 if( PtrPinnedSIndirectBlock
[Index
] )
2515 Ext2DeallocBlock( PtrIrpContext
, PtrVCB
, PtrPinnedSIndirectBlock
[Index
] );
2522 else if( !PtrPinnedSIndirectBlock
[Index
] )
2527 if( NoOfBlocksToBeLeft
<= EXT2_NDIR_BLOCKS
)
2529 Ext2DeallocBlock( PtrIrpContext
, PtrVCB
, PtrFCB
->IBlock
[ EXT2_IND_BLOCK
] );
2530 PtrFCB
->IBlock
[ EXT2_IND_BLOCK
] = 0;
2533 CcUnpinData( PtrBCB
);
2537 // Free up the double indirect blocks...
2538 if( PtrFCB
->IBlock
[ EXT2_DIND_BLOCK
] )
2544 // Free up the triple indirect blocks...
2545 if( PtrFCB
->IBlock
[ EXT2_TIND_BLOCK
] )
2553 BOOLEAN
Ext2IsDirectoryEmpty(
2556 PtrExt2IrpContext PtrIrpContext
)
2559 PFILE_OBJECT PtrFileObject
= NULL
;
2561 if( !Ext2IsFlagOn(PtrFCB
->FCBFlags
, EXT2_FCB_DIRECTORY
) )
2567 // Initialize the Blocks in the FCB...
2569 Ext2InitializeFCBInodeInfo( PtrFCB
);
2573 // Get hold of the file object...
2575 PtrFileObject
= PtrCCB
->PtrFileObject
;
2579 // Now initiating Caching, pinned access to be precise ...
2581 if (PtrFileObject
->PrivateCacheMap
== NULL
)
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
2590 // Getting down to the real business now... ;)
2591 // Read in the directory contents and do a search
2594 LARGE_INTEGER StartBufferOffset
;
2595 ULONG PinBufferLength
;
2598 BYTE
* PtrPinnedBlockBuffer
= NULL
;
2599 PEXT2_DIR_ENTRY PtrDirEntry
= NULL
;
2600 BOOLEAN Found
= FALSE
;
2605 StartBufferOffset
.QuadPart
= 0;
2608 // Read in the whole directory
2609 // **Bad programming**
2612 PinBufferLength
= PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.LowPart
;
2613 if (!CcMapData( PtrFileObject
,
2618 (PVOID
*)&PtrPinnedBlockBuffer
) )
2624 // Walking through now...
2626 for( BufferIndex
= 0, Found
= FALSE
; !Found
&& BufferIndex
< ( PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.QuadPart
- 1) ; BufferIndex
+= PtrDirEntry
->rec_len
)
2628 PtrDirEntry
= (PEXT2_DIR_ENTRY
) &PtrPinnedBlockBuffer
[ BufferIndex
];
2629 if( PtrDirEntry
->inode
== 0)
2635 if( PtrDirEntry
->name
[0] == '.' )
2637 if( PtrDirEntry
->name_len
== 1 ||
2638 ( PtrDirEntry
->name_len
== 2 && PtrDirEntry
->name
[1] == '.' ) )
2645 CcUnpinData( PtrBCB
);
2653 NTSTATUS
Ext2RenameOrLinkFile(
2654 PtrExt2FCB PtrSourceFCB
,
2655 PFILE_OBJECT PtrSourceFileObject
,
2656 PtrExt2IrpContext PtrIrpContext
,
2658 PFILE_RENAME_INFORMATION PtrRenameInfo
)
2660 PtrExt2FCB PtrParentFCB
= NULL
;
2661 PtrExt2VCB PtrSourceVCB
= PtrSourceFCB
->PtrVCB
;
2663 PtrExt2FCB PtrTargetFCB
= NULL
;
2664 PtrExt2CCB PtrTargetCCB
= NULL
;
2665 PtrExt2VCB PtrTargetVCB
= NULL
;
2668 FILE_INFORMATION_CLASS FunctionalityRequested
;
2669 PIO_STACK_LOCATION PtrIoStackLocation
= NULL
;
2670 PFILE_OBJECT TargetFileObject
= NULL
;
2671 BOOLEAN ReplaceExistingFile
= FALSE
;
2672 BOOLEAN Found
= FALSE
;
2674 PtrIoStackLocation
= IoGetCurrentIrpStackLocation(PtrIrp
);
2675 FunctionalityRequested
= PtrIoStackLocation
->Parameters
.SetFile
.FileInformationClass
;
2676 TargetFileObject
= PtrIoStackLocation
->Parameters
.SetFile
.FileObject
;
2677 ReplaceExistingFile
= PtrIoStackLocation
->Parameters
.SetFile
.ReplaceIfExists
;
2679 // Get the FCB and CCB pointers
2680 Ext2GetFCB_CCB_VCB_FromFileObject (
2681 TargetFileObject
, &PtrTargetFCB
, &PtrTargetCCB
, &PtrTargetVCB
);
2685 return STATUS_ACCESS_DENIED
;
2687 if( PtrTargetVCB
!= PtrSourceVCB
)
2689 // Cannot rename across volumes...
2690 return STATUS_ACCESS_DENIED
;
2692 if ( !Ext2IsFlagOn( PtrTargetFCB
->FCBFlags
, EXT2_FCB_DIRECTORY
) )
2694 // Target has to be a folder...
2695 return STATUS_ACCESS_DENIED
;
2699 // Open the parent folder...
2700 PtrParentFCB
= Ext2LocateFCBInCore( PtrSourceVCB
, PtrSourceFCB
->ParentINodeNo
);
2703 // Get the folder from the disk
2704 // Use the inode no PtrSourceFCB->ParentINodeNo
2707 return STATUS_ACCESS_DENIED
;
2711 // Check if the file exists in the TargetFolder...
2713 LARGE_INTEGER StartBufferOffset
;
2714 ULONG PinBufferLength
;
2717 BYTE
* PtrPinnedBlockBuffer
= NULL
;
2718 PEXT2_DIR_ENTRY PtrDirEntry
= NULL
;
2721 StartBufferOffset
.QuadPart
= 0;
2724 // Read in the whole directory
2726 if ( TargetFileObject
->PrivateCacheMap
== NULL
)
2728 CcInitializeCacheMap(
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
2736 PinBufferLength
= PtrTargetFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.LowPart
;
2737 if (!CcMapData( TargetFileObject
,
2742 (PVOID
*)&PtrPinnedBlockBuffer
) )
2748 // Walking through now...
2750 for( BufferIndex
= 0, Found
= FALSE
; !Found
&& BufferIndex
< ( PtrTargetFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
.QuadPart
- 1) ; BufferIndex
+= PtrDirEntry
->rec_len
)
2752 PtrDirEntry
= (PEXT2_DIR_ENTRY
) &PtrPinnedBlockBuffer
[ BufferIndex
];
2753 if( PtrDirEntry
->inode
== 0)
2759 if( PtrDirEntry
->name_len
== (PtrTargetCCB
->RenameLinkTargetFileName
.Length
/2) )
2762 for( i
=0; i
< PtrDirEntry
->name_len
; i
++ )
2764 if( PtrDirEntry
->name
[i
] != PtrTargetCCB
->RenameLinkTargetFileName
.Buffer
[i
] )
2772 CcUnpinData( PtrBCB
);
2777 // If the file exists, delete it if requested..
2780 if( !ReplaceExistingFile
)
2782 return STATUS_OBJECT_NAME_COLLISION
;
2784 // Delete the file...
2785 // Reject this for now...
2786 return STATUS_ACCESS_DENIED
;
2791 ULONG Type
= EXT2_FT_REG_FILE
;
2792 if( Ext2IsFlagOn( PtrSourceFCB
->FCBFlags
, EXT2_FCB_DIRECTORY
) )
2797 ASSERT( TargetFileObject
);
2800 // Remove the old entry...
2801 Ext2FreeDirectoryEntry( PtrIrpContext
, PtrParentFCB
,
2802 &PtrSourceFCB
->FCBName
->ObjectName
);
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...
2817 // Update the PtrSourceFCB...
2820 PtrExt2ObjectName PtrObjectName
;
2821 if( PtrSourceFCB
->FCBName
)
2823 Ext2ReleaseObjectName( PtrSourceFCB
->FCBName
);
2825 PtrObjectName
= Ext2AllocateObjectName();
2826 Ext2CopyUnicodeString( &PtrObjectName
->ObjectName
, &PtrTargetCCB
->RenameLinkTargetFileName
);
2827 PtrSourceFCB
->FCBName
= PtrObjectName
;
2828 PtrSourceFCB
->ParentINodeNo
= PtrTargetFCB
->INodeNo
;
2831 if( PtrTargetCCB
->RenameLinkTargetFileName
.Length
)
2833 Ext2DeallocateUnicodeString( &PtrTargetCCB
->RenameLinkTargetFileName
);
2836 return STATUS_SUCCESS
;