2 * COPYRIGHT: See COPYRIGHT.TXT
3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP
5 * PROGRAMMER: Matt Wu <mattwu@163.com>
6 * HOMEPAGE: http://www.ext2fsd.com
10 /* INCLUDES *****************************************************************/
13 #include <linux/ext4.h>
15 /* GLOBALS ***************************************************************/
17 extern PEXT2_GLOBAL Ext2Global
;
19 /* DEFINITIONS *************************************************************/
22 #pragma alloc_text(PAGE, Ext2QueryFileInformation)
23 #pragma alloc_text(PAGE, Ext2SetFileInformation)
24 #pragma alloc_text(PAGE, Ext2ExpandFile)
25 #pragma alloc_text(PAGE, Ext2TruncateFile)
26 #pragma alloc_text(PAGE, Ext2SetDispositionInfo)
27 #pragma alloc_text(PAGE, Ext2SetRenameInfo)
28 #pragma alloc_text(PAGE, Ext2DeleteFile)
32 Ext2QueryFileInformation (IN PEXT2_IRP_CONTEXT IrpContext
)
34 PDEVICE_OBJECT DeviceObject
;
35 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
36 PFILE_OBJECT FileObject
;
42 PIO_STACK_LOCATION IoStackLocation
;
43 FILE_INFORMATION_CLASS FileInformationClass
;
46 BOOLEAN FcbResourceAcquired
= FALSE
;
50 ASSERT(IrpContext
!= NULL
);
51 ASSERT((IrpContext
->Identifier
.Type
== EXT2ICX
) &&
52 (IrpContext
->Identifier
.Size
== sizeof(EXT2_IRP_CONTEXT
)));
54 DeviceObject
= IrpContext
->DeviceObject
;
57 // This request is not allowed on the main device object
59 if (IsExt2FsDevice(DeviceObject
)) {
60 Status
= STATUS_INVALID_DEVICE_REQUEST
;
64 FileObject
= IrpContext
->FileObject
;
65 Fcb
= (PEXT2_FCB
) FileObject
->FsContext
;
67 Status
= STATUS_INVALID_PARAMETER
;
72 // This request is not allowed on volumes
74 if (Fcb
->Identifier
.Type
== EXT2VCB
) {
75 Status
= STATUS_INVALID_PARAMETER
;
79 if (!((Fcb
->Identifier
.Type
== EXT2FCB
) &&
80 (Fcb
->Identifier
.Size
== sizeof(EXT2_FCB
)))) {
81 Status
= STATUS_INVALID_PARAMETER
;
88 if (!ExAcquireResourceSharedLite(
90 IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
)
93 Status
= STATUS_PENDING
;
97 FcbResourceAcquired
= TRUE
;
100 Ccb
= (PEXT2_CCB
) FileObject
->FsContext2
;
102 ASSERT((Ccb
->Identifier
.Type
== EXT2CCB
) &&
103 (Ccb
->Identifier
.Size
== sizeof(EXT2_CCB
)));
108 Irp
= IrpContext
->Irp
;
109 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
110 FileInformationClass
=
111 IoStackLocation
->Parameters
.QueryFile
.FileInformationClass
;
113 Length
= IoStackLocation
->Parameters
.QueryFile
.Length
;
114 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
115 RtlZeroMemory(Buffer
, Length
);
117 switch (FileInformationClass
) {
119 case FileBasicInformation
:
121 PFILE_BASIC_INFORMATION FileBasicInformation
;
123 if (Length
< sizeof(FILE_BASIC_INFORMATION
)) {
124 Status
= STATUS_BUFFER_OVERFLOW
;
128 FileBasicInformation
= (PFILE_BASIC_INFORMATION
) Buffer
;
130 FileBasicInformation
->CreationTime
= Mcb
->CreationTime
;
131 FileBasicInformation
->LastAccessTime
= Mcb
->LastAccessTime
;
132 FileBasicInformation
->LastWriteTime
= Mcb
->LastWriteTime
;
133 FileBasicInformation
->ChangeTime
= Mcb
->ChangeTime
;
135 FileBasicInformation
->FileAttributes
= Mcb
->FileAttr
;
136 if (IsLinkInvalid(Mcb
)) {
137 ClearFlag(FileBasicInformation
->FileAttributes
, FILE_ATTRIBUTE_DIRECTORY
);
139 if (FileBasicInformation
->FileAttributes
== 0) {
140 FileBasicInformation
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
143 Irp
->IoStatus
.Information
= sizeof(FILE_BASIC_INFORMATION
);
144 Status
= STATUS_SUCCESS
;
148 case FileStandardInformation
:
150 PFILE_STANDARD_INFORMATION FSI
;
152 if (Length
< sizeof(FILE_STANDARD_INFORMATION
)) {
153 Status
= STATUS_BUFFER_OVERFLOW
;
157 FSI
= (PFILE_STANDARD_INFORMATION
) Buffer
;
159 FSI
->NumberOfLinks
= Mcb
->Inode
.i_nlink
;
161 if (IsVcbReadOnly(Fcb
->Vcb
))
162 FSI
->DeletePending
= FALSE
;
164 FSI
->DeletePending
= IsFlagOn(Fcb
->Flags
, FCB_DELETE_PENDING
);
166 if (IsLinkInvalid(Mcb
)) {
167 FSI
->Directory
= FALSE
;
168 FSI
->AllocationSize
.QuadPart
= 0;
169 FSI
->EndOfFile
.QuadPart
= 0;
170 } else if (IsMcbDirectory(Mcb
)) {
171 FSI
->Directory
= TRUE
;
172 FSI
->AllocationSize
.QuadPart
= 0;
173 FSI
->EndOfFile
.QuadPart
= 0;
175 FSI
->Directory
= FALSE
;
176 FSI
->AllocationSize
= Fcb
->Header
.AllocationSize
;
177 FSI
->EndOfFile
= Fcb
->Header
.FileSize
;
180 Irp
->IoStatus
.Information
= sizeof(FILE_STANDARD_INFORMATION
);
181 Status
= STATUS_SUCCESS
;
185 case FileInternalInformation
:
187 PFILE_INTERNAL_INFORMATION FileInternalInformation
;
189 if (Length
< sizeof(FILE_INTERNAL_INFORMATION
)) {
190 Status
= STATUS_BUFFER_OVERFLOW
;
194 FileInternalInformation
= (PFILE_INTERNAL_INFORMATION
) Buffer
;
196 /* we use the inode number as the internal index */
197 FileInternalInformation
->IndexNumber
.QuadPart
= (LONGLONG
)Mcb
->Inode
.i_ino
;
199 Irp
->IoStatus
.Information
= sizeof(FILE_INTERNAL_INFORMATION
);
200 Status
= STATUS_SUCCESS
;
205 case FileEaInformation
:
207 PFILE_EA_INFORMATION FileEaInformation
;
209 if (Length
< sizeof(FILE_EA_INFORMATION
)) {
210 Status
= STATUS_BUFFER_OVERFLOW
;
214 FileEaInformation
= (PFILE_EA_INFORMATION
) Buffer
;
216 // Romfs doesn't have any extended attributes
217 FileEaInformation
->EaSize
= 0;
219 Irp
->IoStatus
.Information
= sizeof(FILE_EA_INFORMATION
);
220 Status
= STATUS_SUCCESS
;
224 case FileNameInformation
:
226 PFILE_NAME_INFORMATION FileNameInformation
;
227 ULONG BytesToCopy
= 0;
229 if (Length
< (ULONG
)FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
) +
230 Mcb
->FullName
.Length
) {
231 BytesToCopy
= Length
- FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
);
232 Status
= STATUS_BUFFER_OVERFLOW
;
234 BytesToCopy
= Mcb
->FullName
.Length
;
235 Status
= STATUS_SUCCESS
;
238 FileNameInformation
= (PFILE_NAME_INFORMATION
) Buffer
;
239 FileNameInformation
->FileNameLength
= Mcb
->FullName
.Length
;
242 FileNameInformation
->FileName
,
243 Mcb
->FullName
.Buffer
,
246 Irp
->IoStatus
.Information
= BytesToCopy
+
247 + FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
);
251 case FilePositionInformation
:
253 PFILE_POSITION_INFORMATION FilePositionInformation
;
255 if (Length
< sizeof(FILE_POSITION_INFORMATION
)) {
256 Status
= STATUS_BUFFER_OVERFLOW
;
260 FilePositionInformation
= (PFILE_POSITION_INFORMATION
) Buffer
;
261 FilePositionInformation
->CurrentByteOffset
=
262 FileObject
->CurrentByteOffset
;
264 Irp
->IoStatus
.Information
= sizeof(FILE_POSITION_INFORMATION
);
265 Status
= STATUS_SUCCESS
;
269 case FileAllInformation
:
271 PFILE_ALL_INFORMATION FileAllInformation
;
272 PFILE_BASIC_INFORMATION FileBasicInformation
;
273 PFILE_STANDARD_INFORMATION FSI
;
274 PFILE_INTERNAL_INFORMATION FileInternalInformation
;
275 PFILE_EA_INFORMATION FileEaInformation
;
276 PFILE_POSITION_INFORMATION FilePositionInformation
;
277 PFILE_NAME_INFORMATION FileNameInformation
;
279 if (Length
< sizeof(FILE_ALL_INFORMATION
)) {
280 Status
= STATUS_BUFFER_OVERFLOW
;
284 FileAllInformation
= (PFILE_ALL_INFORMATION
) Buffer
;
286 FileBasicInformation
=
287 &FileAllInformation
->BasicInformation
;
290 &FileAllInformation
->StandardInformation
;
292 FileInternalInformation
=
293 &FileAllInformation
->InternalInformation
;
296 &FileAllInformation
->EaInformation
;
298 FilePositionInformation
=
299 &FileAllInformation
->PositionInformation
;
301 FileNameInformation
=
302 &FileAllInformation
->NameInformation
;
304 FileBasicInformation
->CreationTime
= Mcb
->CreationTime
;
305 FileBasicInformation
->LastAccessTime
= Mcb
->LastAccessTime
;
306 FileBasicInformation
->LastWriteTime
= Mcb
->LastWriteTime
;
307 FileBasicInformation
->ChangeTime
= Mcb
->ChangeTime
;
309 FileBasicInformation
->FileAttributes
= Mcb
->FileAttr
;
310 if (IsMcbSymLink(Mcb
) && IsFileDeleted(Mcb
->Target
)) {
311 ClearFlag(FileBasicInformation
->FileAttributes
, FILE_ATTRIBUTE_DIRECTORY
);
313 if (FileBasicInformation
->FileAttributes
== 0) {
314 FileBasicInformation
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
317 FSI
->NumberOfLinks
= Mcb
->Inode
.i_nlink
;
319 if (IsVcbReadOnly(Fcb
->Vcb
))
320 FSI
->DeletePending
= FALSE
;
322 FSI
->DeletePending
= IsFlagOn(Fcb
->Flags
, FCB_DELETE_PENDING
);
324 if (IsLinkInvalid(Mcb
)) {
325 FSI
->Directory
= FALSE
;
326 FSI
->AllocationSize
.QuadPart
= 0;
327 FSI
->EndOfFile
.QuadPart
= 0;
328 } else if (IsDirectory(Fcb
)) {
329 FSI
->Directory
= TRUE
;
330 FSI
->AllocationSize
.QuadPart
= 0;
331 FSI
->EndOfFile
.QuadPart
= 0;
333 FSI
->Directory
= FALSE
;
334 FSI
->AllocationSize
= Fcb
->Header
.AllocationSize
;
335 FSI
->EndOfFile
= Fcb
->Header
.FileSize
;
338 // The "inode number"
339 FileInternalInformation
->IndexNumber
.QuadPart
= (LONGLONG
)Mcb
->Inode
.i_ino
;
341 // Romfs doesn't have any extended attributes
342 FileEaInformation
->EaSize
= 0;
344 FilePositionInformation
->CurrentByteOffset
=
345 FileObject
->CurrentByteOffset
;
347 FileNameInformation
->FileNameLength
= Mcb
->ShortName
.Length
;
349 if (Length
< sizeof(FILE_ALL_INFORMATION
) +
350 Mcb
->ShortName
.Length
- sizeof(WCHAR
)) {
351 Irp
->IoStatus
.Information
= sizeof(FILE_ALL_INFORMATION
);
352 Status
= STATUS_BUFFER_OVERFLOW
;
354 FileNameInformation
->FileName
,
355 Mcb
->ShortName
.Buffer
,
356 Length
- FIELD_OFFSET(FILE_ALL_INFORMATION
,
357 NameInformation
.FileName
)
363 FileNameInformation
->FileName
,
364 Mcb
->ShortName
.Buffer
,
365 Mcb
->ShortName
.Length
368 Irp
->IoStatus
.Information
= sizeof(FILE_ALL_INFORMATION
) +
369 Mcb
->ShortName
.Length
- sizeof(WCHAR
);
371 sizeof(FILE_ACCESS_INFORMATION
) -
372 sizeof(FILE_MODE_INFORMATION
) -
373 sizeof(FILE_ALIGNMENT_INFORMATION
);
376 Status
= STATUS_SUCCESS
;
381 case FileAlternateNameInformation:
383 // TODO: Handle FileAlternateNameInformation
385 // Here we would like to use RtlGenerate8dot3Name but I don't
386 // know how to use the argument PGENERATE_NAME_CONTEXT
390 case FileNetworkOpenInformation
:
392 PFILE_NETWORK_OPEN_INFORMATION PFNOI
;
394 if (Length
< sizeof(FILE_NETWORK_OPEN_INFORMATION
)) {
395 Status
= STATUS_BUFFER_OVERFLOW
;
399 PFNOI
= (PFILE_NETWORK_OPEN_INFORMATION
) Buffer
;
401 PFNOI
->FileAttributes
= Mcb
->FileAttr
;
402 if (IsLinkInvalid(Mcb
)) {
403 ClearFlag(PFNOI
->FileAttributes
, FILE_ATTRIBUTE_DIRECTORY
);
404 PFNOI
->AllocationSize
.QuadPart
= 0;
405 PFNOI
->EndOfFile
.QuadPart
= 0;
406 } else if (IsDirectory(Fcb
)) {
407 PFNOI
->AllocationSize
.QuadPart
= 0;
408 PFNOI
->EndOfFile
.QuadPart
= 0;
410 PFNOI
->AllocationSize
= Fcb
->Header
.AllocationSize
;
411 PFNOI
->EndOfFile
= Fcb
->Header
.FileSize
;
414 if (PFNOI
->FileAttributes
== 0) {
415 PFNOI
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
418 PFNOI
->CreationTime
= Mcb
->CreationTime
;
419 PFNOI
->LastAccessTime
= Mcb
->LastAccessTime
;
420 PFNOI
->LastWriteTime
= Mcb
->LastWriteTime
;
421 PFNOI
->ChangeTime
= Mcb
->ChangeTime
;
424 Irp
->IoStatus
.Information
=
425 sizeof(FILE_NETWORK_OPEN_INFORMATION
);
426 Status
= STATUS_SUCCESS
;
430 #if (_WIN32_WINNT >= 0x0500)
432 case FileAttributeTagInformation
:
434 PFILE_ATTRIBUTE_TAG_INFORMATION FATI
;
436 if (Length
< sizeof(FILE_ATTRIBUTE_TAG_INFORMATION
)) {
437 Status
= STATUS_BUFFER_OVERFLOW
;
441 FATI
= (PFILE_ATTRIBUTE_TAG_INFORMATION
) Buffer
;
442 FATI
->FileAttributes
= Mcb
->FileAttr
;
443 if (IsLinkInvalid(Mcb
)) {
444 ClearFlag(FATI
->FileAttributes
, FILE_ATTRIBUTE_DIRECTORY
);
446 if (FATI
->FileAttributes
== 0) {
447 FATI
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
449 FATI
->ReparseTag
= IO_REPARSE_TAG_RESERVED_ZERO
;
450 Irp
->IoStatus
.Information
= sizeof(FILE_ATTRIBUTE_TAG_INFORMATION
);
451 Status
= STATUS_SUCCESS
;
454 #endif // (_WIN32_WINNT >= 0x0500)
456 case FileStreamInformation
:
457 Status
= STATUS_INVALID_PARAMETER
;
461 DEBUG(DL_WRN
, ( "Ext2QueryInformation: invalid class: %d\n",
462 FileInformationClass
));
463 Status
= STATUS_INVALID_PARAMETER
; /* STATUS_INVALID_INFO_CLASS; */
469 if (FcbResourceAcquired
) {
470 ExReleaseResourceLite(&Fcb
->MainResource
);
473 if (!IrpContext
->ExceptionInProgress
) {
474 if (Status
== STATUS_PENDING
||
475 Status
== STATUS_CANT_WAIT
) {
476 Status
= Ext2QueueRequest(IrpContext
);
478 Ext2CompleteIrpContext(IrpContext
, Status
);
488 Ext2SetFileInformation (IN PEXT2_IRP_CONTEXT IrpContext
)
490 PDEVICE_OBJECT DeviceObject
;
491 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
493 PFILE_OBJECT FileObject
;
498 PIO_STACK_LOCATION IoStackLocation
;
499 FILE_INFORMATION_CLASS FileInformationClass
;
501 ULONG NotifyFilter
= 0;
506 BOOLEAN VcbMainResourceAcquired
= FALSE
;
507 BOOLEAN FcbMainResourceAcquired
= FALSE
;
508 BOOLEAN FcbPagingIoResourceAcquired
= FALSE
;
512 ASSERT(IrpContext
!= NULL
);
514 ASSERT((IrpContext
->Identifier
.Type
== EXT2ICX
) &&
515 (IrpContext
->Identifier
.Size
== sizeof(EXT2_IRP_CONTEXT
)));
516 DeviceObject
= IrpContext
->DeviceObject
;
519 // This request is not allowed on the main device object
521 if (IsExt2FsDevice(DeviceObject
)) {
522 Status
= STATUS_INVALID_DEVICE_REQUEST
;
526 /* check io stack location of irp stack */
527 Irp
= IrpContext
->Irp
;
528 IoStackLocation
= IoGetCurrentIrpStackLocation(Irp
);
529 FileInformationClass
=
530 IoStackLocation
->Parameters
.SetFile
.FileInformationClass
;
531 Length
= IoStackLocation
->Parameters
.SetFile
.Length
;
532 Buffer
= Irp
->AssociatedIrp
.SystemBuffer
;
535 Vcb
= (PEXT2_VCB
) DeviceObject
->DeviceExtension
;
537 ASSERT((Vcb
->Identifier
.Type
== EXT2VCB
) &&
538 (Vcb
->Identifier
.Size
== sizeof(EXT2_VCB
)));
539 if (!IsMounted(Vcb
)) {
540 Status
= STATUS_INVALID_DEVICE_REQUEST
;
544 /* we need grab Vcb in case it's a rename operation */
545 if (FileInformationClass
== FileRenameInformation
) {
546 if (!ExAcquireResourceExclusiveLite(
548 IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
) )) {
549 Status
= STATUS_PENDING
;
552 VcbMainResourceAcquired
= TRUE
;
555 if (IsVcbReadOnly(Vcb
)) {
556 if (FileInformationClass
!= FilePositionInformation
) {
557 Status
= STATUS_MEDIA_WRITE_PROTECTED
;
562 if (FlagOn(Vcb
->Flags
, VCB_VOLUME_LOCKED
)) {
563 Status
= STATUS_ACCESS_DENIED
;
567 FileObject
= IrpContext
->FileObject
;
568 Fcb
= (PEXT2_FCB
) FileObject
->FsContext
;
570 // This request is issued to volumes, just return success
571 if (Fcb
== NULL
|| Fcb
->Identifier
.Type
== EXT2VCB
) {
572 Status
= STATUS_SUCCESS
;
575 ASSERT((Fcb
->Identifier
.Type
== EXT2FCB
) &&
576 (Fcb
->Identifier
.Size
== sizeof(EXT2_FCB
)));
578 if (IsFlagOn(Fcb
->Mcb
->Flags
, MCB_FILE_DELETED
)) {
579 Status
= STATUS_FILE_DELETED
;
583 Ccb
= (PEXT2_CCB
) FileObject
->FsContext2
;
585 ASSERT((Ccb
->Identifier
.Type
== EXT2CCB
) &&
586 (Ccb
->Identifier
.Size
== sizeof(EXT2_CCB
)));
589 if (IsFlagOn(Mcb
->Flags
, MCB_FILE_DELETED
)) {
590 Status
= STATUS_FILE_DELETED
;
597 if ( !IsDirectory(Fcb
) && !FlagOn(Fcb
->Flags
, FCB_PAGE_FILE
) &&
598 ((FileInformationClass
== FileEndOfFileInformation
) ||
599 (FileInformationClass
== FileValidDataLengthInformation
) ||
600 (FileInformationClass
== FileAllocationInformation
))) {
602 Status
= FsRtlCheckOplock( &Fcb
->Oplock
,
608 if (Status
!= STATUS_SUCCESS
) {
613 // Set the flag indicating if Fast I/O is possible
616 Fcb
->Header
.IsFastIoPossible
= Ext2IsFastIoPossible(Fcb
);
619 /* for renaming, we must not get any Fcb locks here, function
620 Ext2SetRenameInfo will get Dcb resource exclusively. */
621 if (!IsFlagOn(Fcb
->Flags
, FCB_PAGE_FILE
) &&
622 FileInformationClass
!= FileRenameInformation
) {
624 if (!ExAcquireResourceExclusiveLite(
626 IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
) )) {
627 Status
= STATUS_PENDING
;
631 FcbMainResourceAcquired
= TRUE
;
633 if ( FileInformationClass
== FileAllocationInformation
||
634 FileInformationClass
== FileEndOfFileInformation
||
635 FileInformationClass
== FileValidDataLengthInformation
) {
637 if (!ExAcquireResourceExclusiveLite(
638 &Fcb
->PagingIoResource
,
639 IsFlagOn(IrpContext
->Flags
, IRP_CONTEXT_FLAG_WAIT
) )) {
640 Status
= STATUS_PENDING
;
644 FcbPagingIoResourceAcquired
= TRUE
;
648 switch (FileInformationClass
) {
650 case FileBasicInformation
:
652 PFILE_BASIC_INFORMATION FBI
= (PFILE_BASIC_INFORMATION
) Buffer
;
653 struct inode
*Inode
= &Mcb
->Inode
;
655 if (FBI
->CreationTime
.QuadPart
!= 0 && FBI
->CreationTime
.QuadPart
!= -1) {
656 Inode
->i_ctime
= Ext2LinuxTime(FBI
->CreationTime
);
657 Mcb
->CreationTime
= Ext2NtTime(Inode
->i_ctime
);
658 NotifyFilter
|= FILE_NOTIFY_CHANGE_CREATION
;
661 if (FBI
->LastAccessTime
.QuadPart
!= 0 && FBI
->LastAccessTime
.QuadPart
!= -1) {
662 Inode
->i_atime
= Ext2LinuxTime(FBI
->LastAccessTime
);
663 Mcb
->LastAccessTime
= Ext2NtTime(Inode
->i_atime
);
664 NotifyFilter
|= FILE_NOTIFY_CHANGE_LAST_ACCESS
;
667 if (FBI
->LastWriteTime
.QuadPart
!= 0 && FBI
->LastWriteTime
.QuadPart
!= -1) {
668 Inode
->i_mtime
= Ext2LinuxTime(FBI
->LastWriteTime
);
669 Mcb
->LastWriteTime
= Ext2NtTime(Inode
->i_mtime
);
670 NotifyFilter
|= FILE_NOTIFY_CHANGE_LAST_WRITE
;
671 SetFlag(Ccb
->Flags
, CCB_LAST_WRITE_UPDATED
);
674 if (FBI
->ChangeTime
.QuadPart
!=0 && FBI
->ChangeTime
.QuadPart
!= -1) {
675 Mcb
->ChangeTime
= FBI
->ChangeTime
;
678 if (FBI
->FileAttributes
!= 0) {
680 BOOLEAN bIsDirectory
= IsDirectory(Fcb
);
681 NotifyFilter
|= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
683 if (IsFlagOn(FBI
->FileAttributes
, FILE_ATTRIBUTE_READONLY
)) {
684 Ext2SetOwnerReadOnly(Inode
->i_mode
);
686 Ext2SetOwnerWritable(Inode
->i_mode
);
689 if (FBI
->FileAttributes
& FILE_ATTRIBUTE_TEMPORARY
) {
690 SetFlag(FileObject
->Flags
, FO_TEMPORARY_FILE
);
692 ClearFlag(FileObject
->Flags
, FO_TEMPORARY_FILE
);
695 Mcb
->FileAttr
= FBI
->FileAttributes
;
697 SetFlag(Mcb
->FileAttr
, FILE_ATTRIBUTE_DIRECTORY
);
698 ClearFlag(Mcb
->FileAttr
, FILE_ATTRIBUTE_NORMAL
);
702 if (NotifyFilter
!= 0) {
703 if (Ext2SaveInode(IrpContext
, Vcb
, Inode
)) {
704 Status
= STATUS_SUCCESS
;
708 ClearFlag(NotifyFilter
, FILE_NOTIFY_CHANGE_LAST_ACCESS
);
709 Status
= STATUS_SUCCESS
;
714 case FileAllocationInformation
:
716 PFILE_ALLOCATION_INFORMATION FAI
= (PFILE_ALLOCATION_INFORMATION
)Buffer
;
717 LARGE_INTEGER AllocationSize
;
719 if (IsMcbDirectory(Mcb
) || IsMcbSpecialFile(Mcb
)) {
720 Status
= STATUS_INVALID_DEVICE_REQUEST
;
723 Status
= STATUS_SUCCESS
;
726 /* set Mcb to it's target */
727 if (IsMcbSymLink(Mcb
)) {
728 ASSERT(Fcb
->Mcb
== Mcb
->Target
);
732 /* get user specified allocationsize aligned with BLOCK_SIZE */
733 AllocationSize
.QuadPart
= CEILING_ALIGNED(ULONGLONG
,
734 (ULONGLONG
)FAI
->AllocationSize
.QuadPart
,
735 (ULONGLONG
)BLOCK_SIZE
);
737 if (AllocationSize
.QuadPart
> Fcb
->Header
.AllocationSize
.QuadPart
) {
739 Status
= Ext2ExpandFile(IrpContext
, Vcb
, Mcb
, &AllocationSize
);
740 Fcb
->Header
.AllocationSize
= AllocationSize
;
741 NotifyFilter
= FILE_NOTIFY_CHANGE_SIZE
;
742 SetLongFlag(Fcb
->Flags
, FCB_ALLOC_IN_SETINFO
);
744 } else if (AllocationSize
.QuadPart
< Fcb
->Header
.AllocationSize
.QuadPart
) {
746 if (MmCanFileBeTruncated(&(Fcb
->SectionObject
), &AllocationSize
)) {
748 /* truncate file blocks */
749 Status
= Ext2TruncateFile(IrpContext
, Vcb
, Mcb
, &AllocationSize
);
751 if (NT_SUCCESS(Status
)) {
752 ClearLongFlag(Fcb
->Flags
, FCB_ALLOC_IN_CREATE
);
755 NotifyFilter
= FILE_NOTIFY_CHANGE_SIZE
;
756 Fcb
->Header
.AllocationSize
.QuadPart
= AllocationSize
.QuadPart
;
757 if (Mcb
->Inode
.i_size
> (loff_t
)AllocationSize
.QuadPart
) {
758 Mcb
->Inode
.i_size
= AllocationSize
.QuadPart
;
760 Fcb
->Header
.FileSize
.QuadPart
= Mcb
->Inode
.i_size
;
761 if (Fcb
->Header
.ValidDataLength
.QuadPart
> Fcb
->Header
.FileSize
.QuadPart
) {
762 Fcb
->Header
.ValidDataLength
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
767 Status
= STATUS_USER_MAPPED_FILE
;
775 SetFlag(FileObject
->Flags
, FO_FILE_MODIFIED
);
776 SetLongFlag(Fcb
->Flags
, FCB_FILE_MODIFIED
);
777 Ext2SaveInode(IrpContext
, Vcb
, &Mcb
->Inode
);
778 if (CcIsFileCached(FileObject
)) {
779 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)(&(Fcb
->Header
.AllocationSize
)));
783 DEBUG(DL_IO
, ("Ext2SetInformation: %wZ NewSize=%I64xh AllocationSize=%I64xh "
784 "FileSize=%I64xh VDL=%I64xh i_size=%I64xh status = %xh\n",
785 &Fcb
->Mcb
->ShortName
, AllocationSize
.QuadPart
,
786 Fcb
->Header
.AllocationSize
.QuadPart
,
787 Fcb
->Header
.FileSize
.QuadPart
, Fcb
->Header
.ValidDataLength
.QuadPart
,
788 Mcb
->Inode
.i_size
, Status
));
793 case FileEndOfFileInformation
:
795 PFILE_END_OF_FILE_INFORMATION FEOFI
= (PFILE_END_OF_FILE_INFORMATION
) Buffer
;
796 LARGE_INTEGER NewSize
, OldSize
, EndOfFile
;
798 if (IsMcbDirectory(Mcb
) || IsMcbSpecialFile(Mcb
)) {
799 Status
= STATUS_INVALID_DEVICE_REQUEST
;
802 Status
= STATUS_SUCCESS
;
805 /* set Mcb to it's target */
806 if (IsMcbSymLink(Mcb
)) {
807 ASSERT(Fcb
->Mcb
== Mcb
->Target
);
811 OldSize
= Fcb
->Header
.AllocationSize
;
812 EndOfFile
= FEOFI
->EndOfFile
;
814 if (IoStackLocation
->Parameters
.SetFile
.AdvanceOnly
) {
816 if (IsFlagOn(Fcb
->Flags
, FCB_DELETE_PENDING
)) {
820 if (EndOfFile
.QuadPart
> Fcb
->Header
.FileSize
.QuadPart
) {
821 EndOfFile
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
824 if (EndOfFile
.QuadPart
> Fcb
->Header
.ValidDataLength
.QuadPart
) {
825 Fcb
->Header
.ValidDataLength
.QuadPart
= EndOfFile
.QuadPart
;
826 NotifyFilter
= FILE_NOTIFY_CHANGE_SIZE
;
832 NewSize
.QuadPart
= CEILING_ALIGNED(ULONGLONG
,
833 EndOfFile
.QuadPart
, BLOCK_SIZE
);
835 if (NewSize
.QuadPart
> OldSize
.QuadPart
) {
837 Fcb
->Header
.AllocationSize
= NewSize
;
838 Status
= Ext2ExpandFile(
842 &(Fcb
->Header
.AllocationSize
)
844 NotifyFilter
= FILE_NOTIFY_CHANGE_SIZE
;
845 SetLongFlag(Fcb
->Flags
, FCB_ALLOC_IN_SETINFO
);
848 } else if (NewSize
.QuadPart
== OldSize
.QuadPart
) {
851 Status
= STATUS_SUCCESS
;
855 /* don't truncate file data since it's still being written */
856 if (IsFlagOn(Fcb
->Flags
, FCB_ALLOC_IN_WRITE
)) {
858 Status
= STATUS_SUCCESS
;
862 if (!MmCanFileBeTruncated(&(Fcb
->SectionObject
), &NewSize
)) {
863 Status
= STATUS_USER_MAPPED_FILE
;
868 /* truncate file blocks */
869 Status
= Ext2TruncateFile(IrpContext
, Vcb
, Mcb
, &NewSize
);
871 /* restore original file size */
872 if (NT_SUCCESS(Status
)) {
873 ClearLongFlag(Fcb
->Flags
, FCB_ALLOC_IN_CREATE
);
876 /* update file allocateion size */
877 Fcb
->Header
.AllocationSize
.QuadPart
= NewSize
.QuadPart
;
879 ASSERT((loff_t
)NewSize
.QuadPart
>= Mcb
->Inode
.i_size
);
880 if ((loff_t
)Fcb
->Header
.FileSize
.QuadPart
< Mcb
->Inode
.i_size
) {
881 Fcb
->Header
.FileSize
.QuadPart
= Mcb
->Inode
.i_size
;
883 if (Fcb
->Header
.ValidDataLength
.QuadPart
> Fcb
->Header
.FileSize
.QuadPart
) {
884 Fcb
->Header
.ValidDataLength
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
887 SetFlag(FileObject
->Flags
, FO_FILE_MODIFIED
);
888 SetLongFlag(Fcb
->Flags
, FCB_FILE_MODIFIED
);
891 NotifyFilter
= FILE_NOTIFY_CHANGE_SIZE
;
894 if (NT_SUCCESS(Status
)) {
896 Fcb
->Header
.FileSize
.QuadPart
= Mcb
->Inode
.i_size
= EndOfFile
.QuadPart
;
897 if (CcIsFileCached(FileObject
)) {
898 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)(&(Fcb
->Header
.AllocationSize
)));
901 if (Fcb
->Header
.FileSize
.QuadPart
>= 0x80000000 &&
902 !IsFlagOn(SUPER_BLOCK
->s_feature_ro_compat
, EXT2_FEATURE_RO_COMPAT_LARGE_FILE
)) {
903 SetFlag(SUPER_BLOCK
->s_feature_ro_compat
, EXT2_FEATURE_RO_COMPAT_LARGE_FILE
);
904 Ext2SaveSuper(IrpContext
, Vcb
);
907 SetFlag(FileObject
->Flags
, FO_FILE_MODIFIED
);
908 SetLongFlag(Fcb
->Flags
, FCB_FILE_MODIFIED
);
909 NotifyFilter
= FILE_NOTIFY_CHANGE_SIZE
;
913 Ext2SaveInode( IrpContext
, Vcb
, &Mcb
->Inode
);
915 DEBUG(DL_IO
, ("Ext2SetInformation: FileEndOfFileInformation %wZ EndofFile=%I64xh "
916 "AllocatieonSize=%I64xh FileSize=%I64xh VDL=%I64xh i_size=%I64xh status = %xh\n",
917 &Fcb
->Mcb
->ShortName
, EndOfFile
.QuadPart
, Fcb
->Header
.AllocationSize
.QuadPart
,
918 Fcb
->Header
.FileSize
.QuadPart
, Fcb
->Header
.ValidDataLength
.QuadPart
,
919 Mcb
->Inode
.i_size
, Status
));
924 case FileValidDataLengthInformation
:
926 PFILE_VALID_DATA_LENGTH_INFORMATION FVDL
= (PFILE_VALID_DATA_LENGTH_INFORMATION
) Buffer
;
927 LARGE_INTEGER NewVDL
;
929 if (IsMcbDirectory(Mcb
) || IsMcbSpecialFile(Mcb
)) {
930 Status
= STATUS_INVALID_DEVICE_REQUEST
;
933 Status
= STATUS_SUCCESS
;
936 NewVDL
= FVDL
->ValidDataLength
;
937 if ((NewVDL
.QuadPart
< Fcb
->Header
.ValidDataLength
.QuadPart
)) {
938 Status
= STATUS_INVALID_PARAMETER
;
941 if (NewVDL
.QuadPart
> Fcb
->Header
.FileSize
.QuadPart
)
942 NewVDL
= Fcb
->Header
.FileSize
;
944 if (!MmCanFileBeTruncated(FileObject
->SectionObjectPointer
,
946 Status
= STATUS_USER_MAPPED_FILE
;
950 Fcb
->Header
.ValidDataLength
= NewVDL
;
951 FileObject
->Flags
|= FO_FILE_MODIFIED
;
952 if (CcIsFileCached(FileObject
)) {
953 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)(&(Fcb
->Header
.AllocationSize
)));
959 case FileDispositionInformation
:
961 PFILE_DISPOSITION_INFORMATION FDI
= (PFILE_DISPOSITION_INFORMATION
)Buffer
;
963 Status
= Ext2SetDispositionInfo(IrpContext
, Vcb
, Fcb
, Ccb
, FDI
->DeleteFile
);
965 DEBUG(DL_INF
, ( "Ext2SetInformation: SetDispositionInformation: DeleteFile=%d %wZ status = %xh\n",
966 FDI
->DeleteFile
, &Mcb
->ShortName
, Status
));
971 case FileRenameInformation
:
973 Status
= Ext2SetRenameInfo(IrpContext
, Vcb
, Fcb
, Ccb
);
979 // This is the only set file information request supported on read
982 case FilePositionInformation
:
984 PFILE_POSITION_INFORMATION FilePositionInformation
;
986 if (Length
< sizeof(FILE_POSITION_INFORMATION
)) {
987 Status
= STATUS_INVALID_PARAMETER
;
991 FilePositionInformation
= (PFILE_POSITION_INFORMATION
) Buffer
;
993 if ((FlagOn(FileObject
->Flags
, FO_NO_INTERMEDIATE_BUFFERING
)) &&
994 (FilePositionInformation
->CurrentByteOffset
.LowPart
&
995 DeviceObject
->AlignmentRequirement
) ) {
996 Status
= STATUS_INVALID_PARAMETER
;
1000 FileObject
->CurrentByteOffset
=
1001 FilePositionInformation
->CurrentByteOffset
;
1003 Status
= STATUS_SUCCESS
;
1009 case FileLinkInformation
:
1011 Status
= STATUS_INVALID_DEVICE_REQUEST
;
1015 DEBUG(DL_WRN
, ( "Ext2SetInformation: invalid class: %d\n",
1016 FileInformationClass
));
1017 Status
= STATUS_INVALID_PARAMETER
;/* STATUS_INVALID_INFO_CLASS; */
1022 if (FcbPagingIoResourceAcquired
) {
1023 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
1026 if (NT_SUCCESS(Status
) && (NotifyFilter
!= 0)) {
1027 Ext2NotifyReportChange(
1032 FILE_ACTION_MODIFIED
);
1036 if (FcbMainResourceAcquired
) {
1037 ExReleaseResourceLite(&Fcb
->MainResource
);
1040 if (VcbMainResourceAcquired
) {
1041 ExReleaseResourceLite(&Vcb
->MainResource
);
1044 if (!IrpContext
->ExceptionInProgress
) {
1045 if (Status
== STATUS_PENDING
||
1046 Status
== STATUS_CANT_WAIT
) {
1048 Status
= Ext2QueueRequest(IrpContext
);
1050 Ext2CompleteIrpContext(IrpContext
, Status
);
1061 PLARGE_INTEGER Size
,
1065 ULONG Blocks
, Meta
=0, Remain
;
1067 Blocks
= (ULONG
)((Size
->QuadPart
+ BLOCK_SIZE
- 1) >> BLOCK_BITS
);
1068 if (Blocks
<= EXT2_NDIR_BLOCKS
)
1070 Blocks
-= EXT2_NDIR_BLOCKS
;
1073 if (Blocks
<= Vcb
->max_blocks_per_layer
[1]) {
1076 Blocks
-= Vcb
->max_blocks_per_layer
[1];
1080 if (Blocks
<= Vcb
->max_blocks_per_layer
[2]) {
1081 Meta
+= 1 + ((Blocks
+ BLOCK_SIZE
/4 - 1) >> (BLOCK_BITS
- 2));
1084 Meta
+= 1 + BLOCK_SIZE
/4;
1085 Blocks
-= Vcb
->max_blocks_per_layer
[2];
1087 if (Blocks
> Vcb
->max_blocks_per_layer
[3]) {
1088 Blocks
= Vcb
->max_blocks_per_layer
[3];
1091 ASSERT(Vcb
->max_blocks_per_layer
[2]);
1092 Remain
= Blocks
% Vcb
->max_blocks_per_layer
[2];
1093 Blocks
= Blocks
/ Vcb
->max_blocks_per_layer
[2];
1094 Meta
+= 1 + Blocks
* (1 + BLOCK_SIZE
/4);
1104 Blocks
= (ULONG
)((Size
->QuadPart
+ BLOCK_SIZE
- 1) >> BLOCK_BITS
);
1105 return (Blocks
+ Meta
);
1110 IN PEXT2_IRP_CONTEXT IrpContext
,
1121 if (INODE_HAS_EXTENT(&Mcb
->Inode
)) {
1122 status
= Ext2MapExtent(IrpContext
, Vcb
, Mcb
, Index
,
1123 bAlloc
, pBlock
, Number
);
1125 status
= Ext2MapIndirect(IrpContext
, Vcb
, Mcb
, Index
,
1126 bAlloc
, pBlock
, Number
);
1135 PEXT2_IRP_CONTEXT IrpContext
,
1141 NTSTATUS status
= STATUS_SUCCESS
;
1145 Start
= (ULONG
)((Mcb
->Inode
.i_size
+ BLOCK_SIZE
- 1) >> BLOCK_BITS
);
1146 End
= (ULONG
)((Size
->QuadPart
+ BLOCK_SIZE
- 1) >> BLOCK_BITS
);
1148 /* it's a truncate operation, not expanding */
1150 Size
->QuadPart
= ((LONGLONG
) Start
) << BLOCK_BITS
;
1151 return STATUS_SUCCESS
;
1154 /* ignore special files */
1155 if (IsMcbSpecialFile(Mcb
)) {
1156 return STATUS_INVALID_DEVICE_REQUEST
;
1159 /* expandind file extents */
1160 if (INODE_HAS_EXTENT(&Mcb
->Inode
)) {
1162 status
= Ext2ExpandExtent(IrpContext
, Vcb
, Mcb
, Start
, End
, Size
);
1168 #if EXT2_PRE_ALLOCATION_SUPPORT
1171 do_expand
= (IrpContext
->MajorFunction
== IRP_MJ_WRITE
) ||
1172 IsMcbDirectory(Mcb
);
1177 status
= Ext2ExpandIndirect(IrpContext
, Vcb
, Mcb
, Start
, End
, Size
);
1187 PEXT2_IRP_CONTEXT IrpContext
,
1193 NTSTATUS status
= STATUS_SUCCESS
;
1195 if (INODE_HAS_EXTENT(&Mcb
->Inode
)) {
1196 status
= Ext2TruncateExtent(IrpContext
, Vcb
, Mcb
, Size
);
1198 status
= Ext2TruncateIndirect(IrpContext
, Vcb
, Mcb
, Size
);
1201 /* check and clear data/meta mcb extents */
1202 if (Size
->QuadPart
== 0) {
1204 /* check and remove all data extents */
1205 if (Ext2ListExtents(&Mcb
->Extents
)) {
1208 Ext2ClearAllExtents(&Mcb
->Extents
);
1209 /* check and remove all meta extents */
1210 if (Ext2ListExtents(&Mcb
->MetaExts
)) {
1213 Ext2ClearAllExtents(&Mcb
->MetaExts
);
1214 ClearLongFlag(Mcb
->Flags
, MCB_ZONE_INITED
);
1221 Ext2IsFileRemovable(
1222 IN PEXT2_IRP_CONTEXT IrpContext
,
1228 PEXT2_MCB Mcb
= Fcb
->Mcb
;
1230 if (Mcb
->Inode
.i_ino
== EXT2_ROOT_INO
) {
1231 return STATUS_CANNOT_DELETE
;
1234 if (IsMcbDirectory(Mcb
)) {
1235 if (!Ext2IsDirectoryEmpty(IrpContext
, Vcb
, Mcb
)) {
1236 return STATUS_DIRECTORY_NOT_EMPTY
;
1240 if (!MmFlushImageSection(&Fcb
->SectionObject
,
1241 MmFlushForDelete
)) {
1242 return STATUS_CANNOT_DELETE
;
1245 if (IsMcbDirectory(Mcb
)) {
1246 FsRtlNotifyFullChangeDirectory(
1260 return STATUS_SUCCESS
;
1264 Ext2SetDispositionInfo(
1265 PEXT2_IRP_CONTEXT IrpContext
,
1272 PIRP Irp
= IrpContext
->Irp
;
1273 PIO_STACK_LOCATION IrpSp
;
1274 NTSTATUS status
= STATUS_SUCCESS
;
1275 PEXT2_MCB Mcb
= Fcb
->Mcb
;
1277 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
1279 DEBUG(DL_INF
, ( "Ext2SetDispositionInfo: bDelete=%x\n", bDelete
));
1283 DEBUG(DL_INF
, ( "Ext2SetDispositionInformation: Removing %wZ.\n",
1286 /* always allow deleting on symlinks */
1287 if (Ccb
->SymLink
== NULL
) {
1288 status
= Ext2IsFileRemovable(IrpContext
, Vcb
, Fcb
, Ccb
);
1291 if (NT_SUCCESS(status
)) {
1292 SetLongFlag(Fcb
->Flags
, FCB_DELETE_PENDING
);
1293 IrpSp
->FileObject
->DeletePending
= TRUE
;
1298 ClearLongFlag(Fcb
->Flags
, FCB_DELETE_PENDING
);
1299 IrpSp
->FileObject
->DeletePending
= FALSE
;
1307 PEXT2_IRP_CONTEXT IrpContext
,
1313 PEXT2_MCB Mcb
= Fcb
->Mcb
;
1315 PEXT2_FCB TargetDcb
= NULL
; /* Dcb of target directory */
1316 PEXT2_MCB TargetMcb
= NULL
;
1317 PEXT2_FCB ParentDcb
= NULL
; /* Dcb of it's current parent */
1318 PEXT2_MCB ParentMcb
= NULL
;
1320 PEXT2_FCB ExistingFcb
= NULL
; /* Target file Fcb if it exists*/
1321 PEXT2_MCB ExistingMcb
= NULL
;
1323 UNICODE_STRING FileName
;
1328 PIO_STACK_LOCATION IrpSp
;
1330 PFILE_OBJECT FileObject
;
1331 PFILE_OBJECT TargetObject
;
1333 struct dentry
*NewEntry
= NULL
;
1335 BOOLEAN ReplaceIfExists
;
1336 BOOLEAN bMove
= FALSE
;
1337 BOOLEAN bTargetRemoved
= FALSE
;
1339 BOOLEAN bNewTargetDcb
= FALSE
;
1340 BOOLEAN bNewParentDcb
= FALSE
;
1342 PFILE_RENAME_INFORMATION FRI
;
1348 if (Mcb
->Inode
.i_ino
== EXT2_ROOT_INO
) {
1349 Status
= STATUS_INVALID_PARAMETER
;
1353 Irp
= IrpContext
->Irp
;
1354 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
1356 FileObject
= IrpSp
->FileObject
;
1357 TargetObject
= IrpSp
->Parameters
.SetFile
.FileObject
;
1358 ReplaceIfExists
= IrpSp
->Parameters
.SetFile
.ReplaceIfExists
;
1360 FRI
= (PFILE_RENAME_INFORMATION
)Irp
->AssociatedIrp
.SystemBuffer
;
1362 if (TargetObject
== NULL
) {
1364 UNICODE_STRING NewName
;
1366 NewName
.Buffer
= FRI
->FileName
;
1367 NewName
.MaximumLength
= NewName
.Length
= (USHORT
)FRI
->FileNameLength
;
1369 while (NewName
.Length
> 0 && NewName
.Buffer
[NewName
.Length
/2 - 1] == L
'\\') {
1370 NewName
.Buffer
[NewName
.Length
/2 - 1] = 0;
1371 NewName
.Length
-= 2;
1374 while (NewName
.Length
> 0 && NewName
.Buffer
[NewName
.Length
/2 - 1] != L
'\\') {
1375 NewName
.Length
-= 2;
1378 NewName
.Buffer
= (USHORT
*)((UCHAR
*)NewName
.Buffer
+ NewName
.Length
);
1379 NewName
.Length
= (USHORT
)(FRI
->FileNameLength
- NewName
.Length
);
1383 TargetMcb
= Mcb
->Parent
;
1384 if (IsMcbSymLink(TargetMcb
)) {
1385 TargetMcb
= TargetMcb
->Target
;
1386 ASSERT(!IsMcbSymLink(TargetMcb
));
1389 if (TargetMcb
== NULL
|| FileName
.Length
>= EXT2_NAME_LEN
*2) {
1390 Status
= STATUS_OBJECT_NAME_INVALID
;
1396 TargetDcb
= (PEXT2_FCB
)(TargetObject
->FsContext
);
1398 if (!TargetDcb
|| TargetDcb
->Vcb
!= Vcb
) {
1402 Status
= STATUS_INVALID_PARAMETER
;
1406 TargetMcb
= TargetDcb
->Mcb
;
1407 FileName
= TargetObject
->FileName
;
1410 if (FsRtlDoesNameContainWildCards(&FileName
)) {
1411 Status
= STATUS_OBJECT_NAME_INVALID
;
1415 if (TargetMcb
->Inode
.i_ino
== Mcb
->Parent
->Inode
.i_ino
) {
1416 if (FsRtlAreNamesEqual( &FileName
,
1420 Status
= STATUS_SUCCESS
;
1427 TargetDcb
= TargetMcb
->Fcb
;
1428 if (TargetDcb
== NULL
) {
1429 TargetDcb
= Ext2AllocateFcb(Vcb
, TargetMcb
);
1431 Ext2ReferXcb(&TargetDcb
->ReferenceCount
);
1432 bNewTargetDcb
= TRUE
;
1436 SetLongFlag(TargetDcb
->Flags
, FCB_STATE_BUSY
);
1439 ParentMcb
= Mcb
->Parent
;
1440 ParentDcb
= ParentMcb
->Fcb
;
1442 if ((TargetMcb
->Inode
.i_ino
!= ParentMcb
->Inode
.i_ino
)) {
1444 if (ParentDcb
== NULL
) {
1445 ParentDcb
= Ext2AllocateFcb(Vcb
, ParentMcb
);
1447 Ext2ReferXcb(&ParentDcb
->ReferenceCount
);
1448 bNewParentDcb
= TRUE
;
1452 SetLongFlag(ParentDcb
->Flags
, FCB_STATE_BUSY
);
1456 if (!TargetDcb
|| !ParentDcb
) {
1457 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1461 DEBUG(DL_RES
, ("Ext2SetRenameInfo: rename %wZ to %wZ\\%wZ\n",
1462 &Mcb
->FullName
, &TargetMcb
->FullName
, &FileName
));
1464 Status
= Ext2LookupFile(
1473 if (NT_SUCCESS(Status
) && ExistingMcb
!= Mcb
) {
1475 if (!ReplaceIfExists
) {
1477 Status
= STATUS_OBJECT_NAME_COLLISION
;
1478 DEBUG(DL_RES
, ("Ext2SetRenameInfo: Target file %wZ exists\n",
1479 &ExistingMcb
->FullName
));
1484 if ( (ExistingFcb
= ExistingMcb
->Fcb
) && !IsMcbSymLink(ExistingMcb
) ) {
1486 Status
= Ext2IsFileRemovable(IrpContext
, Vcb
, ExistingFcb
, Ccb
);
1487 if (!NT_SUCCESS(Status
)) {
1488 DEBUG(DL_REN
, ("Ext2SetRenameInfo: Target file %wZ cannot be removed.\n",
1489 &ExistingMcb
->FullName
));
1494 Status
= Ext2DeleteFile(IrpContext
, Vcb
, ExistingFcb
, ExistingMcb
);
1495 if (!NT_SUCCESS(Status
)) {
1496 DEBUG(DL_REN
, ("Ext2SetRenameInfo: Failed to delete %wZ with status: %xh.\n",
1497 &FileName
, Status
));
1502 bTargetRemoved
= TRUE
;
1506 /* remove directory entry of old name */
1507 Status
= Ext2RemoveEntry(IrpContext
, Vcb
, ParentDcb
, Mcb
);
1508 if (!NT_SUCCESS(Status
)) {
1509 DEBUG(DL_REN
, ("Ext2SetRenameInfo: Failed to remove entry %wZ with status %xh.\n",
1510 &Mcb
->FullName
, Status
));
1515 /* add new entry for new target name */
1516 Status
= Ext2AddEntry(IrpContext
, Vcb
, TargetDcb
, &Mcb
->Inode
, &FileName
, &NewEntry
);
1517 if (!NT_SUCCESS(Status
)) {
1518 DEBUG(DL_REN
, ("Ext2SetRenameInfo: Failed to add entry for %wZ with status: %xh.\n",
1519 &FileName
, Status
));
1520 Ext2AddEntry(IrpContext
, Vcb
, ParentDcb
, &Mcb
->Inode
, &Mcb
->ShortName
, &NewEntry
);
1524 /* correct the inode number in .. entry */
1525 if (IsMcbDirectory(Mcb
)) {
1526 Status
= Ext2SetParentEntry(
1527 IrpContext
, Vcb
, Fcb
,
1528 ParentMcb
->Inode
.i_ino
,
1529 TargetMcb
->Inode
.i_ino
);
1530 if (!NT_SUCCESS(Status
)) {
1531 DEBUG(DL_REN
, ("Ext2SetRenameInfo: Failed to set parent refer of %wZ with %xh.\n",
1532 &Mcb
->FullName
, Status
));
1538 /* Update current dentry from the newly created one. We need keep the original
1539 dentry to assure children's links are valid if current entry is a directory */
1541 char *np
= Mcb
->de
->d_name
.name
;
1542 *(Mcb
->de
) = *NewEntry
;
1543 NewEntry
->d_name
.name
= np
;
1546 if (bTargetRemoved
) {
1547 Ext2NotifyReportChange(
1551 (IsMcbDirectory(ExistingMcb
) ?
1552 FILE_NOTIFY_CHANGE_DIR_NAME
:
1553 FILE_NOTIFY_CHANGE_FILE_NAME
),
1554 FILE_ACTION_REMOVED
);
1557 if (NT_SUCCESS(Status
)) {
1560 Ext2NotifyReportChange(
1565 FILE_NOTIFY_CHANGE_DIR_NAME
:
1566 FILE_NOTIFY_CHANGE_FILE_NAME
),
1567 FILE_ACTION_REMOVED
);
1570 Ext2NotifyReportChange(
1575 FILE_NOTIFY_CHANGE_DIR_NAME
:
1576 FILE_NOTIFY_CHANGE_FILE_NAME
),
1577 FILE_ACTION_RENAMED_OLD_NAME
);
1581 if (TargetMcb
->Inode
.i_ino
!= ParentMcb
->Inode
.i_ino
) {
1582 Ext2RemoveMcb(Vcb
, Mcb
);
1583 Ext2InsertMcb(Vcb
, TargetMcb
, Mcb
);
1586 if (!Ext2BuildName( &Mcb
->ShortName
,
1587 &FileName
, NULL
)) {
1588 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1592 if (!Ext2BuildName( &Mcb
->FullName
,
1594 &TargetMcb
->FullName
)) {
1595 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1600 Ext2NotifyReportChange(
1605 FILE_NOTIFY_CHANGE_DIR_NAME
:
1606 FILE_NOTIFY_CHANGE_FILE_NAME
),
1609 Ext2NotifyReportChange(
1614 FILE_NOTIFY_CHANGE_DIR_NAME
:
1615 FILE_NOTIFY_CHANGE_FILE_NAME
),
1616 FILE_ACTION_RENAMED_NEW_NAME
);
1624 Ext2FreeEntry(NewEntry
);
1627 if (ParentDcb
&& ParentDcb
->Inode
->i_ino
!= TargetDcb
->Inode
->i_ino
) {
1628 ClearLongFlag(ParentDcb
->Flags
, FCB_STATE_BUSY
);
1630 ClearLongFlag(TargetDcb
->Flags
, FCB_STATE_BUSY
);
1633 if (bNewTargetDcb
) {
1634 ASSERT(TargetDcb
!= NULL
);
1635 if (Ext2DerefXcb(&TargetDcb
->ReferenceCount
) == 0) {
1636 Ext2FreeFcb(TargetDcb
);
1639 DEBUG(DL_RES
, ( "Ext2SetRenameInfo: TargetDcb is resued by other threads.\n"));
1643 if (bNewParentDcb
) {
1644 ASSERT(ParentDcb
!= NULL
);
1645 if (Ext2DerefXcb(&ParentDcb
->ReferenceCount
) == 0) {
1646 Ext2FreeFcb(ParentDcb
);
1649 DEBUG(DL_RES
, ( "Ext2SetRenameInfo: ParentDcb is resued by other threads.\n"));
1654 Ext2DerefMcb(ExistingMcb
);
1660 Ext2InodeType(PEXT2_MCB Mcb
)
1662 if (IsMcbSymLink(Mcb
)) {
1663 return EXT2_FT_SYMLINK
;
1666 if (IsMcbDirectory(Mcb
)) {
1670 return EXT2_FT_REG_FILE
;
1675 PEXT2_IRP_CONTEXT IrpContext
,
1681 PEXT2_FCB Dcb
= NULL
;
1683 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1685 BOOLEAN VcbResourceAcquired
= FALSE
;
1686 BOOLEAN FcbPagingIoAcquired
= FALSE
;
1687 BOOLEAN FcbResourceAcquired
= FALSE
;
1688 BOOLEAN DcbResourceAcquired
= FALSE
;
1691 LARGE_INTEGER SysTime
;
1693 BOOLEAN bNewDcb
= FALSE
;
1695 DEBUG(DL_INF
, ( "Ext2DeleteFile: File %wZ (%xh) will be deleted!\n",
1696 &Mcb
->FullName
, Mcb
->Inode
.i_ino
));
1698 if (IsFlagOn(Mcb
->Flags
, MCB_FILE_DELETED
)) {
1699 return STATUS_SUCCESS
;
1702 if (!IsMcbSymLink(Mcb
) && IsMcbDirectory(Mcb
)) {
1703 if (!Ext2IsDirectoryEmpty(IrpContext
, Vcb
, Mcb
)) {
1704 return STATUS_DIRECTORY_NOT_EMPTY
;
1713 ExAcquireResourceExclusiveLite(&Vcb
->MainResource
, TRUE
);
1714 VcbResourceAcquired
= TRUE
;
1716 if (!(Dcb
= Mcb
->Parent
->Fcb
)) {
1717 Dcb
= Ext2AllocateFcb(Vcb
, Mcb
->Parent
);
1719 Ext2ReferXcb(&Dcb
->ReferenceCount
);
1725 SetLongFlag(Dcb
->Flags
, FCB_STATE_BUSY
);
1726 DcbResourceAcquired
=
1727 ExAcquireResourceExclusiveLite(&Dcb
->MainResource
, TRUE
);
1729 /* remove it's entry form it's parent */
1730 Status
= Ext2RemoveEntry(IrpContext
, Vcb
, Dcb
, Mcb
);
1733 if (NT_SUCCESS(Status
)) {
1735 SetFlag(Mcb
->Flags
, MCB_FILE_DELETED
);
1736 Ext2RemoveMcb(Vcb
, Mcb
);
1739 FcbResourceAcquired
=
1740 ExAcquireResourceExclusiveLite(&Fcb
->MainResource
, TRUE
);
1742 FcbPagingIoAcquired
=
1743 ExAcquireResourceExclusiveLite(&Fcb
->PagingIoResource
, TRUE
);
1746 if (DcbResourceAcquired
) {
1747 ExReleaseResourceLite(&Dcb
->MainResource
);
1748 DcbResourceAcquired
= FALSE
;
1751 if (VcbResourceAcquired
) {
1752 ExReleaseResourceLite(&Vcb
->MainResource
);
1753 VcbResourceAcquired
= FALSE
;
1756 if (IsMcbSymLink(Mcb
)) {
1757 if (Mcb
->Inode
.i_nlink
> 0) {
1758 Status
= STATUS_CANNOT_DELETE
;
1761 } else if (!IsMcbDirectory(Mcb
)) {
1762 if (Mcb
->Inode
.i_nlink
> 0) {
1766 if (Mcb
->Inode
.i_nlink
>= 2) {
1771 if (S_ISLNK(Mcb
->Inode
.i_mode
)) {
1773 /* for symlink, we should do differenctly */
1774 if (Mcb
->Inode
.i_size
> EXT2_LINKLEN_IN_INODE
) {
1775 Size
.QuadPart
= (LONGLONG
)0;
1776 Status
= Ext2TruncateFile(IrpContext
, Vcb
, Mcb
, &Size
);
1781 /* truncate file size */
1782 Size
.QuadPart
= (LONGLONG
)0;
1783 Status
= Ext2TruncateFile(IrpContext
, Vcb
, Mcb
, &Size
);
1785 /* check file offset mappings */
1786 DEBUG(DL_EXT
, ("Ext2DeleteFile ...: %wZ\n", &Mcb
->FullName
));
1789 Fcb
->Header
.AllocationSize
.QuadPart
= Size
.QuadPart
;
1790 if (Fcb
->Header
.FileSize
.QuadPart
> Size
.QuadPart
) {
1791 Fcb
->Header
.FileSize
.QuadPart
= Size
.QuadPart
;
1792 Fcb
->Mcb
->Inode
.i_size
= Size
.QuadPart
;
1794 if (Fcb
->Header
.ValidDataLength
.QuadPart
> Fcb
->Header
.FileSize
.QuadPart
) {
1795 Fcb
->Header
.ValidDataLength
.QuadPart
= Fcb
->Header
.FileSize
.QuadPart
;
1798 /* Update the inode's data length . It should be ZERO if succeeds. */
1799 if (Mcb
->Inode
.i_size
> (loff_t
)Size
.QuadPart
) {
1800 Mcb
->Inode
.i_size
= Size
.QuadPart
;
1805 /* set delete time and free the inode */
1806 KeQuerySystemTime(&SysTime
);
1807 Mcb
->Inode
.i_nlink
= 0;
1808 Mcb
->Inode
.i_dtime
= Ext2LinuxTime(SysTime
);
1809 Ext2SaveInode(IrpContext
, Vcb
, &Mcb
->Inode
);
1810 Ext2FreeInode(IrpContext
, Vcb
, Mcb
->Inode
.i_ino
, Ext2InodeType(Mcb
));
1815 if (FcbPagingIoAcquired
) {
1816 ExReleaseResourceLite(&Fcb
->PagingIoResource
);
1819 if (FcbResourceAcquired
) {
1820 ExReleaseResourceLite(&Fcb
->MainResource
);
1823 if (DcbResourceAcquired
) {
1824 ExReleaseResourceLite(&Dcb
->MainResource
);
1828 ClearLongFlag(Dcb
->Flags
, FCB_STATE_BUSY
);
1830 if (Ext2DerefXcb(&Dcb
->ReferenceCount
) == 0) {
1833 DEBUG(DL_ERR
, ( "Ext2DeleteFile: Dcb %wZ used by other threads.\n",
1838 if (VcbResourceAcquired
) {
1839 ExReleaseResourceLite(&Vcb
->MainResource
);
1845 DEBUG(DL_INF
, ( "Ext2DeleteFile: %wZ Succeed... EXT2SB->S_FREE_BLOCKS = %I64xh .\n",
1846 &Mcb
->FullName
, ext3_free_blocks_count(SUPER_BLOCK
)));