[REISERFS]
[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: %S, 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 DPRINT("Comparing '%wZ' and '%wZ'\n", FileName, &Fcb->PathName);
212 if (RtlCompareUnicodeString(FileName, &Fcb->PathName, TRUE) == 0)
213 {
214 Fcb->RefCount++;
215 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
216 return(Fcb);
217 }
218
219 //FIXME: need to compare against short name in FCB here
220
221 current_entry = current_entry->Flink;
222 }
223 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
224
225 return(NULL);
226 }
227
228
229 NTSTATUS
230 CdfsFCBInitializeCache(PVCB Vcb,
231 PFCB Fcb)
232 {
233 PFILE_OBJECT FileObject;
234 PCCB newCCB;
235
236 FileObject = IoCreateStreamFileObject(NULL, Vcb->StorageDevice);
237
238 newCCB = ExAllocatePoolWithTag(NonPagedPool, sizeof(CCB), CDFS_CCB_TAG);
239 if (newCCB == NULL)
240 {
241 return STATUS_INSUFFICIENT_RESOURCES;
242 }
243 RtlZeroMemory(newCCB,
244 sizeof(CCB));
245
246 FileObject->ReadAccess = TRUE;
247 FileObject->WriteAccess = FALSE;
248 FileObject->DeleteAccess = FALSE;
249 FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
250 FileObject->FsContext = Fcb;
251 FileObject->FsContext2 = newCCB;
252 newCCB->PtrFileObject = FileObject;
253 Fcb->FileObject = FileObject;
254 Fcb->DevExt = Vcb;
255
256 _SEH2_TRY
257 {
258 CcInitializeCacheMap(FileObject,
259 (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
260 FALSE,
261 &(CdfsGlobalData->CacheMgrCallbacks),
262 Fcb);
263 }
264 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
265 {
266 FileObject->FsContext2 = NULL;
267 ExFreePoolWithTag(newCCB, CDFS_CCB_TAG);
268 ObDereferenceObject(FileObject);
269 Fcb->FileObject = NULL;
270 return _SEH2_GetExceptionCode();
271 }
272 _SEH2_END;
273
274 ObDereferenceObject(FileObject);
275 Fcb->Flags |= FCB_CACHE_INITIALIZED;
276
277 return STATUS_SUCCESS;
278 }
279
280
281 PFCB
282 CdfsMakeRootFCB(PDEVICE_EXTENSION Vcb)
283 {
284 PFCB Fcb;
285
286 Fcb = CdfsCreateFCB(L"\\");
287
288 Fcb->Entry.DataLengthL = Vcb->CdInfo.RootSize;
289 Fcb->Entry.ExtentLocationL = Vcb->CdInfo.RootStart;
290 Fcb->Entry.FileFlags = FILE_FLAG_DIRECTORY;
291 Fcb->IndexNumber.QuadPart = 0LL;
292 Fcb->RefCount = 1;
293 Fcb->DirIndex = 0;
294 Fcb->RFCB.FileSize.QuadPart = Vcb->CdInfo.RootSize;
295 Fcb->RFCB.ValidDataLength.QuadPart = Vcb->CdInfo.RootSize;
296 Fcb->RFCB.AllocationSize.QuadPart = Vcb->CdInfo.RootSize;
297
298 CdfsFCBInitializeCache(Vcb, Fcb);
299 CdfsAddFCBToTable(Vcb, Fcb);
300 CdfsGrabFCB(Vcb, Fcb);
301
302 return(Fcb);
303 }
304
305
306 PFCB
307 CdfsOpenRootFCB(PDEVICE_EXTENSION Vcb)
308 {
309 UNICODE_STRING FileName;
310 PFCB Fcb;
311
312 RtlInitUnicodeString(&FileName, L"\\");
313
314 Fcb = CdfsGrabFCBFromTable(Vcb,
315 &FileName);
316 if (Fcb == NULL)
317 {
318 Fcb = CdfsMakeRootFCB(Vcb);
319 }
320
321 return(Fcb);
322 }
323
324
325 NTSTATUS
326 CdfsMakeFCBFromDirEntry(PVCB Vcb,
327 PFCB DirectoryFCB,
328 PWSTR LongName,
329 PWSTR ShortName,
330 PDIR_RECORD Record,
331 ULONG DirectorySector,
332 ULONG DirectoryOffset,
333 PFCB * fileFCB)
334 {
335 WCHAR pathName[MAX_PATH];
336 PFCB rcFCB;
337 ULONG Size;
338
339 /* Check if the full string would overflow the pathName buffer (the additional characters are for '\\' and '\0') */
340 if ((LongName[0] != 0) &&
341 ((DirectoryFCB->PathName.Length / sizeof(WCHAR)) + 1 + wcslen(LongName) + 1 > MAX_PATH))
342 {
343 return(STATUS_OBJECT_NAME_INVALID);
344 }
345
346 wcscpy(pathName, DirectoryFCB->PathName.Buffer);
347 if (!CdfsFCBIsRoot(DirectoryFCB))
348 {
349 wcscat(pathName, L"\\");
350 }
351
352 if (LongName[0] != 0)
353 {
354 wcscat(pathName, LongName);
355 }
356 else
357 {
358 WCHAR entryName[MAX_PATH];
359
360 CdfsGetDirEntryName(Vcb, Record, entryName);
361 wcscat(pathName, entryName);
362 }
363
364 rcFCB = CdfsCreateFCB(pathName);
365 memcpy(&rcFCB->Entry, Record, sizeof(DIR_RECORD));
366
367 /* Copy short name into FCB */
368 rcFCB->ShortNameU.Length = wcslen(ShortName) * sizeof(WCHAR);
369 rcFCB->ShortNameU.MaximumLength = rcFCB->ShortNameU.Length;
370 rcFCB->ShortNameU.Buffer = rcFCB->ShortNameBuffer;
371 wcscpy(rcFCB->ShortNameBuffer, ShortName);
372
373 Size = rcFCB->Entry.DataLengthL;
374
375 rcFCB->RFCB.FileSize.QuadPart = Size;
376 rcFCB->RFCB.ValidDataLength.QuadPart = Size;
377 rcFCB->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, BLOCKSIZE);
378 if (CdfsFCBIsDirectory(rcFCB))
379 {
380 CdfsFCBInitializeCache(Vcb, rcFCB);
381 }
382 rcFCB->IndexNumber.u.HighPart = DirectorySector;
383 rcFCB->IndexNumber.u.LowPart = DirectoryOffset;
384 rcFCB->RefCount++;
385 CdfsAddFCBToTable(Vcb, rcFCB);
386 *fileFCB = rcFCB;
387
388 DPRINT("%S %u %I64d\n", LongName, Size, rcFCB->RFCB.AllocationSize.QuadPart);
389
390 return(STATUS_SUCCESS);
391 }
392
393
394 NTSTATUS
395 CdfsAttachFCBToFileObject(PDEVICE_EXTENSION Vcb,
396 PFCB Fcb,
397 PFILE_OBJECT FileObject)
398 {
399 PCCB newCCB;
400
401 newCCB = ExAllocatePoolWithTag(NonPagedPool, sizeof(CCB), CDFS_CCB_TAG);
402 if (newCCB == NULL)
403 {
404 return(STATUS_INSUFFICIENT_RESOURCES);
405 }
406 memset(newCCB, 0, sizeof(CCB));
407
408 FileObject->ReadAccess = TRUE;
409 FileObject->WriteAccess = FALSE;
410 FileObject->DeleteAccess = FALSE;
411 FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
412 FileObject->FsContext = Fcb;
413 FileObject->FsContext2 = newCCB;
414 newCCB->PtrFileObject = FileObject;
415 Fcb->DevExt = Vcb;
416
417 if (CdfsFCBIsDirectory(Fcb))
418 {
419 _SEH2_TRY
420 {
421 CcInitializeCacheMap(FileObject,
422 (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
423 FALSE,
424 &(CdfsGlobalData->CacheMgrCallbacks),
425 Fcb);
426 }
427 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
428 {
429 FileObject->FsContext2 = NULL;
430 ExFreePoolWithTag(newCCB, CDFS_CCB_TAG);
431 return _SEH2_GetExceptionCode();
432 }
433 _SEH2_END;
434 Fcb->Flags |= FCB_CACHE_INITIALIZED;
435 }
436
437 DPRINT("file open: fcb:%p file size: %u\n", Fcb, Fcb->Entry.DataLengthL);
438
439 return(STATUS_SUCCESS);
440 }
441
442
443 NTSTATUS
444 CdfsDirFindFile(PDEVICE_EXTENSION DeviceExt,
445 PFCB DirectoryFcb,
446 PUNICODE_STRING FileToFind,
447 PFCB *FoundFCB)
448 {
449 UNICODE_STRING TempName;
450 WCHAR Name[256];
451 PVOID Block;
452 ULONG DirSize;
453 PDIR_RECORD Record;
454 ULONG Offset;
455 ULONG BlockOffset;
456 NTSTATUS Status;
457
458 LARGE_INTEGER StreamOffset, OffsetOfEntry;
459 PVOID Context;
460
461 WCHAR ShortNameBuffer[13];
462 UNICODE_STRING ShortName;
463 UNICODE_STRING LongName;
464 UNICODE_STRING FileToFindUpcase;
465
466 ASSERT(DeviceExt);
467 ASSERT(DirectoryFcb);
468 ASSERT(FileToFind);
469
470 DPRINT("CdfsDirFindFile(VCB:%p, dirFCB:%p, File:%wZ)\n",
471 DeviceExt,
472 DirectoryFcb,
473 FileToFind);
474 DPRINT("Dir Path:%wZ\n", &DirectoryFcb->PathName);
475
476 /* default to '.' if no filename specified */
477 if (FileToFind->Length == 0)
478 {
479 RtlInitUnicodeString(&TempName, L".");
480 FileToFind = &TempName;
481 }
482
483 DirSize = DirectoryFcb->Entry.DataLengthL;
484 StreamOffset.QuadPart = (LONGLONG)DirectoryFcb->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE;
485
486 _SEH2_TRY
487 {
488 CcMapData(DeviceExt->StreamFileObject, &StreamOffset, BLOCKSIZE, MAP_WAIT, &Context, &Block);
489 }
490 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
491 {
492 DPRINT("CcMapData() failed\n");
493 _SEH2_YIELD(return _SEH2_GetExceptionCode());
494 }
495 _SEH2_END;
496
497 Offset = 0;
498 BlockOffset = 0;
499 Record = (PDIR_RECORD)Block;
500
501 /* Upper case the expression for FsRtlIsNameInExpression */
502 Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFind, TRUE);
503 if (!NT_SUCCESS(Status))
504 {
505 return Status;
506 }
507
508 while(TRUE)
509 {
510 if (Record->RecordLength == 0)
511 {
512 DPRINT("RecordLength == 0 Stopped!\n");
513 break;
514 }
515
516 DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n",
517 Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength);
518
519 if (!CdfsIsRecordValid(DeviceExt, Record))
520 {
521 RtlFreeUnicodeString(&FileToFindUpcase);
522 CcUnpinData(Context);
523 return STATUS_DISK_CORRUPT_ERROR;
524 }
525
526 CdfsGetDirEntryName(DeviceExt, Record, Name);
527 DPRINT ("Name '%S'\n", Name);
528 DPRINT ("Sector %lu\n", DirectoryFcb->Entry.ExtentLocationL);
529 DPRINT ("Offset %lu\n", Offset);
530
531 RtlInitUnicodeString(&LongName, Name);
532 RtlInitEmptyUnicodeString(&ShortName, ShortNameBuffer, sizeof(ShortNameBuffer));
533 RtlZeroMemory(ShortNameBuffer, sizeof(ShortNameBuffer));
534
535 OffsetOfEntry.QuadPart = StreamOffset.QuadPart + Offset;
536 CdfsShortNameCacheGet(DirectoryFcb, &OffsetOfEntry, &LongName, &ShortName);
537
538 DPRINT("ShortName '%wZ'\n", &ShortName);
539
540 ASSERT(LongName.Length >= sizeof(WCHAR));
541 ASSERT(ShortName.Length >= sizeof(WCHAR));
542 if (FsRtlIsNameInExpression(&FileToFindUpcase, &LongName, TRUE, NULL) ||
543 FsRtlIsNameInExpression(&FileToFindUpcase, &ShortName, TRUE, NULL))
544 {
545 DPRINT("Match found, %S\n", Name);
546 Status = CdfsMakeFCBFromDirEntry(DeviceExt,
547 DirectoryFcb,
548 Name,
549 ShortNameBuffer,
550 Record,
551 DirectoryFcb->Entry.ExtentLocationL,
552 Offset,
553 FoundFCB);
554
555 RtlFreeUnicodeString(&FileToFindUpcase);
556 CcUnpinData(Context);
557
558 return(Status);
559 }
560
561 Offset += Record->RecordLength;
562 BlockOffset += Record->RecordLength;
563 Record = (PDIR_RECORD)((ULONG_PTR)Block + BlockOffset);
564 if (BlockOffset >= BLOCKSIZE || Record->RecordLength == 0)
565 {
566 DPRINT("Map next sector\n");
567 CcUnpinData(Context);
568 StreamOffset.QuadPart += BLOCKSIZE;
569 Offset = ROUND_UP(Offset, BLOCKSIZE);
570 BlockOffset = 0;
571
572 _SEH2_TRY
573 {
574 CcMapData(DeviceExt->StreamFileObject, &StreamOffset, BLOCKSIZE, MAP_WAIT, &Context, &Block);
575 }
576 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
577 {
578 DPRINT("CcMapData() failed\n");
579 RtlFreeUnicodeString(&FileToFindUpcase);
580 _SEH2_YIELD(return _SEH2_GetExceptionCode());
581 }
582 _SEH2_END;
583 Record = (PDIR_RECORD)((ULONG_PTR)Block + BlockOffset);
584 }
585
586 if (Offset >= DirSize)
587 break;
588 }
589
590 RtlFreeUnicodeString(&FileToFindUpcase);
591 CcUnpinData(Context);
592
593 return(STATUS_OBJECT_NAME_NOT_FOUND);
594 }
595
596
597 NTSTATUS
598 CdfsGetFCBForFile(PDEVICE_EXTENSION Vcb,
599 PFCB *pParentFCB,
600 PFCB *pFCB,
601 PUNICODE_STRING FileName)
602 {
603 UNICODE_STRING PathName;
604 UNICODE_STRING NextElement;
605 UNICODE_STRING CurrentElement;
606 NTSTATUS Status;
607 PFCB FCB;
608 PFCB parentFCB;
609
610 DPRINT("CdfsGetFCBForFile(%p, %p, %p, '%wZ')\n",
611 Vcb,
612 pParentFCB,
613 pFCB,
614 FileName);
615
616 /* Trivial case, open of the root directory on volume */
617 if (FileName->Length == 0 ||
618 ((FileName->Buffer[0] == '\\') && (FileName->Length == sizeof(WCHAR))))
619 {
620 DPRINT("returning root FCB\n");
621
622 FCB = CdfsOpenRootFCB(Vcb);
623 *pFCB = FCB;
624 *pParentFCB = NULL;
625
626 return((FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND);
627 }
628 else
629 {
630 /* Start with empty path */
631 PathName = *FileName;
632 PathName.Length = 0;
633 CurrentElement = *FileName;
634
635 FCB = CdfsOpenRootFCB (Vcb);
636 }
637 parentFCB = NULL;
638
639 /* Parse filename and check each path element for existence and access */
640 while (CdfsGetNextPathElement(&CurrentElement, &NextElement))
641 {
642 /* Skip blank directory levels */
643 if (CurrentElement.Buffer[0] == L'\\')
644 {
645 CurrentElement.Buffer++;
646 CurrentElement.Length -= sizeof(WCHAR);
647 CurrentElement.MaximumLength -= sizeof(WCHAR);
648 continue;
649 }
650
651 DPRINT("Parsing, currentElement:%wZ\n", &CurrentElement);
652 DPRINT(" parentFCB:%p FCB:%p\n", parentFCB, FCB);
653
654 /* Descend to next directory level */
655 if (parentFCB)
656 {
657 CdfsReleaseFCB(Vcb, parentFCB);
658 parentFCB = NULL;
659 }
660
661 /* fail if element in FCB is not a directory */
662 if (!CdfsFCBIsDirectory(FCB))
663 {
664 DPRINT("Element in requested path is not a directory\n");
665
666 CdfsReleaseFCB(Vcb, FCB);
667 FCB = 0;
668 *pParentFCB = NULL;
669 *pFCB = NULL;
670
671 return(STATUS_OBJECT_PATH_NOT_FOUND);
672 }
673 parentFCB = FCB;
674
675 /* Extract next directory level */
676 PathName.Length = (NextElement.Buffer - FileName->Buffer) * sizeof(WCHAR);
677 DPRINT(" PathName:%wZ\n", &PathName);
678
679 FCB = CdfsGrabFCBFromTable(Vcb, &PathName);
680 if (FCB == NULL)
681 {
682 UNICODE_STRING ChildElement = CurrentElement;
683 ChildElement.Length = (NextElement.Buffer - CurrentElement.Buffer) * sizeof(WCHAR);
684
685 Status = CdfsDirFindFile(Vcb,
686 parentFCB,
687 &ChildElement,
688 &FCB);
689 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
690 {
691 *pParentFCB = parentFCB;
692 *pFCB = NULL;
693
694 if (NextElement.Length == 0)
695 {
696 return(STATUS_OBJECT_NAME_NOT_FOUND);
697 }
698 else
699 {
700 return(STATUS_OBJECT_PATH_NOT_FOUND);
701 }
702 }
703 else if (!NT_SUCCESS(Status))
704 {
705 CdfsReleaseFCB(Vcb, parentFCB);
706 *pParentFCB = NULL;
707 *pFCB = NULL;
708
709 return(Status);
710 }
711 }
712 CurrentElement = NextElement;
713 }
714
715 *pParentFCB = parentFCB;
716 *pFCB = FCB;
717
718 return STATUS_SUCCESS;
719 }
720
721 /* EOF */