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