4acf8707416798df7a066909a3292b705d349c95
[reactos.git] / reactos / drivers / fs / vfat / create.c
1 /* $Id: create.c,v 1.5 2000/06/29 23:35:50 dwelch Exp $
2 *
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)
8
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <ddk/cctypes.h>
15 #include <wchar.h>
16 #include <limits.h>
17
18 #define NDEBUG
19 #include <debug.h>
20
21 #include "vfat.h"
22
23 /* FUNCTIONS ****************************************************************/
24
25 BOOLEAN IsLastEntry(PVOID Block, ULONG Offset)
26 /*
27 * FUNCTION: Determine if the given directory entry is the last
28 */
29 {
30 return(((FATDirEntry *)Block)[Offset].Filename[0] == 0);
31 }
32
33 BOOLEAN IsVolEntry(PVOID Block, ULONG Offset)
34 /*
35 * FUNCTION: Determine if the given directory entry is a vol entry
36 */
37 {
38 if( (((FATDirEntry *)Block)[Offset].Attrib)==0x28 ) return TRUE;
39 else return FALSE;
40 }
41
42 BOOLEAN IsDeletedEntry(PVOID Block, ULONG Offset)
43 /*
44 * FUNCTION: Determines if the given entry is a deleted one
45 */
46 {
47 /* Checks special character */
48
49 return ((((FATDirEntry *)Block)[Offset].Filename[0] == 0xe5) || (((FATDirEntry *)Block)[Offset].Filename[0] == 0));
50 }
51
52 BOOLEAN GetEntryName(PVOID Block, PULONG _Offset, PWSTR Name, PULONG _jloop,
53 PDEVICE_EXTENSION DeviceExt, ULONG * _StartingSector)
54 /*
55 * FUNCTION: Retrieves the file name, be it in short or long file name format
56 */
57 {
58 FATDirEntry* test;
59 slot* test2;
60 ULONG Offset = *_Offset;
61 ULONG StartingSector = *_StartingSector;
62 ULONG jloop = *_jloop;
63 ULONG cpos;
64
65 test = (FATDirEntry *)Block;
66 test2 = (slot *)Block;
67
68 *Name = 0;
69
70 if (IsDeletedEntry(Block,Offset))
71 {
72 return(FALSE);
73 }
74
75 if(test2[Offset].attr == 0x0f)
76 {
77 vfat_initstr(Name, 256);
78 vfat_wcsncpy(Name,test2[Offset].name0_4,5);
79 vfat_wcsncat(Name,test2[Offset].name5_10,5,6);
80 vfat_wcsncat(Name,test2[Offset].name11_12,11,2);
81
82 cpos=0;
83 while((test2[Offset].id!=0x41) && (test2[Offset].id!=0x01) &&
84 (test2[Offset].attr>0))
85 {
86 Offset++;
87 if(Offset==ENTRIES_PER_SECTOR) {
88 Offset=0;
89 StartingSector++;//FIXME : nor always the next sector
90 jloop++;
91 VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,Block);
92 test2 = (slot *)Block;
93 }
94 cpos++;
95 vfat_movstr(Name, 13, 0, cpos*13);
96 vfat_wcsncpy(Name, test2[Offset].name0_4, 5);
97 vfat_wcsncat(Name,test2[Offset].name5_10,5,6);
98 vfat_wcsncat(Name,test2[Offset].name11_12,11,2);
99
100 }
101
102 if (IsDeletedEntry(Block,Offset+1))
103 {
104 Offset++;
105 *_Offset = Offset;
106 *_jloop = jloop;
107 *_StartingSector = StartingSector;
108 return(FALSE);
109 }
110
111 *_Offset = Offset;
112 *_jloop = jloop;
113 *_StartingSector = StartingSector;
114
115 return(TRUE);
116 }
117
118 RtlAnsiToUnicode(Name,test[Offset].Filename,8);
119 if (test[Offset].Ext[0]!=' ')
120 {
121 RtlCatAnsiToUnicode(Name,".",1);
122 }
123 RtlCatAnsiToUnicode(Name,test[Offset].Ext,3);
124
125 *_Offset = Offset;
126
127 return(TRUE);
128 }
129
130 NTSTATUS ReadVolumeLabel(PDEVICE_EXTENSION DeviceExt, PVPB Vpb)
131 /*
132 * FUNCTION: Read the volume label
133 */
134 {
135 ULONG i = 0;
136 ULONG j;
137 ULONG Size;
138 char* block;
139 ULONG StartingSector;
140 ULONG NextCluster;
141
142 Size = DeviceExt->rootDirectorySectors;//FIXME : in fat32, no limit
143 StartingSector = DeviceExt->rootStart;
144 NextCluster=0;
145
146 block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
147 DPRINT("FindFile : start at sector %lx, entry %ld\n",StartingSector,i);
148 for (j=0; j<Size; j++)
149 {
150 VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,block);
151
152 for (i=0; i<ENTRIES_PER_SECTOR; i++)
153 {
154 if (IsVolEntry((PVOID)block,i))
155 {
156 FATDirEntry *test = (FATDirEntry *)block;
157
158 /* copy volume label */
159 RtlAnsiToUnicode(Vpb->VolumeLabel,test[i].Filename,8);
160 RtlCatAnsiToUnicode(Vpb->VolumeLabel,test[i].Ext,3);
161 Vpb->VolumeLabelLength = wcslen(Vpb->VolumeLabel);
162
163 ExFreePool(block);
164 return(STATUS_SUCCESS);
165 }
166 if (IsLastEntry((PVOID)block,i))
167 {
168 *(Vpb->VolumeLabel) = 0;
169 Vpb->VolumeLabelLength = 0;
170 ExFreePool(block);
171 return(STATUS_UNSUCCESSFUL);
172 }
173 }
174 // not found in this sector, try next :
175
176 /* directory can be fragmented although it is best to keep them
177 unfragmented */
178 StartingSector++;
179 if (DeviceExt->FatType ==FAT32)
180 {
181 if(StartingSector==ClusterToSector(DeviceExt,NextCluster+1))
182 {
183 NextCluster = GetNextCluster(DeviceExt,NextCluster);
184 if (NextCluster == 0||NextCluster==0xffffffff)
185 {
186 *(Vpb->VolumeLabel) = 0;
187 Vpb->VolumeLabelLength = 0;
188 ExFreePool(block);
189 return(STATUS_UNSUCCESSFUL);
190 }
191 StartingSector = ClusterToSector(DeviceExt,NextCluster);
192 }
193 }
194 }
195 *(Vpb->VolumeLabel) = 0;
196 Vpb->VolumeLabelLength = 0;
197 ExFreePool(block);
198 return(STATUS_UNSUCCESSFUL);
199 }
200
201
202 NTSTATUS FindFile(PDEVICE_EXTENSION DeviceExt, PVFATFCB Fcb,
203 PVFATFCB Parent, PWSTR FileToFind,ULONG *StartSector,ULONG *Entry)
204 /*
205 * FUNCTION: Find a file
206 */
207 {
208 ULONG i, j;
209 ULONG Size;
210 char* block;
211 WCHAR name[256];
212 ULONG StartingSector;
213 ULONG NextCluster;
214 WCHAR TempStr[2];
215
216 DPRINT("FindFile(Parent %x, FileToFind '%S')\n",Parent,FileToFind);
217
218 if (wcslen(FileToFind)==0)
219 {
220 CHECKPOINT;
221 TempStr[0] = (WCHAR)'.';
222 TempStr[1] = 0;
223 FileToFind=(PWSTR)&TempStr;
224 }
225 if (Parent != NULL)
226 {
227 DPRINT("Parent->entry.FirstCluster %d\n",Parent->entry.FirstCluster);
228 }
229
230 DPRINT("FindFile '%S'\n", FileToFind);
231 if (Parent == NULL||Parent->entry.FirstCluster==1)
232 {
233 CHECKPOINT;
234 Size = DeviceExt->rootDirectorySectors; /* FIXME : in fat32, no limit */
235 StartingSector = DeviceExt->rootStart;
236 NextCluster=0;
237 if(FileToFind[0]==0 ||(FileToFind[0]=='\\' && FileToFind[1]==0) ||
238 (FileToFind[0]=='.' && FileToFind[1]==0))
239 {
240 /* it's root : complete essentials fields then return ok */
241 CHECKPOINT;
242 memset(Fcb,0,sizeof(VFATFCB));
243 memset(Fcb->entry.Filename,' ',11);
244 Fcb->entry.FileSize=DeviceExt->rootDirectorySectors*BLOCKSIZE;
245 Fcb->entry.Attrib=FILE_ATTRIBUTE_DIRECTORY;
246 if (DeviceExt->FatType == FAT32)
247 Fcb->entry.FirstCluster=2;
248 else
249 Fcb->entry.FirstCluster=1; /* FIXME : is 1 the good value for mark root? */
250 if(StartSector)
251 *StartSector=StartingSector;
252 if(Entry)
253 *Entry=0;
254 return(STATUS_SUCCESS);
255 }
256 }
257 else
258 {
259 DPRINT("Parent->entry.FileSize %x\n",Parent->entry.FileSize);
260
261 Size = ULONG_MAX;
262 if (DeviceExt->FatType == FAT32)
263 NextCluster = Parent->entry.FirstCluster
264 +Parent->entry.FirstClusterHigh*65536;
265 else
266 NextCluster = Parent->entry.FirstCluster;
267 StartingSector = ClusterToSector(DeviceExt, NextCluster);
268 if(Parent->entry.FirstCluster==1 && DeviceExt->FatType!=FAT32)
269 {
270 /* read of root directory in FAT16 or FAT12 */
271 StartingSector=DeviceExt->rootStart;
272 }
273 }
274 CHECKPOINT;
275 block = ExAllocatePool(NonPagedPool,BLOCKSIZE);
276 CHECKPOINT;
277 if (StartSector && (*StartSector)) StartingSector=*StartSector;
278 i=(Entry)?(*Entry):0;
279 DPRINT("FindFile : start at sector %lx, entry %ld\n",StartingSector,i);
280 for (j=0; j<Size; j++)
281 {
282 VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,block);
283
284 for (i=(Entry)?(*Entry):0; i<ENTRIES_PER_SECTOR; i++)
285 {
286 if (IsVolEntry((PVOID)block,i))
287 continue;
288 if (IsLastEntry((PVOID)block,i))
289 {
290 if(StartSector) *StartSector=StartingSector;
291 if(Entry) *Entry=i;
292 ExFreePool(block);
293 return(STATUS_UNSUCCESSFUL);
294 }
295 if (GetEntryName((PVOID)block,&i,name,&j,DeviceExt,&StartingSector))
296 {
297 DPRINT("Comparing '%S' '%S'\n",name,FileToFind);
298 if (wstrcmpjoki(name,FileToFind))
299 {
300 /* In the case of a long filename, the firstcluster is stored in
301 the next record -- where it's short name is */
302 if(((FATDirEntry *)block)[i].Attrib==0x0f) i++;
303 if( i==(ENTRIES_PER_SECTOR))
304 {
305 /* entry is in next sector */
306 StartingSector++;
307 /* FIXME : treat case of next sector fragmented */
308 VFATReadSectors(DeviceExt->StorageDevice,StartingSector,1,block);
309 i=0;
310 }
311 memcpy(&Fcb->entry,&((FATDirEntry *)block)[i],
312 sizeof(FATDirEntry));
313 vfat_wcsncpy(Fcb->ObjectName,name,MAX_PATH);
314 if(StartSector) *StartSector=StartingSector;
315 if(Entry) *Entry=i;
316 ExFreePool(block);
317 return(STATUS_SUCCESS);
318 }
319 }
320 }
321 /* not found in this sector, try next : */
322
323 /* directory can be fragmented although it is best to keep them
324 unfragmented */
325 if(Entry) *Entry=0;
326 StartingSector++;
327 if ((Parent != NULL && Parent->entry.FirstCluster!=1)
328 || DeviceExt->FatType ==FAT32)
329 {
330 if(StartingSector==ClusterToSector(DeviceExt,NextCluster+1))
331 {
332 NextCluster = GetNextCluster(DeviceExt,NextCluster);
333 if (NextCluster == 0||NextCluster==0xffffffff)
334 {
335 if(StartSector) *StartSector=StartingSector;
336 if(Entry) *Entry=i;
337 ExFreePool(block);
338 return(STATUS_UNSUCCESSFUL);
339 }
340 StartingSector = ClusterToSector(DeviceExt,NextCluster);
341 }
342 }
343 }
344 if(StartSector) *StartSector=StartingSector;
345 if(Entry) *Entry=i;
346 ExFreePool(block);
347 return(STATUS_UNSUCCESSFUL);
348 }
349
350
351 NTSTATUS FsdCloseFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject)
352 /*
353 * FUNCTION: Closes a file
354 */
355 {
356 PVFATFCB pFcb;
357 PVFATCCB pCcb;
358 KIRQL oldIrql;
359
360 DPRINT("FsdCloseFile(DeviceExt %x, FileObject %x)\n",
361 DeviceExt,FileObject);
362
363 //FIXME : update entry in directory ?
364 pCcb = (PVFATCCB)(FileObject->FsContext2);
365
366 DPRINT("pCcb %x\n",pCcb);
367 if (pCcb == NULL)
368 {
369 return(STATUS_SUCCESS);
370 }
371
372 pFcb = pCcb->pFcb;
373
374 pFcb->RefCount--;
375 if(pFcb->RefCount<=0)
376 {
377 KeAcquireSpinLock(&DeviceExt->FcbListLock, &oldIrql);
378 RemoveEntryList(&pFcb->FcbListEntry);
379 KeReleaseSpinLock(&DeviceExt->FcbListLock, oldIrql);
380 ExFreePool(pFcb);
381 }
382 ExFreePool(pCcb);
383 return STATUS_SUCCESS;
384 }
385
386 NTSTATUS FsdOpenFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
387 PWSTR FileName)
388 /*
389 * FUNCTION: Opens a file
390 */
391 {
392 PWSTR current = NULL;
393 PWSTR next;
394 PWSTR string;
395 PVFATFCB ParentFcb;
396 PVFATFCB Fcb,pRelFcb;
397 PVFATFCB Temp;
398 PVFATCCB newCCB,pRelCcb;
399 NTSTATUS Status;
400 PFILE_OBJECT pRelFileObject;
401 PWSTR AbsFileName=NULL;
402 short i,j;
403 PLIST_ENTRY current_entry;
404 KIRQL oldIrql;
405
406 DPRINT("FsdOpenFile(%08lx, %08lx, %S)\n",
407 DeviceExt,
408 FileObject,
409 FileName);
410
411 /* FIXME : treat relative name */
412 if(FileObject->RelatedFileObject)
413 {
414 DbgPrint("try related for %S\n",FileName);
415 pRelFileObject=FileObject->RelatedFileObject;
416 pRelCcb=pRelFileObject->FsContext2;
417 assert(pRelCcb);
418 pRelFcb=pRelCcb->pFcb;
419 assert(pRelFcb);
420 /*
421 * verify related object is a directory and target name don't start with \.
422 */
423 if( !(pRelFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
424 || (FileName[0]!= '\\') )
425 {
426 Status=STATUS_INVALID_PARAMETER;
427 return Status;
428 }
429 /* construct absolute path name */
430 AbsFileName=ExAllocatePool(NonPagedPool,MAX_PATH);
431 for (i=0;pRelFcb->PathName[i];i++)
432 AbsFileName[i]=pRelFcb->PathName[i];
433 AbsFileName[i++]='\\';
434 for (j=0;FileName[j]&&i<MAX_PATH;j++)
435 AbsFileName[i++]=FileName[j];
436 assert(i<MAX_PATH);
437 AbsFileName[i]=0;
438 FileName=AbsFileName;
439 }
440
441 /*
442 * try first to find an existing FCB in memory
443 */
444 CHECKPOINT;
445
446 KeAcquireSpinLock(&DeviceExt->FcbListLock, &oldIrql);
447 current_entry = DeviceExt->FcbListHead.Flink;
448 while (current_entry != &DeviceExt->FcbListHead)
449 {
450 Fcb = CONTAINING_RECORD(current_entry, VFATFCB, FcbListEntry);
451
452 DPRINT("Scanning %x\n", Fcb);
453 DPRINT("Scanning %S\n", Fcb->PathName);
454
455 if (DeviceExt==Fcb->pDevExt
456 && wstrcmpi(FileName,Fcb->PathName))
457 {
458 Fcb->RefCount++;
459 KeReleaseSpinLock(&DeviceExt->FcbListLock, oldIrql);
460 FileObject->FsContext =(PVOID) &Fcb->NTRequiredFCB;
461 newCCB = ExAllocatePool(NonPagedPool,sizeof(VFATCCB));
462 memset(newCCB,0,sizeof(VFATCCB));
463 FileObject->FsContext2 = newCCB;
464 newCCB->pFcb=Fcb;
465 newCCB->PtrFileObject=FileObject;
466 if(AbsFileName)ExFreePool(AbsFileName);
467 return(STATUS_SUCCESS);
468 }
469
470 current_entry = current_entry->Flink;
471 }
472 KeReleaseSpinLock(&DeviceExt->FcbListLock, oldIrql);
473
474 CHECKPOINT;
475
476 string = FileName;
477 ParentFcb = NULL;
478 Fcb = ExAllocatePool(NonPagedPool, sizeof(VFATFCB));
479 memset(Fcb,0,sizeof(VFATFCB));
480 Fcb->ObjectName=Fcb->PathName;
481 next = &string[0];
482
483 CHECKPOINT;
484 while (next!=NULL)
485 {
486 CHECKPOINT;
487 *next = '\\';
488 current = next+1;
489 next = wcschr(next+1,'\\');
490 if (next!=NULL)
491 {
492 *next=0;
493 }
494 DPRINT("current '%S'\n",current);
495 Status = FindFile(DeviceExt,Fcb,ParentFcb,current,NULL,NULL);
496 if (Status != STATUS_SUCCESS)
497 {
498 CHECKPOINT;
499 if (Fcb != NULL)
500 ExFreePool(Fcb);
501 if (ParentFcb != NULL)
502 ExFreePool(ParentFcb);
503 if(AbsFileName)
504 ExFreePool(AbsFileName);
505 return(Status);
506 }
507 Temp = Fcb;
508 CHECKPOINT;
509 if (ParentFcb == NULL)
510 {
511 CHECKPOINT;
512 Fcb = ExAllocatePool(NonPagedPool,sizeof(VFATFCB));
513 memset(Fcb,0,sizeof(VFATFCB));
514 Fcb->ObjectName=Fcb->PathName;
515 }
516 else
517 Fcb = ParentFcb;
518 CHECKPOINT;
519 ParentFcb = Temp;
520 }
521 CHECKPOINT;
522 FileObject->FsContext =(PVOID) &ParentFcb->NTRequiredFCB;
523 newCCB = ExAllocatePool(NonPagedPool,sizeof(VFATCCB));
524 memset(newCCB,0,sizeof(VFATCCB));
525 FileObject->FsContext2 = newCCB;
526 newCCB->pFcb=ParentFcb;
527 newCCB->PtrFileObject=FileObject;
528 ParentFcb->RefCount++;
529 //FIXME : initialize all fields in FCB and CCB
530
531 KeAcquireSpinLock(&DeviceExt->FcbListLock, &oldIrql);
532 InsertTailList(&DeviceExt->FcbListHead, &ParentFcb->FcbListEntry);
533 KeReleaseSpinLock(&DeviceExt->FcbListLock, oldIrql);
534
535 vfat_wcsncpy(ParentFcb->PathName,FileName,MAX_PATH);
536 ParentFcb->ObjectName=ParentFcb->PathName+(current-FileName);
537 ParentFcb->pDevExt=DeviceExt;
538 DPRINT("file open, fcb=%x\n",ParentFcb);
539 DPRINT("FileSize %d\n",ParentFcb->entry.FileSize);
540 if(Fcb) ExFreePool(Fcb);
541 if(AbsFileName)ExFreePool(AbsFileName);
542 CHECKPOINT;
543 return(STATUS_SUCCESS);
544 }
545
546 NTSTATUS FsdClose(PDEVICE_OBJECT DeviceObject, PIRP Irp)
547 /*
548 * FUNCTION: Close a file
549 */
550 {
551 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
552 PFILE_OBJECT FileObject = Stack->FileObject;
553 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
554 NTSTATUS Status;
555
556 DPRINT("FsdClose(DeviceObject %x, Irp %x)\n",DeviceObject, Irp);
557
558 Status = FsdCloseFile(DeviceExtension,FileObject);
559
560 Irp->IoStatus.Status = Status;
561 Irp->IoStatus.Information = 0;
562
563 IoCompleteRequest(Irp, IO_NO_INCREMENT);
564 return(Status);
565 }
566
567
568 NTSTATUS FsdCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp)
569 /*
570 * FUNCTION: Create or open a file
571 */
572 {
573 PIO_STACK_LOCATION Stack;
574 PFILE_OBJECT FileObject;
575 NTSTATUS Status=STATUS_SUCCESS;
576 PDEVICE_EXTENSION DeviceExt;
577 ULONG RequestedDisposition,RequestedOptions;
578 PVFATCCB pCcb;
579 PVFATFCB pFcb;
580
581 assert(DeviceObject);
582 assert(Irp);
583
584 if (DeviceObject->Size==sizeof(DEVICE_OBJECT))
585 {
586 /* DeviceObject represent FileSystem instead of logical volume */
587 DbgPrint("FsdCreate called with file system\n");
588 Irp->IoStatus.Status=Status;
589 Irp->IoStatus.Information=FILE_OPENED;
590 IoCompleteRequest(Irp,IO_NO_INCREMENT);
591 return(Status);
592 }
593
594 Stack = IoGetCurrentIrpStackLocation(Irp);
595 assert(Stack);
596 RequestedDisposition = ((Stack->Parameters.Create.Options>>24)&0xff);
597 RequestedOptions=Stack->Parameters.Create.Options&FILE_VALID_OPTION_FLAGS;
598 FileObject = Stack->FileObject;
599 DeviceExt = DeviceObject->DeviceExtension;
600 assert(DeviceExt);
601 ExAcquireResourceExclusiveLite(&DeviceExt->DirResource, TRUE);
602 Status = FsdOpenFile(DeviceExt,FileObject,FileObject->FileName.Buffer);
603 CHECKPOINT;
604 Irp->IoStatus.Information = 0;
605 if(!NT_SUCCESS(Status))
606 {
607 if(RequestedDisposition==FILE_CREATE
608 ||RequestedDisposition==FILE_OPEN_IF
609 ||RequestedDisposition==FILE_OVERWRITE_IF)
610 {
611 CHECKPOINT;
612 Status=addEntry(DeviceExt,FileObject,RequestedOptions
613 ,(Stack->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS));
614 if(NT_SUCCESS(Status))
615 Irp->IoStatus.Information = FILE_CREATED;
616 // FIXME set size if AllocationSize requested
617 // FIXME set extended attributes ?
618 // FIXME set share access
619 // IoSetShareAccess(DesiredAccess,ShareAccess,FileObject
620 // ,((PVfatCCB)(FileObject->FsContext2))->pFcb->FCBShareAccess);
621 }
622 }
623 else
624 {
625 if(RequestedDisposition==FILE_CREATE)
626 {
627 Irp->IoStatus.Information = FILE_EXISTS;
628 Status=STATUS_OBJECT_NAME_COLLISION;
629 }
630 pCcb=FileObject->FsContext2;
631 pFcb=pCcb->pFcb;
632 if( (RequestedOptions&FILE_NON_DIRECTORY_FILE)
633 && (pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
634 {
635 Status=STATUS_FILE_IS_A_DIRECTORY;
636 }
637 if( (RequestedOptions&FILE_DIRECTORY_FILE)
638 && !(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
639 {
640 Status=STATUS_NOT_A_DIRECTORY;
641 }
642 // FIXME : test share access
643 // FIXME : test write access if requested
644 if(!NT_SUCCESS(Status))
645 FsdCloseFile(DeviceExt,FileObject);
646 else Irp->IoStatus.Information = FILE_OPENED;
647 // FIXME : make supersed or overwrite if requested
648 }
649 CHECKPOINT;
650
651 Irp->IoStatus.Status = Status;
652 IoCompleteRequest(Irp, IO_NO_INCREMENT);
653 ExReleaseResourceLite(&DeviceExt->DirResource);
654
655 return Status;
656 }
657
658