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