3f75b6e7410dfcd68d69064e3382681241a164bb
[reactos.git] / reactos / drivers / filesystems / cdfs / fcb.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2004 ReactOS Team
4 *
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.
9 *
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.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * FILE: drivers/filesystems/cdfs/fcb.c
23 * PURPOSE: CDROM (ISO 9660) filesystem driver
24 * PROGRAMMER: Art Yerkes
25 * UPDATE HISTORY:
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include "cdfs.h"
31
32 #define NDEBUG
33 #include <debug.h>
34
35 /* FUNCTIONS ****************************************************************/
36
37 #define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
38
39
40 /* FUNCTIONS ****************************************************************/
41
42 static PWCHAR
43 CdfsGetNextPathElement(PWCHAR FileName)
44 {
45 if (*FileName == L'\0')
46 {
47 return(NULL);
48 }
49
50 while (*FileName != L'\0' && *FileName != L'\\')
51 {
52 FileName++;
53 }
54
55 return(FileName);
56 }
57
58
59 static VOID
60 CdfsWSubString(LPWSTR pTarget, LPCWSTR pSource, size_t pLength)
61 {
62 wcsncpy (pTarget, pSource, pLength);
63 pTarget [pLength] = L'\0';
64 }
65
66
67 PFCB
68 CdfsCreateFCB(PCWSTR FileName)
69 {
70 PFCB Fcb;
71
72 Fcb = ExAllocatePoolWithTag(NonPagedPool,
73 sizeof(FCB),
74 CDFS_NONPAGED_FCB_TAG);
75 if(!Fcb) return NULL;
76
77 RtlZeroMemory(Fcb, sizeof(FCB));
78 RtlInitEmptyUnicodeString(&Fcb->PathName, Fcb->PathNameBuffer, sizeof(Fcb->PathNameBuffer));
79
80 if (FileName)
81 {
82 RtlAppendUnicodeToString(&Fcb->PathName, FileName);
83 if (wcsrchr(Fcb->PathName.Buffer, '\\') != 0)
84 {
85 Fcb->ObjectName = wcsrchr(Fcb->PathName.Buffer, '\\');
86 }
87 else
88 {
89 Fcb->ObjectName = Fcb->PathName.Buffer;
90 }
91 }
92
93 ExInitializeResourceLite(&Fcb->PagingIoResource);
94 ExInitializeResourceLite(&Fcb->MainResource);
95 ExInitializeResourceLite(&Fcb->NameListResource);
96 Fcb->RFCB.PagingIoResource = &Fcb->PagingIoResource;
97 Fcb->RFCB.Resource = &Fcb->MainResource;
98 Fcb->RFCB.IsFastIoPossible = FastIoIsNotPossible;
99 InitializeListHead(&Fcb->ShortNameList);
100 FsRtlInitializeFileLock(&Fcb->FileLock, NULL, NULL);
101
102 return(Fcb);
103 }
104
105
106 VOID
107 CdfsDestroyFCB(PFCB Fcb)
108 {
109 PLIST_ENTRY Entry;
110
111 FsRtlUninitializeFileLock(&Fcb->FileLock);
112 ExDeleteResourceLite(&Fcb->PagingIoResource);
113 ExDeleteResourceLite(&Fcb->MainResource);
114
115 while (!IsListEmpty(&Fcb->ShortNameList))
116 {
117 Entry = Fcb->ShortNameList.Flink;
118 RemoveEntryList(Entry);
119 ExFreePoolWithTag(Entry, CDFS_SHORT_NAME_TAG);
120 }
121
122 ExDeleteResourceLite(&Fcb->NameListResource);
123 ExFreePoolWithTag(Fcb, CDFS_NONPAGED_FCB_TAG);
124 }
125
126
127 BOOLEAN
128 CdfsFCBIsDirectory(PFCB Fcb)
129 {
130 return(Fcb->Entry.FileFlags & FILE_FLAG_DIRECTORY);
131 }
132
133
134 BOOLEAN
135 CdfsFCBIsRoot(PFCB Fcb)
136 {
137 return (Fcb->PathName.Length == sizeof(WCHAR) && Fcb->PathName.Buffer[0] == L'\\');
138 }
139
140
141 VOID
142 CdfsGrabFCB(PDEVICE_EXTENSION Vcb,
143 PFCB Fcb)
144 {
145 KIRQL oldIrql;
146
147 DPRINT("grabbing FCB at %p: %S, refCount:%d\n",
148 Fcb,
149 Fcb->PathName,
150 Fcb->RefCount);
151
152 KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
153 Fcb->RefCount++;
154 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
155 }
156
157
158 VOID
159 CdfsReleaseFCB(PDEVICE_EXTENSION Vcb,
160 PFCB Fcb)
161 {
162 KIRQL oldIrql;
163
164 DPRINT("releasing FCB at %p: %wZ, refCount:%d\n",
165 Fcb,
166 &Fcb->PathName,
167 Fcb->RefCount);
168
169 KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
170 Fcb->RefCount--;
171 if (Fcb->RefCount <= 0 && !CdfsFCBIsDirectory(Fcb))
172 {
173 RemoveEntryList(&Fcb->FcbListEntry);
174 CdfsDestroyFCB(Fcb);
175 }
176 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
177 }
178
179
180 VOID
181 CdfsAddFCBToTable(PDEVICE_EXTENSION Vcb,
182 PFCB Fcb)
183 {
184 KIRQL oldIrql;
185
186 KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
187 Fcb->DevExt = Vcb;
188 InsertTailList(&Vcb->FcbListHead, &Fcb->FcbListEntry);
189 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
190 }
191
192
193 PFCB
194 CdfsGrabFCBFromTable(PDEVICE_EXTENSION Vcb,
195 PUNICODE_STRING FileName)
196 {
197 KIRQL oldIrql;
198 PFCB Fcb;
199 PLIST_ENTRY current_entry;
200
201 KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
202
203 if (FileName == NULL || FileName->Length == 0 || FileName->Buffer[0] == 0)
204 {
205 DPRINT("Return FCB for stream file object\n");
206 Fcb = Vcb->StreamFileObject->FsContext;
207 Fcb->RefCount++;
208 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
209 return(Fcb);
210 }
211
212 current_entry = Vcb->FcbListHead.Flink;
213 while (current_entry != &Vcb->FcbListHead)
214 {
215 Fcb = CONTAINING_RECORD(current_entry, FCB, FcbListEntry);
216
217 DPRINT("Comparing '%wZ' and '%wZ'\n", FileName, &Fcb->PathName);
218 if (RtlCompareUnicodeString(FileName, &Fcb->PathName, TRUE) == 0)
219 {
220 Fcb->RefCount++;
221 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
222 return(Fcb);
223 }
224
225 //FIXME: need to compare against short name in FCB here
226
227 current_entry = current_entry->Flink;
228 }
229 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
230
231 return(NULL);
232 }
233
234
235 NTSTATUS
236 CdfsFCBInitializeCache(PVCB Vcb,
237 PFCB Fcb)
238 {
239 PFILE_OBJECT FileObject;
240 PCCB newCCB;
241
242 FileObject = IoCreateStreamFileObject(NULL, Vcb->StorageDevice);
243
244 newCCB = ExAllocatePoolWithTag(NonPagedPool, sizeof(CCB), CDFS_CCB_TAG);
245 if (newCCB == NULL)
246 {
247 return STATUS_INSUFFICIENT_RESOURCES;
248 }
249 RtlZeroMemory(newCCB,
250 sizeof(CCB));
251
252 FileObject->ReadAccess = TRUE;
253 FileObject->WriteAccess = FALSE;
254 FileObject->DeleteAccess = FALSE;
255 FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
256 FileObject->FsContext = Fcb;
257 FileObject->FsContext2 = newCCB;
258 newCCB->PtrFileObject = FileObject;
259 Fcb->FileObject = FileObject;
260 Fcb->DevExt = Vcb;
261
262 _SEH2_TRY
263 {
264 CcInitializeCacheMap(FileObject,
265 (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
266 FALSE,
267 &(CdfsGlobalData->CacheMgrCallbacks),
268 Fcb);
269 }
270 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
271 {
272 FileObject->FsContext2 = NULL;
273 ExFreePoolWithTag(newCCB, CDFS_CCB_TAG);
274 ObDereferenceObject(FileObject);
275 Fcb->FileObject = NULL;
276 return _SEH2_GetExceptionCode();
277 }
278 _SEH2_END;
279
280 ObDereferenceObject(FileObject);
281 Fcb->Flags |= FCB_CACHE_INITIALIZED;
282
283 return STATUS_SUCCESS;
284 }
285
286
287 PFCB
288 CdfsMakeRootFCB(PDEVICE_EXTENSION Vcb)
289 {
290 PFCB Fcb;
291
292 Fcb = CdfsCreateFCB(L"\\");
293
294 Fcb->Entry.DataLengthL = Vcb->CdInfo.RootSize;
295 Fcb->Entry.ExtentLocationL = Vcb->CdInfo.RootStart;
296 Fcb->Entry.FileFlags = FILE_FLAG_DIRECTORY;
297 Fcb->IndexNumber.QuadPart = 0LL;
298 Fcb->RefCount = 1;
299 Fcb->DirIndex = 0;
300 Fcb->RFCB.FileSize.QuadPart = Vcb->CdInfo.RootSize;
301 Fcb->RFCB.ValidDataLength.QuadPart = Vcb->CdInfo.RootSize;
302 Fcb->RFCB.AllocationSize.QuadPart = Vcb->CdInfo.RootSize;
303
304 CdfsFCBInitializeCache(Vcb, Fcb);
305 CdfsAddFCBToTable(Vcb, Fcb);
306 CdfsGrabFCB(Vcb, Fcb);
307
308 return(Fcb);
309 }
310
311
312 PFCB
313 CdfsOpenRootFCB(PDEVICE_EXTENSION Vcb)
314 {
315 UNICODE_STRING FileName;
316 PFCB Fcb;
317
318 RtlInitUnicodeString(&FileName, L"\\");
319
320 Fcb = CdfsGrabFCBFromTable(Vcb,
321 &FileName);
322 if (Fcb == NULL)
323 {
324 Fcb = CdfsMakeRootFCB(Vcb);
325 }
326
327 return(Fcb);
328 }
329
330
331 NTSTATUS
332 CdfsMakeFCBFromDirEntry(PVCB Vcb,
333 PFCB DirectoryFCB,
334 PWSTR LongName,
335 PWSTR ShortName,
336 PDIR_RECORD Record,
337 ULONG DirectorySector,
338 ULONG DirectoryOffset,
339 PFCB * fileFCB)
340 {
341 WCHAR pathName[MAX_PATH];
342 PFCB rcFCB;
343 ULONG Size;
344
345 /* Check if the full string would overflow the pathName buffer (the additional characters are for '\\' and '\0') */
346 if ((LongName[0] != 0) &&
347 ((DirectoryFCB->PathName.Length / sizeof(WCHAR)) + 1 + wcslen(LongName) + 1 > MAX_PATH))
348 {
349 return(STATUS_OBJECT_NAME_INVALID);
350 }
351
352 wcscpy(pathName, DirectoryFCB->PathName.Buffer);
353 if (!CdfsFCBIsRoot(DirectoryFCB))
354 {
355 wcscat(pathName, L"\\");
356 }
357
358 if (LongName[0] != 0)
359 {
360 wcscat(pathName, LongName);
361 }
362 else
363 {
364 WCHAR entryName[MAX_PATH];
365
366 CdfsGetDirEntryName(Vcb, Record, entryName);
367 wcscat(pathName, entryName);
368 }
369
370 rcFCB = CdfsCreateFCB(pathName);
371 memcpy(&rcFCB->Entry, Record, sizeof(DIR_RECORD));
372
373 /* Copy short name into FCB */
374 rcFCB->ShortNameU.Length = wcslen(ShortName) * sizeof(WCHAR);
375 rcFCB->ShortNameU.MaximumLength = rcFCB->ShortNameU.Length;
376 rcFCB->ShortNameU.Buffer = rcFCB->ShortNameBuffer;
377 wcscpy(rcFCB->ShortNameBuffer, ShortName);
378
379 Size = rcFCB->Entry.DataLengthL;
380
381 rcFCB->RFCB.FileSize.QuadPart = Size;
382 rcFCB->RFCB.ValidDataLength.QuadPart = Size;
383 rcFCB->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, BLOCKSIZE);
384 if (CdfsFCBIsDirectory(rcFCB))
385 {
386 CdfsFCBInitializeCache(Vcb, rcFCB);
387 }
388 rcFCB->IndexNumber.u.HighPart = DirectorySector;
389 rcFCB->IndexNumber.u.LowPart = DirectoryOffset;
390 rcFCB->RefCount++;
391 CdfsAddFCBToTable(Vcb, rcFCB);
392 *fileFCB = rcFCB;
393
394 DPRINT("%S %u %I64d\n", LongName, Size, rcFCB->RFCB.AllocationSize.QuadPart);
395
396 return(STATUS_SUCCESS);
397 }
398
399
400 NTSTATUS
401 CdfsAttachFCBToFileObject(PDEVICE_EXTENSION Vcb,
402 PFCB Fcb,
403 PFILE_OBJECT FileObject)
404 {
405 PCCB newCCB;
406
407 newCCB = ExAllocatePoolWithTag(NonPagedPool, sizeof(CCB), CDFS_CCB_TAG);
408 if (newCCB == NULL)
409 {
410 return(STATUS_INSUFFICIENT_RESOURCES);
411 }
412 memset(newCCB, 0, sizeof(CCB));
413
414 FileObject->ReadAccess = TRUE;
415 FileObject->WriteAccess = FALSE;
416 FileObject->DeleteAccess = FALSE;
417 FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
418 FileObject->FsContext = Fcb;
419 FileObject->FsContext2 = newCCB;
420 newCCB->PtrFileObject = FileObject;
421 Fcb->DevExt = Vcb;
422
423 if (CdfsFCBIsDirectory(Fcb))
424 {
425 _SEH2_TRY
426 {
427 CcInitializeCacheMap(FileObject,
428 (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
429 FALSE,
430 &(CdfsGlobalData->CacheMgrCallbacks),
431 Fcb);
432 }
433 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
434 {
435 FileObject->FsContext2 = NULL;
436 ExFreePoolWithTag(newCCB, CDFS_CCB_TAG);
437 return _SEH2_GetExceptionCode();
438 }
439 _SEH2_END;
440 Fcb->Flags |= FCB_CACHE_INITIALIZED;
441 }
442
443 DPRINT("file open: fcb:%p file size: %u\n", Fcb, Fcb->Entry.DataLengthL);
444
445 return(STATUS_SUCCESS);
446 }
447
448
449 NTSTATUS
450 CdfsDirFindFile(PDEVICE_EXTENSION DeviceExt,
451 PFCB DirectoryFcb,
452 PUNICODE_STRING FileToFind,
453 PFCB *FoundFCB)
454 {
455 UNICODE_STRING TempName;
456 WCHAR Name[256];
457 PVOID Block;
458 ULONG DirSize;
459 PDIR_RECORD Record;
460 ULONG Offset;
461 ULONG BlockOffset;
462 NTSTATUS Status;
463
464 LARGE_INTEGER StreamOffset, OffsetOfEntry;
465 PVOID Context;
466
467 WCHAR ShortNameBuffer[13];
468 UNICODE_STRING ShortName;
469 UNICODE_STRING LongName;
470 UNICODE_STRING FileToFindUpcase;
471
472 ASSERT(DeviceExt);
473 ASSERT(DirectoryFcb);
474 ASSERT(FileToFind);
475
476 DPRINT("CdfsDirFindFile(VCB:%p, dirFCB:%p, File:%wZ)\n",
477 DeviceExt,
478 DirectoryFcb,
479 FileToFind);
480 DPRINT("Dir Path:%wZ\n", &DirectoryFcb->PathName);
481
482 /* default to '.' if no filename specified */
483 if (FileToFind->Length == 0)
484 {
485 RtlInitUnicodeString(&TempName, L".");
486 FileToFind = &TempName;
487 }
488
489 DirSize = DirectoryFcb->Entry.DataLengthL;
490 StreamOffset.QuadPart = (LONGLONG)DirectoryFcb->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE;
491
492 _SEH2_TRY
493 {
494 CcMapData(DeviceExt->StreamFileObject, &StreamOffset, BLOCKSIZE, MAP_WAIT, &Context, &Block);
495 }
496 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
497 {
498 DPRINT("CcMapData() failed\n");
499 _SEH2_YIELD(return _SEH2_GetExceptionCode());
500 }
501 _SEH2_END;
502
503 Offset = 0;
504 BlockOffset = 0;
505 Record = (PDIR_RECORD)Block;
506
507 /* Upper case the expression for FsRtlIsNameInExpression */
508 Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFind, TRUE);
509 if (!NT_SUCCESS(Status))
510 {
511 return Status;
512 }
513
514 while(TRUE)
515 {
516 if (Record->RecordLength == 0)
517 {
518 DPRINT("RecordLength == 0 Stopped!\n");
519 break;
520 }
521
522 DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n",
523 Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength);
524
525 if (!CdfsIsRecordValid(DeviceExt, Record))
526 {
527 RtlFreeUnicodeString(&FileToFindUpcase);
528 CcUnpinData(Context);
529 return STATUS_DISK_CORRUPT_ERROR;
530 }
531
532 CdfsGetDirEntryName(DeviceExt, Record, Name);
533 DPRINT ("Name '%S'\n", Name);
534 DPRINT ("Sector %lu\n", DirectoryFcb->Entry.ExtentLocationL);
535 DPRINT ("Offset %lu\n", Offset);
536
537 RtlInitUnicodeString(&LongName, Name);
538 RtlInitEmptyUnicodeString(&ShortName, ShortNameBuffer, sizeof(ShortNameBuffer));
539 RtlZeroMemory(ShortNameBuffer, sizeof(ShortNameBuffer));
540
541 OffsetOfEntry.QuadPart = StreamOffset.QuadPart + Offset;
542 CdfsShortNameCacheGet(DirectoryFcb, &OffsetOfEntry, &LongName, &ShortName);
543
544 DPRINT("ShortName '%wZ'\n", &ShortName);
545
546 ASSERT(LongName.Length >= sizeof(WCHAR));
547 ASSERT(ShortName.Length >= sizeof(WCHAR));
548 if (FsRtlIsNameInExpression(&FileToFindUpcase, &LongName, TRUE, NULL) ||
549 FsRtlIsNameInExpression(&FileToFindUpcase, &ShortName, TRUE, NULL))
550 {
551 DPRINT("Match found, %S\n", Name);
552 Status = CdfsMakeFCBFromDirEntry(DeviceExt,
553 DirectoryFcb,
554 Name,
555 ShortNameBuffer,
556 Record,
557 DirectoryFcb->Entry.ExtentLocationL,
558 Offset,
559 FoundFCB);
560
561 RtlFreeUnicodeString(&FileToFindUpcase);
562 CcUnpinData(Context);
563
564 return(Status);
565 }
566
567 Offset += Record->RecordLength;
568 BlockOffset += Record->RecordLength;
569 Record = (PDIR_RECORD)((ULONG_PTR)Block + BlockOffset);
570 if (BlockOffset >= BLOCKSIZE || Record->RecordLength == 0)
571 {
572 DPRINT("Map next sector\n");
573 CcUnpinData(Context);
574 StreamOffset.QuadPart += BLOCKSIZE;
575 Offset = ROUND_UP(Offset, BLOCKSIZE);
576 BlockOffset = 0;
577
578 _SEH2_TRY
579 {
580 CcMapData(DeviceExt->StreamFileObject, &StreamOffset, BLOCKSIZE, MAP_WAIT, &Context, &Block);
581 }
582 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
583 {
584 DPRINT("CcMapData() failed\n");
585 RtlFreeUnicodeString(&FileToFindUpcase);
586 _SEH2_YIELD(return _SEH2_GetExceptionCode());
587 }
588 _SEH2_END;
589 Record = (PDIR_RECORD)((ULONG_PTR)Block + BlockOffset);
590 }
591
592 if (Offset >= DirSize)
593 break;
594 }
595
596 RtlFreeUnicodeString(&FileToFindUpcase);
597 CcUnpinData(Context);
598
599 return(STATUS_OBJECT_NAME_NOT_FOUND);
600 }
601
602
603 NTSTATUS
604 CdfsGetFCBForFile(PDEVICE_EXTENSION Vcb,
605 PFCB *pParentFCB,
606 PFCB *pFCB,
607 PUNICODE_STRING FileName)
608 {
609 UNICODE_STRING PathName;
610 UNICODE_STRING ElementName;
611 NTSTATUS Status;
612 WCHAR pathName [MAX_PATH];
613 WCHAR elementName [MAX_PATH];
614 PWCHAR currentElement;
615 PFCB FCB;
616 PFCB parentFCB;
617
618 DPRINT("CdfsGetFCBForFile(%p, %p, %p, '%wZ')\n",
619 Vcb,
620 pParentFCB,
621 pFCB,
622 FileName);
623
624 /* Trivial case, open of the root directory on volume */
625 if (FileName->Buffer[0] == L'\0' || wcscmp(FileName->Buffer, L"\\") == 0)
626 {
627 DPRINT("returning root FCB\n");
628
629 FCB = CdfsOpenRootFCB(Vcb);
630 *pFCB = FCB;
631 *pParentFCB = NULL;
632
633 return((FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND);
634 }
635 else
636 {
637 currentElement = &FileName->Buffer[1];
638 wcscpy (pathName, L"\\");
639 FCB = CdfsOpenRootFCB (Vcb);
640 }
641 parentFCB = NULL;
642
643 /* Parse filename and check each path element for existance and access */
644 while (CdfsGetNextPathElement(currentElement) != 0)
645 {
646 /* Skip blank directory levels */
647 if ((CdfsGetNextPathElement(currentElement) - currentElement) == 0)
648 {
649 currentElement++;
650 continue;
651 }
652
653 DPRINT("Parsing, currentElement:%S\n", currentElement);
654 DPRINT(" parentFCB:%p FCB:%p\n", parentFCB, FCB);
655
656 /* Descend to next directory level */
657 if (parentFCB)
658 {
659 CdfsReleaseFCB(Vcb, parentFCB);
660 parentFCB = NULL;
661 }
662
663 /* fail if element in FCB is not a directory */
664 if (!CdfsFCBIsDirectory(FCB))
665 {
666 DPRINT("Element in requested path is not a directory\n");
667
668 CdfsReleaseFCB(Vcb, FCB);
669 FCB = 0;
670 *pParentFCB = NULL;
671 *pFCB = NULL;
672
673 return(STATUS_OBJECT_PATH_NOT_FOUND);
674 }
675 parentFCB = FCB;
676
677 /* Extract next directory level into dirName */
678 CdfsWSubString(pathName,
679 FileName->Buffer,
680 CdfsGetNextPathElement(currentElement) - FileName->Buffer);
681 DPRINT(" pathName:%S\n", pathName);
682
683 RtlInitUnicodeString(&PathName, pathName);
684
685 FCB = CdfsGrabFCBFromTable(Vcb, &PathName);
686 if (FCB == NULL)
687 {
688 CdfsWSubString(elementName,
689 currentElement,
690 CdfsGetNextPathElement(currentElement) - currentElement);
691 DPRINT(" elementName:%S\n", elementName);
692
693 RtlInitUnicodeString(&ElementName, elementName);
694 Status = CdfsDirFindFile(Vcb,
695 parentFCB,
696 &ElementName,
697 &FCB);
698 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
699 {
700 *pParentFCB = parentFCB;
701 *pFCB = NULL;
702 currentElement = CdfsGetNextPathElement(currentElement);
703 if (*currentElement == L'\0' || CdfsGetNextPathElement(currentElement + 1) == 0)
704 {
705 return(STATUS_OBJECT_NAME_NOT_FOUND);
706 }
707 else
708 {
709 return(STATUS_OBJECT_PATH_NOT_FOUND);
710 }
711 }
712 else if (!NT_SUCCESS(Status))
713 {
714 CdfsReleaseFCB(Vcb, parentFCB);
715 *pParentFCB = NULL;
716 *pFCB = NULL;
717
718 return(Status);
719 }
720 }
721 currentElement = CdfsGetNextPathElement(currentElement);
722 }
723
724 *pParentFCB = parentFCB;
725 *pFCB = FCB;
726
727 return STATUS_SUCCESS;
728 }
729
730 /* EOF */