ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

metadata.c
Go to the documentation of this file.
00001 /*************************************************************************
00002 *
00003 * File: metadata.c
00004 *
00005 * Module: Ext2 File System Driver (Kernel mode execution only)
00006 *
00007 * Description:
00008 *   Should contain code to handle Ext2 Metadata.
00009 *
00010 * Author: Manoj Paul Joseph
00011 *
00012 *
00013 *************************************************************************/
00014 
00015 #include            "ext2fsd.h"
00016 
00017 #define         EXT2_BUG_CHECK_ID               EXT2_FILE_METADATA_IO
00018 
00019 #define         DEBUG_LEVEL                     ( DEBUG_TRACE_METADATA )
00020 
00021 extern  Ext2Data                    Ext2GlobalData;
00022 
00023 /*************************************************************************
00024 *
00025 * Function: Ext2ReadInode()
00026 *
00027 * Description:
00028 *
00029 *   The functions will read in the specifiec inode and return it in a buffer
00030 *
00031 * 
00032 * Expected Interrupt Level (for execution) :
00033 *
00034 *  IRQL_PASSIVE_LEVEL 
00035 *
00036 *
00037 * Arguements:
00038 *
00039 *
00040 *
00041 * Return Value: The Status of the Read IO
00042 *
00043 *************************************************************************/
00044 
00045 NTSTATUS NTAPI Ext2ReadInode (
00046     PtrExt2VCB      PtrVcb,         //  the Volume Control Block
00047     uint32          InodeNo,        //  The Inode no
00048     PEXT2_INODE     PtrInode        //  The Inode Buffer
00049     )                   
00050 {
00051     //  The Status to be returned...
00052     NTSTATUS RC = STATUS_SUCCESS;
00053 
00054     //  The Read Buffer Pointer
00055     BYTE * PtrPinnedReadBuffer = NULL;
00056 
00057     PEXT2_INODE     PtrTempInode;
00058 
00059     //  Buffer Control Block
00060     PBCB PtrBCB = NULL;
00061 
00062     LARGE_INTEGER VolumeByteOffset, TempOffset;
00063 
00064     ULONG LogicalBlockSize = 0;
00065 
00066     ULONG NumberOfBytesToRead = 0;
00067     ULONG Difference = 0;
00068 
00069     ULONG GroupNo;
00070     int Index;
00071 
00072     try
00073     {
00074         ASSERT(PtrVcb);
00075         ASSERT(PtrVcb->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB);
00076 
00077         //  Inode numbers start at 1 and not from 0
00078         //  Hence 1 is subtracted from InodeNo to get a zero based index...
00079         GroupNo = ( InodeNo - 1 ) / PtrVcb->InodesPerGroup;
00080 
00081         if( GroupNo >= PtrVcb->NoOfGroups )
00082         {
00083             DebugTrace(DEBUG_TRACE_MISC,   "&&&&&& Invalid Inode no. Group no %d - too big", GroupNo );
00084             DebugTrace(DEBUG_TRACE_MISC,   "Only %d groups available on disk", PtrVcb->NoOfGroups );
00085             RC = STATUS_UNSUCCESSFUL;
00086             try_return();
00087         }
00088 
00089         //if( PtrVcb->InodeTableBlock[ GroupNo ] == 0 )
00090         if( PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock == 0 )
00091         {
00092             DebugTrace(DEBUG_TRACE_MISC,   "&&&&&& Inode Table Group Invalid - Group no %d ", GroupNo );
00093             RC = STATUS_UNSUCCESSFUL;
00094             try_return();
00095         }
00096 
00097         //  Inode numbers start at 1 and not from 0
00098         //  Hence 1 is subtracted from InodeNo to get a zero based index...
00099         Index = ( InodeNo - 1 ) - ( GroupNo * PtrVcb->InodesPerGroup );
00100 
00101         LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVcb->LogBlockSize;
00102         NumberOfBytesToRead = sizeof(EXT2_INODE);   //  LogicalBlockSize;
00103 
00104         VolumeByteOffset.QuadPart = PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock
00105                 * LogicalBlockSize + Index * PtrVcb->InodeSize;
00106         //VolumeByteOffset.QuadPart = PtrVcb->InodeTableBlock[ GroupNo ] * LogicalBlockSize +
00107         //  Index * PtrVcb->InodeSize;
00108         
00109         TempOffset.QuadPart = Ext2Align64( VolumeByteOffset.QuadPart, LogicalBlockSize );
00110         if( TempOffset.QuadPart != VolumeByteOffset.QuadPart )
00111         {
00112             //  TempOffset.QuadPart -= LogicalBlockSize;
00113             Difference = (LONG) (VolumeByteOffset.QuadPart - TempOffset.QuadPart + LogicalBlockSize );
00114             VolumeByteOffset.QuadPart -= Difference;
00115             NumberOfBytesToRead += Difference;
00116         }
00117 
00118         NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
00119 
00120         if( NumberOfBytesToRead > LogicalBlockSize )
00121         {
00122             //  Multiple blocks being read in...
00123             //  Can cause overlap
00124             //  Watch out!!!!
00125             Ext2BreakPoint();
00126         }
00127 
00128 
00129 
00130         if (!CcMapData( PtrVcb->PtrStreamFileObject,
00131             &VolumeByteOffset,
00132             NumberOfBytesToRead,
00133             TRUE,
00134             &PtrBCB,
00135             (PVOID*)&PtrPinnedReadBuffer )) 
00136         {
00137             RC = STATUS_UNSUCCESSFUL;
00138             try_return();
00139         }
00140         else
00141         {
00142             PtrTempInode = (PEXT2_INODE) ( PtrPinnedReadBuffer + Difference );
00143             RtlCopyMemory( PtrInode, PtrTempInode , sizeof(EXT2_INODE) );
00144         }
00145 
00146         try_exit:   NOTHING;
00147     }
00148     finally
00149     {
00150         if( PtrBCB )
00151         {
00152             CcUnpinData( PtrBCB );
00153             PtrBCB = NULL;
00154         }
00155 
00156     }
00157     return RC;
00158 }
00159 
00160 /*************************************************************************
00161 *
00162 * Function: Ext2InitializeFCBInodeInfo()
00163 *
00164 * Description:
00165 *   The functions will initialize the FCB with its i-node info
00166 *   provided it hasn't been initialized as yet...
00167 *
00168 * Expected Interrupt Level (for execution) :
00169 *  IRQL_PASSIVE_LEVEL 
00170 *
00171 * Arguements:
00172 *   Pointer to FCB
00173 *
00174 * Return Value: None
00175 *
00176 *************************************************************************/
00177 void NTAPI Ext2InitializeFCBInodeInfo (
00178     PtrExt2FCB  PtrFCB )
00179 {
00180     PtrExt2VCB          PtrVCB = NULL;
00181     EXT2_INODE          Inode;
00182     int i;
00183     ULONG LogicalBlockSize;
00184 
00185     PtrVCB = PtrFCB->PtrVCB;
00186 
00187     LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
00188 
00189     if( !Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED ) )
00190     {
00191         DebugTrace(DEBUG_TRACE_MISC,   "Reading in the i-node no %d", PtrFCB->INodeNo );
00192 
00193         Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode );   
00194             
00195         for( i = 0; i < EXT2_N_BLOCKS ; i++ )
00196         {
00197             PtrFCB->IBlock[i] = Inode.i_block[ i ];
00198         }
00199 
00200         PtrFCB->CreationTime.QuadPart   = ( __int64 )Inode.i_ctime * 10000000;
00201         PtrFCB->CreationTime.QuadPart   += Ext2GlobalData.TimeDiff.QuadPart;
00202         PtrFCB->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) Inode.i_atime * 10000000);
00203         PtrFCB->LastWriteTime.QuadPart  = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) Inode.i_mtime * 10000000);
00204 
00205 
00206         PtrFCB->LinkCount = Inode.i_links_count;
00207 
00208         //  Getting the file type...
00209         if( ! Ext2IsModeRegularFile( Inode.i_mode ) )
00210         {  
00211             //  Not a reqular file...
00212             if( Ext2IsModeDirectory( Inode.i_mode) )
00213             {
00214                 //  Directory...
00215                 Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY );
00216             }
00217             else
00218             {
00219                 //  Special File...
00220                 //  Treated with respect... ;)
00221                 //
00222                 Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_SPECIAL_FILE );
00223             }
00224 
00225         }
00226         if( Ext2IsModeHidden( Inode.i_mode ) )
00227         {
00228             Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_HIDDEN_FILE );
00229         }
00230         if( Ext2IsModeReadOnly( Inode.i_mode ) )
00231         {
00232             Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_READ_ONLY );
00233         }
00234         
00235 
00236         PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart = Inode.i_size;
00237         Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED );
00238         PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart = Inode.i_blocks * 512;
00239 
00240         if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] )
00241         {
00242             PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart -= LogicalBlockSize / 512;
00243         }
00244         DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [metadata]", Inode );
00245     }
00246 }
00247 
00248 /*************************************************************************
00249 *
00250 * Function: Ext2AllocInode()
00251 *
00252 * Description:
00253 *   The functions will allocate a new on-disk i-node
00254 *
00255 * Expected Interrupt Level (for execution) :
00256 *  IRQL_PASSIVE_LEVEL 
00257 *
00258 *
00259 * Arguements:
00260 *   Parent Inode no
00261 *
00262 * Return Value: The new i-node no or zero
00263 *
00264 *************************************************************************/
00265 ULONG NTAPI Ext2AllocInode( 
00266     PtrExt2IrpContext   PtrIrpContext,
00267     PtrExt2VCB          PtrVCB,
00268     ULONG               ParentINodeNo )
00269 {
00270     ULONG InodeNo = 0;
00271 
00272     //  Buffer Control Block
00273     PBCB        PtrBitmapBCB = NULL;
00274     BYTE *      PtrBitmapBuffer = NULL;
00275 
00276     LARGE_INTEGER VolumeByteOffset;
00277     ULONG LogicalBlockSize = 0;
00278     ULONG NumberOfBytesToRead = 0;
00279     
00280     if( PtrVCB->FreeInodesCount == 0)
00281     {
00282         //
00283         //  No Free Inodes left...
00284         //  Fail request...
00285         //
00286         return 0;
00287     }
00288 
00289     try
00290     {
00291         //  unsigned int DescIndex ;
00292         BOOLEAN Found = FALSE;
00293         ULONG Block;
00294         ULONG GroupNo;
00295 
00296         LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
00297         
00298         for( GroupNo = 0; PtrVCB->NoOfGroups; GroupNo++ )
00299         {
00300             if( PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount )
00301                 break;
00302         }
00303 
00304         VolumeByteOffset.QuadPart = 
00305             PtrVCB->PtrGroupDescriptors[ GroupNo ].InodeBitmapBlock * LogicalBlockSize;
00306         
00307         NumberOfBytesToRead = PtrVCB->InodesCount / PtrVCB->NoOfGroups;
00308 
00309         if( NumberOfBytesToRead % 8 )
00310         {
00311             NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) + 1;
00312         }
00313         else
00314         {
00315             NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) ;
00316         }
00317 
00318         for( Block = 0; !Found && Block < Ext2Align( NumberOfBytesToRead , LogicalBlockSize ); 
00319                 Block += LogicalBlockSize, VolumeByteOffset.QuadPart += LogicalBlockSize)
00320         {   
00321             //
00322             //  Read in the bitmap block...
00323             //
00324             ULONG i, j;
00325             BYTE Bitmap;
00326             
00327             if( !CcPinRead( PtrVCB->PtrStreamFileObject,
00328                    &VolumeByteOffset,
00329                    LogicalBlockSize, //NumberOfBytesToRead,
00330                    TRUE,
00331                    &PtrBitmapBCB,
00332                    (PVOID*)&PtrBitmapBuffer ) )
00333             {
00334                 DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
00335                 return 0;
00336             }
00337             
00338             //
00339             //  Is there a free inode...
00340             //  
00341             for( i = 0; !Found && i < LogicalBlockSize && 
00342                         i + (Block * LogicalBlockSize) < NumberOfBytesToRead; i++ )
00343             {
00344                 Bitmap = PtrBitmapBuffer[i];
00345                 if( Bitmap != 0xff )
00346                 {
00347                     //
00348                     //  Found a free inode...
00349                     for( j = 0; !Found && j < 8; j++ )
00350                     {
00351                         if( ( Bitmap & 0x01 ) == 0 )
00352                         {
00353                             //
00354                             //  Found...
00355                             Found = TRUE;
00356 
00357                             //  Inode numbers start at 1 and not from 0
00358                             //  Hence 1 is addded to j 
00359                             InodeNo = ( ( ( Block * LogicalBlockSize) + i ) * 8) + j + 1 +
00360                                 ( GroupNo * PtrVCB->InodesPerGroup );
00361                         
00362                             //  Update the inode on the disk...
00363                             Bitmap = 1 << j;
00364                             PtrBitmapBuffer[i] |= Bitmap;
00365                             
00366                             CcSetDirtyPinnedData( PtrBitmapBCB, NULL );
00367                             Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject );
00368 
00369                             //
00370                             //  Should update the bitmaps in the other groups too...
00371                             //
00372                             break;
00373                         }
00374                         Bitmap = Bitmap >> 1;
00375                     }
00376                 }
00377             }
00378             //
00379             //  Unpin the BCB...
00380             //
00381             if( PtrBitmapBCB )
00382             {
00383                 CcUnpinData( PtrBitmapBCB );
00384                 PtrBitmapBCB = NULL;
00385             }
00386         }
00387 
00388         {
00389             //
00390             //  Updating the Inode count in the Group Descriptor...
00391             //  
00392             PBCB                    PtrDescriptorBCB = NULL;
00393             PEXT2_GROUP_DESCRIPTOR  PtrGroupDescriptor = NULL;
00394 
00395             PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount--;
00396 
00397             if( PtrVCB->LogBlockSize )
00398             {
00399                 //  First block contains the descriptors...
00400                 VolumeByteOffset.QuadPart = LogicalBlockSize;
00401             }
00402             else
00403             {
00404                 //  Second block contains the descriptors...
00405                 VolumeByteOffset.QuadPart = LogicalBlockSize * 2;
00406             }
00407             NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc );
00408             NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
00409 
00410             if (!CcPinRead( PtrVCB->PtrStreamFileObject,
00411                    &VolumeByteOffset,
00412                    NumberOfBytesToRead,
00413                    TRUE,
00414                    &PtrDescriptorBCB ,
00415                    (PVOID*)&PtrGroupDescriptor )) 
00416             {
00417                 DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
00418                 //
00419                 //  Ignore this error...
00420                 //  Not fatal...
00421             }
00422             else
00423             {
00424                 PtrGroupDescriptor[ GroupNo ].bg_free_inodes_count = 
00425                     PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount; 
00426                 //
00427                 //  Not synchronously flushing this information...
00428                 //  Lazy writing will do...
00429                 //
00430                 CcSetDirtyPinnedData( PtrDescriptorBCB, NULL );
00431                 CcUnpinData( PtrDescriptorBCB );
00432                 PtrDescriptorBCB = NULL;
00433             }
00434         }
00435 
00436 
00437         //
00438         //  Update the Inode count...
00439         //  in the Super Block...
00440         //
00441         {
00442             //  Ext2 Super Block information...
00443             PEXT2_SUPER_BLOCK   PtrSuperBlock = NULL;
00444             PBCB                PtrSuperBlockBCB = NULL;
00445 
00446             PtrVCB->FreeInodesCount--;
00447             //  Reading in the super block...
00448             VolumeByteOffset.QuadPart = 1024;
00449 
00450             //  THis shouldn't be more than a block in size...
00451             NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize );
00452 
00453             if( !CcPinRead( PtrVCB->PtrStreamFileObject,
00454                    &VolumeByteOffset,
00455                    NumberOfBytesToRead,
00456                    TRUE,
00457                    &PtrSuperBlockBCB,
00458                    (PVOID*)&PtrSuperBlock ) )
00459             {
00460                 DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
00461             }
00462             else
00463             {
00464                 PtrSuperBlock->s_free_inodes_count = PtrVCB->FreeInodesCount;
00465                 CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL );
00466                 Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject );
00467                 if( PtrSuperBlockBCB )
00468                 {
00469                     CcUnpinData( PtrSuperBlockBCB );
00470                     PtrSuperBlockBCB = NULL;
00471                 }
00472                 
00473             }
00474         }
00475     }
00476     finally
00477     {
00478         if( PtrBitmapBCB )
00479         {
00480             CcUnpinData( PtrBitmapBCB );
00481             PtrBitmapBCB = NULL;
00482         }
00483     }
00484     DebugTrace( DEBUG_TRACE_SPECIAL, " Allocating an inode - I-Node no : %ld", InodeNo );
00485     
00486     return InodeNo;
00487 
00488 }
00489 
00490 /*************************************************************************
00491 *
00492 * Function: Ext2DeallocInode()
00493 *
00494 * Description:
00495 *   The functions will deallocate an i-node 
00496 *
00497 * Expected Interrupt Level (for execution) :
00498 *  IRQL_PASSIVE_LEVEL 
00499 *
00500 * Return Value: Success / Failure...
00501 *
00502 *************************************************************************/
00503 BOOLEAN NTAPI Ext2DeallocInode( 
00504     PtrExt2IrpContext   PtrIrpContext,
00505     PtrExt2VCB          PtrVCB,
00506     ULONG               INodeNo )
00507 {
00508     BOOLEAN     RC = TRUE;
00509     
00510     //  Buffer Control Block
00511     PBCB        PtrBitmapBCB = NULL;
00512     BYTE *      PtrBitmapBuffer = NULL; 
00513 
00514     LARGE_INTEGER VolumeByteOffset;
00515     ULONG       LogicalBlockSize = 0;
00516     
00517     DebugTrace( DEBUG_TRACE_SPECIAL, " Deallocating an inode - I-Node no : %ld", INodeNo );
00518 
00519     try
00520     {
00521         ULONG   BlockIndex ;
00522         ULONG   BitmapIndex;
00523         ULONG   GroupNo;
00524         BYTE    Bitmap;
00525         
00526         LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
00527 
00528         GroupNo = INodeNo / PtrVCB->InodesPerGroup;
00529         INodeNo = INodeNo % PtrVCB->InodesPerGroup;
00530 
00531         BitmapIndex =  (INodeNo-1) / 8;
00532         Bitmap = 1 << ( (INodeNo-1) % 8 );
00533         BlockIndex = BitmapIndex / LogicalBlockSize;
00534         //  Adjusting to index into the Logical block that contains the bitmap
00535         BitmapIndex = BitmapIndex - ( BlockIndex * LogicalBlockSize );
00536 
00537         VolumeByteOffset.QuadPart = 
00538             ( PtrVCB->PtrGroupDescriptors[ GroupNo ].InodeBitmapBlock + BlockIndex ) 
00539             * LogicalBlockSize;
00540 
00541         //
00542         //  Read in the bitmap block...
00543         //
00544         if( !CcPinRead( PtrVCB->PtrStreamFileObject,
00545                 &VolumeByteOffset,
00546                 LogicalBlockSize,   //  Just the block that contains the bitmap will do...
00547                 TRUE,               //  Can Wait...
00548                 &PtrBitmapBCB,
00549                 (PVOID*)&PtrBitmapBuffer ) )
00550         {
00551             //  Unable to Pin the data into the cache...
00552             try_return (RC = FALSE);
00553         }
00554 
00555         //
00556         //  Locate the inode...
00557         //  This inode is in the byte PtrBitmapBuffer[ BitmapIndex ]
00558         if( ( PtrBitmapBuffer[ BitmapIndex ] & Bitmap ) == 0)
00559         {
00560             //  This shouldn't have been so...
00561             //  The inode was never allocated!
00562             //  How to deallocate something that hasn't been allocated? 
00563             //  Hmmm... ;)
00564             //  Ignore this error...
00565             try_return (RC = TRUE);
00566         }
00567 
00568 
00569         //  Setting the bit for the inode...
00570         PtrBitmapBuffer[ BitmapIndex ] &= (~Bitmap);
00571 
00572         //  Update the cache...
00573         CcSetDirtyPinnedData( PtrBitmapBCB, NULL );
00574 
00575         //  Save up the BCB for forcing a synchronous write...
00576         //  Before completing the IRP...
00577         Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject );
00578 
00579 
00580         if( PtrBitmapBCB )
00581         {
00582             CcUnpinData( PtrBitmapBCB );
00583             PtrBitmapBCB = NULL;
00584         }
00585         
00586         {
00587             //
00588             //  Updating the Inode count in the Group Descriptor...
00589             //  
00590             PBCB                    PtrDescriptorBCB = NULL;
00591             PEXT2_GROUP_DESCRIPTOR  PtrGroupDescriptor = NULL;
00592             ULONG                   NumberOfBytesToRead = 0;
00593 
00594             PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount++;
00595 
00596             if( PtrVCB->LogBlockSize )
00597             {
00598                 //  First block contains the descriptors...
00599                 VolumeByteOffset.QuadPart = LogicalBlockSize;
00600             }
00601             else
00602             {
00603                 //  Second block contains the descriptors...
00604                 VolumeByteOffset.QuadPart = LogicalBlockSize * 2;
00605             }
00606             NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc );
00607             NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
00608 
00609             if (!CcPinRead( PtrVCB->PtrStreamFileObject,
00610                    &VolumeByteOffset,
00611                    NumberOfBytesToRead,
00612                    TRUE,
00613                    &PtrDescriptorBCB ,
00614                    (PVOID*)&PtrGroupDescriptor )) 
00615             {
00616                 DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
00617                 //
00618                 //  Ignore this error...
00619                 //  Not fatal...
00620             }
00621             else
00622             {
00623                 PtrGroupDescriptor[ GroupNo ].bg_free_inodes_count = 
00624                     PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount; 
00625                 //
00626                 //  Not synchronously flushing this information...
00627                 //  Lazy writing will do...
00628                 //
00629                 CcSetDirtyPinnedData( PtrDescriptorBCB, NULL );
00630                 CcUnpinData( PtrDescriptorBCB );
00631                 PtrDescriptorBCB = NULL;
00632             }
00633         }
00634         
00635 
00636         //
00637         //  Update the Inode count...
00638         //  in the Super Block
00639         //  and in the VCB
00640         //
00641         {
00642             //  Ext2 Super Block information...
00643             PEXT2_SUPER_BLOCK   PtrSuperBlock = NULL;
00644             PBCB                PtrSuperBlockBCB = NULL;
00645             ULONG               NumberOfBytesToRead = 0;
00646 
00647             PtrVCB->FreeInodesCount++;
00648 
00649             //  Reading in the super block...
00650             VolumeByteOffset.QuadPart = 1024;
00651             NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize );
00652 
00653             if( !CcPinRead( PtrVCB->PtrStreamFileObject,
00654                    &VolumeByteOffset,
00655                    NumberOfBytesToRead,
00656                    TRUE,
00657                    &PtrSuperBlockBCB,
00658                    (PVOID*)&PtrSuperBlock ) )
00659             {
00660                 DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
00661             }
00662             else
00663             {
00664                 PtrSuperBlock->s_free_inodes_count = PtrVCB->FreeInodesCount;
00665                 CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL );
00666                 Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject );
00667                 if( PtrSuperBlockBCB )
00668                 {
00669                     CcUnpinData( PtrSuperBlockBCB );
00670                     PtrSuperBlockBCB = NULL;
00671                 }
00672                 
00673             }
00674         }
00675         try_exit:   NOTHING;
00676     }
00677     finally
00678     {
00679         if( PtrBitmapBCB )
00680         {
00681             CcUnpinData( PtrBitmapBCB );
00682             PtrBitmapBCB = NULL;
00683         }
00684     }
00685     return RC;
00686 }
00687 
00688 /*************************************************************************
00689 *
00690 * Function: Ext2WriteInode()
00691 *
00692 * Description:
00693 *   The functions will write an i-node to disk
00694 *
00695 * Expected Interrupt Level (for execution) :
00696 *  IRQL_PASSIVE_LEVEL 
00697 *
00698 *
00699 * Return Value: Success / Failure...
00700 *
00701 *************************************************************************/
00702 NTSTATUS NTAPI Ext2WriteInode(
00703     PtrExt2IrpContext   PtrIrpContext,
00704     PtrExt2VCB          PtrVcb,         //  the Volume Control Block
00705     uint32              InodeNo,        //  The Inode no
00706     PEXT2_INODE         PtrInode        //  The Inode Buffer
00707     )                   
00708 {
00709     //  The Status to be returned...
00710     NTSTATUS RC = STATUS_SUCCESS;
00711 
00712     //  The Read Buffer Pointer
00713     BYTE * PtrPinnedBuffer = NULL;
00714 
00715     //  Buffer Control Block
00716     PBCB PtrBCB = NULL;
00717 
00718     LARGE_INTEGER VolumeByteOffset, TempOffset;
00719 
00720     ULONG LogicalBlockSize = 0;
00721     ULONG NumberOfBytesToRead = 0;
00722     ULONG Difference = 0;
00723     ULONG GroupNo;
00724     int Index;
00725 
00726     try
00727     {
00728         DebugTrace( DEBUG_TRACE_SPECIAL, "Writing and updating an inode - I-Node no : %ld", InodeNo );
00729 
00730         ASSERT(PtrVcb);
00731         ASSERT(PtrVcb->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB);
00732         GroupNo = InodeNo / PtrVcb->InodesPerGroup;
00733 
00734         if( GroupNo >= PtrVcb->NoOfGroups )
00735         {
00736             DebugTrace(DEBUG_TRACE_MISC,   "&&&&&& Invalid Inode no. Group no %d - too big", GroupNo );
00737             DebugTrace(DEBUG_TRACE_MISC,   "Only %d groups available on disk", PtrVcb->NoOfGroups );
00738             RC = STATUS_UNSUCCESSFUL;
00739             try_return();
00740         }
00741 
00742         if( PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock == 0 )
00743         {
00744             DebugTrace(DEBUG_TRACE_MISC,   "&&&&&& Inode Table Group Invalid - Group no %d ", GroupNo );
00745             RC = STATUS_UNSUCCESSFUL;
00746             try_return();
00747         }
00748 
00749         Index = ( InodeNo - 1 ) - ( GroupNo * PtrVcb->InodesPerGroup );
00750 
00751         LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVcb->LogBlockSize;
00752         NumberOfBytesToRead = sizeof(EXT2_INODE);
00753 
00754         VolumeByteOffset.QuadPart = PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock
00755                 * LogicalBlockSize + Index * PtrVcb->InodeSize;
00756         
00757         TempOffset.QuadPart = Ext2Align64( VolumeByteOffset.QuadPart, LogicalBlockSize );
00758         if( TempOffset.QuadPart != VolumeByteOffset.QuadPart )
00759         {
00760             //  TempOffset.QuadPart -= LogicalBlockSize;
00761             Difference = (LONG) (VolumeByteOffset.QuadPart - TempOffset.QuadPart + LogicalBlockSize );
00762             VolumeByteOffset.QuadPart -= Difference;
00763             NumberOfBytesToRead += Difference;
00764         }
00765 
00766         NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
00767 
00768         if( NumberOfBytesToRead > LogicalBlockSize )
00769         {
00770             //  Multiple blocks being read in...
00771             //  Can cause overlap
00772             //  Watch out!!!!
00773             Ext2BreakPoint();
00774         }
00775 
00776         if( !CcPinRead( PtrVcb->PtrStreamFileObject,
00777                     &VolumeByteOffset,
00778                     NumberOfBytesToRead,
00779                     TRUE,           //  Can Wait...
00780                     &PtrBCB,
00781                     (PVOID*)&PtrPinnedBuffer ) )
00782         {
00783             RC = STATUS_UNSUCCESSFUL;
00784             try_return();
00785         }
00786         else
00787         {
00788             RtlCopyMemory( PtrPinnedBuffer + Difference, PtrInode, sizeof(EXT2_INODE) );
00789             CcSetDirtyPinnedData( PtrBCB, NULL );
00790             Ext2SaveBCB( PtrIrpContext, PtrBCB, PtrVcb->PtrStreamFileObject );
00791         }
00792     
00793         try_exit:   NOTHING;
00794     }
00795     finally
00796     {
00797         if( PtrBCB )
00798         {
00799             CcUnpinData( PtrBCB );
00800             PtrBCB = NULL;
00801         }
00802 
00803     }
00804     return RC;
00805 }
00806 
00807 
00808 /*************************************************************************
00809 *
00810 * Function: Ext2MakeNewDirectoryEntry()
00811 *
00812 * Description:
00813 *   The functions will make a new directory entry in a directory file...
00814 *
00815 * Expected Interrupt Level (for execution) :
00816 *  IRQL_PASSIVE_LEVEL 
00817 *
00818 *
00819 * Return Value: Success / Failure...
00820 *
00821 *************************************************************************/
00822 BOOLEAN NTAPI Ext2MakeNewDirectoryEntry(
00823     PtrExt2IrpContext       PtrIrpContext,  //  The Irp context
00824     PtrExt2FCB              PtrParentFCB,   //  Parent Folder FCB
00825     PFILE_OBJECT            PtrFileObject,  //  Parent Folder Object
00826     PUNICODE_STRING         PtrName,        //  New entry's name
00827     ULONG                   Type,           //  The type of the new entry
00828     ULONG                   NewInodeNo)     //  The inode no of the new entry...
00829 {
00830     PBCB                PtrLastBlockBCB = NULL;
00831     BYTE *              PtrLastBlock = NULL;
00832     EXT2_DIR_ENTRY      DirEntry;
00833     PEXT2_DIR_ENTRY     PtrTempDirEntry;
00834     
00835     ULONG               BlockNo = 0;
00836     ULONG               i;
00837     PtrExt2VCB          PtrVCB;
00838     LARGE_INTEGER       VolumeByteOffset;
00839     unsigned long       LogicalBlockSize = 0;
00840     BOOLEAN             RC = FALSE;
00841     
00842     USHORT  HeaderLength = sizeof( EXT2_DIR_ENTRY );
00843     USHORT  NewEntryLength = 0; 
00844     USHORT  MinLength   = 0;
00845     #define ActualLength (PtrTempDirEntry->rec_len)
00846     #define NameLength  (PtrTempDirEntry->name_len)
00847 
00848     try
00849     {
00850         ASSERT( PtrFileObject );
00851 
00852         DebugTrace( DEBUG_TRACE_SPECIAL, "Making directory entry: %S", PtrName->Buffer );
00853 
00854         PtrVCB = PtrParentFCB->PtrVCB;
00855         AssertVCB( PtrVCB);
00856 
00857         HeaderLength = sizeof( EXT2_DIR_ENTRY ) -
00858                           (sizeof( char ) * EXT2_NAME_LEN);
00859         //  1. Setting up the entry...
00860         NewEntryLength = sizeof( EXT2_DIR_ENTRY ) - ( sizeof( char ) * ( EXT2_NAME_LEN - (PtrName->Length / 2) ) );
00861         //  Length should be a multiplicant of 4
00862         NewEntryLength = ((NewEntryLength + 3 ) & 0xfffffffc);
00863 
00864         RtlZeroMemory( &DirEntry, sizeof( EXT2_DIR_ENTRY ) );
00865 
00866         DirEntry.file_type = (BYTE) Type;
00867         DirEntry.inode = NewInodeNo;
00868         DirEntry.name_len = (BYTE)(PtrName->Length / 2 );   //  Does not include a NULL
00869         
00870         //  DirEntry.rec_len = (USHORT) NewEntryLength;
00871 
00872         for( i = 0; ; i++ )
00873         {
00874             if( i < (ULONG)( PtrName->Length / 2 ) )
00875             {
00876                 DirEntry.name[i] = (CHAR) PtrName->Buffer[i];
00877             }
00878             else
00879             {
00880                 //DirEntry.name[i] = 0; //  Entry need not be zero terminated...
00881                 break;
00882             }
00883         }
00884 
00885         //
00886         //  2. Read the block in the directory...
00887         //  Initiate Caching...
00888         if ( PtrFileObject->PrivateCacheMap == NULL )
00889         {
00890             CcInitializeCacheMap(
00891                 PtrFileObject, 
00892                 (PCC_FILE_SIZES)(&(PtrParentFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)),
00893                 TRUE,                                   // We utilize pin access for directories
00894                 &(Ext2GlobalData.CacheMgrCallBacks),    // callbacks
00895                 PtrParentFCB );                         // The context used in callbacks
00896         }
00897 
00898         LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
00899         if( PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart > 0 )
00900         {
00901             BlockNo = (ULONG) ( (PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) / LogicalBlockSize) ;
00902         }
00903         else
00904         {
00905             //  This directory doesn't have any data blocks...
00906             //  Allocate a new block...
00907             if( !Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrParentFCB, PtrFileObject, TRUE ) )
00908             {
00909                 try_return( RC = FALSE );
00910             }
00911             else
00912             {
00913                 //  Bring in the newly allocated block to the cache...
00914                 VolumeByteOffset.QuadPart = 0;
00915 
00916                 if( !CcPreparePinWrite( 
00917                     PtrFileObject,
00918                     &VolumeByteOffset,
00919                     LogicalBlockSize,
00920                     TRUE,           //  Zero out the block...
00921                     TRUE,           //  Can Wait...
00922                     &PtrLastBlockBCB,
00923                     (PVOID*)&PtrLastBlock ) )
00924                 {
00925                     try_return( RC = FALSE );
00926                 }
00927 
00928                 DirEntry.rec_len = (USHORT)LogicalBlockSize;
00929                 RtlCopyBytes( PtrLastBlock, &DirEntry, NewEntryLength);
00930                 CcSetDirtyPinnedData( PtrLastBlockBCB, NULL );
00931                 Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject );
00932                 try_return( RC = TRUE );
00933             }
00934         }
00935 
00936         VolumeByteOffset.QuadPart = BlockNo * LogicalBlockSize;
00937         CcMapData(  PtrFileObject,
00938                     &VolumeByteOffset,
00939                     LogicalBlockSize,
00940                     TRUE,
00941                     &PtrLastBlockBCB,
00942                     (PVOID*)&PtrLastBlock );
00943 
00944         for( i = 0 ; i < LogicalBlockSize; )
00945         {
00946             PtrTempDirEntry = (PEXT2_DIR_ENTRY) &PtrLastBlock[ i ];
00947 
00948             MinLength = HeaderLength + NameLength;
00949             MinLength = ( HeaderLength + NameLength + 3 ) & 0xfffffffc;
00950 
00951             
00952             if( PtrTempDirEntry->rec_len == 0 )
00953             {
00954                 if( i == 0 )
00955                 {
00956                     //  Must be an empty Block...
00957                     //  Insert here...
00958                     //  ---------------->>>
00959                     
00960                     CcPinMappedData( PtrFileObject,
00961                                    &VolumeByteOffset,
00962                                    LogicalBlockSize,
00963                                    TRUE,
00964                                    &PtrLastBlockBCB );
00965 
00966                     DirEntry.rec_len = (USHORT)LogicalBlockSize;
00967                     
00968                     RtlCopyBytes( PtrLastBlock, &DirEntry, NewEntryLength);
00969                     CcSetDirtyPinnedData( PtrLastBlockBCB, NULL );
00970                     Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject );
00971                     try_return( RC = TRUE );
00972                 }
00973                 else
00974                 {
00975                     //  This shouldn't be so...
00976                     //  Something is wrong...
00977                     //  Fail this request...
00978                     try_return( RC = FALSE );
00979                 }
00980             }
00981             if( ActualLength - MinLength >= NewEntryLength )
00982             {
00983                 //  Insert here...
00984                 //  ---------------->
00985 
00986                 //  Getting ready for updation...
00987                 CcPinMappedData( PtrFileObject,
00988                                &VolumeByteOffset,
00989                                LogicalBlockSize,
00990                                TRUE,
00991                                &PtrLastBlockBCB );
00992 
00993 
00994                 DirEntry.rec_len = ActualLength - MinLength;
00995 
00996                 //  Updating the current last entry
00997                 PtrTempDirEntry->rec_len = MinLength;
00998                 i += PtrTempDirEntry->rec_len;
00999                 
01000                 //  Making the new entry...
01001                 RtlCopyBytes( (PtrLastBlock + i) , &DirEntry, NewEntryLength);
01002                 CcSetDirtyPinnedData( PtrLastBlockBCB, NULL );
01003                 Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject );
01004                 try_return( RC = TRUE );
01005 
01006             }
01007             i += PtrTempDirEntry->rec_len;
01008         }
01009 
01010         //  Will have to allocate a new block...
01011         //  Old block does not have enough space..
01012         if( !Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrParentFCB, PtrFileObject, TRUE ) )
01013         {
01014             try_return( RC = FALSE );
01015         }
01016         else
01017         {
01018             //  unpin the previously pinned block
01019             CcUnpinData( PtrLastBlockBCB );
01020             PtrLastBlockBCB = NULL;
01021 
01022             //  Bring in the newly allocated block to the cache...
01023             VolumeByteOffset.QuadPart += LogicalBlockSize;
01024             if( !CcPreparePinWrite( 
01025                 PtrFileObject,
01026                 &VolumeByteOffset,
01027                 LogicalBlockSize,
01028                 TRUE,           //  Zero out the block...
01029                 TRUE,           //  Can Wait...
01030                 &PtrLastBlockBCB,
01031                 (PVOID*)&PtrLastBlock ) )
01032             {
01033                 try_return( RC = FALSE );
01034             }
01035 
01036             DirEntry.rec_len = (USHORT)LogicalBlockSize;
01037             RtlCopyBytes( PtrLastBlock, &DirEntry, NewEntryLength);
01038             CcSetDirtyPinnedData( PtrLastBlockBCB, NULL );
01039             Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject );
01040             try_return( RC = TRUE );
01041         }
01042         try_exit:   NOTHING;
01043     }
01044     finally
01045     {
01046         if( PtrLastBlockBCB )
01047         {
01048             CcUnpinData( PtrLastBlockBCB );
01049             PtrLastBlockBCB = NULL;
01050         }
01051     }
01052     if( RC == FALSE )
01053     {
01054         DebugTrace( DEBUG_TRACE_ERROR, "Failed to making directory entry: %S", PtrName->Buffer );
01055     }
01056     return RC;
01057 }
01058 
01059 
01060 BOOLEAN NTAPI Ext2FreeDirectoryEntry(
01061     PtrExt2IrpContext       PtrIrpContext,
01062     PtrExt2FCB              PtrParentFCB,
01063     PUNICODE_STRING         PtrName)
01064 {
01065 
01066     PBCB                PtrDataBlockBCB = NULL;
01067     BYTE *              PtrDataBlock = NULL;
01068     PFILE_OBJECT        PtrFileObject = NULL;
01069     LONGLONG            ByteOffset = 0;
01070     PtrExt2VCB          PtrVCB;
01071     LARGE_INTEGER       VolumeByteOffset;
01072     unsigned long       LogicalBlockSize = 0;
01073     BOOLEAN             RC = FALSE;
01074     
01075 
01076     try
01077     {
01078         DebugTrace( DEBUG_TRACE_SPECIAL, "Freeing directory entry: %S", PtrName->Buffer );
01079 
01080         PtrVCB = PtrParentFCB->PtrVCB;
01081         AssertVCB( PtrVCB);
01082         
01083         LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
01084 
01085         PtrFileObject = PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject;
01086         if( PtrFileObject == NULL )
01087         {
01088             return FALSE;
01089         }
01090         
01091 
01092         //
01093         //  1. Read the block in the directory...
01094         //  Initiate Caching...
01095         if ( PtrFileObject->PrivateCacheMap == NULL )
01096         {
01097             CcInitializeCacheMap(
01098                 PtrFileObject, 
01099                 (PCC_FILE_SIZES)(&(PtrParentFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)),
01100                 TRUE,                                   // We utilize pin access for directories
01101                 &(Ext2GlobalData.CacheMgrCallBacks),    // callbacks
01102                 PtrParentFCB );                         // The context used in callbacks
01103         }
01104 
01105         for( ByteOffset = 0; 
01106              ByteOffset < PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart;
01107              ByteOffset += LogicalBlockSize )
01108         {
01109             ULONG Index = 0;
01110             PEXT2_DIR_ENTRY PtrDirEntry = NULL;
01111 
01112 
01113             VolumeByteOffset.QuadPart = ByteOffset;
01114             
01115             CcPinRead(  PtrFileObject,
01116                         &VolumeByteOffset,
01117                         LogicalBlockSize,
01118                         TRUE,
01119                         &PtrDataBlockBCB,
01120                         (PVOID*)&PtrDataBlock );
01121             while( Index < LogicalBlockSize )
01122             {
01123                 ULONG i;
01124                 //  Parse...
01125                 PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrDataBlock[ Index ];
01126                 Index += PtrDirEntry->rec_len;
01127 
01128                 if( PtrDirEntry->inode == 0 )
01129                 {
01130                     //  This is a deleted entry...
01131                     continue;
01132                 }
01133                 if( ( PtrName->Length/2 ) != PtrDirEntry->name_len )
01134                     continue;
01135                 for( i = 0; ; i++ )
01136                 {
01137                     if( PtrDirEntry->name_len == i )
01138                     {
01139                         //  Remove the entry by setting the inode no to zero
01140                         PtrDirEntry->inode = 0;
01141 
01142                         //  Update the disk
01143                         CcSetDirtyPinnedData( PtrDataBlockBCB , NULL );
01144                         Ext2SaveBCB( PtrIrpContext, PtrDataBlockBCB, PtrFileObject );
01145                         CcUnpinData( PtrDataBlockBCB );
01146                         PtrDataBlockBCB = NULL;
01147 
01148                         //  Return to caller...
01149                         try_return( RC = TRUE );
01150                     }
01151                     if( PtrName->Buffer[i] != PtrDirEntry->name[i] )
01152                     {
01153                         break;
01154                     }
01155                 }
01156             }
01157             CcUnpinData( PtrDataBlockBCB );
01158             PtrDataBlockBCB = NULL;
01159         }
01160         try_return( RC = FALSE );
01161 
01162         try_exit:   NOTHING;
01163     }
01164     finally
01165     {
01166         if( PtrDataBlockBCB )
01167         {
01168             CcUnpinData( PtrDataBlockBCB );
01169             PtrDataBlockBCB = NULL;
01170         }
01171     }
01172     return RC;
01173 }
01174 
01175 /*************************************************************************
01176 *
01177 * Function: Ext2AddBlockToFile()
01178 *
01179 * Description:
01180 *   The functions will add a block to a file...
01181 *   It will update the allocation size but not the file size...
01182 *
01183 * Expected Interrupt Level (for execution) :
01184 *  IRQL_PASSIVE_LEVEL 
01185 *
01186 *
01187 * Return Value: Success / Failure...
01188 *
01189 *************************************************************************/
01190 BOOLEAN NTAPI Ext2AddBlockToFile(
01191     PtrExt2IrpContext   PtrIrpContext,
01192     PtrExt2VCB          PtrVCB,
01193     PtrExt2FCB          PtrFCB,
01194     PFILE_OBJECT        PtrFileObject,
01195     BOOLEAN             UpdateFileSize)
01196 {
01197     BOOLEAN         RC = TRUE; 
01198 
01199     ULONG           NewBlockNo = 0;
01200     LARGE_INTEGER   VolumeByteOffset;
01201     ULONG           LogicalBlockSize = 0;
01202     ULONG           NoOfBlocks = 0;
01203     EXT2_INODE      Inode;
01204 
01205     ULONG   DirectBlocks = 0;
01206     ULONG   SingleIndirectBlocks = 0;
01207     ULONG   DoubleIndirectBlocks = 0;
01208     ULONG   TripleIndirectBlocks = 0;
01209     
01210     ULONG   *PtrSIBBuffer = NULL;
01211     PBCB    PtrSIBBCB = NULL;
01212     ULONG   *PtrDIBBuffer = NULL;
01213     PBCB    PtrDIBBCB = NULL;
01214 
01215 
01216     LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
01217     DirectBlocks =  EXT2_NDIR_BLOCKS ;
01218     SingleIndirectBlocks = LogicalBlockSize / sizeof( ULONG );
01219     DoubleIndirectBlocks = SingleIndirectBlocks * LogicalBlockSize / sizeof( ULONG );
01220     TripleIndirectBlocks = DoubleIndirectBlocks * LogicalBlockSize / sizeof( ULONG );
01221 
01222     try
01223     {
01224         if( PtrFCB && PtrFCB->FCBName->ObjectName.Length )
01225         {
01226             DebugTrace( DEBUG_TRACE_SPECIAL, "Adding Blocks to file  %S", PtrFCB->FCBName->ObjectName.Buffer );
01227         }
01228 
01229         Ext2InitializeFCBInodeInfo( PtrFCB );
01230 
01231         //  Allocate a block...
01232         NewBlockNo = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 );
01233 
01234         if( NewBlockNo == 0 )
01235         {
01236             try_return (RC = FALSE );
01237         }
01238 
01239         //  No of blocks CURRENTLY allocated...
01240         NoOfBlocks = (ULONG) PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart / LogicalBlockSize;
01241         
01242         
01243         if( NoOfBlocks < EXT2_NDIR_BLOCKS )
01244         {
01245             //
01246             //  A direct data block will do...
01247             //
01248             
01249             PtrFCB->IBlock[ NoOfBlocks ] = NewBlockNo;
01250             
01251             //  Update the inode...
01252             Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode  );
01253             Inode.i_block[ NoOfBlocks ] = NewBlockNo;
01254             Inode.i_blocks += ( LogicalBlockSize / 512 );
01255             PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize;
01256             if( UpdateFileSize )
01257             {
01258                 Inode.i_size += LogicalBlockSize;
01259                 PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize;
01260             }
01261 
01262             
01263             if( PtrFileObject->PrivateCacheMap != NULL)
01264             {
01265                 //
01266                 //  Caching has been initiated...
01267                 //  Let the Cache manager in on these changes...
01268                 //  
01269                 CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize));
01270             }
01271             
01272             
01273             //  Updating the inode...
01274             if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode  ) ) )
01275             {
01276                 try_return (RC = TRUE);
01277             }
01278             else
01279             {
01280                 try_return (RC = FALSE );
01281             }
01282             
01283         }
01284         else if( NoOfBlocks < (DirectBlocks + SingleIndirectBlocks) )
01285         {
01286             //
01287             //  A single indirect data block will do...
01288             Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode  );
01289 
01290             if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] == 0 )
01291             {
01292                 //  A Single Indirect block should be allocated as well!!
01293                 PtrFCB->IBlock[ EXT2_IND_BLOCK ] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 );
01294                 if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] == 0 )
01295                 {
01296                     try_return (RC = FALSE );
01297                 }
01298                 Inode.i_blocks += ( LogicalBlockSize / 512 );
01299 
01300                 //  Bring in the new block to the cache
01301                 //  Zero it out
01302                 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize;
01303 
01304                 if( !CcPreparePinWrite( 
01305                     PtrVCB->PtrStreamFileObject,
01306                     &VolumeByteOffset,
01307                     LogicalBlockSize,
01308                     TRUE,           //  Zero out the block...
01309                     TRUE,           //  Can Wait...
01310                     &PtrSIBBCB,
01311                     (PVOID*)&PtrSIBBuffer ) )
01312                 {
01313                     try_return( RC = FALSE );
01314                 }
01315             }
01316             else
01317             {
01318                 //   Just bring in the SIB to the cache
01319                 
01320                 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize;
01321 
01322                 if( !CcPinRead( PtrVCB->PtrStreamFileObject,
01323                             &VolumeByteOffset,
01324                             LogicalBlockSize,
01325                             TRUE,           //  Can Wait...
01326                             &PtrSIBBCB,
01327                             (PVOID*)&PtrSIBBuffer ) )
01328                 {
01329                     try_return( RC = FALSE );
01330                 }
01331             }
01332             
01333             //  Update the inode...
01334             
01335             Inode.i_block[ EXT2_IND_BLOCK ] = PtrFCB->IBlock[ EXT2_IND_BLOCK ];
01336             Inode.i_blocks += ( LogicalBlockSize / 512 );
01337             PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize;
01338             if( UpdateFileSize )
01339             {
01340                 Inode.i_size += LogicalBlockSize;
01341                 PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize;
01342             }
01343             if( PtrFileObject->PrivateCacheMap != NULL)
01344             {
01345                 //
01346                 //  Caching has been initiated...
01347                 //  Let the Cache manager in on these changes...
01348                 //  
01349                 CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize));
01350             }
01351 
01352             if( !NT_SUCCESS( Ext2WriteInode( 
01353                 PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode  ) ) )
01354             {
01355                 try_return (RC = FALSE );
01356             }
01357 
01358             
01359             //  Update the SIB...
01360             PtrSIBBuffer[ NoOfBlocks - DirectBlocks ] = NewBlockNo;
01361             CcSetDirtyPinnedData( PtrSIBBCB, NULL );
01362             Ext2SaveBCB( PtrIrpContext, PtrSIBBCB, PtrVCB->PtrStreamFileObject );
01363 
01364             try_return (RC = TRUE);
01365 
01366         }
01367         else if( NoOfBlocks < (DirectBlocks + SingleIndirectBlocks + DoubleIndirectBlocks ) )
01368         {
01369             //
01370             //  A double indirect block will do...
01371             //
01372             ULONG SBlockNo;
01373             ULONG BlockNo;
01374 
01375             Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode  );
01376 
01377             if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] == 0 )
01378             {
01379                 //  A double indirect pointer block should be allocated as well!!
01380                 PtrFCB->IBlock[ EXT2_DIND_BLOCK ] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 );
01381                 if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] == 0 )
01382                 {
01383                     try_return (RC = FALSE );
01384                 }
01385                 Inode.i_blocks += ( LogicalBlockSize / 512 );
01386 
01387                 //  Bring in the new block to the cache
01388                 //  Zero it out
01389                 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
01390 
01391                 if( !CcPreparePinWrite( 
01392                     PtrVCB->PtrStreamFileObject,
01393                     &VolumeByteOffset,
01394                     LogicalBlockSize,
01395                     TRUE,           //  Zero out the block...
01396                     TRUE,           //  Can Wait...
01397                     &PtrDIBBCB,
01398                     (PVOID*)&PtrDIBBuffer ) )
01399                 {
01400                     try_return( RC = FALSE );
01401                 }
01402             }
01403             else
01404             {
01405                 //   Just bring in the DIB to the cache
01406                 
01407                 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
01408 
01409                 if( !CcPinRead( PtrVCB->PtrStreamFileObject,
01410                             &VolumeByteOffset,
01411                             LogicalBlockSize,
01412                             TRUE,           //  Can Wait...
01413                             &PtrDIBBCB,
01414                             (PVOID*)&PtrDIBBuffer ) )
01415                 {
01416                     try_return( RC = FALSE );
01417                 }
01418             }
01419             
01420             //  See if a single indirect 'pointer' block 
01421             //  should also be allocated...
01422             BlockNo = ( NoOfBlocks - DirectBlocks - SingleIndirectBlocks );
01423             SBlockNo = BlockNo / SingleIndirectBlocks;
01424             if( BlockNo % SingleIndirectBlocks )
01425             {
01426                 //  A single indirect 'pointer' block 
01427                 //  should also be allocated...
01428                 PtrDIBBuffer[SBlockNo] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 );
01429                 CcSetDirtyPinnedData( PtrDIBBCB, NULL );
01430                 VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize;
01431 
01432                 Inode.i_blocks += ( LogicalBlockSize / 512 );
01433 
01434                 if( !CcPreparePinWrite( 
01435                     PtrVCB->PtrStreamFileObject,
01436                     &VolumeByteOffset,
01437                     LogicalBlockSize,
01438                     TRUE,                   //  Zero out the block...
01439                     TRUE,                   //  Can Wait...
01440                     &PtrSIBBCB,
01441                     (PVOID*)&PtrSIBBuffer ) )
01442                 {
01443                     try_return( RC = FALSE );
01444                 }
01445             }
01446             else
01447             {
01448                 VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize;
01449                 if( !CcPinRead( PtrVCB->PtrStreamFileObject,
01450                             &VolumeByteOffset,
01451                             LogicalBlockSize,
01452                             TRUE,               //  Can Wait...
01453                             &PtrSIBBCB,
01454                             (PVOID*)&PtrSIBBuffer ) )
01455                 {
01456                     try_return( RC = FALSE );
01457                 }
01458             }
01459             BlockNo = BlockNo % SingleIndirectBlocks;
01460             
01461             //  Update the inode...
01462             
01463             Inode.i_block[ EXT2_DIND_BLOCK ] = PtrFCB->IBlock[ EXT2_DIND_BLOCK ];
01464             Inode.i_blocks += ( LogicalBlockSize / 512 );
01465             PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize;
01466             if( UpdateFileSize )
01467             {
01468                 Inode.i_size += LogicalBlockSize;
01469                 PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize;
01470             }
01471             if( PtrFileObject->PrivateCacheMap != NULL)
01472             {
01473                 //
01474                 //  Caching has been initiated...
01475                 //  Let the Cache manager in on these changes...
01476                 //  
01477                 CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize));
01478             }
01479 
01480             if( !NT_SUCCESS( Ext2WriteInode( 
01481                 PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode  ) ) )
01482             {
01483                 try_return (RC = FALSE );
01484             }
01485 
01486             
01487             //  Update the SIB...
01488             PtrSIBBuffer[ BlockNo ] = NewBlockNo;
01489             CcSetDirtyPinnedData( PtrSIBBCB, NULL );
01490             Ext2SaveBCB( PtrIrpContext, PtrSIBBCB, PtrVCB->PtrStreamFileObject );
01491             Ext2SaveBCB( PtrIrpContext, PtrDIBBCB, PtrVCB->PtrStreamFileObject );
01492 
01493             try_return (RC = TRUE);
01494 
01495         }
01496         else
01497         {   
01498             //
01499             //  A Triple Indirect block is required
01500             //
01501             ULONG SBlockNo;
01502             ULONG BlockNo;
01503 
01504             //  This is not supported as yet...
01505             try_return (RC = FALSE);
01506 
01507             Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode  );
01508 
01509             if( PtrFCB->IBlock[ EXT2_TIND_BLOCK ] == 0 )
01510             {
01511                 //  A double indirect pointer block should be allocated as well!!
01512                 PtrFCB->IBlock[ EXT2_DIND_BLOCK ] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 );
01513                 if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] == 0 )
01514                 {
01515                     try_return (RC = FALSE );
01516                 }
01517                 Inode.i_blocks += ( LogicalBlockSize / 512 );
01518 
01519                 //  Bring in the new block to the cache
01520                 //  Zero it out
01521                 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
01522 
01523                 if( !CcPreparePinWrite( 
01524                     PtrVCB->PtrStreamFileObject,
01525                     &VolumeByteOffset,
01526                     LogicalBlockSize,
01527                     TRUE,           //  Zero out the block...
01528                     TRUE,           //  Can Wait...
01529                     &PtrDIBBCB,
01530                     (PVOID*)&PtrDIBBuffer ) )
01531                 {
01532                     try_return( RC = FALSE );
01533                 }
01534             }
01535             else
01536             {
01537                 //   Just bring in the DIB to the cache
01538                 
01539                 VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
01540 
01541                 if( !CcPinRead( PtrVCB->PtrStreamFileObject,
01542                             &VolumeByteOffset,
01543                             LogicalBlockSize,
01544                             TRUE,           //  Can Wait...
01545                             &PtrDIBBCB,
01546                             (PVOID*)&PtrDIBBuffer ) )
01547                 {
01548                     try_return( RC = FALSE );
01549                 }
01550             }
01551             
01552             //  See if a single indirect 'pointer' block 
01553             //  should also be allocated...
01554             BlockNo = ( NoOfBlocks - DirectBlocks - SingleIndirectBlocks );
01555             SBlockNo = BlockNo / SingleIndirectBlocks;
01556             if( BlockNo % SingleIndirectBlocks )
01557             {
01558                 //  A single indirect 'pointer' block 
01559                 //  should also be allocated...
01560                 PtrDIBBuffer[SBlockNo] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 );
01561                 CcSetDirtyPinnedData( PtrDIBBCB, NULL );
01562                 VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize;
01563 
01564                 Inode.i_blocks += ( LogicalBlockSize / 512 );
01565 
01566                 if( !CcPreparePinWrite( 
01567                     PtrVCB->PtrStreamFileObject,
01568                     &VolumeByteOffset,
01569                     LogicalBlockSize,
01570                     TRUE,           //  Zero out the block...
01571                     TRUE,           //  Can Wait...
01572                     &PtrSIBBCB,
01573                     (PVOID*)&PtrSIBBuffer ) )
01574                 {
01575                     try_return( RC = FALSE );
01576                 }
01577             }
01578             else
01579             {
01580                 VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize;
01581                 if( !CcPinRead( PtrVCB->PtrStreamFileObject,
01582                             &VolumeByteOffset,
01583                             LogicalBlockSize,
01584                             TRUE,           //  Can Wait...
01585                             &PtrSIBBCB,
01586                             (PVOID*)&PtrSIBBuffer ) )
01587                 {
01588                     try_return( RC = FALSE );
01589                 }
01590             }
01591             BlockNo = BlockNo % SingleIndirectBlocks;
01592             
01593             //  Update the inode...
01594             
01595             Inode.i_block[ EXT2_DIND_BLOCK ] = PtrFCB->IBlock[ EXT2_DIND_BLOCK ];
01596             Inode.i_blocks += ( LogicalBlockSize / 512 );
01597             PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize;
01598             if( UpdateFileSize )
01599             {
01600                 Inode.i_size += LogicalBlockSize;
01601                 PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize;
01602             }
01603             if( PtrFileObject->PrivateCacheMap != NULL)
01604             {
01605                 //
01606                 //  Caching has been initiated...
01607                 //  Let the Cache manager in on these changes...
01608                 //  
01609                 CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize));
01610             }
01611 
01612             if( !NT_SUCCESS( Ext2WriteInode( 
01613                 PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode  ) ) )
01614             {
01615                 try_return (RC = FALSE );
01616             }
01617 
01618             
01619             //  Update the SIB...
01620             PtrSIBBuffer[ BlockNo ] = NewBlockNo;
01621             CcSetDirtyPinnedData( PtrSIBBCB, NULL );
01622             Ext2SaveBCB( PtrIrpContext, PtrSIBBCB, PtrVCB->PtrStreamFileObject );
01623             Ext2SaveBCB( PtrIrpContext, PtrDIBBCB, PtrVCB->PtrStreamFileObject );
01624 
01625             try_return (RC = TRUE);
01626 
01627         }
01628 
01629         try_exit:   NOTHING;
01630     }
01631     finally
01632     {
01633         if( PtrSIBBCB )
01634         {
01635             CcUnpinData( PtrSIBBCB );
01636             PtrSIBBCB = NULL;
01637         }
01638         if( PtrDIBBCB )
01639         {
01640             CcUnpinData( PtrDIBBCB );
01641             PtrDIBBCB = NULL;
01642         }
01643     }
01644     return RC;
01645 }
01646 
01647 /*************************************************************************
01648 *
01649 * Function: Ext2AllocBlock()
01650 *
01651 * Description:
01652 *   The functions will allocate a new block 
01653 *
01654 * Expected Interrupt Level (for execution) :
01655 *  IRQL_PASSIVE_LEVEL 
01656 *
01657 *
01658 * Return Value: Success / Failure...
01659 *
01660 *************************************************************************/
01661 ULONG NTAPI Ext2AllocBlock( 
01662     PtrExt2IrpContext   PtrIrpContext,
01663     PtrExt2VCB          PtrVCB,
01664     ULONG               Count)
01665 {
01666     //  Buffer Control Block
01667     PBCB            PtrBitmapBCB = NULL;
01668     BYTE *          PtrBitmapBuffer = NULL;
01669     ULONG           BlockNo = 0;
01670     LARGE_INTEGER   VolumeByteOffset;
01671     ULONG           LogicalBlockSize = 0;
01672     ULONG           NumberOfBytesToRead = 0;
01673 
01674     if( PtrVCB->FreeBlocksCount == 0 )
01675     {
01676         //
01677         //  No Free Block left...
01678         //  Fail request...
01679         //
01680         return 0;
01681     }
01682 
01683     try
01684     {
01685         BOOLEAN Found = FALSE;
01686         ULONG Block;
01687         ULONG GroupNo;
01688         LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
01689 
01690         for( GroupNo = 0; PtrVCB->NoOfGroups; GroupNo++ )
01691         {
01692             if( PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount )
01693                 break;
01694         }
01695 
01696         VolumeByteOffset.QuadPart = 
01697             PtrVCB->PtrGroupDescriptors[ GroupNo ].BlockBitmapBlock * LogicalBlockSize;
01698         
01699         NumberOfBytesToRead = PtrVCB->BlocksCount / PtrVCB->NoOfGroups;
01700 
01701         if( NumberOfBytesToRead % 8 )
01702         {
01703             NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) + 1;
01704         }
01705         else
01706         {
01707             NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) ;
01708         }
01709         
01710         
01711         for( Block = 0; !Found && Block < Ext2Align( NumberOfBytesToRead , LogicalBlockSize ); 
01712                 Block += LogicalBlockSize, VolumeByteOffset.QuadPart += LogicalBlockSize)           
01713         {
01714             //
01715             //  Read in the block bitmap block...
01716             ULONG i, j;
01717             BYTE Bitmap;
01718                     
01719             if( !CcPinRead( PtrVCB->PtrStreamFileObject,
01720                    &VolumeByteOffset,
01721                    LogicalBlockSize,                    //  NumberOfBytesToRead,
01722                    TRUE,
01723                    &PtrBitmapBCB,
01724                    (PVOID*)&PtrBitmapBuffer ) )
01725             {
01726                 DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0);
01727                 try_return( BlockNo = 0 );
01728             }
01729 
01730             //
01731             //  Is there a free block...
01732             //  
01733             for( i = 0; !Found && i < LogicalBlockSize && 
01734                     i + (Block * LogicalBlockSize) < NumberOfBytesToRead; i++ )
01735             {
01736                 Bitmap = PtrBitmapBuffer[i];
01737                 if( Bitmap != 0xff )
01738                 {
01739                     //
01740                     //  Found a free block...
01741                     for( j = 0; !Found && j < 8; j++ )
01742                     {
01743                         if( ( Bitmap & 0x01 ) == 0 )
01744                         {
01745                             //
01746                             //  Found...
01747                             Found = TRUE;
01748                             BlockNo = ( ( ( Block * LogicalBlockSize) + i ) * 8) + j + 1
01749                                 + ( GroupNo * PtrVCB->BlocksPerGroup );
01750 
01751                             Bitmap = 1 << j;
01752                             PtrBitmapBuffer[i] |= Bitmap;
01753                             
01754                             CcSetDirtyPinnedData( PtrBitmapBCB, NULL );
01755                             Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject );
01756                             //
01757                             //  Should update the bitmaps in the other groups too...
01758                             //
01759                             break;
01760                         }
01761                         Bitmap = Bitmap >> 1;
01762                     }
01763                 }
01764             }
01765             //
01766             //  Unpin the BCB...
01767             //
01768             if( PtrBitmapBCB )
01769             {
01770                 CcUnpinData( PtrBitmapBCB );
01771                 PtrBitmapBCB = NULL;
01772             }
01773 
01774         }
01775 
01776         //
01777         //  Updating the Free Block count in the Group Descriptor...
01778         //  
01779         
01780         {
01781             PBCB                    PtrDescriptorBCB = NULL;
01782             PEXT2_GROUP_DESCRIPTOR  PtrGroupDescriptor = NULL;
01783             //
01784             //  Updating the Free Blocks count in the Group Descriptor...
01785             //  
01786             PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount--;
01787 
01788             if( PtrVCB->LogBlockSize )
01789             {
01790                 //  First block contains the descriptors...
01791                 VolumeByteOffset.QuadPart = LogicalBlockSize;
01792             }
01793             else
01794             {
01795                 //  Second block contains the descriptors...
01796                 VolumeByteOffset.QuadPart = LogicalBlockSize * 2;
01797             }
01798             NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc );
01799             NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
01800 
01801             if (!CcPinRead( PtrVCB->PtrStreamFileObject,
01802                    &VolumeByteOffset,
01803                    NumberOfBytesToRead,
01804                    TRUE,
01805                    &PtrDescriptorBCB ,
01806                    (PVOID*)&PtrGroupDescriptor )) 
01807             {
01808                 DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
01809                 //
01810                 //  Ignore this error...
01811                 //  Not fatal...
01812             }
01813             else
01814             {
01815                 PtrGroupDescriptor[ GroupNo ].bg_free_blocks_count= 
01816                     PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount; 
01817 
01818                 //
01819                 //  Not synchronously flushing this information...
01820                 //  Lazy writing will do...
01821                 //
01822                 CcSetDirtyPinnedData( PtrDescriptorBCB, NULL );
01823                 CcUnpinData( PtrDescriptorBCB );
01824                 PtrDescriptorBCB = NULL;
01825             }
01826         }
01827         
01828         //
01829         //  Update the Block count
01830         //  in the super block and in the VCB
01831         //
01832         {
01833             //  Ext2 Super Block information...
01834             PEXT2_SUPER_BLOCK   PtrSuperBlock = NULL;
01835             PBCB                PtrSuperBlockBCB = NULL;
01836 
01837             PtrVCB->FreeBlocksCount--;
01838 
01839             //  Reading in the super block...
01840             VolumeByteOffset.QuadPart = 1024;
01841             NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize );
01842 
01843             if( !CcPinRead( PtrVCB->PtrStreamFileObject,
01844                    &VolumeByteOffset,
01845                    NumberOfBytesToRead,
01846                    TRUE,
01847                    &PtrSuperBlockBCB,
01848                    (PVOID*)&PtrSuperBlock ) )
01849             {
01850                 DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
01851             }
01852             else
01853             {
01854                 PtrSuperBlock->s_free_blocks_count = PtrVCB->FreeBlocksCount;
01855                 CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL );
01856                 Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject );
01857                 if( PtrSuperBlockBCB )
01858                 {
01859                     CcUnpinData( PtrSuperBlockBCB );
01860                     PtrSuperBlockBCB = NULL;
01861                 }
01862             }
01863         }
01864 
01865         try_exit:   NOTHING;
01866     }
01867     finally
01868     {
01869         if( PtrBitmapBCB )
01870         {
01871             CcUnpinData( PtrBitmapBCB );
01872             PtrBitmapBCB = NULL;
01873         }
01874         DebugTrace( DEBUG_TRACE_SPECIAL, " Allocating a block - Block no : %ld", BlockNo );
01875     }
01876     return BlockNo;
01877 }
01878 
01879 /*************************************************************************
01880 *
01881 * Function: Ext2DeallocBlock()
01882 *
01883 * Description:
01884 *   The functions will deallocate a data block 
01885 *
01886 * Expected Interrupt Level (for execution) :
01887 *  IRQL_PASSIVE_LEVEL 
01888 *
01889 * Return Value: Success / Failure...
01890 *
01891 *************************************************************************/
01892 BOOLEAN NTAPI Ext2DeallocBlock( 
01893     PtrExt2IrpContext   PtrIrpContext,
01894     PtrExt2VCB          PtrVCB,
01895     ULONG               BlockNo )
01896 {
01897     //  Buffer Control Block
01898     PBCB            PtrBitmapBCB = NULL;
01899     BYTE *          PtrBitmapBuffer = NULL;
01900     BOOLEAN         RC = TRUE;
01901     LARGE_INTEGER   VolumeByteOffset;
01902     ULONG           LogicalBlockSize = 0;
01903     //  ULONG           NumberOfBytesToRead = 0;
01904 
01905     DebugTrace( DEBUG_TRACE_SPECIAL, " Deallocating a block - Block no : %ld", BlockNo );
01906     
01907     try
01908     {
01909         ULONG   GroupNo;
01910         ULONG   BlockIndex;
01911         ULONG   BitmapIndex;
01912         BYTE    Bitmap;
01913 
01914         LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
01915 
01916         GroupNo = BlockNo / PtrVCB->BlocksPerGroup;
01917         BlockNo = BlockNo % PtrVCB->BlocksPerGroup;
01918 
01919         Bitmap = 1 << ( (BlockNo-1) % 8 );
01920         BitmapIndex =  (BlockNo-1) / 8;
01921         BlockIndex = BitmapIndex / LogicalBlockSize;
01922         //  Adjusting to index into the Logical block that contains the bitmap
01923         BitmapIndex = BitmapIndex - ( BlockIndex * LogicalBlockSize );
01924 
01925         VolumeByteOffset.QuadPart = 
01926             ( PtrVCB->PtrGroupDescriptors[ GroupNo ].BlockBitmapBlock + BlockIndex ) 
01927             * LogicalBlockSize;
01928         
01929         //
01930         //  Read in the bitmap block...
01931         //
01932         if( !CcPinRead( PtrVCB->PtrStreamFileObject,
01933                 &VolumeByteOffset,
01934                 LogicalBlockSize,
01935                 TRUE,           //  Can Wait...
01936                 &PtrBitmapBCB,
01937                 (PVOID*)&PtrBitmapBuffer ) )
01938         {
01939             //  Unable to Pin the data into the cache...
01940             try_return (RC = FALSE);
01941         }
01942 
01943         //
01944         //  Locate the block 'bit'...
01945         //  This block 'bit' is in the byte PtrBitmapBuffer[ BitmapIndex ]
01946         if( ( PtrBitmapBuffer[ BitmapIndex ] & Bitmap ) == 0)
01947         {
01948             //  This shouldn't have been so...
01949             //  The block was never allocated!
01950             //  How to deallocate something that hasn't been allocated? 
01951             //  Hmmm... ;)
01952             //  Ignore this error...
01953             try_return (RC = TRUE);
01954         }
01955 
01956         //  Setting the bit for the inode...
01957         PtrBitmapBuffer[ BitmapIndex ] &= (~Bitmap);
01958 
01959         //  Update the cache...
01960         CcSetDirtyPinnedData( PtrBitmapBCB, NULL );
01961 
01962         //  Save up the BCB for forcing a synchronous write...
01963         //  Before completing the IRP...
01964         Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject );
01965 
01966 
01967         if( PtrBitmapBCB )
01968         {
01969             CcUnpinData( PtrBitmapBCB );
01970             PtrBitmapBCB = NULL;
01971         }
01972         
01973         //
01974         //  Updating the Block count in the Group Descriptor...
01975         //  
01976         
01977         {
01978             PBCB                    PtrDescriptorBCB = NULL;
01979             PEXT2_GROUP_DESCRIPTOR  PtrGroupDescriptor = NULL;
01980             ULONG                   NumberOfBytesToRead = 0;
01981             //
01982             //  Updating the Free Blocks count in the Group Descriptor...
01983             //  
01984             PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount++;
01985 
01986             if( PtrVCB->LogBlockSize )
01987             {
01988                 //  First block contains the descriptors...
01989                 VolumeByteOffset.QuadPart = LogicalBlockSize;
01990             }
01991             else
01992             {
01993                 //  Second block contains the descriptors...
01994                 VolumeByteOffset.QuadPart = LogicalBlockSize * 2;
01995             }
01996             NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc );
01997             NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
01998 
01999             if (!CcPinRead( PtrVCB->PtrStreamFileObject,
02000                    &VolumeByteOffset,
02001                    NumberOfBytesToRead,
02002                    TRUE,
02003                    &PtrDescriptorBCB ,
02004                    (PVOID*)&PtrGroupDescriptor )) 
02005             {
02006                 DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
02007                 //
02008                 //  Ignore this error...
02009                 //  Not fatal...
02010             }
02011             else
02012             {
02013                 PtrGroupDescriptor[ GroupNo ].bg_free_blocks_count= 
02014                     PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount; 
02015 
02016                 //
02017                 //  Not synchronously flushing this information...
02018                 //  Lazy writing will do...
02019                 //
02020                 CcSetDirtyPinnedData( PtrDescriptorBCB, NULL );
02021                 CcUnpinData( PtrDescriptorBCB );
02022                 PtrDescriptorBCB = NULL;
02023             }
02024         }
02025 
02026         //
02027         //  Update the Block count
02028         //  in the super block and in the VCB
02029         //
02030         {
02031             //  Ext2 Super Block information...
02032             PEXT2_SUPER_BLOCK   PtrSuperBlock = NULL;
02033             PBCB                PtrSuperBlockBCB = NULL;
02034             ULONG               NumberOfBytesToRead = 0;
02035 
02036             PtrVCB->FreeBlocksCount++;
02037 
02038             //  Reading in the super block...
02039             VolumeByteOffset.QuadPart = 1024;
02040             NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize );
02041 
02042             if( !CcPinRead( PtrVCB->PtrStreamFileObject,
02043                    &VolumeByteOffset,
02044                    NumberOfBytesToRead,
02045                    TRUE,
02046                    &PtrSuperBlockBCB,
02047                    (PVOID*)&PtrSuperBlock ) )
02048             {
02049                 DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
02050             }
02051             else
02052             {
02053                 PtrSuperBlock->s_free_blocks_count = PtrVCB->FreeBlocksCount;
02054                 CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL );
02055                 Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject );
02056                 CcUnpinData( PtrSuperBlockBCB );
02057                 PtrSuperBlockBCB = NULL;
02058             }
02059         }
02060         try_exit:   NOTHING;
02061     }
02062     finally
02063     {
02064         if( PtrBitmapBCB )
02065         {
02066             CcUnpinData( PtrBitmapBCB );
02067             PtrBitmapBCB = NULL;
02068         }
02069     }
02070     return RC;
02071 }
02072 
02073 BOOLEAN NTAPI Ext2UpdateFileSize(   
02074     PtrExt2IrpContext   PtrIrpContext,
02075     PFILE_OBJECT        PtrFileObject,
02076     PtrExt2FCB          PtrFCB)
02077 {
02078     EXT2_INODE          Inode;
02079     PtrExt2VCB          PtrVCB = PtrFCB->PtrVCB;
02080 
02081     if( PtrFileObject->PrivateCacheMap )
02082     {
02083         CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize));
02084     }
02085     //  Now update the size on the disk...
02086     //  Read in the inode...
02087     if( ! NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
02088     {
02089         return FALSE;
02090     }
02091 
02092     Inode.i_size = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart;
02093     //  Update time also???
02094 
02095     //  Updating the inode...
02096     if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
02097     {
02098         return TRUE;
02099     }
02100     else
02101     {
02102         return FALSE;
02103     }
02104 }
02105 
02106 /*************************************************************************
02107 *
02108 * Function: Ext2DeleteFile()
02109 *
02110 * Description:
02111 *   The functions will delete a file
02112 *
02113 * Expected Interrupt Level (for execution) :
02114 *  IRQL_PASSIVE_LEVEL 
02115 *
02116 * Return Value: Success / Failure...
02117 *
02118 *************************************************************************/
02119 BOOLEAN NTAPI Ext2DeleteFile(
02120     PtrExt2FCB          PtrFCB,
02121     PtrExt2IrpContext   PtrIrpContext)
02122 {
02123     EXT2_INODE          Inode;
02124     PtrExt2FCB          PtrParentFCB = NULL;
02125     PtrExt2VCB          PtrVCB = PtrFCB->PtrVCB;
02126     
02127     //
02128     //  Get the Parent Directory...
02129     PtrParentFCB = Ext2LocateFCBInCore( PtrVCB, PtrFCB->ParentINodeNo );
02130     Ext2InitializeFCBInodeInfo( PtrFCB );
02131     
02132     //  1.
02133     //  Free up the directory entry...
02134     if( !Ext2FreeDirectoryEntry( PtrIrpContext,
02135             PtrParentFCB, &PtrFCB->FCBName->ObjectName ) )
02136     {
02137         return FALSE;
02138     }
02139 
02140     //  2. 
02141     //  Decrement Link count...
02142     if( !NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
02143     {
02144         return FALSE;
02145     }
02146 
02147     ASSERT( Inode.i_links_count == PtrFCB->LinkCount );
02148     
02149     Inode.i_links_count--;
02150     PtrFCB->LinkCount = Inode.i_links_count; 
02151 
02152     if( !Inode.i_links_count )
02153     {
02154         //
02155         //  Setting the deletion time field in the inode...
02156         //
02157         ULONG Time;
02158         Time = Ext2GetCurrentTime();
02159         Inode.i_dtime = Time ;
02160     }
02161 
02162     //  3. 
02163     //  Updating the inode...
02164 
02165     if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
02166     {
02167         if( Inode.i_links_count )
02168         {
02169             //  Some more links to the same file are available...
02170             //  So we won't deallocate the data blocks...
02171             return TRUE;
02172         }
02173     }
02174     else
02175     {
02176         return FALSE;
02177     }
02178 
02179     //  4.
02180     //  Free up the inode...
02181     Ext2DeallocInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo );
02182 
02183     //  5.
02184     //  Release the data blocks...
02185     Ext2ReleaseDataBlocks( PtrFCB, PtrIrpContext);
02186 
02187     return TRUE;
02188 }
02189 
02190 
02191 /*************************************************************************
02192 *
02193 * Function: Ext2ReleaseDataBlocks()
02194 *
02195 * Description:
02196 *   The functions will release all the data blocks in a file
02197 *   It does NOT update the file inode... 
02198 *
02199 * Expected Interrupt Level (for execution) :
02200 *  IRQL_PASSIVE_LEVEL 
02201 *
02202 * Return Value: Success / Failure...
02203 *
02204 *************************************************************************/
02205 BOOLEAN NTAPI Ext2ReleaseDataBlocks(
02206     PtrExt2FCB          PtrFCB,
02207     PtrExt2IrpContext   PtrIrpContext)
02208 {
02209     PtrExt2VCB          PtrVCB = PtrFCB->PtrVCB;
02210     ULONG LogicalBlockSize;
02211     ULONG i;
02212 
02213 
02214     LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
02215 
02216     //  Release the data blocks...
02217 
02218     //  1.
02219     //  Free up the triple indirect blocks...
02220     if( PtrFCB->IBlock[ EXT2_TIND_BLOCK ] )
02221     {
02222         
02223         PBCB            PtrSIBCB = NULL;
02224         PBCB            PtrDIBCB = NULL;
02225         PBCB            PtrTIBCB = NULL;
02226 
02227         ULONG *         PtrPinnedSIndirectBlock = NULL;
02228         ULONG *         PtrPinnedDIndirectBlock = NULL;
02229         ULONG *         PtrPinnedTIndirectBlock = NULL;
02230         
02231         LARGE_INTEGER   VolumeByteOffset;
02232         ULONG           TIndex, DIndex, SIndex;
02233 
02234         //  Pin the Double Indirect Pointer Block...
02235         VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_TIND_BLOCK ] * LogicalBlockSize;
02236         if (!CcMapData( PtrVCB->PtrStreamFileObject,
02237            &VolumeByteOffset,
02238            LogicalBlockSize,
02239            TRUE,
02240            &PtrTIBCB,
02241            (PVOID*)&PtrPinnedTIndirectBlock )) 
02242         {
02243             return FALSE;
02244         }
02245 
02246         //  Read the Block numbers off the Triple Indirect Pointer Block...
02247         for( TIndex = 0; TIndex < (LogicalBlockSize/sizeof(ULONG)); TIndex++ )
02248         {
02249             if( PtrPinnedTIndirectBlock[ TIndex ] )
02250             {
02251                 VolumeByteOffset.QuadPart = PtrPinnedTIndirectBlock[TIndex] * LogicalBlockSize;
02252                 if (!CcMapData( PtrVCB->PtrStreamFileObject,
02253                    &VolumeByteOffset,
02254                    LogicalBlockSize,
02255                    TRUE,
02256                    &PtrDIBCB,
02257                    (PVOID*)&PtrPinnedDIndirectBlock )) 
02258                 {
02259                     return FALSE;
02260                 }
02261 
02262                 //  Read the Block numbers off the Double Indirect Pointer Blocks...
02263                 for( DIndex = 0; DIndex < (LogicalBlockSize/sizeof(ULONG)); DIndex++ )
02264                 {
02265                     if( PtrPinnedDIndirectBlock[DIndex] )
02266                     {
02267                         VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[DIndex] * LogicalBlockSize;
02268                         if (!CcMapData( PtrVCB->PtrStreamFileObject,
02269                            &VolumeByteOffset,
02270                            LogicalBlockSize,
02271                            TRUE,
02272                            &PtrSIBCB,
02273                            (PVOID*)&PtrPinnedSIndirectBlock )) 
02274                         {
02275                             return FALSE;
02276                         }
02277 
02278                         //  Read the Block numbers off the Single Indirect Pointer Blocks and 
02279                         //  free the data blocks
02280                         for( SIndex = 0; SIndex < (LogicalBlockSize/sizeof(ULONG)); SIndex++ )
02281                         {
02282                             if( PtrPinnedSIndirectBlock[ SIndex ] )
02283                             {
02284                                 Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[SIndex] );
02285                             }
02286                             else
02287                             {
02288                                 break;
02289                             }
02290                         }
02291                         CcUnpinData( PtrSIBCB );
02292                         
02293                         //  Deallocating
02294                         //  Single Indirect Pointer Block
02295                         Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedDIndirectBlock[DIndex] );
02296                     }
02297                     else
02298                     {
02299                         break;
02300                     }
02301                 }
02302             }
02303             else
02304             {
02305                 break;
02306             }
02307         }
02308         CcUnpinData( PtrTIBCB );
02309         //  Deallocating Triple Indirect Pointer Blocks
02310         Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_TIND_BLOCK ] );
02311     }
02312 
02313     //  2.
02314     //  Free up the double indirect blocks...
02315     if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] )
02316     {
02317         PBCB            PtrDIBCB = NULL;
02318         PBCB            PtrSIBCB = NULL;
02319         ULONG *         PtrPinnedSIndirectBlock = NULL;
02320         ULONG *         PtrPinnedDIndirectBlock = NULL;
02321         
02322         LARGE_INTEGER   VolumeByteOffset;
02323         ULONG           DIndex, SIndex;
02324 
02325         //  Pin the Double Indirect Pointer Block...
02326         VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
02327         if (!CcMapData( PtrVCB->PtrStreamFileObject,
02328            &VolumeByteOffset,
02329            LogicalBlockSize,
02330            TRUE,
02331            &PtrDIBCB,
02332            (PVOID*)&PtrPinnedDIndirectBlock )) 
02333         {
02334             return FALSE;
02335         }
02336 
02337         //  Read the Block numbers off the Double Indirect Pointer Block...
02338         for( DIndex = 0; DIndex < (LogicalBlockSize/sizeof(ULONG)); DIndex++ )
02339         {
02340             if( PtrPinnedDIndirectBlock[DIndex] )
02341             {
02342                 VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[DIndex] * LogicalBlockSize;
02343                 if (!CcMapData( PtrVCB->PtrStreamFileObject,
02344                    &VolumeByteOffset,
02345                    LogicalBlockSize,
02346                    TRUE,
02347                    &PtrSIBCB,
02348                    (PVOID*)&PtrPinnedSIndirectBlock )) 
02349                 {
02350                     return FALSE;
02351                 }
02352 
02353                 //  Read the Block numbers off the Single Indirect Pointer Blocks and 
02354                 //  free the data blocks
02355                 for( SIndex = 0; SIndex < (LogicalBlockSize/sizeof(ULONG)); SIndex++ )
02356                 {
02357                     if( PtrPinnedSIndirectBlock[ SIndex ] )
02358                     {
02359                         Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[SIndex] );
02360                     }
02361                     else
02362                     {
02363                         break;
02364                     }
02365                 }
02366                 CcUnpinData( PtrSIBCB );
02367                 
02368                 //  Deallocating
02369                 //  Single Indirect Pointer Block
02370                 Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedDIndirectBlock[DIndex] );
02371             }
02372             else
02373             {
02374                 break;
02375             }
02376         }
02377         CcUnpinData( PtrDIBCB );
02378         //  Deallocating Double Indirect Pointer Blocks
02379         Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_DIND_BLOCK ] );
02380     }
02381 
02382     //  3.
02383     //  Free up the single indirect blocks...
02384     if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] )
02385     {
02386         PBCB            PtrBCB = NULL;
02387         ULONG *         PtrPinnedSIndirectBlock = NULL;
02388         LARGE_INTEGER   VolumeByteOffset;
02389         ULONG           Index;
02390 
02391         //  Pin the Single Indirect Pointer Block...
02392         VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize;
02393         if (!CcMapData( PtrVCB->PtrStreamFileObject,
02394            &VolumeByteOffset,
02395            LogicalBlockSize,
02396            TRUE,
02397            &PtrBCB,
02398            (PVOID*)&PtrPinnedSIndirectBlock )) 
02399         {
02400             return FALSE;
02401         }
02402 
02403         //  Read the Block numbers off the Indirect Pointer Block and 
02404         //  free the data blocks
02405         for( Index = 0; Index < (LogicalBlockSize/sizeof(ULONG)); Index++ )
02406         {
02407             if( PtrPinnedSIndirectBlock[Index] )
02408             {
02409                 Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[Index] );
02410             }
02411             else
02412             {
02413                 break;
02414             }
02415         }
02416         CcUnpinData( PtrBCB );
02417         Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_IND_BLOCK ] );
02418     }
02419 
02420     //  4.
02421     //  Free up the direct blocks...
02422     for( i = 0; i < EXT2_NDIR_BLOCKS; i++ )
02423     {
02424         if( PtrFCB->IBlock[ i ] )
02425         {
02426             Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ i ] );
02427         }
02428         else
02429         {
02430             break;
02431         }
02432     }
02433     return TRUE;
02434 }
02435 
02436 
02437 BOOLEAN NTAPI Ext2TruncateFileAllocationSize(
02438     PtrExt2IrpContext   PtrIrpContext,
02439     PtrExt2FCB          PtrFCB,
02440     PFILE_OBJECT        PtrFileObject,
02441     PLARGE_INTEGER      PtrAllocationSize )
02442 {
02443     PtrExt2VCB          PtrVCB = PtrFCB->PtrVCB;
02444     ULONG LogicalBlockSize;
02445     ULONG i;
02446 
02447     ULONG NoOfBlocksToBeLeft= 0;
02448     ULONG CurrentBlockNo = 0;
02449 
02450     //
02451     //  This function has not been tested...
02452     //
02453     Ext2BreakPoint();
02454 
02455     LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
02456     NoOfBlocksToBeLeft = (ULONG) (PtrAllocationSize->QuadPart / LogicalBlockSize);
02457 
02458     
02459 
02460     //  Release the data blocks...
02461 
02462     //  1.
02463     //  Free up the direct blocks...
02464     for( i = NoOfBlocksToBeLeft; i < EXT2_NDIR_BLOCKS; i++ )
02465     {
02466         if( PtrFCB->IBlock[ i ] )
02467         {
02468             Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ i ] );
02469             PtrFCB->IBlock[ i ] = 0;
02470         }
02471         else
02472         {
02473             break;
02474         }
02475     }
02476 
02477     //  2.
02478     //  Free up the single indirect blocks...
02479     CurrentBlockNo = EXT2_NDIR_BLOCKS;
02480 
02481     if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] )
02482     {
02483         PBCB            PtrBCB = NULL;
02484         ULONG *         PtrPinnedSIndirectBlock = NULL;
02485         LARGE_INTEGER   VolumeByteOffset;
02486         ULONG           Index;
02487 
02488         //  Pin the Single Indirect Pointer Block...
02489         VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize;
02490         if (!CcMapData( PtrVCB->PtrStreamFileObject,
02491            &VolumeByteOffset,
02492            LogicalBlockSize,
02493            TRUE,
02494            &PtrBCB,
02495            (PVOID*)&PtrPinnedSIndirectBlock )) 
02496         {
02497             return FALSE;
02498         }
02499 
02500         //  Read the Block numbers off the Indirect Pointer Block and 
02501         //  free the data blocks
02502         for( Index = 0; Index < (LogicalBlockSize/sizeof(ULONG)); 
02503              Index++, CurrentBlockNo++ )
02504         {
02505             if( CurrentBlockNo >= NoOfBlocksToBeLeft )
02506             {
02507                 if( PtrPinnedSIndirectBlock[Index] )
02508                 {
02509                     Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[Index] );
02510                 }
02511                 else
02512                 {
02513                     break;
02514                 }
02515             }
02516             else if( !PtrPinnedSIndirectBlock[Index] )
02517             {
02518                 break;
02519             }
02520         }
02521         if( NoOfBlocksToBeLeft <= EXT2_NDIR_BLOCKS )
02522         {
02523             Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_IND_BLOCK ] );
02524             PtrFCB->IBlock[ EXT2_IND_BLOCK ] = 0;
02525         }
02526 
02527         CcUnpinData( PtrBCB );
02528     }
02529     
02530     //  3.
02531     //  Free up the double indirect blocks...
02532     if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] )
02533     {
02534         
02535     }
02536 
02537     //  4.
02538     //  Free up the triple indirect blocks...
02539     if( PtrFCB->IBlock[ EXT2_TIND_BLOCK ] )
02540     {
02541         
02542     }
02543 
02544     return TRUE;
02545 }
02546 
02547 BOOLEAN NTAPI Ext2IsDirectoryEmpty(
02548     PtrExt2FCB          PtrFCB,
02549     PtrExt2CCB          PtrCCB,
02550     PtrExt2IrpContext   PtrIrpContext)
02551 {
02552 
02553     PFILE_OBJECT        PtrFileObject = NULL;
02554 
02555     if( !Ext2IsFlagOn(PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY) )
02556     {
02557         return FALSE;
02558     }
02559 
02560     //  1. 
02561     //  Initialize the Blocks in the FCB...
02562     //
02563     Ext2InitializeFCBInodeInfo( PtrFCB );
02564 
02565     
02566     //  2.
02567     //  Get hold of the file object...
02568     //
02569     PtrFileObject = PtrCCB->PtrFileObject;
02570 
02571 
02572     //  3.
02573     //  Now initiating Caching, pinned access to be precise ...
02574     //
02575     if (PtrFileObject->PrivateCacheMap == NULL) 
02576     {
02577         CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)),
02578             TRUE,       // We utilize pin access for directories
02579             &(Ext2GlobalData.CacheMgrCallBacks), // callbacks
02580             PtrFCB );       // The context used in callbacks
02581     }
02582 
02583     //  4.
02584     //  Getting down to the real business now... ;)
02585     //  Read in the directory contents and do a search 
02586     //
02587     {
02588         LARGE_INTEGER   StartBufferOffset;
02589         ULONG           PinBufferLength;
02590         ULONG           BufferIndex;
02591         PBCB            PtrBCB = NULL;
02592         BYTE *          PtrPinnedBlockBuffer = NULL;
02593         PEXT2_DIR_ENTRY PtrDirEntry = NULL;
02594         BOOLEAN         Found = FALSE;
02595 
02596         StartBufferOffset.QuadPart = 0;
02597 
02598         //
02599         //  Read in the whole directory
02600         //  **Bad programming**
02601         //  Will do for now.
02602         //
02603         PinBufferLength = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart;
02604         if (!CcMapData( PtrFileObject,
02605                   &StartBufferOffset,
02606                   PinBufferLength,
02607                   TRUE,
02608                   &PtrBCB,
02609                   (PVOID*)&PtrPinnedBlockBuffer ) )
02610         {
02611             return FALSE;
02612         }
02613         
02614         //
02615         //  Walking through now...
02616         //
02617         for( BufferIndex = 0, Found = FALSE; !Found && BufferIndex < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; BufferIndex += PtrDirEntry->rec_len )
02618         {
02619             PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ BufferIndex ];
02620             if( PtrDirEntry->inode == 0)
02621             {
02622                 //  Deleted entry...
02623                 //  Ignore...
02624                 continue;
02625             }
02626             if( PtrDirEntry->name[0] == '.' )
02627             {
02628                 if( PtrDirEntry->name_len == 1 || 
02629                   ( PtrDirEntry->name_len == 2 && PtrDirEntry->name[1] == '.' ) )
02630                 {
02631                   continue;
02632                 }
02633             }
02634             Found = TRUE;
02635         }
02636         CcUnpinData( PtrBCB );
02637         PtrBCB = NULL;
02638 
02639         return !Found;
02640     }
02641 }
02642 
02643 
02644 NTSTATUS NTAPI Ext2RenameOrLinkFile( 
02645     PtrExt2FCB                  PtrSourceFCB, 
02646     PFILE_OBJECT                PtrSourceFileObject,    
02647     PtrExt2IrpContext           PtrIrpContext,
02648     PIRP                        PtrIrp, 
02649     PFILE_RENAME_INFORMATION    PtrRenameInfo)
02650 {
02651     PtrExt2FCB              PtrParentFCB = NULL;
02652     PtrExt2VCB              PtrSourceVCB = PtrSourceFCB->PtrVCB;
02653 
02654     PtrExt2FCB              PtrTargetFCB = NULL;
02655     PtrExt2CCB              PtrTargetCCB = NULL;
02656     PtrExt2VCB              PtrTargetVCB = NULL;
02657 
02658 
02659     FILE_INFORMATION_CLASS  FunctionalityRequested;
02660     PIO_STACK_LOCATION      PtrIoStackLocation = NULL;
02661     PFILE_OBJECT            TargetFileObject = NULL;
02662     BOOLEAN                 ReplaceExistingFile = FALSE;
02663     BOOLEAN                 Found = FALSE;
02664 
02665     PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp);
02666     FunctionalityRequested = PtrIoStackLocation->Parameters.SetFile.FileInformationClass;
02667     TargetFileObject = PtrIoStackLocation->Parameters.SetFile.FileObject;
02668     ReplaceExistingFile = PtrIoStackLocation->Parameters.SetFile.ReplaceIfExists;
02669 
02670     // Get the FCB and CCB pointers
02671     Ext2GetFCB_CCB_VCB_FromFileObject ( 
02672         TargetFileObject , &PtrTargetFCB, &PtrTargetCCB, &PtrTargetVCB);
02673 
02674     if( !PtrTargetCCB )
02675     {
02676         return STATUS_ACCESS_DENIED;
02677     }
02678     if( PtrTargetVCB != PtrSourceVCB )
02679     {
02680         //  Cannot rename across volumes...
02681         return STATUS_ACCESS_DENIED;
02682     }
02683     if ( !Ext2IsFlagOn( PtrTargetFCB->FCBFlags, EXT2_FCB_DIRECTORY ) )
02684     {
02685         //  Target has to be a folder...
02686         return STATUS_ACCESS_DENIED;
02687     }
02688 
02689     //  1.
02690     //  Open the parent folder...
02691     PtrParentFCB = Ext2LocateFCBInCore( PtrSourceVCB, PtrSourceFCB->ParentINodeNo );
02692     if( !PtrParentFCB )
02693     {
02694         //  Get the folder from the disk
02695         //  Use the inode no PtrSourceFCB->ParentINodeNo
02696         //
02697         //  For now...
02698         return STATUS_ACCESS_DENIED;
02699     }
02700 
02701     //  2.
02702     //  Check if the file exists in the TargetFolder...
02703     {
02704         LARGE_INTEGER   StartBufferOffset;
02705         ULONG           PinBufferLength;
02706         ULONG           BufferIndex;
02707         PBCB            PtrBCB = NULL;
02708         BYTE *          PtrPinnedBlockBuffer = NULL;
02709         PEXT2_DIR_ENTRY PtrDirEntry = NULL;
02710         int             i;
02711 
02712         StartBufferOffset.QuadPart = 0;
02713 
02714         //
02715         //  Read in the whole directory
02716         //
02717         if ( TargetFileObject->PrivateCacheMap == NULL )
02718         {
02719             CcInitializeCacheMap(
02720                 TargetFileObject, 
02721                 (PCC_FILE_SIZES)(&(PtrTargetFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)),
02722                 TRUE,                                   // We utilize pin access for directories
02723                 &(Ext2GlobalData.CacheMgrCallBacks),    // callbacks
02724                 PtrTargetCCB );                         // The context used in callbacks
02725         }
02726         
02727         PinBufferLength = PtrTargetFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart;
02728         if (!CcMapData( TargetFileObject,
02729                   &StartBufferOffset,
02730                   PinBufferLength,
02731                   TRUE,
02732                   &PtrBCB,
02733                   (PVOID*)&PtrPinnedBlockBuffer ) )
02734         {
02735             return FALSE;
02736         }
02737         
02738         //
02739         //  Walking through now...
02740         //
02741         for( BufferIndex = 0, Found = FALSE; !Found && BufferIndex < ( PtrTargetFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; BufferIndex += PtrDirEntry->rec_len )
02742         {
02743             PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ BufferIndex ];
02744             if( PtrDirEntry->inode == 0)
02745             {
02746                 //  Deleted entry...
02747                 //  Ignore...
02748                 continue;
02749             }
02750             if( PtrDirEntry->name_len == (PtrTargetCCB->RenameLinkTargetFileName.Length/2) )
02751             {
02752                 Found = TRUE;
02753                 for( i =0; i < PtrDirEntry->name_len ; i++ )
02754                 {
02755                     if( PtrDirEntry->name[i] != PtrTargetCCB->RenameLinkTargetFileName.Buffer[i] )
02756                     {
02757                         Found = FALSE;
02758                         break;
02759                     }
02760                 }
02761             }
02762         }
02763         CcUnpinData( PtrBCB );
02764         PtrBCB = NULL;
02765     }
02766 
02767     //  3.
02768     //  If the file exists, delete it if requested..
02769     if( Found )
02770     {
02771         if( !ReplaceExistingFile )
02772         {
02773             return STATUS_OBJECT_NAME_COLLISION;
02774         }
02775         //  Delete the file...
02776         //  Reject this for now...
02777         return STATUS_ACCESS_DENIED;
02778     }
02779 
02780 
02781     {
02782         ULONG   Type = EXT2_FT_REG_FILE;
02783         if( Ext2IsFlagOn( PtrSourceFCB->FCBFlags, EXT2_FCB_DIRECTORY ) )
02784         {
02785             Type = EXT2_FT_DIR;
02786         }
02787 
02788         ASSERT( TargetFileObject );
02789 
02790         //  4.
02791         //  Remove the old entry...
02792         Ext2FreeDirectoryEntry( PtrIrpContext, PtrParentFCB,
02793                 &PtrSourceFCB->FCBName->ObjectName);
02794 
02795         //  5. 
02796         //  Create a new entry...
02797         Ext2MakeNewDirectoryEntry(
02798             PtrIrpContext,              //  This IRP Context
02799             PtrTargetFCB,               //  Parent Folder FCB
02800             TargetFileObject,           //  Parent Folder Object
02801             &PtrTargetCCB->RenameLinkTargetFileName, // New entry's name
02802             Type,                       //  The type of the new entry
02803             PtrSourceFCB->INodeNo );    //  The inode no of the new entry...
02804 
02805     }
02806 
02807     //  6. 
02808     //  Update the PtrSourceFCB...
02809     {
02810 
02811         PtrExt2ObjectName       PtrObjectName;
02812         if( PtrSourceFCB->FCBName )
02813         {
02814             Ext2ReleaseObjectName( PtrSourceFCB->FCBName );
02815         }
02816         PtrObjectName = Ext2AllocateObjectName();
02817         Ext2CopyUnicodeString( &PtrObjectName->ObjectName, &PtrTargetCCB->RenameLinkTargetFileName ); 
02818         PtrSourceFCB->FCBName = PtrObjectName;
02819         PtrSourceFCB->ParentINodeNo = PtrTargetFCB->INodeNo;
02820     }
02821 
02822     if( PtrTargetCCB->RenameLinkTargetFileName.Length )
02823     {
02824         Ext2DeallocateUnicodeString( &PtrTargetCCB->RenameLinkTargetFileName );
02825     }
02826 
02827     return STATUS_SUCCESS;
02828 }

Generated on Sun May 27 2012 04:24:48 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.