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