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