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