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