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.54 2003/02/13 22:24:16 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
.FileSize
= DeviceExt
->FatInfo
.rootDirectorySectors
* DeviceExt
->FatInfo
.BytesPerSector
;
242 Fcb
->entry
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
243 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
245 Fcb
->entry
.FirstCluster
= ((PUSHORT
)FirstCluster
)[0];
246 Fcb
->entry
.FirstClusterHigh
= ((PUSHORT
)FirstCluster
)[1];
249 Fcb
->entry
.FirstCluster
= 1;
254 DPRINT("FindFile: new Pathname %S, new Objectname %S)\n",Fcb
->PathName
, Fcb
->ObjectName
);
255 return (STATUS_SUCCESS
);
260 DPRINT ("Parent->entry.FileSize %x\n", Parent
->entry
.FileSize
);
261 FirstCluster
= vfatDirEntryGetFirstCluster (DeviceExt
, &Parent
->entry
);
263 if (pDirIndex
&& (*pDirIndex
))
264 DirIndex
= *pDirIndex
;
266 if (NULL
== wcschr(FileToFind
, L
'?') && NULL
== wcschr(FileToFind
, L
'*'))
268 /* if there is no '*?' in the search name, than look first for an existing fcb */
269 len
= wcslen(Parent
->PathName
);
270 memcpy(name
, Parent
->PathName
, len
* sizeof(WCHAR
));
271 if (!vfatFCBIsRoot(Parent
))
275 wcscpy(name
+ len
, FileToFind
);
276 rcFcb
= vfatGrabFCBFromTable(DeviceExt
, name
);
279 if(rcFcb
->startIndex
>= DirIndex
)
281 wcscpy(Fcb
->PathName
, name
);
282 Fcb
->ObjectName
= &Fcb
->PathName
[len
];
283 memcpy(&Fcb
->entry
, &rcFcb
->entry
, sizeof(FATDirEntry
));
286 *pDirIndex
= rcFcb
->dirIndex
;
290 *pDirIndex2
= rcFcb
->startIndex
;
292 DPRINT("FindFile: new Pathname %S, new Objectname %S, DirIndex %d (%d)\n",Fcb
->PathName
, Fcb
->ObjectName
, rcFcb
->dirIndex
, rcFcb
->startIndex
);
293 vfatReleaseFCB(DeviceExt
, rcFcb
);
294 return STATUS_SUCCESS
;
298 vfatReleaseFCB(DeviceExt
, rcFcb
);
299 return STATUS_UNSUCCESSFUL
;
301 vfatReleaseFCB(DeviceExt
, rcFcb
);
307 Status
= vfatGetNextDirEntry(&Context
, &Page
, Parent
, &DirIndex
, name
, &fatDirEntry
, pDirIndex2
);
308 if (Status
== STATUS_NO_MORE_ENTRIES
)
312 if (vfatIsDirEntryVolume(&fatDirEntry
))
317 vfat8Dot3ToString(&fatDirEntry
, name2
);
318 if (wstrcmpjoki (name
, FileToFind
) || wstrcmpjoki (name2
, FileToFind
))
320 if (Parent
&& Parent
->PathName
)
322 len
= wcslen(Parent
->PathName
);
324 memcpy(Fcb
->PathName
, Parent
->PathName
, len
*sizeof(WCHAR
));
325 Fcb
->ObjectName
=&Fcb
->PathName
[len
];
326 if (len
!= 1 || Fcb
->PathName
[0] != '\\')
328 Fcb
->ObjectName
[0] = '\\';
329 Fcb
->ObjectName
= &Fcb
->ObjectName
[1];
334 Fcb
->ObjectName
=Fcb
->PathName
;
335 Fcb
->ObjectName
[0]='\\';
336 Fcb
->ObjectName
=&Fcb
->ObjectName
[1];
338 memcpy(&Fcb
->entry
, &fatDirEntry
, sizeof(FATDirEntry
));
339 wcsncpy(Fcb
->ObjectName
, *name
== 0 ? name2
: name
, MAX_PATH
);
341 *pDirIndex
= DirIndex
;
342 DPRINT("FindFile: new Pathname %S, new Objectname %S, DirIndex %d\n",Fcb
->PathName
, Fcb
->ObjectName
, DirIndex
);
345 CcUnpinData(Context
);
347 return STATUS_SUCCESS
;
352 *pDirIndex
= DirIndex
;
355 CcUnpinData(Context
);
357 return (STATUS_UNSUCCESSFUL
);
361 vfatMakeAbsoluteFilename (PFILE_OBJECT pFileObject
,
362 PWSTR pRelativeFileName
,
363 PWSTR
*pAbsoluteFilename
)
368 DPRINT ("try related for %S\n", pRelativeFileName
);
369 fcb
= pFileObject
->FsContext
;
372 /* verify related object is a directory and target name
373 don't start with \. */
374 if (!(fcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
375 || (pRelativeFileName
[0] == L
'\\'))
377 return STATUS_INVALID_PARAMETER
;
380 /* construct absolute path name */
381 assert (wcslen (fcb
->PathName
) + 1 + wcslen (pRelativeFileName
) + 1
383 rcName
= ExAllocatePool (NonPagedPool
, MAX_PATH
* sizeof(WCHAR
));
386 return STATUS_INSUFFICIENT_RESOURCES
;
388 wcscpy (rcName
, fcb
->PathName
);
389 if (!vfatFCBIsRoot(fcb
))
390 wcscat (rcName
, L
"\\");
391 wcscat (rcName
, pRelativeFileName
);
392 *pAbsoluteFilename
= rcName
;
394 return STATUS_SUCCESS
;
398 VfatOpenFile (PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
401 * FUNCTION: Opens a file
407 PWSTR AbsFileName
= NULL
;
409 DPRINT ("VfatOpenFile(%08lx, %08lx, %S)\n", DeviceExt
, FileObject
, FileName
);
411 if (FileObject
->RelatedFileObject
)
413 DPRINT ("Converting relative filename to absolute filename\n");
414 Status
= vfatMakeAbsoluteFilename (FileObject
->RelatedFileObject
,
417 FileName
= AbsFileName
;
418 if (!NT_SUCCESS(Status
))
424 //FIXME: Get cannonical path name (remove .'s, ..'s and extra separators)
426 DPRINT ("PathName to open: %S\n", FileName
);
428 /* try first to find an existing FCB in memory */
429 DPRINT ("Checking for existing FCB in memory\n");
430 Fcb
= vfatGrabFCBFromTable (DeviceExt
, FileName
);
433 DPRINT ("No existing FCB found, making a new one if file exists.\n");
434 Status
= vfatGetFCBForFile (DeviceExt
, &ParentFcb
, &Fcb
, FileName
);
435 if (ParentFcb
!= NULL
)
437 vfatReleaseFCB (DeviceExt
, ParentFcb
);
439 if (!NT_SUCCESS (Status
))
441 DPRINT ("Could not make a new FCB, status: %x\n", Status
);
444 ExFreePool (AbsFileName
);
449 if (Fcb
->Flags
& FCB_DELETE_PENDING
)
451 vfatReleaseFCB (DeviceExt
, Fcb
);
453 ExFreePool (AbsFileName
);
454 return STATUS_DELETE_PENDING
;
456 DPRINT ("Attaching FCB to fileObject\n");
457 Status
= vfatAttachFCBToFileObject (DeviceExt
, Fcb
, FileObject
);
460 ExFreePool (AbsFileName
);
466 VfatPagingFileCreate(PDEVICE_EXTENSION DeviceExt
, PVFATFCB Fcb
)
468 ULONG CurrentCluster
, NextCluster
, i
;
471 Fcb
->Flags
|= FCB_IS_PAGE_FILE
;
473 ((Fcb
->entry
.FileSize
+ DeviceExt
->FatInfo
.BytesPerCluster
- 1) /
474 DeviceExt
->FatInfo
.BytesPerCluster
);
475 if (Fcb
->FatChainSize
)
478 ExAllocatePool(NonPagedPool
, Fcb
->FatChainSize
* sizeof(ULONG
));
481 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
483 CurrentCluster
= Fcb
->entry
.FirstCluster
+
484 Fcb
->entry
.FirstClusterHigh
* 65536;
488 CurrentCluster
= Fcb
->entry
.FirstCluster
;
492 if (Fcb
->FatChainSize
)
494 while (CurrentCluster
!= 0xffffffff)
496 Fcb
->FatChain
[i
] = CurrentCluster
;
497 Status
= GetNextCluster (DeviceExt
, CurrentCluster
,
498 &NextCluster
, FALSE
);
500 CurrentCluster
= NextCluster
;
506 VfatSupersedeFile(PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
509 ULONG Cluster
, NextCluster
;
512 Fcb
->entry
.FileSize
= 0;
513 if (DeviceExt
->FatInfo
.FatType
== FAT32
)
515 Cluster
= Fcb
->entry
.FirstCluster
+ Fcb
->entry
.FirstClusterHigh
* 65536;
519 Cluster
= Fcb
->entry
.FirstCluster
;
521 Fcb
->entry
.FirstCluster
= 0;
522 Fcb
->entry
.FirstClusterHigh
= 0;
523 VfatUpdateEntry (DeviceExt
, FileObject
);
524 if (Fcb
->RFCB
.FileSize
.QuadPart
> 0)
526 Fcb
->RFCB
.AllocationSize
.QuadPart
= 0;
527 Fcb
->RFCB
.FileSize
.QuadPart
= 0;
528 Fcb
->RFCB
.ValidDataLength
.QuadPart
= 0;
529 /* Notify cache manager about the change in file size if caching is
530 initialized on the file stream */
531 if (FileObject
->SectionObjectPointers
->SharedCacheMap
!= NULL
)
533 CcSetFileSizes(FileObject
, (PCC_FILE_SIZES
)&Fcb
->RFCB
.AllocationSize
);
536 while (Cluster
!= 0xffffffff && Cluster
> 1)
538 Status
= GetNextCluster (DeviceExt
, Cluster
, &NextCluster
, FALSE
);
539 WriteCluster (DeviceExt
, Cluster
, 0);
540 Cluster
= NextCluster
;
545 VfatCreateFile (PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
547 * FUNCTION: Create or open a file
550 PIO_STACK_LOCATION Stack
;
551 PFILE_OBJECT FileObject
;
552 NTSTATUS Status
= STATUS_SUCCESS
;
553 PDEVICE_EXTENSION DeviceExt
;
554 ULONG RequestedDisposition
, RequestedOptions
;
558 BOOLEAN PagingFileCreate
= FALSE
;
559 LARGE_INTEGER AllocationSize
;
561 /* Unpack the various parameters. */
562 Stack
= IoGetCurrentIrpStackLocation (Irp
);
563 RequestedDisposition
= ((Stack
->Parameters
.Create
.Options
>> 24) & 0xff);
565 Stack
->Parameters
.Create
.Options
& FILE_VALID_OPTION_FLAGS
;
566 PagingFileCreate
= (Stack
->Flags
& SL_OPEN_PAGING_FILE
) ? TRUE
: FALSE
;
567 FileObject
= Stack
->FileObject
;
568 DeviceExt
= DeviceObject
->DeviceExtension
;
570 /* Check their validity. */
571 if (RequestedOptions
& FILE_DIRECTORY_FILE
&&
572 RequestedDisposition
== FILE_SUPERSEDE
)
574 return(STATUS_INVALID_PARAMETER
);
577 /* This a open operation for the volume itself */
578 if (FileObject
->FileName
.Length
== 0 &&
579 FileObject
->RelatedFileObject
== NULL
)
581 if (RequestedDisposition
== FILE_CREATE
||
582 RequestedDisposition
== FILE_OVERWRITE_IF
||
583 RequestedDisposition
== FILE_SUPERSEDE
)
585 return(STATUS_ACCESS_DENIED
);
587 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
589 return(STATUS_NOT_A_DIRECTORY
);
591 pFcb
= DeviceExt
->VolumeFcb
;
592 pCcb
= ExAllocateFromNPagedLookasideList(&VfatGlobalData
->CcbLookasideList
);
595 return (STATUS_INSUFFICIENT_RESOURCES
);
597 memset(pCcb
, 0, sizeof(VFATCCB
));
598 FileObject
->Flags
|= FO_FCB_IS_VALID
;
599 FileObject
->SectionObjectPointers
= &pFcb
->SectionObjectPointers
;
600 FileObject
->FsContext
= pFcb
;
601 FileObject
->FsContext2
= pCcb
;
604 Irp
->IoStatus
.Information
= FILE_OPENED
;
605 return(STATUS_SUCCESS
);
609 * Check for illegal characters in the file name
611 c
= FileObject
->FileName
.Buffer
;
614 if (*c
== L
'*' || *c
== L
'?' || (*c
== L
'\\' && c
[1] == L
'\\'))
616 return(STATUS_OBJECT_NAME_INVALID
);
621 /* Try opening the file. */
622 Status
= VfatOpenFile (DeviceExt
, FileObject
, FileObject
->FileName
.Buffer
);
625 * If the directory containing the file to open doesn't exist then
628 if (Status
== STATUS_OBJECT_PATH_NOT_FOUND
||
629 Status
== STATUS_INVALID_PARAMETER
||
630 Status
== STATUS_DELETE_PENDING
)
636 * If the file open failed then create the required file
638 if (!NT_SUCCESS (Status
))
640 if (RequestedDisposition
== FILE_CREATE
||
641 RequestedDisposition
== FILE_OPEN_IF
||
642 RequestedDisposition
== FILE_OVERWRITE_IF
||
643 RequestedDisposition
== FILE_SUPERSEDE
)
646 Attributes
= Stack
->Parameters
.Create
.FileAttributes
;
647 Status
= VfatAddEntry (DeviceExt
, FileObject
, RequestedOptions
,
648 Attributes
& FILE_ATTRIBUTE_VALID_FLAGS
);
649 if (NT_SUCCESS (Status
))
651 pFcb
= FileObject
->FsContext
;
652 Irp
->IoStatus
.Information
= FILE_CREATED
;
653 VfatSetAllocationSizeInformation(FileObject
,
656 &Irp
->Overlay
.AllocationSize
);
657 VfatSetExtendedAttributes(FileObject
,
658 Irp
->AssociatedIrp
.SystemBuffer
,
659 Stack
->Parameters
.Create
.EaLength
);
660 IoSetShareAccess(0 /*DesiredAccess*/,
661 Stack
->Parameters
.Create
.ShareAccess
,
663 &pFcb
->FCBShareAccess
);
677 /* Otherwise fail if the caller wanted to create a new file */
678 if (RequestedDisposition
== FILE_CREATE
)
680 Irp
->IoStatus
.Information
= FILE_EXISTS
;
681 VfatCloseFile (DeviceExt
, FileObject
);
682 return(STATUS_OBJECT_NAME_COLLISION
);
685 pFcb
= FileObject
->FsContext
;
688 * Check the file has the requested attributes
690 if (RequestedOptions
& FILE_NON_DIRECTORY_FILE
&&
691 pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
693 VfatCloseFile (DeviceExt
, FileObject
);
694 return(STATUS_FILE_IS_A_DIRECTORY
);
696 if (RequestedOptions
& FILE_DIRECTORY_FILE
&&
697 !(pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
699 VfatCloseFile (DeviceExt
, FileObject
);
700 return(STATUS_NOT_A_DIRECTORY
);
703 if (RequestedDisposition
== FILE_OVERWRITE
||
704 RequestedDisposition
== FILE_OVERWRITE_IF
)
706 AllocationSize
.QuadPart
= 0;
707 Status
= VfatSetAllocationSizeInformation (FileObject
,
711 if (!NT_SUCCESS (Status
))
713 VfatCloseFile (DeviceExt
, FileObject
);
719 /* Supersede the file */
720 if (RequestedDisposition
== FILE_SUPERSEDE
)
722 VfatSupersedeFile(DeviceExt
, FileObject
, pFcb
);
723 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
727 Irp
->IoStatus
.Information
= FILE_OPENED
;
732 * If this create was for a paging file then make sure all the
733 * information needed to manipulate it is locked in memory.
735 if (PagingFileCreate
)
737 VfatPagingFileCreate(DeviceExt
, pFcb
);
740 /* FIXME : test share access */
741 /* FIXME : test write access if requested */
747 NTSTATUS
VfatCreate (PVFAT_IRP_CONTEXT IrpContext
)
749 * FUNCTION: Create or open a file
756 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
758 /* DeviceObject represents FileSystem instead of logical volume */
759 DPRINT ("FsdCreate called with file system\n");
760 IrpContext
->Irp
->IoStatus
.Information
= FILE_OPENED
;
761 IrpContext
->Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
762 IoCompleteRequest (IrpContext
->Irp
, IO_DISK_INCREMENT
);
763 VfatFreeIrpContext(IrpContext
);
764 return(STATUS_SUCCESS
);
767 if (!(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
769 return(VfatQueueRequest (IrpContext
));
772 IrpContext
->Irp
->IoStatus
.Information
= 0;
773 ExAcquireResourceExclusiveLite (&IrpContext
->DeviceExt
->DirResource
, TRUE
);
774 Status
= VfatCreateFile (IrpContext
->DeviceObject
, IrpContext
->Irp
);
775 ExReleaseResourceLite (&IrpContext
->DeviceExt
->DirResource
);
777 IrpContext
->Irp
->IoStatus
.Status
= Status
;
778 IoCompleteRequest (IrpContext
->Irp
,
779 NT_SUCCESS(Status
) ? IO_DISK_INCREMENT
: IO_NO_INCREMENT
);
780 VfatFreeIrpContext(IrpContext
);