Silence GCC warnings.
[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 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(<%wZ>, Delete %d)\n", &FCB->PathNameU, DispositionInfo->DeleteFile);
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 ULONG BytesToCopy;
342 ASSERT(NameInfo != NULL);
343 ASSERT(FCB != NULL);
344
345 /* If buffer can't hold at least the file name length, bail out */
346 if (*BufferLength < FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]))
347 return STATUS_BUFFER_OVERFLOW;
348
349 /* Save file name length, and as much file len, as buffer length allows */
350 NameInfo->FileNameLength = FCB->PathNameU.Length;
351
352 /* Calculate amount of bytes to copy not to overflow the buffer */
353 BytesToCopy = min(FCB->PathNameU.Length,
354 *BufferLength - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]));
355
356 /* Fill in the bytes */
357 RtlCopyMemory(NameInfo->FileName, FCB->PathNameU.Buffer, BytesToCopy);
358
359 /* Check if we could write more but are not able to */
360 if (*BufferLength < FCB->PathNameU.Length + (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]))
361 {
362 /* Return number of bytes written */
363 *BufferLength -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + BytesToCopy;
364 return STATUS_BUFFER_OVERFLOW;
365 }
366
367 /* We filled up as many bytes, as needed */
368 *BufferLength -= (FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + FCB->PathNameU.Length);
369
370 return STATUS_SUCCESS;
371 }
372
373 static NTSTATUS
374 VfatGetInternalInformation(PVFATFCB Fcb,
375 PFILE_INTERNAL_INFORMATION InternalInfo,
376 PULONG BufferLength)
377 {
378 ASSERT(InternalInfo);
379 ASSERT(Fcb);
380
381 if (*BufferLength < sizeof(FILE_INTERNAL_INFORMATION))
382 return STATUS_BUFFER_OVERFLOW;
383 // FIXME: get a real index, that can be used in a create operation
384 InternalInfo->IndexNumber.QuadPart = 0;
385 *BufferLength -= sizeof(FILE_INTERNAL_INFORMATION);
386 return STATUS_SUCCESS;
387 }
388
389
390 static NTSTATUS
391 VfatGetNetworkOpenInformation(PVFATFCB Fcb,
392 PDEVICE_EXTENSION DeviceExt,
393 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo,
394 PULONG BufferLength)
395 /*
396 * FUNCTION: Retrieve the file network open information
397 */
398 {
399 ASSERT(NetworkInfo);
400 ASSERT(Fcb);
401
402 if (*BufferLength < sizeof(FILE_NETWORK_OPEN_INFORMATION))
403 return(STATUS_BUFFER_OVERFLOW);
404
405 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
406 {
407 FsdDosDateTimeToSystemTime(DeviceExt,
408 Fcb->entry.FatX.CreationDate,
409 Fcb->entry.FatX.CreationTime,
410 &NetworkInfo->CreationTime);
411 FsdDosDateTimeToSystemTime(DeviceExt,
412 Fcb->entry.FatX.AccessDate,
413 Fcb->entry.FatX.AccessTime,
414 &NetworkInfo->LastAccessTime);
415 FsdDosDateTimeToSystemTime(DeviceExt,
416 Fcb->entry.FatX.UpdateDate,
417 Fcb->entry.FatX.UpdateTime,
418 &NetworkInfo->LastWriteTime);
419 NetworkInfo->ChangeTime.QuadPart = NetworkInfo->LastWriteTime.QuadPart;
420 }
421 else
422 {
423 FsdDosDateTimeToSystemTime(DeviceExt,
424 Fcb->entry.Fat.CreationDate,
425 Fcb->entry.Fat.CreationTime,
426 &NetworkInfo->CreationTime);
427 FsdDosDateTimeToSystemTime(DeviceExt,
428 Fcb->entry.Fat.AccessDate,
429 0,
430 &NetworkInfo->LastAccessTime);
431 FsdDosDateTimeToSystemTime(DeviceExt,
432 Fcb->entry.Fat.UpdateDate,
433 Fcb->entry.Fat.UpdateTime,
434 &NetworkInfo->LastWriteTime);
435 NetworkInfo->ChangeTime.QuadPart = NetworkInfo->LastWriteTime.QuadPart;
436 }
437 if (vfatFCBIsDirectory(Fcb))
438 {
439 NetworkInfo->EndOfFile.QuadPart = 0L;
440 NetworkInfo->AllocationSize.QuadPart = 0L;
441 }
442 else
443 {
444 NetworkInfo->AllocationSize = Fcb->RFCB.AllocationSize;
445 NetworkInfo->EndOfFile = Fcb->RFCB.FileSize;
446 }
447 NetworkInfo->FileAttributes = *Fcb->Attributes & 0x3f;
448 /* Synthesize FILE_ATTRIBUTE_NORMAL */
449 if (0 == (NetworkInfo->FileAttributes & (FILE_ATTRIBUTE_DIRECTORY |
450 FILE_ATTRIBUTE_ARCHIVE |
451 FILE_ATTRIBUTE_SYSTEM |
452 FILE_ATTRIBUTE_HIDDEN |
453 FILE_ATTRIBUTE_READONLY)))
454 {
455 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
456 NetworkInfo->FileAttributes |= FILE_ATTRIBUTE_NORMAL;
457 }
458
459 *BufferLength -= sizeof(FILE_NETWORK_OPEN_INFORMATION);
460 return STATUS_SUCCESS;
461 }
462
463
464 static NTSTATUS
465 VfatGetEaInformation(PFILE_OBJECT FileObject,
466 PVFATFCB Fcb,
467 PDEVICE_OBJECT DeviceObject,
468 PFILE_EA_INFORMATION Info,
469 PULONG BufferLength)
470 {
471 PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
472
473 /* FIXME - use SEH to access the buffer! */
474 Info->EaSize = 0;
475 *BufferLength -= sizeof(*Info);
476 if (DeviceExt->FatInfo.FatType == FAT12 ||
477 DeviceExt->FatInfo.FatType == FAT16)
478 {
479 /* FIXME */
480 DPRINT1("VFAT: FileEaInformation not implemented!\n");
481 }
482 return STATUS_SUCCESS;
483 }
484
485
486 static NTSTATUS
487 VfatGetAllInformation(PFILE_OBJECT FileObject,
488 PVFATFCB Fcb,
489 PDEVICE_OBJECT DeviceObject,
490 PFILE_ALL_INFORMATION Info,
491 PULONG BufferLength)
492 /*
493 * FUNCTION: Retrieve the all file information
494 */
495 {
496 NTSTATUS Status;
497 ULONG InitialBufferLength = *BufferLength;
498
499 ASSERT(Info);
500 ASSERT(Fcb);
501
502 if (*BufferLength < sizeof(FILE_ALL_INFORMATION) + Fcb->PathNameU.Length + sizeof(WCHAR))
503 return(STATUS_BUFFER_OVERFLOW);
504
505 /* Basic Information */
506 Status = VfatGetBasicInformation(FileObject, Fcb, DeviceObject, &Info->BasicInformation, BufferLength);
507 if (!NT_SUCCESS(Status)) return Status;
508 /* Standard Information */
509 Status = VfatGetStandardInformation(Fcb, &Info->StandardInformation, BufferLength);
510 if (!NT_SUCCESS(Status)) return Status;
511 /* Internal Information */
512 Status = VfatGetInternalInformation(Fcb, &Info->InternalInformation, BufferLength);
513 if (!NT_SUCCESS(Status)) return Status;
514 /* EA Information */
515 Info->EaInformation.EaSize = 0;
516 /* Access Information: The IO-Manager adds this information */
517 /* Position Information */
518 Status = VfatGetPositionInformation(FileObject, Fcb, DeviceObject, &Info->PositionInformation, BufferLength);
519 if (!NT_SUCCESS(Status)) return Status;
520 /* Mode Information: The IO-Manager adds this information */
521 /* Alignment Information: The IO-Manager adds this information */
522 /* Name Information */
523 Status = VfatGetNameInformation(FileObject, Fcb, DeviceObject, &Info->NameInformation, BufferLength);
524 if (!NT_SUCCESS(Status)) return Status;
525
526 *BufferLength = InitialBufferLength - (sizeof(FILE_ALL_INFORMATION) + Fcb->PathNameU.Length + sizeof(WCHAR));
527
528 return STATUS_SUCCESS;
529 }
530
531 static VOID UpdateFileSize(PFILE_OBJECT FileObject, PVFATFCB Fcb, ULONG Size, ULONG ClusterSize)
532 {
533 if (Size > 0)
534 {
535 Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, ClusterSize);
536 }
537 else
538 {
539 Fcb->RFCB.AllocationSize.QuadPart = (LONGLONG)0;
540 }
541 if (!vfatFCBIsDirectory(Fcb))
542 {
543 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
544 Fcb->entry.FatX.FileSize = Size;
545 else
546 Fcb->entry.Fat.FileSize = Size;
547 }
548 Fcb->RFCB.FileSize.QuadPart = Size;
549 Fcb->RFCB.ValidDataLength.QuadPart = Size;
550
551 if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
552 {
553 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
554 }
555 }
556
557 NTSTATUS
558 VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject,
559 PVFATFCB Fcb,
560 PDEVICE_EXTENSION DeviceExt,
561 PLARGE_INTEGER AllocationSize)
562 {
563 ULONG OldSize;
564 ULONG Cluster, FirstCluster;
565 NTSTATUS Status;
566
567 ULONG ClusterSize = DeviceExt->FatInfo.BytesPerCluster;
568 ULONG NewSize = AllocationSize->u.LowPart;
569 ULONG NCluster;
570 BOOLEAN AllocSizeChanged = FALSE;
571
572 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %d)\n", &Fcb->PathNameU,
573 AllocationSize->HighPart, AllocationSize->LowPart);
574
575 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
576 OldSize = Fcb->entry.FatX.FileSize;
577 else
578 OldSize = Fcb->entry.Fat.FileSize;
579 if (AllocationSize->u.HighPart > 0)
580 {
581 return STATUS_INVALID_PARAMETER;
582 }
583 if (OldSize == NewSize)
584 {
585 return(STATUS_SUCCESS);
586 }
587
588 FirstCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);
589
590 if (NewSize > Fcb->RFCB.AllocationSize.u.LowPart)
591 {
592 AllocSizeChanged = TRUE;
593 if (FirstCluster == 0)
594 {
595 Fcb->LastCluster = Fcb->LastOffset = 0;
596 Status = NextCluster (DeviceExt, FirstCluster, &FirstCluster, TRUE);
597 if (!NT_SUCCESS(Status))
598 {
599 DPRINT1("NextCluster failed. Status = %x\n", Status);
600 return Status;
601 }
602 if (FirstCluster == 0xffffffff)
603 {
604 return STATUS_DISK_FULL;
605 }
606 Status = OffsetToCluster(DeviceExt, FirstCluster,
607 ROUND_DOWN(NewSize - 1, ClusterSize),
608 &NCluster, TRUE);
609 if (NCluster == 0xffffffff || !NT_SUCCESS(Status))
610 {
611 /* disk is full */
612 NCluster = Cluster = FirstCluster;
613 Status = STATUS_SUCCESS;
614 while (NT_SUCCESS(Status) && Cluster != 0xffffffff && Cluster > 1)
615 {
616 Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
617 WriteCluster (DeviceExt, Cluster, 0);
618 Cluster = NCluster;
619 }
620 return STATUS_DISK_FULL;
621 }
622 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
623 {
624 Fcb->entry.FatX.FirstCluster = FirstCluster;
625 }
626 else
627 {
628 if (DeviceExt->FatInfo.FatType == FAT32)
629 {
630 Fcb->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0x0000FFFF);
631 Fcb->entry.Fat.FirstClusterHigh = FirstCluster >> 16;
632 }
633 else
634 {
635 ASSERT((FirstCluster >> 16) == 0);
636 Fcb->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0x0000FFFF);
637 }
638 }
639 }
640 else
641 {
642 #if 0 /* FIXME */
643 if (Fcb->LastCluster > 0)
644 {
645 if (Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize == Fcb->LastOffset)
646 {
647 Cluster = Fcb->LastCluster;
648 Status = STATUS_SUCCESS;
649 }
650 else
651 {
652 Status = OffsetToCluster(DeviceExt, Fcb->LastCluster,
653 Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize - Fcb->LastOffset,
654 &Cluster, FALSE);
655 }
656 }
657 else
658 {
659 Status = OffsetToCluster(DeviceExt, FirstCluster,
660 Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize,
661 &Cluster, FALSE);
662 }
663 if (!NT_SUCCESS(Status))
664 {
665 return Status;
666 }
667
668 if (Fcb->LastCluster == 0)
669 {
670 Fcb->LastCluster = Cluster;
671 Fcb->LastOffset = Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize;
672 }
673
674 /* FIXME: Check status */
675 /* Cluster points now to the last cluster within the chain */
676 Status = OffsetToCluster(DeviceExt, Cluster,
677 ROUND_DOWN(NewSize - 1, ClusterSize) - Fcb->LastOffset,
678 &NCluster, TRUE);
679 #else
680 Status = OffsetToCluster(DeviceExt, FirstCluster,
681 ROUND_DOWN(NewSize - 1, ClusterSize),
682 &Cluster, TRUE);
683 NCluster = Cluster;
684 #endif
685 if (NCluster == 0xffffffff || !NT_SUCCESS(Status))
686 {
687 /* disk is full */
688 NCluster = Cluster;
689 Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
690 WriteCluster(DeviceExt, Cluster, 0xffffffff);
691 Cluster = NCluster;
692 while (NT_SUCCESS(Status) && Cluster != 0xffffffff && Cluster > 1)
693 {
694 Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
695 WriteCluster (DeviceExt, Cluster, 0);
696 Cluster = NCluster;
697 }
698 return STATUS_DISK_FULL;
699 }
700 }
701 UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
702 }
703 else if (NewSize + ClusterSize <= Fcb->RFCB.AllocationSize.u.LowPart)
704 {
705 AllocSizeChanged = TRUE;
706 /* FIXME: Use the cached cluster/offset better way. */
707 Fcb->LastCluster = Fcb->LastOffset = 0;
708 UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
709 if (NewSize > 0)
710 {
711 Status = OffsetToCluster(DeviceExt, FirstCluster,
712 ROUND_DOWN(NewSize - 1, ClusterSize),
713 &Cluster, FALSE);
714
715 NCluster = Cluster;
716 Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
717 WriteCluster(DeviceExt, Cluster, 0xffffffff);
718 Cluster = NCluster;
719 }
720 else
721 {
722 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
723 {
724 Fcb->entry.FatX.FirstCluster = 0;
725 }
726 else
727 {
728 if (DeviceExt->FatInfo.FatType == FAT32)
729 {
730 Fcb->entry.Fat.FirstCluster = 0;
731 Fcb->entry.Fat.FirstClusterHigh = 0;
732 }
733 else
734 {
735 Fcb->entry.Fat.FirstCluster = 0;
736 }
737 }
738
739 NCluster = Cluster = FirstCluster;
740 Status = STATUS_SUCCESS;
741 }
742 while (NT_SUCCESS(Status) && 0xffffffff != Cluster && Cluster > 1)
743 {
744 Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
745 WriteCluster (DeviceExt, Cluster, 0);
746 Cluster = NCluster;
747 }
748 }
749 else
750 {
751 UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
752 }
753 /* Update the on-disk directory entry */
754 Fcb->Flags |= FCB_IS_DIRTY;
755 if (AllocSizeChanged)
756 {
757 VfatUpdateEntry(Fcb);
758 }
759 return STATUS_SUCCESS;
760 }
761
762 NTSTATUS VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext)
763 /*
764 * FUNCTION: Retrieve the specified file information
765 */
766 {
767 FILE_INFORMATION_CLASS FileInformationClass;
768 PVFATFCB FCB = NULL;
769
770 NTSTATUS Status = STATUS_SUCCESS;
771 PVOID SystemBuffer;
772 ULONG BufferLength;
773
774 /* PRECONDITION */
775 ASSERT(IrpContext);
776
777 /* INITIALIZATION */
778 FileInformationClass = IrpContext->Stack->Parameters.QueryFile.FileInformationClass;
779 FCB = (PVFATFCB) IrpContext->FileObject->FsContext;
780
781 DPRINT("VfatQueryInformation is called for '%s'\n",
782 FileInformationClass >= FileMaximumInformation - 1 ? "????" : FileInformationClassNames[FileInformationClass]);
783
784
785 SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
786 BufferLength = IrpContext->Stack->Parameters.QueryFile.Length;
787
788 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
789 {
790 if (!ExAcquireResourceSharedLite(&FCB->MainResource,
791 (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
792 {
793 return VfatQueueRequest (IrpContext);
794 }
795 }
796
797
798 switch (FileInformationClass)
799 {
800 case FileStandardInformation:
801 Status = VfatGetStandardInformation(FCB,
802 SystemBuffer,
803 &BufferLength);
804 break;
805 case FilePositionInformation:
806 Status = VfatGetPositionInformation(IrpContext->FileObject,
807 FCB,
808 IrpContext->DeviceObject,
809 SystemBuffer,
810 &BufferLength);
811 break;
812 case FileBasicInformation:
813 Status = VfatGetBasicInformation(IrpContext->FileObject,
814 FCB,
815 IrpContext->DeviceObject,
816 SystemBuffer,
817 &BufferLength);
818 break;
819 case FileNameInformation:
820 Status = VfatGetNameInformation(IrpContext->FileObject,
821 FCB,
822 IrpContext->DeviceObject,
823 SystemBuffer,
824 &BufferLength);
825 break;
826 case FileInternalInformation:
827 Status = VfatGetInternalInformation(FCB,
828 SystemBuffer,
829 &BufferLength);
830 break;
831 case FileNetworkOpenInformation:
832 Status = VfatGetNetworkOpenInformation(FCB,
833 IrpContext->DeviceExt,
834 SystemBuffer,
835 &BufferLength);
836 break;
837 case FileAllInformation:
838 Status = VfatGetAllInformation(IrpContext->FileObject,
839 FCB,
840 IrpContext->DeviceObject,
841 SystemBuffer,
842 &BufferLength);
843 break;
844
845 case FileEaInformation:
846 Status = VfatGetEaInformation(IrpContext->FileObject,
847 FCB,
848 IrpContext->DeviceObject,
849 SystemBuffer,
850 &BufferLength);
851 break;
852
853 case FileAlternateNameInformation:
854 Status = STATUS_NOT_IMPLEMENTED;
855 break;
856 default:
857 Status = STATUS_INVALID_PARAMETER;
858 }
859
860 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
861 {
862 ExReleaseResourceLite(&FCB->MainResource);
863 }
864 IrpContext->Irp->IoStatus.Status = Status;
865 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW)
866 IrpContext->Irp->IoStatus.Information =
867 IrpContext->Stack->Parameters.QueryFile.Length - BufferLength;
868 else
869 IrpContext->Irp->IoStatus.Information = 0;
870 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
871 VfatFreeIrpContext(IrpContext);
872
873 return Status;
874 }
875
876 NTSTATUS VfatSetInformation(PVFAT_IRP_CONTEXT IrpContext)
877 /*
878 * FUNCTION: Retrieve the specified file information
879 */
880 {
881 FILE_INFORMATION_CLASS FileInformationClass;
882 PVFATFCB FCB = NULL;
883 NTSTATUS RC = STATUS_SUCCESS;
884 PVOID SystemBuffer;
885 BOOLEAN CanWait = (IrpContext->Flags & IRPCONTEXT_CANWAIT) != 0;
886
887 /* PRECONDITION */
888 ASSERT(IrpContext);
889
890 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext);
891
892 /* INITIALIZATION */
893 FileInformationClass =
894 IrpContext->Stack->Parameters.SetFile.FileInformationClass;
895 FCB = (PVFATFCB) IrpContext->FileObject->FsContext;
896 SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
897
898 DPRINT("VfatSetInformation is called for '%s'\n",
899 FileInformationClass >= FileMaximumInformation - 1 ? "????" : FileInformationClassNames[ FileInformationClass]);
900
901 DPRINT("FileInformationClass %d\n", FileInformationClass);
902 DPRINT("SystemBuffer %p\n", SystemBuffer);
903
904 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
905 {
906 if (!ExAcquireResourceExclusiveLite(&FCB->MainResource,
907 (BOOLEAN)CanWait))
908 {
909 return(VfatQueueRequest (IrpContext));
910 }
911 }
912
913 switch (FileInformationClass)
914 {
915 case FilePositionInformation:
916 RC = VfatSetPositionInformation(IrpContext->FileObject,
917 SystemBuffer);
918 break;
919 case FileDispositionInformation:
920 RC = VfatSetDispositionInformation(IrpContext->FileObject,
921 FCB,
922 IrpContext->DeviceObject,
923 SystemBuffer);
924 break;
925 case FileAllocationInformation:
926 case FileEndOfFileInformation:
927 RC = VfatSetAllocationSizeInformation(IrpContext->FileObject,
928 FCB,
929 IrpContext->DeviceExt,
930 (PLARGE_INTEGER)SystemBuffer);
931 break;
932 case FileBasicInformation:
933 RC = VfatSetBasicInformation(IrpContext->FileObject,
934 FCB,
935 IrpContext->DeviceExt,
936 SystemBuffer);
937 break;
938 case FileRenameInformation:
939 RC = STATUS_NOT_IMPLEMENTED;
940 break;
941 default:
942 RC = STATUS_NOT_SUPPORTED;
943 }
944
945 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
946 {
947 ExReleaseResourceLite(&FCB->MainResource);
948 }
949
950 IrpContext->Irp->IoStatus.Status = RC;
951 IrpContext->Irp->IoStatus.Information = 0;
952 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
953 VfatFreeIrpContext(IrpContext);
954
955 return RC;
956 }
957
958 /* EOF */