1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*************************************************************************
7 *
8 * File: Fileinfo.cpp
9 *
10 * Module: UDF File System Driver (Kernel mode execution only)
11 *
12 * Description:
13 *   Contains code to handle the "set/query file information" dispatch
14 *   entry points.
15 *
16 *************************************************************************/
17 
18 #include            "udffs.h"
19 
20 // define the file specific bug-check id
21 #define         UDF_BUG_CHECK_ID                UDF_FILE_INFORMATION
22 
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"
27 
28 /*************************************************************************
29 *
30 * Function: UDFFileInfo()
31 *
32 * Description:
33 *   The I/O Manager will invoke this routine to handle a set/query file
34 *   information request
35 *
36 * Expected Interrupt Level (for execution) :
37 *
38 *  IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
39 *   to be deferred to a worker thread context)
40 *
41 * Return Value: STATUS_SUCCESS/Error
42 *
43 *************************************************************************/
44 NTSTATUS
45 NTAPI
46 UDFFileInfo(
47     PDEVICE_OBJECT DeviceObject,       // the logical volume device object
48     PIRP           Irp                 // I/O Request Packet
49     )
50 {
51     NTSTATUS         RC = STATUS_SUCCESS;
52     PtrUDFIrpContext PtrIrpContext = NULL;
53     BOOLEAN          AreWeTopLevel = FALSE;
54 
55     TmPrint(("UDFFileInfo: \n"));
56 
57     FsRtlEnterFileSystem();
58     ASSERT(DeviceObject);
59     ASSERT(Irp);
60 
61     // set the top level context
62     AreWeTopLevel = UDFIsIrpTopLevel(Irp);
63     ASSERT(!UDFIsFSDevObj(DeviceObject));
64 
65     _SEH2_TRY {
66 
67         // get an IRP context structure and issue the request
68         PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
69         if(PtrIrpContext) {
70             RC = UDFCommonFileInfo(PtrIrpContext, Irp);
71         } else {
72             RC = STATUS_INSUFFICIENT_RESOURCES;
73             Irp->IoStatus.Status = RC;
74             Irp->IoStatus.Information = 0;
75             // complete the IRP
76             IoCompleteRequest(Irp, IO_DISK_INCREMENT);
77         }
78 
79     } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
80 
81         RC = UDFExceptionHandler(PtrIrpContext, Irp);
82 
83         UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
84     } _SEH2_END;
85 
86     if(AreWeTopLevel) {
87         IoSetTopLevelIrp(NULL);
88     }
89 
90     FsRtlExitFileSystem();
91 
92     return(RC);
93 } // end UDFFileInfo()
94 
95 
96 /*************************************************************************
97 *
98 * Function: UDFCommonFileInfo()
99 *
100 * Description:
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
105 *
106 * Expected Interrupt Level (for execution) :
107 *
108 *  IRQL_PASSIVE_LEVEL
109 *
110 * Return Value: STATUS_SUCCESS/Error
111 *
112 *************************************************************************/
113 NTSTATUS
114 UDFCommonFileInfo(
115     PtrUDFIrpContext PtrIrpContext,
116     PIRP             Irp
117     )
118 {
119     NTSTATUS                RC = STATUS_SUCCESS;
120     PIO_STACK_LOCATION      IrpSp = NULL;
121     PFILE_OBJECT            FileObject = NULL;
122     PtrUDFFCB               Fcb = NULL;
123     PtrUDFCCB               Ccb = NULL;
124     PVCB                    Vcb = 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;
135     PIRP                    TopIrp;
136 
137     TmPrint(("UDFCommonFileInfo: irp %x\n", Irp));
138 
139         TopIrp = IoGetTopLevelIrp();
140         switch((ULONG_PTR)TopIrp) {
141         case FSRTL_FSP_TOP_LEVEL_IRP:
142             UDFPrint(("  FSRTL_FSP_TOP_LEVEL_IRP\n"));
143             break;
144         case FSRTL_CACHE_TOP_LEVEL_IRP:
145             UDFPrint(("  FSRTL_CACHE_TOP_LEVEL_IRP\n"));
146             break;
147         case FSRTL_MOD_WRITE_TOP_LEVEL_IRP:
148             UDFPrint(("  FSRTL_MOD_WRITE_TOP_LEVEL_IRP\n"));
149             break;
150         case FSRTL_FAST_IO_TOP_LEVEL_IRP:
151             UDFPrint(("  FSRTL_FAST_IO_TOP_LEVEL_IRP\n"));
152             BrutePoint()
153             break;
154         case NULL:
155             UDFPrint(("  NULL TOP_LEVEL_IRP\n"));
156             break;
157         default:
158             if(TopIrp == Irp) {
159                 UDFPrint(("  TOP_LEVEL_IRP\n"));
160             } else {
161                 UDFPrint(("  RECURSIVE_IRP, TOP = %x\n", TopIrp));
162             }
163         }
164 
165     _SEH2_TRY {
166         // First, get a pointer to the current I/O stack location.
167         IrpSp = IoGetCurrentIrpStackLocation(Irp);
168         ASSERT(IrpSp);
169 
170         FileObject = IrpSp->FileObject;
171         ASSERT(FileObject);
172 
173         // Get the FCB and CCB pointers.
174         Ccb = (PtrUDFCCB)(FileObject->FsContext2);
175         ASSERT(Ccb);
176         if(!Ccb) {
177             // some applications sends us FO without Ccb
178             // This is not allowed...
179             RC = STATUS_INVALID_PARAMETER;
180             try_return(RC);
181         }
182         Fcb = Ccb->Fcb;
183         ASSERT(Fcb);
184 
185         NtReqFcb = Fcb->NTRequiredFCB;
186 
187         CanWait = (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE;
188 
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;
194             try_return(RC);
195         }
196 
197 
198         Vcb = (PVCB)(IrpSp->DeviceObject->DeviceExtension);
199         ASSERT(Vcb);
200         ASSERT(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB);
201         //Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
202 
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;
208 
209         UDFFlushTryBreak(Vcb);
210         if(!UDFAcquireResourceShared(&(Vcb->VCBResource), CanWait)) {
211             PostRequest = TRUE;
212             try_return(RC = STATUS_PENDING);
213         }
214         AcquiredVcb = TRUE;
215 
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,
225                 0,
226                 &FunctionalityRequested,
227                 NULL);
228             if(!NT_SUCCESS(RC)) {
229                 try_return(RC);
230             }
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;
241             }
242 
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);
247                 break;
248             case FileStandardInformation:
249                 RC = UDFGetStandardInformation(Fcb, (PFILE_STANDARD_INFORMATION) PtrSystemBuffer, &BufferLength);
250                 break;
251 #if(_WIN32_WINNT >= 0x0400)
252             case FileNetworkOpenInformation:
253                  RC = UDFGetNetworkInformation(Fcb, (PFILE_NETWORK_OPEN_INFORMATION)PtrSystemBuffer, &BufferLength);
254                 break;
255 #endif  // _WIN32_WINNT >= 0x0400
256             case FileInternalInformation:
257                 RC = UDFGetInternalInformation(PtrIrpContext, Fcb, Ccb, (PFILE_INTERNAL_INFORMATION) PtrSystemBuffer, &BufferLength);
258                 break;
259             case FileEaInformation:
260                 RC = UDFGetEaInformation(PtrIrpContext, Fcb, (PFILE_EA_INFORMATION) PtrSystemBuffer, &BufferLength);
261                 break;
262             case FileNameInformation:
263                 RC = UDFGetFullNameInformation(FileObject, (PFILE_NAME_INFORMATION) PtrSystemBuffer, &BufferLength);
264                 break;
265             case FileAlternateNameInformation:
266                 RC = UDFGetAltNameInformation(Fcb, (PFILE_NAME_INFORMATION) PtrSystemBuffer, &BufferLength);
267                 break;
268 //            case FileCompressionInformation:
269 //                // RC = UDFGetCompressionInformation(...);
270 //                break;
271             case FilePositionInformation:
272                 RC = UDFGetPositionInformation(FileObject, (PFILE_POSITION_INFORMATION)PtrSystemBuffer, &BufferLength);
273                 break;
274             case FileStreamInformation:
275                 RC = UDFGetFileStreamInformation(Fcb, (PFILE_STREAM_INFORMATION) PtrSystemBuffer, &BufferLength);
276                 break;
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
282                 // buffer)
283                 {
284                     PFILE_ALL_INFORMATION PtrAllInfo = (PFILE_ALL_INFORMATION)PtrSystemBuffer;
285 
286                     BufferLength -= (sizeof(FILE_MODE_INFORMATION) +
287                                      sizeof(FILE_ACCESS_INFORMATION) +
288                                      sizeof(FILE_ALIGNMENT_INFORMATION));
289 
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))
297                         )
298                         try_return(RC);
299                 }
300                 break;
301             default:
302                 RC = STATUS_INVALID_PARAMETER;
303                 try_return(RC);
304             }
305 
306 #ifndef UDF_READ_ONLY_BUILD
307         } else {
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);
316             }
317 #ifdef UDF_ENABLE_SECURITY
318             RC = IoCheckFunctionAccess(
319                 Ccb->PreviouslyGrantedAccess,
320                 PtrIrpContext->MajorFunction,
321                 PtrIrpContext->MinorFunction,
322                 0,
323                 &FunctionalityRequested,
324                 NULL);
325             if(!NT_SUCCESS(RC)) {
326                 try_return(RC);
327             }
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.
332 
333             // Rename, and link operations require creation of a directory
334             // entry and possibly deletion of another directory entry.
335 
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)) {
347                         PostRequest = TRUE;
348                         try_return(RC = STATUS_PENDING);
349                     }
350                     ParentResourceAcquired = TRUE;
351                 }
352                 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
353                 if(!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) {
354                     PostRequest = TRUE;
355                     try_return(RC = STATUS_PENDING);
356                 }
357                 MainResourceAcquired = TRUE;
358             } else
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)) ) {
367 
368                 // Acquire the MainResource shared.
369                 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
370                 if(!UDFAcquireResourceShared(&(NtReqFcb->MainResource), CanWait)) {
371                     PostRequest = TRUE;
372                     try_return(RC = STATUS_PENDING);
373                 }
374                 MainResourceAcquired = TRUE;
375                 // Acquire the PagingResource exclusive.
376                 if(!UDFAcquireResourceExclusive(&(NtReqFcb->PagingIoResource), CanWait)) {
377                     PostRequest = TRUE;
378                     try_return(RC = STATUS_PENDING);
379                 }
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)) {
386                     PostRequest = TRUE;
387                     try_return(RC = STATUS_PENDING);
388                 }
389                 MainResourceAcquired = TRUE;
390             }
391 
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);
396             }
397 
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);
402                 break;
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;
408 
409                 PtrFileInfoBuffer = (PFILE_POSITION_INFORMATION)PtrSystemBuffer;
410 
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);
415                     }
416                 }
417 
418                 FileObject->CurrentByteOffset = PtrFileInfoBuffer->CurrentByteOffset;
419                 break;
420             }
421             case FileDispositionInformation:
422                 RC = UDFSetDispositionInformation(Fcb, Ccb, Vcb, FileObject,
423                             ((PFILE_DISPOSITION_INFORMATION)PtrSystemBuffer)->DeleteFile ? TRUE : FALSE);
424                 break;
425             case FileRenameInformation:
426                 if(!CanWait) {
427                     PostRequest = TRUE;
428                     try_return(RC = STATUS_PENDING);
429                 }
430                 RC = UDFRename(IrpSp, Fcb, Ccb, FileObject, (PFILE_RENAME_INFORMATION)PtrSystemBuffer);
431                 if(RC == STATUS_PENDING) {
432                     PostRequest = TRUE;
433                     try_return(RC);
434                 }
435                 break;
436 #ifdef UDF_ALLOW_HARD_LINKS
437             case FileLinkInformation:
438                 if(!CanWait) {
439                     PostRequest = TRUE;
440                     try_return(RC = STATUS_PENDING);
441                 }
442                 RC = UDFHardLink(IrpSp, Fcb, Ccb, FileObject, (PFILE_LINK_INFORMATION)PtrSystemBuffer);
443                 break;
444 #endif //UDF_ALLOW_HARD_LINKS
445             case FileAllocationInformation:
446                 RC = UDFSetAllocationInformation(Fcb, Ccb, Vcb, FileObject,
447                                                   PtrIrpContext, Irp,
448                                                   (PFILE_ALLOCATION_INFORMATION)PtrSystemBuffer);
449                 break;
450             case FileEndOfFileInformation:
451                 RC = UDFSetEOF(IrpSp, Fcb, Ccb, Vcb, FileObject, Irp, (PFILE_END_OF_FILE_INFORMATION)PtrSystemBuffer);
452                 break;
453             default:
454                 RC = STATUS_INVALID_PARAMETER;
455                 try_return(RC);
456             }
457 #endif //UDF_READ_ONLY_BUILD
458         }
459 
460 try_exit:   NOTHING;
461 
462     } _SEH2_FINALLY {
463 
464         if(PagingIoResourceAcquired) {
465             UDFReleaseResource(&(NtReqFcb->PagingIoResource));
466             PagingIoResourceAcquired = FALSE;
467         }
468 
469         if(MainResourceAcquired) {
470             UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
471             UDFReleaseResource(&(NtReqFcb->MainResource));
472             MainResourceAcquired = FALSE;
473         }
474 
475         if(ParentResourceAcquired) {
476             UDF_CHECK_PAGING_IO_RESOURCE(Fcb->ParentFcb->NTRequiredFCB);
477             UDFReleaseResource(&(Fcb->ParentFcb->NTRequiredFCB->MainResource));
478             ParentResourceAcquired = FALSE;
479         }
480 
481         // Post IRP if required
482         if(PostRequest) {
483 
484             // Since, the I/O Manager gave us a system buffer, we do not
485             // need to "lock" anything.
486 
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);
490 
491         } else {
492 
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
501                 } else
502                 if(NT_SUCCESS(RC)) {
503                     if(FunctionalityRequested == FileDispositionInformation) {
504                         if(AcquiredVcb) {
505                             AcquiredVcb = FALSE;
506                             UDFReleaseResource(&(Vcb->VCBResource));
507                         }
508                         UDFRemoveFromDelayedQueue(Fcb);
509                     }
510 #endif //UDF_DELAYED_CLOSE
511 #endif //UDF_READ_ONLY_BUILD
512                 }
513                 // complete the IRP
514                 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
515                 // Free up the Irp Context
516                 UDFReleaseIrpContext(PtrIrpContext);
517             } // can we complete the IRP ?
518 
519         }
520         if(AcquiredVcb) {
521             UDFReleaseResource(&(Vcb->VCBResource));
522         }
523     } _SEH2_END;// end of "__finally" processing
524 
525     return(RC);
526 } // end UDFCommonFileInfo()
527 
528 /*
529     Return some time-stamps and file attributes to the caller.
530  */
531 NTSTATUS
532 UDFGetBasicInformation(
533     IN PFILE_OBJECT                FileObject,
534     IN PtrUDFFCB                   Fcb,
535     IN PFILE_BASIC_INFORMATION     PtrBuffer,
536  IN OUT LONG*                      PtrReturnedLength
537     )
538 {
539     NTSTATUS            RC = STATUS_SUCCESS;
540     PUDF_FILE_INFO      FileInfo;
541     PDIR_INDEX_ITEM     DirNdx;
542 
543     AdPrint(("UDFGetBasicInformation: \n"));
544 
545     _SEH2_TRY {
546 
547         if(*PtrReturnedLength < (LONG)sizeof(FILE_BASIC_INFORMATION)) {
548             try_return(RC = STATUS_BUFFER_OVERFLOW);
549         }
550 
551         // Zero out the supplied buffer.
552         RtlZeroMemory(PtrBuffer, sizeof(FILE_BASIC_INFORMATION));
553 
554         // Get information from the FCB and update TimesCache in DirIndex
555         FileInfo = Fcb->FileInfo;
556 
557         if(!FileInfo) {
558             AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n"));
559             AdPrint(("!!!! GetBasicInfo to unopened file !!!!\n"));
560             try_return(RC = STATUS_INVALID_PARAMETER);
561         }
562 
563         DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index);
564 
565         PtrBuffer->CreationTime = Fcb->NTRequiredFCB->CreationTime;
566         DirNdx->CreationTime = PtrBuffer->CreationTime.QuadPart;
567 
568         PtrBuffer->LastAccessTime = Fcb->NTRequiredFCB->LastAccessTime;
569         DirNdx->LastAccessTime = PtrBuffer->LastAccessTime.QuadPart;
570 
571         PtrBuffer->LastWriteTime = Fcb->NTRequiredFCB->LastWriteTime;
572         DirNdx->LastWriteTime = PtrBuffer->LastWriteTime.QuadPart;
573 
574         PtrBuffer->ChangeTime = Fcb->NTRequiredFCB->ChangeTime;
575         DirNdx->ChangeTime = PtrBuffer->ChangeTime.QuadPart;
576 
577         // Now fill in the attributes.
578         if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) {
579             PtrBuffer->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
580 #ifdef UDF_DBG
581             if(!FileInfo->Dloc->DirIndex) AdPrint(("*****!!!!! Directory has no DirIndex !!!!!*****\n"));
582 #endif
583         }
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;
590         } else {
591             PtrBuffer->FileAttributes &= ~FILE_ATTRIBUTE_TEMPORARY;
592         }
593         if(!PtrBuffer->FileAttributes) {
594             PtrBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
595         }
596 
597 try_exit: NOTHING;
598 
599     } _SEH2_FINALLY {
600 
601         if(NT_SUCCESS(RC)) {
602             // Return the amount of information filled in.
603             (*PtrReturnedLength) -= sizeof(FILE_BASIC_INFORMATION);
604         }
605     } _SEH2_END;
606     return(RC);
607 } // end UDFGetBasicInformation()
608 
609 
610 /*
611     Return file sizes to the caller.
612  */
613 NTSTATUS
614 UDFGetStandardInformation(
615     IN PtrUDFFCB                   Fcb,
616     IN PFILE_STANDARD_INFORMATION  PtrBuffer,
617  IN OUT LONG*                      PtrReturnedLength
618     )
619 {
620     NTSTATUS            RC = STATUS_SUCCESS;
621     PUDF_FILE_INFO      FileInfo;
622 //    PVCB Vcb;
623 
624     AdPrint(("UDFGetStandardInformation: \n"));
625 
626     _SEH2_TRY {
627 
628         if(*PtrReturnedLength < (LONG)sizeof(FILE_STANDARD_INFORMATION)) {
629             try_return(RC = STATUS_BUFFER_OVERFLOW);
630         }
631 
632         // Zero out the supplied buffer.
633         RtlZeroMemory(PtrBuffer, sizeof(FILE_STANDARD_INFORMATION));
634 
635         FileInfo = Fcb->FileInfo;
636 
637         if(!FileInfo) {
638             AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n"));
639             AdPrint(("!!!! GetStandardInfo to unopened file !!!!\n"));
640             try_return(RC = STATUS_INVALID_PARAMETER);
641         }
642 //        Vcb = Fcb->Vcb;
643         PtrBuffer->NumberOfLinks = UDFGetFileLinkCount(FileInfo);
644         PtrBuffer->DeletePending = (Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) ? TRUE : FALSE;
645 
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;
651         } else {
652             if(Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.LowPart == 0xffffffff) {
653                 Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.QuadPart =
654                     UDFSysGetAllocSize(Fcb->Vcb, UDFGetFileSize(FileInfo));
655             }
656             PtrBuffer->AllocationSize = Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize;
657             PtrBuffer->EndOfFile = Fcb->NTRequiredFCB->CommonFCBHeader.FileSize;
658 
659             PtrBuffer->Directory = FALSE;
660         }
661 
662         try_exit: NOTHING;
663     } _SEH2_FINALLY {
664         if(NT_SUCCESS(RC)) {
665             // Return the amount of information filled in.
666             *PtrReturnedLength -= sizeof(FILE_STANDARD_INFORMATION);
667         }
668     } _SEH2_END;
669     return(RC);
670 } // end UDFGetStandardInformation()
671 
672 /*
673     Return some time-stamps and file attributes to the caller.
674  */
675 NTSTATUS
676 UDFGetNetworkInformation(
677     IN PtrUDFFCB                      Fcb,
678     IN PFILE_NETWORK_OPEN_INFORMATION PtrBuffer,
679  IN OUT PLONG                         PtrReturnedLength
680     )
681 {
682     NTSTATUS            RC = STATUS_SUCCESS;
683     PUDF_FILE_INFO      FileInfo;
684 
685     AdPrint(("UDFGetNetworkInformation: \n"));
686 
687     _SEH2_TRY {
688 
689         if(*PtrReturnedLength < (LONG)sizeof(FILE_NETWORK_OPEN_INFORMATION)) {
690             try_return(RC = STATUS_BUFFER_OVERFLOW);
691         }
692 
693         // Zero out the supplied buffer.
694         RtlZeroMemory(PtrBuffer, sizeof(FILE_NETWORK_OPEN_INFORMATION));
695 
696         // Get information from the FCB.
697         PtrBuffer->CreationTime = Fcb->NTRequiredFCB->CreationTime;
698         PtrBuffer->LastAccessTime = Fcb->NTRequiredFCB->LastAccessTime;
699         PtrBuffer->LastWriteTime = Fcb->NTRequiredFCB->LastWriteTime;
700         PtrBuffer->ChangeTime = Fcb->NTRequiredFCB->ChangeTime;
701 
702         FileInfo = Fcb->FileInfo;
703 
704         if(!FileInfo) {
705             AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n"));
706             AdPrint(("!!!! UDFGetNetworkInformation to unopened file !!!!\n"));
707             try_return(RC = STATUS_INVALID_PARAMETER);
708         }
709         // Now fill in the attributes.
710         if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) {
711             PtrBuffer->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
712 #ifdef UDF_DBG
713             if(!FileInfo->Dloc->DirIndex) AdPrint(("*****!!!!! Directory has no DirIndex !!!!!*****\n"));
714 #endif
715         } else {
716             if(Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.LowPart == 0xffffffff) {
717                 Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.QuadPart =
718                     UDFSysGetAllocSize(Fcb->Vcb, UDFGetFileSize(FileInfo));
719             }
720             PtrBuffer->AllocationSize = Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize;
721             PtrBuffer->EndOfFile = Fcb->NTRequiredFCB->CommonFCBHeader.FileSize;
722         }
723         // Similarly, fill in attributes indicating a hidden file, system
724         // file, compressed file, temporary file, etc. if the FSD supports
725         // such file attribute values.
726         PtrBuffer->FileAttributes |= UDFAttributesToNT(UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index),NULL);
727         if(!PtrBuffer->FileAttributes) {
728             PtrBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
729         }
730 
731 try_exit: NOTHING;
732 
733     } _SEH2_FINALLY {
734         if(NT_SUCCESS(RC)) {
735             // Return the amount of information filled in.
736             (*PtrReturnedLength) -= sizeof(FILE_NETWORK_OPEN_INFORMATION);
737         }
738     } _SEH2_END;
739     return(RC);
740 } // end UDFGetNetworkInformation()
741 
742 
743 /*
744     Return some time-stamps and file attributes to the caller.
745  */
746 NTSTATUS
747 UDFGetInternalInformation(
748     PtrUDFIrpContext              PtrIrpContext,
749     IN PtrUDFFCB                  Fcb,
750     IN PtrUDFCCB                  Ccb,
751     IN PFILE_INTERNAL_INFORMATION PtrBuffer,
752  IN OUT PLONG                     PtrReturnedLength
753     )
754 {
755     NTSTATUS            RC = STATUS_SUCCESS;
756     PUDF_FILE_INFO      FileInfo;
757     PVCB Vcb;
758 
759     AdPrint(("UDFGetInternalInformation\n"));
760 
761     _SEH2_TRY {
762 
763         if(*PtrReturnedLength < (LONG)sizeof(FILE_INTERNAL_INFORMATION)) {
764             try_return(RC = STATUS_BUFFER_OVERFLOW);
765         }
766 
767         // Zero out the supplied buffer.
768         RtlZeroMemory(PtrBuffer, sizeof(FILE_INTERNAL_INFORMATION));
769 
770         FileInfo = Fcb->FileInfo;
771 
772         if(!FileInfo) {
773             AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n"));
774             AdPrint(("!!!! UDFGetInternalInformation to unopened file !!!!\n"));
775             try_return(RC = STATUS_INVALID_PARAMETER);
776         }
777 
778         Vcb = Fcb->Vcb;
779         PtrBuffer->IndexNumber.QuadPart = UDFGetNTFileId(Vcb, FileInfo, &(Fcb->FCBName->ObjectName));
780 
781         UDFAcquireResourceExclusive(&(Fcb->Vcb->FileIdResource), TRUE);
782         // remember File Id & full path
783         UDFStoreFileId(Fcb->Vcb, Ccb, FileInfo, PtrBuffer->IndexNumber.QuadPart);
784         UDFReleaseResource(&(Fcb->Vcb->FileIdResource));
785 
786 try_exit: NOTHING;
787 
788     } _SEH2_FINALLY {
789         if(NT_SUCCESS(RC)) {
790             // Return the amount of information filled in.
791             *PtrReturnedLength -= sizeof(FILE_INTERNAL_INFORMATION);
792         }
793     } _SEH2_END;
794     return(RC);
795 } // end UDFGetInternalInformation()
796 
797 /*
798     Return zero-filled EAs to the caller.
799  */
800 NTSTATUS
801 UDFGetEaInformation(
802     PtrUDFIrpContext        PtrIrpContext,
803     IN PtrUDFFCB            Fcb,
804     IN PFILE_EA_INFORMATION PtrBuffer,
805  IN OUT PLONG               PtrReturnedLength
806     )
807 {
808     NTSTATUS            RC = STATUS_SUCCESS;
809 
810     AdPrint(("UDFGetEaInformation\n"));
811 
812     _SEH2_TRY {
813 
814         if(*PtrReturnedLength < (LONG)sizeof(FILE_EA_INFORMATION)) {
815             try_return(RC = STATUS_BUFFER_OVERFLOW);
816         }
817 
818         // Zero out the supplied buffer.
819         PtrBuffer->EaSize = 0;
820 
821 try_exit: NOTHING;
822 
823     } _SEH2_FINALLY {
824         if(NT_SUCCESS(RC)) {
825             // Return the amount of information filled in.
826             *PtrReturnedLength -= sizeof(FILE_EA_INFORMATION);
827         }
828     } _SEH2_END;
829     return(RC);
830 } // end UDFGetEaInformation()
831 
832 /*
833     Return file's long name to the caller.
834  */
835 NTSTATUS
836 UDFGetFullNameInformation(
837     IN PFILE_OBJECT                FileObject,
838     IN PFILE_NAME_INFORMATION      PtrBuffer,
839  IN OUT PLONG                      PtrReturnedLength
840     )
841 {
842     ULONG BytesToCopy;
843     NTSTATUS RC = STATUS_SUCCESS;
844 
845 
846     AdPrint(("UDFGetFullNameInformation\n"));
847 
848     PtrBuffer->FileNameLength = FileObject->FileName.Length;
849     BytesToCopy = FileObject->FileName.Length;
850 
851     if (PtrBuffer->FileNameLength + sizeof( ULONG ) > (ULONG)(*PtrReturnedLength)) {
852 
853         BytesToCopy = *PtrReturnedLength - sizeof( ULONG );
854         RC = STATUS_BUFFER_OVERFLOW;
855     }
856 
857     RtlCopyMemory( PtrBuffer->FileName, FileObject->FileName.Buffer, BytesToCopy );
858 
859     //  Reduce the available bytes by the amount stored into this buffer.
860     *PtrReturnedLength -= sizeof( ULONG ) + PtrBuffer->FileNameLength;
861 
862     return RC;
863 } // end UDFGetFullNameInformation()
864 
865 /*
866     Return file short(8.3) name to the caller.
867  */
868 NTSTATUS
869 UDFGetAltNameInformation(
870     IN PtrUDFFCB                   Fcb,
871     IN PFILE_NAME_INFORMATION      PtrBuffer,
872     IN OUT PLONG                   PtrReturnedLength
873     )
874 {
875     PDIR_INDEX_ITEM DirNdx;
876     ULONG BytesToCopy;
877     UNICODE_STRING ShortName;
878     WCHAR ShortNameBuffer[13];
879 
880     AdPrint(("UDFGetAltNameInformation: \n"));
881 
882     *PtrReturnedLength -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]);
883     DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb->FileInfo), Fcb->FileInfo->Index);
884 
885     ShortName.MaximumLength = 13 * sizeof(WCHAR);
886     ShortName.Buffer = (PWCHAR)&ShortNameBuffer;
887 
888     UDFDOSName__(Fcb->Vcb, &ShortName, &(DirNdx->FName), Fcb->FileInfo);
889 
890     if(*PtrReturnedLength < ShortName.Length) {
891         return(STATUS_BUFFER_OVERFLOW);
892     } else {
893         BytesToCopy = ShortName.Length;
894         *PtrReturnedLength -= ShortName.Length;
895     }
896 
897     RtlCopyMemory( &(PtrBuffer->FileName),
898                    ShortName.Buffer,
899                    BytesToCopy );
900 
901     PtrBuffer->FileNameLength = ShortName.Length;
902 
903     return(STATUS_SUCCESS);
904 } // end UDFGetAltNameInformation()
905 
906 /*
907     Get file position information
908  */
909 NTSTATUS
910 UDFGetPositionInformation(
911     IN PFILE_OBJECT               FileObject,
912     IN PFILE_POSITION_INFORMATION PtrBuffer,
913  IN OUT PLONG                     PtrReturnedLength
914     )
915 {
916     if(*PtrReturnedLength < (LONG)sizeof(FILE_POSITION_INFORMATION)) {
917         return(STATUS_BUFFER_OVERFLOW);
918     }
919     PtrBuffer->CurrentByteOffset = FileObject->CurrentByteOffset;
920     // Modify the local variable for BufferLength appropriately.
921     *PtrReturnedLength -= sizeof(FILE_POSITION_INFORMATION);
922 
923     return(STATUS_SUCCESS);
924 } // end UDFGetAltNameInformation()
925 
926 /*
927     Get file file stream(s) information
928  */
929 NTSTATUS
930 UDFGetFileStreamInformation(
931     IN PtrUDFFCB                  Fcb,
932     IN PFILE_STREAM_INFORMATION   PtrBuffer,
933  IN OUT PLONG                     PtrReturnedLength
934     )
935 {
936     NTSTATUS        RC = STATUS_SUCCESS;
937     PUDF_FILE_INFO  FileInfo;
938     PUDF_FILE_INFO  SDirInfo;
939     PVCB            Vcb;
940     BOOLEAN         FcbAcquired = FALSE;
941     uint_di         i;
942     LONG            l;
943     PDIR_INDEX_HDR  hSDirIndex;
944     PDIR_INDEX_ITEM SDirIndex;
945     PFILE_BOTH_DIR_INFORMATION NTFileInfo = NULL;
946 
947     AdPrint(("UDFGetFileStreamInformation\n"));
948 
949     _SEH2_TRY {
950 
951         UDFAcquireResourceExclusive(&(Fcb->Vcb->FileIdResource), TRUE);
952         FcbAcquired = TRUE;
953 
954         FileInfo = Fcb->FileInfo;
955         if(!FileInfo) {
956             AdPrint(("!!!!!!!! Bu-u-u-u-u-g !!!!!!!!!!!\n"));
957             AdPrint(("!!!! UDFGetFileStreamInformation to unopened file !!!!\n"));
958             try_return(RC = STATUS_INVALID_PARAMETER);
959         }
960         Vcb = Fcb->Vcb;
961         // Zero out the supplied buffer.
962         RtlZeroMemory(PtrBuffer, *PtrReturnedLength);
963         if(!(SDirInfo = FileInfo->Dloc->SDirInfo) ||
964              UDFIsSDirDeleted(SDirInfo) ) {
965             (*PtrReturnedLength) -= (sizeof(FILE_STREAM_INFORMATION) - sizeof(WCHAR));
966             try_return(RC = STATUS_SUCCESS);
967         }
968 
969         hSDirIndex = SDirInfo->Dloc->DirIndex;
970         NTFileInfo = (PFILE_BOTH_DIR_INFORMATION)MyAllocatePool__(NonPagedPool, sizeof(FILE_BOTH_DIR_INFORMATION)+UDF_NAME_LEN*sizeof(WCHAR));
971         if(!NTFileInfo) try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
972 
973         for(i=2; (SDirIndex = UDFDirIndex(hSDirIndex,i)); i++) {
974             if((SDirIndex->FI_Flags & UDF_FI_FLAG_FI_INTERNAL) ||
975                 UDFIsDeleted(SDirIndex) ||
976                 !SDirIndex->FName.Buffer )
977                 continue;
978             // copy data to buffer
979             if(*PtrReturnedLength < (l = ((sizeof(FILE_STREAM_INFORMATION) - sizeof(WCHAR)) +
980                                            SDirIndex->FName.Length + 3) & (~3)) ) {
981                 try_return(RC = STATUS_BUFFER_OVERFLOW);
982             }
983             RC = UDFFileDirInfoToNT(Vcb, SDirIndex, NTFileInfo);
984 
985             PtrBuffer->NextEntryOffset = l;
986             PtrBuffer->StreamNameLength = SDirIndex->FName.Length;
987             PtrBuffer->StreamSize = NTFileInfo->EndOfFile;
988             PtrBuffer->StreamAllocationSize = NTFileInfo->AllocationSize;
989             RtlCopyMemory(&(PtrBuffer->StreamName), SDirIndex->FName.Buffer, SDirIndex->FName.Length);
990             *PtrReturnedLength -= l;
991             *((PCHAR*)(&PtrBuffer)) += l;
992         }
993 
994 try_exit: NOTHING;
995 
996     } _SEH2_FINALLY {
997         if(FcbAcquired)
998             UDFReleaseResource(&(Fcb->Vcb->FileIdResource));
999         if(NTFileInfo)
1000            MyFreePool__(NTFileInfo);
1001     } _SEH2_END;
1002     return(RC);
1003 } // end UDFGetFileStreamInformation()
1004 
1005 //*******************************************************************
1006 
1007 #ifndef UDF_READ_ONLY_BUILD
1008 
1009 /*
1010     Set some time-stamps and file attributes supplied by the caller.
1011  */
1012 NTSTATUS
1013 UDFSetBasicInformation(
1014     IN PtrUDFFCB                   Fcb,
1015     IN PtrUDFCCB                   Ccb,
1016     IN PFILE_OBJECT                FileObject,
1017     IN PFILE_BASIC_INFORMATION PtrBuffer)
1018 {
1019     NTSTATUS        RC = STATUS_SUCCESS;
1020     ULONG           NotifyFilter = 0;
1021 
1022     AdPrint(("UDFSetBasicInformation\n"));
1023 
1024     _SEH2_TRY {
1025 
1026         // Obtain a pointer to the directory entry associated with
1027         // the FCB being modifed. The directory entry is obviously
1028         // part of the data associated with the parent directory that
1029         // contains this particular file stream.
1030         if(PtrBuffer->FileAttributes) {
1031             UDFUpdateAttrTime(Fcb->Vcb, Fcb->FileInfo);
1032         } else
1033         if( UDFIsADirectory(Fcb->FileInfo) &&
1034             !(Fcb->Vcb->CompatFlags & UDF_VCB_IC_UPDATE_UCHG_DIR_ACCESS_TIME) &&
1035               ((Fcb->FileInfo->Dloc->DataLoc.Modified ||
1036                 Fcb->FileInfo->Dloc->AllocLoc.Modified ||
1037                 (Fcb->FileInfo->Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ||
1038                 Fcb->FileInfo->Dloc->FELoc.Modified))
1039              ) {
1040             // ignore Access Time Modification for unchanged Dir
1041             if(!PtrBuffer->CreationTime.QuadPart &&
1042                PtrBuffer->LastAccessTime.QuadPart &&
1043                !PtrBuffer->ChangeTime.QuadPart &&
1044                !PtrBuffer->LastWriteTime.QuadPart)
1045                 try_return(RC);
1046         }
1047 
1048         UDFSetFileXTime(Fcb->FileInfo,
1049             &(PtrBuffer->CreationTime.QuadPart),
1050             &(PtrBuffer->LastAccessTime.QuadPart),
1051             &(PtrBuffer->ChangeTime.QuadPart),
1052             &(PtrBuffer->LastWriteTime.QuadPart) );
1053 
1054         if(PtrBuffer->CreationTime.QuadPart) {
1055             // The interesting thing here is that the user has set certain time
1056             // fields. However, before doing this, the user may have performed
1057             // I/O which in turn would have caused FSD to mark the fact that
1058             // write/access time should be modifed at cleanup.
1059             // We'll mark the fact that such updates are no longer
1060             // required since the user has explicitly specified the values he
1061             // wishes to see associated with the file stream.
1062             Fcb->NTRequiredFCB->CreationTime = PtrBuffer->CreationTime;
1063             Ccb->CCBFlags |= UDF_CCB_CREATE_TIME_SET;
1064             NotifyFilter |= FILE_NOTIFY_CHANGE_CREATION;
1065         }
1066         if(PtrBuffer->LastAccessTime.QuadPart) {
1067             Fcb->NTRequiredFCB->LastAccessTime = PtrBuffer->LastAccessTime;
1068             Ccb->CCBFlags |= UDF_CCB_ACCESS_TIME_SET;
1069             NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
1070         }
1071         if(PtrBuffer->ChangeTime.QuadPart) {
1072             Fcb->NTRequiredFCB->ChangeTime = PtrBuffer->ChangeTime;
1073             Ccb->CCBFlags |= UDF_CCB_MODIFY_TIME_SET;
1074         }
1075         if(PtrBuffer->LastWriteTime.QuadPart) {
1076             Fcb->NTRequiredFCB->LastWriteTime = PtrBuffer->LastWriteTime;
1077             Ccb->CCBFlags |= UDF_CCB_WRITE_TIME_SET;
1078             NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
1079         }
1080 
1081         // Now come the attributes.
1082         if(PtrBuffer->FileAttributes) {
1083             // We have a non-zero attribute value.
1084             // The presence of a particular attribute indicates that the
1085             // user wishes to set the attribute value. The absence indicates
1086             // the user wishes to clear the particular attribute.
1087 
1088             // Our routine ignores unsupported flags
1089             PtrBuffer->FileAttributes &= ~(FILE_ATTRIBUTE_NORMAL);
1090 
1091             // Similarly, we should pick out other invalid flag values.
1092             if( (PtrBuffer->FileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
1093                !(Fcb->FCBFlags & UDF_FCB_DIRECTORY))
1094                 try_return(RC = STATUS_INVALID_PARAMETER);
1095 
1096             if(PtrBuffer->FileAttributes & FILE_ATTRIBUTE_TEMPORARY) {
1097                 if(Fcb->FCBFlags & UDF_FCB_DIRECTORY)
1098                     try_return(RC = STATUS_INVALID_PARAMETER);
1099                 FileObject->Flags |= FO_TEMPORARY_FILE;
1100             } else {
1101                 FileObject->Flags &= ~FO_TEMPORARY_FILE;
1102             }
1103 
1104             if(PtrBuffer->FileAttributes & FILE_ATTRIBUTE_READONLY) {
1105                 Fcb->FCBFlags |= UDF_FCB_READ_ONLY;
1106             } else {
1107                 Fcb->FCBFlags &= ~UDF_FCB_READ_ONLY;
1108             }
1109 
1110             UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb->FileInfo), Fcb->FileInfo->Index),
1111                                NULL, PtrBuffer->FileAttributes);
1112 
1113             (UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb->FileInfo), Fcb->FileInfo->Index))
1114                 ->FI_Flags |= UDF_FI_FLAG_SYS_ATTR;
1115             // If the FSD supports file compression, we may wish to
1116             // note the user's preferences for compressing/not compressing
1117             // the file at this time.
1118             Ccb->CCBFlags |= UDF_CCB_ATTRIBUTES_SET;
1119             NotifyFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
1120         }
1121 
1122         if(NotifyFilter) {
1123             UDFNotifyFullReportChange( Fcb->Vcb, Fcb->FileInfo,
1124                                        NotifyFilter, FILE_ACTION_MODIFIED);
1125             UDFSetFileSizeInDirNdx(Fcb->Vcb, Fcb->FileInfo, NULL);
1126             Fcb->FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1127         }
1128 
1129 try_exit: NOTHING;
1130     } _SEH2_FINALLY {
1131         ;
1132     } _SEH2_END;
1133     return(RC);
1134 } // end UDFSetBasicInformation()
1135 
1136 NTSTATUS
1137 UDFMarkStreamsForDeletion(
1138     IN PVCB           Vcb,
1139     IN PtrUDFFCB      Fcb,
1140     IN BOOLEAN        ForDel
1141     )
1142 {
1143     NTSTATUS        RC = STATUS_SUCCESS;
1144     PUDF_FILE_INFO  SDirInfo = NULL;
1145     PUDF_FILE_INFO  FileInfo = NULL;
1146     ULONG lc;
1147     BOOLEAN SDirAcq = FALSE;
1148     BOOLEAN StrAcq = FALSE;
1149     uint_di d,i;
1150 
1151     _SEH2_TRY {
1152 
1153         // In some cases we needn't marking Streams for deleteion
1154         // (Not opened or Don't exist)
1155         if(UDFIsAStream(Fcb->FileInfo) ||
1156            UDFIsAStreamDir(Fcb->FileInfo) ||
1157            !UDFHasAStreamDir(Fcb->FileInfo) ||
1158            !Fcb->FileInfo->Dloc->SDirInfo ||
1159            UDFIsSDirDeleted(Fcb->FileInfo->Dloc->SDirInfo) ||
1160            (UDFGetFileLinkCount(Fcb->FileInfo) > 1) )
1161             try_return (RC /*=STATUS_SUCCESS*/);
1162 
1163         // We shall mark Streams for deletion if there is no
1164         // Links to the file. Otherwise we'll delete only the file.
1165         // If we are asked to unmark Streams, we'll precess the whole Tree
1166         RC = UDFOpenStreamDir__(Vcb, Fcb->FileInfo, &SDirInfo);
1167         if(!NT_SUCCESS(RC))
1168             try_return(RC);
1169 
1170         if(SDirInfo->Fcb &&
1171            SDirInfo->Fcb->NTRequiredFCB) {
1172             UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo->Fcb->NTRequiredFCB);
1173             UDFAcquireResourceExclusive(&(SDirInfo->Fcb->NTRequiredFCB->MainResource),TRUE);
1174             SDirAcq = TRUE;
1175         }
1176 
1177         if(!ForDel || ((lc = UDFGetFileLinkCount(Fcb->FileInfo)) < 2)) {
1178 
1179             UDF_DIR_SCAN_CONTEXT ScanContext;
1180             PDIR_INDEX_ITEM DirNdx;
1181 
1182             // It is not worth checking whether the Stream can be deleted if
1183             // Undelete requested
1184             if(ForDel &&
1185                 // scan DirIndex
1186                 UDFDirIndexInitScan(SDirInfo, &ScanContext, 2)) {
1187 
1188                 // Check if we can delete Streams
1189                 while((DirNdx = UDFDirIndexScan(&ScanContext, &FileInfo))) {
1190                     if(!FileInfo)
1191                         continue;
1192                     if(FileInfo->Fcb) {
1193                         FileInfo->Fcb->NTRequiredFCB->AcqFlushCount++;
1194                         MmPrint(("    MmFlushImageSection() for Stream\n"));
1195                         if(!MmFlushImageSection(&(FileInfo->Fcb->NTRequiredFCB->SectionObject), MmFlushForDelete)) {
1196                             FileInfo->Fcb->NTRequiredFCB->AcqFlushCount--;
1197                             try_return(RC = STATUS_CANNOT_DELETE);
1198                         }
1199                         FileInfo->Fcb->NTRequiredFCB->AcqFlushCount--;
1200                     }
1201                 }
1202             }
1203             // (Un)Mark Streams for deletion
1204 
1205             // Perform sequencial Open for Streams & mark 'em
1206             // for deletion. We should not  get FileInfo pointers directly
1207             // from DirNdx[i] to prevent great troubles with linked
1208             // files. We should mark for deletion FI with proper ParentFile
1209             // pointer.
1210             d = UDFDirIndexGetLastIndex(SDirInfo->Dloc->DirIndex);
1211             for(i=2; i<d; i++) {
1212                 RC = UDFOpenFile__(Vcb,
1213                                    FALSE,TRUE,NULL,
1214                                    SDirInfo,&FileInfo,&i);
1215                 ASSERT(NT_SUCCESS(RC) || (RC == STATUS_FILE_DELETED));
1216                 if(NT_SUCCESS(RC)) {
1217                     if(FileInfo->Fcb) {
1218                         if(FileInfo->Fcb->NTRequiredFCB) {
1219                             UDF_CHECK_PAGING_IO_RESOURCE(FileInfo->Fcb->NTRequiredFCB);
1220                             UDFAcquireResourceExclusive(&(FileInfo->Fcb->NTRequiredFCB->MainResource),TRUE);
1221                             StrAcq = TRUE;
1222                         }
1223 #ifndef UDF_ALLOW_LINKS_TO_STREAMS
1224                         if(UDFGetFileLinkCount(FileInfo) >= 2) {
1225                             // Currently, UDF_INFO package doesn't
1226                             // support this case, so we'll inform developer
1227                             // about this to prevent on-disk space leaks...
1228                             BrutePoint();
1229                             try_return(RC = STATUS_CANNOT_DELETE);
1230                         }
1231 #endif //UDF_ALLOW_LINKS_TO_STREAMS
1232                         if(ForDel) {
1233                             AdPrint(("    SET stream DeleteOnClose\n"));
1234 #ifdef UDF_DBG
1235                             ASSERT(!(FileInfo->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
1236                             if(FileInfo->ParentFile &&
1237                                FileInfo->ParentFile->Fcb) {
1238                                 ASSERT(!(FileInfo->ParentFile->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
1239                             }
1240 #endif // UDF_DBG
1241                             FileInfo->Fcb->FCBFlags |= (UDF_FCB_DELETE_ON_CLOSE |
1242                                                         UDF_FCB_DELETE_PARENT);
1243                         } else {
1244                             AdPrint(("    CLEAR stream DeleteOnClose\n"));
1245                             FileInfo->Fcb->FCBFlags &= ~(UDF_FCB_DELETE_ON_CLOSE |
1246                                                          UDF_FCB_DELETE_PARENT);
1247                         }
1248                     }
1249                     UDFCloseFile__(Vcb, FileInfo);
1250                 } else
1251                 if(RC == STATUS_FILE_DELETED) {
1252                     // That's OK if STATUS_FILE_DELETED returned...
1253                     RC = STATUS_SUCCESS;
1254                 }
1255                 if(FileInfo) {
1256                     if(UDFCleanUpFile__(Vcb, FileInfo)) {
1257                         ASSERT(!StrAcq && !(FileInfo->Fcb));
1258                         MyFreePool__(FileInfo);
1259                     }
1260                     if(StrAcq) {
1261                         UDF_CHECK_PAGING_IO_RESOURCE(FileInfo->Fcb->NTRequiredFCB);
1262                         UDFReleaseResource(&(FileInfo->Fcb->NTRequiredFCB->MainResource));
1263                         StrAcq = FALSE;
1264                     }
1265                 }
1266                 FileInfo = NULL;
1267             }
1268             // Mark SDir for deletion
1269             if(SDirInfo->Fcb) {
1270                 if(ForDel) {
1271 #ifdef UDF_DBG
1272                     ASSERT(!(SDirInfo->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
1273                     if(SDirInfo->ParentFile &&
1274                        SDirInfo->ParentFile->Fcb) {
1275                         ASSERT(!(SDirInfo->ParentFile->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
1276                     }
1277 #endif // UDF_DBG
1278                     AdPrint(("    SET stream dir DeleteOnClose\n"));
1279                     SDirInfo->Fcb->FCBFlags |= (UDF_FCB_DELETE_ON_CLOSE |
1280                                                 UDF_FCB_DELETE_PARENT);
1281                 } else {
1282                     AdPrint(("    CLEAR stream dir DeleteOnClose\n"));
1283                     SDirInfo->Fcb->FCBFlags &= ~(UDF_FCB_DELETE_ON_CLOSE |
1284                                                  UDF_FCB_DELETE_PARENT);
1285                 }
1286             }
1287         } else
1288         if(lc >= 2) {
1289             // if caller wants us to perform DelTree for Streams, but
1290             // someone keeps Stream opened and there is a Link to this
1291             // file, we can't delete it immediately (on Cleanup) & should
1292             // not delete the whole Tree. Instead, we'll set DELETE_PARENT
1293             // flag in SDir to kill this file later, when all the Handles
1294             // to Streams, opened via this file, would be closed
1295 #ifdef UDF_DBG
1296             ASSERT(!(SDirInfo->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
1297             if(SDirInfo->ParentFile &&
1298                SDirInfo->ParentFile->Fcb) {
1299                 ASSERT(!(SDirInfo->ParentFile->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY));
1300             }
1301 #endif // UDF_DBG
1302             if(SDirInfo->Fcb)
1303                 SDirInfo->Fcb->FCBFlags |= UDF_FCB_DELETE_PARENT;
1304         }
1305 
1306 try_exit: NOTHING;
1307 
1308     } _SEH2_FINALLY {
1309         if(FileInfo) {
1310             UDFCloseFile__(Vcb, FileInfo);
1311             if(UDFCleanUpFile__(Vcb, FileInfo)) {
1312                 ASSERT(!StrAcq && !(FileInfo->Fcb));
1313                 MyFreePool__(FileInfo);
1314             }
1315             if(StrAcq) {
1316                 UDF_CHECK_PAGING_IO_RESOURCE(FileInfo->Fcb->NTRequiredFCB);
1317                 UDFReleaseResource(&(FileInfo->Fcb->NTRequiredFCB->MainResource));
1318             }
1319             SDirInfo = NULL;
1320         }
1321         if(SDirInfo) {
1322             UDFCloseFile__(Vcb, SDirInfo);
1323             if(SDirAcq) {
1324                 UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo->Fcb->NTRequiredFCB);
1325                 UDFReleaseResource(&(SDirInfo->Fcb->NTRequiredFCB->MainResource));
1326             }
1327             if(UDFCleanUpFile__(Vcb, SDirInfo)) {
1328                 MyFreePool__(SDirInfo);
1329             }
1330             SDirInfo = NULL;
1331         }
1332     } _SEH2_END;
1333     return RC;
1334 } // end UDFMarkStreamsForDeletion()
1335 
1336 /*
1337     (Un)Mark file for deletion.
1338  */
1339 NTSTATUS
1340 UDFSetDispositionInformation(
1341     IN PtrUDFFCB                       Fcb,
1342     IN PtrUDFCCB                       Ccb,
1343     IN PVCB                            Vcb,
1344     IN PFILE_OBJECT                    FileObject,
1345     IN BOOLEAN                         Delete
1346     )
1347 {
1348     NTSTATUS        RC = STATUS_SUCCESS;
1349 //    PUDF_FILE_INFO  SDirInfo = NULL;
1350 //    PUDF_FILE_INFO  FileInfo = NULL;
1351     ULONG lc;
1352 
1353     AdPrint(("UDFSetDispositionInformation\n"));
1354 
1355     _SEH2_TRY {
1356 
1357         if(!Delete) {
1358             AdPrint(("    CLEAR DeleteOnClose\n"));
1359             // "un-delete" the file.
1360             Fcb->FCBFlags &= ~UDF_FCB_DELETE_ON_CLOSE;
1361             if(FileObject)
1362                 FileObject->DeletePending = FALSE;
1363             RC = UDFMarkStreamsForDeletion(Vcb, Fcb, FALSE); // Undelete
1364             try_return(RC);
1365         }
1366         AdPrint(("    SET DeleteOnClose\n"));
1367 
1368         // The easy part is over. Now, we know that the user wishes to
1369         // delete the corresponding directory entry (of course, if this
1370         // is the only link to the file stream, any on-disk storage space
1371         // associated with the file stream will also be released when the
1372         // (only) link is deleted!)
1373 
1374         // Do some checking to see if the file can even be deleted.
1375         if(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) {
1376             // All done!
1377             try_return(RC);
1378         }
1379 
1380         if(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY) {
1381             try_return(RC = STATUS_CANNOT_DELETE);
1382         }
1383 
1384         if(Fcb->FCBFlags & UDF_FCB_READ_ONLY) {
1385             RC = UDFCheckAccessRights(NULL, NULL, Fcb->ParentFcb, NULL, FILE_DELETE_CHILD, 0);
1386             if(!NT_SUCCESS(RC)) {
1387                 try_return (RC = STATUS_CANNOT_DELETE);
1388             }
1389         }
1390 
1391         // It would not be prudent to allow deletion of either a root
1392         // directory or a directory that is not empty.
1393         if(Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY)
1394             try_return(RC = STATUS_CANNOT_DELETE);
1395 
1396         lc = UDFGetFileLinkCount(Fcb->FileInfo);
1397 
1398         if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) {
1399             // Perform check to determine whether the directory
1400             // is empty or not.
1401             if(!UDFIsDirEmpty__(Fcb->FileInfo)) {
1402                  try_return(RC = STATUS_DIRECTORY_NOT_EMPTY);
1403             }
1404 
1405         } else {
1406             // An important step is to check if the file stream has been
1407             // mapped by any process. The delete cannot be allowed to proceed
1408             // in this case.
1409             MmPrint(("    MmFlushImageSection()\n"));
1410             Fcb->NTRequiredFCB->AcqFlushCount++;
1411             if(!MmFlushImageSection(&(Fcb->NTRequiredFCB->SectionObject),
1412                     (lc > 1) ? MmFlushForWrite : MmFlushForDelete)) {
1413                 Fcb->NTRequiredFCB->AcqFlushCount--;
1414                 try_return(RC = STATUS_CANNOT_DELETE);
1415             }
1416             Fcb->NTRequiredFCB->AcqFlushCount--;
1417         }
1418         // We should also mark Streams for deletion if there are no
1419         // Links to the file. Otherwise we'll delete only the file
1420 
1421         if(lc > 1) {
1422             RC = STATUS_SUCCESS;
1423         } else {
1424             RC = UDFMarkStreamsForDeletion(Vcb, Fcb, TRUE); // Delete
1425             if(!NT_SUCCESS(RC))
1426                 try_return(RC);
1427         }
1428 
1429         // Set a flag to indicate that this directory entry will become history
1430         // at cleanup.
1431         Fcb->FCBFlags |= UDF_FCB_DELETE_ON_CLOSE;
1432         if(FileObject)
1433             FileObject->DeletePending = TRUE;
1434 
1435         if((Fcb->FCBFlags & UDF_FCB_DIRECTORY) && Ccb) {
1436             FsRtlNotifyFullChangeDirectory( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP),
1437                                             (PVOID)Ccb, NULL, FALSE, FALSE,
1438                                             0, NULL, NULL, NULL );
1439         }
1440 
1441 try_exit: NOTHING;
1442 
1443     } _SEH2_FINALLY {
1444         ;
1445     } _SEH2_END;
1446     return(RC);
1447 } // end UDFSetDispositionInformation()
1448 
1449 
1450 /*
1451       Change file allocation length.
1452  */
1453 NTSTATUS
1454 UDFSetAllocationInformation(
1455     IN PtrUDFFCB                       Fcb,
1456     IN PtrUDFCCB                       Ccb,
1457     IN PVCB                            Vcb,
1458     IN PFILE_OBJECT                    FileObject,
1459     IN PtrUDFIrpContext                PtrIrpContext,
1460     IN PIRP                            Irp,
1461     IN PFILE_ALLOCATION_INFORMATION    PtrBuffer
1462     )
1463 {
1464     NTSTATUS        RC = STATUS_SUCCESS;
1465     BOOLEAN         TruncatedFile = FALSE;
1466     BOOLEAN         ModifiedAllocSize = FALSE;
1467     BOOLEAN         CacheMapInitialized = FALSE;
1468     BOOLEAN         AcquiredPagingIo = FALSE;
1469 
1470     AdPrint(("UDFSetAllocationInformation\n"));
1471 
1472     _SEH2_TRY {
1473         // Increasing the allocation size associated with a file stream
1474         // is relatively easy. All we have to do is execute some FSD
1475         // specific code to check whether we have enough space available
1476         // (and if the FSD supports user/volume quotas, whether the user
1477         // is not exceeding quota), and then increase the file size in the
1478         // corresponding on-disk and in-memory structures.
1479         // Then, all we should do is inform the Cache Manager about the
1480         // increased allocation size.
1481 
1482         // First, do whatever error checking is appropriate here (e.g. whether
1483         // the caller is trying the change size for a directory, etc.).
1484         if(Fcb->FCBFlags & UDF_FCB_DIRECTORY)
1485             try_return(RC = STATUS_INVALID_PARAMETER);
1486 
1487         Fcb->NTRequiredFCB->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb);
1488 
1489         if ((FileObject->SectionObjectPointer->DataSectionObject != NULL) &&
1490             (FileObject->SectionObjectPointer->SharedCacheMap == NULL) &&
1491             !FlagOn(Irp->Flags, IRP_PAGING_IO)) {
1492             ASSERT( !FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE ) );
1493             //  Now initialize the cache map.
1494             MmPrint(("    CcInitializeCacheMap()\n"));
1495             CcInitializeCacheMap( FileObject,
1496                                   (PCC_FILE_SIZES)&Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize,
1497                                   FALSE,
1498                                   &(UDFGlobalData.CacheMgrCallBacks),
1499                                   Fcb->NTRequiredFCB );
1500 
1501             CacheMapInitialized = TRUE;
1502         }
1503 
1504         // Are we increasing the allocation size?
1505         if(Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.QuadPart <
1506             PtrBuffer->AllocationSize.QuadPart) {
1507 
1508             // Yes. Do the FSD specific stuff i.e. increase reserved
1509             // space on disk.
1510             if(((LONGLONG)UDFGetFreeSpace(Vcb) << Vcb->LBlockSizeBits) < PtrBuffer->AllocationSize.QuadPart) {
1511                 try_return(RC = STATUS_DISK_FULL);
1512             }
1513 //          RC = STATUS_SUCCESS;
1514             ModifiedAllocSize = TRUE;
1515 
1516         } else if(Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize.QuadPart >
1517                                                                 PtrBuffer->AllocationSize.QuadPart) {
1518             // This is the painful part. See if the VMM will allow us to proceed.
1519             // The VMM will deny the request if:
1520             // (a) any image section exists OR
1521             // (b) a data section exists and the size of the user mapped view
1522             //       is greater than the new size
1523             // Otherwise, the VMM should allow the request to proceed.
1524             MmPrint(("    MmCanFileBeTruncated()\n"));
1525             if(!MmCanFileBeTruncated(&(Fcb->NTRequiredFCB->SectionObject), &(PtrBuffer->AllocationSize))) {
1526                 // VMM said no way!
1527                 try_return(RC = STATUS_USER_MAPPED_FILE);
1528             }
1529 
1530             // Perform our directory entry modifications. Release any on-disk
1531             // space we may need to in the process.
1532             ModifiedAllocSize = TRUE;
1533             TruncatedFile = TRUE;
1534         }
1535 
1536         ASSERT(NT_SUCCESS(RC));
1537         // This is a good place to check if we have performed a truncate
1538         // operation. If we have perform a truncate (whether we extended
1539         // or reduced file size or even leave it intact), we should update
1540         // file time stamps.
1541         FileObject->Flags |= FO_FILE_MODIFIED;
1542 
1543         // Last, but not the lease, we must inform the Cache Manager of file size changes.
1544         if(ModifiedAllocSize) {
1545 
1546             // If we decreased the allocation size to less than the
1547             // current file size, modify the file size value.
1548             // Similarly, if we decreased the value to less than the
1549             // current valid data length, modify that value as well.
1550 
1551             AcquiredPagingIo = UDFAcquireResourceExclusiveWithCheck(&(Fcb->NTRequiredFCB->PagingIoResource));
1552             // Update the FCB Header with the new allocation size.
1553             if(TruncatedFile) {
1554                 if(Fcb->NTRequiredFCB->CommonFCBHeader.ValidDataLength.QuadPart >
1555                     PtrBuffer->AllocationSize.QuadPart) {
1556                     // Decrease the valid data length value.
1557                     Fcb->NTRequiredFCB->CommonFCBHeader.ValidDataLength =
1558                         PtrBuffer->AllocationSize;
1559                 }
1560                 if(Fcb->NTRequiredFCB->CommonFCBHeader.FileSize.QuadPart >
1561                     PtrBuffer->AllocationSize.QuadPart) {
1562                     // Decrease the file size value.
1563                     Fcb->NTRequiredFCB->CommonFCBHeader.FileSize =
1564                         PtrBuffer->AllocationSize;
1565                     RC = UDFResizeFile__(Vcb, Fcb->FileInfo, PtrBuffer->AllocationSize.QuadPart);
1566 //                    UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, NULL);
1567                 }
1568             } else {
1569                 Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize = PtrBuffer->AllocationSize;
1570 //                UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo,
1571 //                                       &(PtrBuffer->AllocationSize.QuadPart));
1572             }
1573             if(AcquiredPagingIo) {
1574                 UDFReleaseResource(&(Fcb->NTRequiredFCB->PagingIoResource));
1575                 AcquiredPagingIo = FALSE;
1576             }
1577             // If the FCB has not had caching initiated, it is still valid
1578             // for us to invoke the NT Cache Manager. It is possible in such
1579             // situations for the call to be no'oped (unless some user has
1580             // mapped in the file)
1581 
1582             // NOTE: The invocation to CcSetFileSizes() will quite possibly
1583             //  result in a recursive call back into the file system.
1584             //  This is because the NT Cache Manager will typically
1585             //  perform a flush before telling the VMM to purge pages
1586             //  especially when caching has not been initiated on the
1587             //  file stream, but the user has mapped the file into
1588             //  the process' virtual address space.
1589             MmPrint(("    CcSetFileSizes()\n"));
1590             Fcb->NTRequiredFCB->AcqFlushCount++;
1591             CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&(Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize));
1592             Fcb->NTRequiredFCB->AcqFlushCount--;
1593             Fcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED;
1594 
1595             // Inform any pending IRPs (notify change directory).
1596             if(UDFIsAStream(Fcb->FileInfo)) {
1597                 UDFNotifyFullReportChange( Vcb, Fcb->FileInfo,
1598                                            FILE_NOTIFY_CHANGE_STREAM_SIZE,
1599                                            FILE_ACTION_MODIFIED_STREAM);
1600             } else {
1601                 UDFNotifyFullReportChange( Vcb, Fcb->FileInfo,
1602                                            FILE_NOTIFY_CHANGE_SIZE,
1603                                            FILE_ACTION_MODIFIED);
1604             }
1605         }
1606 
1607 try_exit: NOTHING;
1608 
1609     } _SEH2_FINALLY {
1610         if(AcquiredPagingIo) {
1611             UDFReleaseResource(&(Fcb->NTRequiredFCB->PagingIoResource));
1612             AcquiredPagingIo = FALSE;
1613         }
1614         if (CacheMapInitialized) {
1615 
1616             MmPrint(("    CcUninitializeCacheMap()\n"));
1617             CcUninitializeCacheMap( FileObject, NULL, NULL );
1618         }
1619     } _SEH2_END;
1620     return(RC);
1621 } // end UDFSetAllocationInformation()
1622 
1623 /*
1624     Set end of file (resize).
1625  */
1626 NTSTATUS
1627 UDFSetEOF(
1628     IN PIO_STACK_LOCATION              PtrSp,
1629     IN PtrUDFFCB                       Fcb,
1630     IN PtrUDFCCB                       Ccb,
1631     IN PVCB                            Vcb,
1632     IN PFILE_OBJECT                    FileObject,
1633     IN PIRP                            Irp,
1634     IN PFILE_END_OF_FILE_INFORMATION   PtrBuffer
1635     )
1636 {
1637     NTSTATUS        RC = STATUS_SUCCESS;
1638     BOOLEAN         TruncatedFile = FALSE;
1639     BOOLEAN         ModifiedAllocSize = FALSE;
1640     ULONG           Attr;
1641     PDIR_INDEX_ITEM DirNdx;
1642     PtrUDFNTRequiredFCB NtReqFcb = NULL;
1643     LONGLONG        OldFileSize;
1644 //    BOOLEAN         ZeroBlock;
1645     BOOLEAN         CacheMapInitialized = FALSE;
1646     BOOLEAN         AcquiredPagingIo = FALSE;
1647 
1648     AdPrint(("UDFSetEOF\n"));
1649 
1650     _SEH2_TRY {
1651         // Increasing the allocation size associated with a file stream
1652         // is relatively easy. All we have to do is execute some FSD
1653         // specific code to check whether we have enough space available
1654         // (and if the FSD supports user/volume quotas, whether the user
1655         // is not exceeding quota), and then increase the file size in the
1656         // corresponding on-disk and in-memory structures.
1657         // Then, all we should do is inform the Cache Manager about the
1658         // increased allocation size.
1659 
1660         // First, do whatever error checking is appropriate here (e.g. whether
1661         // the caller is trying the change size for a directory, etc.).
1662         if(Fcb->FCBFlags & UDF_FCB_DIRECTORY)
1663             try_return(RC = STATUS_INVALID_PARAMETER);
1664 
1665         NtReqFcb = Fcb->NTRequiredFCB;
1666 
1667         if((Fcb->FCBFlags & UDF_FCB_DELETED) ||
1668            (NtReqFcb->NtReqFCBFlags & UDF_NTREQ_FCB_DELETED)) {
1669 #ifdef UDF_DBG
1670             if(UDFGetFileLinkCount(Fcb->FileInfo) < 1) {
1671                 BrutePoint();
1672                 try_return(RC = STATUS_SUCCESS);
1673             } else
1674 #endif // UDF_DBG
1675                 try_return(RC = STATUS_SUCCESS);
1676         }
1677 
1678         NtReqFcb->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb);
1679 
1680         if ((FileObject->SectionObjectPointer->DataSectionObject != NULL) &&
1681             (FileObject->SectionObjectPointer->SharedCacheMap == NULL) &&
1682             !(Irp->Flags & IRP_PAGING_IO)) {
1683             ASSERT( !FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE ) );
1684             //  Now initialize the cache map.
1685             MmPrint(("    CcInitializeCacheMap()\n"));
1686             CcInitializeCacheMap( FileObject,
1687                                   (PCC_FILE_SIZES)&Fcb->NTRequiredFCB->CommonFCBHeader.AllocationSize,
1688                                   FALSE,
1689                                   &(UDFGlobalData.CacheMgrCallBacks),
1690                                   Fcb->NTRequiredFCB );
1691 
1692             CacheMapInitialized = TRUE;
1693         }
1694 
1695         AcquiredPagingIo = UDFAcquireResourceExclusiveWithCheck(&(Fcb->NTRequiredFCB->PagingIoResource));
1696         //  Do a special case here for the lazy write of file sizes.
1697         if(PtrSp->Parameters.SetFile.AdvanceOnly) {
1698             //  Never have the dirent filesize larger than the fcb filesize
1699             PtrBuffer->EndOfFile.QuadPart =
1700                 min(PtrBuffer->EndOfFile.QuadPart,
1701                     NtReqFcb->CommonFCBHeader.FileSize.QuadPart);
1702             //  Only advance the file size, never reduce it with this call
1703             RC = STATUS_SUCCESS;
1704             if(UDFGetFileSizeFromDirNdx(Vcb, Fcb->FileInfo) >=
1705                PtrBuffer->EndOfFile.QuadPart)
1706                 try_return(RC);
1707 
1708             UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, &(PtrBuffer->EndOfFile.QuadPart));
1709             goto notify_size_changes;
1710         }
1711 
1712         //             !!! IMPORTANT !!!
1713 
1714         // We can get here after all Handles to the file are closed
1715         // To prevent allocation size incoherency we should
1716         // reference FileInfo _before_ call to UDFResizeFile__()
1717         // and use UDFCloseFile__() _after_ that
1718 
1719         // Are we increasing the allocation size?
1720         OldFileSize = NtReqFcb->CommonFCBHeader.FileSize.QuadPart;
1721         if(OldFileSize < PtrBuffer->EndOfFile.QuadPart) {
1722 
1723             // Yes. Do the FSD specific stuff i.e. increase reserved
1724             // space on disk.
1725 /*
1726             if (FileObject->PrivateCacheMap)
1727                 ZeroBlock = TRUE;
1728 */
1729 
1730             // reference file to pretend that it is opened
1731             UDFReferenceFile__(Fcb->FileInfo);
1732             UDFInterlockedIncrement((PLONG)&(Fcb->ReferenceCount));
1733             UDFInterlockedIncrement((PLONG)&(NtReqFcb->CommonRefCount));
1734             // perform resize operation
1735             RC = UDFResizeFile__(Vcb, Fcb->FileInfo, PtrBuffer->EndOfFile.QuadPart);
1736             // dereference file
1737             UDFCloseFile__(Vcb, Fcb->FileInfo);
1738             UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount));
1739             UDFInterlockedDecrement((PLONG)&(NtReqFcb->CommonRefCount));
1740             // update values in NtReqFcb
1741             NtReqFcb->CommonFCBHeader.FileSize.QuadPart =
1742 //            NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart =
1743                 PtrBuffer->EndOfFile.QuadPart;
1744             ModifiedAllocSize = TRUE;
1745 
1746         } else if(NtReqFcb->CommonFCBHeader.FileSize.QuadPart >
1747                                          PtrBuffer->EndOfFile.QuadPart) {
1748 
1749             // This is the painful part. See if the VMM will allow us to proceed.
1750             // The VMM will deny the request if:
1751             // (a) any image section exists OR
1752             // (b) a data section exists and the size of the user mapped view
1753             //       is greater than the new size
1754             // Otherwise, the VMM should allow the request to proceed.
1755 
1756             MmPrint(("    MmCanFileBeTruncated()\n"));
1757             if(!MmCanFileBeTruncated(&(NtReqFcb->SectionObject), &(PtrBuffer->EndOfFile))) {
1758                 // VMM said no way!
1759                 try_return(RC = STATUS_USER_MAPPED_FILE);
1760             }
1761 
1762             // Perform directory entry modifications. Release any on-disk
1763             // space we may need to in the process.
1764             UDFReferenceFile__(Fcb->FileInfo);
1765             UDFInterlockedIncrement((PLONG)&(Fcb->ReferenceCount));
1766             UDFInterlockedIncrement((PLONG)&(NtReqFcb->CommonRefCount));
1767             // perform resize operation
1768             RC = UDFResizeFile__(Vcb, Fcb->FileInfo, PtrBuffer->EndOfFile.QuadPart);
1769             // dereference file
1770             UDFCloseFile__(Vcb, Fcb->FileInfo);
1771             UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount));
1772             UDFInterlockedDecrement((PLONG)&(NtReqFcb->CommonRefCount));
1773 
1774             ModifiedAllocSize = TRUE;
1775             TruncatedFile = TRUE;
1776         }
1777 
1778         // This is a good place to check if we have performed a truncate
1779         // operation. If we have perform a truncate (whether we extended
1780         // or reduced file size), we should update file time stamps.
1781 
1782         // Last, but not the least, we must inform the Cache Manager of file size changes.
1783         if(ModifiedAllocSize && NT_SUCCESS(RC)) {
1784             // If we decreased the allocation size to less than the
1785             // current file size, modify the file size value.
1786             // Similarly, if we decreased the value to less than the
1787             // current valid data length, modify that value as well.
1788             if(TruncatedFile) {
1789                 if(NtReqFcb->CommonFCBHeader.ValidDataLength.QuadPart >
1790                     PtrBuffer->EndOfFile.QuadPart) {
1791                     // Decrease the valid data length value.
1792                     NtReqFcb->CommonFCBHeader.ValidDataLength =
1793                         PtrBuffer->EndOfFile;
1794                 }
1795                 if(NtReqFcb->CommonFCBHeader.FileSize.QuadPart >
1796                     PtrBuffer->EndOfFile.QuadPart) {
1797                     // Decrease the file size value.
1798                     NtReqFcb->CommonFCBHeader.FileSize =
1799                         PtrBuffer->EndOfFile;
1800                 }
1801                 UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, NULL);
1802             } else {
1803                 // Update the FCB Header with the new allocation size.
1804                 // NT expects AllocationSize to be decreased on Close only
1805                 NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart =
1806                     PtrBuffer->EndOfFile.QuadPart;
1807 //                    UDFSysGetAllocSize(Vcb, UDFGetFileSize(Fcb->FileInfo));
1808                 UDFSetFileSizeInDirNdx(Vcb, Fcb->FileInfo, &(PtrBuffer->EndOfFile.QuadPart));
1809             }
1810 
1811             FileObject->Flags |= FO_FILE_MODIFIED;
1812 //                UDFGetFileAllocationSize(Vcb, Fcb->FileInfo);
1813 
1814             // If the FCB has not had caching initiated, it is still valid
1815             // for us to invoke the NT Cache Manager. It is possible in such
1816             // situations for the call to be no'oped (unless some user has
1817             // mapped in the file)
1818 
1819             // Archive bit
1820             if(Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ARCH_BIT) {
1821                 DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(Fcb->FileInfo), Fcb->FileInfo->Index);
1822                 Ccb->CCBFlags &= ~UDF_CCB_ATTRIBUTES_SET;
1823                 Attr = UDFAttributesToNT(DirNdx, Fcb->FileInfo->Dloc->FileEntry);
1824                 if(!(Attr & FILE_ATTRIBUTE_ARCHIVE))
1825                     UDFAttributesToUDF(DirNdx, Fcb->FileInfo->Dloc->FileEntry, Attr | FILE_ATTRIBUTE_ARCHIVE);
1826             }
1827 
1828             // NOTE: The invocation to CcSetFileSizes() will quite possibly
1829             //  result in a recursive call back into the file system.
1830             //  This is because the NT Cache Manager will typically
1831             //  perform a flush before telling the VMM to purge pages
1832             //  especially when caching has not been initiated on the
1833             //  file stream, but the user has mapped the file into
1834             //  the process' virtual address space.
1835             MmPrint(("    CcSetFileSizes(), thrd:%8.8x\n",PsGetCurrentThread()));
1836             Fcb->NTRequiredFCB->AcqFlushCount++;
1837             CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&(NtReqFcb->CommonFCBHeader.AllocationSize));
1838             Fcb->NTRequiredFCB->AcqFlushCount--;
1839 /*            if(ZeroBlock) {
1840                 UDFZeroDataEx(NtReqFcb,
1841                               OldFileSize,
1842                               PtrBuffer->EndOfFile.QuadPart - OldFileSize,
1843                               TRUE // CanWait, Vcb, FileObject);
1844             }*/
1845             Fcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_MODIFIED;
1846 
1847 notify_size_changes:
1848             if(AcquiredPagingIo) {
1849                 UDFReleaseResource(&(Fcb->NTRequiredFCB->PagingIoResource));
1850                 AcquiredPagingIo = FALSE;
1851             }
1852 
1853             // Inform any pending IRPs (notify change directory).
1854             if(UDFIsAStream(Fcb->FileInfo)) {
1855                 UDFNotifyFullReportChange( Vcb, Fcb->FileInfo,
1856                                            FILE_NOTIFY_CHANGE_STREAM_SIZE,
1857                                            FILE_ACTION_MODIFIED_STREAM);
1858             } else {
1859                 UDFNotifyFullReportChange( Vcb, Fcb->FileInfo,
1860                                            FILE_NOTIFY_CHANGE_SIZE,
1861                                            FILE_ACTION_MODIFIED);
1862             }
1863         }
1864 
1865 try_exit: NOTHING;
1866 
1867     } _SEH2_FINALLY {
1868         if(AcquiredPagingIo) {
1869             UDFReleaseResource(&(Fcb->NTRequiredFCB->PagingIoResource));
1870             AcquiredPagingIo = FALSE;
1871         }
1872         if (CacheMapInitialized) {
1873 
1874             MmPrint(("    CcUninitializeCacheMap()\n"));
1875             CcUninitializeCacheMap( FileObject, NULL, NULL );
1876         }
1877     } _SEH2_END;
1878     return(RC);
1879 } // end UDFSetEOF()
1880 
1881 NTSTATUS
1882 UDFPrepareForRenameMoveLink(
1883     PVCB Vcb,
1884     PBOOLEAN AcquiredVcb,
1885     PBOOLEAN AcquiredVcbEx,
1886     PBOOLEAN SingleDir,
1887     PBOOLEAN AcquiredDir1,
1888     PBOOLEAN AcquiredFcb1,
1889     IN PtrUDFCCB Ccb1,
1890     PUDF_FILE_INFO File1,
1891     PUDF_FILE_INFO Dir1,
1892     PUDF_FILE_INFO Dir2,
1893     BOOLEAN HardLink
1894     )
1895 {
1896     // convert acquisition to Exclusive
1897     // this will prevent us from the following situation:
1898     // There is a pair of objects among input dirs &
1899     // one of them is a parent of another. Sequential resource
1900     // acquisition may lead to deadlock due to concurrent
1901     // CleanUpFcbChain() or UDFCloseFileInfoChain()
1902     UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount));
1903     UDFReleaseResource(&(Vcb->VCBResource));
1904     (*AcquiredVcb) = FALSE;
1905 
1906     // At first, make system to issue last Close request
1907     // for our Source & Target ...
1908     // we needn't flush/purge for Source on HLink
1909     UDFRemoveFromSystemDelayedQueue(Dir2->Fcb);
1910     if(!HardLink && (Dir2 != Dir1))
1911         UDFRemoveFromSystemDelayedQueue(File1->Fcb);
1912 
1913 #ifdef UDF_DELAYED_CLOSE
1914     _SEH2_TRY {
1915         // Do actual close for all "delayed close" calls
1916 
1917         // ... and now remove the rest from our queue
1918         if(!HardLink) {
1919             UDFCloseAllDelayedInDir(Vcb, Dir1);
1920             if(Dir2 != Dir1)
1921                 UDFCloseAllDelayedInDir(Vcb, Dir2);
1922         } else {
1923             UDFCloseAllDelayedInDir(Vcb, Dir2);
1924         }
1925 
1926     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
1927         BrutePoint();
1928         UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
1929         return (STATUS_DRIVER_INTERNAL_ERROR);
1930     } _SEH2_END;
1931 #endif //UDF_DELAYED_CLOSE
1932 
1933     (*SingleDir) = ((Dir1 == Dir2) && (Dir1->Fcb));
1934 
1935     if(!(*SingleDir) ||
1936        (UDFGetFileLinkCount(File1) != 1)) {
1937         UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
1938         (*AcquiredVcb) = TRUE;
1939         (*AcquiredVcbEx) = TRUE;
1940         UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
1941     } else {
1942         UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
1943         (*AcquiredVcb) = TRUE;
1944         UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount));
1945 
1946         UDF_CHECK_PAGING_IO_RESOURCE(Dir1->Fcb->NTRequiredFCB);
1947         UDFAcquireResourceExclusive(&(Dir1->Fcb->NTRequiredFCB->MainResource),TRUE);
1948         (*AcquiredDir1) = TRUE;
1949 
1950         UDF_CHECK_PAGING_IO_RESOURCE(File1->Fcb->NTRequiredFCB);
1951         UDFAcquireResourceExclusive(&(File1->Fcb->NTRequiredFCB->MainResource),TRUE);
1952         (*AcquiredFcb1) = TRUE;
1953     }
1954     return STATUS_SUCCESS;
1955 } // end UDFPrepareForRenameMoveLink()
1956 
1957 /*
1958     Rename or move file
1959  */
1960 NTSTATUS
1961 UDFRename(
1962     IN PIO_STACK_LOCATION PtrSp,
1963     IN PtrUDFFCB Fcb1,
1964     IN PtrUDFCCB Ccb1,
1965     IN PFILE_OBJECT FileObject1,   // Source File
1966     IN PFILE_RENAME_INFORMATION PtrBuffer
1967     )
1968 {
1969     // Source Directory
1970     PFILE_OBJECT DirObject1 = FileObject1->RelatedFileObject;
1971     // Target Directory
1972     PFILE_OBJECT DirObject2 = PtrSp->Parameters.SetFile.FileObject;
1973     // Overwite Flag
1974     BOOLEAN Replace = PtrSp->Parameters.SetFile.ReplaceIfExists &&
1975                       PtrBuffer->ReplaceIfExists;
1976     NTSTATUS RC;
1977     PVCB Vcb = Fcb1->Vcb;
1978     PtrUDFFCB Fcb2;
1979     BOOLEAN ic;
1980     BOOLEAN AcquiredVcb = TRUE;
1981     BOOLEAN AcquiredVcbEx = FALSE;
1982     BOOLEAN AcquiredDir1 = FALSE;
1983     BOOLEAN AcquiredFcb1 = FALSE;
1984     BOOLEAN SingleDir = TRUE;
1985     BOOLEAN UseClose;
1986 
1987     PUDF_FILE_INFO File1;
1988     PUDF_FILE_INFO Dir1;
1989     PUDF_FILE_INFO Dir2;
1990     PUDF_FILE_INFO NextFileInfo, fi;
1991 
1992     UNICODE_STRING NewName;
1993     UNICODE_STRING LocalPath;
1994     PtrUDFCCB CurCcb = NULL;
1995     PLIST_ENTRY Link;
1996     ULONG i;
1997     ULONG DirRefCount;
1998     ULONG FileInfoRefCount;
1999     ULONG Attr;
2000     PDIR_INDEX_ITEM DirNdx;
2001 
2002     AdPrint(("UDFRename %8.8x\n", DirObject2));
2003 
2004     LocalPath.Buffer = NULL;
2005 
2006     _SEH2_TRY {
2007         // do we try to rename Volume ?
2008 #ifdef UDF_ALLOW_RENAME_MOVE
2009         if(!(File1 = Fcb1->FileInfo))
2010 #endif //UDF_ALLOW_RENAME_MOVE
2011              try_return (RC = STATUS_ACCESS_DENIED);
2012 
2013         // do we try to rename RootDir ?
2014         if(!(Dir1 = File1->ParentFile))
2015             try_return (RC = STATUS_ACCESS_DENIED);
2016 
2017         // do we try to rename to RootDir or Volume ?
2018         if(!DirObject2) {
2019             Dir2 = File1->ParentFile;
2020             DirObject2 = DirObject1;
2021         } else
2022         if(DirObject2->FsContext2 &&
2023           (Fcb2 = ((PtrUDFCCB)(DirObject2->FsContext2))->Fcb)) {
2024             Dir2 = ((PtrUDFCCB)(DirObject2->FsContext2))->Fcb->FileInfo;
2025         } else {
2026             try_return (RC = STATUS_INVALID_PARAMETER);
2027         }
2028         // invalid destination ?
2029         if(!Dir2) try_return (RC = STATUS_ACCESS_DENIED);
2030 
2031         // Stream can't be a Dir or have StreamDir
2032         if(UDFIsAStreamDir(Dir2)) {
2033 #ifdef UDF_ENABLE_SECURITY
2034             if(UDFIsADirectory(File1)) {
2035                 try_return (RC = STATUS_ACCESS_DENIED);
2036             }
2037             // We should check whether File1 has only Internal
2038             // (or Deleted) streams. In this case SDir should be
2039             // removed (in UDFRenameMoveFile__()). Otherwise
2040             // return STATUS_ACCESS_DENIED
2041             if(UDFHasAStreamDir(File1)) {
2042                 UDFPrint(("TODO: We should remove Streams from source file\n"));
2043                 try_return (RC = STATUS_ACCESS_DENIED);
2044             }
2045 #else  //UDF_ENABLE_SECURITY
2046             if(UDFIsADirectory(File1) ||
2047                UDFHasAStreamDir(File1)) {
2048                 try_return (RC = STATUS_ACCESS_DENIED);
2049             }
2050 #endif //UDF_ENABLE_SECURITY
2051         }
2052 
2053         RC = UDFPrepareForRenameMoveLink(Vcb, &AcquiredVcb, &AcquiredVcbEx,
2054                                          &SingleDir,
2055                                          &AcquiredDir1, &AcquiredFcb1,
2056                                          Ccb1, File1,
2057                                          Dir1, Dir2,
2058                                          FALSE);  // it is Rename operation
2059         if(!NT_SUCCESS(RC))
2060             try_return(RC);
2061 
2062         // check if the source file is in use
2063         if(Fcb1->OpenHandleCount > 1)
2064             try_return (RC = STATUS_ACCESS_DENIED);
2065         ASSERT(Fcb1->OpenHandleCount);
2066         ASSERT(!Fcb1->IrpContextLite);
2067         if(Fcb1->IrpContextLite) {
2068             try_return (RC = STATUS_ACCESS_DENIED);
2069         }
2070         // Check if we have parallel/pending Close threads
2071         if(Fcb1->CcbCount && !SingleDir) {
2072             // if this is the 1st attempt, we'll try to
2073             // synchronize with Close requests
2074             // otherwise fail request
2075             RC = STATUS_ACCESS_DENIED;
2076 post_rename:
2077             if(Fcb1->FCBFlags & UDF_FCB_POSTED_RENAME) {
2078                 Fcb1->FCBFlags &= ~UDF_FCB_POSTED_RENAME;
2079                 try_return (RC);
2080             }
2081             Fcb1->FCBFlags |= UDF_FCB_POSTED_RENAME;
2082             try_return (RC = STATUS_PENDING);
2083         }
2084 
2085         if(!DirObject2) {
2086             //  Make sure the name is of legal length.
2087             if(PtrBuffer->FileNameLength > UDF_NAME_LEN*sizeof(WCHAR)) {
2088                 try_return(RC = STATUS_OBJECT_NAME_INVALID);
2089             }
2090             NewName.Length = NewName.MaximumLength = (USHORT)(PtrBuffer->FileNameLength);
2091             NewName.Buffer = (PWCHAR)&(PtrBuffer->FileName);
2092         } else {
2093             //  This name is by definition legal.
2094             NewName = *((PUNICODE_STRING)&DirObject2->FileName);
2095         }
2096 
2097         ic = (Ccb1->CCBFlags & UDF_CCB_CASE_SENSETIVE) ? FALSE : TRUE;
2098 
2099         AdPrint(("  %ws ->\n    %ws\n",
2100             Fcb1->FCBName->ObjectName.Buffer,
2101             NewName.Buffer));
2102 
2103         if(UDFIsDirOpened__(File1)) {
2104             // We can't rename file because of unclean references.
2105             // UDF_INFO package can safely do it, but NT side cannot.
2106             // In this case NT requires STATUS_OBJECT_NAME_COLLISION
2107             // rather than STATUS_ACCESS_DENIED
2108             if(NT_SUCCESS(UDFFindFile__(Vcb, ic, &NewName, Dir2)))
2109                 try_return(RC = STATUS_OBJECT_NAME_COLLISION);
2110             try_return (RC = STATUS_ACCESS_DENIED);
2111         } else {
2112             // Last check before Moving.
2113             // We can't move across Dir referenced (even internally) file
2114             if(!SingleDir) {
2115                 RC = UDFDoesOSAllowFileToBeMoved__(File1);
2116                 if(!NT_SUCCESS(RC)) {
2117 //                    try_return(RC);
2118                     goto post_rename;
2119                 }
2120             }
2121 
2122             ASSERT_REF(Fcb1->ReferenceCount >= File1->RefCount);
2123             ASSERT_REF(Dir1->Fcb->ReferenceCount >= Dir1->RefCount);
2124             ASSERT_REF(Dir2->Fcb->ReferenceCount >= Dir2->RefCount);
2125 
2126             RC = UDFRenameMoveFile__(Vcb, ic, &Replace, &NewName, Dir1, Dir2, File1);
2127         }
2128         if(!NT_SUCCESS(RC))
2129             try_return (RC);
2130 
2131         ASSERT(UDFDirIndex(File1->ParentFile->Dloc->DirIndex, File1->Index)->FileInfo == File1);
2132 
2133         RC = MyCloneUnicodeString(&LocalPath, (Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ?
2134                                                     &UDFGlobalData.UnicodeStrRoot :
2135                                                     &(Dir2->Fcb->FCBName->ObjectName) );
2136         if(!NT_SUCCESS(RC)) try_return (RC);
2137 //        RC = MyAppendUnicodeStringToString(&LocalPath, (Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? &(UDFGlobalData.UnicodeStrRoot) : &(Dir2->Fcb->FCBName->ObjectName));
2138 //        if(!NT_SUCCESS(RC)) try_return (RC);
2139         if(Dir2->ParentFile) {
2140             RC = MyAppendUnicodeToString(&LocalPath, L"\\");
2141             if(!NT_SUCCESS(RC)) try_return (RC);
2142         }
2143         RC = MyAppendUnicodeStringToStringTag(&LocalPath, &NewName, MEM_USREN_TAG);
2144         if(!NT_SUCCESS(RC)) try_return (RC);
2145 
2146         // Set Archive bit
2147         DirNdx = UDFDirIndex(File1->ParentFile->Dloc->DirIndex, File1->Index);
2148         if(Vcb->CompatFlags & UDF_VCB_IC_UPDATE_ARCH_BIT) {
2149             Attr = UDFAttributesToNT(DirNdx, File1->Dloc->FileEntry);
2150             if(!(Attr & FILE_ATTRIBUTE_ARCHIVE))
2151                 UDFAttributesToUDF(DirNdx, File1->Dloc->FileEntry, Attr | FILE_ATTRIBUTE_ARCHIVE);
2152         }
2153         // Update Parent Objects (mark 'em as modified)
2154         if(Vcb->CompatFlags & UDF_VCB_IC_UPDATE_DIR_WRITE) {
2155             if(DirObject1)
2156                 DirObject1->Flags |= FO_FILE_MODIFIED;
2157             if(DirObject2) {
2158                 DirObject2->Flags |= FO_FILE_MODIFIED;
2159                 if(!Replace)
2160                     DirObject2->Flags |= FO_FILE_SIZE_CHANGED;
2161             }
2162         }
2163         // report changes
2164         if(SingleDir && !Replace) {
2165             UDFNotifyFullReportChange( Vcb, File1,
2166                                        UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
2167                                        FILE_ACTION_RENAMED_OLD_NAME);
2168 /*          UDFNotifyFullReportChange( Vcb, File2,
2169                                        UDFIsADirectory(File2) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
2170                                        FILE_ACTION_RENAMED_NEW_NAME );*/
2171             FsRtlNotifyFullReportChange( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP),
2172                                          (PSTRING)&LocalPath,
2173                                          ((Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? 0 : Dir2->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR),
2174                                          NULL,NULL,
2175                                          UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
2176                                          FILE_ACTION_RENAMED_NEW_NAME,
2177                                          NULL);
2178         } else {
2179             UDFNotifyFullReportChange( Vcb, File1,
2180                                        UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
2181                                        FILE_ACTION_REMOVED);
2182             if(Replace) {
2183 /*              UDFNotifyFullReportChange( Vcb, File2,
2184                                        FILE_NOTIFY_CHANGE_ATTRIBUTES |
2185                                        FILE_NOTIFY_CHANGE_SIZE |
2186                                        FILE_NOTIFY_CHANGE_LAST_WRITE |
2187                                        FILE_NOTIFY_CHANGE_LAST_ACCESS |
2188                                        FILE_NOTIFY_CHANGE_CREATION |
2189                                        FILE_NOTIFY_CHANGE_EA,
2190                                        FILE_ACTION_MODIFIED );*/
2191                 FsRtlNotifyFullReportChange( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP),
2192                                              (PSTRING)&LocalPath,
2193                                              ((Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ?
2194                                                  0 : Dir2->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR),
2195                                              NULL,NULL,
2196                                              FILE_NOTIFY_CHANGE_ATTRIBUTES |
2197                                                  FILE_NOTIFY_CHANGE_SIZE |
2198                                                  FILE_NOTIFY_CHANGE_LAST_WRITE |
2199                                                  FILE_NOTIFY_CHANGE_LAST_ACCESS |
2200                                                  FILE_NOTIFY_CHANGE_CREATION |
2201                                                  FILE_NOTIFY_CHANGE_EA,
2202                                              FILE_ACTION_MODIFIED,
2203                                              NULL);
2204             } else {
2205 /*              UDFNotifyFullReportChange( Vcb, File2,
2206                                        UDFIsADirectory(File2) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
2207                                        FILE_ACTION_ADDED );*/
2208                 FsRtlNotifyFullReportChange( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP),
2209                                              (PSTRING)&LocalPath,
2210                                              ((Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ?
2211                                                  0 : Dir2->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR),
2212                                              NULL,NULL,
2213                                              UDFIsADirectory(File1) ?
2214                                                  FILE_NOTIFY_CHANGE_DIR_NAME :
2215                                                  FILE_NOTIFY_CHANGE_FILE_NAME,
2216                                              FILE_ACTION_ADDED,
2217                                              NULL);
2218             }
2219         }
2220 
2221         // this will prevent structutre release before call to
2222         // UDFCleanUpFcbChain()
2223         UDFInterlockedIncrement((PLONG)&(Dir1->Fcb->ReferenceCount));
2224         UDFInterlockedIncrement((PLONG)&(Dir1->Fcb->NTRequiredFCB->CommonRefCount));
2225         ASSERT_REF(Dir1->Fcb->ReferenceCount >= Dir1->RefCount);
2226 
2227         // Look through Ccb list & decrement OpenHandleCounter(s)
2228         // acquire CcbList
2229         if(!SingleDir) {
2230             UDFAcquireResourceExclusive(&(Fcb1->CcbListResource),TRUE);
2231             Link = Fcb1->NextCCB.Flink;
2232             DirRefCount = 0;
2233             FileInfoRefCount = 0;
2234             ASSERT(Link != &(Fcb1->NextCCB));
2235             while (Link != &(Fcb1->NextCCB)) {
2236                 NextFileInfo = Dir1;
2237                 CurCcb = CONTAINING_RECORD(Link, UDFCCB, NextCCB);
2238                 ASSERT(CurCcb->TreeLength);
2239                 i = (CurCcb->TreeLength) ? (CurCcb->TreeLength - 1) : 0;
2240                 Link = Link->Flink;
2241                 UseClose = (CurCcb->CCBFlags & UDF_CCB_CLEANED) ? FALSE : TRUE;
2242 
2243                 AdPrint(("  Ccb:%x:%s:i:%x\n", CurCcb, UseClose ? "Close" : "",i));
2244                 // cleanup old parent chain
2245                 for(; i && NextFileInfo; i--) {
2246                     // remember parent file now
2247                     // it will prevent us from data losses
2248                     // due to eventual structure release
2249                     fi = NextFileInfo->ParentFile;
2250                     if(UseClose) {
2251                         ASSERT_REF(NextFileInfo->Fcb->ReferenceCount >= NextFileInfo->RefCount);
2252                         UDFCloseFile__(Vcb, NextFileInfo);
2253                     }
2254                     ASSERT_REF(NextFileInfo->Fcb->ReferenceCount > NextFileInfo->RefCount);
2255                     ASSERT_REF(NextFileInfo->Fcb->ReferenceCount);
2256                     ASSERT_REF(NextFileInfo->Fcb->NTRequiredFCB->CommonRefCount);
2257                     UDFInterlockedDecrement((PLONG)&(NextFileInfo->Fcb->ReferenceCount));
2258                     UDFInterlockedDecrement((PLONG)&(NextFileInfo->Fcb->NTRequiredFCB->CommonRefCount));
2259                     ASSERT_REF(NextFileInfo->Fcb->ReferenceCount >= NextFileInfo->RefCount);
2260                     NextFileInfo = fi;
2261                 }
2262 
2263                 if(CurCcb->TreeLength > 1) {
2264                     DirRefCount++;
2265                     if(UseClose)
2266                         FileInfoRefCount++;
2267                     CurCcb->TreeLength = 2;
2268 #ifdef UDF_DBG
2269                 } else {
2270                     BrutePoint();
2271 #endif // UDF_DBG
2272                 }
2273             }
2274             UDFReleaseResource(&(Fcb1->CcbListResource));
2275 
2276             ASSERT_REF(DirRefCount >= FileInfoRefCount);
2277             // update counters & pointers
2278             Fcb1->ParentFcb = Dir2->Fcb;
2279             // move references to Dir2
2280             UDFInterlockedExchangeAdd((PLONG)&(Dir2->Fcb->ReferenceCount), DirRefCount);
2281             UDFInterlockedExchangeAdd((PLONG)&(Dir2->Fcb->NTRequiredFCB->CommonRefCount), DirRefCount);
2282             ASSERT_REF(Dir2->Fcb->ReferenceCount > Dir2->RefCount);
2283             UDFReferenceFileEx__(Dir2,FileInfoRefCount);
2284             ASSERT_REF(Dir2->Fcb->ReferenceCount >= Dir2->RefCount);
2285         }
2286         ASSERT_REF(Dir2->Fcb->ReferenceCount >= Dir2->RefCount);
2287         ASSERT_REF(Dir2->RefCount);
2288 
2289         ASSERT_REF(Dir1->Fcb->ReferenceCount >= Dir1->RefCount);
2290         // Modify name in Fcb1
2291         if(Fcb1->FCBName) {
2292             if(Fcb1->FCBName->ObjectName.Buffer) {
2293                 MyFreePool__(Fcb1->FCBName->ObjectName.Buffer);
2294             }
2295             UDFReleaseObjectName(Fcb1->FCBName);
2296         }
2297         Fcb1->FCBName = UDFAllocateObjectName();
2298         if(!(Fcb1->FCBName)) {
2299 insuf_res:
2300             BrutePoint();
2301             // UDFCleanUpFcbChain()...
2302             if(AcquiredFcb1) {
2303                 UDF_CHECK_PAGING_IO_RESOURCE(Fcb1->NTRequiredFCB);
2304                 UDFReleaseResource(&(Fcb1->NTRequiredFCB->MainResource));
2305                 AcquiredDir1 = FALSE;
2306             }
2307             if(AcquiredDir1) {
2308                 UDF_CHECK_PAGING_IO_RESOURCE(Dir1->Fcb->NTRequiredFCB);
2309                 UDFReleaseResource(&(Dir1->Fcb->NTRequiredFCB->MainResource));
2310                 AcquiredDir1 = FALSE;
2311             }
2312             UDFCleanUpFcbChain(Vcb, Dir1, 1, TRUE);
2313             try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
2314         }
2315 
2316         RC = MyCloneUnicodeString(&(Fcb1->FCBName->ObjectName), &(Fcb2->FCBName->ObjectName));
2317         if(!NT_SUCCESS(RC))
2318             goto insuf_res;
2319 /*        RC = MyAppendUnicodeStringToString(&(Fcb1->FCBName->ObjectName), &(Fcb2->FCBName->ObjectName));
2320         if(!NT_SUCCESS(RC))
2321             goto insuf_res;*/
2322         // if Dir2 is a RootDir, we shoud not append '\\' because
2323         // uit will be the 2nd '\\' character (RootDir's name is also '\\')
2324         if(Dir2->ParentFile) {
2325             RC = MyAppendUnicodeToString(&(Fcb1->FCBName->ObjectName), L"\\");
2326             if(!NT_SUCCESS(RC))
2327                 goto insuf_res;
2328         }
2329         RC = MyAppendUnicodeStringToStringTag(&(Fcb1->FCBName->ObjectName), &NewName, MEM_USREN2_TAG);
2330         if(!NT_SUCCESS(RC))
2331             goto insuf_res;
2332 
2333         ASSERT_REF(Fcb1->ReferenceCount >= File1->RefCount);
2334         ASSERT_REF(Dir1->Fcb->ReferenceCount >= Dir1->RefCount);
2335         ASSERT_REF(Dir2->Fcb->ReferenceCount >= Dir2->RefCount);
2336 
2337         RC = STATUS_SUCCESS;
2338 
2339 try_exit:    NOTHING;
2340 
2341     } _SEH2_FINALLY {
2342 
2343         if(AcquiredFcb1) {
2344             UDF_CHECK_PAGING_IO_RESOURCE(Fcb1->NTRequiredFCB);
2345             UDFReleaseResource(&(Fcb1->NTRequiredFCB->MainResource));
2346         }
2347         if(AcquiredDir1) {
2348             UDF_CHECK_PAGING_IO_RESOURCE(Dir1->Fcb->NTRequiredFCB);
2349             UDFReleaseResource(&(Dir1->Fcb->NTRequiredFCB->MainResource));
2350         }
2351         // perform protected structure release
2352         if(NT_SUCCESS(RC) &&
2353            (RC != STATUS_PENDING)) {
2354             ASSERT(AcquiredVcb);
2355             UDFCleanUpFcbChain(Vcb, Dir1, 1, TRUE);
2356             ASSERT_REF(Fcb1->ReferenceCount >= File1->RefCount);
2357             ASSERT_REF(Dir2->Fcb->ReferenceCount >= Dir2->RefCount);
2358         }
2359 
2360         if(AcquiredVcb) {
2361             if(AcquiredVcbEx)
2362                 UDFConvertExclusiveToSharedLite(&(Vcb->VCBResource));
2363         } else {
2364             // caller assumes Vcb to be acquired shared
2365             BrutePoint();
2366             UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
2367         }
2368 
2369         if(LocalPath.Buffer) {
2370             MyFreePool__(LocalPath.Buffer);
2371         }
2372     } _SEH2_END;
2373 
2374     return RC;
2375 } // end UDFRename()
2376 
2377 #endif //UDF_READ_ONLY_BUILD
2378 
2379 LONG
2380 UDFFindFileId(
2381     IN PVCB Vcb,
2382     IN LONGLONG Id
2383     )
2384 {
2385     if(!Vcb->FileIdCache) return (-1);
2386     for(ULONG i=0; i<Vcb->FileIdCount; i++) {
2387         if(Vcb->FileIdCache[i].Id == Id) return i;
2388     }
2389     return (-1);
2390 } // end UDFFindFileId()
2391 
2392 LONG
2393 UDFFindFreeFileId(
2394     IN PVCB Vcb,
2395     IN LONGLONG Id
2396     )
2397 {
2398     if(!Vcb->FileIdCache) {
2399         if(!(Vcb->FileIdCache = (PUDFFileIDCacheItem)MyAllocatePool__(NonPagedPool, sizeof(UDFFileIDCacheItem)*FILE_ID_CACHE_GRANULARITY)))
2400             return (-1);
2401         RtlZeroMemory(Vcb->FileIdCache, FILE_ID_CACHE_GRANULARITY*sizeof(UDFFileIDCacheItem));
2402         Vcb->FileIdCount = FILE_ID_CACHE_GRANULARITY;
2403     }
2404     for(ULONG i=0; i<Vcb->FileIdCount; i++) {
2405         if(!Vcb->FileIdCache[i].FullName.Buffer) return i;
2406     }
2407     if(!MyReallocPool__((PCHAR)(Vcb->FileIdCache), Vcb->FileIdCount*sizeof(UDFFileIDCacheItem),
2408                      (PCHAR*)&(Vcb->FileIdCache), (Vcb->FileIdCount+FILE_ID_CACHE_GRANULARITY)*sizeof(UDFFileIDCacheItem))) {
2409         return (-1);
2410     }
2411     RtlZeroMemory(&(Vcb->FileIdCache[Vcb->FileIdCount]), FILE_ID_CACHE_GRANULARITY*sizeof(UDFFileIDCacheItem));
2412     Vcb->FileIdCount += FILE_ID_CACHE_GRANULARITY;
2413     return (Vcb->FileIdCount - FILE_ID_CACHE_GRANULARITY);
2414 } // end UDFFindFreeFileId()
2415 
2416 NTSTATUS
2417 UDFStoreFileId(
2418     IN PVCB Vcb,
2419     IN PtrUDFCCB Ccb,
2420     IN PUDF_FILE_INFO fi,
2421     IN LONGLONG Id
2422     )
2423 {
2424     LONG i;
2425     NTSTATUS RC = STATUS_SUCCESS;
2426 
2427     if((i = UDFFindFileId(Vcb, Id)) == (-1)) {
2428         if((i = UDFFindFreeFileId(Vcb, Id)) == (-1)) return STATUS_INSUFFICIENT_RESOURCES;
2429     } else {
2430         return STATUS_SUCCESS;
2431     }
2432     Vcb->FileIdCache[i].Id = Id;
2433     Vcb->FileIdCache[i].CaseSens = (Ccb->CCBFlags & UDF_CCB_CASE_SENSETIVE) ? TRUE : FALSE;
2434     RC = MyCloneUnicodeString(&(Vcb->FileIdCache[i].FullName), &(Ccb->Fcb->FCBName->ObjectName));
2435 /*    if(NT_SUCCESS(RC)) {
2436         RC = MyAppendUnicodeStringToStringTag(&(Vcb->FileIdCache[i].FullName), &(Ccb->Fcb->FCBName->ObjectName), MEM_USFIDC_TAG);
2437     }*/
2438     return RC;
2439 } // end UDFStoreFileId()
2440 
2441 NTSTATUS
2442 UDFRemoveFileId(
2443     IN PVCB Vcb,
2444     IN LONGLONG Id
2445     )
2446 {
2447     LONG i;
2448 
2449     if((i = UDFFindFileId(Vcb, Id)) == (-1)) return STATUS_INVALID_PARAMETER;
2450     MyFreePool__(Vcb->FileIdCache[i].FullName.Buffer);
2451     RtlZeroMemory(&(Vcb->FileIdCache[i]), sizeof(UDFFileIDCacheItem));
2452     return STATUS_SUCCESS;
2453 } // end UDFRemoveFileId()
2454 
2455 VOID
2456 UDFReleaseFileIdCache(
2457     IN PVCB Vcb
2458     )
2459 {
2460     if(!Vcb->FileIdCache) return;
2461     for(ULONG i=0; i<Vcb->FileIdCount; i++) {
2462         if(Vcb->FileIdCache[i].FullName.Buffer) {
2463             MyFreePool__(Vcb->FileIdCache[i].FullName.Buffer);
2464         }
2465     }
2466     MyFreePool__(Vcb->FileIdCache);
2467     Vcb->FileIdCache = NULL;
2468     Vcb->FileIdCount = 0;
2469 } // end UDFReleaseFileIdCache()
2470 
2471 NTSTATUS
2472 UDFGetOpenParamsByFileId(
2473     IN PVCB Vcb,
2474     IN LONGLONG Id,
2475     OUT PUNICODE_STRING* FName,
2476     OUT BOOLEAN* CaseSens
2477     )
2478 {
2479     LONG i;
2480 
2481     if((i = UDFFindFileId(Vcb, Id)) == (-1)) return STATUS_NOT_FOUND;
2482     (*FName) = &(Vcb->FileIdCache[i].FullName);
2483     (*CaseSens) = !(Vcb->FileIdCache[i].CaseSens);
2484     return STATUS_SUCCESS;
2485 } // end UDFGetOpenParamsByFileId()
2486 
2487 #ifndef UDF_READ_ONLY_BUILD
2488 
2489 #ifdef UDF_ALLOW_HARD_LINKS
2490 /*
2491     create hard link for the file
2492  */
2493 NTSTATUS
2494 UDFHardLink(
2495     IN PIO_STACK_LOCATION PtrSp,
2496     IN PtrUDFFCB Fcb1,
2497     IN PtrUDFCCB Ccb1,
2498     IN PFILE_OBJECT FileObject1,   // Source File
2499     IN PFILE_LINK_INFORMATION PtrBuffer
2500     )
2501 {
2502     // Target Directory
2503     PFILE_OBJECT DirObject2 = PtrSp->Parameters.SetFile.FileObject;
2504     // Overwite Flag
2505     BOOLEAN Replace = PtrSp->Parameters.SetFile.ReplaceIfExists &&
2506                       PtrBuffer->ReplaceIfExists;
2507     NTSTATUS RC;
2508     PVCB Vcb = Fcb1->Vcb;
2509     PtrUDFFCB Fcb2;
2510     BOOLEAN ic;
2511     BOOLEAN AcquiredVcb = TRUE;
2512     BOOLEAN AcquiredVcbEx = FALSE;
2513     BOOLEAN AcquiredDir1 = FALSE;
2514     BOOLEAN AcquiredFcb1 = FALSE;
2515     BOOLEAN SingleDir = TRUE;
2516 
2517     PUDF_FILE_INFO File1;
2518     PUDF_FILE_INFO Dir1 = NULL;
2519     PUDF_FILE_INFO Dir2;
2520 
2521     UNICODE_STRING NewName;
2522     UNICODE_STRING LocalPath;
2523 //    PtrUDFCCB CurCcb = NULL;
2524 
2525     AdPrint(("UDFHardLink\n"));
2526 
2527     LocalPath.Buffer = NULL;
2528 
2529     _SEH2_TRY {
2530 
2531         // do we try to link Volume ?
2532         if(!(File1 = Fcb1->FileInfo))
2533             try_return (RC = STATUS_ACCESS_DENIED);
2534 
2535         // do we try to link RootDir ?
2536         if(!(Dir1 = File1->ParentFile))
2537             try_return (RC = STATUS_ACCESS_DENIED);
2538 
2539         // do we try to link Stream / Stream Dir ?
2540 #ifdef UDF_ALLOW_LINKS_TO_STREAMS
2541         if(UDFIsAStreamDir(File1))
2542             try_return (RC = STATUS_ACCESS_DENIED);
2543 #else //UDF_ALLOW_LINKS_TO_STREAMS
2544         if(UDFIsAStream(File1) || UDFIsAStreamDir(File1) /*||
2545            UDFIsADirectory(File1) || UDFHasAStreamDir(File1)*/)
2546             try_return (RC = STATUS_ACCESS_DENIED);
2547 #endif // UDF_ALLOW_LINKS_TO_STREAMS
2548 
2549         // do we try to link to RootDir or Volume ?
2550         if(!DirObject2) {
2551             Dir2 = File1->ParentFile;
2552             DirObject2 = FileObject1->RelatedFileObject;
2553         } else
2554         if(DirObject2->FsContext2 &&
2555           (Fcb2 = ((PtrUDFCCB)(DirObject2->FsContext2))->Fcb)) {
2556             Dir2 = ((PtrUDFCCB)(DirObject2->FsContext2))->Fcb->FileInfo;
2557         } else {
2558             try_return (RC = STATUS_INVALID_PARAMETER);
2559         }
2560 
2561         // check target dir
2562         if(!Dir2) try_return (RC = STATUS_ACCESS_DENIED);
2563 
2564         // Stream can't be a Dir or have Streams
2565         if(UDFIsAStreamDir(Dir2)) {
2566             try_return (RC = STATUS_ACCESS_DENIED);
2567 /*            if(UDFIsADirectory(File1) ||
2568                UDFHasAStreamDir(File1)) {
2569                 BrutePoint();
2570                 try_return (RC = STATUS_ACCESS_DENIED);
2571             }*/
2572         }
2573 
2574 /*        if(UDFIsAStreamDir(Dir2))
2575             try_return (RC = STATUS_ACCESS_DENIED);*/
2576 
2577         RC = UDFPrepareForRenameMoveLink(Vcb, &AcquiredVcb, &AcquiredVcbEx,
2578                                          &SingleDir,
2579                                          &AcquiredDir1, &AcquiredFcb1,
2580                                          Ccb1, File1,
2581                                          Dir1, Dir2,
2582                                          TRUE); // it is HLink operation
2583         if(!NT_SUCCESS(RC))
2584             try_return(RC);
2585 
2586         // check if the source file is used
2587         if(!DirObject2) {
2588             //  Make sure the name is of legal length.
2589             if(PtrBuffer->FileNameLength > UDF_NAME_LEN*sizeof(WCHAR)) {
2590                 try_return(RC = STATUS_OBJECT_NAME_INVALID);
2591             }
2592             NewName.Length = NewName.MaximumLength = (USHORT)(PtrBuffer->FileNameLength);
2593             NewName.Buffer = (PWCHAR)&(PtrBuffer->FileName);
2594         } else {
2595             //  This name is by definition legal.
2596             NewName = *((PUNICODE_STRING)&DirObject2->FileName);
2597         }
2598 
2599         ic = (Ccb1->CCBFlags & UDF_CCB_CASE_SENSETIVE) ? FALSE : TRUE;
2600 
2601         AdPrint(("  %ws ->\n    %ws\n",
2602             Fcb1->FCBName->ObjectName.Buffer,
2603             NewName.Buffer));
2604 
2605         RC = UDFHardLinkFile__(Vcb, ic, &Replace, &NewName, Dir1, Dir2, File1);
2606         if(!NT_SUCCESS(RC)) try_return (RC);
2607 
2608         // Update Parent Objects (mark 'em as modified)
2609         if(Vcb->CompatFlags & UDF_VCB_IC_UPDATE_DIR_WRITE) {
2610             if(DirObject2) {
2611                 DirObject2->Flags |= FO_FILE_MODIFIED;
2612                 if(!Replace)
2613                     DirObject2->Flags |= FO_FILE_SIZE_CHANGED;
2614             }
2615         }
2616         // report changes
2617         UDFNotifyFullReportChange( Vcb, File1,
2618                                    FILE_NOTIFY_CHANGE_LAST_WRITE |
2619                                    FILE_NOTIFY_CHANGE_LAST_ACCESS,
2620                                    FILE_ACTION_MODIFIED );
2621 
2622         RC = MyCloneUnicodeString(&LocalPath, (Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ?
2623                                                     &UDFGlobalData.UnicodeStrRoot :
2624                                                     &(Dir2->Fcb->FCBName->ObjectName));
2625         if(!NT_SUCCESS(RC)) try_return (RC);
2626 /*        RC = MyAppendUnicodeStringToString(&LocalPath, (Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? &(UDFGlobalData.UnicodeStrRoot) : &(Dir2->Fcb->FCBName->ObjectName));
2627         if(!NT_SUCCESS(RC)) try_return (RC);*/
2628         // if Dir2 is a RootDir, we shoud not append '\\' because
2629         // it will be the 2nd '\\' character (RootDir's name is also '\\')
2630         if(Dir2->ParentFile) {
2631             RC = MyAppendUnicodeToString(&LocalPath, L"\\");
2632             if(!NT_SUCCESS(RC)) try_return (RC);
2633         }
2634         RC = MyAppendUnicodeStringToStringTag(&LocalPath, &NewName, MEM_USHL_TAG);
2635         if(!NT_SUCCESS(RC)) try_return (RC);
2636 
2637         if(!Replace) {
2638 /*          UDFNotifyFullReportChange( Vcb, File2,
2639                                        UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
2640                                        FILE_ACTION_ADDED );*/
2641             FsRtlNotifyFullReportChange( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP),
2642                                          (PSTRING)&LocalPath,
2643                                          ((Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? 0 : Dir2->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR),
2644                                          NULL,NULL,
2645                                          UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
2646                                          FILE_ACTION_ADDED,
2647                                          NULL);
2648         } else {
2649 /*          UDFNotifyFullReportChange( Vcb, File2,
2650                                        FILE_NOTIFY_CHANGE_ATTRIBUTES |
2651                                        FILE_NOTIFY_CHANGE_SIZE |
2652                                        FILE_NOTIFY_CHANGE_LAST_WRITE |
2653                                        FILE_NOTIFY_CHANGE_LAST_ACCESS |
2654                                        FILE_NOTIFY_CHANGE_CREATION |
2655                                        FILE_NOTIFY_CHANGE_EA,
2656                                        FILE_ACTION_MODIFIED );*/
2657             FsRtlNotifyFullReportChange( Vcb->NotifyIRPMutex, &(Vcb->NextNotifyIRP),
2658                                          (PSTRING)&LocalPath,
2659                                          ((Dir2->Fcb->FCBFlags & UDF_FCB_ROOT_DIRECTORY) ? 0 : Dir2->Fcb->FCBName->ObjectName.Length) + sizeof(WCHAR),
2660                                          NULL,NULL,
2661                                          UDFIsADirectory(File1) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME,
2662                                          FILE_NOTIFY_CHANGE_ATTRIBUTES |
2663                                              FILE_NOTIFY_CHANGE_SIZE |
2664                                              FILE_NOTIFY_CHANGE_LAST_WRITE |
2665                                              FILE_NOTIFY_CHANGE_LAST_ACCESS |
2666                                              FILE_NOTIFY_CHANGE_CREATION |
2667                                              FILE_NOTIFY_CHANGE_EA,
2668                                          NULL);
2669         }
2670 
2671         RC = STATUS_SUCCESS;
2672 
2673 try_exit:    NOTHING;
2674 
2675     } _SEH2_FINALLY {
2676 
2677         if(AcquiredFcb1) {
2678             UDF_CHECK_PAGING_IO_RESOURCE(Fcb1->NTRequiredFCB);
2679             UDFReleaseResource(&(Fcb1->NTRequiredFCB->MainResource));
2680         }
2681         if(AcquiredDir1) {
2682             UDF_CHECK_PAGING_IO_RESOURCE(Dir1->Fcb->NTRequiredFCB);
2683             UDFReleaseResource(&(Dir1->Fcb->NTRequiredFCB->MainResource));
2684         }
2685         if(AcquiredVcb) {
2686             if(AcquiredVcbEx)
2687                 UDFConvertExclusiveToSharedLite(&(Vcb->VCBResource));
2688         } else {
2689             // caller assumes Vcb to be acquired shared
2690             BrutePoint();
2691             UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE);
2692         }
2693 
2694         if(LocalPath.Buffer) {
2695             MyFreePool__(LocalPath.Buffer);
2696         }
2697     } _SEH2_END;
2698 
2699     return RC;
2700 } // end UDFHardLink()
2701 #endif //UDF_ALLOW_HARD_LINKS
2702 
2703 #endif //UDF_READ_ONLY_BUILD
2704