xref: /reactos/drivers/filesystems/ntfs/create.c (revision 037d8820)
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
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
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 
114c2c66affSColin Finck     DPRINT1("NtfsMoonWalkID(%p, %I64x, %p)\n", DeviceExt, Id, OutPath);
115c2c66affSColin Finck 
116c2c66affSColin Finck     RtlZeroMemory(FullPath, sizeof(FullPath));
117c2c66affSColin Finck     MftRecord = ExAllocatePoolWithTag(NonPagedPool,
118c2c66affSColin Finck                                       DeviceExt->NtfsInfo.BytesPerFileRecord,
119c2c66affSColin Finck                                       TAG_NTFS);
120c2c66affSColin Finck     if (MftRecord == NULL)
121c2c66affSColin Finck     {
122c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
123c2c66affSColin Finck     }
124c2c66affSColin Finck 
125c2c66affSColin Finck     while (TRUE)
126c2c66affSColin Finck     {
127c2c66affSColin Finck         Status = ReadFileRecord(DeviceExt, Id, MftRecord);
128c2c66affSColin Finck         if (!NT_SUCCESS(Status))
129c2c66affSColin Finck             break;
130c2c66affSColin Finck 
131c2c66affSColin Finck         ASSERT(MftRecord->Ntfs.Type == NRH_FILE_TYPE);
132c2c66affSColin Finck         if (!(MftRecord->Flags & FRH_IN_USE))
133c2c66affSColin Finck         {
134c2c66affSColin Finck             Status = STATUS_OBJECT_PATH_NOT_FOUND;
135c2c66affSColin Finck             break;
136c2c66affSColin Finck         }
137c2c66affSColin Finck 
138c2c66affSColin Finck         FileName = GetBestFileNameFromRecord(DeviceExt, MftRecord);
139c2c66affSColin Finck         if (FileName == NULL)
140c2c66affSColin Finck         {
141c2c66affSColin Finck             DPRINT1("$FILE_NAME attribute not found for %I64x\n", Id);
142c2c66affSColin Finck             Status = STATUS_OBJECT_PATH_NOT_FOUND;
143c2c66affSColin Finck             break;
144c2c66affSColin Finck         }
145c2c66affSColin Finck 
146c2c66affSColin Finck         WritePosition -= FileName->NameLength;
147c2c66affSColin Finck         ASSERT(WritePosition < MAX_PATH);
148c2c66affSColin Finck         RtlCopyMemory(FullPath + WritePosition, FileName->Name, FileName->NameLength * sizeof(WCHAR));
149c2c66affSColin Finck         WritePosition -= 1;
150c2c66affSColin Finck         ASSERT(WritePosition < MAX_PATH);
151c2c66affSColin Finck         FullPath[WritePosition] = L'\\';
152c2c66affSColin Finck 
153c2c66affSColin Finck         Id = FileName->DirectoryFileReferenceNumber & NTFS_MFT_MASK;
154c2c66affSColin Finck         if (Id == NTFS_FILE_ROOT)
155c2c66affSColin Finck             break;
156c2c66affSColin Finck     }
157c2c66affSColin Finck 
158c2c66affSColin Finck     ExFreePoolWithTag(MftRecord, TAG_NTFS);
159c2c66affSColin Finck 
160c2c66affSColin Finck     if (!NT_SUCCESS(Status))
161c2c66affSColin Finck         return Status;
162c2c66affSColin Finck 
163c2c66affSColin Finck     OutPath->Length = (MAX_PATH - WritePosition - 1) * sizeof(WCHAR);
164c2c66affSColin Finck     OutPath->MaximumLength = (MAX_PATH - WritePosition) * sizeof(WCHAR);
165c2c66affSColin Finck     OutPath->Buffer = ExAllocatePoolWithTag(NonPagedPool, OutPath->MaximumLength, TAG_NTFS);
166c2c66affSColin Finck     if (OutPath->Buffer == NULL)
167c2c66affSColin Finck     {
168c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
169c2c66affSColin Finck     }
170c2c66affSColin Finck     RtlCopyMemory(OutPath->Buffer, FullPath + WritePosition, OutPath->MaximumLength);
171c2c66affSColin Finck 
172c2c66affSColin Finck     return Status;
173c2c66affSColin Finck }
174c2c66affSColin Finck 
175c2c66affSColin Finck static
176c2c66affSColin Finck NTSTATUS
177c2c66affSColin Finck NtfsOpenFileById(PDEVICE_EXTENSION DeviceExt,
178c2c66affSColin Finck                  PFILE_OBJECT FileObject,
179c2c66affSColin Finck                  ULONGLONG MftId,
180c2c66affSColin Finck                  PNTFS_FCB * FoundFCB)
181c2c66affSColin Finck {
182c2c66affSColin Finck     NTSTATUS Status;
183c2c66affSColin Finck     PNTFS_FCB FCB;
184c2c66affSColin Finck     PFILE_RECORD_HEADER MftRecord;
185c2c66affSColin Finck 
186c2c66affSColin Finck     DPRINT1("NtfsOpenFileById(%p, %p, %I64x, %p)\n", DeviceExt, FileObject, MftId, FoundFCB);
187c2c66affSColin Finck 
188c2c66affSColin Finck     ASSERT(MftId < 0x10);
189c2c66affSColin Finck     if (MftId > 0xb) /* No entries are used yet beyond this */
190c2c66affSColin Finck     {
191c2c66affSColin Finck         return STATUS_OBJECT_NAME_NOT_FOUND;
192c2c66affSColin Finck     }
193c2c66affSColin Finck 
194c2c66affSColin Finck     MftRecord = ExAllocatePoolWithTag(NonPagedPool,
195c2c66affSColin Finck                                       DeviceExt->NtfsInfo.BytesPerFileRecord,
196c2c66affSColin Finck                                       TAG_NTFS);
197c2c66affSColin Finck     if (MftRecord == NULL)
198c2c66affSColin Finck     {
199c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
200c2c66affSColin Finck     }
201c2c66affSColin Finck 
202c2c66affSColin Finck     Status = ReadFileRecord(DeviceExt, MftId, MftRecord);
203c2c66affSColin Finck     if (!NT_SUCCESS(Status))
204c2c66affSColin Finck     {
205c2c66affSColin Finck         ExFreePoolWithTag(MftRecord, TAG_NTFS);
206c2c66affSColin Finck         return Status;
207c2c66affSColin Finck     }
208c2c66affSColin Finck 
209c2c66affSColin Finck     if (!(MftRecord->Flags & FRH_IN_USE))
210c2c66affSColin Finck     {
211c2c66affSColin Finck         ExFreePoolWithTag(MftRecord, TAG_NTFS);
212c2c66affSColin Finck         return STATUS_OBJECT_PATH_NOT_FOUND;
213c2c66affSColin Finck     }
214c2c66affSColin Finck 
215c2c66affSColin Finck     FCB = NtfsGrabFCBFromTable(DeviceExt, MftIdToName[MftId]);
216c2c66affSColin Finck     if (FCB == NULL)
217c2c66affSColin Finck     {
218c2c66affSColin Finck         UNICODE_STRING Name;
219c2c66affSColin Finck 
220c2c66affSColin Finck         RtlInitUnicodeString(&Name, MftIdToName[MftId]);
221c2c66affSColin Finck         Status = NtfsMakeFCBFromDirEntry(DeviceExt, NULL, &Name, NULL, MftRecord, MftId, &FCB);
222c2c66affSColin Finck         if (!NT_SUCCESS(Status))
223c2c66affSColin Finck         {
224c2c66affSColin Finck             ExFreePoolWithTag(MftRecord, TAG_NTFS);
225c2c66affSColin Finck             return Status;
226c2c66affSColin Finck         }
227c2c66affSColin Finck     }
228c2c66affSColin Finck 
229c2c66affSColin Finck     ASSERT(FCB != NULL);
230c2c66affSColin Finck 
231c2c66affSColin Finck     ExFreePoolWithTag(MftRecord, TAG_NTFS);
232c2c66affSColin Finck 
233c2c66affSColin Finck     Status = NtfsAttachFCBToFileObject(DeviceExt,
234c2c66affSColin Finck                                        FCB,
235c2c66affSColin Finck                                        FileObject);
236c2c66affSColin Finck     *FoundFCB = FCB;
237c2c66affSColin Finck 
238c2c66affSColin Finck     return Status;
239c2c66affSColin Finck }
240c2c66affSColin Finck 
241c2c66affSColin Finck /*
242c2c66affSColin Finck  * FUNCTION: Opens a file
243c2c66affSColin Finck  */
244c2c66affSColin Finck static
245c2c66affSColin Finck NTSTATUS
246c2c66affSColin Finck NtfsOpenFile(PDEVICE_EXTENSION DeviceExt,
247c2c66affSColin Finck              PFILE_OBJECT FileObject,
248c2c66affSColin Finck              PWSTR FileName,
249c2c66affSColin Finck              PNTFS_FCB * FoundFCB)
250c2c66affSColin Finck {
251c2c66affSColin Finck     PNTFS_FCB ParentFcb;
252c2c66affSColin Finck     PNTFS_FCB Fcb;
253c2c66affSColin Finck     NTSTATUS Status;
254c2c66affSColin Finck     PWSTR AbsFileName = NULL;
255c2c66affSColin Finck 
256c2c66affSColin Finck     DPRINT1("NtfsOpenFile(%p, %p, %S, %p)\n", DeviceExt, FileObject, FileName, FoundFCB);
257c2c66affSColin Finck 
258c2c66affSColin Finck     *FoundFCB = NULL;
259c2c66affSColin Finck 
260c2c66affSColin Finck     if (FileObject->RelatedFileObject)
261c2c66affSColin Finck     {
262c2c66affSColin Finck         DPRINT("Converting relative filename to absolute filename\n");
263c2c66affSColin Finck 
264c2c66affSColin Finck         Status = NtfsMakeAbsoluteFilename(FileObject->RelatedFileObject,
265c2c66affSColin Finck                                           FileName,
266c2c66affSColin Finck                                           &AbsFileName);
267c2c66affSColin Finck         if (AbsFileName) FileName = AbsFileName;
268c2c66affSColin Finck         if (!NT_SUCCESS(Status))
269c2c66affSColin Finck         {
270c2c66affSColin Finck             return Status;
271c2c66affSColin Finck         }
272c2c66affSColin Finck     }
273c2c66affSColin Finck 
274c2c66affSColin Finck     //FIXME: Get canonical path name (remove .'s, ..'s and extra separators)
275c2c66affSColin Finck 
276c2c66affSColin Finck     DPRINT("PathName to open: %S\n", FileName);
277c2c66affSColin Finck 
278c2c66affSColin Finck     /*  try first to find an existing FCB in memory  */
279c2c66affSColin Finck     DPRINT("Checking for existing FCB in memory\n");
280c2c66affSColin Finck     Fcb = NtfsGrabFCBFromTable(DeviceExt,
281c2c66affSColin Finck                                FileName);
282c2c66affSColin Finck     if (Fcb == NULL)
283c2c66affSColin Finck     {
284c2c66affSColin Finck         DPRINT("No existing FCB found, making a new one if file exists.\n");
285c2c66affSColin Finck         Status = NtfsGetFCBForFile(DeviceExt,
286c2c66affSColin Finck                                    &ParentFcb,
287c2c66affSColin Finck                                    &Fcb,
288c2c66affSColin Finck                                    FileName);
289c2c66affSColin Finck         if (ParentFcb != NULL)
290c2c66affSColin Finck         {
291c2c66affSColin Finck             NtfsReleaseFCB(DeviceExt,
292c2c66affSColin Finck                            ParentFcb);
293c2c66affSColin Finck         }
294c2c66affSColin Finck 
295c2c66affSColin Finck         if (!NT_SUCCESS (Status))
296c2c66affSColin Finck         {
297c2c66affSColin Finck             DPRINT("Could not make a new FCB, status: %x\n", Status);
298c2c66affSColin Finck 
299c2c66affSColin Finck             if (AbsFileName)
300c2c66affSColin Finck                 ExFreePool(AbsFileName);
301c2c66affSColin Finck 
302c2c66affSColin Finck             return Status;
303c2c66affSColin Finck         }
304c2c66affSColin Finck     }
305c2c66affSColin Finck 
306c2c66affSColin Finck     DPRINT("Attaching FCB to fileObject\n");
307c2c66affSColin Finck     Status = NtfsAttachFCBToFileObject(DeviceExt,
308c2c66affSColin Finck                                        Fcb,
309c2c66affSColin Finck                                        FileObject);
310c2c66affSColin Finck 
311c2c66affSColin Finck     if (AbsFileName)
312c2c66affSColin Finck         ExFreePool(AbsFileName);
313c2c66affSColin Finck 
314c2c66affSColin Finck     *FoundFCB = Fcb;
315c2c66affSColin Finck 
316c2c66affSColin Finck     return Status;
317c2c66affSColin Finck }
318c2c66affSColin Finck 
319c2c66affSColin Finck 
320c2c66affSColin Finck /*
321c2c66affSColin Finck  * FUNCTION: Opens a file
322c2c66affSColin Finck  */
323c2c66affSColin Finck static
324c2c66affSColin Finck NTSTATUS
325c2c66affSColin Finck NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
326c2c66affSColin Finck                PIRP Irp)
327c2c66affSColin Finck {
328c2c66affSColin Finck     PDEVICE_EXTENSION DeviceExt;
329c2c66affSColin Finck     PIO_STACK_LOCATION Stack;
330c2c66affSColin Finck     PFILE_OBJECT FileObject;
331c2c66affSColin Finck     ULONG RequestedDisposition;
332c2c66affSColin Finck     ULONG RequestedOptions;
333c2c66affSColin Finck     PNTFS_FCB Fcb = NULL;
334c2c66affSColin Finck //    PWSTR FileName;
335c2c66affSColin Finck     NTSTATUS Status;
336c2c66affSColin Finck     UNICODE_STRING FullPath;
337c2c66affSColin Finck 
338c2c66affSColin Finck     DPRINT1("NtfsCreateFile(%p, %p) called\n", DeviceObject, Irp);
339c2c66affSColin Finck 
340c2c66affSColin Finck     DeviceExt = DeviceObject->DeviceExtension;
341c2c66affSColin Finck     ASSERT(DeviceExt);
342c2c66affSColin Finck     Stack = IoGetCurrentIrpStackLocation (Irp);
343c2c66affSColin Finck     ASSERT(Stack);
344c2c66affSColin Finck 
345c2c66affSColin Finck     RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
346c2c66affSColin Finck     RequestedOptions = Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
347c2c66affSColin Finck //  PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
348c2c66affSColin Finck     if (RequestedOptions & FILE_DIRECTORY_FILE &&
349c2c66affSColin Finck         RequestedDisposition == FILE_SUPERSEDE)
350c2c66affSColin Finck     {
351c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
352c2c66affSColin Finck     }
353c2c66affSColin Finck 
354c2c66affSColin Finck     /* Deny create if the volume is locked */
355c2c66affSColin Finck     if (DeviceExt->Flags & VCB_VOLUME_LOCKED)
356c2c66affSColin Finck     {
357c2c66affSColin Finck         return STATUS_ACCESS_DENIED;
358c2c66affSColin Finck     }
359c2c66affSColin Finck 
360c2c66affSColin Finck     FileObject = Stack->FileObject;
361c2c66affSColin Finck 
362c2c66affSColin Finck     if ((RequestedOptions & FILE_OPEN_BY_FILE_ID) == FILE_OPEN_BY_FILE_ID)
363c2c66affSColin Finck     {
364c2c66affSColin Finck         ULONGLONG MFTId;
365c2c66affSColin Finck 
366c2c66affSColin Finck         if (FileObject->FileName.Length != sizeof(ULONGLONG))
367c2c66affSColin Finck             return STATUS_INVALID_PARAMETER;
368c2c66affSColin Finck 
369c2c66affSColin Finck         MFTId = (*(PULONGLONG)FileObject->FileName.Buffer) & NTFS_MFT_MASK;
370c2c66affSColin Finck         if (MFTId < 0x10)
371c2c66affSColin Finck         {
372c2c66affSColin Finck             Status = NtfsOpenFileById(DeviceExt, FileObject, MFTId, &Fcb);
373c2c66affSColin Finck         }
374c2c66affSColin Finck         else
375c2c66affSColin Finck         {
376c2c66affSColin Finck             Status = NtfsMoonWalkID(DeviceExt, MFTId, &FullPath);
377c2c66affSColin Finck         }
378c2c66affSColin Finck 
379c2c66affSColin Finck         if (!NT_SUCCESS(Status))
380c2c66affSColin Finck         {
381c2c66affSColin Finck             return Status;
382c2c66affSColin Finck         }
383c2c66affSColin Finck 
384c2c66affSColin Finck         DPRINT1("Open by ID: %I64x -> %wZ\n", (*(PULONGLONG)FileObject->FileName.Buffer) & NTFS_MFT_MASK, &FullPath);
385c2c66affSColin Finck     }
386c2c66affSColin Finck 
387c2c66affSColin Finck     /* This a open operation for the volume itself */
388c2c66affSColin Finck     if (FileObject->FileName.Length == 0 &&
389c2c66affSColin Finck         (FileObject->RelatedFileObject == NULL || FileObject->RelatedFileObject->FsContext2 != NULL))
390c2c66affSColin Finck     {
391c2c66affSColin Finck         if (RequestedDisposition != FILE_OPEN &&
392c2c66affSColin Finck             RequestedDisposition != FILE_OPEN_IF)
393c2c66affSColin Finck         {
394c2c66affSColin Finck             return STATUS_ACCESS_DENIED;
395c2c66affSColin Finck         }
396c2c66affSColin Finck 
397c2c66affSColin Finck         if (RequestedOptions & FILE_DIRECTORY_FILE)
398c2c66affSColin Finck         {
399c2c66affSColin Finck             return STATUS_NOT_A_DIRECTORY;
400c2c66affSColin Finck         }
401c2c66affSColin Finck 
402c2c66affSColin Finck         NtfsAttachFCBToFileObject(DeviceExt, DeviceExt->VolumeFcb, FileObject);
403c2c66affSColin Finck         DeviceExt->VolumeFcb->RefCount++;
404c2c66affSColin Finck 
405c2c66affSColin Finck         Irp->IoStatus.Information = FILE_OPENED;
406c2c66affSColin Finck         return STATUS_SUCCESS;
407c2c66affSColin Finck     }
408c2c66affSColin Finck 
409c2c66affSColin Finck     if (Fcb == NULL)
410c2c66affSColin Finck     {
411c2c66affSColin Finck         Status = NtfsOpenFile(DeviceExt,
412c2c66affSColin Finck                               FileObject,
413c2c66affSColin Finck                               ((RequestedOptions & FILE_OPEN_BY_FILE_ID) ? FullPath.Buffer : FileObject->FileName.Buffer),
414c2c66affSColin Finck                               &Fcb);
415c2c66affSColin Finck 
416c2c66affSColin Finck         if (RequestedOptions & FILE_OPEN_BY_FILE_ID)
417c2c66affSColin Finck         {
418c2c66affSColin Finck             ExFreePoolWithTag(FullPath.Buffer, TAG_NTFS);
419c2c66affSColin Finck         }
420c2c66affSColin Finck     }
421c2c66affSColin Finck 
422c2c66affSColin Finck     if (NT_SUCCESS(Status))
423c2c66affSColin Finck     {
424c2c66affSColin Finck         if (RequestedDisposition == FILE_CREATE)
425c2c66affSColin Finck         {
426c2c66affSColin Finck             Irp->IoStatus.Information = FILE_EXISTS;
427c2c66affSColin Finck             NtfsCloseFile(DeviceExt, FileObject);
428c2c66affSColin Finck             return STATUS_OBJECT_NAME_COLLISION;
429c2c66affSColin Finck         }
430c2c66affSColin Finck 
431c2c66affSColin Finck         if (RequestedOptions & FILE_NON_DIRECTORY_FILE &&
432c2c66affSColin Finck             NtfsFCBIsDirectory(Fcb))
433c2c66affSColin Finck         {
434c2c66affSColin Finck             NtfsCloseFile(DeviceExt, FileObject);
435c2c66affSColin Finck             return STATUS_FILE_IS_A_DIRECTORY;
436c2c66affSColin Finck         }
437c2c66affSColin Finck 
438c2c66affSColin Finck         if (RequestedOptions & FILE_DIRECTORY_FILE &&
439c2c66affSColin Finck             !NtfsFCBIsDirectory(Fcb))
440c2c66affSColin Finck         {
441c2c66affSColin Finck             NtfsCloseFile(DeviceExt, FileObject);
442c2c66affSColin Finck             return STATUS_NOT_A_DIRECTORY;
443c2c66affSColin Finck         }
444c2c66affSColin Finck 
445c2c66affSColin Finck         /*
446c2c66affSColin Finck          * If it is a reparse point & FILE_OPEN_REPARSE_POINT, then allow opening it
447c2c66affSColin Finck          * as a normal file.
448c2c66affSColin Finck          * Otherwise, attempt to read reparse data and hand them to the Io manager
449c2c66affSColin Finck          * with status reparse to force a reparse.
450c2c66affSColin Finck          */
451c2c66affSColin Finck         if (NtfsFCBIsReparsePoint(Fcb) &&
452c2c66affSColin Finck             ((RequestedOptions & FILE_OPEN_REPARSE_POINT) != FILE_OPEN_REPARSE_POINT))
453c2c66affSColin Finck         {
454c2c66affSColin Finck             PREPARSE_DATA_BUFFER ReparseData = NULL;
455c2c66affSColin Finck 
456c2c66affSColin Finck             Status = NtfsReadFCBAttribute(DeviceExt, Fcb,
457c2c66affSColin Finck                                           AttributeReparsePoint, L"", 0,
458c2c66affSColin Finck                                           (PVOID *)&Irp->Tail.Overlay.AuxiliaryBuffer);
459c2c66affSColin Finck             if (NT_SUCCESS(Status))
460c2c66affSColin Finck             {
461c2c66affSColin Finck                 ReparseData = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
462c2c66affSColin Finck                 if (ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
463c2c66affSColin Finck                 {
464c2c66affSColin Finck                     Status = STATUS_REPARSE;
465c2c66affSColin Finck                 }
466c2c66affSColin Finck                 else
467c2c66affSColin Finck                 {
468c2c66affSColin Finck                     Status = STATUS_NOT_IMPLEMENTED;
469c2c66affSColin Finck                     ExFreePoolWithTag(ReparseData, TAG_NTFS);
470c2c66affSColin Finck                 }
471c2c66affSColin Finck             }
472c2c66affSColin Finck 
473c2c66affSColin Finck             Irp->IoStatus.Information = ((Status == STATUS_REPARSE) ? ReparseData->ReparseTag : 0);
474c2c66affSColin Finck 
475c2c66affSColin Finck             NtfsCloseFile(DeviceExt, FileObject);
476c2c66affSColin Finck             return Status;
477c2c66affSColin Finck         }
478c2c66affSColin Finck 
479c2c66affSColin Finck         if (RequestedDisposition == FILE_OVERWRITE ||
480c2c66affSColin Finck             RequestedDisposition == FILE_OVERWRITE_IF ||
481c2c66affSColin Finck             RequestedDisposition == FILE_SUPERSEDE)
482c2c66affSColin Finck         {
48384a1280fSTrevor Thompson             PFILE_RECORD_HEADER fileRecord = NULL;
48484a1280fSTrevor Thompson             PNTFS_ATTR_CONTEXT dataContext = NULL;
48584a1280fSTrevor Thompson             ULONG DataAttributeOffset;
48684a1280fSTrevor Thompson             LARGE_INTEGER Zero;
48784a1280fSTrevor Thompson             Zero.QuadPart = 0;
48884a1280fSTrevor Thompson 
489*037d8820STrevor Thompson             if (!NtfsGlobalData->EnableWriteSupport)
490*037d8820STrevor Thompson             {
491*037d8820STrevor Thompson                 DPRINT1("NTFS write-support is EXPERIMENTAL and is disabled by default!\n");
492*037d8820STrevor Thompson                 NtfsCloseFile(DeviceExt, FileObject);
493*037d8820STrevor Thompson                 return STATUS_ACCESS_DENIED;
494*037d8820STrevor Thompson             }
495*037d8820STrevor Thompson 
49684a1280fSTrevor Thompson             // TODO: check for appropriate access
49784a1280fSTrevor Thompson 
49884a1280fSTrevor Thompson             ExAcquireResourceExclusiveLite(&(Fcb->MainResource), TRUE);
49984a1280fSTrevor Thompson 
50084a1280fSTrevor Thompson             fileRecord = ExAllocatePoolWithTag(NonPagedPool,
50184a1280fSTrevor Thompson                                                Fcb->Vcb->NtfsInfo.BytesPerFileRecord,
50284a1280fSTrevor Thompson                                                TAG_NTFS);
50384a1280fSTrevor Thompson             if (fileRecord)
50484a1280fSTrevor Thompson             {
50584a1280fSTrevor Thompson 
50684a1280fSTrevor Thompson                 Status = ReadFileRecord(Fcb->Vcb,
50784a1280fSTrevor Thompson                                         Fcb->MFTIndex,
50884a1280fSTrevor Thompson                                         fileRecord);
50984a1280fSTrevor Thompson                 if (!NT_SUCCESS(Status))
51084a1280fSTrevor Thompson                     goto DoneOverwriting;
51184a1280fSTrevor Thompson 
51284a1280fSTrevor Thompson                 // find the data attribute and set it's length to 0 (TODO: Handle Alternate Data Streams)
51384a1280fSTrevor Thompson                 Status = FindAttribute(Fcb->Vcb, fileRecord, AttributeData, L"", 0, &dataContext, &DataAttributeOffset);
51484a1280fSTrevor Thompson                 if (!NT_SUCCESS(Status))
51584a1280fSTrevor Thompson                     goto DoneOverwriting;
51684a1280fSTrevor Thompson 
51784a1280fSTrevor Thompson                 Status = SetAttributeDataLength(FileObject, Fcb, dataContext, DataAttributeOffset, fileRecord, &Zero);
51884a1280fSTrevor Thompson             }
51984a1280fSTrevor Thompson             else
52084a1280fSTrevor Thompson             {
52184a1280fSTrevor Thompson                 Status = STATUS_NO_MEMORY;
52284a1280fSTrevor Thompson             }
52384a1280fSTrevor Thompson 
52484a1280fSTrevor Thompson         DoneOverwriting:
52584a1280fSTrevor Thompson             if (fileRecord)
52684a1280fSTrevor Thompson                 ExFreePool(fileRecord);
52784a1280fSTrevor Thompson             if (dataContext)
52884a1280fSTrevor Thompson                 ReleaseAttributeContext(dataContext);
52984a1280fSTrevor Thompson 
53084a1280fSTrevor Thompson             ExReleaseResourceLite(&(Fcb->MainResource));
53184a1280fSTrevor Thompson 
53284a1280fSTrevor Thompson             if (!NT_SUCCESS(Status))
53384a1280fSTrevor Thompson             {
534c2c66affSColin Finck                 NtfsCloseFile(DeviceExt, FileObject);
53584a1280fSTrevor Thompson                 return Status;
53684a1280fSTrevor Thompson             }
53784a1280fSTrevor Thompson 
53884a1280fSTrevor Thompson             if (RequestedDisposition == FILE_SUPERSEDE)
53984a1280fSTrevor Thompson             {
54084a1280fSTrevor Thompson                 Irp->IoStatus.Information = FILE_SUPERSEDED;
54184a1280fSTrevor Thompson             }
54284a1280fSTrevor Thompson             else
54384a1280fSTrevor Thompson             {
54484a1280fSTrevor Thompson                 Irp->IoStatus.Information = FILE_OVERWRITTEN;
54584a1280fSTrevor Thompson             }
546c2c66affSColin Finck         }
547c2c66affSColin Finck     }
548c2c66affSColin Finck     else
549c2c66affSColin Finck     {
55058a13831STrevor Thompson         /* HUGLY HACK: Can't create new files yet... */
551c2c66affSColin Finck         if (RequestedDisposition == FILE_CREATE ||
552c2c66affSColin Finck             RequestedDisposition == FILE_OPEN_IF ||
553c2c66affSColin Finck             RequestedDisposition == FILE_OVERWRITE_IF ||
554c2c66affSColin Finck             RequestedDisposition == FILE_SUPERSEDE)
555c2c66affSColin Finck         {
556*037d8820STrevor Thompson             if (!NtfsGlobalData->EnableWriteSupport)
557*037d8820STrevor Thompson             {
558*037d8820STrevor Thompson                 DPRINT1("NTFS write-support is EXPERIMENTAL and is disabled by default!\n");
559*037d8820STrevor Thompson                 NtfsCloseFile(DeviceExt, FileObject);
560*037d8820STrevor Thompson                 return STATUS_ACCESS_DENIED;
561*037d8820STrevor Thompson             }
562*037d8820STrevor Thompson 
5630409b316STrevor Thompson             // Create the file record on disk
5640409b316STrevor Thompson             Status = NtfsCreateFileRecord(DeviceExt, FileObject);
5650409b316STrevor Thompson 
5660409b316STrevor Thompson             // Update the parent directory index
5670409b316STrevor Thompson             // Still TODO
5680409b316STrevor Thompson 
5690409b316STrevor Thompson             // Call NtfsOpenFile()
5700409b316STrevor Thompson 
57158a13831STrevor Thompson             return STATUS_CANNOT_MAKE;
572c2c66affSColin Finck         }
573c2c66affSColin Finck     }
574c2c66affSColin Finck 
575c2c66affSColin Finck     if (NT_SUCCESS(Status))
576c2c66affSColin Finck     {
577c2c66affSColin Finck         Fcb->OpenHandleCount++;
578c2c66affSColin Finck         DeviceExt->OpenHandleCount++;
579c2c66affSColin Finck     }
580c2c66affSColin Finck 
581c2c66affSColin Finck     /*
582c2c66affSColin Finck      * If the directory containing the file to open doesn't exist then
583c2c66affSColin Finck      * fail immediately
584c2c66affSColin Finck      */
585c2c66affSColin Finck     Irp->IoStatus.Information = (NT_SUCCESS(Status)) ? FILE_OPENED : 0;
586c2c66affSColin Finck 
587c2c66affSColin Finck     return Status;
588c2c66affSColin Finck }
589c2c66affSColin Finck 
590c2c66affSColin Finck 
591c2c66affSColin Finck NTSTATUS
592c2c66affSColin Finck NtfsCreate(PNTFS_IRP_CONTEXT IrpContext)
593c2c66affSColin Finck {
594c2c66affSColin Finck     PDEVICE_EXTENSION DeviceExt;
595c2c66affSColin Finck     NTSTATUS Status;
596c2c66affSColin Finck     PDEVICE_OBJECT DeviceObject;
597c2c66affSColin Finck 
598c2c66affSColin Finck     DeviceObject = IrpContext->DeviceObject;
599c2c66affSColin Finck     if (DeviceObject == NtfsGlobalData->DeviceObject)
600c2c66affSColin Finck     {
601c2c66affSColin Finck         /* DeviceObject represents FileSystem instead of logical volume */
602c2c66affSColin Finck         DPRINT("Opening file system\n");
603c2c66affSColin Finck         IrpContext->Irp->IoStatus.Information = FILE_OPENED;
604c2c66affSColin Finck         return STATUS_SUCCESS;
605c2c66affSColin Finck     }
606c2c66affSColin Finck 
607c2c66affSColin Finck     DeviceExt = DeviceObject->DeviceExtension;
608c2c66affSColin Finck 
609c2c66affSColin Finck     if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
610c2c66affSColin Finck     {
611c2c66affSColin Finck         return NtfsMarkIrpContextForQueue(IrpContext);
612c2c66affSColin Finck     }
613c2c66affSColin Finck 
614c2c66affSColin Finck     ExAcquireResourceExclusiveLite(&DeviceExt->DirResource,
615c2c66affSColin Finck                                    TRUE);
616c2c66affSColin Finck     Status = NtfsCreateFile(DeviceObject,
617c2c66affSColin Finck                             IrpContext->Irp);
618c2c66affSColin Finck     ExReleaseResourceLite(&DeviceExt->DirResource);
619c2c66affSColin Finck 
620c2c66affSColin Finck     return Status;
621c2c66affSColin Finck }
622c2c66affSColin Finck 
6230409b316STrevor Thompson /**
6240409b316STrevor Thompson * @name NtfsCreateFileRecord()
6250409b316STrevor Thompson * @implemented
6260409b316STrevor Thompson *
6270409b316STrevor Thompson * Creates a file record and saves it to the MFT.
6280409b316STrevor Thompson *
6290409b316STrevor Thompson * @param DeviceExt
6300409b316STrevor Thompson * Points to the target disk's DEVICE_EXTENSION
6310409b316STrevor Thompson *
6320409b316STrevor Thompson * @param FileObject
6330409b316STrevor Thompson * Pointer to a FILE_OBJECT describing the file to be created
6340409b316STrevor Thompson *
6350409b316STrevor Thompson * @return
6360409b316STrevor Thompson * STATUS_SUCCESS on success.
6370409b316STrevor Thompson * STATUS_INSUFFICIENT_RESOURCES if unable to allocate memory for the file record.
6380409b316STrevor Thompson */
6390409b316STrevor Thompson NTSTATUS
6400409b316STrevor Thompson NtfsCreateFileRecord(PDEVICE_EXTENSION DeviceExt,
6410409b316STrevor Thompson                      PFILE_OBJECT FileObject)
6420409b316STrevor Thompson {
6430409b316STrevor Thompson     NTSTATUS Status = STATUS_SUCCESS;
6440409b316STrevor Thompson     PFILE_RECORD_HEADER FileRecord;
6450409b316STrevor Thompson     PNTFS_ATTR_RECORD NextAttribute;
6460409b316STrevor Thompson 
6470409b316STrevor Thompson     // allocate memory for file record
6480409b316STrevor Thompson     FileRecord = ExAllocatePoolWithTag(NonPagedPool,
6490409b316STrevor Thompson                                        DeviceExt->NtfsInfo.BytesPerFileRecord,
6500409b316STrevor Thompson                                        TAG_NTFS);
6510409b316STrevor Thompson     if (!FileRecord)
6520409b316STrevor Thompson     {
6530409b316STrevor Thompson         DPRINT1("ERROR: Unable to allocate memory for file record!\n");
6540409b316STrevor Thompson         return STATUS_INSUFFICIENT_RESOURCES;
6550409b316STrevor Thompson     }
6560409b316STrevor Thompson 
6570409b316STrevor Thompson     RtlZeroMemory(FileRecord, DeviceExt->NtfsInfo.BytesPerFileRecord);
6580409b316STrevor Thompson 
6590409b316STrevor Thompson     FileRecord->Ntfs.Type = NRH_FILE_TYPE;
6600409b316STrevor Thompson 
6610409b316STrevor Thompson     // calculate USA offset and count
6620409b316STrevor Thompson     FileRecord->Ntfs.UsaOffset = FIELD_OFFSET(FILE_RECORD_HEADER, MFTRecordNumber) + sizeof(ULONG);
6630409b316STrevor Thompson 
6640409b316STrevor Thompson     // size of USA (in ULONG's) will be 1 (for USA number) + 1 for every sector the file record uses
6650409b316STrevor Thompson     FileRecord->BytesAllocated = DeviceExt->NtfsInfo.BytesPerFileRecord;
6660409b316STrevor Thompson     FileRecord->Ntfs.UsaCount = (FileRecord->BytesAllocated / DeviceExt->NtfsInfo.BytesPerSector) + 1;
6670409b316STrevor Thompson 
6680409b316STrevor Thompson     // setup other file record fields
6690409b316STrevor Thompson     FileRecord->SequenceNumber = 1;
6700409b316STrevor Thompson     FileRecord->AttributeOffset = FileRecord->Ntfs.UsaOffset + (2 * FileRecord->Ntfs.UsaCount);
6710409b316STrevor Thompson     FileRecord->AttributeOffset = ALIGN_UP_BY(FileRecord->AttributeOffset, 8);
6720409b316STrevor Thompson     FileRecord->Flags = FRH_IN_USE;
6730409b316STrevor Thompson     FileRecord->BytesInUse = FileRecord->AttributeOffset + sizeof(ULONG) * 2;
6740409b316STrevor Thompson 
6750409b316STrevor Thompson     // find where the first attribute will be added
6760409b316STrevor Thompson     NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)FileRecord + FileRecord->AttributeOffset);
6770409b316STrevor Thompson 
6780409b316STrevor Thompson     // mark the (temporary) end of the file-record
6790409b316STrevor Thompson     NextAttribute->Type = AttributeEnd;
6800409b316STrevor Thompson     NextAttribute->Length = FILE_RECORD_END;
6810409b316STrevor Thompson 
6820409b316STrevor Thompson     // add first attribute, $STANDARD_INFORMATION
6830409b316STrevor Thompson     AddStandardInformation(FileRecord, NextAttribute);
6840409b316STrevor Thompson 
6850409b316STrevor Thompson     // advance NextAttribute pointer to the next attribute
6860409b316STrevor Thompson     NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute + (ULONG_PTR)NextAttribute->Length);
6870409b316STrevor Thompson 
6880409b316STrevor Thompson     // Add the $FILE_NAME attribute
6890409b316STrevor Thompson     AddFileName(FileRecord, NextAttribute, DeviceExt, FileObject);
6900409b316STrevor Thompson 
6910409b316STrevor Thompson     // advance NextAttribute pointer to the next attribute
6920409b316STrevor Thompson     NextAttribute = (PNTFS_ATTR_RECORD)((ULONG_PTR)NextAttribute + (ULONG_PTR)NextAttribute->Length);
6930409b316STrevor Thompson 
6940409b316STrevor Thompson     // add the $DATA attribute
6950409b316STrevor Thompson     AddData(FileRecord, NextAttribute);
6960409b316STrevor Thompson 
6970409b316STrevor Thompson     // dump file record in memory (for debugging)
6980409b316STrevor Thompson     NtfsDumpFileRecord(DeviceExt, FileRecord);
6990409b316STrevor Thompson 
7000409b316STrevor Thompson     // Now that we've built the file record in memory, we need to store it in the MFT.
7010409b316STrevor Thompson     Status = AddNewMftEntry(FileRecord, DeviceExt);
7020409b316STrevor Thompson 
7030409b316STrevor Thompson     ExFreePoolWithTag(FileRecord, TAG_NTFS);
7040409b316STrevor Thompson 
7050409b316STrevor Thompson     return Status;
7060409b316STrevor Thompson }
7070409b316STrevor Thompson 
708c2c66affSColin Finck /* EOF */
709