[FASTFAT]
[reactos.git] / reactos / drivers / filesystems / fastfat / finfo.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/vfat/finfo.c
5 * PURPOSE: VFAT Filesystem
6 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
7 * Herve Poussineau (reactos@poussine.freesurf.fr)
8 *
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #define NDEBUG
14 #include "vfat.h"
15
16 /* GLOBALS ******************************************************************/
17
18 const char* FileInformationClassNames[] =
19 {
20 "??????",
21 "FileDirectoryInformation",
22 "FileFullDirectoryInformation",
23 "FileBothDirectoryInformation",
24 "FileBasicInformation",
25 "FileStandardInformation",
26 "FileInternalInformation",
27 "FileEaInformation",
28 "FileAccessInformation",
29 "FileNameInformation",
30 "FileRenameInformation",
31 "FileLinkInformation",
32 "FileNamesInformation",
33 "FileDispositionInformation",
34 "FilePositionInformation",
35 "FileFullEaInformation",
36 "FileModeInformation",
37 "FileAlignmentInformation",
38 "FileAllInformation",
39 "FileAllocationInformation",
40 "FileEndOfFileInformation",
41 "FileAlternateNameInformation",
42 "FileStreamInformation",
43 "FilePipeInformation",
44 "FilePipeLocalInformation",
45 "FilePipeRemoteInformation",
46 "FileMailslotQueryInformation",
47 "FileMailslotSetInformation",
48 "FileCompressionInformation",
49 "FileObjectIdInformation",
50 "FileCompletionInformation",
51 "FileMoveClusterInformation",
52 "FileQuotaInformation",
53 "FileReparsePointInformation",
54 "FileNetworkOpenInformation",
55 "FileAttributeTagInformation",
56 "FileTrackingInformation",
57 "FileIdBothDirectoryInformation",
58 "FileIdFullDirectoryInformation",
59 "FileValidDataLengthInformation",
60 "FileShortNameInformation",
61 "FileMaximumInformation"
62 };
63
64 /* FUNCTIONS ****************************************************************/
65
66 /*
67 * FUNCTION: Retrieve the standard file information
68 */
69 static
70 NTSTATUS
71 VfatGetStandardInformation(
72 PVFATFCB FCB,
73 PFILE_STANDARD_INFORMATION StandardInfo,
74 PULONG BufferLength)
75 {
76 if (*BufferLength < sizeof(FILE_STANDARD_INFORMATION))
77 return STATUS_BUFFER_OVERFLOW;
78
79 /* PRECONDITION */
80 ASSERT(StandardInfo != NULL);
81 ASSERT(FCB != NULL);
82
83 if (vfatFCBIsDirectory(FCB))
84 {
85 StandardInfo->AllocationSize.QuadPart = 0;
86 StandardInfo->EndOfFile.QuadPart = 0;
87 StandardInfo->Directory = TRUE;
88 }
89 else
90 {
91 StandardInfo->AllocationSize = FCB->RFCB.AllocationSize;
92 StandardInfo->EndOfFile = FCB->RFCB.FileSize;
93 StandardInfo->Directory = FALSE;
94 }
95 StandardInfo->NumberOfLinks = 1;
96 StandardInfo->DeletePending = FCB->Flags & FCB_DELETE_PENDING ? TRUE : FALSE;
97
98 *BufferLength -= sizeof(FILE_STANDARD_INFORMATION);
99 return STATUS_SUCCESS;
100 }
101
102 static
103 NTSTATUS
104 VfatSetPositionInformation(
105 PFILE_OBJECT FileObject,
106 PFILE_POSITION_INFORMATION PositionInfo)
107 {
108 DPRINT("FsdSetPositionInformation()\n");
109
110 DPRINT("PositionInfo %p\n", PositionInfo);
111 DPRINT("Setting position %u\n", PositionInfo->CurrentByteOffset.u.LowPart);
112
113 FileObject->CurrentByteOffset.QuadPart =
114 PositionInfo->CurrentByteOffset.QuadPart;
115
116 return STATUS_SUCCESS;
117 }
118
119 static
120 NTSTATUS
121 VfatGetPositionInformation(
122 PFILE_OBJECT FileObject,
123 PVFATFCB FCB,
124 PDEVICE_OBJECT DeviceObject,
125 PFILE_POSITION_INFORMATION PositionInfo,
126 PULONG BufferLength)
127 {
128 UNREFERENCED_PARAMETER(FileObject);
129 UNREFERENCED_PARAMETER(FCB);
130 UNREFERENCED_PARAMETER(DeviceObject);
131
132 DPRINT("VfatGetPositionInformation()\n");
133
134 if (*BufferLength < sizeof(FILE_POSITION_INFORMATION))
135 return STATUS_BUFFER_OVERFLOW;
136
137 PositionInfo->CurrentByteOffset.QuadPart =
138 FileObject->CurrentByteOffset.QuadPart;
139
140 DPRINT("Getting position %I64x\n",
141 PositionInfo->CurrentByteOffset.QuadPart);
142
143 *BufferLength -= sizeof(FILE_POSITION_INFORMATION);
144 return STATUS_SUCCESS;
145 }
146
147 static
148 NTSTATUS
149 VfatSetBasicInformation(
150 PFILE_OBJECT FileObject,
151 PVFATFCB FCB,
152 PDEVICE_EXTENSION DeviceExt,
153 PFILE_BASIC_INFORMATION BasicInfo)
154 {
155 DPRINT("VfatSetBasicInformation()\n");
156
157 ASSERT(NULL != FileObject);
158 ASSERT(NULL != FCB);
159 ASSERT(NULL != DeviceExt);
160 ASSERT(NULL != BasicInfo);
161 /* Check volume label bit */
162 ASSERT(0 == (*FCB->Attributes & _A_VOLID));
163
164 if (FCB->Flags & FCB_IS_FATX_ENTRY)
165 {
166 if (BasicInfo->CreationTime.QuadPart != 0 && BasicInfo->CreationTime.QuadPart != -1)
167 {
168 FsdSystemTimeToDosDateTime(DeviceExt,
169 &BasicInfo->CreationTime,
170 &FCB->entry.FatX.CreationDate,
171 &FCB->entry.FatX.CreationTime);
172 }
173
174 if (BasicInfo->LastAccessTime.QuadPart != 0 && BasicInfo->LastAccessTime.QuadPart != -1)
175 {
176 FsdSystemTimeToDosDateTime(DeviceExt,
177 &BasicInfo->LastAccessTime,
178 &FCB->entry.FatX.AccessDate,
179 &FCB->entry.FatX.AccessTime);
180 }
181
182 if (BasicInfo->LastWriteTime.QuadPart != 0 && BasicInfo->LastWriteTime.QuadPart != -1)
183 {
184 FsdSystemTimeToDosDateTime(DeviceExt,
185 &BasicInfo->LastWriteTime,
186 &FCB->entry.FatX.UpdateDate,
187 &FCB->entry.FatX.UpdateTime);
188 }
189 }
190 else
191 {
192 if (BasicInfo->CreationTime.QuadPart != 0 && BasicInfo->CreationTime.QuadPart != -1)
193 {
194 FsdSystemTimeToDosDateTime(DeviceExt,
195 &BasicInfo->CreationTime,
196 &FCB->entry.Fat.CreationDate,
197 &FCB->entry.Fat.CreationTime);
198 }
199
200 if (BasicInfo->LastAccessTime.QuadPart != 0 && BasicInfo->LastAccessTime.QuadPart != -1)
201 {
202 FsdSystemTimeToDosDateTime(DeviceExt,
203 &BasicInfo->LastAccessTime,
204 &FCB->entry.Fat.AccessDate,
205 NULL);
206 }
207
208 if (BasicInfo->LastWriteTime.QuadPart != 0 && BasicInfo->LastWriteTime.QuadPart != -1)
209 {
210 FsdSystemTimeToDosDateTime(DeviceExt,
211 &BasicInfo->LastWriteTime,
212 &FCB->entry.Fat.UpdateDate,
213 &FCB->entry.Fat.UpdateTime);
214 }
215 }
216
217 if (BasicInfo->FileAttributes)
218 {
219 *FCB->Attributes = (unsigned char)((*FCB->Attributes &
220 (FILE_ATTRIBUTE_DIRECTORY | 0x48)) |
221 (BasicInfo->FileAttributes &
222 (FILE_ATTRIBUTE_ARCHIVE |
223 FILE_ATTRIBUTE_SYSTEM |
224 FILE_ATTRIBUTE_HIDDEN |
225 FILE_ATTRIBUTE_READONLY)));
226 DPRINT("Setting attributes 0x%02x\n", *FCB->Attributes);
227 }
228
229 VfatUpdateEntry(FCB);
230
231 return STATUS_SUCCESS;
232 }
233
234 static
235 NTSTATUS
236 VfatGetBasicInformation(
237 PFILE_OBJECT FileObject,
238 PVFATFCB FCB,
239 PDEVICE_OBJECT DeviceObject,
240 PFILE_BASIC_INFORMATION BasicInfo,
241 PULONG BufferLength)
242 {
243 PDEVICE_EXTENSION DeviceExt;
244
245 UNREFERENCED_PARAMETER(FileObject);
246
247 DPRINT("VfatGetBasicInformation()\n");
248
249 DeviceExt = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
250
251 if (*BufferLength < sizeof(FILE_BASIC_INFORMATION))
252 return STATUS_BUFFER_OVERFLOW;
253
254 if (FCB->Flags & FCB_IS_FATX_ENTRY)
255 {
256 FsdDosDateTimeToSystemTime(DeviceExt,
257 FCB->entry.FatX.CreationDate,
258 FCB->entry.FatX.CreationTime,
259 &BasicInfo->CreationTime);
260 FsdDosDateTimeToSystemTime(DeviceExt,
261 FCB->entry.FatX.AccessDate,
262 FCB->entry.FatX.AccessTime,
263 &BasicInfo->LastAccessTime);
264 FsdDosDateTimeToSystemTime(DeviceExt,
265 FCB->entry.FatX.UpdateDate,
266 FCB->entry.FatX.UpdateTime,
267 &BasicInfo->LastWriteTime);
268 BasicInfo->ChangeTime = BasicInfo->LastWriteTime;
269 }
270 else
271 {
272 FsdDosDateTimeToSystemTime(DeviceExt,
273 FCB->entry.Fat.CreationDate,
274 FCB->entry.Fat.CreationTime,
275 &BasicInfo->CreationTime);
276 FsdDosDateTimeToSystemTime(DeviceExt,
277 FCB->entry.Fat.AccessDate,
278 0,
279 &BasicInfo->LastAccessTime);
280 FsdDosDateTimeToSystemTime(DeviceExt,
281 FCB->entry.Fat.UpdateDate,
282 FCB->entry.Fat.UpdateTime,
283 &BasicInfo->LastWriteTime);
284 BasicInfo->ChangeTime = BasicInfo->LastWriteTime;
285 }
286
287 BasicInfo->FileAttributes = *FCB->Attributes & 0x3f;
288 /* Synthesize FILE_ATTRIBUTE_NORMAL */
289 if (0 == (BasicInfo->FileAttributes & (FILE_ATTRIBUTE_DIRECTORY |
290 FILE_ATTRIBUTE_ARCHIVE |
291 FILE_ATTRIBUTE_SYSTEM |
292 FILE_ATTRIBUTE_HIDDEN |
293 FILE_ATTRIBUTE_READONLY)))
294 {
295 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
296 BasicInfo->FileAttributes |= FILE_ATTRIBUTE_NORMAL;
297 }
298 DPRINT("Getting attributes 0x%02x\n", BasicInfo->FileAttributes);
299
300 *BufferLength -= sizeof(FILE_BASIC_INFORMATION);
301 return STATUS_SUCCESS;
302 }
303
304
305 static
306 NTSTATUS
307 VfatSetDispositionInformation(
308 PFILE_OBJECT FileObject,
309 PVFATFCB FCB,
310 PDEVICE_OBJECT DeviceObject,
311 PFILE_DISPOSITION_INFORMATION DispositionInfo)
312 {
313 #if DBG
314 PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
315 #endif
316
317 DPRINT("FsdSetDispositionInformation(<%wZ>, Delete %u)\n", &FCB->PathNameU, DispositionInfo->DeleteFile);
318
319 ASSERT(DeviceExt != NULL);
320 ASSERT(DeviceExt->FatInfo.BytesPerCluster != 0);
321 ASSERT(FCB != NULL);
322
323 if (!DispositionInfo->DeleteFile)
324 {
325 /* undelete the file */
326 FCB->Flags &= ~FCB_DELETE_PENDING;
327 FileObject->DeletePending = FALSE;
328 return STATUS_SUCCESS;
329 }
330
331 if (FCB->Flags & FCB_DELETE_PENDING)
332 {
333 /* stream already marked for deletion. just update the file object */
334 FileObject->DeletePending = TRUE;
335 return STATUS_SUCCESS;
336 }
337
338 if (*FCB->Attributes & FILE_ATTRIBUTE_READONLY)
339 {
340 return STATUS_CANNOT_DELETE;
341 }
342
343 if (vfatFCBIsRoot(FCB) ||
344 (FCB->LongNameU.Length == sizeof(WCHAR) && FCB->LongNameU.Buffer[0] == L'.') ||
345 (FCB->LongNameU.Length == 2 * sizeof(WCHAR) && FCB->LongNameU.Buffer[0] == L'.' && FCB->LongNameU.Buffer[1] == L'.'))
346 {
347 // we cannot delete a '.', '..' or the root directory
348 return STATUS_ACCESS_DENIED;
349 }
350
351
352 if (!MmFlushImageSection (FileObject->SectionObjectPointer, MmFlushForDelete))
353 {
354 /* can't delete a file if its mapped into a process */
355
356 DPRINT("MmFlushImageSection returned FALSE\n");
357 return STATUS_CANNOT_DELETE;
358 }
359
360 if (vfatFCBIsDirectory(FCB) && !VfatIsDirectoryEmpty(FCB))
361 {
362 /* can't delete a non-empty directory */
363
364 return STATUS_DIRECTORY_NOT_EMPTY;
365 }
366
367 /* all good */
368 FCB->Flags |= FCB_DELETE_PENDING;
369 FileObject->DeletePending = TRUE;
370
371 return STATUS_SUCCESS;
372 }
373
374 /*
375 * FUNCTION: Retrieve the file name information
376 */
377 static
378 NTSTATUS
379 VfatGetNameInformation(
380 PFILE_OBJECT FileObject,
381 PVFATFCB FCB,
382 PDEVICE_OBJECT DeviceObject,
383 PFILE_NAME_INFORMATION NameInfo,
384 PULONG BufferLength)
385 {
386 ULONG BytesToCopy;
387
388 UNREFERENCED_PARAMETER(FileObject);
389 UNREFERENCED_PARAMETER(DeviceObject);
390
391 ASSERT(NameInfo != NULL);
392 ASSERT(FCB != NULL);
393
394 /* If buffer can't hold at least the file name length, bail out */
395 if (*BufferLength < (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]))
396 return STATUS_BUFFER_OVERFLOW;
397
398 /* Save file name length, and as much file len, as buffer length allows */
399 NameInfo->FileNameLength = FCB->PathNameU.Length;
400
401 /* Calculate amount of bytes to copy not to overflow the buffer */
402 BytesToCopy = min(FCB->PathNameU.Length,
403 *BufferLength - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]));
404
405 /* Fill in the bytes */
406 RtlCopyMemory(NameInfo->FileName, FCB->PathNameU.Buffer, BytesToCopy);
407
408 /* Check if we could write more but are not able to */
409 if (*BufferLength < FCB->PathNameU.Length + (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]))
410 {
411 /* Return number of bytes written */
412 *BufferLength -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + BytesToCopy;
413 return STATUS_BUFFER_OVERFLOW;
414 }
415
416 /* We filled up as many bytes, as needed */
417 *BufferLength -= (FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + FCB->PathNameU.Length);
418
419 return STATUS_SUCCESS;
420 }
421
422 static
423 NTSTATUS
424 VfatGetInternalInformation(
425 PVFATFCB Fcb,
426 PFILE_INTERNAL_INFORMATION InternalInfo,
427 PULONG BufferLength)
428 {
429 ASSERT(InternalInfo);
430 ASSERT(Fcb);
431
432 if (*BufferLength < sizeof(FILE_INTERNAL_INFORMATION))
433 return STATUS_BUFFER_OVERFLOW;
434 // FIXME: get a real index, that can be used in a create operation
435 InternalInfo->IndexNumber.QuadPart = 0;
436 *BufferLength -= sizeof(FILE_INTERNAL_INFORMATION);
437 return STATUS_SUCCESS;
438 }
439
440
441 /*
442 * FUNCTION: Retrieve the file network open information
443 */
444 static
445 NTSTATUS
446 VfatGetNetworkOpenInformation(
447 PVFATFCB Fcb,
448 PDEVICE_EXTENSION DeviceExt,
449 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo,
450 PULONG BufferLength)
451 {
452 ASSERT(NetworkInfo);
453 ASSERT(Fcb);
454
455 if (*BufferLength < sizeof(FILE_NETWORK_OPEN_INFORMATION))
456 return(STATUS_BUFFER_OVERFLOW);
457
458 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
459 {
460 FsdDosDateTimeToSystemTime(DeviceExt,
461 Fcb->entry.FatX.CreationDate,
462 Fcb->entry.FatX.CreationTime,
463 &NetworkInfo->CreationTime);
464 FsdDosDateTimeToSystemTime(DeviceExt,
465 Fcb->entry.FatX.AccessDate,
466 Fcb->entry.FatX.AccessTime,
467 &NetworkInfo->LastAccessTime);
468 FsdDosDateTimeToSystemTime(DeviceExt,
469 Fcb->entry.FatX.UpdateDate,
470 Fcb->entry.FatX.UpdateTime,
471 &NetworkInfo->LastWriteTime);
472 NetworkInfo->ChangeTime.QuadPart = NetworkInfo->LastWriteTime.QuadPart;
473 }
474 else
475 {
476 FsdDosDateTimeToSystemTime(DeviceExt,
477 Fcb->entry.Fat.CreationDate,
478 Fcb->entry.Fat.CreationTime,
479 &NetworkInfo->CreationTime);
480 FsdDosDateTimeToSystemTime(DeviceExt,
481 Fcb->entry.Fat.AccessDate,
482 0,
483 &NetworkInfo->LastAccessTime);
484 FsdDosDateTimeToSystemTime(DeviceExt,
485 Fcb->entry.Fat.UpdateDate,
486 Fcb->entry.Fat.UpdateTime,
487 &NetworkInfo->LastWriteTime);
488 NetworkInfo->ChangeTime.QuadPart = NetworkInfo->LastWriteTime.QuadPart;
489 }
490
491 if (vfatFCBIsDirectory(Fcb))
492 {
493 NetworkInfo->EndOfFile.QuadPart = 0L;
494 NetworkInfo->AllocationSize.QuadPart = 0L;
495 }
496 else
497 {
498 NetworkInfo->AllocationSize = Fcb->RFCB.AllocationSize;
499 NetworkInfo->EndOfFile = Fcb->RFCB.FileSize;
500 }
501
502 NetworkInfo->FileAttributes = *Fcb->Attributes & 0x3f;
503 /* Synthesize FILE_ATTRIBUTE_NORMAL */
504 if (0 == (NetworkInfo->FileAttributes & (FILE_ATTRIBUTE_DIRECTORY |
505 FILE_ATTRIBUTE_ARCHIVE |
506 FILE_ATTRIBUTE_SYSTEM |
507 FILE_ATTRIBUTE_HIDDEN |
508 FILE_ATTRIBUTE_READONLY)))
509 {
510 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
511 NetworkInfo->FileAttributes |= FILE_ATTRIBUTE_NORMAL;
512 }
513
514 *BufferLength -= sizeof(FILE_NETWORK_OPEN_INFORMATION);
515 return STATUS_SUCCESS;
516 }
517
518
519 static
520 NTSTATUS
521 VfatGetEaInformation(
522 PFILE_OBJECT FileObject,
523 PVFATFCB Fcb,
524 PDEVICE_OBJECT DeviceObject,
525 PFILE_EA_INFORMATION Info,
526 PULONG BufferLength)
527 {
528 PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
529
530 UNREFERENCED_PARAMETER(FileObject);
531 UNREFERENCED_PARAMETER(Fcb);
532
533 /* FIXME - use SEH to access the buffer! */
534 Info->EaSize = 0;
535 *BufferLength -= sizeof(*Info);
536 if (DeviceExt->FatInfo.FatType == FAT12 ||
537 DeviceExt->FatInfo.FatType == FAT16)
538 {
539 /* FIXME */
540 DPRINT1("VFAT: FileEaInformation not implemented!\n");
541 }
542 return STATUS_SUCCESS;
543 }
544
545
546 /*
547 * FUNCTION: Retrieve the all file information
548 */
549 static
550 NTSTATUS
551 VfatGetAllInformation(
552 PFILE_OBJECT FileObject,
553 PVFATFCB Fcb,
554 PDEVICE_OBJECT DeviceObject,
555 PFILE_ALL_INFORMATION Info,
556 PULONG BufferLength)
557 {
558 NTSTATUS Status;
559 ULONG InitialBufferLength = *BufferLength;
560
561 ASSERT(Info);
562 ASSERT(Fcb);
563
564 if (*BufferLength < sizeof(FILE_ALL_INFORMATION) + Fcb->PathNameU.Length + sizeof(WCHAR))
565 return(STATUS_BUFFER_OVERFLOW);
566
567 /* Basic Information */
568 Status = VfatGetBasicInformation(FileObject, Fcb, DeviceObject, &Info->BasicInformation, BufferLength);
569 if (!NT_SUCCESS(Status)) return Status;
570 /* Standard Information */
571 Status = VfatGetStandardInformation(Fcb, &Info->StandardInformation, BufferLength);
572 if (!NT_SUCCESS(Status)) return Status;
573 /* Internal Information */
574 Status = VfatGetInternalInformation(Fcb, &Info->InternalInformation, BufferLength);
575 if (!NT_SUCCESS(Status)) return Status;
576 /* EA Information */
577 Info->EaInformation.EaSize = 0;
578 /* Access Information: The IO-Manager adds this information */
579 /* Position Information */
580 Status = VfatGetPositionInformation(FileObject, Fcb, DeviceObject, &Info->PositionInformation, BufferLength);
581 if (!NT_SUCCESS(Status)) return Status;
582 /* Mode Information: The IO-Manager adds this information */
583 /* Alignment Information: The IO-Manager adds this information */
584 /* Name Information */
585 Status = VfatGetNameInformation(FileObject, Fcb, DeviceObject, &Info->NameInformation, BufferLength);
586 if (!NT_SUCCESS(Status)) return Status;
587
588 *BufferLength = InitialBufferLength - (sizeof(FILE_ALL_INFORMATION) + Fcb->PathNameU.Length + sizeof(WCHAR));
589
590 return STATUS_SUCCESS;
591 }
592
593 static
594 VOID
595 UpdateFileSize(
596 PFILE_OBJECT FileObject,
597 PVFATFCB Fcb,
598 ULONG Size,
599 ULONG ClusterSize)
600 {
601 if (Size > 0)
602 {
603 Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, ClusterSize);
604 }
605 else
606 {
607 Fcb->RFCB.AllocationSize.QuadPart = (LONGLONG)0;
608 }
609 if (!vfatFCBIsDirectory(Fcb))
610 {
611 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
612 Fcb->entry.FatX.FileSize = Size;
613 else
614 Fcb->entry.Fat.FileSize = Size;
615 }
616 Fcb->RFCB.FileSize.QuadPart = Size;
617 Fcb->RFCB.ValidDataLength.QuadPart = Size;
618
619 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
620 }
621
622 NTSTATUS
623 VfatSetAllocationSizeInformation(
624 PFILE_OBJECT FileObject,
625 PVFATFCB Fcb,
626 PDEVICE_EXTENSION DeviceExt,
627 PLARGE_INTEGER AllocationSize)
628 {
629 ULONG OldSize;
630 ULONG Cluster, FirstCluster;
631 NTSTATUS Status;
632
633 ULONG ClusterSize = DeviceExt->FatInfo.BytesPerCluster;
634 ULONG NewSize = AllocationSize->u.LowPart;
635 ULONG NCluster;
636 BOOLEAN AllocSizeChanged = FALSE;
637
638 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %u)\n",
639 &Fcb->PathNameU, AllocationSize->HighPart, AllocationSize->LowPart);
640
641 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
642 OldSize = Fcb->entry.FatX.FileSize;
643 else
644 OldSize = Fcb->entry.Fat.FileSize;
645
646 if (AllocationSize->u.HighPart > 0)
647 {
648 return STATUS_INVALID_PARAMETER;
649 }
650
651 if (OldSize == NewSize)
652 {
653 return STATUS_SUCCESS;
654 }
655
656 FirstCluster = vfatDirEntryGetFirstCluster(DeviceExt, &Fcb->entry);
657
658 if (NewSize > Fcb->RFCB.AllocationSize.u.LowPart)
659 {
660 AllocSizeChanged = TRUE;
661 if (FirstCluster == 0)
662 {
663 Fcb->LastCluster = Fcb->LastOffset = 0;
664 Status = NextCluster(DeviceExt, FirstCluster, &FirstCluster, TRUE);
665 if (!NT_SUCCESS(Status))
666 {
667 DPRINT1("NextCluster failed. Status = %x\n", Status);
668 return Status;
669 }
670
671 if (FirstCluster == 0xffffffff)
672 {
673 return STATUS_DISK_FULL;
674 }
675
676 Status = OffsetToCluster(DeviceExt, FirstCluster,
677 ROUND_DOWN(NewSize - 1, ClusterSize),
678 &NCluster, TRUE);
679 if (NCluster == 0xffffffff || !NT_SUCCESS(Status))
680 {
681 /* disk is full */
682 NCluster = Cluster = FirstCluster;
683 Status = STATUS_SUCCESS;
684 while (NT_SUCCESS(Status) && Cluster != 0xffffffff && Cluster > 1)
685 {
686 Status = NextCluster(DeviceExt, FirstCluster, &NCluster, FALSE);
687 WriteCluster(DeviceExt, Cluster, 0);
688 Cluster = NCluster;
689 }
690 return STATUS_DISK_FULL;
691 }
692
693 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
694 {
695 Fcb->entry.FatX.FirstCluster = FirstCluster;
696 }
697 else
698 {
699 if (DeviceExt->FatInfo.FatType == FAT32)
700 {
701 Fcb->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0x0000FFFF);
702 Fcb->entry.Fat.FirstClusterHigh = FirstCluster >> 16;
703 }
704 else
705 {
706 ASSERT((FirstCluster >> 16) == 0);
707 Fcb->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0x0000FFFF);
708 }
709 }
710 }
711 else
712 {
713 if (Fcb->LastCluster > 0)
714 {
715 if (Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize == Fcb->LastOffset)
716 {
717 Cluster = Fcb->LastCluster;
718 Status = STATUS_SUCCESS;
719 }
720 else
721 {
722 Status = OffsetToCluster(DeviceExt, Fcb->LastCluster,
723 Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize - Fcb->LastOffset,
724 &Cluster, FALSE);
725 }
726 }
727 else
728 {
729 Status = OffsetToCluster(DeviceExt, FirstCluster,
730 Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize,
731 &Cluster, FALSE);
732 }
733
734 if (!NT_SUCCESS(Status))
735 {
736 return Status;
737 }
738
739 Fcb->LastCluster = Cluster;
740 Fcb->LastOffset = Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize;
741
742 /* FIXME: Check status */
743 /* Cluster points now to the last cluster within the chain */
744 Status = OffsetToCluster(DeviceExt, Cluster,
745 ROUND_DOWN(NewSize - 1, ClusterSize) - Fcb->LastOffset,
746 &NCluster, TRUE);
747 if (NCluster == 0xffffffff || !NT_SUCCESS(Status))
748 {
749 /* disk is full */
750 NCluster = Cluster;
751 Status = NextCluster(DeviceExt, FirstCluster, &NCluster, FALSE);
752 WriteCluster(DeviceExt, Cluster, 0xffffffff);
753 Cluster = NCluster;
754 while (NT_SUCCESS(Status) && Cluster != 0xffffffff && Cluster > 1)
755 {
756 Status = NextCluster(DeviceExt, FirstCluster, &NCluster, FALSE);
757 WriteCluster(DeviceExt, Cluster, 0);
758 Cluster = NCluster;
759 }
760 return STATUS_DISK_FULL;
761 }
762 }
763 UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
764 }
765 else if (NewSize + ClusterSize <= Fcb->RFCB.AllocationSize.u.LowPart)
766 {
767 DPRINT("Check for the ability to set file size\n");
768 if (!MmCanFileBeTruncated(FileObject->SectionObjectPointer,
769 (PLARGE_INTEGER)AllocationSize))
770 {
771 DPRINT("Couldn't set file size!\n");
772 return STATUS_USER_MAPPED_FILE;
773 }
774 DPRINT("Can set file size\n");
775
776 AllocSizeChanged = TRUE;
777 /* FIXME: Use the cached cluster/offset better way. */
778 Fcb->LastCluster = Fcb->LastOffset = 0;
779 UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
780 if (NewSize > 0)
781 {
782 Status = OffsetToCluster(DeviceExt, FirstCluster,
783 ROUND_DOWN(NewSize - 1, ClusterSize),
784 &Cluster, FALSE);
785
786 NCluster = Cluster;
787 Status = NextCluster(DeviceExt, FirstCluster, &NCluster, FALSE);
788 WriteCluster(DeviceExt, Cluster, 0xffffffff);
789 Cluster = NCluster;
790 }
791 else
792 {
793 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
794 {
795 Fcb->entry.FatX.FirstCluster = 0;
796 }
797 else
798 {
799 if (DeviceExt->FatInfo.FatType == FAT32)
800 {
801 Fcb->entry.Fat.FirstCluster = 0;
802 Fcb->entry.Fat.FirstClusterHigh = 0;
803 }
804 else
805 {
806 Fcb->entry.Fat.FirstCluster = 0;
807 }
808 }
809
810 NCluster = Cluster = FirstCluster;
811 Status = STATUS_SUCCESS;
812 }
813
814 while (NT_SUCCESS(Status) && 0xffffffff != Cluster && Cluster > 1)
815 {
816 Status = NextCluster(DeviceExt, FirstCluster, &NCluster, FALSE);
817 WriteCluster(DeviceExt, Cluster, 0);
818 Cluster = NCluster;
819 }
820 }
821 else
822 {
823 UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
824 }
825
826 /* Update the on-disk directory entry */
827 Fcb->Flags |= FCB_IS_DIRTY;
828 if (AllocSizeChanged)
829 {
830 VfatUpdateEntry(Fcb);
831 }
832 return STATUS_SUCCESS;
833 }
834
835 /*
836 * FUNCTION: Retrieve the specified file information
837 */
838 NTSTATUS
839 VfatQueryInformation(
840 PVFAT_IRP_CONTEXT IrpContext)
841 {
842 FILE_INFORMATION_CLASS FileInformationClass;
843 PVFATFCB FCB = NULL;
844
845 NTSTATUS Status = STATUS_SUCCESS;
846 PVOID SystemBuffer;
847 ULONG BufferLength;
848
849 /* PRECONDITION */
850 ASSERT(IrpContext);
851
852 /* INITIALIZATION */
853 FileInformationClass = IrpContext->Stack->Parameters.QueryFile.FileInformationClass;
854 FCB = (PVFATFCB) IrpContext->FileObject->FsContext;
855
856 DPRINT("VfatQueryInformation is called for '%s'\n",
857 FileInformationClass >= FileMaximumInformation - 1 ? "????" : FileInformationClassNames[FileInformationClass]);
858
859
860 SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
861 BufferLength = IrpContext->Stack->Parameters.QueryFile.Length;
862
863 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
864 {
865 if (!ExAcquireResourceSharedLite(&FCB->MainResource,
866 (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
867 {
868 return VfatQueueRequest(IrpContext);
869 }
870 }
871
872 switch (FileInformationClass)
873 {
874 case FileStandardInformation:
875 Status = VfatGetStandardInformation(FCB,
876 SystemBuffer,
877 &BufferLength);
878 break;
879
880 case FilePositionInformation:
881 Status = VfatGetPositionInformation(IrpContext->FileObject,
882 FCB,
883 IrpContext->DeviceObject,
884 SystemBuffer,
885 &BufferLength);
886 break;
887
888 case FileBasicInformation:
889 Status = VfatGetBasicInformation(IrpContext->FileObject,
890 FCB,
891 IrpContext->DeviceObject,
892 SystemBuffer,
893 &BufferLength);
894 break;
895
896 case FileNameInformation:
897 Status = VfatGetNameInformation(IrpContext->FileObject,
898 FCB,
899 IrpContext->DeviceObject,
900 SystemBuffer,
901 &BufferLength);
902 break;
903
904 case FileInternalInformation:
905 Status = VfatGetInternalInformation(FCB,
906 SystemBuffer,
907 &BufferLength);
908 break;
909
910 case FileNetworkOpenInformation:
911 Status = VfatGetNetworkOpenInformation(FCB,
912 IrpContext->DeviceExt,
913 SystemBuffer,
914 &BufferLength);
915 break;
916
917 case FileAllInformation:
918 Status = VfatGetAllInformation(IrpContext->FileObject,
919 FCB,
920 IrpContext->DeviceObject,
921 SystemBuffer,
922 &BufferLength);
923 break;
924
925 case FileEaInformation:
926 Status = VfatGetEaInformation(IrpContext->FileObject,
927 FCB,
928 IrpContext->DeviceObject,
929 SystemBuffer,
930 &BufferLength);
931 break;
932
933 case FileAlternateNameInformation:
934 Status = STATUS_NOT_IMPLEMENTED;
935 break;
936
937 default:
938 Status = STATUS_INVALID_PARAMETER;
939 }
940
941 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
942 {
943 ExReleaseResourceLite(&FCB->MainResource);
944 }
945
946 IrpContext->Irp->IoStatus.Status = Status;
947 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW)
948 IrpContext->Irp->IoStatus.Information =
949 IrpContext->Stack->Parameters.QueryFile.Length - BufferLength;
950 else
951 IrpContext->Irp->IoStatus.Information = 0;
952 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
953 VfatFreeIrpContext(IrpContext);
954
955 return Status;
956 }
957
958 /*
959 * FUNCTION: Retrieve the specified file information
960 */
961 NTSTATUS
962 VfatSetInformation(
963 PVFAT_IRP_CONTEXT IrpContext)
964 {
965 FILE_INFORMATION_CLASS FileInformationClass;
966 PVFATFCB FCB = NULL;
967 NTSTATUS Status = STATUS_SUCCESS;
968 PVOID SystemBuffer;
969
970 /* PRECONDITION */
971 ASSERT(IrpContext);
972
973 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext);
974
975 /* INITIALIZATION */
976 FileInformationClass =
977 IrpContext->Stack->Parameters.SetFile.FileInformationClass;
978 FCB = (PVFATFCB) IrpContext->FileObject->FsContext;
979 SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
980
981 DPRINT("VfatSetInformation is called for '%s'\n",
982 FileInformationClass >= FileMaximumInformation - 1 ? "????" : FileInformationClassNames[ FileInformationClass]);
983
984 DPRINT("FileInformationClass %d\n", FileInformationClass);
985 DPRINT("SystemBuffer %p\n", SystemBuffer);
986
987 /* Special: We should call MmCanFileBeTruncated here to determine if changing
988 the file size would be allowed. If not, we bail with the right error.
989 We must do this before acquiring the lock. */
990 if (FileInformationClass == FileEndOfFileInformation)
991 {
992 DPRINT("Check for the ability to set file size\n");
993 if (!MmCanFileBeTruncated(IrpContext->FileObject->SectionObjectPointer,
994 (PLARGE_INTEGER)SystemBuffer))
995 {
996 DPRINT("Couldn't set file size!\n");
997 IrpContext->Irp->IoStatus.Status = STATUS_USER_MAPPED_FILE;
998 IrpContext->Irp->IoStatus.Information = 0;
999 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
1000 VfatFreeIrpContext(IrpContext);
1001 return STATUS_USER_MAPPED_FILE;
1002 }
1003 DPRINT("Can set file size\n");
1004 }
1005
1006 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
1007 {
1008 if (!ExAcquireResourceExclusiveLite(&FCB->MainResource,
1009 (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
1010 {
1011 return VfatQueueRequest(IrpContext);
1012 }
1013 }
1014
1015 switch (FileInformationClass)
1016 {
1017 case FilePositionInformation:
1018 Status = VfatSetPositionInformation(IrpContext->FileObject,
1019 SystemBuffer);
1020 break;
1021
1022 case FileDispositionInformation:
1023 Status = VfatSetDispositionInformation(IrpContext->FileObject,
1024 FCB,
1025 IrpContext->DeviceObject,
1026 SystemBuffer);
1027 break;
1028
1029 case FileAllocationInformation:
1030 case FileEndOfFileInformation:
1031 Status = VfatSetAllocationSizeInformation(IrpContext->FileObject,
1032 FCB,
1033 IrpContext->DeviceExt,
1034 (PLARGE_INTEGER)SystemBuffer);
1035 break;
1036
1037 case FileBasicInformation:
1038 Status = VfatSetBasicInformation(IrpContext->FileObject,
1039 FCB,
1040 IrpContext->DeviceExt,
1041 SystemBuffer);
1042 break;
1043
1044 case FileRenameInformation:
1045 Status = STATUS_NOT_IMPLEMENTED;
1046 break;
1047
1048 default:
1049 Status = STATUS_NOT_SUPPORTED;
1050 }
1051
1052 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
1053 {
1054 ExReleaseResourceLite(&FCB->MainResource);
1055 }
1056
1057 IrpContext->Irp->IoStatus.Status = Status;
1058 IrpContext->Irp->IoStatus.Information = 0;
1059 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
1060 VfatFreeIrpContext(IrpContext);
1061
1062 return Status;
1063 }
1064
1065 /* EOF */