xref: /reactos/drivers/filesystems/btrfs/create.c (revision eb7fbc25)
1c2c66affSColin Finck /* Copyright (c) Mark Harmstone 2016-17
2c2c66affSColin Finck  *
3c2c66affSColin Finck  * This file is part of WinBtrfs.
4c2c66affSColin Finck  *
5c2c66affSColin Finck  * WinBtrfs is free software: you can redistribute it and/or modify
6c2c66affSColin Finck  * it under the terms of the GNU Lesser General Public Licence as published by
7c2c66affSColin Finck  * the Free Software Foundation, either version 3 of the Licence, or
8c2c66affSColin Finck  * (at your option) any later version.
9c2c66affSColin Finck  *
10c2c66affSColin Finck  * WinBtrfs 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 Lesser General Public Licence for more details.
14c2c66affSColin Finck  *
15c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public Licence
16c2c66affSColin Finck  * along with WinBtrfs.  If not, see <http://www.gnu.org/licenses/>. */
17c2c66affSColin Finck 
18c2c66affSColin Finck #ifndef __REACTOS__
19c2c66affSColin Finck #include <sys/stat.h>
20c2c66affSColin Finck #endif /* __REACTOS__ */
21c2c66affSColin Finck #include "btrfs_drv.h"
22c2c66affSColin Finck #include <ntddstor.h>
23c2c66affSColin Finck 
24c2c66affSColin Finck extern PDEVICE_OBJECT master_devobj;
25c2c66affSColin Finck 
26*eb7fbc25SPierre Schweitzer static const WCHAR datastring[] = L"::$DATA";
27*eb7fbc25SPierre Schweitzer 
28*eb7fbc25SPierre Schweitzer // Windows 10
29*eb7fbc25SPierre Schweitzer #define ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED   0x0002
30*eb7fbc25SPierre Schweitzer #define ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT               0x0100
31*eb7fbc25SPierre Schweitzer #define ATOMIC_CREATE_ECP_OUT_FLAG_REPARSE_POINT_SET        0x0002
32*eb7fbc25SPierre Schweitzer 
33*eb7fbc25SPierre Schweitzer typedef struct _ATOMIC_CREATE_ECP_CONTEXT {
34*eb7fbc25SPierre Schweitzer     USHORT Size;
35*eb7fbc25SPierre Schweitzer     USHORT InFlags;
36*eb7fbc25SPierre Schweitzer     USHORT OutFlags;
37*eb7fbc25SPierre Schweitzer     USHORT ReparseBufferLength;
38*eb7fbc25SPierre Schweitzer     PREPARSE_DATA_BUFFER ReparseBuffer;
39*eb7fbc25SPierre Schweitzer     LONGLONG FileSize;
40*eb7fbc25SPierre Schweitzer     LONGLONG ValidDataLength;
41*eb7fbc25SPierre Schweitzer } ATOMIC_CREATE_ECP_CONTEXT, *PATOMIC_CREATE_ECP_CONTEXT;
42*eb7fbc25SPierre Schweitzer 
43*eb7fbc25SPierre Schweitzer static const GUID GUID_ECP_ATOMIC_CREATE = { 0x4720bd83, 0x52ac, 0x4104, { 0xa1, 0x30, 0xd1, 0xec, 0x6a, 0x8c, 0xc8, 0xe5 } };
44c2c66affSColin Finck 
45c2c66affSColin Finck fcb* create_fcb(device_extension* Vcb, POOL_TYPE pool_type) {
46c2c66affSColin Finck     fcb* fcb;
47c2c66affSColin Finck 
48c2c66affSColin Finck     if (pool_type == NonPagedPool) {
49c2c66affSColin Finck         fcb = ExAllocatePoolWithTag(pool_type, sizeof(struct _fcb), ALLOC_TAG);
50c2c66affSColin Finck         if (!fcb) {
51c2c66affSColin Finck             ERR("out of memory\n");
52c2c66affSColin Finck             return NULL;
53c2c66affSColin Finck         }
54c2c66affSColin Finck     } else {
55c2c66affSColin Finck         fcb = ExAllocateFromPagedLookasideList(&Vcb->fcb_lookaside);
56c2c66affSColin Finck         if (!fcb) {
57c2c66affSColin Finck             ERR("out of memory\n");
58c2c66affSColin Finck             return NULL;
59c2c66affSColin Finck         }
60c2c66affSColin Finck     }
61c2c66affSColin Finck 
62c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
63c2c66affSColin Finck     WARN("allocating fcb %p\n", fcb);
64c2c66affSColin Finck #endif
65c2c66affSColin Finck     RtlZeroMemory(fcb, sizeof(struct _fcb));
66c2c66affSColin Finck     fcb->pool_type = pool_type;
67c2c66affSColin Finck 
68c2c66affSColin Finck     fcb->Header.NodeTypeCode = BTRFS_NODE_TYPE_FCB;
69c2c66affSColin Finck     fcb->Header.NodeByteSize = sizeof(struct _fcb);
70c2c66affSColin Finck 
71c2c66affSColin Finck     fcb->nonpaged = ExAllocateFromNPagedLookasideList(&Vcb->fcb_np_lookaside);
72c2c66affSColin Finck     if (!fcb->nonpaged) {
73c2c66affSColin Finck         ERR("out of memory\n");
74c2c66affSColin Finck 
75c2c66affSColin Finck         if (pool_type == NonPagedPool)
76c2c66affSColin Finck             ExFreePool(fcb);
77c2c66affSColin Finck         else
78c2c66affSColin Finck             ExFreeToPagedLookasideList(&Vcb->fcb_lookaside, fcb);
79c2c66affSColin Finck 
80c2c66affSColin Finck         return NULL;
81c2c66affSColin Finck     }
82c2c66affSColin Finck     RtlZeroMemory(fcb->nonpaged, sizeof(struct _fcb_nonpaged));
83c2c66affSColin Finck 
84c2c66affSColin Finck     ExInitializeResourceLite(&fcb->nonpaged->paging_resource);
85c2c66affSColin Finck     fcb->Header.PagingIoResource = &fcb->nonpaged->paging_resource;
86c2c66affSColin Finck 
87c2c66affSColin Finck     ExInitializeFastMutex(&fcb->nonpaged->HeaderMutex);
88c2c66affSColin Finck     FsRtlSetupAdvancedHeader(&fcb->Header, &fcb->nonpaged->HeaderMutex);
89c2c66affSColin Finck 
90c2c66affSColin Finck     fcb->refcount = 1;
91c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
92c2c66affSColin Finck     WARN("fcb %p: refcount now %i\n", fcb, fcb->refcount);
93c2c66affSColin Finck #endif
94c2c66affSColin Finck 
95c2c66affSColin Finck     ExInitializeResourceLite(&fcb->nonpaged->resource);
96c2c66affSColin Finck     fcb->Header.Resource = &fcb->nonpaged->resource;
97c2c66affSColin Finck 
98c2c66affSColin Finck     ExInitializeResourceLite(&fcb->nonpaged->dir_children_lock);
99c2c66affSColin Finck 
100c2c66affSColin Finck     FsRtlInitializeFileLock(&fcb->lock, NULL, NULL);
101c2c66affSColin Finck 
102c2c66affSColin Finck     InitializeListHead(&fcb->extents);
103c2c66affSColin Finck     InitializeListHead(&fcb->hardlinks);
104c2c66affSColin Finck     InitializeListHead(&fcb->xattrs);
105c2c66affSColin Finck 
106c2c66affSColin Finck     InitializeListHead(&fcb->dir_children_index);
107c2c66affSColin Finck     InitializeListHead(&fcb->dir_children_hash);
108c2c66affSColin Finck     InitializeListHead(&fcb->dir_children_hash_uc);
109c2c66affSColin Finck 
110c2c66affSColin Finck     return fcb;
111c2c66affSColin Finck }
112c2c66affSColin Finck 
113c2c66affSColin Finck file_ref* create_fileref(device_extension* Vcb) {
114c2c66affSColin Finck     file_ref* fr;
115c2c66affSColin Finck 
116c2c66affSColin Finck     fr = ExAllocateFromPagedLookasideList(&Vcb->fileref_lookaside);
117c2c66affSColin Finck     if (!fr) {
118c2c66affSColin Finck         ERR("out of memory\n");
119c2c66affSColin Finck         return NULL;
120c2c66affSColin Finck     }
121c2c66affSColin Finck 
122c2c66affSColin Finck     RtlZeroMemory(fr, sizeof(file_ref));
123c2c66affSColin Finck 
124c2c66affSColin Finck     fr->nonpaged = ExAllocateFromNPagedLookasideList(&Vcb->fileref_np_lookaside);
125c2c66affSColin Finck     if (!fr->nonpaged) {
126c2c66affSColin Finck         ERR("out of memory\n");
127c2c66affSColin Finck         ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, fr);
128c2c66affSColin Finck         return NULL;
129c2c66affSColin Finck     }
130c2c66affSColin Finck 
131c2c66affSColin Finck     fr->refcount = 1;
132c2c66affSColin Finck 
133c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
134c2c66affSColin Finck     WARN("fileref %p: refcount now 1\n", fr);
135c2c66affSColin Finck #endif
136c2c66affSColin Finck 
137c2c66affSColin Finck     InitializeListHead(&fr->children);
138c2c66affSColin Finck 
139c2c66affSColin Finck     ExInitializeResourceLite(&fr->nonpaged->fileref_lock);
140c2c66affSColin Finck     ExInitializeResourceLite(&fr->nonpaged->children_lock);
141c2c66affSColin Finck 
142c2c66affSColin Finck     return fr;
143c2c66affSColin Finck }
144c2c66affSColin Finck 
145c2c66affSColin Finck NTSTATUS find_file_in_dir(PUNICODE_STRING filename, fcb* fcb, root** subvol, UINT64* inode, dir_child** pdc, BOOL case_sensitive) {
146c2c66affSColin Finck     NTSTATUS Status;
147c2c66affSColin Finck     UNICODE_STRING fnus;
148c2c66affSColin Finck     UINT32 hash;
149c2c66affSColin Finck     LIST_ENTRY* le;
150c2c66affSColin Finck     UINT8 c;
151c2c66affSColin Finck     BOOL locked = FALSE;
152c2c66affSColin Finck 
153c2c66affSColin Finck     if (!case_sensitive) {
154c2c66affSColin Finck         Status = RtlUpcaseUnicodeString(&fnus, filename, TRUE);
155c2c66affSColin Finck 
156c2c66affSColin Finck         if (!NT_SUCCESS(Status)) {
157c2c66affSColin Finck             ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
158c2c66affSColin Finck             return Status;
159c2c66affSColin Finck         }
160c2c66affSColin Finck     } else
161c2c66affSColin Finck         fnus = *filename;
162c2c66affSColin Finck 
163c2c66affSColin Finck     hash = calc_crc32c(0xffffffff, (UINT8*)fnus.Buffer, fnus.Length);
164c2c66affSColin Finck 
165c2c66affSColin Finck     c = hash >> 24;
166c2c66affSColin Finck 
167c2c66affSColin Finck     if (!ExIsResourceAcquiredSharedLite(&fcb->nonpaged->dir_children_lock)) {
168c2c66affSColin Finck         ExAcquireResourceSharedLite(&fcb->nonpaged->dir_children_lock, TRUE);
169c2c66affSColin Finck         locked = TRUE;
170c2c66affSColin Finck     }
171c2c66affSColin Finck 
172c2c66affSColin Finck     if (case_sensitive) {
173c2c66affSColin Finck         if (!fcb->hash_ptrs[c]) {
174c2c66affSColin Finck             Status = STATUS_OBJECT_NAME_NOT_FOUND;
175c2c66affSColin Finck             goto end;
176c2c66affSColin Finck         }
177c2c66affSColin Finck 
178c2c66affSColin Finck         le = fcb->hash_ptrs[c];
179c2c66affSColin Finck         while (le != &fcb->dir_children_hash) {
180c2c66affSColin Finck             dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_hash);
181c2c66affSColin Finck 
182c2c66affSColin Finck             if (dc->hash == hash) {
183c2c66affSColin Finck                 if (dc->name.Length == fnus.Length && RtlCompareMemory(dc->name.Buffer, fnus.Buffer, fnus.Length) == fnus.Length) {
184c2c66affSColin Finck                     if (dc->key.obj_type == TYPE_ROOT_ITEM) {
185c2c66affSColin Finck                         LIST_ENTRY* le2;
186c2c66affSColin Finck 
187c2c66affSColin Finck                         *subvol = NULL;
188c2c66affSColin Finck 
189c2c66affSColin Finck                         le2 = fcb->Vcb->roots.Flink;
190c2c66affSColin Finck                         while (le2 != &fcb->Vcb->roots) {
191c2c66affSColin Finck                             root* r2 = CONTAINING_RECORD(le2, root, list_entry);
192c2c66affSColin Finck 
193c2c66affSColin Finck                             if (r2->id == dc->key.obj_id) {
194c2c66affSColin Finck                                 *subvol = r2;
195c2c66affSColin Finck                                 break;
196c2c66affSColin Finck                             }
197c2c66affSColin Finck 
198c2c66affSColin Finck                             le2 = le2->Flink;
199c2c66affSColin Finck                         }
200c2c66affSColin Finck 
201c2c66affSColin Finck                         *inode = SUBVOL_ROOT_INODE;
202c2c66affSColin Finck                     } else {
203c2c66affSColin Finck                         *subvol = fcb->subvol;
204c2c66affSColin Finck                         *inode = dc->key.obj_id;
205c2c66affSColin Finck                     }
206c2c66affSColin Finck 
207c2c66affSColin Finck                     *pdc = dc;
208c2c66affSColin Finck 
209c2c66affSColin Finck                     Status = STATUS_SUCCESS;
210c2c66affSColin Finck                     goto end;
211c2c66affSColin Finck                 }
212c2c66affSColin Finck             } else if (dc->hash > hash) {
213c2c66affSColin Finck                 Status = STATUS_OBJECT_NAME_NOT_FOUND;
214c2c66affSColin Finck                 goto end;
215c2c66affSColin Finck             }
216c2c66affSColin Finck 
217c2c66affSColin Finck             le = le->Flink;
218c2c66affSColin Finck         }
219c2c66affSColin Finck     } else {
220c2c66affSColin Finck         if (!fcb->hash_ptrs_uc[c]) {
221c2c66affSColin Finck             Status = STATUS_OBJECT_NAME_NOT_FOUND;
222c2c66affSColin Finck             goto end;
223c2c66affSColin Finck         }
224c2c66affSColin Finck 
225c2c66affSColin Finck         le = fcb->hash_ptrs_uc[c];
226c2c66affSColin Finck         while (le != &fcb->dir_children_hash_uc) {
227c2c66affSColin Finck             dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_hash_uc);
228c2c66affSColin Finck 
229c2c66affSColin Finck             if (dc->hash_uc == hash) {
230c2c66affSColin Finck                 if (dc->name_uc.Length == fnus.Length && RtlCompareMemory(dc->name_uc.Buffer, fnus.Buffer, fnus.Length) == fnus.Length) {
231c2c66affSColin Finck                     if (dc->key.obj_type == TYPE_ROOT_ITEM) {
232c2c66affSColin Finck                         LIST_ENTRY* le2;
233c2c66affSColin Finck 
234c2c66affSColin Finck                         *subvol = NULL;
235c2c66affSColin Finck 
236c2c66affSColin Finck                         le2 = fcb->Vcb->roots.Flink;
237c2c66affSColin Finck                         while (le2 != &fcb->Vcb->roots) {
238c2c66affSColin Finck                             root* r2 = CONTAINING_RECORD(le2, root, list_entry);
239c2c66affSColin Finck 
240c2c66affSColin Finck                             if (r2->id == dc->key.obj_id) {
241c2c66affSColin Finck                                 *subvol = r2;
242c2c66affSColin Finck                                 break;
243c2c66affSColin Finck                             }
244c2c66affSColin Finck 
245c2c66affSColin Finck                             le2 = le2->Flink;
246c2c66affSColin Finck                         }
247c2c66affSColin Finck 
248c2c66affSColin Finck                         *inode = SUBVOL_ROOT_INODE;
249c2c66affSColin Finck                     } else {
250c2c66affSColin Finck                         *subvol = fcb->subvol;
251c2c66affSColin Finck                         *inode = dc->key.obj_id;
252c2c66affSColin Finck                     }
253c2c66affSColin Finck 
254c2c66affSColin Finck                     *pdc = dc;
255c2c66affSColin Finck 
256c2c66affSColin Finck                     Status = STATUS_SUCCESS;
257c2c66affSColin Finck                     goto end;
258c2c66affSColin Finck                 }
259c2c66affSColin Finck             } else if (dc->hash_uc > hash) {
260c2c66affSColin Finck                 Status = STATUS_OBJECT_NAME_NOT_FOUND;
261c2c66affSColin Finck                 goto end;
262c2c66affSColin Finck             }
263c2c66affSColin Finck 
264c2c66affSColin Finck             le = le->Flink;
265c2c66affSColin Finck         }
266c2c66affSColin Finck     }
267c2c66affSColin Finck 
268c2c66affSColin Finck     Status = STATUS_OBJECT_NAME_NOT_FOUND;
269c2c66affSColin Finck 
270c2c66affSColin Finck end:
271c2c66affSColin Finck     if (locked)
272c2c66affSColin Finck         ExReleaseResourceLite(&fcb->nonpaged->dir_children_lock);
273c2c66affSColin Finck 
274c2c66affSColin Finck     if (!case_sensitive)
275c2c66affSColin Finck         ExFreePool(fnus.Buffer);
276c2c66affSColin Finck 
277c2c66affSColin Finck     return Status;
278c2c66affSColin Finck }
279c2c66affSColin Finck 
280c2c66affSColin Finck static NTSTATUS split_path(device_extension* Vcb, PUNICODE_STRING path, LIST_ENTRY* parts, BOOL* stream) {
281c2c66affSColin Finck     ULONG len, i;
282c2c66affSColin Finck     BOOL has_stream;
283c2c66affSColin Finck     WCHAR* buf;
284c2c66affSColin Finck     name_bit* nb;
285c2c66affSColin Finck 
286c2c66affSColin Finck     len = path->Length / sizeof(WCHAR);
287c2c66affSColin Finck     if (len > 0 && (path->Buffer[len - 1] == '/' || path->Buffer[len - 1] == '\\'))
288c2c66affSColin Finck         len--;
289c2c66affSColin Finck 
290c2c66affSColin Finck     has_stream = FALSE;
291c2c66affSColin Finck     for (i = 0; i < len; i++) {
292c2c66affSColin Finck         if (path->Buffer[i] == '/' || path->Buffer[i] == '\\') {
293c2c66affSColin Finck             has_stream = FALSE;
294c2c66affSColin Finck         } else if (path->Buffer[i] == ':') {
295c2c66affSColin Finck             has_stream = TRUE;
296c2c66affSColin Finck         }
297c2c66affSColin Finck     }
298c2c66affSColin Finck 
299c2c66affSColin Finck     buf = path->Buffer;
300c2c66affSColin Finck 
301c2c66affSColin Finck     for (i = 0; i < len; i++) {
302c2c66affSColin Finck         if (path->Buffer[i] == '/' || path->Buffer[i] == '\\') {
303c2c66affSColin Finck             nb = ExAllocateFromPagedLookasideList(&Vcb->name_bit_lookaside);
304c2c66affSColin Finck             if (!nb) {
305c2c66affSColin Finck                 ERR("out of memory\n");
306c2c66affSColin Finck                 return STATUS_INSUFFICIENT_RESOURCES;
307c2c66affSColin Finck             }
308c2c66affSColin Finck 
309c2c66affSColin Finck             nb->us.Buffer = buf;
310c2c66affSColin Finck             nb->us.Length = nb->us.MaximumLength = (USHORT)(&path->Buffer[i] - buf) * sizeof(WCHAR);
311c2c66affSColin Finck             InsertTailList(parts, &nb->list_entry);
312c2c66affSColin Finck 
313c2c66affSColin Finck             buf = &path->Buffer[i+1];
314c2c66affSColin Finck         }
315c2c66affSColin Finck     }
316c2c66affSColin Finck 
317c2c66affSColin Finck     nb = ExAllocateFromPagedLookasideList(&Vcb->name_bit_lookaside);
318c2c66affSColin Finck     if (!nb) {
319c2c66affSColin Finck         ERR("out of memory\n");
320c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
321c2c66affSColin Finck     }
322c2c66affSColin Finck 
323c2c66affSColin Finck     nb->us.Buffer = buf;
324c2c66affSColin Finck     nb->us.Length = nb->us.MaximumLength = (USHORT)(&path->Buffer[i] - buf) * sizeof(WCHAR);
325c2c66affSColin Finck     InsertTailList(parts, &nb->list_entry);
326c2c66affSColin Finck 
327c2c66affSColin Finck     if (has_stream) {
328*eb7fbc25SPierre Schweitzer         static const WCHAR datasuf[] = {':','$','D','A','T','A',0};
329c2c66affSColin Finck         UNICODE_STRING dsus;
330c2c66affSColin Finck 
331*eb7fbc25SPierre Schweitzer         dsus.Buffer = (WCHAR*)datasuf;
332*eb7fbc25SPierre Schweitzer         dsus.Length = dsus.MaximumLength = sizeof(datasuf) - sizeof(WCHAR);
333c2c66affSColin Finck 
334c2c66affSColin Finck         for (i = 0; i < nb->us.Length / sizeof(WCHAR); i++) {
335c2c66affSColin Finck             if (nb->us.Buffer[i] == ':') {
336c2c66affSColin Finck                 name_bit* nb2;
337c2c66affSColin Finck 
338c2c66affSColin Finck                 nb2 = ExAllocateFromPagedLookasideList(&Vcb->name_bit_lookaside);
339c2c66affSColin Finck                 if (!nb2) {
340c2c66affSColin Finck                     ERR("out of memory\n");
341c2c66affSColin Finck                     return STATUS_INSUFFICIENT_RESOURCES;
342c2c66affSColin Finck                 }
343c2c66affSColin Finck 
344c2c66affSColin Finck                 nb2->us.Buffer = &nb->us.Buffer[i+1];
345c2c66affSColin Finck                 nb2->us.Length = nb2->us.MaximumLength = (UINT16)(nb->us.Length - (i * sizeof(WCHAR)) - sizeof(WCHAR));
346c2c66affSColin Finck                 InsertTailList(parts, &nb2->list_entry);
347c2c66affSColin Finck 
348c2c66affSColin Finck                 nb->us.Length = (UINT16)i * sizeof(WCHAR);
349c2c66affSColin Finck                 nb->us.MaximumLength = nb->us.Length;
350c2c66affSColin Finck 
351c2c66affSColin Finck                 nb = nb2;
352c2c66affSColin Finck 
353c2c66affSColin Finck                 break;
354c2c66affSColin Finck             }
355c2c66affSColin Finck         }
356c2c66affSColin Finck 
357c2c66affSColin Finck         // FIXME - should comparison be case-insensitive?
358c2c66affSColin Finck         // remove :$DATA suffix
359c2c66affSColin Finck         if (nb->us.Length >= dsus.Length && RtlCompareMemory(&nb->us.Buffer[(nb->us.Length - dsus.Length)/sizeof(WCHAR)], dsus.Buffer, dsus.Length) == dsus.Length)
360c2c66affSColin Finck             nb->us.Length -= dsus.Length;
361c2c66affSColin Finck 
362c2c66affSColin Finck         if (nb->us.Length == 0) {
363c2c66affSColin Finck             RemoveTailList(parts);
364c2c66affSColin Finck             ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb);
365c2c66affSColin Finck 
366c2c66affSColin Finck             has_stream = FALSE;
367c2c66affSColin Finck         }
368c2c66affSColin Finck     }
369c2c66affSColin Finck 
370c2c66affSColin Finck     // if path is just stream name, remove first empty item
371c2c66affSColin Finck     if (has_stream && path->Length >= sizeof(WCHAR) && path->Buffer[0] == ':') {
372c2c66affSColin Finck         name_bit *nb1 = CONTAINING_RECORD(RemoveHeadList(parts), name_bit, list_entry);
373c2c66affSColin Finck 
374c2c66affSColin Finck         ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb1);
375c2c66affSColin Finck     }
376c2c66affSColin Finck 
377c2c66affSColin Finck     *stream = has_stream;
378c2c66affSColin Finck 
379c2c66affSColin Finck     return STATUS_SUCCESS;
380c2c66affSColin Finck }
381c2c66affSColin Finck 
382c2c66affSColin Finck NTSTATUS load_csum(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, UINT32* csum, UINT64 start, UINT64 length, PIRP Irp) {
383c2c66affSColin Finck     NTSTATUS Status;
384c2c66affSColin Finck     KEY searchkey;
385c2c66affSColin Finck     traverse_ptr tp, next_tp;
386c2c66affSColin Finck     UINT64 i, j;
387c2c66affSColin Finck     BOOL b;
388c2c66affSColin Finck 
389c2c66affSColin Finck     searchkey.obj_id = EXTENT_CSUM_ID;
390c2c66affSColin Finck     searchkey.obj_type = TYPE_EXTENT_CSUM;
391c2c66affSColin Finck     searchkey.offset = start;
392c2c66affSColin Finck 
393c2c66affSColin Finck     Status = find_item(Vcb, Vcb->checksum_root, &tp, &searchkey, FALSE, Irp);
394c2c66affSColin Finck     if (!NT_SUCCESS(Status)) {
395c2c66affSColin Finck         ERR("error - find_item returned %08x\n", Status);
396c2c66affSColin Finck         return Status;
397c2c66affSColin Finck     }
398c2c66affSColin Finck 
399c2c66affSColin Finck     i = 0;
400c2c66affSColin Finck     do {
401c2c66affSColin Finck         if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
402c2c66affSColin Finck             ULONG readlen;
403c2c66affSColin Finck 
404c2c66affSColin Finck             if (start < tp.item->key.offset)
405c2c66affSColin Finck                 j = 0;
406c2c66affSColin Finck             else
407c2c66affSColin Finck                 j = ((start - tp.item->key.offset) / Vcb->superblock.sector_size) + i;
408c2c66affSColin Finck 
409c2c66affSColin Finck             if (j * sizeof(UINT32) > tp.item->size || tp.item->key.offset > start + (i * Vcb->superblock.sector_size)) {
410c2c66affSColin Finck                 ERR("checksum not found for %llx\n", start + (i * Vcb->superblock.sector_size));
411c2c66affSColin Finck                 return STATUS_INTERNAL_ERROR;
412c2c66affSColin Finck             }
413c2c66affSColin Finck 
414c2c66affSColin Finck             readlen = (ULONG)min((tp.item->size / sizeof(UINT32)) - j, length - i);
415c2c66affSColin Finck             RtlCopyMemory(&csum[i], tp.item->data + (j * sizeof(UINT32)), readlen * sizeof(UINT32));
416c2c66affSColin Finck             i += readlen;
417c2c66affSColin Finck 
418c2c66affSColin Finck             if (i == length)
419c2c66affSColin Finck                 break;
420c2c66affSColin Finck         }
421c2c66affSColin Finck 
422c2c66affSColin Finck         b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
423c2c66affSColin Finck 
424c2c66affSColin Finck         if (b)
425c2c66affSColin Finck             tp = next_tp;
426c2c66affSColin Finck     } while (b);
427c2c66affSColin Finck 
428c2c66affSColin Finck     if (i < length) {
429c2c66affSColin Finck         ERR("could not read checksums: offset %llx, length %llx sectors\n", start, length);
430c2c66affSColin Finck         return STATUS_INTERNAL_ERROR;
431c2c66affSColin Finck     }
432c2c66affSColin Finck 
433c2c66affSColin Finck     return STATUS_SUCCESS;
434c2c66affSColin Finck }
435c2c66affSColin Finck 
436c2c66affSColin Finck NTSTATUS load_dir_children(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, fcb* fcb, BOOL ignore_size, PIRP Irp) {
437c2c66affSColin Finck     KEY searchkey;
438c2c66affSColin Finck     traverse_ptr tp, next_tp;
439c2c66affSColin Finck     NTSTATUS Status;
440c2c66affSColin Finck     ULONG num_children = 0;
441c2c66affSColin Finck 
442c2c66affSColin Finck     fcb->hash_ptrs = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG);
443c2c66affSColin Finck     if (!fcb->hash_ptrs) {
444c2c66affSColin Finck         ERR("out of memory\n");
445c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
446c2c66affSColin Finck     }
447c2c66affSColin Finck 
448c2c66affSColin Finck     RtlZeroMemory(fcb->hash_ptrs, sizeof(LIST_ENTRY*) * 256);
449c2c66affSColin Finck 
450c2c66affSColin Finck     fcb->hash_ptrs_uc = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG);
451c2c66affSColin Finck     if (!fcb->hash_ptrs_uc) {
452c2c66affSColin Finck         ERR("out of memory\n");
453c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
454c2c66affSColin Finck     }
455c2c66affSColin Finck 
456c2c66affSColin Finck     RtlZeroMemory(fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256);
457c2c66affSColin Finck 
458c2c66affSColin Finck     if (!ignore_size && fcb->inode_item.st_size == 0)
459c2c66affSColin Finck         return STATUS_SUCCESS;
460c2c66affSColin Finck 
461c2c66affSColin Finck     searchkey.obj_id = fcb->inode;
462c2c66affSColin Finck     searchkey.obj_type = TYPE_DIR_INDEX;
463c2c66affSColin Finck     searchkey.offset = 2;
464c2c66affSColin Finck 
465c2c66affSColin Finck     Status = find_item(Vcb, fcb->subvol, &tp, &searchkey, FALSE, Irp);
466c2c66affSColin Finck     if (!NT_SUCCESS(Status)) {
467c2c66affSColin Finck         ERR("find_item returned %08x\n", Status);
468c2c66affSColin Finck         return Status;
469c2c66affSColin Finck     }
470c2c66affSColin Finck 
471c2c66affSColin Finck     if (keycmp(tp.item->key, searchkey) == -1) {
472c2c66affSColin Finck         if (find_next_item(Vcb, &tp, &next_tp, FALSE, Irp)) {
473c2c66affSColin Finck             tp = next_tp;
474c2c66affSColin Finck             TRACE("moving on to %llx,%x,%llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
475c2c66affSColin Finck         }
476c2c66affSColin Finck     }
477c2c66affSColin Finck 
478c2c66affSColin Finck     while (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
479c2c66affSColin Finck         DIR_ITEM* di = (DIR_ITEM*)tp.item->data;
480c2c66affSColin Finck         dir_child* dc;
481c2c66affSColin Finck         ULONG utf16len;
482c2c66affSColin Finck 
483c2c66affSColin Finck         if (tp.item->size < sizeof(DIR_ITEM)) {
484c2c66affSColin Finck             WARN("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM));
485c2c66affSColin Finck             goto cont;
486c2c66affSColin Finck         }
487c2c66affSColin Finck 
488c2c66affSColin Finck         if (di->n == 0) {
489c2c66affSColin Finck             WARN("(%llx,%x,%llx): DIR_ITEM name length is zero\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
490c2c66affSColin Finck             goto cont;
491c2c66affSColin Finck         }
492c2c66affSColin Finck 
493c2c66affSColin Finck         Status = RtlUTF8ToUnicodeN(NULL, 0, &utf16len, di->name, di->n);
494c2c66affSColin Finck         if (!NT_SUCCESS(Status)) {
495c2c66affSColin Finck             ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
496c2c66affSColin Finck             goto cont;
497c2c66affSColin Finck         }
498c2c66affSColin Finck 
499c2c66affSColin Finck         dc = ExAllocatePoolWithTag(PagedPool, sizeof(dir_child), ALLOC_TAG);
500c2c66affSColin Finck         if (!dc) {
501c2c66affSColin Finck             ERR("out of memory\n");
502c2c66affSColin Finck             return STATUS_INSUFFICIENT_RESOURCES;
503c2c66affSColin Finck         }
504c2c66affSColin Finck 
505c2c66affSColin Finck         dc->key = di->key;
506c2c66affSColin Finck         dc->index = tp.item->key.offset;
507c2c66affSColin Finck         dc->type = di->type;
508c2c66affSColin Finck         dc->fileref = NULL;
509c2c66affSColin Finck 
510c2c66affSColin Finck         dc->utf8.MaximumLength = dc->utf8.Length = di->n;
511c2c66affSColin Finck         dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, di->n, ALLOC_TAG);
512c2c66affSColin Finck         if (!dc->utf8.Buffer) {
513c2c66affSColin Finck             ERR("out of memory\n");
514c2c66affSColin Finck             ExFreePool(dc);
515c2c66affSColin Finck             return STATUS_INSUFFICIENT_RESOURCES;
516c2c66affSColin Finck         }
517c2c66affSColin Finck 
518c2c66affSColin Finck         RtlCopyMemory(dc->utf8.Buffer, di->name, di->n);
519c2c66affSColin Finck 
520c2c66affSColin Finck         dc->name.MaximumLength = dc->name.Length = (UINT16)utf16len;
521c2c66affSColin Finck         dc->name.Buffer = ExAllocatePoolWithTag(PagedPool, dc->name.MaximumLength, ALLOC_TAG);
522c2c66affSColin Finck         if (!dc->name.Buffer) {
523c2c66affSColin Finck             ERR("out of memory\n");
524c2c66affSColin Finck             ExFreePool(dc->utf8.Buffer);
525c2c66affSColin Finck             ExFreePool(dc);
526c2c66affSColin Finck             return STATUS_INSUFFICIENT_RESOURCES;
527c2c66affSColin Finck         }
528c2c66affSColin Finck 
529c2c66affSColin Finck         Status = RtlUTF8ToUnicodeN(dc->name.Buffer, utf16len, &utf16len, di->name, di->n);
530c2c66affSColin Finck         if (!NT_SUCCESS(Status)) {
531c2c66affSColin Finck             ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
532c2c66affSColin Finck             ExFreePool(dc->utf8.Buffer);
533c2c66affSColin Finck             ExFreePool(dc->name.Buffer);
534c2c66affSColin Finck             ExFreePool(dc);
535c2c66affSColin Finck             goto cont;
536c2c66affSColin Finck         }
537c2c66affSColin Finck 
538c2c66affSColin Finck         Status = RtlUpcaseUnicodeString(&dc->name_uc, &dc->name, TRUE);
539c2c66affSColin Finck         if (!NT_SUCCESS(Status)) {
540c2c66affSColin Finck             ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
541c2c66affSColin Finck             ExFreePool(dc->utf8.Buffer);
542c2c66affSColin Finck             ExFreePool(dc->name.Buffer);
543c2c66affSColin Finck             ExFreePool(dc);
544c2c66affSColin Finck             goto cont;
545c2c66affSColin Finck         }
546c2c66affSColin Finck 
547c2c66affSColin Finck         dc->hash = calc_crc32c(0xffffffff, (UINT8*)dc->name.Buffer, dc->name.Length);
548c2c66affSColin Finck         dc->hash_uc = calc_crc32c(0xffffffff, (UINT8*)dc->name_uc.Buffer, dc->name_uc.Length);
549c2c66affSColin Finck 
550c2c66affSColin Finck         InsertTailList(&fcb->dir_children_index, &dc->list_entry_index);
551c2c66affSColin Finck 
552c2c66affSColin Finck         insert_dir_child_into_hash_lists(fcb, dc);
553c2c66affSColin Finck 
554c2c66affSColin Finck         num_children++;
555c2c66affSColin Finck 
556c2c66affSColin Finck cont:
557c2c66affSColin Finck         if (find_next_item(Vcb, &tp, &next_tp, FALSE, Irp))
558c2c66affSColin Finck             tp = next_tp;
559c2c66affSColin Finck         else
560c2c66affSColin Finck             break;
561c2c66affSColin Finck     }
562c2c66affSColin Finck 
563c2c66affSColin Finck     // If a directory has a lot of files, force it to stick around until the next flush
564c2c66affSColin Finck     // so we aren't constantly re-reading.
565c2c66affSColin Finck     if (num_children >= 100)
566c2c66affSColin Finck         mark_fcb_dirty(fcb);
567c2c66affSColin Finck 
568c2c66affSColin Finck     return STATUS_SUCCESS;
569c2c66affSColin Finck }
570c2c66affSColin Finck 
571c2c66affSColin Finck NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension* Vcb,
572c2c66affSColin Finck                   root* subvol, UINT64 inode, UINT8 type, PANSI_STRING utf8, fcb* parent, fcb** pfcb, POOL_TYPE pooltype, PIRP Irp) {
573c2c66affSColin Finck     KEY searchkey;
574c2c66affSColin Finck     traverse_ptr tp, next_tp;
575c2c66affSColin Finck     NTSTATUS Status;
576c2c66affSColin Finck     fcb *fcb, *deleted_fcb = NULL;
577c2c66affSColin Finck     BOOL atts_set = FALSE, sd_set = FALSE, no_data;
578c2c66affSColin Finck     LIST_ENTRY* lastle = NULL;
579c2c66affSColin Finck     EXTENT_DATA* ed = NULL;
580c2c66affSColin Finck 
581c2c66affSColin Finck     if (!IsListEmpty(&subvol->fcbs)) {
582c2c66affSColin Finck         LIST_ENTRY* le = subvol->fcbs.Flink;
583c2c66affSColin Finck 
584c2c66affSColin Finck         while (le != &subvol->fcbs) {
585c2c66affSColin Finck             fcb = CONTAINING_RECORD(le, struct _fcb, list_entry);
586c2c66affSColin Finck 
587c2c66affSColin Finck             if (fcb->inode == inode) {
588c2c66affSColin Finck                 if (!fcb->ads) {
589c2c66affSColin Finck                     if (fcb->deleted)
590c2c66affSColin Finck                         deleted_fcb = fcb;
591c2c66affSColin Finck                     else {
592c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
593c2c66affSColin Finck                         LONG rc = InterlockedIncrement(&fcb->refcount);
594c2c66affSColin Finck 
595c2c66affSColin Finck                         WARN("fcb %p: refcount now %i (subvol %llx, inode %llx)\n", fcb, rc, fcb->subvol->id, fcb->inode);
596c2c66affSColin Finck #else
597c2c66affSColin Finck                         InterlockedIncrement(&fcb->refcount);
598c2c66affSColin Finck #endif
599c2c66affSColin Finck 
600c2c66affSColin Finck                         *pfcb = fcb;
601c2c66affSColin Finck                         return STATUS_SUCCESS;
602c2c66affSColin Finck                     }
603c2c66affSColin Finck                 }
604c2c66affSColin Finck             } else if (fcb->inode > inode) {
605c2c66affSColin Finck                 if (deleted_fcb) {
606c2c66affSColin Finck                     InterlockedIncrement(&deleted_fcb->refcount);
607c2c66affSColin Finck                     *pfcb = deleted_fcb;
608c2c66affSColin Finck                     return STATUS_SUCCESS;
609c2c66affSColin Finck                 }
610c2c66affSColin Finck 
611c2c66affSColin Finck                 lastle = le->Blink;
612c2c66affSColin Finck                 break;
613c2c66affSColin Finck             }
614c2c66affSColin Finck 
615c2c66affSColin Finck             le = le->Flink;
616c2c66affSColin Finck         }
617c2c66affSColin Finck     }
618c2c66affSColin Finck 
619c2c66affSColin Finck     if (deleted_fcb) {
620c2c66affSColin Finck         InterlockedIncrement(&deleted_fcb->refcount);
621c2c66affSColin Finck         *pfcb = deleted_fcb;
622c2c66affSColin Finck         return STATUS_SUCCESS;
623c2c66affSColin Finck     }
624c2c66affSColin Finck 
625c2c66affSColin Finck     fcb = create_fcb(Vcb, pooltype);
626c2c66affSColin Finck     if (!fcb) {
627c2c66affSColin Finck         ERR("out of memory\n");
628c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
629c2c66affSColin Finck     }
630c2c66affSColin Finck 
631c2c66affSColin Finck     fcb->Vcb = Vcb;
632c2c66affSColin Finck 
633c2c66affSColin Finck     fcb->subvol = subvol;
634c2c66affSColin Finck     fcb->inode = inode;
635c2c66affSColin Finck     fcb->type = type;
636c2c66affSColin Finck 
637c2c66affSColin Finck     searchkey.obj_id = inode;
638c2c66affSColin Finck     searchkey.obj_type = TYPE_INODE_ITEM;
639c2c66affSColin Finck     searchkey.offset = 0xffffffffffffffff;
640c2c66affSColin Finck 
641c2c66affSColin Finck     Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE, Irp);
642c2c66affSColin Finck     if (!NT_SUCCESS(Status)) {
643c2c66affSColin Finck         ERR("error - find_item returned %08x\n", Status);
644c2c66affSColin Finck         free_fcb(Vcb, fcb);
645c2c66affSColin Finck         return Status;
646c2c66affSColin Finck     }
647c2c66affSColin Finck 
648c2c66affSColin Finck     if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
649c2c66affSColin Finck         WARN("couldn't find INODE_ITEM for inode %llx in subvol %llx\n", inode, subvol->id);
650c2c66affSColin Finck         free_fcb(Vcb, fcb);
651c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
652c2c66affSColin Finck     }
653c2c66affSColin Finck 
654c2c66affSColin Finck     if (tp.item->size > 0)
655c2c66affSColin Finck         RtlCopyMemory(&fcb->inode_item, tp.item->data, min(sizeof(INODE_ITEM), tp.item->size));
656c2c66affSColin Finck 
657c2c66affSColin Finck     if (fcb->type == 0) { // guess the type from the inode mode, if the caller doesn't know already
658c2c66affSColin Finck         if ((fcb->inode_item.st_mode & __S_IFDIR) == __S_IFDIR)
659c2c66affSColin Finck             fcb->type = BTRFS_TYPE_DIRECTORY;
660c2c66affSColin Finck         else if ((fcb->inode_item.st_mode & __S_IFCHR) == __S_IFCHR)
661c2c66affSColin Finck             fcb->type = BTRFS_TYPE_CHARDEV;
662c2c66affSColin Finck         else if ((fcb->inode_item.st_mode & __S_IFBLK) == __S_IFBLK)
663c2c66affSColin Finck             fcb->type = BTRFS_TYPE_BLOCKDEV;
664c2c66affSColin Finck         else if ((fcb->inode_item.st_mode & __S_IFIFO) == __S_IFIFO)
665c2c66affSColin Finck             fcb->type = BTRFS_TYPE_FIFO;
666c2c66affSColin Finck         else if ((fcb->inode_item.st_mode & __S_IFLNK) == __S_IFLNK)
667c2c66affSColin Finck             fcb->type = BTRFS_TYPE_SYMLINK;
668c2c66affSColin Finck         else if ((fcb->inode_item.st_mode & __S_IFSOCK) == __S_IFSOCK)
669c2c66affSColin Finck             fcb->type = BTRFS_TYPE_SOCKET;
670c2c66affSColin Finck         else
671c2c66affSColin Finck             fcb->type = BTRFS_TYPE_FILE;
672c2c66affSColin Finck     }
673c2c66affSColin Finck 
674c2c66affSColin Finck     no_data = fcb->inode_item.st_size == 0 || (fcb->type != BTRFS_TYPE_FILE && fcb->type != BTRFS_TYPE_SYMLINK);
675c2c66affSColin Finck 
676c2c66affSColin Finck     while (find_next_item(Vcb, &tp, &next_tp, FALSE, Irp)) {
677c2c66affSColin Finck         tp = next_tp;
678c2c66affSColin Finck 
679c2c66affSColin Finck         if (tp.item->key.obj_id > inode)
680c2c66affSColin Finck             break;
681c2c66affSColin Finck 
682c2c66affSColin Finck         if ((no_data && tp.item->key.obj_type > TYPE_XATTR_ITEM) || tp.item->key.obj_type > TYPE_EXTENT_DATA)
683c2c66affSColin Finck             break;
684c2c66affSColin Finck 
685c2c66affSColin Finck         if (fcb->inode_item.st_nlink > 1 && tp.item->key.obj_type == TYPE_INODE_REF) {
686c2c66affSColin Finck             ULONG len;
687c2c66affSColin Finck             INODE_REF* ir;
688c2c66affSColin Finck 
689c2c66affSColin Finck             len = tp.item->size;
690c2c66affSColin Finck             ir = (INODE_REF*)tp.item->data;
691c2c66affSColin Finck 
692c2c66affSColin Finck             while (len >= sizeof(INODE_REF) - 1) {
693c2c66affSColin Finck                 hardlink* hl;
694c2c66affSColin Finck                 ULONG stringlen;
695c2c66affSColin Finck 
696c2c66affSColin Finck                 hl = ExAllocatePoolWithTag(pooltype, sizeof(hardlink), ALLOC_TAG);
697c2c66affSColin Finck                 if (!hl) {
698c2c66affSColin Finck                     ERR("out of memory\n");
699c2c66affSColin Finck                     free_fcb(Vcb, fcb);
700c2c66affSColin Finck                     return STATUS_INSUFFICIENT_RESOURCES;
701c2c66affSColin Finck                 }
702c2c66affSColin Finck 
703c2c66affSColin Finck                 hl->parent = tp.item->key.offset;
704c2c66affSColin Finck                 hl->index = ir->index;
705c2c66affSColin Finck 
706c2c66affSColin Finck                 hl->utf8.Length = hl->utf8.MaximumLength = ir->n;
707c2c66affSColin Finck 
708c2c66affSColin Finck                 if (hl->utf8.Length > 0) {
709c2c66affSColin Finck                     hl->utf8.Buffer = ExAllocatePoolWithTag(pooltype, hl->utf8.MaximumLength, ALLOC_TAG);
710c2c66affSColin Finck                     RtlCopyMemory(hl->utf8.Buffer, ir->name, ir->n);
711c2c66affSColin Finck                 }
712c2c66affSColin Finck 
713c2c66affSColin Finck                 Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, ir->name, ir->n);
714c2c66affSColin Finck                 if (!NT_SUCCESS(Status)) {
715c2c66affSColin Finck                     ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
716c2c66affSColin Finck                     ExFreePool(hl);
717c2c66affSColin Finck                     free_fcb(Vcb, fcb);
718c2c66affSColin Finck                     return Status;
719c2c66affSColin Finck                 }
720c2c66affSColin Finck 
721c2c66affSColin Finck                 hl->name.Length = hl->name.MaximumLength = (UINT16)stringlen;
722c2c66affSColin Finck 
723c2c66affSColin Finck                 if (stringlen == 0)
724c2c66affSColin Finck                     hl->name.Buffer = NULL;
725c2c66affSColin Finck                 else {
726c2c66affSColin Finck                     hl->name.Buffer = ExAllocatePoolWithTag(pooltype, hl->name.MaximumLength, ALLOC_TAG);
727c2c66affSColin Finck 
728c2c66affSColin Finck                     if (!hl->name.Buffer) {
729c2c66affSColin Finck                         ERR("out of memory\n");
730c2c66affSColin Finck                         ExFreePool(hl);
731c2c66affSColin Finck                         free_fcb(Vcb, fcb);
732c2c66affSColin Finck                         return STATUS_INSUFFICIENT_RESOURCES;
733c2c66affSColin Finck                     }
734c2c66affSColin Finck 
735c2c66affSColin Finck                     Status = RtlUTF8ToUnicodeN(hl->name.Buffer, stringlen, &stringlen, ir->name, ir->n);
736c2c66affSColin Finck                     if (!NT_SUCCESS(Status)) {
737c2c66affSColin Finck                         ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
738c2c66affSColin Finck                         ExFreePool(hl->name.Buffer);
739c2c66affSColin Finck                         ExFreePool(hl);
740c2c66affSColin Finck                         free_fcb(Vcb, fcb);
741c2c66affSColin Finck                         return Status;
742c2c66affSColin Finck                     }
743c2c66affSColin Finck                 }
744c2c66affSColin Finck 
745c2c66affSColin Finck                 InsertTailList(&fcb->hardlinks, &hl->list_entry);
746c2c66affSColin Finck 
747c2c66affSColin Finck                 len -= sizeof(INODE_REF) - 1 + ir->n;
748c2c66affSColin Finck                 ir = (INODE_REF*)&ir->name[ir->n];
749c2c66affSColin Finck             }
750c2c66affSColin Finck         } else if (fcb->inode_item.st_nlink > 1 && tp.item->key.obj_type == TYPE_INODE_EXTREF) {
751c2c66affSColin Finck             ULONG len;
752c2c66affSColin Finck             INODE_EXTREF* ier;
753c2c66affSColin Finck 
754c2c66affSColin Finck             len = tp.item->size;
755c2c66affSColin Finck             ier = (INODE_EXTREF*)tp.item->data;
756c2c66affSColin Finck 
757c2c66affSColin Finck             while (len >= sizeof(INODE_EXTREF) - 1) {
758c2c66affSColin Finck                 hardlink* hl;
759c2c66affSColin Finck                 ULONG stringlen;
760c2c66affSColin Finck 
761c2c66affSColin Finck                 hl = ExAllocatePoolWithTag(pooltype, sizeof(hardlink), ALLOC_TAG);
762c2c66affSColin Finck                 if (!hl) {
763c2c66affSColin Finck                     ERR("out of memory\n");
764c2c66affSColin Finck                     free_fcb(Vcb, fcb);
765c2c66affSColin Finck                     return STATUS_INSUFFICIENT_RESOURCES;
766c2c66affSColin Finck                 }
767c2c66affSColin Finck 
768c2c66affSColin Finck                 hl->parent = ier->dir;
769c2c66affSColin Finck                 hl->index = ier->index;
770c2c66affSColin Finck 
771c2c66affSColin Finck                 hl->utf8.Length = hl->utf8.MaximumLength = ier->n;
772c2c66affSColin Finck 
773c2c66affSColin Finck                 if (hl->utf8.Length > 0) {
774c2c66affSColin Finck                     hl->utf8.Buffer = ExAllocatePoolWithTag(pooltype, hl->utf8.MaximumLength, ALLOC_TAG);
775c2c66affSColin Finck                     RtlCopyMemory(hl->utf8.Buffer, ier->name, ier->n);
776c2c66affSColin Finck                 }
777c2c66affSColin Finck 
778c2c66affSColin Finck                 Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, ier->name, ier->n);
779c2c66affSColin Finck                 if (!NT_SUCCESS(Status)) {
780c2c66affSColin Finck                     ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
781c2c66affSColin Finck                     ExFreePool(hl);
782c2c66affSColin Finck                     free_fcb(Vcb, fcb);
783c2c66affSColin Finck                     return Status;
784c2c66affSColin Finck                 }
785c2c66affSColin Finck 
786c2c66affSColin Finck                 hl->name.Length = hl->name.MaximumLength = (UINT16)stringlen;
787c2c66affSColin Finck 
788c2c66affSColin Finck                 if (stringlen == 0)
789c2c66affSColin Finck                     hl->name.Buffer = NULL;
790c2c66affSColin Finck                 else {
791c2c66affSColin Finck                     hl->name.Buffer = ExAllocatePoolWithTag(pooltype, hl->name.MaximumLength, ALLOC_TAG);
792c2c66affSColin Finck 
793c2c66affSColin Finck                     if (!hl->name.Buffer) {
794c2c66affSColin Finck                         ERR("out of memory\n");
795c2c66affSColin Finck                         ExFreePool(hl);
796c2c66affSColin Finck                         free_fcb(Vcb, fcb);
797c2c66affSColin Finck                         return STATUS_INSUFFICIENT_RESOURCES;
798c2c66affSColin Finck                     }
799c2c66affSColin Finck 
800c2c66affSColin Finck                     Status = RtlUTF8ToUnicodeN(hl->name.Buffer, stringlen, &stringlen, ier->name, ier->n);
801c2c66affSColin Finck                     if (!NT_SUCCESS(Status)) {
802c2c66affSColin Finck                         ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
803c2c66affSColin Finck                         ExFreePool(hl->name.Buffer);
804c2c66affSColin Finck                         ExFreePool(hl);
805c2c66affSColin Finck                         free_fcb(Vcb, fcb);
806c2c66affSColin Finck                         return Status;
807c2c66affSColin Finck                     }
808c2c66affSColin Finck                 }
809c2c66affSColin Finck 
810c2c66affSColin Finck                 InsertTailList(&fcb->hardlinks, &hl->list_entry);
811c2c66affSColin Finck 
812c2c66affSColin Finck                 len -= sizeof(INODE_EXTREF) - 1 + ier->n;
813c2c66affSColin Finck                 ier = (INODE_EXTREF*)&ier->name[ier->n];
814c2c66affSColin Finck             }
815c2c66affSColin Finck         } else if (tp.item->key.obj_type == TYPE_XATTR_ITEM) {
816c2c66affSColin Finck             ULONG len;
817c2c66affSColin Finck             DIR_ITEM* di;
818c2c66affSColin Finck 
819*eb7fbc25SPierre Schweitzer             static const char xapref[] = "user.";
820c2c66affSColin Finck 
821c2c66affSColin Finck             if (tp.item->size < offsetof(DIR_ITEM, name[0])) {
822c2c66affSColin Finck                 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, offsetof(DIR_ITEM, name[0]));
823c2c66affSColin Finck                 continue;
824c2c66affSColin Finck             }
825c2c66affSColin Finck 
826c2c66affSColin Finck             len = tp.item->size;
827c2c66affSColin Finck             di = (DIR_ITEM*)tp.item->data;
828c2c66affSColin Finck 
829c2c66affSColin Finck             do {
830c2c66affSColin Finck                 if (len < offsetof(DIR_ITEM, name[0]) + di->m + di->n)
831c2c66affSColin Finck                     break;
832c2c66affSColin Finck 
833*eb7fbc25SPierre Schweitzer                 if (tp.item->key.offset == EA_REPARSE_HASH && di->n == sizeof(EA_REPARSE) - 1 && RtlCompareMemory(EA_REPARSE, di->name, di->n) == di->n) {
834c2c66affSColin Finck                     if (di->m > 0) {
835c2c66affSColin Finck                         fcb->reparse_xattr.Buffer = ExAllocatePoolWithTag(PagedPool, di->m, ALLOC_TAG);
836c2c66affSColin Finck                         if (!fcb->reparse_xattr.Buffer) {
837c2c66affSColin Finck                             ERR("out of memory\n");
838c2c66affSColin Finck                             free_fcb(Vcb, fcb);
839c2c66affSColin Finck                             return STATUS_INSUFFICIENT_RESOURCES;
840c2c66affSColin Finck                         }
841c2c66affSColin Finck 
842c2c66affSColin Finck                         RtlCopyMemory(fcb->reparse_xattr.Buffer, &di->name[di->n], di->m);
843c2c66affSColin Finck                     } else
844c2c66affSColin Finck                         fcb->reparse_xattr.Buffer = NULL;
845c2c66affSColin Finck 
846c2c66affSColin Finck                     fcb->reparse_xattr.Length = fcb->reparse_xattr.MaximumLength = di->m;
847*eb7fbc25SPierre Schweitzer                 } else if (tp.item->key.offset == EA_EA_HASH && di->n == sizeof(EA_EA) - 1 && RtlCompareMemory(EA_EA, di->name, di->n) == di->n) {
848c2c66affSColin Finck                     if (di->m > 0) {
849c2c66affSColin Finck                         ULONG offset;
850c2c66affSColin Finck 
851c2c66affSColin Finck                         Status = IoCheckEaBufferValidity((FILE_FULL_EA_INFORMATION*)&di->name[di->n], di->m, &offset);
852c2c66affSColin Finck 
853c2c66affSColin Finck                         if (!NT_SUCCESS(Status))
854c2c66affSColin Finck                             WARN("IoCheckEaBufferValidity returned %08x (error at offset %u)\n", Status, offset);
855c2c66affSColin Finck                         else {
856c2c66affSColin Finck                             FILE_FULL_EA_INFORMATION* eainfo;
857c2c66affSColin Finck 
858c2c66affSColin Finck                             fcb->ea_xattr.Buffer = ExAllocatePoolWithTag(PagedPool, di->m, ALLOC_TAG);
859c2c66affSColin Finck                             if (!fcb->ea_xattr.Buffer) {
860c2c66affSColin Finck                                 ERR("out of memory\n");
861c2c66affSColin Finck                                 free_fcb(Vcb, fcb);
862c2c66affSColin Finck                                 return STATUS_INSUFFICIENT_RESOURCES;
863c2c66affSColin Finck                             }
864c2c66affSColin Finck 
865c2c66affSColin Finck                             RtlCopyMemory(fcb->ea_xattr.Buffer, &di->name[di->n], di->m);
866c2c66affSColin Finck 
867c2c66affSColin Finck                             fcb->ea_xattr.Length = fcb->ea_xattr.MaximumLength = di->m;
868c2c66affSColin Finck 
869c2c66affSColin Finck                             fcb->ealen = 4;
870c2c66affSColin Finck 
871c2c66affSColin Finck                             // calculate ealen
872c2c66affSColin Finck                             eainfo = (FILE_FULL_EA_INFORMATION*)&di->name[di->n];
873c2c66affSColin Finck                             do {
874c2c66affSColin Finck                                 fcb->ealen += 5 + eainfo->EaNameLength + eainfo->EaValueLength;
875c2c66affSColin Finck 
876c2c66affSColin Finck                                 if (eainfo->NextEntryOffset == 0)
877c2c66affSColin Finck                                     break;
878c2c66affSColin Finck 
879c2c66affSColin Finck                                 eainfo = (FILE_FULL_EA_INFORMATION*)(((UINT8*)eainfo) + eainfo->NextEntryOffset);
880c2c66affSColin Finck                             } while (TRUE);
881c2c66affSColin Finck                         }
882c2c66affSColin Finck                     }
883*eb7fbc25SPierre Schweitzer                 } else if (tp.item->key.offset == EA_DOSATTRIB_HASH && di->n == sizeof(EA_DOSATTRIB) - 1 && RtlCompareMemory(EA_DOSATTRIB, di->name, di->n) == di->n) {
884c2c66affSColin Finck                     if (di->m > 0) {
885c2c66affSColin Finck                         if (get_file_attributes_from_xattr(&di->name[di->n], di->m, &fcb->atts)) {
886c2c66affSColin Finck                             atts_set = TRUE;
887c2c66affSColin Finck 
888c2c66affSColin Finck                             if (fcb->type == BTRFS_TYPE_DIRECTORY)
889c2c66affSColin Finck                                 fcb->atts |= FILE_ATTRIBUTE_DIRECTORY;
890c2c66affSColin Finck                             else if (fcb->type == BTRFS_TYPE_SYMLINK)
891c2c66affSColin Finck                                 fcb->atts |= FILE_ATTRIBUTE_REPARSE_POINT;
892c2c66affSColin Finck 
893c2c66affSColin Finck                             if (fcb->type != BTRFS_TYPE_DIRECTORY)
894c2c66affSColin Finck                                 fcb->atts &= ~FILE_ATTRIBUTE_DIRECTORY;
895c2c66affSColin Finck 
896c2c66affSColin Finck                             if (inode == SUBVOL_ROOT_INODE) {
897c2c66affSColin Finck                                 if (subvol->root_item.flags & BTRFS_SUBVOL_READONLY)
898c2c66affSColin Finck                                     fcb->atts |= FILE_ATTRIBUTE_READONLY;
899c2c66affSColin Finck                                 else
900c2c66affSColin Finck                                     fcb->atts &= ~FILE_ATTRIBUTE_READONLY;
901c2c66affSColin Finck                             }
902c2c66affSColin Finck                         }
903c2c66affSColin Finck                     }
904*eb7fbc25SPierre Schweitzer                 } else if (tp.item->key.offset == EA_NTACL_HASH && di->n == sizeof(EA_NTACL) - 1 && RtlCompareMemory(EA_NTACL, di->name, di->n) == di->n) {
905c2c66affSColin Finck                     if (di->m > 0) {
906c2c66affSColin Finck                         fcb->sd = ExAllocatePoolWithTag(PagedPool, di->m, ALLOC_TAG);
907c2c66affSColin Finck                         if (!fcb->sd) {
908c2c66affSColin Finck                             ERR("out of memory\n");
909c2c66affSColin Finck                             free_fcb(Vcb, fcb);
910c2c66affSColin Finck                             return STATUS_INSUFFICIENT_RESOURCES;
911c2c66affSColin Finck                         }
912c2c66affSColin Finck 
913c2c66affSColin Finck                         RtlCopyMemory(fcb->sd, &di->name[di->n], di->m);
914c2c66affSColin Finck 
915c2c66affSColin Finck                         // We have to test against our copy rather than the source, as RtlValidRelativeSecurityDescriptor
916c2c66affSColin Finck                         // will fail if the ACLs aren't 32-bit aligned.
917c2c66affSColin Finck                         if (!RtlValidRelativeSecurityDescriptor(fcb->sd, di->m, 0))
918c2c66affSColin Finck                             ExFreePool(fcb->sd);
919c2c66affSColin Finck                         else
920c2c66affSColin Finck                             sd_set = TRUE;
921c2c66affSColin Finck                     }
922*eb7fbc25SPierre Schweitzer                 } else if (tp.item->key.offset == EA_PROP_COMPRESSION_HASH && di->n == sizeof(EA_PROP_COMPRESSION) - 1 && RtlCompareMemory(EA_PROP_COMPRESSION, di->name, di->n) == di->n) {
923c2c66affSColin Finck                     if (di->m > 0) {
924*eb7fbc25SPierre Schweitzer                         static const char lzo[] = "lzo";
925*eb7fbc25SPierre Schweitzer                         static const char zlib[] = "zlib";
926*eb7fbc25SPierre Schweitzer                         static const char zstd[] = "zstd";
927c2c66affSColin Finck 
928*eb7fbc25SPierre Schweitzer                         if (di->m == sizeof(lzo) - 1 && RtlCompareMemory(&di->name[di->n], lzo, di->m) == di->m)
929c2c66affSColin Finck                             fcb->prop_compression = PropCompression_LZO;
930*eb7fbc25SPierre Schweitzer                         else if (di->m == sizeof(zlib) - 1 && RtlCompareMemory(&di->name[di->n], zlib, di->m) == di->m)
931c2c66affSColin Finck                             fcb->prop_compression = PropCompression_Zlib;
932*eb7fbc25SPierre Schweitzer                         else if (di->m == sizeof(zstd) - 1 && RtlCompareMemory(&di->name[di->n], zstd, di->m) == di->m)
933*eb7fbc25SPierre Schweitzer                             fcb->prop_compression = PropCompression_ZSTD;
934c2c66affSColin Finck                         else
935c2c66affSColin Finck                             fcb->prop_compression = PropCompression_None;
936c2c66affSColin Finck                     }
937*eb7fbc25SPierre Schweitzer                 } else if (di->n > sizeof(xapref) - 1 && RtlCompareMemory(xapref, di->name, sizeof(xapref) - 1) == sizeof(xapref) - 1) {
938c2c66affSColin Finck                     dir_child* dc;
939c2c66affSColin Finck                     ULONG utf16len;
940c2c66affSColin Finck 
941*eb7fbc25SPierre Schweitzer                     Status = RtlUTF8ToUnicodeN(NULL, 0, &utf16len, &di->name[sizeof(xapref) - 1], di->n + 1 - sizeof(xapref));
942c2c66affSColin Finck                     if (!NT_SUCCESS(Status)) {
943c2c66affSColin Finck                         ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
944c2c66affSColin Finck                         free_fcb(Vcb, fcb);
945c2c66affSColin Finck                         return Status;
946c2c66affSColin Finck                     }
947c2c66affSColin Finck 
948c2c66affSColin Finck                     dc = ExAllocatePoolWithTag(PagedPool, sizeof(dir_child), ALLOC_TAG);
949c2c66affSColin Finck                     if (!dc) {
950c2c66affSColin Finck                         ERR("out of memory\n");
951c2c66affSColin Finck                         free_fcb(Vcb, fcb);
952c2c66affSColin Finck                         return STATUS_INSUFFICIENT_RESOURCES;
953c2c66affSColin Finck                     }
954c2c66affSColin Finck 
955c2c66affSColin Finck                     RtlZeroMemory(dc, sizeof(dir_child));
956c2c66affSColin Finck 
957*eb7fbc25SPierre Schweitzer                     dc->utf8.MaximumLength = dc->utf8.Length = di->n + 1 - sizeof(xapref);
958c2c66affSColin Finck                     dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, dc->utf8.MaximumLength, ALLOC_TAG);
959c2c66affSColin Finck                     if (!dc->utf8.Buffer) {
960c2c66affSColin Finck                         ERR("out of memory\n");
961c2c66affSColin Finck                         ExFreePool(dc);
962c2c66affSColin Finck                         free_fcb(Vcb, fcb);
963c2c66affSColin Finck                         return STATUS_INSUFFICIENT_RESOURCES;
964c2c66affSColin Finck                     }
965c2c66affSColin Finck 
966*eb7fbc25SPierre Schweitzer                     RtlCopyMemory(dc->utf8.Buffer, &di->name[sizeof(xapref) - 1], dc->utf8.Length);
967c2c66affSColin Finck 
968c2c66affSColin Finck                     dc->name.MaximumLength = dc->name.Length = (UINT16)utf16len;
969c2c66affSColin Finck                     dc->name.Buffer = ExAllocatePoolWithTag(PagedPool, dc->name.MaximumLength, ALLOC_TAG);
970c2c66affSColin Finck                     if (!dc->name.Buffer) {
971c2c66affSColin Finck                         ERR("out of memory\n");
972c2c66affSColin Finck                         ExFreePool(dc->utf8.Buffer);
973c2c66affSColin Finck                         ExFreePool(dc);
974c2c66affSColin Finck                         free_fcb(Vcb, fcb);
975c2c66affSColin Finck                         return STATUS_INSUFFICIENT_RESOURCES;
976c2c66affSColin Finck                     }
977c2c66affSColin Finck 
978c2c66affSColin Finck                     Status = RtlUTF8ToUnicodeN(dc->name.Buffer, utf16len, &utf16len, dc->utf8.Buffer, dc->utf8.Length);
979c2c66affSColin Finck                     if (!NT_SUCCESS(Status)) {
980c2c66affSColin Finck                         ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
981c2c66affSColin Finck                         ExFreePool(dc->utf8.Buffer);
982c2c66affSColin Finck                         ExFreePool(dc->name.Buffer);
983c2c66affSColin Finck                         ExFreePool(dc);
984c2c66affSColin Finck                         free_fcb(Vcb, fcb);
985c2c66affSColin Finck                         return Status;
986c2c66affSColin Finck                     }
987c2c66affSColin Finck 
988c2c66affSColin Finck                     Status = RtlUpcaseUnicodeString(&dc->name_uc, &dc->name, TRUE);
989c2c66affSColin Finck                     if (!NT_SUCCESS(Status)) {
990c2c66affSColin Finck                         ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
991c2c66affSColin Finck                         ExFreePool(dc->utf8.Buffer);
992c2c66affSColin Finck                         ExFreePool(dc->name.Buffer);
993c2c66affSColin Finck                         ExFreePool(dc);
994c2c66affSColin Finck                         free_fcb(Vcb, fcb);
995c2c66affSColin Finck                         return Status;
996c2c66affSColin Finck                     }
997c2c66affSColin Finck 
998c2c66affSColin Finck                     dc->size = di->m;
999c2c66affSColin Finck 
1000c2c66affSColin Finck                     InsertTailList(&fcb->dir_children_index, &dc->list_entry_index);
1001c2c66affSColin Finck                 } else {
1002c2c66affSColin Finck                     xattr* xa;
1003c2c66affSColin Finck 
1004c2c66affSColin Finck                     xa = ExAllocatePoolWithTag(PagedPool, offsetof(xattr, data[0]) + di->m + di->n, ALLOC_TAG);
1005c2c66affSColin Finck                     if (!xa) {
1006c2c66affSColin Finck                         ERR("out of memory\n");
1007c2c66affSColin Finck                         free_fcb(Vcb, fcb);
1008c2c66affSColin Finck                         return STATUS_INSUFFICIENT_RESOURCES;
1009c2c66affSColin Finck                     }
1010c2c66affSColin Finck 
1011c2c66affSColin Finck                     xa->namelen = di->n;
1012c2c66affSColin Finck                     xa->valuelen = di->m;
1013c2c66affSColin Finck                     xa->dirty = FALSE;
1014c2c66affSColin Finck                     RtlCopyMemory(xa->data, di->name, di->m + di->n);
1015c2c66affSColin Finck 
1016c2c66affSColin Finck                     InsertTailList(&fcb->xattrs, &xa->list_entry);
1017c2c66affSColin Finck                 }
1018c2c66affSColin Finck 
1019c2c66affSColin Finck                 len -= (ULONG)offsetof(DIR_ITEM, name[0]) + di->m + di->n;
1020c2c66affSColin Finck 
1021c2c66affSColin Finck                 if (len < offsetof(DIR_ITEM, name[0]))
1022c2c66affSColin Finck                     break;
1023c2c66affSColin Finck 
1024c2c66affSColin Finck                 di = (DIR_ITEM*)&di->name[di->m + di->n];
1025c2c66affSColin Finck             } while (TRUE);
1026c2c66affSColin Finck         } else if (tp.item->key.obj_type == TYPE_EXTENT_DATA) {
1027c2c66affSColin Finck             extent* ext;
1028c2c66affSColin Finck             BOOL unique = FALSE;
1029c2c66affSColin Finck 
1030c2c66affSColin Finck             ed = (EXTENT_DATA*)tp.item->data;
1031c2c66affSColin Finck 
1032c2c66affSColin Finck             if (tp.item->size < sizeof(EXTENT_DATA)) {
1033c2c66affSColin Finck                 ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset,
1034c2c66affSColin Finck                     tp.item->size, sizeof(EXTENT_DATA));
1035c2c66affSColin Finck 
1036c2c66affSColin Finck                 free_fcb(Vcb, fcb);
1037c2c66affSColin Finck                 return STATUS_INTERNAL_ERROR;
1038c2c66affSColin Finck             }
1039c2c66affSColin Finck 
1040c2c66affSColin Finck             if (ed->type == EXTENT_TYPE_REGULAR || ed->type == EXTENT_TYPE_PREALLOC) {
1041c2c66affSColin Finck                 EXTENT_DATA2* ed2 = (EXTENT_DATA2*)&ed->data[0];
1042c2c66affSColin Finck 
1043c2c66affSColin Finck                 if (tp.item->size < sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2)) {
1044c2c66affSColin Finck                     ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset,
1045c2c66affSColin Finck                         tp.item->size, sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2));
1046c2c66affSColin Finck 
1047c2c66affSColin Finck                     free_fcb(Vcb, fcb);
1048c2c66affSColin Finck                     return STATUS_INTERNAL_ERROR;
1049c2c66affSColin Finck                 }
1050c2c66affSColin Finck 
1051c2c66affSColin Finck                 if (ed2->address == 0 || ed2->size == 0) // sparse
1052c2c66affSColin Finck                     continue;
1053c2c66affSColin Finck 
1054c2c66affSColin Finck                 if (ed2->size != 0 && is_tree_unique(Vcb, tp.tree, Irp))
1055c2c66affSColin Finck                     unique = is_extent_unique(Vcb, ed2->address, ed2->size, Irp);
1056c2c66affSColin Finck             }
1057c2c66affSColin Finck 
1058c2c66affSColin Finck             ext = ExAllocatePoolWithTag(pooltype, offsetof(extent, extent_data) + tp.item->size, ALLOC_TAG);
1059c2c66affSColin Finck             if (!ext) {
1060c2c66affSColin Finck                 ERR("out of memory\n");
1061c2c66affSColin Finck                 free_fcb(Vcb, fcb);
1062c2c66affSColin Finck                 return STATUS_INSUFFICIENT_RESOURCES;
1063c2c66affSColin Finck             }
1064c2c66affSColin Finck 
1065c2c66affSColin Finck             ext->offset = tp.item->key.offset;
1066c2c66affSColin Finck             RtlCopyMemory(&ext->extent_data, tp.item->data, tp.item->size);
1067c2c66affSColin Finck             ext->datalen = tp.item->size;
1068c2c66affSColin Finck             ext->unique = unique;
1069c2c66affSColin Finck             ext->ignore = FALSE;
1070c2c66affSColin Finck             ext->inserted = FALSE;
1071c2c66affSColin Finck             ext->csum = NULL;
1072c2c66affSColin Finck 
1073c2c66affSColin Finck             InsertTailList(&fcb->extents, &ext->list_entry);
1074c2c66affSColin Finck         }
1075c2c66affSColin Finck     }
1076c2c66affSColin Finck 
1077c2c66affSColin Finck     if (fcb->type == BTRFS_TYPE_DIRECTORY) {
1078c2c66affSColin Finck         Status = load_dir_children(Vcb, fcb, FALSE, Irp);
1079c2c66affSColin Finck         if (!NT_SUCCESS(Status)) {
1080c2c66affSColin Finck             ERR("load_dir_children returned %08x\n", Status);
1081c2c66affSColin Finck             free_fcb(Vcb, fcb);
1082c2c66affSColin Finck             return Status;
1083c2c66affSColin Finck         }
1084c2c66affSColin Finck     }
1085c2c66affSColin Finck 
1086c2c66affSColin Finck     if (no_data) {
1087c2c66affSColin Finck         fcb->Header.AllocationSize.QuadPart = 0;
1088c2c66affSColin Finck         fcb->Header.FileSize.QuadPart = 0;
1089c2c66affSColin Finck         fcb->Header.ValidDataLength.QuadPart = 0;
1090c2c66affSColin Finck     } else {
1091c2c66affSColin Finck         if (ed && ed->type == EXTENT_TYPE_INLINE)
1092c2c66affSColin Finck             fcb->Header.AllocationSize.QuadPart = fcb->inode_item.st_size;
1093c2c66affSColin Finck         else
1094c2c66affSColin Finck             fcb->Header.AllocationSize.QuadPart = sector_align(fcb->inode_item.st_size, fcb->Vcb->superblock.sector_size);
1095c2c66affSColin Finck 
1096c2c66affSColin Finck         fcb->Header.FileSize.QuadPart = fcb->inode_item.st_size;
1097c2c66affSColin Finck         fcb->Header.ValidDataLength.QuadPart = fcb->inode_item.st_size;
1098c2c66affSColin Finck     }
1099c2c66affSColin Finck 
1100c2c66affSColin Finck     if (!atts_set)
1101c2c66affSColin Finck         fcb->atts = get_file_attributes(Vcb, fcb->subvol, fcb->inode, fcb->type, utf8 && utf8->Buffer[0] == '.', TRUE, Irp);
1102c2c66affSColin Finck 
1103c2c66affSColin Finck     if (!sd_set)
1104c2c66affSColin Finck         fcb_get_sd(fcb, parent, FALSE, Irp);
1105c2c66affSColin Finck 
1106c2c66affSColin Finck     if (fcb->type == BTRFS_TYPE_DIRECTORY && fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT && fcb->reparse_xattr.Length == 0) {
1107c2c66affSColin Finck         fcb->atts &= ~FILE_ATTRIBUTE_REPARSE_POINT;
1108c2c66affSColin Finck 
1109c2c66affSColin Finck         if (!Vcb->readonly && !is_subvol_readonly(subvol, Irp)) {
1110c2c66affSColin Finck             fcb->atts_changed = TRUE;
1111c2c66affSColin Finck             mark_fcb_dirty(fcb);
1112c2c66affSColin Finck         }
1113c2c66affSColin Finck     }
1114c2c66affSColin Finck 
1115c2c66affSColin Finck     if (lastle)
1116c2c66affSColin Finck         InsertHeadList(lastle, &fcb->list_entry);
1117c2c66affSColin Finck     else
1118c2c66affSColin Finck         InsertTailList(&subvol->fcbs, &fcb->list_entry);
1119c2c66affSColin Finck 
1120c2c66affSColin Finck     InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
1121c2c66affSColin Finck 
1122c2c66affSColin Finck     fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
1123c2c66affSColin Finck 
1124c2c66affSColin Finck     *pfcb = fcb;
1125c2c66affSColin Finck     return STATUS_SUCCESS;
1126c2c66affSColin Finck }
1127c2c66affSColin Finck 
1128c2c66affSColin Finck static NTSTATUS open_fcb_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension* Vcb,
1129c2c66affSColin Finck                                 dir_child* dc, fcb* parent, fcb** pfcb, PIRP Irp) {
1130c2c66affSColin Finck     fcb* fcb;
1131c2c66affSColin Finck     UINT8* xattrdata;
1132c2c66affSColin Finck     UINT16 xattrlen, overhead;
1133c2c66affSColin Finck     NTSTATUS Status;
1134c2c66affSColin Finck     KEY searchkey;
1135c2c66affSColin Finck     traverse_ptr tp;
1136*eb7fbc25SPierre Schweitzer     static const char xapref[] = "user.";
1137c2c66affSColin Finck     ANSI_STRING xattr;
1138c2c66affSColin Finck     UINT32 crc32;
1139c2c66affSColin Finck 
1140*eb7fbc25SPierre Schweitzer     xattr.Length = sizeof(xapref) - 1 + dc->utf8.Length;
1141c2c66affSColin Finck     xattr.MaximumLength = xattr.Length + 1;
1142c2c66affSColin Finck     xattr.Buffer = ExAllocatePoolWithTag(PagedPool, xattr.MaximumLength, ALLOC_TAG);
1143c2c66affSColin Finck     if (!xattr.Buffer) {
1144c2c66affSColin Finck         ERR("out of memory\n");
1145c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
1146c2c66affSColin Finck     }
1147c2c66affSColin Finck 
1148*eb7fbc25SPierre Schweitzer     RtlCopyMemory(xattr.Buffer, xapref, sizeof(xapref) - 1);
1149*eb7fbc25SPierre Schweitzer     RtlCopyMemory(&xattr.Buffer[sizeof(xapref) - 1], dc->utf8.Buffer, dc->utf8.Length);
1150c2c66affSColin Finck     xattr.Buffer[xattr.Length] = 0;
1151c2c66affSColin Finck 
1152c2c66affSColin Finck     fcb = create_fcb(Vcb, PagedPool);
1153c2c66affSColin Finck     if (!fcb) {
1154c2c66affSColin Finck         ERR("out of memory\n");
1155c2c66affSColin Finck         ExFreePool(xattr.Buffer);
1156c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
1157c2c66affSColin Finck     }
1158c2c66affSColin Finck 
1159c2c66affSColin Finck     fcb->Vcb = Vcb;
1160c2c66affSColin Finck 
1161c2c66affSColin Finck     crc32 = calc_crc32c(0xfffffffe, (UINT8*)xattr.Buffer, xattr.Length);
1162c2c66affSColin Finck 
1163c2c66affSColin Finck     if (!get_xattr(Vcb, parent->subvol, parent->inode, xattr.Buffer, crc32, &xattrdata, &xattrlen, Irp)) {
1164c2c66affSColin Finck         ERR("get_xattr failed\n");
1165c2c66affSColin Finck         free_fcb(Vcb, fcb);
1166c2c66affSColin Finck         ExFreePool(xattr.Buffer);
1167c2c66affSColin Finck         return STATUS_INTERNAL_ERROR;
1168c2c66affSColin Finck     }
1169c2c66affSColin Finck 
1170c2c66affSColin Finck     fcb->subvol = parent->subvol;
1171c2c66affSColin Finck     fcb->inode = parent->inode;
1172c2c66affSColin Finck     fcb->type = parent->type;
1173c2c66affSColin Finck     fcb->ads = TRUE;
1174c2c66affSColin Finck     fcb->adshash = crc32;
1175c2c66affSColin Finck     fcb->adsxattr = xattr;
1176c2c66affSColin Finck 
1177c2c66affSColin Finck     // find XATTR_ITEM overhead and hence calculate maximum length
1178c2c66affSColin Finck 
1179c2c66affSColin Finck     searchkey.obj_id = parent->inode;
1180c2c66affSColin Finck     searchkey.obj_type = TYPE_XATTR_ITEM;
1181c2c66affSColin Finck     searchkey.offset = crc32;
1182c2c66affSColin Finck 
1183c2c66affSColin Finck     Status = find_item(Vcb, parent->subvol, &tp, &searchkey, FALSE, Irp);
1184c2c66affSColin Finck     if (!NT_SUCCESS(Status)) {
1185c2c66affSColin Finck         ERR("find_item returned %08x\n", Status);
1186c2c66affSColin Finck         free_fcb(Vcb, fcb);
1187c2c66affSColin Finck         return Status;
1188c2c66affSColin Finck     }
1189c2c66affSColin Finck 
1190c2c66affSColin Finck     if (keycmp(tp.item->key, searchkey)) {
1191c2c66affSColin Finck         ERR("error - could not find key for xattr\n");
1192c2c66affSColin Finck         free_fcb(Vcb, fcb);
1193c2c66affSColin Finck         return STATUS_INTERNAL_ERROR;
1194c2c66affSColin Finck     }
1195c2c66affSColin Finck 
1196c2c66affSColin Finck     if (tp.item->size < xattrlen) {
1197c2c66affSColin Finck         ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, xattrlen);
1198c2c66affSColin Finck         free_fcb(Vcb, fcb);
1199c2c66affSColin Finck         return STATUS_INTERNAL_ERROR;
1200c2c66affSColin Finck     }
1201c2c66affSColin Finck 
1202c2c66affSColin Finck     overhead = tp.item->size - xattrlen;
1203c2c66affSColin Finck 
1204c2c66affSColin Finck     fcb->adsmaxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - overhead;
1205c2c66affSColin Finck 
1206c2c66affSColin Finck     fcb->adsdata.Buffer = (char*)xattrdata;
1207c2c66affSColin Finck     fcb->adsdata.Length = fcb->adsdata.MaximumLength = xattrlen;
1208c2c66affSColin Finck 
1209c2c66affSColin Finck     fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
1210c2c66affSColin Finck     fcb->Header.AllocationSize.QuadPart = xattrlen;
1211c2c66affSColin Finck     fcb->Header.FileSize.QuadPart = xattrlen;
1212c2c66affSColin Finck     fcb->Header.ValidDataLength.QuadPart = xattrlen;
1213c2c66affSColin Finck 
1214c2c66affSColin Finck     TRACE("stream found: size = %x, hash = %08x\n", xattrlen, fcb->adshash);
1215c2c66affSColin Finck 
1216c2c66affSColin Finck     InsertHeadList(&parent->list_entry, &fcb->list_entry);
1217c2c66affSColin Finck 
1218c2c66affSColin Finck     InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
1219c2c66affSColin Finck 
1220c2c66affSColin Finck     *pfcb = fcb;
1221c2c66affSColin Finck 
1222c2c66affSColin Finck     return STATUS_SUCCESS;
1223c2c66affSColin Finck }
1224c2c66affSColin Finck 
1225c2c66affSColin Finck NTSTATUS open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb,
1226c2c66affSColin Finck                             _In_ file_ref* sf, _In_ PUNICODE_STRING name, _In_ BOOL case_sensitive, _In_ BOOL lastpart, _In_ BOOL streampart,
1227c2c66affSColin Finck                             _In_ POOL_TYPE pooltype, _Out_ file_ref** psf2, _In_opt_ PIRP Irp) {
1228c2c66affSColin Finck     NTSTATUS Status;
1229c2c66affSColin Finck     file_ref* sf2;
1230c2c66affSColin Finck 
1231c2c66affSColin Finck     if (sf->fcb == Vcb->dummy_fcb)
1232c2c66affSColin Finck         return STATUS_OBJECT_NAME_NOT_FOUND;
1233c2c66affSColin Finck 
1234c2c66affSColin Finck     if (streampart) {
1235c2c66affSColin Finck         BOOL locked = FALSE;
1236c2c66affSColin Finck         LIST_ENTRY* le;
1237c2c66affSColin Finck         UNICODE_STRING name_uc;
1238c2c66affSColin Finck         dir_child* dc = NULL;
1239c2c66affSColin Finck         fcb* fcb;
1240c2c66affSColin Finck 
1241c2c66affSColin Finck         if (!case_sensitive) {
1242c2c66affSColin Finck             Status = RtlUpcaseUnicodeString(&name_uc, name, TRUE);
1243c2c66affSColin Finck             if (!NT_SUCCESS(Status)) {
1244c2c66affSColin Finck                 ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
1245c2c66affSColin Finck                 return Status;
1246c2c66affSColin Finck             }
1247c2c66affSColin Finck         }
1248c2c66affSColin Finck 
1249c2c66affSColin Finck         if (!ExIsResourceAcquiredSharedLite(&sf->fcb->nonpaged->dir_children_lock)) {
1250c2c66affSColin Finck             ExAcquireResourceSharedLite(&sf->fcb->nonpaged->dir_children_lock, TRUE);
1251c2c66affSColin Finck             locked = TRUE;
1252c2c66affSColin Finck         }
1253c2c66affSColin Finck 
1254c2c66affSColin Finck         le = sf->fcb->dir_children_index.Flink;
1255c2c66affSColin Finck         while (le != &sf->fcb->dir_children_index) {
1256c2c66affSColin Finck             dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_index);
1257c2c66affSColin Finck 
1258c2c66affSColin Finck             if (dc2->index == 0) {
1259c2c66affSColin Finck                 if ((case_sensitive && dc2->name.Length == name->Length && RtlCompareMemory(dc2->name.Buffer, name->Buffer, dc2->name.Length) == dc2->name.Length) ||
1260c2c66affSColin Finck                     (!case_sensitive && dc2->name_uc.Length == name_uc.Length && RtlCompareMemory(dc2->name_uc.Buffer, name_uc.Buffer, dc2->name_uc.Length) == dc2->name_uc.Length)
1261c2c66affSColin Finck                 ) {
1262c2c66affSColin Finck                     dc = dc2;
1263c2c66affSColin Finck                     break;
1264c2c66affSColin Finck                 }
1265c2c66affSColin Finck             } else
1266c2c66affSColin Finck                 break;
1267c2c66affSColin Finck 
1268c2c66affSColin Finck             le = le->Flink;
1269c2c66affSColin Finck         }
1270c2c66affSColin Finck 
1271c2c66affSColin Finck         if (!case_sensitive)
1272c2c66affSColin Finck             ExFreePool(name_uc.Buffer);
1273c2c66affSColin Finck 
1274c2c66affSColin Finck         if (locked)
1275c2c66affSColin Finck             ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock);
1276c2c66affSColin Finck 
1277c2c66affSColin Finck         if (!dc)
1278c2c66affSColin Finck             return STATUS_OBJECT_NAME_NOT_FOUND;
1279c2c66affSColin Finck 
1280c2c66affSColin Finck         if (dc->fileref) {
1281c2c66affSColin Finck             increase_fileref_refcount(dc->fileref);
1282c2c66affSColin Finck             *psf2 = dc->fileref;
1283c2c66affSColin Finck             return STATUS_SUCCESS;
1284c2c66affSColin Finck         }
1285c2c66affSColin Finck 
1286c2c66affSColin Finck         Status = open_fcb_stream(Vcb, dc, sf->fcb, &fcb, Irp);
1287c2c66affSColin Finck         if (!NT_SUCCESS(Status)) {
1288c2c66affSColin Finck             ERR("open_fcb_stream returned %08x\n", Status);
1289c2c66affSColin Finck             return Status;
1290c2c66affSColin Finck         }
1291c2c66affSColin Finck 
1292c2c66affSColin Finck         sf2 = create_fileref(Vcb);
1293c2c66affSColin Finck         if (!sf2) {
1294c2c66affSColin Finck             ERR("out of memory\n");
1295c2c66affSColin Finck             free_fcb(Vcb, fcb);
1296c2c66affSColin Finck             return STATUS_INSUFFICIENT_RESOURCES;
1297c2c66affSColin Finck         }
1298c2c66affSColin Finck 
1299c2c66affSColin Finck         sf2->fcb = fcb;
1300c2c66affSColin Finck 
1301c2c66affSColin Finck         sf2->parent = (struct _file_ref*)sf;
1302c2c66affSColin Finck 
1303c2c66affSColin Finck         sf2->dc = dc;
1304c2c66affSColin Finck         dc->fileref = sf2;
1305c2c66affSColin Finck 
1306c2c66affSColin Finck         ExAcquireResourceExclusiveLite(&sf->nonpaged->children_lock, TRUE);
1307c2c66affSColin Finck         InsertTailList(&sf->children, &sf2->list_entry);
1308c2c66affSColin Finck         ExReleaseResourceLite(&sf->nonpaged->children_lock);
1309c2c66affSColin Finck 
1310c2c66affSColin Finck         increase_fileref_refcount(sf);
1311c2c66affSColin Finck     } else {
1312c2c66affSColin Finck         root* subvol;
1313c2c66affSColin Finck         UINT64 inode;
1314c2c66affSColin Finck         dir_child* dc;
1315c2c66affSColin Finck 
1316c2c66affSColin Finck         Status = find_file_in_dir(name, sf->fcb, &subvol, &inode, &dc, case_sensitive);
1317c2c66affSColin Finck         if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
1318c2c66affSColin Finck             TRACE("could not find %.*S\n", name->Length / sizeof(WCHAR), name->Buffer);
1319c2c66affSColin Finck 
1320c2c66affSColin Finck             return lastpart ? STATUS_OBJECT_NAME_NOT_FOUND : STATUS_OBJECT_PATH_NOT_FOUND;
1321c2c66affSColin Finck         } else if (!NT_SUCCESS(Status)) {
1322c2c66affSColin Finck             ERR("find_file_in_dir returned %08x\n", Status);
1323c2c66affSColin Finck             return Status;
1324c2c66affSColin Finck         } else {
1325c2c66affSColin Finck             fcb* fcb;
1326c2c66affSColin Finck #ifdef DEBUG_STATS
1327c2c66affSColin Finck             LARGE_INTEGER time1, time2;
1328c2c66affSColin Finck #endif
1329c2c66affSColin Finck 
1330c2c66affSColin Finck             if (dc->fileref) {
1331c2c66affSColin Finck                 if (!lastpart && dc->type != BTRFS_TYPE_DIRECTORY) {
1332c2c66affSColin Finck                     TRACE("passed path including file as subdirectory\n");
1333c2c66affSColin Finck                     return STATUS_OBJECT_PATH_NOT_FOUND;
1334c2c66affSColin Finck                 }
1335c2c66affSColin Finck 
1336c2c66affSColin Finck                 InterlockedIncrement(&dc->fileref->refcount);
1337c2c66affSColin Finck                 *psf2 = dc->fileref;
1338c2c66affSColin Finck                 return STATUS_SUCCESS;
1339c2c66affSColin Finck             }
1340c2c66affSColin Finck 
1341c2c66affSColin Finck             if (!subvol || (subvol != Vcb->root_fileref->fcb->subvol && inode == SUBVOL_ROOT_INODE && subvol->parent != sf->fcb->subvol->id)) {
1342c2c66affSColin Finck                 fcb = Vcb->dummy_fcb;
1343c2c66affSColin Finck                 InterlockedIncrement(&fcb->refcount);
1344c2c66affSColin Finck             } else {
1345c2c66affSColin Finck #ifdef DEBUG_STATS
1346c2c66affSColin Finck                 time1 = KeQueryPerformanceCounter(NULL);
1347c2c66affSColin Finck #endif
1348c2c66affSColin Finck                 Status = open_fcb(Vcb, subvol, inode, dc->type, &dc->utf8, sf->fcb, &fcb, pooltype, Irp);
1349c2c66affSColin Finck #ifdef DEBUG_STATS
1350c2c66affSColin Finck                 time2 = KeQueryPerformanceCounter(NULL);
1351c2c66affSColin Finck                 Vcb->stats.open_fcb_calls++;
1352c2c66affSColin Finck                 Vcb->stats.open_fcb_time += time2.QuadPart - time1.QuadPart;
1353c2c66affSColin Finck #endif
1354c2c66affSColin Finck 
1355c2c66affSColin Finck                 if (!NT_SUCCESS(Status)) {
1356c2c66affSColin Finck                     ERR("open_fcb returned %08x\n", Status);
1357c2c66affSColin Finck                     return Status;
1358c2c66affSColin Finck                 }
1359c2c66affSColin Finck             }
1360c2c66affSColin Finck 
1361c2c66affSColin Finck             if (dc->type != BTRFS_TYPE_DIRECTORY && !lastpart && !(fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT)) {
1362c2c66affSColin Finck                 TRACE("passed path including file as subdirectory\n");
1363c2c66affSColin Finck                 free_fcb(Vcb, fcb);
1364c2c66affSColin Finck                 return STATUS_OBJECT_PATH_NOT_FOUND;
1365c2c66affSColin Finck             }
1366c2c66affSColin Finck 
1367c2c66affSColin Finck             sf2 = create_fileref(Vcb);
1368c2c66affSColin Finck             if (!sf2) {
1369c2c66affSColin Finck                 ERR("out of memory\n");
1370c2c66affSColin Finck                 free_fcb(Vcb, fcb);
1371c2c66affSColin Finck                 return STATUS_INSUFFICIENT_RESOURCES;
1372c2c66affSColin Finck             }
1373c2c66affSColin Finck 
1374c2c66affSColin Finck             sf2->fcb = fcb;
1375c2c66affSColin Finck 
1376c2c66affSColin Finck             if (dc->type == BTRFS_TYPE_DIRECTORY)
1377c2c66affSColin Finck                 fcb->fileref = sf2;
1378c2c66affSColin Finck 
1379c2c66affSColin Finck             sf2->dc = dc;
1380c2c66affSColin Finck             dc->fileref = sf2;
1381c2c66affSColin Finck 
1382c2c66affSColin Finck             sf2->parent = (struct _file_ref*)sf;
1383c2c66affSColin Finck 
1384c2c66affSColin Finck             ExAcquireResourceExclusiveLite(&sf->nonpaged->children_lock, TRUE);
1385c2c66affSColin Finck             InsertTailList(&sf->children, &sf2->list_entry);
1386c2c66affSColin Finck             ExReleaseResourceLite(&sf->nonpaged->children_lock);
1387c2c66affSColin Finck 
1388c2c66affSColin Finck             increase_fileref_refcount(sf);
1389c2c66affSColin Finck         }
1390c2c66affSColin Finck     }
1391c2c66affSColin Finck 
1392c2c66affSColin Finck     *psf2 = sf2;
1393c2c66affSColin Finck 
1394c2c66affSColin Finck     return STATUS_SUCCESS;
1395c2c66affSColin Finck }
1396c2c66affSColin Finck 
1397c2c66affSColin Finck NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _Out_ file_ref** pfr,
1398c2c66affSColin Finck                       _In_ PUNICODE_STRING fnus, _In_opt_ file_ref* related, _In_ BOOL parent, _Out_opt_ USHORT* parsed, _Out_opt_ ULONG* fn_offset, _In_ POOL_TYPE pooltype,
1399c2c66affSColin Finck                       _In_ BOOL case_sensitive, _In_opt_ PIRP Irp) {
1400c2c66affSColin Finck     UNICODE_STRING fnus2;
1401c2c66affSColin Finck     file_ref *dir, *sf, *sf2;
1402c2c66affSColin Finck     LIST_ENTRY parts;
1403c2c66affSColin Finck     BOOL has_stream;
1404c2c66affSColin Finck     NTSTATUS Status;
1405c2c66affSColin Finck     LIST_ENTRY* le;
1406c2c66affSColin Finck 
1407c2c66affSColin Finck     TRACE("(%p, %p, %p, %u, %p)\n", Vcb, pfr, related, parent, parsed);
1408c2c66affSColin Finck 
1409c2c66affSColin Finck #ifdef DEBUG
1410c2c66affSColin Finck     if (!ExIsResourceAcquiredExclusiveLite(&Vcb->fcb_lock) && !ExIsResourceAcquiredExclusiveLite(&Vcb->tree_lock)) {
1411c2c66affSColin Finck         ERR("fcb_lock not acquired exclusively\n");
1412c2c66affSColin Finck         int3;
1413c2c66affSColin Finck     }
1414c2c66affSColin Finck #endif
1415c2c66affSColin Finck 
1416c2c66affSColin Finck     if (Vcb->removing || Vcb->locked)
1417c2c66affSColin Finck         return STATUS_ACCESS_DENIED;
1418c2c66affSColin Finck 
1419c2c66affSColin Finck     fnus2 = *fnus;
1420c2c66affSColin Finck 
1421c2c66affSColin Finck     if (fnus2.Length < sizeof(WCHAR) && !related) {
1422c2c66affSColin Finck         ERR("error - fnus was too short\n");
1423c2c66affSColin Finck         return STATUS_INTERNAL_ERROR;
1424c2c66affSColin Finck     }
1425c2c66affSColin Finck 
1426c2c66affSColin Finck     if (related && fnus->Length == 0) {
1427c2c66affSColin Finck         increase_fileref_refcount(related);
1428c2c66affSColin Finck 
1429c2c66affSColin Finck         *pfr = related;
1430c2c66affSColin Finck         return STATUS_SUCCESS;
1431c2c66affSColin Finck     }
1432c2c66affSColin Finck 
1433c2c66affSColin Finck     if (related) {
1434c2c66affSColin Finck         dir = related;
1435c2c66affSColin Finck     } else {
1436c2c66affSColin Finck         if (fnus2.Buffer[0] != '\\') {
1437c2c66affSColin Finck             ERR("error - filename %.*S did not begin with \\\n", fnus2.Length / sizeof(WCHAR), fnus2.Buffer);
1438c2c66affSColin Finck             return STATUS_OBJECT_PATH_NOT_FOUND;
1439c2c66affSColin Finck         }
1440c2c66affSColin Finck 
14414672b2baSPierre Schweitzer         // if path starts with two backslashes, ignore one of them
14424672b2baSPierre Schweitzer         if (fnus2.Length >= 2 * sizeof(WCHAR) && fnus2.Buffer[1] == '\\') {
14434672b2baSPierre Schweitzer             fnus2.Buffer++;
14444672b2baSPierre Schweitzer             fnus2.Length -= sizeof(WCHAR);
14454672b2baSPierre Schweitzer             fnus2.MaximumLength -= sizeof(WCHAR);
14464672b2baSPierre Schweitzer         }
14474672b2baSPierre Schweitzer 
1448c2c66affSColin Finck         if (fnus2.Length == sizeof(WCHAR)) {
1449c2c66affSColin Finck             if (Vcb->root_fileref->open_count == 0 && !(Vcb->Vpb->Flags & VPB_MOUNTED)) // don't allow root to be opened on unmounted FS
1450c2c66affSColin Finck                 return STATUS_DEVICE_NOT_READY;
1451c2c66affSColin Finck 
1452c2c66affSColin Finck             increase_fileref_refcount(Vcb->root_fileref);
1453c2c66affSColin Finck             *pfr = Vcb->root_fileref;
1454c2c66affSColin Finck 
1455c2c66affSColin Finck             if (fn_offset)
1456c2c66affSColin Finck                 *fn_offset = 0;
1457c2c66affSColin Finck 
1458c2c66affSColin Finck             return STATUS_SUCCESS;
1459c2c66affSColin Finck         }
1460c2c66affSColin Finck 
1461c2c66affSColin Finck         dir = Vcb->root_fileref;
1462c2c66affSColin Finck 
1463c2c66affSColin Finck         fnus2.Buffer++;
1464c2c66affSColin Finck         fnus2.Length -= sizeof(WCHAR);
1465c2c66affSColin Finck         fnus2.MaximumLength -= sizeof(WCHAR);
1466c2c66affSColin Finck     }
1467c2c66affSColin Finck 
1468c2c66affSColin Finck     if (dir->fcb->type != BTRFS_TYPE_DIRECTORY && (fnus->Length < sizeof(WCHAR) || fnus->Buffer[0] != ':')) {
1469c2c66affSColin Finck         WARN("passed related fileref which isn't a directory (%S) (fnus = %.*S)\n",
1470c2c66affSColin Finck              file_desc_fileref(related), fnus->Length / sizeof(WCHAR), fnus->Buffer);
1471c2c66affSColin Finck         return STATUS_OBJECT_PATH_NOT_FOUND;
1472c2c66affSColin Finck     }
1473c2c66affSColin Finck 
1474c2c66affSColin Finck     InitializeListHead(&parts);
1475c2c66affSColin Finck 
1476c2c66affSColin Finck     if (fnus->Length != 0 &&
1477*eb7fbc25SPierre Schweitzer         (fnus->Length != sizeof(datastring) - sizeof(WCHAR) || RtlCompareMemory(fnus->Buffer, datastring, sizeof(datastring) - sizeof(WCHAR)) != sizeof(datastring) - sizeof(WCHAR))) {
1478c2c66affSColin Finck         Status = split_path(Vcb, &fnus2, &parts, &has_stream);
1479c2c66affSColin Finck         if (!NT_SUCCESS(Status)) {
1480c2c66affSColin Finck             ERR("split_path returned %08x\n", Status);
1481c2c66affSColin Finck             return Status;
1482c2c66affSColin Finck         }
1483c2c66affSColin Finck     }
1484c2c66affSColin Finck 
1485c2c66affSColin Finck     sf = dir;
1486c2c66affSColin Finck     increase_fileref_refcount(dir);
1487c2c66affSColin Finck 
1488c2c66affSColin Finck     if (parent && !IsListEmpty(&parts)) {
1489c2c66affSColin Finck         name_bit* nb;
1490c2c66affSColin Finck 
1491c2c66affSColin Finck         nb = CONTAINING_RECORD(RemoveTailList(&parts), name_bit, list_entry);
1492c2c66affSColin Finck         ExFreePool(nb);
1493c2c66affSColin Finck 
1494c2c66affSColin Finck         if (has_stream && !IsListEmpty(&parts)) {
1495c2c66affSColin Finck             nb = CONTAINING_RECORD(RemoveTailList(&parts), name_bit, list_entry);
1496c2c66affSColin Finck             ExFreePool(nb);
1497c2c66affSColin Finck 
1498c2c66affSColin Finck             has_stream = FALSE;
1499c2c66affSColin Finck         }
1500c2c66affSColin Finck     }
1501c2c66affSColin Finck 
1502c2c66affSColin Finck     if (IsListEmpty(&parts)) {
1503c2c66affSColin Finck         Status = STATUS_SUCCESS;
1504c2c66affSColin Finck         *pfr = dir;
1505c2c66affSColin Finck 
1506c2c66affSColin Finck         if (fn_offset)
1507c2c66affSColin Finck             *fn_offset = 0;
1508c2c66affSColin Finck 
1509c2c66affSColin Finck         goto end2;
1510c2c66affSColin Finck     }
1511c2c66affSColin Finck 
1512c2c66affSColin Finck     le = parts.Flink;
1513c2c66affSColin Finck     do {
1514c2c66affSColin Finck         name_bit* nb = CONTAINING_RECORD(le, name_bit, list_entry);
1515c2c66affSColin Finck         BOOL lastpart = le->Flink == &parts || (has_stream && le->Flink->Flink == &parts);
1516c2c66affSColin Finck         BOOL streampart = has_stream && le->Flink == &parts;
15174672b2baSPierre Schweitzer #ifdef DEBUG_STATS
15184672b2baSPierre Schweitzer         LARGE_INTEGER time1, time2;
15194672b2baSPierre Schweitzer #endif
1520c2c66affSColin Finck 
15214672b2baSPierre Schweitzer #ifdef DEBUG_STATS
15224672b2baSPierre Schweitzer         time1 = KeQueryPerformanceCounter(NULL);
15234672b2baSPierre Schweitzer #endif
1524c2c66affSColin Finck         Status = open_fileref_child(Vcb, sf, &nb->us, case_sensitive, lastpart, streampart, pooltype, &sf2, Irp);
15254672b2baSPierre Schweitzer #ifdef DEBUG_STATS
15264672b2baSPierre Schweitzer         time2 = KeQueryPerformanceCounter(NULL);
15274672b2baSPierre Schweitzer         Vcb->stats.open_fileref_child_calls++;
15284672b2baSPierre Schweitzer         Vcb->stats.open_fileref_child_time += time2.QuadPart - time1.QuadPart;
15294672b2baSPierre Schweitzer #endif
1530c2c66affSColin Finck         if (!NT_SUCCESS(Status)) {
1531c2c66affSColin Finck             if (Status == STATUS_OBJECT_PATH_NOT_FOUND || Status == STATUS_OBJECT_NAME_NOT_FOUND)
1532c2c66affSColin Finck                 TRACE("open_fileref_child returned %08x\n", Status);
1533c2c66affSColin Finck             else
1534c2c66affSColin Finck                 ERR("open_fileref_child returned %08x\n", Status);
1535c2c66affSColin Finck 
1536c2c66affSColin Finck             goto end;
1537c2c66affSColin Finck         }
1538c2c66affSColin Finck 
1539c2c66affSColin Finck         if (le->Flink == &parts) { // last entry
1540c2c66affSColin Finck             if (fn_offset) {
1541c2c66affSColin Finck                 if (has_stream)
1542c2c66affSColin Finck                     nb = CONTAINING_RECORD(le->Blink, name_bit, list_entry);
1543c2c66affSColin Finck 
1544c2c66affSColin Finck                 *fn_offset = (ULONG)(nb->us.Buffer - fnus->Buffer);
1545c2c66affSColin Finck             }
1546c2c66affSColin Finck 
1547c2c66affSColin Finck             break;
1548c2c66affSColin Finck         }
1549c2c66affSColin Finck 
1550c2c66affSColin Finck         if (sf2->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT) {
1551c2c66affSColin Finck             Status = STATUS_REPARSE;
1552c2c66affSColin Finck 
1553c2c66affSColin Finck             if (parsed) {
1554c2c66affSColin Finck                 name_bit* nb2 = CONTAINING_RECORD(le->Flink, name_bit, list_entry);
1555c2c66affSColin Finck 
1556c2c66affSColin Finck                 *parsed = (USHORT)(nb2->us.Buffer - fnus->Buffer - 1) * sizeof(WCHAR);
1557c2c66affSColin Finck             }
1558c2c66affSColin Finck 
1559c2c66affSColin Finck             break;
1560c2c66affSColin Finck         }
1561c2c66affSColin Finck 
1562c2c66affSColin Finck         free_fileref(Vcb, sf);
1563c2c66affSColin Finck         sf = sf2;
1564c2c66affSColin Finck 
1565c2c66affSColin Finck         le = le->Flink;
1566c2c66affSColin Finck     } while (le != &parts);
1567c2c66affSColin Finck 
1568c2c66affSColin Finck     if (Status != STATUS_REPARSE)
1569c2c66affSColin Finck         Status = STATUS_SUCCESS;
1570c2c66affSColin Finck     *pfr = sf2;
1571c2c66affSColin Finck 
1572c2c66affSColin Finck end:
1573c2c66affSColin Finck     free_fileref(Vcb, sf);
1574c2c66affSColin Finck 
1575c2c66affSColin Finck     while (!IsListEmpty(&parts)) {
1576c2c66affSColin Finck         name_bit* nb = CONTAINING_RECORD(RemoveHeadList(&parts), name_bit, list_entry);
1577c2c66affSColin Finck         ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb);
1578c2c66affSColin Finck     }
1579c2c66affSColin Finck 
1580c2c66affSColin Finck end2:
1581c2c66affSColin Finck     TRACE("returning %08x\n", Status);
1582c2c66affSColin Finck 
1583c2c66affSColin Finck     return Status;
1584c2c66affSColin Finck }
1585c2c66affSColin Finck 
1586c2c66affSColin Finck NTSTATUS add_dir_child(fcb* fcb, UINT64 inode, BOOL subvol, PANSI_STRING utf8, PUNICODE_STRING name, UINT8 type, dir_child** pdc) {
1587c2c66affSColin Finck     NTSTATUS Status;
1588c2c66affSColin Finck     dir_child* dc;
1589c2c66affSColin Finck 
1590c2c66affSColin Finck     dc = ExAllocatePoolWithTag(PagedPool, sizeof(dir_child), ALLOC_TAG);
1591c2c66affSColin Finck     if (!dc) {
1592c2c66affSColin Finck         ERR("out of memory\n");
1593c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
1594c2c66affSColin Finck     }
1595c2c66affSColin Finck 
1596c2c66affSColin Finck     dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, utf8->Length, ALLOC_TAG);
1597c2c66affSColin Finck     if (!dc->utf8.Buffer) {
1598c2c66affSColin Finck         ERR("out of memory\n");
1599c2c66affSColin Finck         ExFreePool(dc);
1600c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
1601c2c66affSColin Finck     }
1602c2c66affSColin Finck 
1603c2c66affSColin Finck     dc->name.Buffer = ExAllocatePoolWithTag(PagedPool, name->Length, ALLOC_TAG);
1604c2c66affSColin Finck     if (!dc->name.Buffer) {
1605c2c66affSColin Finck         ERR("out of memory\n");
1606c2c66affSColin Finck         ExFreePool(dc->utf8.Buffer);
1607c2c66affSColin Finck         ExFreePool(dc);
1608c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
1609c2c66affSColin Finck     }
1610c2c66affSColin Finck 
1611c2c66affSColin Finck     dc->key.obj_id = inode;
1612c2c66affSColin Finck     dc->key.obj_type = subvol ? TYPE_ROOT_ITEM : TYPE_INODE_ITEM;
1613c2c66affSColin Finck     dc->key.offset = subvol ? 0xffffffffffffffff : 0;
1614c2c66affSColin Finck     dc->type = type;
1615c2c66affSColin Finck     dc->fileref = NULL;
1616c2c66affSColin Finck 
1617c2c66affSColin Finck     dc->utf8.Length = dc->utf8.MaximumLength = utf8->Length;
1618c2c66affSColin Finck     RtlCopyMemory(dc->utf8.Buffer, utf8->Buffer, utf8->Length);
1619c2c66affSColin Finck 
1620c2c66affSColin Finck     dc->name.Length = dc->name.MaximumLength = name->Length;
1621c2c66affSColin Finck     RtlCopyMemory(dc->name.Buffer, name->Buffer, name->Length);
1622c2c66affSColin Finck 
1623c2c66affSColin Finck     Status = RtlUpcaseUnicodeString(&dc->name_uc, name, TRUE);
1624c2c66affSColin Finck     if (!NT_SUCCESS(Status)) {
1625c2c66affSColin Finck         ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
1626c2c66affSColin Finck         ExFreePool(dc->utf8.Buffer);
1627c2c66affSColin Finck         ExFreePool(dc->name.Buffer);
1628c2c66affSColin Finck         ExFreePool(dc);
1629c2c66affSColin Finck         return Status;
1630c2c66affSColin Finck     }
1631c2c66affSColin Finck 
1632c2c66affSColin Finck     dc->hash = calc_crc32c(0xffffffff, (UINT8*)dc->name.Buffer, dc->name.Length);
1633c2c66affSColin Finck     dc->hash_uc = calc_crc32c(0xffffffff, (UINT8*)dc->name_uc.Buffer, dc->name_uc.Length);
1634c2c66affSColin Finck 
1635c2c66affSColin Finck     ExAcquireResourceExclusiveLite(&fcb->nonpaged->dir_children_lock, TRUE);
1636c2c66affSColin Finck 
1637c2c66affSColin Finck     if (IsListEmpty(&fcb->dir_children_index))
1638c2c66affSColin Finck         dc->index = 2;
1639c2c66affSColin Finck     else {
1640c2c66affSColin Finck         dir_child* dc2 = CONTAINING_RECORD(fcb->dir_children_index.Blink, dir_child, list_entry_index);
1641c2c66affSColin Finck 
1642c2c66affSColin Finck         dc->index = max(2, dc2->index + 1);
1643c2c66affSColin Finck     }
1644c2c66affSColin Finck 
1645c2c66affSColin Finck     InsertTailList(&fcb->dir_children_index, &dc->list_entry_index);
1646c2c66affSColin Finck 
1647c2c66affSColin Finck     insert_dir_child_into_hash_lists(fcb, dc);
1648c2c66affSColin Finck 
1649c2c66affSColin Finck     ExReleaseResourceLite(&fcb->nonpaged->dir_children_lock);
1650c2c66affSColin Finck 
1651c2c66affSColin Finck     *pdc = dc;
1652c2c66affSColin Finck 
1653c2c66affSColin Finck     return STATUS_SUCCESS;
1654c2c66affSColin Finck }
1655c2c66affSColin Finck 
1656c2c66affSColin Finck UINT32 inherit_mode(fcb* parfcb, BOOL is_dir) {
1657c2c66affSColin Finck     UINT32 mode;
1658c2c66affSColin Finck 
1659c2c66affSColin Finck     if (!parfcb)
1660c2c66affSColin Finck         return 0755;
1661c2c66affSColin Finck 
1662c2c66affSColin Finck     mode = parfcb->inode_item.st_mode & ~S_IFDIR;
1663c2c66affSColin Finck     mode &= ~S_ISVTX; // clear sticky bit
1664c2c66affSColin Finck     mode &= ~S_ISUID; // clear setuid bit
1665c2c66affSColin Finck 
1666c2c66affSColin Finck     if (!is_dir)
1667c2c66affSColin Finck         mode &= ~S_ISGID; // if not directory, clear setgid bit
1668c2c66affSColin Finck 
1669c2c66affSColin Finck     return mode;
1670c2c66affSColin Finck }
1671c2c66affSColin Finck 
1672*eb7fbc25SPierre Schweitzer static NTSTATUS file_create_parse_ea(fcb* fcb, FILE_FULL_EA_INFORMATION* ea) {
1673*eb7fbc25SPierre Schweitzer     NTSTATUS Status;
1674*eb7fbc25SPierre Schweitzer     LIST_ENTRY ealist, *le;
1675*eb7fbc25SPierre Schweitzer     UINT16 size = 0;
1676*eb7fbc25SPierre Schweitzer     char* buf;
1677*eb7fbc25SPierre Schweitzer 
1678*eb7fbc25SPierre Schweitzer     InitializeListHead(&ealist);
1679*eb7fbc25SPierre Schweitzer 
1680*eb7fbc25SPierre Schweitzer     do {
1681*eb7fbc25SPierre Schweitzer         STRING s;
1682*eb7fbc25SPierre Schweitzer         BOOL found = FALSE;
1683*eb7fbc25SPierre Schweitzer 
1684*eb7fbc25SPierre Schweitzer         s.Length = s.MaximumLength = ea->EaNameLength;
1685*eb7fbc25SPierre Schweitzer         s.Buffer = ea->EaName;
1686*eb7fbc25SPierre Schweitzer 
1687*eb7fbc25SPierre Schweitzer         RtlUpperString(&s, &s);
1688*eb7fbc25SPierre Schweitzer 
1689*eb7fbc25SPierre Schweitzer         le = ealist.Flink;
1690*eb7fbc25SPierre Schweitzer         while (le != &ealist) {
1691*eb7fbc25SPierre Schweitzer             ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry);
1692*eb7fbc25SPierre Schweitzer 
1693*eb7fbc25SPierre Schweitzer             if (item->name.Length == s.Length && RtlCompareMemory(item->name.Buffer, s.Buffer, s.Length) == s.Length) {
1694*eb7fbc25SPierre Schweitzer                 item->flags = ea->Flags;
1695*eb7fbc25SPierre Schweitzer                 item->value.Length = item->value.MaximumLength = ea->EaValueLength;
1696*eb7fbc25SPierre Schweitzer                 item->value.Buffer = &ea->EaName[ea->EaNameLength + 1];
1697*eb7fbc25SPierre Schweitzer                 found = TRUE;
1698*eb7fbc25SPierre Schweitzer                 break;
1699*eb7fbc25SPierre Schweitzer             }
1700*eb7fbc25SPierre Schweitzer 
1701*eb7fbc25SPierre Schweitzer             le = le->Flink;
1702*eb7fbc25SPierre Schweitzer         }
1703*eb7fbc25SPierre Schweitzer 
1704*eb7fbc25SPierre Schweitzer         if (!found) {
1705*eb7fbc25SPierre Schweitzer             ea_item* item = ExAllocatePoolWithTag(PagedPool, sizeof(ea_item), ALLOC_TAG);
1706*eb7fbc25SPierre Schweitzer             if (!item) {
1707*eb7fbc25SPierre Schweitzer                 ERR("out of memory\n");
1708*eb7fbc25SPierre Schweitzer                 Status = STATUS_INSUFFICIENT_RESOURCES;
1709*eb7fbc25SPierre Schweitzer                 goto end;
1710*eb7fbc25SPierre Schweitzer             }
1711*eb7fbc25SPierre Schweitzer 
1712*eb7fbc25SPierre Schweitzer             item->name.Length = item->name.MaximumLength = ea->EaNameLength;
1713*eb7fbc25SPierre Schweitzer             item->name.Buffer = ea->EaName;
1714*eb7fbc25SPierre Schweitzer 
1715*eb7fbc25SPierre Schweitzer             item->value.Length = item->value.MaximumLength = ea->EaValueLength;
1716*eb7fbc25SPierre Schweitzer             item->value.Buffer = &ea->EaName[ea->EaNameLength + 1];
1717*eb7fbc25SPierre Schweitzer 
1718*eb7fbc25SPierre Schweitzer             item->flags = ea->Flags;
1719*eb7fbc25SPierre Schweitzer 
1720*eb7fbc25SPierre Schweitzer             InsertTailList(&ealist, &item->list_entry);
1721*eb7fbc25SPierre Schweitzer         }
1722*eb7fbc25SPierre Schweitzer 
1723*eb7fbc25SPierre Schweitzer         if (ea->NextEntryOffset == 0)
1724*eb7fbc25SPierre Schweitzer             break;
1725*eb7fbc25SPierre Schweitzer 
1726*eb7fbc25SPierre Schweitzer         ea = (FILE_FULL_EA_INFORMATION*)(((UINT8*)ea) + ea->NextEntryOffset);
1727*eb7fbc25SPierre Schweitzer     } while (TRUE);
1728*eb7fbc25SPierre Schweitzer 
1729*eb7fbc25SPierre Schweitzer     // handle LXSS values
1730*eb7fbc25SPierre Schweitzer     le = ealist.Flink;
1731*eb7fbc25SPierre Schweitzer     while (le != &ealist) {
1732*eb7fbc25SPierre Schweitzer         LIST_ENTRY* le2 = le->Flink;
1733*eb7fbc25SPierre Schweitzer         ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry);
1734*eb7fbc25SPierre Schweitzer 
1735*eb7fbc25SPierre Schweitzer         if (item->name.Length == sizeof(lxuid) - 1 && RtlCompareMemory(item->name.Buffer, lxuid, item->name.Length) == item->name.Length) {
1736*eb7fbc25SPierre Schweitzer             if (item->value.Length < sizeof(UINT32)) {
1737*eb7fbc25SPierre Schweitzer                 ERR("uid value was shorter than expected\n");
1738*eb7fbc25SPierre Schweitzer                 Status = STATUS_INVALID_PARAMETER;
1739*eb7fbc25SPierre Schweitzer                 goto end;
1740*eb7fbc25SPierre Schweitzer             }
1741*eb7fbc25SPierre Schweitzer 
1742*eb7fbc25SPierre Schweitzer             RtlCopyMemory(&fcb->inode_item.st_uid, item->value.Buffer, sizeof(UINT32));
1743*eb7fbc25SPierre Schweitzer             fcb->sd_dirty = TRUE;
1744*eb7fbc25SPierre Schweitzer             fcb->sd_deleted = FALSE;
1745*eb7fbc25SPierre Schweitzer 
1746*eb7fbc25SPierre Schweitzer             RemoveEntryList(&item->list_entry);
1747*eb7fbc25SPierre Schweitzer             ExFreePool(item);
1748*eb7fbc25SPierre Schweitzer         } else if (item->name.Length == sizeof(lxgid) - 1 && RtlCompareMemory(item->name.Buffer, lxgid, item->name.Length) == item->name.Length) {
1749*eb7fbc25SPierre Schweitzer             if (item->value.Length < sizeof(UINT32)) {
1750*eb7fbc25SPierre Schweitzer                 ERR("gid value was shorter than expected\n");
1751*eb7fbc25SPierre Schweitzer                 Status = STATUS_INVALID_PARAMETER;
1752*eb7fbc25SPierre Schweitzer                 goto end;
1753*eb7fbc25SPierre Schweitzer             }
1754*eb7fbc25SPierre Schweitzer 
1755*eb7fbc25SPierre Schweitzer             RtlCopyMemory(&fcb->inode_item.st_gid, item->value.Buffer, sizeof(UINT32));
1756*eb7fbc25SPierre Schweitzer 
1757*eb7fbc25SPierre Schweitzer             RemoveEntryList(&item->list_entry);
1758*eb7fbc25SPierre Schweitzer             ExFreePool(item);
1759*eb7fbc25SPierre Schweitzer         } else if (item->name.Length == sizeof(lxmod) - 1 && RtlCompareMemory(item->name.Buffer, lxmod, item->name.Length) == item->name.Length) {
1760*eb7fbc25SPierre Schweitzer             UINT32 allowed = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH | S_ISGID | S_ISVTX | S_ISUID;
1761*eb7fbc25SPierre Schweitzer             UINT32 val;
1762*eb7fbc25SPierre Schweitzer 
1763*eb7fbc25SPierre Schweitzer             if (item->value.Length < sizeof(UINT32)) {
1764*eb7fbc25SPierre Schweitzer                 ERR("mode value was shorter than expected\n");
1765*eb7fbc25SPierre Schweitzer                 Status = STATUS_INVALID_PARAMETER;
1766*eb7fbc25SPierre Schweitzer                 goto end;
1767*eb7fbc25SPierre Schweitzer             }
1768*eb7fbc25SPierre Schweitzer 
1769*eb7fbc25SPierre Schweitzer             RtlCopyMemory(&val, item->value.Buffer, sizeof(UINT32));
1770*eb7fbc25SPierre Schweitzer 
1771*eb7fbc25SPierre Schweitzer             if (fcb->type != BTRFS_TYPE_DIRECTORY)
1772*eb7fbc25SPierre Schweitzer                 allowed |= __S_IFIFO | __S_IFCHR | __S_IFBLK | __S_IFSOCK;
1773*eb7fbc25SPierre Schweitzer 
1774*eb7fbc25SPierre Schweitzer             fcb->inode_item.st_mode &= ~allowed;
1775*eb7fbc25SPierre Schweitzer             fcb->inode_item.st_mode |= val & allowed;
1776*eb7fbc25SPierre Schweitzer 
1777*eb7fbc25SPierre Schweitzer             if (fcb->type != BTRFS_TYPE_DIRECTORY) {
1778*eb7fbc25SPierre Schweitzer                 if ((fcb->inode_item.st_mode & __S_IFCHR) == __S_IFCHR)
1779*eb7fbc25SPierre Schweitzer                     fcb->type = BTRFS_TYPE_CHARDEV;
1780*eb7fbc25SPierre Schweitzer                 else if ((fcb->inode_item.st_mode & __S_IFBLK) == __S_IFBLK)
1781*eb7fbc25SPierre Schweitzer                     fcb->type = BTRFS_TYPE_BLOCKDEV;
1782*eb7fbc25SPierre Schweitzer                 else if ((fcb->inode_item.st_mode & __S_IFIFO) == __S_IFIFO)
1783*eb7fbc25SPierre Schweitzer                     fcb->type = BTRFS_TYPE_FIFO;
1784*eb7fbc25SPierre Schweitzer                 else if ((fcb->inode_item.st_mode & __S_IFSOCK) == __S_IFSOCK)
1785*eb7fbc25SPierre Schweitzer                     fcb->type = BTRFS_TYPE_SOCKET;
1786*eb7fbc25SPierre Schweitzer             }
1787*eb7fbc25SPierre Schweitzer 
1788*eb7fbc25SPierre Schweitzer             RemoveEntryList(&item->list_entry);
1789*eb7fbc25SPierre Schweitzer             ExFreePool(item);
1790*eb7fbc25SPierre Schweitzer         } else if (item->name.Length == sizeof(lxdev) - 1 && RtlCompareMemory(item->name.Buffer, lxdev, item->name.Length) == item->name.Length) {
1791*eb7fbc25SPierre Schweitzer             UINT32 major, minor;
1792*eb7fbc25SPierre Schweitzer 
1793*eb7fbc25SPierre Schweitzer             if (item->value.Length < sizeof(UINT64)) {
1794*eb7fbc25SPierre Schweitzer                 ERR("dev value was shorter than expected\n");
1795*eb7fbc25SPierre Schweitzer                 Status = STATUS_INVALID_PARAMETER;
1796*eb7fbc25SPierre Schweitzer                 goto end;
1797*eb7fbc25SPierre Schweitzer             }
1798*eb7fbc25SPierre Schweitzer 
1799*eb7fbc25SPierre Schweitzer             major = *(UINT32*)item->value.Buffer;
1800*eb7fbc25SPierre Schweitzer             minor = *(UINT32*)&item->value.Buffer[sizeof(UINT32)];
1801*eb7fbc25SPierre Schweitzer 
1802*eb7fbc25SPierre Schweitzer             fcb->inode_item.st_rdev = (minor & 0xFFFFF) | ((major & 0xFFFFFFFFFFF) << 20);
1803*eb7fbc25SPierre Schweitzer 
1804*eb7fbc25SPierre Schweitzer             RemoveEntryList(&item->list_entry);
1805*eb7fbc25SPierre Schweitzer             ExFreePool(item);
1806*eb7fbc25SPierre Schweitzer         }
1807*eb7fbc25SPierre Schweitzer 
1808*eb7fbc25SPierre Schweitzer         le = le2;
1809*eb7fbc25SPierre Schweitzer     }
1810*eb7fbc25SPierre Schweitzer 
1811*eb7fbc25SPierre Schweitzer     if (fcb->type != BTRFS_TYPE_CHARDEV && fcb->type != BTRFS_TYPE_BLOCKDEV)
1812*eb7fbc25SPierre Schweitzer         fcb->inode_item.st_rdev = 0;
1813*eb7fbc25SPierre Schweitzer 
1814*eb7fbc25SPierre Schweitzer     if (IsListEmpty(&ealist))
1815*eb7fbc25SPierre Schweitzer         return STATUS_SUCCESS;
1816*eb7fbc25SPierre Schweitzer 
1817*eb7fbc25SPierre Schweitzer     le = ealist.Flink;
1818*eb7fbc25SPierre Schweitzer     while (le != &ealist) {
1819*eb7fbc25SPierre Schweitzer         ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry);
1820*eb7fbc25SPierre Schweitzer 
1821*eb7fbc25SPierre Schweitzer         if (size % 4 > 0)
1822*eb7fbc25SPierre Schweitzer             size += 4 - (size % 4);
1823*eb7fbc25SPierre Schweitzer 
1824*eb7fbc25SPierre Schweitzer         size += (UINT16)offsetof(FILE_FULL_EA_INFORMATION, EaName[0]) + item->name.Length + 1 + item->value.Length;
1825*eb7fbc25SPierre Schweitzer 
1826*eb7fbc25SPierre Schweitzer         le = le->Flink;
1827*eb7fbc25SPierre Schweitzer     }
1828*eb7fbc25SPierre Schweitzer 
1829*eb7fbc25SPierre Schweitzer     buf = ExAllocatePoolWithTag(PagedPool, size, ALLOC_TAG);
1830*eb7fbc25SPierre Schweitzer     if (!buf) {
1831*eb7fbc25SPierre Schweitzer         ERR("out of memory\n");
1832*eb7fbc25SPierre Schweitzer         Status = STATUS_INSUFFICIENT_RESOURCES;
1833*eb7fbc25SPierre Schweitzer         goto end;
1834*eb7fbc25SPierre Schweitzer     }
1835*eb7fbc25SPierre Schweitzer 
1836*eb7fbc25SPierre Schweitzer     fcb->ea_xattr.Length = fcb->ea_xattr.MaximumLength = size;
1837*eb7fbc25SPierre Schweitzer     fcb->ea_xattr.Buffer = buf;
1838*eb7fbc25SPierre Schweitzer 
1839*eb7fbc25SPierre Schweitzer     fcb->ealen = 4;
1840*eb7fbc25SPierre Schweitzer     ea = NULL;
1841*eb7fbc25SPierre Schweitzer 
1842*eb7fbc25SPierre Schweitzer     le = ealist.Flink;
1843*eb7fbc25SPierre Schweitzer     while (le != &ealist) {
1844*eb7fbc25SPierre Schweitzer         ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry);
1845*eb7fbc25SPierre Schweitzer 
1846*eb7fbc25SPierre Schweitzer         if (ea) {
1847*eb7fbc25SPierre Schweitzer             ea->NextEntryOffset = (ULONG)offsetof(FILE_FULL_EA_INFORMATION, EaName[0]) + ea->EaNameLength + ea->EaValueLength;
1848*eb7fbc25SPierre Schweitzer 
1849*eb7fbc25SPierre Schweitzer             if (ea->NextEntryOffset % 4 > 0)
1850*eb7fbc25SPierre Schweitzer                 ea->NextEntryOffset += 4 - (ea->NextEntryOffset % 4);
1851*eb7fbc25SPierre Schweitzer 
1852*eb7fbc25SPierre Schweitzer             ea = (FILE_FULL_EA_INFORMATION*)(((UINT8*)ea) + ea->NextEntryOffset);
1853*eb7fbc25SPierre Schweitzer         } else
1854*eb7fbc25SPierre Schweitzer             ea = (FILE_FULL_EA_INFORMATION*)fcb->ea_xattr.Buffer;
1855*eb7fbc25SPierre Schweitzer 
1856*eb7fbc25SPierre Schweitzer         ea->NextEntryOffset = 0;
1857*eb7fbc25SPierre Schweitzer         ea->Flags = item->flags;
1858*eb7fbc25SPierre Schweitzer         ea->EaNameLength = (UCHAR)item->name.Length;
1859*eb7fbc25SPierre Schweitzer         ea->EaValueLength = item->value.Length;
1860*eb7fbc25SPierre Schweitzer 
1861*eb7fbc25SPierre Schweitzer         RtlCopyMemory(ea->EaName, item->name.Buffer, item->name.Length);
1862*eb7fbc25SPierre Schweitzer         ea->EaName[item->name.Length] = 0;
1863*eb7fbc25SPierre Schweitzer         RtlCopyMemory(&ea->EaName[item->name.Length + 1], item->value.Buffer, item->value.Length);
1864*eb7fbc25SPierre Schweitzer 
1865*eb7fbc25SPierre Schweitzer         fcb->ealen += 5 + item->name.Length + item->value.Length;
1866*eb7fbc25SPierre Schweitzer 
1867*eb7fbc25SPierre Schweitzer         le = le->Flink;
1868*eb7fbc25SPierre Schweitzer     }
1869*eb7fbc25SPierre Schweitzer 
1870*eb7fbc25SPierre Schweitzer     fcb->ea_changed = TRUE;
1871*eb7fbc25SPierre Schweitzer 
1872*eb7fbc25SPierre Schweitzer     Status = STATUS_SUCCESS;
1873*eb7fbc25SPierre Schweitzer 
1874*eb7fbc25SPierre Schweitzer end:
1875*eb7fbc25SPierre Schweitzer     while (!IsListEmpty(&ealist)) {
1876*eb7fbc25SPierre Schweitzer         ea_item* item = CONTAINING_RECORD(RemoveHeadList(&ealist), ea_item, list_entry);
1877*eb7fbc25SPierre Schweitzer 
1878*eb7fbc25SPierre Schweitzer         ExFreePool(item);
1879*eb7fbc25SPierre Schweitzer     }
1880*eb7fbc25SPierre Schweitzer 
1881*eb7fbc25SPierre Schweitzer     return Status;
1882*eb7fbc25SPierre Schweitzer }
1883*eb7fbc25SPierre Schweitzer 
1884c2c66affSColin Finck static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _In_ PUNICODE_STRING fpus,
1885c2c66affSColin Finck                              _In_ file_ref* parfileref, _In_ ULONG options, _In_reads_bytes_opt_(ealen) FILE_FULL_EA_INFORMATION* ea, _In_ ULONG ealen,
1886c2c66affSColin Finck                              _Out_ file_ref** pfr, _In_ LIST_ENTRY* rollback) {
1887c2c66affSColin Finck     NTSTATUS Status;
1888c2c66affSColin Finck     fcb* fcb;
1889c2c66affSColin Finck     ULONG utf8len;
1890c2c66affSColin Finck     char* utf8 = NULL;
1891c2c66affSColin Finck     UINT64 inode;
1892c2c66affSColin Finck     UINT8 type;
1893c2c66affSColin Finck     LARGE_INTEGER time;
1894c2c66affSColin Finck     BTRFS_TIME now;
1895c2c66affSColin Finck     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
1896c2c66affSColin Finck     POOL_TYPE pool_type = IrpSp->Flags & SL_OPEN_PAGING_FILE ? NonPagedPool : PagedPool;
1897c2c66affSColin Finck     USHORT defda;
1898c2c66affSColin Finck     file_ref* fileref;
1899c2c66affSColin Finck     dir_child* dc;
1900c2c66affSColin Finck     ANSI_STRING utf8as;
1901c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
1902c2c66affSColin Finck     LONG rc;
1903c2c66affSColin Finck #endif
1904c2c66affSColin Finck 
1905c2c66affSColin Finck     if (parfileref->fcb == Vcb->dummy_fcb)
1906c2c66affSColin Finck         return STATUS_ACCESS_DENIED;
1907c2c66affSColin Finck 
19084672b2baSPierre Schweitzer     if (options & FILE_DIRECTORY_FILE && IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_TEMPORARY)
19094672b2baSPierre Schweitzer         return STATUS_INVALID_PARAMETER;
19104672b2baSPierre Schweitzer 
1911c2c66affSColin Finck     Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, fpus->Buffer, fpus->Length);
1912c2c66affSColin Finck     if (!NT_SUCCESS(Status)) {
1913c2c66affSColin Finck         ERR("RtlUnicodeToUTF8N returned %08x\n", Status);
1914c2c66affSColin Finck         return Status;
1915c2c66affSColin Finck     }
1916c2c66affSColin Finck 
1917c2c66affSColin Finck     utf8 = ExAllocatePoolWithTag(pool_type, utf8len + 1, ALLOC_TAG);
1918c2c66affSColin Finck     if (!utf8) {
1919c2c66affSColin Finck         ERR("out of memory\n");
1920c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
1921c2c66affSColin Finck     }
1922c2c66affSColin Finck 
1923c2c66affSColin Finck     Status = RtlUnicodeToUTF8N(utf8, utf8len, &utf8len, fpus->Buffer, fpus->Length);
1924c2c66affSColin Finck     if (!NT_SUCCESS(Status)) {
1925c2c66affSColin Finck         ERR("RtlUnicodeToUTF8N returned %08x\n", Status);
1926c2c66affSColin Finck         ExFreePool(utf8);
1927c2c66affSColin Finck         return Status;
1928c2c66affSColin Finck     }
1929c2c66affSColin Finck 
1930c2c66affSColin Finck     utf8[utf8len] = 0;
1931c2c66affSColin Finck 
1932c2c66affSColin Finck     KeQuerySystemTime(&time);
1933c2c66affSColin Finck     win_time_to_unix(time, &now);
1934c2c66affSColin Finck 
1935c2c66affSColin Finck     TRACE("create file %.*S\n", fpus->Length / sizeof(WCHAR), fpus->Buffer);
1936c2c66affSColin Finck     ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
1937c2c66affSColin Finck     TRACE("parfileref->fcb->inode_item.st_size (inode %llx) was %llx\n", parfileref->fcb->inode, parfileref->fcb->inode_item.st_size);
1938c2c66affSColin Finck     parfileref->fcb->inode_item.st_size += utf8len * 2;
1939c2c66affSColin Finck     TRACE("parfileref->fcb->inode_item.st_size (inode %llx) now %llx\n", parfileref->fcb->inode, parfileref->fcb->inode_item.st_size);
1940c2c66affSColin Finck     parfileref->fcb->inode_item.transid = Vcb->superblock.generation;
1941c2c66affSColin Finck     parfileref->fcb->inode_item.sequence++;
1942c2c66affSColin Finck     parfileref->fcb->inode_item.st_ctime = now;
1943c2c66affSColin Finck     parfileref->fcb->inode_item.st_mtime = now;
1944c2c66affSColin Finck     ExReleaseResourceLite(parfileref->fcb->Header.Resource);
1945c2c66affSColin Finck 
1946c2c66affSColin Finck     parfileref->fcb->inode_item_changed = TRUE;
1947c2c66affSColin Finck     mark_fcb_dirty(parfileref->fcb);
1948c2c66affSColin Finck 
1949c2c66affSColin Finck     inode = InterlockedIncrement64(&parfileref->fcb->subvol->lastinode);
1950c2c66affSColin Finck 
1951c2c66affSColin Finck     type = options & FILE_DIRECTORY_FILE ? BTRFS_TYPE_DIRECTORY : BTRFS_TYPE_FILE;
1952c2c66affSColin Finck 
1953c2c66affSColin Finck     // FIXME - link FILE_ATTRIBUTE_READONLY to st_mode
1954c2c66affSColin Finck 
1955c2c66affSColin Finck     TRACE("requested attributes = %x\n", IrpSp->Parameters.Create.FileAttributes);
1956c2c66affSColin Finck 
19574672b2baSPierre Schweitzer     defda = 0;
1958c2c66affSColin Finck 
1959c2c66affSColin Finck     if (utf8[0] == '.')
1960c2c66affSColin Finck         defda |= FILE_ATTRIBUTE_HIDDEN;
1961c2c66affSColin Finck 
1962c2c66affSColin Finck     if (options & FILE_DIRECTORY_FILE) {
1963c2c66affSColin Finck         defda |= FILE_ATTRIBUTE_DIRECTORY;
1964c2c66affSColin Finck         IrpSp->Parameters.Create.FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
1965c2c66affSColin Finck     } else
1966c2c66affSColin Finck         IrpSp->Parameters.Create.FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
1967c2c66affSColin Finck 
19684672b2baSPierre Schweitzer     if (!(IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
19694672b2baSPierre Schweitzer         IrpSp->Parameters.Create.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
19704672b2baSPierre Schweitzer         defda |= FILE_ATTRIBUTE_ARCHIVE;
19714672b2baSPierre Schweitzer     }
19724672b2baSPierre Schweitzer 
1973c2c66affSColin Finck     TRACE("defda = %x\n", defda);
1974c2c66affSColin Finck 
1975c2c66affSColin Finck     if (IrpSp->Parameters.Create.FileAttributes == FILE_ATTRIBUTE_NORMAL)
1976c2c66affSColin Finck         IrpSp->Parameters.Create.FileAttributes = defda;
1977c2c66affSColin Finck 
1978c2c66affSColin Finck     fcb = create_fcb(Vcb, pool_type);
1979c2c66affSColin Finck     if (!fcb) {
1980c2c66affSColin Finck         ERR("out of memory\n");
1981c2c66affSColin Finck         ExFreePool(utf8);
1982c2c66affSColin Finck 
1983c2c66affSColin Finck         ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
1984c2c66affSColin Finck         parfileref->fcb->inode_item.st_size -= utf8len * 2;
1985c2c66affSColin Finck         ExReleaseResourceLite(parfileref->fcb->Header.Resource);
1986c2c66affSColin Finck 
1987c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
1988c2c66affSColin Finck     }
1989c2c66affSColin Finck 
1990c2c66affSColin Finck     fcb->Vcb = Vcb;
1991c2c66affSColin Finck 
1992c2c66affSColin Finck     if (IrpSp->Flags & SL_OPEN_PAGING_FILE) {
1993c2c66affSColin Finck         fcb->Header.Flags2 |= FSRTL_FLAG2_IS_PAGING_FILE;
1994c2c66affSColin Finck         Vcb->disallow_dismount = TRUE;
1995c2c66affSColin Finck     }
1996c2c66affSColin Finck 
1997c2c66affSColin Finck     fcb->inode_item.generation = Vcb->superblock.generation;
1998c2c66affSColin Finck     fcb->inode_item.transid = Vcb->superblock.generation;
1999c2c66affSColin Finck     fcb->inode_item.st_size = 0;
2000c2c66affSColin Finck     fcb->inode_item.st_blocks = 0;
2001c2c66affSColin Finck     fcb->inode_item.block_group = 0;
2002c2c66affSColin Finck     fcb->inode_item.st_nlink = 1;
2003c2c66affSColin Finck     fcb->inode_item.st_gid = GID_NOBODY; // FIXME?
2004c2c66affSColin Finck     fcb->inode_item.st_mode = inherit_mode(parfileref->fcb, type == BTRFS_TYPE_DIRECTORY); // use parent's permissions by default
2005c2c66affSColin Finck     fcb->inode_item.st_rdev = 0;
2006c2c66affSColin Finck     fcb->inode_item.flags = 0;
2007c2c66affSColin Finck     fcb->inode_item.sequence = 1;
2008c2c66affSColin Finck     fcb->inode_item.st_atime = now;
2009c2c66affSColin Finck     fcb->inode_item.st_ctime = now;
2010c2c66affSColin Finck     fcb->inode_item.st_mtime = now;
2011c2c66affSColin Finck     fcb->inode_item.otime = now;
2012c2c66affSColin Finck 
2013c2c66affSColin Finck     if (type == BTRFS_TYPE_DIRECTORY)
2014c2c66affSColin Finck         fcb->inode_item.st_mode |= S_IFDIR;
2015c2c66affSColin Finck     else {
2016c2c66affSColin Finck         fcb->inode_item.st_mode |= S_IFREG;
2017c2c66affSColin Finck         fcb->inode_item.st_mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH); // remove executable bit if not directory
2018c2c66affSColin Finck     }
2019c2c66affSColin Finck 
2020c2c66affSColin Finck     if (IrpSp->Flags & SL_OPEN_PAGING_FILE) {
2021c2c66affSColin Finck         fcb->inode_item.flags = BTRFS_INODE_NODATACOW | BTRFS_INODE_NODATASUM | BTRFS_INODE_NOCOMPRESS;
2022c2c66affSColin Finck     } else {
2023c2c66affSColin Finck         // inherit nodatacow flag from parent directory
2024c2c66affSColin Finck         if (parfileref->fcb->inode_item.flags & BTRFS_INODE_NODATACOW) {
2025c2c66affSColin Finck             fcb->inode_item.flags |= BTRFS_INODE_NODATACOW;
2026c2c66affSColin Finck 
2027c2c66affSColin Finck             if (type != BTRFS_TYPE_DIRECTORY)
2028c2c66affSColin Finck                 fcb->inode_item.flags |= BTRFS_INODE_NODATASUM;
2029c2c66affSColin Finck         }
2030c2c66affSColin Finck 
2031c2c66affSColin Finck         if (parfileref->fcb->inode_item.flags & BTRFS_INODE_COMPRESS)
2032c2c66affSColin Finck             fcb->inode_item.flags |= BTRFS_INODE_COMPRESS;
2033c2c66affSColin Finck     }
2034c2c66affSColin Finck 
2035c2c66affSColin Finck     fcb->prop_compression = parfileref->fcb->prop_compression;
2036c2c66affSColin Finck     fcb->prop_compression_changed = fcb->prop_compression != PropCompression_None;
2037c2c66affSColin Finck 
2038c2c66affSColin Finck     fcb->inode_item_changed = TRUE;
2039c2c66affSColin Finck 
2040c2c66affSColin Finck     fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
2041c2c66affSColin Finck     fcb->Header.AllocationSize.QuadPart = 0;
2042c2c66affSColin Finck     fcb->Header.FileSize.QuadPart = 0;
2043c2c66affSColin Finck     fcb->Header.ValidDataLength.QuadPart = 0;
2044c2c66affSColin Finck 
2045c2c66affSColin Finck     fcb->atts = IrpSp->Parameters.Create.FileAttributes & ~FILE_ATTRIBUTE_NORMAL;
2046c2c66affSColin Finck     fcb->atts_changed = fcb->atts != defda;
2047c2c66affSColin Finck 
2048c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
2049c2c66affSColin Finck     rc = InterlockedIncrement(&parfileref->fcb->refcount);
2050c2c66affSColin Finck     WARN("fcb %p: refcount now %i (%S)\n", parfileref->fcb, rc, file_desc_fileref(parfileref));
2051c2c66affSColin Finck #else
2052c2c66affSColin Finck     InterlockedIncrement(&parfileref->fcb->refcount);
2053c2c66affSColin Finck #endif
2054c2c66affSColin Finck     fcb->subvol = parfileref->fcb->subvol;
2055c2c66affSColin Finck     fcb->inode = inode;
2056c2c66affSColin Finck     fcb->type = type;
2057c2c66affSColin Finck     fcb->created = TRUE;
2058c2c66affSColin Finck     fcb->deleted = TRUE;
2059c2c66affSColin Finck 
2060c2c66affSColin Finck     mark_fcb_dirty(fcb);
2061c2c66affSColin Finck 
2062c2c66affSColin Finck     Status = fcb_get_new_sd(fcb, parfileref, IrpSp->Parameters.Create.SecurityContext->AccessState);
2063c2c66affSColin Finck 
2064c2c66affSColin Finck     if (!NT_SUCCESS(Status)) {
2065c2c66affSColin Finck         ERR("fcb_get_new_sd returned %08x\n", Status);
2066c2c66affSColin Finck         free_fcb(Vcb, fcb);
2067c2c66affSColin Finck 
2068c2c66affSColin Finck         ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
2069c2c66affSColin Finck         parfileref->fcb->inode_item.st_size -= utf8len * 2;
2070c2c66affSColin Finck         ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2071c2c66affSColin Finck 
2072c2c66affSColin Finck         return Status;
2073c2c66affSColin Finck     }
2074c2c66affSColin Finck 
2075c2c66affSColin Finck     fcb->sd_dirty = TRUE;
2076c2c66affSColin Finck 
2077c2c66affSColin Finck     if (ea && ealen > 0) {
2078*eb7fbc25SPierre Schweitzer         Status = file_create_parse_ea(fcb, ea);
2079*eb7fbc25SPierre Schweitzer         if (!NT_SUCCESS(Status)) {
2080*eb7fbc25SPierre Schweitzer             ERR("file_create_parse_ea returned %08x\n", Status);
2081c2c66affSColin Finck             free_fcb(Vcb, fcb);
2082c2c66affSColin Finck 
2083c2c66affSColin Finck             ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
2084c2c66affSColin Finck             parfileref->fcb->inode_item.st_size -= utf8len * 2;
2085c2c66affSColin Finck             ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2086c2c66affSColin Finck 
2087*eb7fbc25SPierre Schweitzer             return Status;
2088c2c66affSColin Finck         }
2089c2c66affSColin Finck     }
2090c2c66affSColin Finck 
2091c2c66affSColin Finck     fileref = create_fileref(Vcb);
2092c2c66affSColin Finck     if (!fileref) {
2093c2c66affSColin Finck         ERR("out of memory\n");
2094c2c66affSColin Finck         free_fcb(Vcb, fcb);
2095c2c66affSColin Finck 
2096c2c66affSColin Finck         ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
2097c2c66affSColin Finck         parfileref->fcb->inode_item.st_size -= utf8len * 2;
2098c2c66affSColin Finck         ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2099c2c66affSColin Finck 
2100c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
2101c2c66affSColin Finck     }
2102c2c66affSColin Finck 
2103c2c66affSColin Finck     fileref->fcb = fcb;
2104c2c66affSColin Finck 
2105c2c66affSColin Finck     if (Irp->Overlay.AllocationSize.QuadPart > 0 && !write_fcb_compressed(fcb)) {
2106c2c66affSColin Finck         Status = extend_file(fcb, fileref, Irp->Overlay.AllocationSize.QuadPart, TRUE, NULL, rollback);
2107c2c66affSColin Finck 
2108c2c66affSColin Finck         if (!NT_SUCCESS(Status)) {
2109c2c66affSColin Finck             ERR("extend_file returned %08x\n", Status);
2110c2c66affSColin Finck             free_fileref(Vcb, fileref);
2111c2c66affSColin Finck 
2112c2c66affSColin Finck             ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
2113c2c66affSColin Finck             parfileref->fcb->inode_item.st_size -= utf8len * 2;
2114c2c66affSColin Finck             ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2115c2c66affSColin Finck 
2116c2c66affSColin Finck             return Status;
2117c2c66affSColin Finck         }
2118c2c66affSColin Finck     }
2119c2c66affSColin Finck 
2120c2c66affSColin Finck     if (fcb->type == BTRFS_TYPE_DIRECTORY) {
2121c2c66affSColin Finck         fcb->hash_ptrs = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG);
2122c2c66affSColin Finck         if (!fcb->hash_ptrs) {
2123c2c66affSColin Finck             ERR("out of memory\n");
2124c2c66affSColin Finck             free_fileref(Vcb, fileref);
2125c2c66affSColin Finck 
2126c2c66affSColin Finck             ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
2127c2c66affSColin Finck             parfileref->fcb->inode_item.st_size -= utf8len * 2;
2128c2c66affSColin Finck             ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2129c2c66affSColin Finck 
2130c2c66affSColin Finck             return STATUS_INSUFFICIENT_RESOURCES;
2131c2c66affSColin Finck         }
2132c2c66affSColin Finck 
2133c2c66affSColin Finck         RtlZeroMemory(fcb->hash_ptrs, sizeof(LIST_ENTRY*) * 256);
2134c2c66affSColin Finck 
2135c2c66affSColin Finck         fcb->hash_ptrs_uc = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG);
2136c2c66affSColin Finck         if (!fcb->hash_ptrs_uc) {
2137c2c66affSColin Finck             ERR("out of memory\n");
2138c2c66affSColin Finck             free_fileref(Vcb, fileref);
2139c2c66affSColin Finck 
2140c2c66affSColin Finck             ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
2141c2c66affSColin Finck             parfileref->fcb->inode_item.st_size -= utf8len * 2;
2142c2c66affSColin Finck             ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2143c2c66affSColin Finck 
2144c2c66affSColin Finck             return STATUS_INSUFFICIENT_RESOURCES;
2145c2c66affSColin Finck         }
2146c2c66affSColin Finck 
2147c2c66affSColin Finck         RtlZeroMemory(fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256);
2148c2c66affSColin Finck     }
2149c2c66affSColin Finck 
2150c2c66affSColin Finck     fcb->deleted = FALSE;
2151c2c66affSColin Finck 
2152c2c66affSColin Finck     fileref->created = TRUE;
2153c2c66affSColin Finck     mark_fileref_dirty(fileref);
2154c2c66affSColin Finck 
2155c2c66affSColin Finck     fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
2156c2c66affSColin Finck     fcb->subvol->root_item.ctime = now;
2157c2c66affSColin Finck 
2158c2c66affSColin Finck     fileref->parent = parfileref;
2159c2c66affSColin Finck 
2160c2c66affSColin Finck     utf8as.Buffer = utf8;
2161c2c66affSColin Finck     utf8as.Length = utf8as.MaximumLength = (UINT16)utf8len;
2162c2c66affSColin Finck 
2163c2c66affSColin Finck     Status = add_dir_child(fileref->parent->fcb, fcb->inode, FALSE, &utf8as, fpus, fcb->type, &dc);
2164c2c66affSColin Finck     if (!NT_SUCCESS(Status))
2165c2c66affSColin Finck         WARN("add_dir_child returned %08x\n", Status);
2166c2c66affSColin Finck 
2167c2c66affSColin Finck     ExFreePool(utf8);
2168c2c66affSColin Finck 
2169c2c66affSColin Finck     fileref->dc = dc;
2170c2c66affSColin Finck     dc->fileref = fileref;
2171c2c66affSColin Finck 
2172c2c66affSColin Finck     ExAcquireResourceExclusiveLite(&parfileref->nonpaged->children_lock, TRUE);
2173c2c66affSColin Finck     InsertTailList(&parfileref->children, &fileref->list_entry);
2174c2c66affSColin Finck     ExReleaseResourceLite(&parfileref->nonpaged->children_lock);
2175c2c66affSColin Finck 
2176c2c66affSColin Finck     increase_fileref_refcount(parfileref);
2177c2c66affSColin Finck 
2178c2c66affSColin Finck     InsertTailList(&fcb->subvol->fcbs, &fcb->list_entry);
2179c2c66affSColin Finck     InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
2180c2c66affSColin Finck 
2181c2c66affSColin Finck     *pfr = fileref;
2182c2c66affSColin Finck 
2183c2c66affSColin Finck     if (type == BTRFS_TYPE_DIRECTORY)
2184c2c66affSColin Finck         fileref->fcb->fileref = fileref;
2185c2c66affSColin Finck 
2186c2c66affSColin Finck     TRACE("created new file %S in subvol %llx, inode %llx\n", file_desc_fileref(fileref), fcb->subvol->id, fcb->inode);
2187c2c66affSColin Finck 
2188c2c66affSColin Finck     return STATUS_SUCCESS;
2189c2c66affSColin Finck }
2190c2c66affSColin Finck 
2191c2c66affSColin Finck static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension* Vcb,
2192c2c66affSColin Finck                               file_ref** pfileref, file_ref** pparfileref, PUNICODE_STRING fpus, PUNICODE_STRING stream, PIRP Irp,
2193c2c66affSColin Finck                               ULONG options, POOL_TYPE pool_type, BOOL case_sensitive, LIST_ENTRY* rollback) {
2194c2c66affSColin Finck     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
2195c2c66affSColin Finck     file_ref *fileref, *newpar, *parfileref;
2196c2c66affSColin Finck     fcb* fcb;
2197*eb7fbc25SPierre Schweitzer     static const char xapref[] = "user.";
2198*eb7fbc25SPierre Schweitzer     static const WCHAR DOSATTRIB[] = L"DOSATTRIB";
2199*eb7fbc25SPierre Schweitzer     static const WCHAR EA[] = L"EA";
2200*eb7fbc25SPierre Schweitzer     static const WCHAR reparse[] = L"reparse";
2201c2c66affSColin Finck     LARGE_INTEGER time;
2202c2c66affSColin Finck     BTRFS_TIME now;
2203c2c66affSColin Finck     ULONG utf8len, overhead;
2204c2c66affSColin Finck     NTSTATUS Status;
2205c2c66affSColin Finck     KEY searchkey;
2206c2c66affSColin Finck     traverse_ptr tp;
2207c2c66affSColin Finck     dir_child* dc;
2208c2c66affSColin Finck     ACCESS_MASK granted_access;
2209c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
2210c2c66affSColin Finck     LONG rc;
2211c2c66affSColin Finck #endif
2212c2c66affSColin Finck 
2213c2c66affSColin Finck     TRACE("fpus = %.*S\n", fpus->Length / sizeof(WCHAR), fpus->Buffer);
2214c2c66affSColin Finck     TRACE("stream = %.*S\n", stream->Length / sizeof(WCHAR), stream->Buffer);
2215c2c66affSColin Finck 
2216c2c66affSColin Finck     parfileref = *pparfileref;
2217c2c66affSColin Finck 
2218c2c66affSColin Finck     if (parfileref->fcb == Vcb->dummy_fcb)
2219c2c66affSColin Finck         return STATUS_ACCESS_DENIED;
2220c2c66affSColin Finck 
2221c2c66affSColin Finck     Status = open_fileref(Vcb, &newpar, fpus, parfileref, FALSE, NULL, NULL, PagedPool, case_sensitive, Irp);
2222c2c66affSColin Finck 
2223c2c66affSColin Finck     if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
2224c2c66affSColin Finck         UNICODE_STRING fpus2;
2225c2c66affSColin Finck 
2226c2c66affSColin Finck         if (!is_file_name_valid(fpus, FALSE))
2227c2c66affSColin Finck             return STATUS_OBJECT_NAME_INVALID;
2228c2c66affSColin Finck 
2229c2c66affSColin Finck         fpus2.Length = fpus2.MaximumLength = fpus->Length;
2230c2c66affSColin Finck         fpus2.Buffer = ExAllocatePoolWithTag(pool_type, fpus2.MaximumLength, ALLOC_TAG);
2231c2c66affSColin Finck 
2232c2c66affSColin Finck         if (!fpus2.Buffer) {
2233c2c66affSColin Finck             ERR("out of memory\n");
2234c2c66affSColin Finck             return STATUS_INSUFFICIENT_RESOURCES;
2235c2c66affSColin Finck         }
2236c2c66affSColin Finck 
2237c2c66affSColin Finck         RtlCopyMemory(fpus2.Buffer, fpus->Buffer, fpus2.Length);
2238c2c66affSColin Finck 
2239c2c66affSColin Finck         SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2240c2c66affSColin Finck 
2241c2c66affSColin Finck         if (!SeAccessCheck(parfileref->fcb->sd, &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
2242c2c66affSColin Finck                            TRUE, options & FILE_DIRECTORY_FILE ? FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE, 0, NULL,
2243c2c66affSColin Finck                            IoGetFileObjectGenericMapping(), IrpSp->Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode,
2244c2c66affSColin Finck                            &granted_access, &Status)) {
2245c2c66affSColin Finck             SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2246c2c66affSColin Finck             return Status;
2247c2c66affSColin Finck         }
2248c2c66affSColin Finck 
2249c2c66affSColin Finck         SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2250c2c66affSColin Finck 
2251c2c66affSColin Finck         Status = file_create2(Irp, Vcb, &fpus2, parfileref, options, NULL, 0, &newpar, rollback);
2252c2c66affSColin Finck 
2253c2c66affSColin Finck         if (!NT_SUCCESS(Status)) {
2254c2c66affSColin Finck             ERR("file_create2 returned %08x\n", Status);
2255c2c66affSColin Finck             ExFreePool(fpus2.Buffer);
2256c2c66affSColin Finck             return Status;
2257c2c66affSColin Finck         }
2258c2c66affSColin Finck 
2259c2c66affSColin Finck         send_notification_fileref(newpar, options & FILE_DIRECTORY_FILE ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, NULL);
2260c2c66affSColin Finck         send_notification_fcb(newpar->parent, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL);
2261c2c66affSColin Finck     } else if (!NT_SUCCESS(Status)) {
2262c2c66affSColin Finck         ERR("open_fileref returned %08x\n", Status);
2263c2c66affSColin Finck         return Status;
2264c2c66affSColin Finck     }
2265c2c66affSColin Finck 
2266c2c66affSColin Finck     parfileref = newpar;
2267c2c66affSColin Finck     *pparfileref = parfileref;
2268c2c66affSColin Finck 
2269c2c66affSColin Finck     if (parfileref->fcb->type != BTRFS_TYPE_FILE && parfileref->fcb->type != BTRFS_TYPE_SYMLINK && parfileref->fcb->type != BTRFS_TYPE_DIRECTORY) {
2270c2c66affSColin Finck         WARN("parent not file, directory, or symlink\n");
2271c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
2272c2c66affSColin Finck     }
2273c2c66affSColin Finck 
2274c2c66affSColin Finck     if (options & FILE_DIRECTORY_FILE) {
2275c2c66affSColin Finck         WARN("tried to create directory as stream\n");
2276c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
2277c2c66affSColin Finck     }
2278c2c66affSColin Finck 
2279c2c66affSColin Finck     if (parfileref->fcb->atts & FILE_ATTRIBUTE_READONLY)
2280c2c66affSColin Finck         return STATUS_ACCESS_DENIED;
2281c2c66affSColin Finck 
2282c2c66affSColin Finck     SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2283c2c66affSColin Finck 
2284c2c66affSColin Finck     if (!SeAccessCheck(parfileref->fcb->sd, &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
2285c2c66affSColin Finck                        TRUE, FILE_WRITE_DATA, 0, NULL, IoGetFileObjectGenericMapping(), IrpSp->Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode,
2286c2c66affSColin Finck                        &granted_access, &Status)) {
2287c2c66affSColin Finck         SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2288c2c66affSColin Finck         return Status;
2289c2c66affSColin Finck     }
2290c2c66affSColin Finck 
2291c2c66affSColin Finck     SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2292c2c66affSColin Finck 
2293*eb7fbc25SPierre Schweitzer     if ((stream->Length == sizeof(DOSATTRIB) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, DOSATTRIB, stream->Length) == stream->Length) ||
2294*eb7fbc25SPierre Schweitzer         (stream->Length == sizeof(EA) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, EA, stream->Length) == stream->Length) ||
2295*eb7fbc25SPierre Schweitzer         (stream->Length == sizeof(reparse) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, reparse, stream->Length) == stream->Length)) {
2296c2c66affSColin Finck         return STATUS_OBJECT_NAME_INVALID;
2297c2c66affSColin Finck     }
2298c2c66affSColin Finck 
2299c2c66affSColin Finck     fcb = create_fcb(Vcb, pool_type);
2300c2c66affSColin Finck     if (!fcb) {
2301c2c66affSColin Finck         ERR("out of memory\n");
2302c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
2303c2c66affSColin Finck     }
2304c2c66affSColin Finck 
2305c2c66affSColin Finck     fcb->Vcb = Vcb;
2306c2c66affSColin Finck 
2307c2c66affSColin Finck     fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
2308c2c66affSColin Finck     fcb->Header.AllocationSize.QuadPart = 0;
2309c2c66affSColin Finck     fcb->Header.FileSize.QuadPart = 0;
2310c2c66affSColin Finck     fcb->Header.ValidDataLength.QuadPart = 0;
2311c2c66affSColin Finck 
2312c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
2313c2c66affSColin Finck     rc = InterlockedIncrement(&parfileref->fcb->refcount);
2314c2c66affSColin Finck     WARN("fcb %p: refcount now %i (%S)\n", parfileref->fcb, rc, file_desc_fileref(parfileref));
2315c2c66affSColin Finck #else
2316c2c66affSColin Finck     InterlockedIncrement(&parfileref->fcb->refcount);
2317c2c66affSColin Finck #endif
2318c2c66affSColin Finck     fcb->subvol = parfileref->fcb->subvol;
2319c2c66affSColin Finck     fcb->inode = parfileref->fcb->inode;
2320c2c66affSColin Finck     fcb->type = parfileref->fcb->type;
2321c2c66affSColin Finck 
2322c2c66affSColin Finck     fcb->ads = TRUE;
2323c2c66affSColin Finck 
2324c2c66affSColin Finck     Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, stream->Buffer, stream->Length);
2325c2c66affSColin Finck     if (!NT_SUCCESS(Status)) {
2326c2c66affSColin Finck         ERR("RtlUnicodeToUTF8N 1 returned %08x\n", Status);
2327c2c66affSColin Finck         free_fcb(Vcb, fcb);
2328c2c66affSColin Finck         return Status;
2329c2c66affSColin Finck     }
2330c2c66affSColin Finck 
2331*eb7fbc25SPierre Schweitzer     fcb->adsxattr.Length = (UINT16)utf8len + sizeof(xapref) - 1;
2332c2c66affSColin Finck     fcb->adsxattr.MaximumLength = fcb->adsxattr.Length + 1;
2333c2c66affSColin Finck     fcb->adsxattr.Buffer = ExAllocatePoolWithTag(pool_type, fcb->adsxattr.MaximumLength, ALLOC_TAG);
2334c2c66affSColin Finck     if (!fcb->adsxattr.Buffer) {
2335c2c66affSColin Finck         ERR("out of memory\n");
2336c2c66affSColin Finck         free_fcb(Vcb, fcb);
2337c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
2338c2c66affSColin Finck     }
2339c2c66affSColin Finck 
2340*eb7fbc25SPierre Schweitzer     RtlCopyMemory(fcb->adsxattr.Buffer, xapref, sizeof(xapref) - 1);
2341c2c66affSColin Finck 
2342*eb7fbc25SPierre Schweitzer     Status = RtlUnicodeToUTF8N(&fcb->adsxattr.Buffer[sizeof(xapref) - 1], utf8len, &utf8len, stream->Buffer, stream->Length);
2343c2c66affSColin Finck     if (!NT_SUCCESS(Status)) {
2344c2c66affSColin Finck         ERR("RtlUnicodeToUTF8N 2 returned %08x\n", Status);
2345c2c66affSColin Finck         free_fcb(Vcb, fcb);
2346c2c66affSColin Finck         return Status;
2347c2c66affSColin Finck     }
2348c2c66affSColin Finck 
2349c2c66affSColin Finck     fcb->adsxattr.Buffer[fcb->adsxattr.Length] = 0;
2350c2c66affSColin Finck 
2351c2c66affSColin Finck     TRACE("adsxattr = %s\n", fcb->adsxattr.Buffer);
2352c2c66affSColin Finck 
2353c2c66affSColin Finck     fcb->adshash = calc_crc32c(0xfffffffe, (UINT8*)fcb->adsxattr.Buffer, fcb->adsxattr.Length);
2354c2c66affSColin Finck     TRACE("adshash = %08x\n", fcb->adshash);
2355c2c66affSColin Finck 
2356c2c66affSColin Finck     searchkey.obj_id = parfileref->fcb->inode;
2357c2c66affSColin Finck     searchkey.obj_type = TYPE_XATTR_ITEM;
2358c2c66affSColin Finck     searchkey.offset = fcb->adshash;
2359c2c66affSColin Finck 
2360c2c66affSColin Finck     Status = find_item(Vcb, parfileref->fcb->subvol, &tp, &searchkey, FALSE, Irp);
2361c2c66affSColin Finck     if (!NT_SUCCESS(Status)) {
2362c2c66affSColin Finck         ERR("find_item returned %08x\n", Status);
2363c2c66affSColin Finck         free_fcb(Vcb, fcb);
2364c2c66affSColin Finck         return Status;
2365c2c66affSColin Finck     }
2366c2c66affSColin Finck 
2367c2c66affSColin Finck     if (!keycmp(tp.item->key, searchkey))
2368c2c66affSColin Finck         overhead = tp.item->size;
2369c2c66affSColin Finck     else
2370c2c66affSColin Finck         overhead = 0;
2371c2c66affSColin Finck 
2372c2c66affSColin Finck     fcb->adsmaxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - (sizeof(DIR_ITEM) - 1);
2373c2c66affSColin Finck 
2374*eb7fbc25SPierre Schweitzer     if (utf8len + sizeof(xapref) - 1 + overhead > fcb->adsmaxlen) {
2375*eb7fbc25SPierre Schweitzer         WARN("not enough room for new DIR_ITEM (%u + %u > %u)", utf8len + sizeof(xapref) - 1, overhead, fcb->adsmaxlen);
2376c2c66affSColin Finck         free_fcb(Vcb, fcb);
2377c2c66affSColin Finck         return STATUS_DISK_FULL;
2378c2c66affSColin Finck     } else
2379*eb7fbc25SPierre Schweitzer         fcb->adsmaxlen -= overhead + utf8len + sizeof(xapref) - 1;
2380c2c66affSColin Finck 
2381c2c66affSColin Finck     fileref = create_fileref(Vcb);
2382c2c66affSColin Finck     if (!fileref) {
2383c2c66affSColin Finck         ERR("out of memory\n");
2384c2c66affSColin Finck         free_fcb(Vcb, fcb);
2385c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
2386c2c66affSColin Finck     }
2387c2c66affSColin Finck 
2388c2c66affSColin Finck     fileref->fcb = fcb;
2389c2c66affSColin Finck 
2390c2c66affSColin Finck     dc = ExAllocatePoolWithTag(PagedPool, sizeof(dir_child), ALLOC_TAG);
2391c2c66affSColin Finck     if (!dc) {
2392c2c66affSColin Finck         ERR("out of memory\n");
2393c2c66affSColin Finck         free_fileref(Vcb, fileref);
2394c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
2395c2c66affSColin Finck     }
2396c2c66affSColin Finck 
2397c2c66affSColin Finck     RtlZeroMemory(dc, sizeof(dir_child));
2398c2c66affSColin Finck 
2399*eb7fbc25SPierre Schweitzer     dc->utf8.MaximumLength = dc->utf8.Length = fcb->adsxattr.Length + 1 - sizeof(xapref);
2400c2c66affSColin Finck     dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, dc->utf8.MaximumLength, ALLOC_TAG);
2401c2c66affSColin Finck     if (!dc->utf8.Buffer) {
2402c2c66affSColin Finck         ERR("out of memory\n");
2403c2c66affSColin Finck         ExFreePool(dc);
2404c2c66affSColin Finck         free_fileref(Vcb, fileref);
2405c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
2406c2c66affSColin Finck     }
2407c2c66affSColin Finck 
2408*eb7fbc25SPierre Schweitzer     RtlCopyMemory(dc->utf8.Buffer, &fcb->adsxattr.Buffer[sizeof(xapref) - 1], fcb->adsxattr.Length + 1 - sizeof(xapref));
2409c2c66affSColin Finck 
2410c2c66affSColin Finck     dc->name.MaximumLength = dc->name.Length = stream->Length;
2411c2c66affSColin Finck     dc->name.Buffer = ExAllocatePoolWithTag(pool_type, dc->name.MaximumLength, ALLOC_TAG);
2412c2c66affSColin Finck     if (!dc->name.Buffer) {
2413c2c66affSColin Finck         ERR("out of memory\n");
2414c2c66affSColin Finck         ExFreePool(dc->utf8.Buffer);
2415c2c66affSColin Finck         ExFreePool(dc);
2416c2c66affSColin Finck         free_fileref(Vcb, fileref);
2417c2c66affSColin Finck         return STATUS_INSUFFICIENT_RESOURCES;
2418c2c66affSColin Finck     }
2419c2c66affSColin Finck 
2420c2c66affSColin Finck     RtlCopyMemory(dc->name.Buffer, stream->Buffer, stream->Length);
2421c2c66affSColin Finck 
2422c2c66affSColin Finck     Status = RtlUpcaseUnicodeString(&dc->name_uc, &dc->name, TRUE);
2423c2c66affSColin Finck     if (!NT_SUCCESS(Status)) {
2424c2c66affSColin Finck         ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
2425c2c66affSColin Finck         ExFreePool(dc->utf8.Buffer);
2426c2c66affSColin Finck         ExFreePool(dc->name.Buffer);
2427c2c66affSColin Finck         ExFreePool(dc);
2428c2c66affSColin Finck         free_fileref(Vcb, fileref);
2429c2c66affSColin Finck         return Status;
2430c2c66affSColin Finck     }
2431c2c66affSColin Finck 
2432c2c66affSColin Finck     dc->fileref = fileref;
2433c2c66affSColin Finck     fileref->dc = dc;
2434c2c66affSColin Finck 
2435c2c66affSColin Finck     InsertHeadList(&parfileref->fcb->dir_children_index, &dc->list_entry_index);
2436c2c66affSColin Finck 
2437c2c66affSColin Finck     mark_fcb_dirty(fcb);
2438c2c66affSColin Finck     mark_fileref_dirty(fileref);
2439c2c66affSColin Finck 
2440c2c66affSColin Finck     InsertHeadList(&parfileref->fcb->list_entry, &fcb->list_entry); // insert in list after parent fcb
2441c2c66affSColin Finck     InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
2442c2c66affSColin Finck 
2443c2c66affSColin Finck     KeQuerySystemTime(&time);
2444c2c66affSColin Finck     win_time_to_unix(time, &now);
2445c2c66affSColin Finck 
2446c2c66affSColin Finck     parfileref->fcb->inode_item.transid = Vcb->superblock.generation;
2447c2c66affSColin Finck     parfileref->fcb->inode_item.sequence++;
2448c2c66affSColin Finck     parfileref->fcb->inode_item.st_ctime = now;
2449c2c66affSColin Finck     parfileref->fcb->inode_item_changed = TRUE;
2450c2c66affSColin Finck 
2451c2c66affSColin Finck     mark_fcb_dirty(parfileref->fcb);
2452c2c66affSColin Finck 
2453c2c66affSColin Finck     parfileref->fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
2454c2c66affSColin Finck     parfileref->fcb->subvol->root_item.ctime = now;
2455c2c66affSColin Finck 
2456c2c66affSColin Finck     fileref->parent = (struct _file_ref*)parfileref;
2457c2c66affSColin Finck 
2458c2c66affSColin Finck     ExAcquireResourceExclusiveLite(&parfileref->nonpaged->children_lock, TRUE);
2459c2c66affSColin Finck     InsertTailList(&parfileref->children, &fileref->list_entry);
2460c2c66affSColin Finck     ExReleaseResourceLite(&parfileref->nonpaged->children_lock);
2461c2c66affSColin Finck 
2462c2c66affSColin Finck     increase_fileref_refcount(parfileref);
2463c2c66affSColin Finck 
2464c2c66affSColin Finck     *pfileref = fileref;
2465c2c66affSColin Finck 
24664672b2baSPierre Schweitzer     send_notification_fileref(parfileref, FILE_NOTIFY_CHANGE_STREAM_NAME, FILE_ACTION_ADDED_STREAM, &fileref->dc->name);
2467c2c66affSColin Finck 
2468c2c66affSColin Finck     return STATUS_SUCCESS;
2469c2c66affSColin Finck }
2470c2c66affSColin Finck 
2471c2c66affSColin Finck // LXSS programs can be distinguished by the fact they have a NULL PEB.
2472c2c66affSColin Finck #ifdef _AMD64_
247360733590STimo Kreuzer #ifdef __REACTOS__
247460733590STimo Kreuzer NTSYSAPI
247560733590STimo Kreuzer NTSTATUS
247660733590STimo Kreuzer NTAPI
247760733590STimo Kreuzer ZwQueryInformationProcess (
247860733590STimo Kreuzer     _In_ HANDLE ProcessHandle,
247960733590STimo Kreuzer     _In_ PROCESSINFOCLASS ProcessInformationClass,
248060733590STimo Kreuzer     _Out_ PVOID ProcessInformation,
248160733590STimo Kreuzer     _In_ ULONG ProcessInformationLength,
248260733590STimo Kreuzer     _Out_opt_ PULONG ReturnLength
248360733590STimo Kreuzer );
248460733590STimo Kreuzer #endif
2485c2c66affSColin Finck static __inline BOOL called_from_lxss() {
2486c2c66affSColin Finck     NTSTATUS Status;
2487c2c66affSColin Finck     PROCESS_BASIC_INFORMATION pbi;
2488c2c66affSColin Finck     ULONG retlen;
2489c2c66affSColin Finck 
2490c2c66affSColin Finck     Status = ZwQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), &retlen);
2491c2c66affSColin Finck 
2492c2c66affSColin Finck     if (!NT_SUCCESS(Status)) {
2493c2c66affSColin Finck         ERR("ZwQueryInformationProcess returned %08x\n", Status);
2494c2c66affSColin Finck         return FALSE;
2495c2c66affSColin Finck     }
2496c2c66affSColin Finck 
2497c2c66affSColin Finck     return !pbi.PebBaseAddress;
2498c2c66affSColin Finck }
2499c2c66affSColin Finck #else
2500c2c66affSColin Finck #define called_from_lxss() FALSE
2501c2c66affSColin Finck #endif
2502c2c66affSColin Finck 
2503c2c66affSColin Finck static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension* Vcb,
2504c2c66affSColin Finck                             PFILE_OBJECT FileObject, file_ref* related, BOOL loaded_related, PUNICODE_STRING fnus, ULONG disposition, ULONG options, LIST_ENTRY* rollback) {
2505c2c66affSColin Finck     NTSTATUS Status;
2506c2c66affSColin Finck     file_ref *fileref, *parfileref = NULL;
2507c2c66affSColin Finck     ULONG i, j;
2508c2c66affSColin Finck     ccb* ccb;
2509*eb7fbc25SPierre Schweitzer     static const WCHAR datasuf[] = {':','$','D','A','T','A',0};
2510c2c66affSColin Finck     UNICODE_STRING dsus, fpus, stream;
2511c2c66affSColin Finck     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
2512c2c66affSColin Finck     POOL_TYPE pool_type = IrpSp->Flags & SL_OPEN_PAGING_FILE ? NonPagedPool : PagedPool;
2513*eb7fbc25SPierre Schweitzer #ifndef __REACTOS__
2514*eb7fbc25SPierre Schweitzer     ECP_LIST* ecp_list;
2515*eb7fbc25SPierre Schweitzer     ATOMIC_CREATE_ECP_CONTEXT* acec = NULL;
2516*eb7fbc25SPierre Schweitzer #endif
2517c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
2518c2c66affSColin Finck     LONG oc;
2519c2c66affSColin Finck #endif
2520c2c66affSColin Finck 
2521c2c66affSColin Finck     TRACE("(%p, %p, %p, %.*S, %x, %x)\n", Irp, Vcb, FileObject, fnus->Length / sizeof(WCHAR), fnus->Buffer, disposition, options);
2522c2c66affSColin Finck 
2523c2c66affSColin Finck     if (Vcb->readonly)
2524c2c66affSColin Finck         return STATUS_MEDIA_WRITE_PROTECTED;
2525c2c66affSColin Finck 
25264672b2baSPierre Schweitzer     if (options & FILE_DELETE_ON_CLOSE && IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_READONLY)
25274672b2baSPierre Schweitzer         return STATUS_CANNOT_DELETE;
25284672b2baSPierre Schweitzer 
2529*eb7fbc25SPierre Schweitzer #ifndef __REACTOS__
2530*eb7fbc25SPierre Schweitzer     if (NT_SUCCESS(FsRtlGetEcpListFromIrp(Irp, &ecp_list)) && ecp_list) {
2531*eb7fbc25SPierre Schweitzer         void* ctx = NULL;
2532*eb7fbc25SPierre Schweitzer         GUID type;
2533*eb7fbc25SPierre Schweitzer         ULONG ctxsize;
2534*eb7fbc25SPierre Schweitzer 
2535*eb7fbc25SPierre Schweitzer         do {
2536*eb7fbc25SPierre Schweitzer             Status = FsRtlGetNextExtraCreateParameter(ecp_list, ctx, &type, &ctx, &ctxsize);
2537*eb7fbc25SPierre Schweitzer 
2538*eb7fbc25SPierre Schweitzer             if (NT_SUCCESS(Status)) {
2539*eb7fbc25SPierre Schweitzer                 if (RtlCompareMemory(&type, &GUID_ECP_ATOMIC_CREATE, sizeof(GUID)) == sizeof(GUID) && ctxsize >= sizeof(ATOMIC_CREATE_ECP_CONTEXT)) {
2540*eb7fbc25SPierre Schweitzer                     acec = ctx;
2541*eb7fbc25SPierre Schweitzer                     break;
2542*eb7fbc25SPierre Schweitzer                 }
2543*eb7fbc25SPierre Schweitzer             }
2544*eb7fbc25SPierre Schweitzer         } while (NT_SUCCESS(Status));
2545*eb7fbc25SPierre Schweitzer     }
2546*eb7fbc25SPierre Schweitzer #endif
2547*eb7fbc25SPierre Schweitzer 
2548*eb7fbc25SPierre Schweitzer     dsus.Buffer = (WCHAR*)datasuf;
2549*eb7fbc25SPierre Schweitzer     dsus.Length = dsus.MaximumLength = sizeof(datasuf) - sizeof(WCHAR);
2550c2c66affSColin Finck     fpus.Buffer = NULL;
2551c2c66affSColin Finck 
2552c2c66affSColin Finck     if (!loaded_related) {
2553c2c66affSColin Finck         Status = open_fileref(Vcb, &parfileref, fnus, related, TRUE, NULL, NULL, pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp);
2554c2c66affSColin Finck 
2555c2c66affSColin Finck         if (!NT_SUCCESS(Status))
2556c2c66affSColin Finck             goto end;
2557c2c66affSColin Finck     } else
2558c2c66affSColin Finck         parfileref = related;
2559c2c66affSColin Finck 
2560c2c66affSColin Finck     if (parfileref->fcb->type != BTRFS_TYPE_DIRECTORY && (fnus->Length < sizeof(WCHAR) || fnus->Buffer[0] != ':')) {
2561c2c66affSColin Finck         Status = STATUS_OBJECT_PATH_NOT_FOUND;
2562c2c66affSColin Finck         goto end;
2563c2c66affSColin Finck     }
2564c2c66affSColin Finck 
2565c2c66affSColin Finck     if (is_subvol_readonly(parfileref->fcb->subvol, Irp)) {
2566c2c66affSColin Finck         Status = STATUS_ACCESS_DENIED;
2567c2c66affSColin Finck         goto end;
2568c2c66affSColin Finck     }
2569c2c66affSColin Finck 
2570c2c66affSColin Finck     i = (fnus->Length / sizeof(WCHAR))-1;
2571c2c66affSColin Finck     while ((fnus->Buffer[i] == '\\' || fnus->Buffer[i] == '/') && i > 0) { i--; }
2572c2c66affSColin Finck 
2573c2c66affSColin Finck     j = i;
2574c2c66affSColin Finck 
2575c2c66affSColin Finck     while (i > 0 && fnus->Buffer[i-1] != '\\' && fnus->Buffer[i-1] != '/') { i--; }
2576c2c66affSColin Finck 
2577c2c66affSColin Finck     fpus.MaximumLength = (USHORT)((j - i + 2) * sizeof(WCHAR));
2578c2c66affSColin Finck     fpus.Buffer = ExAllocatePoolWithTag(pool_type, fpus.MaximumLength, ALLOC_TAG);
2579c2c66affSColin Finck     if (!fpus.Buffer) {
2580c2c66affSColin Finck         ERR("out of memory\n");
2581c2c66affSColin Finck         Status = STATUS_INSUFFICIENT_RESOURCES;
2582c2c66affSColin Finck         goto end;
2583c2c66affSColin Finck     }
2584c2c66affSColin Finck 
2585c2c66affSColin Finck     fpus.Length = (USHORT)((j - i + 1) * sizeof(WCHAR));
2586c2c66affSColin Finck 
2587c2c66affSColin Finck     RtlCopyMemory(fpus.Buffer, &fnus->Buffer[i], (j - i + 1) * sizeof(WCHAR));
2588c2c66affSColin Finck     fpus.Buffer[j - i + 1] = 0;
2589c2c66affSColin Finck 
2590c2c66affSColin Finck     if (fpus.Length > dsus.Length) { // check for :$DATA suffix
2591c2c66affSColin Finck         UNICODE_STRING lb;
2592c2c66affSColin Finck 
2593c2c66affSColin Finck         lb.Buffer = &fpus.Buffer[(fpus.Length - dsus.Length)/sizeof(WCHAR)];
2594c2c66affSColin Finck         lb.Length = lb.MaximumLength = dsus.Length;
2595c2c66affSColin Finck 
2596c2c66affSColin Finck         TRACE("lb = %.*S\n", lb.Length/sizeof(WCHAR), lb.Buffer);
2597c2c66affSColin Finck 
2598c2c66affSColin Finck         if (FsRtlAreNamesEqual(&dsus, &lb, TRUE, NULL)) {
2599c2c66affSColin Finck             TRACE("ignoring :$DATA suffix\n");
2600c2c66affSColin Finck 
2601c2c66affSColin Finck             fpus.Length -= lb.Length;
2602c2c66affSColin Finck 
2603c2c66affSColin Finck             if (fpus.Length > sizeof(WCHAR) && fpus.Buffer[(fpus.Length-1)/sizeof(WCHAR)] == ':')
2604c2c66affSColin Finck                 fpus.Length -= sizeof(WCHAR);
2605c2c66affSColin Finck 
2606c2c66affSColin Finck             TRACE("fpus = %.*S\n", fpus.Length / sizeof(WCHAR), fpus.Buffer);
2607c2c66affSColin Finck         }
2608c2c66affSColin Finck     }
2609c2c66affSColin Finck 
2610c2c66affSColin Finck     stream.Length = 0;
2611c2c66affSColin Finck 
2612c2c66affSColin Finck     for (i = 0; i < fpus.Length / sizeof(WCHAR); i++) {
2613c2c66affSColin Finck         if (fpus.Buffer[i] == ':') {
2614c2c66affSColin Finck             stream.Length = (USHORT)(fpus.Length - (i * sizeof(WCHAR)) - sizeof(WCHAR));
2615c2c66affSColin Finck             stream.Buffer = &fpus.Buffer[i+1];
2616c2c66affSColin Finck             fpus.Buffer[i] = 0;
2617c2c66affSColin Finck             fpus.Length = (USHORT)(i * sizeof(WCHAR));
2618c2c66affSColin Finck             break;
2619c2c66affSColin Finck         }
2620c2c66affSColin Finck     }
2621c2c66affSColin Finck 
2622c2c66affSColin Finck     if (stream.Length > 0) {
2623c2c66affSColin Finck         Status = create_stream(Vcb, &fileref, &parfileref, &fpus, &stream, Irp, options, pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, rollback);
2624c2c66affSColin Finck         if (!NT_SUCCESS(Status)) {
2625c2c66affSColin Finck             ERR("create_stream returned %08x\n", Status);
2626c2c66affSColin Finck             goto end;
2627c2c66affSColin Finck         }
2628c2c66affSColin Finck 
2629c2c66affSColin Finck         IoSetShareAccess(IrpSp->Parameters.Create.SecurityContext->DesiredAccess, IrpSp->Parameters.Create.ShareAccess,
2630c2c66affSColin Finck                          FileObject, &fileref->fcb->share_access);
2631c2c66affSColin Finck     } else {
2632c2c66affSColin Finck         ACCESS_MASK granted_access;
2633c2c66affSColin Finck 
2634c2c66affSColin Finck         if (!is_file_name_valid(&fpus, FALSE)) {
2635c2c66affSColin Finck             Status = STATUS_OBJECT_NAME_INVALID;
2636c2c66affSColin Finck             goto end;
2637c2c66affSColin Finck         }
2638c2c66affSColin Finck 
2639c2c66affSColin Finck         SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2640c2c66affSColin Finck 
2641c2c66affSColin Finck         if (!SeAccessCheck(parfileref->fcb->sd, &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
2642c2c66affSColin Finck                            TRUE, options & FILE_DIRECTORY_FILE ? FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE, 0, NULL,
2643c2c66affSColin Finck                            IoGetFileObjectGenericMapping(), IrpSp->Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode,
2644c2c66affSColin Finck                            &granted_access, &Status)) {
2645c2c66affSColin Finck             SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2646c2c66affSColin Finck             goto end;
2647c2c66affSColin Finck         }
2648c2c66affSColin Finck 
2649c2c66affSColin Finck         SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2650c2c66affSColin Finck 
2651c2c66affSColin Finck         if (Irp->AssociatedIrp.SystemBuffer && IrpSp->Parameters.Create.EaLength > 0) {
2652c2c66affSColin Finck             ULONG offset;
2653c2c66affSColin Finck 
2654c2c66affSColin Finck             Status = IoCheckEaBufferValidity(Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.Create.EaLength, &offset);
2655c2c66affSColin Finck             if (!NT_SUCCESS(Status)) {
2656c2c66affSColin Finck                 ERR("IoCheckEaBufferValidity returned %08x (error at offset %u)\n", Status, offset);
2657c2c66affSColin Finck                 goto end;
2658c2c66affSColin Finck             }
2659c2c66affSColin Finck         }
2660c2c66affSColin Finck 
2661c2c66affSColin Finck         Status = file_create2(Irp, Vcb, &fpus, parfileref, options, Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.Create.EaLength,
2662c2c66affSColin Finck                               &fileref, rollback);
2663c2c66affSColin Finck 
2664c2c66affSColin Finck         if (!NT_SUCCESS(Status)) {
2665c2c66affSColin Finck             ERR("file_create2 returned %08x\n", Status);
2666c2c66affSColin Finck             goto end;
2667c2c66affSColin Finck         }
2668c2c66affSColin Finck 
2669c2c66affSColin Finck         IoSetShareAccess(IrpSp->Parameters.Create.SecurityContext->DesiredAccess, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access);
2670c2c66affSColin Finck 
2671c2c66affSColin Finck         send_notification_fileref(fileref, options & FILE_DIRECTORY_FILE ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, NULL);
2672c2c66affSColin Finck         send_notification_fcb(fileref->parent, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL);
2673c2c66affSColin Finck     }
2674c2c66affSColin Finck 
2675c2c66affSColin Finck     FileObject->FsContext = fileref->fcb;
2676c2c66affSColin Finck 
2677c2c66affSColin Finck     ccb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ccb), ALLOC_TAG);
2678c2c66affSColin Finck     if (!ccb) {
2679c2c66affSColin Finck         ERR("out of memory\n");
2680c2c66affSColin Finck         Status = STATUS_INSUFFICIENT_RESOURCES;
2681*eb7fbc25SPierre Schweitzer         fileref->deleted = TRUE;
2682*eb7fbc25SPierre Schweitzer         fileref->fcb->deleted = TRUE;
2683*eb7fbc25SPierre Schweitzer 
2684*eb7fbc25SPierre Schweitzer         if (stream.Length == 0) {
2685*eb7fbc25SPierre Schweitzer             ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
2686*eb7fbc25SPierre Schweitzer             parfileref->fcb->inode_item.st_size -= fileref->dc->utf8.Length * 2;
2687*eb7fbc25SPierre Schweitzer             ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2688*eb7fbc25SPierre Schweitzer         }
2689*eb7fbc25SPierre Schweitzer 
2690c2c66affSColin Finck         free_fileref(Vcb, fileref);
2691c2c66affSColin Finck         goto end;
2692c2c66affSColin Finck     }
2693c2c66affSColin Finck 
2694c2c66affSColin Finck     RtlZeroMemory(ccb, sizeof(*ccb));
2695c2c66affSColin Finck 
2696c2c66affSColin Finck     ccb->fileref = fileref;
2697c2c66affSColin Finck 
2698c2c66affSColin Finck     ccb->NodeType = BTRFS_NODE_TYPE_CCB;
2699c2c66affSColin Finck     ccb->NodeSize = sizeof(*ccb);
2700c2c66affSColin Finck     ccb->disposition = disposition;
2701c2c66affSColin Finck     ccb->options = options;
2702c2c66affSColin Finck     ccb->query_dir_offset = 0;
2703c2c66affSColin Finck     RtlInitUnicodeString(&ccb->query_string, NULL);
2704c2c66affSColin Finck     ccb->has_wildcard = FALSE;
2705c2c66affSColin Finck     ccb->specific_file = FALSE;
2706c2c66affSColin Finck     ccb->access = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
2707c2c66affSColin Finck     ccb->case_sensitive = IrpSp->Flags & SL_CASE_SENSITIVE;
2708c2c66affSColin Finck     ccb->reserving = FALSE;
2709c2c66affSColin Finck     ccb->lxss = called_from_lxss();
2710c2c66affSColin Finck 
2711c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
2712c2c66affSColin Finck     oc = InterlockedIncrement(&fileref->open_count);
2713c2c66affSColin Finck     ERR("fileref %p: open_count now %i\n", fileref, oc);
2714c2c66affSColin Finck #else
2715c2c66affSColin Finck     InterlockedIncrement(&fileref->open_count);
2716c2c66affSColin Finck #endif
2717c2c66affSColin Finck     InterlockedIncrement(&Vcb->open_files);
2718c2c66affSColin Finck 
2719c2c66affSColin Finck     FileObject->FsContext2 = ccb;
2720c2c66affSColin Finck 
2721c2c66affSColin Finck     FileObject->SectionObjectPointer = &fileref->fcb->nonpaged->segment_object;
2722c2c66affSColin Finck 
2723*eb7fbc25SPierre Schweitzer #ifndef __REACTOS__
2724*eb7fbc25SPierre Schweitzer     // FIXME - ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT
2725*eb7fbc25SPierre Schweitzer     if (acec && acec->InFlags & ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED) {
2726*eb7fbc25SPierre Schweitzer         if (acec->ReparseBufferLength > sizeof(UINT32) && *(UINT32*)acec->ReparseBuffer == IO_REPARSE_TAG_SYMLINK) {
2727*eb7fbc25SPierre Schweitzer             fileref->fcb->inode_item.st_mode &= ~(__S_IFIFO | __S_IFCHR | __S_IFBLK | __S_IFSOCK);
2728*eb7fbc25SPierre Schweitzer             fileref->fcb->type = BTRFS_TYPE_FILE;
2729*eb7fbc25SPierre Schweitzer         }
2730*eb7fbc25SPierre Schweitzer 
2731*eb7fbc25SPierre Schweitzer         if (fileref->fcb->type == BTRFS_TYPE_SOCKET || fileref->fcb->type == BTRFS_TYPE_FIFO ||
2732*eb7fbc25SPierre Schweitzer             fileref->fcb->type == BTRFS_TYPE_CHARDEV || fileref->fcb->type == BTRFS_TYPE_BLOCKDEV) {
2733*eb7fbc25SPierre Schweitzer             // NOP. If called from LXSS, humour it - we hardcode the values elsewhere.
2734*eb7fbc25SPierre Schweitzer         } else {
2735*eb7fbc25SPierre Schweitzer             Status = set_reparse_point2(fileref->fcb, acec->ReparseBuffer, acec->ReparseBufferLength, NULL, NULL, Irp, rollback);
2736*eb7fbc25SPierre Schweitzer             if (!NT_SUCCESS(Status)) {
2737*eb7fbc25SPierre Schweitzer                 ERR("set_reparse_point2 returned %08x\n", Status);
2738*eb7fbc25SPierre Schweitzer                 fileref->deleted = TRUE;
2739*eb7fbc25SPierre Schweitzer                 fileref->fcb->deleted = TRUE;
2740*eb7fbc25SPierre Schweitzer 
2741*eb7fbc25SPierre Schweitzer                 if (stream.Length == 0) {
2742*eb7fbc25SPierre Schweitzer                     ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
2743*eb7fbc25SPierre Schweitzer                     parfileref->fcb->inode_item.st_size -= fileref->dc->utf8.Length * 2;
2744*eb7fbc25SPierre Schweitzer                     ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2745*eb7fbc25SPierre Schweitzer                 }
2746*eb7fbc25SPierre Schweitzer 
2747*eb7fbc25SPierre Schweitzer                 free_fileref(Vcb, fileref);
2748*eb7fbc25SPierre Schweitzer                 return Status;
2749*eb7fbc25SPierre Schweitzer             }
2750*eb7fbc25SPierre Schweitzer         }
2751*eb7fbc25SPierre Schweitzer 
2752*eb7fbc25SPierre Schweitzer         acec->OutFlags |= ATOMIC_CREATE_ECP_OUT_FLAG_REPARSE_POINT_SET;
2753*eb7fbc25SPierre Schweitzer     }
2754*eb7fbc25SPierre Schweitzer #endif
2755*eb7fbc25SPierre Schweitzer 
2756*eb7fbc25SPierre Schweitzer     fileref->dc->type = fileref->fcb->type;
2757*eb7fbc25SPierre Schweitzer 
2758c2c66affSColin Finck     goto end2;
2759c2c66affSColin Finck 
2760c2c66affSColin Finck end:
2761c2c66affSColin Finck     if (fpus.Buffer)
2762c2c66affSColin Finck         ExFreePool(fpus.Buffer);
2763c2c66affSColin Finck 
2764c2c66affSColin Finck end2:
2765c2c66affSColin Finck     if (parfileref && !loaded_related)
2766c2c66affSColin Finck         free_fileref(Vcb, parfileref);
2767c2c66affSColin Finck 
2768c2c66affSColin Finck     return Status;
2769c2c66affSColin Finck }
2770c2c66affSColin Finck 
2771c2c66affSColin Finck static __inline void debug_create_options(ULONG RequestedOptions) {
2772c2c66affSColin Finck     if (RequestedOptions != 0) {
2773c2c66affSColin Finck         ULONG options = RequestedOptions;
2774c2c66affSColin Finck 
2775c2c66affSColin Finck         TRACE("requested options:\n");
2776c2c66affSColin Finck 
2777c2c66affSColin Finck         if (options & FILE_DIRECTORY_FILE) {
2778c2c66affSColin Finck             TRACE("    FILE_DIRECTORY_FILE\n");
2779c2c66affSColin Finck             options &= ~FILE_DIRECTORY_FILE;
2780c2c66affSColin Finck         }
2781c2c66affSColin Finck 
2782c2c66affSColin Finck         if (options & FILE_WRITE_THROUGH) {
2783c2c66affSColin Finck             TRACE("    FILE_WRITE_THROUGH\n");
2784c2c66affSColin Finck             options &= ~FILE_WRITE_THROUGH;
2785c2c66affSColin Finck         }
2786c2c66affSColin Finck 
2787c2c66affSColin Finck         if (options & FILE_SEQUENTIAL_ONLY) {
2788c2c66affSColin Finck             TRACE("    FILE_SEQUENTIAL_ONLY\n");
2789c2c66affSColin Finck             options &= ~FILE_SEQUENTIAL_ONLY;
2790c2c66affSColin Finck         }
2791c2c66affSColin Finck 
2792c2c66affSColin Finck         if (options & FILE_NO_INTERMEDIATE_BUFFERING) {
2793c2c66affSColin Finck             TRACE("    FILE_NO_INTERMEDIATE_BUFFERING\n");
2794c2c66affSColin Finck             options &= ~FILE_NO_INTERMEDIATE_BUFFERING;
2795c2c66affSColin Finck         }
2796c2c66affSColin Finck 
2797c2c66affSColin Finck         if (options & FILE_SYNCHRONOUS_IO_ALERT) {
2798c2c66affSColin Finck             TRACE("    FILE_SYNCHRONOUS_IO_ALERT\n");
2799c2c66affSColin Finck             options &= ~FILE_SYNCHRONOUS_IO_ALERT;
2800c2c66affSColin Finck         }
2801c2c66affSColin Finck 
2802c2c66affSColin Finck         if (options & FILE_SYNCHRONOUS_IO_NONALERT) {
2803c2c66affSColin Finck             TRACE("    FILE_SYNCHRONOUS_IO_NONALERT\n");
2804c2c66affSColin Finck             options &= ~FILE_SYNCHRONOUS_IO_NONALERT;
2805c2c66affSColin Finck         }
2806c2c66affSColin Finck 
2807c2c66affSColin Finck         if (options & FILE_NON_DIRECTORY_FILE) {
2808c2c66affSColin Finck             TRACE("    FILE_NON_DIRECTORY_FILE\n");
2809c2c66affSColin Finck             options &= ~FILE_NON_DIRECTORY_FILE;
2810c2c66affSColin Finck         }
2811c2c66affSColin Finck 
2812c2c66affSColin Finck         if (options & FILE_CREATE_TREE_CONNECTION) {
2813c2c66affSColin Finck             TRACE("    FILE_CREATE_TREE_CONNECTION\n");
2814c2c66affSColin Finck             options &= ~FILE_CREATE_TREE_CONNECTION;
2815c2c66affSColin Finck         }
2816c2c66affSColin Finck 
2817c2c66affSColin Finck         if (options & FILE_COMPLETE_IF_OPLOCKED) {
2818c2c66affSColin Finck             TRACE("    FILE_COMPLETE_IF_OPLOCKED\n");
2819c2c66affSColin Finck             options &= ~FILE_COMPLETE_IF_OPLOCKED;
2820c2c66affSColin Finck         }
2821c2c66affSColin Finck 
2822c2c66affSColin Finck         if (options & FILE_NO_EA_KNOWLEDGE) {
2823c2c66affSColin Finck             TRACE("    FILE_NO_EA_KNOWLEDGE\n");
2824c2c66affSColin Finck             options &= ~FILE_NO_EA_KNOWLEDGE;
2825c2c66affSColin Finck         }
2826c2c66affSColin Finck 
2827c2c66affSColin Finck         if (options & FILE_OPEN_REMOTE_INSTANCE) {
2828c2c66affSColin Finck             TRACE("    FILE_OPEN_REMOTE_INSTANCE\n");
2829c2c66affSColin Finck             options &= ~FILE_OPEN_REMOTE_INSTANCE;
2830c2c66affSColin Finck         }
2831c2c66affSColin Finck 
2832c2c66affSColin Finck         if (options & FILE_RANDOM_ACCESS) {
2833c2c66affSColin Finck             TRACE("    FILE_RANDOM_ACCESS\n");
2834c2c66affSColin Finck             options &= ~FILE_RANDOM_ACCESS;
2835c2c66affSColin Finck         }
2836c2c66affSColin Finck 
2837c2c66affSColin Finck         if (options & FILE_DELETE_ON_CLOSE) {
2838c2c66affSColin Finck             TRACE("    FILE_DELETE_ON_CLOSE\n");
2839c2c66affSColin Finck             options &= ~FILE_DELETE_ON_CLOSE;
2840c2c66affSColin Finck         }
2841c2c66affSColin Finck 
2842c2c66affSColin Finck         if (options & FILE_OPEN_BY_FILE_ID) {
2843c2c66affSColin Finck             TRACE("    FILE_OPEN_BY_FILE_ID\n");
2844c2c66affSColin Finck             options &= ~FILE_OPEN_BY_FILE_ID;
2845c2c66affSColin Finck         }
2846c2c66affSColin Finck 
2847c2c66affSColin Finck         if (options & FILE_OPEN_FOR_BACKUP_INTENT) {
2848c2c66affSColin Finck             TRACE("    FILE_OPEN_FOR_BACKUP_INTENT\n");
2849c2c66affSColin Finck             options &= ~FILE_OPEN_FOR_BACKUP_INTENT;
2850c2c66affSColin Finck         }
2851c2c66affSColin Finck 
2852c2c66affSColin Finck         if (options & FILE_NO_COMPRESSION) {
2853c2c66affSColin Finck             TRACE("    FILE_NO_COMPRESSION\n");
2854c2c66affSColin Finck             options &= ~FILE_NO_COMPRESSION;
2855c2c66affSColin Finck         }
2856c2c66affSColin Finck 
2857c2c66affSColin Finck #if NTDDI_VERSION >= NTDDI_WIN7
2858c2c66affSColin Finck         if (options & FILE_OPEN_REQUIRING_OPLOCK) {
2859c2c66affSColin Finck             TRACE("    FILE_OPEN_REQUIRING_OPLOCK\n");
2860c2c66affSColin Finck             options &= ~FILE_OPEN_REQUIRING_OPLOCK;
2861c2c66affSColin Finck         }
2862c2c66affSColin Finck 
2863c2c66affSColin Finck         if (options & FILE_DISALLOW_EXCLUSIVE) {
2864c2c66affSColin Finck             TRACE("    FILE_DISALLOW_EXCLUSIVE\n");
2865c2c66affSColin Finck             options &= ~FILE_DISALLOW_EXCLUSIVE;
2866c2c66affSColin Finck         }
2867c2c66affSColin Finck #endif
2868c2c66affSColin Finck 
2869c2c66affSColin Finck         if (options & FILE_RESERVE_OPFILTER) {
2870c2c66affSColin Finck             TRACE("    FILE_RESERVE_OPFILTER\n");
2871c2c66affSColin Finck             options &= ~FILE_RESERVE_OPFILTER;
2872c2c66affSColin Finck         }
2873c2c66affSColin Finck 
2874c2c66affSColin Finck         if (options & FILE_OPEN_REPARSE_POINT) {
2875c2c66affSColin Finck             TRACE("    FILE_OPEN_REPARSE_POINT\n");
2876c2c66affSColin Finck             options &= ~FILE_OPEN_REPARSE_POINT;
2877c2c66affSColin Finck         }
2878c2c66affSColin Finck 
2879c2c66affSColin Finck         if (options & FILE_OPEN_NO_RECALL) {
2880c2c66affSColin Finck             TRACE("    FILE_OPEN_NO_RECALL\n");
2881c2c66affSColin Finck             options &= ~FILE_OPEN_NO_RECALL;
2882c2c66affSColin Finck         }
2883c2c66affSColin Finck 
2884c2c66affSColin Finck         if (options & FILE_OPEN_FOR_FREE_SPACE_QUERY) {
2885c2c66affSColin Finck             TRACE("    FILE_OPEN_FOR_FREE_SPACE_QUERY\n");
2886c2c66affSColin Finck             options &= ~FILE_OPEN_FOR_FREE_SPACE_QUERY;
2887c2c66affSColin Finck         }
2888c2c66affSColin Finck 
2889c2c66affSColin Finck         if (options)
2890c2c66affSColin Finck             TRACE("    unknown options: %x\n", options);
2891c2c66affSColin Finck     } else {
2892c2c66affSColin Finck         TRACE("requested options: (none)\n");
2893c2c66affSColin Finck     }
2894c2c66affSColin Finck }
2895c2c66affSColin Finck 
2896c2c66affSColin Finck static NTSTATUS get_reparse_block(fcb* fcb, UINT8** data) {
2897c2c66affSColin Finck     NTSTATUS Status;
2898c2c66affSColin Finck 
2899c2c66affSColin Finck     if (fcb->type == BTRFS_TYPE_FILE || fcb->type == BTRFS_TYPE_SYMLINK) {
2900c2c66affSColin Finck         ULONG size, bytes_read, i;
2901c2c66affSColin Finck 
2902c2c66affSColin Finck         if (fcb->type == BTRFS_TYPE_FILE && fcb->inode_item.st_size < sizeof(ULONG)) {
2903c2c66affSColin Finck             WARN("file was too short to be a reparse point\n");
2904c2c66affSColin Finck             return STATUS_INVALID_PARAMETER;
2905c2c66affSColin Finck         }
2906c2c66affSColin Finck 
2907c2c66affSColin Finck         // 0x10007 = 0xffff (maximum length of data buffer) + 8 bytes header
2908c2c66affSColin Finck         size = (ULONG)min(0x10007, fcb->inode_item.st_size);
2909c2c66affSColin Finck 
2910c2c66affSColin Finck         if (size == 0)
2911c2c66affSColin Finck             return STATUS_INVALID_PARAMETER;
2912c2c66affSColin Finck 
2913c2c66affSColin Finck         *data = ExAllocatePoolWithTag(PagedPool, size, ALLOC_TAG);
2914c2c66affSColin Finck         if (!*data) {
2915c2c66affSColin Finck             ERR("out of memory\n");
2916c2c66affSColin Finck             return STATUS_INSUFFICIENT_RESOURCES;
2917c2c66affSColin Finck         }
2918c2c66affSColin Finck 
2919c2c66affSColin Finck         Status = read_file(fcb, *data, 0, size, &bytes_read, NULL);
2920c2c66affSColin Finck         if (!NT_SUCCESS(Status)) {
2921c2c66affSColin Finck             ERR("read_file_fcb returned %08x\n", Status);
2922c2c66affSColin Finck             ExFreePool(*data);
2923c2c66affSColin Finck             return Status;
2924c2c66affSColin Finck         }
2925c2c66affSColin Finck 
2926c2c66affSColin Finck         if (fcb->type == BTRFS_TYPE_SYMLINK) {
2927c2c66affSColin Finck             ULONG stringlen, reqlen;
2928c2c66affSColin Finck             UINT16 subnamelen, printnamelen;
2929c2c66affSColin Finck             REPARSE_DATA_BUFFER* rdb;
2930c2c66affSColin Finck 
2931c2c66affSColin Finck             Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, (char*)*data, bytes_read);
2932c2c66affSColin Finck             if (!NT_SUCCESS(Status)) {
2933c2c66affSColin Finck                 ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
2934c2c66affSColin Finck                 ExFreePool(*data);
2935c2c66affSColin Finck                 return Status;
2936c2c66affSColin Finck             }
2937c2c66affSColin Finck 
2938c2c66affSColin Finck             subnamelen = printnamelen = (USHORT)stringlen;
2939c2c66affSColin Finck 
2940c2c66affSColin Finck             reqlen = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + subnamelen + printnamelen;
2941c2c66affSColin Finck 
2942c2c66affSColin Finck             rdb = ExAllocatePoolWithTag(PagedPool, reqlen, ALLOC_TAG);
2943c2c66affSColin Finck 
2944c2c66affSColin Finck             if (!rdb) {
2945c2c66affSColin Finck                 ERR("out of memory\n");
2946c2c66affSColin Finck                 ExFreePool(*data);
2947c2c66affSColin Finck                 return STATUS_INSUFFICIENT_RESOURCES;
2948c2c66affSColin Finck             }
2949c2c66affSColin Finck 
2950c2c66affSColin Finck             rdb->ReparseTag = IO_REPARSE_TAG_SYMLINK;
2951c2c66affSColin Finck             rdb->ReparseDataLength = (USHORT)(reqlen - offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer));
2952c2c66affSColin Finck             rdb->Reserved = 0;
2953c2c66affSColin Finck 
2954c2c66affSColin Finck             rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
2955c2c66affSColin Finck             rdb->SymbolicLinkReparseBuffer.SubstituteNameLength = subnamelen;
2956c2c66affSColin Finck             rdb->SymbolicLinkReparseBuffer.PrintNameOffset = subnamelen;
2957c2c66affSColin Finck             rdb->SymbolicLinkReparseBuffer.PrintNameLength = printnamelen;
2958c2c66affSColin Finck             rdb->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
2959c2c66affSColin Finck 
2960c2c66affSColin Finck             Status = RtlUTF8ToUnicodeN(&rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)],
2961c2c66affSColin Finck                                     stringlen, &stringlen, (char*)*data, size);
2962c2c66affSColin Finck 
2963c2c66affSColin Finck             if (!NT_SUCCESS(Status)) {
2964c2c66affSColin Finck                 ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
2965c2c66affSColin Finck                 ExFreePool(rdb);
2966c2c66affSColin Finck                 ExFreePool(*data);
2967c2c66affSColin Finck                 return Status;
2968c2c66affSColin Finck             }
2969c2c66affSColin Finck 
2970c2c66affSColin Finck             for (i = 0; i < stringlen / sizeof(WCHAR); i++) {
2971c2c66affSColin Finck                 if (rdb->SymbolicLinkReparseBuffer.PathBuffer[(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)) + i] == '/')
2972c2c66affSColin Finck                     rdb->SymbolicLinkReparseBuffer.PathBuffer[(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)) + i] = '\\';
2973c2c66affSColin Finck             }
2974c2c66affSColin Finck 
2975c2c66affSColin Finck             RtlCopyMemory(&rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)],
2976c2c66affSColin Finck                         &rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)],
2977c2c66affSColin Finck                         rdb->SymbolicLinkReparseBuffer.SubstituteNameLength);
2978c2c66affSColin Finck 
2979c2c66affSColin Finck             ExFreePool(*data);
2980c2c66affSColin Finck 
2981c2c66affSColin Finck             *data = (UINT8*)rdb;
2982c2c66affSColin Finck         } else {
2983c2c66affSColin Finck             Status = FsRtlValidateReparsePointBuffer(bytes_read, (REPARSE_DATA_BUFFER*)*data);
2984c2c66affSColin Finck             if (!NT_SUCCESS(Status)) {
2985c2c66affSColin Finck                 ERR("FsRtlValidateReparsePointBuffer returned %08x\n", Status);
2986c2c66affSColin Finck                 ExFreePool(*data);
2987c2c66affSColin Finck                 return Status;
2988c2c66affSColin Finck             }
2989c2c66affSColin Finck         }
2990c2c66affSColin Finck     } else if (fcb->type == BTRFS_TYPE_DIRECTORY) {
2991c2c66affSColin Finck         if (!fcb->reparse_xattr.Buffer || fcb->reparse_xattr.Length == 0)
2992c2c66affSColin Finck             return STATUS_INTERNAL_ERROR;
2993c2c66affSColin Finck 
2994c2c66affSColin Finck         if (fcb->reparse_xattr.Length < sizeof(ULONG)) {
2995c2c66affSColin Finck             WARN("xattr was too short to be a reparse point\n");
2996c2c66affSColin Finck             return STATUS_INTERNAL_ERROR;
2997c2c66affSColin Finck         }
2998c2c66affSColin Finck 
2999c2c66affSColin Finck         Status = FsRtlValidateReparsePointBuffer(fcb->reparse_xattr.Length, (REPARSE_DATA_BUFFER*)fcb->reparse_xattr.Buffer);
3000c2c66affSColin Finck         if (!NT_SUCCESS(Status)) {
3001c2c66affSColin Finck             ERR("FsRtlValidateReparsePointBuffer returned %08x\n", Status);
3002c2c66affSColin Finck             return Status;
3003c2c66affSColin Finck         }
3004c2c66affSColin Finck 
3005c2c66affSColin Finck         *data = ExAllocatePoolWithTag(PagedPool, fcb->reparse_xattr.Length, ALLOC_TAG);
3006c2c66affSColin Finck         if (!*data) {
3007c2c66affSColin Finck             ERR("out of memory\n");
3008c2c66affSColin Finck             return STATUS_INSUFFICIENT_RESOURCES;
3009c2c66affSColin Finck         }
3010c2c66affSColin Finck 
3011c2c66affSColin Finck         RtlCopyMemory(*data, fcb->reparse_xattr.Buffer, fcb->reparse_xattr.Length);
3012*eb7fbc25SPierre Schweitzer     } else
3013*eb7fbc25SPierre Schweitzer         return STATUS_INVALID_PARAMETER;
3014c2c66affSColin Finck 
3015c2c66affSColin Finck     return STATUS_SUCCESS;
3016c2c66affSColin Finck }
3017c2c66affSColin Finck 
3018c2c66affSColin Finck static void fcb_load_csums(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, fcb* fcb, PIRP Irp) {
3019c2c66affSColin Finck     LIST_ENTRY* le;
3020c2c66affSColin Finck     NTSTATUS Status;
3021c2c66affSColin Finck 
3022c2c66affSColin Finck     if (fcb->csum_loaded)
3023c2c66affSColin Finck         return;
3024c2c66affSColin Finck 
3025c2c66affSColin Finck     if (IsListEmpty(&fcb->extents) || fcb->inode_item.flags & BTRFS_INODE_NODATASUM)
3026c2c66affSColin Finck         goto end;
3027c2c66affSColin Finck 
3028c2c66affSColin Finck     le = fcb->extents.Flink;
3029c2c66affSColin Finck     while (le != &fcb->extents) {
3030c2c66affSColin Finck         extent* ext = CONTAINING_RECORD(le, extent, list_entry);
3031c2c66affSColin Finck 
3032c2c66affSColin Finck         if (ext->extent_data.type == EXTENT_TYPE_REGULAR) {
3033c2c66affSColin Finck             EXTENT_DATA2* ed2 = (EXTENT_DATA2*)&ext->extent_data.data[0];
3034c2c66affSColin Finck             UINT64 len;
3035c2c66affSColin Finck 
3036c2c66affSColin Finck             len = (ext->extent_data.compression == BTRFS_COMPRESSION_NONE ? ed2->num_bytes : ed2->size) / Vcb->superblock.sector_size;
3037c2c66affSColin Finck 
3038c2c66affSColin Finck             ext->csum = ExAllocatePoolWithTag(NonPagedPool, (ULONG)(len * sizeof(UINT32)), ALLOC_TAG);
3039c2c66affSColin Finck             if (!ext->csum) {
3040c2c66affSColin Finck                 ERR("out of memory\n");
3041c2c66affSColin Finck                 goto end;
3042c2c66affSColin Finck             }
3043c2c66affSColin Finck 
3044c2c66affSColin Finck             Status = load_csum(Vcb, ext->csum, ed2->address + (ext->extent_data.compression == BTRFS_COMPRESSION_NONE ? ed2->offset : 0), len, Irp);
3045c2c66affSColin Finck 
3046c2c66affSColin Finck             if (!NT_SUCCESS(Status)) {
3047c2c66affSColin Finck                 ERR("load_csum returned %08x\n", Status);
3048c2c66affSColin Finck                 goto end;
3049c2c66affSColin Finck             }
3050c2c66affSColin Finck         }
3051c2c66affSColin Finck 
3052c2c66affSColin Finck         le = le->Flink;
3053c2c66affSColin Finck     }
3054c2c66affSColin Finck 
3055c2c66affSColin Finck end:
3056c2c66affSColin Finck     fcb->csum_loaded = TRUE;
3057c2c66affSColin Finck }
3058c2c66affSColin Finck 
3059c2c66affSColin Finck static NTSTATUS open_file(PDEVICE_OBJECT DeviceObject, _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, PIRP Irp, LIST_ENTRY* rollback) {
3060c2c66affSColin Finck     PFILE_OBJECT FileObject = NULL;
3061c2c66affSColin Finck     ULONG RequestedDisposition;
3062c2c66affSColin Finck     ULONG options;
3063c2c66affSColin Finck     NTSTATUS Status;
3064c2c66affSColin Finck     ccb* ccb;
3065c2c66affSColin Finck     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
3066c2c66affSColin Finck     USHORT parsed;
3067c2c66affSColin Finck     ULONG fn_offset = 0;
3068c2c66affSColin Finck     file_ref *related, *fileref = NULL;
3069c2c66affSColin Finck     POOL_TYPE pool_type = IrpSp->Flags & SL_OPEN_PAGING_FILE ? NonPagedPool : PagedPool;
3070c2c66affSColin Finck     ACCESS_MASK granted_access;
3071c2c66affSColin Finck     BOOL loaded_related = FALSE;
3072c2c66affSColin Finck     UNICODE_STRING fn;
3073c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
3074c2c66affSColin Finck     LONG oc;
3075c2c66affSColin Finck #endif
3076c2c66affSColin Finck #ifdef DEBUG_STATS
3077c2c66affSColin Finck     LARGE_INTEGER time1, time2;
3078c2c66affSColin Finck     UINT8 open_type = 0;
3079c2c66affSColin Finck 
3080c2c66affSColin Finck     time1 = KeQueryPerformanceCounter(NULL);
3081c2c66affSColin Finck #endif
3082c2c66affSColin Finck 
3083c2c66affSColin Finck     Irp->IoStatus.Information = 0;
3084c2c66affSColin Finck 
3085c2c66affSColin Finck     RequestedDisposition = ((IrpSp->Parameters.Create.Options >> 24) & 0xff);
3086c2c66affSColin Finck     options = IrpSp->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
3087c2c66affSColin Finck 
3088c2c66affSColin Finck     if (options & FILE_DIRECTORY_FILE && RequestedDisposition == FILE_SUPERSEDE) {
3089c2c66affSColin Finck         WARN("error - supersede requested with FILE_DIRECTORY_FILE\n");
3090c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
3091c2c66affSColin Finck     }
3092c2c66affSColin Finck 
3093c2c66affSColin Finck     FileObject = IrpSp->FileObject;
3094c2c66affSColin Finck 
3095c2c66affSColin Finck     if (!FileObject) {
3096c2c66affSColin Finck         ERR("FileObject was NULL\n");
3097c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
3098c2c66affSColin Finck     }
3099c2c66affSColin Finck 
3100c2c66affSColin Finck     if (FileObject->RelatedFileObject && FileObject->RelatedFileObject->FsContext2) {
3101c2c66affSColin Finck         struct _ccb* relatedccb = FileObject->RelatedFileObject->FsContext2;
3102c2c66affSColin Finck 
3103c2c66affSColin Finck         related = relatedccb->fileref;
3104c2c66affSColin Finck     } else
3105c2c66affSColin Finck         related = NULL;
3106c2c66affSColin Finck 
3107c2c66affSColin Finck     debug_create_options(options);
3108c2c66affSColin Finck 
3109c2c66affSColin Finck     switch (RequestedDisposition) {
3110c2c66affSColin Finck         case FILE_SUPERSEDE:
3111c2c66affSColin Finck             TRACE("requested disposition: FILE_SUPERSEDE\n");
3112c2c66affSColin Finck             break;
3113c2c66affSColin Finck 
3114c2c66affSColin Finck         case FILE_CREATE:
3115c2c66affSColin Finck             TRACE("requested disposition: FILE_CREATE\n");
3116c2c66affSColin Finck             break;
3117c2c66affSColin Finck 
3118c2c66affSColin Finck         case FILE_OPEN:
3119c2c66affSColin Finck             TRACE("requested disposition: FILE_OPEN\n");
3120c2c66affSColin Finck             break;
3121c2c66affSColin Finck 
3122c2c66affSColin Finck         case FILE_OPEN_IF:
3123c2c66affSColin Finck             TRACE("requested disposition: FILE_OPEN_IF\n");
3124c2c66affSColin Finck             break;
3125c2c66affSColin Finck 
3126c2c66affSColin Finck         case FILE_OVERWRITE:
3127c2c66affSColin Finck             TRACE("requested disposition: FILE_OVERWRITE\n");
3128c2c66affSColin Finck             break;
3129c2c66affSColin Finck 
3130c2c66affSColin Finck         case FILE_OVERWRITE_IF:
3131c2c66affSColin Finck             TRACE("requested disposition: FILE_OVERWRITE_IF\n");
3132c2c66affSColin Finck             break;
3133c2c66affSColin Finck 
3134c2c66affSColin Finck         default:
3135c2c66affSColin Finck             ERR("unknown disposition: %x\n", RequestedDisposition);
3136c2c66affSColin Finck             Status = STATUS_NOT_IMPLEMENTED;
3137c2c66affSColin Finck             goto exit;
3138c2c66affSColin Finck     }
3139c2c66affSColin Finck 
3140c2c66affSColin Finck     fn = FileObject->FileName;
3141c2c66affSColin Finck 
3142c2c66affSColin Finck     TRACE("(%.*S)\n", fn.Length / sizeof(WCHAR), fn.Buffer);
3143c2c66affSColin Finck     TRACE("FileObject = %p\n", FileObject);
3144c2c66affSColin Finck 
3145c2c66affSColin Finck     if (Vcb->readonly && (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == FILE_CREATE || RequestedDisposition == FILE_OVERWRITE)) {
3146c2c66affSColin Finck         Status = STATUS_MEDIA_WRITE_PROTECTED;
3147c2c66affSColin Finck         goto exit;
3148c2c66affSColin Finck     }
3149c2c66affSColin Finck 
31504672b2baSPierre Schweitzer     acquire_fcb_lock_exclusive(Vcb);
3151c2c66affSColin Finck 
3152c2c66affSColin Finck     if (options & FILE_OPEN_BY_FILE_ID) {
3153c2c66affSColin Finck         if (fn.Length == sizeof(UINT64) && related && RequestedDisposition == FILE_OPEN) {
3154c2c66affSColin Finck             UINT64 inode;
3155c2c66affSColin Finck 
3156c2c66affSColin Finck             RtlCopyMemory(&inode, fn.Buffer, sizeof(UINT64));
3157c2c66affSColin Finck 
3158c2c66affSColin Finck             if (related->fcb == Vcb->root_fileref->fcb && inode == 0)
3159c2c66affSColin Finck                 inode = Vcb->root_fileref->fcb->inode;
3160c2c66affSColin Finck 
3161c2c66affSColin Finck             if (inode == 0) { // we use 0 to mean the parent of a subvolume
3162c2c66affSColin Finck                 fileref = related->parent;
3163c2c66affSColin Finck                 increase_fileref_refcount(fileref);
3164c2c66affSColin Finck                 Status = STATUS_SUCCESS;
3165c2c66affSColin Finck             } else {
3166c2c66affSColin Finck                 Status = open_fileref_by_inode(Vcb, related->fcb->subvol, inode, &fileref, Irp);
3167c2c66affSColin Finck             }
3168c2c66affSColin Finck         } else {
3169c2c66affSColin Finck             WARN("FILE_OPEN_BY_FILE_ID only supported for inodes\n");
3170c2c66affSColin Finck             Status = STATUS_NOT_IMPLEMENTED;
31714672b2baSPierre Schweitzer             release_fcb_lock(Vcb);
3172c2c66affSColin Finck             goto exit;
3173c2c66affSColin Finck         }
3174c2c66affSColin Finck     } else {
3175c2c66affSColin Finck         if (related && fn.Length != 0 && fn.Buffer[0] == '\\') {
31764672b2baSPierre Schweitzer             Status = STATUS_INVALID_PARAMETER;
31774672b2baSPierre Schweitzer             release_fcb_lock(Vcb);
3178c2c66affSColin Finck             goto exit;
3179c2c66affSColin Finck         }
3180c2c66affSColin Finck 
3181c2c66affSColin Finck         if (!related && RequestedDisposition != FILE_OPEN && !(IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY)) {
3182c2c66affSColin Finck             ULONG fnoff;
3183c2c66affSColin Finck 
3184c2c66affSColin Finck             Status = open_fileref(Vcb, &related, &fn, NULL, TRUE, &parsed, &fnoff,
3185c2c66affSColin Finck                                   pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp);
3186c2c66affSColin Finck 
3187c2c66affSColin Finck             if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
3188c2c66affSColin Finck                 Status = STATUS_OBJECT_PATH_NOT_FOUND;
3189c2c66affSColin Finck             else if (Status == STATUS_REPARSE)
3190c2c66affSColin Finck                 fileref = related;
3191c2c66affSColin Finck             else if (NT_SUCCESS(Status)) {
3192c2c66affSColin Finck                 fnoff *= sizeof(WCHAR);
3193c2c66affSColin Finck                 fnoff += (related->dc ? related->dc->name.Length : 0) + sizeof(WCHAR);
3194c2c66affSColin Finck 
3195c2c66affSColin Finck                 if (related->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT) {
3196c2c66affSColin Finck                     Status = STATUS_REPARSE;
3197c2c66affSColin Finck                     fileref = related;
3198c2c66affSColin Finck                     parsed = (USHORT)fnoff - sizeof(WCHAR);
3199c2c66affSColin Finck                 } else {
3200c2c66affSColin Finck                     fn.Buffer = &fn.Buffer[fnoff / sizeof(WCHAR)];
3201c2c66affSColin Finck                     fn.Length -= (USHORT)fnoff;
3202c2c66affSColin Finck 
3203c2c66affSColin Finck                     Status = open_fileref(Vcb, &fileref, &fn, related, IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY, &parsed, &fn_offset,
3204c2c66affSColin Finck                                           pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp);
3205c2c66affSColin Finck 
3206c2c66affSColin Finck                     loaded_related = TRUE;
3207c2c66affSColin Finck                 }
3208c2c66affSColin Finck 
3209c2c66affSColin Finck             }
3210c2c66affSColin Finck         } else {
3211c2c66affSColin Finck             Status = open_fileref(Vcb, &fileref, &fn, related, IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY, &parsed, &fn_offset,
3212c2c66affSColin Finck                                   pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp);
3213c2c66affSColin Finck         }
3214c2c66affSColin Finck     }
3215c2c66affSColin Finck 
3216c2c66affSColin Finck     if (Status == STATUS_REPARSE) {
3217c2c66affSColin Finck         REPARSE_DATA_BUFFER* data;
3218c2c66affSColin Finck 
3219c2c66affSColin Finck         ExAcquireResourceSharedLite(fileref->fcb->Header.Resource, TRUE);
3220c2c66affSColin Finck         Status = get_reparse_block(fileref->fcb, (UINT8**)&data);
3221c2c66affSColin Finck         ExReleaseResourceLite(fileref->fcb->Header.Resource);
3222c2c66affSColin Finck 
3223c2c66affSColin Finck         if (!NT_SUCCESS(Status)) {
3224c2c66affSColin Finck             ERR("get_reparse_block returned %08x\n", Status);
3225c2c66affSColin Finck 
3226c2c66affSColin Finck             Status = STATUS_SUCCESS;
3227c2c66affSColin Finck         } else {
3228c2c66affSColin Finck             Status = STATUS_REPARSE;
3229c2c66affSColin Finck             RtlCopyMemory(&Irp->IoStatus.Information, data, sizeof(ULONG));
3230c2c66affSColin Finck 
3231c2c66affSColin Finck             data->Reserved = FileObject->FileName.Length - parsed;
3232c2c66affSColin Finck 
3233c2c66affSColin Finck             Irp->Tail.Overlay.AuxiliaryBuffer = (void*)data;
3234c2c66affSColin Finck 
3235c2c66affSColin Finck             free_fileref(Vcb, fileref);
32364672b2baSPierre Schweitzer             release_fcb_lock(Vcb);
3237c2c66affSColin Finck 
3238c2c66affSColin Finck             goto exit;
3239c2c66affSColin Finck         }
3240c2c66affSColin Finck     }
3241c2c66affSColin Finck 
3242c2c66affSColin Finck     if (NT_SUCCESS(Status) && fileref->deleted)
3243c2c66affSColin Finck         Status = STATUS_OBJECT_NAME_NOT_FOUND;
3244c2c66affSColin Finck 
3245c2c66affSColin Finck     if (NT_SUCCESS(Status)) {
3246c2c66affSColin Finck         if (RequestedDisposition == FILE_CREATE) {
3247c2c66affSColin Finck             TRACE("file %S already exists, returning STATUS_OBJECT_NAME_COLLISION\n", file_desc_fileref(fileref));
3248c2c66affSColin Finck             Status = STATUS_OBJECT_NAME_COLLISION;
3249c2c66affSColin Finck 
3250c2c66affSColin Finck             free_fileref(Vcb, fileref);
32514672b2baSPierre Schweitzer             release_fcb_lock(Vcb);
3252c2c66affSColin Finck 
3253c2c66affSColin Finck             goto exit;
3254c2c66affSColin Finck         }
3255c2c66affSColin Finck     } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
3256c2c66affSColin Finck         if (RequestedDisposition == FILE_OPEN || RequestedDisposition == FILE_OVERWRITE) {
3257c2c66affSColin Finck             TRACE("file doesn't exist, returning STATUS_OBJECT_NAME_NOT_FOUND\n");
32584672b2baSPierre Schweitzer             release_fcb_lock(Vcb);
3259c2c66affSColin Finck             goto exit;
3260c2c66affSColin Finck         }
3261c2c66affSColin Finck     } else if (Status == STATUS_OBJECT_PATH_NOT_FOUND) {
3262c2c66affSColin Finck         TRACE("open_fileref returned %08x\n", Status);
32634672b2baSPierre Schweitzer         release_fcb_lock(Vcb);
3264c2c66affSColin Finck         goto exit;
3265c2c66affSColin Finck     } else {
3266c2c66affSColin Finck         ERR("open_fileref returned %08x\n", Status);
32674672b2baSPierre Schweitzer         release_fcb_lock(Vcb);
3268c2c66affSColin Finck         goto exit;
3269c2c66affSColin Finck     }
3270c2c66affSColin Finck 
3271c2c66affSColin Finck     if (NT_SUCCESS(Status)) { // file already exists
3272c2c66affSColin Finck         file_ref* sf;
3273c2c66affSColin Finck         BOOL readonly;
3274c2c66affSColin Finck 
32754672b2baSPierre Schweitzer         release_fcb_lock(Vcb);
3276c2c66affSColin Finck 
3277c2c66affSColin Finck         if (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF) {
3278c2c66affSColin Finck             LARGE_INTEGER zero;
3279c2c66affSColin Finck 
3280c2c66affSColin Finck #ifdef DEBUG_STATS
3281c2c66affSColin Finck             open_type = 1;
3282c2c66affSColin Finck #endif
3283c2c66affSColin Finck             if (fileref->fcb->type == BTRFS_TYPE_DIRECTORY || is_subvol_readonly(fileref->fcb->subvol, Irp)) {
3284c2c66affSColin Finck                 Status = STATUS_ACCESS_DENIED;
3285c2c66affSColin Finck 
32864672b2baSPierre Schweitzer                 acquire_fcb_lock_exclusive(Vcb);
3287c2c66affSColin Finck                 free_fileref(Vcb, fileref);
32884672b2baSPierre Schweitzer                 release_fcb_lock(Vcb);
3289c2c66affSColin Finck 
3290c2c66affSColin Finck                 goto exit;
3291c2c66affSColin Finck             }
3292c2c66affSColin Finck 
3293c2c66affSColin Finck             if (Vcb->readonly) {
3294c2c66affSColin Finck                 Status = STATUS_MEDIA_WRITE_PROTECTED;
3295c2c66affSColin Finck 
32964672b2baSPierre Schweitzer                 acquire_fcb_lock_exclusive(Vcb);
3297c2c66affSColin Finck                 free_fileref(Vcb, fileref);
32984672b2baSPierre Schweitzer                 release_fcb_lock(Vcb);
3299c2c66affSColin Finck 
3300c2c66affSColin Finck                 goto exit;
3301c2c66affSColin Finck             }
3302c2c66affSColin Finck 
3303c2c66affSColin Finck             zero.QuadPart = 0;
3304c2c66affSColin Finck             if (!MmCanFileBeTruncated(&fileref->fcb->nonpaged->segment_object, &zero)) {
3305c2c66affSColin Finck                 Status = STATUS_USER_MAPPED_FILE;
3306c2c66affSColin Finck 
33074672b2baSPierre Schweitzer                 acquire_fcb_lock_exclusive(Vcb);
3308c2c66affSColin Finck                 free_fileref(Vcb, fileref);
33094672b2baSPierre Schweitzer                 release_fcb_lock(Vcb);
3310c2c66affSColin Finck 
3311c2c66affSColin Finck                 goto exit;
3312c2c66affSColin Finck             }
3313c2c66affSColin Finck         }
3314c2c66affSColin Finck 
3315c2c66affSColin Finck         if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess != 0) {
3316c2c66affSColin Finck             SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
3317c2c66affSColin Finck 
3318c2c66affSColin Finck             if (!SeAccessCheck((fileref->fcb->ads || fileref->fcb == Vcb->dummy_fcb) ? fileref->parent->fcb->sd : fileref->fcb->sd,
3319c2c66affSColin Finck                                &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
3320c2c66affSColin Finck                                TRUE, IrpSp->Parameters.Create.SecurityContext->DesiredAccess, 0, NULL,
3321c2c66affSColin Finck                                IoGetFileObjectGenericMapping(), IrpSp->Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode,
3322c2c66affSColin Finck                                &granted_access, &Status)) {
3323c2c66affSColin Finck                 SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
3324c2c66affSColin Finck                 TRACE("SeAccessCheck failed, returning %08x\n", Status);
3325c2c66affSColin Finck 
33264672b2baSPierre Schweitzer                 acquire_fcb_lock_exclusive(Vcb);
3327c2c66affSColin Finck                 free_fileref(Vcb, fileref);
33284672b2baSPierre Schweitzer                 release_fcb_lock(Vcb);
3329c2c66affSColin Finck 
3330c2c66affSColin Finck                 goto exit;
3331c2c66affSColin Finck             }
3332c2c66affSColin Finck 
3333c2c66affSColin Finck             SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
3334c2c66affSColin Finck         } else
3335c2c66affSColin Finck             granted_access = 0;
3336c2c66affSColin Finck 
3337c2c66affSColin Finck         TRACE("deleted = %s\n", fileref->deleted ? "TRUE" : "FALSE");
3338c2c66affSColin Finck 
3339c2c66affSColin Finck         sf = fileref;
3340c2c66affSColin Finck         while (sf) {
3341c2c66affSColin Finck             if (sf->delete_on_close) {
3342c2c66affSColin Finck                 TRACE("could not open as deletion pending\n");
3343c2c66affSColin Finck                 Status = STATUS_DELETE_PENDING;
3344c2c66affSColin Finck 
33454672b2baSPierre Schweitzer                 acquire_fcb_lock_exclusive(Vcb);
3346c2c66affSColin Finck                 free_fileref(Vcb, fileref);
33474672b2baSPierre Schweitzer                 release_fcb_lock(Vcb);
3348c2c66affSColin Finck 
3349c2c66affSColin Finck                 goto exit;
3350c2c66affSColin Finck             }
3351c2c66affSColin Finck             sf = sf->parent;
3352c2c66affSColin Finck         }
3353c2c66affSColin Finck 
3354c2c66affSColin Finck         readonly = (!fileref->fcb->ads && fileref->fcb->atts & FILE_ATTRIBUTE_READONLY) || (fileref->fcb->ads && fileref->parent->fcb->atts & FILE_ATTRIBUTE_READONLY) ||
3355c2c66affSColin Finck                    is_subvol_readonly(fileref->fcb->subvol, Irp) || fileref->fcb == Vcb->dummy_fcb || Vcb->readonly;
3356c2c66affSColin Finck 
33574672b2baSPierre Schweitzer         if (options & FILE_DELETE_ON_CLOSE && (fileref == Vcb->root_fileref || readonly)) {
33584672b2baSPierre Schweitzer             Status = STATUS_CANNOT_DELETE;
33594672b2baSPierre Schweitzer 
33604672b2baSPierre Schweitzer             acquire_fcb_lock_exclusive(Vcb);
33614672b2baSPierre Schweitzer             free_fileref(Vcb, fileref);
33624672b2baSPierre Schweitzer             release_fcb_lock(Vcb);
33634672b2baSPierre Schweitzer 
33644672b2baSPierre Schweitzer             goto exit;
33654672b2baSPierre Schweitzer         }
33664672b2baSPierre Schweitzer 
3367c2c66affSColin Finck         if (readonly) {
3368c2c66affSColin Finck             ACCESS_MASK allowed;
3369c2c66affSColin Finck 
3370c2c66affSColin Finck             allowed = READ_CONTROL | SYNCHRONIZE | ACCESS_SYSTEM_SECURITY | FILE_READ_DATA |
3371c2c66affSColin Finck                       FILE_READ_EA | FILE_READ_ATTRIBUTES | FILE_EXECUTE | FILE_LIST_DIRECTORY |
3372c2c66affSColin Finck                       FILE_TRAVERSE;
3373c2c66affSColin Finck 
3374c2c66affSColin Finck             if (!Vcb->readonly && (fileref->fcb == Vcb->dummy_fcb || fileref->fcb->inode == SUBVOL_ROOT_INODE))
3375c2c66affSColin Finck                 allowed |= DELETE;
3376c2c66affSColin Finck 
3377c2c66affSColin Finck             if (fileref->fcb != Vcb->dummy_fcb && !is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) {
3378c7806a6bSPierre Schweitzer                 allowed |= DELETE | WRITE_OWNER | WRITE_DAC | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES;
3379c2c66affSColin Finck 
3380c2c66affSColin Finck                 if (!fileref->fcb->ads && fileref->fcb->type == BTRFS_TYPE_DIRECTORY)
3381c2c66affSColin Finck                     allowed |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE | FILE_DELETE_CHILD;
3382c2c66affSColin Finck             } else if (fileref->fcb->inode == SUBVOL_ROOT_INODE && is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) {
3383c2c66affSColin Finck                 // We allow a subvolume root to be opened read-write even if its readonly flag is set, so it can be cleared
3384c2c66affSColin Finck 
3385c2c66affSColin Finck                 allowed |= FILE_WRITE_ATTRIBUTES;
3386c2c66affSColin Finck             }
3387c2c66affSColin Finck 
3388c2c66affSColin Finck             if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess & MAXIMUM_ALLOWED) {
3389c2c66affSColin Finck                 granted_access &= allowed;
3390c2c66affSColin Finck                 IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess &= allowed;
3391c2c66affSColin Finck             } else if (granted_access & ~allowed) {
3392c2c66affSColin Finck                 Status = Vcb->readonly ? STATUS_MEDIA_WRITE_PROTECTED : STATUS_ACCESS_DENIED;
3393c2c66affSColin Finck 
33944672b2baSPierre Schweitzer                 acquire_fcb_lock_exclusive(Vcb);
3395c2c66affSColin Finck                 free_fileref(Vcb, fileref);
33964672b2baSPierre Schweitzer                 release_fcb_lock(Vcb);
3397c2c66affSColin Finck 
3398c2c66affSColin Finck                 goto exit;
3399c2c66affSColin Finck             }
3400c2c66affSColin Finck         }
3401c2c66affSColin Finck 
3402c2c66affSColin Finck         if ((fileref->fcb->type == BTRFS_TYPE_SYMLINK || fileref->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT) && !(options & FILE_OPEN_REPARSE_POINT))  {
3403c2c66affSColin Finck             REPARSE_DATA_BUFFER* data;
3404c2c66affSColin Finck 
3405c2c66affSColin Finck             /* How reparse points work from the point of view of the filesystem appears to
3406c2c66affSColin Finck              * undocumented. When returning STATUS_REPARSE, MSDN encourages us to return
3407c2c66affSColin Finck              * IO_REPARSE in Irp->IoStatus.Information, but that means we have to do our own
3408c2c66affSColin Finck              * translation. If we instead return the reparse tag in Information, and store
3409c2c66affSColin Finck              * a pointer to the reparse data buffer in Irp->Tail.Overlay.AuxiliaryBuffer,
3410c2c66affSColin Finck              * IopSymlinkProcessReparse will do the translation for us. */
3411c2c66affSColin Finck 
3412c2c66affSColin Finck             Status = get_reparse_block(fileref->fcb, (UINT8**)&data);
3413c2c66affSColin Finck             if (!NT_SUCCESS(Status)) {
3414c2c66affSColin Finck                 ERR("get_reparse_block returned %08x\n", Status);
3415c2c66affSColin Finck                 Status = STATUS_SUCCESS;
3416c2c66affSColin Finck             } else {
3417c2c66affSColin Finck                 Status = STATUS_REPARSE;
3418c2c66affSColin Finck                 Irp->IoStatus.Information = data->ReparseTag;
3419c2c66affSColin Finck 
3420c2c66affSColin Finck                 if (fn.Buffer[(fn.Length / sizeof(WCHAR)) - 1] == '\\')
3421c2c66affSColin Finck                     data->Reserved = sizeof(WCHAR);
3422c2c66affSColin Finck 
3423c2c66affSColin Finck                 Irp->Tail.Overlay.AuxiliaryBuffer = (void*)data;
3424c2c66affSColin Finck 
34254672b2baSPierre Schweitzer                 acquire_fcb_lock_exclusive(Vcb);
3426c2c66affSColin Finck                 free_fileref(Vcb, fileref);
34274672b2baSPierre Schweitzer                 release_fcb_lock(Vcb);
3428c2c66affSColin Finck 
3429c2c66affSColin Finck                 goto exit;
3430c2c66affSColin Finck             }
3431c2c66affSColin Finck         }
3432c2c66affSColin Finck 
3433c2c66affSColin Finck         if (fileref->fcb->type == BTRFS_TYPE_DIRECTORY && !fileref->fcb->ads) {
3434c2c66affSColin Finck             if (options & FILE_NON_DIRECTORY_FILE && !(fileref->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT)) {
3435c2c66affSColin Finck                 Status = STATUS_FILE_IS_A_DIRECTORY;
3436c2c66affSColin Finck 
34374672b2baSPierre Schweitzer                 acquire_fcb_lock_exclusive(Vcb);
3438c2c66affSColin Finck                 free_fileref(Vcb, fileref);
34394672b2baSPierre Schweitzer                 release_fcb_lock(Vcb);
3440c2c66affSColin Finck 
3441c2c66affSColin Finck                 goto exit;
3442c2c66affSColin Finck             }
3443c2c66affSColin Finck         } else if (options & FILE_DIRECTORY_FILE) {
3444c2c66affSColin Finck             TRACE("returning STATUS_NOT_A_DIRECTORY (type = %u, %S)\n", fileref->fcb->type, file_desc_fileref(fileref));
3445c2c66affSColin Finck             Status = STATUS_NOT_A_DIRECTORY;
3446c2c66affSColin Finck 
34474672b2baSPierre Schweitzer             acquire_fcb_lock_exclusive(Vcb);
3448c2c66affSColin Finck             free_fileref(Vcb, fileref);
34494672b2baSPierre Schweitzer             release_fcb_lock(Vcb);
3450c2c66affSColin Finck 
3451c2c66affSColin Finck             goto exit;
3452c2c66affSColin Finck         }
3453c2c66affSColin Finck 
3454c2c66affSColin Finck         if (fileref->open_count > 0) {
3455c2c66affSColin Finck             Status = IoCheckShareAccess(granted_access, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access, FALSE);
3456c2c66affSColin Finck 
3457c2c66affSColin Finck             if (!NT_SUCCESS(Status)) {
3458c2c66affSColin Finck                 if (Status == STATUS_SHARING_VIOLATION)
3459c2c66affSColin Finck                     TRACE("IoCheckShareAccess failed, returning %08x\n", Status);
3460c2c66affSColin Finck                 else
3461c2c66affSColin Finck                     WARN("IoCheckShareAccess failed, returning %08x\n", Status);
3462c2c66affSColin Finck 
34634672b2baSPierre Schweitzer                 acquire_fcb_lock_exclusive(Vcb);
3464c2c66affSColin Finck                 free_fileref(Vcb, fileref);
34654672b2baSPierre Schweitzer                 release_fcb_lock(Vcb);
3466c2c66affSColin Finck 
3467c2c66affSColin Finck                 goto exit;
3468c2c66affSColin Finck             }
3469c2c66affSColin Finck 
3470c2c66affSColin Finck             IoUpdateShareAccess(FileObject, &fileref->fcb->share_access);
3471c2c66affSColin Finck         } else
3472c2c66affSColin Finck             IoSetShareAccess(granted_access, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access);
3473c2c66affSColin Finck 
3474c2c66affSColin Finck         if (granted_access & FILE_WRITE_DATA || options & FILE_DELETE_ON_CLOSE) {
3475c2c66affSColin Finck             if (!MmFlushImageSection(&fileref->fcb->nonpaged->segment_object, MmFlushForWrite)) {
3476c2c66affSColin Finck                 Status = (options & FILE_DELETE_ON_CLOSE) ? STATUS_CANNOT_DELETE : STATUS_SHARING_VIOLATION;
3477c2c66affSColin Finck 
3478c2c66affSColin Finck                 IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
3479c2c66affSColin Finck 
34804672b2baSPierre Schweitzer                 acquire_fcb_lock_exclusive(Vcb);
3481c2c66affSColin Finck                 free_fileref(Vcb, fileref);
34824672b2baSPierre Schweitzer                 release_fcb_lock(Vcb);
3483c2c66affSColin Finck 
3484c2c66affSColin Finck                 goto exit;
3485c2c66affSColin Finck             }
3486c2c66affSColin Finck         }
3487c2c66affSColin Finck 
3488c2c66affSColin Finck         if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF || RequestedDisposition == FILE_SUPERSEDE) {
3489c2c66affSColin Finck             ULONG defda, oldatts, filter;
3490c2c66affSColin Finck             LARGE_INTEGER time;
3491c2c66affSColin Finck             BTRFS_TIME now;
3492c2c66affSColin Finck 
3493c2c66affSColin Finck             if ((RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF) && readonly) {
3494c2c66affSColin Finck                 WARN("cannot overwrite readonly file\n");
3495c2c66affSColin Finck                 Status = STATUS_ACCESS_DENIED;
3496c2c66affSColin Finck 
3497c2c66affSColin Finck                 IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
3498c2c66affSColin Finck 
34994672b2baSPierre Schweitzer                 acquire_fcb_lock_exclusive(Vcb);
3500c2c66affSColin Finck                 free_fileref(Vcb, fileref);
35014672b2baSPierre Schweitzer                 release_fcb_lock(Vcb);
3502c2c66affSColin Finck 
3503c2c66affSColin Finck                 goto exit;
3504c2c66affSColin Finck             }
3505c2c66affSColin Finck 
35064672b2baSPierre Schweitzer             if (!fileref->fcb->ads && (IrpSp->Parameters.Create.FileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != ((fileref->fcb->atts & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN)))) {
35074672b2baSPierre Schweitzer                 IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
35084672b2baSPierre Schweitzer 
35094672b2baSPierre Schweitzer                 acquire_fcb_lock_exclusive(Vcb);
35104672b2baSPierre Schweitzer                 free_fileref(Vcb, fileref);
35114672b2baSPierre Schweitzer                 release_fcb_lock(Vcb);
35124672b2baSPierre Schweitzer 
35134672b2baSPierre Schweitzer                 Status = STATUS_ACCESS_DENIED;
35144672b2baSPierre Schweitzer                 goto exit;
35154672b2baSPierre Schweitzer             }
35164672b2baSPierre Schweitzer 
3517c2c66affSColin Finck             if (fileref->fcb->ads) {
3518c2c66affSColin Finck                 Status = stream_set_end_of_file_information(Vcb, 0, fileref->fcb, fileref, FALSE);
3519c2c66affSColin Finck                 if (!NT_SUCCESS(Status)) {
3520c2c66affSColin Finck                     ERR("stream_set_end_of_file_information returned %08x\n", Status);
3521c2c66affSColin Finck 
3522c2c66affSColin Finck                     IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
3523c2c66affSColin Finck 
35244672b2baSPierre Schweitzer                     acquire_fcb_lock_exclusive(Vcb);
3525c2c66affSColin Finck                     free_fileref(Vcb, fileref);
35264672b2baSPierre Schweitzer                     release_fcb_lock(Vcb);
3527c2c66affSColin Finck 
3528c2c66affSColin Finck                     goto exit;
3529c2c66affSColin Finck                 }
3530c2c66affSColin Finck             } else {
3531c2c66affSColin Finck                 Status = truncate_file(fileref->fcb, 0, Irp, rollback);
3532c2c66affSColin Finck                 if (!NT_SUCCESS(Status)) {
3533c2c66affSColin Finck                     ERR("truncate_file returned %08x\n", Status);
3534c2c66affSColin Finck 
3535c2c66affSColin Finck                     IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
3536c2c66affSColin Finck 
35374672b2baSPierre Schweitzer                     acquire_fcb_lock_exclusive(Vcb);
3538c2c66affSColin Finck                     free_fileref(Vcb, fileref);
35394672b2baSPierre Schweitzer                     release_fcb_lock(Vcb);
3540c2c66affSColin Finck 
3541c2c66affSColin Finck                     goto exit;
3542c2c66affSColin Finck                 }
3543c2c66affSColin Finck             }
3544c2c66affSColin Finck 
3545c2c66affSColin Finck             if (Irp->Overlay.AllocationSize.QuadPart > 0) {
3546c2c66affSColin Finck                 Status = extend_file(fileref->fcb, fileref, Irp->Overlay.AllocationSize.QuadPart, TRUE, NULL, rollback);
3547c2c66affSColin Finck 
3548c2c66affSColin Finck                 if (!NT_SUCCESS(Status)) {
3549c2c66affSColin Finck                     ERR("extend_file returned %08x\n", Status);
3550c2c66affSColin Finck 
3551c2c66affSColin Finck                     IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
3552c2c66affSColin Finck 
35534672b2baSPierre Schweitzer                     acquire_fcb_lock_exclusive(Vcb);
3554c2c66affSColin Finck                     free_fileref(Vcb, fileref);
35554672b2baSPierre Schweitzer                     release_fcb_lock(Vcb);
3556c2c66affSColin Finck 
3557c2c66affSColin Finck                     goto exit;
3558c2c66affSColin Finck                 }
3559c2c66affSColin Finck             }
3560c2c66affSColin Finck 
3561c2c66affSColin Finck             if (!fileref->fcb->ads) {
35624672b2baSPierre Schweitzer                 LIST_ENTRY* le;
35634672b2baSPierre Schweitzer 
3564c2c66affSColin Finck                 if (Irp->AssociatedIrp.SystemBuffer && IrpSp->Parameters.Create.EaLength > 0) {
3565c2c66affSColin Finck                     ULONG offset;
3566c2c66affSColin Finck                     FILE_FULL_EA_INFORMATION* eainfo;
3567c2c66affSColin Finck 
3568c2c66affSColin Finck                     Status = IoCheckEaBufferValidity(Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.Create.EaLength, &offset);
3569c2c66affSColin Finck                     if (!NT_SUCCESS(Status)) {
3570c2c66affSColin Finck                         ERR("IoCheckEaBufferValidity returned %08x (error at offset %u)\n", Status, offset);
3571c2c66affSColin Finck 
3572c2c66affSColin Finck                         IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
3573c2c66affSColin Finck 
35744672b2baSPierre Schweitzer                         acquire_fcb_lock_exclusive(Vcb);
3575c2c66affSColin Finck                         free_fileref(Vcb, fileref);
35764672b2baSPierre Schweitzer                         release_fcb_lock(Vcb);
3577c2c66affSColin Finck 
3578c2c66affSColin Finck                         goto exit;
3579c2c66affSColin Finck                     }
3580c2c66affSColin Finck 
3581c2c66affSColin Finck                     fileref->fcb->ealen = 4;
3582c2c66affSColin Finck 
3583c2c66affSColin Finck                     // capitalize EA name
3584c2c66affSColin Finck                     eainfo = Irp->AssociatedIrp.SystemBuffer;
3585c2c66affSColin Finck                     do {
3586c2c66affSColin Finck                         STRING s;
3587c2c66affSColin Finck 
3588c2c66affSColin Finck                         s.Length = s.MaximumLength = eainfo->EaNameLength;
3589c2c66affSColin Finck                         s.Buffer = eainfo->EaName;
3590c2c66affSColin Finck 
3591c2c66affSColin Finck                         RtlUpperString(&s, &s);
3592c2c66affSColin Finck 
3593c2c66affSColin Finck                         fileref->fcb->ealen += 5 + eainfo->EaNameLength + eainfo->EaValueLength;
3594c2c66affSColin Finck 
3595c2c66affSColin Finck                         if (eainfo->NextEntryOffset == 0)
3596c2c66affSColin Finck                             break;
3597c2c66affSColin Finck 
3598c2c66affSColin Finck                         eainfo = (FILE_FULL_EA_INFORMATION*)(((UINT8*)eainfo) + eainfo->NextEntryOffset);
3599c2c66affSColin Finck                     } while (TRUE);
3600c2c66affSColin Finck 
3601c2c66affSColin Finck                     if (fileref->fcb->ea_xattr.Buffer)
3602c2c66affSColin Finck                         ExFreePool(fileref->fcb->ea_xattr.Buffer);
3603c2c66affSColin Finck 
3604c2c66affSColin Finck                     fileref->fcb->ea_xattr.Buffer = ExAllocatePoolWithTag(pool_type, IrpSp->Parameters.Create.EaLength, ALLOC_TAG);
3605c2c66affSColin Finck                     if (!fileref->fcb->ea_xattr.Buffer) {
3606c2c66affSColin Finck                         ERR("out of memory\n");
3607c2c66affSColin Finck                         Status = STATUS_INSUFFICIENT_RESOURCES;
3608c2c66affSColin Finck 
3609c2c66affSColin Finck                         IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
3610c2c66affSColin Finck 
36114672b2baSPierre Schweitzer                         acquire_fcb_lock_exclusive(Vcb);
3612c2c66affSColin Finck                         free_fileref(Vcb, fileref);
36134672b2baSPierre Schweitzer                         release_fcb_lock(Vcb);
3614c2c66affSColin Finck 
3615c2c66affSColin Finck                         goto exit;
3616c2c66affSColin Finck                     }
3617c2c66affSColin Finck 
3618c2c66affSColin Finck                     fileref->fcb->ea_xattr.Length = fileref->fcb->ea_xattr.MaximumLength = (USHORT)IrpSp->Parameters.Create.EaLength;
3619c2c66affSColin Finck                     RtlCopyMemory(fileref->fcb->ea_xattr.Buffer, Irp->AssociatedIrp.SystemBuffer, fileref->fcb->ea_xattr.Length);
3620c2c66affSColin Finck                 } else {
3621c2c66affSColin Finck                     if (fileref->fcb->ea_xattr.Length > 0) {
3622c2c66affSColin Finck                         ExFreePool(fileref->fcb->ea_xattr.Buffer);
3623c2c66affSColin Finck                         fileref->fcb->ea_xattr.Buffer = NULL;
3624c2c66affSColin Finck                         fileref->fcb->ea_xattr.Length = fileref->fcb->ea_xattr.MaximumLength = 0;
3625c2c66affSColin Finck 
3626c2c66affSColin Finck                         fileref->fcb->ea_changed = TRUE;
3627c2c66affSColin Finck                         fileref->fcb->ealen = 0;
3628c2c66affSColin Finck                     }
3629c2c66affSColin Finck                 }
36304672b2baSPierre Schweitzer 
36314672b2baSPierre Schweitzer                 // remove streams and send notifications
36324672b2baSPierre Schweitzer                 le = fileref->fcb->dir_children_index.Flink;
36334672b2baSPierre Schweitzer                 while (le != &fileref->fcb->dir_children_index) {
36344672b2baSPierre Schweitzer                     dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index);
36354672b2baSPierre Schweitzer                     LIST_ENTRY* le2 = le->Flink;
36364672b2baSPierre Schweitzer 
36374672b2baSPierre Schweitzer                     if (dc->index == 0) {
36384672b2baSPierre Schweitzer                         if (!dc->fileref) {
36394672b2baSPierre Schweitzer                             file_ref* fr2;
36404672b2baSPierre Schweitzer 
36414672b2baSPierre Schweitzer                             Status = open_fileref_child(Vcb, fileref, &dc->name, TRUE, TRUE, TRUE, PagedPool, &fr2, NULL);
36424672b2baSPierre Schweitzer                             if (!NT_SUCCESS(Status))
36434672b2baSPierre Schweitzer                                 WARN("open_fileref_child returned %08x\n", Status);
36444672b2baSPierre Schweitzer                         }
36454672b2baSPierre Schweitzer 
36464672b2baSPierre Schweitzer                         if (dc->fileref) {
36474672b2baSPierre Schweitzer                             send_notification_fcb(fileref, FILE_NOTIFY_CHANGE_STREAM_NAME, FILE_ACTION_REMOVED_STREAM, &dc->name);
36484672b2baSPierre Schweitzer 
36494672b2baSPierre Schweitzer                             Status = delete_fileref(dc->fileref, NULL, NULL, rollback);
36504672b2baSPierre Schweitzer                             if (!NT_SUCCESS(Status)) {
36514672b2baSPierre Schweitzer                                 ERR("delete_fileref returned %08x\n", Status);
36524672b2baSPierre Schweitzer 
36534672b2baSPierre Schweitzer                                 acquire_fcb_lock_exclusive(Vcb);
36544672b2baSPierre Schweitzer                                 free_fileref(Vcb, fileref);
36554672b2baSPierre Schweitzer                                 release_fcb_lock(Vcb);
36564672b2baSPierre Schweitzer 
36574672b2baSPierre Schweitzer                                 goto exit;
36584672b2baSPierre Schweitzer                             }
36594672b2baSPierre Schweitzer                         }
36604672b2baSPierre Schweitzer                     } else
36614672b2baSPierre Schweitzer                         break;
36624672b2baSPierre Schweitzer 
36634672b2baSPierre Schweitzer                     le = le2;
36644672b2baSPierre Schweitzer                 }
3665c2c66affSColin Finck             }
3666c2c66affSColin Finck 
3667c2c66affSColin Finck             KeQuerySystemTime(&time);
3668c2c66affSColin Finck             win_time_to_unix(time, &now);
3669c2c66affSColin Finck 
3670c2c66affSColin Finck             filter = FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE;
3671c2c66affSColin Finck 
3672c2c66affSColin Finck             if (fileref->fcb->ads) {
3673c2c66affSColin Finck                 fileref->parent->fcb->inode_item.st_mtime = now;
3674c2c66affSColin Finck                 fileref->parent->fcb->inode_item_changed = TRUE;
3675c2c66affSColin Finck                 mark_fcb_dirty(fileref->parent->fcb);
3676c2c66affSColin Finck 
3677c2c66affSColin Finck                 send_notification_fcb(fileref->parent, filter, FILE_ACTION_MODIFIED, &fileref->dc->name);
3678c2c66affSColin Finck             } else {
3679c2c66affSColin Finck                 mark_fcb_dirty(fileref->fcb);
3680c2c66affSColin Finck 
3681c2c66affSColin Finck                 oldatts = fileref->fcb->atts;
3682c2c66affSColin Finck 
3683c2c66affSColin Finck                 defda = get_file_attributes(Vcb, fileref->fcb->subvol, fileref->fcb->inode, fileref->fcb->type,
3684c2c66affSColin Finck                                             fileref->dc && fileref->dc->name.Length >= sizeof(WCHAR) && fileref->dc->name.Buffer[0] == '.', TRUE, Irp);
3685c2c66affSColin Finck 
3686c2c66affSColin Finck                 if (RequestedDisposition == FILE_SUPERSEDE)
3687c2c66affSColin Finck                     fileref->fcb->atts = IrpSp->Parameters.Create.FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
3688c2c66affSColin Finck                 else
3689c2c66affSColin Finck                     fileref->fcb->atts |= IrpSp->Parameters.Create.FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
3690c2c66affSColin Finck 
3691c2c66affSColin Finck                 if (fileref->fcb->atts != oldatts) {
3692c2c66affSColin Finck                     fileref->fcb->atts_changed = TRUE;
3693c2c66affSColin Finck                     fileref->fcb->atts_deleted = IrpSp->Parameters.Create.FileAttributes == defda;
3694c2c66affSColin Finck                     filter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
3695c2c66affSColin Finck                 }
3696c2c66affSColin Finck 
3697c2c66affSColin Finck                 fileref->fcb->inode_item.transid = Vcb->superblock.generation;
3698c2c66affSColin Finck                 fileref->fcb->inode_item.sequence++;
3699c2c66affSColin Finck                 fileref->fcb->inode_item.st_ctime = now;
3700c2c66affSColin Finck                 fileref->fcb->inode_item.st_mtime = now;
3701c2c66affSColin Finck                 fileref->fcb->inode_item_changed = TRUE;
3702c2c66affSColin Finck 
3703c2c66affSColin Finck                 send_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL);
3704c2c66affSColin Finck             }
3705c2c66affSColin Finck         } else {
3706c2c66affSColin Finck             if (options & FILE_NO_EA_KNOWLEDGE && fileref->fcb->ea_xattr.Length > 0) {
3707c2c66affSColin Finck                 FILE_FULL_EA_INFORMATION* ffei = (FILE_FULL_EA_INFORMATION*)fileref->fcb->ea_xattr.Buffer;
3708c2c66affSColin Finck 
3709c2c66affSColin Finck                 do {
3710c2c66affSColin Finck                     if (ffei->Flags & FILE_NEED_EA) {
3711c2c66affSColin Finck                         WARN("returning STATUS_ACCESS_DENIED as no EA knowledge\n");
3712c2c66affSColin Finck                         Status = STATUS_ACCESS_DENIED;
3713c2c66affSColin Finck 
3714c2c66affSColin Finck                         IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
3715c2c66affSColin Finck 
37164672b2baSPierre Schweitzer                         acquire_fcb_lock_exclusive(Vcb);
3717c2c66affSColin Finck                         free_fileref(Vcb, fileref);
37184672b2baSPierre Schweitzer                         release_fcb_lock(Vcb);
3719c2c66affSColin Finck 
3720c2c66affSColin Finck                         goto exit;
3721c2c66affSColin Finck                     }
3722c2c66affSColin Finck 
3723c2c66affSColin Finck                     if (ffei->NextEntryOffset == 0)
3724c2c66affSColin Finck                         break;
3725c2c66affSColin Finck 
3726c2c66affSColin Finck                     ffei = (FILE_FULL_EA_INFORMATION*)(((UINT8*)ffei) + ffei->NextEntryOffset);
3727c2c66affSColin Finck                 } while (TRUE);
3728c2c66affSColin Finck             }
3729c2c66affSColin Finck         }
3730c2c66affSColin Finck 
3731c2c66affSColin Finck         FileObject->FsContext = fileref->fcb;
3732c2c66affSColin Finck 
3733c2c66affSColin Finck         ccb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ccb), ALLOC_TAG);
3734c2c66affSColin Finck         if (!ccb) {
3735c2c66affSColin Finck             ERR("out of memory\n");
3736c2c66affSColin Finck             Status = STATUS_INSUFFICIENT_RESOURCES;
3737c2c66affSColin Finck 
3738c2c66affSColin Finck             IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
3739c2c66affSColin Finck 
37404672b2baSPierre Schweitzer             acquire_fcb_lock_exclusive(Vcb);
3741c2c66affSColin Finck             free_fileref(Vcb, fileref);
37424672b2baSPierre Schweitzer             release_fcb_lock(Vcb);
3743c2c66affSColin Finck 
3744c2c66affSColin Finck             goto exit;
3745c2c66affSColin Finck         }
3746c2c66affSColin Finck 
3747c2c66affSColin Finck         RtlZeroMemory(ccb, sizeof(*ccb));
3748c2c66affSColin Finck 
3749c2c66affSColin Finck         ccb->NodeType = BTRFS_NODE_TYPE_CCB;
3750c2c66affSColin Finck         ccb->NodeSize = sizeof(*ccb);
3751c2c66affSColin Finck         ccb->disposition = RequestedDisposition;
3752c2c66affSColin Finck         ccb->options = options;
3753c2c66affSColin Finck         ccb->query_dir_offset = 0;
3754c2c66affSColin Finck         RtlInitUnicodeString(&ccb->query_string, NULL);
3755c2c66affSColin Finck         ccb->has_wildcard = FALSE;
3756c2c66affSColin Finck         ccb->specific_file = FALSE;
3757c2c66affSColin Finck         ccb->access = granted_access;
3758c2c66affSColin Finck         ccb->case_sensitive = IrpSp->Flags & SL_CASE_SENSITIVE;
3759c2c66affSColin Finck         ccb->reserving = FALSE;
3760c2c66affSColin Finck         ccb->lxss = called_from_lxss();
3761c2c66affSColin Finck 
3762c2c66affSColin Finck         ccb->fileref = fileref;
3763c2c66affSColin Finck 
3764c2c66affSColin Finck         FileObject->FsContext2 = ccb;
3765c2c66affSColin Finck         FileObject->SectionObjectPointer = &fileref->fcb->nonpaged->segment_object;
3766c2c66affSColin Finck 
3767c2c66affSColin Finck         if (NT_SUCCESS(Status)) {
3768c2c66affSColin Finck             switch (RequestedDisposition) {
3769c2c66affSColin Finck                 case FILE_SUPERSEDE:
3770c2c66affSColin Finck                     Irp->IoStatus.Information = FILE_SUPERSEDED;
3771c2c66affSColin Finck                     break;
3772c2c66affSColin Finck 
3773c2c66affSColin Finck                 case FILE_OPEN:
3774c2c66affSColin Finck                 case FILE_OPEN_IF:
3775c2c66affSColin Finck                     Irp->IoStatus.Information = FILE_OPENED;
3776c2c66affSColin Finck                     break;
3777c2c66affSColin Finck 
3778c2c66affSColin Finck                 case FILE_OVERWRITE:
3779c2c66affSColin Finck                 case FILE_OVERWRITE_IF:
3780c2c66affSColin Finck                     Irp->IoStatus.Information = FILE_OVERWRITTEN;
3781c2c66affSColin Finck                     break;
3782c2c66affSColin Finck             }
3783c2c66affSColin Finck         }
3784c2c66affSColin Finck 
3785c2c66affSColin Finck         // Make sure paging files don't have any extents marked as being prealloc,
3786c2c66affSColin Finck         // as this would mean we'd have to lock exclusively when writing.
3787c2c66affSColin Finck         if (IrpSp->Flags & SL_OPEN_PAGING_FILE) {
3788c2c66affSColin Finck             LIST_ENTRY* le;
3789c2c66affSColin Finck             BOOL changed = FALSE;
3790c2c66affSColin Finck 
3791c2c66affSColin Finck             ExAcquireResourceExclusiveLite(fileref->fcb->Header.Resource, TRUE);
3792c2c66affSColin Finck 
3793c2c66affSColin Finck             le = fileref->fcb->extents.Flink;
3794c2c66affSColin Finck 
3795c2c66affSColin Finck             while (le != &fileref->fcb->extents) {
3796c2c66affSColin Finck                 extent* ext = CONTAINING_RECORD(le, extent, list_entry);
3797c2c66affSColin Finck 
3798c2c66affSColin Finck                 if (ext->extent_data.type == EXTENT_TYPE_PREALLOC) {
3799c2c66affSColin Finck                     ext->extent_data.type = EXTENT_TYPE_REGULAR;
3800c2c66affSColin Finck                     changed = TRUE;
3801c2c66affSColin Finck                 }
3802c2c66affSColin Finck 
3803c2c66affSColin Finck                 le = le->Flink;
3804c2c66affSColin Finck             }
3805c2c66affSColin Finck 
3806c2c66affSColin Finck             ExReleaseResourceLite(fileref->fcb->Header.Resource);
3807c2c66affSColin Finck 
3808c2c66affSColin Finck             if (changed) {
3809c2c66affSColin Finck                 fileref->fcb->extents_changed = TRUE;
3810c2c66affSColin Finck                 mark_fcb_dirty(fileref->fcb);
3811c2c66affSColin Finck             }
3812c2c66affSColin Finck 
3813c2c66affSColin Finck             fileref->fcb->Header.Flags2 |= FSRTL_FLAG2_IS_PAGING_FILE;
3814c2c66affSColin Finck             Vcb->disallow_dismount = TRUE;
3815c2c66affSColin Finck         }
3816c2c66affSColin Finck 
3817c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
3818c2c66affSColin Finck         oc = InterlockedIncrement(&fileref->open_count);
3819c2c66affSColin Finck         ERR("fileref %p: open_count now %i\n", fileref, oc);
3820c2c66affSColin Finck #else
3821c2c66affSColin Finck         InterlockedIncrement(&fileref->open_count);
3822c2c66affSColin Finck #endif
3823c2c66affSColin Finck         InterlockedIncrement(&Vcb->open_files);
3824c2c66affSColin Finck     } else {
3825c2c66affSColin Finck #ifdef DEBUG_STATS
3826c2c66affSColin Finck         open_type = 2;
3827c2c66affSColin Finck #endif
38284672b2baSPierre Schweitzer         Status = file_create(Irp, Vcb, FileObject, related, loaded_related, &fn, RequestedDisposition, options, rollback);
38294672b2baSPierre Schweitzer         release_fcb_lock(Vcb);
3830c2c66affSColin Finck 
3831c2c66affSColin Finck         Irp->IoStatus.Information = NT_SUCCESS(Status) ? FILE_CREATED : 0;
383257293803SMark Harmstone         granted_access = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
3833c2c66affSColin Finck     }
3834c2c66affSColin Finck 
3835c2c66affSColin Finck     if (NT_SUCCESS(Status) && !(options & FILE_NO_INTERMEDIATE_BUFFERING))
3836c2c66affSColin Finck         FileObject->Flags |= FO_CACHE_SUPPORTED;
3837c2c66affSColin Finck 
3838c2c66affSColin Finck exit:
3839c2c66affSColin Finck     if (loaded_related) {
38404672b2baSPierre Schweitzer         acquire_fcb_lock_exclusive(Vcb);
3841c2c66affSColin Finck         free_fileref(Vcb, related);
38424672b2baSPierre Schweitzer         release_fcb_lock(Vcb);
3843c2c66affSColin Finck     }
3844c2c66affSColin Finck 
3845c2c66affSColin Finck     if (Status == STATUS_SUCCESS) {
3846c2c66affSColin Finck         fcb* fcb2;
3847c2c66affSColin Finck 
3848c2c66affSColin Finck         IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess |= granted_access;
3849c2c66affSColin Finck         IrpSp->Parameters.Create.SecurityContext->AccessState->RemainingDesiredAccess &= ~(granted_access | MAXIMUM_ALLOWED);
3850c2c66affSColin Finck 
3851c2c66affSColin Finck         if (!FileObject->Vpb)
3852c2c66affSColin Finck             FileObject->Vpb = DeviceObject->Vpb;
3853c2c66affSColin Finck 
3854c2c66affSColin Finck         fcb2 = FileObject->FsContext;
3855c2c66affSColin Finck 
3856c2c66affSColin Finck         if (fcb2->ads) {
3857c2c66affSColin Finck             struct _ccb* ccb2 = FileObject->FsContext2;
3858c2c66affSColin Finck 
3859c2c66affSColin Finck             fcb2 = ccb2->fileref->parent->fcb;
3860c2c66affSColin Finck         }
3861c2c66affSColin Finck 
3862c2c66affSColin Finck         ExAcquireResourceExclusiveLite(fcb2->Header.Resource, TRUE);
3863c2c66affSColin Finck         fcb_load_csums(Vcb, fcb2, Irp);
3864c2c66affSColin Finck         ExReleaseResourceLite(fcb2->Header.Resource);
3865c2c66affSColin Finck     } else if (Status != STATUS_REPARSE && Status != STATUS_OBJECT_NAME_NOT_FOUND && Status != STATUS_OBJECT_PATH_NOT_FOUND)
3866c2c66affSColin Finck         TRACE("returning %08x\n", Status);
3867c2c66affSColin Finck 
3868c2c66affSColin Finck #ifdef DEBUG_STATS
3869c2c66affSColin Finck     time2 = KeQueryPerformanceCounter(NULL);
3870c2c66affSColin Finck 
3871c2c66affSColin Finck     if (open_type == 0) {
3872c2c66affSColin Finck         Vcb->stats.open_total_time += time2.QuadPart - time1.QuadPart;
3873c2c66affSColin Finck         Vcb->stats.num_opens++;
3874c2c66affSColin Finck     } else if (open_type == 1) {
3875c2c66affSColin Finck         Vcb->stats.overwrite_total_time += time2.QuadPart - time1.QuadPart;
3876c2c66affSColin Finck         Vcb->stats.num_overwrites++;
3877c2c66affSColin Finck     } else if (open_type == 2) {
3878c2c66affSColin Finck         Vcb->stats.create_total_time += time2.QuadPart - time1.QuadPart;
3879c2c66affSColin Finck         Vcb->stats.num_creates++;
3880c2c66affSColin Finck     }
3881c2c66affSColin Finck #endif
3882c2c66affSColin Finck 
3883c2c66affSColin Finck     return Status;
3884c2c66affSColin Finck }
3885c2c66affSColin Finck 
3886c2c66affSColin Finck static NTSTATUS verify_vcb(device_extension* Vcb, PIRP Irp) {
3887c2c66affSColin Finck     NTSTATUS Status;
3888c2c66affSColin Finck     LIST_ENTRY* le;
3889c2c66affSColin Finck     BOOL need_verify = FALSE;
3890c2c66affSColin Finck 
3891c2c66affSColin Finck     ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
3892c2c66affSColin Finck 
3893c2c66affSColin Finck     le = Vcb->devices.Flink;
3894c2c66affSColin Finck     while (le != &Vcb->devices) {
3895c2c66affSColin Finck         device* dev = CONTAINING_RECORD(le, device, list_entry);
3896c2c66affSColin Finck 
3897c2c66affSColin Finck         if (dev->devobj && dev->removable) {
3898c2c66affSColin Finck             ULONG cc;
3899c2c66affSColin Finck             IO_STATUS_BLOCK iosb;
3900c2c66affSColin Finck 
3901c2c66affSColin Finck             Status = dev_ioctl(dev->devobj, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, &cc, sizeof(ULONG), TRUE, &iosb);
3902c2c66affSColin Finck 
3903c2c66affSColin Finck             if (IoIsErrorUserInduced(Status)) {
3904c2c66affSColin Finck                 ERR("IOCTL_STORAGE_CHECK_VERIFY returned %08x (user-induced)\n", Status);
3905c2c66affSColin Finck                 need_verify = TRUE;
3906c2c66affSColin Finck             } else if (!NT_SUCCESS(Status)) {
3907c2c66affSColin Finck                 ERR("IOCTL_STORAGE_CHECK_VERIFY returned %08x\n", Status);
3908c2c66affSColin Finck                 goto end;
3909c2c66affSColin Finck             } else if (iosb.Information < sizeof(ULONG)) {
3910c2c66affSColin Finck                 ERR("iosb.Information was too short\n");
3911c2c66affSColin Finck                 Status = STATUS_INTERNAL_ERROR;
3912c2c66affSColin Finck             } else if (cc != dev->change_count) {
3913c2c66affSColin Finck                 dev->devobj->Flags |= DO_VERIFY_VOLUME;
3914c2c66affSColin Finck                 need_verify = TRUE;
3915c2c66affSColin Finck             }
3916c2c66affSColin Finck         }
3917c2c66affSColin Finck 
3918c2c66affSColin Finck         le = le->Flink;
3919c2c66affSColin Finck     }
3920c2c66affSColin Finck 
3921c2c66affSColin Finck     Status = STATUS_SUCCESS;
3922c2c66affSColin Finck 
3923c2c66affSColin Finck end:
3924c2c66affSColin Finck     ExReleaseResourceLite(&Vcb->tree_lock);
3925c2c66affSColin Finck 
3926c2c66affSColin Finck     if (need_verify) {
3927c2c66affSColin Finck         PDEVICE_OBJECT devobj;
3928c2c66affSColin Finck 
3929c2c66affSColin Finck         devobj = IoGetDeviceToVerify(Irp->Tail.Overlay.Thread);
3930c2c66affSColin Finck         IoSetDeviceToVerify(Irp->Tail.Overlay.Thread, NULL);
3931c2c66affSColin Finck 
3932c2c66affSColin Finck         if (!devobj) {
3933c2c66affSColin Finck             devobj = IoGetDeviceToVerify(PsGetCurrentThread());
3934c2c66affSColin Finck             IoSetDeviceToVerify(PsGetCurrentThread(), NULL);
3935c2c66affSColin Finck         }
3936c2c66affSColin Finck 
3937c2c66affSColin Finck         devobj = Vcb->Vpb ? Vcb->Vpb->RealDevice : NULL;
3938c2c66affSColin Finck 
3939c2c66affSColin Finck         if (devobj)
3940c2c66affSColin Finck             Status = IoVerifyVolume(devobj, FALSE);
3941c2c66affSColin Finck         else
3942c2c66affSColin Finck             Status = STATUS_VERIFY_REQUIRED;
3943c2c66affSColin Finck     }
3944c2c66affSColin Finck 
3945c2c66affSColin Finck     return Status;
3946c2c66affSColin Finck }
3947c2c66affSColin Finck 
3948c2c66affSColin Finck static BOOL has_manage_volume_privilege(ACCESS_STATE* access_state, KPROCESSOR_MODE processor_mode) {
3949c2c66affSColin Finck     PRIVILEGE_SET privset;
3950c2c66affSColin Finck 
3951c2c66affSColin Finck     privset.PrivilegeCount = 1;
3952c2c66affSColin Finck     privset.Control = PRIVILEGE_SET_ALL_NECESSARY;
3953c2c66affSColin Finck     privset.Privilege[0].Luid = RtlConvertLongToLuid(SE_MANAGE_VOLUME_PRIVILEGE);
3954c2c66affSColin Finck     privset.Privilege[0].Attributes = 0;
3955c2c66affSColin Finck 
3956c2c66affSColin Finck     return SePrivilegeCheck(&privset, &access_state->SubjectSecurityContext, processor_mode) ? TRUE : FALSE;
3957c2c66affSColin Finck }
3958c2c66affSColin Finck 
3959c2c66affSColin Finck _Dispatch_type_(IRP_MJ_CREATE)
3960c2c66affSColin Finck _Function_class_(DRIVER_DISPATCH)
39616c75215bSMark Jansen NTSTATUS NTAPI drv_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
3962c2c66affSColin Finck     NTSTATUS Status;
3963c2c66affSColin Finck     PIO_STACK_LOCATION IrpSp;
3964c2c66affSColin Finck     device_extension* Vcb = DeviceObject->DeviceExtension;
3965c2c66affSColin Finck     BOOL top_level, locked = FALSE;
3966c2c66affSColin Finck 
3967c2c66affSColin Finck     FsRtlEnterFileSystem();
3968c2c66affSColin Finck 
3969c2c66affSColin Finck     TRACE("create (flags = %x)\n", Irp->Flags);
3970c2c66affSColin Finck 
3971c2c66affSColin Finck     top_level = is_top_level(Irp);
3972c2c66affSColin Finck 
3973c2c66affSColin Finck     /* return success if just called for FS device object */
3974c2c66affSColin Finck     if (DeviceObject == master_devobj)  {
3975c2c66affSColin Finck         TRACE("create called for FS device object\n");
3976c2c66affSColin Finck 
3977c2c66affSColin Finck         Irp->IoStatus.Information = FILE_OPENED;
3978c2c66affSColin Finck         Status = STATUS_SUCCESS;
3979c2c66affSColin Finck 
3980c2c66affSColin Finck         goto exit;
3981c2c66affSColin Finck     } else if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
3982c2c66affSColin Finck         Status = vol_create(DeviceObject, Irp);
3983c2c66affSColin Finck         goto exit;
3984c2c66affSColin Finck     } else if (!Vcb || Vcb->type != VCB_TYPE_FS) {
3985c2c66affSColin Finck         Status = STATUS_INVALID_PARAMETER;
3986c2c66affSColin Finck         goto exit;
3987c2c66affSColin Finck     }
3988c2c66affSColin Finck 
3989c2c66affSColin Finck     if (!(Vcb->Vpb->Flags & VPB_MOUNTED)) {
3990c2c66affSColin Finck         Status = STATUS_DEVICE_NOT_READY;
3991c2c66affSColin Finck         goto exit;
3992c2c66affSColin Finck     }
3993c2c66affSColin Finck 
3994c2c66affSColin Finck     if (Vcb->removing) {
3995c2c66affSColin Finck         Status = STATUS_ACCESS_DENIED;
3996c2c66affSColin Finck         goto exit;
3997c2c66affSColin Finck     }
3998c2c66affSColin Finck 
3999c2c66affSColin Finck     Status = verify_vcb(Vcb, Irp);
4000c2c66affSColin Finck     if (!NT_SUCCESS(Status)) {
4001c2c66affSColin Finck         ERR("verify_vcb returned %08x\n", Status);
4002c2c66affSColin Finck         goto exit;
4003c2c66affSColin Finck     }
4004c2c66affSColin Finck 
4005c2c66affSColin Finck     ExAcquireResourceSharedLite(&Vcb->load_lock, TRUE);
4006c2c66affSColin Finck     locked = TRUE;
4007c2c66affSColin Finck 
4008c2c66affSColin Finck     IrpSp = IoGetCurrentIrpStackLocation(Irp);
4009c2c66affSColin Finck 
4010c2c66affSColin Finck     if (IrpSp->Flags != 0) {
4011c2c66affSColin Finck         UINT32 flags = IrpSp->Flags;
4012c2c66affSColin Finck 
4013c2c66affSColin Finck         TRACE("flags:\n");
4014c2c66affSColin Finck 
4015c2c66affSColin Finck         if (flags & SL_CASE_SENSITIVE) {
4016c2c66affSColin Finck             TRACE("SL_CASE_SENSITIVE\n");
4017c2c66affSColin Finck             flags &= ~SL_CASE_SENSITIVE;
4018c2c66affSColin Finck         }
4019c2c66affSColin Finck 
4020c2c66affSColin Finck         if (flags & SL_FORCE_ACCESS_CHECK) {
4021c2c66affSColin Finck             TRACE("SL_FORCE_ACCESS_CHECK\n");
4022c2c66affSColin Finck             flags &= ~SL_FORCE_ACCESS_CHECK;
4023c2c66affSColin Finck         }
4024c2c66affSColin Finck 
4025c2c66affSColin Finck         if (flags & SL_OPEN_PAGING_FILE) {
4026c2c66affSColin Finck             TRACE("SL_OPEN_PAGING_FILE\n");
4027c2c66affSColin Finck             flags &= ~SL_OPEN_PAGING_FILE;
4028c2c66affSColin Finck         }
4029c2c66affSColin Finck 
4030c2c66affSColin Finck         if (flags & SL_OPEN_TARGET_DIRECTORY) {
4031c2c66affSColin Finck             TRACE("SL_OPEN_TARGET_DIRECTORY\n");
4032c2c66affSColin Finck             flags &= ~SL_OPEN_TARGET_DIRECTORY;
4033c2c66affSColin Finck         }
4034c2c66affSColin Finck 
4035c2c66affSColin Finck         if (flags & SL_STOP_ON_SYMLINK) {
4036c2c66affSColin Finck             TRACE("SL_STOP_ON_SYMLINK\n");
4037c2c66affSColin Finck             flags &= ~SL_STOP_ON_SYMLINK;
4038c2c66affSColin Finck         }
4039c2c66affSColin Finck 
4040c2c66affSColin Finck         if (flags)
4041c2c66affSColin Finck             WARN("unknown flags: %x\n", flags);
4042c2c66affSColin Finck     } else {
4043c2c66affSColin Finck         TRACE("flags: (none)\n");
4044c2c66affSColin Finck     }
4045c2c66affSColin Finck 
4046c2c66affSColin Finck     if (!IrpSp->FileObject) {
4047c2c66affSColin Finck         ERR("FileObject was NULL\n");
4048c2c66affSColin Finck         Status = STATUS_INVALID_PARAMETER;
4049c2c66affSColin Finck         goto exit;
4050c2c66affSColin Finck     }
4051c2c66affSColin Finck 
4052c2c66affSColin Finck     if (IrpSp->FileObject->RelatedFileObject) {
4053c2c66affSColin Finck         fcb* relatedfcb = IrpSp->FileObject->RelatedFileObject->FsContext;
4054c2c66affSColin Finck 
4055c2c66affSColin Finck         if (relatedfcb && relatedfcb->Vcb != Vcb) {
4056c2c66affSColin Finck             WARN("RelatedFileObject was for different device\n");
4057c2c66affSColin Finck             Status = STATUS_INVALID_PARAMETER;
4058c2c66affSColin Finck             goto exit;
4059c2c66affSColin Finck         }
4060c2c66affSColin Finck     }
4061c2c66affSColin Finck 
4062c2c66affSColin Finck     // opening volume
4063c2c66affSColin Finck     if (IrpSp->FileObject->FileName.Length == 0 && !IrpSp->FileObject->RelatedFileObject) {
4064c2c66affSColin Finck         ULONG RequestedDisposition = ((IrpSp->Parameters.Create.Options >> 24) & 0xff);
4065c2c66affSColin Finck         ULONG RequestedOptions = IrpSp->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
4066c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
4067c2c66affSColin Finck         LONG rc;
4068c2c66affSColin Finck #endif
4069c2c66affSColin Finck         ccb* ccb;
4070c2c66affSColin Finck 
4071c2c66affSColin Finck         TRACE("open operation for volume\n");
4072c2c66affSColin Finck 
4073c2c66affSColin Finck         if (RequestedDisposition != FILE_OPEN && RequestedDisposition != FILE_OPEN_IF) {
4074c2c66affSColin Finck             Status = STATUS_ACCESS_DENIED;
4075c2c66affSColin Finck             goto exit;
4076c2c66affSColin Finck         }
4077c2c66affSColin Finck 
4078c2c66affSColin Finck         if (RequestedOptions & FILE_DIRECTORY_FILE) {
4079c2c66affSColin Finck             Status = STATUS_NOT_A_DIRECTORY;
4080c2c66affSColin Finck             goto exit;
4081c2c66affSColin Finck         }
4082c2c66affSColin Finck 
4083c2c66affSColin Finck         ccb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ccb), ALLOC_TAG);
4084c2c66affSColin Finck         if (!ccb) {
4085c2c66affSColin Finck             ERR("out of memory\n");
4086c2c66affSColin Finck             Status = STATUS_INSUFFICIENT_RESOURCES;
4087c2c66affSColin Finck             goto exit;
4088c2c66affSColin Finck         }
4089c2c66affSColin Finck 
4090c2c66affSColin Finck         RtlZeroMemory(ccb, sizeof(*ccb));
4091c2c66affSColin Finck 
4092c2c66affSColin Finck         ccb->NodeType = BTRFS_NODE_TYPE_CCB;
4093c2c66affSColin Finck         ccb->NodeSize = sizeof(*ccb);
4094c2c66affSColin Finck         ccb->disposition = RequestedDisposition;
4095c2c66affSColin Finck         ccb->options = RequestedOptions;
4096c2c66affSColin Finck         ccb->access = IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess;
4097c2c66affSColin Finck         ccb->manage_volume_privilege = has_manage_volume_privilege(IrpSp->Parameters.Create.SecurityContext->AccessState,
4098c2c66affSColin Finck                                                                    IrpSp->Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode);
4099c2c66affSColin Finck         ccb->reserving = FALSE;
4100c2c66affSColin Finck         ccb->lxss = called_from_lxss();
4101c2c66affSColin Finck 
4102c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
4103c2c66affSColin Finck         rc = InterlockedIncrement(&Vcb->volume_fcb->refcount);
4104c2c66affSColin Finck         WARN("fcb %p: refcount now %i (volume)\n", Vcb->volume_fcb, rc);
4105c2c66affSColin Finck #else
4106c2c66affSColin Finck         InterlockedIncrement(&Vcb->volume_fcb->refcount);
4107c2c66affSColin Finck #endif
4108c2c66affSColin Finck         IrpSp->FileObject->FsContext = Vcb->volume_fcb;
4109c2c66affSColin Finck         IrpSp->FileObject->FsContext2 = ccb;
4110c2c66affSColin Finck 
4111c2c66affSColin Finck         IrpSp->FileObject->SectionObjectPointer = &Vcb->volume_fcb->nonpaged->segment_object;
4112c2c66affSColin Finck 
4113c2c66affSColin Finck         if (!IrpSp->FileObject->Vpb)
4114c2c66affSColin Finck             IrpSp->FileObject->Vpb = DeviceObject->Vpb;
4115c2c66affSColin Finck 
4116c2c66affSColin Finck         InterlockedIncrement(&Vcb->open_files);
4117c2c66affSColin Finck 
4118c2c66affSColin Finck         Irp->IoStatus.Information = FILE_OPENED;
4119c2c66affSColin Finck         Status = STATUS_SUCCESS;
4120c2c66affSColin Finck     } else {
4121c2c66affSColin Finck         LIST_ENTRY rollback;
4122c2c66affSColin Finck         BOOL skip_lock;
4123c2c66affSColin Finck 
4124c2c66affSColin Finck         InitializeListHead(&rollback);
4125c2c66affSColin Finck 
4126c2c66affSColin Finck         TRACE("file name: %.*S\n", IrpSp->FileObject->FileName.Length / sizeof(WCHAR), IrpSp->FileObject->FileName.Buffer);
4127c2c66affSColin Finck 
4128c2c66affSColin Finck         if (IrpSp->FileObject->RelatedFileObject)
4129c2c66affSColin Finck             TRACE("related file = %S\n", file_desc(IrpSp->FileObject->RelatedFileObject));
4130c2c66affSColin Finck 
4131c2c66affSColin Finck         // Don't lock again if we're being called from within CcCopyRead etc.
4132c2c66affSColin Finck         skip_lock = ExIsResourceAcquiredExclusiveLite(&Vcb->tree_lock);
4133c2c66affSColin Finck 
4134c2c66affSColin Finck         if (!skip_lock)
4135c2c66affSColin Finck             ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
4136c2c66affSColin Finck 
4137c2c66affSColin Finck         Status = open_file(DeviceObject, Vcb, Irp, &rollback);
4138c2c66affSColin Finck 
4139c2c66affSColin Finck         if (!NT_SUCCESS(Status))
4140c2c66affSColin Finck             do_rollback(Vcb, &rollback);
4141c2c66affSColin Finck         else
4142c2c66affSColin Finck             clear_rollback(&rollback);
4143c2c66affSColin Finck 
4144c2c66affSColin Finck         if (!skip_lock)
4145c2c66affSColin Finck             ExReleaseResourceLite(&Vcb->tree_lock);
4146c2c66affSColin Finck     }
4147c2c66affSColin Finck 
4148c2c66affSColin Finck exit:
4149c2c66affSColin Finck     Irp->IoStatus.Status = Status;
4150c2c66affSColin Finck     IoCompleteRequest( Irp, NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT );
4151c2c66affSColin Finck 
4152c2c66affSColin Finck     TRACE("create returning %08x\n", Status);
4153c2c66affSColin Finck 
4154c2c66affSColin Finck     if (locked)
4155c2c66affSColin Finck         ExReleaseResourceLite(&Vcb->load_lock);
4156c2c66affSColin Finck 
4157c2c66affSColin Finck     if (top_level)
4158c2c66affSColin Finck         IoSetTopLevelIrp(NULL);
4159c2c66affSColin Finck 
4160c2c66affSColin Finck     FsRtlExitFileSystem();
4161c2c66affSColin Finck 
4162c2c66affSColin Finck     return Status;
4163c2c66affSColin Finck }
4164