1 /* $Id: create.c,v 1.18 2001/03/06 17:28:25 dwelch Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: services/fs/vfat/create.c
6 * PURPOSE: VFAT Filesystem
7 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
11 /* INCLUDES *****************************************************************/
13 #include <ddk/ntddk.h>
22 /* FUNCTIONS ****************************************************************/
25 IsLastEntry (PVOID Block
, ULONG Offset
)
27 * FUNCTION: Determine if the given directory entry is the last
30 return (((FATDirEntry
*) Block
)[Offset
].Filename
[0] == 0);
34 IsVolEntry (PVOID Block
, ULONG Offset
)
36 * FUNCTION: Determine if the given directory entry is a vol entry
39 if ((((FATDirEntry
*) Block
)[Offset
].Attrib
) == 0x28)
46 IsDeletedEntry (PVOID Block
, ULONG Offset
)
48 * FUNCTION: Determines if the given entry is a deleted one
51 /* Checks special character */
53 return ((((FATDirEntry
*) Block
)[Offset
].Filename
[0] == 0xe5) ||
54 (((FATDirEntry
*) Block
)[Offset
].Filename
[0] == 0));
58 GetEntryName (PVOID Block
, PULONG _Offset
, PWSTR Name
, PULONG _jloop
,
59 PDEVICE_EXTENSION DeviceExt
, ULONG
* _StartingSector
)
61 * FUNCTION: Retrieves the file name, be it in short or long file name format
66 ULONG Offset
= *_Offset
;
67 ULONG StartingSector
= *_StartingSector
;
68 ULONG jloop
= *_jloop
;
71 test
= (FATDirEntry
*) Block
;
72 test2
= (slot
*) Block
;
76 if (IsDeletedEntry (Block
, Offset
))
81 if (test2
[Offset
].attr
== 0x0f)
83 vfat_initstr (Name
, 256);
84 vfat_wcsncpy (Name
, test2
[Offset
].name0_4
, 5);
85 vfat_wcsncat (Name
, test2
[Offset
].name5_10
, 5, 6);
86 vfat_wcsncat (Name
, test2
[Offset
].name11_12
, 11, 2);
89 while ((test2
[Offset
].id
!= 0x41) && (test2
[Offset
].id
!= 0x01) &&
90 (test2
[Offset
].attr
> 0))
93 if (Offset
== ENTRIES_PER_SECTOR
)
96 /* FIXME: Check status */
97 GetNextSector (DeviceExt
, StartingSector
, &StartingSector
, FALSE
);
99 /* FIXME: Check status */
100 VfatReadSectors (DeviceExt
->StorageDevice
,
101 StartingSector
, 1, Block
);
102 test2
= (slot
*) Block
;
105 vfat_movstr (Name
, 13, 0, cpos
* 13);
106 vfat_wcsncpy (Name
, test2
[Offset
].name0_4
, 5);
107 vfat_wcsncat (Name
, test2
[Offset
].name5_10
, 5, 6);
108 vfat_wcsncat (Name
, test2
[Offset
].name11_12
, 11, 2);
112 if (IsDeletedEntry (Block
, Offset
+ 1))
117 *_StartingSector
= StartingSector
;
123 *_StartingSector
= StartingSector
;
128 RtlAnsiToUnicode (Name
, test
[Offset
].Filename
, 8);
129 if (test
[Offset
].Ext
[0] != ' ')
131 RtlCatAnsiToUnicode (Name
, ".", 1);
133 RtlCatAnsiToUnicode (Name
, test
[Offset
].Ext
, 3);
141 ReadVolumeLabel (PDEVICE_EXTENSION DeviceExt
, PVPB Vpb
)
143 * FUNCTION: Read the volume label
150 ULONG StartingSector
;
154 Size
= DeviceExt
->rootDirectorySectors
; /* FIXME : in fat32, no limit */
155 StartingSector
= DeviceExt
->rootStart
;
158 block
= ExAllocatePool (NonPagedPool
, BLOCKSIZE
);
159 DPRINT ("FindFile : start at sector %lx, entry %ld\n", StartingSector
, i
);
160 for (j
= 0; j
< Size
; j
++)
162 /* FIXME: Check status */
163 VfatReadSectors (DeviceExt
->StorageDevice
, StartingSector
, 1, block
);
165 for (i
= 0; i
< ENTRIES_PER_SECTOR
; i
++)
167 if (IsVolEntry ((PVOID
) block
, i
))
169 FATDirEntry
*test
= (FATDirEntry
*) block
;
171 /* copy volume label */
172 RtlAnsiToUnicode (Vpb
->VolumeLabel
, test
[i
].Filename
, 8);
173 RtlCatAnsiToUnicode (Vpb
->VolumeLabel
, test
[i
].Ext
, 3);
174 Vpb
->VolumeLabelLength
= wcslen (Vpb
->VolumeLabel
);
177 return (STATUS_SUCCESS
);
179 if (IsLastEntry ((PVOID
) block
, i
))
181 *(Vpb
->VolumeLabel
) = 0;
182 Vpb
->VolumeLabelLength
= 0;
184 return (STATUS_UNSUCCESSFUL
);
187 /* not found in this sector, try next : */
189 /* directory can be fragmented although it is best to keep them
193 if (DeviceExt
->FatType
== FAT32
)
195 if (StartingSector
== ClusterToSector (DeviceExt
, NextCluster
+ 1))
197 Status
= GetNextCluster (DeviceExt
, NextCluster
, &NextCluster
,
199 if (NextCluster
== 0 || NextCluster
== 0xffffffff)
201 *(Vpb
->VolumeLabel
) = 0;
202 Vpb
->VolumeLabelLength
= 0;
204 return (STATUS_UNSUCCESSFUL
);
206 StartingSector
= ClusterToSector (DeviceExt
, NextCluster
);
210 *(Vpb
->VolumeLabel
) = 0;
211 Vpb
->VolumeLabelLength
= 0;
213 return (STATUS_UNSUCCESSFUL
);
218 FindFile (PDEVICE_EXTENSION DeviceExt
, PVFATFCB Fcb
,
219 PVFATFCB Parent
, PWSTR FileToFind
, ULONG
* StartSector
,
222 * FUNCTION: Find a file
229 ULONG StartingSector
;
234 DPRINT ("FindFile(Parent %x, FileToFind '%S')\n", Parent
, FileToFind
);
236 if (wcslen (FileToFind
) == 0)
239 TempStr
[0] = (WCHAR
) '.';
241 FileToFind
= (PWSTR
)&TempStr
;
244 if (Parent
== NULL
|| Parent
->entry
.FirstCluster
== 1)
246 Size
= DeviceExt
->rootDirectorySectors
; /* FIXME : in fat32, no limit */
247 StartingSector
= DeviceExt
->rootStart
;
249 if (FileToFind
[0] == 0 || (FileToFind
[0] == '\\' && FileToFind
[1] == 0)
250 || (FileToFind
[0] == '.' && FileToFind
[1] == 0))
252 /* it's root : complete essentials fields then return ok */
253 memset (Fcb
, 0, sizeof (VFATFCB
));
254 memset (Fcb
->entry
.Filename
, ' ', 11);
255 Fcb
->entry
.FileSize
= DeviceExt
->rootDirectorySectors
* BLOCKSIZE
;
256 Fcb
->entry
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
257 if (DeviceExt
->FatType
== FAT32
)
258 Fcb
->entry
.FirstCluster
= 2;
260 Fcb
->entry
.FirstCluster
= 1;
262 *StartSector
= StartingSector
;
265 return (STATUS_SUCCESS
);
270 DPRINT ("Parent->entry.FileSize %x\n", Parent
->entry
.FileSize
);
273 if (DeviceExt
->FatType
== FAT32
)
274 NextCluster
= Parent
->entry
.FirstCluster
275 + Parent
->entry
.FirstClusterHigh
* 65536;
277 NextCluster
= Parent
->entry
.FirstCluster
;
278 StartingSector
= ClusterToSector (DeviceExt
, NextCluster
);
279 if (Parent
->entry
.FirstCluster
== 1 && DeviceExt
->FatType
!= FAT32
)
281 /* read of root directory in FAT16 or FAT12 */
282 StartingSector
= DeviceExt
->rootStart
;
285 block
= ExAllocatePool (NonPagedPool
, BLOCKSIZE
);
286 if (StartSector
&& (*StartSector
))
287 StartingSector
= *StartSector
;
288 i
= (Entry
) ? (*Entry
) : 0;
289 for (j
= 0; j
< Size
; j
++)
291 /* FIXME: Check status */
292 VfatReadSectors (DeviceExt
->StorageDevice
, StartingSector
, 1, block
);
294 for (i
= (Entry
) ? (*Entry
) : 0; i
< ENTRIES_PER_SECTOR
; i
++)
296 if (IsVolEntry ((PVOID
) block
, i
))
298 if (IsLastEntry ((PVOID
) block
, i
))
301 *StartSector
= StartingSector
;
305 return (STATUS_UNSUCCESSFUL
);
308 ((PVOID
) block
, &i
, name
, &j
, DeviceExt
, &StartingSector
))
310 if (wstrcmpjoki (name
, FileToFind
))
312 /* In the case of a long filename, the firstcluster is
313 stored in the next record -- where it's short name is */
314 if (((FATDirEntry
*) block
)[i
].Attrib
== 0x0f)
316 if (i
== (ENTRIES_PER_SECTOR
))
318 /* FIXME: Check status */
319 GetNextSector (DeviceExt
, StartingSector
, &StartingSector
, FALSE
);
321 /* FIXME: Check status */
322 VfatReadSectors (DeviceExt
->StorageDevice
,
323 StartingSector
, 1, block
);
326 memcpy (&Fcb
->entry
, &((FATDirEntry
*) block
)[i
],
327 sizeof (FATDirEntry
));
328 vfat_wcsncpy (Fcb
->ObjectName
, name
, MAX_PATH
);
330 *StartSector
= StartingSector
;
334 return (STATUS_SUCCESS
);
338 /* not found in this sector, try next : */
340 /* directory can be fragmented although it is best to keep them
341 unfragmented. Should we change this to also use GetNextSector?
342 GetNextSector was originally implemented to handle the case above */
346 if ((Parent
!= NULL
&& Parent
->entry
.FirstCluster
!= 1)
347 || DeviceExt
->FatType
== FAT32
)
349 if (StartingSector
== ClusterToSector (DeviceExt
, NextCluster
+ 1))
351 Status
= GetNextCluster (DeviceExt
, NextCluster
, &NextCluster
,
353 if (NextCluster
== 0 || NextCluster
== 0xffffffff)
356 *StartSector
= StartingSector
;
360 return (STATUS_UNSUCCESSFUL
);
362 StartingSector
= ClusterToSector (DeviceExt
, NextCluster
);
367 *StartSector
= StartingSector
;
371 return (STATUS_UNSUCCESSFUL
);
377 VfatOpenFile (PDEVICE_EXTENSION DeviceExt
, PFILE_OBJECT FileObject
,
380 * FUNCTION: Opens a file
383 PWSTR current
= NULL
;
387 PVFATFCB Fcb
, pRelFcb
;
389 PVFATCCB newCCB
, pRelCcb
;
391 PFILE_OBJECT pRelFileObject
;
392 PWSTR AbsFileName
= NULL
;
394 PLIST_ENTRY current_entry
;
396 ULONG BytesPerCluster
;
398 DPRINT ("VfatOpenFile(%08lx, %08lx, %S)\n", DeviceExt
, FileObject
, FileName
);
400 /* FIXME : treat relative name */
401 if (FileObject
->RelatedFileObject
)
403 DbgPrint ("try related for %S\n", FileName
);
404 pRelFileObject
= FileObject
->RelatedFileObject
;
405 pRelCcb
= pRelFileObject
->FsContext2
;
407 pRelFcb
= pRelCcb
->pFcb
;
410 * verify related object is a directory and target name don't start with
413 if (!(pRelFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
)
414 || (FileName
[0] != '\\'))
416 Status
= STATUS_INVALID_PARAMETER
;
419 /* construct absolute path name */
420 AbsFileName
= ExAllocatePool (NonPagedPool
, MAX_PATH
);
421 for (i
= 0; pRelFcb
->PathName
[i
]; i
++)
422 AbsFileName
[i
] = pRelFcb
->PathName
[i
];
423 AbsFileName
[i
++] = '\\';
424 for (j
= 0; FileName
[j
] && i
< MAX_PATH
; j
++)
425 AbsFileName
[i
++] = FileName
[j
];
426 assert (i
< MAX_PATH
);
428 FileName
= AbsFileName
;
432 * try first to find an existing FCB in memory
436 KeAcquireSpinLock (&DeviceExt
->FcbListLock
, &oldIrql
);
437 current_entry
= DeviceExt
->FcbListHead
.Flink
;
438 while (current_entry
!= &DeviceExt
->FcbListHead
)
440 Fcb
= CONTAINING_RECORD (current_entry
, VFATFCB
, FcbListEntry
);
442 DPRINT ("Scanning %x\n", Fcb
);
443 DPRINT ("Scanning %S\n", Fcb
->PathName
);
445 if (DeviceExt
== Fcb
->pDevExt
&& wstrcmpi (FileName
, Fcb
->PathName
))
448 KeReleaseSpinLock (&DeviceExt
->FcbListLock
, oldIrql
);
449 FileObject
->FsContext
= (PVOID
)&Fcb
->RFCB
;
450 newCCB
= ExAllocatePool (NonPagedPool
, sizeof (VFATCCB
));
451 memset (newCCB
, 0, sizeof (VFATCCB
));
452 FileObject
->Flags
= FileObject
->Flags
|
453 FO_FCB_IS_VALID
| FO_DIRECT_CACHE_PAGING_READ
;
454 FileObject
->SectionObjectPointers
=
455 &Fcb
->SectionObjectPointers
;
456 FileObject
->FsContext2
= newCCB
;
458 newCCB
->PtrFileObject
= FileObject
;
460 ExFreePool (AbsFileName
);
461 return (STATUS_SUCCESS
);
464 current_entry
= current_entry
->Flink
;
466 KeReleaseSpinLock (&DeviceExt
->FcbListLock
, oldIrql
);
469 DPRINT ("FileName %S\n", FileName
);
473 Fcb
= ExAllocatePool (NonPagedPool
, sizeof (VFATFCB
));
474 memset (Fcb
, 0, sizeof (VFATFCB
));
475 Fcb
->ObjectName
= Fcb
->PathName
;
479 if (*next
== 0) // root
481 memset (Fcb
->entry
.Filename
, ' ', 11);
482 Fcb
->entry
.FileSize
= DeviceExt
->rootDirectorySectors
* BLOCKSIZE
;
483 Fcb
->entry
.Attrib
= FILE_ATTRIBUTE_DIRECTORY
;
484 if (DeviceExt
->FatType
== FAT32
)
485 Fcb
->entry
.FirstCluster
= 2;
487 Fcb
->entry
.FirstCluster
= 1;
488 /* FIXME : is 1 the good value for mark root? */
499 next
= wcschr (next
+ 1, '\\');
506 /* reached the last path component */
507 DPRINT ("exiting: current '%S'\n", current
);
511 DPRINT ("current '%S'\n", current
);
512 Status
= FindFile (DeviceExt
, Fcb
, ParentFcb
, current
, NULL
, NULL
);
513 if (Status
!= STATUS_SUCCESS
)
518 if (ParentFcb
!= NULL
)
519 ExFreePool (ParentFcb
);
521 ExFreePool (AbsFileName
);
523 DPRINT ("error STATUS_OBJECT_PATH_NOT_FOUND\n");
524 return STATUS_OBJECT_PATH_NOT_FOUND
;
528 if (ParentFcb
== NULL
)
531 Fcb
= ExAllocatePool (NonPagedPool
, sizeof (VFATFCB
));
532 memset (Fcb
, 0, sizeof (VFATFCB
));
533 Fcb
->ObjectName
= Fcb
->PathName
;
541 /* searching for last path component */
542 DPRINT ("current '%S'\n", current
);
543 Status
= FindFile (DeviceExt
, Fcb
, ParentFcb
, current
, NULL
, NULL
);
544 if (Status
!= STATUS_SUCCESS
)
546 /* file does not exist */
550 if (ParentFcb
!= NULL
)
551 ExFreePool (ParentFcb
);
553 ExFreePool (AbsFileName
);
555 return STATUS_OBJECT_NAME_NOT_FOUND
;
559 if (ParentFcb
== NULL
)
562 Fcb
= ExAllocatePool (NonPagedPool
, sizeof (VFATFCB
));
563 memset (Fcb
, 0, sizeof (VFATFCB
));
564 Fcb
->ObjectName
= Fcb
->PathName
;
571 FileObject
->Flags
= FileObject
->Flags
|
572 FO_FCB_IS_VALID
| FO_DIRECT_CACHE_PAGING_READ
;
573 FileObject
->SectionObjectPointers
= &ParentFcb
->SectionObjectPointers
;
574 memset(FileObject
->SectionObjectPointers
, 0,
575 sizeof(SECTION_OBJECT_POINTERS
));
576 FileObject
->FsContext
= (PVOID
)&ParentFcb
->RFCB
;
577 newCCB
= ExAllocatePool (NonPagedPool
, sizeof (VFATCCB
));
578 memset (newCCB
, 0, sizeof (VFATCCB
));
579 FileObject
->FsContext2
= newCCB
;
580 newCCB
->pFcb
= ParentFcb
;
581 newCCB
->PtrFileObject
= FileObject
;
582 ParentFcb
->RefCount
++;
583 /* FIXME : initialize all fields in FCB and CCB */
585 KeAcquireSpinLock (&DeviceExt
->FcbListLock
, &oldIrql
);
586 InsertTailList (&DeviceExt
->FcbListHead
, &ParentFcb
->FcbListEntry
);
587 KeReleaseSpinLock (&DeviceExt
->FcbListLock
, oldIrql
);
589 vfat_wcsncpy (ParentFcb
->PathName
, FileName
, MAX_PATH
);
590 ParentFcb
->ObjectName
= ParentFcb
->PathName
+ (current
- FileName
);
591 ParentFcb
->pDevExt
= DeviceExt
;
592 BytesPerCluster
= DeviceExt
->Boot
->SectorsPerCluster
* BLOCKSIZE
;
593 if (BytesPerCluster
>= PAGESIZE
)
595 Status
= CcInitializeFileCache(FileObject
, &ParentFcb
->RFCB
.Bcb
,
600 Status
= CcInitializeFileCache(FileObject
, &ParentFcb
->RFCB
.Bcb
,
603 if (!NT_SUCCESS(Status
))
605 DbgPrint("CcInitializeFileCache failed\n");
608 DPRINT ("file open, fcb=%x\n", ParentFcb
);
609 DPRINT ("FileSize %d\n", ParentFcb
->entry
.FileSize
);
613 ExFreePool (AbsFileName
);
616 return (STATUS_SUCCESS
);
621 VfatCreateFile (PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
623 * FUNCTION: Create or open a file
626 PIO_STACK_LOCATION Stack
;
627 PFILE_OBJECT FileObject
;
628 NTSTATUS Status
= STATUS_SUCCESS
;
629 PDEVICE_EXTENSION DeviceExt
;
630 ULONG RequestedDisposition
, RequestedOptions
;
635 Stack
= IoGetCurrentIrpStackLocation (Irp
);
637 RequestedDisposition
= ((Stack
->Parameters
.Create
.Options
>> 24) & 0xff);
639 Stack
->Parameters
.Create
.Options
& FILE_VALID_OPTION_FLAGS
;
640 if ((RequestedOptions
& FILE_DIRECTORY_FILE
)
641 && RequestedDisposition
== FILE_SUPERSEDE
)
642 return STATUS_INVALID_PARAMETER
;
643 FileObject
= Stack
->FileObject
;
644 DeviceExt
= DeviceObject
->DeviceExtension
;
648 * Check for illegal characters in the file name
650 c
= FileObject
->FileName
.Buffer
;
653 if (*c
== L
'*' || *c
== L
'?')
655 Irp
->IoStatus
.Information
= 0;
656 Irp
->IoStatus
.Status
= STATUS_OBJECT_NAME_INVALID
;
662 Status
= VfatOpenFile (DeviceExt
, FileObject
, FileObject
->FileName
.Buffer
);
665 * If the directory containing the file to open doesn't exist then
668 Irp
->IoStatus
.Information
= 0;
669 if (Status
== STATUS_OBJECT_PATH_NOT_FOUND
)
671 Irp
->IoStatus
.Status
= Status
;
675 if (!NT_SUCCESS (Status
))
678 * If the file open failed then create the required file
680 if (RequestedDisposition
== FILE_CREATE
||
681 RequestedDisposition
== FILE_OPEN_IF
||
682 RequestedDisposition
== FILE_OVERWRITE_IF
||
683 RequestedDisposition
== FILE_SUPERSEDE
)
687 addEntry (DeviceExt
, FileObject
, RequestedOptions
,
689 Create
.FileAttributes
& FILE_ATTRIBUTE_VALID_FLAGS
));
690 if (NT_SUCCESS (Status
))
691 Irp
->IoStatus
.Information
= FILE_CREATED
;
692 /* FIXME set size if AllocationSize requested */
693 /* FIXME set extended attributes? */
694 /* FIXME set share access */
695 /* IoSetShareAccess(DesiredAccess,ShareAccess,FileObject,
696 * ((PVfatCCB)(FileObject->FsContext2))->pFcb->FCBShareAccess);
703 * Otherwise fail if the caller wanted to create a new file
705 if (RequestedDisposition
== FILE_CREATE
)
707 Irp
->IoStatus
.Information
= FILE_EXISTS
;
708 Status
= STATUS_OBJECT_NAME_COLLISION
;
710 pCcb
= FileObject
->FsContext2
;
713 * If requested then delete the file and create a new one with the
716 if (RequestedDisposition
== FILE_SUPERSEDE
)
718 ULONG Cluster
, NextCluster
;
719 /* FIXME set size to 0 and free clusters */
720 pFcb
->entry
.FileSize
= 0;
721 if (DeviceExt
->FatType
== FAT32
)
722 Cluster
= pFcb
->entry
.FirstCluster
723 + pFcb
->entry
.FirstClusterHigh
* 65536;
725 Cluster
= pFcb
->entry
.FirstCluster
;
726 pFcb
->entry
.FirstCluster
= 0;
727 pFcb
->entry
.FirstClusterHigh
= 0;
728 updEntry (DeviceExt
, FileObject
);
729 while (Cluster
!= 0xffffffff && Cluster
> 1)
731 Status
= GetNextCluster (DeviceExt
, Cluster
, &NextCluster
, TRUE
);
732 WriteCluster (DeviceExt
, Cluster
, 0);
733 Cluster
= NextCluster
;
738 * Check the file has the requested attributes
740 if ((RequestedOptions
& FILE_NON_DIRECTORY_FILE
)
741 && (pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
743 Status
= STATUS_FILE_IS_A_DIRECTORY
;
745 if ((RequestedOptions
& FILE_DIRECTORY_FILE
)
746 && !(pFcb
->entry
.Attrib
& FILE_ATTRIBUTE_DIRECTORY
))
748 Status
= STATUS_NOT_A_DIRECTORY
;
750 /* FIXME : test share access */
751 /* FIXME : test write access if requested */
752 if (!NT_SUCCESS (Status
))
753 VfatCloseFile (DeviceExt
, FileObject
);
755 Irp
->IoStatus
.Information
= FILE_OPENED
;
756 /* FIXME : make supersed or overwrite if requested */
759 Irp
->IoStatus
.Status
= Status
;
766 VfatCreate (PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
768 * FUNCTION: Create or open a file
771 NTSTATUS Status
= STATUS_SUCCESS
;
772 PDEVICE_EXTENSION DeviceExt
;
774 assert (DeviceObject
);
777 if (DeviceObject
->Size
== sizeof (DEVICE_OBJECT
))
779 /* DeviceObject represents FileSystem instead of logical volume */
780 DbgPrint ("FsdCreate called with file system\n");
781 Irp
->IoStatus
.Status
= Status
;
782 Irp
->IoStatus
.Information
= FILE_OPENED
;
783 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);
787 DeviceExt
= DeviceObject
->DeviceExtension
;
789 ExAcquireResourceExclusiveLite (&DeviceExt
->DirResource
, TRUE
);
791 Status
= VfatCreateFile (DeviceObject
, Irp
);
793 ExReleaseResourceLite (&DeviceExt
->DirResource
);
795 Irp
->IoStatus
.Status
= Status
;
796 IoCompleteRequest (Irp
, IO_NO_INCREMENT
);