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