1 /*
2  * COPYRIGHT:        See COPYRIGHT.TXT
3  * PROJECT:          Ext2 File System Driver for WinNT/2K/XP
4  * FILE:             fileinfo.c
5  * PROGRAMMER:       Matt Wu <mattwu@163.com>
6  * HOMEPAGE:         http://www.ext2fsd.com
7  * UPDATE HISTORY:
8  */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include "ext2fs.h"
13 #include <linux/ext4.h>
14 #include "linux/ext4_xattr.h"
15 
16 /* GLOBALS ***************************************************************/
17 
18 extern PEXT2_GLOBAL Ext2Global;
19 
20 /* DEFINITIONS *************************************************************/
21 
22 #ifdef ALLOC_PRAGMA
23 #pragma alloc_text(PAGE, Ext2QueryFileInformation)
24 #pragma alloc_text(PAGE, Ext2SetFileInformation)
25 #pragma alloc_text(PAGE, Ext2ExpandFile)
26 #pragma alloc_text(PAGE, Ext2TruncateFile)
27 #pragma alloc_text(PAGE, Ext2SetDispositionInfo)
28 #pragma alloc_text(PAGE, Ext2SetRenameInfo)
29 #pragma alloc_text(PAGE, Ext2SetLinkInfo)
30 #pragma alloc_text(PAGE, Ext2DeleteFile)
31 #endif
32 
33 static int Ext2IterateAllEa(struct ext4_xattr_ref *xattr_ref, struct ext4_xattr_item *item, BOOL is_last)
34 {
35     PULONG EaSize = xattr_ref->iter_arg;
36     ULONG EaEntrySize = 4 + 1 + 1 + 2 + item->name_len + 1 + item->data_size;
37 
38     *EaSize += EaEntrySize - 4;
39     return EXT4_XATTR_ITERATE_CONT;
40 }
41 
42 NTSTATUS
43 Ext2QueryFileInformation (IN PEXT2_IRP_CONTEXT IrpContext)
44 {
45     PDEVICE_OBJECT          DeviceObject;
46     NTSTATUS                Status = STATUS_UNSUCCESSFUL;
47     PFILE_OBJECT            FileObject;
48     PEXT2_VCB               Vcb = NULL;
49     PEXT2_FCB               Fcb = NULL;
50     PEXT2_MCB               Mcb = NULL;
51     PEXT2_CCB               Ccb = NULL;
52     PIRP                    Irp = NULL;
53     PIO_STACK_LOCATION      IoStackLocation;
54     FILE_INFORMATION_CLASS  FileInformationClass;
55     ULONG                   Length;
56     PVOID                   Buffer;
57     BOOLEAN                 FcbResourceAcquired = FALSE;
58 
59     _SEH2_TRY {
60 
61         ASSERT(IrpContext != NULL);
62         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
63                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
64 
65         DeviceObject = IrpContext->DeviceObject;
66 
67         //
68         // This request is not allowed on the main device object
69         //
70         if (IsExt2FsDevice(DeviceObject)) {
71             Status = STATUS_INVALID_DEVICE_REQUEST;
72             _SEH2_LEAVE;
73         }
74 
75         FileObject = IrpContext->FileObject;
76         Fcb = (PEXT2_FCB) FileObject->FsContext;
77         if (Fcb == NULL) {
78             Status = STATUS_INVALID_PARAMETER;
79             _SEH2_LEAVE;
80         }
81 
82         //
83         // This request is not allowed on volumes
84         //
85         if (Fcb->Identifier.Type == EXT2VCB) {
86             Status = STATUS_INVALID_PARAMETER;
87             _SEH2_LEAVE;
88         }
89 
90         if (!((Fcb->Identifier.Type == EXT2FCB) &&
91                 (Fcb->Identifier.Size == sizeof(EXT2_FCB)))) {
92             Status = STATUS_INVALID_PARAMETER;
93             _SEH2_LEAVE;
94         }
95 
96         Vcb = Fcb->Vcb;
97 
98         {
99             if (!ExAcquireResourceSharedLite(
100                         &Fcb->MainResource,
101                         IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)
102                     )) {
103 
104                 Status = STATUS_PENDING;
105                 _SEH2_LEAVE;
106             }
107 
108             FcbResourceAcquired = TRUE;
109         }
110 
111         Ccb = (PEXT2_CCB) FileObject->FsContext2;
112         ASSERT(Ccb != NULL);
113         ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
114                (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
115         Mcb = Ccb->SymLink;
116         if (!Mcb)
117             Mcb = Fcb->Mcb;
118 
119         Irp = IrpContext->Irp;
120         IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
121         FileInformationClass =
122             IoStackLocation->Parameters.QueryFile.FileInformationClass;
123 
124         Length = IoStackLocation->Parameters.QueryFile.Length;
125         Buffer = Irp->AssociatedIrp.SystemBuffer;
126         RtlZeroMemory(Buffer, Length);
127 
128         switch (FileInformationClass) {
129 
130         case FileBasicInformation:
131         {
132             PFILE_BASIC_INFORMATION FileBasicInformation;
133 
134             if (Length < sizeof(FILE_BASIC_INFORMATION)) {
135                 Status = STATUS_BUFFER_OVERFLOW;
136                 _SEH2_LEAVE;
137             }
138 
139             FileBasicInformation = (PFILE_BASIC_INFORMATION) Buffer;
140 
141             FileBasicInformation->CreationTime = Mcb->CreationTime;
142             FileBasicInformation->LastAccessTime = Mcb->LastAccessTime;
143             FileBasicInformation->LastWriteTime = Mcb->LastWriteTime;
144             FileBasicInformation->ChangeTime = Mcb->ChangeTime;
145 
146             FileBasicInformation->FileAttributes = Mcb->FileAttr;
147             if (IsLinkInvalid(Mcb)) {
148                 ClearFlag(FileBasicInformation->FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
149             }
150             if (FileBasicInformation->FileAttributes == 0) {
151                 FileBasicInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL;
152             }
153 
154             Irp->IoStatus.Information = sizeof(FILE_BASIC_INFORMATION);
155             Status = STATUS_SUCCESS;
156         }
157         break;
158 
159         case FileStandardInformation:
160         {
161             PFILE_STANDARD_INFORMATION FSI;
162 
163             if (Length < sizeof(FILE_STANDARD_INFORMATION)) {
164                 Status = STATUS_BUFFER_OVERFLOW;
165                 _SEH2_LEAVE;
166             }
167 
168             FSI = (PFILE_STANDARD_INFORMATION) Buffer;
169 
170             FSI->NumberOfLinks = Mcb->Inode.i_nlink;
171 
172             if (IsVcbReadOnly(Fcb->Vcb))
173                 FSI->DeletePending = FALSE;
174             else
175                 FSI->DeletePending = IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING);
176 
177             if (IsLinkInvalid(Mcb)) {
178                 FSI->Directory = FALSE;
179                 FSI->AllocationSize.QuadPart = 0;
180                 FSI->EndOfFile.QuadPart = 0;
181             } else if (IsMcbDirectory(Mcb)) {
182                 FSI->Directory = TRUE;
183                 FSI->AllocationSize.QuadPart = 0;
184                 FSI->EndOfFile.QuadPart = 0;
185             } else {
186                 FSI->Directory = FALSE;
187                 FSI->AllocationSize = Fcb->Header.AllocationSize;
188                 FSI->EndOfFile = Fcb->Header.FileSize;
189             }
190 
191             Irp->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION);
192             Status = STATUS_SUCCESS;
193         }
194         break;
195 
196         case FileInternalInformation:
197         {
198             PFILE_INTERNAL_INFORMATION FileInternalInformation;
199 
200             if (Length < sizeof(FILE_INTERNAL_INFORMATION)) {
201                 Status = STATUS_BUFFER_OVERFLOW;
202                 _SEH2_LEAVE;
203             }
204 
205             FileInternalInformation = (PFILE_INTERNAL_INFORMATION) Buffer;
206 
207             /* we use the inode number as the internal index */
208             FileInternalInformation->IndexNumber.QuadPart = (LONGLONG)Mcb->Inode.i_ino;
209 
210             Irp->IoStatus.Information = sizeof(FILE_INTERNAL_INFORMATION);
211             Status = STATUS_SUCCESS;
212         }
213         break;
214 
215 
216         case FileEaInformation:
217         {
218             struct ext4_xattr_ref xattr_ref;
219             PFILE_EA_INFORMATION FileEaInformation;
220 
221             if (Length < sizeof(FILE_EA_INFORMATION)) {
222                 Status = STATUS_BUFFER_OVERFLOW;
223                 _SEH2_LEAVE;
224             }
225 
226             FileEaInformation = (PFILE_EA_INFORMATION) Buffer;
227             FileEaInformation->EaSize = 0;
228 
229             Status = Ext2WinntError(ext4_fs_get_xattr_ref(IrpContext, Vcb, Fcb->Mcb, &xattr_ref));
230             if (!NT_SUCCESS(Status))
231                 _SEH2_LEAVE;
232 
233             xattr_ref.iter_arg = &FileEaInformation->EaSize;
234             ext4_fs_xattr_iterate(&xattr_ref, Ext2IterateAllEa);
235             ext4_fs_put_xattr_ref(&xattr_ref);
236 
237             if (FileEaInformation->EaSize)
238                 FileEaInformation->EaSize += 4;
239 
240             Irp->IoStatus.Information = sizeof(FILE_EA_INFORMATION);
241             Status = STATUS_SUCCESS;
242         }
243         break;
244 
245         case FileNameInformation:
246         {
247             PFILE_NAME_INFORMATION FileNameInformation;
248             ULONG   BytesToCopy = 0;
249 
250             if (Length < (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) +
251                     Mcb->FullName.Length) {
252                 BytesToCopy = Length - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
253                 Status = STATUS_BUFFER_OVERFLOW;
254             } else {
255                 BytesToCopy = Mcb->FullName.Length;
256                 Status = STATUS_SUCCESS;
257             }
258 
259             FileNameInformation = (PFILE_NAME_INFORMATION) Buffer;
260             FileNameInformation->FileNameLength = Mcb->FullName.Length;
261 
262             RtlCopyMemory(
263                 FileNameInformation->FileName,
264                 Mcb->FullName.Buffer,
265                 BytesToCopy );
266 
267             Irp->IoStatus.Information = BytesToCopy +
268                                         + FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
269         }
270         break;
271 
272         case FilePositionInformation:
273         {
274             PFILE_POSITION_INFORMATION FilePositionInformation;
275 
276             if (Length < sizeof(FILE_POSITION_INFORMATION)) {
277                 Status = STATUS_BUFFER_OVERFLOW;
278                 _SEH2_LEAVE;
279             }
280 
281             FilePositionInformation = (PFILE_POSITION_INFORMATION) Buffer;
282             FilePositionInformation->CurrentByteOffset =
283                 FileObject->CurrentByteOffset;
284 
285             Irp->IoStatus.Information = sizeof(FILE_POSITION_INFORMATION);
286             Status = STATUS_SUCCESS;
287         }
288         break;
289 
290         case FileAllInformation:
291         {
292             PFILE_ALL_INFORMATION       FileAllInformation;
293             PFILE_BASIC_INFORMATION     FileBasicInformation;
294             PFILE_STANDARD_INFORMATION  FSI;
295             PFILE_INTERNAL_INFORMATION  FileInternalInformation;
296             PFILE_EA_INFORMATION        FileEaInformation;
297             PFILE_POSITION_INFORMATION  FilePositionInformation;
298             PFILE_NAME_INFORMATION      FileNameInformation;
299 
300             if (Length < sizeof(FILE_ALL_INFORMATION)) {
301                 Status = STATUS_BUFFER_OVERFLOW;
302                 _SEH2_LEAVE;
303             }
304 
305             FileAllInformation = (PFILE_ALL_INFORMATION) Buffer;
306 
307             FileBasicInformation =
308                 &FileAllInformation->BasicInformation;
309 
310             FSI =
311                 &FileAllInformation->StandardInformation;
312 
313             FileInternalInformation =
314                 &FileAllInformation->InternalInformation;
315 
316             FileEaInformation =
317                 &FileAllInformation->EaInformation;
318 
319             FilePositionInformation =
320                 &FileAllInformation->PositionInformation;
321 
322             FileNameInformation =
323                 &FileAllInformation->NameInformation;
324 
325             FileBasicInformation->CreationTime = Mcb->CreationTime;
326             FileBasicInformation->LastAccessTime = Mcb->LastAccessTime;
327             FileBasicInformation->LastWriteTime = Mcb->LastWriteTime;
328             FileBasicInformation->ChangeTime = Mcb->ChangeTime;
329 
330             FileBasicInformation->FileAttributes = Mcb->FileAttr;
331             if (IsMcbSymLink(Mcb) && IsFileDeleted(Mcb->Target)) {
332                 ClearFlag(FileBasicInformation->FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
333             }
334             if (FileBasicInformation->FileAttributes == 0) {
335                 FileBasicInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL;
336             }
337 
338             FSI->NumberOfLinks = Mcb->Inode.i_nlink;
339 
340             if (IsVcbReadOnly(Fcb->Vcb))
341                 FSI->DeletePending = FALSE;
342             else
343                 FSI->DeletePending = IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING);
344 
345             if (IsLinkInvalid(Mcb)) {
346                 FSI->Directory = FALSE;
347                 FSI->AllocationSize.QuadPart = 0;
348                 FSI->EndOfFile.QuadPart = 0;
349             } else if (IsDirectory(Fcb)) {
350                 FSI->Directory = TRUE;
351                 FSI->AllocationSize.QuadPart = 0;
352                 FSI->EndOfFile.QuadPart = 0;
353             } else {
354                 FSI->Directory = FALSE;
355                 FSI->AllocationSize = Fcb->Header.AllocationSize;
356                 FSI->EndOfFile = Fcb->Header.FileSize;
357             }
358 
359             // The "inode number"
360             FileInternalInformation->IndexNumber.QuadPart = (LONGLONG)Mcb->Inode.i_ino;
361 
362             // Romfs doesn't have any extended attributes
363             FileEaInformation->EaSize = 0;
364 
365             FilePositionInformation->CurrentByteOffset =
366                 FileObject->CurrentByteOffset;
367 
368             FileNameInformation->FileNameLength = Mcb->ShortName.Length;
369 
370             if (Length < sizeof(FILE_ALL_INFORMATION) +
371                     Mcb->ShortName.Length - sizeof(WCHAR)) {
372                 Irp->IoStatus.Information = sizeof(FILE_ALL_INFORMATION);
373                 Status = STATUS_BUFFER_OVERFLOW;
374                 RtlCopyMemory(
375                     FileNameInformation->FileName,
376                     Mcb->ShortName.Buffer,
377                     Length - FIELD_OFFSET(FILE_ALL_INFORMATION,
378                                           NameInformation.FileName)
379                 );
380                 _SEH2_LEAVE;
381             }
382 
383             RtlCopyMemory(
384                 FileNameInformation->FileName,
385                 Mcb->ShortName.Buffer,
386                 Mcb->ShortName.Length
387             );
388 
389             Irp->IoStatus.Information = sizeof(FILE_ALL_INFORMATION) +
390                                         Mcb->ShortName.Length - sizeof(WCHAR);
391 #if 0
392             sizeof(FILE_ACCESS_INFORMATION) -
393             sizeof(FILE_MODE_INFORMATION) -
394             sizeof(FILE_ALIGNMENT_INFORMATION);
395 #endif
396 
397             Status = STATUS_SUCCESS;
398         }
399         break;
400 
401         /*
402         case FileAlternateNameInformation:
403         {
404             // TODO: Handle FileAlternateNameInformation
405 
406             // Here we would like to use RtlGenerate8dot3Name but I don't
407             // know how to use the argument PGENERATE_NAME_CONTEXT
408         }
409         */
410 
411         case FileNetworkOpenInformation:
412         {
413             PFILE_NETWORK_OPEN_INFORMATION PFNOI;
414 
415             if (Length < sizeof(FILE_NETWORK_OPEN_INFORMATION)) {
416                 Status = STATUS_BUFFER_OVERFLOW;
417                 _SEH2_LEAVE;
418             }
419 
420             PFNOI = (PFILE_NETWORK_OPEN_INFORMATION) Buffer;
421 
422             PFNOI->FileAttributes = Mcb->FileAttr;
423             if (IsLinkInvalid(Mcb)) {
424                 ClearFlag(PFNOI->FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
425                 PFNOI->AllocationSize.QuadPart = 0;
426                 PFNOI->EndOfFile.QuadPart = 0;
427             } else if (IsDirectory(Fcb)) {
428                 PFNOI->AllocationSize.QuadPart = 0;
429                 PFNOI->EndOfFile.QuadPart = 0;
430             } else {
431                 PFNOI->AllocationSize = Fcb->Header.AllocationSize;
432                 PFNOI->EndOfFile      = Fcb->Header.FileSize;
433             }
434 
435             if (PFNOI->FileAttributes == 0) {
436                 PFNOI->FileAttributes = FILE_ATTRIBUTE_NORMAL;
437             }
438 
439             PFNOI->CreationTime   = Mcb->CreationTime;
440             PFNOI->LastAccessTime = Mcb->LastAccessTime;
441             PFNOI->LastWriteTime  = Mcb->LastWriteTime;
442             PFNOI->ChangeTime     = Mcb->ChangeTime;
443 
444 
445             Irp->IoStatus.Information =
446                 sizeof(FILE_NETWORK_OPEN_INFORMATION);
447             Status = STATUS_SUCCESS;
448         }
449         break;
450 
451 #if (_WIN32_WINNT >= 0x0500)
452 
453         case FileAttributeTagInformation:
454         {
455             PFILE_ATTRIBUTE_TAG_INFORMATION FATI;
456 
457             if (Length < sizeof(FILE_ATTRIBUTE_TAG_INFORMATION)) {
458                 Status = STATUS_BUFFER_OVERFLOW;
459                 _SEH2_LEAVE;
460             }
461 
462             FATI = (PFILE_ATTRIBUTE_TAG_INFORMATION) Buffer;
463             FATI->FileAttributes = Mcb->FileAttr;
464             if (IsLinkInvalid(Mcb)) {
465                 ClearFlag(FATI->FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
466             }
467             if (FATI->FileAttributes == 0) {
468                 FATI->FileAttributes = FILE_ATTRIBUTE_NORMAL;
469             }
470             FATI->ReparseTag = IO_REPARSE_TAG_RESERVED_ZERO;
471             Irp->IoStatus.Information = sizeof(FILE_ATTRIBUTE_TAG_INFORMATION);
472             Status = STATUS_SUCCESS;
473         }
474         break;
475 #endif // (_WIN32_WINNT >= 0x0500)
476 
477         case FileStreamInformation:
478             Status = STATUS_INVALID_PARAMETER;
479             break;
480 
481         default:
482             DEBUG(DL_WRN, ( "Ext2QueryInformation: invalid class: %d\n",
483                             FileInformationClass));
484             Status = STATUS_INVALID_PARAMETER; /* STATUS_INVALID_INFO_CLASS; */
485             break;
486         }
487 
488     } _SEH2_FINALLY {
489 
490         if (FcbResourceAcquired) {
491             ExReleaseResourceLite(&Fcb->MainResource);
492         }
493 
494         if (!IrpContext->ExceptionInProgress) {
495             if (Status == STATUS_PENDING ||
496                     Status == STATUS_CANT_WAIT) {
497                 Status = Ext2QueueRequest(IrpContext);
498             } else {
499                 Ext2CompleteIrpContext(IrpContext,  Status);
500             }
501         }
502     } _SEH2_END;
503 
504     return Status;
505 }
506 
507 
508 NTSTATUS
509 Ext2SetFileInformation (IN PEXT2_IRP_CONTEXT IrpContext)
510 {
511     PDEVICE_OBJECT          DeviceObject;
512     NTSTATUS                Status = STATUS_UNSUCCESSFUL;
513     PEXT2_VCB               Vcb = NULL;
514     PFILE_OBJECT            FileObject = NULL;
515     PEXT2_FCB               Fcb = NULL;
516     PEXT2_CCB               Ccb = NULL;
517     PEXT2_MCB               Mcb = NULL;
518     PIRP                    Irp = NULL;
519     PIO_STACK_LOCATION      IoStackLocation = NULL;
520     FILE_INFORMATION_CLASS  FileInformationClass;
521 
522     ULONG                   NotifyFilter = 0;
523 
524     ULONG                   Length;
525     PVOID                   Buffer;
526 
527     BOOLEAN                 FcbMainResourceAcquired = FALSE;
528     BOOLEAN                 FcbPagingIoResourceAcquired = FALSE;
529 
530     _SEH2_TRY {
531 
532         ASSERT(IrpContext != NULL);
533 
534         ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
535                (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
536         DeviceObject = IrpContext->DeviceObject;
537 
538         //
539         // This request is not allowed on the main device object
540         //
541         if (IsExt2FsDevice(DeviceObject)) {
542             Status = STATUS_INVALID_DEVICE_REQUEST;
543             _SEH2_LEAVE;
544         }
545 
546         /* check io stack location of irp stack */
547         Irp = IrpContext->Irp;
548         IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
549         FileInformationClass =
550             IoStackLocation->Parameters.SetFile.FileInformationClass;
551         Length = IoStackLocation->Parameters.SetFile.Length;
552         Buffer = Irp->AssociatedIrp.SystemBuffer;
553 
554         /* check Vcb */
555         Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
556         ASSERT(Vcb != NULL);
557         ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
558                (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
559         if (!IsMounted(Vcb)) {
560             Status = STATUS_INVALID_DEVICE_REQUEST;
561             _SEH2_LEAVE;
562         }
563 
564         if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
565             Status = STATUS_ACCESS_DENIED;
566             _SEH2_LEAVE;
567         }
568 
569         FileObject = IrpContext->FileObject;
570         Fcb = (PEXT2_FCB) FileObject->FsContext;
571 
572         // This request is issued to volumes, just return success
573         if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
574             Status = STATUS_SUCCESS;
575             _SEH2_LEAVE;
576         }
577         ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
578                (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
579 
580         if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
581             Status = STATUS_FILE_DELETED;
582             _SEH2_LEAVE;
583         }
584 
585         Ccb = (PEXT2_CCB) FileObject->FsContext2;
586         ASSERT(Ccb != NULL);
587         ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
588                (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
589         Mcb = Ccb->SymLink;
590         if (Mcb) {
591             if (IsFlagOn(Mcb->Flags, MCB_FILE_DELETED)) {
592                 Status = STATUS_FILE_DELETED;
593                 _SEH2_LEAVE;
594             }
595         } else {
596             Mcb = Fcb->Mcb;
597         }
598 
599         if (FileInformationClass != FilePositionInformation) {
600             if (IsVcbReadOnly(Vcb)) {
601                 Status = STATUS_MEDIA_WRITE_PROTECTED;
602                 _SEH2_LEAVE;
603             }
604             if (!Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanWrite)) {
605                 Status = STATUS_ACCESS_DENIED;
606                 _SEH2_LEAVE;
607             }
608         }
609 
610         if ( !IsDirectory(Fcb) && !FlagOn(Fcb->Flags, FCB_PAGE_FILE) &&
611                 ((FileInformationClass == FileEndOfFileInformation) ||
612                  (FileInformationClass == FileValidDataLengthInformation) ||
613                  (FileInformationClass == FileAllocationInformation))) {
614 
615             Status = FsRtlCheckOplock( &Fcb->Oplock,
616                                        Irp,
617                                        IrpContext,
618                                        NULL,
619                                        NULL );
620 
621             if (Status != STATUS_SUCCESS) {
622                 _SEH2_LEAVE;
623             }
624 
625             //
626             //  Set the flag indicating if Fast I/O is possible
627             //
628 
629             Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);
630         }
631 
632         /* for renaming or set link, we must not grab any Fcb locks,
633            and later we will get Dcb or Fcb resources exclusively.  */
634         if (!IsFlagOn(Fcb->Flags, FCB_PAGE_FILE) &&
635             FileInformationClass != FileRenameInformation &&
636             FileInformationClass != FileLinkInformation) {
637 
638             if (!ExAcquireResourceExclusiveLite(
639                         &Fcb->MainResource,
640                         IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
641                 Status = STATUS_PENDING;
642                 _SEH2_LEAVE;
643             }
644 
645             FcbMainResourceAcquired = TRUE;
646 
647             if ( FileInformationClass == FileAllocationInformation ||
648                  FileInformationClass == FileEndOfFileInformation ||
649                  FileInformationClass == FileValidDataLengthInformation) {
650 
651                 if (!ExAcquireResourceExclusiveLite(
652                             &Fcb->PagingIoResource,
653                             IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
654                     Status = STATUS_PENDING;
655                     DbgBreak();
656                     _SEH2_LEAVE;
657                 }
658                 FcbPagingIoResourceAcquired = TRUE;
659             }
660         }
661 
662         switch (FileInformationClass) {
663 
664         case FileBasicInformation:
665         {
666             PFILE_BASIC_INFORMATION FBI = (PFILE_BASIC_INFORMATION) Buffer;
667             struct inode *Inode = &Mcb->Inode;
668 
669             if (FBI->CreationTime.QuadPart != 0 && FBI->CreationTime.QuadPart != -1) {
670                 Inode->i_ctime = Ext2LinuxTime(FBI->CreationTime);
671                 Mcb->CreationTime = Ext2NtTime(Inode->i_ctime);
672                 NotifyFilter |= FILE_NOTIFY_CHANGE_CREATION;
673             }
674 
675             if (FBI->LastAccessTime.QuadPart != 0 && FBI->LastAccessTime.QuadPart != -1) {
676                 Inode->i_atime = Ext2LinuxTime(FBI->LastAccessTime);
677                 Mcb->LastAccessTime = Ext2NtTime(Inode->i_atime);
678                 NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
679             }
680 
681             if (FBI->LastWriteTime.QuadPart != 0 && FBI->LastWriteTime.QuadPart != -1) {
682                 Inode->i_mtime = Ext2LinuxTime(FBI->LastWriteTime);
683                 Mcb->LastWriteTime = Ext2NtTime(Inode->i_mtime);
684                 NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
685                 SetFlag(Ccb->Flags, CCB_LAST_WRITE_UPDATED);
686             }
687 
688             if (FBI->ChangeTime.QuadPart !=0 && FBI->ChangeTime.QuadPart != -1) {
689                 Mcb->ChangeTime = FBI->ChangeTime;
690             }
691 
692             if (FBI->FileAttributes != 0) {
693 
694                 BOOLEAN bIsDirectory = IsDirectory(Fcb);
695                 NotifyFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
696 
697                 if (IsFlagOn(FBI->FileAttributes, FILE_ATTRIBUTE_READONLY)) {
698                     Ext2SetOwnerReadOnly(Inode->i_mode);
699                 } else {
700                     Ext2SetOwnerWritable(Inode->i_mode);
701                 }
702 
703                 if (FBI->FileAttributes & FILE_ATTRIBUTE_TEMPORARY) {
704                     SetFlag(FileObject->Flags, FO_TEMPORARY_FILE);
705                 } else {
706                     ClearFlag(FileObject->Flags, FO_TEMPORARY_FILE);
707                 }
708 
709                 Mcb->FileAttr = FBI->FileAttributes;
710                 if (bIsDirectory) {
711                     SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY);
712                     ClearFlag(Mcb->FileAttr, FILE_ATTRIBUTE_NORMAL);
713                 }
714             }
715 
716             if (NotifyFilter != 0) {
717                 if (Ext2SaveInode(IrpContext, Vcb, Inode)) {
718                     Status = STATUS_SUCCESS;
719                 }
720             }
721 
722             ClearFlag(NotifyFilter, FILE_NOTIFY_CHANGE_LAST_ACCESS);
723             Status = STATUS_SUCCESS;
724         }
725 
726         break;
727 
728         case FileAllocationInformation:
729         {
730             PFILE_ALLOCATION_INFORMATION FAI = (PFILE_ALLOCATION_INFORMATION)Buffer;
731             LARGE_INTEGER  AllocationSize;
732 
733             if (IsMcbDirectory(Mcb) || IsMcbSpecialFile(Mcb)) {
734                 Status = STATUS_INVALID_DEVICE_REQUEST;
735                 _SEH2_LEAVE;
736             } else {
737                 Status = STATUS_SUCCESS;
738             }
739 
740             /* set Mcb to it's target */
741             if (IsMcbSymLink(Mcb)) {
742                 ASSERT(Fcb->Mcb == Mcb->Target);
743             }
744             Mcb = Fcb->Mcb;
745 
746             /* get user specified allocationsize aligned with BLOCK_SIZE */
747             AllocationSize.QuadPart = CEILING_ALIGNED(ULONGLONG,
748                                       (ULONGLONG)FAI->AllocationSize.QuadPart,
749                                       (ULONGLONG)BLOCK_SIZE);
750 
751             if (AllocationSize.QuadPart > Fcb->Header.AllocationSize.QuadPart) {
752 
753                 Status = Ext2ExpandFile(IrpContext, Vcb, Mcb, &AllocationSize);
754                 Fcb->Header.AllocationSize = AllocationSize;
755                 NotifyFilter = FILE_NOTIFY_CHANGE_SIZE;
756                 SetLongFlag(Fcb->Flags, FCB_ALLOC_IN_SETINFO);
757 
758             } else if (AllocationSize.QuadPart < Fcb->Header.AllocationSize.QuadPart) {
759 
760                 if (MmCanFileBeTruncated(&(Fcb->SectionObject), &AllocationSize))  {
761 
762                     /* truncate file blocks */
763                     Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &AllocationSize);
764 
765                     if (NT_SUCCESS(Status)) {
766                         ClearLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE);
767                     }
768 
769                     NotifyFilter = FILE_NOTIFY_CHANGE_SIZE;
770                     Fcb->Header.AllocationSize.QuadPart = AllocationSize.QuadPart;
771                     if (Mcb->Inode.i_size > (loff_t)AllocationSize.QuadPart) {
772                         Mcb->Inode.i_size = AllocationSize.QuadPart;
773                     }
774                     Fcb->Header.FileSize.QuadPart = Mcb->Inode.i_size;
775                     if (Fcb->Header.ValidDataLength.QuadPart > Fcb->Header.FileSize.QuadPart) {
776                         Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
777                     }
778 
779                 } else {
780 
781                     Status = STATUS_USER_MAPPED_FILE;
782                     DbgBreak();
783                     _SEH2_LEAVE;
784                 }
785             }
786 
787             if (NotifyFilter) {
788 
789                 SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
790                 SetLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
791                 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
792                 if (CcIsFileCached(FileObject)) {
793                     CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
794                 }
795             }
796 
797             DEBUG(DL_IO, ("Ext2SetInformation: %wZ NewSize=%I64xh AllocationSize=%I64xh "
798                           "FileSize=%I64xh VDL=%I64xh i_size=%I64xh status = %xh\n",
799                           &Fcb->Mcb->ShortName, AllocationSize.QuadPart,
800                           Fcb->Header.AllocationSize.QuadPart,
801                           Fcb->Header.FileSize.QuadPart, Fcb->Header.ValidDataLength.QuadPart,
802                           Mcb->Inode.i_size, Status));
803         }
804 
805         break;
806 
807         case FileEndOfFileInformation:
808         {
809             PFILE_END_OF_FILE_INFORMATION FEOFI = (PFILE_END_OF_FILE_INFORMATION) Buffer;
810             LARGE_INTEGER NewSize, OldSize, EndOfFile;
811 
812             if (IsMcbDirectory(Mcb) || IsMcbSpecialFile(Mcb)) {
813                 Status = STATUS_INVALID_DEVICE_REQUEST;
814                 _SEH2_LEAVE;
815             } else {
816                 Status = STATUS_SUCCESS;
817             }
818 
819             /* set Mcb to it's target */
820             if (IsMcbSymLink(Mcb)) {
821                 ASSERT(Fcb->Mcb == Mcb->Target);
822             }
823             Mcb = Fcb->Mcb;
824 
825             OldSize = Fcb->Header.AllocationSize;
826             EndOfFile = FEOFI->EndOfFile;
827 
828             if (IoStackLocation->Parameters.SetFile.AdvanceOnly) {
829 
830                 if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
831                     _SEH2_LEAVE;
832                 }
833 
834                 if (EndOfFile.QuadPart > Fcb->Header.FileSize.QuadPart) {
835                     EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart;
836                 }
837 
838                 if (EndOfFile.QuadPart > Fcb->Header.ValidDataLength.QuadPart) {
839                     Fcb->Header.ValidDataLength.QuadPart = EndOfFile.QuadPart;
840                     NotifyFilter = FILE_NOTIFY_CHANGE_SIZE;
841                 }
842 
843                 _SEH2_LEAVE;
844             }
845 
846             NewSize.QuadPart = CEILING_ALIGNED(ULONGLONG,
847                                                EndOfFile.QuadPart, BLOCK_SIZE);
848 
849             if (NewSize.QuadPart > OldSize.QuadPart) {
850 
851                 Fcb->Header.AllocationSize = NewSize;
852                 Status = Ext2ExpandFile(
853                                  IrpContext,
854                                  Vcb,
855                                  Mcb,
856                                  &(Fcb->Header.AllocationSize)
857                              );
858                 NotifyFilter = FILE_NOTIFY_CHANGE_SIZE;
859                 SetLongFlag(Fcb->Flags, FCB_ALLOC_IN_SETINFO);
860 
861 
862             } else if (NewSize.QuadPart == OldSize.QuadPart) {
863 
864                 /* we are luck ;) */
865                 Status = STATUS_SUCCESS;
866 
867             } else {
868 
869                 /* don't truncate file data since it's still being written */
870                 if (IsFlagOn(Fcb->Flags, FCB_ALLOC_IN_WRITE)) {
871 
872                     Status = STATUS_SUCCESS;
873 
874                 } else {
875 
876                     if (!MmCanFileBeTruncated(&(Fcb->SectionObject), &NewSize)) {
877                         Status = STATUS_USER_MAPPED_FILE;
878                         DbgBreak();
879                         _SEH2_LEAVE;
880                     }
881 
882                     /* truncate file blocks */
883                     Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &NewSize);
884 
885                     /* restore original file size */
886                     if (NT_SUCCESS(Status)) {
887                         ClearLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE);
888                     }
889 
890                     /* update file allocateion size */
891                     Fcb->Header.AllocationSize.QuadPart = NewSize.QuadPart;
892 
893                     ASSERT((loff_t)NewSize.QuadPart >= Mcb->Inode.i_size);
894                     if ((loff_t)Fcb->Header.FileSize.QuadPart < Mcb->Inode.i_size) {
895                         Fcb->Header.FileSize.QuadPart = Mcb->Inode.i_size;
896                     }
897                     if (Fcb->Header.ValidDataLength.QuadPart > Fcb->Header.FileSize.QuadPart) {
898                         Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
899                     }
900 
901                     SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
902                     SetLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
903                 }
904 
905                 NotifyFilter = FILE_NOTIFY_CHANGE_SIZE;
906             }
907 
908             if (NT_SUCCESS(Status)) {
909 
910                 Fcb->Header.FileSize.QuadPart = Mcb->Inode.i_size = EndOfFile.QuadPart;
911                 if (CcIsFileCached(FileObject)) {
912                     CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
913                 }
914 
915                 if (Fcb->Header.FileSize.QuadPart >= 0x80000000 &&
916                         !IsFlagOn(SUPER_BLOCK->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
917                     SetFlag(SUPER_BLOCK->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_LARGE_FILE);
918                     Ext2SaveSuper(IrpContext, Vcb);
919                 }
920 
921                 SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
922                 SetLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
923                 NotifyFilter = FILE_NOTIFY_CHANGE_SIZE;
924             }
925 
926 
927             Ext2SaveInode( IrpContext, Vcb, &Mcb->Inode);
928 
929             DEBUG(DL_IO, ("Ext2SetInformation: FileEndOfFileInformation %wZ EndofFile=%I64xh "
930                           "AllocatieonSize=%I64xh FileSize=%I64xh VDL=%I64xh i_size=%I64xh status = %xh\n",
931                           &Fcb->Mcb->ShortName, EndOfFile.QuadPart, Fcb->Header.AllocationSize.QuadPart,
932                           Fcb->Header.FileSize.QuadPart, Fcb->Header.ValidDataLength.QuadPart,
933                           Mcb->Inode.i_size, Status));
934         }
935 
936         break;
937 
938         case FileValidDataLengthInformation:
939         {
940             PFILE_VALID_DATA_LENGTH_INFORMATION FVDL = (PFILE_VALID_DATA_LENGTH_INFORMATION) Buffer;
941             LARGE_INTEGER NewVDL;
942 
943             if (IsMcbDirectory(Mcb) || IsMcbSpecialFile(Mcb)) {
944                 Status = STATUS_INVALID_DEVICE_REQUEST;
945                 _SEH2_LEAVE;
946             } else {
947                 Status = STATUS_SUCCESS;
948             }
949 
950             NewVDL = FVDL->ValidDataLength;
951             if ((NewVDL.QuadPart < Fcb->Header.ValidDataLength.QuadPart)) {
952                 Status = STATUS_INVALID_PARAMETER;
953                 _SEH2_LEAVE;
954             }
955             if (NewVDL.QuadPart > Fcb->Header.FileSize.QuadPart)
956                 NewVDL = Fcb->Header.FileSize;
957 
958             if (!MmCanFileBeTruncated(FileObject->SectionObjectPointer,
959                                       &NewVDL)) {
960                 Status = STATUS_USER_MAPPED_FILE;
961                 _SEH2_LEAVE;
962             }
963 
964             Fcb->Header.ValidDataLength = NewVDL;
965             FileObject->Flags |= FO_FILE_MODIFIED;
966             if (CcIsFileCached(FileObject)) {
967                 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
968             }
969         }
970 
971         break;
972 
973         case FileDispositionInformation:
974         {
975             PFILE_DISPOSITION_INFORMATION FDI = (PFILE_DISPOSITION_INFORMATION)Buffer;
976 
977             Status = Ext2SetDispositionInfo(IrpContext, Vcb, Fcb, Ccb, FDI->DeleteFile);
978 
979             DEBUG(DL_INF, ( "Ext2SetInformation: SetDispositionInformation: DeleteFile=%d %wZ status = %xh\n",
980                             FDI->DeleteFile, &Mcb->ShortName, Status));
981         }
982 
983         break;
984 
985         case FileRenameInformation:
986         {
987             Status = Ext2SetRenameInfo(IrpContext, Vcb, Fcb, Ccb);
988         }
989 
990         break;
991 
992 
993         case FileLinkInformation:
994         {
995             Status = Ext2SetLinkInfo(IrpContext, Vcb, Fcb, Ccb);
996         }
997 
998         break;
999 
1000         //
1001         // This is the only set file information request supported on read
1002         // only file systems
1003         //
1004         case FilePositionInformation:
1005         {
1006             PFILE_POSITION_INFORMATION FilePositionInformation;
1007 
1008             if (Length < sizeof(FILE_POSITION_INFORMATION)) {
1009                 Status = STATUS_INVALID_PARAMETER;
1010                 _SEH2_LEAVE;
1011             }
1012 
1013             FilePositionInformation = (PFILE_POSITION_INFORMATION) Buffer;
1014 
1015             if ((FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) &&
1016                     (FilePositionInformation->CurrentByteOffset.LowPart &
1017                      DeviceObject->AlignmentRequirement) ) {
1018                 Status = STATUS_INVALID_PARAMETER;
1019                 _SEH2_LEAVE;
1020             }
1021 
1022             FileObject->CurrentByteOffset =
1023                 FilePositionInformation->CurrentByteOffset;
1024 
1025             Status = STATUS_SUCCESS;
1026             _SEH2_LEAVE;
1027         }
1028 
1029         break;
1030 
1031         default:
1032             DEBUG(DL_WRN, ( "Ext2SetInformation: invalid class: %d\n",
1033                             FileInformationClass));
1034             Status = STATUS_INVALID_PARAMETER;/* STATUS_INVALID_INFO_CLASS; */
1035         }
1036 
1037     } _SEH2_FINALLY {
1038 
1039         if (FcbPagingIoResourceAcquired) {
1040             ExReleaseResourceLite(&Fcb->PagingIoResource);
1041         }
1042 
1043         if (NT_SUCCESS(Status) && (NotifyFilter != 0)) {
1044             Ext2NotifyReportChange(
1045                 IrpContext,
1046                 Vcb,
1047                 Mcb,
1048                 NotifyFilter,
1049                 FILE_ACTION_MODIFIED );
1050 
1051         }
1052 
1053         if (FcbMainResourceAcquired) {
1054             ExReleaseResourceLite(&Fcb->MainResource);
1055         }
1056 
1057         if (!IrpContext->ExceptionInProgress) {
1058             if (Status == STATUS_PENDING ||
1059                     Status == STATUS_CANT_WAIT ) {
1060                 DbgBreak();
1061                 Status = Ext2QueueRequest(IrpContext);
1062             } else {
1063                 Ext2CompleteIrpContext(IrpContext,  Status);
1064             }
1065         }
1066     } _SEH2_END;
1067 
1068     return Status;
1069 }
1070 
1071 ULONG
1072 Ext2TotalBlocks(
1073     PEXT2_VCB         Vcb,
1074     PLARGE_INTEGER    Size,
1075     PULONG            pMeta
1076 )
1077 {
1078     ULONG Blocks, Meta =0, Remain;
1079 
1080     Blocks = (ULONG)((Size->QuadPart + BLOCK_SIZE - 1) >> BLOCK_BITS);
1081     if (Blocks <= EXT2_NDIR_BLOCKS)
1082         goto errorout;
1083     Blocks -= EXT2_NDIR_BLOCKS;
1084 
1085     Meta += 1;
1086     if (Blocks <= Vcb->max_blocks_per_layer[1]) {
1087         goto errorout;
1088     }
1089     Blocks -= Vcb->max_blocks_per_layer[1];
1090 
1091 level2:
1092 
1093     if (Blocks <= Vcb->max_blocks_per_layer[2]) {
1094         Meta += 1 + ((Blocks + BLOCK_SIZE/4 - 1) >> (BLOCK_BITS - 2));
1095         goto errorout;
1096     }
1097     Meta += 1 + BLOCK_SIZE/4;
1098     Blocks -= Vcb->max_blocks_per_layer[2];
1099 
1100     if (Blocks > Vcb->max_blocks_per_layer[3]) {
1101         Blocks  = Vcb->max_blocks_per_layer[3];
1102     }
1103 
1104     ASSERT(Vcb->max_blocks_per_layer[2]);
1105     Remain = Blocks % Vcb->max_blocks_per_layer[2];
1106     Blocks = Blocks / Vcb->max_blocks_per_layer[2];
1107     Meta += 1 + Blocks * (1 + BLOCK_SIZE/4);
1108     if (Remain) {
1109         Blocks = Remain;
1110         goto level2;
1111     }
1112 
1113 errorout:
1114 
1115     if (pMeta)
1116         *pMeta = Meta;
1117     Blocks = (ULONG)((Size->QuadPart + BLOCK_SIZE - 1) >> BLOCK_BITS);
1118     return (Blocks + Meta);
1119 }
1120 
1121 NTSTATUS
1122 Ext2BlockMap(
1123     IN PEXT2_IRP_CONTEXT    IrpContext,
1124     IN PEXT2_VCB            Vcb,
1125     IN PEXT2_MCB            Mcb,
1126     IN ULONG                Index,
1127     IN BOOLEAN              bAlloc,
1128     OUT PULONG              pBlock,
1129     OUT PULONG              Number
1130 )
1131 {
1132 	NTSTATUS status;
1133 
1134 	if (INODE_HAS_EXTENT(&Mcb->Inode)) {
1135         status = Ext2MapExtent(IrpContext, Vcb, Mcb, Index,
1136                                bAlloc, pBlock, Number );
1137 	} else {
1138         status = Ext2MapIndirect(IrpContext, Vcb, Mcb, Index,
1139                                  bAlloc, pBlock, Number );
1140     }
1141 
1142 	return status;
1143 }
1144 
1145 
1146 NTSTATUS
1147 Ext2ExpandFile(
1148     PEXT2_IRP_CONTEXT IrpContext,
1149     PEXT2_VCB         Vcb,
1150     PEXT2_MCB         Mcb,
1151     PLARGE_INTEGER    Size
1152 )
1153 {
1154     NTSTATUS status = STATUS_SUCCESS;
1155     ULONG    Start = 0;
1156     ULONG    End = 0;
1157 
1158     Start = (ULONG)((Mcb->Inode.i_size + BLOCK_SIZE - 1) >> BLOCK_BITS);
1159     End = (ULONG)((Size->QuadPart + BLOCK_SIZE - 1) >> BLOCK_BITS);
1160 
1161     /* it's a truncate operation, not expanding */
1162     if (Start >= End) {
1163         Size->QuadPart = ((LONGLONG) Start) << BLOCK_BITS;
1164         return STATUS_SUCCESS;
1165     }
1166 
1167 	/* ignore special files */
1168 	if (IsMcbSpecialFile(Mcb)) {
1169         return STATUS_INVALID_DEVICE_REQUEST;
1170     }
1171 
1172 	/* expandind file extents */
1173     if (INODE_HAS_EXTENT(&Mcb->Inode)) {
1174 
1175         status = Ext2ExpandExtent(IrpContext, Vcb, Mcb, Start, End, Size);
1176 
1177     } else {
1178 
1179         BOOLEAN do_expand;
1180 
1181 #if EXT2_PRE_ALLOCATION_SUPPORT
1182         do_expand = TRUE;
1183 #else
1184         do_expand = (IrpContext->MajorFunction == IRP_MJ_WRITE) ||
1185                     IsMcbDirectory(Mcb);
1186 #endif
1187         if (!do_expand)
1188             goto errorout;
1189 
1190         status = Ext2ExpandIndirect(IrpContext, Vcb, Mcb, Start, End, Size);
1191     }
1192 
1193 errorout:
1194     return status;
1195 }
1196 
1197 
1198 NTSTATUS
1199 Ext2TruncateFile(
1200     PEXT2_IRP_CONTEXT IrpContext,
1201     PEXT2_VCB         Vcb,
1202     PEXT2_MCB         Mcb,
1203     PLARGE_INTEGER    Size
1204 )
1205 {
1206     NTSTATUS status = STATUS_SUCCESS;
1207 
1208     if (INODE_HAS_EXTENT(&Mcb->Inode)) {
1209 		status = Ext2TruncateExtent(IrpContext, Vcb, Mcb, Size);
1210     } else {
1211 		status = Ext2TruncateIndirect(IrpContext, Vcb, Mcb, Size);
1212 	}
1213 
1214     /* check and clear data/meta mcb extents */
1215     if (Size->QuadPart == 0) {
1216 
1217         /* check and remove all data extents */
1218         if (Ext2ListExtents(&Mcb->Extents)) {
1219             DbgBreak();
1220         }
1221         Ext2ClearAllExtents(&Mcb->Extents);
1222         /* check and remove all meta extents */
1223         if (Ext2ListExtents(&Mcb->MetaExts)) {
1224             DbgBreak();
1225         }
1226         Ext2ClearAllExtents(&Mcb->MetaExts);
1227         ClearLongFlag(Mcb->Flags, MCB_ZONE_INITED);
1228     }
1229 
1230     return status;
1231 }
1232 
1233 NTSTATUS
1234 Ext2IsFileRemovable(
1235     IN PEXT2_IRP_CONTEXT    IrpContext,
1236     IN PEXT2_VCB            Vcb,
1237     IN PEXT2_FCB            Fcb,
1238     IN PEXT2_CCB            Ccb
1239 )
1240 {
1241     PEXT2_MCB Mcb = Fcb->Mcb;
1242 
1243     if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
1244         return STATUS_CANNOT_DELETE;
1245     }
1246 
1247     if (IsMcbDirectory(Mcb)) {
1248         if (!Ext2IsDirectoryEmpty(IrpContext, Vcb, Mcb)) {
1249             return STATUS_DIRECTORY_NOT_EMPTY;
1250         }
1251     }
1252 
1253     if (!MmFlushImageSection(&Fcb->SectionObject,
1254                              MmFlushForDelete )) {
1255         return STATUS_CANNOT_DELETE;
1256     }
1257 
1258     if (IsMcbDirectory(Mcb)) {
1259         FsRtlNotifyFullChangeDirectory(
1260             Vcb->NotifySync,
1261             &Vcb->NotifyList,
1262             Ccb,
1263             NULL,
1264             FALSE,
1265             FALSE,
1266             0,
1267             NULL,
1268             NULL,
1269             NULL
1270         );
1271     }
1272 
1273     return STATUS_SUCCESS;
1274 }
1275 
1276 NTSTATUS
1277 Ext2SetDispositionInfo(
1278     PEXT2_IRP_CONTEXT IrpContext,
1279     PEXT2_VCB Vcb,
1280     PEXT2_FCB Fcb,
1281     PEXT2_CCB Ccb,
1282     BOOLEAN bDelete
1283 )
1284 {
1285     PIRP    Irp = IrpContext->Irp;
1286     PIO_STACK_LOCATION IrpSp;
1287     NTSTATUS status = STATUS_SUCCESS;
1288     PEXT2_MCB  Mcb = Fcb->Mcb;
1289 
1290     IrpSp = IoGetCurrentIrpStackLocation(Irp);
1291 
1292     DEBUG(DL_INF, ( "Ext2SetDispositionInfo: bDelete=%x\n", bDelete));
1293 
1294     if (bDelete) {
1295 
1296         DEBUG(DL_INF, ( "Ext2SetDispositionInformation: Removing %wZ.\n",
1297                         &Mcb->FullName));
1298 
1299         if (Ccb->SymLink || IsInodeSymLink(&Mcb->Inode)) {
1300             /* always allow deleting on symlinks */
1301         } else {
1302             status = Ext2IsFileRemovable(IrpContext, Vcb, Fcb, Ccb);
1303         }
1304 
1305         if (NT_SUCCESS(status)) {
1306             SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING);
1307             IrpSp->FileObject->DeletePending = TRUE;
1308         }
1309 
1310     } else {
1311 
1312         ClearLongFlag(Fcb->Flags, FCB_DELETE_PENDING);
1313         IrpSp->FileObject->DeletePending = FALSE;
1314     }
1315 
1316     return status;
1317 }
1318 
1319 NTSTATUS
1320 Ext2SetRenameInfo(
1321     PEXT2_IRP_CONTEXT IrpContext,
1322     PEXT2_VCB         Vcb,
1323     PEXT2_FCB         Fcb,
1324     PEXT2_CCB         Ccb
1325 )
1326 {
1327     PEXT2_MCB               Mcb = Fcb->Mcb;
1328 
1329     PEXT2_FCB               TargetDcb = NULL;   /* Dcb of target directory */
1330     PEXT2_MCB               TargetMcb = NULL;
1331     PEXT2_FCB               ParentDcb = NULL;   /* Dcb of it's current parent */
1332     PEXT2_MCB               ParentMcb = NULL;
1333 
1334     PEXT2_FCB               ExistingFcb = NULL; /* Target file Fcb if it exists*/
1335     PEXT2_MCB               ExistingMcb = NULL;
1336 
1337     UNICODE_STRING          FileName;
1338 
1339     NTSTATUS                Status;
1340 
1341     PIRP                    Irp;
1342     PIO_STACK_LOCATION      IrpSp;
1343 
1344     PFILE_OBJECT            FileObject;
1345     PFILE_OBJECT            TargetObject;
1346 
1347     struct dentry          *NewEntry = NULL;
1348 
1349     BOOLEAN                 ReplaceIfExists;
1350     BOOLEAN                 bMove = FALSE;
1351     BOOLEAN                 bTargetRemoved = FALSE;
1352 
1353     BOOLEAN                 bFcbLockAcquired = FALSE;
1354 
1355     PFILE_RENAME_INFORMATION    FRI;
1356 
1357     if (Ccb->SymLink) {
1358         Mcb = Ccb->SymLink;
1359     }
1360 
1361     if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
1362         Status = STATUS_INVALID_PARAMETER;
1363         goto errorout;
1364     }
1365 
1366     Irp = IrpContext->Irp;
1367     IrpSp = IoGetCurrentIrpStackLocation(Irp);
1368 
1369     FileObject = IrpSp->FileObject;
1370     TargetObject = IrpSp->Parameters.SetFile.FileObject;
1371     ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists;
1372 
1373     FRI = (PFILE_RENAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
1374 
1375     if (TargetObject == NULL) {
1376 
1377         UNICODE_STRING  NewName;
1378 
1379         NewName.Buffer = FRI->FileName;
1380         NewName.MaximumLength = NewName.Length = (USHORT)FRI->FileNameLength;
1381 
1382         while (NewName.Length > 0 && NewName.Buffer[NewName.Length/2 - 1] == L'\\') {
1383             NewName.Buffer[NewName.Length/2 - 1] = 0;
1384             NewName.Length -= 2;
1385         }
1386 
1387         while (NewName.Length > 0 && NewName.Buffer[NewName.Length/2 - 1] != L'\\') {
1388             NewName.Length -= 2;
1389         }
1390 
1391         NewName.Buffer = (USHORT *)((UCHAR *)NewName.Buffer + NewName.Length);
1392         NewName.Length = (USHORT)(FRI->FileNameLength - NewName.Length);
1393 
1394         FileName = NewName;
1395 
1396         TargetMcb = Mcb->Parent;
1397         if (IsMcbSymLink(TargetMcb)) {
1398             TargetMcb = TargetMcb->Target;
1399             ASSERT(!IsMcbSymLink(TargetMcb));
1400         }
1401 
1402         if (TargetMcb == NULL || FileName.Length >= EXT2_NAME_LEN*2) {
1403             Status = STATUS_OBJECT_NAME_INVALID;
1404             goto errorout;
1405         }
1406 
1407     } else {
1408 
1409         TargetDcb = (PEXT2_FCB)(TargetObject->FsContext);
1410 
1411         if (!TargetDcb || TargetDcb->Vcb != Vcb) {
1412 
1413             DbgBreak();
1414 
1415             Status = STATUS_INVALID_PARAMETER;
1416             goto errorout;
1417         }
1418 
1419         TargetMcb = TargetDcb->Mcb;
1420         FileName = TargetObject->FileName;
1421     }
1422 
1423     if (FsRtlDoesNameContainWildCards(&FileName)) {
1424         Status = STATUS_OBJECT_NAME_INVALID;
1425         goto errorout;
1426     }
1427 
1428     if (TargetMcb->Inode.i_ino == Mcb->Parent->Inode.i_ino) {
1429         if (FsRtlAreNamesEqual( &FileName,
1430                                 &(Mcb->ShortName),
1431                                 FALSE,
1432                                 NULL )) {
1433             Status = STATUS_SUCCESS;
1434             goto errorout;
1435         }
1436     } else {
1437         bMove = TRUE;
1438     }
1439 
1440     if (!bFcbLockAcquired) {
1441         ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
1442         bFcbLockAcquired = TRUE;
1443     }
1444 
1445     TargetDcb = TargetMcb->Fcb;
1446     if (TargetDcb == NULL) {
1447         TargetDcb = Ext2AllocateFcb(Vcb, TargetMcb);
1448     }
1449     if (TargetDcb) {
1450         Ext2ReferXcb(&TargetDcb->ReferenceCount);
1451     }
1452 
1453     ParentMcb = Mcb->Parent;
1454     ParentDcb = ParentMcb->Fcb;
1455 
1456     if ((TargetMcb->Inode.i_ino != ParentMcb->Inode.i_ino)) {
1457 
1458         if (ParentDcb == NULL) {
1459             ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
1460         }
1461     }
1462     if (ParentDcb) {
1463         Ext2ReferXcb(&ParentDcb->ReferenceCount);
1464     }
1465 
1466     if (bFcbLockAcquired) {
1467         ExReleaseResourceLite(&Vcb->FcbLock);
1468         bFcbLockAcquired = FALSE;
1469     }
1470 
1471     if (!TargetDcb || !ParentDcb) {
1472         Status = STATUS_INSUFFICIENT_RESOURCES;
1473         goto errorout;
1474     }
1475 
1476     DEBUG(DL_RES, ("Ext2SetRenameInfo: rename %wZ to %wZ\\%wZ\n",
1477                    &Mcb->FullName, &TargetMcb->FullName, &FileName));
1478 
1479     Status = Ext2LookupFile(
1480                  IrpContext,
1481                  Vcb,
1482                  &FileName,
1483                  TargetMcb,
1484                  &ExistingMcb,
1485                  0
1486              );
1487 
1488     if (NT_SUCCESS(Status) && ExistingMcb != Mcb) {
1489 
1490         if (!ReplaceIfExists) {
1491 
1492             Status = STATUS_OBJECT_NAME_COLLISION;
1493             DEBUG(DL_RES, ("Ext2SetRenameInfo: Target file %wZ exists\n",
1494                            &ExistingMcb->FullName));
1495             goto errorout;
1496 
1497         } else {
1498 
1499             if ( (ExistingFcb = ExistingMcb->Fcb) && !IsMcbSymLink(ExistingMcb) ) {
1500 
1501                 Status = Ext2IsFileRemovable(IrpContext, Vcb, ExistingFcb, Ccb);
1502                 if (!NT_SUCCESS(Status)) {
1503                     DEBUG(DL_REN, ("Ext2SetRenameInfo: Target file %wZ cannot be removed.\n",
1504                                    &ExistingMcb->FullName));
1505                     goto errorout;
1506                 }
1507             }
1508 
1509             Status = Ext2DeleteFile(IrpContext, Vcb, ExistingFcb, ExistingMcb);
1510             if (!NT_SUCCESS(Status)) {
1511                 DEBUG(DL_REN, ("Ext2SetRenameInfo: Failed to delete %wZ with status: %xh.\n",
1512                                &FileName, Status));
1513 
1514                 goto errorout;
1515             }
1516 
1517             bTargetRemoved = TRUE;
1518         }
1519     }
1520 
1521     /* remove directory entry of old name */
1522     Status = Ext2RemoveEntry(IrpContext, Vcb, ParentDcb, Mcb);
1523     if (!NT_SUCCESS(Status)) {
1524         DEBUG(DL_REN, ("Ext2SetRenameInfo: Failed to remove entry %wZ with status %xh.\n",
1525                        &Mcb->FullName, Status));
1526         DbgBreak();
1527         goto errorout;
1528     }
1529 
1530     /* add new entry for new target name */
1531     Status = Ext2AddEntry(IrpContext, Vcb, TargetDcb, &Mcb->Inode, &FileName, &NewEntry);
1532     if (!NT_SUCCESS(Status)) {
1533         DEBUG(DL_REN, ("Ext2SetRenameInfo: Failed to add entry for %wZ with status: %xh.\n",
1534                        &FileName, Status));
1535         Ext2AddEntry(IrpContext, Vcb, ParentDcb, &Mcb->Inode, &Mcb->ShortName, &NewEntry);
1536         goto errorout;
1537     }
1538 
1539     /* correct the inode number in ..  entry */
1540     if (IsMcbDirectory(Mcb)) {
1541         Status = Ext2SetParentEntry(
1542                      IrpContext, Vcb, Fcb,
1543                      ParentMcb->Inode.i_ino,
1544                      TargetMcb->Inode.i_ino );
1545         if (!NT_SUCCESS(Status)) {
1546             DEBUG(DL_REN, ("Ext2SetRenameInfo: Failed to set parent refer of %wZ with %xh.\n",
1547                            &Mcb->FullName, Status));
1548             DbgBreak();
1549             goto errorout;
1550         }
1551     }
1552 
1553     /* Update current dentry from the newly created one. We need keep the original
1554        dentry to assure children's links are valid if current entry is a directory */
1555     if (Mcb->de) {
1556         char *np = Mcb->de->d_name.name;
1557         *(Mcb->de) = *NewEntry;
1558         NewEntry->d_name.name = np;
1559     }
1560 
1561     if (bTargetRemoved) {
1562         Ext2NotifyReportChange(
1563             IrpContext,
1564             Vcb,
1565             ExistingMcb,
1566             (IsMcbDirectory(ExistingMcb) ?
1567              FILE_NOTIFY_CHANGE_DIR_NAME :
1568              FILE_NOTIFY_CHANGE_FILE_NAME ),
1569             FILE_ACTION_REMOVED);
1570     }
1571 
1572     if (NT_SUCCESS(Status)) {
1573 
1574         if (bMove) {
1575             Ext2NotifyReportChange(
1576                 IrpContext,
1577                 Vcb,
1578                 Mcb,
1579                 (IsDirectory(Fcb) ?
1580                  FILE_NOTIFY_CHANGE_DIR_NAME :
1581                  FILE_NOTIFY_CHANGE_FILE_NAME ),
1582                 FILE_ACTION_REMOVED);
1583 
1584         } else {
1585             Ext2NotifyReportChange(
1586                 IrpContext,
1587                 Vcb,
1588                 Mcb,
1589                 (IsDirectory(Fcb) ?
1590                  FILE_NOTIFY_CHANGE_DIR_NAME :
1591                  FILE_NOTIFY_CHANGE_FILE_NAME ),
1592                 FILE_ACTION_RENAMED_OLD_NAME);
1593 
1594         }
1595 
1596         if (TargetMcb->Inode.i_ino != ParentMcb->Inode.i_ino) {
1597             Ext2RemoveMcb(Vcb, Mcb);
1598             Ext2InsertMcb(Vcb, TargetMcb, Mcb);
1599         }
1600 
1601         if (!Ext2BuildName( &Mcb->ShortName,
1602                             &FileName, NULL     )) {
1603             Status = STATUS_INSUFFICIENT_RESOURCES;
1604             goto errorout;
1605         }
1606 
1607         if (!Ext2BuildName( &Mcb->FullName,
1608                             &FileName,
1609                             &TargetMcb->FullName)) {
1610             Status = STATUS_INSUFFICIENT_RESOURCES;
1611             goto errorout;
1612         }
1613 
1614         if (bMove) {
1615             Ext2NotifyReportChange(
1616                 IrpContext,
1617                 Vcb,
1618                 Mcb,
1619                 (IsDirectory(Fcb) ?
1620                  FILE_NOTIFY_CHANGE_DIR_NAME :
1621                  FILE_NOTIFY_CHANGE_FILE_NAME ),
1622                 FILE_ACTION_ADDED);
1623         } else {
1624             Ext2NotifyReportChange(
1625                 IrpContext,
1626                 Vcb,
1627                 Mcb,
1628                 (IsDirectory(Fcb) ?
1629                  FILE_NOTIFY_CHANGE_DIR_NAME :
1630                  FILE_NOTIFY_CHANGE_FILE_NAME ),
1631                 FILE_ACTION_RENAMED_NEW_NAME  );
1632         }
1633     }
1634 
1635 errorout:
1636 
1637     if (bFcbLockAcquired) {
1638         ExReleaseResourceLite(&Vcb->FcbLock);
1639         bFcbLockAcquired = FALSE;
1640     }
1641 
1642     if (NewEntry)
1643         Ext2FreeEntry(NewEntry);
1644 
1645     if (TargetDcb) {
1646         Ext2ReleaseFcb(TargetDcb);
1647     }
1648 
1649     if (ParentDcb) {
1650         Ext2ReleaseFcb(ParentDcb);
1651     }
1652 
1653     if (ExistingMcb)
1654         Ext2DerefMcb(ExistingMcb);
1655 
1656     return Status;
1657 }
1658 
1659 NTSTATUS
1660 Ext2SetLinkInfo(
1661     PEXT2_IRP_CONTEXT IrpContext,
1662     PEXT2_VCB         Vcb,
1663     PEXT2_FCB         Fcb,
1664     PEXT2_CCB         Ccb
1665 )
1666 {
1667     PEXT2_MCB               Mcb = Fcb->Mcb;
1668 
1669     PEXT2_FCB               TargetDcb = NULL;   /* Dcb of target directory */
1670     PEXT2_MCB               TargetMcb = NULL;
1671     PEXT2_FCB               ParentDcb = NULL;   /* Dcb of it's current parent */
1672     PEXT2_MCB               ParentMcb = NULL;
1673 
1674     PEXT2_FCB               ExistingFcb = NULL; /* Target file Fcb if it exists*/
1675     PEXT2_MCB               ExistingMcb = NULL;
1676     PEXT2_MCB               LinkMcb = NULL;     /* Mcb for new hardlink */
1677 
1678     UNICODE_STRING          FileName;
1679 
1680     NTSTATUS                Status;
1681 
1682     PIRP                    Irp;
1683     PIO_STACK_LOCATION      IrpSp;
1684 
1685     PFILE_OBJECT            FileObject;
1686     PFILE_OBJECT            TargetObject;
1687 
1688     BOOLEAN                 ReplaceIfExists;
1689     BOOLEAN                 bTargetRemoved = FALSE;
1690 
1691     BOOLEAN                 bFcbLockAcquired = FALSE;
1692 
1693     PFILE_LINK_INFORMATION  FLI;
1694 
1695     if (Ccb->SymLink) {
1696         Mcb = Ccb->SymLink;
1697     }
1698 
1699     if (IsMcbDirectory(Mcb)) {
1700         Status = STATUS_INVALID_PARAMETER;
1701         goto errorout;
1702     }
1703 
1704     Irp = IrpContext->Irp;
1705     IrpSp = IoGetCurrentIrpStackLocation(Irp);
1706 
1707     FileObject = IrpSp->FileObject;
1708     TargetObject = IrpSp->Parameters.SetFile.FileObject;
1709     ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists;
1710 
1711     FLI = (PFILE_LINK_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
1712 
1713     if (TargetObject == NULL) {
1714 
1715         UNICODE_STRING  NewName;
1716 
1717         NewName.Buffer = FLI->FileName;
1718         NewName.MaximumLength = NewName.Length = (USHORT)FLI->FileNameLength;
1719 
1720         while (NewName.Length > 0 && NewName.Buffer[NewName.Length/2 - 1] == L'\\') {
1721             NewName.Buffer[NewName.Length/2 - 1] = 0;
1722             NewName.Length -= 2;
1723         }
1724 
1725         while (NewName.Length > 0 && NewName.Buffer[NewName.Length/2 - 1] != L'\\') {
1726             NewName.Length -= 2;
1727         }
1728 
1729         NewName.Buffer = (USHORT *)((UCHAR *)NewName.Buffer + NewName.Length);
1730         NewName.Length = (USHORT)(FLI->FileNameLength - NewName.Length);
1731 
1732         FileName = NewName;
1733 
1734         TargetMcb = Mcb->Parent;
1735         if (IsMcbSymLink(TargetMcb)) {
1736             TargetMcb = TargetMcb->Target;
1737             ASSERT(!IsMcbSymLink(TargetMcb));
1738         }
1739 
1740         if (TargetMcb == NULL || FileName.Length >= EXT2_NAME_LEN*2) {
1741             Status = STATUS_OBJECT_NAME_INVALID;
1742             goto errorout;
1743         }
1744 
1745     } else {
1746 
1747         TargetDcb = (PEXT2_FCB)(TargetObject->FsContext);
1748         if (!TargetDcb || TargetDcb->Vcb != Vcb) {
1749             DbgBreak();
1750             Status = STATUS_INVALID_PARAMETER;
1751             goto errorout;
1752         }
1753 
1754         TargetMcb = TargetDcb->Mcb;
1755         FileName = TargetObject->FileName;
1756     }
1757 
1758     if (FsRtlDoesNameContainWildCards(&FileName)) {
1759         Status = STATUS_OBJECT_NAME_INVALID;
1760         goto errorout;
1761     }
1762 
1763     if (TargetMcb->Inode.i_ino == Mcb->Parent->Inode.i_ino) {
1764         if (FsRtlAreNamesEqual( &FileName,
1765                                 &(Mcb->ShortName),
1766                                 FALSE,
1767                                 NULL )) {
1768             Status = STATUS_SUCCESS;
1769             goto errorout;
1770         }
1771     }
1772 
1773     ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
1774     bFcbLockAcquired = TRUE;
1775 
1776     TargetDcb = TargetMcb->Fcb;
1777     if (TargetDcb == NULL) {
1778         TargetDcb = Ext2AllocateFcb(Vcb, TargetMcb);
1779     }
1780     if (TargetDcb) {
1781         Ext2ReferXcb(&TargetDcb->ReferenceCount);
1782     }
1783 
1784     ParentMcb = Mcb->Parent;
1785     ParentDcb = ParentMcb->Fcb;
1786 
1787     if ((TargetMcb->Inode.i_ino != ParentMcb->Inode.i_ino)) {
1788 
1789         if (ParentDcb == NULL) {
1790             ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
1791         }
1792     }
1793     if (ParentDcb) {
1794         Ext2ReferXcb(&ParentDcb->ReferenceCount);
1795     }
1796 
1797     if (bFcbLockAcquired) {
1798         ExReleaseResourceLite(&Vcb->FcbLock);
1799         bFcbLockAcquired = FALSE;
1800     }
1801 
1802     if (!TargetDcb || !ParentDcb) {
1803         Status = STATUS_INSUFFICIENT_RESOURCES;
1804         goto errorout;
1805     }
1806 
1807     DEBUG(DL_RES, ("Ext2SetLinkInfo: %wZ\\%wZ -> %wZ\n",
1808                    &TargetMcb->FullName, &FileName, &Mcb->FullName));
1809 
1810     Status = Ext2LookupFile(IrpContext, Vcb, &FileName,
1811                             TargetMcb, &ExistingMcb, 0);
1812     if (NT_SUCCESS(Status) && ExistingMcb != Mcb) {
1813 
1814         if (!ReplaceIfExists) {
1815 
1816             Status = STATUS_OBJECT_NAME_COLLISION;
1817             DEBUG(DL_RES, ("Ext2SetRenameInfo: Target file %wZ exists\n",
1818                            &ExistingMcb->FullName));
1819             goto errorout;
1820 
1821         } else {
1822 
1823             if ( (ExistingFcb = ExistingMcb->Fcb) && !IsMcbSymLink(ExistingMcb) ) {
1824                 Status = Ext2IsFileRemovable(IrpContext, Vcb, ExistingFcb, Ccb);
1825                 if (!NT_SUCCESS(Status)) {
1826                     DEBUG(DL_REN, ("Ext2SetRenameInfo: Target file %wZ cannot be removed.\n",
1827                                    &ExistingMcb->FullName));
1828                     goto errorout;
1829                 }
1830             }
1831 
1832             Status = Ext2DeleteFile(IrpContext, Vcb, ExistingFcb, ExistingMcb);
1833             if (!NT_SUCCESS(Status)) {
1834                 DEBUG(DL_REN, ("Ext2SetRenameInfo: Failed to delete %wZ with status: %xh.\n",
1835                                &FileName, Status));
1836 
1837                 goto errorout;
1838             }
1839             bTargetRemoved = TRUE;
1840         }
1841     }
1842 
1843     /* add new entry for new target name */
1844     Status = Ext2AddEntry(IrpContext, Vcb, TargetDcb, &Mcb->Inode, &FileName, NULL);
1845     if (!NT_SUCCESS(Status)) {
1846         DEBUG(DL_REN, ("Ext2SetLinkInfo: Failed to add entry for %wZ with status: %xh.\n",
1847                        &FileName, Status));
1848         goto errorout;
1849     }
1850 
1851     if (bTargetRemoved) {
1852         Ext2NotifyReportChange(
1853             IrpContext,
1854             Vcb,
1855             ExistingMcb,
1856             (IsMcbDirectory(ExistingMcb) ?
1857              FILE_NOTIFY_CHANGE_DIR_NAME :
1858              FILE_NOTIFY_CHANGE_FILE_NAME ),
1859             FILE_ACTION_REMOVED);
1860     }
1861 
1862     if (NT_SUCCESS(Status)) {
1863 
1864         Ext2LookupFile(IrpContext, Vcb, &FileName, TargetMcb, &LinkMcb, 0);
1865         if (!LinkMcb)
1866             goto errorout;
1867 
1868         Ext2NotifyReportChange(
1869             IrpContext,
1870             Vcb,
1871             LinkMcb,
1872             FILE_NOTIFY_CHANGE_FILE_NAME,
1873             FILE_ACTION_ADDED);
1874     }
1875 
1876 errorout:
1877 
1878     if (bFcbLockAcquired) {
1879         ExReleaseResourceLite(&Vcb->FcbLock);
1880         bFcbLockAcquired = FALSE;
1881     }
1882 
1883     if (TargetDcb) {
1884         Ext2ReleaseFcb(TargetDcb);
1885     }
1886 
1887     if (ParentDcb) {
1888         Ext2ReleaseFcb(ParentDcb);
1889     }
1890 
1891     if (ExistingMcb)
1892         Ext2DerefMcb(ExistingMcb);
1893 
1894     if (LinkMcb)
1895         Ext2DerefMcb(LinkMcb);
1896 
1897     return Status;
1898 }
1899 
1900 ULONG
1901 Ext2InodeType(PEXT2_MCB Mcb)
1902 {
1903     if (IsMcbSymLink(Mcb)) {
1904         return EXT2_FT_SYMLINK;
1905     }
1906 
1907     if (IsMcbDirectory(Mcb)) {
1908         return EXT2_FT_DIR;
1909     }
1910 
1911     return EXT2_FT_REG_FILE;
1912 }
1913 
1914 NTSTATUS
1915 Ext2DeleteFile(
1916     PEXT2_IRP_CONTEXT IrpContext,
1917     PEXT2_VCB         Vcb,
1918     PEXT2_FCB         Fcb,
1919     PEXT2_MCB         Mcb
1920 )
1921 {
1922     PEXT2_FCB       Dcb = NULL;
1923 
1924     NTSTATUS        Status = STATUS_UNSUCCESSFUL;
1925 
1926     BOOLEAN         VcbResourceAcquired = FALSE;
1927     BOOLEAN         FcbPagingIoAcquired = FALSE;
1928     BOOLEAN         FcbResourceAcquired = FALSE;
1929     BOOLEAN         DcbResourceAcquired = FALSE;
1930 
1931     LARGE_INTEGER   Size;
1932     LARGE_INTEGER   SysTime;
1933 
1934     BOOLEAN         bFcbLockAcquired = FALSE;
1935 
1936     DEBUG(DL_INF, ( "Ext2DeleteFile: File %wZ (%xh) will be deleted!\n",
1937                     &Mcb->FullName, Mcb->Inode.i_ino));
1938 
1939     if (IsFlagOn(Mcb->Flags, MCB_FILE_DELETED)) {
1940         return STATUS_SUCCESS;
1941     }
1942 
1943     if (!IsMcbSymLink(Mcb) && IsMcbDirectory(Mcb)) {
1944         if (!Ext2IsDirectoryEmpty(IrpContext, Vcb, Mcb)) {
1945             return STATUS_DIRECTORY_NOT_EMPTY;
1946         }
1947     }
1948 
1949     _SEH2_TRY {
1950 
1951         Ext2ReferMcb(Mcb);
1952 
1953         ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
1954         VcbResourceAcquired = TRUE;
1955 
1956         ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
1957         bFcbLockAcquired = TRUE;
1958 
1959         /* Mcb->Parent could be NULL when working with layered file systems */
1960         if (Mcb->Parent) {
1961             Dcb = Mcb->Parent->Fcb;
1962             if (!Dcb)
1963                 Dcb = Ext2AllocateFcb(Vcb, Mcb->Parent);
1964         }
1965         if (Dcb)
1966             Ext2ReferXcb(&Dcb->ReferenceCount);
1967 
1968         if (bFcbLockAcquired) {
1969             ExReleaseResourceLite(&Vcb->FcbLock);
1970             bFcbLockAcquired = FALSE;
1971         }
1972 
1973         if (Dcb) {
1974             DcbResourceAcquired =
1975                 ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
1976 
1977             /* remove it's entry form it's parent */
1978             Status = Ext2RemoveEntry(IrpContext, Vcb, Dcb, Mcb);
1979         }
1980 
1981         if (NT_SUCCESS(Status)) {
1982 
1983             SetFlag(Mcb->Flags, MCB_FILE_DELETED);
1984             Ext2RemoveMcb(Vcb, Mcb);
1985 
1986             if (Fcb) {
1987                 FcbResourceAcquired =
1988                     ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE);
1989 
1990                 FcbPagingIoAcquired =
1991                     ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE);
1992             }
1993 
1994             if (DcbResourceAcquired) {
1995                 ExReleaseResourceLite(&Dcb->MainResource);
1996                 DcbResourceAcquired = FALSE;
1997             }
1998 
1999             if (VcbResourceAcquired) {
2000                 ExReleaseResourceLite(&Vcb->MainResource);
2001                 VcbResourceAcquired = FALSE;
2002             }
2003 
2004             if (IsMcbSymLink(Mcb)) {
2005                 if (Mcb->Inode.i_nlink > 0) {
2006                     Status = STATUS_CANNOT_DELETE;
2007                     _SEH2_LEAVE;
2008                 }
2009             } else if (!IsMcbDirectory(Mcb)) {
2010                 if (Mcb->Inode.i_nlink > 0) {
2011                     _SEH2_LEAVE;
2012                 }
2013             } else {
2014                 if (Mcb->Inode.i_nlink >= 2) {
2015                     _SEH2_LEAVE;
2016                 }
2017             }
2018 
2019             if (S_ISLNK(Mcb->Inode.i_mode)) {
2020 
2021                 /* for symlink, we should do differenctly  */
2022                 if (Mcb->Inode.i_size > EXT2_LINKLEN_IN_INODE) {
2023                     Size.QuadPart = (LONGLONG)0;
2024                     Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &Size);
2025                 }
2026 
2027             } else {
2028 
2029                 /* truncate file size */
2030                 Size.QuadPart = (LONGLONG)0;
2031                 Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &Size);
2032 
2033                 /* check file offset mappings */
2034                 DEBUG(DL_EXT, ("Ext2DeleteFile ...: %wZ\n", &Mcb->FullName));
2035 
2036                 if (Fcb) {
2037                     Fcb->Header.AllocationSize.QuadPart = Size.QuadPart;
2038                     if (Fcb->Header.FileSize.QuadPart > Size.QuadPart) {
2039                         Fcb->Header.FileSize.QuadPart = Size.QuadPart;
2040                         Fcb->Mcb->Inode.i_size = Size.QuadPart;
2041                     }
2042                     if (Fcb->Header.ValidDataLength.QuadPart > Fcb->Header.FileSize.QuadPart) {
2043                         Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
2044                     }
2045                 } else if (Mcb) {
2046                     /* Update the inode's data length . It should be ZERO if succeeds. */
2047                     if (Mcb->Inode.i_size > (loff_t)Size.QuadPart) {
2048                         Mcb->Inode.i_size = Size.QuadPart;
2049                     }
2050                 }
2051             }
2052 
2053             /* set delete time and free the inode */
2054             KeQuerySystemTime(&SysTime);
2055             Mcb->Inode.i_nlink = 0;
2056             Mcb->Inode.i_dtime = Ext2LinuxTime(SysTime);
2057             Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
2058             Ext2FreeInode(IrpContext, Vcb, Mcb->Inode.i_ino, Ext2InodeType(Mcb));
2059         }
2060 
2061     } _SEH2_FINALLY {
2062 
2063         if (FcbPagingIoAcquired) {
2064             ExReleaseResourceLite(&Fcb->PagingIoResource);
2065         }
2066 
2067         if (FcbResourceAcquired) {
2068             ExReleaseResourceLite(&Fcb->MainResource);
2069         }
2070 
2071         if (DcbResourceAcquired) {
2072             ExReleaseResourceLite(&Dcb->MainResource);
2073         }
2074 
2075         if (bFcbLockAcquired) {
2076             ExReleaseResourceLite(&Vcb->FcbLock);
2077         }
2078 
2079         if (VcbResourceAcquired) {
2080             ExReleaseResourceLite(&Vcb->MainResource);
2081         }
2082 
2083         if (Dcb) {
2084             Ext2ReleaseFcb(Dcb);
2085         }
2086 
2087         Ext2DerefMcb(Mcb);
2088     } _SEH2_END;
2089 
2090     DEBUG(DL_INF, ( "Ext2DeleteFile: %wZ Succeed... EXT2SB->S_FREE_BLOCKS = %I64xh .\n",
2091                     &Mcb->FullName, ext3_free_blocks_count(SUPER_BLOCK)));
2092 
2093     return Status;
2094 }
2095