- Update to r53061
[reactos.git] / drivers / filesystems / ext2 / src / fileinfo.c
1 /*************************************************************************
2 *
3 * File: fileinfo.c
4 *
5 * Module: Ext2 File System Driver (Kernel mode execution only)
6 *
7 * Description:
8 * Contains code to handle the "set/query file information" dispatch
9 * entry points.
10 *
11 * Author: Manoj Paul Joseph
12 *
13 *
14 *************************************************************************/
15
16 #include "ext2fsd.h"
17
18 // define the file specific bug-check id
19 #define EXT2_BUG_CHECK_ID EXT2_FILE_INFORMATION
20 #define DEBUG_LEVEL (DEBUG_TRACE_FILEINFO)
21
22
23 /*************************************************************************
24 *
25 * Function: Ext2FileInfo()
26 *
27 * Description:
28 * The I/O Manager will invoke this routine to handle a set/query file
29 * information request
30 *
31 * Expected Interrupt Level (for execution) :
32 *
33 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
34 * to be deferred to a worker thread context)
35 *
36 * Return Value: STATUS_SUCCESS/Error
37 *
38 *************************************************************************/
39 NTSTATUS NTAPI Ext2FileInfo(
40 PDEVICE_OBJECT DeviceObject, // the logical volume device object
41 PIRP Irp) // I/O Request Packet
42 {
43 NTSTATUS RC = STATUS_SUCCESS;
44 PtrExt2IrpContext PtrIrpContext = NULL;
45 BOOLEAN AreWeTopLevel = FALSE;
46
47 DebugTrace(DEBUG_TRACE_IRP_ENTRY, "File Info Control IRP received...", 0);
48
49 FsRtlEnterFileSystem();
50
51 ASSERT(DeviceObject);
52 ASSERT(Irp);
53
54 // set the top level context
55 AreWeTopLevel = Ext2IsIrpTopLevel(Irp);
56
57 try
58 {
59
60 // get an IRP context structure and issue the request
61 PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject);
62 ASSERT(PtrIrpContext);
63
64 RC = Ext2CommonFileInfo(PtrIrpContext, Irp);
65
66 }
67 except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation()))
68 {
69
70 RC = Ext2ExceptionHandler(PtrIrpContext, Irp);
71
72 Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
73 }
74
75 if (AreWeTopLevel)
76 {
77 IoSetTopLevelIrp(NULL);
78 }
79
80 FsRtlExitFileSystem();
81
82 return(RC);
83 }
84
85
86
87 /*************************************************************************
88 *
89 * Function: Ext2CommonFileInfo()
90 *
91 * Description:
92 * The actual work is performed here. This routine may be invoked in one'
93 * of the two possible contexts:
94 * (a) in the context of a system worker thread
95 * (b) in the context of the original caller
96 *
97 * Expected Interrupt Level (for execution) :
98 *
99 * IRQL_PASSIVE_LEVEL
100 *
101 * Return Value: STATUS_SUCCESS/Error
102 *
103 *************************************************************************/
104 NTSTATUS NTAPI Ext2CommonFileInfo(
105 PtrExt2IrpContext PtrIrpContext,
106 PIRP PtrIrp)
107 {
108 NTSTATUS RC = STATUS_SUCCESS;
109 PIO_STACK_LOCATION PtrIoStackLocation = NULL;
110 PFILE_OBJECT PtrFileObject = NULL;
111 PtrExt2FCB PtrFCB = NULL;
112 PtrExt2CCB PtrCCB = NULL;
113 PtrExt2VCB PtrVCB = NULL;
114 PtrExt2NTRequiredFCB PtrReqdFCB = NULL;
115 BOOLEAN MainResourceAcquired = FALSE;
116 BOOLEAN VCBResourceAcquired = FALSE;
117 BOOLEAN PagingIoResourceAcquired = FALSE;
118 void *PtrSystemBuffer = NULL;
119 long BufferLength = 0;
120 FILE_INFORMATION_CLASS FunctionalityRequested;
121 BOOLEAN CanWait = FALSE;
122 BOOLEAN PostRequest = FALSE;
123
124 try
125 {
126 // First, get a pointer to the current I/O stack location.
127 PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp);
128 ASSERT(PtrIoStackLocation);
129
130 PtrFileObject = PtrIoStackLocation->FileObject;
131 ASSERT(PtrFileObject);
132
133 // Get the FCB and CCB pointers
134 Ext2GetFCB_CCB_VCB_FromFileObject (
135 PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB );
136
137 PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
138
139 CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
140
141 // If the caller has opened a logical volume and is attempting to
142 // query information for it as a file stream, return an error.
143 if (PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB)
144 {
145 // This is not allowed. Caller must use get/set volume information instead.
146 RC = STATUS_INVALID_PARAMETER;
147 try_return();
148 }
149
150 // ASSERT(PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB);
151 AssertFCB( PtrFCB );
152
153 PtrSystemBuffer = PtrIrp->AssociatedIrp.SystemBuffer;
154
155 if (PtrIoStackLocation->MajorFunction == IRP_MJ_QUERY_INFORMATION)
156 {
157 // ***********************
158 // Query File Information
159 // ***********************
160
161 // Now, obtain some parameters.
162 DebugTrace(DEBUG_TRACE_MISC, "Buffer length = 0x%lX[FileInfo]", BufferLength );
163
164 BufferLength = PtrIoStackLocation->Parameters.QueryFile.Length;
165
166 FunctionalityRequested = PtrIoStackLocation->Parameters.QueryFile.FileInformationClass;
167
168 // Read in the file inode if it hasn't already been read...
169 Ext2InitializeFCBInodeInfo( PtrFCB );
170
171 //
172 // Acquire the MainResource shared
173 // except for page files...
174 //
175 if (!(PtrFCB->FCBFlags & EXT2_FCB_PAGE_FILE))
176 {
177 // Acquire the MainResource shared.
178 DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Shared [FileInfo]", 0);
179 DebugTraceState( "FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters );
180 if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->MainResource), CanWait))
181 {
182 DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquisition FAILED [FileInfo]", 0);
183 PostRequest = TRUE;
184 try_return(RC = STATUS_PENDING);
185 }
186 MainResourceAcquired = TRUE;
187 DebugTrace(DEBUG_TRACE_MISC, "*** FCB acquired [FileInfo]", 0);
188 }
189
190 // Do whatever the caller asked us to do
191 switch (FunctionalityRequested)
192 {
193 case FileBasicInformation:
194 DebugTrace(DEBUG_TRACE_FILEINFO, "FileBasicInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
195 RC = Ext2GetBasicInformation(PtrFCB, (PFILE_BASIC_INFORMATION)PtrSystemBuffer, &BufferLength);
196 break;
197 case FileStandardInformation:
198 DebugTrace(DEBUG_TRACE_FILEINFO, "FileStandardInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
199 RC = Ext2GetStandardInformation(PtrFCB, (PFILE_STANDARD_INFORMATION)PtrSystemBuffer, &BufferLength);
200 break;
201 // Similarly, implement all of the other query information routines
202 // that your FSD can support.
203 #if(_WIN32_WINNT >= 0x0400)
204 case FileNetworkOpenInformation:
205 DebugTrace(DEBUG_TRACE_FILEINFO, "FileNetworkOpenInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
206 RC = Ext2GetNetworkOpenInformation(PtrFCB, (PFILE_NETWORK_OPEN_INFORMATION)PtrSystemBuffer, &BufferLength);
207 // RC = STATUS_INVALID_PARAMETER;
208 // try_return();
209 break;
210 #endif // _WIN32_WINNT >= 0x0400
211 case FileInternalInformation:
212 DebugTrace(DEBUG_TRACE_FILEINFO, "FileInternalInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
213 // RC = Ext2GetInternalInformation(...);
214 RC = STATUS_INVALID_PARAMETER;
215 try_return();
216 break;
217 case FileEaInformation:
218 DebugTrace(DEBUG_TRACE_FILEINFO, "FileEaInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
219 {
220 PFILE_EA_INFORMATION EaInformation;
221 EaInformation = (PFILE_EA_INFORMATION) PtrSystemBuffer;
222 EaInformation->EaSize = 0;
223 BufferLength = sizeof( FILE_EA_INFORMATION );
224 break;
225 }
226 // RC = Ext2GetEaInformation(...);
227 break;
228
229 case FilePositionInformation:
230 DebugTrace(DEBUG_TRACE_FILEINFO, "FilePositionInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
231 // This is fairly simple. Copy over the information from the
232 // file object.
233 {
234 PFILE_POSITION_INFORMATION PtrFileInfoBuffer;
235
236 PtrFileInfoBuffer = (PFILE_POSITION_INFORMATION)PtrSystemBuffer;
237
238 ASSERT(BufferLength >= sizeof(FILE_POSITION_INFORMATION));
239 PtrFileInfoBuffer->CurrentByteOffset = PtrFileObject->CurrentByteOffset;
240 // Modify the local variable for BufferLength appropriately.
241 BufferLength = sizeof(FILE_POSITION_INFORMATION);
242 }
243 break;
244 case FileStreamInformation:
245 DebugTrace(DEBUG_TRACE_FILEINFO, "FileStreamInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
246 // RC = Ext2GetFileStreamInformation(...);
247
248 RC = STATUS_INVALID_PARAMETER;
249 try_return();
250
251 break;
252 case FileAllInformation:
253 DebugTrace(DEBUG_TRACE_FILEINFO, "FileAllInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
254 // The I/O Manager supplies the Mode, Access, and Alignment
255 // information. The rest is up to us to provide.
256 // Therefore, decrement the BufferLength appropriately (assuming
257 // that the above 3 types on information are already in the
258 // buffer)
259 {
260
261 PFILE_POSITION_INFORMATION PtrFileInfoBuffer;
262 PFILE_ALL_INFORMATION PtrAllInfo = (PFILE_ALL_INFORMATION)PtrSystemBuffer;
263
264 // Fill in the position information.
265
266 PtrFileInfoBuffer = (PFILE_POSITION_INFORMATION)&(PtrAllInfo->PositionInformation);
267
268 PtrFileInfoBuffer->CurrentByteOffset = PtrFileObject->CurrentByteOffset;
269
270 // Modify the local variable for BufferLength appropriately.
271 BufferLength = sizeof(FILE_ALL_INFORMATION);
272
273 // Get the remaining stuff.
274 if (!NT_SUCCESS(RC = Ext2GetBasicInformation(PtrFCB, (PFILE_BASIC_INFORMATION)&(PtrAllInfo->BasicInformation),
275 &BufferLength)))
276 {
277 try_return();
278 }
279 if (!NT_SUCCESS(RC = Ext2GetStandardInformation(PtrFCB, &(PtrAllInfo->StandardInformation), &BufferLength)))
280 {
281 try_return();
282 }
283 // Similarly, get all of the others ...
284 }
285 break;
286 case FileNameInformation:
287 DebugTrace(DEBUG_TRACE_FILEINFO, "FileNameInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
288 // RC = Ext2GetFullNameInformation(...);
289 RC = Ext2GetFullNameInformation(PtrFCB, PtrCCB, (PFILE_NAME_INFORMATION)PtrSystemBuffer, &BufferLength);
290 break;
291 case FileAlternateNameInformation:
292 DebugTrace(DEBUG_TRACE_FILEINFO, "FileAlternateNameInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
293 RC = STATUS_INVALID_PARAMETER;
294 try_return();
295 // RC = Ext2GetAltNameInformation(...);
296 break;
297 case FileCompressionInformation:
298 DebugTrace(DEBUG_TRACE_FILEINFO, "FileCompressionInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
299 RC = STATUS_INVALID_PARAMETER;
300 try_return();
301 // RC = Ext2GetCompressionInformation(...);
302 break;
303
304 default:
305 RC = STATUS_INVALID_PARAMETER;
306 try_return();
307 }
308
309 // If we completed successfully, the return the amount of information transferred.
310 if (NT_SUCCESS(RC))
311 {
312 PtrIrp->IoStatus.Information = BufferLength;
313 }
314 else
315 {
316 PtrIrp->IoStatus.Information = 0;
317 }
318
319 }
320 else
321 {
322 // ***********************
323 // Set File Information
324 // ***********************
325 ASSERT(PtrIoStackLocation->MajorFunction == IRP_MJ_SET_INFORMATION);
326
327 DebugTrace(DEBUG_TRACE_FILEINFO, ">>>>>>>> Set File Information <<<<<<<<< [FileInfo]", 0);
328
329
330 // Now, obtain some parameters.
331 FunctionalityRequested = PtrIoStackLocation->Parameters.SetFile.FileInformationClass;
332
333 // Check oplocks...
334
335 //
336 // Acquire the VCB resource exclusively for
337 // deletion, rename and link operations...
338 // To synchronize with create and cleanup operations
339 //
340 if ((FunctionalityRequested == FileDispositionInformation) ||
341 (FunctionalityRequested == FileRenameInformation) ||
342 (FunctionalityRequested == FileLinkInformation))
343 {
344 DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire VCB Exclusively [FileInfo]", 0);
345 DebugTraceState( " VCB AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters );
346 if (!ExAcquireResourceExclusiveLite(&(PtrVCB->VCBResource), CanWait))
347 {
348 DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquisition FAILED [FileInfo]", 0);
349 PostRequest = TRUE;
350 try_return(RC = STATUS_PENDING);
351 }
352 // We have the VCB acquired exclusively.
353 DebugTrace(DEBUG_TRACE_MISC, "*** VCB Acquired [FileInfo]", 0);
354 VCBResourceAcquired = TRUE;
355 }
356
357
358 // Acquire the FCB exclusively at this time...
359 if (!(PtrFCB->FCBFlags & EXT2_FCB_PAGE_FILE))
360 {
361 // Acquire the MainResource shared.
362 DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCB Exclusively [FileInfo]", 0);
363 DebugTraceState( " FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters );
364 if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), CanWait))
365 {
366 DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquisition FAILED [FileInfo]", 0);
367 PostRequest = TRUE;
368 try_return(RC = STATUS_PENDING);
369 }
370 MainResourceAcquired = TRUE;
371 DebugTrace(DEBUG_TRACE_MISC, "*** FCB Acquired [FileInfo]", 0);
372 }
373
374 //
375 // For delete link (rename),
376 // set allocation size, and set EOF, should also acquire the paging-IO
377 // resource, thereby synchronizing with paging-IO requests.
378 //
379 if( PtrFileObject )
380 {
381 DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FileInfo]", PtrFileObject);
382
383 }
384 DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire FCBPaging Exclusively [FileInfo]", 0);
385 DebugTraceState( " FCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]", PtrReqdFCB->PagingIoResource.ActiveCount, PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters );
386 if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->PagingIoResource), CanWait))
387 {
388 DebugTrace(DEBUG_TRACE_MISC, "*** Attempt to acquire FCBPaging FAILED [FileInfo]", 0);
389 PostRequest = TRUE;
390 try_return(RC = STATUS_PENDING);
391 }
392 PagingIoResourceAcquired = TRUE;
393 DebugTrace(DEBUG_TRACE_MISC, "*** Acquired FCBPaging [FileInfo]", 0);
394
395 // Do whatever the caller asked us to do
396 switch (FunctionalityRequested)
397 {
398 case FileBasicInformation:
399 DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FileBasicInformation for %S", PtrFCB->FCBName->ObjectName.Buffer );
400 RC = Ext2SetBasicInformation(PtrIrpContext, PtrFCB, PtrFileObject, (PFILE_BASIC_INFORMATION)PtrSystemBuffer);
401 // RC = STATUS_ACCESS_DENIED;
402 break;
403 case FileAllocationInformation:
404 DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FileAllocationInformation for %S", PtrFCB->FCBName->ObjectName.Buffer );
405 RC = Ext2SetAllocationInformation(PtrFCB, PtrCCB, PtrVCB, PtrFileObject,
406 PtrIrpContext, PtrIrp, PtrSystemBuffer);
407 break;
408 case FileEndOfFileInformation:
409 DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FileEndOfFileInformation for %S", PtrFCB->FCBName->ObjectName.Buffer );
410 // RC = Ext2SetEOF(...);
411 RC = STATUS_INVALID_PARAMETER;
412 try_return();
413 break;
414
415 case FilePositionInformation:
416 DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FilePositionInformation for %S", PtrFCB->FCBName->ObjectName.Buffer );
417 // Check if no intermediate buffering has been specified.
418 // If it was specified, do not allow non-aligned set file
419 // position requests to succeed.
420 {
421 PFILE_POSITION_INFORMATION PtrFileInfoBuffer;
422
423 PtrFileInfoBuffer = (PFILE_POSITION_INFORMATION)PtrSystemBuffer;
424
425 if (PtrFileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)
426 {
427 if (PtrFileInfoBuffer->CurrentByteOffset.LowPart & PtrIoStackLocation->DeviceObject->AlignmentRequirement)
428 {
429 // Invalid alignment.
430 try_return(RC = STATUS_INVALID_PARAMETER);
431 }
432 }
433 PtrFileObject->CurrentByteOffset = PtrFileInfoBuffer->CurrentByteOffset;
434 }
435 break;
436
437 case FileDispositionInformation:
438 DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FileDispositionInformation for %S", PtrFCB->FCBName->ObjectName.Buffer );
439 RC = Ext2SetDispositionInformation(PtrFCB, PtrCCB, PtrVCB, PtrFileObject,
440 PtrIrpContext, PtrIrp,
441 (PFILE_DISPOSITION_INFORMATION)PtrSystemBuffer);
442 break;
443
444 case FileRenameInformation:
445 DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FileRenameInformation for %S", PtrFCB->FCBName->ObjectName.Buffer );
446 RC = Ext2RenameOrLinkFile( PtrFCB, PtrFileObject, PtrIrpContext,
447 PtrIrp, (PFILE_RENAME_INFORMATION)PtrSystemBuffer);
448 break;
449 case FileLinkInformation:
450 DebugTrace(DEBUG_TRACE_FILEINFO, "Attempt to set FileLinkInformation for %S", PtrFCB->FCBName->ObjectName.Buffer );
451 RC = STATUS_INVALID_PARAMETER;
452 try_return();
453 // When you implement your rename/link routine, be careful to
454 // check the following two arguments:
455 // TargetFileObject = PtrIoStackLocation->Parameters.SetFile.FileObject;
456 // ReplaceExistingFile = PtrIoStackLocation->Parameters.SetFile.ReplaceIfExists;
457 //
458 // The TargetFileObject argument is a pointer to the "target
459 // directory" file object obtained during the "create" routine
460 // invoked by the NT I/O Manager with the SL_OPEN_TARGET_DIRECTORY
461 // flag specified. Remember that it is quite possible that if the
462 // rename/link is contained within a single directory, the target
463 // and source directories will be the same.
464 // The ReplaceExistingFile argument should be used by you to
465 // determine if the caller wishes to replace the target (if it
466 // currently exists) with the new link/renamed file. If this
467 // value is FALSE, and if the target directory entry (being
468 // renamed-to, or the target of the link) exists, you should
469 // return a STATUS_OBJECT_NAME_COLLISION error to the caller.
470
471 // RC = Ext2RenameOrLinkFile(PtrFCB, PtrCCB, PtrFileObject, PtrIrpContext,
472 // PtrIrp, (PFILE_RENAME_INFORMATION)PtrSystemBuffer);
473
474 // Once you have completed the rename/link operation, do not
475 // forget to notify any "notify IRPs" about the actions you have
476 // performed.
477 // An example is if you renamed across directories, you should
478 // report that a new entry was added with the FILE_ACTION_ADDED
479 // action type. The actual modification would then be reported
480 // as either FILE_NOTIFY_CHANGE_FILE_NAME (if a file was renamed)
481 // or FILE_NOTIFY_CHANGE_DIR_NAME (if a directory was renamed).
482
483 break;
484 default:
485 DebugTrace(DEBUG_TRACE_FILEINFO, "Unrecoganised SetFileInformation code for %S", PtrFCB->FCBName->ObjectName.Buffer );
486 RC = STATUS_INVALID_PARAMETER;
487 try_return();
488 }
489 }
490
491 try_exit: NOTHING;
492 }
493 finally
494 {
495 if (PagingIoResourceAcquired)
496 {
497 Ext2ReleaseResource(&(PtrReqdFCB->PagingIoResource));
498 DebugTrace(DEBUG_TRACE_MISC, "*** FCBPaging Released [FileInfo]", 0);
499 DebugTraceState( " FCBPaging AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]",
500 PtrReqdFCB->PagingIoResource.ActiveCount,
501 PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters,
502 PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters );
503
504 if( PtrFileObject )
505 {
506 DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FileInfo]", PtrFileObject);
507 }
508
509 PagingIoResourceAcquired = FALSE;
510 }
511
512 if (MainResourceAcquired)
513 {
514 Ext2ReleaseResource(&(PtrReqdFCB->MainResource));
515 DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [FileInfo]", 0);
516 DebugTraceState( " FCBMain AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]",
517 PtrReqdFCB->MainResource.ActiveCount,
518 PtrReqdFCB->MainResource.NumberOfExclusiveWaiters,
519 PtrReqdFCB->MainResource.NumberOfSharedWaiters );
520 if( PtrFileObject )
521 {
522 DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FileInfo]", PtrFileObject);
523 }
524
525 MainResourceAcquired = FALSE;
526 }
527
528 if (VCBResourceAcquired)
529 {
530 Ext2ReleaseResource(&(PtrVCB->VCBResource));
531 DebugTrace(DEBUG_TRACE_MISC, "*** VCB Released [FileInfo]", 0);
532 DebugTraceState( " VCB AC:0x%LX SW:0x%LX EX:0x%LX [FileInfo]",
533 PtrVCB->VCBResource.ActiveCount,
534 PtrVCB->VCBResource.NumberOfExclusiveWaiters,
535 PtrVCB->VCBResource.NumberOfSharedWaiters );
536
537 VCBResourceAcquired = FALSE;
538 }
539
540 // Post IRP if required
541 if (PostRequest)
542 {
543
544 // Since, the I/O Manager gave us a system buffer, we do not
545 // need to "lock" anything.
546
547 // Perform the post operation which will mark the IRP pending
548 // and will return STATUS_PENDING back to us
549 RC = Ext2PostRequest(PtrIrpContext, PtrIrp);
550
551 }
552 else
553 {
554
555 // Can complete the IRP here if no exception was encountered
556 if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) {
557 PtrIrp->IoStatus.Status = RC;
558
559 // Free up the Irp Context
560 Ext2ReleaseIrpContext(PtrIrpContext);
561
562 // complete the IRP
563 IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT);
564 }
565 } // can we complete the IRP ?
566 } // end of "finally" processing
567
568 // DbgPrint( "\n === File Info IRP returning --> RC : 0x%lX Bytes: 0x%lX", PtrIrp->IoStatus.Status, PtrIrp->IoStatus.Information );
569
570 return(RC);
571 }
572
573
574 /*************************************************************************
575 *
576 * Function: Ext2GetBasicInformation()
577 *
578 * Description:
579 * Return some time-stamps and file attributes to the caller.
580 *
581 * Expected Interrupt Level (for execution) :
582 *
583 * IRQL_PASSIVE_LEVEL
584 *
585 * Return Value: STATUS_SUCCESS/Error
586 *
587 *************************************************************************/
588 NTSTATUS NTAPI Ext2GetBasicInformation(
589 PtrExt2FCB PtrFCB,
590 PFILE_BASIC_INFORMATION PtrBuffer,
591 long *PtrReturnedLength )
592 {
593 NTSTATUS RC = STATUS_SUCCESS;
594
595 try
596 {
597 if (*PtrReturnedLength < sizeof(FILE_BASIC_INFORMATION))
598 {
599 try_return(RC = STATUS_BUFFER_OVERFLOW);
600 }
601
602 // Zero out the supplied buffer.
603 RtlZeroMemory(PtrBuffer, sizeof(FILE_BASIC_INFORMATION));
604
605 // Get information from the FCB.
606 PtrBuffer->CreationTime = PtrFCB->CreationTime;
607 PtrBuffer->LastAccessTime = PtrFCB->LastAccessTime;
608 PtrBuffer->LastWriteTime = PtrFCB->LastWriteTime;
609 PtrBuffer->ChangeTime = PtrFCB->LastWriteTime;
610
611 // Now fill in the attributes.
612 PtrBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
613 if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY ) )
614 {
615 PtrBuffer->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
616 }
617 else if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_SPECIAL_FILE ) )
618 {
619 // Special File...
620 // Treated with respect... ;)
621 //
622 PtrBuffer->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY) ;
623 }
624
625 if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_HIDDEN_FILE ) )
626 {
627 PtrBuffer->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
628 }
629
630 if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_READ_ONLY ) )
631 {
632 PtrBuffer->FileAttributes |= FILE_ATTRIBUTE_READONLY;
633 }
634
635 try_exit: NOTHING;
636 }
637 finally
638 {
639 if (NT_SUCCESS(RC))
640 {
641 // Return the amount of information filled in.
642 *PtrReturnedLength = sizeof(FILE_BASIC_INFORMATION);
643 }
644 }
645 return(RC);
646 }
647
648 NTSTATUS NTAPI Ext2GetStandardInformation(
649 PtrExt2FCB PtrFCB,
650
651 PFILE_STANDARD_INFORMATION PtrStdInformation,
652 long *PtrReturnedLength )
653 {
654
655 NTSTATUS RC = STATUS_SUCCESS;
656
657
658 try
659 {
660 if (*PtrReturnedLength < sizeof( FILE_STANDARD_INFORMATION ))
661 {
662 try_return(RC = STATUS_BUFFER_OVERFLOW);
663 }
664
665 // Zero out the supplied buffer.
666 RtlZeroMemory(PtrStdInformation, sizeof(FILE_STANDARD_INFORMATION));
667
668
669 PtrStdInformation->AllocationSize = PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize;
670 PtrStdInformation->EndOfFile = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize;
671 PtrStdInformation->DeletePending = Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DELETE_ON_CLOSE);
672 PtrStdInformation->Directory = Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY );
673 PtrStdInformation->NumberOfLinks = PtrFCB->LinkCount;
674
675 try_exit: NOTHING;
676 }
677 finally
678 {
679 if (NT_SUCCESS(RC))
680 {
681 // Return the amount of information filled in.
682 *PtrReturnedLength = sizeof( FILE_STANDARD_INFORMATION );
683 }
684 }
685 return(RC);
686 }
687
688 NTSTATUS NTAPI Ext2GetNetworkOpenInformation(
689 PtrExt2FCB PtrFCB,
690 PFILE_NETWORK_OPEN_INFORMATION PtrNetworkOpenInformation,
691 long *PtrReturnedLength )
692 {
693
694 NTSTATUS RC = STATUS_SUCCESS;
695
696 try
697 {
698 if (*PtrReturnedLength < sizeof( FILE_NETWORK_OPEN_INFORMATION ))
699 {
700 try_return(RC = STATUS_BUFFER_OVERFLOW);
701 }
702
703 // Zero out the supplied buffer.
704 RtlZeroMemory(PtrNetworkOpenInformation, sizeof(FILE_NETWORK_OPEN_INFORMATION));
705
706 PtrNetworkOpenInformation->CreationTime = PtrFCB->CreationTime;
707 PtrNetworkOpenInformation->LastAccessTime = PtrFCB->LastAccessTime;
708 PtrNetworkOpenInformation->LastWriteTime = PtrFCB->LastWriteTime;
709 PtrNetworkOpenInformation->ChangeTime = PtrFCB->LastWriteTime;
710 PtrNetworkOpenInformation->AllocationSize = PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize;
711 PtrNetworkOpenInformation->EndOfFile = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize;
712
713 // Now fill in the attributes.
714 PtrNetworkOpenInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL;
715
716 if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY ) )
717 {
718 PtrNetworkOpenInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
719 }
720 else if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_SPECIAL_FILE ) )
721 {
722 // Special File...
723 // Treated with respect... ;)
724 //
725 PtrNetworkOpenInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY) ;
726 }
727 if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_HIDDEN_FILE ) )
728 {
729 PtrNetworkOpenInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
730 }
731
732 if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_READ_ONLY ) )
733 {
734 PtrNetworkOpenInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY;
735 }
736 try_exit: NOTHING;
737 }
738 finally
739 {
740 if (NT_SUCCESS(RC))
741 {
742 // Return the amount of information filled in.
743 *PtrReturnedLength = sizeof( FILE_NETWORK_OPEN_INFORMATION );
744 }
745 }
746 return(RC);
747 }
748
749
750 NTSTATUS NTAPI Ext2GetFullNameInformation(
751 PtrExt2FCB PtrFCB,
752 PtrExt2CCB PtrCCB,
753 PFILE_NAME_INFORMATION PtrNameInformation,
754 long *PtrReturnedLength )
755 {
756
757 NTSTATUS RC = STATUS_SUCCESS;
758
759 try
760 {
761 if (*PtrReturnedLength <
762 (long)( sizeof(FILE_NAME_INFORMATION) + PtrCCB->AbsolutePathName.Length) )
763 {
764 try_return(RC = STATUS_BUFFER_OVERFLOW);
765 }
766
767 // Zero out the supplied buffer.
768 RtlZeroMemory(PtrNameInformation, sizeof( FILE_NAME_INFORMATION ) );
769
770 if( PtrCCB->AbsolutePathName.Length )
771 {
772 RtlCopyMemory(
773 PtrNameInformation->FileName, // Destination,
774 PtrCCB->AbsolutePathName.Buffer, // Source,
775 PtrCCB->AbsolutePathName.Length ); // Length
776
777 PtrNameInformation->FileNameLength = PtrCCB->AbsolutePathName.Length;
778 try_return(RC = STATUS_SUCCESS);
779 }
780 else
781 {
782 try_return(RC = STATUS_INVALID_PARAMETER);
783 }
784
785 try_exit: NOTHING;
786 }
787 finally
788 {
789 if (NT_SUCCESS(RC))
790 {
791 // Return the amount of information filled in.
792 *PtrReturnedLength =
793 sizeof( FILE_NAME_INFORMATION ) +
794 PtrCCB->AbsolutePathName.Length;
795 }
796 }
797 return(RC);
798 }
799 /*************************************************************************
800 *
801 * Function: Ext2SetBasicInformation()
802 *
803 * Description:
804 * Set some time-stamps and file attributes supplied by the caller.
805 *
806 * Expected Interrupt Level (for execution) :
807 *
808 * IRQL_PASSIVE_LEVEL
809 *
810 * Return Value: STATUS_SUCCESS/Error
811 *
812 *************************************************************************/
813 NTSTATUS NTAPI Ext2SetBasicInformation(
814 PtrExt2IrpContext PtrIrpContext,
815 PtrExt2FCB PtrFCB,
816 PFILE_OBJECT PtrFileObject,
817 PFILE_BASIC_INFORMATION PtrFileInformation )
818 {
819 NTSTATUS RC = STATUS_SUCCESS;
820
821 PtrExt2VCB PtrVCB = PtrFCB->PtrVCB;
822 AssertVCB( PtrVCB );
823
824 // BOOLEAN CreationTimeChanged = FALSE;
825 // BOOLEAN AttributesChanged = FALSE;
826
827 // return STATUS_INVALID_PARAMETER;
828
829 try
830 {
831 EXT2_INODE Inode;
832 RtlZeroMemory(&Inode, sizeof( EXT2_INODE ));
833
834 if( NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
835 {
836 //
837 // Update time stamps in the inode
838 // and in the FCB...
839 //
840 if( PtrFileInformation->CreationTime.QuadPart )
841 {
842 PtrFCB->CreationTime.QuadPart = PtrFileInformation->CreationTime.QuadPart;
843 Inode.i_ctime = (ULONG) ( (PtrFCB->CreationTime.QuadPart
844 - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 );
845
846 }
847 if( PtrFileInformation->LastAccessTime.QuadPart )
848 {
849 PtrFCB->LastAccessTime.QuadPart = PtrFileInformation->LastAccessTime.QuadPart;
850 Inode.i_atime = (ULONG) ( (PtrFCB->LastAccessTime.QuadPart
851 - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 );
852
853 }
854 if( PtrFileInformation->LastWriteTime.QuadPart )
855 {
856 PtrFCB->LastWriteTime.QuadPart = PtrFileInformation->LastWriteTime.QuadPart;
857 Inode.i_mtime = (ULONG) ( (PtrFCB->LastWriteTime.QuadPart
858 - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 );
859 }
860
861 // Now come the attributes.
862 if (PtrFileInformation->FileAttributes)
863 {
864 if (PtrFileInformation->FileAttributes & FILE_ATTRIBUTE_READONLY )
865 {
866 // Turn off the write bits...
867 Ext2SetModeReadOnly( Inode.i_mode );
868 }
869 if (PtrFileInformation->FileAttributes & FILE_ATTRIBUTE_HIDDEN )
870 {
871 // Turn off the read and write bits...
872 Ext2SetModeHidden( Inode.i_mode );
873
874 }
875 if (PtrFileInformation->FileAttributes & FILE_ATTRIBUTE_SYSTEM )
876 {
877 // Just turn off the read and write bits...
878 // No special field to indicate that this is a system file...
879 Ext2SetModeReadOnly( Inode.i_mode );
880 Ext2SetModeHidden( Inode.i_mode );
881 }
882 }
883
884 // Updating the inode...
885 Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode );
886 }
887
888 if (PtrFileInformation->FileAttributes & FILE_ATTRIBUTE_TEMPORARY)
889 {
890 Ext2SetFlag(PtrFileObject->Flags, FO_TEMPORARY_FILE);
891 }
892 else
893 {
894 Ext2ClearFlag(PtrFileObject->Flags, FO_TEMPORARY_FILE);
895 }
896 }
897 finally
898 {
899 ;
900 }
901 return(RC);
902 }
903
904
905 /*************************************************************************
906 *
907 * Function: Ext2SetDispositionInformation()
908 *
909 * Description:
910 * Mark/Unmark a file for deletion.
911 *
912 * Expected Interrupt Level (for execution) :
913 *
914 * IRQL_PASSIVE_LEVEL
915 *
916 * Return Value: STATUS_SUCCESS/Error
917 *
918 *************************************************************************/
919 NTSTATUS NTAPI Ext2SetDispositionInformation(
920 PtrExt2FCB PtrFCB,
921 PtrExt2CCB PtrCCB,
922 PtrExt2VCB PtrVCB,
923 PFILE_OBJECT PtrFileObject,
924 PtrExt2IrpContext PtrIrpContext,
925 PIRP PtrIrp,
926 PFILE_DISPOSITION_INFORMATION PtrBuffer)
927 {
928 NTSTATUS RC = STATUS_SUCCESS;
929
930 try
931 {
932 if (!PtrBuffer->DeleteFile)
933 {
934 // "un-delete" the file.
935 Ext2ClearFlag(PtrFCB->FCBFlags, EXT2_FCB_DELETE_ON_CLOSE);
936 PtrFileObject->DeletePending = FALSE;
937 try_return();
938 }
939
940 // Do some checking to see if the file can even be deleted.
941
942 if (PtrFCB->FCBFlags & EXT2_FCB_DELETE_ON_CLOSE)
943 {
944 // All done!
945 try_return();
946 }
947
948 if (PtrFCB->FCBFlags & EXT2_FCB_READ_ONLY)
949 {
950 try_return(RC = STATUS_CANNOT_DELETE);
951 }
952
953 if (PtrVCB->VCBFlags & EXT2_VCB_FLAGS_VOLUME_READ_ONLY)
954 {
955 try_return(RC = STATUS_CANNOT_DELETE);
956 }
957
958 // An important step is to check if the file stream has been
959 // mapped by any process. The delete cannot be allowed to proceed
960 // in this case.
961 if (!MmFlushImageSection(&(PtrFCB->NTRequiredFCB.SectionObject), MmFlushForDelete))
962 {
963 try_return(RC = STATUS_CANNOT_DELETE);
964 }
965
966 // Disallow deletion of either a root
967 // directory or a directory that is not empty.
968 if( PtrFCB->INodeNo == EXT2_ROOT_INO )
969 {
970 try_return(RC = STATUS_CANNOT_DELETE);
971 }
972
973 if (PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)
974 {
975 if (!Ext2IsDirectoryEmpty(PtrFCB, PtrCCB, PtrIrpContext))
976 {
977 try_return(RC = STATUS_DIRECTORY_NOT_EMPTY);
978 }
979 }
980
981 // Set a flag to indicate that this directory entry will become history
982 // at cleanup.
983 Ext2SetFlag(PtrFCB->FCBFlags, EXT2_FCB_DELETE_ON_CLOSE);
984 PtrFileObject->DeletePending = TRUE;
985
986 try_exit: NOTHING;
987 }
988 finally
989 {
990 ;
991 }
992 return(RC);
993 }
994
995
996
997 /*************************************************************************
998 *
999 * Function: Ext2SetAllocationInformation()
1000 *
1001 * Description:
1002 * Mark/Unmark a file for deletion.
1003 *
1004 * Expected Interrupt Level (for execution) :
1005 *
1006 * IRQL_PASSIVE_LEVEL
1007 *
1008 * Return Value: STATUS_SUCCESS/Error
1009 *
1010 *************************************************************************/
1011 NTSTATUS NTAPI Ext2SetAllocationInformation(
1012 PtrExt2FCB PtrFCB,
1013 PtrExt2CCB PtrCCB,
1014 PtrExt2VCB PtrVCB,
1015 PFILE_OBJECT PtrFileObject,
1016 PtrExt2IrpContext PtrIrpContext,
1017 PIRP PtrIrp,
1018 PFILE_ALLOCATION_INFORMATION PtrBuffer)
1019 {
1020 NTSTATUS RC = STATUS_SUCCESS;
1021 BOOLEAN TruncatedFile = FALSE;
1022 BOOLEAN ModifiedAllocSize = FALSE;
1023
1024 try
1025 {
1026
1027 // Are we increasing the allocation size?
1028 if (RtlLargeIntegerLessThan(
1029 PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize,
1030 PtrBuffer->AllocationSize))
1031 {
1032 ULONG CurrentSize;
1033 ULONG LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
1034
1035 for( CurrentSize = 0; CurrentSize < PtrBuffer->AllocationSize.QuadPart; CurrentSize += LogicalBlockSize )
1036 {
1037 Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrFCB, PtrFileObject, FALSE );
1038 }
1039 ModifiedAllocSize = TRUE;
1040 }
1041 else if (RtlLargeIntegerGreaterThan(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize,
1042 PtrBuffer->AllocationSize))
1043 {
1044 // This is the painful part. See if the VMM will allow us to proceed.
1045 // The VMM will deny the request if:
1046 // (a) any image section exists OR
1047 // (b) a data section exists and the size of the user mapped view
1048 // is greater than the new size
1049 // Otherwise, the VMM should allow the request to proceed.
1050 if (!MmCanFileBeTruncated(&(PtrFCB->NTRequiredFCB.SectionObject), &(PtrBuffer->AllocationSize)))
1051 {
1052 // VMM said no way!
1053 try_return(RC = STATUS_USER_MAPPED_FILE);
1054 }
1055
1056 if( !Ext2TruncateFileAllocationSize( PtrIrpContext, PtrFCB, PtrFileObject, &PtrBuffer->AllocationSize) )
1057 {
1058 // This will do until I figure out a better error message code ;)
1059 RC = STATUS_INSUFFICIENT_RESOURCES;
1060
1061 }
1062
1063 ModifiedAllocSize = TRUE;
1064 TruncatedFile = TRUE;
1065 }
1066
1067 try_exit:
1068
1069 // This is a good place to check if we have performed a truncate
1070 // operation. If we have perform a truncate (whether we extended
1071 // or reduced file size), you should update file time stamps.
1072
1073 // Last, but not the lease, you must inform the Cache Manager of file size changes.
1074 if (ModifiedAllocSize && NT_SUCCESS(RC))
1075 {
1076 // Update the FCB Header with the new allocation size.
1077 PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize = PtrBuffer->AllocationSize;
1078
1079 // If we decreased the allocation size to less than the
1080 // current file size, modify the file size value.
1081 // Similarly, if we decreased the value to less than the
1082 // current valid data length, modify that value as well.
1083 if (TruncatedFile)
1084 {
1085 if (RtlLargeIntegerLessThan(PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize, PtrBuffer->AllocationSize))
1086 {
1087 // Decrease the file size value.
1088 PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize = PtrBuffer->AllocationSize;
1089 }
1090
1091 if (RtlLargeIntegerLessThan(PtrFCB->NTRequiredFCB.CommonFCBHeader.ValidDataLength, PtrBuffer->AllocationSize))
1092 {
1093 // Decrease the valid data length value.
1094 PtrFCB->NTRequiredFCB.CommonFCBHeader.ValidDataLength = PtrBuffer->AllocationSize;
1095 }
1096 }
1097
1098
1099 // If the FCB has not had caching initiated, it is still valid
1100 // for you to invoke the NT Cache Manager. It is possible in such
1101 // situations for the call to be no'oped (unless some user has
1102 // mapped in the file)
1103
1104 // NOTE: The invocation to CcSetFileSizes() will quite possibly
1105 // result in a recursive call back into the file system.
1106 // This is because the NT Cache Manager will typically
1107 // perform a flush before telling the VMM to purge pages
1108 // especially when caching has not been initiated on the
1109 // file stream, but the user has mapped the file into
1110 // the process' virtual address space.
1111 CcSetFileSizes(PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize));
1112
1113 // Inform any pending IRPs (notify change directory).
1114 }
1115
1116 }
1117 finally
1118 {
1119 ;
1120 }
1121 return(RC);
1122 }