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
UDFFileInfo(PDEVICE_OBJECT DeviceObject,PIRP Irp)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
UDFCommonFileInfo(PtrUDFIrpContext PtrIrpContext,PIRP Irp)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
UDFGetBasicInformation(IN PFILE_OBJECT FileObject,IN PtrUDFFCB Fcb,IN PFILE_BASIC_INFORMATION PtrBuffer,IN OUT LONG * PtrReturnedLength)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
UDFGetStandardInformation(IN PtrUDFFCB Fcb,IN PFILE_STANDARD_INFORMATION PtrBuffer,IN OUT LONG * PtrReturnedLength)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
UDFGetNetworkInformation(IN PtrUDFFCB Fcb,IN PFILE_NETWORK_OPEN_INFORMATION PtrBuffer,IN OUT PLONG PtrReturnedLength)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
UDFGetInternalInformation(PtrUDFIrpContext PtrIrpContext,IN PtrUDFFCB Fcb,IN PtrUDFCCB Ccb,IN PFILE_INTERNAL_INFORMATION PtrBuffer,IN OUT PLONG PtrReturnedLength)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
UDFGetEaInformation(PtrUDFIrpContext PtrIrpContext,IN PtrUDFFCB Fcb,IN PFILE_EA_INFORMATION PtrBuffer,IN OUT PLONG PtrReturnedLength)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
UDFGetFullNameInformation(IN PFILE_OBJECT FileObject,IN PFILE_NAME_INFORMATION PtrBuffer,IN OUT PLONG PtrReturnedLength)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
UDFGetAltNameInformation(IN PtrUDFFCB Fcb,IN PFILE_NAME_INFORMATION PtrBuffer,IN OUT PLONG PtrReturnedLength)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
UDFGetPositionInformation(IN PFILE_OBJECT FileObject,IN PFILE_POSITION_INFORMATION PtrBuffer,IN OUT PLONG PtrReturnedLength)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
UDFGetFileStreamInformation(IN PtrUDFFCB Fcb,IN PFILE_STREAM_INFORMATION PtrBuffer,IN OUT PLONG PtrReturnedLength)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
UDFSetBasicInformation(IN PtrUDFFCB Fcb,IN PtrUDFCCB Ccb,IN PFILE_OBJECT FileObject,IN PFILE_BASIC_INFORMATION PtrBuffer)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
UDFMarkStreamsForDeletion(IN PVCB Vcb,IN PtrUDFFCB Fcb,IN BOOLEAN ForDel)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
UDFSetDispositionInformation(IN PtrUDFFCB Fcb,IN PtrUDFCCB Ccb,IN PVCB Vcb,IN PFILE_OBJECT FileObject,IN BOOLEAN Delete)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
UDFSetAllocationInformation(IN PtrUDFFCB Fcb,IN PtrUDFCCB Ccb,IN PVCB Vcb,IN PFILE_OBJECT FileObject,IN PtrUDFIrpContext PtrIrpContext,IN PIRP Irp,IN PFILE_ALLOCATION_INFORMATION PtrBuffer)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
UDFSetEOF(IN PIO_STACK_LOCATION PtrSp,IN PtrUDFFCB Fcb,IN PtrUDFCCB Ccb,IN PVCB Vcb,IN PFILE_OBJECT FileObject,IN PIRP Irp,IN PFILE_END_OF_FILE_INFORMATION PtrBuffer)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
UDFPrepareForRenameMoveLink(PVCB Vcb,PBOOLEAN AcquiredVcb,PBOOLEAN AcquiredVcbEx,PBOOLEAN SingleDir,PBOOLEAN AcquiredDir1,PBOOLEAN AcquiredFcb1,IN PtrUDFCCB Ccb1,PUDF_FILE_INFO File1,PUDF_FILE_INFO Dir1,PUDF_FILE_INFO Dir2,BOOLEAN HardLink)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
UDFRename(IN PIO_STACK_LOCATION PtrSp,IN PtrUDFFCB Fcb1,IN PtrUDFCCB Ccb1,IN PFILE_OBJECT FileObject1,IN PFILE_RENAME_INFORMATION PtrBuffer)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
UDFFindFileId(IN PVCB Vcb,IN LONGLONG Id)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
UDFFindFreeFileId(IN PVCB Vcb,IN LONGLONG Id)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
UDFStoreFileId(IN PVCB Vcb,IN PtrUDFCCB Ccb,IN PUDF_FILE_INFO fi,IN LONGLONG Id)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
UDFRemoveFileId(IN PVCB Vcb,IN LONGLONG Id)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
UDFReleaseFileIdCache(IN PVCB Vcb)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
UDFGetOpenParamsByFileId(IN PVCB Vcb,IN LONGLONG Id,OUT PUNICODE_STRING * FName,OUT BOOLEAN * CaseSens)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
UDFHardLink(IN PIO_STACK_LOCATION PtrSp,IN PtrUDFFCB Fcb1,IN PtrUDFCCB Ccb1,IN PFILE_OBJECT FileObject1,IN PFILE_LINK_INFORMATION PtrBuffer)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