fe79511bb329b0ad78c4d98a11ebe4e1d8176740
[reactos.git] / drivers / filesystems / ntfs / fcb.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2014 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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystem/ntfs/fcb.c
22 * PURPOSE: NTFS filesystem driver
23 * PROGRAMMERS: Eric Kohl
24 * Pierre Schweitzer (pierre@reactos.org)
25 * Hervé Poussineau (hpoussin@reactos.org)
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include "ntfs.h"
31
32 #define NDEBUG
33 #include <debug.h>
34
35 /* FUNCTIONS ****************************************************************/
36
37 static
38 PCWSTR
39 NtfsGetNextPathElement(PCWSTR FileName)
40 {
41 if (*FileName == L'\0')
42 {
43 return NULL;
44 }
45
46 while (*FileName != L'\0' && *FileName != L'\\')
47 {
48 FileName++;
49 }
50
51 return FileName;
52 }
53
54
55 static
56 VOID
57 NtfsWSubString(PWCHAR pTarget,
58 PCWSTR pSource,
59 size_t pLength)
60 {
61 wcsncpy(pTarget, pSource, pLength);
62 pTarget[pLength] = L'\0';
63 }
64
65
66 PNTFS_FCB
67 NtfsCreateFCB(PCWSTR FileName,
68 PCWSTR Stream,
69 PNTFS_VCB Vcb)
70 {
71 PNTFS_FCB Fcb;
72
73 ASSERT(Vcb);
74 ASSERT(Vcb->Identifier.Type == NTFS_TYPE_VCB);
75
76 Fcb = ExAllocateFromNPagedLookasideList(&NtfsGlobalData->FcbLookasideList);
77 RtlZeroMemory(Fcb, sizeof(NTFS_FCB));
78
79 Fcb->Identifier.Type = NTFS_TYPE_FCB;
80 Fcb->Identifier.Size = sizeof(NTFS_TYPE_FCB);
81
82 Fcb->Vcb = Vcb;
83
84 if (FileName)
85 {
86 wcscpy(Fcb->PathName, FileName);
87 if (wcsrchr(Fcb->PathName, '\\') != 0)
88 {
89 Fcb->ObjectName = wcsrchr(Fcb->PathName, '\\');
90 }
91 else
92 {
93 Fcb->ObjectName = Fcb->PathName;
94 }
95 }
96
97 if (Stream)
98 {
99 wcscpy(Fcb->Stream, Stream);
100 }
101 else
102 {
103 Fcb->Stream[0] = UNICODE_NULL;
104 }
105
106 ExInitializeResourceLite(&Fcb->MainResource);
107
108 Fcb->RFCB.Resource = &(Fcb->MainResource);
109
110 return Fcb;
111 }
112
113
114 VOID
115 NtfsDestroyFCB(PNTFS_FCB Fcb)
116 {
117 ASSERT(Fcb);
118 ASSERT(Fcb->Identifier.Type == NTFS_TYPE_FCB);
119
120 ExDeleteResourceLite(&Fcb->MainResource);
121
122 ExFreeToNPagedLookasideList(&NtfsGlobalData->FcbLookasideList, Fcb);
123 }
124
125
126 BOOLEAN
127 NtfsFCBIsDirectory(PNTFS_FCB Fcb)
128 {
129 return ((Fcb->Entry.FileAttributes & NTFS_FILE_TYPE_DIRECTORY) == NTFS_FILE_TYPE_DIRECTORY);
130 }
131
132
133 BOOLEAN
134 NtfsFCBIsReparsePoint(PNTFS_FCB Fcb)
135 {
136 return ((Fcb->Entry.FileAttributes & NTFS_FILE_TYPE_REPARSE) == NTFS_FILE_TYPE_REPARSE);
137 }
138
139
140 BOOLEAN
141 NtfsFCBIsCompressed(PNTFS_FCB Fcb)
142 {
143 return ((Fcb->Entry.FileAttributes & NTFS_FILE_TYPE_COMPRESSED) == NTFS_FILE_TYPE_COMPRESSED);
144 }
145
146 BOOLEAN
147 NtfsFCBIsRoot(PNTFS_FCB Fcb)
148 {
149 return (wcscmp(Fcb->PathName, L"\\") == 0);
150 }
151
152
153 VOID
154 NtfsGrabFCB(PNTFS_VCB Vcb,
155 PNTFS_FCB Fcb)
156 {
157 KIRQL oldIrql;
158
159 DPRINT("grabbing 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 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
167 }
168
169
170 VOID
171 NtfsReleaseFCB(PNTFS_VCB Vcb,
172 PNTFS_FCB Fcb)
173 {
174 KIRQL oldIrql;
175
176 DPRINT("releasing FCB at %p: %S, refCount:%d\n",
177 Fcb,
178 Fcb->PathName,
179 Fcb->RefCount);
180
181 KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
182 Fcb->RefCount--;
183 if (Fcb->RefCount <= 0 && !NtfsFCBIsDirectory(Fcb))
184 {
185 RemoveEntryList(&Fcb->FcbListEntry);
186 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
187 CcUninitializeCacheMap(Fcb->FileObject, NULL, NULL);
188 NtfsDestroyFCB(Fcb);
189 }
190 else
191 {
192 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
193 }
194 }
195
196
197 VOID
198 NtfsAddFCBToTable(PNTFS_VCB Vcb,
199 PNTFS_FCB Fcb)
200 {
201 KIRQL oldIrql;
202
203 KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
204 Fcb->Vcb = Vcb;
205 InsertTailList(&Vcb->FcbListHead, &Fcb->FcbListEntry);
206 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
207 }
208
209
210 PNTFS_FCB
211 NtfsGrabFCBFromTable(PNTFS_VCB Vcb,
212 PCWSTR FileName)
213 {
214 KIRQL oldIrql;
215 PNTFS_FCB Fcb;
216 PLIST_ENTRY current_entry;
217
218 KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
219
220 if (FileName == NULL || *FileName == 0)
221 {
222 DPRINT("Return FCB for stream file object\n");
223 Fcb = Vcb->StreamFileObject->FsContext;
224 Fcb->RefCount++;
225 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
226 return Fcb;
227 }
228
229 current_entry = Vcb->FcbListHead.Flink;
230 while (current_entry != &Vcb->FcbListHead)
231 {
232 Fcb = CONTAINING_RECORD(current_entry, NTFS_FCB, FcbListEntry);
233
234 DPRINT("Comparing '%S' and '%S'\n", FileName, Fcb->PathName);
235 if (_wcsicmp(FileName, Fcb->PathName) == 0)
236 {
237 Fcb->RefCount++;
238 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
239 return Fcb;
240 }
241
242 //FIXME: need to compare against short name in FCB here
243
244 current_entry = current_entry->Flink;
245 }
246
247 KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
248
249 return NULL;
250 }
251
252
253 NTSTATUS
254 NtfsFCBInitializeCache(PNTFS_VCB Vcb,
255 PNTFS_FCB Fcb)
256 {
257 PFILE_OBJECT FileObject;
258 NTSTATUS Status;
259 PNTFS_CCB newCCB;
260
261 FileObject = IoCreateStreamFileObject(NULL, Vcb->StorageDevice);
262
263 newCCB = ExAllocatePoolWithTag(NonPagedPool, sizeof(NTFS_CCB), TAG_CCB);
264 if (newCCB == NULL)
265 {
266 return STATUS_INSUFFICIENT_RESOURCES;
267 }
268
269 RtlZeroMemory(newCCB, sizeof(NTFS_CCB));
270
271 newCCB->Identifier.Type = NTFS_TYPE_CCB;
272 newCCB->Identifier.Size = sizeof(NTFS_TYPE_CCB);
273
274 FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
275 FileObject->FsContext = Fcb;
276 FileObject->FsContext2 = newCCB;
277 newCCB->PtrFileObject = FileObject;
278 Fcb->FileObject = FileObject;
279 Fcb->Vcb = Vcb;
280
281 Status = STATUS_SUCCESS;
282 _SEH2_TRY
283 {
284 CcInitializeCacheMap(FileObject,
285 (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
286 FALSE,
287 &(NtfsGlobalData->CacheMgrCallbacks),
288 Fcb);
289 }
290 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
291 {
292 FileObject->FsContext2 = NULL;
293 ExFreePoolWithTag(newCCB, TAG_CCB);
294 ObDereferenceObject(FileObject);
295 Fcb->FileObject = NULL;
296 return _SEH2_GetExceptionCode();
297 }
298 _SEH2_END;
299
300 ObDereferenceObject(FileObject);
301 Fcb->Flags |= FCB_CACHE_INITIALIZED;
302
303 return Status;
304 }
305
306
307 PNTFS_FCB
308 NtfsMakeRootFCB(PNTFS_VCB Vcb)
309 {
310 PNTFS_FCB Fcb;
311 PFILE_RECORD_HEADER MftRecord;
312 PFILENAME_ATTRIBUTE FileName;
313
314 MftRecord = ExAllocatePoolWithTag(NonPagedPool,
315 Vcb->NtfsInfo.BytesPerFileRecord,
316 TAG_NTFS);
317 if (MftRecord == NULL)
318 {
319 return NULL;
320 }
321
322 if (!NT_SUCCESS(ReadFileRecord(Vcb, NTFS_FILE_ROOT, MftRecord)))
323 {
324 ExFreePoolWithTag(MftRecord, TAG_NTFS);
325 return NULL;
326 }
327
328 FileName = GetFileNameFromRecord(Vcb, MftRecord, NTFS_FILE_NAME_WIN32);
329 if (!FileName)
330 {
331 ExFreePoolWithTag(MftRecord, TAG_NTFS);
332 return NULL;
333 }
334
335 Fcb = NtfsCreateFCB(L"\\", NULL, Vcb);
336 if (!Fcb)
337 {
338 ExFreePoolWithTag(MftRecord, TAG_NTFS);
339 return NULL;
340 }
341
342 memcpy(&Fcb->Entry, FileName, FIELD_OFFSET(FILENAME_ATTRIBUTE, NameLength));
343 Fcb->Entry.NameType = FileName->NameType;
344 Fcb->Entry.NameLength = 0;
345 Fcb->Entry.Name[0] = UNICODE_NULL;
346 Fcb->RefCount = 1;
347 Fcb->DirIndex = 0;
348 Fcb->RFCB.FileSize.QuadPart = FileName->DataSize;
349 Fcb->RFCB.ValidDataLength.QuadPart = FileName->DataSize;
350 Fcb->RFCB.AllocationSize.QuadPart = FileName->AllocatedSize;
351 Fcb->MFTIndex = NTFS_FILE_ROOT;
352 Fcb->LinkCount = MftRecord->LinkCount;
353
354 NtfsFCBInitializeCache(Vcb, Fcb);
355 NtfsAddFCBToTable(Vcb, Fcb);
356 NtfsGrabFCB(Vcb, Fcb);
357
358 ExFreePoolWithTag(MftRecord, TAG_NTFS);
359
360 return Fcb;
361 }
362
363
364 PNTFS_FCB
365 NtfsOpenRootFCB(PNTFS_VCB Vcb)
366 {
367 PNTFS_FCB Fcb;
368
369 Fcb = NtfsGrabFCBFromTable(Vcb, L"\\");
370 if (Fcb == NULL)
371 {
372 Fcb = NtfsMakeRootFCB(Vcb);
373 }
374
375 return Fcb;
376 }
377
378
379 NTSTATUS
380 NtfsMakeFCBFromDirEntry(PNTFS_VCB Vcb,
381 PNTFS_FCB DirectoryFCB,
382 PUNICODE_STRING Name,
383 PCWSTR Stream,
384 PFILE_RECORD_HEADER Record,
385 ULONGLONG MFTIndex,
386 PNTFS_FCB * fileFCB)
387 {
388 WCHAR pathName[MAX_PATH];
389 PFILENAME_ATTRIBUTE FileName;
390 PSTANDARD_INFORMATION StdInfo;
391 PNTFS_FCB rcFCB;
392 ULONGLONG Size, AllocatedSize;
393
394 DPRINT1("NtfsMakeFCBFromDirEntry(%p, %p, %wZ, %p, %p, %p)\n", Vcb, DirectoryFCB, Name, Stream, Record, fileFCB);
395
396 FileName = GetBestFileNameFromRecord(Vcb, Record);
397 if (!FileName)
398 {
399 return STATUS_OBJECT_NAME_NOT_FOUND; // Not sure that's the best here
400 }
401
402 if (DirectoryFCB && Name)
403 {
404 if (Name->Buffer[0] != 0 && wcslen(DirectoryFCB->PathName) +
405 sizeof(WCHAR) + Name->Length / sizeof(WCHAR) > MAX_PATH)
406 {
407 return STATUS_OBJECT_NAME_INVALID;
408 }
409
410 wcscpy(pathName, DirectoryFCB->PathName);
411 if (!NtfsFCBIsRoot(DirectoryFCB))
412 {
413 wcscat(pathName, L"\\");
414 }
415 wcscat(pathName, Name->Buffer);
416 }
417 else
418 {
419 RtlCopyMemory(pathName, FileName->Name, FileName->NameLength * sizeof (WCHAR));
420 pathName[FileName->NameLength] = UNICODE_NULL;
421 }
422
423 Size = NtfsGetFileSize(Vcb, Record, (Stream ? Stream : L""), (Stream ? wcslen(Stream) : 0), &AllocatedSize);
424
425 rcFCB = NtfsCreateFCB(pathName, Stream, Vcb);
426 if (!rcFCB)
427 {
428 return STATUS_INSUFFICIENT_RESOURCES;
429 }
430
431 memcpy(&rcFCB->Entry, FileName, FIELD_OFFSET(FILENAME_ATTRIBUTE, NameLength));
432 rcFCB->Entry.NameType = FileName->NameType;
433 rcFCB->RFCB.FileSize.QuadPart = Size;
434 rcFCB->RFCB.ValidDataLength.QuadPart = Size;
435 rcFCB->RFCB.AllocationSize.QuadPart = AllocatedSize;
436
437 StdInfo = GetStandardInformationFromRecord(Vcb, Record);
438 if (StdInfo != NULL)
439 {
440 rcFCB->Entry.FileAttributes |= StdInfo->FileAttribute;
441 }
442
443 NtfsFCBInitializeCache(Vcb, rcFCB);
444 rcFCB->RefCount = 1;
445 rcFCB->MFTIndex = MFTIndex;
446 rcFCB->LinkCount = Record->LinkCount;
447 NtfsAddFCBToTable(Vcb, rcFCB);
448 *fileFCB = rcFCB;
449
450 return STATUS_SUCCESS;
451 }
452
453
454 NTSTATUS
455 NtfsAttachFCBToFileObject(PNTFS_VCB Vcb,
456 PNTFS_FCB Fcb,
457 PFILE_OBJECT FileObject)
458 {
459 PNTFS_CCB newCCB;
460
461 newCCB = ExAllocatePoolWithTag(NonPagedPool, sizeof(NTFS_CCB), TAG_CCB);
462 if (newCCB == NULL)
463 {
464 return STATUS_INSUFFICIENT_RESOURCES;
465 }
466
467 RtlZeroMemory(newCCB, sizeof(NTFS_CCB));
468
469 newCCB->Identifier.Type = NTFS_TYPE_CCB;
470 newCCB->Identifier.Size = sizeof(NTFS_TYPE_CCB);
471
472 FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
473 FileObject->FsContext = Fcb;
474 FileObject->FsContext2 = newCCB;
475 newCCB->PtrFileObject = FileObject;
476 Fcb->Vcb = Vcb;
477
478 if (!(Fcb->Flags & FCB_CACHE_INITIALIZED))
479 {
480 _SEH2_TRY
481 {
482 CcInitializeCacheMap(FileObject,
483 (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
484 FALSE,
485 &(NtfsGlobalData->CacheMgrCallbacks),
486 Fcb);
487 }
488 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
489 {
490 FileObject->FsContext2 = NULL;
491 ExFreePoolWithTag(newCCB, TAG_CCB);
492 return _SEH2_GetExceptionCode();
493 }
494 _SEH2_END;
495
496 Fcb->Flags |= FCB_CACHE_INITIALIZED;
497 }
498
499 //DPRINT("file open: fcb:%x file size: %d\n", Fcb, Fcb->Entry.DataLengthL);
500
501 return STATUS_SUCCESS;
502 }
503
504
505 static NTSTATUS
506 NtfsDirFindFile(PNTFS_VCB Vcb,
507 PNTFS_FCB DirectoryFcb,
508 PWSTR FileToFind,
509 BOOLEAN CaseSensitive,
510 PNTFS_FCB *FoundFCB)
511 {
512 NTSTATUS Status;
513 ULONGLONG CurrentDir;
514 UNICODE_STRING File;
515 PFILE_RECORD_HEADER FileRecord;
516 ULONGLONG MFTIndex;
517 PWSTR Colon, OldColon;
518 PNTFS_ATTR_CONTEXT DataContext;
519 USHORT Length = 0;
520
521 DPRINT1("NtfsDirFindFile(%p, %p, %S, %s, %p)\n",
522 Vcb,
523 DirectoryFcb,
524 FileToFind,
525 CaseSensitive ? "TRUE" : "FALSE",
526 FoundFCB);
527
528 *FoundFCB = NULL;
529 RtlInitUnicodeString(&File, FileToFind);
530 CurrentDir = DirectoryFcb->MFTIndex;
531
532 Colon = wcsrchr(FileToFind, L':');
533 if (Colon != NULL)
534 {
535 Length = File.Length;
536 File.Length = (Colon - FileToFind) * sizeof(WCHAR);
537
538 if (_wcsicmp(Colon + 1, L"$DATA") == 0)
539 {
540 OldColon = Colon;
541 Colon[0] = UNICODE_NULL;
542 Colon = wcsrchr(FileToFind, L':');
543 if (Colon != NULL)
544 {
545 Length = File.Length;
546 File.Length = (Colon - FileToFind) * sizeof(WCHAR);
547 }
548 else
549 {
550 Colon = OldColon;
551 Colon[0] = L':';
552 }
553 }
554
555 /* Skip colon */
556 ++Colon;
557 DPRINT1("Will now look for file '%wZ' with stream '%S'\n", &File, Colon);
558 }
559
560 Status = NtfsLookupFileAt(Vcb, &File, CaseSensitive, &FileRecord, &MFTIndex, CurrentDir);
561 if (!NT_SUCCESS(Status))
562 {
563 return Status;
564 }
565
566 if (Length != 0)
567 {
568 File.Length = Length;
569 }
570
571 if ((FileRecord->Flags & FRH_DIRECTORY) && Colon != 0)
572 {
573 return STATUS_INVALID_PARAMETER;
574 }
575 else if (Colon != 0)
576 {
577 Status = FindAttribute(Vcb, FileRecord, AttributeData, Colon, wcslen(Colon), &DataContext, NULL);
578 if (!NT_SUCCESS(Status))
579 {
580 return STATUS_OBJECT_NAME_NOT_FOUND;
581 }
582 ReleaseAttributeContext(DataContext);
583 }
584
585 Status = NtfsMakeFCBFromDirEntry(Vcb, DirectoryFcb, &File, Colon, FileRecord, MFTIndex, FoundFCB);
586 ExFreePoolWithTag(FileRecord, TAG_NTFS);
587
588 return Status;
589 }
590
591
592 NTSTATUS
593 NtfsGetFCBForFile(PNTFS_VCB Vcb,
594 PNTFS_FCB *pParentFCB,
595 PNTFS_FCB *pFCB,
596 PCWSTR pFileName,
597 BOOLEAN CaseSensitive)
598 {
599 NTSTATUS Status;
600 WCHAR pathName [MAX_PATH];
601 WCHAR elementName [MAX_PATH];
602 PCWSTR currentElement;
603 PNTFS_FCB FCB;
604 PNTFS_FCB parentFCB;
605
606 DPRINT("NtfsGetFCBForFile(%p, %p, %p, '%S', %s)\n",
607 Vcb,
608 pParentFCB,
609 pFCB,
610 pFileName,
611 CaseSensitive ? "TRUE" : "FALSE");
612
613 /* Dummy code */
614 // FCB = NtfsOpenRootFCB(Vcb);
615 // *pFCB = FCB;
616 // *pParentFCB = NULL;
617
618 #if 1
619 /* Trivial case, open of the root directory on volume */
620 if (pFileName[0] == L'\0' || wcscmp(pFileName, L"\\") == 0)
621 {
622 DPRINT("returning root FCB\n");
623
624 FCB = NtfsOpenRootFCB(Vcb);
625 *pFCB = FCB;
626 *pParentFCB = NULL;
627
628 return (FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND;
629 }
630 else
631 {
632 currentElement = pFileName + 1;
633 wcscpy (pathName, L"\\");
634 FCB = NtfsOpenRootFCB (Vcb);
635 }
636
637 parentFCB = NULL;
638
639 /* Parse filename and check each path element for existence and access */
640 while (NtfsGetNextPathElement(currentElement) != 0)
641 {
642 /* Skip blank directory levels */
643 if ((NtfsGetNextPathElement(currentElement) - currentElement) == 0)
644 {
645 currentElement++;
646 continue;
647 }
648
649 DPRINT("Parsing, currentElement:%S\n", currentElement);
650 DPRINT(" parentFCB:%p FCB:%p\n", parentFCB, FCB);
651
652 /* Descend to next directory level */
653 if (parentFCB)
654 {
655 NtfsReleaseFCB(Vcb, parentFCB);
656 parentFCB = NULL;
657 }
658
659 /* fail if element in FCB is not a directory */
660 if (!NtfsFCBIsDirectory(FCB))
661 {
662 DPRINT("Element in requested path is not a directory\n");
663
664 NtfsReleaseFCB(Vcb, FCB);
665 FCB = 0;
666 *pParentFCB = NULL;
667 *pFCB = NULL;
668
669 return STATUS_OBJECT_PATH_NOT_FOUND;
670 }
671
672 parentFCB = FCB;
673
674 /* Extract next directory level into dirName */
675 NtfsWSubString(pathName,
676 pFileName,
677 NtfsGetNextPathElement(currentElement) - pFileName);
678 DPRINT(" pathName:%S\n", pathName);
679
680 FCB = NtfsGrabFCBFromTable(Vcb, pathName);
681 if (FCB == NULL)
682 {
683 NtfsWSubString(elementName,
684 currentElement,
685 NtfsGetNextPathElement(currentElement) - currentElement);
686 DPRINT(" elementName:%S\n", elementName);
687
688 Status = NtfsDirFindFile(Vcb, parentFCB, elementName, CaseSensitive, &FCB);
689 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
690 {
691 *pParentFCB = parentFCB;
692 *pFCB = NULL;
693 currentElement = NtfsGetNextPathElement(currentElement);
694 if (*currentElement == L'\0' || NtfsGetNextPathElement(currentElement + 1) == 0)
695 {
696 return STATUS_OBJECT_NAME_NOT_FOUND;
697 }
698 else
699 {
700 return STATUS_OBJECT_PATH_NOT_FOUND;
701 }
702 }
703 else if (!NT_SUCCESS(Status))
704 {
705 NtfsReleaseFCB(Vcb, parentFCB);
706 *pParentFCB = NULL;
707 *pFCB = NULL;
708
709 return Status;
710 }
711 }
712
713 currentElement = NtfsGetNextPathElement(currentElement);
714 }
715
716 *pParentFCB = parentFCB;
717 *pFCB = FCB;
718 #endif
719
720 return STATUS_SUCCESS;
721 }
722
723
724 NTSTATUS
725 NtfsReadFCBAttribute(PNTFS_VCB Vcb,
726 PNTFS_FCB pFCB,
727 ULONG Type,
728 PCWSTR Name,
729 ULONG NameLength,
730 PVOID * Data)
731 {
732 NTSTATUS Status;
733 PFILE_RECORD_HEADER FileRecord;
734 PNTFS_ATTR_CONTEXT AttrCtxt;
735 ULONGLONG AttrLength;
736
737 FileRecord = ExAllocatePoolWithTag(NonPagedPool,
738 Vcb->NtfsInfo.BytesPerFileRecord,
739 TAG_NTFS);
740 if (FileRecord == NULL)
741 {
742 return STATUS_INSUFFICIENT_RESOURCES;
743 }
744
745 Status = ReadFileRecord(Vcb, pFCB->MFTIndex, FileRecord);
746 if (!NT_SUCCESS(Status))
747 {
748 ExFreePoolWithTag(FileRecord, TAG_NTFS);
749 return Status;
750 }
751
752 Status = FindAttribute(Vcb, FileRecord, Type, Name, NameLength, &AttrCtxt, NULL);
753 if (!NT_SUCCESS(Status))
754 {
755 ExFreePoolWithTag(FileRecord, TAG_NTFS);
756 return Status;
757 }
758
759 AttrLength = AttributeDataLength(&AttrCtxt->Record);
760 *Data = ExAllocatePoolWithTag(NonPagedPool, AttrLength, TAG_NTFS);
761 if (*Data == NULL)
762 {
763 ReleaseAttributeContext(AttrCtxt);
764 ExFreePoolWithTag(FileRecord, TAG_NTFS);
765 return STATUS_INSUFFICIENT_RESOURCES;
766 }
767
768 ReadAttribute(Vcb, AttrCtxt, 0, *Data, AttrLength);
769
770 ReleaseAttributeContext(AttrCtxt);
771 ExFreePoolWithTag(FileRecord, TAG_NTFS);
772
773 return STATUS_SUCCESS;
774 }
775
776 /* EOF */