1 /*************************************************************************
5 * Module: Ext2 File System Driver (Kernel mode execution only)
8 * Contains code to handle the "set/query file information" dispatch
11 * Author: Manoj Paul Joseph
14 *************************************************************************/
18 // define the file specific bug-check id
19 #define EXT2_BUG_CHECK_ID EXT2_FILE_INFORMATION
20 #define DEBUG_LEVEL (DEBUG_TRACE_FILEINFO)
23 /*************************************************************************
25 * Function: Ext2FileInfo()
28 * The I/O Manager will invoke this routine to handle a set/query file
31 * Expected Interrupt Level (for execution) :
33 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
34 * to be deferred to a worker thread context)
36 * Return Value: STATUS_SUCCESS/Error
38 *************************************************************************/
39 NTSTATUS NTAPI
Ext2FileInfo(
40 PDEVICE_OBJECT DeviceObject
, // the logical volume device object
41 PIRP Irp
) // I/O Request Packet
43 NTSTATUS RC
= STATUS_SUCCESS
;
44 PtrExt2IrpContext PtrIrpContext
= NULL
;
45 BOOLEAN AreWeTopLevel
= FALSE
;
47 DebugTrace(DEBUG_TRACE_IRP_ENTRY
, "File Info Control IRP received...", 0);
49 FsRtlEnterFileSystem();
54 // set the top level context
55 AreWeTopLevel
= Ext2IsIrpTopLevel(Irp
);
60 // get an IRP context structure and issue the request
61 PtrIrpContext
= Ext2AllocateIrpContext(Irp
, DeviceObject
);
62 ASSERT(PtrIrpContext
);
64 RC
= Ext2CommonFileInfo(PtrIrpContext
, Irp
);
67 except (Ext2ExceptionFilter(PtrIrpContext
, GetExceptionInformation()))
70 RC
= Ext2ExceptionHandler(PtrIrpContext
, Irp
);
72 Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR
, RC
);
77 IoSetTopLevelIrp(NULL
);
80 FsRtlExitFileSystem();
87 /*************************************************************************
89 * Function: Ext2CommonFileInfo()
92 * The actual work is performed here. This routine may be invoked in one'
93 * of the two possible contexts:
94 * (a) in the context of a system worker thread
95 * (b) in the context of the original caller
97 * Expected Interrupt Level (for execution) :
101 * Return Value: STATUS_SUCCESS/Error
103 *************************************************************************/
104 NTSTATUS NTAPI
Ext2CommonFileInfo(
105 PtrExt2IrpContext PtrIrpContext
,
108 NTSTATUS RC
= STATUS_SUCCESS
;
109 PIO_STACK_LOCATION PtrIoStackLocation
= NULL
;
110 PFILE_OBJECT PtrFileObject
= NULL
;
111 PtrExt2FCB PtrFCB
= NULL
;
112 PtrExt2CCB PtrCCB
= NULL
;
113 PtrExt2VCB PtrVCB
= NULL
;
114 PtrExt2NTRequiredFCB PtrReqdFCB
= NULL
;
115 BOOLEAN MainResourceAcquired
= FALSE
;
116 BOOLEAN VCBResourceAcquired
= FALSE
;
117 BOOLEAN PagingIoResourceAcquired
= FALSE
;
118 void *PtrSystemBuffer
= NULL
;
119 long BufferLength
= 0;
120 FILE_INFORMATION_CLASS FunctionalityRequested
;
121 BOOLEAN CanWait
= FALSE
;
122 BOOLEAN PostRequest
= FALSE
;
126 // First, get a pointer to the current I/O stack location.
127 PtrIoStackLocation
= IoGetCurrentIrpStackLocation(PtrIrp
);
128 ASSERT(PtrIoStackLocation
);
130 PtrFileObject
= PtrIoStackLocation
->FileObject
;
131 ASSERT(PtrFileObject
);
133 // Get the FCB and CCB pointers
134 Ext2GetFCB_CCB_VCB_FromFileObject (
135 PtrFileObject
, &PtrFCB
, &PtrCCB
, &PtrVCB
);
137 PtrReqdFCB
= &(PtrFCB
->NTRequiredFCB
);
139 CanWait
= ((PtrIrpContext
->IrpContextFlags
& EXT2_IRP_CONTEXT_CAN_BLOCK
) ? TRUE
: FALSE
);
141 // If the caller has opened a logical volume and is attempting to
142 // query information for it as a file stream, return an error.
143 if (PtrFCB
->NodeIdentifier
.NodeType
== EXT2_NODE_TYPE_VCB
)
145 // This is not allowed. Caller must use get/set volume information instead.
146 RC
= STATUS_INVALID_PARAMETER
;
150 // ASSERT(PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB);
153 PtrSystemBuffer
= PtrIrp
->AssociatedIrp
.SystemBuffer
;
155 if (PtrIoStackLocation
->MajorFunction
== IRP_MJ_QUERY_INFORMATION
)
157 // ***********************
158 // Query File Information
159 // ***********************
161 // Now, obtain some parameters.
162 DebugTrace(DEBUG_TRACE_MISC
, "Buffer length = 0x%lX[FileInfo]", BufferLength
);
164 BufferLength
= PtrIoStackLocation
->Parameters
.QueryFile
.Length
;
166 FunctionalityRequested
= PtrIoStackLocation
->Parameters
.QueryFile
.FileInformationClass
;
168 // Read in the file inode if it hasn't already been read...
169 Ext2InitializeFCBInodeInfo( PtrFCB
);
172 // Acquire the MainResource shared
173 // except for page files...
175 if (!(PtrFCB
->FCBFlags
& EXT2_FCB_PAGE_FILE
))
177 // Acquire the MainResource shared.
178 DebugTrace(DEBUG_TRACE_MISC
, "*** Attempting to acquire FCB Shared [FileInfo]", 0);
179 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", PtrReqdFCB
->MainResource
.ActiveCount
, PtrReqdFCB
->MainResource
.NumberOfExclusiveWaiters
, PtrReqdFCB
->MainResource
.NumberOfSharedWaiters
);
180 if (!ExAcquireResourceSharedLite(&(PtrReqdFCB
->MainResource
), CanWait
))
182 DebugTrace(DEBUG_TRACE_MISC
, "*** FCB acquisition FAILED [FileInfo]", 0);
184 try_return(RC
= STATUS_PENDING
);
186 MainResourceAcquired
= TRUE
;
187 DebugTrace(DEBUG_TRACE_MISC
, "*** FCB acquired [FileInfo]", 0);
190 // Do whatever the caller asked us to do
191 switch (FunctionalityRequested
)
193 case FileBasicInformation
:
194 DebugTrace(DEBUG_TRACE_FILEINFO
, "FileBasicInformation requested for %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
195 RC
= Ext2GetBasicInformation(PtrFCB
, (PFILE_BASIC_INFORMATION
)PtrSystemBuffer
, &BufferLength
);
197 case FileStandardInformation
:
198 DebugTrace(DEBUG_TRACE_FILEINFO
, "FileStandardInformation requested for %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
199 RC
= Ext2GetStandardInformation(PtrFCB
, (PFILE_STANDARD_INFORMATION
)PtrSystemBuffer
, &BufferLength
);
201 // Similarly, implement all of the other query information routines
202 // that your FSD can support.
203 #if(_WIN32_WINNT >= 0x0400)
204 case FileNetworkOpenInformation
:
205 DebugTrace(DEBUG_TRACE_FILEINFO
, "FileNetworkOpenInformation requested for %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
206 RC
= Ext2GetNetworkOpenInformation(PtrFCB
, (PFILE_NETWORK_OPEN_INFORMATION
)PtrSystemBuffer
, &BufferLength
);
207 // RC = STATUS_INVALID_PARAMETER;
210 #endif // _WIN32_WINNT >= 0x0400
211 case FileInternalInformation
:
212 DebugTrace(DEBUG_TRACE_FILEINFO
, "FileInternalInformation requested for %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
213 // RC = Ext2GetInternalInformation(...);
214 RC
= STATUS_INVALID_PARAMETER
;
217 case FileEaInformation
:
218 DebugTrace(DEBUG_TRACE_FILEINFO
, "FileEaInformation requested for %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
220 PFILE_EA_INFORMATION EaInformation
;
221 EaInformation
= (PFILE_EA_INFORMATION
) PtrSystemBuffer
;
222 EaInformation
->EaSize
= 0;
223 BufferLength
= sizeof( FILE_EA_INFORMATION
);
226 // RC = Ext2GetEaInformation(...);
229 case FilePositionInformation
:
230 DebugTrace(DEBUG_TRACE_FILEINFO
, "FilePositionInformation requested for %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
231 // This is fairly simple. Copy over the information from the
234 PFILE_POSITION_INFORMATION PtrFileInfoBuffer
;
236 PtrFileInfoBuffer
= (PFILE_POSITION_INFORMATION
)PtrSystemBuffer
;
238 ASSERT(BufferLength
>= sizeof(FILE_POSITION_INFORMATION
));
239 PtrFileInfoBuffer
->CurrentByteOffset
= PtrFileObject
->CurrentByteOffset
;
240 // Modify the local variable for BufferLength appropriately.
241 BufferLength
= sizeof(FILE_POSITION_INFORMATION
);
244 case FileStreamInformation
:
245 DebugTrace(DEBUG_TRACE_FILEINFO
, "FileStreamInformation requested for %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
246 // RC = Ext2GetFileStreamInformation(...);
248 RC
= STATUS_INVALID_PARAMETER
;
252 case FileAllInformation
:
253 DebugTrace(DEBUG_TRACE_FILEINFO
, "FileAllInformation requested for %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
254 // The I/O Manager supplies the Mode, Access, and Alignment
255 // information. The rest is up to us to provide.
256 // Therefore, decrement the BufferLength appropriately (assuming
257 // that the above 3 types on information are already in the
261 PFILE_POSITION_INFORMATION PtrFileInfoBuffer
;
262 PFILE_ALL_INFORMATION PtrAllInfo
= (PFILE_ALL_INFORMATION
)PtrSystemBuffer
;
264 // Fill in the position information.
266 PtrFileInfoBuffer
= (PFILE_POSITION_INFORMATION
)&(PtrAllInfo
->PositionInformation
);
268 PtrFileInfoBuffer
->CurrentByteOffset
= PtrFileObject
->CurrentByteOffset
;
270 // Modify the local variable for BufferLength appropriately.
271 BufferLength
= sizeof(FILE_ALL_INFORMATION
);
273 // Get the remaining stuff.
274 if (!NT_SUCCESS(RC
= Ext2GetBasicInformation(PtrFCB
, (PFILE_BASIC_INFORMATION
)&(PtrAllInfo
->BasicInformation
),
279 if (!NT_SUCCESS(RC
= Ext2GetStandardInformation(PtrFCB
, &(PtrAllInfo
->StandardInformation
), &BufferLength
)))
283 // Similarly, get all of the others ...
286 case FileNameInformation
:
287 DebugTrace(DEBUG_TRACE_FILEINFO
, "FileNameInformation requested for %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
288 // RC = Ext2GetFullNameInformation(...);
289 RC
= Ext2GetFullNameInformation(PtrFCB
, PtrCCB
, (PFILE_NAME_INFORMATION
)PtrSystemBuffer
, &BufferLength
);
291 case FileAlternateNameInformation
:
292 DebugTrace(DEBUG_TRACE_FILEINFO
, "FileAlternateNameInformation requested for %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
293 RC
= STATUS_INVALID_PARAMETER
;
295 // RC = Ext2GetAltNameInformation(...);
297 case FileCompressionInformation
:
298 DebugTrace(DEBUG_TRACE_FILEINFO
, "FileCompressionInformation requested for %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
299 RC
= STATUS_INVALID_PARAMETER
;
301 // RC = Ext2GetCompressionInformation(...);
305 RC
= STATUS_INVALID_PARAMETER
;
309 // If we completed successfully, the return the amount of information transferred.
312 PtrIrp
->IoStatus
.Information
= BufferLength
;
316 PtrIrp
->IoStatus
.Information
= 0;
322 // ***********************
323 // Set File Information
324 // ***********************
325 ASSERT(PtrIoStackLocation
->MajorFunction
== IRP_MJ_SET_INFORMATION
);
327 DebugTrace(DEBUG_TRACE_FILEINFO
, ">>>>>>>> Set File Information <<<<<<<<< [FileInfo]", 0);
330 // Now, obtain some parameters.
331 FunctionalityRequested
= PtrIoStackLocation
->Parameters
.SetFile
.FileInformationClass
;
336 // Acquire the VCB resource exclusively for
337 // deletion, rename and link operations...
338 // To synchronize with create and cleanup operations
340 if ((FunctionalityRequested
== FileDispositionInformation
) ||
341 (FunctionalityRequested
== FileRenameInformation
) ||
342 (FunctionalityRequested
== FileLinkInformation
))
344 DebugTrace(DEBUG_TRACE_MISC
, "*** Attempting to acquire VCB Exclusively [FileInfo]", 0);
345 DebugTraceState( " VCB AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", PtrVCB
->VCBResource
.ActiveCount
, PtrVCB
->VCBResource
.NumberOfExclusiveWaiters
, PtrVCB
->VCBResource
.NumberOfSharedWaiters
);
346 if (!ExAcquireResourceExclusiveLite(&(PtrVCB
->VCBResource
), CanWait
))
348 DebugTrace(DEBUG_TRACE_MISC
, "*** VCB Acquisition FAILED [FileInfo]", 0);
350 try_return(RC
= STATUS_PENDING
);
352 // We have the VCB acquired exclusively.
353 DebugTrace(DEBUG_TRACE_MISC
, "*** VCB Acquired [FileInfo]", 0);
354 VCBResourceAcquired
= TRUE
;
358 // Acquire the FCB exclusively at this time...
359 if (!(PtrFCB
->FCBFlags
& EXT2_FCB_PAGE_FILE
))
361 // Acquire the MainResource shared.
362 DebugTrace(DEBUG_TRACE_MISC
, "*** Attempting to acquire FCB Exclusively [FileInfo]", 0);
363 DebugTraceState( " FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", PtrReqdFCB
->MainResource
.ActiveCount
, PtrReqdFCB
->MainResource
.NumberOfExclusiveWaiters
, PtrReqdFCB
->MainResource
.NumberOfSharedWaiters
);
364 if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB
->MainResource
), CanWait
))
366 DebugTrace(DEBUG_TRACE_MISC
, "*** FCB Acquisition FAILED [FileInfo]", 0);
368 try_return(RC
= STATUS_PENDING
);
370 MainResourceAcquired
= TRUE
;
371 DebugTrace(DEBUG_TRACE_MISC
, "*** FCB Acquired [FileInfo]", 0);
375 // For delete link (rename),
376 // set allocation size, and set EOF, should also acquire the paging-IO
377 // resource, thereby synchronizing with paging-IO requests.
381 DebugTrace(DEBUG_TRACE_FILE_OBJ
, "###### File Pointer 0x%LX [FileInfo]", PtrFileObject
);
384 DebugTrace(DEBUG_TRACE_MISC
, "*** Attempting to acquire FCBPaging Exclusively [FileInfo]", 0);
385 DebugTraceState( " FCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", PtrReqdFCB
->PagingIoResource
.ActiveCount
, PtrReqdFCB
->PagingIoResource
.NumberOfExclusiveWaiters
, PtrReqdFCB
->PagingIoResource
.NumberOfSharedWaiters
);
386 if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB
->PagingIoResource
), CanWait
))
388 DebugTrace(DEBUG_TRACE_MISC
, "*** Attempt to acquire FCBPaging FAILED [FileInfo]", 0);
390 try_return(RC
= STATUS_PENDING
);
392 PagingIoResourceAcquired
= TRUE
;
393 DebugTrace(DEBUG_TRACE_MISC
, "*** Acquired FCBPaging [FileInfo]", 0);
395 // Do whatever the caller asked us to do
396 switch (FunctionalityRequested
)
398 case FileBasicInformation
:
399 DebugTrace(DEBUG_TRACE_FILEINFO
, "Attempt to set FileBasicInformation for %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
400 RC
= Ext2SetBasicInformation(PtrIrpContext
, PtrFCB
, PtrFileObject
, (PFILE_BASIC_INFORMATION
)PtrSystemBuffer
);
401 // RC = STATUS_ACCESS_DENIED;
403 case FileAllocationInformation
:
404 DebugTrace(DEBUG_TRACE_FILEINFO
, "Attempt to set FileAllocationInformation for %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
405 RC
= Ext2SetAllocationInformation(PtrFCB
, PtrCCB
, PtrVCB
, PtrFileObject
,
406 PtrIrpContext
, PtrIrp
, PtrSystemBuffer
);
408 case FileEndOfFileInformation
:
409 DebugTrace(DEBUG_TRACE_FILEINFO
, "Attempt to set FileEndOfFileInformation for %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
410 // RC = Ext2SetEOF(...);
411 RC
= STATUS_INVALID_PARAMETER
;
415 case FilePositionInformation
:
416 DebugTrace(DEBUG_TRACE_FILEINFO
, "Attempt to set FilePositionInformation for %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
417 // Check if no intermediate buffering has been specified.
418 // If it was specified, do not allow non-aligned set file
419 // position requests to succeed.
421 PFILE_POSITION_INFORMATION PtrFileInfoBuffer
;
423 PtrFileInfoBuffer
= (PFILE_POSITION_INFORMATION
)PtrSystemBuffer
;
425 if (PtrFileObject
->Flags
& FO_NO_INTERMEDIATE_BUFFERING
)
427 if (PtrFileInfoBuffer
->CurrentByteOffset
.LowPart
& PtrIoStackLocation
->DeviceObject
->AlignmentRequirement
)
429 // Invalid alignment.
430 try_return(RC
= STATUS_INVALID_PARAMETER
);
433 PtrFileObject
->CurrentByteOffset
= PtrFileInfoBuffer
->CurrentByteOffset
;
437 case FileDispositionInformation
:
438 DebugTrace(DEBUG_TRACE_FILEINFO
, "Attempt to set FileDispositionInformation for %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
439 RC
= Ext2SetDispositionInformation(PtrFCB
, PtrCCB
, PtrVCB
, PtrFileObject
,
440 PtrIrpContext
, PtrIrp
,
441 (PFILE_DISPOSITION_INFORMATION
)PtrSystemBuffer
);
444 case FileRenameInformation
:
445 DebugTrace(DEBUG_TRACE_FILEINFO
, "Attempt to set FileRenameInformation for %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
446 RC
= Ext2RenameOrLinkFile( PtrFCB
, PtrFileObject
, PtrIrpContext
,
447 PtrIrp
, (PFILE_RENAME_INFORMATION
)PtrSystemBuffer
);
449 case FileLinkInformation
:
450 DebugTrace(DEBUG_TRACE_FILEINFO
, "Attempt to set FileLinkInformation for %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
451 RC
= STATUS_INVALID_PARAMETER
;
453 // When you implement your rename/link routine, be careful to
454 // check the following two arguments:
455 // TargetFileObject = PtrIoStackLocation->Parameters.SetFile.FileObject;
456 // ReplaceExistingFile = PtrIoStackLocation->Parameters.SetFile.ReplaceIfExists;
458 // The TargetFileObject argument is a pointer to the "target
459 // directory" file object obtained during the "create" routine
460 // invoked by the NT I/O Manager with the SL_OPEN_TARGET_DIRECTORY
461 // flag specified. Remember that it is quite possible that if the
462 // rename/link is contained within a single directory, the target
463 // and source directories will be the same.
464 // The ReplaceExistingFile argument should be used by you to
465 // determine if the caller wishes to replace the target (if it
466 // currently exists) with the new link/renamed file. If this
467 // value is FALSE, and if the target directory entry (being
468 // renamed-to, or the target of the link) exists, you should
469 // return a STATUS_OBJECT_NAME_COLLISION error to the caller.
471 // RC = Ext2RenameOrLinkFile(PtrFCB, PtrCCB, PtrFileObject, PtrIrpContext,
472 // PtrIrp, (PFILE_RENAME_INFORMATION)PtrSystemBuffer);
474 // Once you have completed the rename/link operation, do not
475 // forget to notify any "notify IRPs" about the actions you have
477 // An example is if you renamed across directories, you should
478 // report that a new entry was added with the FILE_ACTION_ADDED
479 // action type. The actual modification would then be reported
480 // as either FILE_NOTIFY_CHANGE_FILE_NAME (if a file was renamed)
481 // or FILE_NOTIFY_CHANGE_DIR_NAME (if a directory was renamed).
485 DebugTrace(DEBUG_TRACE_FILEINFO
, "Unrecoganised SetFileInformation code for %S", PtrFCB
->FCBName
->ObjectName
.Buffer
);
486 RC
= STATUS_INVALID_PARAMETER
;
495 if (PagingIoResourceAcquired
)
497 Ext2ReleaseResource(&(PtrReqdFCB
->PagingIoResource
));
498 DebugTrace(DEBUG_TRACE_MISC
, "*** FCBPaging Released [FileInfo]", 0);
499 DebugTraceState( " FCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]",
500 PtrReqdFCB
->PagingIoResource
.ActiveCount
,
501 PtrReqdFCB
->PagingIoResource
.NumberOfExclusiveWaiters
,
502 PtrReqdFCB
->PagingIoResource
.NumberOfSharedWaiters
);
506 DebugTrace(DEBUG_TRACE_FILE_OBJ
, "###### File Pointer 0x%LX [FileInfo]", PtrFileObject
);
509 PagingIoResourceAcquired
= FALSE
;
512 if (MainResourceAcquired
)
514 Ext2ReleaseResource(&(PtrReqdFCB
->MainResource
));
515 DebugTrace(DEBUG_TRACE_MISC
, "*** FCB Released [FileInfo]", 0);
516 DebugTraceState( " FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]",
517 PtrReqdFCB
->MainResource
.ActiveCount
,
518 PtrReqdFCB
->MainResource
.NumberOfExclusiveWaiters
,
519 PtrReqdFCB
->MainResource
.NumberOfSharedWaiters
);
522 DebugTrace(DEBUG_TRACE_FILE_OBJ
, "###### File Pointer 0x%LX [FileInfo]", PtrFileObject
);
525 MainResourceAcquired
= FALSE
;
528 if (VCBResourceAcquired
)
530 Ext2ReleaseResource(&(PtrVCB
->VCBResource
));
531 DebugTrace(DEBUG_TRACE_MISC
, "*** VCB Released [FileInfo]", 0);
532 DebugTraceState( " VCB AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]",
533 PtrVCB
->VCBResource
.ActiveCount
,
534 PtrVCB
->VCBResource
.NumberOfExclusiveWaiters
,
535 PtrVCB
->VCBResource
.NumberOfSharedWaiters
);
537 VCBResourceAcquired
= FALSE
;
540 // Post IRP if required
544 // Since, the I/O Manager gave us a system buffer, we do not
545 // need to "lock" anything.
547 // Perform the post operation which will mark the IRP pending
548 // and will return STATUS_PENDING back to us
549 RC
= Ext2PostRequest(PtrIrpContext
, PtrIrp
);
555 // Can complete the IRP here if no exception was encountered
556 if (!(PtrIrpContext
->IrpContextFlags
& EXT2_IRP_CONTEXT_EXCEPTION
)) {
557 PtrIrp
->IoStatus
.Status
= RC
;
559 // Free up the Irp Context
560 Ext2ReleaseIrpContext(PtrIrpContext
);
563 IoCompleteRequest(PtrIrp
, IO_DISK_INCREMENT
);
565 } // can we complete the IRP ?
566 } // end of "finally" processing
568 // DbgPrint( "\n === File Info IRP returning --> RC : 0x%lX Bytes: 0x%lX", PtrIrp->IoStatus.Status, PtrIrp->IoStatus.Information );
574 /*************************************************************************
576 * Function: Ext2GetBasicInformation()
579 * Return some time-stamps and file attributes to the caller.
581 * Expected Interrupt Level (for execution) :
585 * Return Value: STATUS_SUCCESS/Error
587 *************************************************************************/
588 NTSTATUS NTAPI
Ext2GetBasicInformation(
590 PFILE_BASIC_INFORMATION PtrBuffer
,
591 long *PtrReturnedLength
)
593 NTSTATUS RC
= STATUS_SUCCESS
;
597 if (*PtrReturnedLength
< sizeof(FILE_BASIC_INFORMATION
))
599 try_return(RC
= STATUS_BUFFER_OVERFLOW
);
602 // Zero out the supplied buffer.
603 RtlZeroMemory(PtrBuffer
, sizeof(FILE_BASIC_INFORMATION
));
605 // Get information from the FCB.
606 PtrBuffer
->CreationTime
= PtrFCB
->CreationTime
;
607 PtrBuffer
->LastAccessTime
= PtrFCB
->LastAccessTime
;
608 PtrBuffer
->LastWriteTime
= PtrFCB
->LastWriteTime
;
609 PtrBuffer
->ChangeTime
= PtrFCB
->LastWriteTime
;
611 // Now fill in the attributes.
612 PtrBuffer
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
613 if ( Ext2IsFlagOn( PtrFCB
->FCBFlags
, EXT2_FCB_DIRECTORY
) )
615 PtrBuffer
->FileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
617 else if ( Ext2IsFlagOn( PtrFCB
->FCBFlags
, EXT2_FCB_SPECIAL_FILE
) )
620 // Treated with respect... ;)
622 PtrBuffer
->FileAttributes
|= ( FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_READONLY
) ;
625 if ( Ext2IsFlagOn( PtrFCB
->FCBFlags
, EXT2_FCB_HIDDEN_FILE
) )
627 PtrBuffer
->FileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
630 if ( Ext2IsFlagOn( PtrFCB
->FCBFlags
, EXT2_FCB_READ_ONLY
) )
632 PtrBuffer
->FileAttributes
|= FILE_ATTRIBUTE_READONLY
;
641 // Return the amount of information filled in.
642 *PtrReturnedLength
= sizeof(FILE_BASIC_INFORMATION
);
648 NTSTATUS NTAPI
Ext2GetStandardInformation(
651 PFILE_STANDARD_INFORMATION PtrStdInformation
,
652 long *PtrReturnedLength
)
655 NTSTATUS RC
= STATUS_SUCCESS
;
660 if (*PtrReturnedLength
< sizeof( FILE_STANDARD_INFORMATION
))
662 try_return(RC
= STATUS_BUFFER_OVERFLOW
);
665 // Zero out the supplied buffer.
666 RtlZeroMemory(PtrStdInformation
, sizeof(FILE_STANDARD_INFORMATION
));
669 PtrStdInformation
->AllocationSize
= PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.AllocationSize
;
670 PtrStdInformation
->EndOfFile
= PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
;
671 PtrStdInformation
->DeletePending
= Ext2IsFlagOn( PtrFCB
->FCBFlags
, EXT2_FCB_DELETE_ON_CLOSE
);
672 PtrStdInformation
->Directory
= Ext2IsFlagOn( PtrFCB
->FCBFlags
, EXT2_FCB_DIRECTORY
);
673 PtrStdInformation
->NumberOfLinks
= PtrFCB
->LinkCount
;
681 // Return the amount of information filled in.
682 *PtrReturnedLength
= sizeof( FILE_STANDARD_INFORMATION
);
688 NTSTATUS NTAPI
Ext2GetNetworkOpenInformation(
690 PFILE_NETWORK_OPEN_INFORMATION PtrNetworkOpenInformation
,
691 long *PtrReturnedLength
)
694 NTSTATUS RC
= STATUS_SUCCESS
;
698 if (*PtrReturnedLength
< sizeof( FILE_NETWORK_OPEN_INFORMATION
))
700 try_return(RC
= STATUS_BUFFER_OVERFLOW
);
703 // Zero out the supplied buffer.
704 RtlZeroMemory(PtrNetworkOpenInformation
, sizeof(FILE_NETWORK_OPEN_INFORMATION
));
706 PtrNetworkOpenInformation
->CreationTime
= PtrFCB
->CreationTime
;
707 PtrNetworkOpenInformation
->LastAccessTime
= PtrFCB
->LastAccessTime
;
708 PtrNetworkOpenInformation
->LastWriteTime
= PtrFCB
->LastWriteTime
;
709 PtrNetworkOpenInformation
->ChangeTime
= PtrFCB
->LastWriteTime
;
710 PtrNetworkOpenInformation
->AllocationSize
= PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.AllocationSize
;
711 PtrNetworkOpenInformation
->EndOfFile
= PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
;
713 // Now fill in the attributes.
714 PtrNetworkOpenInformation
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
716 if ( Ext2IsFlagOn( PtrFCB
->FCBFlags
, EXT2_FCB_DIRECTORY
) )
718 PtrNetworkOpenInformation
->FileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
720 else if ( Ext2IsFlagOn( PtrFCB
->FCBFlags
, EXT2_FCB_SPECIAL_FILE
) )
723 // Treated with respect... ;)
725 PtrNetworkOpenInformation
->FileAttributes
|= ( FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_READONLY
) ;
727 if ( Ext2IsFlagOn( PtrFCB
->FCBFlags
, EXT2_FCB_HIDDEN_FILE
) )
729 PtrNetworkOpenInformation
->FileAttributes
|= FILE_ATTRIBUTE_HIDDEN
;
732 if ( Ext2IsFlagOn( PtrFCB
->FCBFlags
, EXT2_FCB_READ_ONLY
) )
734 PtrNetworkOpenInformation
->FileAttributes
|= FILE_ATTRIBUTE_READONLY
;
742 // Return the amount of information filled in.
743 *PtrReturnedLength
= sizeof( FILE_NETWORK_OPEN_INFORMATION
);
750 NTSTATUS NTAPI
Ext2GetFullNameInformation(
753 PFILE_NAME_INFORMATION PtrNameInformation
,
754 long *PtrReturnedLength
)
757 NTSTATUS RC
= STATUS_SUCCESS
;
761 if (*PtrReturnedLength
<
762 (long)( sizeof(FILE_NAME_INFORMATION
) + PtrCCB
->AbsolutePathName
.Length
) )
764 try_return(RC
= STATUS_BUFFER_OVERFLOW
);
767 // Zero out the supplied buffer.
768 RtlZeroMemory(PtrNameInformation
, sizeof( FILE_NAME_INFORMATION
) );
770 if( PtrCCB
->AbsolutePathName
.Length
)
773 PtrNameInformation
->FileName
, // Destination,
774 PtrCCB
->AbsolutePathName
.Buffer
, // Source,
775 PtrCCB
->AbsolutePathName
.Length
); // Length
777 PtrNameInformation
->FileNameLength
= PtrCCB
->AbsolutePathName
.Length
;
778 try_return(RC
= STATUS_SUCCESS
);
782 try_return(RC
= STATUS_INVALID_PARAMETER
);
791 // Return the amount of information filled in.
793 sizeof( FILE_NAME_INFORMATION
) +
794 PtrCCB
->AbsolutePathName
.Length
;
799 /*************************************************************************
801 * Function: Ext2SetBasicInformation()
804 * Set some time-stamps and file attributes supplied by the caller.
806 * Expected Interrupt Level (for execution) :
810 * Return Value: STATUS_SUCCESS/Error
812 *************************************************************************/
813 NTSTATUS NTAPI
Ext2SetBasicInformation(
814 PtrExt2IrpContext PtrIrpContext
,
816 PFILE_OBJECT PtrFileObject
,
817 PFILE_BASIC_INFORMATION PtrFileInformation
)
819 NTSTATUS RC
= STATUS_SUCCESS
;
821 PtrExt2VCB PtrVCB
= PtrFCB
->PtrVCB
;
824 // BOOLEAN CreationTimeChanged = FALSE;
825 // BOOLEAN AttributesChanged = FALSE;
827 // return STATUS_INVALID_PARAMETER;
832 RtlZeroMemory(&Inode
, sizeof( EXT2_INODE
));
834 if( NT_SUCCESS( Ext2ReadInode( PtrVCB
, PtrFCB
->INodeNo
, &Inode
) ) )
837 // Update time stamps in the inode
840 if( PtrFileInformation
->CreationTime
.QuadPart
)
842 PtrFCB
->CreationTime
.QuadPart
= PtrFileInformation
->CreationTime
.QuadPart
;
843 Inode
.i_ctime
= (ULONG
) ( (PtrFCB
->CreationTime
.QuadPart
844 - Ext2GlobalData
.TimeDiff
.QuadPart
) / 10000000 );
847 if( PtrFileInformation
->LastAccessTime
.QuadPart
)
849 PtrFCB
->LastAccessTime
.QuadPart
= PtrFileInformation
->LastAccessTime
.QuadPart
;
850 Inode
.i_atime
= (ULONG
) ( (PtrFCB
->LastAccessTime
.QuadPart
851 - Ext2GlobalData
.TimeDiff
.QuadPart
) / 10000000 );
854 if( PtrFileInformation
->LastWriteTime
.QuadPart
)
856 PtrFCB
->LastWriteTime
.QuadPart
= PtrFileInformation
->LastWriteTime
.QuadPart
;
857 Inode
.i_mtime
= (ULONG
) ( (PtrFCB
->LastWriteTime
.QuadPart
858 - Ext2GlobalData
.TimeDiff
.QuadPart
) / 10000000 );
861 // Now come the attributes.
862 if (PtrFileInformation
->FileAttributes
)
864 if (PtrFileInformation
->FileAttributes
& FILE_ATTRIBUTE_READONLY
)
866 // Turn off the write bits...
867 Ext2SetModeReadOnly( Inode
.i_mode
);
869 if (PtrFileInformation
->FileAttributes
& FILE_ATTRIBUTE_HIDDEN
)
871 // Turn off the read and write bits...
872 Ext2SetModeHidden( Inode
.i_mode
);
875 if (PtrFileInformation
->FileAttributes
& FILE_ATTRIBUTE_SYSTEM
)
877 // Just turn off the read and write bits...
878 // No special field to indicate that this is a system file...
879 Ext2SetModeReadOnly( Inode
.i_mode
);
880 Ext2SetModeHidden( Inode
.i_mode
);
884 // Updating the inode...
885 Ext2WriteInode( PtrIrpContext
, PtrVCB
, PtrFCB
->INodeNo
, &Inode
);
888 if (PtrFileInformation
->FileAttributes
& FILE_ATTRIBUTE_TEMPORARY
)
890 Ext2SetFlag(PtrFileObject
->Flags
, FO_TEMPORARY_FILE
);
894 Ext2ClearFlag(PtrFileObject
->Flags
, FO_TEMPORARY_FILE
);
905 /*************************************************************************
907 * Function: Ext2SetDispositionInformation()
910 * Mark/Unmark a file for deletion.
912 * Expected Interrupt Level (for execution) :
916 * Return Value: STATUS_SUCCESS/Error
918 *************************************************************************/
919 NTSTATUS NTAPI
Ext2SetDispositionInformation(
923 PFILE_OBJECT PtrFileObject
,
924 PtrExt2IrpContext PtrIrpContext
,
926 PFILE_DISPOSITION_INFORMATION PtrBuffer
)
928 NTSTATUS RC
= STATUS_SUCCESS
;
932 if (!PtrBuffer
->DeleteFile
)
934 // "un-delete" the file.
935 Ext2ClearFlag(PtrFCB
->FCBFlags
, EXT2_FCB_DELETE_ON_CLOSE
);
936 PtrFileObject
->DeletePending
= FALSE
;
940 // Do some checking to see if the file can even be deleted.
942 if (PtrFCB
->FCBFlags
& EXT2_FCB_DELETE_ON_CLOSE
)
948 if (PtrFCB
->FCBFlags
& EXT2_FCB_READ_ONLY
)
950 try_return(RC
= STATUS_CANNOT_DELETE
);
953 if (PtrVCB
->VCBFlags
& EXT2_VCB_FLAGS_VOLUME_READ_ONLY
)
955 try_return(RC
= STATUS_CANNOT_DELETE
);
958 // An important step is to check if the file stream has been
959 // mapped by any process. The delete cannot be allowed to proceed
961 if (!MmFlushImageSection(&(PtrFCB
->NTRequiredFCB
.SectionObject
), MmFlushForDelete
))
963 try_return(RC
= STATUS_CANNOT_DELETE
);
966 // Disallow deletion of either a root
967 // directory or a directory that is not empty.
968 if( PtrFCB
->INodeNo
== EXT2_ROOT_INO
)
970 try_return(RC
= STATUS_CANNOT_DELETE
);
973 if (PtrFCB
->FCBFlags
& EXT2_FCB_DIRECTORY
)
975 if (!Ext2IsDirectoryEmpty(PtrFCB
, PtrCCB
, PtrIrpContext
))
977 try_return(RC
= STATUS_DIRECTORY_NOT_EMPTY
);
981 // Set a flag to indicate that this directory entry will become history
983 Ext2SetFlag(PtrFCB
->FCBFlags
, EXT2_FCB_DELETE_ON_CLOSE
);
984 PtrFileObject
->DeletePending
= TRUE
;
997 /*************************************************************************
999 * Function: Ext2SetAllocationInformation()
1002 * Mark/Unmark a file for deletion.
1004 * Expected Interrupt Level (for execution) :
1006 * IRQL_PASSIVE_LEVEL
1008 * Return Value: STATUS_SUCCESS/Error
1010 *************************************************************************/
1011 NTSTATUS NTAPI
Ext2SetAllocationInformation(
1015 PFILE_OBJECT PtrFileObject
,
1016 PtrExt2IrpContext PtrIrpContext
,
1018 PFILE_ALLOCATION_INFORMATION PtrBuffer
)
1020 NTSTATUS RC
= STATUS_SUCCESS
;
1021 BOOLEAN TruncatedFile
= FALSE
;
1022 BOOLEAN ModifiedAllocSize
= FALSE
;
1027 // Are we increasing the allocation size?
1028 if (RtlLargeIntegerLessThan(
1029 PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.AllocationSize
,
1030 PtrBuffer
->AllocationSize
))
1033 ULONG LogicalBlockSize
= EXT2_MIN_BLOCK_SIZE
<< PtrVCB
->LogBlockSize
;
1035 for( CurrentSize
= 0; CurrentSize
< PtrBuffer
->AllocationSize
.QuadPart
; CurrentSize
+= LogicalBlockSize
)
1037 Ext2AddBlockToFile( PtrIrpContext
, PtrVCB
, PtrFCB
, PtrFileObject
, FALSE
);
1039 ModifiedAllocSize
= TRUE
;
1041 else if (RtlLargeIntegerGreaterThan(PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.AllocationSize
,
1042 PtrBuffer
->AllocationSize
))
1044 // This is the painful part. See if the VMM will allow us to proceed.
1045 // The VMM will deny the request if:
1046 // (a) any image section exists OR
1047 // (b) a data section exists and the size of the user mapped view
1048 // is greater than the new size
1049 // Otherwise, the VMM should allow the request to proceed.
1050 if (!MmCanFileBeTruncated(&(PtrFCB
->NTRequiredFCB
.SectionObject
), &(PtrBuffer
->AllocationSize
)))
1053 try_return(RC
= STATUS_USER_MAPPED_FILE
);
1056 if( !Ext2TruncateFileAllocationSize( PtrIrpContext
, PtrFCB
, PtrFileObject
, &PtrBuffer
->AllocationSize
) )
1058 // This will do until I figure out a better error message code ;)
1059 RC
= STATUS_INSUFFICIENT_RESOURCES
;
1063 ModifiedAllocSize
= TRUE
;
1064 TruncatedFile
= TRUE
;
1069 // This is a good place to check if we have performed a truncate
1070 // operation. If we have perform a truncate (whether we extended
1071 // or reduced file size), you should update file time stamps.
1073 // Last, but not the lease, you must inform the Cache Manager of file size changes.
1074 if (ModifiedAllocSize
&& NT_SUCCESS(RC
))
1076 // Update the FCB Header with the new allocation size.
1077 PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.AllocationSize
= PtrBuffer
->AllocationSize
;
1079 // If we decreased the allocation size to less than the
1080 // current file size, modify the file size value.
1081 // Similarly, if we decreased the value to less than the
1082 // current valid data length, modify that value as well.
1085 if (RtlLargeIntegerLessThan(PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
, PtrBuffer
->AllocationSize
))
1087 // Decrease the file size value.
1088 PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.FileSize
= PtrBuffer
->AllocationSize
;
1091 if (RtlLargeIntegerLessThan(PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.ValidDataLength
, PtrBuffer
->AllocationSize
))
1093 // Decrease the valid data length value.
1094 PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.ValidDataLength
= PtrBuffer
->AllocationSize
;
1099 // If the FCB has not had caching initiated, it is still valid
1100 // for you to invoke the NT Cache Manager. It is possible in such
1101 // situations for the call to be no'oped (unless some user has
1102 // mapped in the file)
1104 // NOTE: The invocation to CcSetFileSizes() will quite possibly
1105 // result in a recursive call back into the file system.
1106 // This is because the NT Cache Manager will typically
1107 // perform a flush before telling the VMM to purge pages
1108 // especially when caching has not been initiated on the
1109 // file stream, but the user has mapped the file into
1110 // the process' virtual address space.
1111 CcSetFileSizes(PtrFileObject
, (PCC_FILE_SIZES
)&(PtrFCB
->NTRequiredFCB
.CommonFCBHeader
.AllocationSize
));
1113 // Inform any pending IRPs (notify change directory).