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