[FS_REC]
[reactos.git] / reactos / drivers / filesystems / fastfat_new / finfo.c
1 /*
2 * PROJECT: ReactOS FAT file system driver
3 * LICENSE: GNU GPLv3 as published by the Free Software Foundation
4 * FILE: drivers/filesystems/fastfat/finfo.c
5 * PURPOSE: File Information support routines
6 * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #define NDEBUG
12 #include "fastfat.h"
13
14 /* FUNCTIONS ****************************************************************/
15
16 VOID
17 NTAPI
18 FatiQueryBasicInformation(IN PFAT_IRP_CONTEXT IrpContext,
19 IN PFCB Fcb,
20 IN PFILE_OBJECT FileObject,
21 IN OUT PFILE_BASIC_INFORMATION Buffer,
22 IN OUT PLONG Length)
23 {
24 /* Zero the buffer */
25 RtlZeroMemory(Buffer, sizeof(FILE_BASIC_INFORMATION));
26
27 /* Deduct the written length */
28 *Length -= sizeof(FILE_BASIC_INFORMATION);
29
30 /* Check if it's a dir or a file */
31 if (FatNodeType(Fcb) == FAT_NTC_FCB)
32 {
33 // FIXME: Read dirent and get times from there
34 Buffer->LastAccessTime.QuadPart = 0;
35 Buffer->CreationTime.QuadPart = 0;
36 Buffer->LastWriteTime.QuadPart = 0;
37 }
38 else
39 {
40 // FIXME: May not be really correct
41 Buffer->FileAttributes = 0;
42 DPRINT1("Basic info of a directory '%wZ' is requested!\n", &Fcb->FullFileName);
43 }
44
45
46 /* If attribute is 0, set normal */
47 if (Buffer->FileAttributes == 0)
48 Buffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
49 }
50
51 VOID
52 NTAPI
53 FatiQueryStandardInformation(IN PFAT_IRP_CONTEXT IrpContext,
54 IN PFCB Fcb,
55 IN PFILE_OBJECT FileObject,
56 IN OUT PFILE_STANDARD_INFORMATION Buffer,
57 IN OUT PLONG Length)
58 {
59 /* Zero the buffer */
60 RtlZeroMemory(Buffer, sizeof(FILE_STANDARD_INFORMATION));
61
62 /* Deduct the written length */
63 *Length -= sizeof(FILE_STANDARD_INFORMATION);
64
65 Buffer->NumberOfLinks = 1;
66 Buffer->DeletePending = FALSE; // FIXME
67
68 /* Check if it's a dir or a file */
69 if (FatNodeType(Fcb) == FAT_NTC_FCB)
70 {
71 Buffer->Directory = FALSE;
72
73 Buffer->EndOfFile.LowPart = Fcb->FatHandle->Filesize;
74 Buffer->AllocationSize = Buffer->EndOfFile;
75 DPRINT("Filesize %d, chain length %d\n", Fcb->FatHandle->Filesize, Fcb->FatHandle->iChainLength);
76 }
77 else
78 {
79 Buffer->Directory = TRUE;
80 }
81 }
82
83 VOID
84 NTAPI
85 FatiQueryInternalInformation(IN PFAT_IRP_CONTEXT IrpContext,
86 IN PFCB Fcb,
87 IN PFILE_OBJECT FileObject,
88 IN OUT PFILE_INTERNAL_INFORMATION Buffer,
89 IN OUT PLONG Length)
90 {
91 UNIMPLEMENTED;
92 }
93
94 VOID
95 NTAPI
96 FatiQueryNameInformation(IN PFAT_IRP_CONTEXT IrpContext,
97 IN PFCB Fcb,
98 IN PFILE_OBJECT FileObject,
99 IN OUT PFILE_NAME_INFORMATION Buffer,
100 IN OUT PLONG Length)
101 {
102 ULONG ByteSize;
103 ULONG Trim = 0;
104 BOOLEAN Overflow = FALSE;
105
106 /* Deduct the minimum written length */
107 *Length -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]);
108
109 /* Build full name if needed */
110 if (!Fcb->FullFileName.Buffer)
111 {
112 FatSetFullFileNameInFcb(IrpContext, Fcb);
113 }
114
115 DPRINT("FullFileName %wZ\n", &Fcb->FullFileName);
116
117 if (*Length < Fcb->FullFileName.Length - Trim)
118 {
119 /* Buffer can't fit all data */
120 ByteSize = *Length;
121 Overflow = TRUE;
122 }
123 else
124 {
125 /* Deduct the amount of bytes we are going to write */
126 ByteSize = Fcb->FullFileName.Length - Trim;
127 *Length -= ByteSize;
128 }
129
130 /* Copy the name */
131 RtlCopyMemory(Buffer->FileName,
132 Fcb->FullFileName.Buffer,
133 ByteSize);
134
135 /* Set the length */
136 Buffer->FileNameLength = Fcb->FullFileName.Length - Trim;
137
138 /* Is this a shortname query? */
139 if (Trim)
140 {
141 /* Yes, not supported atm */
142 ASSERT(FALSE);
143 }
144
145 /* Indicate overflow by passing -1 as the length */
146 if (Overflow) *Length = -1;
147 }
148
149 NTSTATUS
150 NTAPI
151 FatiQueryInformation(IN PFAT_IRP_CONTEXT IrpContext,
152 IN PIRP Irp)
153 {
154 PFILE_OBJECT FileObject;
155 PIO_STACK_LOCATION IrpSp;
156 FILE_INFORMATION_CLASS InfoClass;
157 TYPE_OF_OPEN FileType;
158 PVCB Vcb;
159 PFCB Fcb;
160 PCCB Ccb;
161 LONG Length;
162 PVOID Buffer;
163 BOOLEAN VcbLocked = FALSE, FcbLocked = FALSE;
164 NTSTATUS Status = STATUS_SUCCESS;
165
166 /* Get IRP stack location */
167 IrpSp = IoGetCurrentIrpStackLocation(Irp);
168
169 /* Get the file object */
170 FileObject = IrpSp->FileObject;
171
172 /* Copy variables to something with shorter names */
173 InfoClass = IrpSp->Parameters.QueryFile.FileInformationClass;
174 Length = IrpSp->Parameters.QueryFile.Length;
175 Buffer = Irp->AssociatedIrp.SystemBuffer;
176
177 DPRINT("FatiQueryInformation\n", 0);
178 DPRINT("\tIrp = %08lx\n", Irp);
179 DPRINT("\tLength = %08lx\n", Length);
180 DPRINT("\tFileInformationClass = %08lx\n", InfoClass);
181 DPRINT("\tBuffer = %08lx\n", Buffer);
182
183 FileType = FatDecodeFileObject(FileObject, &Vcb, &Fcb, &Ccb);
184
185 DPRINT("Vcb %p, Fcb %p, Ccb %p, open type %d\n", Vcb, Fcb, Ccb, FileType);
186
187 /* Acquire VCB lock */
188 if (InfoClass == FileNameInformation ||
189 InfoClass == FileAllInformation)
190 {
191 if (!FatAcquireExclusiveVcb(IrpContext, Vcb))
192 {
193 ASSERT(FALSE);
194 }
195
196 /* Remember we locked the VCB */
197 VcbLocked = TRUE;
198 }
199
200 /* Acquire FCB lock */
201 // FIXME: If not paging file
202 if (!FatAcquireSharedFcb(IrpContext, Fcb))
203 {
204 ASSERT(FALSE);
205 }
206 FcbLocked = TRUE;
207
208 switch (InfoClass)
209 {
210 case FileBasicInformation:
211 FatiQueryBasicInformation(IrpContext, Fcb, FileObject, Buffer, &Length);
212 break;
213 case FileStandardInformation:
214 FatiQueryStandardInformation(IrpContext, Fcb, FileObject, Buffer, &Length);
215 break;
216 case FileInternalInformation:
217 FatiQueryInternalInformation(IrpContext, Fcb, FileObject, Buffer, &Length);
218 break;
219 case FileNameInformation:
220 FatiQueryNameInformation(IrpContext, Fcb, FileObject, Buffer, &Length);
221 break;
222 default:
223 DPRINT1("Unimplemented information class %d requested\n", InfoClass);
224 Status = STATUS_INVALID_PARAMETER;
225 }
226
227 /* Check for buffer overflow */
228 if (Length < 0)
229 {
230 Status = STATUS_BUFFER_OVERFLOW;
231 Length = 0;
232 }
233
234 /* Set IoStatus.Information to amount of filled bytes */
235 Irp->IoStatus.Information = IrpSp->Parameters.QueryFile.Length - Length;
236
237 /* Release FCB locks */
238 if (FcbLocked) FatReleaseFcb(IrpContext, Fcb);
239 if (VcbLocked) FatReleaseVcb(IrpContext, Vcb);
240
241 /* Complete request and return status */
242 FatCompleteRequest(IrpContext, Irp, Status);
243 return Status;
244 }
245
246 NTSTATUS
247 NTAPI
248 FatQueryInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp)
249 {
250 NTSTATUS Status;
251 BOOLEAN TopLevel, CanWait;
252 PFAT_IRP_CONTEXT IrpContext;
253
254 CanWait = TRUE;
255 TopLevel = FALSE;
256 Status = STATUS_INVALID_DEVICE_REQUEST;
257
258 /* Get CanWait flag */
259 if (IoGetCurrentIrpStackLocation(Irp)->FileObject != NULL)
260 CanWait = IoIsOperationSynchronous(Irp);
261
262 /* Enter FsRtl critical region */
263 FsRtlEnterFileSystem();
264
265 /* Set Top Level IRP if not set */
266 TopLevel = FatIsTopLevelIrp(Irp);
267
268 /* Build an irp context */
269 IrpContext = FatBuildIrpContext(Irp, CanWait);
270
271 /* Perform the actual read */
272 Status = FatiQueryInformation(IrpContext, Irp);
273
274 /* Restore top level Irp */
275 if (TopLevel) IoSetTopLevelIrp(NULL);
276
277 /* Leave FsRtl critical region */
278 FsRtlExitFileSystem();
279
280 return Status;
281 }
282
283 NTSTATUS
284 NTAPI
285 FatSetEndOfFileInfo(IN PFAT_IRP_CONTEXT IrpContext,
286 IN PIRP Irp,
287 IN PFILE_OBJECT FileObject,
288 IN PVCB Vcb,
289 IN PFCB Fcb)
290 {
291 PFILE_END_OF_FILE_INFORMATION Buffer;
292 ULONG NewFileSize;
293 ULONG InitialFileSize;
294 ULONG InitialValidDataLength;
295 //ULONG InitialValidDataToDisk;
296 BOOLEAN CacheMapInitialized = FALSE;
297 BOOLEAN ResourceAcquired = FALSE;
298 NTSTATUS Status;
299
300 Buffer = Irp->AssociatedIrp.SystemBuffer;
301
302 if (FatNodeType(Fcb) != FAT_NTC_FCB)
303 {
304 /* Trying to change size of a dir */
305 Status = STATUS_INVALID_DEVICE_REQUEST;
306 return Status;
307 }
308
309 /* Validate new size */
310 if (!FatIsIoRangeValid(Buffer->EndOfFile, 0))
311 {
312 Status = STATUS_DISK_FULL;
313 return Status;
314 }
315
316 NewFileSize = Buffer->EndOfFile.LowPart;
317
318 /* Lookup allocation size if needed */
319 if (Fcb->Header.AllocationSize.QuadPart == (LONGLONG)-1)
320 UNIMPLEMENTED;//FatLookupFileAllocationSize(IrpContext, Fcb);
321
322 /* Cache the file if there is a data section */
323 if (FileObject->SectionObjectPointer->DataSectionObject &&
324 (FileObject->SectionObjectPointer->SharedCacheMap == NULL) &&
325 !FlagOn(Irp->Flags, IRP_PAGING_IO))
326 {
327 if (FlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE))
328 {
329 /* This is a really weird condition */
330 UNIMPLEMENTED;
331 //Raise(STATUS_FILE_CLOSED);
332 }
333
334 /* Initialize the cache map */
335 CcInitializeCacheMap(FileObject,
336 (PCC_FILE_SIZES)&Fcb->Header.AllocationSize,
337 FALSE,
338 &FatGlobalData.CacheMgrCallbacks,
339 Fcb);
340
341 CacheMapInitialized = TRUE;
342 }
343
344 /* Lazy write case */
345 if (IoGetCurrentIrpStackLocation(Irp)->Parameters.SetFile.AdvanceOnly)
346 {
347 if (!IsFileDeleted(Fcb) &&
348 (Fcb->Condition == FcbGood))
349 {
350 /* Clamp the new file size */
351 if (NewFileSize >= Fcb->Header.FileSize.LowPart)
352 NewFileSize = Fcb->Header.FileSize.LowPart;
353
354 ASSERT(NewFileSize <= Fcb->Header.AllocationSize.LowPart);
355
356 /* Never reduce the file size here! */
357
358 // TODO: Actually change file size
359 DPRINT1("Actually changing file size is missing\n");
360
361 /* Notify about file size change */
362 FatNotifyReportChange(IrpContext,
363 Vcb,
364 Fcb,
365 FILE_NOTIFY_CHANGE_SIZE,
366 FILE_ACTION_MODIFIED);
367 }
368 else
369 {
370 DPRINT1("Cannot set size on deleted file\n");
371 }
372
373 Status = STATUS_SUCCESS;
374 return Status;
375 }
376
377 if ( NewFileSize > Fcb->Header.AllocationSize.LowPart )
378 {
379 // TODO: Increase file size
380 DPRINT1("Actually changing file size is missing\n");
381 }
382
383 if (Fcb->Header.FileSize.LowPart != NewFileSize)
384 {
385 if (NewFileSize < Fcb->Header.FileSize.LowPart)
386 {
387 if (!MmCanFileBeTruncated(FileObject->SectionObjectPointer,
388 &Buffer->EndOfFile))
389 {
390 Status = STATUS_USER_MAPPED_FILE;
391
392 /* Free up resources if necessary */
393 if (CacheMapInitialized)
394 CcUninitializeCacheMap(FileObject, NULL, NULL);
395
396 return Status;
397 }
398
399 ResourceAcquired = ExAcquireResourceExclusiveLite(Fcb->Header.PagingIoResource, TRUE);
400 }
401
402 /* Set new file sizes */
403 InitialFileSize = Fcb->Header.FileSize.LowPart;
404 InitialValidDataLength = Fcb->Header.ValidDataLength.LowPart;
405 //InitialValidDataToDisk = Fcb->ValidDataToDisk;
406
407 Fcb->Header.FileSize.LowPart = NewFileSize;
408
409 /* Adjust valid data length if new size is less than that */
410 if (Fcb->Header.ValidDataLength.LowPart > NewFileSize)
411 Fcb->Header.ValidDataLength.LowPart = NewFileSize;
412
413 //if (Fcb->ValidDataToDisk > NewFileSize)
414 // Fcb->ValidDataToDisk = NewFileSize;
415
416 DPRINT1("New file size is 0x%08lx\n", NewFileSize);
417
418 /* Update cache mapping */
419 CcSetFileSizes(FileObject,
420 (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
421
422 /* Notify about size change */
423 FatNotifyReportChange(IrpContext,
424 Vcb,
425 Fcb,
426 FILE_NOTIFY_CHANGE_SIZE,
427 FILE_ACTION_MODIFIED);
428
429 /* Set truncate on close flag */
430 SetFlag(Fcb->State, FCB_STATE_TRUNCATE_ON_CLOSE);
431 }
432
433 /* Set modified flag */
434 FileObject->Flags |= FO_FILE_MODIFIED;
435
436 /* Free up resources if necessary */
437 if (CacheMapInitialized)
438 CcUninitializeCacheMap(FileObject, NULL, NULL);
439
440 if (ResourceAcquired)
441 ExReleaseResourceLite(Fcb->Header.PagingIoResource);
442
443 return STATUS_SUCCESS;
444 }
445
446 NTSTATUS
447 NTAPI
448 FatiSetInformation(IN PFAT_IRP_CONTEXT IrpContext,
449 IN PIRP Irp)
450 {
451 PFILE_OBJECT FileObject;
452 PIO_STACK_LOCATION IrpSp;
453 FILE_INFORMATION_CLASS InfoClass;
454 TYPE_OF_OPEN TypeOfOpen;
455 PVCB Vcb;
456 PFCB Fcb;
457 PCCB Ccb;
458 LONG Length;
459 PVOID Buffer;
460 NTSTATUS Status = STATUS_SUCCESS;
461 BOOLEAN VcbAcquired = FALSE, FcbAcquired = FALSE;
462
463 /* Get IRP stack location */
464 IrpSp = IoGetCurrentIrpStackLocation(Irp);
465
466 /* Get the file object */
467 FileObject = IrpSp->FileObject;
468
469 /* Copy variables to something with shorter names */
470 InfoClass = IrpSp->Parameters.SetFile.FileInformationClass;
471 Length = IrpSp->Parameters.SetFile.Length;
472 Buffer = Irp->AssociatedIrp.SystemBuffer;
473
474 DPRINT("FatiSetInformation\n", 0);
475 DPRINT("\tIrp = %08lx\n", Irp);
476 DPRINT("\tLength = %08lx\n", Length);
477 DPRINT("\tFileInformationClass = %08lx\n", InfoClass);
478 DPRINT("\tFileObject = %08lx\n", IrpSp->Parameters.SetFile.FileObject);
479 DPRINT("\tBuffer = %08lx\n", Buffer);
480
481 TypeOfOpen = FatDecodeFileObject(FileObject, &Vcb, &Fcb, &Ccb);
482
483 DPRINT("Vcb %p, Fcb %p, Ccb %p, open type %d\n", Vcb, Fcb, Ccb, TypeOfOpen);
484
485 switch (TypeOfOpen)
486 {
487 case UserVolumeOpen:
488 Status = STATUS_INVALID_PARAMETER;
489 /* Complete request and return status */
490 FatCompleteRequest(IrpContext, Irp, Status);
491 return Status;
492 case UserFileOpen:
493 /* Check oplocks */
494 if (!FlagOn(Fcb->State, FCB_STATE_PAGEFILE) &&
495 ((InfoClass == FileEndOfFileInformation) ||
496 (InfoClass == FileAllocationInformation)))
497 {
498 Status = FsRtlCheckOplock(&Fcb->Fcb.Oplock,
499 Irp,
500 IrpContext,
501 NULL,
502 NULL);
503
504 if (Status != STATUS_SUCCESS)
505 {
506 /* Complete request and return status */
507 FatCompleteRequest(IrpContext, Irp, Status);
508 return Status;
509 }
510
511 /* Update Fast IO flag */
512 Fcb->Header.IsFastIoPossible = FatIsFastIoPossible(Fcb);
513 }
514 break;
515
516 case UserDirectoryOpen:
517 break;
518
519 default:
520 Status = STATUS_INVALID_PARAMETER;
521 /* Complete request and return status */
522 FatCompleteRequest(IrpContext, Irp, Status);
523 return Status;
524 }
525
526 /* If it's a root DCB - fail */
527 if (FatNodeType(Fcb) == FAT_NTC_ROOT_DCB)
528 {
529 if (InfoClass == FileDispositionInformation)
530 Status = STATUS_CANNOT_DELETE;
531 else
532 Status = STATUS_INVALID_PARAMETER;
533
534 /* Complete request and return status */
535 FatCompleteRequest(IrpContext, Irp, Status);
536 return Status;
537 }
538
539 /* Acquire the volume lock if needed */
540 if (InfoClass == FileDispositionInformation ||
541 InfoClass == FileRenameInformation)
542 {
543 if (!FatAcquireExclusiveVcb(IrpContext, Vcb))
544 {
545 UNIMPLEMENTED;
546 }
547
548 VcbAcquired = TRUE;
549 }
550
551 /* Acquire FCB lock */
552 if (!FlagOn(Fcb->State, FCB_STATE_PAGEFILE))
553 {
554 if (!FatAcquireExclusiveFcb(IrpContext, Fcb))
555 {
556 UNIMPLEMENTED;
557 }
558
559 FcbAcquired = TRUE;
560 }
561
562 // TODO: VerifyFcb
563
564 switch (InfoClass)
565 {
566 case FileBasicInformation:
567 //Status = FatSetBasicInfo(IrpContext, Irp, Fcb, Ccb);
568 DPRINT1("FileBasicInformation\n");
569 break;
570
571 case FileDispositionInformation:
572 if (FlagOn(Vcb->State, VCB_STATE_FLAG_DEFERRED_FLUSH) &&
573 !FlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT))
574 {
575 UNIMPLEMENTED;
576 }
577 else
578 {
579 //Status = FatSetDispositionInfo(IrpContext, Irp, FileObject, Fcb);
580 DPRINT1("FileDispositionInformation\n");
581 }
582
583 break;
584
585 case FileRenameInformation:
586 if (!FlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT))
587 {
588 UNIMPLEMENTED;
589 }
590 else
591 {
592 //Status = FatSetRenameInfo(IrpContext, Irp, Vcb, Fcb, Ccb);
593 DPRINT1("FileRenameInformation\n");
594
595 /* NOTE: Request must not be completed here!
596 That's why Irp/IrpContext are set to NULL */
597 if (Status == STATUS_PENDING)
598 {
599 Irp = NULL;
600 IrpContext = NULL;
601 }
602 }
603 break;
604
605 case FilePositionInformation:
606 //Status = FatSetPositionInfo(IrpContext, Irp, FileObject);
607 DPRINT1("FilePositionInformation\n");
608 break;
609
610 case FileLinkInformation:
611 Status = STATUS_INVALID_DEVICE_REQUEST;
612 break;
613
614 case FileAllocationInformation:
615 //Status = FatSetAllocationInfo(IrpContext, Irp, Fcb, FileObject);
616 DPRINT1("FileAllocationInformation\n");
617 break;
618
619 case FileEndOfFileInformation:
620 Status = FatSetEndOfFileInfo(IrpContext, Irp, FileObject, Vcb, Fcb);
621 break;
622
623 default:
624 Status = STATUS_INVALID_PARAMETER;
625 }
626
627 /* Release locks */
628 if (FcbAcquired) FatReleaseFcb(IrpContext, Fcb);
629 if (VcbAcquired) FatReleaseVcb(IrpContext, Vcb);
630
631 /* Complete request and return status */
632 FatCompleteRequest(IrpContext, Irp, Status);
633 return Status;
634 }
635
636 NTSTATUS
637 NTAPI
638 FatSetInformation(PDEVICE_OBJECT DeviceObject, PIRP Irp)
639 {
640 NTSTATUS Status;
641 BOOLEAN TopLevel, CanWait;
642 PFAT_IRP_CONTEXT IrpContext;
643
644 CanWait = TRUE;
645 TopLevel = FALSE;
646 Status = STATUS_INVALID_DEVICE_REQUEST;
647
648 /* Get CanWait flag */
649 if (IoGetCurrentIrpStackLocation(Irp)->FileObject != NULL)
650 CanWait = IoIsOperationSynchronous(Irp);
651
652 /* Enter FsRtl critical region */
653 FsRtlEnterFileSystem();
654
655 /* Set Top Level IRP if not set */
656 TopLevel = FatIsTopLevelIrp(Irp);
657
658 /* Build an irp context */
659 IrpContext = FatBuildIrpContext(Irp, CanWait);
660
661 /* Perform the actual read */
662 Status = FatiSetInformation(IrpContext, Irp);
663
664 /* Restore top level Irp */
665 if (TopLevel) IoSetTopLevelIrp(NULL);
666
667 /* Leave FsRtl critical region */
668 FsRtlExitFileSystem();
669
670 return Status;
671 }
672
673 /* EOF */