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