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 KdPrint((" FSRTL_FSP_TOP_LEVEL_IRP\n"));
144 case FSRTL_CACHE_TOP_LEVEL_IRP
:
145 KdPrint((" FSRTL_CACHE_TOP_LEVEL_IRP\n"));
147 case FSRTL_MOD_WRITE_TOP_LEVEL_IRP
:
148 KdPrint((" FSRTL_MOD_WRITE_TOP_LEVEL_IRP\n"));
150 case FSRTL_FAST_IO_TOP_LEVEL_IRP
:
151 KdPrint((" FSRTL_FAST_IO_TOP_LEVEL_IRP\n"));
155 KdPrint((" NULL TOP_LEVEL_IRP\n"));
159 KdPrint((" TOP_LEVEL_IRP\n"));
161 KdPrint((" 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
< 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
< 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
< 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
< 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
< 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
834 NTSTATUS RC
= STATUS_SUCCESS
;
837 AdPrint(("UDFGetFullNameInformation\n"));
839 PtrBuffer
->FileNameLength
= FileObject
->FileName
.Length
;
841 if (PtrBuffer
->FileNameLength
+ sizeof( ULONG
) > (ULONG
)(*PtrReturnedLength
)) {
843 PtrBuffer
->FileNameLength
= *PtrReturnedLength
- sizeof( ULONG
);
844 RC
= STATUS_BUFFER_OVERFLOW
;
847 RtlCopyMemory( PtrBuffer
->FileName
, FileObject
->FileName
.Buffer
, PtrBuffer
->FileNameLength
);
849 // Reduce the available bytes by the amount stored into this buffer.
850 *PtrReturnedLength
-= sizeof( ULONG
) + PtrBuffer
->FileNameLength
;
853 } // end UDFGetFullNameInformation()
856 Return file short(8.3) name to the caller.
859 UDFGetAltNameInformation(
861 IN PFILE_NAME_INFORMATION PtrBuffer
,
862 IN OUT PLONG PtrReturnedLength
865 PDIR_INDEX_ITEM DirNdx
;
867 UNICODE_STRING ShortName
;
868 WCHAR ShortNameBuffer
[13];
870 AdPrint(("UDFGetAltNameInformation: \n"));
872 *PtrReturnedLength
-= FIELD_OFFSET(FILE_NAME_INFORMATION
, FileName
[0]);
873 DirNdx
= UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb
->FileInfo
), Fcb
->FileInfo
->Index
);
875 ShortName
.MaximumLength
= 13 * sizeof(WCHAR
);
876 ShortName
.Buffer
= (PWCHAR
)&ShortNameBuffer
;
878 UDFDOSName__(Fcb
->Vcb
, &ShortName
, &(DirNdx
->FName
), Fcb
->FileInfo
);
880 if(*PtrReturnedLength
< ShortName
.Length
) {
881 return(STATUS_BUFFER_OVERFLOW
);
883 BytesToCopy
= ShortName
.Length
;
884 *PtrReturnedLength
-= ShortName
.Length
;
887 RtlCopyMemory( &(PtrBuffer
->FileName
),
891 PtrBuffer
->FileNameLength
= ShortName
.Length
;
893 return(STATUS_SUCCESS
);
894 } // end UDFGetAltNameInformation()
897 Get file position information
900 UDFGetPositionInformation(
901 IN PFILE_OBJECT FileObject
,
902 IN PFILE_POSITION_INFORMATION PtrBuffer
,
903 IN OUT PLONG PtrReturnedLength
906 if(*PtrReturnedLength
< sizeof(FILE_POSITION_INFORMATION
)) {
907 return(STATUS_BUFFER_OVERFLOW
);
909 PtrBuffer
->CurrentByteOffset
= FileObject
->CurrentByteOffset
;
910 // Modify the local variable for BufferLength appropriately.
911 *PtrReturnedLength
-= sizeof(FILE_POSITION_INFORMATION
);
913 return(STATUS_SUCCESS
);
914 } // end UDFGetAltNameInformation()
917 Get file file stream(s) information
920 UDFGetFileStreamInformation(
922 IN PFILE_STREAM_INFORMATION PtrBuffer
,
923 IN OUT PLONG PtrReturnedLength
926 NTSTATUS RC
= STATUS_SUCCESS
;
927 PUDF_FILE_INFO FileInfo
;
928 PUDF_FILE_INFO SDirInfo
;
930 BOOLEAN FcbAcquired
= FALSE
;
933 PDIR_INDEX_HDR hSDirIndex
;
934 PDIR_INDEX_ITEM SDirIndex
;
935 PFILE_BOTH_DIR_INFORMATION NTFileInfo
= NULL
;
937 AdPrint(("UDFGetFileStreamInformation\n"));
941 UDFAcquireResourceExclusive(&(Fcb
->Vcb
->FileIdResource
), TRUE
);
944 FileInfo
= Fcb
->FileInfo
;
946 AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n"));
947 AdPrint(("!!!! UDFGetFileStreamInformation to unopened file !!!!\n"));
948 try_return(RC
= STATUS_INVALID_PARAMETER
);
951 // Zero out the supplied buffer.
952 RtlZeroMemory(PtrBuffer
, *PtrReturnedLength
);
953 if(!(SDirInfo
= FileInfo
->Dloc
->SDirInfo
) ||
954 UDFIsSDirDeleted(SDirInfo
) ) {
955 (*PtrReturnedLength
) -= (sizeof(FILE_STREAM_INFORMATION
) - sizeof(WCHAR
));
956 try_return(RC
= STATUS_SUCCESS
);
959 hSDirIndex
= SDirInfo
->Dloc
->DirIndex
;
960 NTFileInfo
= (PFILE_BOTH_DIR_INFORMATION
)MyAllocatePool__(NonPagedPool
, sizeof(FILE_BOTH_DIR_INFORMATION
)+UDF_NAME_LEN
*sizeof(WCHAR
));
961 if(!NTFileInfo
) try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
963 for(i
=2; SDirIndex
= UDFDirIndex(hSDirIndex
,i
); i
++) {
964 if((SDirIndex
->FI_Flags
& UDF_FI_FLAG_FI_INTERNAL
) ||
965 UDFIsDeleted(SDirIndex
) ||
966 !SDirIndex
->FName
.Buffer
)
968 // copy data to buffer
969 if(*PtrReturnedLength
< (l
= ((sizeof(FILE_STREAM_INFORMATION
) - sizeof(WCHAR
)) +
970 SDirIndex
->FName
.Length
+ 3) & (~3)) ) {
971 try_return(RC
= STATUS_BUFFER_OVERFLOW
);
973 RC
= UDFFileDirInfoToNT(Vcb
, SDirIndex
, NTFileInfo
);
975 PtrBuffer
->NextEntryOffset
= l
;
976 PtrBuffer
->StreamNameLength
= SDirIndex
->FName
.Length
;
977 PtrBuffer
->StreamSize
= NTFileInfo
->EndOfFile
;
978 PtrBuffer
->StreamAllocationSize
= NTFileInfo
->AllocationSize
;
979 RtlCopyMemory(&(PtrBuffer
->StreamName
), SDirIndex
->FName
.Buffer
, SDirIndex
->FName
.Length
);
980 *PtrReturnedLength
-= l
;
981 *((PCHAR
*)(&PtrBuffer
)) += l
;
988 UDFReleaseResource(&(Fcb
->Vcb
->FileIdResource
));
990 MyFreePool__(NTFileInfo
);
993 } // end UDFGetFileStreamInformation()
995 //*******************************************************************
997 #ifndef UDF_READ_ONLY_BUILD
1000 Set some time-stamps and file attributes supplied by the caller.
1003 UDFSetBasicInformation(
1006 IN PFILE_OBJECT FileObject
,
1007 IN PFILE_BASIC_INFORMATION PtrBuffer
)
1009 NTSTATUS RC
= STATUS_SUCCESS
;
1010 ULONG NotifyFilter
= 0;
1012 AdPrint(("UDFSetBasicInformation\n"));
1016 // Obtain a pointer to the directory entry associated with
1017 // the FCB being modifed. The directory entry is obviously
1018 // part of the data associated with the parent directory that
1019 // contains this particular file stream.
1020 if(PtrBuffer
->FileAttributes
) {
1021 UDFUpdateAttrTime(Fcb
->Vcb
, Fcb
->FileInfo
);
1023 if( UDFIsADirectory(Fcb
->FileInfo
) &&
1024 !(Fcb
->Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_UCHG_DIR_ACCESS_TIME
) &&
1025 ((Fcb
->FileInfo
->Dloc
->DataLoc
.Modified
||
1026 Fcb
->FileInfo
->Dloc
->AllocLoc
.Modified
||
1027 (Fcb
->FileInfo
->Dloc
->FE_Flags
& UDF_FE_FLAG_FE_MODIFIED
) ||
1028 Fcb
->FileInfo
->Dloc
->FELoc
.Modified
))
1030 // ignore Access Time Modification for unchanged Dir
1031 if(!PtrBuffer
->CreationTime
.QuadPart
&&
1032 PtrBuffer
->LastAccessTime
.QuadPart
&&
1033 !PtrBuffer
->ChangeTime
.QuadPart
&&
1034 !PtrBuffer
->LastWriteTime
.QuadPart
)
1038 UDFSetFileXTime(Fcb
->FileInfo
,
1039 &(PtrBuffer
->CreationTime
.QuadPart
),
1040 &(PtrBuffer
->LastAccessTime
.QuadPart
),
1041 &(PtrBuffer
->ChangeTime
.QuadPart
),
1042 &(PtrBuffer
->LastWriteTime
.QuadPart
) );
1044 if(PtrBuffer
->CreationTime
.QuadPart
) {
1045 // The interesting thing here is that the user has set certain time
1046 // fields. However, before doing this, the user may have performed
1047 // I/O which in turn would have caused FSD to mark the fact that
1048 // write/access time should be modifed at cleanup.
1049 // We'll mark the fact that such updates are no longer
1050 // required since the user has explicitly specified the values he
1051 // wishes to see associated with the file stream.
1052 Fcb
->NTRequiredFCB
->CreationTime
= PtrBuffer
->CreationTime
;
1053 Ccb
->CCBFlags
|= UDF_CCB_CREATE_TIME_SET
;
1054 NotifyFilter
|= FILE_NOTIFY_CHANGE_CREATION
;
1056 if(PtrBuffer
->LastAccessTime
.QuadPart
) {
1057 Fcb
->NTRequiredFCB
->LastAccessTime
= PtrBuffer
->LastAccessTime
;
1058 Ccb
->CCBFlags
|= UDF_CCB_ACCESS_TIME_SET
;
1059 NotifyFilter
|= FILE_NOTIFY_CHANGE_LAST_ACCESS
;
1061 if(PtrBuffer
->ChangeTime
.QuadPart
) {
1062 Fcb
->NTRequiredFCB
->ChangeTime
= PtrBuffer
->ChangeTime
;
1063 Ccb
->CCBFlags
|= UDF_CCB_MODIFY_TIME_SET
;
1065 if(PtrBuffer
->LastWriteTime
.QuadPart
) {
1066 Fcb
->NTRequiredFCB
->LastWriteTime
= PtrBuffer
->LastWriteTime
;
1067 Ccb
->CCBFlags
|= UDF_CCB_WRITE_TIME_SET
;
1068 NotifyFilter
|= FILE_NOTIFY_CHANGE_LAST_WRITE
;
1071 // Now come the attributes.
1072 if(PtrBuffer
->FileAttributes
) {
1073 // We have a non-zero attribute value.
1074 // The presence of a particular attribute indicates that the
1075 // user wishes to set the attribute value. The absence indicates
1076 // the user wishes to clear the particular attribute.
1078 // Our routine ignores unsupported flags
1079 PtrBuffer
->FileAttributes
&= ~(FILE_ATTRIBUTE_NORMAL
);
1081 // Similarly, we should pick out other invalid flag values.
1082 if( (PtrBuffer
->FileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) &&
1083 !(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
))
1084 try_return(RC
= STATUS_INVALID_PARAMETER
);
1086 if(PtrBuffer
->FileAttributes
& FILE_ATTRIBUTE_TEMPORARY
) {
1087 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
)
1088 try_return(RC
= STATUS_INVALID_PARAMETER
);
1089 FileObject
->Flags
|= FO_TEMPORARY_FILE
;
1091 FileObject
->Flags
&= ~FO_TEMPORARY_FILE
;
1094 if(PtrBuffer
->FileAttributes
& FILE_ATTRIBUTE_READONLY
) {
1095 Fcb
->FCBFlags
|= UDF_FCB_READ_ONLY
;
1097 Fcb
->FCBFlags
&= ~UDF_FCB_READ_ONLY
;
1100 UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb
->FileInfo
), Fcb
->FileInfo
->Index
),
1101 NULL
, PtrBuffer
->FileAttributes
);
1103 (UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb
->FileInfo
), Fcb
->FileInfo
->Index
))
1104 ->FI_Flags
|= UDF_FI_FLAG_SYS_ATTR
;
1105 // If the FSD supports file compression, we may wish to
1106 // note the user's preferences for compressing/not compressing
1107 // the file at this time.
1108 Ccb
->CCBFlags
|= UDF_CCB_ATTRIBUTES_SET
;
1109 NotifyFilter
|= FILE_NOTIFY_CHANGE_ATTRIBUTES
;
1113 UDFNotifyFullReportChange( Fcb
->Vcb
, Fcb
->FileInfo
,
1114 NotifyFilter
, FILE_ACTION_MODIFIED
);
1115 UDFSetFileSizeInDirNdx(Fcb
->Vcb
, Fcb
->FileInfo
, NULL
);
1116 Fcb
->FileInfo
->Dloc
->FE_Flags
|= UDF_FE_FLAG_FE_MODIFIED
;
1124 } // end UDFSetBasicInformation()
1127 UDFMarkStreamsForDeletion(
1133 NTSTATUS RC
= STATUS_SUCCESS
;
1134 PUDF_FILE_INFO SDirInfo
= NULL
;
1135 PUDF_FILE_INFO FileInfo
= NULL
;
1137 BOOLEAN SDirAcq
= FALSE
;
1138 BOOLEAN StrAcq
= FALSE
;
1143 // In some cases we needn't marking Streams for deleteion
1144 // (Not opened or Don't exist)
1145 if(UDFIsAStream(Fcb
->FileInfo
) ||
1146 UDFIsAStreamDir(Fcb
->FileInfo
) ||
1147 !UDFHasAStreamDir(Fcb
->FileInfo
) ||
1148 !Fcb
->FileInfo
->Dloc
->SDirInfo
||
1149 UDFIsSDirDeleted(Fcb
->FileInfo
->Dloc
->SDirInfo
) ||
1150 (UDFGetFileLinkCount(Fcb
->FileInfo
) > 1) )
1151 try_return (RC
/*=STATUS_SUCCESS*/);
1153 // We shall mark Streams for deletion if there is no
1154 // Links to the file. Otherwise we'll delete only the file.
1155 // If we are asked to unmark Streams, we'll precess the whole Tree
1156 RC
= UDFOpenStreamDir__(Vcb
, Fcb
->FileInfo
, &SDirInfo
);
1161 SDirInfo
->Fcb
->NTRequiredFCB
) {
1162 UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo
->Fcb
->NTRequiredFCB
);
1163 UDFAcquireResourceExclusive(&(SDirInfo
->Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
1167 if(!ForDel
|| ((lc
= UDFGetFileLinkCount(Fcb
->FileInfo
)) < 2)) {
1169 UDF_DIR_SCAN_CONTEXT ScanContext
;
1170 PDIR_INDEX_ITEM DirNdx
;
1172 // It is not worth checking whether the Stream can be deleted if
1173 // Undelete requested
1176 UDFDirIndexInitScan(SDirInfo
, &ScanContext
, 2)) {
1178 // Check if we can delete Streams
1179 while(DirNdx
= UDFDirIndexScan(&ScanContext
, &FileInfo
)) {
1183 FileInfo
->Fcb
->NTRequiredFCB
->AcqFlushCount
++;
1184 MmPrint((" MmFlushImageSection() for Stream\n"));
1185 if(!MmFlushImageSection(&(FileInfo
->Fcb
->NTRequiredFCB
->SectionObject
), MmFlushForDelete
)) {
1186 FileInfo
->Fcb
->NTRequiredFCB
->AcqFlushCount
--;
1187 try_return(RC
= STATUS_CANNOT_DELETE
);
1189 FileInfo
->Fcb
->NTRequiredFCB
->AcqFlushCount
--;
1193 // (Un)Mark Streams for deletion
1195 // Perform sequencial Open for Streams & mark 'em
1196 // for deletion. We should not get FileInfo pointers directly
1197 // from DirNdx[i] to prevent great troubles with linked
1198 // files. We should mark for deletion FI with proper ParentFile
1200 d
= UDFDirIndexGetLastIndex(SDirInfo
->Dloc
->DirIndex
);
1201 for(i
=2; i
<d
; i
++) {
1202 RC
= UDFOpenFile__(Vcb
,
1204 SDirInfo
,&FileInfo
,&i
);
1205 ASSERT(NT_SUCCESS(RC
) || (RC
== STATUS_FILE_DELETED
));
1206 if(NT_SUCCESS(RC
)) {
1208 if(FileInfo
->Fcb
->NTRequiredFCB
) {
1209 UDF_CHECK_PAGING_IO_RESOURCE(FileInfo
->Fcb
->NTRequiredFCB
);
1210 UDFAcquireResourceExclusive(&(FileInfo
->Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
1213 #ifndef UDF_ALLOW_LINKS_TO_STREAMS
1214 if(UDFGetFileLinkCount(FileInfo
) >= 2) {
1215 // Currently, UDF_INFO package doesn't
1216 // support this case, so we'll inform developer
1217 // about this to prevent on-disk space leaks...
1219 try_return(RC
= STATUS_CANNOT_DELETE
);
1221 #endif //UDF_ALLOW_LINKS_TO_STREAMS
1223 AdPrint((" SET stream DeleteOnClose\n"));
1225 ASSERT(!(FileInfo
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
1226 if(FileInfo
->ParentFile
&&
1227 FileInfo
->ParentFile
->Fcb
) {
1228 ASSERT(!(FileInfo
->ParentFile
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
1231 FileInfo
->Fcb
->FCBFlags
|= (UDF_FCB_DELETE_ON_CLOSE
|
1232 UDF_FCB_DELETE_PARENT
);
1234 AdPrint((" CLEAR stream DeleteOnClose\n"));
1235 FileInfo
->Fcb
->FCBFlags
&= !(UDF_FCB_DELETE_ON_CLOSE
|
1236 UDF_FCB_DELETE_PARENT
);
1239 UDFCloseFile__(Vcb
, FileInfo
);
1241 if(RC
== STATUS_FILE_DELETED
) {
1242 // That's OK if STATUS_FILE_DELETED returned...
1243 RC
= STATUS_SUCCESS
;
1246 if(UDFCleanUpFile__(Vcb
, FileInfo
)) {
1247 ASSERT(!StrAcq
&& !(FileInfo
->Fcb
));
1248 MyFreePool__(FileInfo
);
1251 UDF_CHECK_PAGING_IO_RESOURCE(FileInfo
->Fcb
->NTRequiredFCB
);
1252 UDFReleaseResource(&(FileInfo
->Fcb
->NTRequiredFCB
->MainResource
));
1258 // Mark SDir for deletion
1262 ASSERT(!(SDirInfo
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
1263 if(SDirInfo
->ParentFile
&&
1264 SDirInfo
->ParentFile
->Fcb
) {
1265 ASSERT(!(SDirInfo
->ParentFile
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
1268 AdPrint((" SET stream dir DeleteOnClose\n"));
1269 SDirInfo
->Fcb
->FCBFlags
|= (UDF_FCB_DELETE_ON_CLOSE
|
1270 UDF_FCB_DELETE_PARENT
);
1272 AdPrint((" CLEAR stream dir DeleteOnClose\n"));
1273 SDirInfo
->Fcb
->FCBFlags
&= ~(UDF_FCB_DELETE_ON_CLOSE
|
1274 UDF_FCB_DELETE_PARENT
);
1279 // if caller wants us to perform DelTree for Streams, but
1280 // someone keeps Stream opened and there is a Link to this
1281 // file, we can't delete it immediately (on Cleanup) & should
1282 // not delete the whole Tree. Instead, we'll set DELETE_PARENT
1283 // flag in SDir to kill this file later, when all the Handles
1284 // to Streams, opened via this file, would be closed
1286 ASSERT(!(SDirInfo
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
1287 if(SDirInfo
->ParentFile
&&
1288 SDirInfo
->ParentFile
->Fcb
) {
1289 ASSERT(!(SDirInfo
->ParentFile
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
));
1293 SDirInfo
->Fcb
->FCBFlags
|= UDF_FCB_DELETE_PARENT
;
1300 UDFCloseFile__(Vcb
, FileInfo
);
1301 if(UDFCleanUpFile__(Vcb
, FileInfo
)) {
1302 ASSERT(!StrAcq
&& !(FileInfo
->Fcb
));
1303 MyFreePool__(FileInfo
);
1306 UDF_CHECK_PAGING_IO_RESOURCE(FileInfo
->Fcb
->NTRequiredFCB
);
1307 UDFReleaseResource(&(FileInfo
->Fcb
->NTRequiredFCB
->MainResource
));
1312 UDFCloseFile__(Vcb
, SDirInfo
);
1314 UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo
->Fcb
->NTRequiredFCB
);
1315 UDFReleaseResource(&(SDirInfo
->Fcb
->NTRequiredFCB
->MainResource
));
1317 if(UDFCleanUpFile__(Vcb
, SDirInfo
)) {
1318 MyFreePool__(SDirInfo
);
1324 } // end UDFMarkStreamsForDeletion()
1327 (Un)Mark file for deletion.
1330 UDFSetDispositionInformation(
1334 IN PFILE_OBJECT FileObject
,
1338 NTSTATUS RC
= STATUS_SUCCESS
;
1339 // PUDF_FILE_INFO SDirInfo = NULL;
1340 // PUDF_FILE_INFO FileInfo = NULL;
1343 AdPrint(("UDFSetDispositionInformation\n"));
1348 AdPrint((" CLEAR DeleteOnClose\n"));
1349 // "un-delete" the file.
1350 Fcb
->FCBFlags
&= ~UDF_FCB_DELETE_ON_CLOSE
;
1352 FileObject
->DeletePending
= FALSE
;
1353 RC
= UDFMarkStreamsForDeletion(Vcb
, Fcb
, FALSE
); // Undelete
1356 AdPrint((" SET DeleteOnClose\n"));
1358 // The easy part is over. Now, we know that the user wishes to
1359 // delete the corresponding directory entry (of course, if this
1360 // is the only link to the file stream, any on-disk storage space
1361 // associated with the file stream will also be released when the
1362 // (only) link is deleted!)
1364 // Do some checking to see if the file can even be deleted.
1365 if(Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
) {
1370 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_READ_ONLY
) {
1371 try_return(RC
= STATUS_CANNOT_DELETE
);
1374 if(Fcb
->FCBFlags
& UDF_FCB_READ_ONLY
) {
1375 RC
= UDFCheckAccessRights(NULL
, NULL
, Fcb
->ParentFcb
, NULL
, FILE_DELETE_CHILD
, 0);
1376 if(!NT_SUCCESS(RC
)) {
1377 try_return (RC
= STATUS_CANNOT_DELETE
);
1381 // It would not be prudent to allow deletion of either a root
1382 // directory or a directory that is not empty.
1383 if(Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
)
1384 try_return(RC
= STATUS_CANNOT_DELETE
);
1386 lc
= UDFGetFileLinkCount(Fcb
->FileInfo
);
1388 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
1389 // Perform check to determine whether the directory
1391 if(!UDFIsDirEmpty__(Fcb
->FileInfo
)) {
1392 try_return(RC
= STATUS_DIRECTORY_NOT_EMPTY
);
1396 // An important step is to check if the file stream has been
1397 // mapped by any process. The delete cannot be allowed to proceed
1399 MmPrint((" MmFlushImageSection()\n"));
1400 Fcb
->NTRequiredFCB
->AcqFlushCount
++;
1401 if(!MmFlushImageSection(&(Fcb
->NTRequiredFCB
->SectionObject
),
1402 (lc
> 1) ? MmFlushForWrite
: MmFlushForDelete
)) {
1403 Fcb
->NTRequiredFCB
->AcqFlushCount
--;
1404 try_return(RC
= STATUS_CANNOT_DELETE
);
1406 Fcb
->NTRequiredFCB
->AcqFlushCount
--;
1408 // We should also mark Streams for deletion if there are no
1409 // Links to the file. Otherwise we'll delete only the file
1412 RC
= STATUS_SUCCESS
;
1414 RC
= UDFMarkStreamsForDeletion(Vcb
, Fcb
, TRUE
); // Delete
1419 // Set a flag to indicate that this directory entry will become history
1421 Fcb
->FCBFlags
|= UDF_FCB_DELETE_ON_CLOSE
;
1423 FileObject
->DeletePending
= TRUE
;
1425 if((Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) && Ccb
) {
1426 FsRtlNotifyFullChangeDirectory( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
1427 (PVOID
)Ccb
, NULL
, FALSE
, FALSE
,
1428 0, NULL
, NULL
, NULL
);
1437 } // end UDFSetDispositionInformation()
1441 Change file allocation length.
1444 UDFSetAllocationInformation(
1448 IN PFILE_OBJECT FileObject
,
1449 IN PtrUDFIrpContext PtrIrpContext
,
1451 IN PFILE_ALLOCATION_INFORMATION PtrBuffer
1454 NTSTATUS RC
= STATUS_SUCCESS
;
1455 BOOLEAN TruncatedFile
= FALSE
;
1456 BOOLEAN ModifiedAllocSize
= FALSE
;
1457 BOOLEAN CacheMapInitialized
= FALSE
;
1458 BOOLEAN AcquiredPagingIo
= FALSE
;
1460 AdPrint(("UDFSetAllocationInformation\n"));
1463 // Increasing the allocation size associated with a file stream
1464 // is relatively easy. All we have to do is execute some FSD
1465 // specific code to check whether we have enough space available
1466 // (and if the FSD supports user/volume quotas, whether the user
1467 // is not exceeding quota), and then increase the file size in the
1468 // corresponding on-disk and in-memory structures.
1469 // Then, all we should do is inform the Cache Manager about the
1470 // increased allocation size.
1472 // First, do whatever error checking is appropriate here (e.g. whether
1473 // the caller is trying the change size for a directory, etc.).
1474 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
)
1475 try_return(RC
= STATUS_INVALID_PARAMETER
);
1477 Fcb
->NTRequiredFCB
->CommonFCBHeader
.IsFastIoPossible
= UDFIsFastIoPossible(Fcb
);
1479 if ((FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
) &&
1480 (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
) &&
1481 !FlagOn(Irp
->Flags
, IRP_PAGING_IO
)) {
1482 ASSERT( !FlagOn( FileObject
->Flags
, FO_CLEANUP_COMPLETE
) );
1483 // Now initialize the cache map.
1484 MmPrint((" CcInitializeCacheMap()\n"));
1485 CcInitializeCacheMap( FileObject
,
1486 (PCC_FILE_SIZES
)&Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
,
1488 &(UDFGlobalData
.CacheMgrCallBacks
),
1489 Fcb
->NTRequiredFCB
);
1491 CacheMapInitialized
= TRUE
;
1494 // Are we increasing the allocation size?
1495 if(Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
.QuadPart
<
1496 PtrBuffer
->AllocationSize
.QuadPart
) {
1498 // Yes. Do the FSD specific stuff i.e. increase reserved
1500 if(((LONGLONG
)UDFGetFreeSpace(Vcb
) << Vcb
->LBlockSizeBits
) < PtrBuffer
->AllocationSize
.QuadPart
) {
1501 try_return(RC
= STATUS_DISK_FULL
);
1503 // RC = STATUS_SUCCESS;
1504 ModifiedAllocSize
= TRUE
;
1506 } else if(Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
.QuadPart
>
1507 PtrBuffer
->AllocationSize
.QuadPart
) {
1508 // This is the painful part. See if the VMM will allow us to proceed.
1509 // The VMM will deny the request if:
1510 // (a) any image section exists OR
1511 // (b) a data section exists and the size of the user mapped view
1512 // is greater than the new size
1513 // Otherwise, the VMM should allow the request to proceed.
1514 MmPrint((" MmCanFileBeTruncated()\n"));
1515 if(!MmCanFileBeTruncated(&(Fcb
->NTRequiredFCB
->SectionObject
), &(PtrBuffer
->AllocationSize
))) {
1517 try_return(RC
= STATUS_USER_MAPPED_FILE
);
1520 // Perform our directory entry modifications. Release any on-disk
1521 // space we may need to in the process.
1522 ModifiedAllocSize
= TRUE
;
1523 TruncatedFile
= TRUE
;
1526 ASSERT(NT_SUCCESS(RC
));
1527 // This is a good place to check if we have performed a truncate
1528 // operation. If we have perform a truncate (whether we extended
1529 // or reduced file size or even leave it intact), we should update
1530 // file time stamps.
1531 FileObject
->Flags
|= FO_FILE_MODIFIED
;
1533 // Last, but not the lease, we must inform the Cache Manager of file size changes.
1534 if(ModifiedAllocSize
) {
1536 // If we decreased the allocation size to less than the
1537 // current file size, modify the file size value.
1538 // Similarly, if we decreased the value to less than the
1539 // current valid data length, modify that value as well.
1541 AcquiredPagingIo
= UDFAcquireResourceExclusiveWithCheck(&(Fcb
->NTRequiredFCB
->PagingIoResource
));
1542 // Update the FCB Header with the new allocation size.
1544 if(Fcb
->NTRequiredFCB
->CommonFCBHeader
.ValidDataLength
.QuadPart
>
1545 PtrBuffer
->AllocationSize
.QuadPart
) {
1546 // Decrease the valid data length value.
1547 Fcb
->NTRequiredFCB
->CommonFCBHeader
.ValidDataLength
=
1548 PtrBuffer
->AllocationSize
;
1550 if(Fcb
->NTRequiredFCB
->CommonFCBHeader
.FileSize
.QuadPart
>
1551 PtrBuffer
->AllocationSize
.QuadPart
) {
1552 // Decrease the file size value.
1553 Fcb
->NTRequiredFCB
->CommonFCBHeader
.FileSize
=
1554 PtrBuffer
->AllocationSize
;
1555 RC
= UDFResizeFile__(Vcb
, Fcb
->FileInfo
, PtrBuffer
->AllocationSize
.QuadPart
);
1556 // UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, NULL);
1559 Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
= PtrBuffer
->AllocationSize
;
1560 // UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo,
1561 // &(PtrBuffer->AllocationSize.QuadPart));
1563 if(AcquiredPagingIo
) {
1564 UDFReleaseResource(&(Fcb
->NTRequiredFCB
->PagingIoResource
));
1565 AcquiredPagingIo
= FALSE
;
1567 // If the FCB has not had caching initiated, it is still valid
1568 // for us to invoke the NT Cache Manager. It is possible in such
1569 // situations for the call to be no'oped (unless some user has
1570 // mapped in the file)
1572 // NOTE: The invocation to CcSetFileSizes() will quite possibly
1573 // result in a recursive call back into the file system.
1574 // This is because the NT Cache Manager will typically
1575 // perform a flush before telling the VMM to purge pages
1576 // especially when caching has not been initiated on the
1577 // file stream, but the user has mapped the file into
1578 // the process' virtual address space.
1579 MmPrint((" CcSetFileSizes()\n"));
1580 Fcb
->NTRequiredFCB
->AcqFlushCount
++;
1581 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&(Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
));
1582 Fcb
->NTRequiredFCB
->AcqFlushCount
--;
1583 Fcb
->NTRequiredFCB
->NtReqFCBFlags
|= UDF_NTREQ_FCB_MODIFIED
;
1585 // Inform any pending IRPs (notify change directory).
1586 if(UDFIsAStream(Fcb
->FileInfo
)) {
1587 UDFNotifyFullReportChange( Vcb
, Fcb
->FileInfo
,
1588 FILE_NOTIFY_CHANGE_STREAM_SIZE
,
1589 FILE_ACTION_MODIFIED_STREAM
);
1591 UDFNotifyFullReportChange( Vcb
, Fcb
->FileInfo
,
1592 FILE_NOTIFY_CHANGE_SIZE
,
1593 FILE_ACTION_MODIFIED
);
1600 if(AcquiredPagingIo
) {
1601 UDFReleaseResource(&(Fcb
->NTRequiredFCB
->PagingIoResource
));
1602 AcquiredPagingIo
= FALSE
;
1604 if (CacheMapInitialized
) {
1606 MmPrint((" CcUninitializeCacheMap()\n"));
1607 CcUninitializeCacheMap( FileObject
, NULL
, NULL
);
1611 } // end UDFSetAllocationInformation()
1614 Set end of file (resize).
1618 IN PIO_STACK_LOCATION PtrSp
,
1622 IN PFILE_OBJECT FileObject
,
1624 IN PFILE_END_OF_FILE_INFORMATION PtrBuffer
1627 NTSTATUS RC
= STATUS_SUCCESS
;
1628 BOOLEAN TruncatedFile
= FALSE
;
1629 BOOLEAN ModifiedAllocSize
= FALSE
;
1631 PDIR_INDEX_ITEM DirNdx
;
1632 PtrUDFNTRequiredFCB NtReqFcb
= NULL
;
1633 LONGLONG OldFileSize
;
1635 BOOLEAN CacheMapInitialized
= FALSE
;
1636 BOOLEAN AcquiredPagingIo
= FALSE
;
1638 AdPrint(("UDFSetEOF\n"));
1641 // Increasing the allocation size associated with a file stream
1642 // is relatively easy. All we have to do is execute some FSD
1643 // specific code to check whether we have enough space available
1644 // (and if the FSD supports user/volume quotas, whether the user
1645 // is not exceeding quota), and then increase the file size in the
1646 // corresponding on-disk and in-memory structures.
1647 // Then, all we should do is inform the Cache Manager about the
1648 // increased allocation size.
1650 // First, do whatever error checking is appropriate here (e.g. whether
1651 // the caller is trying the change size for a directory, etc.).
1652 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
)
1653 try_return(RC
= STATUS_INVALID_PARAMETER
);
1655 NtReqFcb
= Fcb
->NTRequiredFCB
;
1657 if((Fcb
->FCBFlags
& UDF_FCB_DELETED
) ||
1658 (NtReqFcb
->NtReqFCBFlags
& UDF_NTREQ_FCB_DELETED
)) {
1660 if(UDFGetFileLinkCount(Fcb
->FileInfo
) < 1) {
1662 try_return(RC
= STATUS_SUCCESS
);
1665 try_return(RC
= STATUS_SUCCESS
);
1668 NtReqFcb
->CommonFCBHeader
.IsFastIoPossible
= UDFIsFastIoPossible(Fcb
);
1670 if ((FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
) &&
1671 (FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
) &&
1672 !(Irp
->Flags
& IRP_PAGING_IO
)) {
1673 ASSERT( !FlagOn( FileObject
->Flags
, FO_CLEANUP_COMPLETE
) );
1674 // Now initialize the cache map.
1675 MmPrint((" CcInitializeCacheMap()\n"));
1676 CcInitializeCacheMap( FileObject
,
1677 (PCC_FILE_SIZES
)&Fcb
->NTRequiredFCB
->CommonFCBHeader
.AllocationSize
,
1679 &(UDFGlobalData
.CacheMgrCallBacks
),
1680 Fcb
->NTRequiredFCB
);
1682 CacheMapInitialized
= TRUE
;
1685 AcquiredPagingIo
= UDFAcquireResourceExclusiveWithCheck(&(Fcb
->NTRequiredFCB
->PagingIoResource
));
1686 // Do a special case here for the lazy write of file sizes.
1687 if(PtrSp
->Parameters
.SetFile
.AdvanceOnly
) {
1688 // Never have the dirent filesize larger than the fcb filesize
1689 PtrBuffer
->EndOfFile
.QuadPart
=
1690 min(PtrBuffer
->EndOfFile
.QuadPart
,
1691 NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
);
1692 // Only advance the file size, never reduce it with this call
1693 RC
= STATUS_SUCCESS
;
1694 if(UDFGetFileSizeFromDirNdx(Vcb
, Fcb
->FileInfo
) >=
1695 PtrBuffer
->EndOfFile
.QuadPart
)
1698 UDFSetFileSizeInDirNdx(Vcb
, Fcb
->FileInfo
, &(PtrBuffer
->EndOfFile
.QuadPart
));
1699 goto notify_size_changes
;
1702 // !!! IMPORTANT !!!
1704 // We can get here after all Handles to the file are closed
1705 // To prevent allocation size incoherency we should
1706 // reference FileInfo _before_ call to UDFResizeFile__()
1707 // and use UDFCloseFile__() _after_ that
1709 // Are we increasing the allocation size?
1710 OldFileSize
= NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
;
1711 if(OldFileSize
< PtrBuffer
->EndOfFile
.QuadPart
) {
1713 // Yes. Do the FSD specific stuff i.e. increase reserved
1715 if (FileObject
->PrivateCacheMap
)
1718 // reference file to pretend that it is opened
1719 UDFReferenceFile__(Fcb
->FileInfo
);
1720 UDFInterlockedIncrement((PLONG
)&(Fcb
->ReferenceCount
));
1721 UDFInterlockedIncrement((PLONG
)&(NtReqFcb
->CommonRefCount
));
1722 // perform resize operation
1723 RC
= UDFResizeFile__(Vcb
, Fcb
->FileInfo
, PtrBuffer
->EndOfFile
.QuadPart
);
1725 UDFCloseFile__(Vcb
, Fcb
->FileInfo
);
1726 UDFInterlockedDecrement((PLONG
)&(Fcb
->ReferenceCount
));
1727 UDFInterlockedDecrement((PLONG
)&(NtReqFcb
->CommonRefCount
));
1728 // update values in NtReqFcb
1729 NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
=
1730 // NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart =
1731 PtrBuffer
->EndOfFile
.QuadPart
;
1732 ModifiedAllocSize
= TRUE
;
1734 } else if(NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
>
1735 PtrBuffer
->EndOfFile
.QuadPart
) {
1737 // This is the painful part. See if the VMM will allow us to proceed.
1738 // The VMM will deny the request if:
1739 // (a) any image section exists OR
1740 // (b) a data section exists and the size of the user mapped view
1741 // is greater than the new size
1742 // Otherwise, the VMM should allow the request to proceed.
1744 MmPrint((" MmCanFileBeTruncated()\n"));
1745 if(!MmCanFileBeTruncated(&(NtReqFcb
->SectionObject
), &(PtrBuffer
->EndOfFile
))) {
1747 try_return(RC
= STATUS_USER_MAPPED_FILE
);
1750 // Perform directory entry modifications. Release any on-disk
1751 // space we may need to in the process.
1752 UDFReferenceFile__(Fcb
->FileInfo
);
1753 UDFInterlockedIncrement((PLONG
)&(Fcb
->ReferenceCount
));
1754 UDFInterlockedIncrement((PLONG
)&(NtReqFcb
->CommonRefCount
));
1755 // perform resize operation
1756 RC
= UDFResizeFile__(Vcb
, Fcb
->FileInfo
, PtrBuffer
->EndOfFile
.QuadPart
);
1758 UDFCloseFile__(Vcb
, Fcb
->FileInfo
);
1759 UDFInterlockedDecrement((PLONG
)&(Fcb
->ReferenceCount
));
1760 UDFInterlockedDecrement((PLONG
)&(NtReqFcb
->CommonRefCount
));
1762 ModifiedAllocSize
= TRUE
;
1763 TruncatedFile
= TRUE
;
1766 // This is a good place to check if we have performed a truncate
1767 // operation. If we have perform a truncate (whether we extended
1768 // or reduced file size), we should update file time stamps.
1770 // Last, but not the least, we must inform the Cache Manager of file size changes.
1771 if(ModifiedAllocSize
&& NT_SUCCESS(RC
)) {
1772 // If we decreased the allocation size to less than the
1773 // current file size, modify the file size value.
1774 // Similarly, if we decreased the value to less than the
1775 // current valid data length, modify that value as well.
1777 if(NtReqFcb
->CommonFCBHeader
.ValidDataLength
.QuadPart
>
1778 PtrBuffer
->EndOfFile
.QuadPart
) {
1779 // Decrease the valid data length value.
1780 NtReqFcb
->CommonFCBHeader
.ValidDataLength
=
1781 PtrBuffer
->EndOfFile
;
1783 if(NtReqFcb
->CommonFCBHeader
.FileSize
.QuadPart
>
1784 PtrBuffer
->EndOfFile
.QuadPart
) {
1785 // Decrease the file size value.
1786 NtReqFcb
->CommonFCBHeader
.FileSize
=
1787 PtrBuffer
->EndOfFile
;
1789 UDFSetFileSizeInDirNdx(Vcb
, Fcb
->FileInfo
, NULL
);
1791 // Update the FCB Header with the new allocation size.
1792 // NT expects AllocationSize to be decreased on Close only
1793 NtReqFcb
->CommonFCBHeader
.AllocationSize
.QuadPart
=
1794 PtrBuffer
->EndOfFile
.QuadPart
;
1795 // UDFSysGetAllocSize(Vcb, UDFGetFileSize(Fcb->FileInfo));
1796 UDFSetFileSizeInDirNdx(Vcb
, Fcb
->FileInfo
, &(PtrBuffer
->EndOfFile
.QuadPart
));
1799 FileObject
->Flags
|= FO_FILE_MODIFIED
;
1800 // UDFGetFileAllocationSize(Vcb, Fcb->FileInfo);
1802 // If the FCB has not had caching initiated, it is still valid
1803 // for us to invoke the NT Cache Manager. It is possible in such
1804 // situations for the call to be no'oped (unless some user has
1805 // mapped in the file)
1808 if(Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_ARCH_BIT
) {
1809 DirNdx
= UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb
->FileInfo
), Fcb
->FileInfo
->Index
);
1810 Ccb
->CCBFlags
&= ~UDF_CCB_ATTRIBUTES_SET
;
1811 Attr
= UDFAttributesToNT(DirNdx
, Fcb
->FileInfo
->Dloc
->FileEntry
);
1812 if(!(Attr
& FILE_ATTRIBUTE_ARCHIVE
))
1813 UDFAttributesToUDF(DirNdx
, Fcb
->FileInfo
->Dloc
->FileEntry
, Attr
| FILE_ATTRIBUTE_ARCHIVE
);
1816 // NOTE: The invocation to CcSetFileSizes() will quite possibly
1817 // result in a recursive call back into the file system.
1818 // This is because the NT Cache Manager will typically
1819 // perform a flush before telling the VMM to purge pages
1820 // especially when caching has not been initiated on the
1821 // file stream, but the user has mapped the file into
1822 // the process' virtual address space.
1823 MmPrint((" CcSetFileSizes(), thrd:%8.8x\n",PsGetCurrentThread()));
1824 Fcb
->NTRequiredFCB
->AcqFlushCount
++;
1825 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&(NtReqFcb
->CommonFCBHeader
.AllocationSize
));
1826 Fcb
->NTRequiredFCB
->AcqFlushCount
--;
1828 UDFZeroDataEx(NtReqFcb,
1830 PtrBuffer->EndOfFile.QuadPart - OldFileSize,
1831 TRUE/*CanWait, Vcb, FileObject);
1833 Fcb
->NTRequiredFCB
->NtReqFCBFlags
|= UDF_NTREQ_FCB_MODIFIED
;
1835 notify_size_changes
:
1836 if(AcquiredPagingIo
) {
1837 UDFReleaseResource(&(Fcb
->NTRequiredFCB
->PagingIoResource
));
1838 AcquiredPagingIo
= FALSE
;
1841 // Inform any pending IRPs (notify change directory).
1842 if(UDFIsAStream(Fcb
->FileInfo
)) {
1843 UDFNotifyFullReportChange( Vcb
, Fcb
->FileInfo
,
1844 FILE_NOTIFY_CHANGE_STREAM_SIZE
,
1845 FILE_ACTION_MODIFIED_STREAM
);
1847 UDFNotifyFullReportChange( Vcb
, Fcb
->FileInfo
,
1848 FILE_NOTIFY_CHANGE_SIZE
,
1849 FILE_ACTION_MODIFIED
);
1856 if(AcquiredPagingIo
) {
1857 UDFReleaseResource(&(Fcb
->NTRequiredFCB
->PagingIoResource
));
1858 AcquiredPagingIo
= FALSE
;
1860 if (CacheMapInitialized
) {
1862 MmPrint((" CcUninitializeCacheMap()\n"));
1863 CcUninitializeCacheMap( FileObject
, NULL
, NULL
);
1867 } // end UDFSetEOF()
1870 UDFPrepareForRenameMoveLink(
1872 PBOOLEAN AcquiredVcb
,
1873 PBOOLEAN AcquiredVcbEx
,
1875 PBOOLEAN AcquiredDir1
,
1876 PBOOLEAN AcquiredFcb1
,
1878 PUDF_FILE_INFO File1
,
1879 PUDF_FILE_INFO Dir1
,
1880 PUDF_FILE_INFO Dir2
,
1884 // convert acquisition to Exclusive
1885 // this will prevent us from the following situation:
1886 // There is a pair of objects among input dirs &
1887 // one of them is a parent of another. Sequential resource
1888 // acquisition may lead to deadlock due to concurrent
1889 // CleanUpFcbChain() or UDFCloseFileInfoChain()
1890 UDFInterlockedIncrement((PLONG
)&(Vcb
->VCBOpenCount
));
1891 UDFReleaseResource(&(Vcb
->VCBResource
));
1892 (*AcquiredVcb
) = FALSE
;
1894 // At first, make system to issue last Close request
1895 // for our Source & Target ...
1896 // we needn't flush/purge for Source on HLink
1897 UDFRemoveFromSystemDelayedQueue(Dir2
->Fcb
);
1898 if(!HardLink
&& (Dir2
!= Dir1
))
1899 UDFRemoveFromSystemDelayedQueue(File1
->Fcb
);
1901 #ifdef UDF_DELAYED_CLOSE
1903 // Do actual close for all "delayed close" calls
1905 // ... and now remove the rest from our queue
1907 UDFCloseAllDelayedInDir(Vcb
, Dir1
);
1909 UDFCloseAllDelayedInDir(Vcb
, Dir2
);
1911 UDFCloseAllDelayedInDir(Vcb
, Dir2
);
1914 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
1916 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCount
));
1917 return (STATUS_DRIVER_INTERNAL_ERROR
);
1919 #endif //UDF_DELAYED_CLOSE
1921 (*SingleDir
) = ((Dir1
== Dir2
) && (Dir1
->Fcb
));
1924 (UDFGetFileLinkCount(File1
) != 1)) {
1925 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
1926 (*AcquiredVcb
) = TRUE
;
1927 (*AcquiredVcbEx
) = TRUE
;
1928 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCount
));
1930 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
1931 (*AcquiredVcb
) = TRUE
;
1932 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCount
));
1934 UDF_CHECK_PAGING_IO_RESOURCE(Dir1
->Fcb
->NTRequiredFCB
);
1935 UDFAcquireResourceExclusive(&(Dir1
->Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
1936 (*AcquiredDir1
) = TRUE
;
1938 UDF_CHECK_PAGING_IO_RESOURCE(File1
->Fcb
->NTRequiredFCB
);
1939 UDFAcquireResourceExclusive(&(File1
->Fcb
->NTRequiredFCB
->MainResource
),TRUE
);
1940 (*AcquiredFcb1
) = TRUE
;
1942 return STATUS_SUCCESS
;
1943 } // end UDFPrepareForRenameMoveLink()
1950 IN PIO_STACK_LOCATION PtrSp
,
1953 IN PFILE_OBJECT FileObject1
, // Source File
1954 IN PFILE_RENAME_INFORMATION PtrBuffer
1958 PFILE_OBJECT DirObject1
= FileObject1
->RelatedFileObject
;
1960 PFILE_OBJECT DirObject2
= PtrSp
->Parameters
.SetFile
.FileObject
;
1962 BOOLEAN Replace
= PtrSp
->Parameters
.SetFile
.ReplaceIfExists
&&
1963 PtrBuffer
->ReplaceIfExists
;
1965 PVCB Vcb
= Fcb1
->Vcb
;
1968 BOOLEAN AcquiredVcb
= TRUE
;
1969 BOOLEAN AcquiredVcbEx
= FALSE
;
1970 BOOLEAN AcquiredDir1
= FALSE
;
1971 BOOLEAN AcquiredFcb1
= FALSE
;
1972 BOOLEAN SingleDir
= TRUE
;
1975 PUDF_FILE_INFO File1
;
1976 PUDF_FILE_INFO Dir1
;
1977 PUDF_FILE_INFO Dir2
;
1978 PUDF_FILE_INFO NextFileInfo
, fi
;
1980 UNICODE_STRING NewName
;
1981 UNICODE_STRING LocalPath
;
1982 PtrUDFCCB CurCcb
= NULL
;
1986 ULONG FileInfoRefCount
;
1988 PDIR_INDEX_ITEM DirNdx
;
1990 AdPrint(("UDFRename %8.8x\n", DirObject2
));
1992 LocalPath
.Buffer
= NULL
;
1995 // do we try to rename Volume ?
1996 #ifdef UDF_ALLOW_RENAME_MOVE
1997 if(!(File1
= Fcb1
->FileInfo
))
1998 #endif //UDF_ALLOW_RENAME_MOVE
1999 try_return (RC
= STATUS_ACCESS_DENIED
);
2001 // do we try to rename RootDir ?
2002 if(!(Dir1
= File1
->ParentFile
))
2003 try_return (RC
= STATUS_ACCESS_DENIED
);
2005 // do we try to rename to RootDir or Volume ?
2007 Dir2
= File1
->ParentFile
;
2008 DirObject2
= DirObject1
;
2010 if(DirObject2
->FsContext2
&&
2011 (Fcb2
= ((PtrUDFCCB
)(DirObject2
->FsContext2
))->Fcb
)) {
2012 Dir2
= ((PtrUDFCCB
)(DirObject2
->FsContext2
))->Fcb
->FileInfo
;
2014 try_return (RC
= STATUS_INVALID_PARAMETER
);
2016 // invalid destination ?
2017 if(!Dir2
) try_return (RC
= STATUS_ACCESS_DENIED
);
2019 // Stream can't be a Dir or have StreamDir
2020 if(UDFIsAStreamDir(Dir2
)) {
2021 #ifdef UDF_ENABLE_SECURITY
2022 if(UDFIsADirectory(File1
)) {
2023 try_return (RC
= STATUS_ACCESS_DENIED
);
2025 // We should check whether File1 has only Internal
2026 // (or Deleted) streams. In this case SDir should be
2027 // removed (in UDFRenameMoveFile__()). Otherwise
2028 // return STATUS_ACCESS_DENIED
2029 if(UDFHasAStreamDir(File1
)) {
2030 KdPrint(("TODO: We should remove Streams from source file\n"));
2031 try_return (RC
= STATUS_ACCESS_DENIED
);
2033 #else //UDF_ENABLE_SECURITY
2034 if(UDFIsADirectory(File1
) ||
2035 UDFHasAStreamDir(File1
)) {
2036 try_return (RC
= STATUS_ACCESS_DENIED
);
2038 #endif //UDF_ENABLE_SECURITY
2041 RC
= UDFPrepareForRenameMoveLink(Vcb
, &AcquiredVcb
, &AcquiredVcbEx
,
2043 &AcquiredDir1
, &AcquiredFcb1
,
2046 FALSE
); // it is Rename operation
2050 // check if the source file is in use
2051 if(Fcb1
->OpenHandleCount
> 1)
2052 try_return (RC
= STATUS_ACCESS_DENIED
);
2053 ASSERT(Fcb1
->OpenHandleCount
);
2054 ASSERT(!Fcb1
->IrpContextLite
);
2055 if(Fcb1
->IrpContextLite
) {
2056 try_return (RC
= STATUS_ACCESS_DENIED
);
2058 // Check if we have parallel/pending Close threads
2059 if(Fcb1
->CcbCount
&& !SingleDir
) {
2060 // if this is the 1st attempt, we'll try to
2061 // synchronize with Close requests
2062 // otherwise fail request
2063 RC
= STATUS_ACCESS_DENIED
;
2065 if(Fcb1
->FCBFlags
& UDF_FCB_POSTED_RENAME
) {
2066 Fcb1
->FCBFlags
&= ~UDF_FCB_POSTED_RENAME
;
2069 Fcb1
->FCBFlags
|= UDF_FCB_POSTED_RENAME
;
2070 try_return (RC
= STATUS_PENDING
);
2074 // Make sure the name is of legal length.
2075 if(PtrBuffer
->FileNameLength
> UDF_NAME_LEN
*sizeof(WCHAR
)) {
2076 try_return(RC
= STATUS_OBJECT_NAME_INVALID
);
2078 NewName
.Length
= NewName
.MaximumLength
= (USHORT
)(PtrBuffer
->FileNameLength
);
2079 NewName
.Buffer
= (PWCHAR
)&(PtrBuffer
->FileName
);
2081 // This name is by definition legal.
2082 NewName
= *((PUNICODE_STRING
)&DirObject2
->FileName
);
2085 ic
= (Ccb1
->CCBFlags
& UDF_CCB_CASE_SENSETIVE
) ? FALSE
: TRUE
;
2087 AdPrint((" %ws ->\n %ws\n",
2088 Fcb1
->FCBName
->ObjectName
.Buffer
,
2091 if(UDFIsDirOpened__(File1
)) {
2092 // We can't rename file because of unclean references.
2093 // UDF_INFO package can safely do it, but NT side cannot.
2094 // In this case NT requires STATUS_OBJECT_NAME_COLLISION
2095 // rather than STATUS_ACCESS_DENIED
2096 if(NT_SUCCESS(UDFFindFile__(Vcb
, ic
, &NewName
, Dir2
)))
2097 try_return(RC
= STATUS_OBJECT_NAME_COLLISION
);
2098 try_return (RC
= STATUS_ACCESS_DENIED
);
2100 // Last check before Moving.
2101 // We can't move across Dir referenced (even internally) file
2103 RC
= UDFDoesOSAllowFileToBeMoved__(File1
);
2104 if(!NT_SUCCESS(RC
)) {
2110 ASSERT_REF(Fcb1
->ReferenceCount
>= File1
->RefCount
);
2111 ASSERT_REF(Dir1
->Fcb
->ReferenceCount
>= Dir1
->RefCount
);
2112 ASSERT_REF(Dir2
->Fcb
->ReferenceCount
>= Dir2
->RefCount
);
2114 RC
= UDFRenameMoveFile__(Vcb
, ic
, &Replace
, &NewName
, Dir1
, Dir2
, File1
);
2119 ASSERT(UDFDirIndex(File1
->ParentFile
->Dloc
->DirIndex
, File1
->Index
)->FileInfo
== File1
);
2121 RC
= MyCloneUnicodeString(&LocalPath
, (Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ?
2122 &UDFGlobalData
.UnicodeStrRoot
:
2123 &(Dir2
->Fcb
->FCBName
->ObjectName
) );
2124 if(!NT_SUCCESS(RC
)) try_return (RC
);
2125 // RC = MyAppendUnicodeStringToString(&LocalPath, (Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? &(UDFGlobalData.UnicodeStrRoot) : &(Dir2->Fcb->FCBName->ObjectName));
2126 // if(!NT_SUCCESS(RC)) try_return (RC);
2127 if(Dir2
->ParentFile
) {
2128 RC
= MyAppendUnicodeToString(&LocalPath
, L
"\\");
2129 if(!NT_SUCCESS(RC
)) try_return (RC
);
2131 RC
= MyAppendUnicodeStringToStringTag(&LocalPath
, &NewName
, MEM_USREN_TAG
);
2132 if(!NT_SUCCESS(RC
)) try_return (RC
);
2135 DirNdx
= UDFDirIndex(File1
->ParentFile
->Dloc
->DirIndex
, File1
->Index
);
2136 if(Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_ARCH_BIT
) {
2137 Attr
= UDFAttributesToNT(DirNdx
, File1
->Dloc
->FileEntry
);
2138 if(!(Attr
& FILE_ATTRIBUTE_ARCHIVE
))
2139 UDFAttributesToUDF(DirNdx
, File1
->Dloc
->FileEntry
, Attr
| FILE_ATTRIBUTE_ARCHIVE
);
2141 // Update Parent Objects (mark 'em as modified)
2142 if(Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_DIR_WRITE
) {
2144 DirObject1
->Flags
|= FO_FILE_MODIFIED
;
2146 DirObject2
->Flags
|= FO_FILE_MODIFIED
;
2148 DirObject2
->Flags
|= FO_FILE_SIZE_CHANGED
;
2152 if(SingleDir
&& !Replace
) {
2153 UDFNotifyFullReportChange( Vcb
, File1
,
2154 UDFIsADirectory(File1
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
2155 FILE_ACTION_RENAMED_OLD_NAME
);
2156 /* UDFNotifyFullReportChange( Vcb, File2,
2157 UDFIsADirectory(File2) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
2158 FILE_ACTION_RENAMED_NEW_NAME );*/
2159 FsRtlNotifyFullReportChange( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
2160 (PSTRING
)&LocalPath
,
2161 ((Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ? 0 : Dir2
->Fcb
->FCBName
->ObjectName
.Length
) + sizeof(WCHAR
),
2163 UDFIsADirectory(File1
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
2164 FILE_ACTION_RENAMED_NEW_NAME
,
2167 UDFNotifyFullReportChange( Vcb
, File1
,
2168 UDFIsADirectory(File1
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
2169 FILE_ACTION_REMOVED
);
2171 /* UDFNotifyFullReportChange( Vcb, File2,
2172 FILE_NOTIFY_CHANGE_ATTRIBUTES |
2173 FILE_NOTIFY_CHANGE_SIZE |
2174 FILE_NOTIFY_CHANGE_LAST_WRITE |
2175 FILE_NOTIFY_CHANGE_LAST_ACCESS |
2176 FILE_NOTIFY_CHANGE_CREATION |
2177 FILE_NOTIFY_CHANGE_EA,
2178 FILE_ACTION_MODIFIED );*/
2179 FsRtlNotifyFullReportChange( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
2180 (PSTRING
)&LocalPath
,
2181 ((Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ?
2182 0 : Dir2
->Fcb
->FCBName
->ObjectName
.Length
) + sizeof(WCHAR
),
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
,
2193 /* UDFNotifyFullReportChange( Vcb, File2,
2194 UDFIsADirectory(File2) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
2195 FILE_ACTION_ADDED );*/
2196 FsRtlNotifyFullReportChange( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
2197 (PSTRING
)&LocalPath
,
2198 ((Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ?
2199 0 : Dir2
->Fcb
->FCBName
->ObjectName
.Length
) + sizeof(WCHAR
),
2201 UDFIsADirectory(File1
) ?
2202 FILE_NOTIFY_CHANGE_DIR_NAME
:
2203 FILE_NOTIFY_CHANGE_FILE_NAME
,
2209 // this will prevent structutre release before call to
2210 // UDFCleanUpFcbChain()
2211 UDFInterlockedIncrement((PLONG
)&(Dir1
->Fcb
->ReferenceCount
));
2212 UDFInterlockedIncrement((PLONG
)&(Dir1
->Fcb
->NTRequiredFCB
->CommonRefCount
));
2213 ASSERT_REF(Dir1
->Fcb
->ReferenceCount
>= Dir1
->RefCount
);
2215 // Look through Ccb list & decrement OpenHandleCounter(s)
2218 UDFAcquireResourceExclusive(&(Fcb1
->CcbListResource
),TRUE
);
2219 Link
= Fcb1
->NextCCB
.Flink
;
2221 FileInfoRefCount
= 0;
2222 ASSERT(Link
!= &(Fcb1
->NextCCB
));
2223 while (Link
!= &(Fcb1
->NextCCB
)) {
2224 NextFileInfo
= Dir1
;
2225 CurCcb
= CONTAINING_RECORD(Link
, UDFCCB
, NextCCB
);
2226 ASSERT(CurCcb
->TreeLength
);
2227 i
= (CurCcb
->TreeLength
) ? (CurCcb
->TreeLength
- 1) : 0;
2229 UseClose
= (CurCcb
->CCBFlags
& UDF_CCB_CLEANED
) ? FALSE
: TRUE
;
2231 AdPrint((" Ccb:%x:%s:i:%x\n", CurCcb
, UseClose
? "Close" : "",i
));
2232 // cleanup old parent chain
2233 for(; i
&& NextFileInfo
; i
--) {
2234 // remember parent file now
2235 // it will prevent us from data losses
2236 // due to eventual structure release
2237 fi
= NextFileInfo
->ParentFile
;
2239 ASSERT_REF(NextFileInfo
->Fcb
->ReferenceCount
>= NextFileInfo
->RefCount
);
2240 UDFCloseFile__(Vcb
, NextFileInfo
);
2242 ASSERT_REF(NextFileInfo
->Fcb
->ReferenceCount
> NextFileInfo
->RefCount
);
2243 ASSERT_REF(NextFileInfo
->Fcb
->ReferenceCount
);
2244 ASSERT_REF(NextFileInfo
->Fcb
->NTRequiredFCB
->CommonRefCount
);
2245 UDFInterlockedDecrement((PLONG
)&(NextFileInfo
->Fcb
->ReferenceCount
));
2246 UDFInterlockedDecrement((PLONG
)&(NextFileInfo
->Fcb
->NTRequiredFCB
->CommonRefCount
));
2247 ASSERT_REF(NextFileInfo
->Fcb
->ReferenceCount
>= NextFileInfo
->RefCount
);
2251 if(CurCcb
->TreeLength
> 1) {
2255 CurCcb
->TreeLength
= 2;
2262 UDFReleaseResource(&(Fcb1
->CcbListResource
));
2264 ASSERT_REF(DirRefCount
>= FileInfoRefCount
);
2265 // update counters & pointers
2266 Fcb1
->ParentFcb
= Dir2
->Fcb
;
2267 // move references to Dir2
2268 UDFInterlockedExchangeAdd((PLONG
)&(Dir2
->Fcb
->ReferenceCount
), DirRefCount
);
2269 UDFInterlockedExchangeAdd((PLONG
)&(Dir2
->Fcb
->NTRequiredFCB
->CommonRefCount
), DirRefCount
);
2270 ASSERT_REF(Dir2
->Fcb
->ReferenceCount
> Dir2
->RefCount
);
2271 UDFReferenceFileEx__(Dir2
,FileInfoRefCount
);
2272 ASSERT_REF(Dir2
->Fcb
->ReferenceCount
>= Dir2
->RefCount
);
2274 ASSERT_REF(Dir2
->Fcb
->ReferenceCount
>= Dir2
->RefCount
);
2275 ASSERT_REF(Dir2
->RefCount
);
2277 ASSERT_REF(Dir1
->Fcb
->ReferenceCount
>= Dir1
->RefCount
);
2278 // Modify name in Fcb1
2280 if(Fcb1
->FCBName
->ObjectName
.Buffer
) {
2281 MyFreePool__(Fcb1
->FCBName
->ObjectName
.Buffer
);
2283 UDFReleaseObjectName(Fcb1
->FCBName
);
2285 Fcb1
->FCBName
= UDFAllocateObjectName();
2286 if(!(Fcb1
->FCBName
)) {
2289 // UDFCleanUpFcbChain()...
2291 UDF_CHECK_PAGING_IO_RESOURCE(Fcb1
->NTRequiredFCB
);
2292 UDFReleaseResource(&(Fcb1
->NTRequiredFCB
->MainResource
));
2293 AcquiredDir1
= FALSE
;
2296 UDF_CHECK_PAGING_IO_RESOURCE(Dir1
->Fcb
->NTRequiredFCB
);
2297 UDFReleaseResource(&(Dir1
->Fcb
->NTRequiredFCB
->MainResource
));
2298 AcquiredDir1
= FALSE
;
2300 UDFCleanUpFcbChain(Vcb
, Dir1
, 1, TRUE
);
2301 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
2304 RC
= MyCloneUnicodeString(&(Fcb1
->FCBName
->ObjectName
), &(Fcb2
->FCBName
->ObjectName
));
2307 /* RC = MyAppendUnicodeStringToString(&(Fcb1->FCBName->ObjectName), &(Fcb2->FCBName->ObjectName));
2310 // if Dir2 is a RootDir, we shoud not append '\\' because
2311 // uit will be the 2nd '\\' character (RootDir's name is also '\\')
2312 if(Dir2
->ParentFile
) {
2313 RC
= MyAppendUnicodeToString(&(Fcb1
->FCBName
->ObjectName
), L
"\\");
2317 RC
= MyAppendUnicodeStringToStringTag(&(Fcb1
->FCBName
->ObjectName
), &NewName
, MEM_USREN2_TAG
);
2321 ASSERT_REF(Fcb1
->ReferenceCount
>= File1
->RefCount
);
2322 ASSERT_REF(Dir1
->Fcb
->ReferenceCount
>= Dir1
->RefCount
);
2323 ASSERT_REF(Dir2
->Fcb
->ReferenceCount
>= Dir2
->RefCount
);
2325 RC
= STATUS_SUCCESS
;
2332 UDF_CHECK_PAGING_IO_RESOURCE(Fcb1
->NTRequiredFCB
);
2333 UDFReleaseResource(&(Fcb1
->NTRequiredFCB
->MainResource
));
2336 UDF_CHECK_PAGING_IO_RESOURCE(Dir1
->Fcb
->NTRequiredFCB
);
2337 UDFReleaseResource(&(Dir1
->Fcb
->NTRequiredFCB
->MainResource
));
2339 // perform protected structure release
2340 if(NT_SUCCESS(RC
) &&
2341 (RC
!= STATUS_PENDING
)) {
2342 ASSERT(AcquiredVcb
);
2343 UDFCleanUpFcbChain(Vcb
, Dir1
, 1, TRUE
);
2344 ASSERT_REF(Fcb1
->ReferenceCount
>= File1
->RefCount
);
2345 ASSERT_REF(Dir2
->Fcb
->ReferenceCount
>= Dir2
->RefCount
);
2350 UDFConvertExclusiveToSharedLite(&(Vcb
->VCBResource
));
2352 // caller assumes Vcb to be acquired shared
2354 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
2357 if(LocalPath
.Buffer
) {
2358 MyFreePool__(LocalPath
.Buffer
);
2363 } // end UDFRename()
2365 #endif //UDF_READ_ONLY_BUILD
2373 if(!Vcb
->FileIdCache
) return (-1);
2374 for(ULONG i
=0; i
<Vcb
->FileIdCount
; i
++) {
2375 if(Vcb
->FileIdCache
[i
].Id
== Id
) return i
;
2378 } // end UDFFindFileId()
2386 if(!Vcb
->FileIdCache
) {
2387 if(!(Vcb
->FileIdCache
= (PUDFFileIDCacheItem
)MyAllocatePool__(NonPagedPool
, sizeof(UDFFileIDCacheItem
)*FILE_ID_CACHE_GRANULARITY
)))
2389 RtlZeroMemory(Vcb
->FileIdCache
, FILE_ID_CACHE_GRANULARITY
*sizeof(UDFFileIDCacheItem
));
2390 Vcb
->FileIdCount
= FILE_ID_CACHE_GRANULARITY
;
2392 for(ULONG i
=0; i
<Vcb
->FileIdCount
; i
++) {
2393 if(!Vcb
->FileIdCache
[i
].FullName
.Buffer
) return i
;
2395 if(!MyReallocPool__((PCHAR
)(Vcb
->FileIdCache
), Vcb
->FileIdCount
*sizeof(UDFFileIDCacheItem
),
2396 (PCHAR
*)&(Vcb
->FileIdCache
), (Vcb
->FileIdCount
+FILE_ID_CACHE_GRANULARITY
)*sizeof(UDFFileIDCacheItem
))) {
2399 RtlZeroMemory(&(Vcb
->FileIdCache
[Vcb
->FileIdCount
]), FILE_ID_CACHE_GRANULARITY
*sizeof(UDFFileIDCacheItem
));
2400 Vcb
->FileIdCount
+= FILE_ID_CACHE_GRANULARITY
;
2401 return (Vcb
->FileIdCount
- FILE_ID_CACHE_GRANULARITY
);
2402 } // end UDFFindFreeFileId()
2408 IN PUDF_FILE_INFO fi
,
2413 NTSTATUS RC
= STATUS_SUCCESS
;
2415 if((i
= UDFFindFileId(Vcb
, Id
)) == (-1)) {
2416 if((i
= UDFFindFreeFileId(Vcb
, Id
)) == (-1)) return STATUS_INSUFFICIENT_RESOURCES
;
2418 return STATUS_SUCCESS
;
2420 Vcb
->FileIdCache
[i
].Id
= Id
;
2421 Vcb
->FileIdCache
[i
].CaseSens
= (Ccb
->CCBFlags
& UDF_CCB_CASE_SENSETIVE
) ? TRUE
: FALSE
;
2422 RC
= MyCloneUnicodeString(&(Vcb
->FileIdCache
[i
].FullName
), &(Ccb
->Fcb
->FCBName
->ObjectName
));
2423 /* if(NT_SUCCESS(RC)) {
2424 RC = MyAppendUnicodeStringToStringTag(&(Vcb->FileIdCache[i].FullName), &(Ccb->Fcb->FCBName->ObjectName), MEM_USFIDC_TAG);
2427 } // end UDFStoreFileId()
2437 if((i
= UDFFindFileId(Vcb
, Id
)) == (-1)) return STATUS_INVALID_PARAMETER
;
2438 MyFreePool__(Vcb
->FileIdCache
[i
].FullName
.Buffer
);
2439 RtlZeroMemory(&(Vcb
->FileIdCache
[i
]), sizeof(UDFFileIDCacheItem
));
2440 return STATUS_SUCCESS
;
2441 } // end UDFRemoveFileId()
2444 UDFReleaseFileIdCache(
2448 if(!Vcb
->FileIdCache
) return;
2449 for(ULONG i
=0; i
<Vcb
->FileIdCount
; i
++) {
2450 if(Vcb
->FileIdCache
[i
].FullName
.Buffer
) {
2451 MyFreePool__(Vcb
->FileIdCache
[i
].FullName
.Buffer
);
2454 MyFreePool__(Vcb
->FileIdCache
);
2455 Vcb
->FileIdCache
= NULL
;
2456 Vcb
->FileIdCount
= 0;
2457 } // end UDFReleaseFileIdCache()
2460 UDFGetOpenParamsByFileId(
2463 OUT PUNICODE_STRING
* FName
,
2464 OUT BOOLEAN
* CaseSens
2469 if((i
= UDFFindFileId(Vcb
, Id
)) == (-1)) return STATUS_NOT_FOUND
;
2470 (*FName
) = &(Vcb
->FileIdCache
[i
].FullName
);
2471 (*CaseSens
) = !(Vcb
->FileIdCache
[i
].CaseSens
);
2472 return STATUS_SUCCESS
;
2473 } // end UDFGetOpenParamsByFileId()
2475 #ifndef UDF_READ_ONLY_BUILD
2477 #ifdef UDF_ALLOW_HARD_LINKS
2479 create hard link for the file
2483 IN PIO_STACK_LOCATION PtrSp
,
2486 IN PFILE_OBJECT FileObject1
, // Source File
2487 IN PFILE_LINK_INFORMATION PtrBuffer
2491 PFILE_OBJECT DirObject2
= PtrSp
->Parameters
.SetFile
.FileObject
;
2493 BOOLEAN Replace
= PtrSp
->Parameters
.SetFile
.ReplaceIfExists
&&
2494 PtrBuffer
->ReplaceIfExists
;
2496 PVCB Vcb
= Fcb1
->Vcb
;
2499 BOOLEAN AcquiredVcb
= TRUE
;
2500 BOOLEAN AcquiredVcbEx
= FALSE
;
2501 BOOLEAN AcquiredDir1
= FALSE
;
2502 BOOLEAN AcquiredFcb1
= FALSE
;
2503 BOOLEAN SingleDir
= TRUE
;
2505 PUDF_FILE_INFO File1
;
2506 PUDF_FILE_INFO Dir1
= NULL
;
2507 PUDF_FILE_INFO Dir2
;
2509 UNICODE_STRING NewName
;
2510 UNICODE_STRING LocalPath
;
2511 // PtrUDFCCB CurCcb = NULL;
2513 AdPrint(("UDFHardLink\n"));
2515 LocalPath
.Buffer
= NULL
;
2519 // do we try to link Volume ?
2520 if(!(File1
= Fcb1
->FileInfo
))
2521 try_return (RC
= STATUS_ACCESS_DENIED
);
2523 // do we try to link RootDir ?
2524 if(!(Dir1
= File1
->ParentFile
))
2525 try_return (RC
= STATUS_ACCESS_DENIED
);
2527 // do we try to link Stream / Stream Dir ?
2528 #ifdef UDF_ALLOW_LINKS_TO_STREAMS
2529 if(UDFIsAStreamDir(File1
))
2530 try_return (RC
= STATUS_ACCESS_DENIED
);
2531 #else //UDF_ALLOW_LINKS_TO_STREAMS
2532 if(UDFIsAStream(File1
) || UDFIsAStreamDir(File1
) /*||
2533 UDFIsADirectory(File1) || UDFHasAStreamDir(File1)*/)
2534 try_return (RC
= STATUS_ACCESS_DENIED
);
2535 #endif // UDF_ALLOW_LINKS_TO_STREAMS
2537 // do we try to link to RootDir or Volume ?
2539 Dir2
= File1
->ParentFile
;
2540 DirObject2
= FileObject1
->RelatedFileObject
;
2542 if(DirObject2
->FsContext2
&&
2543 (Fcb2
= ((PtrUDFCCB
)(DirObject2
->FsContext2
))->Fcb
)) {
2544 Dir2
= ((PtrUDFCCB
)(DirObject2
->FsContext2
))->Fcb
->FileInfo
;
2546 try_return (RC
= STATUS_INVALID_PARAMETER
);
2550 if(!Dir2
) try_return (RC
= STATUS_ACCESS_DENIED
);
2552 // Stream can't be a Dir or have Streams
2553 if(UDFIsAStreamDir(Dir2
)) {
2554 try_return (RC
= STATUS_ACCESS_DENIED
);
2555 /* if(UDFIsADirectory(File1) ||
2556 UDFHasAStreamDir(File1)) {
2558 try_return (RC = STATUS_ACCESS_DENIED);
2562 /* if(UDFIsAStreamDir(Dir2))
2563 try_return (RC = STATUS_ACCESS_DENIED);*/
2565 RC
= UDFPrepareForRenameMoveLink(Vcb
, &AcquiredVcb
, &AcquiredVcbEx
,
2567 &AcquiredDir1
, &AcquiredFcb1
,
2570 TRUE
); // it is HLink operation
2574 // check if the source file is used
2576 // Make sure the name is of legal length.
2577 if(PtrBuffer
->FileNameLength
> UDF_NAME_LEN
*sizeof(WCHAR
)) {
2578 try_return(RC
= STATUS_OBJECT_NAME_INVALID
);
2580 NewName
.Length
= NewName
.MaximumLength
= (USHORT
)(PtrBuffer
->FileNameLength
);
2581 NewName
.Buffer
= (PWCHAR
)&(PtrBuffer
->FileName
);
2583 // This name is by definition legal.
2584 NewName
= *((PUNICODE_STRING
)&DirObject2
->FileName
);
2587 ic
= (Ccb1
->CCBFlags
& UDF_CCB_CASE_SENSETIVE
) ? FALSE
: TRUE
;
2589 AdPrint((" %ws ->\n %ws\n",
2590 Fcb1
->FCBName
->ObjectName
.Buffer
,
2593 RC
= UDFHardLinkFile__(Vcb
, ic
, &Replace
, &NewName
, Dir1
, Dir2
, File1
);
2594 if(!NT_SUCCESS(RC
)) try_return (RC
);
2596 // Update Parent Objects (mark 'em as modified)
2597 if(Vcb
->CompatFlags
& UDF_VCB_IC_UPDATE_DIR_WRITE
) {
2599 DirObject2
->Flags
|= FO_FILE_MODIFIED
;
2601 DirObject2
->Flags
|= FO_FILE_SIZE_CHANGED
;
2605 UDFNotifyFullReportChange( Vcb
, File1
,
2606 FILE_NOTIFY_CHANGE_LAST_WRITE
|
2607 FILE_NOTIFY_CHANGE_LAST_ACCESS
,
2608 FILE_ACTION_MODIFIED
);
2610 RC
= MyCloneUnicodeString(&LocalPath
, (Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ?
2611 &UDFGlobalData
.UnicodeStrRoot
:
2612 &(Dir2
->Fcb
->FCBName
->ObjectName
));
2613 if(!NT_SUCCESS(RC
)) try_return (RC
);
2614 /* RC = MyAppendUnicodeStringToString(&LocalPath, (Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? &(UDFGlobalData.UnicodeStrRoot) : &(Dir2->Fcb->FCBName->ObjectName));
2615 if(!NT_SUCCESS(RC)) try_return (RC);*/
2616 // if Dir2 is a RootDir, we shoud not append '\\' because
2617 // it will be the 2nd '\\' character (RootDir's name is also '\\')
2618 if(Dir2
->ParentFile
) {
2619 RC
= MyAppendUnicodeToString(&LocalPath
, L
"\\");
2620 if(!NT_SUCCESS(RC
)) try_return (RC
);
2622 RC
= MyAppendUnicodeStringToStringTag(&LocalPath
, &NewName
, MEM_USHL_TAG
);
2623 if(!NT_SUCCESS(RC
)) try_return (RC
);
2626 /* UDFNotifyFullReportChange( Vcb, File2,
2627 UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
2628 FILE_ACTION_ADDED );*/
2629 FsRtlNotifyFullReportChange( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
2630 (PSTRING
)&LocalPath
,
2631 ((Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ? 0 : Dir2
->Fcb
->FCBName
->ObjectName
.Length
) + sizeof(WCHAR
),
2633 UDFIsADirectory(File1
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
2637 /* UDFNotifyFullReportChange( Vcb, File2,
2638 FILE_NOTIFY_CHANGE_ATTRIBUTES |
2639 FILE_NOTIFY_CHANGE_SIZE |
2640 FILE_NOTIFY_CHANGE_LAST_WRITE |
2641 FILE_NOTIFY_CHANGE_LAST_ACCESS |
2642 FILE_NOTIFY_CHANGE_CREATION |
2643 FILE_NOTIFY_CHANGE_EA,
2644 FILE_ACTION_MODIFIED );*/
2645 FsRtlNotifyFullReportChange( Vcb
->NotifyIRPMutex
, &(Vcb
->NextNotifyIRP
),
2646 (PSTRING
)&LocalPath
,
2647 ((Dir2
->Fcb
->FCBFlags
& UDF_FCB_ROOT_DIRECTORY
) ? 0 : Dir2
->Fcb
->FCBName
->ObjectName
.Length
) + sizeof(WCHAR
),
2649 UDFIsADirectory(File1
) ? FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
,
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
,
2659 RC
= STATUS_SUCCESS
;
2666 UDF_CHECK_PAGING_IO_RESOURCE(Fcb1
->NTRequiredFCB
);
2667 UDFReleaseResource(&(Fcb1
->NTRequiredFCB
->MainResource
));
2670 UDF_CHECK_PAGING_IO_RESOURCE(Dir1
->Fcb
->NTRequiredFCB
);
2671 UDFReleaseResource(&(Dir1
->Fcb
->NTRequiredFCB
->MainResource
));
2675 UDFConvertExclusiveToSharedLite(&(Vcb
->VCBResource
));
2677 // caller assumes Vcb to be acquired shared
2679 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
2682 if(LocalPath
.Buffer
) {
2683 MyFreePool__(LocalPath
.Buffer
);
2688 } // end UDFHardLink()
2689 #endif //UDF_ALLOW_HARD_LINKS
2691 #endif //UDF_READ_ONLY_BUILD