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