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