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
)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
;
701 FileInfo
= Fcb
->FileInfo
;
704 AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n"));
705 AdPrint(("!!!! UDFGetNetworkInformation to unopened file !!!!\n"));
706 try_return(RC
= STATUS_INVALID_PARAMETER
);
708 // Now fill in the attributes.
709 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
710 PtrBuffer
->FileAttributes
= FILE_ATTRIBUTE_DIRECTORY
;
712 if(!FileInfo
->Dloc
->DirIndex
) AdPrint(("*****!!!!! Directory has no DirIndex !!!!!*****\n"));
715 // Similarly, fill in attributes indicating a hidden file, system
716 // file, compressed file, temporary file, etc. if the FSD supports
717 // such file attribute values.
718 PtrBuffer
->FileAttributes
|= UDFAttributesToNT(UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo
), FileInfo
->Index
),NULL
);
719 if(!PtrBuffer
->FileAttributes
) {
720 PtrBuffer
->FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
727 // Return the amount of information filled in.
728 (*PtrReturnedLength
) -= sizeof(FILE_NETWORK_OPEN_INFORMATION
);
732 } // end UDFGetNetworkInformation()
736 Return some time-stamps and file attributes to the caller.
739 UDFGetInternalInformation(
740 PtrUDFIrpContext PtrIrpContext
,
743 IN PFILE_INTERNAL_INFORMATION PtrBuffer
,
744 IN OUT PLONG PtrReturnedLength
747 NTSTATUS RC
= STATUS_SUCCESS
;
748 PUDF_FILE_INFO FileInfo
;
751 AdPrint(("UDFGetInternalInformation\n"));
755 if(*PtrReturnedLength
< (LONG
)sizeof(FILE_INTERNAL_INFORMATION
)) {
756 try_return(RC
= STATUS_BUFFER_OVERFLOW
);
759 // Zero out the supplied buffer.
760 RtlZeroMemory(PtrBuffer
, sizeof(FILE_INTERNAL_INFORMATION
));
762 FileInfo
= Fcb
->FileInfo
;
765 AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n"));
766 AdPrint(("!!!! UDFGetInternalInformation to unopened file !!!!\n"));
767 try_return(RC
= STATUS_INVALID_PARAMETER
);
771 PtrBuffer
->IndexNumber
.QuadPart
= UDFGetNTFileId(Vcb
, FileInfo
, &(Fcb
->FCBName
->ObjectName
));
773 UDFAcquireResourceExclusive(&(Fcb
->Vcb
->FileIdResource
), TRUE
);
774 // remember File Id & full path
775 UDFStoreFileId(Fcb
->Vcb
, Ccb
, FileInfo
, PtrBuffer
->IndexNumber
.QuadPart
);
776 UDFReleaseResource(&(Fcb
->Vcb
->FileIdResource
));
782 // Return the amount of information filled in.
783 *PtrReturnedLength
-= sizeof(FILE_INTERNAL_INFORMATION
);
787 } // end UDFGetInternalInformation()
790 Return zero-filled EAs to the caller.
794 PtrUDFIrpContext PtrIrpContext
,
796 IN PFILE_EA_INFORMATION PtrBuffer
,
797 IN OUT PLONG PtrReturnedLength
800 NTSTATUS RC
= STATUS_SUCCESS
;
802 AdPrint(("UDFGetEaInformation\n"));
806 if(*PtrReturnedLength
< (LONG
)sizeof(FILE_EA_INFORMATION
)) {
807 try_return(RC
= STATUS_BUFFER_OVERFLOW
);
810 // Zero out the supplied buffer.
811 PtrBuffer
->EaSize
= 0;
817 // Return the amount of information filled in.
818 *PtrReturnedLength
-= sizeof(FILE_EA_INFORMATION
);
822 } // end UDFGetEaInformation()
825 Return file's long name to the caller.
828 UDFGetFullNameInformation(
829 IN PFILE_OBJECT FileObject
,
830 IN PFILE_NAME_INFORMATION PtrBuffer
,
831 IN OUT PLONG PtrReturnedLength
835 NTSTATUS RC
= STATUS_SUCCESS
;
838 AdPrint(("UDFGetFullNameInformation\n"));
840 PtrBuffer
->FileNameLength
= FileObject
->FileName
.Length
;
841 BytesToCopy
= FileObject
->FileName
.Length
;
843 if (PtrBuffer
->FileNameLength
+ sizeof( ULONG
) > (ULONG
)(*PtrReturnedLength
)) {
845 BytesToCopy
= *PtrReturnedLength
- sizeof( ULONG
);
846 RC
= STATUS_BUFFER_OVERFLOW
;
849 RtlCopyMemory( PtrBuffer
->FileName
, FileObject
->FileName
.Buffer
, BytesToCopy
);
851 // Reduce the available bytes by the amount stored into this buffer.
852 *PtrReturnedLength
-= sizeof( ULONG
) + PtrBuffer
->FileNameLength
;
855 } // end UDFGetFullNameInformation()
858 Return file short(8.3) name to the caller.
861 UDFGetAltNameInformation(
863 IN PFILE_NAME_INFORMATION PtrBuffer
,
864 IN OUT PLONG PtrReturnedLength
867 PDIR_INDEX_ITEM DirNdx
;
869 UNICODE_STRING ShortName
;
870 WCHAR ShortNameBuffer
[13];
872 AdPrint(("UDFGetAltNameInformation: \n"));
874 *PtrReturnedLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]);
875 DirNdx
= UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb
->FileInfo
), Fcb
->FileInfo
->Index
);
877 ShortName
.MaximumLength
= 13 * sizeof(WCHAR
);
878 ShortName
.Buffer
= (PWCHAR
)&ShortNameBuffer
;
880 UDFDOSName__(Fcb
->Vcb
, &ShortName
, &(DirNdx
->FName
), Fcb
->FileInfo
);
882 if(*PtrReturnedLength
< ShortName
.Length
) {
883 return(STATUS_BUFFER_OVERFLOW
);
885 BytesToCopy
= ShortName
.Length
;
886 *PtrReturnedLength
-= ShortName
.Length
;
889 RtlCopyMemory( &(PtrBuffer
->FileName
),
893 PtrBuffer
->FileNameLength
= ShortName
.Length
;
895 return(STATUS_SUCCESS
);
896 } // end UDFGetAltNameInformation()
899 Get file position information
902 UDFGetPositionInformation(
903 IN PFILE_OBJECT FileObject
,
904 IN PFILE_POSITION_INFORMATION PtrBuffer
,
905 IN OUT PLONG PtrReturnedLength
908 if(*PtrReturnedLength
< (LONG
)sizeof(FILE_POSITION_INFORMATION
)) {
909 return(STATUS_BUFFER_OVERFLOW
);
911 PtrBuffer
->CurrentByteOffset
= FileObject
->CurrentByteOffset
;
912 // Modify the local variable for BufferLength appropriately.
913 *PtrReturnedLength
-= sizeof(FILE_POSITION_INFORMATION
);
915 return(STATUS_SUCCESS
);
916 } // end UDFGetAltNameInformation()
919 Get file file stream(s) information
922 UDFGetFileStreamInformation(
924 IN PFILE_STREAM_INFORMATION PtrBuffer
,
925 IN OUT PLONG PtrReturnedLength
928 NTSTATUS RC
= STATUS_SUCCESS
;
929 PUDF_FILE_INFO FileInfo
;
930 PUDF_FILE_INFO SDirInfo
;
932 BOOLEAN FcbAcquired
= FALSE
;
935 PDIR_INDEX_HDR hSDirIndex
;
936 PDIR_INDEX_ITEM SDirIndex
;
937 PFILE_BOTH_DIR_INFORMATION NTFileInfo
= NULL
;
939 AdPrint(("UDFGetFileStreamInformation\n"));
943 UDFAcquireResourceExclusive(&(Fcb
->Vcb
->FileIdResource
), TRUE
);
946 FileInfo
= Fcb
->FileInfo
;
948 AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n"));
949 AdPrint(("!!!! UDFGetFileStreamInformation to unopened file !!!!\n"));
950 try_return(RC
= STATUS_INVALID_PARAMETER
);
953 // Zero out the supplied buffer.
954 RtlZeroMemory(PtrBuffer
, *PtrReturnedLength
);
955 if(!(SDirInfo
= FileInfo
->Dloc
->SDirInfo
) ||
956 UDFIsSDirDeleted(SDirInfo
) ) {
957 (*PtrReturnedLength
) -= (sizeof(FILE_STREAM_INFORMATION
) - sizeof(WCHAR
));
958 try_return(RC
= STATUS_SUCCESS
);
961 hSDirIndex
= SDirInfo
->Dloc
->DirIndex
;
962 NTFileInfo
= (PFILE_BOTH_DIR_INFORMATION
)MyAllocatePool__(NonPagedPool
, sizeof(FILE_BOTH_DIR_INFORMATION
)+UDF_NAME_LEN
*sizeof(WCHAR
));
963 if(!NTFileInfo
) try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
965 for(i
=2; (SDirIndex
= UDFDirIndex(hSDirIndex
,i
)); i
++) {
966 if((SDirIndex
->FI_Flags
& UDF_FI_FLAG_FI_INTERNAL
) ||
967 UDFIsDeleted(SDirIndex
) ||
968 !SDirIndex
->FName
.Buffer
)
970 // copy data to buffer
971 if(*PtrReturnedLength
< (l
= ((sizeof(FILE_STREAM_INFORMATION
) - sizeof(WCHAR
)) +
972 SDirIndex
->FName
.Length
+ 3) & (~3)) ) {
973 try_return(RC
= STATUS_BUFFER_OVERFLOW
);
975 RC
= UDFFileDirInfoToNT(Vcb
, SDirIndex
, NTFileInfo
);
977 PtrBuffer
->NextEntryOffset
= l
;
978 PtrBuffer
->StreamNameLength
= SDirIndex
->FName
.Length
;
979 PtrBuffer
->StreamSize
= NTFileInfo
->EndOfFile
;
980 PtrBuffer
->StreamAllocationSize
= NTFileInfo
->AllocationSize
;
981 RtlCopyMemory(&(PtrBuffer
->StreamName
), SDirIndex
->FName
.Buffer
, SDirIndex
->FName
.Length
);
982 *PtrReturnedLength
-= l
;
983 *((PCHAR
*)(&PtrBuffer
)) += l
;
990 UDFReleaseResource(&(Fcb
->Vcb
->FileIdResource
));
992 MyFreePool__(NTFileInfo
);
995 } // end UDFGetFileStreamInformation()
997 //*******************************************************************
999 #ifndef UDF_READ_ONLY_BUILD
1002 Set some time-stamps and file attributes supplied by the caller.
1005 UDFSetBasicInformation(
1008 IN PFILE_OBJECT FileObject
,
1009 IN PFILE_BASIC_INFORMATION PtrBuffer
)
1011 NTSTATUS RC
= STATUS_SUCCESS
;
1012 ULONG NotifyFilter
= 0;
1014 AdPrint(("UDFSetBasicInformation\n"));
1018 // Obtain a pointer to the directory entry associated with
1019 // the FCB being modifed. The directory entry is obviously
1020 // part of the data associated with the parent directory that
1021 // contains this particular file stream.
1022 if(PtrBuffer
->FileAttributes
) {
1023 UDFUpdateAttrTime(Fcb
->Vcb
, Fcb
->FileInfo
);
1025 if( UDFIsADirectory(Fcb
->FileInfo
) &&
1026 !(Fcb
->Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_UCHG_DIR_ACCESS_TIME
) &&
1027 ((Fcb
->FileInfo
->Dloc
->DataLoc
.Modified
||
1028 Fcb
->FileInfo
->Dloc
->AllocLoc
.Modified
||
1029 (Fcb
->FileInfo
->Dloc
->FE_Flags
& UDF_FE_FLAG_FE_MODIFIED
) ||
1030 Fcb
->FileInfo
->Dloc
->FELoc
.Modified
))
1032 // ignore Access Time Modification for unchanged Dir
1033 if(!PtrBuffer
->CreationTime
.QuadPart
&&
1034 PtrBuffer
->LastAccessTime
.QuadPart
&&
1035 !PtrBuffer
->ChangeTime
.QuadPart
&&
1036 !PtrBuffer
->LastWriteTime
.QuadPart
)
1040 UDFSetFileXTime(Fcb
->FileInfo
,
1041 &(PtrBuffer
->CreationTime
.QuadPart
),
1042 &(PtrBuffer
->LastAccessTime
.QuadPart
),
1043 &(PtrBuffer
->ChangeTime
.QuadPart
),
1044 &(PtrBuffer
->LastWriteTime
.QuadPart
) );
1046 if(PtrBuffer
->CreationTime
.QuadPart
) {
1047 // The interesting thing here is that the user has set certain time
1048 // fields. However, before doing this, the user may have performed
1049 // I/O which in turn would have caused FSD to mark the fact that
1050 // write/access time should be modifed at cleanup.
1051 // We'll mark the fact that such updates are no longer
1052 // required since the user has explicitly specified the values he
1053 // wishes to see associated with the file stream.
1054 Fcb
->NTRequiredFCB
->CreationTime
= PtrBuffer
->CreationTime
;
1055 Ccb
->CCBFlags
|= UDF_CCB_CREATE_TIME_SET
;
1056 NotifyFilter
|= FILE_NOTIFY_CHANGE_CREATION
;
1058 if(PtrBuffer
->LastAccessTime
.QuadPart
) {
1059 Fcb
->NTRequiredFCB
->LastAccessTime
= PtrBuffer
->LastAccessTime
;
1060 Ccb
->CCBFlags
|= UDF_CCB_ACCESS_TIME_SET
;
1061 NotifyFilter
|= FILE_NOTIFY_CHANGE_LAST_ACCESS
;
1063 if(PtrBuffer
->ChangeTime
.QuadPart
) {
1064 Fcb
->NTRequiredFCB
->ChangeTime
= PtrBuffer
->ChangeTime
;
1065 Ccb
->CCBFlags
|= UDF_CCB_MODIFY_TIME_SET
;
1067 if(PtrBuffer
->LastWriteTime
.QuadPart
) {
1068 Fcb
->NTRequiredFCB
->LastWriteTime
= PtrBuffer
->LastWriteTime
;
1069 Ccb
->CCBFlags
|= UDF_CCB_WRITE_TIME_SET
;
1070 NotifyFilter
|= FILE_NOTIFY_CHANGE_LAST_WRITE
;
1073 // Now come the attributes.
1074 if(PtrBuffer
->FileAttributes
) {
1075 // We have a non-zero attribute value.
1076 // The presence of a particular attribute indicates that the
1077 // user wishes to set the attribute value. The absence indicates
1078 // the user wishes to clear the particular attribute.
1080 // Our routine ignores unsupported flags
1081 PtrBuffer
->FileAttributes
&= ~(FILE_ATTRIBUTE_NORMAL
);
1083 // Similarly, we should pick out other invalid flag values.
1084 if( (PtrBuffer
->FileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) &&
1085 !(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
))
1086 try_return(RC
= STATUS_INVALID_PARAMETER
);
1088 if(PtrBuffer
->FileAttributes
& FILE_ATTRIBUTE_TEMPORARY
) {
1089 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
)
1090 try_return(RC
= STATUS_INVALID_PARAMETER
);
1091 FileObject
->Flags
|= FO_TEMPORARY_FILE
;
1093 FileObject
->Flags
&= ~FO_TEMPORARY_FILE
;
1096 if(PtrBuffer
->FileAttributes
& FILE_ATTRIBUTE_READONLY
) {
1097 Fcb
->FCBFlags
|= UDF_FCB_READ_ONLY
;
1099 Fcb
->FCBFlags
&= ~UDF_FCB_READ_ONLY
;
1102 UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb
->FileInfo
), Fcb
->FileInfo
->Index
),
1103 NULL
, PtrBuffer
->FileAttributes
);
1105 (UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb
->FileInfo
), Fcb
->FileInfo
->Index
))
1106 ->FI_Flags
|= UDF_FI_FLAG_SYS_ATTR
;
1107 // If the FSD supports file compression, we may wish to
1108 // note the user's preferences for compressing/not compressing
1109 // the file at this time.
1110 Ccb
->CCBFlags
|= UDF_CCB_ATTRIBUTES_SET
;
1111 NotifyFilter
|= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
1115 UDFNotifyFullReportChange( Fcb
->Vcb
, Fcb
->FileInfo
,
1116 NotifyFilter
, FILE_ACTION_MODIFIED
);
1117 UDFSetFileSizeInDirNdx(Fcb
->Vcb
, Fcb
->FileInfo
, NULL
);
1118 Fcb
->FileInfo
->Dloc
->FE_Flags
|= UDF_FE_FLAG_FE_MODIFIED
;
1126 } // end UDFSetBasicInformation()
1129 UDFMarkStreamsForDeletion(
1135 NTSTATUS RC
= STATUS_SUCCESS
;
1136 PUDF_FILE_INFO SDirInfo
= NULL
;
1137 PUDF_FILE_INFO FileInfo
= NULL
;
1139 BOOLEAN SDirAcq
= FALSE
;
1140 BOOLEAN StrAcq
= FALSE
;
1145 // In some cases we needn't marking Streams for deleteion
1146 // (Not opened or Don't exist)
1147 if(UDFIsAStream(Fcb
->FileInfo
) ||
1148 UDFIsAStreamDir(Fcb
->FileInfo
) ||
1149 !UDFHasAStreamDir(Fcb
->FileInfo
) ||
1150 !Fcb
->FileInfo
->Dloc
->SDirInfo
||
1151 UDFIsSDirDeleted(Fcb
->FileInfo
->Dloc
->SDirInfo
) ||
1152 (UDFGetFileLinkCount(Fcb
->FileInfo
) > 1) )
1153 try_return (RC
/*=STATUS_SUCCESS*/);
1155 // We shall mark Streams for deletion if there is no
1156 // Links to the file. Otherwise we'll delete only the file.
1157 // If we are asked to unmark Streams, we'll precess the whole Tree
1158 RC
= UDFOpenStreamDir__(Vcb
, Fcb
->FileInfo
, &SDirInfo
);
1163 SDirInfo
->Fcb
->NTRequiredFCB
) {
1164 UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo
->Fcb
->NTRequiredFCB
);
1165 UDFAcquireResourceExclusive(&(SDirInfo
->Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
1169 if(!ForDel
|| ((lc
= UDFGetFileLinkCount(Fcb
->FileInfo
)) < 2)) {
1171 UDF_DIR_SCAN_CONTEXT ScanContext
;
1172 PDIR_INDEX_ITEM DirNdx
;
1174 // It is not worth checking whether the Stream can be deleted if
1175 // Undelete requested
1178 UDFDirIndexInitScan(SDirInfo
, &ScanContext
, 2)) {
1180 // Check if we can delete Streams
1181 while((DirNdx
= UDFDirIndexScan(&ScanContext
, &FileInfo
))) {
1185 FileInfo
->Fcb
->NTRequiredFCB
->AcqFlushCount
++;
1186 MmPrint((" MmFlushImageSection() for Stream\n"));
1187 if(!MmFlushImageSection(&(FileInfo
->Fcb
->NTRequiredFCB
->SectionObject
), MmFlushForDelete
)) {
1188 FileInfo
->Fcb
->NTRequiredFCB
->AcqFlushCount
--;
1189 try_return(RC
= STATUS_CANNOT_DELETE
);
1191 FileInfo
->Fcb
->NTRequiredFCB
->AcqFlushCount
--;
1195 // (Un)Mark Streams for deletion
1197 // Perform sequencial Open for Streams & mark 'em
1198 // for deletion. We should not get FileInfo pointers directly
1199 // from DirNdx[i] to prevent great troubles with linked
1200 // files. We should mark for deletion FI with proper ParentFile
1202 d
= UDFDirIndexGetLastIndex(SDirInfo
->Dloc
->DirIndex
);
1203 for(i
=2; i
<d
; i
++) {
1204 RC
= UDFOpenFile__(Vcb
,
1206 SDirInfo
,&FileInfo
,&i
);
1207 ASSERT(NT_SUCCESS(RC
) || (RC
== STATUS_FILE_DELETED
));
1208 if(NT_SUCCESS(RC
)) {
1210 if(FileInfo
->Fcb
->NTRequiredFCB
) {
1211 UDF_CHECK_PAGING_IO_RESOURCE(FileInfo
->Fcb
->NTRequiredFCB
);
1212 UDFAcquireResourceExclusive(&(FileInfo
->Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
1215 #ifndef UDF_ALLOW_LINKS_TO_STREAMS
1216 if(UDFGetFileLinkCount(FileInfo
) >= 2) {
1217 // Currently, UDF_INFO package doesn't
1218 // support this case, so we'll inform developer
1219 // about this to prevent on-disk space leaks...
1221 try_return(RC
= STATUS_CANNOT_DELETE
);
1223 #endif //UDF_ALLOW_LINKS_TO_STREAMS
1225 AdPrint((" SET stream DeleteOnClose\n"));
1227 ASSERT(!(FileInfo
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
1228 if(FileInfo
->ParentFile
&&
1229 FileInfo
->ParentFile
->Fcb
) {
1230 ASSERT(!(FileInfo
->ParentFile
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
1233 FileInfo
->Fcb
->FCBFlags
|= (UDF_FCB_DELETE_ON_CLOSE
|
1234 UDF_FCB_DELETE_PARENT
);
1236 AdPrint((" CLEAR stream DeleteOnClose\n"));
1237 FileInfo
->Fcb
->FCBFlags
&= !(UDF_FCB_DELETE_ON_CLOSE
|
1238 UDF_FCB_DELETE_PARENT
);
1241 UDFCloseFile__(Vcb
, FileInfo
);
1243 if(RC
== STATUS_FILE_DELETED
) {
1244 // That's OK if STATUS_FILE_DELETED returned...
1245 RC
= STATUS_SUCCESS
;
1248 if(UDFCleanUpFile__(Vcb
, FileInfo
)) {
1249 ASSERT(!StrAcq
&& !(FileInfo
->Fcb
));
1250 MyFreePool__(FileInfo
);
1253 UDF_CHECK_PAGING_IO_RESOURCE(FileInfo
->Fcb
->NTRequiredFCB
);
1254 UDFReleaseResource(&(FileInfo
->Fcb
->NTRequiredFCB
->MainResource
));
1260 // Mark SDir for deletion
1264 ASSERT(!(SDirInfo
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
1265 if(SDirInfo
->ParentFile
&&
1266 SDirInfo
->ParentFile
->Fcb
) {
1267 ASSERT(!(SDirInfo
->ParentFile
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
1270 AdPrint((" SET stream dir DeleteOnClose\n"));
1271 SDirInfo
->Fcb
->FCBFlags
|= (UDF_FCB_DELETE_ON_CLOSE
|
1272 UDF_FCB_DELETE_PARENT
);
1274 AdPrint((" CLEAR stream dir DeleteOnClose\n"));
1275 SDirInfo
->Fcb
->FCBFlags
&= ~(UDF_FCB_DELETE_ON_CLOSE
|
1276 UDF_FCB_DELETE_PARENT
);
1281 // if caller wants us to perform DelTree for Streams, but
1282 // someone keeps Stream opened and there is a Link to this
1283 // file, we can't delete it immediately (on Cleanup) & should
1284 // not delete the whole Tree. Instead, we'll set DELETE_PARENT
1285 // flag in SDir to kill this file later, when all the Handles
1286 // to Streams, opened via this file, would be closed
1288 ASSERT(!(SDirInfo
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
1289 if(SDirInfo
->ParentFile
&&
1290 SDirInfo
->ParentFile
->Fcb
) {
1291 ASSERT(!(SDirInfo
->ParentFile
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
1295 SDirInfo
->Fcb
->FCBFlags
|= UDF_FCB_DELETE_PARENT
;
1302 UDFCloseFile__(Vcb
, FileInfo
);
1303 if(UDFCleanUpFile__(Vcb
, FileInfo
)) {
1304 ASSERT(!StrAcq
&& !(FileInfo
->Fcb
));
1305 MyFreePool__(FileInfo
);
1308 UDF_CHECK_PAGING_IO_RESOURCE(FileInfo
->Fcb
->NTRequiredFCB
);
1309 UDFReleaseResource(&(FileInfo
->Fcb
->NTRequiredFCB
->MainResource
));
1314 UDFCloseFile__(Vcb
, SDirInfo
);
1316 UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo
->Fcb
->NTRequiredFCB
);
1317 UDFReleaseResource(&(SDirInfo
->Fcb
->NTRequiredFCB
->MainResource
));
1319 if(UDFCleanUpFile__(Vcb
, SDirInfo
)) {
1320 MyFreePool__(SDirInfo
);
1326 } // end UDFMarkStreamsForDeletion()
1329 (Un)Mark file for deletion.
1332 UDFSetDispositionInformation(
1336 IN PFILE_OBJECT FileObject
,
1340 NTSTATUS RC
= STATUS_SUCCESS
;
1341 // PUDF_FILE_INFO SDirInfo = NULL;
1342 // PUDF_FILE_INFO FileInfo = NULL;
1345 AdPrint(("UDFSetDispositionInformation\n"));
1350 AdPrint((" CLEAR DeleteOnClose\n"));
1351 // "un-delete" the file.
1352 Fcb
->FCBFlags
&= ~UDF_FCB_DELETE_ON_CLOSE
;
1354 FileObject
->DeletePending
= FALSE
;
1355 RC
= UDFMarkStreamsForDeletion(Vcb
, Fcb
, FALSE
); // Undelete
1358 AdPrint((" SET DeleteOnClose\n"));
1360 // The easy part is over. Now, we know that the user wishes to
1361 // delete the corresponding directory entry (of course, if this
1362 // is the only link to the file stream, any on-disk storage space
1363 // associated with the file stream will also be released when the
1364 // (only) link is deleted!)
1366 // Do some checking to see if the file can even be deleted.
1367 if(Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
) {
1372 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_READ_ONLY
) {
1373 try_return(RC
= STATUS_CANNOT_DELETE
);
1376 if(Fcb
->FCBFlags
& UDF_FCB_READ_ONLY
) {
1377 RC
= UDFCheckAccessRights(NULL
, NULL
, Fcb
->ParentFcb
, NULL
, FILE_DELETE_CHILD
, 0);
1378 if(!NT_SUCCESS(RC
)) {
1379 try_return (RC
= STATUS_CANNOT_DELETE
);
1383 // It would not be prudent to allow deletion of either a root
1384 // directory or a directory that is not empty.
1385 if(Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
)
1386 try_return(RC
= STATUS_CANNOT_DELETE
);
1388 lc
= UDFGetFileLinkCount(Fcb
->FileInfo
);
1390 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
1391 // Perform check to determine whether the directory
1393 if(!UDFIsDirEmpty__(Fcb
->FileInfo
)) {
1394 try_return(RC
= STATUS_DIRECTORY_NOT_EMPTY
);
1398 // An important step is to check if the file stream has been
1399 // mapped by any process. The delete cannot be allowed to proceed
1401 MmPrint((" MmFlushImageSection()\n"));
1402 Fcb
->NTRequiredFCB
->AcqFlushCount
++;
1403 if(!MmFlushImageSection(&(Fcb
->NTRequiredFCB
->SectionObject
),
1404 (lc
> 1) ? MmFlushForWrite
: MmFlushForDelete
)) {
1405 Fcb
->NTRequiredFCB
->AcqFlushCount
--;
1406 try_return(RC
= STATUS_CANNOT_DELETE
);
1408 Fcb
->NTRequiredFCB
->AcqFlushCount
--;
1410 // We should also mark Streams for deletion if there are no
1411 // Links to the file. Otherwise we'll delete only the file
1414 RC
= STATUS_SUCCESS
;
1416 RC
= UDFMarkStreamsForDeletion(Vcb
, Fcb
, TRUE
); // Delete
1421 // Set a flag to indicate that this directory entry will become history
1423 Fcb
->FCBFlags
|= UDF_FCB_DELETE_ON_CLOSE
;
1425 FileObject
->DeletePending
= TRUE
;
1427 if((Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) && Ccb
) {
1428 FsRtlNotifyFullChangeDirectory( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
1429 (PVOID
)Ccb
, NULL
, FALSE
, FALSE
,
1430 0, NULL
, NULL
, NULL
);
1439 } // end UDFSetDispositionInformation()
1443 Change file allocation length.
1446 UDFSetAllocationInformation(
1450 IN PFILE_OBJECT FileObject
,
1451 IN PtrUDFIrpContext PtrIrpContext
,
1453 IN PFILE_ALLOCATION_INFORMATION PtrBuffer
1456 NTSTATUS RC
= STATUS_SUCCESS
;
1457 BOOLEAN TruncatedFile
= FALSE
;
1458 BOOLEAN ModifiedAllocSize
= FALSE
;
1459 BOOLEAN CacheMapInitialized
= FALSE
;
1460 BOOLEAN AcquiredPagingIo
= FALSE
;
1462 AdPrint(("UDFSetAllocationInformation\n"));
1465 // Increasing the allocation size associated with a file stream
1466 // is relatively easy. All we have to do is execute some FSD
1467 // specific code to check whether we have enough space available
1468 // (and if the FSD supports user/volume quotas, whether the user
1469 // is not exceeding quota), and then increase the file size in the
1470 // corresponding on-disk and in-memory structures.
1471 // Then, all we should do is inform the Cache Manager about the
1472 // increased allocation size.
1474 // First, do whatever error checking is appropriate here (e.g. whether
1475 // the caller is trying the change size for a directory, etc.).
1476 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
)
1477 try_return(RC
= STATUS_INVALID_PARAMETER
);
1479 Fcb
->NTRequiredFCB
->CommonFCBHeader
.IsFastIoPossible
= UDFIsFastIoPossible(Fcb
);
1481 if ((FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
) &&
1482 (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
) &&
1483 !FlagOn(Irp
->Flags
, IRP_PAGING_IO
)) {
1484 ASSERT( !FlagOn( FileObject
->Flags
, FO_CLEANUP_COMPLETE
) );
1485 // Now initialize the cache map.
1486 MmPrint((" CcInitializeCacheMap()\n"));
1487 CcInitializeCacheMap( FileObject
,
1488 (PCC_FILE_SIZES
)&Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
,
1490 &(UDFGlobalData
.CacheMgrCallBacks
),
1491 Fcb
->NTRequiredFCB
);
1493 CacheMapInitialized
= TRUE
;
1496 // Are we increasing the allocation size?
1497 if(Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
.QuadPart
<
1498 PtrBuffer
->AllocationSize
.QuadPart
) {
1500 // Yes. Do the FSD specific stuff i.e. increase reserved
1502 if(((LONGLONG
)UDFGetFreeSpace(Vcb
) << Vcb
->LBlockSizeBits
) < PtrBuffer
->AllocationSize
.QuadPart
) {
1503 try_return(RC
= STATUS_DISK_FULL
);
1505 // RC = STATUS_SUCCESS;
1506 ModifiedAllocSize
= TRUE
;
1508 } else if(Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
.QuadPart
>
1509 PtrBuffer
->AllocationSize
.QuadPart
) {
1510 // This is the painful part. See if the VMM will allow us to proceed.
1511 // The VMM will deny the request if:
1512 // (a) any image section exists OR
1513 // (b) a data section exists and the size of the user mapped view
1514 // is greater than the new size
1515 // Otherwise, the VMM should allow the request to proceed.
1516 MmPrint((" MmCanFileBeTruncated()\n"));
1517 if(!MmCanFileBeTruncated(&(Fcb
->NTRequiredFCB
->SectionObject
), &(PtrBuffer
->AllocationSize
))) {
1519 try_return(RC
= STATUS_USER_MAPPED_FILE
);
1522 // Perform our directory entry modifications. Release any on-disk
1523 // space we may need to in the process.
1524 ModifiedAllocSize
= TRUE
;
1525 TruncatedFile
= TRUE
;
1528 ASSERT(NT_SUCCESS(RC
));
1529 // This is a good place to check if we have performed a truncate
1530 // operation. If we have perform a truncate (whether we extended
1531 // or reduced file size or even leave it intact), we should update
1532 // file time stamps.
1533 FileObject
->Flags
|= FO_FILE_MODIFIED
;
1535 // Last, but not the lease, we must inform the Cache Manager of file size changes.
1536 if(ModifiedAllocSize
) {
1538 // If we decreased the allocation size to less than the
1539 // current file size, modify the file size value.
1540 // Similarly, if we decreased the value to less than the
1541 // current valid data length, modify that value as well.
1543 AcquiredPagingIo
= UDFAcquireResourceExclusiveWithCheck(&(Fcb
->NTRequiredFCB
->PagingIoResource
));
1544 // Update the FCB Header with the new allocation size.
1546 if(Fcb
->NTRequiredFCB
->CommonFCBHeader
.ValidDataLength
.QuadPart
>
1547 PtrBuffer
->AllocationSize
.QuadPart
) {
1548 // Decrease the valid data length value.
1549 Fcb
->NTRequiredFCB
->CommonFCBHeader
.ValidDataLength
=
1550 PtrBuffer
->AllocationSize
;
1552 if(Fcb
->NTRequiredFCB
->CommonFCBHeader
.FileSize
.QuadPart
>
1553 PtrBuffer
->AllocationSize
.QuadPart
) {
1554 // Decrease the file size value.
1555 Fcb
->NTRequiredFCB
->CommonFCBHeader
.FileSize
=
1556 PtrBuffer
->AllocationSize
;
1557 RC
= UDFResizeFile__(Vcb
, Fcb
->FileInfo
, PtrBuffer
->AllocationSize
.QuadPart
);
1558 // UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, NULL);
1561 Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
= PtrBuffer
->AllocationSize
;
1562 // UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo,
1563 // &(PtrBuffer->AllocationSize.QuadPart));
1565 if(AcquiredPagingIo
) {
1566 UDFReleaseResource(&(Fcb
->NTRequiredFCB
->PagingIoResource
));
1567 AcquiredPagingIo
= FALSE
;
1569 // If the FCB has not had caching initiated, it is still valid
1570 // for us to invoke the NT Cache Manager. It is possible in such
1571 // situations for the call to be no'oped (unless some user has
1572 // mapped in the file)
1574 // NOTE: The invocation to CcSetFileSizes() will quite possibly
1575 // result in a recursive call back into the file system.
1576 // This is because the NT Cache Manager will typically
1577 // perform a flush before telling the VMM to purge pages
1578 // especially when caching has not been initiated on the
1579 // file stream, but the user has mapped the file into
1580 // the process' virtual address space.
1581 MmPrint((" CcSetFileSizes()\n"));
1582 Fcb
->NTRequiredFCB
->AcqFlushCount
++;
1583 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&(Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
));
1584 Fcb
->NTRequiredFCB
->AcqFlushCount
--;
1585 Fcb
->NTRequiredFCB
->NtReqFCBFlags
|= UDF_NTREQ_FCB_MODIFIED
;
1587 // Inform any pending IRPs (notify change directory).
1588 if(UDFIsAStream(Fcb
->FileInfo
)) {
1589 UDFNotifyFullReportChange( Vcb
, Fcb
->FileInfo
,
1590 FILE_NOTIFY_CHANGE_STREAM_SIZE
,
1591 FILE_ACTION_MODIFIED_STREAM
);
1593 UDFNotifyFullReportChange( Vcb
, Fcb
->FileInfo
,
1594 FILE_NOTIFY_CHANGE_SIZE
,
1595 FILE_ACTION_MODIFIED
);
1602 if(AcquiredPagingIo
) {
1603 UDFReleaseResource(&(Fcb
->NTRequiredFCB
->PagingIoResource
));
1604 AcquiredPagingIo
= FALSE
;
1606 if (CacheMapInitialized
) {
1608 MmPrint((" CcUninitializeCacheMap()\n"));
1609 CcUninitializeCacheMap( FileObject
, NULL
, NULL
);
1613 } // end UDFSetAllocationInformation()
1616 Set end of file (resize).
1620 IN PIO_STACK_LOCATION PtrSp
,
1624 IN PFILE_OBJECT FileObject
,
1626 IN PFILE_END_OF_FILE_INFORMATION PtrBuffer
1629 NTSTATUS RC
= STATUS_SUCCESS
;
1630 BOOLEAN TruncatedFile
= FALSE
;
1631 BOOLEAN ModifiedAllocSize
= FALSE
;
1633 PDIR_INDEX_ITEM DirNdx
;
1634 PtrUDFNTRequiredFCB NtReqFcb
= NULL
;
1635 LONGLONG OldFileSize
;
1636 // BOOLEAN ZeroBlock;
1637 BOOLEAN CacheMapInitialized
= FALSE
;
1638 BOOLEAN AcquiredPagingIo
= FALSE
;
1640 AdPrint(("UDFSetEOF\n"));
1643 // Increasing the allocation size associated with a file stream
1644 // is relatively easy. All we have to do is execute some FSD
1645 // specific code to check whether we have enough space available
1646 // (and if the FSD supports user/volume quotas, whether the user
1647 // is not exceeding quota), and then increase the file size in the
1648 // corresponding on-disk and in-memory structures.
1649 // Then, all we should do is inform the Cache Manager about the
1650 // increased allocation size.
1652 // First, do whatever error checking is appropriate here (e.g. whether
1653 // the caller is trying the change size for a directory, etc.).
1654 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
)
1655 try_return(RC
= STATUS_INVALID_PARAMETER
);
1657 NtReqFcb
= Fcb
->NTRequiredFCB
;
1659 if((Fcb
->FCBFlags
& UDF_FCB_DELETED
) ||
1660 (NtReqFcb
->NtReqFCBFlags
& UDF_NTREQ_FCB_DELETED
)) {
1662 if(UDFGetFileLinkCount(Fcb
->FileInfo
) < 1) {
1664 try_return(RC
= STATUS_SUCCESS
);
1667 try_return(RC
= STATUS_SUCCESS
);
1670 NtReqFcb
->CommonFCBHeader
.IsFastIoPossible
= UDFIsFastIoPossible(Fcb
);
1672 if ((FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
) &&
1673 (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
) &&
1674 !(Irp
->Flags
& IRP_PAGING_IO
)) {
1675 ASSERT( !FlagOn( FileObject
->Flags
, FO_CLEANUP_COMPLETE
) );
1676 // Now initialize the cache map.
1677 MmPrint((" CcInitializeCacheMap()\n"));
1678 CcInitializeCacheMap( FileObject
,
1679 (PCC_FILE_SIZES
)&Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
,
1681 &(UDFGlobalData
.CacheMgrCallBacks
),
1682 Fcb
->NTRequiredFCB
);
1684 CacheMapInitialized
= TRUE
;
1687 AcquiredPagingIo
= UDFAcquireResourceExclusiveWithCheck(&(Fcb
->NTRequiredFCB
->PagingIoResource
));
1688 // Do a special case here for the lazy write of file sizes.
1689 if(PtrSp
->Parameters
.SetFile
.AdvanceOnly
) {
1690 // Never have the dirent filesize larger than the fcb filesize
1691 PtrBuffer
->EndOfFile
.QuadPart
=
1692 min(PtrBuffer
->EndOfFile
.QuadPart
,
1693 NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
);
1694 // Only advance the file size, never reduce it with this call
1695 RC
= STATUS_SUCCESS
;
1696 if(UDFGetFileSizeFromDirNdx(Vcb
, Fcb
->FileInfo
) >=
1697 PtrBuffer
->EndOfFile
.QuadPart
)
1700 UDFSetFileSizeInDirNdx(Vcb
, Fcb
->FileInfo
, &(PtrBuffer
->EndOfFile
.QuadPart
));
1701 goto notify_size_changes
;
1704 // !!! IMPORTANT !!!
1706 // We can get here after all Handles to the file are closed
1707 // To prevent allocation size incoherency we should
1708 // reference FileInfo _before_ call to UDFResizeFile__()
1709 // and use UDFCloseFile__() _after_ that
1711 // Are we increasing the allocation size?
1712 OldFileSize
= NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
;
1713 if(OldFileSize
< PtrBuffer
->EndOfFile
.QuadPart
) {
1715 // Yes. Do the FSD specific stuff i.e. increase reserved
1718 if (FileObject->PrivateCacheMap)
1722 // reference file to pretend that it is opened
1723 UDFReferenceFile__(Fcb
->FileInfo
);
1724 UDFInterlockedIncrement((PLONG
)&(Fcb
->ReferenceCount
));
1725 UDFInterlockedIncrement((PLONG
)&(NtReqFcb
->CommonRefCount
));
1726 // perform resize operation
1727 RC
= UDFResizeFile__(Vcb
, Fcb
->FileInfo
, PtrBuffer
->EndOfFile
.QuadPart
);
1729 UDFCloseFile__(Vcb
, Fcb
->FileInfo
);
1730 UDFInterlockedDecrement((PLONG
)&(Fcb
->ReferenceCount
));
1731 UDFInterlockedDecrement((PLONG
)&(NtReqFcb
->CommonRefCount
));
1732 // update values in NtReqFcb
1733 NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
=
1734 // NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart =
1735 PtrBuffer
->EndOfFile
.QuadPart
;
1736 ModifiedAllocSize
= TRUE
;
1738 } else if(NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
>
1739 PtrBuffer
->EndOfFile
.QuadPart
) {
1741 // This is the painful part. See if the VMM will allow us to proceed.
1742 // The VMM will deny the request if:
1743 // (a) any image section exists OR
1744 // (b) a data section exists and the size of the user mapped view
1745 // is greater than the new size
1746 // Otherwise, the VMM should allow the request to proceed.
1748 MmPrint((" MmCanFileBeTruncated()\n"));
1749 if(!MmCanFileBeTruncated(&(NtReqFcb
->SectionObject
), &(PtrBuffer
->EndOfFile
))) {
1751 try_return(RC
= STATUS_USER_MAPPED_FILE
);
1754 // Perform directory entry modifications. Release any on-disk
1755 // space we may need to in the process.
1756 UDFReferenceFile__(Fcb
->FileInfo
);
1757 UDFInterlockedIncrement((PLONG
)&(Fcb
->ReferenceCount
));
1758 UDFInterlockedIncrement((PLONG
)&(NtReqFcb
->CommonRefCount
));
1759 // perform resize operation
1760 RC
= UDFResizeFile__(Vcb
, Fcb
->FileInfo
, PtrBuffer
->EndOfFile
.QuadPart
);
1762 UDFCloseFile__(Vcb
, Fcb
->FileInfo
);
1763 UDFInterlockedDecrement((PLONG
)&(Fcb
->ReferenceCount
));
1764 UDFInterlockedDecrement((PLONG
)&(NtReqFcb
->CommonRefCount
));
1766 ModifiedAllocSize
= TRUE
;
1767 TruncatedFile
= TRUE
;
1770 // This is a good place to check if we have performed a truncate
1771 // operation. If we have perform a truncate (whether we extended
1772 // or reduced file size), we should update file time stamps.
1774 // Last, but not the least, we must inform the Cache Manager of file size changes.
1775 if(ModifiedAllocSize
&& NT_SUCCESS(RC
)) {
1776 // If we decreased the allocation size to less than the
1777 // current file size, modify the file size value.
1778 // Similarly, if we decreased the value to less than the
1779 // current valid data length, modify that value as well.
1781 if(NtReqFcb
->CommonFCBHeader
.ValidDataLength
.QuadPart
>
1782 PtrBuffer
->EndOfFile
.QuadPart
) {
1783 // Decrease the valid data length value.
1784 NtReqFcb
->CommonFCBHeader
.ValidDataLength
=
1785 PtrBuffer
->EndOfFile
;
1787 if(NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
>
1788 PtrBuffer
->EndOfFile
.QuadPart
) {
1789 // Decrease the file size value.
1790 NtReqFcb
->CommonFCBHeader
.FileSize
=
1791 PtrBuffer
->EndOfFile
;
1793 UDFSetFileSizeInDirNdx(Vcb
, Fcb
->FileInfo
, NULL
);
1795 // Update the FCB Header with the new allocation size.
1796 // NT expects AllocationSize to be decreased on Close only
1797 NtReqFcb
->CommonFCBHeader
.AllocationSize
.QuadPart
=
1798 PtrBuffer
->EndOfFile
.QuadPart
;
1799 // UDFSysGetAllocSize(Vcb, UDFGetFileSize(Fcb->FileInfo));
1800 UDFSetFileSizeInDirNdx(Vcb
, Fcb
->FileInfo
, &(PtrBuffer
->EndOfFile
.QuadPart
));
1803 FileObject
->Flags
|= FO_FILE_MODIFIED
;
1804 // UDFGetFileAllocationSize(Vcb, Fcb->FileInfo);
1806 // If the FCB has not had caching initiated, it is still valid
1807 // for us to invoke the NT Cache Manager. It is possible in such
1808 // situations for the call to be no'oped (unless some user has
1809 // mapped in the file)
1812 if(Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_ARCH_BIT
) {
1813 DirNdx
= UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb
->FileInfo
), Fcb
->FileInfo
->Index
);
1814 Ccb
->CCBFlags
&= ~UDF_CCB_ATTRIBUTES_SET
;
1815 Attr
= UDFAttributesToNT(DirNdx
, Fcb
->FileInfo
->Dloc
->FileEntry
);
1816 if(!(Attr
& FILE_ATTRIBUTE_ARCHIVE
))
1817 UDFAttributesToUDF(DirNdx
, Fcb
->FileInfo
->Dloc
->FileEntry
, Attr
| FILE_ATTRIBUTE_ARCHIVE
);
1820 // NOTE: The invocation to CcSetFileSizes() will quite possibly
1821 // result in a recursive call back into the file system.
1822 // This is because the NT Cache Manager will typically
1823 // perform a flush before telling the VMM to purge pages
1824 // especially when caching has not been initiated on the
1825 // file stream, but the user has mapped the file into
1826 // the process' virtual address space.
1827 MmPrint((" CcSetFileSizes(), thrd:%8.8x\n",PsGetCurrentThread()));
1828 Fcb
->NTRequiredFCB
->AcqFlushCount
++;
1829 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&(NtReqFcb
->CommonFCBHeader
.AllocationSize
));
1830 Fcb
->NTRequiredFCB
->AcqFlushCount
--;
1832 UDFZeroDataEx(NtReqFcb,
1834 PtrBuffer->EndOfFile.QuadPart - OldFileSize,
1835 TRUE // CanWait, Vcb, FileObject);
1837 Fcb
->NTRequiredFCB
->NtReqFCBFlags
|= UDF_NTREQ_FCB_MODIFIED
;
1839 notify_size_changes
:
1840 if(AcquiredPagingIo
) {
1841 UDFReleaseResource(&(Fcb
->NTRequiredFCB
->PagingIoResource
));
1842 AcquiredPagingIo
= FALSE
;
1845 // Inform any pending IRPs (notify change directory).
1846 if(UDFIsAStream(Fcb
->FileInfo
)) {
1847 UDFNotifyFullReportChange( Vcb
, Fcb
->FileInfo
,
1848 FILE_NOTIFY_CHANGE_STREAM_SIZE
,
1849 FILE_ACTION_MODIFIED_STREAM
);
1851 UDFNotifyFullReportChange( Vcb
, Fcb
->FileInfo
,
1852 FILE_NOTIFY_CHANGE_SIZE
,
1853 FILE_ACTION_MODIFIED
);
1860 if(AcquiredPagingIo
) {
1861 UDFReleaseResource(&(Fcb
->NTRequiredFCB
->PagingIoResource
));
1862 AcquiredPagingIo
= FALSE
;
1864 if (CacheMapInitialized
) {
1866 MmPrint((" CcUninitializeCacheMap()\n"));
1867 CcUninitializeCacheMap( FileObject
, NULL
, NULL
);
1871 } // end UDFSetEOF()
1874 UDFPrepareForRenameMoveLink(
1876 PBOOLEAN AcquiredVcb
,
1877 PBOOLEAN AcquiredVcbEx
,
1879 PBOOLEAN AcquiredDir1
,
1880 PBOOLEAN AcquiredFcb1
,
1882 PUDF_FILE_INFO File1
,
1883 PUDF_FILE_INFO Dir1
,
1884 PUDF_FILE_INFO Dir2
,
1888 // convert acquisition to Exclusive
1889 // this will prevent us from the following situation:
1890 // There is a pair of objects among input dirs &
1891 // one of them is a parent of another. Sequential resource
1892 // acquisition may lead to deadlock due to concurrent
1893 // CleanUpFcbChain() or UDFCloseFileInfoChain()
1894 UDFInterlockedIncrement((PLONG
)&(Vcb
->VCBOpenCount
));
1895 UDFReleaseResource(&(Vcb
->VCBResource
));
1896 (*AcquiredVcb
) = FALSE
;
1898 // At first, make system to issue last Close request
1899 // for our Source & Target ...
1900 // we needn't flush/purge for Source on HLink
1901 UDFRemoveFromSystemDelayedQueue(Dir2
->Fcb
);
1902 if(!HardLink
&& (Dir2
!= Dir1
))
1903 UDFRemoveFromSystemDelayedQueue(File1
->Fcb
);
1905 #ifdef UDF_DELAYED_CLOSE
1907 // Do actual close for all "delayed close" calls
1909 // ... and now remove the rest from our queue
1911 UDFCloseAllDelayedInDir(Vcb
, Dir1
);
1913 UDFCloseAllDelayedInDir(Vcb
, Dir2
);
1915 UDFCloseAllDelayedInDir(Vcb
, Dir2
);
1918 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
1920 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCount
));
1921 return (STATUS_DRIVER_INTERNAL_ERROR
);
1923 #endif //UDF_DELAYED_CLOSE
1925 (*SingleDir
) = ((Dir1
== Dir2
) && (Dir1
->Fcb
));
1928 (UDFGetFileLinkCount(File1
) != 1)) {
1929 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
1930 (*AcquiredVcb
) = TRUE
;
1931 (*AcquiredVcbEx
) = TRUE
;
1932 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCount
));
1934 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
1935 (*AcquiredVcb
) = TRUE
;
1936 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCount
));
1938 UDF_CHECK_PAGING_IO_RESOURCE(Dir1
->Fcb
->NTRequiredFCB
);
1939 UDFAcquireResourceExclusive(&(Dir1
->Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
1940 (*AcquiredDir1
) = TRUE
;
1942 UDF_CHECK_PAGING_IO_RESOURCE(File1
->Fcb
->NTRequiredFCB
);
1943 UDFAcquireResourceExclusive(&(File1
->Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
1944 (*AcquiredFcb1
) = TRUE
;
1946 return STATUS_SUCCESS
;
1947 } // end UDFPrepareForRenameMoveLink()
1954 IN PIO_STACK_LOCATION PtrSp
,
1957 IN PFILE_OBJECT FileObject1
, // Source File
1958 IN PFILE_RENAME_INFORMATION PtrBuffer
1962 PFILE_OBJECT DirObject1
= FileObject1
->RelatedFileObject
;
1964 PFILE_OBJECT DirObject2
= PtrSp
->Parameters
.SetFile
.FileObject
;
1966 BOOLEAN Replace
= PtrSp
->Parameters
.SetFile
.ReplaceIfExists
&&
1967 PtrBuffer
->ReplaceIfExists
;
1969 PVCB Vcb
= Fcb1
->Vcb
;
1972 BOOLEAN AcquiredVcb
= TRUE
;
1973 BOOLEAN AcquiredVcbEx
= FALSE
;
1974 BOOLEAN AcquiredDir1
= FALSE
;
1975 BOOLEAN AcquiredFcb1
= FALSE
;
1976 BOOLEAN SingleDir
= TRUE
;
1979 PUDF_FILE_INFO File1
;
1980 PUDF_FILE_INFO Dir1
;
1981 PUDF_FILE_INFO Dir2
;
1982 PUDF_FILE_INFO NextFileInfo
, fi
;
1984 UNICODE_STRING NewName
;
1985 UNICODE_STRING LocalPath
;
1986 PtrUDFCCB CurCcb
= NULL
;
1990 ULONG FileInfoRefCount
;
1992 PDIR_INDEX_ITEM DirNdx
;
1994 AdPrint(("UDFRename %8.8x\n", DirObject2
));
1996 LocalPath
.Buffer
= NULL
;
1999 // do we try to rename Volume ?
2000 #ifdef UDF_ALLOW_RENAME_MOVE
2001 if(!(File1
= Fcb1
->FileInfo
))
2002 #endif //UDF_ALLOW_RENAME_MOVE
2003 try_return (RC
= STATUS_ACCESS_DENIED
);
2005 // do we try to rename RootDir ?
2006 if(!(Dir1
= File1
->ParentFile
))
2007 try_return (RC
= STATUS_ACCESS_DENIED
);
2009 // do we try to rename to RootDir or Volume ?
2011 Dir2
= File1
->ParentFile
;
2012 DirObject2
= DirObject1
;
2014 if(DirObject2
->FsContext2
&&
2015 (Fcb2
= ((PtrUDFCCB
)(DirObject2
->FsContext2
))->Fcb
)) {
2016 Dir2
= ((PtrUDFCCB
)(DirObject2
->FsContext2
))->Fcb
->FileInfo
;
2018 try_return (RC
= STATUS_INVALID_PARAMETER
);
2020 // invalid destination ?
2021 if(!Dir2
) try_return (RC
= STATUS_ACCESS_DENIED
);
2023 // Stream can't be a Dir or have StreamDir
2024 if(UDFIsAStreamDir(Dir2
)) {
2025 #ifdef UDF_ENABLE_SECURITY
2026 if(UDFIsADirectory(File1
)) {
2027 try_return (RC
= STATUS_ACCESS_DENIED
);
2029 // We should check whether File1 has only Internal
2030 // (or Deleted) streams. In this case SDir should be
2031 // removed (in UDFRenameMoveFile__()). Otherwise
2032 // return STATUS_ACCESS_DENIED
2033 if(UDFHasAStreamDir(File1
)) {
2034 UDFPrint(("TODO: We should remove Streams from source file\n"));
2035 try_return (RC
= STATUS_ACCESS_DENIED
);
2037 #else //UDF_ENABLE_SECURITY
2038 if(UDFIsADirectory(File1
) ||
2039 UDFHasAStreamDir(File1
)) {
2040 try_return (RC
= STATUS_ACCESS_DENIED
);
2042 #endif //UDF_ENABLE_SECURITY
2045 RC
= UDFPrepareForRenameMoveLink(Vcb
, &AcquiredVcb
, &AcquiredVcbEx
,
2047 &AcquiredDir1
, &AcquiredFcb1
,
2050 FALSE
); // it is Rename operation
2054 // check if the source file is in use
2055 if(Fcb1
->OpenHandleCount
> 1)
2056 try_return (RC
= STATUS_ACCESS_DENIED
);
2057 ASSERT(Fcb1
->OpenHandleCount
);
2058 ASSERT(!Fcb1
->IrpContextLite
);
2059 if(Fcb1
->IrpContextLite
) {
2060 try_return (RC
= STATUS_ACCESS_DENIED
);
2062 // Check if we have parallel/pending Close threads
2063 if(Fcb1
->CcbCount
&& !SingleDir
) {
2064 // if this is the 1st attempt, we'll try to
2065 // synchronize with Close requests
2066 // otherwise fail request
2067 RC
= STATUS_ACCESS_DENIED
;
2069 if(Fcb1
->FCBFlags
& UDF_FCB_POSTED_RENAME
) {
2070 Fcb1
->FCBFlags
&= ~UDF_FCB_POSTED_RENAME
;
2073 Fcb1
->FCBFlags
|= UDF_FCB_POSTED_RENAME
;
2074 try_return (RC
= STATUS_PENDING
);
2078 // Make sure the name is of legal length.
2079 if(PtrBuffer
->FileNameLength
> UDF_NAME_LEN
*sizeof(WCHAR
)) {
2080 try_return(RC
= STATUS_OBJECT_NAME_INVALID
);
2082 NewName
.Length
= NewName
.MaximumLength
= (USHORT
)(PtrBuffer
->FileNameLength
);
2083 NewName
.Buffer
= (PWCHAR
)&(PtrBuffer
->FileName
);
2085 // This name is by definition legal.
2086 NewName
= *((PUNICODE_STRING
)&DirObject2
->FileName
);
2089 ic
= (Ccb1
->CCBFlags
& UDF_CCB_CASE_SENSETIVE
) ? FALSE
: TRUE
;
2091 AdPrint((" %ws ->\n %ws\n",
2092 Fcb1
->FCBName
->ObjectName
.Buffer
,
2095 if(UDFIsDirOpened__(File1
)) {
2096 // We can't rename file because of unclean references.
2097 // UDF_INFO package can safely do it, but NT side cannot.
2098 // In this case NT requires STATUS_OBJECT_NAME_COLLISION
2099 // rather than STATUS_ACCESS_DENIED
2100 if(NT_SUCCESS(UDFFindFile__(Vcb
, ic
, &NewName
, Dir2
)))
2101 try_return(RC
= STATUS_OBJECT_NAME_COLLISION
);
2102 try_return (RC
= STATUS_ACCESS_DENIED
);
2104 // Last check before Moving.
2105 // We can't move across Dir referenced (even internally) file
2107 RC
= UDFDoesOSAllowFileToBeMoved__(File1
);
2108 if(!NT_SUCCESS(RC
)) {
2114 ASSERT_REF(Fcb1
->ReferenceCount
>= File1
->RefCount
);
2115 ASSERT_REF(Dir1
->Fcb
->ReferenceCount
>= Dir1
->RefCount
);
2116 ASSERT_REF(Dir2
->Fcb
->ReferenceCount
>= Dir2
->RefCount
);
2118 RC
= UDFRenameMoveFile__(Vcb
, ic
, &Replace
, &NewName
, Dir1
, Dir2
, File1
);
2123 ASSERT(UDFDirIndex(File1
->ParentFile
->Dloc
->DirIndex
, File1
->Index
)->FileInfo
== File1
);
2125 RC
= MyCloneUnicodeString(&LocalPath
, (Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ?
2126 &UDFGlobalData
.UnicodeStrRoot
:
2127 &(Dir2
->Fcb
->FCBName
->ObjectName
) );
2128 if(!NT_SUCCESS(RC
)) try_return (RC
);
2129 // RC = MyAppendUnicodeStringToString(&LocalPath, (Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? &(UDFGlobalData.UnicodeStrRoot) : &(Dir2->Fcb->FCBName->ObjectName));
2130 // if(!NT_SUCCESS(RC)) try_return (RC);
2131 if(Dir2
->ParentFile
) {
2132 RC
= MyAppendUnicodeToString(&LocalPath
, L
"\\");
2133 if(!NT_SUCCESS(RC
)) try_return (RC
);
2135 RC
= MyAppendUnicodeStringToStringTag(&LocalPath
, &NewName
, MEM_USREN_TAG
);
2136 if(!NT_SUCCESS(RC
)) try_return (RC
);
2139 DirNdx
= UDFDirIndex(File1
->ParentFile
->Dloc
->DirIndex
, File1
->Index
);
2140 if(Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_ARCH_BIT
) {
2141 Attr
= UDFAttributesToNT(DirNdx
, File1
->Dloc
->FileEntry
);
2142 if(!(Attr
& FILE_ATTRIBUTE_ARCHIVE
))
2143 UDFAttributesToUDF(DirNdx
, File1
->Dloc
->FileEntry
, Attr
| FILE_ATTRIBUTE_ARCHIVE
);
2145 // Update Parent Objects (mark 'em as modified)
2146 if(Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_DIR_WRITE
) {
2148 DirObject1
->Flags
|= FO_FILE_MODIFIED
;
2150 DirObject2
->Flags
|= FO_FILE_MODIFIED
;
2152 DirObject2
->Flags
|= FO_FILE_SIZE_CHANGED
;
2156 if(SingleDir
&& !Replace
) {
2157 UDFNotifyFullReportChange( Vcb
, File1
,
2158 UDFIsADirectory(File1
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
2159 FILE_ACTION_RENAMED_OLD_NAME
);
2160 /* UDFNotifyFullReportChange( Vcb, File2,
2161 UDFIsADirectory(File2) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
2162 FILE_ACTION_RENAMED_NEW_NAME );*/
2163 FsRtlNotifyFullReportChange( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
2164 (PSTRING
)&LocalPath
,
2165 ((Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ? 0 : Dir2
->Fcb
->FCBName
->ObjectName
.Length
) + sizeof(WCHAR
),
2167 UDFIsADirectory(File1
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
2168 FILE_ACTION_RENAMED_NEW_NAME
,
2171 UDFNotifyFullReportChange( Vcb
, File1
,
2172 UDFIsADirectory(File1
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
2173 FILE_ACTION_REMOVED
);
2175 /* UDFNotifyFullReportChange( Vcb, File2,
2176 FILE_NOTIFY_CHANGE_ATTRIBUTES |
2177 FILE_NOTIFY_CHANGE_SIZE |
2178 FILE_NOTIFY_CHANGE_LAST_WRITE |
2179 FILE_NOTIFY_CHANGE_LAST_ACCESS |
2180 FILE_NOTIFY_CHANGE_CREATION |
2181 FILE_NOTIFY_CHANGE_EA,
2182 FILE_ACTION_MODIFIED );*/
2183 FsRtlNotifyFullReportChange( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
2184 (PSTRING
)&LocalPath
,
2185 ((Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ?
2186 0 : Dir2
->Fcb
->FCBName
->ObjectName
.Length
) + sizeof(WCHAR
),
2188 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
2189 FILE_NOTIFY_CHANGE_SIZE
|
2190 FILE_NOTIFY_CHANGE_LAST_WRITE
|
2191 FILE_NOTIFY_CHANGE_LAST_ACCESS
|
2192 FILE_NOTIFY_CHANGE_CREATION
|
2193 FILE_NOTIFY_CHANGE_EA
,
2194 FILE_ACTION_MODIFIED
,
2197 /* UDFNotifyFullReportChange( Vcb, File2,
2198 UDFIsADirectory(File2) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
2199 FILE_ACTION_ADDED );*/
2200 FsRtlNotifyFullReportChange( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
2201 (PSTRING
)&LocalPath
,
2202 ((Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ?
2203 0 : Dir2
->Fcb
->FCBName
->ObjectName
.Length
) + sizeof(WCHAR
),
2205 UDFIsADirectory(File1
) ?
2206 FILE_NOTIFY_CHANGE_DIR_NAME
:
2207 FILE_NOTIFY_CHANGE_FILE_NAME
,
2213 // this will prevent structutre release before call to
2214 // UDFCleanUpFcbChain()
2215 UDFInterlockedIncrement((PLONG
)&(Dir1
->Fcb
->ReferenceCount
));
2216 UDFInterlockedIncrement((PLONG
)&(Dir1
->Fcb
->NTRequiredFCB
->CommonRefCount
));
2217 ASSERT_REF(Dir1
->Fcb
->ReferenceCount
>= Dir1
->RefCount
);
2219 // Look through Ccb list & decrement OpenHandleCounter(s)
2222 UDFAcquireResourceExclusive(&(Fcb1
->CcbListResource
),TRUE
);
2223 Link
= Fcb1
->NextCCB
.Flink
;
2225 FileInfoRefCount
= 0;
2226 ASSERT(Link
!= &(Fcb1
->NextCCB
));
2227 while (Link
!= &(Fcb1
->NextCCB
)) {
2228 NextFileInfo
= Dir1
;
2229 CurCcb
= CONTAINING_RECORD(Link
, UDFCCB
, NextCCB
);
2230 ASSERT(CurCcb
->TreeLength
);
2231 i
= (CurCcb
->TreeLength
) ? (CurCcb
->TreeLength
- 1) : 0;
2233 UseClose
= (CurCcb
->CCBFlags
& UDF_CCB_CLEANED
) ? FALSE
: TRUE
;
2235 AdPrint((" Ccb:%x:%s:i:%x\n", CurCcb
, UseClose
? "Close" : "",i
));
2236 // cleanup old parent chain
2237 for(; i
&& NextFileInfo
; i
--) {
2238 // remember parent file now
2239 // it will prevent us from data losses
2240 // due to eventual structure release
2241 fi
= NextFileInfo
->ParentFile
;
2243 ASSERT_REF(NextFileInfo
->Fcb
->ReferenceCount
>= NextFileInfo
->RefCount
);
2244 UDFCloseFile__(Vcb
, NextFileInfo
);
2246 ASSERT_REF(NextFileInfo
->Fcb
->ReferenceCount
> NextFileInfo
->RefCount
);
2247 ASSERT_REF(NextFileInfo
->Fcb
->ReferenceCount
);
2248 ASSERT_REF(NextFileInfo
->Fcb
->NTRequiredFCB
->CommonRefCount
);
2249 UDFInterlockedDecrement((PLONG
)&(NextFileInfo
->Fcb
->ReferenceCount
));
2250 UDFInterlockedDecrement((PLONG
)&(NextFileInfo
->Fcb
->NTRequiredFCB
->CommonRefCount
));
2251 ASSERT_REF(NextFileInfo
->Fcb
->ReferenceCount
>= NextFileInfo
->RefCount
);
2255 if(CurCcb
->TreeLength
> 1) {
2259 CurCcb
->TreeLength
= 2;
2266 UDFReleaseResource(&(Fcb1
->CcbListResource
));
2268 ASSERT_REF(DirRefCount
>= FileInfoRefCount
);
2269 // update counters & pointers
2270 Fcb1
->ParentFcb
= Dir2
->Fcb
;
2271 // move references to Dir2
2272 UDFInterlockedExchangeAdd((PLONG
)&(Dir2
->Fcb
->ReferenceCount
), DirRefCount
);
2273 UDFInterlockedExchangeAdd((PLONG
)&(Dir2
->Fcb
->NTRequiredFCB
->CommonRefCount
), DirRefCount
);
2274 ASSERT_REF(Dir2
->Fcb
->ReferenceCount
> Dir2
->RefCount
);
2275 UDFReferenceFileEx__(Dir2
,FileInfoRefCount
);
2276 ASSERT_REF(Dir2
->Fcb
->ReferenceCount
>= Dir2
->RefCount
);
2278 ASSERT_REF(Dir2
->Fcb
->ReferenceCount
>= Dir2
->RefCount
);
2279 ASSERT_REF(Dir2
->RefCount
);
2281 ASSERT_REF(Dir1
->Fcb
->ReferenceCount
>= Dir1
->RefCount
);
2282 // Modify name in Fcb1
2284 if(Fcb1
->FCBName
->ObjectName
.Buffer
) {
2285 MyFreePool__(Fcb1
->FCBName
->ObjectName
.Buffer
);
2287 UDFReleaseObjectName(Fcb1
->FCBName
);
2289 Fcb1
->FCBName
= UDFAllocateObjectName();
2290 if(!(Fcb1
->FCBName
)) {
2293 // UDFCleanUpFcbChain()...
2295 UDF_CHECK_PAGING_IO_RESOURCE(Fcb1
->NTRequiredFCB
);
2296 UDFReleaseResource(&(Fcb1
->NTRequiredFCB
->MainResource
));
2297 AcquiredDir1
= FALSE
;
2300 UDF_CHECK_PAGING_IO_RESOURCE(Dir1
->Fcb
->NTRequiredFCB
);
2301 UDFReleaseResource(&(Dir1
->Fcb
->NTRequiredFCB
->MainResource
));
2302 AcquiredDir1
= FALSE
;
2304 UDFCleanUpFcbChain(Vcb
, Dir1
, 1, TRUE
);
2305 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
2308 RC
= MyCloneUnicodeString(&(Fcb1
->FCBName
->ObjectName
), &(Fcb2
->FCBName
->ObjectName
));
2311 /* RC = MyAppendUnicodeStringToString(&(Fcb1->FCBName->ObjectName), &(Fcb2->FCBName->ObjectName));
2314 // if Dir2 is a RootDir, we shoud not append '\\' because
2315 // uit will be the 2nd '\\' character (RootDir's name is also '\\')
2316 if(Dir2
->ParentFile
) {
2317 RC
= MyAppendUnicodeToString(&(Fcb1
->FCBName
->ObjectName
), L
"\\");
2321 RC
= MyAppendUnicodeStringToStringTag(&(Fcb1
->FCBName
->ObjectName
), &NewName
, MEM_USREN2_TAG
);
2325 ASSERT_REF(Fcb1
->ReferenceCount
>= File1
->RefCount
);
2326 ASSERT_REF(Dir1
->Fcb
->ReferenceCount
>= Dir1
->RefCount
);
2327 ASSERT_REF(Dir2
->Fcb
->ReferenceCount
>= Dir2
->RefCount
);
2329 RC
= STATUS_SUCCESS
;
2336 UDF_CHECK_PAGING_IO_RESOURCE(Fcb1
->NTRequiredFCB
);
2337 UDFReleaseResource(&(Fcb1
->NTRequiredFCB
->MainResource
));
2340 UDF_CHECK_PAGING_IO_RESOURCE(Dir1
->Fcb
->NTRequiredFCB
);
2341 UDFReleaseResource(&(Dir1
->Fcb
->NTRequiredFCB
->MainResource
));
2343 // perform protected structure release
2344 if(NT_SUCCESS(RC
) &&
2345 (RC
!= STATUS_PENDING
)) {
2346 ASSERT(AcquiredVcb
);
2347 UDFCleanUpFcbChain(Vcb
, Dir1
, 1, TRUE
);
2348 ASSERT_REF(Fcb1
->ReferenceCount
>= File1
->RefCount
);
2349 ASSERT_REF(Dir2
->Fcb
->ReferenceCount
>= Dir2
->RefCount
);
2354 UDFConvertExclusiveToSharedLite(&(Vcb
->VCBResource
));
2356 // caller assumes Vcb to be acquired shared
2358 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
2361 if(LocalPath
.Buffer
) {
2362 MyFreePool__(LocalPath
.Buffer
);
2367 } // end UDFRename()
2369 #endif //UDF_READ_ONLY_BUILD
2377 if(!Vcb
->FileIdCache
) return (-1);
2378 for(ULONG i
=0; i
<Vcb
->FileIdCount
; i
++) {
2379 if(Vcb
->FileIdCache
[i
].Id
== Id
) return i
;
2382 } // end UDFFindFileId()
2390 if(!Vcb
->FileIdCache
) {
2391 if(!(Vcb
->FileIdCache
= (PUDFFileIDCacheItem
)MyAllocatePool__(NonPagedPool
, sizeof(UDFFileIDCacheItem
)*FILE_ID_CACHE_GRANULARITY
)))
2393 RtlZeroMemory(Vcb
->FileIdCache
, FILE_ID_CACHE_GRANULARITY
*sizeof(UDFFileIDCacheItem
));
2394 Vcb
->FileIdCount
= FILE_ID_CACHE_GRANULARITY
;
2396 for(ULONG i
=0; i
<Vcb
->FileIdCount
; i
++) {
2397 if(!Vcb
->FileIdCache
[i
].FullName
.Buffer
) return i
;
2399 if(!MyReallocPool__((PCHAR
)(Vcb
->FileIdCache
), Vcb
->FileIdCount
*sizeof(UDFFileIDCacheItem
),
2400 (PCHAR
*)&(Vcb
->FileIdCache
), (Vcb
->FileIdCount
+FILE_ID_CACHE_GRANULARITY
)*sizeof(UDFFileIDCacheItem
))) {
2403 RtlZeroMemory(&(Vcb
->FileIdCache
[Vcb
->FileIdCount
]), FILE_ID_CACHE_GRANULARITY
*sizeof(UDFFileIDCacheItem
));
2404 Vcb
->FileIdCount
+= FILE_ID_CACHE_GRANULARITY
;
2405 return (Vcb
->FileIdCount
- FILE_ID_CACHE_GRANULARITY
);
2406 } // end UDFFindFreeFileId()
2412 IN PUDF_FILE_INFO fi
,
2417 NTSTATUS RC
= STATUS_SUCCESS
;
2419 if((i
= UDFFindFileId(Vcb
, Id
)) == (-1)) {
2420 if((i
= UDFFindFreeFileId(Vcb
, Id
)) == (-1)) return STATUS_INSUFFICIENT_RESOURCES
;
2422 return STATUS_SUCCESS
;
2424 Vcb
->FileIdCache
[i
].Id
= Id
;
2425 Vcb
->FileIdCache
[i
].CaseSens
= (Ccb
->CCBFlags
& UDF_CCB_CASE_SENSETIVE
) ? TRUE
: FALSE
;
2426 RC
= MyCloneUnicodeString(&(Vcb
->FileIdCache
[i
].FullName
), &(Ccb
->Fcb
->FCBName
->ObjectName
));
2427 /* if(NT_SUCCESS(RC)) {
2428 RC = MyAppendUnicodeStringToStringTag(&(Vcb->FileIdCache[i].FullName), &(Ccb->Fcb->FCBName->ObjectName), MEM_USFIDC_TAG);
2431 } // end UDFStoreFileId()
2441 if((i
= UDFFindFileId(Vcb
, Id
)) == (-1)) return STATUS_INVALID_PARAMETER
;
2442 MyFreePool__(Vcb
->FileIdCache
[i
].FullName
.Buffer
);
2443 RtlZeroMemory(&(Vcb
->FileIdCache
[i
]), sizeof(UDFFileIDCacheItem
));
2444 return STATUS_SUCCESS
;
2445 } // end UDFRemoveFileId()
2448 UDFReleaseFileIdCache(
2452 if(!Vcb
->FileIdCache
) return;
2453 for(ULONG i
=0; i
<Vcb
->FileIdCount
; i
++) {
2454 if(Vcb
->FileIdCache
[i
].FullName
.Buffer
) {
2455 MyFreePool__(Vcb
->FileIdCache
[i
].FullName
.Buffer
);
2458 MyFreePool__(Vcb
->FileIdCache
);
2459 Vcb
->FileIdCache
= NULL
;
2460 Vcb
->FileIdCount
= 0;
2461 } // end UDFReleaseFileIdCache()
2464 UDFGetOpenParamsByFileId(
2467 OUT PUNICODE_STRING
* FName
,
2468 OUT BOOLEAN
* CaseSens
2473 if((i
= UDFFindFileId(Vcb
, Id
)) == (-1)) return STATUS_NOT_FOUND
;
2474 (*FName
) = &(Vcb
->FileIdCache
[i
].FullName
);
2475 (*CaseSens
) = !(Vcb
->FileIdCache
[i
].CaseSens
);
2476 return STATUS_SUCCESS
;
2477 } // end UDFGetOpenParamsByFileId()
2479 #ifndef UDF_READ_ONLY_BUILD
2481 #ifdef UDF_ALLOW_HARD_LINKS
2483 create hard link for the file
2487 IN PIO_STACK_LOCATION PtrSp
,
2490 IN PFILE_OBJECT FileObject1
, // Source File
2491 IN PFILE_LINK_INFORMATION PtrBuffer
2495 PFILE_OBJECT DirObject2
= PtrSp
->Parameters
.SetFile
.FileObject
;
2497 BOOLEAN Replace
= PtrSp
->Parameters
.SetFile
.ReplaceIfExists
&&
2498 PtrBuffer
->ReplaceIfExists
;
2500 PVCB Vcb
= Fcb1
->Vcb
;
2503 BOOLEAN AcquiredVcb
= TRUE
;
2504 BOOLEAN AcquiredVcbEx
= FALSE
;
2505 BOOLEAN AcquiredDir1
= FALSE
;
2506 BOOLEAN AcquiredFcb1
= FALSE
;
2507 BOOLEAN SingleDir
= TRUE
;
2509 PUDF_FILE_INFO File1
;
2510 PUDF_FILE_INFO Dir1
= NULL
;
2511 PUDF_FILE_INFO Dir2
;
2513 UNICODE_STRING NewName
;
2514 UNICODE_STRING LocalPath
;
2515 // PtrUDFCCB CurCcb = NULL;
2517 AdPrint(("UDFHardLink\n"));
2519 LocalPath
.Buffer
= NULL
;
2523 // do we try to link Volume ?
2524 if(!(File1
= Fcb1
->FileInfo
))
2525 try_return (RC
= STATUS_ACCESS_DENIED
);
2527 // do we try to link RootDir ?
2528 if(!(Dir1
= File1
->ParentFile
))
2529 try_return (RC
= STATUS_ACCESS_DENIED
);
2531 // do we try to link Stream / Stream Dir ?
2532 #ifdef UDF_ALLOW_LINKS_TO_STREAMS
2533 if(UDFIsAStreamDir(File1
))
2534 try_return (RC
= STATUS_ACCESS_DENIED
);
2535 #else //UDF_ALLOW_LINKS_TO_STREAMS
2536 if(UDFIsAStream(File1
) || UDFIsAStreamDir(File1
) /*||
2537 UDFIsADirectory(File1) || UDFHasAStreamDir(File1)*/)
2538 try_return (RC
= STATUS_ACCESS_DENIED
);
2539 #endif // UDF_ALLOW_LINKS_TO_STREAMS
2541 // do we try to link to RootDir or Volume ?
2543 Dir2
= File1
->ParentFile
;
2544 DirObject2
= FileObject1
->RelatedFileObject
;
2546 if(DirObject2
->FsContext2
&&
2547 (Fcb2
= ((PtrUDFCCB
)(DirObject2
->FsContext2
))->Fcb
)) {
2548 Dir2
= ((PtrUDFCCB
)(DirObject2
->FsContext2
))->Fcb
->FileInfo
;
2550 try_return (RC
= STATUS_INVALID_PARAMETER
);
2554 if(!Dir2
) try_return (RC
= STATUS_ACCESS_DENIED
);
2556 // Stream can't be a Dir or have Streams
2557 if(UDFIsAStreamDir(Dir2
)) {
2558 try_return (RC
= STATUS_ACCESS_DENIED
);
2559 /* if(UDFIsADirectory(File1) ||
2560 UDFHasAStreamDir(File1)) {
2562 try_return (RC = STATUS_ACCESS_DENIED);
2566 /* if(UDFIsAStreamDir(Dir2))
2567 try_return (RC = STATUS_ACCESS_DENIED);*/
2569 RC
= UDFPrepareForRenameMoveLink(Vcb
, &AcquiredVcb
, &AcquiredVcbEx
,
2571 &AcquiredDir1
, &AcquiredFcb1
,
2574 TRUE
); // it is HLink operation
2578 // check if the source file is used
2580 // Make sure the name is of legal length.
2581 if(PtrBuffer
->FileNameLength
> UDF_NAME_LEN
*sizeof(WCHAR
)) {
2582 try_return(RC
= STATUS_OBJECT_NAME_INVALID
);
2584 NewName
.Length
= NewName
.MaximumLength
= (USHORT
)(PtrBuffer
->FileNameLength
);
2585 NewName
.Buffer
= (PWCHAR
)&(PtrBuffer
->FileName
);
2587 // This name is by definition legal.
2588 NewName
= *((PUNICODE_STRING
)&DirObject2
->FileName
);
2591 ic
= (Ccb1
->CCBFlags
& UDF_CCB_CASE_SENSETIVE
) ? FALSE
: TRUE
;
2593 AdPrint((" %ws ->\n %ws\n",
2594 Fcb1
->FCBName
->ObjectName
.Buffer
,
2597 RC
= UDFHardLinkFile__(Vcb
, ic
, &Replace
, &NewName
, Dir1
, Dir2
, File1
);
2598 if(!NT_SUCCESS(RC
)) try_return (RC
);
2600 // Update Parent Objects (mark 'em as modified)
2601 if(Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_DIR_WRITE
) {
2603 DirObject2
->Flags
|= FO_FILE_MODIFIED
;
2605 DirObject2
->Flags
|= FO_FILE_SIZE_CHANGED
;
2609 UDFNotifyFullReportChange( Vcb
, File1
,
2610 FILE_NOTIFY_CHANGE_LAST_WRITE
|
2611 FILE_NOTIFY_CHANGE_LAST_ACCESS
,
2612 FILE_ACTION_MODIFIED
);
2614 RC
= MyCloneUnicodeString(&LocalPath
, (Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ?
2615 &UDFGlobalData
.UnicodeStrRoot
:
2616 &(Dir2
->Fcb
->FCBName
->ObjectName
));
2617 if(!NT_SUCCESS(RC
)) try_return (RC
);
2618 /* RC = MyAppendUnicodeStringToString(&LocalPath, (Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? &(UDFGlobalData.UnicodeStrRoot) : &(Dir2->Fcb->FCBName->ObjectName));
2619 if(!NT_SUCCESS(RC)) try_return (RC);*/
2620 // if Dir2 is a RootDir, we shoud not append '\\' because
2621 // it will be the 2nd '\\' character (RootDir's name is also '\\')
2622 if(Dir2
->ParentFile
) {
2623 RC
= MyAppendUnicodeToString(&LocalPath
, L
"\\");
2624 if(!NT_SUCCESS(RC
)) try_return (RC
);
2626 RC
= MyAppendUnicodeStringToStringTag(&LocalPath
, &NewName
, MEM_USHL_TAG
);
2627 if(!NT_SUCCESS(RC
)) try_return (RC
);
2630 /* UDFNotifyFullReportChange( Vcb, File2,
2631 UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
2632 FILE_ACTION_ADDED );*/
2633 FsRtlNotifyFullReportChange( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
2634 (PSTRING
)&LocalPath
,
2635 ((Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ? 0 : Dir2
->Fcb
->FCBName
->ObjectName
.Length
) + sizeof(WCHAR
),
2637 UDFIsADirectory(File1
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
2641 /* UDFNotifyFullReportChange( Vcb, File2,
2642 FILE_NOTIFY_CHANGE_ATTRIBUTES |
2643 FILE_NOTIFY_CHANGE_SIZE |
2644 FILE_NOTIFY_CHANGE_LAST_WRITE |
2645 FILE_NOTIFY_CHANGE_LAST_ACCESS |
2646 FILE_NOTIFY_CHANGE_CREATION |
2647 FILE_NOTIFY_CHANGE_EA,
2648 FILE_ACTION_MODIFIED );*/
2649 FsRtlNotifyFullReportChange( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
2650 (PSTRING
)&LocalPath
,
2651 ((Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ? 0 : Dir2
->Fcb
->FCBName
->ObjectName
.Length
) + sizeof(WCHAR
),
2653 UDFIsADirectory(File1
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
2654 FILE_NOTIFY_CHANGE_ATTRIBUTES
|
2655 FILE_NOTIFY_CHANGE_SIZE
|
2656 FILE_NOTIFY_CHANGE_LAST_WRITE
|
2657 FILE_NOTIFY_CHANGE_LAST_ACCESS
|
2658 FILE_NOTIFY_CHANGE_CREATION
|
2659 FILE_NOTIFY_CHANGE_EA
,
2663 RC
= STATUS_SUCCESS
;
2670 UDF_CHECK_PAGING_IO_RESOURCE(Fcb1
->NTRequiredFCB
);
2671 UDFReleaseResource(&(Fcb1
->NTRequiredFCB
->MainResource
));
2674 UDF_CHECK_PAGING_IO_RESOURCE(Dir1
->Fcb
->NTRequiredFCB
);
2675 UDFReleaseResource(&(Dir1
->Fcb
->NTRequiredFCB
->MainResource
));
2679 UDFConvertExclusiveToSharedLite(&(Vcb
->VCBResource
));
2681 // caller assumes Vcb to be acquired shared
2683 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
2686 if(LocalPath
.Buffer
) {
2687 MyFreePool__(LocalPath
.Buffer
);
2692 } // end UDFHardLink()
2693 #endif //UDF_ALLOW_HARD_LINKS
2695 #endif //UDF_READ_ONLY_BUILD