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