Sync to trunk r39350.
[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 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
552 }
553
554 NTSTATUS
555 VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject,
556 PVFATFCB Fcb,
557 PDEVICE_EXTENSION DeviceExt,
558 PLARGE_INTEGER AllocationSize)
559 {
560 ULONG OldSize;
561 ULONG Cluster, FirstCluster;
562 NTSTATUS Status;
563
564 ULONG ClusterSize = DeviceExt->FatInfo.BytesPerCluster;
565 ULONG NewSize = AllocationSize->u.LowPart;
566 ULONG NCluster;
567 BOOLEAN AllocSizeChanged = FALSE;
568
569 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %d)\n", &Fcb->PathNameU,
570 AllocationSize->HighPart, AllocationSize->LowPart);
571
572 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
573 OldSize = Fcb->entry.FatX.FileSize;
574 else
575 OldSize = Fcb->entry.Fat.FileSize;
576 if (AllocationSize->u.HighPart > 0)
577 {
578 return STATUS_INVALID_PARAMETER;
579 }
580 if (OldSize == NewSize)
581 {
582 return(STATUS_SUCCESS);
583 }
584
585 FirstCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);
586
587 if (NewSize > Fcb->RFCB.AllocationSize.u.LowPart)
588 {
589 AllocSizeChanged = TRUE;
590 if (FirstCluster == 0)
591 {
592 Fcb->LastCluster = Fcb->LastOffset = 0;
593 Status = NextCluster (DeviceExt, FirstCluster, &FirstCluster, TRUE);
594 if (!NT_SUCCESS(Status))
595 {
596 DPRINT1("NextCluster failed. Status = %x\n", Status);
597 return Status;
598 }
599 if (FirstCluster == 0xffffffff)
600 {
601 return STATUS_DISK_FULL;
602 }
603 Status = OffsetToCluster(DeviceExt, FirstCluster,
604 ROUND_DOWN(NewSize - 1, ClusterSize),
605 &NCluster, TRUE);
606 if (NCluster == 0xffffffff || !NT_SUCCESS(Status))
607 {
608 /* disk is full */
609 NCluster = Cluster = FirstCluster;
610 Status = STATUS_SUCCESS;
611 while (NT_SUCCESS(Status) && Cluster != 0xffffffff && Cluster > 1)
612 {
613 Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
614 WriteCluster (DeviceExt, Cluster, 0);
615 Cluster = NCluster;
616 }
617 return STATUS_DISK_FULL;
618 }
619 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
620 {
621 Fcb->entry.FatX.FirstCluster = FirstCluster;
622 }
623 else
624 {
625 if (DeviceExt->FatInfo.FatType == FAT32)
626 {
627 Fcb->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0x0000FFFF);
628 Fcb->entry.Fat.FirstClusterHigh = FirstCluster >> 16;
629 }
630 else
631 {
632 ASSERT((FirstCluster >> 16) == 0);
633 Fcb->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0x0000FFFF);
634 }
635 }
636 }
637 else
638 {
639 if (Fcb->LastCluster > 0)
640 {
641 if (Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize == Fcb->LastOffset)
642 {
643 Cluster = Fcb->LastCluster;
644 Status = STATUS_SUCCESS;
645 }
646 else
647 {
648 Status = OffsetToCluster(DeviceExt, Fcb->LastCluster,
649 Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize - Fcb->LastOffset,
650 &Cluster, FALSE);
651 }
652 }
653 else
654 {
655 Status = OffsetToCluster(DeviceExt, FirstCluster,
656 Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize,
657 &Cluster, FALSE);
658 }
659 if (!NT_SUCCESS(Status))
660 {
661 return Status;
662 }
663
664 Fcb->LastCluster = Cluster;
665 Fcb->LastOffset = Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize;
666
667 /* FIXME: Check status */
668 /* Cluster points now to the last cluster within the chain */
669 Status = OffsetToCluster(DeviceExt, Cluster,
670 ROUND_DOWN(NewSize - 1, ClusterSize) - Fcb->LastOffset,
671 &NCluster, TRUE);
672 if (NCluster == 0xffffffff || !NT_SUCCESS(Status))
673 {
674 /* disk is full */
675 NCluster = Cluster;
676 Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
677 WriteCluster(DeviceExt, Cluster, 0xffffffff);
678 Cluster = NCluster;
679 while (NT_SUCCESS(Status) && Cluster != 0xffffffff && Cluster > 1)
680 {
681 Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
682 WriteCluster (DeviceExt, Cluster, 0);
683 Cluster = NCluster;
684 }
685 return STATUS_DISK_FULL;
686 }
687 }
688 UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
689 }
690 else if (NewSize + ClusterSize <= Fcb->RFCB.AllocationSize.u.LowPart)
691 {
692
693 DPRINT("Check for the ability to set file size\n");
694 if (!MmCanFileBeTruncated
695 (FileObject->SectionObjectPointer,
696 (PLARGE_INTEGER)AllocationSize))
697 {
698 DPRINT("Couldn't set file size!\n");
699 return STATUS_USER_MAPPED_FILE;
700 }
701 DPRINT("Can set file size\n");
702
703 AllocSizeChanged = TRUE;
704 /* FIXME: Use the cached cluster/offset better way. */
705 Fcb->LastCluster = Fcb->LastOffset = 0;
706 UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
707 if (NewSize > 0)
708 {
709 Status = OffsetToCluster(DeviceExt, FirstCluster,
710 ROUND_DOWN(NewSize - 1, ClusterSize),
711 &Cluster, FALSE);
712
713 NCluster = Cluster;
714 Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
715 WriteCluster(DeviceExt, Cluster, 0xffffffff);
716 Cluster = NCluster;
717 }
718 else
719 {
720 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
721 {
722 Fcb->entry.FatX.FirstCluster = 0;
723 }
724 else
725 {
726 if (DeviceExt->FatInfo.FatType == FAT32)
727 {
728 Fcb->entry.Fat.FirstCluster = 0;
729 Fcb->entry.Fat.FirstClusterHigh = 0;
730 }
731 else
732 {
733 Fcb->entry.Fat.FirstCluster = 0;
734 }
735 }
736
737 NCluster = Cluster = FirstCluster;
738 Status = STATUS_SUCCESS;
739 }
740 while (NT_SUCCESS(Status) && 0xffffffff != Cluster && Cluster > 1)
741 {
742 Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
743 WriteCluster (DeviceExt, Cluster, 0);
744 Cluster = NCluster;
745 }
746 }
747 else
748 {
749 UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
750 }
751 /* Update the on-disk directory entry */
752 Fcb->Flags |= FCB_IS_DIRTY;
753 if (AllocSizeChanged)
754 {
755 VfatUpdateEntry(Fcb);
756 }
757 return STATUS_SUCCESS;
758 }
759
760 NTSTATUS VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext)
761 /*
762 * FUNCTION: Retrieve the specified file information
763 */
764 {
765 FILE_INFORMATION_CLASS FileInformationClass;
766 PVFATFCB FCB = NULL;
767
768 NTSTATUS Status = STATUS_SUCCESS;
769 PVOID SystemBuffer;
770 ULONG BufferLength;
771
772 /* PRECONDITION */
773 ASSERT(IrpContext);
774
775 /* INITIALIZATION */
776 FileInformationClass = IrpContext->Stack->Parameters.QueryFile.FileInformationClass;
777 FCB = (PVFATFCB) IrpContext->FileObject->FsContext;
778
779 DPRINT("VfatQueryInformation is called for '%s'\n",
780 FileInformationClass >= FileMaximumInformation - 1 ? "????" : FileInformationClassNames[FileInformationClass]);
781
782
783 SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
784 BufferLength = IrpContext->Stack->Parameters.QueryFile.Length;
785
786 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
787 {
788 if (!ExAcquireResourceSharedLite(&FCB->MainResource,
789 (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
790 {
791 return VfatQueueRequest (IrpContext);
792 }
793 }
794
795
796 switch (FileInformationClass)
797 {
798 case FileStandardInformation:
799 Status = VfatGetStandardInformation(FCB,
800 SystemBuffer,
801 &BufferLength);
802 break;
803 case FilePositionInformation:
804 Status = VfatGetPositionInformation(IrpContext->FileObject,
805 FCB,
806 IrpContext->DeviceObject,
807 SystemBuffer,
808 &BufferLength);
809 break;
810 case FileBasicInformation:
811 Status = VfatGetBasicInformation(IrpContext->FileObject,
812 FCB,
813 IrpContext->DeviceObject,
814 SystemBuffer,
815 &BufferLength);
816 break;
817 case FileNameInformation:
818 Status = VfatGetNameInformation(IrpContext->FileObject,
819 FCB,
820 IrpContext->DeviceObject,
821 SystemBuffer,
822 &BufferLength);
823 break;
824 case FileInternalInformation:
825 Status = VfatGetInternalInformation(FCB,
826 SystemBuffer,
827 &BufferLength);
828 break;
829 case FileNetworkOpenInformation:
830 Status = VfatGetNetworkOpenInformation(FCB,
831 IrpContext->DeviceExt,
832 SystemBuffer,
833 &BufferLength);
834 break;
835 case FileAllInformation:
836 Status = VfatGetAllInformation(IrpContext->FileObject,
837 FCB,
838 IrpContext->DeviceObject,
839 SystemBuffer,
840 &BufferLength);
841 break;
842
843 case FileEaInformation:
844 Status = VfatGetEaInformation(IrpContext->FileObject,
845 FCB,
846 IrpContext->DeviceObject,
847 SystemBuffer,
848 &BufferLength);
849 break;
850
851 case FileAlternateNameInformation:
852 Status = STATUS_NOT_IMPLEMENTED;
853 break;
854 default:
855 Status = STATUS_INVALID_PARAMETER;
856 }
857
858 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
859 {
860 ExReleaseResourceLite(&FCB->MainResource);
861 }
862 IrpContext->Irp->IoStatus.Status = Status;
863 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW)
864 IrpContext->Irp->IoStatus.Information =
865 IrpContext->Stack->Parameters.QueryFile.Length - BufferLength;
866 else
867 IrpContext->Irp->IoStatus.Information = 0;
868 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
869 VfatFreeIrpContext(IrpContext);
870
871 return Status;
872 }
873
874 NTSTATUS VfatSetInformation(PVFAT_IRP_CONTEXT IrpContext)
875 /*
876 * FUNCTION: Retrieve the specified file information
877 */
878 {
879 FILE_INFORMATION_CLASS FileInformationClass;
880 PVFATFCB FCB = NULL;
881 NTSTATUS RC = STATUS_SUCCESS;
882 PVOID SystemBuffer;
883 BOOLEAN CanWait = (IrpContext->Flags & IRPCONTEXT_CANWAIT) != 0;
884
885 /* PRECONDITION */
886 ASSERT(IrpContext);
887
888 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext);
889
890 /* INITIALIZATION */
891 FileInformationClass =
892 IrpContext->Stack->Parameters.SetFile.FileInformationClass;
893 FCB = (PVFATFCB) IrpContext->FileObject->FsContext;
894 SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
895
896 DPRINT("VfatSetInformation is called for '%s'\n",
897 FileInformationClass >= FileMaximumInformation - 1 ? "????" : FileInformationClassNames[ FileInformationClass]);
898
899 DPRINT("FileInformationClass %d\n", FileInformationClass);
900 DPRINT("SystemBuffer %p\n", SystemBuffer);
901
902 /* Special: We should call MmCanFileBeTruncated here to determine if changing
903 the file size would be allowed. If not, we bail with the right error.
904 We must do this before acquiring the lock. */
905 if (FileInformationClass == FileEndOfFileInformation)
906 {
907 DPRINT("Check for the ability to set file size\n");
908 if (!MmCanFileBeTruncated
909 (IrpContext->FileObject->SectionObjectPointer,
910 (PLARGE_INTEGER)SystemBuffer))
911 {
912 DPRINT("Couldn't set file size!\n");
913 IrpContext->Irp->IoStatus.Status = STATUS_USER_MAPPED_FILE;
914 IrpContext->Irp->IoStatus.Information = 0;
915 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
916 VfatFreeIrpContext(IrpContext);
917 return STATUS_USER_MAPPED_FILE;
918 }
919 DPRINT("Can set file size\n");
920 }
921
922 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
923 {
924 if (!ExAcquireResourceExclusiveLite(&FCB->MainResource,
925 (BOOLEAN)CanWait))
926 {
927 return(VfatQueueRequest (IrpContext));
928 }
929 }
930
931 switch (FileInformationClass)
932 {
933 case FilePositionInformation:
934 RC = VfatSetPositionInformation(IrpContext->FileObject,
935 SystemBuffer);
936 break;
937 case FileDispositionInformation:
938 RC = VfatSetDispositionInformation(IrpContext->FileObject,
939 FCB,
940 IrpContext->DeviceObject,
941 SystemBuffer);
942 break;
943 case FileAllocationInformation:
944 case FileEndOfFileInformation:
945 RC = VfatSetAllocationSizeInformation(IrpContext->FileObject,
946 FCB,
947 IrpContext->DeviceExt,
948 (PLARGE_INTEGER)SystemBuffer);
949 break;
950 case FileBasicInformation:
951 RC = VfatSetBasicInformation(IrpContext->FileObject,
952 FCB,
953 IrpContext->DeviceExt,
954 SystemBuffer);
955 break;
956 case FileRenameInformation:
957 RC = STATUS_NOT_IMPLEMENTED;
958 break;
959 default:
960 RC = STATUS_NOT_SUPPORTED;
961 }
962
963 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
964 {
965 ExReleaseResourceLite(&FCB->MainResource);
966 }
967
968 IrpContext->Irp->IoStatus.Status = RC;
969 IrpContext->Irp->IoStatus.Information = 0;
970 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
971 VfatFreeIrpContext(IrpContext);
972
973 return RC;
974 }
975
976 /* EOF */