[FASTFAT]
[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/filesystems/fastfat/finfo.c
5 * PURPOSE: VFAT Filesystem
6 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
7 * Herve Poussineau (reactos@poussine.freesurf.fr)
8 * Pierre Schweitzer (pierre@reactos.org)
9 *
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include "vfat.h"
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* GLOBALS ******************************************************************/
20
21 const char* FileInformationClassNames[] =
22 {
23 "??????",
24 "FileDirectoryInformation",
25 "FileFullDirectoryInformation",
26 "FileBothDirectoryInformation",
27 "FileBasicInformation",
28 "FileStandardInformation",
29 "FileInternalInformation",
30 "FileEaInformation",
31 "FileAccessInformation",
32 "FileNameInformation",
33 "FileRenameInformation",
34 "FileLinkInformation",
35 "FileNamesInformation",
36 "FileDispositionInformation",
37 "FilePositionInformation",
38 "FileFullEaInformation",
39 "FileModeInformation",
40 "FileAlignmentInformation",
41 "FileAllInformation",
42 "FileAllocationInformation",
43 "FileEndOfFileInformation",
44 "FileAlternateNameInformation",
45 "FileStreamInformation",
46 "FilePipeInformation",
47 "FilePipeLocalInformation",
48 "FilePipeRemoteInformation",
49 "FileMailslotQueryInformation",
50 "FileMailslotSetInformation",
51 "FileCompressionInformation",
52 "FileObjectIdInformation",
53 "FileCompletionInformation",
54 "FileMoveClusterInformation",
55 "FileQuotaInformation",
56 "FileReparsePointInformation",
57 "FileNetworkOpenInformation",
58 "FileAttributeTagInformation",
59 "FileTrackingInformation",
60 "FileIdBothDirectoryInformation",
61 "FileIdFullDirectoryInformation",
62 "FileValidDataLengthInformation",
63 "FileShortNameInformation",
64 "FileMaximumInformation"
65 };
66
67 /* FUNCTIONS ****************************************************************/
68
69 /*
70 * FUNCTION: Retrieve the standard file information
71 */
72 static
73 NTSTATUS
74 VfatGetStandardInformation(
75 PVFATFCB FCB,
76 PFILE_STANDARD_INFORMATION StandardInfo,
77 PULONG BufferLength)
78 {
79 if (*BufferLength < sizeof(FILE_STANDARD_INFORMATION))
80 return STATUS_BUFFER_OVERFLOW;
81
82 /* PRECONDITION */
83 ASSERT(StandardInfo != NULL);
84 ASSERT(FCB != NULL);
85
86 if (vfatFCBIsDirectory(FCB))
87 {
88 StandardInfo->AllocationSize.QuadPart = 0;
89 StandardInfo->EndOfFile.QuadPart = 0;
90 StandardInfo->Directory = TRUE;
91 }
92 else
93 {
94 StandardInfo->AllocationSize = FCB->RFCB.AllocationSize;
95 StandardInfo->EndOfFile = FCB->RFCB.FileSize;
96 StandardInfo->Directory = FALSE;
97 }
98 StandardInfo->NumberOfLinks = 1;
99 StandardInfo->DeletePending = FCB->Flags & FCB_DELETE_PENDING ? TRUE : FALSE;
100
101 *BufferLength -= sizeof(FILE_STANDARD_INFORMATION);
102 return STATUS_SUCCESS;
103 }
104
105 static
106 NTSTATUS
107 VfatSetPositionInformation(
108 PFILE_OBJECT FileObject,
109 PFILE_POSITION_INFORMATION PositionInfo)
110 {
111 DPRINT("FsdSetPositionInformation()\n");
112
113 DPRINT("PositionInfo %p\n", PositionInfo);
114 DPRINT("Setting position %u\n", PositionInfo->CurrentByteOffset.u.LowPart);
115
116 FileObject->CurrentByteOffset.QuadPart =
117 PositionInfo->CurrentByteOffset.QuadPart;
118
119 return STATUS_SUCCESS;
120 }
121
122 static
123 NTSTATUS
124 VfatGetPositionInformation(
125 PFILE_OBJECT FileObject,
126 PVFATFCB FCB,
127 PDEVICE_OBJECT DeviceObject,
128 PFILE_POSITION_INFORMATION PositionInfo,
129 PULONG BufferLength)
130 {
131 UNREFERENCED_PARAMETER(FileObject);
132 UNREFERENCED_PARAMETER(FCB);
133 UNREFERENCED_PARAMETER(DeviceObject);
134
135 DPRINT("VfatGetPositionInformation()\n");
136
137 if (*BufferLength < sizeof(FILE_POSITION_INFORMATION))
138 return STATUS_BUFFER_OVERFLOW;
139
140 PositionInfo->CurrentByteOffset.QuadPart =
141 FileObject->CurrentByteOffset.QuadPart;
142
143 DPRINT("Getting position %I64x\n",
144 PositionInfo->CurrentByteOffset.QuadPart);
145
146 *BufferLength -= sizeof(FILE_POSITION_INFORMATION);
147 return STATUS_SUCCESS;
148 }
149
150 static
151 NTSTATUS
152 VfatSetBasicInformation(
153 PFILE_OBJECT FileObject,
154 PVFATFCB FCB,
155 PDEVICE_EXTENSION DeviceExt,
156 PFILE_BASIC_INFORMATION BasicInfo)
157 {
158 DPRINT("VfatSetBasicInformation()\n");
159
160 ASSERT(NULL != FileObject);
161 ASSERT(NULL != FCB);
162 ASSERT(NULL != DeviceExt);
163 ASSERT(NULL != BasicInfo);
164 /* Check volume label bit */
165 ASSERT(0 == (*FCB->Attributes & _A_VOLID));
166
167 if (FCB->Flags & FCB_IS_FATX_ENTRY)
168 {
169 if (BasicInfo->CreationTime.QuadPart != 0 && BasicInfo->CreationTime.QuadPart != -1)
170 {
171 FsdSystemTimeToDosDateTime(DeviceExt,
172 &BasicInfo->CreationTime,
173 &FCB->entry.FatX.CreationDate,
174 &FCB->entry.FatX.CreationTime);
175 }
176
177 if (BasicInfo->LastAccessTime.QuadPart != 0 && BasicInfo->LastAccessTime.QuadPart != -1)
178 {
179 FsdSystemTimeToDosDateTime(DeviceExt,
180 &BasicInfo->LastAccessTime,
181 &FCB->entry.FatX.AccessDate,
182 &FCB->entry.FatX.AccessTime);
183 }
184
185 if (BasicInfo->LastWriteTime.QuadPart != 0 && BasicInfo->LastWriteTime.QuadPart != -1)
186 {
187 FsdSystemTimeToDosDateTime(DeviceExt,
188 &BasicInfo->LastWriteTime,
189 &FCB->entry.FatX.UpdateDate,
190 &FCB->entry.FatX.UpdateTime);
191 }
192 }
193 else
194 {
195 if (BasicInfo->CreationTime.QuadPart != 0 && BasicInfo->CreationTime.QuadPart != -1)
196 {
197 FsdSystemTimeToDosDateTime(DeviceExt,
198 &BasicInfo->CreationTime,
199 &FCB->entry.Fat.CreationDate,
200 &FCB->entry.Fat.CreationTime);
201 }
202
203 if (BasicInfo->LastAccessTime.QuadPart != 0 && BasicInfo->LastAccessTime.QuadPart != -1)
204 {
205 FsdSystemTimeToDosDateTime(DeviceExt,
206 &BasicInfo->LastAccessTime,
207 &FCB->entry.Fat.AccessDate,
208 NULL);
209 }
210
211 if (BasicInfo->LastWriteTime.QuadPart != 0 && BasicInfo->LastWriteTime.QuadPart != -1)
212 {
213 FsdSystemTimeToDosDateTime(DeviceExt,
214 &BasicInfo->LastWriteTime,
215 &FCB->entry.Fat.UpdateDate,
216 &FCB->entry.Fat.UpdateTime);
217 }
218 }
219
220 if (BasicInfo->FileAttributes)
221 {
222 *FCB->Attributes = (unsigned char)((*FCB->Attributes &
223 (FILE_ATTRIBUTE_DIRECTORY | 0x48)) |
224 (BasicInfo->FileAttributes &
225 (FILE_ATTRIBUTE_ARCHIVE |
226 FILE_ATTRIBUTE_SYSTEM |
227 FILE_ATTRIBUTE_HIDDEN |
228 FILE_ATTRIBUTE_READONLY)));
229 DPRINT("Setting attributes 0x%02x\n", *FCB->Attributes);
230 }
231
232 VfatUpdateEntry(FCB);
233
234 return STATUS_SUCCESS;
235 }
236
237 static
238 NTSTATUS
239 VfatGetBasicInformation(
240 PFILE_OBJECT FileObject,
241 PVFATFCB FCB,
242 PDEVICE_OBJECT DeviceObject,
243 PFILE_BASIC_INFORMATION BasicInfo,
244 PULONG BufferLength)
245 {
246 PDEVICE_EXTENSION DeviceExt;
247
248 UNREFERENCED_PARAMETER(FileObject);
249
250 DPRINT("VfatGetBasicInformation()\n");
251
252 DeviceExt = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
253
254 if (*BufferLength < sizeof(FILE_BASIC_INFORMATION))
255 return STATUS_BUFFER_OVERFLOW;
256
257 if (FCB->Flags & FCB_IS_FATX_ENTRY)
258 {
259 FsdDosDateTimeToSystemTime(DeviceExt,
260 FCB->entry.FatX.CreationDate,
261 FCB->entry.FatX.CreationTime,
262 &BasicInfo->CreationTime);
263 FsdDosDateTimeToSystemTime(DeviceExt,
264 FCB->entry.FatX.AccessDate,
265 FCB->entry.FatX.AccessTime,
266 &BasicInfo->LastAccessTime);
267 FsdDosDateTimeToSystemTime(DeviceExt,
268 FCB->entry.FatX.UpdateDate,
269 FCB->entry.FatX.UpdateTime,
270 &BasicInfo->LastWriteTime);
271 BasicInfo->ChangeTime = BasicInfo->LastWriteTime;
272 }
273 else
274 {
275 FsdDosDateTimeToSystemTime(DeviceExt,
276 FCB->entry.Fat.CreationDate,
277 FCB->entry.Fat.CreationTime,
278 &BasicInfo->CreationTime);
279 FsdDosDateTimeToSystemTime(DeviceExt,
280 FCB->entry.Fat.AccessDate,
281 0,
282 &BasicInfo->LastAccessTime);
283 FsdDosDateTimeToSystemTime(DeviceExt,
284 FCB->entry.Fat.UpdateDate,
285 FCB->entry.Fat.UpdateTime,
286 &BasicInfo->LastWriteTime);
287 BasicInfo->ChangeTime = BasicInfo->LastWriteTime;
288 }
289
290 BasicInfo->FileAttributes = *FCB->Attributes & 0x3f;
291 /* Synthesize FILE_ATTRIBUTE_NORMAL */
292 if (0 == (BasicInfo->FileAttributes & (FILE_ATTRIBUTE_DIRECTORY |
293 FILE_ATTRIBUTE_ARCHIVE |
294 FILE_ATTRIBUTE_SYSTEM |
295 FILE_ATTRIBUTE_HIDDEN |
296 FILE_ATTRIBUTE_READONLY)))
297 {
298 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
299 BasicInfo->FileAttributes |= FILE_ATTRIBUTE_NORMAL;
300 }
301 DPRINT("Getting attributes 0x%02x\n", BasicInfo->FileAttributes);
302
303 *BufferLength -= sizeof(FILE_BASIC_INFORMATION);
304 return STATUS_SUCCESS;
305 }
306
307
308 static
309 NTSTATUS
310 VfatSetDispositionInformation(
311 PFILE_OBJECT FileObject,
312 PVFATFCB FCB,
313 PDEVICE_OBJECT DeviceObject,
314 PFILE_DISPOSITION_INFORMATION DispositionInfo)
315 {
316 #if DBG
317 PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
318 #endif
319
320 DPRINT("FsdSetDispositionInformation(<%wZ>, Delete %u)\n", &FCB->PathNameU, DispositionInfo->DeleteFile);
321
322 ASSERT(DeviceExt != NULL);
323 ASSERT(DeviceExt->FatInfo.BytesPerCluster != 0);
324 ASSERT(FCB != NULL);
325
326 if (!DispositionInfo->DeleteFile)
327 {
328 /* undelete the file */
329 FCB->Flags &= ~FCB_DELETE_PENDING;
330 FileObject->DeletePending = FALSE;
331 return STATUS_SUCCESS;
332 }
333
334 if (FCB->Flags & FCB_DELETE_PENDING)
335 {
336 /* stream already marked for deletion. just update the file object */
337 FileObject->DeletePending = TRUE;
338 return STATUS_SUCCESS;
339 }
340
341 if (*FCB->Attributes & FILE_ATTRIBUTE_READONLY)
342 {
343 return STATUS_CANNOT_DELETE;
344 }
345
346 if (vfatFCBIsRoot(FCB) ||
347 (FCB->LongNameU.Length == sizeof(WCHAR) && FCB->LongNameU.Buffer[0] == L'.') ||
348 (FCB->LongNameU.Length == 2 * sizeof(WCHAR) && FCB->LongNameU.Buffer[0] == L'.' && FCB->LongNameU.Buffer[1] == L'.'))
349 {
350 // we cannot delete a '.', '..' or the root directory
351 return STATUS_ACCESS_DENIED;
352 }
353
354
355 if (!MmFlushImageSection (FileObject->SectionObjectPointer, MmFlushForDelete))
356 {
357 /* can't delete a file if its mapped into a process */
358
359 DPRINT("MmFlushImageSection returned FALSE\n");
360 return STATUS_CANNOT_DELETE;
361 }
362
363 if (vfatFCBIsDirectory(FCB) && !VfatIsDirectoryEmpty(FCB))
364 {
365 /* can't delete a non-empty directory */
366
367 return STATUS_DIRECTORY_NOT_EMPTY;
368 }
369
370 /* all good */
371 FCB->Flags |= FCB_DELETE_PENDING;
372 FileObject->DeletePending = TRUE;
373
374 return STATUS_SUCCESS;
375 }
376
377 static NTSTATUS
378 vfatPrepareTargetForRename(
379 IN PDEVICE_EXTENSION DeviceExt,
380 IN PVFATFCB * ParentFCB,
381 IN PUNICODE_STRING NewName,
382 IN BOOLEAN ReplaceIfExists,
383 IN PUNICODE_STRING ParentName,
384 OUT PBOOLEAN Deleted)
385 {
386 NTSTATUS Status;
387 PVFATFCB TargetFcb;
388
389 DPRINT("vfatPrepareTargetForRename(%p, %p, %wZ, %d, %wZ, %p)\n", DeviceExt, ParentFCB, NewName, ReplaceIfExists, ParentName);
390
391 *Deleted = FALSE;
392 /* Try to open target */
393 Status = vfatGetFCBForFile(DeviceExt, ParentFCB, &TargetFcb, NewName);
394 /* If it exists */
395 if (NT_SUCCESS(Status))
396 {
397 /* Check whether we are allowed to replace */
398 if (ReplaceIfExists)
399 {
400 /* If that's a directory or a read-only file, we're not allowed */
401 if (vfatFCBIsDirectory(TargetFcb) || ((*TargetFcb->Attributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY));
402 {
403 vfatReleaseFCB(DeviceExt, *ParentFCB);
404 *ParentFCB = NULL;
405 vfatReleaseFCB(DeviceExt, TargetFcb);
406 return STATUS_OBJECT_NAME_COLLISION;
407 }
408
409 /* Attempt to flush (might close the file) */
410 if (!MmFlushImageSection(TargetFcb->FileObject->SectionObjectPointer, MmFlushForDelete))
411 {
412 vfatReleaseFCB(DeviceExt, *ParentFCB);
413 *ParentFCB = NULL;
414 vfatReleaseFCB(DeviceExt, TargetFcb);
415 return STATUS_ACCESS_DENIED;
416 }
417
418 /* If we are, ensure the file isn't open by anyone! */
419 if (TargetFcb->OpenHandleCount != 0)
420 {
421 vfatReleaseFCB(DeviceExt, *ParentFCB);
422 *ParentFCB = NULL;
423 vfatReleaseFCB(DeviceExt, TargetFcb);
424 return STATUS_ACCESS_DENIED;
425 }
426
427 /* Effectively delete old file to allow renaming */
428 VfatDelEntry(DeviceExt, TargetFcb, NULL);
429 vfatGrabFCB(DeviceExt, *ParentFCB);
430 vfatReleaseFCB(DeviceExt, TargetFcb);
431 *Deleted = TRUE;
432 }
433 else
434 {
435 vfatReleaseFCB(DeviceExt, *ParentFCB);
436 *ParentFCB = NULL;
437 vfatReleaseFCB(DeviceExt, TargetFcb);
438 return STATUS_OBJECT_NAME_COLLISION;
439 }
440 }
441 else if (*ParentFCB != NULL)
442 {
443 return STATUS_SUCCESS;
444 }
445
446 /* Failure */
447 return Status;
448 }
449
450 /*
451 * FUNCTION: Set the file name information
452 */
453 static
454 NTSTATUS
455 VfatSetRenameInformation(
456 PFILE_OBJECT FileObject,
457 PVFATFCB FCB,
458 PDEVICE_EXTENSION DeviceObject,
459 PFILE_RENAME_INFORMATION RenameInfo,
460 PFILE_OBJECT TargetFileObject)
461 {
462 NTSTATUS Status;
463 UNICODE_STRING NewName;
464 UNICODE_STRING SourcePath;
465 UNICODE_STRING SourceFile;
466 UNICODE_STRING NewPath;
467 UNICODE_STRING NewFile;
468 PFILE_OBJECT RootFileObject;
469 PVFATFCB RootFCB;
470 UNICODE_STRING RenameInfoString;
471 PVFATFCB ParentFCB;
472 IO_STATUS_BLOCK IoStatusBlock;
473 OBJECT_ATTRIBUTES ObjectAttributes;
474 HANDLE TargetHandle;
475 BOOLEAN DeletedTarget;
476
477 DPRINT("VfatSetRenameInfo(%p, %p, %p, %p, %p)\n", FileObject, FCB, DeviceObject, RenameInfo, TargetFileObject);
478
479 /* Disallow renaming root */
480 if (vfatFCBIsRoot(FCB))
481 {
482 return STATUS_INVALID_PARAMETER;
483 }
484
485 /* If we are performing relative opening for rename, get FO for getting FCB and path name */
486 if (RenameInfo->RootDirectory != NULL)
487 {
488 /* We cannot tolerate relative opening with a full path */
489 if (RenameInfo->FileName[0] == L'\\')
490 {
491 return STATUS_OBJECT_NAME_INVALID;
492 }
493
494 Status = ObReferenceObjectByHandle(RenameInfo->RootDirectory,
495 FILE_READ_DATA,
496 *IoFileObjectType,
497 ExGetPreviousMode(),
498 (PVOID *)&RootFileObject,
499 NULL);
500 if (!NT_SUCCESS(Status))
501 {
502 return Status;
503 }
504
505 RootFCB = RootFileObject->FsContext;
506 }
507
508 ParentFCB = NULL;
509
510 if (TargetFileObject == NULL)
511 {
512 /* If we don't have target file object, construct paths thanks to relative FCB, if any, and with
513 * information supplied by the user
514 */
515
516 /* First, setup a string we'll work on */
517 RenameInfoString.Length = RenameInfo->FileNameLength;
518 RenameInfoString.MaximumLength = RenameInfo->FileNameLength;
519 RenameInfoString.Buffer = RenameInfo->FileName;
520
521 /* Check whether we have FQN */
522 if (RenameInfoString.Length > 6 * sizeof(WCHAR))
523 {
524 if (RenameInfoString.Buffer[0] == L'\\' && RenameInfoString.Buffer[1] == L'?' &&
525 RenameInfoString.Buffer[2] == L'?' && RenameInfoString.Buffer[3] == L'\\' &&
526 RenameInfoString.Buffer[5] == L':' && (RenameInfoString.Buffer[4] >= L'A' &&
527 RenameInfoString.Buffer[4] <= L'Z'))
528 {
529 /* If so, open its target directory */
530 InitializeObjectAttributes(&ObjectAttributes,
531 &RenameInfoString,
532 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
533 NULL, NULL);
534
535 Status = IoCreateFile(&TargetHandle,
536 FILE_WRITE_DATA | SYNCHRONIZE,
537 &ObjectAttributes,
538 &IoStatusBlock,
539 NULL, 0,
540 FILE_SHARE_READ | FILE_SHARE_WRITE,
541 FILE_OPEN,
542 FILE_OPEN_FOR_BACKUP_INTENT,
543 NULL, 0,
544 CreateFileTypeNone,
545 NULL,
546 IO_FORCE_ACCESS_CHECK | IO_OPEN_TARGET_DIRECTORY);
547 if (!NT_SUCCESS(Status))
548 {
549 goto Cleanup;
550 }
551
552 /* Get its FO to get the FCB */
553 Status = ObReferenceObjectByHandle(TargetHandle,
554 FILE_WRITE_DATA,
555 *IoFileObjectType,
556 KernelMode,
557 (PVOID *)&TargetFileObject,
558 NULL);
559 if (!NT_SUCCESS(Status))
560 {
561 ZwClose(TargetHandle);
562 goto Cleanup;
563 }
564
565 /* Are we working on the same volume? */
566 if (IoGetRelatedDeviceObject(TargetFileObject) != IoGetRelatedDeviceObject(FileObject))
567 {
568 ObDereferenceObject(TargetFileObject);
569 ZwClose(TargetHandle);
570 TargetFileObject = NULL;
571 Status = STATUS_NOT_SAME_DEVICE;
572 goto Cleanup;
573 }
574 }
575 }
576
577 NewName.Length = 0;
578 NewName.MaximumLength = RenameInfo->FileNameLength;
579 if (RenameInfo->RootDirectory != NULL)
580 {
581 NewName.MaximumLength += sizeof(WCHAR) + RootFCB->PathNameU.Length;
582 }
583 else if (RenameInfo->FileName[0] != L'\\')
584 {
585 /* We don't have full path, and we don't have root directory:
586 * => we move inside the same directory
587 */
588 NewName.MaximumLength += sizeof(WCHAR) + FCB->DirNameU.Length;
589 }
590 else if (TargetFileObject != NULL)
591 {
592 /* We had a FQN:
593 * => we need to use its correct path
594 */
595 NewName.MaximumLength += sizeof(WCHAR) + ((PVFATFCB)TargetFileObject->FsContext)->PathNameU.Length;
596 }
597
598 NewName.Buffer = ExAllocatePoolWithTag(NonPagedPool, NewName.MaximumLength, TAG_VFAT);
599 if (NewName.Buffer == NULL)
600 {
601 if (TargetFileObject != NULL)
602 {
603 ObDereferenceObject(TargetFileObject);
604 ZwClose(TargetHandle);
605 TargetFileObject = NULL;
606 }
607 Status = STATUS_INSUFFICIENT_RESOURCES;
608 goto Cleanup;
609 }
610
611 if (RenameInfo->RootDirectory != NULL)
612 {
613 /* Here, copy first absolute and then append relative */
614 RtlCopyUnicodeString(&NewName, &RootFCB->PathNameU);
615 NewName.Buffer[NewName.Length / sizeof(WCHAR)] = L'\\';
616 NewName.Length += sizeof(WCHAR);
617 RtlAppendUnicodeStringToString(&NewName, &RenameInfoString);
618 }
619 else if (RenameInfo->FileName[0] != L'\\')
620 {
621 /* Here, copy first work directory and then append filename */
622 RtlCopyUnicodeString(&NewName, &FCB->DirNameU);
623 NewName.Buffer[NewName.Length / sizeof(WCHAR)] = L'\\';
624 NewName.Length += sizeof(WCHAR);
625 RtlAppendUnicodeStringToString(&NewName, &RenameInfoString);
626 }
627 else if (TargetFileObject != NULL)
628 {
629 /* Here, copy first path name and then append filename */
630 RtlCopyUnicodeString(&NewName, &((PVFATFCB)TargetFileObject->FsContext)->PathNameU);
631 NewName.Buffer[NewName.Length / sizeof(WCHAR)] = L'\\';
632 NewName.Length += sizeof(WCHAR);
633 RtlAppendUnicodeStringToString(&NewName, &RenameInfoString);
634 }
635 else
636 {
637 /* Here we should have full path, so simply copy it */
638 RtlCopyUnicodeString(&NewName, &RenameInfoString);
639 }
640
641 /* Do we have to cleanup some stuff? */
642 if (TargetFileObject != NULL)
643 {
644 ObDereferenceObject(TargetFileObject);
645 ZwClose(TargetHandle);
646 TargetFileObject = NULL;
647 }
648 }
649 else
650 {
651 /* At that point, we shouldn't care about whether we are relative opening
652 * Target FO FCB should already have full path
653 */
654
655 /* Before constructing string, just make a sanity check (just to be sure!) */
656 if (IoGetRelatedDeviceObject(TargetFileObject) != IoGetRelatedDeviceObject(FileObject))
657 {
658 Status = STATUS_NOT_SAME_DEVICE;
659 goto Cleanup;
660 }
661
662 NewName.Length = 0;
663 NewName.MaximumLength = TargetFileObject->FileName.Length + ((PVFATFCB)TargetFileObject->FsContext)->PathNameU.Length + sizeof(WCHAR);
664 NewName.Buffer = ExAllocatePoolWithTag(NonPagedPool, NewName.MaximumLength, TAG_VFAT);
665 if (NewName.Buffer == NULL)
666 {
667 Status = STATUS_INSUFFICIENT_RESOURCES;
668 goto Cleanup;
669 }
670
671 RtlCopyUnicodeString(&NewName, &((PVFATFCB)TargetFileObject->FsContext)->PathNameU);
672 NewName.Buffer[NewName.Length / sizeof(WCHAR)] = L'\\';
673 NewName.Length += sizeof(WCHAR);
674 RtlAppendUnicodeStringToString(&NewName, &TargetFileObject->FileName);
675 }
676
677 /* Explode our paths to get path & filename */
678 vfatSplitPathName(&FCB->PathNameU, &SourcePath, &SourceFile);
679 DPRINT("Old dir: %wZ, Old file: %wZ\n", &SourcePath, &SourceFile);
680 vfatSplitPathName(&NewName, &NewPath, &NewFile);
681 DPRINT("New dir: %wZ, New file: %wZ\n", &NewPath, &NewFile);
682
683 /* Are we working in place? */
684 if (FsRtlAreNamesEqual(&SourcePath, &NewPath, TRUE, NULL))
685 {
686 if (FsRtlAreNamesEqual(&SourceFile, &NewFile, FALSE, NULL))
687 {
688 Status = STATUS_SUCCESS;
689 goto Cleanup;
690 }
691
692 if (FsRtlAreNamesEqual(&SourceFile, &NewFile, TRUE, NULL))
693 {
694 FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
695 &(DeviceObject->NotifyList),
696 (PSTRING)&FCB->PathNameU,
697 FCB->PathNameU.Length - FCB->LongNameU.Length,
698 NULL,
699 NULL,
700 ((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
701 FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
702 FILE_ACTION_RENAMED_OLD_NAME,
703 NULL);
704 Status = vfatRenameEntry(DeviceObject, FCB, &NewFile, TRUE);
705 if (NT_SUCCESS(Status))
706 {
707 FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
708 &(DeviceObject->NotifyList),
709 (PSTRING)&FCB->PathNameU,
710 FCB->PathNameU.Length - FCB->LongNameU.Length,
711 NULL,
712 NULL,
713 ((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
714 FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
715 FILE_ACTION_RENAMED_NEW_NAME,
716 NULL);
717 }
718 }
719 else
720 {
721 /* Try to find target */
722 ParentFCB = FCB->parentFcb;
723 vfatGrabFCB(DeviceObject, ParentFCB);
724 Status = vfatPrepareTargetForRename(DeviceObject,
725 &ParentFCB,
726 &NewFile,
727 RenameInfo->ReplaceIfExists,
728 &NewPath,
729 &DeletedTarget);
730 if (!NT_SUCCESS(Status))
731 {
732 goto Cleanup;
733 }
734
735 FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
736 &(DeviceObject->NotifyList),
737 (PSTRING)&FCB->PathNameU,
738 FCB->PathNameU.Length - FCB->LongNameU.Length,
739 NULL,
740 NULL,
741 ((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
742 FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
743 (DeletedTarget ? FILE_ACTION_REMOVED : FILE_ACTION_RENAMED_OLD_NAME),
744 NULL);
745 Status = vfatRenameEntry(DeviceObject, FCB, &NewFile, FALSE);
746 if (NT_SUCCESS(Status))
747 {
748 if (DeletedTarget)
749 {
750 FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
751 &(DeviceObject->NotifyList),
752 (PSTRING)&FCB->PathNameU,
753 FCB->PathNameU.Length - FCB->LongNameU.Length,
754 NULL,
755 NULL,
756 FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE
757 | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_EA,
758 FILE_ACTION_MODIFIED,
759 NULL);
760 }
761 else
762 {
763 FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
764 &(DeviceObject->NotifyList),
765 (PSTRING)&FCB->PathNameU,
766 FCB->PathNameU.Length - FCB->LongNameU.Length,
767 NULL,
768 NULL,
769 ((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
770 FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
771 FILE_ACTION_RENAMED_NEW_NAME,
772 NULL);
773 }
774 }
775 }
776 }
777 else
778 {
779 /* Try to find target */
780 ParentFCB = NULL;
781 Status = vfatPrepareTargetForRename(DeviceObject,
782 &ParentFCB,
783 &NewName,
784 RenameInfo->ReplaceIfExists,
785 &NewPath,
786 &DeletedTarget);
787 if (!NT_SUCCESS(Status))
788 {
789 goto Cleanup;
790 }
791
792 FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
793 &(DeviceObject->NotifyList),
794 (PSTRING)&FCB->PathNameU,
795 FCB->PathNameU.Length - FCB->LongNameU.Length,
796 NULL,
797 NULL,
798 ((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
799 FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
800 FILE_ACTION_REMOVED,
801 NULL);
802 Status = VfatMoveEntry(DeviceObject, FCB, &NewFile, ParentFCB);
803 if (NT_SUCCESS(Status))
804 {
805 if (DeletedTarget)
806 {
807 FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
808 &(DeviceObject->NotifyList),
809 (PSTRING)&FCB->PathNameU,
810 FCB->PathNameU.Length - FCB->LongNameU.Length,
811 NULL,
812 NULL,
813 FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE
814 | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_EA,
815 FILE_ACTION_MODIFIED,
816 NULL);
817 }
818 else
819 {
820 FsRtlNotifyFullReportChange(DeviceObject->NotifySync,
821 &(DeviceObject->NotifyList),
822 (PSTRING)&FCB->PathNameU,
823 FCB->PathNameU.Length - FCB->LongNameU.Length,
824 NULL,
825 NULL,
826 ((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) ?
827 FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
828 FILE_ACTION_ADDED,
829 NULL);
830 }
831 }
832 }
833
834 Cleanup:
835 if (ParentFCB != NULL) vfatReleaseFCB(DeviceObject, ParentFCB);
836 if (NewName.Buffer != NULL) ExFreePoolWithTag(NewName.Buffer, TAG_VFAT);
837 if (RenameInfo->RootDirectory != NULL) ObDereferenceObject(RootFileObject);
838
839 return Status;
840 }
841
842 /*
843 * FUNCTION: Retrieve the file name information
844 */
845 static
846 NTSTATUS
847 VfatGetNameInformation(
848 PFILE_OBJECT FileObject,
849 PVFATFCB FCB,
850 PDEVICE_OBJECT DeviceObject,
851 PFILE_NAME_INFORMATION NameInfo,
852 PULONG BufferLength)
853 {
854 ULONG BytesToCopy;
855
856 UNREFERENCED_PARAMETER(FileObject);
857 UNREFERENCED_PARAMETER(DeviceObject);
858
859 ASSERT(NameInfo != NULL);
860 ASSERT(FCB != NULL);
861
862 /* If buffer can't hold at least the file name length, bail out */
863 if (*BufferLength < (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]))
864 return STATUS_BUFFER_OVERFLOW;
865
866 /* Save file name length, and as much file len, as buffer length allows */
867 NameInfo->FileNameLength = FCB->PathNameU.Length;
868
869 /* Calculate amount of bytes to copy not to overflow the buffer */
870 BytesToCopy = min(FCB->PathNameU.Length,
871 *BufferLength - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]));
872
873 /* Fill in the bytes */
874 RtlCopyMemory(NameInfo->FileName, FCB->PathNameU.Buffer, BytesToCopy);
875
876 /* Check if we could write more but are not able to */
877 if (*BufferLength < FCB->PathNameU.Length + (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]))
878 {
879 /* Return number of bytes written */
880 *BufferLength -= FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + BytesToCopy;
881 return STATUS_BUFFER_OVERFLOW;
882 }
883
884 /* We filled up as many bytes, as needed */
885 *BufferLength -= (FIELD_OFFSET(FILE_NAME_INFORMATION, FileName[0]) + FCB->PathNameU.Length);
886
887 return STATUS_SUCCESS;
888 }
889
890 static
891 NTSTATUS
892 VfatGetInternalInformation(
893 PVFATFCB Fcb,
894 PFILE_INTERNAL_INFORMATION InternalInfo,
895 PULONG BufferLength)
896 {
897 ASSERT(InternalInfo);
898 ASSERT(Fcb);
899
900 if (*BufferLength < sizeof(FILE_INTERNAL_INFORMATION))
901 return STATUS_BUFFER_OVERFLOW;
902 // FIXME: get a real index, that can be used in a create operation
903 InternalInfo->IndexNumber.QuadPart = 0;
904 *BufferLength -= sizeof(FILE_INTERNAL_INFORMATION);
905 return STATUS_SUCCESS;
906 }
907
908
909 /*
910 * FUNCTION: Retrieve the file network open information
911 */
912 static
913 NTSTATUS
914 VfatGetNetworkOpenInformation(
915 PVFATFCB Fcb,
916 PDEVICE_EXTENSION DeviceExt,
917 PFILE_NETWORK_OPEN_INFORMATION NetworkInfo,
918 PULONG BufferLength)
919 {
920 ASSERT(NetworkInfo);
921 ASSERT(Fcb);
922
923 if (*BufferLength < sizeof(FILE_NETWORK_OPEN_INFORMATION))
924 return(STATUS_BUFFER_OVERFLOW);
925
926 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
927 {
928 FsdDosDateTimeToSystemTime(DeviceExt,
929 Fcb->entry.FatX.CreationDate,
930 Fcb->entry.FatX.CreationTime,
931 &NetworkInfo->CreationTime);
932 FsdDosDateTimeToSystemTime(DeviceExt,
933 Fcb->entry.FatX.AccessDate,
934 Fcb->entry.FatX.AccessTime,
935 &NetworkInfo->LastAccessTime);
936 FsdDosDateTimeToSystemTime(DeviceExt,
937 Fcb->entry.FatX.UpdateDate,
938 Fcb->entry.FatX.UpdateTime,
939 &NetworkInfo->LastWriteTime);
940 NetworkInfo->ChangeTime.QuadPart = NetworkInfo->LastWriteTime.QuadPart;
941 }
942 else
943 {
944 FsdDosDateTimeToSystemTime(DeviceExt,
945 Fcb->entry.Fat.CreationDate,
946 Fcb->entry.Fat.CreationTime,
947 &NetworkInfo->CreationTime);
948 FsdDosDateTimeToSystemTime(DeviceExt,
949 Fcb->entry.Fat.AccessDate,
950 0,
951 &NetworkInfo->LastAccessTime);
952 FsdDosDateTimeToSystemTime(DeviceExt,
953 Fcb->entry.Fat.UpdateDate,
954 Fcb->entry.Fat.UpdateTime,
955 &NetworkInfo->LastWriteTime);
956 NetworkInfo->ChangeTime.QuadPart = NetworkInfo->LastWriteTime.QuadPart;
957 }
958
959 if (vfatFCBIsDirectory(Fcb))
960 {
961 NetworkInfo->EndOfFile.QuadPart = 0L;
962 NetworkInfo->AllocationSize.QuadPart = 0L;
963 }
964 else
965 {
966 NetworkInfo->AllocationSize = Fcb->RFCB.AllocationSize;
967 NetworkInfo->EndOfFile = Fcb->RFCB.FileSize;
968 }
969
970 NetworkInfo->FileAttributes = *Fcb->Attributes & 0x3f;
971 /* Synthesize FILE_ATTRIBUTE_NORMAL */
972 if (0 == (NetworkInfo->FileAttributes & (FILE_ATTRIBUTE_DIRECTORY |
973 FILE_ATTRIBUTE_ARCHIVE |
974 FILE_ATTRIBUTE_SYSTEM |
975 FILE_ATTRIBUTE_HIDDEN |
976 FILE_ATTRIBUTE_READONLY)))
977 {
978 DPRINT("Synthesizing FILE_ATTRIBUTE_NORMAL\n");
979 NetworkInfo->FileAttributes |= FILE_ATTRIBUTE_NORMAL;
980 }
981
982 *BufferLength -= sizeof(FILE_NETWORK_OPEN_INFORMATION);
983 return STATUS_SUCCESS;
984 }
985
986
987 static
988 NTSTATUS
989 VfatGetEaInformation(
990 PFILE_OBJECT FileObject,
991 PVFATFCB Fcb,
992 PDEVICE_OBJECT DeviceObject,
993 PFILE_EA_INFORMATION Info,
994 PULONG BufferLength)
995 {
996 PDEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
997
998 UNREFERENCED_PARAMETER(FileObject);
999 UNREFERENCED_PARAMETER(Fcb);
1000
1001 /* FIXME - use SEH to access the buffer! */
1002 Info->EaSize = 0;
1003 *BufferLength -= sizeof(*Info);
1004 if (DeviceExt->FatInfo.FatType == FAT12 ||
1005 DeviceExt->FatInfo.FatType == FAT16)
1006 {
1007 /* FIXME */
1008 DPRINT1("VFAT: FileEaInformation not implemented!\n");
1009 }
1010 return STATUS_SUCCESS;
1011 }
1012
1013
1014 /*
1015 * FUNCTION: Retrieve the all file information
1016 */
1017 static
1018 NTSTATUS
1019 VfatGetAllInformation(
1020 PFILE_OBJECT FileObject,
1021 PVFATFCB Fcb,
1022 PDEVICE_OBJECT DeviceObject,
1023 PFILE_ALL_INFORMATION Info,
1024 PULONG BufferLength)
1025 {
1026 NTSTATUS Status;
1027 ULONG InitialBufferLength = *BufferLength;
1028
1029 ASSERT(Info);
1030 ASSERT(Fcb);
1031
1032 if (*BufferLength < sizeof(FILE_ALL_INFORMATION) + Fcb->PathNameU.Length + sizeof(WCHAR))
1033 return(STATUS_BUFFER_OVERFLOW);
1034
1035 /* Basic Information */
1036 Status = VfatGetBasicInformation(FileObject, Fcb, DeviceObject, &Info->BasicInformation, BufferLength);
1037 if (!NT_SUCCESS(Status)) return Status;
1038 /* Standard Information */
1039 Status = VfatGetStandardInformation(Fcb, &Info->StandardInformation, BufferLength);
1040 if (!NT_SUCCESS(Status)) return Status;
1041 /* Internal Information */
1042 Status = VfatGetInternalInformation(Fcb, &Info->InternalInformation, BufferLength);
1043 if (!NT_SUCCESS(Status)) return Status;
1044 /* EA Information */
1045 Info->EaInformation.EaSize = 0;
1046 /* Access Information: The IO-Manager adds this information */
1047 /* Position Information */
1048 Status = VfatGetPositionInformation(FileObject, Fcb, DeviceObject, &Info->PositionInformation, BufferLength);
1049 if (!NT_SUCCESS(Status)) return Status;
1050 /* Mode Information: The IO-Manager adds this information */
1051 /* Alignment Information: The IO-Manager adds this information */
1052 /* Name Information */
1053 Status = VfatGetNameInformation(FileObject, Fcb, DeviceObject, &Info->NameInformation, BufferLength);
1054 if (!NT_SUCCESS(Status)) return Status;
1055
1056 *BufferLength = InitialBufferLength - (sizeof(FILE_ALL_INFORMATION) + Fcb->PathNameU.Length + sizeof(WCHAR));
1057
1058 return STATUS_SUCCESS;
1059 }
1060
1061 static
1062 VOID
1063 UpdateFileSize(
1064 PFILE_OBJECT FileObject,
1065 PVFATFCB Fcb,
1066 ULONG Size,
1067 ULONG ClusterSize)
1068 {
1069 if (Size > 0)
1070 {
1071 Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, ClusterSize);
1072 }
1073 else
1074 {
1075 Fcb->RFCB.AllocationSize.QuadPart = (LONGLONG)0;
1076 }
1077 if (!vfatFCBIsDirectory(Fcb))
1078 {
1079 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
1080 Fcb->entry.FatX.FileSize = Size;
1081 else
1082 Fcb->entry.Fat.FileSize = Size;
1083 }
1084 Fcb->RFCB.FileSize.QuadPart = Size;
1085 Fcb->RFCB.ValidDataLength.QuadPart = Size;
1086
1087 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->RFCB.AllocationSize);
1088 }
1089
1090 NTSTATUS
1091 VfatSetAllocationSizeInformation(
1092 PFILE_OBJECT FileObject,
1093 PVFATFCB Fcb,
1094 PDEVICE_EXTENSION DeviceExt,
1095 PLARGE_INTEGER AllocationSize)
1096 {
1097 ULONG OldSize;
1098 ULONG Cluster, FirstCluster;
1099 NTSTATUS Status;
1100
1101 ULONG ClusterSize = DeviceExt->FatInfo.BytesPerCluster;
1102 ULONG NewSize = AllocationSize->u.LowPart;
1103 ULONG NCluster;
1104 BOOLEAN AllocSizeChanged = FALSE;
1105
1106 DPRINT("VfatSetAllocationSizeInformation(File <%wZ>, AllocationSize %d %u)\n",
1107 &Fcb->PathNameU, AllocationSize->HighPart, AllocationSize->LowPart);
1108
1109 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
1110 OldSize = Fcb->entry.FatX.FileSize;
1111 else
1112 OldSize = Fcb->entry.Fat.FileSize;
1113
1114 if (AllocationSize->u.HighPart > 0)
1115 {
1116 return STATUS_INVALID_PARAMETER;
1117 }
1118
1119 if (OldSize == NewSize)
1120 {
1121 return STATUS_SUCCESS;
1122 }
1123
1124 FirstCluster = vfatDirEntryGetFirstCluster(DeviceExt, &Fcb->entry);
1125
1126 if (NewSize > Fcb->RFCB.AllocationSize.u.LowPart)
1127 {
1128 AllocSizeChanged = TRUE;
1129 if (FirstCluster == 0)
1130 {
1131 Fcb->LastCluster = Fcb->LastOffset = 0;
1132 Status = NextCluster(DeviceExt, FirstCluster, &FirstCluster, TRUE);
1133 if (!NT_SUCCESS(Status))
1134 {
1135 DPRINT1("NextCluster failed. Status = %x\n", Status);
1136 return Status;
1137 }
1138
1139 if (FirstCluster == 0xffffffff)
1140 {
1141 return STATUS_DISK_FULL;
1142 }
1143
1144 Status = OffsetToCluster(DeviceExt, FirstCluster,
1145 ROUND_DOWN(NewSize - 1, ClusterSize),
1146 &NCluster, TRUE);
1147 if (NCluster == 0xffffffff || !NT_SUCCESS(Status))
1148 {
1149 /* disk is full */
1150 NCluster = Cluster = FirstCluster;
1151 Status = STATUS_SUCCESS;
1152 while (NT_SUCCESS(Status) && Cluster != 0xffffffff && Cluster > 1)
1153 {
1154 Status = NextCluster(DeviceExt, FirstCluster, &NCluster, FALSE);
1155 WriteCluster(DeviceExt, Cluster, 0);
1156 Cluster = NCluster;
1157 }
1158 return STATUS_DISK_FULL;
1159 }
1160
1161 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
1162 {
1163 Fcb->entry.FatX.FirstCluster = FirstCluster;
1164 }
1165 else
1166 {
1167 if (DeviceExt->FatInfo.FatType == FAT32)
1168 {
1169 Fcb->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0x0000FFFF);
1170 Fcb->entry.Fat.FirstClusterHigh = FirstCluster >> 16;
1171 }
1172 else
1173 {
1174 ASSERT((FirstCluster >> 16) == 0);
1175 Fcb->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0x0000FFFF);
1176 }
1177 }
1178 }
1179 else
1180 {
1181 if (Fcb->LastCluster > 0)
1182 {
1183 if (Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize == Fcb->LastOffset)
1184 {
1185 Cluster = Fcb->LastCluster;
1186 Status = STATUS_SUCCESS;
1187 }
1188 else
1189 {
1190 Status = OffsetToCluster(DeviceExt, Fcb->LastCluster,
1191 Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize - Fcb->LastOffset,
1192 &Cluster, FALSE);
1193 }
1194 }
1195 else
1196 {
1197 Status = OffsetToCluster(DeviceExt, FirstCluster,
1198 Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize,
1199 &Cluster, FALSE);
1200 }
1201
1202 if (!NT_SUCCESS(Status))
1203 {
1204 return Status;
1205 }
1206
1207 Fcb->LastCluster = Cluster;
1208 Fcb->LastOffset = Fcb->RFCB.AllocationSize.u.LowPart - ClusterSize;
1209
1210 /* FIXME: Check status */
1211 /* Cluster points now to the last cluster within the chain */
1212 Status = OffsetToCluster(DeviceExt, Cluster,
1213 ROUND_DOWN(NewSize - 1, ClusterSize) - Fcb->LastOffset,
1214 &NCluster, TRUE);
1215 if (NCluster == 0xffffffff || !NT_SUCCESS(Status))
1216 {
1217 /* disk is full */
1218 NCluster = Cluster;
1219 Status = NextCluster(DeviceExt, FirstCluster, &NCluster, FALSE);
1220 WriteCluster(DeviceExt, Cluster, 0xffffffff);
1221 Cluster = NCluster;
1222 while (NT_SUCCESS(Status) && Cluster != 0xffffffff && Cluster > 1)
1223 {
1224 Status = NextCluster(DeviceExt, FirstCluster, &NCluster, FALSE);
1225 WriteCluster(DeviceExt, Cluster, 0);
1226 Cluster = NCluster;
1227 }
1228 return STATUS_DISK_FULL;
1229 }
1230 }
1231 UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
1232 }
1233 else if (NewSize + ClusterSize <= Fcb->RFCB.AllocationSize.u.LowPart)
1234 {
1235 DPRINT("Check for the ability to set file size\n");
1236 if (!MmCanFileBeTruncated(FileObject->SectionObjectPointer,
1237 (PLARGE_INTEGER)AllocationSize))
1238 {
1239 DPRINT("Couldn't set file size!\n");
1240 return STATUS_USER_MAPPED_FILE;
1241 }
1242 DPRINT("Can set file size\n");
1243
1244 AllocSizeChanged = TRUE;
1245 /* FIXME: Use the cached cluster/offset better way. */
1246 Fcb->LastCluster = Fcb->LastOffset = 0;
1247 UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
1248 if (NewSize > 0)
1249 {
1250 Status = OffsetToCluster(DeviceExt, FirstCluster,
1251 ROUND_DOWN(NewSize - 1, ClusterSize),
1252 &Cluster, FALSE);
1253
1254 NCluster = Cluster;
1255 Status = NextCluster(DeviceExt, FirstCluster, &NCluster, FALSE);
1256 WriteCluster(DeviceExt, Cluster, 0xffffffff);
1257 Cluster = NCluster;
1258 }
1259 else
1260 {
1261 if (Fcb->Flags & FCB_IS_FATX_ENTRY)
1262 {
1263 Fcb->entry.FatX.FirstCluster = 0;
1264 }
1265 else
1266 {
1267 if (DeviceExt->FatInfo.FatType == FAT32)
1268 {
1269 Fcb->entry.Fat.FirstCluster = 0;
1270 Fcb->entry.Fat.FirstClusterHigh = 0;
1271 }
1272 else
1273 {
1274 Fcb->entry.Fat.FirstCluster = 0;
1275 }
1276 }
1277
1278 NCluster = Cluster = FirstCluster;
1279 Status = STATUS_SUCCESS;
1280 }
1281
1282 while (NT_SUCCESS(Status) && 0xffffffff != Cluster && Cluster > 1)
1283 {
1284 Status = NextCluster(DeviceExt, FirstCluster, &NCluster, FALSE);
1285 WriteCluster(DeviceExt, Cluster, 0);
1286 Cluster = NCluster;
1287 }
1288 }
1289 else
1290 {
1291 UpdateFileSize(FileObject, Fcb, NewSize, ClusterSize);
1292 }
1293
1294 /* Update the on-disk directory entry */
1295 Fcb->Flags |= FCB_IS_DIRTY;
1296 if (AllocSizeChanged)
1297 {
1298 VfatUpdateEntry(Fcb);
1299 }
1300 return STATUS_SUCCESS;
1301 }
1302
1303 /*
1304 * FUNCTION: Retrieve the specified file information
1305 */
1306 NTSTATUS
1307 VfatQueryInformation(
1308 PVFAT_IRP_CONTEXT IrpContext)
1309 {
1310 FILE_INFORMATION_CLASS FileInformationClass;
1311 PVFATFCB FCB = NULL;
1312
1313 NTSTATUS Status = STATUS_SUCCESS;
1314 PVOID SystemBuffer;
1315 ULONG BufferLength;
1316
1317 /* PRECONDITION */
1318 ASSERT(IrpContext);
1319
1320 /* INITIALIZATION */
1321 FileInformationClass = IrpContext->Stack->Parameters.QueryFile.FileInformationClass;
1322 FCB = (PVFATFCB) IrpContext->FileObject->FsContext;
1323
1324 DPRINT("VfatQueryInformation is called for '%s'\n",
1325 FileInformationClass >= FileMaximumInformation - 1 ? "????" : FileInformationClassNames[FileInformationClass]);
1326
1327
1328 SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
1329 BufferLength = IrpContext->Stack->Parameters.QueryFile.Length;
1330
1331 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
1332 {
1333 if (!ExAcquireResourceSharedLite(&FCB->MainResource,
1334 (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
1335 {
1336 return VfatQueueRequest(IrpContext);
1337 }
1338 }
1339
1340 switch (FileInformationClass)
1341 {
1342 case FileStandardInformation:
1343 Status = VfatGetStandardInformation(FCB,
1344 SystemBuffer,
1345 &BufferLength);
1346 break;
1347
1348 case FilePositionInformation:
1349 Status = VfatGetPositionInformation(IrpContext->FileObject,
1350 FCB,
1351 IrpContext->DeviceObject,
1352 SystemBuffer,
1353 &BufferLength);
1354 break;
1355
1356 case FileBasicInformation:
1357 Status = VfatGetBasicInformation(IrpContext->FileObject,
1358 FCB,
1359 IrpContext->DeviceObject,
1360 SystemBuffer,
1361 &BufferLength);
1362 break;
1363
1364 case FileNameInformation:
1365 Status = VfatGetNameInformation(IrpContext->FileObject,
1366 FCB,
1367 IrpContext->DeviceObject,
1368 SystemBuffer,
1369 &BufferLength);
1370 break;
1371
1372 case FileInternalInformation:
1373 Status = VfatGetInternalInformation(FCB,
1374 SystemBuffer,
1375 &BufferLength);
1376 break;
1377
1378 case FileNetworkOpenInformation:
1379 Status = VfatGetNetworkOpenInformation(FCB,
1380 IrpContext->DeviceExt,
1381 SystemBuffer,
1382 &BufferLength);
1383 break;
1384
1385 case FileAllInformation:
1386 Status = VfatGetAllInformation(IrpContext->FileObject,
1387 FCB,
1388 IrpContext->DeviceObject,
1389 SystemBuffer,
1390 &BufferLength);
1391 break;
1392
1393 case FileEaInformation:
1394 Status = VfatGetEaInformation(IrpContext->FileObject,
1395 FCB,
1396 IrpContext->DeviceObject,
1397 SystemBuffer,
1398 &BufferLength);
1399 break;
1400
1401 case FileAlternateNameInformation:
1402 Status = STATUS_NOT_IMPLEMENTED;
1403 break;
1404
1405 default:
1406 Status = STATUS_INVALID_PARAMETER;
1407 }
1408
1409 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
1410 {
1411 ExReleaseResourceLite(&FCB->MainResource);
1412 }
1413
1414 IrpContext->Irp->IoStatus.Status = Status;
1415 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW)
1416 IrpContext->Irp->IoStatus.Information =
1417 IrpContext->Stack->Parameters.QueryFile.Length - BufferLength;
1418 else
1419 IrpContext->Irp->IoStatus.Information = 0;
1420 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
1421 VfatFreeIrpContext(IrpContext);
1422
1423 return Status;
1424 }
1425
1426 /*
1427 * FUNCTION: Retrieve the specified file information
1428 */
1429 NTSTATUS
1430 VfatSetInformation(
1431 PVFAT_IRP_CONTEXT IrpContext)
1432 {
1433 FILE_INFORMATION_CLASS FileInformationClass;
1434 PVFATFCB FCB = NULL;
1435 NTSTATUS Status = STATUS_SUCCESS;
1436 PVOID SystemBuffer;
1437
1438 /* PRECONDITION */
1439 ASSERT(IrpContext);
1440
1441 DPRINT("VfatSetInformation(IrpContext %p)\n", IrpContext);
1442
1443 /* INITIALIZATION */
1444 FileInformationClass =
1445 IrpContext->Stack->Parameters.SetFile.FileInformationClass;
1446 FCB = (PVFATFCB) IrpContext->FileObject->FsContext;
1447 SystemBuffer = IrpContext->Irp->AssociatedIrp.SystemBuffer;
1448
1449 DPRINT("VfatSetInformation is called for '%s'\n",
1450 FileInformationClass >= FileMaximumInformation - 1 ? "????" : FileInformationClassNames[ FileInformationClass]);
1451
1452 DPRINT("FileInformationClass %d\n", FileInformationClass);
1453 DPRINT("SystemBuffer %p\n", SystemBuffer);
1454
1455 /* Special: We should call MmCanFileBeTruncated here to determine if changing
1456 the file size would be allowed. If not, we bail with the right error.
1457 We must do this before acquiring the lock. */
1458 if (FileInformationClass == FileEndOfFileInformation)
1459 {
1460 DPRINT("Check for the ability to set file size\n");
1461 if (!MmCanFileBeTruncated(IrpContext->FileObject->SectionObjectPointer,
1462 (PLARGE_INTEGER)SystemBuffer))
1463 {
1464 DPRINT("Couldn't set file size!\n");
1465 IrpContext->Irp->IoStatus.Status = STATUS_USER_MAPPED_FILE;
1466 IrpContext->Irp->IoStatus.Information = 0;
1467 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
1468 VfatFreeIrpContext(IrpContext);
1469 return STATUS_USER_MAPPED_FILE;
1470 }
1471 DPRINT("Can set file size\n");
1472 }
1473
1474 if (FileInformationClass == FileRenameInformation)
1475 {
1476 if (!ExAcquireResourceExclusiveLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource,
1477 (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
1478 {
1479 return VfatQueueRequest(IrpContext);
1480 }
1481 }
1482
1483 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
1484 {
1485 if (!ExAcquireResourceExclusiveLite(&FCB->MainResource,
1486 (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
1487 {
1488 if (FileInformationClass == FileRenameInformation)
1489 {
1490 ExReleaseResourceLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource);
1491 }
1492 return VfatQueueRequest(IrpContext);
1493 }
1494 }
1495
1496 switch (FileInformationClass)
1497 {
1498 case FilePositionInformation:
1499 Status = VfatSetPositionInformation(IrpContext->FileObject,
1500 SystemBuffer);
1501 break;
1502
1503 case FileDispositionInformation:
1504 Status = VfatSetDispositionInformation(IrpContext->FileObject,
1505 FCB,
1506 IrpContext->DeviceObject,
1507 SystemBuffer);
1508 break;
1509
1510 case FileAllocationInformation:
1511 case FileEndOfFileInformation:
1512 Status = VfatSetAllocationSizeInformation(IrpContext->FileObject,
1513 FCB,
1514 IrpContext->DeviceExt,
1515 (PLARGE_INTEGER)SystemBuffer);
1516 break;
1517
1518 case FileBasicInformation:
1519 Status = VfatSetBasicInformation(IrpContext->FileObject,
1520 FCB,
1521 IrpContext->DeviceExt,
1522 SystemBuffer);
1523 break;
1524
1525 case FileRenameInformation:
1526 Status = VfatSetRenameInformation(IrpContext->FileObject,
1527 FCB,
1528 IrpContext->DeviceExt,
1529 SystemBuffer,
1530 IrpContext->Stack->Parameters.SetFile.FileObject);
1531 break;
1532
1533 default:
1534 Status = STATUS_NOT_SUPPORTED;
1535 }
1536
1537 if (!(FCB->Flags & FCB_IS_PAGE_FILE))
1538 {
1539 ExReleaseResourceLite(&FCB->MainResource);
1540 }
1541
1542 if (FileInformationClass == FileRenameInformation)
1543 {
1544 ExReleaseResourceLite(&((PDEVICE_EXTENSION)IrpContext->DeviceObject->DeviceExtension)->DirResource);
1545 }
1546
1547 IrpContext->Irp->IoStatus.Status = Status;
1548 IrpContext->Irp->IoStatus.Information = 0;
1549 IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
1550 VfatFreeIrpContext(IrpContext);
1551
1552 return Status;
1553 }
1554
1555 /* EOF */