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