Don't check the share access for directories.
[reactos.git] / reactos / drivers / fs / vfat / 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 * Hartmut Birr
8 * Herve Poussineau (reactos@poussine.freesurf.fr)
9 *
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #define NDEBUG
15 #include "vfat.h"
16
17 /* GLOBALS ******************************************************************/
18
19 const char* FileInformationClassNames[] =
20 {
21 "??????",
22 "FileDirectoryInformation",
23 "FileFullDirectoryInformation",
24 "FileBothDirectoryInformation",
25 "FileBasicInformation",
26 "FileStandardInformation",
27 "FileInternalInformation",
28 "FileEaInformation",
29 "FileAccessInformation",
30 "FileNameInformation",
31 "FileRenameInformation",
32 "FileLinkInformation",
33 "FileNamesInformation",
34 "FileDispositionInformation",
35 "FilePositionInformation",
36 "FileFullEaInformation",
37 "FileModeInformation",
38 "FileAlignmentInformation",
39 "FileAllInformation",
40 "FileAllocationInformation",
41 "FileEndOfFileInformation",
42 "FileAlternateNameInformation",
43 "FileStreamInformation",
44 "FilePipeInformation",
45 "FilePipeLocalInformation",
46 "FilePipeRemoteInformation",
47 "FileMailslotQueryInformation",
48 "FileMailslotSetInformation",
49 "FileCompressionInformation",
50 "FileObjectIdInformation",
51 "FileCompletionInformation",
52 "FileMoveClusterInformation",
53 "FileQuotaInformation",
54 "FileReparsePointInformation",
55 "FileNetworkOpenInformation",
56 "FileAttributeTagInformation",
57 "FileTrackingInformation",
58 "FileIdBothDirectoryInformation",
59 "FileIdFullDirectoryInformation",
60 "FileValidDataLengthInformation",
61 "FileShortNameInformation",
62 "FileMaximumInformation"
63 };
64
65 /* FUNCTIONS ****************************************************************/
66
67 static NTSTATUS
68 VfatGetStandardInformation(PVFATFCB FCB,
69 PFILE_STANDARD_INFORMATION StandardInfo,
70 PULONG BufferLength)
71 /*
72 * FUNCTION: Retrieve the standard file information
73 */
74 {
75
76 if (*BufferLength < sizeof(FILE_STANDARD_INFORMATION))
77 return STATUS_BUFFER_OVERFLOW;
78
79 /* PRECONDITION */
80 ASSERT(StandardInfo != NULL);
81 ASSERT(FCB != NULL);
82
83 if (vfatFCBIsDirectory(FCB))
84 {
85 StandardInfo->AllocationSize.QuadPart = 0;
86 StandardInfo->EndOfFile.QuadPart = 0;
87 StandardInfo->Directory = TRUE;
88 }
89 else
90 {
91 StandardInfo->AllocationSize = FCB->RFCB.AllocationSize;
92 StandardInfo->EndOfFile = FCB->RFCB.FileSize;
93 StandardInfo->Directory = FALSE;
94 }
95 StandardInfo->NumberOfLinks = 0;
96 StandardInfo->DeletePending = FCB->Flags & FCB_DELETE_PENDING ? TRUE : FALSE;
97
98 *BufferLength -= sizeof(FILE_STANDARD_INFORMATION);
99 return(STATUS_SUCCESS);
100 }
101
102 static NTSTATUS
103 VfatSetPositionInformation(PFILE_OBJECT FileObject,
104 PFILE_POSITION_INFORMATION PositionInfo)
105 {
106 DPRINT ("FsdSetPositionInformation()\n");
107
108 DPRINT ("PositionInfo %x\n", PositionInfo);
109 DPRINT ("Setting position %d\n", PositionInfo->CurrentByteOffset.u.LowPart);
110
111 FileObject->CurrentByteOffset.QuadPart =
112 PositionInfo->CurrentByteOffset.QuadPart;
113
114 return (STATUS_SUCCESS);
115 }
116
117 static NTSTATUS
118 VfatGetPositionInformation(PFILE_OBJECT FileObject,
119 PVFATFCB FCB,
120 PDEVICE_OBJECT DeviceObject,
121 PFILE_POSITION_INFORMATION PositionInfo,
122 PULONG BufferLength)
123 {
124 DPRINT ("VfatGetPositionInformation()\n");
125
126 if (*BufferLength < sizeof(FILE_POSITION_INFORMATION))
127 return STATUS_BUFFER_OVERFLOW;
128
129 PositionInfo->CurrentByteOffset.QuadPart =
130 FileObject->CurrentByteOffset.QuadPart;
131
132 DPRINT("Getting position %I64x\n",
133 PositionInfo->CurrentByteOffset.QuadPart);
134
135 *BufferLength -= sizeof(FILE_POSITION_INFORMATION);
136 return(STATUS_SUCCESS);
137 }
138
139 static NTSTATUS
140 VfatSetBasicInformation(PFILE_OBJECT FileObject,
141 PVFATFCB FCB,
142 PDEVICE_EXTENSION DeviceExt,
143 PFILE_BASIC_INFORMATION BasicInfo)
144 {
145 DPRINT("VfatSetBasicInformation()\n");
146
147 ASSERT(NULL != FileObject);
148 ASSERT(NULL != FCB);
149 ASSERT(NULL != DeviceExt);
150 ASSERT(NULL != BasicInfo);
151 /* Check volume label bit */
152 ASSERT(0 == (*FCB->Attributes & 0x08));
153
154 if (FCB->Flags & FCB_IS_FATX_ENTRY)
155 {
156 FsdSystemTimeToDosDateTime(DeviceExt,
157 &BasicInfo->CreationTime,
158 &FCB->entry.FatX.CreationDate,
159 &FCB->entry.FatX.CreationTime);
160 FsdSystemTimeToDosDateTime(DeviceExt,
161 &BasicInfo->LastAccessTime,
162 &FCB->entry.FatX.AccessDate,
163 &FCB->entry.FatX.AccessTime);
164 FsdSystemTimeToDosDateTime(DeviceExt,
165 &BasicInfo->LastWriteTime,
166 &FCB->entry.FatX.UpdateDate,
167 &FCB->entry.FatX.UpdateTime);
168 }
169 else
170 {
171 FsdSystemTimeToDosDateTime(DeviceExt,
172 &BasicInfo->CreationTime,
173 &FCB->entry.Fat.CreationDate,
174 &FCB->entry.Fat.CreationTime);
175 FsdSystemTimeToDosDateTime(DeviceExt,
176 &BasicInfo->LastAccessTime,
177 &FCB->entry.Fat.AccessDate,
178 NULL);
179 FsdSystemTimeToDosDateTime(DeviceExt,
180 &BasicInfo->LastWriteTime,
181 &FCB->entry.Fat.UpdateDate,
182 &FCB->entry.Fat.UpdateTime);
183 }
184
185 *FCB->Attributes = (unsigned char)((*FCB->Attributes &
186 (FILE_ATTRIBUTE_DIRECTORY | 0x48)) |
187 (BasicInfo->FileAttributes &
188 (FILE_ATTRIBUTE_ARCHIVE |
189 FILE_ATTRIBUTE_SYSTEM |
190 FILE_ATTRIBUTE_HIDDEN |
191 FILE_ATTRIBUTE_READONLY)));
192 DPRINT("Setting attributes 0x%02x\n", *FCB->Attributes);
193
194 VfatUpdateEntry(FCB);
195
196 return(STATUS_SUCCESS);
197 }
198
199 static NTSTATUS
200 VfatGetBasicInformation(PFILE_OBJECT FileObject,
201 PVFATFCB FCB,
202 PDEVICE_OBJECT DeviceObject,
203 PFILE_BASIC_INFORMATION BasicInfo,
204 PULONG BufferLength)
205 {
206 PDEVICE_EXTENSION DeviceExt;
207 DPRINT("VfatGetBasicInformation()\n");
208
209 DeviceExt = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
210
211 if (*BufferLength < sizeof(FILE_BASIC_INFORMATION))
212 return STATUS_BUFFER_OVERFLOW;
213
214 if (FCB->Flags & FCB_IS_FATX_ENTRY)
215 {
216 FsdDosDateTimeToSystemTime(DeviceExt,
217 FCB->entry.FatX.CreationDate,
218 FCB->entry.FatX.CreationTime,
219 &BasicInfo->CreationTime);
220 FsdDosDateTimeToSystemTime(DeviceExt,
221 FCB->entry.FatX.AccessDate,
222 FCB->entry.FatX.AccessTime,
223 &BasicInfo->LastAccessTime);
224 FsdDosDateTimeToSystemTime(DeviceExt,
225 FCB->entry.FatX.UpdateDate,
226 FCB->entry.FatX.UpdateTime,
227 &BasicInfo->LastWriteTime);
228 BasicInfo->ChangeTime = BasicInfo->LastWriteTime;
229 }
230 else
231 {
232 FsdDosDateTimeToSystemTime(DeviceExt,
233 FCB->entry.Fat.CreationDate,
234 FCB->entry.Fat.CreationTime,
235 &BasicInfo->CreationTime);
236 FsdDosDateTimeToSystemTime(DeviceExt,
237 FCB->entry.Fat.AccessDate,
238 0,
239 &BasicInfo->LastAccessTime);
240 FsdDosDateTimeToSystemTime(DeviceExt,
241 FCB->entry.Fat.UpdateDate,
242 FCB->entry.Fat.UpdateTime,
243 &BasicInfo->LastWriteTime);
244 BasicInfo->ChangeTime = BasicInfo->LastWriteTime;
245 }
246
247 BasicInfo->FileAttributes = *FCB->Attributes & 0x3f;
248 /* Synthesize FILE_ATTRIBUTE_NORMAL */
249 if (0 == (BasicInfo->FileAttributes & (FILE_ATTRIBUTE_DIRECTORY |
250 FILE_ATTRIBUTE_ARCHIVE |
251 FILE_ATTRIBUTE_SYSTEM |
252 FILE_ATTRIBUTE_HIDDEN |
253 FILE_ATTRIBUTE_READONLY)))
254 {
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 if (*BufferLength < sizeof(FILE_NAME_INFORMATION) + FCB->PathNameU.Length + sizeof(WCHAR))
345 return STATUS_BUFFER_OVERFLOW;
346
347 NameInfo->FileNameLength = FCB->PathNameU.Length;
348 RtlCopyMemory(NameInfo->FileName, FCB->PathNameU.Buffer, FCB->PathNameU.Length);
349 NameInfo->FileName[FCB->PathNameU.Length / sizeof(WCHAR)] = 0;
350
351 *BufferLength -= (sizeof(FILE_NAME_INFORMATION) + FCB->PathNameU.Length + sizeof(WCHAR));
352
353 return STATUS_SUCCESS;
354 }
355
356 static NTSTATUS
357 VfatGetInternalInformation(PVFATFCB Fcb,
358 PFILE_INTERNAL_INFORMATION InternalInfo,
359 PULONG BufferLength)
360 {
361 ASSERT(InternalInfo);
362 ASSERT(Fcb);
363
364 if (*BufferLength < sizeof(FILE_INTERNAL_INFORMATION))
365 return STATUS_BUFFER_OVERFLOW;
366 // FIXME: get a real index, that can be used in a create operation
367 InternalInfo->IndexNumber.QuadPart = 0;
368 *BufferLength -= sizeof(FILE_INTERNAL_INFORMATION);
369 return STATUS_SUCCESS;
370 }
371
372
373 static NTSTATUS
374 VfatGetNetworkOpenInformation(PVFATFCB Fcb,
375 PDEVICE_EXTENSION DeviceExt,
376 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo,
377 PULONG BufferLength)
378 /*
379 * FUNCTION: Retrieve the file network open information
380 */
381 {
382 ASSERT(NetworkInfo);
383 ASSERT(Fcb);
384
385 if (*BufferLength < sizeof(FILE_NETWORK_OPEN_INFORMATION))
386 return(STATUS_BUFFER_OVERFLOW);
387
388 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
389 {
390 FsdDosDateTimeToSystemTime(DeviceExt,
391 Fcb->entry.FatX.CreationDate,
392 Fcb->entry.FatX.CreationTime,
393 &NetworkInfo->CreationTime);
394 FsdDosDateTimeToSystemTime(DeviceExt,
395 Fcb->entry.FatX.AccessDate,
396 Fcb->entry.FatX.AccessTime,
397 &NetworkInfo->LastAccessTime);
398 FsdDosDateTimeToSystemTime(DeviceExt,
399 Fcb->entry.FatX.UpdateDate,
400 Fcb->entry.FatX.UpdateTime,
401 &NetworkInfo->LastWriteTime);
402 NetworkInfo->ChangeTime.QuadPart = NetworkInfo->LastWriteTime.QuadPart;
403 }
404 else
405 {
406 FsdDosDateTimeToSystemTime(DeviceExt,
407 Fcb->entry.Fat.CreationDate,
408 Fcb->entry.Fat.CreationTime,
409 &NetworkInfo->CreationTime);
410 FsdDosDateTimeToSystemTime(DeviceExt,
411 Fcb->entry.Fat.AccessDate,
412 0,
413 &NetworkInfo->LastAccessTime);
414 FsdDosDateTimeToSystemTime(DeviceExt,
415 Fcb->entry.Fat.UpdateDate,
416 Fcb->entry.Fat.UpdateTime,
417 &NetworkInfo->LastWriteTime);
418 NetworkInfo->ChangeTime.QuadPart = NetworkInfo->LastWriteTime.QuadPart;
419 }
420 if (vfatFCBIsDirectory(Fcb))
421 {
422 NetworkInfo->EndOfFile.QuadPart = 0L;
423 NetworkInfo->AllocationSize.QuadPart = 0L;
424 }
425 else
426 {
427 NetworkInfo->AllocationSize = Fcb->RFCB.AllocationSize;
428 NetworkInfo->EndOfFile = Fcb->RFCB.FileSize;
429 }
430 NetworkInfo->FileAttributes = *Fcb->Attributes & 0x3f;
431
432 *BufferLength -= sizeof(FILE_NETWORK_OPEN_INFORMATION);
433 return STATUS_SUCCESS;
434 }
435
436
437 static NTSTATUS
438 VfatGetAllInformation(PFILE_OBJECT FileObject,
439 PVFATFCB Fcb,
440 PDEVICE_OBJECT DeviceObject,
441 PFILE_ALL_INFORMATION Info,
442 PULONG BufferLength)
443 /*
444 * FUNCTION: Retrieve the all file information
445 */
446 {
447 NTSTATUS Status;
448 ULONG InitialBufferLength = *BufferLength;
449
450 ASSERT(Info);
451 ASSERT(Fcb);
452
453 if (*BufferLength < sizeof(FILE_ALL_INFORMATION) + Fcb->PathNameU.Length + sizeof(WCHAR))
454 return(STATUS_BUFFER_OVERFLOW);
455
456 /* Basic Information */
457 Status = VfatGetBasicInformation(FileObject, Fcb, DeviceObject, &Info->BasicInformation, BufferLength);
458 if (!NT_SUCCESS(Status)) return Status;
459 /* Standard Information */
460 Status = VfatGetStandardInformation(Fcb, &Info->StandardInformation, BufferLength);
461 if (!NT_SUCCESS(Status)) return Status;
462 /* Internal Information */
463 Status = VfatGetInternalInformation(Fcb, &Info->InternalInformation, BufferLength);
464 if (!NT_SUCCESS(Status)) return Status;
465 /* EA Information */
466 Info->EaInformation.EaSize = 0;
467 /* Access Information: The IO-Manager adds this information */
468 /* Position Information */
469 Status = VfatGetPositionInformation(FileObject, Fcb, DeviceObject, &Info->PositionInformation, BufferLength);
470 if (!NT_SUCCESS(Status)) return Status;
471 /* Mode Information: The IO-Manager adds this information */
472 /* Alignment Information: The IO-Manager adds this information */
473 /* Name Information */
474 Status = VfatGetNameInformation(FileObject, Fcb, DeviceObject, &Info->NameInformation, BufferLength);
475 if (!NT_SUCCESS(Status)) return Status;
476
477 *BufferLength = InitialBufferLength - (sizeof(FILE_ALL_INFORMATION) + Fcb->PathNameU.Length + sizeof(WCHAR));
478
479 return STATUS_SUCCESS;
480 }
481
482 VOID UpdateFileSize(PFILE_OBJECT FileObject, PVFATFCB Fcb, ULONG Size, ULONG ClusterSize)
483 {
484 if (Size > 0)
485 {
486 Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, ClusterSize);
487 }
488 else
489 {
490 Fcb->RFCB.AllocationSize.QuadPart = (LONGLONG)0;
491 }
492 if (!vfatFCBIsDirectory(Fcb))
493 {
494 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
495 Fcb->entry.FatX.FileSize = Size;
496 else
497 Fcb->entry.Fat.FileSize = Size;
498 }
499 Fcb->RFCB.FileSize.QuadPart = Size;
500 Fcb->RFCB.ValidDataLength.QuadPart = Size;
501
502 if (FileObject->SectionObjectPointer->SharedCacheMap != NULL)
503 {
504 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
505 }
506 }
507
508 NTSTATUS
509 VfatSetAllocationSizeInformation(PFILE_OBJECT FileObject,
510 PVFATFCB Fcb,
511 PDEVICE_EXTENSION DeviceExt,
512 PLARGE_INTEGER AllocationSize)
513 {
514 ULONG OldSize;
515 ULONG Cluster, FirstCluster;
516 NTSTATUS Status;
517
518 ULONG ClusterSize = DeviceExt->FatInfo.BytesPerCluster;
519 ULONG NewSize = AllocationSize->u.LowPart;
520 ULONG NCluster;
521 BOOLEAN AllocSizeChanged = FALSE;
522
523 DPRINT("VfatSetAllocationSizeInformation()\n");
524
525 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
526 OldSize = Fcb->entry.FatX.FileSize;
527 else
528 OldSize = Fcb->entry.Fat.FileSize;
529 if (AllocationSize->u.HighPart > 0)
530 {
531 return STATUS_INVALID_PARAMETER;
532 }
533 if (OldSize == NewSize)
534 {
535 return(STATUS_SUCCESS);
536 }
537
538 FirstCluster = vfatDirEntryGetFirstCluster (DeviceExt, &Fcb->entry);
539
540 if (NewSize > Fcb->RFCB.AllocationSize.u.LowPart)
541 {
542 AllocSizeChanged = TRUE;
543 if (FirstCluster == 0)
544 {
545 Fcb->LastCluster = Fcb->LastOffset = 0;
546 Status = NextCluster (DeviceExt, FirstCluster, &FirstCluster, TRUE);
547 if (!NT_SUCCESS(Status))
548 {
549 DPRINT1("NextCluster failed. Status = %x\n", Status);
550 return Status;
551 }
552 if (FirstCluster == 0xffffffff)
553 {
554 return STATUS_DISK_FULL;
555 }
556 Status = OffsetToCluster(DeviceExt, FirstCluster,
557 ROUND_DOWN(NewSize - 1, ClusterSize),
558 &NCluster, TRUE);
559 if (NCluster == 0xffffffff || !NT_SUCCESS(Status))
560 {
561 /* disk is full */
562 NCluster = Cluster = FirstCluster;
563 Status = STATUS_SUCCESS;
564 while (NT_SUCCESS(Status) && Cluster != 0xffffffff && Cluster > 1)
565 {
566 Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
567 WriteCluster (DeviceExt, Cluster, 0);
568 Cluster = NCluster;
569 }
570 return STATUS_DISK_FULL;
571 }
572 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
573 {
574 Fcb->entry.FatX.FirstCluster = FirstCluster;
575 }
576 else
577 {
578 Fcb->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0x0000FFFF);
579 Fcb->entry.Fat.FirstClusterHigh = (unsigned short)((FirstCluster & 0xFFFF0000) >> 16);
580 }
581 }
582 else
583 {
584 if (Fcb->LastCluster > 0 &&
585 (Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize) > Fcb->LastOffset)
586 {
587 Status = OffsetToCluster(DeviceExt, Fcb->LastCluster,
588 Fcb->RFCB.AllocationSize.u.LowPart -
589 ClusterSize - Fcb->LastOffset,
590 &Cluster, FALSE);
591 }
592 else
593 {
594 Status = OffsetToCluster(DeviceExt, FirstCluster,
595 Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize,
596 &Cluster, FALSE);
597 }
598
599 Fcb->LastCluster = Cluster;
600 Fcb->LastOffset = Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize;
601
602 /* FIXME: Check status */
603 /* Cluster points now to the last cluster within the chain */
604 Status = OffsetToCluster(DeviceExt, FirstCluster,
605 ROUND_DOWN(NewSize - 1, ClusterSize),
606 &NCluster, TRUE);
607 if (NCluster == 0xffffffff || !NT_SUCCESS(Status))
608 {
609 /* disk is full */
610 NCluster = Cluster;
611 Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
612 WriteCluster(DeviceExt, Cluster, 0xffffffff);
613 Cluster = NCluster;
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 }
623 UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
624 }
625 else if (NewSize + ClusterSize <= Fcb->RFCB.AllocationSize.u.LowPart)
626 {
627 AllocSizeChanged = TRUE;
628 /* FIXME: Use the cached cluster/offset better way. */
629 Fcb->LastCluster = Fcb->LastCluster = 0;
630 UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
631 if (NewSize > 0)
632 {
633 Status = OffsetToCluster(DeviceExt, FirstCluster,
634 ROUND_DOWN(NewSize - 1, ClusterSize),
635 &Cluster, FALSE);
636
637 NCluster = Cluster;
638 Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
639 WriteCluster(DeviceExt, Cluster, 0xffffffff);
640 Cluster = NCluster;
641 }
642 else
643 {
644 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
645 {
646 Fcb->entry.FatX.FirstCluster = 0;
647 }
648 else
649 {
650 Fcb->entry.Fat.FirstCluster = 0;
651 Fcb->entry.Fat.FirstClusterHigh = 0;
652 }
653
654 NCluster = Cluster = FirstCluster;
655 Status = STATUS_SUCCESS;
656 }
657 while (NT_SUCCESS(Status) && 0xffffffff != Cluster && Cluster > 1)
658 {
659 Status = NextCluster (DeviceExt, FirstCluster, &NCluster, FALSE);
660 WriteCluster (DeviceExt, Cluster, 0);
661 Cluster = NCluster;
662 }
663 }
664 else
665 {
666 UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
667 }
668 /* Update the on-disk directory entry */
669 Fcb->Flags |= FCB_IS_DIRTY;
670 if (AllocSizeChanged)
671 {
672 VfatUpdateEntry(Fcb);
673 }
674 return STATUS_SUCCESS;
675 }
676
677 NTSTATUS VfatQueryInformation(PVFAT_IRP_CONTEXT IrpContext)
678 /*
679 * FUNCTION: Retrieve the specified file information
680 */
681 {
682 FILE_INFORMATION_CLASS FileInformationClass;
683 PVFATFCB FCB = NULL;
684
685 NTSTATUS RC = STATUS_SUCCESS;
686 PVOID SystemBuffer;
687 ULONG BufferLength;
688
689 /* PRECONDITION */
690 ASSERT(IrpContext);
691
692 /* INITIALIZATION */
693 FileInformationClass = IrpContext->Stack->Parameters.QueryFile.FileInformationClass;
694 FCB = (PVFATFCB) IrpContext->FileObject->FsContext;
695
696 DPRINT("VfatQueryInformation is called for '%s'\n",
697 FileInformationClass >= FileMaximumInformation - 1 ? "????" : FileInformationClassNames[FileInformationClass]);
698
699
700 SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
701 BufferLength = IrpContext->Stack->Parameters.QueryFile.Length;
702
703 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
704 {
705 if (!ExAcquireResourceSharedLite(&FCB->MainResource,
706 (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
707 {
708 return VfatQueueRequest (IrpContext);
709 }
710 }
711
712
713 switch (FileInformationClass)
714 {
715 case FileStandardInformation:
716 RC = VfatGetStandardInformation(FCB,
717 SystemBuffer,
718 &BufferLength);
719 break;
720 case FilePositionInformation:
721 RC = VfatGetPositionInformation(IrpContext->FileObject,
722 FCB,
723 IrpContext->DeviceObject,
724 SystemBuffer,
725 &BufferLength);
726 break;
727 case FileBasicInformation:
728 RC = VfatGetBasicInformation(IrpContext->FileObject,
729 FCB,
730 IrpContext->DeviceObject,
731 SystemBuffer,
732 &BufferLength);
733 break;
734 case FileNameInformation:
735 RC = VfatGetNameInformation(IrpContext->FileObject,
736 FCB,
737 IrpContext->DeviceObject,
738 SystemBuffer,
739 &BufferLength);
740 break;
741 case FileInternalInformation:
742 RC = VfatGetInternalInformation(FCB,
743 SystemBuffer,
744 &BufferLength);
745 break;
746 case FileNetworkOpenInformation:
747 RC = VfatGetNetworkOpenInformation(FCB,
748 IrpContext->DeviceExt,
749 SystemBuffer,
750 &BufferLength);
751 break;
752 case FileAllInformation:
753 RC = VfatGetAllInformation(IrpContext->FileObject,
754 FCB,
755 IrpContext->DeviceObject,
756 SystemBuffer,
757 &BufferLength);
758 break;
759
760 case FileAlternateNameInformation:
761 RC = STATUS_NOT_IMPLEMENTED;
762 break;
763 default:
764 RC = STATUS_NOT_SUPPORTED;
765 }
766
767 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
768 {
769 ExReleaseResourceLite(&FCB->MainResource);
770 }
771 IrpContext->Irp->IoStatus.Status = RC;
772 if (NT_SUCCESS(RC))
773 IrpContext->Irp->IoStatus.Information =
774 IrpContext->Stack->Parameters.QueryFile.Length - BufferLength;
775 else
776 IrpContext->Irp->IoStatus.Information = 0;
777 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
778 VfatFreeIrpContext(IrpContext);
779
780 return RC;
781 }
782
783 NTSTATUS VfatSetInformation(PVFAT_IRP_CONTEXT IrpContext)
784 /*
785 * FUNCTION: Retrieve the specified file information
786 */
787 {
788 FILE_INFORMATION_CLASS FileInformationClass;
789 PVFATFCB FCB = NULL;
790 NTSTATUS RC = STATUS_SUCCESS;
791 PVOID SystemBuffer;
792 BOOLEAN CanWait = (IrpContext->Flags & IRPCONTEXT_CANWAIT) != 0;
793
794 /* PRECONDITION */
795 ASSERT(IrpContext);
796
797 DPRINT("VfatSetInformation(IrpContext %x)\n", IrpContext);
798
799 /* INITIALIZATION */
800 FileInformationClass =
801 IrpContext->Stack->Parameters.SetFile.FileInformationClass;
802 FCB = (PVFATFCB) IrpContext->FileObject->FsContext;
803 SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
804
805 DPRINT("VfatSetInformation is called for '%s'\n",
806 FileInformationClass >= FileMaximumInformation - 1 ? "????" : FileInformationClassNames[ FileInformationClass]);
807
808 DPRINT("FileInformationClass %d\n", FileInformationClass);
809 DPRINT("SystemBuffer %x\n", SystemBuffer);
810
811 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
812 {
813 if (!ExAcquireResourceExclusiveLite(&FCB->MainResource,
814 (BOOLEAN)CanWait))
815 {
816 return(VfatQueueRequest (IrpContext));
817 }
818 }
819
820 switch (FileInformationClass)
821 {
822 case FilePositionInformation:
823 RC = VfatSetPositionInformation(IrpContext->FileObject,
824 SystemBuffer);
825 break;
826 case FileDispositionInformation:
827 RC = VfatSetDispositionInformation(IrpContext->FileObject,
828 FCB,
829 IrpContext->DeviceObject,
830 SystemBuffer);
831 break;
832 case FileAllocationInformation:
833 case FileEndOfFileInformation:
834 RC = VfatSetAllocationSizeInformation(IrpContext->FileObject,
835 FCB,
836 IrpContext->DeviceExt,
837 (PLARGE_INTEGER)SystemBuffer);
838 break;
839 case FileBasicInformation:
840 RC = VfatSetBasicInformation(IrpContext->FileObject,
841 FCB,
842 IrpContext->DeviceExt,
843 SystemBuffer);
844 break;
845 case FileRenameInformation:
846 RC = STATUS_NOT_IMPLEMENTED;
847 break;
848 default:
849 RC = STATUS_NOT_SUPPORTED;
850 }
851
852 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
853 {
854 ExReleaseResourceLite(&FCB->MainResource);
855 }
856
857 IrpContext->Irp->IoStatus.Status = RC;
858 IrpContext->Irp->IoStatus.Information = 0;
859 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
860 VfatFreeIrpContext(IrpContext);
861
862 return RC;
863 }
864
865 /* EOF */