1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*************************************************************************
10 * Module: UDF File System Driver (Kernel mode execution only)
13 * Contains code to handle the "set/query file information" dispatch
16 *************************************************************************/
20 // define the file specific bug-check id
21 #define UDF_BUG_CHECK_ID UDF_FILE_INFORMATION
23 #define MEM_USREN_TAG "US_Ren"
24 #define MEM_USREN2_TAG "US_Ren2"
25 #define MEM_USFIDC_TAG "US_FIDC"
26 #define MEM_USHL_TAG "US_HL"
28 /*************************************************************************
30 * Function: UDFFileInfo()
33 * The I/O Manager will invoke this routine to handle a set/query file
36 * Expected Interrupt Level (for execution) :
38 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
39 * to be deferred to a worker thread context)
41 * Return Value: STATUS_SUCCESS/Error
43 *************************************************************************/
47 PDEVICE_OBJECT DeviceObject
, // the logical volume device object
48 PIRP Irp
// I/O Request Packet
51 NTSTATUS RC
= STATUS_SUCCESS
;
52 PtrUDFIrpContext PtrIrpContext
= NULL
;
53 BOOLEAN AreWeTopLevel
= FALSE
;
55 TmPrint(("UDFFileInfo: \n"));
57 FsRtlEnterFileSystem();
61 // set the top level context
62 AreWeTopLevel
= UDFIsIrpTopLevel(Irp
);
63 ASSERT(!UDFIsFSDevObj(DeviceObject
));
67 // get an IRP context structure and issue the request
68 PtrIrpContext
= UDFAllocateIrpContext(Irp
, DeviceObject
);
70 RC
= UDFCommonFileInfo(PtrIrpContext
, Irp
);
72 RC
= STATUS_INSUFFICIENT_RESOURCES
;
73 Irp
->IoStatus
.Status
= RC
;
74 Irp
->IoStatus
.Information
= 0;
76 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
79 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext
, _SEH2_GetExceptionInformation())) {
81 RC
= UDFExceptionHandler(PtrIrpContext
, Irp
);
83 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR
, RC
);
87 IoSetTopLevelIrp(NULL
);
90 FsRtlExitFileSystem();
93 } // end UDFFileInfo()
96 /*************************************************************************
98 * Function: UDFCommonFileInfo()
101 * The actual work is performed here. This routine may be invoked in one'
102 * of the two possible contexts:
103 * (a) in the context of a system worker thread
104 * (b) in the context of the original caller
106 * Expected Interrupt Level (for execution) :
110 * Return Value: STATUS_SUCCESS/Error
112 *************************************************************************/
115 PtrUDFIrpContext PtrIrpContext
,
119 NTSTATUS RC
= STATUS_SUCCESS
;
120 PIO_STACK_LOCATION IrpSp
= NULL
;
121 PFILE_OBJECT FileObject
= NULL
;
122 PtrUDFFCB Fcb
= NULL
;
123 PtrUDFCCB Ccb
= NULL
;
125 PtrUDFNTRequiredFCB NtReqFcb
= NULL
;
126 BOOLEAN MainResourceAcquired
= FALSE
;
127 BOOLEAN ParentResourceAcquired
= FALSE
;
128 BOOLEAN PagingIoResourceAcquired
= FALSE
;
129 PVOID PtrSystemBuffer
= NULL
;
130 LONG BufferLength
= 0;
131 FILE_INFORMATION_CLASS FunctionalityRequested
;
132 BOOLEAN CanWait
= FALSE
;
133 BOOLEAN PostRequest
= FALSE
;
134 BOOLEAN AcquiredVcb
= FALSE
;
137 TmPrint(("UDFCommonFileInfo: irp %x\n", Irp
));
139 TopIrp
= IoGetTopLevelIrp();
140 switch((ULONG_PTR
)TopIrp
) {
141 case FSRTL_FSP_TOP_LEVEL_IRP
:
142 UDFPrint((" FSRTL_FSP_TOP_LEVEL_IRP\n"));
144 case FSRTL_CACHE_TOP_LEVEL_IRP
:
145 UDFPrint((" FSRTL_CACHE_TOP_LEVEL_IRP\n"));
147 case FSRTL_MOD_WRITE_TOP_LEVEL_IRP
:
148 UDFPrint((" FSRTL_MOD_WRITE_TOP_LEVEL_IRP\n"));
150 case FSRTL_FAST_IO_TOP_LEVEL_IRP
:
151 UDFPrint((" FSRTL_FAST_IO_TOP_LEVEL_IRP\n"));
155 UDFPrint((" NULL TOP_LEVEL_IRP\n"));
159 UDFPrint((" TOP_LEVEL_IRP\n"));
161 UDFPrint((" RECURSIVE_IRP, TOP = %x\n", TopIrp
));
166 // First, get a pointer to the current I/O stack location.
167 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
170 FileObject
= IrpSp
->FileObject
;
173 // Get the FCB and CCB pointers.
174 Ccb
= (PtrUDFCCB
)(FileObject
->FsContext2
);
177 // some applications sends us FO without Ccb
178 // This is not allowed...
179 RC
= STATUS_INVALID_PARAMETER
;
185 NtReqFcb
= Fcb
->NTRequiredFCB
;
187 CanWait
= (PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_CAN_BLOCK
) ? TRUE
: FALSE
;
189 // If the caller has opened a logical volume and is attempting to
190 // query information for it as a file stream, return an error.
191 if(Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
) {
192 // This is not allowed. Caller must use get/set volume information instead.
193 RC
= STATUS_INVALID_PARAMETER
;
198 Vcb
= (PVCB
)(IrpSp
->DeviceObject
->DeviceExtension
);
200 ASSERT(Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_FCB
);
201 //Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
203 // The NT I/O Manager always allocates and supplies a system
204 // buffer for query and set file information calls.
205 // Copying information to/from the user buffer and the system
206 // buffer is performed by the I/O Manager and the FSD need not worry about it.
207 PtrSystemBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
209 UDFFlushTryBreak(Vcb
);
210 if(!UDFAcquireResourceShared(&(Vcb
->VCBResource
), CanWait
)) {
212 try_return(RC
= STATUS_PENDING
);
216 if(IrpSp
->MajorFunction
== IRP_MJ_QUERY_INFORMATION
) {
217 // Now, obtain some parameters.
218 BufferLength
= IrpSp
->Parameters
.QueryFile
.Length
;
219 FunctionalityRequested
= IrpSp
->Parameters
.QueryFile
.FileInformationClass
;
220 #ifdef UDF_ENABLE_SECURITY
221 RC
= IoCheckFunctionAccess(
222 Ccb
->PreviouslyGrantedAccess
,
223 PtrIrpContext
->MajorFunction
,
224 PtrIrpContext
->MinorFunction
,
226 &FunctionalityRequested
,
228 if(!NT_SUCCESS(RC
)) {
231 #endif //UDF_ENABLE_SECURITY
232 // Acquire the MainResource shared (NOTE: for paging-IO on a
233 // page file, we should avoid acquiring any resources and simply
234 // trust the VMM to do the right thing, else we could possibly
235 // run into deadlocks).
236 if(!(Fcb
->FCBFlags
& UDF_FCB_PAGE_FILE
)) {
237 // Acquire the MainResource shared.
238 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
239 UDFAcquireResourceShared(&(NtReqFcb
->MainResource
), TRUE
);
240 MainResourceAcquired
= TRUE
;
243 // Do whatever the caller asked us to do
244 switch (FunctionalityRequested
) {
245 case FileBasicInformation
:
246 RC
= UDFGetBasicInformation(FileObject
, Fcb
, (PFILE_BASIC_INFORMATION
)PtrSystemBuffer
, &BufferLength
);
248 case FileStandardInformation
:
249 RC
= UDFGetStandardInformation(Fcb
, (PFILE_STANDARD_INFORMATION
) PtrSystemBuffer
, &BufferLength
);
251 #if(_WIN32_WINNT >= 0x0400)
252 case FileNetworkOpenInformation
:
253 RC
= UDFGetNetworkInformation(Fcb
, (PFILE_NETWORK_OPEN_INFORMATION
)PtrSystemBuffer
, &BufferLength
);
255 #endif // _WIN32_WINNT >= 0x0400
256 case FileInternalInformation
:
257 RC
= UDFGetInternalInformation(PtrIrpContext
, Fcb
, Ccb
, (PFILE_INTERNAL_INFORMATION
) PtrSystemBuffer
, &BufferLength
);
259 case FileEaInformation
:
260 RC
= UDFGetEaInformation(PtrIrpContext
, Fcb
, (PFILE_EA_INFORMATION
) PtrSystemBuffer
, &BufferLength
);
262 case FileNameInformation
:
263 RC
= UDFGetFullNameInformation(FileObject
, (PFILE_NAME_INFORMATION
) PtrSystemBuffer
, &BufferLength
);
265 case FileAlternateNameInformation
:
266 RC
= UDFGetAltNameInformation(Fcb
, (PFILE_NAME_INFORMATION
) PtrSystemBuffer
, &BufferLength
);
268 // case FileCompressionInformation:
269 // // RC = UDFGetCompressionInformation(...);
271 case FilePositionInformation
:
272 RC
= UDFGetPositionInformation(FileObject
, (PFILE_POSITION_INFORMATION
)PtrSystemBuffer
, &BufferLength
);
274 case FileStreamInformation
:
275 RC
= UDFGetFileStreamInformation(Fcb
, (PFILE_STREAM_INFORMATION
) PtrSystemBuffer
, &BufferLength
);
277 case FileAllInformation
:
278 // The I/O Manager supplies the Mode, Access, and Alignment
279 // information. The rest is up to us to provide.
280 // Therefore, decrement the BufferLength appropriately (assuming
281 // that the above 3 types on information are already in the
284 PFILE_ALL_INFORMATION PtrAllInfo
= (PFILE_ALL_INFORMATION
)PtrSystemBuffer
;
286 BufferLength
-= (sizeof(FILE_MODE_INFORMATION
) +
287 sizeof(FILE_ACCESS_INFORMATION
) +
288 sizeof(FILE_ALIGNMENT_INFORMATION
));
290 // Get the remaining stuff.
291 if(!NT_SUCCESS(RC
= UDFGetBasicInformation(FileObject
, Fcb
, &(PtrAllInfo
->BasicInformation
), &BufferLength
)) ||
292 !NT_SUCCESS(RC
= UDFGetStandardInformation(Fcb
, &(PtrAllInfo
->StandardInformation
), &BufferLength
)) ||
293 !NT_SUCCESS(RC
= UDFGetInternalInformation(PtrIrpContext
, Fcb
, Ccb
, &(PtrAllInfo
->InternalInformation
), &BufferLength
)) ||
294 !NT_SUCCESS(RC
= UDFGetEaInformation(PtrIrpContext
, Fcb
, &(PtrAllInfo
->EaInformation
), &BufferLength
)) ||
295 !NT_SUCCESS(RC
= UDFGetPositionInformation(FileObject
, &(PtrAllInfo
->PositionInformation
), &BufferLength
)) ||
296 !NT_SUCCESS(RC
= UDFGetFullNameInformation(FileObject
, &(PtrAllInfo
->NameInformation
), &BufferLength
))
302 RC
= STATUS_INVALID_PARAMETER
;
306 #ifndef UDF_READ_ONLY_BUILD
308 // if(IrpSp->MajorFunction == IRP_MJ_SET_INFORMATION) {
309 Vcb
->VCBFlags
|= UDF_VCB_SKIP_EJECT_CHECK
;
310 ASSERT(IrpSp
->MajorFunction
== IRP_MJ_SET_INFORMATION
);
311 // Now, obtain some parameters.
312 FunctionalityRequested
= IrpSp
->Parameters
.SetFile
.FileInformationClass
;
313 if((Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_READ_ONLY
) &&
314 (FunctionalityRequested
!= FilePositionInformation
)) {
315 try_return(RC
= STATUS_ACCESS_DENIED
);
317 #ifdef UDF_ENABLE_SECURITY
318 RC
= IoCheckFunctionAccess(
319 Ccb
->PreviouslyGrantedAccess
,
320 PtrIrpContext
->MajorFunction
,
321 PtrIrpContext
->MinorFunction
,
323 &FunctionalityRequested
,
325 if(!NT_SUCCESS(RC
)) {
328 #endif //UDF_ENABLE_SECURITY
329 // If the FSD supports opportunistic locking,
330 // then we should check whether the oplock state
331 // allows the caller to proceed.
333 // Rename, and link operations require creation of a directory
334 // entry and possibly deletion of another directory entry.
336 // Unless this is an operation on a page file, we should go ahead and
337 // acquire the FCB exclusively at this time. Note that we will pretty
338 // much block out anything being done to the FCB from this point on.
339 if(!(Fcb
->FCBFlags
& UDF_FCB_PAGE_FILE
) &&
340 (FunctionalityRequested
!= FilePositionInformation
) &&
341 (FunctionalityRequested
!= FileRenameInformation
) &&
342 (FunctionalityRequested
!= FileLinkInformation
)) {
343 // Acquire the Parent & Main Resources exclusive.
344 if(Fcb
->FileInfo
->ParentFile
) {
345 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->ParentFcb
->NTRequiredFCB
);
346 if(!UDFAcquireResourceExclusive(&(Fcb
->ParentFcb
->NTRequiredFCB
->MainResource
), CanWait
)) {
348 try_return(RC
= STATUS_PENDING
);
350 ParentResourceAcquired
= TRUE
;
352 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
353 if(!UDFAcquireResourceExclusive(&(NtReqFcb
->MainResource
), CanWait
)) {
355 try_return(RC
= STATUS_PENDING
);
357 MainResourceAcquired
= TRUE
;
359 // The only operations that could conceivably proceed from this point
360 // on are paging-IO read/write operations. For delete, link (rename),
361 // set allocation size, and set EOF, should also acquire the paging-IO
362 // resource, thereby synchronizing with paging-IO requests.
363 if((Fcb
->FCBFlags
& UDF_FCB_PAGE_FILE
) &&
364 ((FunctionalityRequested
== FileDispositionInformation
) ||
365 (FunctionalityRequested
== FileAllocationInformation
) ||
366 (FunctionalityRequested
== FileEndOfFileInformation
)) ) {
368 // Acquire the MainResource shared.
369 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
370 if(!UDFAcquireResourceShared(&(NtReqFcb
->MainResource
), CanWait
)) {
372 try_return(RC
= STATUS_PENDING
);
374 MainResourceAcquired
= TRUE
;
375 // Acquire the PagingResource exclusive.
376 if(!UDFAcquireResourceExclusive(&(NtReqFcb
->PagingIoResource
), CanWait
)) {
378 try_return(RC
= STATUS_PENDING
);
380 PagingIoResourceAcquired
= TRUE
;
381 } else if((FunctionalityRequested
!= FileRenameInformation
) &&
382 (FunctionalityRequested
!= FileLinkInformation
)) {
383 // Acquire the MainResource shared.
384 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
385 if(!UDFAcquireResourceShared(&(NtReqFcb
->MainResource
), CanWait
)) {
387 try_return(RC
= STATUS_PENDING
);
389 MainResourceAcquired
= TRUE
;
392 if((Vcb
->VCBFlags
& UDF_VCB_FLAGS_RAW_DISK
) &&
393 (FunctionalityRequested
!= FilePositionInformation
)) {
394 AdPrint((" Can't change File Information on blank volume ;)\n"));
395 try_return(RC
= STATUS_ACCESS_DENIED
);
398 // Do whatever the caller asked us to do
399 switch (FunctionalityRequested
) {
400 case FileBasicInformation
:
401 RC
= UDFSetBasicInformation(Fcb
, Ccb
, FileObject
, (PFILE_BASIC_INFORMATION
)PtrSystemBuffer
);
403 case FilePositionInformation
: {
404 // Check if no intermediate buffering has been specified.
405 // If it was specified, do not allow non-aligned set file
406 // position requests to succeed.
407 PFILE_POSITION_INFORMATION PtrFileInfoBuffer
;
409 PtrFileInfoBuffer
= (PFILE_POSITION_INFORMATION
)PtrSystemBuffer
;
411 if(FileObject
->Flags
& FO_NO_INTERMEDIATE_BUFFERING
) {
412 if(PtrFileInfoBuffer
->CurrentByteOffset
.LowPart
& IrpSp
->DeviceObject
->AlignmentRequirement
) {
413 // Invalid alignment.
414 try_return(RC
= STATUS_INVALID_PARAMETER
);
418 FileObject
->CurrentByteOffset
= PtrFileInfoBuffer
->CurrentByteOffset
;
421 case FileDispositionInformation
:
422 RC
= UDFSetDispositionInformation(Fcb
, Ccb
, Vcb
, FileObject
,
423 ((PFILE_DISPOSITION_INFORMATION
)PtrSystemBuffer
)->DeleteFile
? TRUE
: FALSE
);
425 case FileRenameInformation
:
428 try_return(RC
= STATUS_PENDING
);
430 RC
= UDFRename(IrpSp
, Fcb
, Ccb
, FileObject
, (PFILE_RENAME_INFORMATION
)PtrSystemBuffer
);
431 if(RC
== STATUS_PENDING
) {
436 #ifdef UDF_ALLOW_HARD_LINKS
437 case FileLinkInformation
:
440 try_return(RC
= STATUS_PENDING
);
442 RC
= UDFHardLink(IrpSp
, Fcb
, Ccb
, FileObject
, (PFILE_LINK_INFORMATION
)PtrSystemBuffer
);
444 #endif //UDF_ALLOW_HARD_LINKS
445 case FileAllocationInformation
:
446 RC
= UDFSetAllocationInformation(Fcb
, Ccb
, Vcb
, FileObject
,
448 (PFILE_ALLOCATION_INFORMATION
)PtrSystemBuffer
);
450 case FileEndOfFileInformation
:
451 RC
= UDFSetEOF(IrpSp
, Fcb
, Ccb
, Vcb
, FileObject
, Irp
, (PFILE_END_OF_FILE_INFORMATION
)PtrSystemBuffer
);
454 RC
= STATUS_INVALID_PARAMETER
;
457 #endif //UDF_READ_ONLY_BUILD
464 if(PagingIoResourceAcquired
) {
465 UDFReleaseResource(&(NtReqFcb
->PagingIoResource
));
466 PagingIoResourceAcquired
= FALSE
;
469 if(MainResourceAcquired
) {
470 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
471 UDFReleaseResource(&(NtReqFcb
->MainResource
));
472 MainResourceAcquired
= FALSE
;
475 if(ParentResourceAcquired
) {
476 UDF_CHECK_PAGING_IO_RESOURCE(Fcb
->ParentFcb
->NTRequiredFCB
);
477 UDFReleaseResource(&(Fcb
->ParentFcb
->NTRequiredFCB
->MainResource
));
478 ParentResourceAcquired
= FALSE
;
481 // Post IRP if required
484 // Since, the I/O Manager gave us a system buffer, we do not
485 // need to "lock" anything.
487 // Perform the post operation which will mark the IRP pending
488 // and will return STATUS_PENDING back to us
489 RC
= UDFPostRequest(PtrIrpContext
, Irp
);
493 if (!_SEH2_AbnormalTermination()) {
494 Irp
->IoStatus
.Status
= RC
;
495 // Set status for "query" requests
496 if(IrpSp
->MajorFunction
== IRP_MJ_QUERY_INFORMATION
) {
497 // Return the amount of information transferred.
498 Irp
->IoStatus
.Information
= IrpSp
->Parameters
.QueryFile
.Length
- BufferLength
;
499 #ifndef UDF_READ_ONLY_BUILD
500 #ifdef UDF_DELAYED_CLOSE
503 if(FunctionalityRequested
== FileDispositionInformation
) {
506 UDFReleaseResource(&(Vcb
->VCBResource
));
508 UDFRemoveFromDelayedQueue(Fcb
);
510 #endif //UDF_DELAYED_CLOSE
511 #endif //UDF_READ_ONLY_BUILD
514 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
515 // Free up the Irp Context
516 UDFReleaseIrpContext(PtrIrpContext
);
517 } // can we complete the IRP ?
521 UDFReleaseResource(&(Vcb
->VCBResource
));
523 } _SEH2_END
;// end of "__finally" processing
526 } // end UDFCommonFileInfo()
529 Return some time-stamps and file attributes to the caller.
532 UDFGetBasicInformation(
533 IN PFILE_OBJECT FileObject
,
535 IN PFILE_BASIC_INFORMATION PtrBuffer
,
536 IN OUT LONG
* PtrReturnedLength
539 NTSTATUS RC
= STATUS_SUCCESS
;
540 PUDF_FILE_INFO FileInfo
;
541 PDIR_INDEX_ITEM DirNdx
;
543 AdPrint(("UDFGetBasicInformation: \n"));
547 if(*PtrReturnedLength
< (LONG
)sizeof(FILE_BASIC_INFORMATION
)) {
548 try_return(RC
= STATUS_BUFFER_OVERFLOW
);
551 // Zero out the supplied buffer.
552 RtlZeroMemory(PtrBuffer
, sizeof(FILE_BASIC_INFORMATION
));
554 // Get information from the FCB and update TimesCache in DirIndex
555 FileInfo
= Fcb
->FileInfo
;
558 AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n"));
559 AdPrint(("!!!! GetBasicInfo to unopened file !!!!\n"));
560 try_return(RC
= STATUS_INVALID_PARAMETER
);
563 DirNdx
= UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo
), FileInfo
->Index
);
565 PtrBuffer
->CreationTime
= Fcb
->NTRequiredFCB
->CreationTime
;
566 DirNdx
->CreationTime
= PtrBuffer
->CreationTime
.QuadPart
;
568 PtrBuffer
->LastAccessTime
= Fcb
->NTRequiredFCB
->LastAccessTime
;
569 DirNdx
->LastAccessTime
= PtrBuffer
->LastAccessTime
.QuadPart
;
571 PtrBuffer
->LastWriteTime
= Fcb
->NTRequiredFCB
->LastWriteTime
;
572 DirNdx
->LastWriteTime
= PtrBuffer
->LastWriteTime
.QuadPart
;
574 PtrBuffer
->ChangeTime
= Fcb
->NTRequiredFCB
->ChangeTime
;
575 DirNdx
->ChangeTime
= PtrBuffer
->ChangeTime
.QuadPart
;
577 // Now fill in the attributes.
578 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
579 PtrBuffer
->FileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
581 if(!FileInfo
->Dloc
->DirIndex
) AdPrint(("*****!!!!! Directory has no DirIndex !!!!!*****\n"));
584 // Similarly, fill in attributes indicating a hidden file, system
585 // file, compressed file, temporary file, etc. if the FSD supports
586 // such file attribute values.
587 PtrBuffer
->FileAttributes
|= UDFAttributesToNT(DirNdx
,NULL
);
588 if(FileObject
->Flags
& FO_TEMPORARY_FILE
) {
589 PtrBuffer
->FileAttributes
|= FILE_ATTRIBUTE_TEMPORARY
;
591 PtrBuffer
->FileAttributes
&= ~FILE_ATTRIBUTE_TEMPORARY
;
593 if(!PtrBuffer
->FileAttributes
) {
594 PtrBuffer
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
602 // Return the amount of information filled in.
603 (*PtrReturnedLength
) -= sizeof(FILE_BASIC_INFORMATION
);
607 } // end UDFGetBasicInformation()
611 Return file sizes to the caller.
614 UDFGetStandardInformation(
616 IN PFILE_STANDARD_INFORMATION PtrBuffer
,
617 IN OUT LONG
* PtrReturnedLength
620 NTSTATUS RC
= STATUS_SUCCESS
;
621 PUDF_FILE_INFO FileInfo
;
624 AdPrint(("UDFGetStandardInformation: \n"));
628 if(*PtrReturnedLength
< (LONG
)sizeof(FILE_STANDARD_INFORMATION
)) {
629 try_return(RC
= STATUS_BUFFER_OVERFLOW
);
632 // Zero out the supplied buffer.
633 RtlZeroMemory(PtrBuffer
, sizeof(FILE_STANDARD_INFORMATION
));
635 FileInfo
= Fcb
->FileInfo
;
638 AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n"));
639 AdPrint(("!!!! GetStandardInfo to unopened file !!!!\n"));
640 try_return(RC
= STATUS_INVALID_PARAMETER
);
643 PtrBuffer
->NumberOfLinks
= UDFGetFileLinkCount(FileInfo
);
644 PtrBuffer
->DeletePending
= (Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
) ? TRUE
: FALSE
;
646 // Case on whether this is a file or a directory, and extract
647 // the information and fill in the fcb/dcb specific parts
648 // of the output buffer
649 if(UDFIsADirectory(Fcb
->FileInfo
)) {
650 PtrBuffer
->Directory
= TRUE
;
652 if(Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
.LowPart
== 0xffffffff) {
653 Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
.QuadPart
=
654 UDFSysGetAllocSize(Fcb
->Vcb
, UDFGetFileSize(FileInfo
));
656 PtrBuffer
->AllocationSize
= Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
;
657 PtrBuffer
->EndOfFile
= Fcb
->NTRequiredFCB
->CommonFCBHeader
.FileSize
;
659 PtrBuffer
->Directory
= FALSE
;
665 // Return the amount of information filled in.
666 *PtrReturnedLength
-= sizeof(FILE_STANDARD_INFORMATION
);
670 } // end UDFGetStandardInformation()
673 Return some time-stamps and file attributes to the caller.
676 UDFGetNetworkInformation(
678 IN PFILE_NETWORK_OPEN_INFORMATION PtrBuffer
,
679 IN OUT PLONG PtrReturnedLength
682 NTSTATUS RC
= STATUS_SUCCESS
;
683 PUDF_FILE_INFO FileInfo
;
685 AdPrint(("UDFGetNetworkInformation: \n"));
689 if(*PtrReturnedLength
< (LONG
)sizeof(FILE_NETWORK_OPEN_INFORMATION
)) {
690 try_return(RC
= STATUS_BUFFER_OVERFLOW
);
693 // Zero out the supplied buffer.
694 RtlZeroMemory(PtrBuffer
, sizeof(FILE_NETWORK_OPEN_INFORMATION
));
696 // Get information from the FCB.
697 PtrBuffer
->CreationTime
= Fcb
->NTRequiredFCB
->CreationTime
;
698 PtrBuffer
->LastAccessTime
= Fcb
->NTRequiredFCB
->LastAccessTime
;
699 PtrBuffer
->LastWriteTime
= Fcb
->NTRequiredFCB
->LastWriteTime
;
700 PtrBuffer
->ChangeTime
= Fcb
->NTRequiredFCB
->ChangeTime
;
702 FileInfo
= Fcb
->FileInfo
;
705 AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n"));
706 AdPrint(("!!!! UDFGetNetworkInformation to unopened file !!!!\n"));
707 try_return(RC
= STATUS_INVALID_PARAMETER
);
709 // Now fill in the attributes.
710 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
711 PtrBuffer
->FileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
713 if(!FileInfo
->Dloc
->DirIndex
) AdPrint(("*****!!!!! Directory has no DirIndex !!!!!*****\n"));
716 if(Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
.LowPart
== 0xffffffff) {
717 Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
.QuadPart
=
718 UDFSysGetAllocSize(Fcb
->Vcb
, UDFGetFileSize(FileInfo
));
720 PtrBuffer
->AllocationSize
= Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
;
721 PtrBuffer
->EndOfFile
= Fcb
->NTRequiredFCB
->CommonFCBHeader
.FileSize
;
723 // Similarly, fill in attributes indicating a hidden file, system
724 // file, compressed file, temporary file, etc. if the FSD supports
725 // such file attribute values.
726 PtrBuffer
->FileAttributes
|= UDFAttributesToNT(UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo
), FileInfo
->Index
),NULL
);
727 if(!PtrBuffer
->FileAttributes
) {
728 PtrBuffer
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
735 // Return the amount of information filled in.
736 (*PtrReturnedLength
) -= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
740 } // end UDFGetNetworkInformation()
744 Return some time-stamps and file attributes to the caller.
747 UDFGetInternalInformation(
748 PtrUDFIrpContext PtrIrpContext
,
751 IN PFILE_INTERNAL_INFORMATION PtrBuffer
,
752 IN OUT PLONG PtrReturnedLength
755 NTSTATUS RC
= STATUS_SUCCESS
;
756 PUDF_FILE_INFO FileInfo
;
759 AdPrint(("UDFGetInternalInformation\n"));
763 if(*PtrReturnedLength
< (LONG
)sizeof(FILE_INTERNAL_INFORMATION
)) {
764 try_return(RC
= STATUS_BUFFER_OVERFLOW
);
767 // Zero out the supplied buffer.
768 RtlZeroMemory(PtrBuffer
, sizeof(FILE_INTERNAL_INFORMATION
));
770 FileInfo
= Fcb
->FileInfo
;
773 AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n"));
774 AdPrint(("!!!! UDFGetInternalInformation to unopened file !!!!\n"));
775 try_return(RC
= STATUS_INVALID_PARAMETER
);
779 PtrBuffer
->IndexNumber
.QuadPart
= UDFGetNTFileId(Vcb
, FileInfo
, &(Fcb
->FCBName
->ObjectName
));
781 UDFAcquireResourceExclusive(&(Fcb
->Vcb
->FileIdResource
), TRUE
);
782 // remember File Id & full path
783 UDFStoreFileId(Fcb
->Vcb
, Ccb
, FileInfo
, PtrBuffer
->IndexNumber
.QuadPart
);
784 UDFReleaseResource(&(Fcb
->Vcb
->FileIdResource
));
790 // Return the amount of information filled in.
791 *PtrReturnedLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
795 } // end UDFGetInternalInformation()
798 Return zero-filled EAs to the caller.
802 PtrUDFIrpContext PtrIrpContext
,
804 IN PFILE_EA_INFORMATION PtrBuffer
,
805 IN OUT PLONG PtrReturnedLength
808 NTSTATUS RC
= STATUS_SUCCESS
;
810 AdPrint(("UDFGetEaInformation\n"));
814 if(*PtrReturnedLength
< (LONG
)sizeof(FILE_EA_INFORMATION
)) {
815 try_return(RC
= STATUS_BUFFER_OVERFLOW
);
818 // Zero out the supplied buffer.
819 PtrBuffer
->EaSize
= 0;
825 // Return the amount of information filled in.
826 *PtrReturnedLength
-= sizeof(FILE_EA_INFORMATION
);
830 } // end UDFGetEaInformation()
833 Return file's long name to the caller.
836 UDFGetFullNameInformation(
837 IN PFILE_OBJECT FileObject
,
838 IN PFILE_NAME_INFORMATION PtrBuffer
,
839 IN OUT PLONG PtrReturnedLength
843 NTSTATUS RC
= STATUS_SUCCESS
;
846 AdPrint(("UDFGetFullNameInformation\n"));
848 PtrBuffer
->FileNameLength
= FileObject
->FileName
.Length
;
849 BytesToCopy
= FileObject
->FileName
.Length
;
851 if (PtrBuffer
->FileNameLength
+ sizeof( ULONG
) > (ULONG
)(*PtrReturnedLength
)) {
853 BytesToCopy
= *PtrReturnedLength
- sizeof( ULONG
);
854 RC
= STATUS_BUFFER_OVERFLOW
;
857 RtlCopyMemory( PtrBuffer
->FileName
, FileObject
->FileName
.Buffer
, BytesToCopy
);
859 // Reduce the available bytes by the amount stored into this buffer.
860 *PtrReturnedLength
-= sizeof( ULONG
) + PtrBuffer
->FileNameLength
;
863 } // end UDFGetFullNameInformation()
866 Return file short(8.3) name to the caller.
869 UDFGetAltNameInformation(
871 IN PFILE_NAME_INFORMATION PtrBuffer
,
872 IN OUT PLONG PtrReturnedLength
875 PDIR_INDEX_ITEM DirNdx
;
877 UNICODE_STRING ShortName
;
878 WCHAR ShortNameBuffer
[13];
880 AdPrint(("UDFGetAltNameInformation: \n"));
882 *PtrReturnedLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]);
883 DirNdx
= UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb
->FileInfo
), Fcb
->FileInfo
->Index
);
885 ShortName
.MaximumLength
= 13 * sizeof(WCHAR
);
886 ShortName
.Buffer
= (PWCHAR
)&ShortNameBuffer
;
888 UDFDOSName__(Fcb
->Vcb
, &ShortName
, &(DirNdx
->FName
), Fcb
->FileInfo
);
890 if(*PtrReturnedLength
< ShortName
.Length
) {
891 return(STATUS_BUFFER_OVERFLOW
);
893 BytesToCopy
= ShortName
.Length
;
894 *PtrReturnedLength
-= ShortName
.Length
;
897 RtlCopyMemory( &(PtrBuffer
->FileName
),
901 PtrBuffer
->FileNameLength
= ShortName
.Length
;
903 return(STATUS_SUCCESS
);
904 } // end UDFGetAltNameInformation()
907 Get file position information
910 UDFGetPositionInformation(
911 IN PFILE_OBJECT FileObject
,
912 IN PFILE_POSITION_INFORMATION PtrBuffer
,
913 IN OUT PLONG PtrReturnedLength
916 if(*PtrReturnedLength
< (LONG
)sizeof(FILE_POSITION_INFORMATION
)) {
917 return(STATUS_BUFFER_OVERFLOW
);
919 PtrBuffer
->CurrentByteOffset
= FileObject
->CurrentByteOffset
;
920 // Modify the local variable for BufferLength appropriately.
921 *PtrReturnedLength
-= sizeof(FILE_POSITION_INFORMATION
);
923 return(STATUS_SUCCESS
);
924 } // end UDFGetAltNameInformation()
927 Get file file stream(s) information
930 UDFGetFileStreamInformation(
932 IN PFILE_STREAM_INFORMATION PtrBuffer
,
933 IN OUT PLONG PtrReturnedLength
936 NTSTATUS RC
= STATUS_SUCCESS
;
937 PUDF_FILE_INFO FileInfo
;
938 PUDF_FILE_INFO SDirInfo
;
940 BOOLEAN FcbAcquired
= FALSE
;
943 PDIR_INDEX_HDR hSDirIndex
;
944 PDIR_INDEX_ITEM SDirIndex
;
945 PFILE_BOTH_DIR_INFORMATION NTFileInfo
= NULL
;
947 AdPrint(("UDFGetFileStreamInformation\n"));
951 UDFAcquireResourceExclusive(&(Fcb
->Vcb
->FileIdResource
), TRUE
);
954 FileInfo
= Fcb
->FileInfo
;
956 AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n"));
957 AdPrint(("!!!! UDFGetFileStreamInformation to unopened file !!!!\n"));
958 try_return(RC
= STATUS_INVALID_PARAMETER
);
961 // Zero out the supplied buffer.
962 RtlZeroMemory(PtrBuffer
, *PtrReturnedLength
);
963 if(!(SDirInfo
= FileInfo
->Dloc
->SDirInfo
) ||
964 UDFIsSDirDeleted(SDirInfo
) ) {
965 (*PtrReturnedLength
) -= (sizeof(FILE_STREAM_INFORMATION
) - sizeof(WCHAR
));
966 try_return(RC
= STATUS_SUCCESS
);
969 hSDirIndex
= SDirInfo
->Dloc
->DirIndex
;
970 NTFileInfo
= (PFILE_BOTH_DIR_INFORMATION
)MyAllocatePool__(NonPagedPool
, sizeof(FILE_BOTH_DIR_INFORMATION
)+UDF_NAME_LEN
*sizeof(WCHAR
));
971 if(!NTFileInfo
) try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
973 for(i
=2; (SDirIndex
= UDFDirIndex(hSDirIndex
,i
)); i
++) {
974 if((SDirIndex
->FI_Flags
& UDF_FI_FLAG_FI_INTERNAL
) ||
975 UDFIsDeleted(SDirIndex
) ||
976 !SDirIndex
->FName
.Buffer
)
978 // copy data to buffer
979 if(*PtrReturnedLength
< (l
= ((sizeof(FILE_STREAM_INFORMATION
) - sizeof(WCHAR
)) +
980 SDirIndex
->FName
.Length
+ 3) & (~3)) ) {
981 try_return(RC
= STATUS_BUFFER_OVERFLOW
);
983 RC
= UDFFileDirInfoToNT(Vcb
, SDirIndex
, NTFileInfo
);
985 PtrBuffer
->NextEntryOffset
= l
;
986 PtrBuffer
->StreamNameLength
= SDirIndex
->FName
.Length
;
987 PtrBuffer
->StreamSize
= NTFileInfo
->EndOfFile
;
988 PtrBuffer
->StreamAllocationSize
= NTFileInfo
->AllocationSize
;
989 RtlCopyMemory(&(PtrBuffer
->StreamName
), SDirIndex
->FName
.Buffer
, SDirIndex
->FName
.Length
);
990 *PtrReturnedLength
-= l
;
991 *((PCHAR
*)(&PtrBuffer
)) += l
;
998 UDFReleaseResource(&(Fcb
->Vcb
->FileIdResource
));
1000 MyFreePool__(NTFileInfo
);
1003 } // end UDFGetFileStreamInformation()
1005 //*******************************************************************
1007 #ifndef UDF_READ_ONLY_BUILD
1010 Set some time-stamps and file attributes supplied by the caller.
1013 UDFSetBasicInformation(
1016 IN PFILE_OBJECT FileObject
,
1017 IN PFILE_BASIC_INFORMATION PtrBuffer
)
1019 NTSTATUS RC
= STATUS_SUCCESS
;
1020 ULONG NotifyFilter
= 0;
1022 AdPrint(("UDFSetBasicInformation\n"));
1026 // Obtain a pointer to the directory entry associated with
1027 // the FCB being modifed. The directory entry is obviously
1028 // part of the data associated with the parent directory that
1029 // contains this particular file stream.
1030 if(PtrBuffer
->FileAttributes
) {
1031 UDFUpdateAttrTime(Fcb
->Vcb
, Fcb
->FileInfo
);
1033 if( UDFIsADirectory(Fcb
->FileInfo
) &&
1034 !(Fcb
->Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_UCHG_DIR_ACCESS_TIME
) &&
1035 ((Fcb
->FileInfo
->Dloc
->DataLoc
.Modified
||
1036 Fcb
->FileInfo
->Dloc
->AllocLoc
.Modified
||
1037 (Fcb
->FileInfo
->Dloc
->FE_Flags
& UDF_FE_FLAG_FE_MODIFIED
) ||
1038 Fcb
->FileInfo
->Dloc
->FELoc
.Modified
))
1040 // ignore Access Time Modification for unchanged Dir
1041 if(!PtrBuffer
->CreationTime
.QuadPart
&&
1042 PtrBuffer
->LastAccessTime
.QuadPart
&&
1043 !PtrBuffer
->ChangeTime
.QuadPart
&&
1044 !PtrBuffer
->LastWriteTime
.QuadPart
)
1048 UDFSetFileXTime(Fcb
->FileInfo
,
1049 &(PtrBuffer
->CreationTime
.QuadPart
),
1050 &(PtrBuffer
->LastAccessTime
.QuadPart
),
1051 &(PtrBuffer
->ChangeTime
.QuadPart
),
1052 &(PtrBuffer
->LastWriteTime
.QuadPart
) );
1054 if(PtrBuffer
->CreationTime
.QuadPart
) {
1055 // The interesting thing here is that the user has set certain time
1056 // fields. However, before doing this, the user may have performed
1057 // I/O which in turn would have caused FSD to mark the fact that
1058 // write/access time should be modifed at cleanup.
1059 // We'll mark the fact that such updates are no longer
1060 // required since the user has explicitly specified the values he
1061 // wishes to see associated with the file stream.
1062 Fcb
->NTRequiredFCB
->CreationTime
= PtrBuffer
->CreationTime
;
1063 Ccb
->CCBFlags
|= UDF_CCB_CREATE_TIME_SET
;
1064 NotifyFilter
|= FILE_NOTIFY_CHANGE_CREATION
;
1066 if(PtrBuffer
->LastAccessTime
.QuadPart
) {
1067 Fcb
->NTRequiredFCB
->LastAccessTime
= PtrBuffer
->LastAccessTime
;
1068 Ccb
->CCBFlags
|= UDF_CCB_ACCESS_TIME_SET
;
1069 NotifyFilter
|= FILE_NOTIFY_CHANGE_LAST_ACCESS
;
1071 if(PtrBuffer
->ChangeTime
.QuadPart
) {
1072 Fcb
->NTRequiredFCB
->ChangeTime
= PtrBuffer
->ChangeTime
;
1073 Ccb
->CCBFlags
|= UDF_CCB_MODIFY_TIME_SET
;
1075 if(PtrBuffer
->LastWriteTime
.QuadPart
) {
1076 Fcb
->NTRequiredFCB
->LastWriteTime
= PtrBuffer
->LastWriteTime
;
1077 Ccb
->CCBFlags
|= UDF_CCB_WRITE_TIME_SET
;
1078 NotifyFilter
|= FILE_NOTIFY_CHANGE_LAST_WRITE
;
1081 // Now come the attributes.
1082 if(PtrBuffer
->FileAttributes
) {
1083 // We have a non-zero attribute value.
1084 // The presence of a particular attribute indicates that the
1085 // user wishes to set the attribute value. The absence indicates
1086 // the user wishes to clear the particular attribute.
1088 // Our routine ignores unsupported flags
1089 PtrBuffer
->FileAttributes
&= ~(FILE_ATTRIBUTE_NORMAL
);
1091 // Similarly, we should pick out other invalid flag values.
1092 if( (PtrBuffer
->FileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) &&
1093 !(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
))
1094 try_return(RC
= STATUS_INVALID_PARAMETER
);
1096 if(PtrBuffer
->FileAttributes
& FILE_ATTRIBUTE_TEMPORARY
) {
1097 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
)
1098 try_return(RC
= STATUS_INVALID_PARAMETER
);
1099 FileObject
->Flags
|= FO_TEMPORARY_FILE
;
1101 FileObject
->Flags
&= ~FO_TEMPORARY_FILE
;
1104 if(PtrBuffer
->FileAttributes
& FILE_ATTRIBUTE_READONLY
) {
1105 Fcb
->FCBFlags
|= UDF_FCB_READ_ONLY
;
1107 Fcb
->FCBFlags
&= ~UDF_FCB_READ_ONLY
;
1110 UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb
->FileInfo
), Fcb
->FileInfo
->Index
),
1111 NULL
, PtrBuffer
->FileAttributes
);
1113 (UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb
->FileInfo
), Fcb
->FileInfo
->Index
))
1114 ->FI_Flags
|= UDF_FI_FLAG_SYS_ATTR
;
1115 // If the FSD supports file compression, we may wish to
1116 // note the user's preferences for compressing/not compressing
1117 // the file at this time.
1118 Ccb
->CCBFlags
|= UDF_CCB_ATTRIBUTES_SET
;
1119 NotifyFilter
|= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
1123 UDFNotifyFullReportChange( Fcb
->Vcb
, Fcb
->FileInfo
,
1124 NotifyFilter
, FILE_ACTION_MODIFIED
);
1125 UDFSetFileSizeInDirNdx(Fcb
->Vcb
, Fcb
->FileInfo
, NULL
);
1126 Fcb
->FileInfo
->Dloc
->FE_Flags
|= UDF_FE_FLAG_FE_MODIFIED
;
1134 } // end UDFSetBasicInformation()
1137 UDFMarkStreamsForDeletion(
1143 NTSTATUS RC
= STATUS_SUCCESS
;
1144 PUDF_FILE_INFO SDirInfo
= NULL
;
1145 PUDF_FILE_INFO FileInfo
= NULL
;
1147 BOOLEAN SDirAcq
= FALSE
;
1148 BOOLEAN StrAcq
= FALSE
;
1153 // In some cases we needn't marking Streams for deleteion
1154 // (Not opened or Don't exist)
1155 if(UDFIsAStream(Fcb
->FileInfo
) ||
1156 UDFIsAStreamDir(Fcb
->FileInfo
) ||
1157 !UDFHasAStreamDir(Fcb
->FileInfo
) ||
1158 !Fcb
->FileInfo
->Dloc
->SDirInfo
||
1159 UDFIsSDirDeleted(Fcb
->FileInfo
->Dloc
->SDirInfo
) ||
1160 (UDFGetFileLinkCount(Fcb
->FileInfo
) > 1) )
1161 try_return (RC
/*=STATUS_SUCCESS*/);
1163 // We shall mark Streams for deletion if there is no
1164 // Links to the file. Otherwise we'll delete only the file.
1165 // If we are asked to unmark Streams, we'll precess the whole Tree
1166 RC
= UDFOpenStreamDir__(Vcb
, Fcb
->FileInfo
, &SDirInfo
);
1171 SDirInfo
->Fcb
->NTRequiredFCB
) {
1172 UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo
->Fcb
->NTRequiredFCB
);
1173 UDFAcquireResourceExclusive(&(SDirInfo
->Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
1177 if(!ForDel
|| ((lc
= UDFGetFileLinkCount(Fcb
->FileInfo
)) < 2)) {
1179 UDF_DIR_SCAN_CONTEXT ScanContext
;
1180 PDIR_INDEX_ITEM DirNdx
;
1182 // It is not worth checking whether the Stream can be deleted if
1183 // Undelete requested
1186 UDFDirIndexInitScan(SDirInfo
, &ScanContext
, 2)) {
1188 // Check if we can delete Streams
1189 while((DirNdx
= UDFDirIndexScan(&ScanContext
, &FileInfo
))) {
1193 FileInfo
->Fcb
->NTRequiredFCB
->AcqFlushCount
++;
1194 MmPrint((" MmFlushImageSection() for Stream\n"));
1195 if(!MmFlushImageSection(&(FileInfo
->Fcb
->NTRequiredFCB
->SectionObject
), MmFlushForDelete
)) {
1196 FileInfo
->Fcb
->NTRequiredFCB
->AcqFlushCount
--;
1197 try_return(RC
= STATUS_CANNOT_DELETE
);
1199 FileInfo
->Fcb
->NTRequiredFCB
->AcqFlushCount
--;
1203 // (Un)Mark Streams for deletion
1205 // Perform sequencial Open for Streams & mark 'em
1206 // for deletion. We should not get FileInfo pointers directly
1207 // from DirNdx[i] to prevent great troubles with linked
1208 // files. We should mark for deletion FI with proper ParentFile
1210 d
= UDFDirIndexGetLastIndex(SDirInfo
->Dloc
->DirIndex
);
1211 for(i
=2; i
<d
; i
++) {
1212 RC
= UDFOpenFile__(Vcb
,
1214 SDirInfo
,&FileInfo
,&i
);
1215 ASSERT(NT_SUCCESS(RC
) || (RC
== STATUS_FILE_DELETED
));
1216 if(NT_SUCCESS(RC
)) {
1218 if(FileInfo
->Fcb
->NTRequiredFCB
) {
1219 UDF_CHECK_PAGING_IO_RESOURCE(FileInfo
->Fcb
->NTRequiredFCB
);
1220 UDFAcquireResourceExclusive(&(FileInfo
->Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
1223 #ifndef UDF_ALLOW_LINKS_TO_STREAMS
1224 if(UDFGetFileLinkCount(FileInfo
) >= 2) {
1225 // Currently, UDF_INFO package doesn't
1226 // support this case, so we'll inform developer
1227 // about this to prevent on-disk space leaks...
1229 try_return(RC
= STATUS_CANNOT_DELETE
);
1231 #endif //UDF_ALLOW_LINKS_TO_STREAMS
1233 AdPrint((" SET stream DeleteOnClose\n"));
1235 ASSERT(!(FileInfo
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
1236 if(FileInfo
->ParentFile
&&
1237 FileInfo
->ParentFile
->Fcb
) {
1238 ASSERT(!(FileInfo
->ParentFile
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
1241 FileInfo
->Fcb
->FCBFlags
|= (UDF_FCB_DELETE_ON_CLOSE
|
1242 UDF_FCB_DELETE_PARENT
);
1244 AdPrint((" CLEAR stream DeleteOnClose\n"));
1245 FileInfo
->Fcb
->FCBFlags
&= ~(UDF_FCB_DELETE_ON_CLOSE
|
1246 UDF_FCB_DELETE_PARENT
);
1249 UDFCloseFile__(Vcb
, FileInfo
);
1251 if(RC
== STATUS_FILE_DELETED
) {
1252 // That's OK if STATUS_FILE_DELETED returned...
1253 RC
= STATUS_SUCCESS
;
1256 if(UDFCleanUpFile__(Vcb
, FileInfo
)) {
1257 ASSERT(!StrAcq
&& !(FileInfo
->Fcb
));
1258 MyFreePool__(FileInfo
);
1261 UDF_CHECK_PAGING_IO_RESOURCE(FileInfo
->Fcb
->NTRequiredFCB
);
1262 UDFReleaseResource(&(FileInfo
->Fcb
->NTRequiredFCB
->MainResource
));
1268 // Mark SDir for deletion
1272 ASSERT(!(SDirInfo
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
1273 if(SDirInfo
->ParentFile
&&
1274 SDirInfo
->ParentFile
->Fcb
) {
1275 ASSERT(!(SDirInfo
->ParentFile
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
1278 AdPrint((" SET stream dir DeleteOnClose\n"));
1279 SDirInfo
->Fcb
->FCBFlags
|= (UDF_FCB_DELETE_ON_CLOSE
|
1280 UDF_FCB_DELETE_PARENT
);
1282 AdPrint((" CLEAR stream dir DeleteOnClose\n"));
1283 SDirInfo
->Fcb
->FCBFlags
&= ~(UDF_FCB_DELETE_ON_CLOSE
|
1284 UDF_FCB_DELETE_PARENT
);
1289 // if caller wants us to perform DelTree for Streams, but
1290 // someone keeps Stream opened and there is a Link to this
1291 // file, we can't delete it immediately (on Cleanup) & should
1292 // not delete the whole Tree. Instead, we'll set DELETE_PARENT
1293 // flag in SDir to kill this file later, when all the Handles
1294 // to Streams, opened via this file, would be closed
1296 ASSERT(!(SDirInfo
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
1297 if(SDirInfo
->ParentFile
&&
1298 SDirInfo
->ParentFile
->Fcb
) {
1299 ASSERT(!(SDirInfo
->ParentFile
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
1303 SDirInfo
->Fcb
->FCBFlags
|= UDF_FCB_DELETE_PARENT
;
1310 UDFCloseFile__(Vcb
, FileInfo
);
1311 if(UDFCleanUpFile__(Vcb
, FileInfo
)) {
1312 ASSERT(!StrAcq
&& !(FileInfo
->Fcb
));
1313 MyFreePool__(FileInfo
);
1316 UDF_CHECK_PAGING_IO_RESOURCE(FileInfo
->Fcb
->NTRequiredFCB
);
1317 UDFReleaseResource(&(FileInfo
->Fcb
->NTRequiredFCB
->MainResource
));
1322 UDFCloseFile__(Vcb
, SDirInfo
);
1324 UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo
->Fcb
->NTRequiredFCB
);
1325 UDFReleaseResource(&(SDirInfo
->Fcb
->NTRequiredFCB
->MainResource
));
1327 if(UDFCleanUpFile__(Vcb
, SDirInfo
)) {
1328 MyFreePool__(SDirInfo
);
1334 } // end UDFMarkStreamsForDeletion()
1337 (Un)Mark file for deletion.
1340 UDFSetDispositionInformation(
1344 IN PFILE_OBJECT FileObject
,
1348 NTSTATUS RC
= STATUS_SUCCESS
;
1349 // PUDF_FILE_INFO SDirInfo = NULL;
1350 // PUDF_FILE_INFO FileInfo = NULL;
1353 AdPrint(("UDFSetDispositionInformation\n"));
1358 AdPrint((" CLEAR DeleteOnClose\n"));
1359 // "un-delete" the file.
1360 Fcb
->FCBFlags
&= ~UDF_FCB_DELETE_ON_CLOSE
;
1362 FileObject
->DeletePending
= FALSE
;
1363 RC
= UDFMarkStreamsForDeletion(Vcb
, Fcb
, FALSE
); // Undelete
1366 AdPrint((" SET DeleteOnClose\n"));
1368 // The easy part is over. Now, we know that the user wishes to
1369 // delete the corresponding directory entry (of course, if this
1370 // is the only link to the file stream, any on-disk storage space
1371 // associated with the file stream will also be released when the
1372 // (only) link is deleted!)
1374 // Do some checking to see if the file can even be deleted.
1375 if(Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
) {
1380 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_READ_ONLY
) {
1381 try_return(RC
= STATUS_CANNOT_DELETE
);
1384 if(Fcb
->FCBFlags
& UDF_FCB_READ_ONLY
) {
1385 RC
= UDFCheckAccessRights(NULL
, NULL
, Fcb
->ParentFcb
, NULL
, FILE_DELETE_CHILD
, 0);
1386 if(!NT_SUCCESS(RC
)) {
1387 try_return (RC
= STATUS_CANNOT_DELETE
);
1391 // It would not be prudent to allow deletion of either a root
1392 // directory or a directory that is not empty.
1393 if(Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
)
1394 try_return(RC
= STATUS_CANNOT_DELETE
);
1396 lc
= UDFGetFileLinkCount(Fcb
->FileInfo
);
1398 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
1399 // Perform check to determine whether the directory
1401 if(!UDFIsDirEmpty__(Fcb
->FileInfo
)) {
1402 try_return(RC
= STATUS_DIRECTORY_NOT_EMPTY
);
1406 // An important step is to check if the file stream has been
1407 // mapped by any process. The delete cannot be allowed to proceed
1409 MmPrint((" MmFlushImageSection()\n"));
1410 Fcb
->NTRequiredFCB
->AcqFlushCount
++;
1411 if(!MmFlushImageSection(&(Fcb
->NTRequiredFCB
->SectionObject
),
1412 (lc
> 1) ? MmFlushForWrite
: MmFlushForDelete
)) {
1413 Fcb
->NTRequiredFCB
->AcqFlushCount
--;
1414 try_return(RC
= STATUS_CANNOT_DELETE
);
1416 Fcb
->NTRequiredFCB
->AcqFlushCount
--;
1418 // We should also mark Streams for deletion if there are no
1419 // Links to the file. Otherwise we'll delete only the file
1422 RC
= STATUS_SUCCESS
;
1424 RC
= UDFMarkStreamsForDeletion(Vcb
, Fcb
, TRUE
); // Delete
1429 // Set a flag to indicate that this directory entry will become history
1431 Fcb
->FCBFlags
|= UDF_FCB_DELETE_ON_CLOSE
;
1433 FileObject
->DeletePending
= TRUE
;
1435 if((Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) && Ccb
) {
1436 FsRtlNotifyFullChangeDirectory( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
1437 (PVOID
)Ccb
, NULL
, FALSE
, FALSE
,
1438 0, NULL
, NULL
, NULL
);
1447 } // end UDFSetDispositionInformation()
1451 Change file allocation length.
1454 UDFSetAllocationInformation(
1458 IN PFILE_OBJECT FileObject
,
1459 IN PtrUDFIrpContext PtrIrpContext
,
1461 IN PFILE_ALLOCATION_INFORMATION PtrBuffer
1464 NTSTATUS RC
= STATUS_SUCCESS
;
1465 BOOLEAN TruncatedFile
= FALSE
;
1466 BOOLEAN ModifiedAllocSize
= FALSE
;
1467 BOOLEAN CacheMapInitialized
= FALSE
;
1468 BOOLEAN AcquiredPagingIo
= FALSE
;
1470 AdPrint(("UDFSetAllocationInformation\n"));
1473 // Increasing the allocation size associated with a file stream
1474 // is relatively easy. All we have to do is execute some FSD
1475 // specific code to check whether we have enough space available
1476 // (and if the FSD supports user/volume quotas, whether the user
1477 // is not exceeding quota), and then increase the file size in the
1478 // corresponding on-disk and in-memory structures.
1479 // Then, all we should do is inform the Cache Manager about the
1480 // increased allocation size.
1482 // First, do whatever error checking is appropriate here (e.g. whether
1483 // the caller is trying the change size for a directory, etc.).
1484 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
)
1485 try_return(RC
= STATUS_INVALID_PARAMETER
);
1487 Fcb
->NTRequiredFCB
->CommonFCBHeader
.IsFastIoPossible
= UDFIsFastIoPossible(Fcb
);
1489 if ((FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
) &&
1490 (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
) &&
1491 !FlagOn(Irp
->Flags
, IRP_PAGING_IO
)) {
1492 ASSERT( !FlagOn( FileObject
->Flags
, FO_CLEANUP_COMPLETE
) );
1493 // Now initialize the cache map.
1494 MmPrint((" CcInitializeCacheMap()\n"));
1495 CcInitializeCacheMap( FileObject
,
1496 (PCC_FILE_SIZES
)&Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
,
1498 &(UDFGlobalData
.CacheMgrCallBacks
),
1499 Fcb
->NTRequiredFCB
);
1501 CacheMapInitialized
= TRUE
;
1504 // Are we increasing the allocation size?
1505 if(Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
.QuadPart
<
1506 PtrBuffer
->AllocationSize
.QuadPart
) {
1508 // Yes. Do the FSD specific stuff i.e. increase reserved
1510 if(((LONGLONG
)UDFGetFreeSpace(Vcb
) << Vcb
->LBlockSizeBits
) < PtrBuffer
->AllocationSize
.QuadPart
) {
1511 try_return(RC
= STATUS_DISK_FULL
);
1513 // RC = STATUS_SUCCESS;
1514 ModifiedAllocSize
= TRUE
;
1516 } else if(Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
.QuadPart
>
1517 PtrBuffer
->AllocationSize
.QuadPart
) {
1518 // This is the painful part. See if the VMM will allow us to proceed.
1519 // The VMM will deny the request if:
1520 // (a) any image section exists OR
1521 // (b) a data section exists and the size of the user mapped view
1522 // is greater than the new size
1523 // Otherwise, the VMM should allow the request to proceed.
1524 MmPrint((" MmCanFileBeTruncated()\n"));
1525 if(!MmCanFileBeTruncated(&(Fcb
->NTRequiredFCB
->SectionObject
), &(PtrBuffer
->AllocationSize
))) {
1527 try_return(RC
= STATUS_USER_MAPPED_FILE
);
1530 // Perform our directory entry modifications. Release any on-disk
1531 // space we may need to in the process.
1532 ModifiedAllocSize
= TRUE
;
1533 TruncatedFile
= TRUE
;
1536 ASSERT(NT_SUCCESS(RC
));
1537 // This is a good place to check if we have performed a truncate
1538 // operation. If we have perform a truncate (whether we extended
1539 // or reduced file size or even leave it intact), we should update
1540 // file time stamps.
1541 FileObject
->Flags
|= FO_FILE_MODIFIED
;
1543 // Last, but not the lease, we must inform the Cache Manager of file size changes.
1544 if(ModifiedAllocSize
) {
1546 // If we decreased the allocation size to less than the
1547 // current file size, modify the file size value.
1548 // Similarly, if we decreased the value to less than the
1549 // current valid data length, modify that value as well.
1551 AcquiredPagingIo
= UDFAcquireResourceExclusiveWithCheck(&(Fcb
->NTRequiredFCB
->PagingIoResource
));
1552 // Update the FCB Header with the new allocation size.
1554 if(Fcb
->NTRequiredFCB
->CommonFCBHeader
.ValidDataLength
.QuadPart
>
1555 PtrBuffer
->AllocationSize
.QuadPart
) {
1556 // Decrease the valid data length value.
1557 Fcb
->NTRequiredFCB
->CommonFCBHeader
.ValidDataLength
=
1558 PtrBuffer
->AllocationSize
;
1560 if(Fcb
->NTRequiredFCB
->CommonFCBHeader
.FileSize
.QuadPart
>
1561 PtrBuffer
->AllocationSize
.QuadPart
) {
1562 // Decrease the file size value.
1563 Fcb
->NTRequiredFCB
->CommonFCBHeader
.FileSize
=
1564 PtrBuffer
->AllocationSize
;
1565 RC
= UDFResizeFile__(Vcb
, Fcb
->FileInfo
, PtrBuffer
->AllocationSize
.QuadPart
);
1566 // UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, NULL);
1569 Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
= PtrBuffer
->AllocationSize
;
1570 // UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo,
1571 // &(PtrBuffer->AllocationSize.QuadPart));
1573 if(AcquiredPagingIo
) {
1574 UDFReleaseResource(&(Fcb
->NTRequiredFCB
->PagingIoResource
));
1575 AcquiredPagingIo
= FALSE
;
1577 // If the FCB has not had caching initiated, it is still valid
1578 // for us to invoke the NT Cache Manager. It is possible in such
1579 // situations for the call to be no'oped (unless some user has
1580 // mapped in the file)
1582 // NOTE: The invocation to CcSetFileSizes() will quite possibly
1583 // result in a recursive call back into the file system.
1584 // This is because the NT Cache Manager will typically
1585 // perform a flush before telling the VMM to purge pages
1586 // especially when caching has not been initiated on the
1587 // file stream, but the user has mapped the file into
1588 // the process' virtual address space.
1589 MmPrint((" CcSetFileSizes()\n"));
1590 Fcb
->NTRequiredFCB
->AcqFlushCount
++;
1591 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&(Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
));
1592 Fcb
->NTRequiredFCB
->AcqFlushCount
--;
1593 Fcb
->NTRequiredFCB
->NtReqFCBFlags
|= UDF_NTREQ_FCB_MODIFIED
;
1595 // Inform any pending IRPs (notify change directory).
1596 if(UDFIsAStream(Fcb
->FileInfo
)) {
1597 UDFNotifyFullReportChange( Vcb
, Fcb
->FileInfo
,
1598 FILE_NOTIFY_CHANGE_STREAM_SIZE
,
1599 FILE_ACTION_MODIFIED_STREAM
);
1601 UDFNotifyFullReportChange( Vcb
, Fcb
->FileInfo
,
1602 FILE_NOTIFY_CHANGE_SIZE
,
1603 FILE_ACTION_MODIFIED
);
1610 if(AcquiredPagingIo
) {
1611 UDFReleaseResource(&(Fcb
->NTRequiredFCB
->PagingIoResource
));
1612 AcquiredPagingIo
= FALSE
;
1614 if (CacheMapInitialized
) {
1616 MmPrint((" CcUninitializeCacheMap()\n"));
1617 CcUninitializeCacheMap( FileObject
, NULL
, NULL
);
1621 } // end UDFSetAllocationInformation()
1624 Set end of file (resize).
1628 IN PIO_STACK_LOCATION PtrSp
,
1632 IN PFILE_OBJECT FileObject
,
1634 IN PFILE_END_OF_FILE_INFORMATION PtrBuffer
1637 NTSTATUS RC
= STATUS_SUCCESS
;
1638 BOOLEAN TruncatedFile
= FALSE
;
1639 BOOLEAN ModifiedAllocSize
= FALSE
;
1641 PDIR_INDEX_ITEM DirNdx
;
1642 PtrUDFNTRequiredFCB NtReqFcb
= NULL
;
1643 LONGLONG OldFileSize
;
1644 // BOOLEAN ZeroBlock;
1645 BOOLEAN CacheMapInitialized
= FALSE
;
1646 BOOLEAN AcquiredPagingIo
= FALSE
;
1648 AdPrint(("UDFSetEOF\n"));
1651 // Increasing the allocation size associated with a file stream
1652 // is relatively easy. All we have to do is execute some FSD
1653 // specific code to check whether we have enough space available
1654 // (and if the FSD supports user/volume quotas, whether the user
1655 // is not exceeding quota), and then increase the file size in the
1656 // corresponding on-disk and in-memory structures.
1657 // Then, all we should do is inform the Cache Manager about the
1658 // increased allocation size.
1660 // First, do whatever error checking is appropriate here (e.g. whether
1661 // the caller is trying the change size for a directory, etc.).
1662 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
)
1663 try_return(RC
= STATUS_INVALID_PARAMETER
);
1665 NtReqFcb
= Fcb
->NTRequiredFCB
;
1667 if((Fcb
->FCBFlags
& UDF_FCB_DELETED
) ||
1668 (NtReqFcb
->NtReqFCBFlags
& UDF_NTREQ_FCB_DELETED
)) {
1670 if(UDFGetFileLinkCount(Fcb
->FileInfo
) < 1) {
1672 try_return(RC
= STATUS_SUCCESS
);
1675 try_return(RC
= STATUS_SUCCESS
);
1678 NtReqFcb
->CommonFCBHeader
.IsFastIoPossible
= UDFIsFastIoPossible(Fcb
);
1680 if ((FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
) &&
1681 (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
) &&
1682 !(Irp
->Flags
& IRP_PAGING_IO
)) {
1683 ASSERT( !FlagOn( FileObject
->Flags
, FO_CLEANUP_COMPLETE
) );
1684 // Now initialize the cache map.
1685 MmPrint((" CcInitializeCacheMap()\n"));
1686 CcInitializeCacheMap( FileObject
,
1687 (PCC_FILE_SIZES
)&Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
,
1689 &(UDFGlobalData
.CacheMgrCallBacks
),
1690 Fcb
->NTRequiredFCB
);
1692 CacheMapInitialized
= TRUE
;
1695 AcquiredPagingIo
= UDFAcquireResourceExclusiveWithCheck(&(Fcb
->NTRequiredFCB
->PagingIoResource
));
1696 // Do a special case here for the lazy write of file sizes.
1697 if(PtrSp
->Parameters
.SetFile
.AdvanceOnly
) {
1698 // Never have the dirent filesize larger than the fcb filesize
1699 PtrBuffer
->EndOfFile
.QuadPart
=
1700 min(PtrBuffer
->EndOfFile
.QuadPart
,
1701 NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
);
1702 // Only advance the file size, never reduce it with this call
1703 RC
= STATUS_SUCCESS
;
1704 if(UDFGetFileSizeFromDirNdx(Vcb
, Fcb
->FileInfo
) >=
1705 PtrBuffer
->EndOfFile
.QuadPart
)
1708 UDFSetFileSizeInDirNdx(Vcb
, Fcb
->FileInfo
, &(PtrBuffer
->EndOfFile
.QuadPart
));
1709 goto notify_size_changes
;
1712 // !!! IMPORTANT !!!
1714 // We can get here after all Handles to the file are closed
1715 // To prevent allocation size incoherency we should
1716 // reference FileInfo _before_ call to UDFResizeFile__()
1717 // and use UDFCloseFile__() _after_ that
1719 // Are we increasing the allocation size?
1720 OldFileSize
= NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
;
1721 if(OldFileSize
< PtrBuffer
->EndOfFile
.QuadPart
) {
1723 // Yes. Do the FSD specific stuff i.e. increase reserved
1726 if (FileObject->PrivateCacheMap)
1730 // reference file to pretend that it is opened
1731 UDFReferenceFile__(Fcb
->FileInfo
);
1732 UDFInterlockedIncrement((PLONG
)&(Fcb
->ReferenceCount
));
1733 UDFInterlockedIncrement((PLONG
)&(NtReqFcb
->CommonRefCount
));
1734 // perform resize operation
1735 RC
= UDFResizeFile__(Vcb
, Fcb
->FileInfo
, PtrBuffer
->EndOfFile
.QuadPart
);
1737 UDFCloseFile__(Vcb
, Fcb
->FileInfo
);
1738 UDFInterlockedDecrement((PLONG
)&(Fcb
->ReferenceCount
));
1739 UDFInterlockedDecrement((PLONG
)&(NtReqFcb
->CommonRefCount
));
1740 // update values in NtReqFcb
1741 NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
=
1742 // NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart =
1743 PtrBuffer
->EndOfFile
.QuadPart
;
1744 ModifiedAllocSize
= TRUE
;
1746 } else if(NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
>
1747 PtrBuffer
->EndOfFile
.QuadPart
) {
1749 // This is the painful part. See if the VMM will allow us to proceed.
1750 // The VMM will deny the request if:
1751 // (a) any image section exists OR
1752 // (b) a data section exists and the size of the user mapped view
1753 // is greater than the new size
1754 // Otherwise, the VMM should allow the request to proceed.
1756 MmPrint((" MmCanFileBeTruncated()\n"));
1757 if(!MmCanFileBeTruncated(&(NtReqFcb
->SectionObject
), &(PtrBuffer
->EndOfFile
))) {
1759 try_return(RC
= STATUS_USER_MAPPED_FILE
);
1762 // Perform directory entry modifications. Release any on-disk
1763 // space we may need to in the process.
1764 UDFReferenceFile__(Fcb
->FileInfo
);
1765 UDFInterlockedIncrement((PLONG
)&(Fcb
->ReferenceCount
));
1766 UDFInterlockedIncrement((PLONG
)&(NtReqFcb
->CommonRefCount
));
1767 // perform resize operation
1768 RC
= UDFResizeFile__(Vcb
, Fcb
->FileInfo
, PtrBuffer
->EndOfFile
.QuadPart
);
1770 UDFCloseFile__(Vcb
, Fcb
->FileInfo
);
1771 UDFInterlockedDecrement((PLONG
)&(Fcb
->ReferenceCount
));
1772 UDFInterlockedDecrement((PLONG
)&(NtReqFcb
->CommonRefCount
));
1774 ModifiedAllocSize
= TRUE
;
1775 TruncatedFile
= TRUE
;
1778 // This is a good place to check if we have performed a truncate
1779 // operation. If we have perform a truncate (whether we extended
1780 // or reduced file size), we should update file time stamps.
1782 // Last, but not the least, we must inform the Cache Manager of file size changes.
1783 if(ModifiedAllocSize
&& NT_SUCCESS(RC
)) {
1784 // If we decreased the allocation size to less than the
1785 // current file size, modify the file size value.
1786 // Similarly, if we decreased the value to less than the
1787 // current valid data length, modify that value as well.
1789 if(NtReqFcb
->CommonFCBHeader
.ValidDataLength
.QuadPart
>
1790 PtrBuffer
->EndOfFile
.QuadPart
) {
1791 // Decrease the valid data length value.
1792 NtReqFcb
->CommonFCBHeader
.ValidDataLength
=
1793 PtrBuffer
->EndOfFile
;
1795 if(NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
>
1796 PtrBuffer
->EndOfFile
.QuadPart
) {
1797 // Decrease the file size value.
1798 NtReqFcb
->CommonFCBHeader
.FileSize
=
1799 PtrBuffer
->EndOfFile
;
1801 UDFSetFileSizeInDirNdx(Vcb
, Fcb
->FileInfo
, NULL
);
1803 // Update the FCB Header with the new allocation size.
1804 // NT expects AllocationSize to be decreased on Close only
1805 NtReqFcb
->CommonFCBHeader
.AllocationSize
.QuadPart
=
1806 PtrBuffer
->EndOfFile
.QuadPart
;
1807 // UDFSysGetAllocSize(Vcb, UDFGetFileSize(Fcb->FileInfo));
1808 UDFSetFileSizeInDirNdx(Vcb
, Fcb
->FileInfo
, &(PtrBuffer
->EndOfFile
.QuadPart
));
1811 FileObject
->Flags
|= FO_FILE_MODIFIED
;
1812 // UDFGetFileAllocationSize(Vcb, Fcb->FileInfo);
1814 // If the FCB has not had caching initiated, it is still valid
1815 // for us to invoke the NT Cache Manager. It is possible in such
1816 // situations for the call to be no'oped (unless some user has
1817 // mapped in the file)
1820 if(Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_ARCH_BIT
) {
1821 DirNdx
= UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb
->FileInfo
), Fcb
->FileInfo
->Index
);
1822 Ccb
->CCBFlags
&= ~UDF_CCB_ATTRIBUTES_SET
;
1823 Attr
= UDFAttributesToNT(DirNdx
, Fcb
->FileInfo
->Dloc
->FileEntry
);
1824 if(!(Attr
& FILE_ATTRIBUTE_ARCHIVE
))
1825 UDFAttributesToUDF(DirNdx
, Fcb
->FileInfo
->Dloc
->FileEntry
, Attr
| FILE_ATTRIBUTE_ARCHIVE
);
1828 // NOTE: The invocation to CcSetFileSizes() will quite possibly
1829 // result in a recursive call back into the file system.
1830 // This is because the NT Cache Manager will typically
1831 // perform a flush before telling the VMM to purge pages
1832 // especially when caching has not been initiated on the
1833 // file stream, but the user has mapped the file into
1834 // the process' virtual address space.
1835 MmPrint((" CcSetFileSizes(), thrd:%8.8x\n",PsGetCurrentThread()));
1836 Fcb
->NTRequiredFCB
->AcqFlushCount
++;
1837 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&(NtReqFcb
->CommonFCBHeader
.AllocationSize
));
1838 Fcb
->NTRequiredFCB
->AcqFlushCount
--;
1840 UDFZeroDataEx(NtReqFcb,
1842 PtrBuffer->EndOfFile.QuadPart - OldFileSize,
1843 TRUE // CanWait, Vcb, FileObject);
1845 Fcb
->NTRequiredFCB
->NtReqFCBFlags
|= UDF_NTREQ_FCB_MODIFIED
;
1847 notify_size_changes
:
1848 if(AcquiredPagingIo
) {
1849 UDFReleaseResource(&(Fcb
->NTRequiredFCB
->PagingIoResource
));
1850 AcquiredPagingIo
= FALSE
;
1853 // Inform any pending IRPs (notify change directory).
1854 if(UDFIsAStream(Fcb
->FileInfo
)) {
1855 UDFNotifyFullReportChange( Vcb
, Fcb
->FileInfo
,
1856 FILE_NOTIFY_CHANGE_STREAM_SIZE
,
1857 FILE_ACTION_MODIFIED_STREAM
);
1859 UDFNotifyFullReportChange( Vcb
, Fcb
->FileInfo
,
1860 FILE_NOTIFY_CHANGE_SIZE
,
1861 FILE_ACTION_MODIFIED
);
1868 if(AcquiredPagingIo
) {
1869 UDFReleaseResource(&(Fcb
->NTRequiredFCB
->PagingIoResource
));
1870 AcquiredPagingIo
= FALSE
;
1872 if (CacheMapInitialized
) {
1874 MmPrint((" CcUninitializeCacheMap()\n"));
1875 CcUninitializeCacheMap( FileObject
, NULL
, NULL
);
1879 } // end UDFSetEOF()
1882 UDFPrepareForRenameMoveLink(
1884 PBOOLEAN AcquiredVcb
,
1885 PBOOLEAN AcquiredVcbEx
,
1887 PBOOLEAN AcquiredDir1
,
1888 PBOOLEAN AcquiredFcb1
,
1890 PUDF_FILE_INFO File1
,
1891 PUDF_FILE_INFO Dir1
,
1892 PUDF_FILE_INFO Dir2
,
1896 // convert acquisition to Exclusive
1897 // this will prevent us from the following situation:
1898 // There is a pair of objects among input dirs &
1899 // one of them is a parent of another. Sequential resource
1900 // acquisition may lead to deadlock due to concurrent
1901 // CleanUpFcbChain() or UDFCloseFileInfoChain()
1902 UDFInterlockedIncrement((PLONG
)&(Vcb
->VCBOpenCount
));
1903 UDFReleaseResource(&(Vcb
->VCBResource
));
1904 (*AcquiredVcb
) = FALSE
;
1906 // At first, make system to issue last Close request
1907 // for our Source & Target ...
1908 // we needn't flush/purge for Source on HLink
1909 UDFRemoveFromSystemDelayedQueue(Dir2
->Fcb
);
1910 if(!HardLink
&& (Dir2
!= Dir1
))
1911 UDFRemoveFromSystemDelayedQueue(File1
->Fcb
);
1913 #ifdef UDF_DELAYED_CLOSE
1915 // Do actual close for all "delayed close" calls
1917 // ... and now remove the rest from our queue
1919 UDFCloseAllDelayedInDir(Vcb
, Dir1
);
1921 UDFCloseAllDelayedInDir(Vcb
, Dir2
);
1923 UDFCloseAllDelayedInDir(Vcb
, Dir2
);
1926 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
1928 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCount
));
1929 return (STATUS_DRIVER_INTERNAL_ERROR
);
1931 #endif //UDF_DELAYED_CLOSE
1933 (*SingleDir
) = ((Dir1
== Dir2
) && (Dir1
->Fcb
));
1936 (UDFGetFileLinkCount(File1
) != 1)) {
1937 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
1938 (*AcquiredVcb
) = TRUE
;
1939 (*AcquiredVcbEx
) = TRUE
;
1940 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCount
));
1942 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
1943 (*AcquiredVcb
) = TRUE
;
1944 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCount
));
1946 UDF_CHECK_PAGING_IO_RESOURCE(Dir1
->Fcb
->NTRequiredFCB
);
1947 UDFAcquireResourceExclusive(&(Dir1
->Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
1948 (*AcquiredDir1
) = TRUE
;
1950 UDF_CHECK_PAGING_IO_RESOURCE(File1
->Fcb
->NTRequiredFCB
);
1951 UDFAcquireResourceExclusive(&(File1
->Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
1952 (*AcquiredFcb1
) = TRUE
;
1954 return STATUS_SUCCESS
;
1955 } // end UDFPrepareForRenameMoveLink()
1962 IN PIO_STACK_LOCATION PtrSp
,
1965 IN PFILE_OBJECT FileObject1
, // Source File
1966 IN PFILE_RENAME_INFORMATION PtrBuffer
1970 PFILE_OBJECT DirObject1
= FileObject1
->RelatedFileObject
;
1972 PFILE_OBJECT DirObject2
= PtrSp
->Parameters
.SetFile
.FileObject
;
1974 BOOLEAN Replace
= PtrSp
->Parameters
.SetFile
.ReplaceIfExists
&&
1975 PtrBuffer
->ReplaceIfExists
;
1977 PVCB Vcb
= Fcb1
->Vcb
;
1980 BOOLEAN AcquiredVcb
= TRUE
;
1981 BOOLEAN AcquiredVcbEx
= FALSE
;
1982 BOOLEAN AcquiredDir1
= FALSE
;
1983 BOOLEAN AcquiredFcb1
= FALSE
;
1984 BOOLEAN SingleDir
= TRUE
;
1987 PUDF_FILE_INFO File1
;
1988 PUDF_FILE_INFO Dir1
;
1989 PUDF_FILE_INFO Dir2
;
1990 PUDF_FILE_INFO NextFileInfo
, fi
;
1992 UNICODE_STRING NewName
;
1993 UNICODE_STRING LocalPath
;
1994 PtrUDFCCB CurCcb
= NULL
;
1998 ULONG FileInfoRefCount
;
2000 PDIR_INDEX_ITEM DirNdx
;
2002 AdPrint(("UDFRename %8.8x\n", DirObject2
));
2004 LocalPath
.Buffer
= NULL
;
2007 // do we try to rename Volume ?
2008 #ifdef UDF_ALLOW_RENAME_MOVE
2009 if(!(File1
= Fcb1
->FileInfo
))
2010 #endif //UDF_ALLOW_RENAME_MOVE
2011 try_return (RC
= STATUS_ACCESS_DENIED
);
2013 // do we try to rename RootDir ?
2014 if(!(Dir1
= File1
->ParentFile
))
2015 try_return (RC
= STATUS_ACCESS_DENIED
);
2017 // do we try to rename to RootDir or Volume ?
2019 Dir2
= File1
->ParentFile
;
2020 DirObject2
= DirObject1
;
2022 if(DirObject2
->FsContext2
&&
2023 (Fcb2
= ((PtrUDFCCB
)(DirObject2
->FsContext2
))->Fcb
)) {
2024 Dir2
= ((PtrUDFCCB
)(DirObject2
->FsContext2
))->Fcb
->FileInfo
;
2026 try_return (RC
= STATUS_INVALID_PARAMETER
);
2028 // invalid destination ?
2029 if(!Dir2
) try_return (RC
= STATUS_ACCESS_DENIED
);
2031 // Stream can't be a Dir or have StreamDir
2032 if(UDFIsAStreamDir(Dir2
)) {
2033 #ifdef UDF_ENABLE_SECURITY
2034 if(UDFIsADirectory(File1
)) {
2035 try_return (RC
= STATUS_ACCESS_DENIED
);
2037 // We should check whether File1 has only Internal
2038 // (or Deleted) streams. In this case SDir should be
2039 // removed (in UDFRenameMoveFile__()). Otherwise
2040 // return STATUS_ACCESS_DENIED
2041 if(UDFHasAStreamDir(File1
)) {
2042 UDFPrint(("TODO: We should remove Streams from source file\n"));
2043 try_return (RC
= STATUS_ACCESS_DENIED
);
2045 #else //UDF_ENABLE_SECURITY
2046 if(UDFIsADirectory(File1
) ||
2047 UDFHasAStreamDir(File1
)) {
2048 try_return (RC
= STATUS_ACCESS_DENIED
);
2050 #endif //UDF_ENABLE_SECURITY
2053 RC
= UDFPrepareForRenameMoveLink(Vcb
, &AcquiredVcb
, &AcquiredVcbEx
,
2055 &AcquiredDir1
, &AcquiredFcb1
,
2058 FALSE
); // it is Rename operation
2062 // check if the source file is in use
2063 if(Fcb1
->OpenHandleCount
> 1)
2064 try_return (RC
= STATUS_ACCESS_DENIED
);
2065 ASSERT(Fcb1
->OpenHandleCount
);
2066 ASSERT(!Fcb1
->IrpContextLite
);
2067 if(Fcb1
->IrpContextLite
) {
2068 try_return (RC
= STATUS_ACCESS_DENIED
);
2070 // Check if we have parallel/pending Close threads
2071 if(Fcb1
->CcbCount
&& !SingleDir
) {
2072 // if this is the 1st attempt, we'll try to
2073 // synchronize with Close requests
2074 // otherwise fail request
2075 RC
= STATUS_ACCESS_DENIED
;
2077 if(Fcb1
->FCBFlags
& UDF_FCB_POSTED_RENAME
) {
2078 Fcb1
->FCBFlags
&= ~UDF_FCB_POSTED_RENAME
;
2081 Fcb1
->FCBFlags
|= UDF_FCB_POSTED_RENAME
;
2082 try_return (RC
= STATUS_PENDING
);
2086 // Make sure the name is of legal length.
2087 if(PtrBuffer
->FileNameLength
> UDF_NAME_LEN
*sizeof(WCHAR
)) {
2088 try_return(RC
= STATUS_OBJECT_NAME_INVALID
);
2090 NewName
.Length
= NewName
.MaximumLength
= (USHORT
)(PtrBuffer
->FileNameLength
);
2091 NewName
.Buffer
= (PWCHAR
)&(PtrBuffer
->FileName
);
2093 // This name is by definition legal.
2094 NewName
= *((PUNICODE_STRING
)&DirObject2
->FileName
);
2097 ic
= (Ccb1
->CCBFlags
& UDF_CCB_CASE_SENSETIVE
) ? FALSE
: TRUE
;
2099 AdPrint((" %ws ->\n %ws\n",
2100 Fcb1
->FCBName
->ObjectName
.Buffer
,
2103 if(UDFIsDirOpened__(File1
)) {
2104 // We can't rename file because of unclean references.
2105 // UDF_INFO package can safely do it, but NT side cannot.
2106 // In this case NT requires STATUS_OBJECT_NAME_COLLISION
2107 // rather than STATUS_ACCESS_DENIED
2108 if(NT_SUCCESS(UDFFindFile__(Vcb
, ic
, &NewName
, Dir2
)))
2109 try_return(RC
= STATUS_OBJECT_NAME_COLLISION
);
2110 try_return (RC
= STATUS_ACCESS_DENIED
);
2112 // Last check before Moving.
2113 // We can't move across Dir referenced (even internally) file
2115 RC
= UDFDoesOSAllowFileToBeMoved__(File1
);
2116 if(!NT_SUCCESS(RC
)) {
2122 ASSERT_REF(Fcb1
->ReferenceCount
>= File1
->RefCount
);
2123 ASSERT_REF(Dir1
->Fcb
->ReferenceCount
>= Dir1
->RefCount
);
2124 ASSERT_REF(Dir2
->Fcb
->ReferenceCount
>= Dir2
->RefCount
);
2126 RC
= UDFRenameMoveFile__(Vcb
, ic
, &Replace
, &NewName
, Dir1
, Dir2
, File1
);
2131 ASSERT(UDFDirIndex(File1
->ParentFile
->Dloc
->DirIndex
, File1
->Index
)->FileInfo
== File1
);
2133 RC
= MyCloneUnicodeString(&LocalPath
, (Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ?
2134 &UDFGlobalData
.UnicodeStrRoot
:
2135 &(Dir2
->Fcb
->FCBName
->ObjectName
) );
2136 if(!NT_SUCCESS(RC
)) try_return (RC
);
2137 // RC = MyAppendUnicodeStringToString(&LocalPath, (Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? &(UDFGlobalData.UnicodeStrRoot) : &(Dir2->Fcb->FCBName->ObjectName));
2138 // if(!NT_SUCCESS(RC)) try_return (RC);
2139 if(Dir2
->ParentFile
) {
2140 RC
= MyAppendUnicodeToString(&LocalPath
, L
"\\");
2141 if(!NT_SUCCESS(RC
)) try_return (RC
);
2143 RC
= MyAppendUnicodeStringToStringTag(&LocalPath
, &NewName
, MEM_USREN_TAG
);
2144 if(!NT_SUCCESS(RC
)) try_return (RC
);
2147 DirNdx
= UDFDirIndex(File1
->ParentFile
->Dloc
->DirIndex
, File1
->Index
);
2148 if(Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_ARCH_BIT
) {
2149 Attr
= UDFAttributesToNT(DirNdx
, File1
->Dloc
->FileEntry
);
2150 if(!(Attr
& FILE_ATTRIBUTE_ARCHIVE
))
2151 UDFAttributesToUDF(DirNdx
, File1
->Dloc
->FileEntry
, Attr
| FILE_ATTRIBUTE_ARCHIVE
);
2153 // Update Parent Objects (mark 'em as modified)
2154 if(Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_DIR_WRITE
) {
2156 DirObject1
->Flags
|= FO_FILE_MODIFIED
;
2158 DirObject2
->Flags
|= FO_FILE_MODIFIED
;
2160 DirObject2
->Flags
|= FO_FILE_SIZE_CHANGED
;
2164 if(SingleDir
&& !Replace
) {
2165 UDFNotifyFullReportChange( Vcb
, File1
,
2166 UDFIsADirectory(File1
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
2167 FILE_ACTION_RENAMED_OLD_NAME
);
2168 /* UDFNotifyFullReportChange( Vcb, File2,
2169 UDFIsADirectory(File2) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
2170 FILE_ACTION_RENAMED_NEW_NAME );*/
2171 FsRtlNotifyFullReportChange( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
2172 (PSTRING
)&LocalPath
,
2173 ((Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ? 0 : Dir2
->Fcb
->FCBName
->ObjectName
.Length
) + sizeof(WCHAR
),
2175 UDFIsADirectory(File1
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
2176 FILE_ACTION_RENAMED_NEW_NAME
,
2179 UDFNotifyFullReportChange( Vcb
, File1
,
2180 UDFIsADirectory(File1
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
2181 FILE_ACTION_REMOVED
);
2183 /* UDFNotifyFullReportChange( Vcb, File2,
2184 FILE_NOTIFY_CHANGE_ATTRIBUTES |
2185 FILE_NOTIFY_CHANGE_SIZE |
2186 FILE_NOTIFY_CHANGE_LAST_WRITE |
2187 FILE_NOTIFY_CHANGE_LAST_ACCESS |
2188 FILE_NOTIFY_CHANGE_CREATION |
2189 FILE_NOTIFY_CHANGE_EA,
2190 FILE_ACTION_MODIFIED );*/
2191 FsRtlNotifyFullReportChange( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
2192 (PSTRING
)&LocalPath
,
2193 ((Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ?
2194 0 : Dir2
->Fcb
->FCBName
->ObjectName
.Length
) + sizeof(WCHAR
),
2196 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
2197 FILE_NOTIFY_CHANGE_SIZE
|
2198 FILE_NOTIFY_CHANGE_LAST_WRITE
|
2199 FILE_NOTIFY_CHANGE_LAST_ACCESS
|
2200 FILE_NOTIFY_CHANGE_CREATION
|
2201 FILE_NOTIFY_CHANGE_EA
,
2202 FILE_ACTION_MODIFIED
,
2205 /* UDFNotifyFullReportChange( Vcb, File2,
2206 UDFIsADirectory(File2) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
2207 FILE_ACTION_ADDED );*/
2208 FsRtlNotifyFullReportChange( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
2209 (PSTRING
)&LocalPath
,
2210 ((Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ?
2211 0 : Dir2
->Fcb
->FCBName
->ObjectName
.Length
) + sizeof(WCHAR
),
2213 UDFIsADirectory(File1
) ?
2214 FILE_NOTIFY_CHANGE_DIR_NAME
:
2215 FILE_NOTIFY_CHANGE_FILE_NAME
,
2221 // this will prevent structutre release before call to
2222 // UDFCleanUpFcbChain()
2223 UDFInterlockedIncrement((PLONG
)&(Dir1
->Fcb
->ReferenceCount
));
2224 UDFInterlockedIncrement((PLONG
)&(Dir1
->Fcb
->NTRequiredFCB
->CommonRefCount
));
2225 ASSERT_REF(Dir1
->Fcb
->ReferenceCount
>= Dir1
->RefCount
);
2227 // Look through Ccb list & decrement OpenHandleCounter(s)
2230 UDFAcquireResourceExclusive(&(Fcb1
->CcbListResource
),TRUE
);
2231 Link
= Fcb1
->NextCCB
.Flink
;
2233 FileInfoRefCount
= 0;
2234 ASSERT(Link
!= &(Fcb1
->NextCCB
));
2235 while (Link
!= &(Fcb1
->NextCCB
)) {
2236 NextFileInfo
= Dir1
;
2237 CurCcb
= CONTAINING_RECORD(Link
, UDFCCB
, NextCCB
);
2238 ASSERT(CurCcb
->TreeLength
);
2239 i
= (CurCcb
->TreeLength
) ? (CurCcb
->TreeLength
- 1) : 0;
2241 UseClose
= (CurCcb
->CCBFlags
& UDF_CCB_CLEANED
) ? FALSE
: TRUE
;
2243 AdPrint((" Ccb:%x:%s:i:%x\n", CurCcb
, UseClose
? "Close" : "",i
));
2244 // cleanup old parent chain
2245 for(; i
&& NextFileInfo
; i
--) {
2246 // remember parent file now
2247 // it will prevent us from data losses
2248 // due to eventual structure release
2249 fi
= NextFileInfo
->ParentFile
;
2251 ASSERT_REF(NextFileInfo
->Fcb
->ReferenceCount
>= NextFileInfo
->RefCount
);
2252 UDFCloseFile__(Vcb
, NextFileInfo
);
2254 ASSERT_REF(NextFileInfo
->Fcb
->ReferenceCount
> NextFileInfo
->RefCount
);
2255 ASSERT_REF(NextFileInfo
->Fcb
->ReferenceCount
);
2256 ASSERT_REF(NextFileInfo
->Fcb
->NTRequiredFCB
->CommonRefCount
);
2257 UDFInterlockedDecrement((PLONG
)&(NextFileInfo
->Fcb
->ReferenceCount
));
2258 UDFInterlockedDecrement((PLONG
)&(NextFileInfo
->Fcb
->NTRequiredFCB
->CommonRefCount
));
2259 ASSERT_REF(NextFileInfo
->Fcb
->ReferenceCount
>= NextFileInfo
->RefCount
);
2263 if(CurCcb
->TreeLength
> 1) {
2267 CurCcb
->TreeLength
= 2;
2274 UDFReleaseResource(&(Fcb1
->CcbListResource
));
2276 ASSERT_REF(DirRefCount
>= FileInfoRefCount
);
2277 // update counters & pointers
2278 Fcb1
->ParentFcb
= Dir2
->Fcb
;
2279 // move references to Dir2
2280 UDFInterlockedExchangeAdd((PLONG
)&(Dir2
->Fcb
->ReferenceCount
), DirRefCount
);
2281 UDFInterlockedExchangeAdd((PLONG
)&(Dir2
->Fcb
->NTRequiredFCB
->CommonRefCount
), DirRefCount
);
2282 ASSERT_REF(Dir2
->Fcb
->ReferenceCount
> Dir2
->RefCount
);
2283 UDFReferenceFileEx__(Dir2
,FileInfoRefCount
);
2284 ASSERT_REF(Dir2
->Fcb
->ReferenceCount
>= Dir2
->RefCount
);
2286 ASSERT_REF(Dir2
->Fcb
->ReferenceCount
>= Dir2
->RefCount
);
2287 ASSERT_REF(Dir2
->RefCount
);
2289 ASSERT_REF(Dir1
->Fcb
->ReferenceCount
>= Dir1
->RefCount
);
2290 // Modify name in Fcb1
2292 if(Fcb1
->FCBName
->ObjectName
.Buffer
) {
2293 MyFreePool__(Fcb1
->FCBName
->ObjectName
.Buffer
);
2295 UDFReleaseObjectName(Fcb1
->FCBName
);
2297 Fcb1
->FCBName
= UDFAllocateObjectName();
2298 if(!(Fcb1
->FCBName
)) {
2301 // UDFCleanUpFcbChain()...
2303 UDF_CHECK_PAGING_IO_RESOURCE(Fcb1
->NTRequiredFCB
);
2304 UDFReleaseResource(&(Fcb1
->NTRequiredFCB
->MainResource
));
2305 AcquiredDir1
= FALSE
;
2308 UDF_CHECK_PAGING_IO_RESOURCE(Dir1
->Fcb
->NTRequiredFCB
);
2309 UDFReleaseResource(&(Dir1
->Fcb
->NTRequiredFCB
->MainResource
));
2310 AcquiredDir1
= FALSE
;
2312 UDFCleanUpFcbChain(Vcb
, Dir1
, 1, TRUE
);
2313 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
2316 RC
= MyCloneUnicodeString(&(Fcb1
->FCBName
->ObjectName
), &(Fcb2
->FCBName
->ObjectName
));
2319 /* RC = MyAppendUnicodeStringToString(&(Fcb1->FCBName->ObjectName), &(Fcb2->FCBName->ObjectName));
2322 // if Dir2 is a RootDir, we shoud not append '\\' because
2323 // uit will be the 2nd '\\' character (RootDir's name is also '\\')
2324 if(Dir2
->ParentFile
) {
2325 RC
= MyAppendUnicodeToString(&(Fcb1
->FCBName
->ObjectName
), L
"\\");
2329 RC
= MyAppendUnicodeStringToStringTag(&(Fcb1
->FCBName
->ObjectName
), &NewName
, MEM_USREN2_TAG
);
2333 ASSERT_REF(Fcb1
->ReferenceCount
>= File1
->RefCount
);
2334 ASSERT_REF(Dir1
->Fcb
->ReferenceCount
>= Dir1
->RefCount
);
2335 ASSERT_REF(Dir2
->Fcb
->ReferenceCount
>= Dir2
->RefCount
);
2337 RC
= STATUS_SUCCESS
;
2344 UDF_CHECK_PAGING_IO_RESOURCE(Fcb1
->NTRequiredFCB
);
2345 UDFReleaseResource(&(Fcb1
->NTRequiredFCB
->MainResource
));
2348 UDF_CHECK_PAGING_IO_RESOURCE(Dir1
->Fcb
->NTRequiredFCB
);
2349 UDFReleaseResource(&(Dir1
->Fcb
->NTRequiredFCB
->MainResource
));
2351 // perform protected structure release
2352 if(NT_SUCCESS(RC
) &&
2353 (RC
!= STATUS_PENDING
)) {
2354 ASSERT(AcquiredVcb
);
2355 UDFCleanUpFcbChain(Vcb
, Dir1
, 1, TRUE
);
2356 ASSERT_REF(Fcb1
->ReferenceCount
>= File1
->RefCount
);
2357 ASSERT_REF(Dir2
->Fcb
->ReferenceCount
>= Dir2
->RefCount
);
2362 UDFConvertExclusiveToSharedLite(&(Vcb
->VCBResource
));
2364 // caller assumes Vcb to be acquired shared
2366 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
2369 if(LocalPath
.Buffer
) {
2370 MyFreePool__(LocalPath
.Buffer
);
2375 } // end UDFRename()
2377 #endif //UDF_READ_ONLY_BUILD
2385 if(!Vcb
->FileIdCache
) return (-1);
2386 for(ULONG i
=0; i
<Vcb
->FileIdCount
; i
++) {
2387 if(Vcb
->FileIdCache
[i
].Id
== Id
) return i
;
2390 } // end UDFFindFileId()
2398 if(!Vcb
->FileIdCache
) {
2399 if(!(Vcb
->FileIdCache
= (PUDFFileIDCacheItem
)MyAllocatePool__(NonPagedPool
, sizeof(UDFFileIDCacheItem
)*FILE_ID_CACHE_GRANULARITY
)))
2401 RtlZeroMemory(Vcb
->FileIdCache
, FILE_ID_CACHE_GRANULARITY
*sizeof(UDFFileIDCacheItem
));
2402 Vcb
->FileIdCount
= FILE_ID_CACHE_GRANULARITY
;
2404 for(ULONG i
=0; i
<Vcb
->FileIdCount
; i
++) {
2405 if(!Vcb
->FileIdCache
[i
].FullName
.Buffer
) return i
;
2407 if(!MyReallocPool__((PCHAR
)(Vcb
->FileIdCache
), Vcb
->FileIdCount
*sizeof(UDFFileIDCacheItem
),
2408 (PCHAR
*)&(Vcb
->FileIdCache
), (Vcb
->FileIdCount
+FILE_ID_CACHE_GRANULARITY
)*sizeof(UDFFileIDCacheItem
))) {
2411 RtlZeroMemory(&(Vcb
->FileIdCache
[Vcb
->FileIdCount
]), FILE_ID_CACHE_GRANULARITY
*sizeof(UDFFileIDCacheItem
));
2412 Vcb
->FileIdCount
+= FILE_ID_CACHE_GRANULARITY
;
2413 return (Vcb
->FileIdCount
- FILE_ID_CACHE_GRANULARITY
);
2414 } // end UDFFindFreeFileId()
2420 IN PUDF_FILE_INFO fi
,
2425 NTSTATUS RC
= STATUS_SUCCESS
;
2427 if((i
= UDFFindFileId(Vcb
, Id
)) == (-1)) {
2428 if((i
= UDFFindFreeFileId(Vcb
, Id
)) == (-1)) return STATUS_INSUFFICIENT_RESOURCES
;
2430 return STATUS_SUCCESS
;
2432 Vcb
->FileIdCache
[i
].Id
= Id
;
2433 Vcb
->FileIdCache
[i
].CaseSens
= (Ccb
->CCBFlags
& UDF_CCB_CASE_SENSETIVE
) ? TRUE
: FALSE
;
2434 RC
= MyCloneUnicodeString(&(Vcb
->FileIdCache
[i
].FullName
), &(Ccb
->Fcb
->FCBName
->ObjectName
));
2435 /* if(NT_SUCCESS(RC)) {
2436 RC = MyAppendUnicodeStringToStringTag(&(Vcb->FileIdCache[i].FullName), &(Ccb->Fcb->FCBName->ObjectName), MEM_USFIDC_TAG);
2439 } // end UDFStoreFileId()
2449 if((i
= UDFFindFileId(Vcb
, Id
)) == (-1)) return STATUS_INVALID_PARAMETER
;
2450 MyFreePool__(Vcb
->FileIdCache
[i
].FullName
.Buffer
);
2451 RtlZeroMemory(&(Vcb
->FileIdCache
[i
]), sizeof(UDFFileIDCacheItem
));
2452 return STATUS_SUCCESS
;
2453 } // end UDFRemoveFileId()
2456 UDFReleaseFileIdCache(
2460 if(!Vcb
->FileIdCache
) return;
2461 for(ULONG i
=0; i
<Vcb
->FileIdCount
; i
++) {
2462 if(Vcb
->FileIdCache
[i
].FullName
.Buffer
) {
2463 MyFreePool__(Vcb
->FileIdCache
[i
].FullName
.Buffer
);
2466 MyFreePool__(Vcb
->FileIdCache
);
2467 Vcb
->FileIdCache
= NULL
;
2468 Vcb
->FileIdCount
= 0;
2469 } // end UDFReleaseFileIdCache()
2472 UDFGetOpenParamsByFileId(
2475 OUT PUNICODE_STRING
* FName
,
2476 OUT BOOLEAN
* CaseSens
2481 if((i
= UDFFindFileId(Vcb
, Id
)) == (-1)) return STATUS_NOT_FOUND
;
2482 (*FName
) = &(Vcb
->FileIdCache
[i
].FullName
);
2483 (*CaseSens
) = !(Vcb
->FileIdCache
[i
].CaseSens
);
2484 return STATUS_SUCCESS
;
2485 } // end UDFGetOpenParamsByFileId()
2487 #ifndef UDF_READ_ONLY_BUILD
2489 #ifdef UDF_ALLOW_HARD_LINKS
2491 create hard link for the file
2495 IN PIO_STACK_LOCATION PtrSp
,
2498 IN PFILE_OBJECT FileObject1
, // Source File
2499 IN PFILE_LINK_INFORMATION PtrBuffer
2503 PFILE_OBJECT DirObject2
= PtrSp
->Parameters
.SetFile
.FileObject
;
2505 BOOLEAN Replace
= PtrSp
->Parameters
.SetFile
.ReplaceIfExists
&&
2506 PtrBuffer
->ReplaceIfExists
;
2508 PVCB Vcb
= Fcb1
->Vcb
;
2511 BOOLEAN AcquiredVcb
= TRUE
;
2512 BOOLEAN AcquiredVcbEx
= FALSE
;
2513 BOOLEAN AcquiredDir1
= FALSE
;
2514 BOOLEAN AcquiredFcb1
= FALSE
;
2515 BOOLEAN SingleDir
= TRUE
;
2517 PUDF_FILE_INFO File1
;
2518 PUDF_FILE_INFO Dir1
= NULL
;
2519 PUDF_FILE_INFO Dir2
;
2521 UNICODE_STRING NewName
;
2522 UNICODE_STRING LocalPath
;
2523 // PtrUDFCCB CurCcb = NULL;
2525 AdPrint(("UDFHardLink\n"));
2527 LocalPath
.Buffer
= NULL
;
2531 // do we try to link Volume ?
2532 if(!(File1
= Fcb1
->FileInfo
))
2533 try_return (RC
= STATUS_ACCESS_DENIED
);
2535 // do we try to link RootDir ?
2536 if(!(Dir1
= File1
->ParentFile
))
2537 try_return (RC
= STATUS_ACCESS_DENIED
);
2539 // do we try to link Stream / Stream Dir ?
2540 #ifdef UDF_ALLOW_LINKS_TO_STREAMS
2541 if(UDFIsAStreamDir(File1
))
2542 try_return (RC
= STATUS_ACCESS_DENIED
);
2543 #else //UDF_ALLOW_LINKS_TO_STREAMS
2544 if(UDFIsAStream(File1
) || UDFIsAStreamDir(File1
) /*||
2545 UDFIsADirectory(File1) || UDFHasAStreamDir(File1)*/)
2546 try_return (RC
= STATUS_ACCESS_DENIED
);
2547 #endif // UDF_ALLOW_LINKS_TO_STREAMS
2549 // do we try to link to RootDir or Volume ?
2551 Dir2
= File1
->ParentFile
;
2552 DirObject2
= FileObject1
->RelatedFileObject
;
2554 if(DirObject2
->FsContext2
&&
2555 (Fcb2
= ((PtrUDFCCB
)(DirObject2
->FsContext2
))->Fcb
)) {
2556 Dir2
= ((PtrUDFCCB
)(DirObject2
->FsContext2
))->Fcb
->FileInfo
;
2558 try_return (RC
= STATUS_INVALID_PARAMETER
);
2562 if(!Dir2
) try_return (RC
= STATUS_ACCESS_DENIED
);
2564 // Stream can't be a Dir or have Streams
2565 if(UDFIsAStreamDir(Dir2
)) {
2566 try_return (RC
= STATUS_ACCESS_DENIED
);
2567 /* if(UDFIsADirectory(File1) ||
2568 UDFHasAStreamDir(File1)) {
2570 try_return (RC = STATUS_ACCESS_DENIED);
2574 /* if(UDFIsAStreamDir(Dir2))
2575 try_return (RC = STATUS_ACCESS_DENIED);*/
2577 RC
= UDFPrepareForRenameMoveLink(Vcb
, &AcquiredVcb
, &AcquiredVcbEx
,
2579 &AcquiredDir1
, &AcquiredFcb1
,
2582 TRUE
); // it is HLink operation
2586 // check if the source file is used
2588 // Make sure the name is of legal length.
2589 if(PtrBuffer
->FileNameLength
> UDF_NAME_LEN
*sizeof(WCHAR
)) {
2590 try_return(RC
= STATUS_OBJECT_NAME_INVALID
);
2592 NewName
.Length
= NewName
.MaximumLength
= (USHORT
)(PtrBuffer
->FileNameLength
);
2593 NewName
.Buffer
= (PWCHAR
)&(PtrBuffer
->FileName
);
2595 // This name is by definition legal.
2596 NewName
= *((PUNICODE_STRING
)&DirObject2
->FileName
);
2599 ic
= (Ccb1
->CCBFlags
& UDF_CCB_CASE_SENSETIVE
) ? FALSE
: TRUE
;
2601 AdPrint((" %ws ->\n %ws\n",
2602 Fcb1
->FCBName
->ObjectName
.Buffer
,
2605 RC
= UDFHardLinkFile__(Vcb
, ic
, &Replace
, &NewName
, Dir1
, Dir2
, File1
);
2606 if(!NT_SUCCESS(RC
)) try_return (RC
);
2608 // Update Parent Objects (mark 'em as modified)
2609 if(Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_DIR_WRITE
) {
2611 DirObject2
->Flags
|= FO_FILE_MODIFIED
;
2613 DirObject2
->Flags
|= FO_FILE_SIZE_CHANGED
;
2617 UDFNotifyFullReportChange( Vcb
, File1
,
2618 FILE_NOTIFY_CHANGE_LAST_WRITE
|
2619 FILE_NOTIFY_CHANGE_LAST_ACCESS
,
2620 FILE_ACTION_MODIFIED
);
2622 RC
= MyCloneUnicodeString(&LocalPath
, (Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ?
2623 &UDFGlobalData
.UnicodeStrRoot
:
2624 &(Dir2
->Fcb
->FCBName
->ObjectName
));
2625 if(!NT_SUCCESS(RC
)) try_return (RC
);
2626 /* RC = MyAppendUnicodeStringToString(&LocalPath, (Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? &(UDFGlobalData.UnicodeStrRoot) : &(Dir2->Fcb->FCBName->ObjectName));
2627 if(!NT_SUCCESS(RC)) try_return (RC);*/
2628 // if Dir2 is a RootDir, we shoud not append '\\' because
2629 // it will be the 2nd '\\' character (RootDir's name is also '\\')
2630 if(Dir2
->ParentFile
) {
2631 RC
= MyAppendUnicodeToString(&LocalPath
, L
"\\");
2632 if(!NT_SUCCESS(RC
)) try_return (RC
);
2634 RC
= MyAppendUnicodeStringToStringTag(&LocalPath
, &NewName
, MEM_USHL_TAG
);
2635 if(!NT_SUCCESS(RC
)) try_return (RC
);
2638 /* UDFNotifyFullReportChange( Vcb, File2,
2639 UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
2640 FILE_ACTION_ADDED );*/
2641 FsRtlNotifyFullReportChange( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
2642 (PSTRING
)&LocalPath
,
2643 ((Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ? 0 : Dir2
->Fcb
->FCBName
->ObjectName
.Length
) + sizeof(WCHAR
),
2645 UDFIsADirectory(File1
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
2649 /* UDFNotifyFullReportChange( Vcb, File2,
2650 FILE_NOTIFY_CHANGE_ATTRIBUTES |
2651 FILE_NOTIFY_CHANGE_SIZE |
2652 FILE_NOTIFY_CHANGE_LAST_WRITE |
2653 FILE_NOTIFY_CHANGE_LAST_ACCESS |
2654 FILE_NOTIFY_CHANGE_CREATION |
2655 FILE_NOTIFY_CHANGE_EA,
2656 FILE_ACTION_MODIFIED );*/
2657 FsRtlNotifyFullReportChange( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
2658 (PSTRING
)&LocalPath
,
2659 ((Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ? 0 : Dir2
->Fcb
->FCBName
->ObjectName
.Length
) + sizeof(WCHAR
),
2661 UDFIsADirectory(File1
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
2662 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
2663 FILE_NOTIFY_CHANGE_SIZE
|
2664 FILE_NOTIFY_CHANGE_LAST_WRITE
|
2665 FILE_NOTIFY_CHANGE_LAST_ACCESS
|
2666 FILE_NOTIFY_CHANGE_CREATION
|
2667 FILE_NOTIFY_CHANGE_EA
,
2671 RC
= STATUS_SUCCESS
;
2678 UDF_CHECK_PAGING_IO_RESOURCE(Fcb1
->NTRequiredFCB
);
2679 UDFReleaseResource(&(Fcb1
->NTRequiredFCB
->MainResource
));
2682 UDF_CHECK_PAGING_IO_RESOURCE(Dir1
->Fcb
->NTRequiredFCB
);
2683 UDFReleaseResource(&(Dir1
->Fcb
->NTRequiredFCB
->MainResource
));
2687 UDFConvertExclusiveToSharedLite(&(Vcb
->VCBResource
));
2689 // caller assumes Vcb to be acquired shared
2691 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
2694 if(LocalPath
.Buffer
) {
2695 MyFreePool__(LocalPath
.Buffer
);
2700 } // end UDFHardLink()
2701 #endif //UDF_ALLOW_HARD_LINKS
2703 #endif //UDF_READ_ONLY_BUILD