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