3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: create.c,v 1.55 2003/03/23 10:45:56 hbirr Exp $
21 * PROJECT: ReactOS kernel
22 * FILE: services/fs/vfat/create.c
23 * PURPOSE: VFAT Filesystem
24 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
28 /* INCLUDES *****************************************************************/
30 #include <ddk/ntddk.h>
39 /* GLOBALS *******************************************************************/
41 #define ENTRIES_PER_PAGE (PAGE_SIZE / sizeof (FATDirEntry))
43 /* FUNCTIONS *****************************************************************/
45 void vfat8Dot3ToString (PFAT_DIR_ENTRY pEntry
, PWSTR pName
)
47 int fromIndex
, toIndex
;
49 fromIndex
= toIndex
= 0;
50 while (fromIndex
< 8 && pEntry
->Filename
[fromIndex
] != ' ')
52 if (pEntry
->lCase
& VFAT_CASE_LOWER_BASE
)
54 pName
[toIndex
++] = tolower(pEntry
->Filename
[fromIndex
++]);
58 pName
[toIndex
++] = pEntry
->Filename
[fromIndex
++];
61 if (pEntry
->Ext
[0] != ' ')
63 pName
[toIndex
++] = L
'.';
65 while (fromIndex
< 3 && pEntry
->Ext
[fromIndex
] != ' ')
67 if (pEntry
->lCase
& VFAT_CASE_LOWER_EXT
)
69 pName
[toIndex
++] = tolower(pEntry
->Ext
[fromIndex
++]);
73 pName
[toIndex
++] = pEntry
->Ext
[fromIndex
++];
77 pName
[toIndex
] = L
'\0';
80 static void vfat8Dot3ToVolumeLabel (PFAT_DIR_ENTRY pEntry
, PWSTR pName
)
82 int fromIndex
, toIndex
;
84 fromIndex
= toIndex
= 0;
85 while (fromIndex
< 8 && pEntry
->Filename
[fromIndex
] != ' ')
87 if (pEntry
->lCase
& VFAT_CASE_LOWER_BASE
)
89 pName
[toIndex
++] = tolower(pEntry
->Filename
[fromIndex
++]);
93 pName
[toIndex
++] = pEntry
->Filename
[fromIndex
++];
96 if (pEntry
->Ext
[0] != ' ')
99 while (fromIndex
< 3 && pEntry
->Ext
[fromIndex
] != ' ')
101 if (pEntry
->lCase
& VFAT_CASE_LOWER_EXT
)
103 pName
[toIndex
++] = tolower(pEntry
->Ext
[fromIndex
++]);
107 pName
[toIndex
++] = pEntry
->Ext
[fromIndex
++];
111 pName
[toIndex
] = L
'\0';
115 ReadVolumeLabel (PDEVICE_EXTENSION DeviceExt
, PVPB Vpb
)
117 * FUNCTION: Read the volume label
120 PVOID Context
= NULL
;
124 LARGE_INTEGER FileOffset
;
126 *(Vpb
->VolumeLabel
) = 0;
127 Vpb
->VolumeLabelLength
= 0;
129 pFcb
= vfatOpenRootFCB (DeviceExt
);
131 FileOffset
.QuadPart
= 0;
132 if (CcMapData(pFcb
->FileObject
, &FileOffset
, PAGE_SIZE
, TRUE
, &Context
, (PVOID
*)&Entry
))
136 if (vfatIsDirEntryVolume(Entry
))
138 /* copy volume label */
139 vfat8Dot3ToVolumeLabel (Entry
, Vpb
->VolumeLabel
);
140 Vpb
->VolumeLabelLength
= wcslen (Vpb
->VolumeLabel
) * sizeof(WCHAR
);
143 if (vfatIsDirEntryEndMarker(Entry
))
149 if ((DirIndex
% ENTRIES_PER_PAGE
) == 0)
151 CcUnpinData(Context
);
152 FileOffset
.u
.LowPart
+= PAGE_SIZE
;
153 if (!CcMapData(pFcb
->FileObject
, &FileOffset
, PAGE_SIZE
, TRUE
, &Context
, (PVOID
*)&Entry
))
162 CcUnpinData(Context
);
165 vfatReleaseFCB (DeviceExt
, pFcb
);
167 return STATUS_SUCCESS
;
171 FindFile (PDEVICE_EXTENSION DeviceExt
,
178 * FUNCTION: Find a file
190 PVOID Context
= NULL
;
194 FATDirEntry fatDirEntry
;
196 DPRINT ("FindFile(Parent %x, FileToFind '%S', DirIndex: %d)\n", Parent
, FileToFind
, pDirIndex
? *pDirIndex
: 0);
197 DPRINT ("FindFile: old Pathname %x, old Objectname %x)\n",Fcb
->PathName
, Fcb
->ObjectName
);
201 if (wcslen (FileToFind
) == 0)
204 TempStr
[0] = (WCHAR
) '*';
206 FileToFind
= (PWSTR
)&TempStr
;
210 FirstCluster
= vfatDirEntryGetFirstCluster(DeviceExt
, &Parent
->entry
);
211 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
213 if (FirstCluster
== DeviceExt
->FatInfo
.RootCluster
)
218 if (FirstCluster
== 1)
226 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
227 FirstCluster
= DeviceExt
->FatInfo
.RootCluster
;
231 if (FileToFind
[0] == 0 || (FileToFind
[0] == '\\' && FileToFind
[1] == 0)
232 || (FileToFind
[0] == '.' && FileToFind
[1] == 0))
234 /* it's root : complete essentials fields then return ok */
236 memset (Fcb
, 0, sizeof (VFATFCB
));
237 memset (Fcb
->entry
.Filename
, ' ', 11);
239 Fcb
->PathName
[0]='\\';
240 Fcb
->ObjectName
= &Fcb
->PathName
[1];
241 Fcb
->entry
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
242 Fcb
->entry
.CreationDate
= 0x0021; /* 1.1.1980 */
243 Fcb
->entry
.AccessDate
= 0x0021;
244 Fcb
->entry
.UpdateDate
= 0x0021;
245 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
247 Fcb
->entry
.FirstCluster
= ((PUSHORT
)&FirstCluster
)[0];
248 Fcb
->entry
.FirstClusterHigh
= ((PUSHORT
)&FirstCluster
)[1];
251 Fcb
->entry
.FirstCluster
= 1;
256 DPRINT("FindFile: new Pathname %S, new Objectname %S)\n",Fcb
->PathName
, Fcb
->ObjectName
);
257 return (STATUS_SUCCESS
);
262 DPRINT ("Parent->entry.FileSize %x\n", Parent
->entry
.FileSize
);
263 FirstCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Parent
->entry
);
265 if (pDirIndex
&& (*pDirIndex
))
266 DirIndex
= *pDirIndex
;
268 if (NULL
== wcschr(FileToFind
, L
'?') && NULL
== wcschr(FileToFind
, L
'*'))
270 /* if there is no '*?' in the search name, than look first for an existing fcb */
271 len
= wcslen(Parent
->PathName
);
272 memcpy(name
, Parent
->PathName
, len
* sizeof(WCHAR
));
273 if (!vfatFCBIsRoot(Parent
))
277 wcscpy(name
+ len
, FileToFind
);
278 rcFcb
= vfatGrabFCBFromTable(DeviceExt
, name
);
281 if(rcFcb
->startIndex
>= DirIndex
)
283 wcscpy(Fcb
->PathName
, name
);
284 Fcb
->ObjectName
= &Fcb
->PathName
[len
];
285 memcpy(&Fcb
->entry
, &rcFcb
->entry
, sizeof(FATDirEntry
));
288 *pDirIndex
= rcFcb
->dirIndex
;
292 *pDirIndex2
= rcFcb
->startIndex
;
294 DPRINT("FindFile: new Pathname %S, new Objectname %S, DirIndex %d (%d)\n",Fcb
->PathName
, Fcb
->ObjectName
, rcFcb
->dirIndex
, rcFcb
->startIndex
);
295 vfatReleaseFCB(DeviceExt
, rcFcb
);
296 return STATUS_SUCCESS
;
300 vfatReleaseFCB(DeviceExt
, rcFcb
);
301 return STATUS_UNSUCCESSFUL
;
303 vfatReleaseFCB(DeviceExt
, rcFcb
);
309 Status
= vfatGetNextDirEntry(&Context
, &Page
, Parent
, &DirIndex
, name
, &fatDirEntry
, pDirIndex2
);
310 if (Status
== STATUS_NO_MORE_ENTRIES
)
314 if (vfatIsDirEntryVolume(&fatDirEntry
))
319 vfat8Dot3ToString(&fatDirEntry
, name2
);
320 if (wstrcmpjoki (name
, FileToFind
) || wstrcmpjoki (name2
, FileToFind
))
322 if (Parent
&& Parent
->PathName
)
324 len
= wcslen(Parent
->PathName
);
326 memcpy(Fcb
->PathName
, Parent
->PathName
, len
*sizeof(WCHAR
));
327 Fcb
->ObjectName
=&Fcb
->PathName
[len
];
328 if (len
!= 1 || Fcb
->PathName
[0] != '\\')
330 Fcb
->ObjectName
[0] = '\\';
331 Fcb
->ObjectName
= &Fcb
->ObjectName
[1];
336 Fcb
->ObjectName
=Fcb
->PathName
;
337 Fcb
->ObjectName
[0]='\\';
338 Fcb
->ObjectName
=&Fcb
->ObjectName
[1];
340 memcpy(&Fcb
->entry
, &fatDirEntry
, sizeof(FATDirEntry
));
341 wcsncpy(Fcb
->ObjectName
, *name
== 0 ? name2
: name
, MAX_PATH
);
343 *pDirIndex
= DirIndex
;
344 DPRINT("FindFile: new Pathname %S, new Objectname %S, DirIndex %d\n",Fcb
->PathName
, Fcb
->ObjectName
, DirIndex
);
347 CcUnpinData(Context
);
349 return STATUS_SUCCESS
;
354 *pDirIndex
= DirIndex
;
357 CcUnpinData(Context
);
359 return (STATUS_UNSUCCESSFUL
);
363 vfatMakeAbsoluteFilename (PFILE_OBJECT pFileObject
,
364 PWSTR pRelativeFileName
,
365 PWSTR
*pAbsoluteFilename
)
370 DPRINT ("try related for %S\n", pRelativeFileName
);
371 fcb
= pFileObject
->FsContext
;
374 /* verify related object is a directory and target name
375 don't start with \. */
376 if (!(fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
377 || (pRelativeFileName
[0] == L
'\\'))
379 return STATUS_INVALID_PARAMETER
;
382 /* construct absolute path name */
383 assert (wcslen (fcb
->PathName
) + 1 + wcslen (pRelativeFileName
) + 1
385 rcName
= ExAllocatePool (NonPagedPool
, MAX_PATH
* sizeof(WCHAR
));
388 return STATUS_INSUFFICIENT_RESOURCES
;
390 wcscpy (rcName
, fcb
->PathName
);
391 if (!vfatFCBIsRoot(fcb
))
392 wcscat (rcName
, L
"\\");
393 wcscat (rcName
, pRelativeFileName
);
394 *pAbsoluteFilename
= rcName
;
396 return STATUS_SUCCESS
;
400 VfatOpenFile (PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
403 * FUNCTION: Opens a file
409 PWSTR AbsFileName
= NULL
;
411 DPRINT ("VfatOpenFile(%08lx, %08lx, %S)\n", DeviceExt
, FileObject
, FileName
);
413 if (FileObject
->RelatedFileObject
)
415 DPRINT ("Converting relative filename to absolute filename\n");
416 Status
= vfatMakeAbsoluteFilename (FileObject
->RelatedFileObject
,
419 FileName
= AbsFileName
;
420 if (!NT_SUCCESS(Status
))
426 //FIXME: Get cannonical path name (remove .'s, ..'s and extra separators)
428 DPRINT ("PathName to open: %S\n", FileName
);
430 /* try first to find an existing FCB in memory */
431 DPRINT ("Checking for existing FCB in memory\n");
432 Fcb
= vfatGrabFCBFromTable (DeviceExt
, FileName
);
435 DPRINT ("No existing FCB found, making a new one if file exists.\n");
436 Status
= vfatGetFCBForFile (DeviceExt
, &ParentFcb
, &Fcb
, FileName
);
437 if (ParentFcb
!= NULL
)
439 vfatReleaseFCB (DeviceExt
, ParentFcb
);
441 if (!NT_SUCCESS (Status
))
443 DPRINT ("Could not make a new FCB, status: %x\n", Status
);
446 ExFreePool (AbsFileName
);
451 if (Fcb
->Flags
& FCB_DELETE_PENDING
)
453 vfatReleaseFCB (DeviceExt
, Fcb
);
455 ExFreePool (AbsFileName
);
456 return STATUS_DELETE_PENDING
;
458 DPRINT ("Attaching FCB to fileObject\n");
459 Status
= vfatAttachFCBToFileObject (DeviceExt
, Fcb
, FileObject
);
462 ExFreePool (AbsFileName
);
468 VfatPagingFileCreate(PDEVICE_EXTENSION DeviceExt
, PVFATFCB Fcb
)
470 ULONG CurrentCluster
, NextCluster
, i
;
473 Fcb
->Flags
|= FCB_IS_PAGE_FILE
;
475 ((Fcb
->entry
.FileSize
+ DeviceExt
->FatInfo
.BytesPerCluster
- 1) /
476 DeviceExt
->FatInfo
.BytesPerCluster
);
477 if (Fcb
->FatChainSize
)
480 ExAllocatePool(NonPagedPool
, Fcb
->FatChainSize
* sizeof(ULONG
));
483 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
485 CurrentCluster
= Fcb
->entry
.FirstCluster
+
486 Fcb
->entry
.FirstClusterHigh
* 65536;
490 CurrentCluster
= Fcb
->entry
.FirstCluster
;
494 if (Fcb
->FatChainSize
)
496 while (CurrentCluster
!= 0xffffffff)
498 Fcb
->FatChain
[i
] = CurrentCluster
;
499 Status
= GetNextCluster (DeviceExt
, CurrentCluster
,
500 &NextCluster
, FALSE
);
502 CurrentCluster
= NextCluster
;
508 VfatSupersedeFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
511 ULONG Cluster
, NextCluster
;
514 Fcb
->entry
.FileSize
= 0;
515 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
517 Cluster
= Fcb
->entry
.FirstCluster
+ Fcb
->entry
.FirstClusterHigh
* 65536;
521 Cluster
= Fcb
->entry
.FirstCluster
;
523 Fcb
->entry
.FirstCluster
= 0;
524 Fcb
->entry
.FirstClusterHigh
= 0;
525 VfatUpdateEntry (DeviceExt
, FileObject
);
526 if (Fcb
->RFCB
.FileSize
.QuadPart
> 0)
528 Fcb
->RFCB
.AllocationSize
.QuadPart
= 0;
529 Fcb
->RFCB
.FileSize
.QuadPart
= 0;
530 Fcb
->RFCB
.ValidDataLength
.QuadPart
= 0;
531 /* Notify cache manager about the change in file size if caching is
532 initialized on the file stream */
533 if (FileObject
->SectionObjectPointers
->SharedCacheMap
!= NULL
)
535 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
538 while (Cluster
!= 0xffffffff && Cluster
> 1)
540 Status
= GetNextCluster (DeviceExt
, Cluster
, &NextCluster
, FALSE
);
541 WriteCluster (DeviceExt
, Cluster
, 0);
542 Cluster
= NextCluster
;
547 VfatCreateFile (PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
549 * FUNCTION: Create or open a file
552 PIO_STACK_LOCATION Stack
;
553 PFILE_OBJECT FileObject
;
554 NTSTATUS Status
= STATUS_SUCCESS
;
555 PDEVICE_EXTENSION DeviceExt
;
556 ULONG RequestedDisposition
, RequestedOptions
;
560 BOOLEAN PagingFileCreate
= FALSE
;
561 LARGE_INTEGER AllocationSize
;
563 /* Unpack the various parameters. */
564 Stack
= IoGetCurrentIrpStackLocation (Irp
);
565 RequestedDisposition
= ((Stack
->Parameters
.Create
.Options
>> 24) & 0xff);
567 Stack
->Parameters
.Create
.Options
& FILE_VALID_OPTION_FLAGS
;
568 PagingFileCreate
= (Stack
->Flags
& SL_OPEN_PAGING_FILE
) ? TRUE
: FALSE
;
569 FileObject
= Stack
->FileObject
;
570 DeviceExt
= DeviceObject
->DeviceExtension
;
572 /* Check their validity. */
573 if (RequestedOptions
& FILE_DIRECTORY_FILE
&&
574 RequestedDisposition
== FILE_SUPERSEDE
)
576 return(STATUS_INVALID_PARAMETER
);
579 /* This a open operation for the volume itself */
580 if (FileObject
->FileName
.Length
== 0 &&
581 FileObject
->RelatedFileObject
== NULL
)
583 if (RequestedDisposition
== FILE_CREATE
||
584 RequestedDisposition
== FILE_OVERWRITE_IF
||
585 RequestedDisposition
== FILE_SUPERSEDE
)
587 return(STATUS_ACCESS_DENIED
);
589 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
591 return(STATUS_NOT_A_DIRECTORY
);
593 pFcb
= DeviceExt
->VolumeFcb
;
594 pCcb
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
);
597 return (STATUS_INSUFFICIENT_RESOURCES
);
599 memset(pCcb
, 0, sizeof(VFATCCB
));
600 FileObject
->Flags
|= FO_FCB_IS_VALID
;
601 FileObject
->SectionObjectPointers
= &pFcb
->SectionObjectPointers
;
602 FileObject
->FsContext
= pFcb
;
603 FileObject
->FsContext2
= pCcb
;
606 Irp
->IoStatus
.Information
= FILE_OPENED
;
607 return(STATUS_SUCCESS
);
611 * Check for illegal characters in the file name
613 c
= FileObject
->FileName
.Buffer
;
616 if (*c
== L
'*' || *c
== L
'?' || (*c
== L
'\\' && c
[1] == L
'\\'))
618 return(STATUS_OBJECT_NAME_INVALID
);
623 /* Try opening the file. */
624 Status
= VfatOpenFile (DeviceExt
, FileObject
, FileObject
->FileName
.Buffer
);
627 * If the directory containing the file to open doesn't exist then
630 if (Status
== STATUS_OBJECT_PATH_NOT_FOUND
||
631 Status
== STATUS_INVALID_PARAMETER
||
632 Status
== STATUS_DELETE_PENDING
)
638 * If the file open failed then create the required file
640 if (!NT_SUCCESS (Status
))
642 if (RequestedDisposition
== FILE_CREATE
||
643 RequestedDisposition
== FILE_OPEN_IF
||
644 RequestedDisposition
== FILE_OVERWRITE_IF
||
645 RequestedDisposition
== FILE_SUPERSEDE
)
648 Attributes
= Stack
->Parameters
.Create
.FileAttributes
;
649 Status
= VfatAddEntry (DeviceExt
, FileObject
, RequestedOptions
,
650 Attributes
& FILE_ATTRIBUTE_VALID_FLAGS
);
651 if (NT_SUCCESS (Status
))
653 pFcb
= FileObject
->FsContext
;
654 Irp
->IoStatus
.Information
= FILE_CREATED
;
655 VfatSetAllocationSizeInformation(FileObject
,
658 &Irp
->Overlay
.AllocationSize
);
659 VfatSetExtendedAttributes(FileObject
,
660 Irp
->AssociatedIrp
.SystemBuffer
,
661 Stack
->Parameters
.Create
.EaLength
);
662 IoSetShareAccess(0 /*DesiredAccess*/,
663 Stack
->Parameters
.Create
.ShareAccess
,
665 &pFcb
->FCBShareAccess
);
679 /* Otherwise fail if the caller wanted to create a new file */
680 if (RequestedDisposition
== FILE_CREATE
)
682 Irp
->IoStatus
.Information
= FILE_EXISTS
;
683 VfatCloseFile (DeviceExt
, FileObject
);
684 return(STATUS_OBJECT_NAME_COLLISION
);
687 pFcb
= FileObject
->FsContext
;
690 * Check the file has the requested attributes
692 if (RequestedOptions
& FILE_NON_DIRECTORY_FILE
&&
693 pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
695 VfatCloseFile (DeviceExt
, FileObject
);
696 return(STATUS_FILE_IS_A_DIRECTORY
);
698 if (RequestedOptions
& FILE_DIRECTORY_FILE
&&
699 !(pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
701 VfatCloseFile (DeviceExt
, FileObject
);
702 return(STATUS_NOT_A_DIRECTORY
);
705 if (RequestedDisposition
== FILE_OVERWRITE
||
706 RequestedDisposition
== FILE_OVERWRITE_IF
)
708 AllocationSize
.QuadPart
= 0;
709 Status
= VfatSetAllocationSizeInformation (FileObject
,
713 if (!NT_SUCCESS (Status
))
715 VfatCloseFile (DeviceExt
, FileObject
);
721 /* Supersede the file */
722 if (RequestedDisposition
== FILE_SUPERSEDE
)
724 VfatSupersedeFile(DeviceExt
, FileObject
, pFcb
);
725 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
729 Irp
->IoStatus
.Information
= FILE_OPENED
;
734 * If this create was for a paging file then make sure all the
735 * information needed to manipulate it is locked in memory.
737 if (PagingFileCreate
)
739 VfatPagingFileCreate(DeviceExt
, pFcb
);
742 /* FIXME : test share access */
743 /* FIXME : test write access if requested */
749 NTSTATUS
VfatCreate (PVFAT_IRP_CONTEXT IrpContext
)
751 * FUNCTION: Create or open a file
758 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
760 /* DeviceObject represents FileSystem instead of logical volume */
761 DPRINT ("FsdCreate called with file system\n");
762 IrpContext
->Irp
->IoStatus
.Information
= FILE_OPENED
;
763 IrpContext
->Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
764 IoCompleteRequest (IrpContext
->Irp
, IO_DISK_INCREMENT
);
765 VfatFreeIrpContext(IrpContext
);
766 return(STATUS_SUCCESS
);
769 if (!(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
771 return(VfatQueueRequest (IrpContext
));
774 IrpContext
->Irp
->IoStatus
.Information
= 0;
775 ExAcquireResourceExclusiveLite (&IrpContext
->DeviceExt
->DirResource
, TRUE
);
776 Status
= VfatCreateFile (IrpContext
->DeviceObject
, IrpContext
->Irp
);
777 ExReleaseResourceLite (&IrpContext
->DeviceExt
->DirResource
);
779 IrpContext
->Irp
->IoStatus
.Status
= Status
;
780 IoCompleteRequest (IrpContext
->Irp
,
781 NT_SUCCESS(Status
) ? IO_DISK_INCREMENT
: IO_NO_INCREMENT
);
782 VfatFreeIrpContext(IrpContext
);