* Sync up to trunk head (r65481).
[reactos.git] / drivers / filesystems / ntfs / create.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002, 2014 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 * COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystem/ntfs/create.c
22 * PURPOSE: NTFS filesystem driver
23 * PROGRAMMERS: Eric Kohl
24 * Pierre Schweitzer (pierre@reactos.org)
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include "ntfs.h"
30
31 #define NDEBUG
32 #include <debug.h>
33
34 /* FUNCTIONS ****************************************************************/
35
36 static
37 NTSTATUS
38 NtfsMakeAbsoluteFilename(PFILE_OBJECT pFileObject,
39 PWSTR pRelativeFileName,
40 PWSTR *pAbsoluteFilename)
41 {
42 PWSTR rcName;
43 PNTFS_FCB Fcb;
44
45 DPRINT("try related for %S\n", pRelativeFileName);
46 Fcb = pFileObject->FsContext;
47 ASSERT(Fcb);
48
49 /* verify related object is a directory and target name
50 don't start with \. */
51 if (NtfsFCBIsDirectory(Fcb) == FALSE ||
52 pRelativeFileName[0] == L'\\')
53 {
54 return STATUS_INVALID_PARAMETER;
55 }
56
57 /* construct absolute path name */
58 ASSERT(wcslen (Fcb->PathName) + 1 + wcslen (pRelativeFileName) + 1 <= MAX_PATH);
59 rcName = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH * sizeof(WCHAR), TAG_NTFS);
60 if (!rcName)
61 {
62 return STATUS_INSUFFICIENT_RESOURCES;
63 }
64
65 wcscpy(rcName, Fcb->PathName);
66 if (!NtfsFCBIsRoot(Fcb))
67 wcscat (rcName, L"\\");
68 wcscat (rcName, pRelativeFileName);
69 *pAbsoluteFilename = rcName;
70
71 return STATUS_SUCCESS;
72 }
73
74
75 /*
76 * FUNCTION: Opens a file
77 */
78 static
79 NTSTATUS
80 NtfsOpenFile(PDEVICE_EXTENSION DeviceExt,
81 PFILE_OBJECT FileObject,
82 PWSTR FileName,
83 PNTFS_FCB * FoundFCB)
84 {
85 PNTFS_FCB ParentFcb;
86 PNTFS_FCB Fcb;
87 NTSTATUS Status;
88 PWSTR AbsFileName = NULL;
89
90 DPRINT1("NtfsOpenFile(%p, %p, %S, %p)\n", DeviceExt, FileObject, FileName, FoundFCB);
91
92 *FoundFCB = NULL;
93
94 if (FileObject->RelatedFileObject)
95 {
96 DPRINT("Converting relative filename to absolute filename\n");
97
98 Status = NtfsMakeAbsoluteFilename(FileObject->RelatedFileObject,
99 FileName,
100 &AbsFileName);
101 FileName = AbsFileName;
102 if (!NT_SUCCESS(Status))
103 {
104 return Status;
105 }
106
107 return STATUS_UNSUCCESSFUL;
108 }
109
110 //FIXME: Get cannonical path name (remove .'s, ..'s and extra separators)
111
112 DPRINT("PathName to open: %S\n", FileName);
113
114 /* try first to find an existing FCB in memory */
115 DPRINT("Checking for existing FCB in memory\n");
116 Fcb = NtfsGrabFCBFromTable(DeviceExt,
117 FileName);
118 if (Fcb == NULL)
119 {
120 DPRINT("No existing FCB found, making a new one if file exists.\n");
121 Status = NtfsGetFCBForFile(DeviceExt,
122 &ParentFcb,
123 &Fcb,
124 FileName);
125 if (ParentFcb != NULL)
126 {
127 NtfsReleaseFCB(DeviceExt,
128 ParentFcb);
129 }
130
131 if (!NT_SUCCESS (Status))
132 {
133 DPRINT("Could not make a new FCB, status: %x\n", Status);
134
135 if (AbsFileName)
136 ExFreePool(AbsFileName);
137
138 return Status;
139 }
140 }
141
142 DPRINT("Attaching FCB to fileObject\n");
143 Status = NtfsAttachFCBToFileObject(DeviceExt,
144 Fcb,
145 FileObject);
146
147 if (AbsFileName)
148 ExFreePool(AbsFileName);
149
150 *FoundFCB = Fcb;
151
152 return Status;
153 }
154
155
156 /*
157 * FUNCTION: Opens a file
158 */
159 static
160 NTSTATUS
161 NtfsCreateFile(PDEVICE_OBJECT DeviceObject,
162 PIRP Irp)
163 {
164 PDEVICE_EXTENSION DeviceExt;
165 PIO_STACK_LOCATION Stack;
166 PFILE_OBJECT FileObject;
167 ULONG RequestedDisposition;
168 ULONG RequestedOptions;
169 PNTFS_FCB Fcb;
170 // PWSTR FileName;
171 NTSTATUS Status;
172
173 DPRINT1("NtfsCreateFile(%p, %p) called\n", DeviceObject, Irp);
174
175 DeviceExt = DeviceObject->DeviceExtension;
176 ASSERT(DeviceExt);
177 Stack = IoGetCurrentIrpStackLocation (Irp);
178 ASSERT(Stack);
179
180 RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
181 RequestedOptions = Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
182 // PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
183 if (RequestedOptions & FILE_DIRECTORY_FILE &&
184 RequestedDisposition == FILE_SUPERSEDE)
185 {
186 return STATUS_INVALID_PARAMETER;
187 }
188
189 FileObject = Stack->FileObject;
190
191 if (RequestedDisposition == FILE_CREATE ||
192 RequestedDisposition == FILE_OVERWRITE_IF ||
193 RequestedDisposition == FILE_SUPERSEDE)
194 {
195 return STATUS_ACCESS_DENIED;
196 }
197
198 /* This a open operation for the volume itself */
199 if (FileObject->FileName.Length == 0 &&
200 (FileObject->RelatedFileObject == NULL || FileObject->RelatedFileObject->FsContext2 != NULL))
201 {
202 if (RequestedDisposition != FILE_OPEN &&
203 RequestedDisposition != FILE_OPEN_IF)
204 {
205 return STATUS_ACCESS_DENIED;
206 }
207
208 if (RequestedOptions & FILE_DIRECTORY_FILE)
209 {
210 return STATUS_NOT_A_DIRECTORY;
211 }
212
213 NtfsAttachFCBToFileObject(DeviceExt, DeviceExt->VolumeFcb, FileObject);
214 DeviceExt->VolumeFcb->RefCount++;
215
216 Irp->IoStatus.Information = FILE_OPENED;
217 return STATUS_SUCCESS;
218 }
219
220 Status = NtfsOpenFile(DeviceExt,
221 FileObject,
222 FileObject->FileName.Buffer,
223 &Fcb);
224
225 if (NT_SUCCESS(Status))
226 {
227 if (RequestedDisposition == FILE_CREATE)
228 {
229 Irp->IoStatus.Information = FILE_EXISTS;
230 NtfsCloseFile(DeviceExt, FileObject);
231 return STATUS_OBJECT_NAME_COLLISION;
232 }
233
234 if (RequestedOptions & FILE_NON_DIRECTORY_FILE &&
235 NtfsFCBIsDirectory(Fcb))
236 {
237 NtfsCloseFile(DeviceExt, FileObject);
238 return STATUS_FILE_IS_A_DIRECTORY;
239 }
240
241 if (RequestedOptions & FILE_DIRECTORY_FILE &&
242 !NtfsFCBIsDirectory(Fcb))
243 {
244 NtfsCloseFile(DeviceExt, FileObject);
245 return STATUS_NOT_A_DIRECTORY;
246 }
247
248 /* HUGLY HACK: remain RO so far... */
249 if (RequestedDisposition == FILE_OVERWRITE ||
250 RequestedDisposition == FILE_OVERWRITE_IF ||
251 RequestedDisposition == FILE_SUPERSEDE)
252 {
253 DPRINT1("Denying write request on NTFS volume\n");
254 NtfsCloseFile(DeviceExt, FileObject);
255 return STATUS_ACCESS_DENIED;
256 }
257 }
258 else
259 {
260 /* HUGLY HACK: remain RO so far... */
261 if (RequestedDisposition == FILE_CREATE ||
262 RequestedDisposition == FILE_OPEN_IF ||
263 RequestedDisposition == FILE_OVERWRITE_IF ||
264 RequestedDisposition == FILE_SUPERSEDE)
265 {
266 DPRINT1("Denying write request on NTFS volume\n");
267 return STATUS_ACCESS_DENIED;
268 }
269 }
270
271 /*
272 * If the directory containing the file to open doesn't exist then
273 * fail immediately
274 */
275 Irp->IoStatus.Information = (NT_SUCCESS(Status)) ? FILE_OPENED : 0;
276 Irp->IoStatus.Status = Status;
277
278 return Status;
279 }
280
281
282 NTSTATUS
283 NTAPI
284 NtfsFsdCreate(PDEVICE_OBJECT DeviceObject,
285 PIRP Irp)
286 {
287 PDEVICE_EXTENSION DeviceExt;
288 NTSTATUS Status;
289
290 if (DeviceObject == NtfsGlobalData->DeviceObject)
291 {
292 /* DeviceObject represents FileSystem instead of logical volume */
293 DPRINT("Opening file system\n");
294 Irp->IoStatus.Information = FILE_OPENED;
295 Status = STATUS_SUCCESS;
296 goto ByeBye;
297 }
298
299 DeviceExt = DeviceObject->DeviceExtension;
300
301 FsRtlEnterFileSystem();
302 ExAcquireResourceExclusiveLite(&DeviceExt->DirResource,
303 TRUE);
304 Status = NtfsCreateFile(DeviceObject,
305 Irp);
306 ExReleaseResourceLite(&DeviceExt->DirResource);
307 FsRtlExitFileSystem();
308
309 ByeBye:
310 Irp->IoStatus.Status = Status;
311 IoCompleteRequest(Irp,
312 NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
313
314 return Status;
315 }
316
317 /* EOF */