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