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