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