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