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/create.c
22c2c66affSColin Finck * PURPOSE: NTFS filesystem driver
23c2c66affSColin Finck * PROGRAMMERS: Eric Kohl
24c2c66affSColin Finck * Pierre Schweitzer (pierre@reactos.org)
25c2c66affSColin Finck */
26c2c66affSColin Finck
27c2c66affSColin Finck /* INCLUDES *****************************************************************/
28c2c66affSColin Finck
29c2c66affSColin Finck #include "ntfs.h"
30c2c66affSColin Finck
31c2c66affSColin Finck #define NDEBUG
32c2c66affSColin Finck #include <debug.h>
33c2c66affSColin Finck
34c2c66affSColin Finck static PCWSTR MftIdToName[] = {
35c2c66affSColin Finck L"$MFT",
36c2c66affSColin Finck L"$MFTMirr",
37c2c66affSColin Finck L"$LogFile",
38c2c66affSColin Finck L"$Volume",
39c2c66affSColin Finck L"AttrDef",
40c2c66affSColin Finck L".",
41c2c66affSColin Finck L"$Bitmap",
42c2c66affSColin Finck L"$Boot",
43c2c66affSColin Finck L"$BadClus",
44c2c66affSColin Finck L"$Quota",
45c2c66affSColin Finck L"$UpCase",
46c2c66affSColin Finck L"$Extended",
47c2c66affSColin Finck };
48c2c66affSColin Finck
49c2c66affSColin Finck /* FUNCTIONS ****************************************************************/
50c2c66affSColin Finck
51c2c66affSColin Finck static
52c2c66affSColin Finck NTSTATUS
NtfsMakeAbsoluteFilename(PFILE_OBJECT pFileObject,PWSTR pRelativeFileName,PWSTR * pAbsoluteFilename)53c2c66affSColin Finck NtfsMakeAbsoluteFilename(PFILE_OBJECT pFileObject,
54c2c66affSColin Finck PWSTR pRelativeFileName,
55c2c66affSColin Finck PWSTR *pAbsoluteFilename)
56c2c66affSColin Finck {
57c2c66affSColin Finck PWSTR rcName;
58c2c66affSColin Finck PNTFS_FCB Fcb;
59c2c66affSColin Finck
60c2c66affSColin Finck DPRINT("try related for %S\n", pRelativeFileName);
61c2c66affSColin Finck Fcb = pFileObject->FsContext;
62c2c66affSColin Finck ASSERT(Fcb);
63c2c66affSColin Finck
64c2c66affSColin Finck if (Fcb->Flags & FCB_IS_VOLUME)
65c2c66affSColin Finck {
66c2c66affSColin Finck /* This is likely to be an opening by ID, return ourselves */
67c2c66affSColin Finck if (pRelativeFileName[0] == L'\\')
68c2c66affSColin Finck {
69c2c66affSColin Finck *pAbsoluteFilename = NULL;
70c2c66affSColin Finck return STATUS_SUCCESS;
71c2c66affSColin Finck }
72c2c66affSColin Finck
73c2c66affSColin Finck return STATUS_INVALID_PARAMETER;
74c2c66affSColin Finck }
75c2c66affSColin Finck
76c2c66affSColin Finck /* verify related object is a directory and target name
77c2c66affSColin Finck don't start with \. */
78c2c66affSColin Finck if (NtfsFCBIsDirectory(Fcb) == FALSE ||
79c2c66affSColin Finck pRelativeFileName[0] == L'\\')
80c2c66affSColin Finck {
81c2c66affSColin Finck return STATUS_INVALID_PARAMETER;
82c2c66affSColin Finck }
83c2c66affSColin Finck
84c2c66affSColin Finck /* construct absolute path name */
85c2c66affSColin Finck ASSERT(wcslen (Fcb->PathName) + 1 + wcslen (pRelativeFileName) + 1 <= MAX_PATH);
86c2c66affSColin Finck rcName = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH * sizeof(WCHAR), TAG_NTFS);
87c2c66affSColin Finck if (!rcName)
88c2c66affSColin Finck {
89c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
90c2c66affSColin Finck }
91c2c66affSColin Finck
92c2c66affSColin Finck wcscpy(rcName, Fcb->PathName);
93c2c66affSColin Finck if (!NtfsFCBIsRoot(Fcb))
94c2c66affSColin Finck wcscat (rcName, L"\\");
95c2c66affSColin Finck wcscat (rcName, pRelativeFileName);
96c2c66affSColin Finck *pAbsoluteFilename = rcName;
97c2c66affSColin Finck
98c2c66affSColin Finck return STATUS_SUCCESS;
99c2c66affSColin Finck }
100c2c66affSColin Finck
101c2c66affSColin Finck
102c2c66affSColin Finck static
103c2c66affSColin Finck NTSTATUS
NtfsMoonWalkID(PDEVICE_EXTENSION DeviceExt,ULONGLONG Id,PUNICODE_STRING OutPath)104c2c66affSColin Finck NtfsMoonWalkID(PDEVICE_EXTENSION DeviceExt,
105c2c66affSColin Finck ULONGLONG Id,
106c2c66affSColin Finck PUNICODE_STRING OutPath)
107c2c66affSColin Finck {
108c2c66affSColin Finck NTSTATUS Status;
109c2c66affSColin Finck PFILE_RECORD_HEADER MftRecord;
110c2c66affSColin Finck PFILENAME_ATTRIBUTE FileName;
111c2c66affSColin Finck WCHAR FullPath[MAX_PATH];
112c2c66affSColin Finck ULONG WritePosition = MAX_PATH - 1;
113c2c66affSColin Finck
114*15524349SVictor Perevertkin DPRINT("NtfsMoonWalkID(%p, %I64x, %p)\n", DeviceExt, Id, OutPath);
115c2c66affSColin Finck
116c2c66affSColin Finck RtlZeroMemory(FullPath, sizeof(FullPath));
117216a2caeSPierre Schweitzer MftRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList);
118c2c66affSColin Finck if (MftRecord == NULL)
119c2c66affSColin Finck {
120c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
121c2c66affSColin Finck }
122c2c66affSColin Finck
123c2c66affSColin Finck while (TRUE)
124c2c66affSColin Finck {
125c2c66affSColin Finck Status = ReadFileRecord(DeviceExt, Id, MftRecord);
126c2c66affSColin Finck if (!NT_SUCCESS(Status))
127c2c66affSColin Finck break;
128c2c66affSColin Finck
129c2c66affSColin Finck ASSERT(MftRecord->Ntfs.Type == NRH_FILE_TYPE);
130c2c66affSColin Finck if (!(MftRecord->Flags & FRH_IN_USE))
131c2c66affSColin Finck {
132c2c66affSColin Finck Status = STATUS_OBJECT_PATH_NOT_FOUND;
133c2c66affSColin Finck break;
134c2c66affSColin Finck }
135c2c66affSColin Finck
136c2c66affSColin Finck FileName = GetBestFileNameFromRecord(DeviceExt, MftRecord);
137c2c66affSColin Finck if (FileName == NULL)
138c2c66affSColin Finck {
139c2c66affSColin Finck DPRINT1("$FILE_NAME attribute not found for %I64x\n", Id);
140c2c66affSColin Finck Status = STATUS_OBJECT_PATH_NOT_FOUND;
141c2c66affSColin Finck break;
142c2c66affSColin Finck }
143c2c66affSColin Finck
144c2c66affSColin Finck WritePosition -= FileName->NameLength;
145c2c66affSColin Finck ASSERT(WritePosition < MAX_PATH);
146c2c66affSColin Finck RtlCopyMemory(FullPath + WritePosition, FileName->Name, FileName->NameLength * sizeof(WCHAR));
147c2c66affSColin Finck WritePosition -= 1;
148c2c66affSColin Finck ASSERT(WritePosition < MAX_PATH);
149c2c66affSColin Finck FullPath[WritePosition] = L'\\';
150c2c66affSColin Finck
151c2c66affSColin Finck Id = FileName->DirectoryFileReferenceNumber & NTFS_MFT_MASK;
152c2c66affSColin Finck if (Id == NTFS_FILE_ROOT)
153c2c66affSColin Finck break;
154c2c66affSColin Finck }
155c2c66affSColin Finck
156216a2caeSPierre Schweitzer ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, MftRecord);
157c2c66affSColin Finck
158c2c66affSColin Finck if (!NT_SUCCESS(Status))
159c2c66affSColin Finck return Status;
160c2c66affSColin Finck
161c2c66affSColin Finck OutPath->Length = (MAX_PATH - WritePosition - 1) * sizeof(WCHAR);
162c2c66affSColin Finck OutPath->MaximumLength = (MAX_PATH - WritePosition) * sizeof(WCHAR);
163c2c66affSColin Finck OutPath->Buffer = ExAllocatePoolWithTag(NonPagedPool, OutPath->MaximumLength, TAG_NTFS);
164c2c66affSColin Finck if (OutPath->Buffer == NULL)
165c2c66affSColin Finck {
166c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
167c2c66affSColin Finck }
168c2c66affSColin Finck RtlCopyMemory(OutPath->Buffer, FullPath + WritePosition, OutPath->MaximumLength);
169c2c66affSColin Finck
170c2c66affSColin Finck return Status;
171c2c66affSColin Finck }
172c2c66affSColin Finck
173c2c66affSColin Finck static
174c2c66affSColin Finck NTSTATUS
NtfsOpenFileById(PDEVICE_EXTENSION DeviceExt,PFILE_OBJECT FileObject,ULONGLONG MftId,PNTFS_FCB * FoundFCB)175c2c66affSColin Finck NtfsOpenFileById(PDEVICE_EXTENSION DeviceExt,
176c2c66affSColin Finck PFILE_OBJECT FileObject,
177c2c66affSColin Finck ULONGLONG MftId,
178c2c66affSColin Finck PNTFS_FCB * FoundFCB)
179c2c66affSColin Finck {
180c2c66affSColin Finck NTSTATUS Status;
181c2c66affSColin Finck PNTFS_FCB FCB;
182c2c66affSColin Finck PFILE_RECORD_HEADER MftRecord;
183c2c66affSColin Finck
184*15524349SVictor Perevertkin DPRINT("NtfsOpenFileById(%p, %p, %I64x, %p)\n", DeviceExt, FileObject, MftId, FoundFCB);
185c2c66affSColin Finck
186935fcd1bSTrevor Thompson ASSERT(MftId < NTFS_FILE_FIRST_USER_FILE);
187c2c66affSColin Finck if (MftId > 0xb) /* No entries are used yet beyond this */
188c2c66affSColin Finck {
189c2c66affSColin Finck return STATUS_OBJECT_NAME_NOT_FOUND;
190c2c66affSColin Finck }
191c2c66affSColin Finck
192216a2caeSPierre Schweitzer MftRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList);
193c2c66affSColin Finck if (MftRecord == NULL)
194c2c66affSColin Finck {
195c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
196c2c66affSColin Finck }
197c2c66affSColin Finck
198c2c66affSColin Finck Status = ReadFileRecord(DeviceExt, MftId, MftRecord);
199c2c66affSColin Finck if (!NT_SUCCESS(Status))
200c2c66affSColin Finck {
201216a2caeSPierre Schweitzer ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, MftRecord);
202c2c66affSColin Finck return Status;
203c2c66affSColin Finck }
204c2c66affSColin Finck
205c2c66affSColin Finck if (!(MftRecord->Flags & FRH_IN_USE))
206c2c66affSColin Finck {
207216a2caeSPierre Schweitzer ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, MftRecord);
208c2c66affSColin Finck return STATUS_OBJECT_PATH_NOT_FOUND;
209c2c66affSColin Finck }
210c2c66affSColin Finck
211c2c66affSColin Finck FCB = NtfsGrabFCBFromTable(DeviceExt, MftIdToName[MftId]);
212c2c66affSColin Finck if (FCB == NULL)
213c2c66affSColin Finck {
214c2c66affSColin Finck UNICODE_STRING Name;
215c2c66affSColin Finck
216c2c66affSColin Finck RtlInitUnicodeString(&Name, MftIdToName[MftId]);
217c2c66affSColin Finck Status = NtfsMakeFCBFromDirEntry(DeviceExt, NULL, &Name, NULL, MftRecord, MftId, &FCB);
218c2c66affSColin Finck if (!NT_SUCCESS(Status))
219c2c66affSColin Finck {
220216a2caeSPierre Schweitzer ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, MftRecord);
221c2c66affSColin Finck return Status;
222c2c66affSColin Finck }
223c2c66affSColin Finck }
224c2c66affSColin Finck
225c2c66affSColin Finck ASSERT(FCB != NULL);
226c2c66affSColin Finck
227216a2caeSPierre Schweitzer ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, MftRecord);
228c2c66affSColin Finck
229c2c66affSColin Finck Status = NtfsAttachFCBToFileObject(DeviceExt,
230c2c66affSColin Finck FCB,
231c2c66affSColin Finck FileObject);
232c2c66affSColin Finck *FoundFCB = FCB;
233c2c66affSColin Finck
234c2c66affSColin Finck return Status;
235c2c66affSColin Finck }
236c2c66affSColin Finck
237c2c66affSColin Finck /*
238c2c66affSColin Finck * FUNCTION: Opens a file
239c2c66affSColin Finck */
240c2c66affSColin Finck static
241c2c66affSColin Finck NTSTATUS
NtfsOpenFile(PDEVICE_EXTENSION DeviceExt,PFILE_OBJECT FileObject,PWSTR FileName,BOOLEAN CaseSensitive,PNTFS_FCB * FoundFCB)242c2c66affSColin Finck NtfsOpenFile(PDEVICE_EXTENSION DeviceExt,
243c2c66affSColin Finck PFILE_OBJECT FileObject,
244c2c66affSColin Finck PWSTR FileName,
245032be029STrevor Thompson BOOLEAN CaseSensitive,
246c2c66affSColin Finck PNTFS_FCB * FoundFCB)
247c2c66affSColin Finck {
248c2c66affSColin Finck PNTFS_FCB ParentFcb;
249c2c66affSColin Finck PNTFS_FCB Fcb;
250c2c66affSColin Finck NTSTATUS Status;
251c2c66affSColin Finck PWSTR AbsFileName = NULL;
252c2c66affSColin Finck
253*15524349SVictor Perevertkin DPRINT("NtfsOpenFile(%p, %p, %S, %s, %p)\n",
254032be029STrevor Thompson DeviceExt,
255032be029STrevor Thompson FileObject,
256032be029STrevor Thompson FileName,
257032be029STrevor Thompson CaseSensitive ? "TRUE" : "FALSE",
258032be029STrevor Thompson FoundFCB);
259c2c66affSColin Finck
260c2c66affSColin Finck *FoundFCB = NULL;
261c2c66affSColin Finck
262c2c66affSColin Finck if (FileObject->RelatedFileObject)
263c2c66affSColin Finck {
264c2c66affSColin Finck DPRINT("Converting relative filename to absolute filename\n");
265c2c66affSColin Finck
266c2c66affSColin Finck Status = NtfsMakeAbsoluteFilename(FileObject->RelatedFileObject,
267c2c66affSColin Finck FileName,
268c2c66affSColin Finck &AbsFileName);
269c2c66affSColin Finck if (AbsFileName) FileName = AbsFileName;
270c2c66affSColin Finck if (!NT_SUCCESS(Status))
271c2c66affSColin Finck {
272c2c66affSColin Finck return Status;
273c2c66affSColin Finck }
274c2c66affSColin Finck }
275c2c66affSColin Finck
276c2c66affSColin Finck //FIXME: Get canonical path name (remove .'s, ..'s and extra separators)
277c2c66affSColin Finck
278c2c66affSColin Finck DPRINT("PathName to open: %S\n", FileName);
279c2c66affSColin Finck
280c2c66affSColin Finck /* try first to find an existing FCB in memory */
281c2c66affSColin Finck DPRINT("Checking for existing FCB in memory\n");
282c2c66affSColin Finck Fcb = NtfsGrabFCBFromTable(DeviceExt,
283c2c66affSColin Finck FileName);
284c2c66affSColin Finck if (Fcb == NULL)
285c2c66affSColin Finck {
286c2c66affSColin Finck DPRINT("No existing FCB found, making a new one if file exists.\n");
287c2c66affSColin Finck Status = NtfsGetFCBForFile(DeviceExt,
288c2c66affSColin Finck &ParentFcb,
289c2c66affSColin Finck &Fcb,
290032be029STrevor Thompson FileName,
291032be029STrevor Thompson CaseSensitive);
292c2c66affSColin Finck if (ParentFcb != NULL)
293c2c66affSColin Finck {
294c2c66affSColin Finck NtfsReleaseFCB(DeviceExt,
295c2c66affSColin Finck ParentFcb);
296c2c66affSColin Finck }
297c2c66affSColin Finck
298c2c66affSColin Finck if (!NT_SUCCESS(Status))
299c2c66affSColin Finck {
300c2c66affSColin Finck DPRINT("Could not make a new FCB, status: %x\n", Status);
301c2c66affSColin Finck
302c2c66affSColin Finck if (AbsFileName)
30339a06faeSTrevor Thompson ExFreePoolWithTag(AbsFileName, TAG_NTFS);
304c2c66affSColin Finck
305c2c66affSColin Finck return Status;
306c2c66affSColin Finck }
307c2c66affSColin Finck }
308c2c66affSColin Finck
309c2c66affSColin Finck DPRINT("Attaching FCB to fileObject\n");
310c2c66affSColin Finck Status = NtfsAttachFCBToFileObject(DeviceExt,
311c2c66affSColin Finck Fcb,
312c2c66affSColin Finck FileObject);
313c2c66affSColin Finck
314c2c66affSColin Finck if (AbsFileName)
315c2c66affSColin Finck ExFreePool(AbsFileName);
316c2c66affSColin Finck
317c2c66affSColin Finck *FoundFCB = Fcb;
318c2c66affSColin Finck
319c2c66affSColin Finck return Status;
320c2c66affSColin Finck }
321c2c66affSColin Finck
322c2c66affSColin Finck
323c2c66affSColin Finck /*
324c2c66affSColin Finck * FUNCTION: Opens a file
325c2c66affSColin Finck */
326c2c66affSColin Finck static
327c2c66affSColin Finck NTSTATUS
NtfsCreateFile(PDEVICE_OBJECT DeviceObject,PNTFS_IRP_CONTEXT IrpContext)328c2c66affSColin Finck NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
32998ddf610STrevor Thompson PNTFS_IRP_CONTEXT IrpContext)
330c2c66affSColin Finck {
331c2c66affSColin Finck PDEVICE_EXTENSION DeviceExt;
332c2c66affSColin Finck PIO_STACK_LOCATION Stack;
333c2c66affSColin Finck PFILE_OBJECT FileObject;
334c2c66affSColin Finck ULONG RequestedDisposition;
335c2c66affSColin Finck ULONG RequestedOptions;
336c2c66affSColin Finck PNTFS_FCB Fcb = NULL;
337c2c66affSColin Finck // PWSTR FileName;
338c2c66affSColin Finck NTSTATUS Status;
339c2c66affSColin Finck UNICODE_STRING FullPath;
34098ddf610STrevor Thompson PIRP Irp = IrpContext->Irp;
341c2c66affSColin Finck
342*15524349SVictor Perevertkin DPRINT("NtfsCreateFile(%p, %p) called\n", DeviceObject, IrpContext);
343c2c66affSColin Finck
344c2c66affSColin Finck DeviceExt = DeviceObject->DeviceExtension;
345c2c66affSColin Finck ASSERT(DeviceExt);
346c2c66affSColin Finck Stack = IoGetCurrentIrpStackLocation(Irp);
347c2c66affSColin Finck ASSERT(Stack);
348c2c66affSColin Finck
349c2c66affSColin Finck RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
350c2c66affSColin Finck RequestedOptions = Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
351c2c66affSColin Finck // PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
352c2c66affSColin Finck if (RequestedOptions & FILE_DIRECTORY_FILE &&
353c2c66affSColin Finck RequestedDisposition == FILE_SUPERSEDE)
354c2c66affSColin Finck {
355c2c66affSColin Finck return STATUS_INVALID_PARAMETER;
356c2c66affSColin Finck }
357c2c66affSColin Finck
358c2c66affSColin Finck /* Deny create if the volume is locked */
359c2c66affSColin Finck if (DeviceExt->Flags & VCB_VOLUME_LOCKED)
360c2c66affSColin Finck {
361c2c66affSColin Finck return STATUS_ACCESS_DENIED;
362c2c66affSColin Finck }
363c2c66affSColin Finck
364c2c66affSColin Finck FileObject = Stack->FileObject;
365c2c66affSColin Finck
366c2c66affSColin Finck if ((RequestedOptions & FILE_OPEN_BY_FILE_ID) == FILE_OPEN_BY_FILE_ID)
367c2c66affSColin Finck {
368c2c66affSColin Finck ULONGLONG MFTId;
369c2c66affSColin Finck
370c2c66affSColin Finck if (FileObject->FileName.Length != sizeof(ULONGLONG))
371c2c66affSColin Finck return STATUS_INVALID_PARAMETER;
372c2c66affSColin Finck
373c2c66affSColin Finck MFTId = (*(PULONGLONG)FileObject->FileName.Buffer) & NTFS_MFT_MASK;
374935fcd1bSTrevor Thompson if (MFTId < NTFS_FILE_FIRST_USER_FILE)
375c2c66affSColin Finck {
376c2c66affSColin Finck Status = NtfsOpenFileById(DeviceExt, FileObject, MFTId, &Fcb);
377c2c66affSColin Finck }
378c2c66affSColin Finck else
379c2c66affSColin Finck {
380c2c66affSColin Finck Status = NtfsMoonWalkID(DeviceExt, MFTId, &FullPath);
381c2c66affSColin Finck }
382c2c66affSColin Finck
383c2c66affSColin Finck if (!NT_SUCCESS(Status))
384c2c66affSColin Finck {
385c2c66affSColin Finck return Status;
386c2c66affSColin Finck }
387c2c66affSColin Finck
388c2c66affSColin Finck DPRINT1("Open by ID: %I64x -> %wZ\n", (*(PULONGLONG)FileObject->FileName.Buffer) & NTFS_MFT_MASK, &FullPath);
389c2c66affSColin Finck }
390c2c66affSColin Finck
391c2c66affSColin Finck /* This a open operation for the volume itself */
392c2c66affSColin Finck if (FileObject->FileName.Length == 0 &&
393c2c66affSColin Finck (FileObject->RelatedFileObject == NULL || FileObject->RelatedFileObject->FsContext2 != NULL))
394c2c66affSColin Finck {
395c2c66affSColin Finck if (RequestedDisposition != FILE_OPEN &&
396c2c66affSColin Finck RequestedDisposition != FILE_OPEN_IF)
397c2c66affSColin Finck {
398c2c66affSColin Finck return STATUS_ACCESS_DENIED;
399c2c66affSColin Finck }
400c2c66affSColin Finck
401c2c66affSColin Finck if (RequestedOptions & FILE_DIRECTORY_FILE)
402c2c66affSColin Finck {
403c2c66affSColin Finck return STATUS_NOT_A_DIRECTORY;
404c2c66affSColin Finck }
405c2c66affSColin Finck
406c2c66affSColin Finck NtfsAttachFCBToFileObject(DeviceExt, DeviceExt->VolumeFcb, FileObject);
407c2c66affSColin Finck DeviceExt->VolumeFcb->RefCount++;
408c2c66affSColin Finck
409c2c66affSColin Finck Irp->IoStatus.Information = FILE_OPENED;
410c2c66affSColin Finck return STATUS_SUCCESS;
411c2c66affSColin Finck }
412c2c66affSColin Finck
413c2c66affSColin Finck if (Fcb == NULL)
414c2c66affSColin Finck {
415c2c66affSColin Finck Status = NtfsOpenFile(DeviceExt,
416c2c66affSColin Finck FileObject,
417c2c66affSColin Finck ((RequestedOptions & FILE_OPEN_BY_FILE_ID) ? FullPath.Buffer : FileObject->FileName.Buffer),
4182dc49385STrevor Thompson BooleanFlagOn(Stack->Flags, SL_CASE_SENSITIVE),
419c2c66affSColin Finck &Fcb);
420c2c66affSColin Finck
421c2c66affSColin Finck if (RequestedOptions & FILE_OPEN_BY_FILE_ID)
422c2c66affSColin Finck {
423c2c66affSColin Finck ExFreePoolWithTag(FullPath.Buffer, TAG_NTFS);
424c2c66affSColin Finck }
425c2c66affSColin Finck }
426c2c66affSColin Finck
427c2c66affSColin Finck if (NT_SUCCESS(Status))
428c2c66affSColin Finck {
429c2c66affSColin Finck if (RequestedDisposition == FILE_CREATE)
430c2c66affSColin Finck {
431c2c66affSColin Finck Irp->IoStatus.Information = FILE_EXISTS;
432c2c66affSColin Finck NtfsCloseFile(DeviceExt, FileObject);
433c2c66affSColin Finck return STATUS_OBJECT_NAME_COLLISION;
434c2c66affSColin Finck }
435c2c66affSColin Finck
436c2c66affSColin Finck if (RequestedOptions & FILE_NON_DIRECTORY_FILE &&
437c2c66affSColin Finck NtfsFCBIsDirectory(Fcb))
438c2c66affSColin Finck {
439c2c66affSColin Finck NtfsCloseFile(DeviceExt, FileObject);
440c2c66affSColin Finck return STATUS_FILE_IS_A_DIRECTORY;
441c2c66affSColin Finck }
442c2c66affSColin Finck
443c2c66affSColin Finck if (RequestedOptions & FILE_DIRECTORY_FILE &&
444c2c66affSColin Finck !NtfsFCBIsDirectory(Fcb))
445c2c66affSColin Finck {
446c2c66affSColin Finck NtfsCloseFile(DeviceExt, FileObject);
447c2c66affSColin Finck return STATUS_NOT_A_DIRECTORY;
448c2c66affSColin Finck }
449c2c66affSColin Finck
450c2c66affSColin Finck /*
451c2c66affSColin Finck * If it is a reparse point & FILE_OPEN_REPARSE_POINT, then allow opening it
452c2c66affSColin Finck * as a normal file.
453c2c66affSColin Finck * Otherwise, attempt to read reparse data and hand them to the Io manager
454c2c66affSColin Finck * with status reparse to force a reparse.
455c2c66affSColin Finck */
456c2c66affSColin Finck if (NtfsFCBIsReparsePoint(Fcb) &&
457c2c66affSColin Finck ((RequestedOptions & FILE_OPEN_REPARSE_POINT) != FILE_OPEN_REPARSE_POINT))
458c2c66affSColin Finck {
459c2c66affSColin Finck PREPARSE_DATA_BUFFER ReparseData = NULL;
460c2c66affSColin Finck
461c2c66affSColin Finck Status = NtfsReadFCBAttribute(DeviceExt, Fcb,
462c2c66affSColin Finck AttributeReparsePoint, L"", 0,
463c2c66affSColin Finck (PVOID *)&Irp->Tail.Overlay.AuxiliaryBuffer);
464c2c66affSColin Finck if (NT_SUCCESS(Status))
465c2c66affSColin Finck {
466c2c66affSColin Finck ReparseData = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
467c2c66affSColin Finck if (ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
468c2c66affSColin Finck {
469c2c66affSColin Finck Status = STATUS_REPARSE;
470c2c66affSColin Finck }
471c2c66affSColin Finck else
472c2c66affSColin Finck {
473c2c66affSColin Finck Status = STATUS_NOT_IMPLEMENTED;
474c2c66affSColin Finck ExFreePoolWithTag(ReparseData, TAG_NTFS);
475c2c66affSColin Finck }
476c2c66affSColin Finck }
477c2c66affSColin Finck
478c2c66affSColin Finck Irp->IoStatus.Information = ((Status == STATUS_REPARSE) ? ReparseData->ReparseTag : 0);
479c2c66affSColin Finck
480c2c66affSColin Finck NtfsCloseFile(DeviceExt, FileObject);
481c2c66affSColin Finck return Status;
482c2c66affSColin Finck }
483c2c66affSColin Finck
484c2c66affSColin Finck if (RequestedDisposition == FILE_OVERWRITE ||
485c2c66affSColin Finck RequestedDisposition == FILE_OVERWRITE_IF ||
486c2c66affSColin Finck RequestedDisposition == FILE_SUPERSEDE)
487c2c66affSColin Finck {
48884a1280fSTrevor Thompson PFILE_RECORD_HEADER fileRecord = NULL;
48984a1280fSTrevor Thompson PNTFS_ATTR_CONTEXT dataContext = NULL;
49084a1280fSTrevor Thompson ULONG DataAttributeOffset;
49184a1280fSTrevor Thompson LARGE_INTEGER Zero;
49284a1280fSTrevor Thompson Zero.QuadPart = 0;
49384a1280fSTrevor Thompson
494037d8820STrevor Thompson if (!NtfsGlobalData->EnableWriteSupport)
495037d8820STrevor Thompson {
496037d8820STrevor Thompson DPRINT1("NTFS write-support is EXPERIMENTAL and is disabled by default!\n");
497037d8820STrevor Thompson NtfsCloseFile(DeviceExt, FileObject);
498037d8820STrevor Thompson return STATUS_ACCESS_DENIED;
499037d8820STrevor Thompson }
500037d8820STrevor Thompson
50184a1280fSTrevor Thompson // TODO: check for appropriate access
50284a1280fSTrevor Thompson
50384a1280fSTrevor Thompson ExAcquireResourceExclusiveLite(&(Fcb->MainResource), TRUE);
50484a1280fSTrevor Thompson
505216a2caeSPierre Schweitzer fileRecord = ExAllocateFromNPagedLookasideList(&Fcb->Vcb->FileRecLookasideList);
50684a1280fSTrevor Thompson if (fileRecord)
50784a1280fSTrevor Thompson {
50884a1280fSTrevor Thompson
50984a1280fSTrevor Thompson Status = ReadFileRecord(Fcb->Vcb,
51084a1280fSTrevor Thompson Fcb->MFTIndex,
51184a1280fSTrevor Thompson fileRecord);
51284a1280fSTrevor Thompson if (!NT_SUCCESS(Status))
51384a1280fSTrevor Thompson goto DoneOverwriting;
51484a1280fSTrevor Thompson
51584a1280fSTrevor Thompson // find the data attribute and set it's length to 0 (TODO: Handle Alternate Data Streams)
51684a1280fSTrevor Thompson Status = FindAttribute(Fcb->Vcb, fileRecord, AttributeData, L"", 0, &dataContext, &DataAttributeOffset);
51784a1280fSTrevor Thompson if (!NT_SUCCESS(Status))
51884a1280fSTrevor Thompson goto DoneOverwriting;
51984a1280fSTrevor Thompson
52084a1280fSTrevor Thompson Status = SetAttributeDataLength(FileObject, Fcb, dataContext, DataAttributeOffset, fileRecord, &Zero);
52184a1280fSTrevor Thompson }
52284a1280fSTrevor Thompson else
52384a1280fSTrevor Thompson {
52484a1280fSTrevor Thompson Status = STATUS_NO_MEMORY;
52584a1280fSTrevor Thompson }
52684a1280fSTrevor Thompson
52784a1280fSTrevor Thompson DoneOverwriting:
52884a1280fSTrevor Thompson if (fileRecord)
529216a2caeSPierre Schweitzer ExFreeToNPagedLookasideList(&Fcb->Vcb->FileRecLookasideList, fileRecord);
53084a1280fSTrevor Thompson if (dataContext)
53184a1280fSTrevor Thompson ReleaseAttributeContext(dataContext);
53284a1280fSTrevor Thompson
53384a1280fSTrevor Thompson ExReleaseResourceLite(&(Fcb->MainResource));
53484a1280fSTrevor Thompson
53584a1280fSTrevor Thompson if (!NT_SUCCESS(Status))
53684a1280fSTrevor Thompson {
537c2c66affSColin Finck NtfsCloseFile(DeviceExt, FileObject);
53884a1280fSTrevor Thompson return Status;
53984a1280fSTrevor Thompson }
54084a1280fSTrevor Thompson
54184a1280fSTrevor Thompson if (RequestedDisposition == FILE_SUPERSEDE)
54284a1280fSTrevor Thompson {
54384a1280fSTrevor Thompson Irp->IoStatus.Information = FILE_SUPERSEDED;
54484a1280fSTrevor Thompson }
54584a1280fSTrevor Thompson else
54684a1280fSTrevor Thompson {
54784a1280fSTrevor Thompson Irp->IoStatus.Information = FILE_OVERWRITTEN;
54884a1280fSTrevor Thompson }
549c2c66affSColin Finck }
550c2c66affSColin Finck }
551c2c66affSColin Finck else
552c2c66affSColin Finck {
55358a13831STrevor Thompson /* HUGLY HACK: Can't create new files yet... */
554c2c66affSColin Finck if (RequestedDisposition == FILE_CREATE ||
555c2c66affSColin Finck RequestedDisposition == FILE_OPEN_IF ||
556c2c66affSColin Finck RequestedDisposition == FILE_OVERWRITE_IF ||
557c2c66affSColin Finck RequestedDisposition == FILE_SUPERSEDE)
558c2c66affSColin Finck {
559037d8820STrevor Thompson if (!NtfsGlobalData->EnableWriteSupport)
560037d8820STrevor Thompson {
561037d8820STrevor Thompson DPRINT1("NTFS write-support is EXPERIMENTAL and is disabled by default!\n");
562037d8820STrevor Thompson NtfsCloseFile(DeviceExt, FileObject);
563037d8820STrevor Thompson return STATUS_ACCESS_DENIED;
564037d8820STrevor Thompson }
565037d8820STrevor Thompson
566b033f00fSTrevor Thompson // Was the user trying to create a directory?
567c63e7e54STrevor Thompson if (RequestedOptions & FILE_DIRECTORY_FILE)
568c63e7e54STrevor Thompson {
569b033f00fSTrevor Thompson // Create the directory on disk
570b033f00fSTrevor Thompson Status = NtfsCreateDirectory(DeviceExt,
571b033f00fSTrevor Thompson FileObject,
572b033f00fSTrevor Thompson BooleanFlagOn(Stack->Flags, SL_CASE_SENSITIVE),
573b033f00fSTrevor Thompson BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT));
574c63e7e54STrevor Thompson }
575b033f00fSTrevor Thompson else
576b033f00fSTrevor Thompson {
5770409b316STrevor Thompson // Create the file record on disk
578948e9190STrevor Thompson Status = NtfsCreateFileRecord(DeviceExt,
579948e9190STrevor Thompson FileObject,
58039a06faeSTrevor Thompson BooleanFlagOn(Stack->Flags, SL_CASE_SENSITIVE),
581948e9190STrevor Thompson BooleanFlagOn(IrpContext->Flags, IRPCONTEXT_CANWAIT));
582b033f00fSTrevor Thompson }
583b033f00fSTrevor Thompson
584e0048b13STrevor Thompson if (!NT_SUCCESS(Status))
585e0048b13STrevor Thompson {
586e0048b13STrevor Thompson DPRINT1("ERROR: Couldn't create file record!\n");
587e0048b13STrevor Thompson return Status;
588e0048b13STrevor Thompson }
5890409b316STrevor Thompson
590b033f00fSTrevor Thompson // Before we open the file/directory we just created, we need to change the disposition (upper 8 bits of ULONG)
5919cef4254STrevor Thompson // from create to open, since we already created the file
5929cef4254STrevor Thompson Stack->Parameters.Create.Options = (ULONG)FILE_OPEN << 24 | RequestedOptions;
5939cef4254STrevor Thompson
5949cef4254STrevor Thompson // Now we should be able to open the file using NtfsCreateFile()
5959cef4254STrevor Thompson Status = NtfsCreateFile(DeviceObject, IrpContext);
5969cef4254STrevor Thompson if (NT_SUCCESS(Status))
5979cef4254STrevor Thompson {
5989cef4254STrevor Thompson // We need to change Irp->IoStatus.Information to reflect creation
5999cef4254STrevor Thompson Irp->IoStatus.Information = FILE_CREATED;
6009cef4254STrevor Thompson }
6019cef4254STrevor Thompson return Status;
602c2c66affSColin Finck }
603c2c66affSColin Finck }
604c2c66affSColin Finck
605c2c66affSColin Finck if (NT_SUCCESS(Status))
606c2c66affSColin Finck {
607c2c66affSColin Finck Fcb->OpenHandleCount++;
608c2c66affSColin Finck DeviceExt->OpenHandleCount++;
609c2c66affSColin Finck }
610c2c66affSColin Finck
611c2c66affSColin Finck /*
612c2c66affSColin Finck * If the directory containing the file to open doesn't exist then
613c2c66affSColin Finck * fail immediately
614c2c66affSColin Finck */
615c2c66affSColin Finck Irp->IoStatus.Information = (NT_SUCCESS(Status)) ? FILE_OPENED : 0;
616c2c66affSColin Finck
617c2c66affSColin Finck return Status;
618c2c66affSColin Finck }
619c2c66affSColin Finck
620c2c66affSColin Finck
621c2c66affSColin Finck NTSTATUS
NtfsCreate(PNTFS_IRP_CONTEXT IrpContext)622c2c66affSColin Finck NtfsCreate(PNTFS_IRP_CONTEXT IrpContext)
623c2c66affSColin Finck {
624c2c66affSColin Finck PDEVICE_EXTENSION DeviceExt;
625c2c66affSColin Finck NTSTATUS Status;
626c2c66affSColin Finck PDEVICE_OBJECT DeviceObject;
627c2c66affSColin Finck
628c2c66affSColin Finck DeviceObject = IrpContext->DeviceObject;
629c2c66affSColin Finck if (DeviceObject == NtfsGlobalData->DeviceObject)
630c2c66affSColin Finck {
631c2c66affSColin Finck /* DeviceObject represents FileSystem instead of logical volume */
632c2c66affSColin Finck DPRINT("Opening file system\n");
633c2c66affSColin Finck IrpContext->Irp->IoStatus.Information = FILE_OPENED;
634c2c66affSColin Finck return STATUS_SUCCESS;
635c2c66affSColin Finck }
636c2c66affSColin Finck
637c2c66affSColin Finck DeviceExt = DeviceObject->DeviceExtension;
638c2c66affSColin Finck
639c2c66affSColin Finck if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
640c2c66affSColin Finck {
641c2c66affSColin Finck return NtfsMarkIrpContextForQueue(IrpContext);
642c2c66affSColin Finck }
643c2c66affSColin Finck
644c2c66affSColin Finck ExAcquireResourceExclusiveLite(&DeviceExt->DirResource,
645c2c66affSColin Finck TRUE);
646c2c66affSColin Finck Status = NtfsCreateFile(DeviceObject,
64798ddf610STrevor Thompson IrpContext);
648c2c66affSColin Finck ExReleaseResourceLite(&DeviceExt->DirResource);
649c2c66affSColin Finck
650c2c66affSColin Finck return Status;
651c2c66affSColin Finck }
652c2c66affSColin Finck
6530409b316STrevor Thompson /**
654b033f00fSTrevor Thompson * @name NtfsCreateDirectory()
655b033f00fSTrevor Thompson * @implemented
656b033f00fSTrevor Thompson *
657b033f00fSTrevor Thompson * Creates a file record for a new directory and saves it to the MFT. Adds the filename attribute of the
658b033f00fSTrevor Thompson * created directory to the parent directory's index.
659b033f00fSTrevor Thompson *
660b033f00fSTrevor Thompson * @param DeviceExt
661b033f00fSTrevor Thompson * Points to the target disk's DEVICE_EXTENSION
662b033f00fSTrevor Thompson *
663b033f00fSTrevor Thompson * @param FileObject
664b033f00fSTrevor Thompson * Pointer to a FILE_OBJECT describing the directory to be created
665b033f00fSTrevor Thompson *
666b033f00fSTrevor Thompson * @param CaseSensitive
667b033f00fSTrevor Thompson * Boolean indicating if the function should operate in case-sensitive mode. This will be TRUE
668b033f00fSTrevor Thompson * if an application created the folder with the FILE_FLAG_POSIX_SEMANTICS flag.
669b033f00fSTrevor Thompson *
670b033f00fSTrevor Thompson * @param CanWait
671b033f00fSTrevor Thompson * Boolean indicating if the function is allowed to wait for exclusive access to the master file table.
672b033f00fSTrevor Thompson * This will only be relevant if the MFT doesn't have any free file records and needs to be enlarged.
673b033f00fSTrevor Thompson *
674b033f00fSTrevor Thompson * @return
675b033f00fSTrevor Thompson * STATUS_SUCCESS on success.
676b033f00fSTrevor Thompson * STATUS_INSUFFICIENT_RESOURCES if unable to allocate memory for the file record.
677b033f00fSTrevor Thompson * STATUS_CANT_WAIT if CanWait was FALSE and the function needed to resize the MFT but
678b033f00fSTrevor Thompson * couldn't get immediate, exclusive access to it.
679b033f00fSTrevor Thompson */
680b033f00fSTrevor Thompson NTSTATUS
NtfsCreateDirectory(PDEVICE_EXTENSION DeviceExt,PFILE_OBJECT FileObject,BOOLEAN CaseSensitive,BOOLEAN CanWait)681b033f00fSTrevor Thompson NtfsCreateDirectory(PDEVICE_EXTENSION DeviceExt,
682b033f00fSTrevor Thompson PFILE_OBJECT FileObject,
683b033f00fSTrevor Thompson BOOLEAN CaseSensitive,
684b033f00fSTrevor Thompson BOOLEAN CanWait)
685b033f00fSTrevor Thompson {
686b033f00fSTrevor Thompson
687b033f00fSTrevor Thompson NTSTATUS Status = STATUS_SUCCESS;
688b033f00fSTrevor Thompson PFILE_RECORD_HEADER FileRecord;
689b033f00fSTrevor Thompson PNTFS_ATTR_RECORD NextAttribute;
690b033f00fSTrevor Thompson PFILENAME_ATTRIBUTE FilenameAttribute;
691b033f00fSTrevor Thompson ULONGLONG ParentMftIndex;
692b033f00fSTrevor Thompson ULONGLONG FileMftIndex;
693b033f00fSTrevor Thompson PB_TREE Tree;
694b033f00fSTrevor Thompson PINDEX_ROOT_ATTRIBUTE NewIndexRoot;
6959a91a51fSTrevor Thompson ULONG MaxIndexRootSize;
696b033f00fSTrevor Thompson ULONG RootLength;
697b033f00fSTrevor Thompson
698*15524349SVictor Perevertkin DPRINT("NtfsCreateFileRecord(%p, %p, %s, %s)\n",
699b033f00fSTrevor Thompson DeviceExt,
700b033f00fSTrevor Thompson FileObject,
701b033f00fSTrevor Thompson CaseSensitive ? "TRUE" : "FALSE",
702b033f00fSTrevor Thompson CanWait ? "TRUE" : "FALSE");
703b033f00fSTrevor Thompson
704b033f00fSTrevor Thompson // Start with an empty file record
705b033f00fSTrevor Thompson FileRecord = NtfsCreateEmptyFileRecord(DeviceExt);
706b033f00fSTrevor Thompson if (!FileRecord)
707b033f00fSTrevor Thompson {
708b033f00fSTrevor Thompson DPRINT1("ERROR: Unable to allocate memory for file record!\n");
709b033f00fSTrevor Thompson return STATUS_INSUFFICIENT_RESOURCES;
710b033f00fSTrevor Thompson }
711b033f00fSTrevor Thompson
712b033f00fSTrevor Thompson // Set the directory flag
713b033f00fSTrevor Thompson FileRecord->Flags |= FRH_DIRECTORY;
714b033f00fSTrevor Thompson
715b033f00fSTrevor Thompson // find where the first attribute will be added
716b033f00fSTrevor Thompson NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
717b033f00fSTrevor Thompson
718b033f00fSTrevor Thompson // add first attribute, $STANDARD_INFORMATION
719b033f00fSTrevor Thompson AddStandardInformation(FileRecord, NextAttribute);
720b033f00fSTrevor Thompson
721b033f00fSTrevor Thompson // advance NextAttribute pointer to the next attribute
722b033f00fSTrevor Thompson NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute + (ULONG_PTR)NextAttribute->Length);
723b033f00fSTrevor Thompson
724b033f00fSTrevor Thompson // Add the $FILE_NAME attribute
725b033f00fSTrevor Thompson AddFileName(FileRecord, NextAttribute, DeviceExt, FileObject, CaseSensitive, &ParentMftIndex);
726b033f00fSTrevor Thompson
727b033f00fSTrevor Thompson // save a pointer to the filename attribute
728b033f00fSTrevor Thompson FilenameAttribute = (PFILENAME_ATTRIBUTE)((ULONG_PTR)NextAttribute + NextAttribute->Resident.ValueOffset);
729b033f00fSTrevor Thompson
730b033f00fSTrevor Thompson // advance NextAttribute pointer to the next attribute
731b033f00fSTrevor Thompson NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute + (ULONG_PTR)NextAttribute->Length);
732b033f00fSTrevor Thompson
733b033f00fSTrevor Thompson // Create an empty b-tree to represent our new index
734b033f00fSTrevor Thompson Status = CreateEmptyBTree(&Tree);
735b033f00fSTrevor Thompson if (!NT_SUCCESS(Status))
736b033f00fSTrevor Thompson {
737b033f00fSTrevor Thompson DPRINT1("ERROR: Failed to create empty B-Tree!\n");
738216a2caeSPierre Schweitzer ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
739b033f00fSTrevor Thompson return Status;
740b033f00fSTrevor Thompson }
741b033f00fSTrevor Thompson
742b033f00fSTrevor Thompson // Calculate maximum size of index root
7439a91a51fSTrevor Thompson MaxIndexRootSize = DeviceExt->NtfsInfo.BytesPerFileRecord
744b033f00fSTrevor Thompson - ((ULONG_PTR)NextAttribute - (ULONG_PTR)FileRecord)
745b033f00fSTrevor Thompson - sizeof(ULONG) * 2;
746b033f00fSTrevor Thompson
747b033f00fSTrevor Thompson // Create a new index record from the tree
748b033f00fSTrevor Thompson Status = CreateIndexRootFromBTree(DeviceExt,
749b033f00fSTrevor Thompson Tree,
750b033f00fSTrevor Thompson MaxIndexRootSize,
751b033f00fSTrevor Thompson &NewIndexRoot,
752b033f00fSTrevor Thompson &RootLength);
753b033f00fSTrevor Thompson if (!NT_SUCCESS(Status))
754b033f00fSTrevor Thompson {
755b033f00fSTrevor Thompson DPRINT1("ERROR: Unable to create empty index root!\n");
756b033f00fSTrevor Thompson DestroyBTree(Tree);
757216a2caeSPierre Schweitzer ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
758b033f00fSTrevor Thompson return Status;
759b033f00fSTrevor Thompson }
760b033f00fSTrevor Thompson
761b033f00fSTrevor Thompson // We're done with the B-Tree
762b033f00fSTrevor Thompson DestroyBTree(Tree);
763b033f00fSTrevor Thompson
764b033f00fSTrevor Thompson // add the $INDEX_ROOT attribute
765b033f00fSTrevor Thompson Status = AddIndexRoot(DeviceExt, FileRecord, NextAttribute, NewIndexRoot, RootLength, L"$I30", 4);
766b033f00fSTrevor Thompson if (!NT_SUCCESS(Status))
767b033f00fSTrevor Thompson {
768b033f00fSTrevor Thompson DPRINT1("ERROR: Failed to add index root to new file record!\n");
7697a88e3bfSPierre Schweitzer ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
770216a2caeSPierre Schweitzer ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
771b033f00fSTrevor Thompson return Status;
772b033f00fSTrevor Thompson }
773b033f00fSTrevor Thompson
774b033f00fSTrevor Thompson
775b033f00fSTrevor Thompson #ifndef NDEBUG
776b033f00fSTrevor Thompson NtfsDumpFileRecord(DeviceExt, FileRecord);
777b033f00fSTrevor Thompson #endif
778b033f00fSTrevor Thompson
779b033f00fSTrevor Thompson // Now that we've built the file record in memory, we need to store it in the MFT.
780b033f00fSTrevor Thompson Status = AddNewMftEntry(FileRecord, DeviceExt, &FileMftIndex, CanWait);
781b033f00fSTrevor Thompson if (NT_SUCCESS(Status))
782b033f00fSTrevor Thompson {
783b033f00fSTrevor Thompson // The highest 2 bytes should be the sequence number, unless the parent happens to be root
784b033f00fSTrevor Thompson if (FileMftIndex == NTFS_FILE_ROOT)
785b033f00fSTrevor Thompson FileMftIndex = FileMftIndex + ((ULONGLONG)NTFS_FILE_ROOT << 48);
786b033f00fSTrevor Thompson else
787b033f00fSTrevor Thompson FileMftIndex = FileMftIndex + ((ULONGLONG)FileRecord->SequenceNumber << 48);
788b033f00fSTrevor Thompson
789b033f00fSTrevor Thompson DPRINT1("New File Reference: 0x%016I64x\n", FileMftIndex);
790b033f00fSTrevor Thompson
791b033f00fSTrevor Thompson // Add the filename attribute to the filename-index of the parent directory
792b033f00fSTrevor Thompson Status = NtfsAddFilenameToDirectory(DeviceExt,
793b033f00fSTrevor Thompson ParentMftIndex,
794b033f00fSTrevor Thompson FileMftIndex,
795b033f00fSTrevor Thompson FilenameAttribute,
796b033f00fSTrevor Thompson CaseSensitive);
797b033f00fSTrevor Thompson }
798b033f00fSTrevor Thompson
799b033f00fSTrevor Thompson ExFreePoolWithTag(NewIndexRoot, TAG_NTFS);
800216a2caeSPierre Schweitzer ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
801b033f00fSTrevor Thompson
802b033f00fSTrevor Thompson return Status;
803b033f00fSTrevor Thompson }
804b033f00fSTrevor Thompson
805b033f00fSTrevor Thompson /**
806b033f00fSTrevor Thompson * @name NtfsCreateEmptyFileRecord
807b033f00fSTrevor Thompson * @implemented
808b033f00fSTrevor Thompson *
809b033f00fSTrevor Thompson * Creates a new, empty file record, with no attributes.
810b033f00fSTrevor Thompson *
811b033f00fSTrevor Thompson * @param DeviceExt
812b033f00fSTrevor Thompson * Pointer to the DEVICE_EXTENSION of the target volume the file record will be stored on.
813b033f00fSTrevor Thompson *
814b033f00fSTrevor Thompson * @return
815b033f00fSTrevor Thompson * A pointer to the newly-created FILE_RECORD_HEADER if the function succeeds, NULL otherwise.
816b033f00fSTrevor Thompson */
817b033f00fSTrevor Thompson PFILE_RECORD_HEADER
NtfsCreateEmptyFileRecord(PDEVICE_EXTENSION DeviceExt)818b033f00fSTrevor Thompson NtfsCreateEmptyFileRecord(PDEVICE_EXTENSION DeviceExt)
819b033f00fSTrevor Thompson {
820b033f00fSTrevor Thompson PFILE_RECORD_HEADER FileRecord;
821b033f00fSTrevor Thompson PNTFS_ATTR_RECORD NextAttribute;
822b033f00fSTrevor Thompson
823*15524349SVictor Perevertkin DPRINT("NtfsCreateEmptyFileRecord(%p)\n", DeviceExt);
824b033f00fSTrevor Thompson
825b033f00fSTrevor Thompson // allocate memory for file record
826216a2caeSPierre Schweitzer FileRecord = ExAllocateFromNPagedLookasideList(&DeviceExt->FileRecLookasideList);
827b033f00fSTrevor Thompson if (!FileRecord)
828b033f00fSTrevor Thompson {
829b033f00fSTrevor Thompson DPRINT1("ERROR: Unable to allocate memory for file record!\n");
830b033f00fSTrevor Thompson return NULL;
831b033f00fSTrevor Thompson }
832b033f00fSTrevor Thompson
833b033f00fSTrevor Thompson RtlZeroMemory(FileRecord, DeviceExt->NtfsInfo.BytesPerFileRecord);
834b033f00fSTrevor Thompson
835b033f00fSTrevor Thompson FileRecord->Ntfs.Type = NRH_FILE_TYPE;
836b033f00fSTrevor Thompson
837b033f00fSTrevor Thompson // calculate USA offset and count
838b033f00fSTrevor Thompson FileRecord->Ntfs.UsaOffset = FIELD_OFFSET(FILE_RECORD_HEADER, MFTRecordNumber) + sizeof(ULONG);
839b033f00fSTrevor Thompson
840b033f00fSTrevor Thompson // size of USA (in ULONG's) will be 1 (for USA number) + 1 for every sector the file record uses
841b033f00fSTrevor Thompson FileRecord->BytesAllocated = DeviceExt->NtfsInfo.BytesPerFileRecord;
842b033f00fSTrevor Thompson FileRecord->Ntfs.UsaCount = (FileRecord->BytesAllocated / DeviceExt->NtfsInfo.BytesPerSector) + 1;
843b033f00fSTrevor Thompson
844b033f00fSTrevor Thompson // setup other file record fields
845b033f00fSTrevor Thompson FileRecord->SequenceNumber = 1;
846b033f00fSTrevor Thompson FileRecord->AttributeOffset = FileRecord->Ntfs.UsaOffset + (2 * FileRecord->Ntfs.UsaCount);
847b033f00fSTrevor Thompson FileRecord->AttributeOffset = ALIGN_UP_BY(FileRecord->AttributeOffset, ATTR_RECORD_ALIGNMENT);
848b033f00fSTrevor Thompson FileRecord->Flags = FRH_IN_USE;
849b033f00fSTrevor Thompson FileRecord->BytesInUse = FileRecord->AttributeOffset + sizeof(ULONG) * 2;
850b033f00fSTrevor Thompson
851b033f00fSTrevor Thompson // find where the first attribute will be added
852b033f00fSTrevor Thompson NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
853b033f00fSTrevor Thompson
854b033f00fSTrevor Thompson // mark the (temporary) end of the file-record
855b033f00fSTrevor Thompson NextAttribute->Type = AttributeEnd;
856b033f00fSTrevor Thompson NextAttribute->Length = FILE_RECORD_END;
857b033f00fSTrevor Thompson
858b033f00fSTrevor Thompson return FileRecord;
859b033f00fSTrevor Thompson }
860b033f00fSTrevor Thompson
861b033f00fSTrevor Thompson
862b033f00fSTrevor Thompson /**
8630409b316STrevor Thompson * @name NtfsCreateFileRecord()
8640409b316STrevor Thompson * @implemented
8650409b316STrevor Thompson *
866e0048b13STrevor Thompson * Creates a file record and saves it to the MFT. Adds the filename attribute of the
867e0048b13STrevor Thompson * created file to the parent directory's index.
8680409b316STrevor Thompson *
8690409b316STrevor Thompson * @param DeviceExt
8700409b316STrevor Thompson * Points to the target disk's DEVICE_EXTENSION
8710409b316STrevor Thompson *
8720409b316STrevor Thompson * @param FileObject
8730409b316STrevor Thompson * Pointer to a FILE_OBJECT describing the file to be created
8740409b316STrevor Thompson *
87598ddf610STrevor Thompson * @param CanWait
87698ddf610STrevor Thompson * Boolean indicating if the function is allowed to wait for exclusive access to the master file table.
87798ddf610STrevor Thompson * This will only be relevant if the MFT doesn't have any free file records and needs to be enlarged.
87898ddf610STrevor Thompson *
8790409b316STrevor Thompson * @return
8800409b316STrevor Thompson * STATUS_SUCCESS on success.
8810409b316STrevor Thompson * STATUS_INSUFFICIENT_RESOURCES if unable to allocate memory for the file record.
88298ddf610STrevor Thompson * STATUS_CANT_WAIT if CanWait was FALSE and the function needed to resize the MFT but
88398ddf610STrevor Thompson * couldn't get immediate, exclusive access to it.
8840409b316STrevor Thompson */
8850409b316STrevor Thompson NTSTATUS
NtfsCreateFileRecord(PDEVICE_EXTENSION DeviceExt,PFILE_OBJECT FileObject,BOOLEAN CaseSensitive,BOOLEAN CanWait)8860409b316STrevor Thompson NtfsCreateFileRecord(PDEVICE_EXTENSION DeviceExt,
88798ddf610STrevor Thompson PFILE_OBJECT FileObject,
888948e9190STrevor Thompson BOOLEAN CaseSensitive,
88998ddf610STrevor Thompson BOOLEAN CanWait)
8900409b316STrevor Thompson {
8910409b316STrevor Thompson NTSTATUS Status = STATUS_SUCCESS;
8920409b316STrevor Thompson PFILE_RECORD_HEADER FileRecord;
8930409b316STrevor Thompson PNTFS_ATTR_RECORD NextAttribute;
894e0048b13STrevor Thompson PFILENAME_ATTRIBUTE FilenameAttribute;
895e0048b13STrevor Thompson ULONGLONG ParentMftIndex;
896e0048b13STrevor Thompson ULONGLONG FileMftIndex;
8970409b316STrevor Thompson
898*15524349SVictor Perevertkin DPRINT("NtfsCreateFileRecord(%p, %p, %s, %s)\n",
899948e9190STrevor Thompson DeviceExt,
900948e9190STrevor Thompson FileObject,
901948e9190STrevor Thompson CaseSensitive ? "TRUE" : "FALSE",
902948e9190STrevor Thompson CanWait ? "TRUE" : "FALSE");
9039ab86116STrevor Thompson
9040409b316STrevor Thompson // allocate memory for file record
905b033f00fSTrevor Thompson FileRecord = NtfsCreateEmptyFileRecord(DeviceExt);
9060409b316STrevor Thompson if (!FileRecord)
9070409b316STrevor Thompson {
9080409b316STrevor Thompson DPRINT1("ERROR: Unable to allocate memory for file record!\n");
9090409b316STrevor Thompson return STATUS_INSUFFICIENT_RESOURCES;
9100409b316STrevor Thompson }
9110409b316STrevor Thompson
9120409b316STrevor Thompson // find where the first attribute will be added
9130409b316STrevor Thompson NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
9140409b316STrevor Thompson
9150409b316STrevor Thompson // add first attribute, $STANDARD_INFORMATION
9160409b316STrevor Thompson AddStandardInformation(FileRecord, NextAttribute);
9170409b316STrevor Thompson
9180409b316STrevor Thompson // advance NextAttribute pointer to the next attribute
9190409b316STrevor Thompson NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute + (ULONG_PTR)NextAttribute->Length);
9200409b316STrevor Thompson
9210409b316STrevor Thompson // Add the $FILE_NAME attribute
922948e9190STrevor Thompson AddFileName(FileRecord, NextAttribute, DeviceExt, FileObject, CaseSensitive, &ParentMftIndex);
923e0048b13STrevor Thompson
924e0048b13STrevor Thompson // save a pointer to the filename attribute
925e0048b13STrevor Thompson FilenameAttribute = (PFILENAME_ATTRIBUTE)((ULONG_PTR)NextAttribute + NextAttribute->Resident.ValueOffset);
9260409b316STrevor Thompson
9270409b316STrevor Thompson // advance NextAttribute pointer to the next attribute
9280409b316STrevor Thompson NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute + (ULONG_PTR)NextAttribute->Length);
9290409b316STrevor Thompson
9300409b316STrevor Thompson // add the $DATA attribute
9310409b316STrevor Thompson AddData(FileRecord, NextAttribute);
9320409b316STrevor Thompson
933b033f00fSTrevor Thompson #ifndef NDEBUG
9340409b316STrevor Thompson // dump file record in memory (for debugging)
9350409b316STrevor Thompson NtfsDumpFileRecord(DeviceExt, FileRecord);
936b033f00fSTrevor Thompson #endif
9370409b316STrevor Thompson
9380409b316STrevor Thompson // Now that we've built the file record in memory, we need to store it in the MFT.
93998ddf610STrevor Thompson Status = AddNewMftEntry(FileRecord, DeviceExt, &FileMftIndex, CanWait);
940e0048b13STrevor Thompson if (NT_SUCCESS(Status))
941e0048b13STrevor Thompson {
942e0048b13STrevor Thompson // The highest 2 bytes should be the sequence number, unless the parent happens to be root
943e0048b13STrevor Thompson if (FileMftIndex == NTFS_FILE_ROOT)
944e0048b13STrevor Thompson FileMftIndex = FileMftIndex + ((ULONGLONG)NTFS_FILE_ROOT << 48);
945e0048b13STrevor Thompson else
946e0048b13STrevor Thompson FileMftIndex = FileMftIndex + ((ULONGLONG)FileRecord->SequenceNumber << 48);
947e0048b13STrevor Thompson
948e0048b13STrevor Thompson DPRINT1("New File Reference: 0x%016I64x\n", FileMftIndex);
949e0048b13STrevor Thompson
950e0048b13STrevor Thompson // Add the filename attribute to the filename-index of the parent directory
951e0048b13STrevor Thompson Status = NtfsAddFilenameToDirectory(DeviceExt,
952e0048b13STrevor Thompson ParentMftIndex,
953e0048b13STrevor Thompson FileMftIndex,
95454f5c3b6STrevor Thompson FilenameAttribute,
95554f5c3b6STrevor Thompson CaseSensitive);
956e0048b13STrevor Thompson }
9570409b316STrevor Thompson
958216a2caeSPierre Schweitzer ExFreeToNPagedLookasideList(&DeviceExt->FileRecLookasideList, FileRecord);
9590409b316STrevor Thompson
9600409b316STrevor Thompson return Status;
9610409b316STrevor Thompson }
9620409b316STrevor Thompson
963c2c66affSColin Finck /* EOF */
964