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"
22194ea909SVictor Perevertkin #include "crc32c.h"
23c2c66affSColin Finck #include <ntddstor.h>
24c2c66affSColin Finck
25c2c66affSColin Finck extern PDEVICE_OBJECT master_devobj;
26318da0c1SPierre Schweitzer extern tFsRtlGetEcpListFromIrp fFsRtlGetEcpListFromIrp;
27318da0c1SPierre Schweitzer extern tFsRtlGetNextExtraCreateParameter fFsRtlGetNextExtraCreateParameter;
28318da0c1SPierre Schweitzer extern tFsRtlValidateReparsePointBuffer fFsRtlValidateReparsePointBuffer;
29c2c66affSColin Finck
30eb7fbc25SPierre Schweitzer static const WCHAR datastring[] = L"::$DATA";
31eb7fbc25SPierre Schweitzer
3262e630deSPierre Schweitzer static const char root_dir[] = "$Root";
3362e630deSPierre Schweitzer static const WCHAR root_dir_utf16[] = L"$Root";
3462e630deSPierre Schweitzer
35eb7fbc25SPierre Schweitzer // Windows 10
36eb7fbc25SPierre Schweitzer #define ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED 0x0002
37194ea909SVictor Perevertkin #define ATOMIC_CREATE_ECP_IN_FLAG_OP_FLAGS_SPECIFIED 0x0080
38eb7fbc25SPierre Schweitzer #define ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT 0x0100
39194ea909SVictor Perevertkin
40eb7fbc25SPierre Schweitzer #define ATOMIC_CREATE_ECP_OUT_FLAG_REPARSE_POINT_SET 0x0002
41194ea909SVictor Perevertkin #define ATOMIC_CREATE_ECP_OUT_FLAG_OP_FLAGS_HONORED 0x0080
42194ea909SVictor Perevertkin
43194ea909SVictor Perevertkin #define ATOMIC_CREATE_ECP_IN_OP_FLAG_CASE_SENSITIVE_FLAGS_SPECIFIED 1
44194ea909SVictor Perevertkin #define ATOMIC_CREATE_ECP_OUT_OP_FLAG_CASE_SENSITIVE_FLAGS_SET 1
45194ea909SVictor Perevertkin
46174dfab6SVincent Franchomme #ifndef SL_IGNORE_READONLY_ATTRIBUTE
47174dfab6SVincent Franchomme #define SL_IGNORE_READONLY_ATTRIBUTE 0x40 // introduced in Windows 10, not in mingw
48174dfab6SVincent Franchomme #endif
49174dfab6SVincent Franchomme
50194ea909SVictor Perevertkin typedef struct _FILE_TIMESTAMPS {
51194ea909SVictor Perevertkin LARGE_INTEGER CreationTime;
52194ea909SVictor Perevertkin LARGE_INTEGER LastAccessTime;
53194ea909SVictor Perevertkin LARGE_INTEGER LastWriteTime;
54194ea909SVictor Perevertkin LARGE_INTEGER ChangeTime;
55194ea909SVictor Perevertkin } FILE_TIMESTAMPS, *PFILE_TIMESTAMPS;
56eb7fbc25SPierre Schweitzer
57eb7fbc25SPierre Schweitzer typedef struct _ATOMIC_CREATE_ECP_CONTEXT {
58eb7fbc25SPierre Schweitzer USHORT Size;
59eb7fbc25SPierre Schweitzer USHORT InFlags;
60eb7fbc25SPierre Schweitzer USHORT OutFlags;
61eb7fbc25SPierre Schweitzer USHORT ReparseBufferLength;
62eb7fbc25SPierre Schweitzer PREPARSE_DATA_BUFFER ReparseBuffer;
63eb7fbc25SPierre Schweitzer LONGLONG FileSize;
64eb7fbc25SPierre Schweitzer LONGLONG ValidDataLength;
65194ea909SVictor Perevertkin PFILE_TIMESTAMPS FileTimestamps;
66194ea909SVictor Perevertkin ULONG FileAttributes;
67194ea909SVictor Perevertkin ULONG UsnSourceInfo;
68194ea909SVictor Perevertkin USN Usn;
69194ea909SVictor Perevertkin ULONG SuppressFileAttributeInheritanceMask;
70194ea909SVictor Perevertkin ULONG InOpFlags;
71194ea909SVictor Perevertkin ULONG OutOpFlags;
72194ea909SVictor Perevertkin ULONG InGenFlags;
73194ea909SVictor Perevertkin ULONG OutGenFlags;
74194ea909SVictor Perevertkin ULONG CaseSensitiveFlagsMask;
75194ea909SVictor Perevertkin ULONG InCaseSensitiveFlags;
76194ea909SVictor Perevertkin ULONG OutCaseSensitiveFlags;
77eb7fbc25SPierre Schweitzer } ATOMIC_CREATE_ECP_CONTEXT, *PATOMIC_CREATE_ECP_CONTEXT;
78eb7fbc25SPierre Schweitzer
79eb7fbc25SPierre Schweitzer static const GUID GUID_ECP_ATOMIC_CREATE = { 0x4720bd83, 0x52ac, 0x4104, { 0xa1, 0x30, 0xd1, 0xec, 0x6a, 0x8c, 0xc8, 0xe5 } };
80194ea909SVictor Perevertkin static const GUID GUID_ECP_QUERY_ON_CREATE = { 0x1aca62e9, 0xabb4, 0x4ff2, { 0xbb, 0x5c, 0x1c, 0x79, 0x02, 0x5e, 0x41, 0x7f } };
81194ea909SVictor Perevertkin static const GUID GUID_ECP_CREATE_REDIRECTION = { 0x188d6bd6, 0xa126, 0x4fa8, { 0xbd, 0xf2, 0x1c, 0xcd, 0xf8, 0x96, 0xf3, 0xe0 } };
82c2c66affSColin Finck
83c982533eSVincent Franchomme typedef struct {
84c982533eSVincent Franchomme device_extension* Vcb;
85c982533eSVincent Franchomme ACCESS_MASK granted_access;
86c982533eSVincent Franchomme file_ref* fileref;
876e0cf03dSVincent Franchomme NTSTATUS Status;
886e0cf03dSVincent Franchomme KEVENT event;
89c982533eSVincent Franchomme } oplock_context;
90c982533eSVincent Franchomme
create_fcb(device_extension * Vcb,POOL_TYPE pool_type)91c2c66affSColin Finck fcb* create_fcb(device_extension* Vcb, POOL_TYPE pool_type) {
92c2c66affSColin Finck fcb* fcb;
93c2c66affSColin Finck
94c2c66affSColin Finck if (pool_type == NonPagedPool) {
95c2c66affSColin Finck fcb = ExAllocatePoolWithTag(pool_type, sizeof(struct _fcb), ALLOC_TAG);
96c2c66affSColin Finck if (!fcb) {
97c2c66affSColin Finck ERR("out of memory\n");
98c2c66affSColin Finck return NULL;
99c2c66affSColin Finck }
100c2c66affSColin Finck } else {
101c2c66affSColin Finck fcb = ExAllocateFromPagedLookasideList(&Vcb->fcb_lookaside);
102c2c66affSColin Finck if (!fcb) {
103c2c66affSColin Finck ERR("out of memory\n");
104c2c66affSColin Finck return NULL;
105c2c66affSColin Finck }
106c2c66affSColin Finck }
107c2c66affSColin Finck
108c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
109c2c66affSColin Finck WARN("allocating fcb %p\n", fcb);
110c2c66affSColin Finck #endif
111c2c66affSColin Finck RtlZeroMemory(fcb, sizeof(struct _fcb));
112c2c66affSColin Finck fcb->pool_type = pool_type;
113c2c66affSColin Finck
114c2c66affSColin Finck fcb->Header.NodeTypeCode = BTRFS_NODE_TYPE_FCB;
115c2c66affSColin Finck fcb->Header.NodeByteSize = sizeof(struct _fcb);
116c2c66affSColin Finck
117c2c66affSColin Finck fcb->nonpaged = ExAllocateFromNPagedLookasideList(&Vcb->fcb_np_lookaside);
118c2c66affSColin Finck if (!fcb->nonpaged) {
119c2c66affSColin Finck ERR("out of memory\n");
120c2c66affSColin Finck
121c2c66affSColin Finck if (pool_type == NonPagedPool)
122c2c66affSColin Finck ExFreePool(fcb);
123c2c66affSColin Finck else
124c2c66affSColin Finck ExFreeToPagedLookasideList(&Vcb->fcb_lookaside, fcb);
125c2c66affSColin Finck
126c2c66affSColin Finck return NULL;
127c2c66affSColin Finck }
128c2c66affSColin Finck RtlZeroMemory(fcb->nonpaged, sizeof(struct _fcb_nonpaged));
129c2c66affSColin Finck
130c2c66affSColin Finck ExInitializeResourceLite(&fcb->nonpaged->paging_resource);
131c2c66affSColin Finck fcb->Header.PagingIoResource = &fcb->nonpaged->paging_resource;
132c2c66affSColin Finck
133c2c66affSColin Finck ExInitializeFastMutex(&fcb->nonpaged->HeaderMutex);
134c2c66affSColin Finck FsRtlSetupAdvancedHeader(&fcb->Header, &fcb->nonpaged->HeaderMutex);
135c2c66affSColin Finck
136c2c66affSColin Finck fcb->refcount = 1;
137c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
138c2c66affSColin Finck WARN("fcb %p: refcount now %i\n", fcb, fcb->refcount);
139c2c66affSColin Finck #endif
140c2c66affSColin Finck
141c2c66affSColin Finck ExInitializeResourceLite(&fcb->nonpaged->resource);
142c2c66affSColin Finck fcb->Header.Resource = &fcb->nonpaged->resource;
143c2c66affSColin Finck
144c2c66affSColin Finck ExInitializeResourceLite(&fcb->nonpaged->dir_children_lock);
145c2c66affSColin Finck
146c2c66affSColin Finck FsRtlInitializeFileLock(&fcb->lock, NULL, NULL);
14762e630deSPierre Schweitzer FsRtlInitializeOplock(fcb_oplock(fcb));
148c2c66affSColin Finck
149c2c66affSColin Finck InitializeListHead(&fcb->extents);
150c2c66affSColin Finck InitializeListHead(&fcb->hardlinks);
151c2c66affSColin Finck InitializeListHead(&fcb->xattrs);
152c2c66affSColin Finck
153c2c66affSColin Finck InitializeListHead(&fcb->dir_children_index);
154c2c66affSColin Finck InitializeListHead(&fcb->dir_children_hash);
155c2c66affSColin Finck InitializeListHead(&fcb->dir_children_hash_uc);
156c2c66affSColin Finck
157c2c66affSColin Finck return fcb;
158c2c66affSColin Finck }
159c2c66affSColin Finck
create_fileref(device_extension * Vcb)160c2c66affSColin Finck file_ref* create_fileref(device_extension* Vcb) {
161c2c66affSColin Finck file_ref* fr;
162c2c66affSColin Finck
163c2c66affSColin Finck fr = ExAllocateFromPagedLookasideList(&Vcb->fileref_lookaside);
164c2c66affSColin Finck if (!fr) {
165c2c66affSColin Finck ERR("out of memory\n");
166c2c66affSColin Finck return NULL;
167c2c66affSColin Finck }
168c2c66affSColin Finck
169c2c66affSColin Finck RtlZeroMemory(fr, sizeof(file_ref));
170c2c66affSColin Finck
171c2c66affSColin Finck fr->refcount = 1;
172c2c66affSColin Finck
173c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
174c2c66affSColin Finck WARN("fileref %p: refcount now 1\n", fr);
175c2c66affSColin Finck #endif
176c2c66affSColin Finck
177c2c66affSColin Finck InitializeListHead(&fr->children);
178c2c66affSColin Finck
179c2c66affSColin Finck return fr;
180c2c66affSColin Finck }
181c2c66affSColin Finck
find_file_in_dir(PUNICODE_STRING filename,fcb * fcb,root ** subvol,uint64_t * inode,dir_child ** pdc,bool case_sensitive)182318da0c1SPierre Schweitzer NTSTATUS find_file_in_dir(PUNICODE_STRING filename, fcb* fcb, root** subvol, uint64_t* inode, dir_child** pdc, bool case_sensitive) {
183c2c66affSColin Finck NTSTATUS Status;
184c2c66affSColin Finck UNICODE_STRING fnus;
185318da0c1SPierre Schweitzer uint32_t hash;
186c2c66affSColin Finck LIST_ENTRY* le;
187318da0c1SPierre Schweitzer uint8_t c;
188318da0c1SPierre Schweitzer bool locked = false;
189c2c66affSColin Finck
190c2c66affSColin Finck if (!case_sensitive) {
191318da0c1SPierre Schweitzer Status = RtlUpcaseUnicodeString(&fnus, filename, true);
192c2c66affSColin Finck
193c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
194194ea909SVictor Perevertkin ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
195c2c66affSColin Finck return Status;
196c2c66affSColin Finck }
197c2c66affSColin Finck } else
198c2c66affSColin Finck fnus = *filename;
199c2c66affSColin Finck
20098654b54SVincent Franchomme Status = check_file_name_valid(filename, false, false);
20198654b54SVincent Franchomme if (!NT_SUCCESS(Status))
20298654b54SVincent Franchomme return Status;
20398654b54SVincent Franchomme
204318da0c1SPierre Schweitzer hash = calc_crc32c(0xffffffff, (uint8_t*)fnus.Buffer, fnus.Length);
205c2c66affSColin Finck
206c2c66affSColin Finck c = hash >> 24;
207c2c66affSColin Finck
208c2c66affSColin Finck if (!ExIsResourceAcquiredSharedLite(&fcb->nonpaged->dir_children_lock)) {
209318da0c1SPierre Schweitzer ExAcquireResourceSharedLite(&fcb->nonpaged->dir_children_lock, true);
210318da0c1SPierre Schweitzer locked = true;
211c2c66affSColin Finck }
212c2c66affSColin Finck
213c2c66affSColin Finck if (case_sensitive) {
214c2c66affSColin Finck if (!fcb->hash_ptrs[c]) {
215c2c66affSColin Finck Status = STATUS_OBJECT_NAME_NOT_FOUND;
216c2c66affSColin Finck goto end;
217c2c66affSColin Finck }
218c2c66affSColin Finck
219c2c66affSColin Finck le = fcb->hash_ptrs[c];
220c2c66affSColin Finck while (le != &fcb->dir_children_hash) {
221c2c66affSColin Finck dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_hash);
222c2c66affSColin Finck
223c2c66affSColin Finck if (dc->hash == hash) {
224c2c66affSColin Finck if (dc->name.Length == fnus.Length && RtlCompareMemory(dc->name.Buffer, fnus.Buffer, fnus.Length) == fnus.Length) {
225c2c66affSColin Finck if (dc->key.obj_type == TYPE_ROOT_ITEM) {
226c2c66affSColin Finck LIST_ENTRY* le2;
227c2c66affSColin Finck
228c2c66affSColin Finck *subvol = NULL;
229c2c66affSColin Finck
230c2c66affSColin Finck le2 = fcb->Vcb->roots.Flink;
231c2c66affSColin Finck while (le2 != &fcb->Vcb->roots) {
232c2c66affSColin Finck root* r2 = CONTAINING_RECORD(le2, root, list_entry);
233c2c66affSColin Finck
234c2c66affSColin Finck if (r2->id == dc->key.obj_id) {
235c2c66affSColin Finck *subvol = r2;
236c2c66affSColin Finck break;
237c2c66affSColin Finck }
238c2c66affSColin Finck
239c2c66affSColin Finck le2 = le2->Flink;
240c2c66affSColin Finck }
241c2c66affSColin Finck
242c2c66affSColin Finck *inode = SUBVOL_ROOT_INODE;
243c2c66affSColin Finck } else {
244c2c66affSColin Finck *subvol = fcb->subvol;
245c2c66affSColin Finck *inode = dc->key.obj_id;
246c2c66affSColin Finck }
247c2c66affSColin Finck
248c2c66affSColin Finck *pdc = dc;
249c2c66affSColin Finck
250c2c66affSColin Finck Status = STATUS_SUCCESS;
251c2c66affSColin Finck goto end;
252c2c66affSColin Finck }
253c2c66affSColin Finck } else if (dc->hash > hash) {
254c2c66affSColin Finck Status = STATUS_OBJECT_NAME_NOT_FOUND;
255c2c66affSColin Finck goto end;
256c2c66affSColin Finck }
257c2c66affSColin Finck
258c2c66affSColin Finck le = le->Flink;
259c2c66affSColin Finck }
260c2c66affSColin Finck } else {
261c2c66affSColin Finck if (!fcb->hash_ptrs_uc[c]) {
262c2c66affSColin Finck Status = STATUS_OBJECT_NAME_NOT_FOUND;
263c2c66affSColin Finck goto end;
264c2c66affSColin Finck }
265c2c66affSColin Finck
266c2c66affSColin Finck le = fcb->hash_ptrs_uc[c];
267c2c66affSColin Finck while (le != &fcb->dir_children_hash_uc) {
268c2c66affSColin Finck dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_hash_uc);
269c2c66affSColin Finck
270c2c66affSColin Finck if (dc->hash_uc == hash) {
271c2c66affSColin Finck if (dc->name_uc.Length == fnus.Length && RtlCompareMemory(dc->name_uc.Buffer, fnus.Buffer, fnus.Length) == fnus.Length) {
272c2c66affSColin Finck if (dc->key.obj_type == TYPE_ROOT_ITEM) {
273c2c66affSColin Finck LIST_ENTRY* le2;
274c2c66affSColin Finck
275c2c66affSColin Finck *subvol = NULL;
276c2c66affSColin Finck
277c2c66affSColin Finck le2 = fcb->Vcb->roots.Flink;
278c2c66affSColin Finck while (le2 != &fcb->Vcb->roots) {
279c2c66affSColin Finck root* r2 = CONTAINING_RECORD(le2, root, list_entry);
280c2c66affSColin Finck
281c2c66affSColin Finck if (r2->id == dc->key.obj_id) {
282c2c66affSColin Finck *subvol = r2;
283c2c66affSColin Finck break;
284c2c66affSColin Finck }
285c2c66affSColin Finck
286c2c66affSColin Finck le2 = le2->Flink;
287c2c66affSColin Finck }
288c2c66affSColin Finck
289c2c66affSColin Finck *inode = SUBVOL_ROOT_INODE;
290c2c66affSColin Finck } else {
291c2c66affSColin Finck *subvol = fcb->subvol;
292c2c66affSColin Finck *inode = dc->key.obj_id;
293c2c66affSColin Finck }
294c2c66affSColin Finck
295c2c66affSColin Finck *pdc = dc;
296c2c66affSColin Finck
297c2c66affSColin Finck Status = STATUS_SUCCESS;
298c2c66affSColin Finck goto end;
299c2c66affSColin Finck }
300c2c66affSColin Finck } else if (dc->hash_uc > hash) {
301c2c66affSColin Finck Status = STATUS_OBJECT_NAME_NOT_FOUND;
302c2c66affSColin Finck goto end;
303c2c66affSColin Finck }
304c2c66affSColin Finck
305c2c66affSColin Finck le = le->Flink;
306c2c66affSColin Finck }
307c2c66affSColin Finck }
308c2c66affSColin Finck
309c2c66affSColin Finck Status = STATUS_OBJECT_NAME_NOT_FOUND;
310c2c66affSColin Finck
311c2c66affSColin Finck end:
312c2c66affSColin Finck if (locked)
313c2c66affSColin Finck ExReleaseResourceLite(&fcb->nonpaged->dir_children_lock);
314c2c66affSColin Finck
315c2c66affSColin Finck if (!case_sensitive)
316c2c66affSColin Finck ExFreePool(fnus.Buffer);
317c2c66affSColin Finck
318c2c66affSColin Finck return Status;
319c2c66affSColin Finck }
320c2c66affSColin Finck
split_path(device_extension * Vcb,PUNICODE_STRING path,LIST_ENTRY * parts,bool * stream)321318da0c1SPierre Schweitzer static NTSTATUS split_path(device_extension* Vcb, PUNICODE_STRING path, LIST_ENTRY* parts, bool* stream) {
322c2c66affSColin Finck ULONG len, i;
323318da0c1SPierre Schweitzer bool has_stream;
324c2c66affSColin Finck WCHAR* buf;
325c2c66affSColin Finck name_bit* nb;
326883b1f31SPierre Schweitzer NTSTATUS Status;
327c2c66affSColin Finck
328c2c66affSColin Finck len = path->Length / sizeof(WCHAR);
329c2c66affSColin Finck if (len > 0 && (path->Buffer[len - 1] == '/' || path->Buffer[len - 1] == '\\'))
330c2c66affSColin Finck len--;
331c2c66affSColin Finck
332883b1f31SPierre Schweitzer if (len == 0 || (path->Buffer[len - 1] == '/' || path->Buffer[len - 1] == '\\')) {
333883b1f31SPierre Schweitzer WARN("zero-length filename part\n");
334883b1f31SPierre Schweitzer return STATUS_OBJECT_NAME_INVALID;
335883b1f31SPierre Schweitzer }
336883b1f31SPierre Schweitzer
337318da0c1SPierre Schweitzer has_stream = false;
338c2c66affSColin Finck for (i = 0; i < len; i++) {
339c2c66affSColin Finck if (path->Buffer[i] == '/' || path->Buffer[i] == '\\') {
340318da0c1SPierre Schweitzer has_stream = false;
341c2c66affSColin Finck } else if (path->Buffer[i] == ':') {
342318da0c1SPierre Schweitzer has_stream = true;
343c2c66affSColin Finck }
344c2c66affSColin Finck }
345c2c66affSColin Finck
346c2c66affSColin Finck buf = path->Buffer;
347c2c66affSColin Finck
348c2c66affSColin Finck for (i = 0; i < len; i++) {
349c2c66affSColin Finck if (path->Buffer[i] == '/' || path->Buffer[i] == '\\') {
350883b1f31SPierre Schweitzer if (buf[0] == '/' || buf[0] == '\\') {
351883b1f31SPierre Schweitzer WARN("zero-length filename part\n");
352883b1f31SPierre Schweitzer Status = STATUS_OBJECT_NAME_INVALID;
353883b1f31SPierre Schweitzer goto cleanup;
354883b1f31SPierre Schweitzer }
355883b1f31SPierre Schweitzer
356c2c66affSColin Finck nb = ExAllocateFromPagedLookasideList(&Vcb->name_bit_lookaside);
357c2c66affSColin Finck if (!nb) {
358c2c66affSColin Finck ERR("out of memory\n");
359883b1f31SPierre Schweitzer Status = STATUS_INSUFFICIENT_RESOURCES;
360883b1f31SPierre Schweitzer goto cleanup;
361c2c66affSColin Finck }
362c2c66affSColin Finck
363c2c66affSColin Finck nb->us.Buffer = buf;
364c2c66affSColin Finck nb->us.Length = nb->us.MaximumLength = (USHORT)(&path->Buffer[i] - buf) * sizeof(WCHAR);
365c2c66affSColin Finck InsertTailList(parts, &nb->list_entry);
366c2c66affSColin Finck
367c2c66affSColin Finck buf = &path->Buffer[i+1];
368c2c66affSColin Finck }
369c2c66affSColin Finck }
370c2c66affSColin Finck
371c2c66affSColin Finck nb = ExAllocateFromPagedLookasideList(&Vcb->name_bit_lookaside);
372c2c66affSColin Finck if (!nb) {
373c2c66affSColin Finck ERR("out of memory\n");
374883b1f31SPierre Schweitzer Status = STATUS_INSUFFICIENT_RESOURCES;
375883b1f31SPierre Schweitzer goto cleanup;
376c2c66affSColin Finck }
377c2c66affSColin Finck
378c2c66affSColin Finck nb->us.Buffer = buf;
379c2c66affSColin Finck nb->us.Length = nb->us.MaximumLength = (USHORT)(&path->Buffer[i] - buf) * sizeof(WCHAR);
380c2c66affSColin Finck InsertTailList(parts, &nb->list_entry);
381c2c66affSColin Finck
382c2c66affSColin Finck if (has_stream) {
383eb7fbc25SPierre Schweitzer static const WCHAR datasuf[] = {':','$','D','A','T','A',0};
384c2c66affSColin Finck UNICODE_STRING dsus;
385c2c66affSColin Finck
386eb7fbc25SPierre Schweitzer dsus.Buffer = (WCHAR*)datasuf;
387eb7fbc25SPierre Schweitzer dsus.Length = dsus.MaximumLength = sizeof(datasuf) - sizeof(WCHAR);
388c2c66affSColin Finck
389c2c66affSColin Finck for (i = 0; i < nb->us.Length / sizeof(WCHAR); i++) {
390c2c66affSColin Finck if (nb->us.Buffer[i] == ':') {
391c2c66affSColin Finck name_bit* nb2;
392c2c66affSColin Finck
39306042735SVincent Franchomme if (i + 1 == nb->us.Length / sizeof(WCHAR)) {
394883b1f31SPierre Schweitzer WARN("zero-length stream name\n");
395883b1f31SPierre Schweitzer Status = STATUS_OBJECT_NAME_INVALID;
396883b1f31SPierre Schweitzer goto cleanup;
397883b1f31SPierre Schweitzer }
398883b1f31SPierre Schweitzer
399c2c66affSColin Finck nb2 = ExAllocateFromPagedLookasideList(&Vcb->name_bit_lookaside);
400c2c66affSColin Finck if (!nb2) {
401c2c66affSColin Finck ERR("out of memory\n");
402883b1f31SPierre Schweitzer Status = STATUS_INSUFFICIENT_RESOURCES;
403883b1f31SPierre Schweitzer goto cleanup;
404c2c66affSColin Finck }
405c2c66affSColin Finck
406c2c66affSColin Finck nb2->us.Buffer = &nb->us.Buffer[i+1];
407318da0c1SPierre Schweitzer nb2->us.Length = nb2->us.MaximumLength = (uint16_t)(nb->us.Length - (i * sizeof(WCHAR)) - sizeof(WCHAR));
408c2c66affSColin Finck InsertTailList(parts, &nb2->list_entry);
409c2c66affSColin Finck
410318da0c1SPierre Schweitzer nb->us.Length = (uint16_t)i * sizeof(WCHAR);
411c2c66affSColin Finck nb->us.MaximumLength = nb->us.Length;
412c2c66affSColin Finck
413c2c66affSColin Finck nb = nb2;
414c2c66affSColin Finck
415c2c66affSColin Finck break;
416c2c66affSColin Finck }
417c2c66affSColin Finck }
418c2c66affSColin Finck
419c2c66affSColin Finck // FIXME - should comparison be case-insensitive?
420c2c66affSColin Finck // remove :$DATA suffix
421c2c66affSColin Finck if (nb->us.Length >= dsus.Length && RtlCompareMemory(&nb->us.Buffer[(nb->us.Length - dsus.Length)/sizeof(WCHAR)], dsus.Buffer, dsus.Length) == dsus.Length)
422c2c66affSColin Finck nb->us.Length -= dsus.Length;
423c2c66affSColin Finck
424c2c66affSColin Finck if (nb->us.Length == 0) {
425c2c66affSColin Finck RemoveTailList(parts);
426c2c66affSColin Finck ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb);
427c2c66affSColin Finck
428318da0c1SPierre Schweitzer has_stream = false;
429c2c66affSColin Finck }
430c2c66affSColin Finck }
431c2c66affSColin Finck
432c2c66affSColin Finck // if path is just stream name, remove first empty item
433c2c66affSColin Finck if (has_stream && path->Length >= sizeof(WCHAR) && path->Buffer[0] == ':') {
434c2c66affSColin Finck name_bit *nb1 = CONTAINING_RECORD(RemoveHeadList(parts), name_bit, list_entry);
435c2c66affSColin Finck
436c2c66affSColin Finck ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb1);
437c2c66affSColin Finck }
438c2c66affSColin Finck
439c2c66affSColin Finck *stream = has_stream;
440c2c66affSColin Finck
441c2c66affSColin Finck return STATUS_SUCCESS;
442883b1f31SPierre Schweitzer
443883b1f31SPierre Schweitzer cleanup:
444883b1f31SPierre Schweitzer while (!IsListEmpty(parts)) {
445883b1f31SPierre Schweitzer nb = CONTAINING_RECORD(RemoveHeadList(parts), name_bit, list_entry);
446883b1f31SPierre Schweitzer
447883b1f31SPierre Schweitzer ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb);
448883b1f31SPierre Schweitzer }
449883b1f31SPierre Schweitzer
450883b1f31SPierre Schweitzer return Status;
451c2c66affSColin Finck }
452c2c66affSColin Finck
453194ea909SVictor Perevertkin NTSTATUS load_csum(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, void* csum, uint64_t start, uint64_t length, PIRP Irp) {
454c2c66affSColin Finck NTSTATUS Status;
455c2c66affSColin Finck KEY searchkey;
456c2c66affSColin Finck traverse_ptr tp, next_tp;
457318da0c1SPierre Schweitzer uint64_t i, j;
458318da0c1SPierre Schweitzer bool b;
459194ea909SVictor Perevertkin void* ptr = csum;
460c2c66affSColin Finck
461c2c66affSColin Finck searchkey.obj_id = EXTENT_CSUM_ID;
462c2c66affSColin Finck searchkey.obj_type = TYPE_EXTENT_CSUM;
463c2c66affSColin Finck searchkey.offset = start;
464c2c66affSColin Finck
465318da0c1SPierre Schweitzer Status = find_item(Vcb, Vcb->checksum_root, &tp, &searchkey, false, Irp);
466c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
467194ea909SVictor Perevertkin ERR("error - find_item returned %08lx\n", Status);
468c2c66affSColin Finck return Status;
469c2c66affSColin Finck }
470c2c66affSColin Finck
471c2c66affSColin Finck i = 0;
472c2c66affSColin Finck do {
473c2c66affSColin Finck if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
474c2c66affSColin Finck ULONG readlen;
475c2c66affSColin Finck
476c2c66affSColin Finck if (start < tp.item->key.offset)
477c2c66affSColin Finck j = 0;
478c2c66affSColin Finck else
479174dfab6SVincent Franchomme j = ((start - tp.item->key.offset) >> Vcb->sector_shift) + i;
480c2c66affSColin Finck
481174dfab6SVincent Franchomme if (j * Vcb->csum_size > tp.item->size || tp.item->key.offset > start + (i << Vcb->sector_shift)) {
482174dfab6SVincent Franchomme ERR("checksum not found for %I64x\n", start + (i << Vcb->sector_shift));
483c2c66affSColin Finck return STATUS_INTERNAL_ERROR;
484c2c66affSColin Finck }
485c2c66affSColin Finck
486194ea909SVictor Perevertkin readlen = (ULONG)min((tp.item->size / Vcb->csum_size) - j, length - i);
487194ea909SVictor Perevertkin RtlCopyMemory(ptr, tp.item->data + (j * Vcb->csum_size), readlen * Vcb->csum_size);
488194ea909SVictor Perevertkin
489194ea909SVictor Perevertkin ptr = (uint8_t*)ptr + (readlen * Vcb->csum_size);
490c2c66affSColin Finck i += readlen;
491c2c66affSColin Finck
492c2c66affSColin Finck if (i == length)
493c2c66affSColin Finck break;
494c2c66affSColin Finck }
495c2c66affSColin Finck
496318da0c1SPierre Schweitzer b = find_next_item(Vcb, &tp, &next_tp, false, Irp);
497c2c66affSColin Finck
498c2c66affSColin Finck if (b)
499c2c66affSColin Finck tp = next_tp;
500c2c66affSColin Finck } while (b);
501c2c66affSColin Finck
502c2c66affSColin Finck if (i < length) {
503318da0c1SPierre Schweitzer ERR("could not read checksums: offset %I64x, length %I64x sectors\n", start, length);
504c2c66affSColin Finck return STATUS_INTERNAL_ERROR;
505c2c66affSColin Finck }
506c2c66affSColin Finck
507c2c66affSColin Finck return STATUS_SUCCESS;
508c2c66affSColin Finck }
509c2c66affSColin Finck
510318da0c1SPierre Schweitzer NTSTATUS load_dir_children(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, fcb* fcb, bool ignore_size, PIRP Irp) {
511c2c66affSColin Finck KEY searchkey;
512c2c66affSColin Finck traverse_ptr tp, next_tp;
513c2c66affSColin Finck NTSTATUS Status;
514c2c66affSColin Finck ULONG num_children = 0;
51562e630deSPierre Schweitzer uint64_t max_index = 2;
516c2c66affSColin Finck
517c2c66affSColin Finck fcb->hash_ptrs = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG);
518c2c66affSColin Finck if (!fcb->hash_ptrs) {
519c2c66affSColin Finck ERR("out of memory\n");
520c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
521c2c66affSColin Finck }
522c2c66affSColin Finck
523c2c66affSColin Finck RtlZeroMemory(fcb->hash_ptrs, sizeof(LIST_ENTRY*) * 256);
524c2c66affSColin Finck
525c2c66affSColin Finck fcb->hash_ptrs_uc = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG);
526c2c66affSColin Finck if (!fcb->hash_ptrs_uc) {
527c2c66affSColin Finck ERR("out of memory\n");
528c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
529c2c66affSColin Finck }
530c2c66affSColin Finck
531c2c66affSColin Finck RtlZeroMemory(fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256);
532c2c66affSColin Finck
533c2c66affSColin Finck if (!ignore_size && fcb->inode_item.st_size == 0)
534c2c66affSColin Finck return STATUS_SUCCESS;
535c2c66affSColin Finck
536c2c66affSColin Finck searchkey.obj_id = fcb->inode;
537c2c66affSColin Finck searchkey.obj_type = TYPE_DIR_INDEX;
538c2c66affSColin Finck searchkey.offset = 2;
539c2c66affSColin Finck
540318da0c1SPierre Schweitzer Status = find_item(Vcb, fcb->subvol, &tp, &searchkey, false, Irp);
541c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
542194ea909SVictor Perevertkin ERR("find_item returned %08lx\n", Status);
543c2c66affSColin Finck return Status;
544c2c66affSColin Finck }
545c2c66affSColin Finck
546c2c66affSColin Finck if (keycmp(tp.item->key, searchkey) == -1) {
547318da0c1SPierre Schweitzer if (find_next_item(Vcb, &tp, &next_tp, false, Irp)) {
548c2c66affSColin Finck tp = next_tp;
549318da0c1SPierre Schweitzer TRACE("moving on to %I64x,%x,%I64x\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
550c2c66affSColin Finck }
551c2c66affSColin Finck }
552c2c66affSColin Finck
553c2c66affSColin Finck while (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
554c2c66affSColin Finck DIR_ITEM* di = (DIR_ITEM*)tp.item->data;
555c2c66affSColin Finck dir_child* dc;
556c2c66affSColin Finck ULONG utf16len;
557c2c66affSColin Finck
558c2c66affSColin Finck if (tp.item->size < sizeof(DIR_ITEM)) {
559194ea909SVictor Perevertkin WARN("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM));
560c2c66affSColin Finck goto cont;
561c2c66affSColin Finck }
562c2c66affSColin Finck
563c2c66affSColin Finck if (di->n == 0) {
564318da0c1SPierre Schweitzer WARN("(%I64x,%x,%I64x): DIR_ITEM name length is zero\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
565c2c66affSColin Finck goto cont;
566c2c66affSColin Finck }
567c2c66affSColin Finck
568318da0c1SPierre Schweitzer Status = utf8_to_utf16(NULL, 0, &utf16len, di->name, di->n);
569c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
570194ea909SVictor Perevertkin ERR("utf8_to_utf16 1 returned %08lx\n", Status);
571c2c66affSColin Finck goto cont;
572c2c66affSColin Finck }
573c2c66affSColin Finck
574c2c66affSColin Finck dc = ExAllocatePoolWithTag(PagedPool, sizeof(dir_child), ALLOC_TAG);
575c2c66affSColin Finck if (!dc) {
576c2c66affSColin Finck ERR("out of memory\n");
577c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
578c2c66affSColin Finck }
579c2c66affSColin Finck
580c2c66affSColin Finck dc->key = di->key;
581c2c66affSColin Finck dc->index = tp.item->key.offset;
582c2c66affSColin Finck dc->type = di->type;
583c2c66affSColin Finck dc->fileref = NULL;
58462e630deSPierre Schweitzer dc->root_dir = false;
58562e630deSPierre Schweitzer
58662e630deSPierre Schweitzer max_index = dc->index;
587c2c66affSColin Finck
588c2c66affSColin Finck dc->utf8.MaximumLength = dc->utf8.Length = di->n;
589c2c66affSColin Finck dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, di->n, ALLOC_TAG);
590c2c66affSColin Finck if (!dc->utf8.Buffer) {
591c2c66affSColin Finck ERR("out of memory\n");
592c2c66affSColin Finck ExFreePool(dc);
593c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
594c2c66affSColin Finck }
595c2c66affSColin Finck
596c2c66affSColin Finck RtlCopyMemory(dc->utf8.Buffer, di->name, di->n);
597c2c66affSColin Finck
598318da0c1SPierre Schweitzer dc->name.MaximumLength = dc->name.Length = (uint16_t)utf16len;
599c2c66affSColin Finck dc->name.Buffer = ExAllocatePoolWithTag(PagedPool, dc->name.MaximumLength, ALLOC_TAG);
600c2c66affSColin Finck if (!dc->name.Buffer) {
601c2c66affSColin Finck ERR("out of memory\n");
602c2c66affSColin Finck ExFreePool(dc->utf8.Buffer);
603c2c66affSColin Finck ExFreePool(dc);
604c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
605c2c66affSColin Finck }
606c2c66affSColin Finck
607318da0c1SPierre Schweitzer Status = utf8_to_utf16(dc->name.Buffer, utf16len, &utf16len, di->name, di->n);
608c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
609194ea909SVictor Perevertkin ERR("utf8_to_utf16 2 returned %08lx\n", Status);
610c2c66affSColin Finck ExFreePool(dc->utf8.Buffer);
611c2c66affSColin Finck ExFreePool(dc->name.Buffer);
612c2c66affSColin Finck ExFreePool(dc);
613c2c66affSColin Finck goto cont;
614c2c66affSColin Finck }
615c2c66affSColin Finck
616318da0c1SPierre Schweitzer Status = RtlUpcaseUnicodeString(&dc->name_uc, &dc->name, true);
617c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
618194ea909SVictor Perevertkin ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
619c2c66affSColin Finck ExFreePool(dc->utf8.Buffer);
620c2c66affSColin Finck ExFreePool(dc->name.Buffer);
621c2c66affSColin Finck ExFreePool(dc);
622c2c66affSColin Finck goto cont;
623c2c66affSColin Finck }
624c2c66affSColin Finck
625318da0c1SPierre Schweitzer dc->hash = calc_crc32c(0xffffffff, (uint8_t*)dc->name.Buffer, dc->name.Length);
626318da0c1SPierre Schweitzer dc->hash_uc = calc_crc32c(0xffffffff, (uint8_t*)dc->name_uc.Buffer, dc->name_uc.Length);
627c2c66affSColin Finck
628c2c66affSColin Finck InsertTailList(&fcb->dir_children_index, &dc->list_entry_index);
629c2c66affSColin Finck
630c2c66affSColin Finck insert_dir_child_into_hash_lists(fcb, dc);
631c2c66affSColin Finck
632c2c66affSColin Finck num_children++;
633c2c66affSColin Finck
634c2c66affSColin Finck cont:
635318da0c1SPierre Schweitzer if (find_next_item(Vcb, &tp, &next_tp, false, Irp))
636c2c66affSColin Finck tp = next_tp;
637c2c66affSColin Finck else
638c2c66affSColin Finck break;
639c2c66affSColin Finck }
640c2c66affSColin Finck
64162e630deSPierre Schweitzer if (!Vcb->options.no_root_dir && fcb->inode == SUBVOL_ROOT_INODE) {
64262e630deSPierre Schweitzer root* top_subvol;
64362e630deSPierre Schweitzer
64462e630deSPierre Schweitzer if (Vcb->root_fileref && Vcb->root_fileref->fcb)
64562e630deSPierre Schweitzer top_subvol = Vcb->root_fileref->fcb->subvol;
64662e630deSPierre Schweitzer else
64762e630deSPierre Schweitzer top_subvol = find_default_subvol(Vcb, NULL);
64862e630deSPierre Schweitzer
64962e630deSPierre Schweitzer if (fcb->subvol == top_subvol && top_subvol->id != BTRFS_ROOT_FSTREE) {
65062e630deSPierre Schweitzer dir_child* dc = ExAllocatePoolWithTag(PagedPool, sizeof(dir_child), ALLOC_TAG);
65162e630deSPierre Schweitzer if (!dc) {
65262e630deSPierre Schweitzer ERR("out of memory\n");
65362e630deSPierre Schweitzer return STATUS_INSUFFICIENT_RESOURCES;
65462e630deSPierre Schweitzer }
65562e630deSPierre Schweitzer
65662e630deSPierre Schweitzer dc->key.obj_id = BTRFS_ROOT_FSTREE;
65762e630deSPierre Schweitzer dc->key.obj_type = TYPE_ROOT_ITEM;
65862e630deSPierre Schweitzer dc->key.offset = 0;
65962e630deSPierre Schweitzer dc->index = max_index + 1;
66062e630deSPierre Schweitzer dc->type = BTRFS_TYPE_DIRECTORY;
66162e630deSPierre Schweitzer dc->fileref = NULL;
66262e630deSPierre Schweitzer dc->root_dir = true;
66362e630deSPierre Schweitzer
66462e630deSPierre Schweitzer dc->utf8.MaximumLength = dc->utf8.Length = sizeof(root_dir) - sizeof(char);
66562e630deSPierre Schweitzer dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(root_dir) - sizeof(char), ALLOC_TAG);
66662e630deSPierre Schweitzer if (!dc->utf8.Buffer) {
66762e630deSPierre Schweitzer ERR("out of memory\n");
66862e630deSPierre Schweitzer ExFreePool(dc);
66962e630deSPierre Schweitzer return STATUS_INSUFFICIENT_RESOURCES;
67062e630deSPierre Schweitzer }
67162e630deSPierre Schweitzer
67262e630deSPierre Schweitzer RtlCopyMemory(dc->utf8.Buffer, root_dir, sizeof(root_dir) - sizeof(char));
67362e630deSPierre Schweitzer
67462e630deSPierre Schweitzer dc->name.MaximumLength = dc->name.Length = sizeof(root_dir_utf16) - sizeof(WCHAR);
67562e630deSPierre Schweitzer dc->name.Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(root_dir_utf16) - sizeof(WCHAR), ALLOC_TAG);
67662e630deSPierre Schweitzer if (!dc->name.Buffer) {
67762e630deSPierre Schweitzer ERR("out of memory\n");
67862e630deSPierre Schweitzer ExFreePool(dc->utf8.Buffer);
67962e630deSPierre Schweitzer ExFreePool(dc);
68062e630deSPierre Schweitzer return STATUS_INSUFFICIENT_RESOURCES;
68162e630deSPierre Schweitzer }
68262e630deSPierre Schweitzer
68362e630deSPierre Schweitzer RtlCopyMemory(dc->name.Buffer, root_dir_utf16, sizeof(root_dir_utf16) - sizeof(WCHAR));
68462e630deSPierre Schweitzer
68562e630deSPierre Schweitzer Status = RtlUpcaseUnicodeString(&dc->name_uc, &dc->name, true);
68662e630deSPierre Schweitzer if (!NT_SUCCESS(Status)) {
687194ea909SVictor Perevertkin ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
68862e630deSPierre Schweitzer ExFreePool(dc->utf8.Buffer);
68962e630deSPierre Schweitzer ExFreePool(dc->name.Buffer);
69062e630deSPierre Schweitzer ExFreePool(dc);
69162e630deSPierre Schweitzer goto cont;
69262e630deSPierre Schweitzer }
69362e630deSPierre Schweitzer
69462e630deSPierre Schweitzer dc->hash = calc_crc32c(0xffffffff, (uint8_t*)dc->name.Buffer, dc->name.Length);
69562e630deSPierre Schweitzer dc->hash_uc = calc_crc32c(0xffffffff, (uint8_t*)dc->name_uc.Buffer, dc->name_uc.Length);
69662e630deSPierre Schweitzer
69762e630deSPierre Schweitzer InsertTailList(&fcb->dir_children_index, &dc->list_entry_index);
69862e630deSPierre Schweitzer
69962e630deSPierre Schweitzer insert_dir_child_into_hash_lists(fcb, dc);
70062e630deSPierre Schweitzer }
70162e630deSPierre Schweitzer }
70262e630deSPierre Schweitzer
703c2c66affSColin Finck return STATUS_SUCCESS;
704c2c66affSColin Finck }
705c2c66affSColin Finck
706c2c66affSColin Finck NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension* Vcb,
707318da0c1SPierre Schweitzer root* subvol, uint64_t inode, uint8_t type, PANSI_STRING utf8, bool always_add_hl, fcb* parent, fcb** pfcb, POOL_TYPE pooltype, PIRP Irp) {
708c2c66affSColin Finck KEY searchkey;
709c2c66affSColin Finck traverse_ptr tp, next_tp;
710c2c66affSColin Finck NTSTATUS Status;
711c2c66affSColin Finck fcb *fcb, *deleted_fcb = NULL;
712318da0c1SPierre Schweitzer bool atts_set = false, sd_set = false, no_data;
713c2c66affSColin Finck LIST_ENTRY* lastle = NULL;
714c2c66affSColin Finck EXTENT_DATA* ed = NULL;
71506042735SVincent Franchomme uint64_t fcbs_version = 0;
716318da0c1SPierre Schweitzer uint32_t hash;
717c2c66affSColin Finck
718318da0c1SPierre Schweitzer hash = calc_crc32c(0xffffffff, (uint8_t*)&inode, sizeof(uint64_t));
719883b1f31SPierre Schweitzer
720883b1f31SPierre Schweitzer acquire_fcb_lock_shared(Vcb);
721883b1f31SPierre Schweitzer
722883b1f31SPierre Schweitzer if (subvol->fcbs_ptrs[hash >> 24]) {
723883b1f31SPierre Schweitzer LIST_ENTRY* le = subvol->fcbs_ptrs[hash >> 24];
724c2c66affSColin Finck
725c2c66affSColin Finck while (le != &subvol->fcbs) {
726c2c66affSColin Finck fcb = CONTAINING_RECORD(le, struct _fcb, list_entry);
727c2c66affSColin Finck
728c2c66affSColin Finck if (fcb->inode == inode) {
729c2c66affSColin Finck if (!fcb->ads) {
730c2c66affSColin Finck if (fcb->deleted)
731c2c66affSColin Finck deleted_fcb = fcb;
732c2c66affSColin Finck else {
733c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
734c2c66affSColin Finck LONG rc = InterlockedIncrement(&fcb->refcount);
735c2c66affSColin Finck
736318da0c1SPierre Schweitzer WARN("fcb %p: refcount now %i (subvol %I64x, inode %I64x)\n", fcb, rc, fcb->subvol->id, fcb->inode);
737c2c66affSColin Finck #else
738c2c66affSColin Finck InterlockedIncrement(&fcb->refcount);
739c2c66affSColin Finck #endif
740c2c66affSColin Finck
741c2c66affSColin Finck *pfcb = fcb;
742883b1f31SPierre Schweitzer release_fcb_lock(Vcb);
743c2c66affSColin Finck return STATUS_SUCCESS;
744c2c66affSColin Finck }
745c2c66affSColin Finck }
746883b1f31SPierre Schweitzer } else if (fcb->hash > hash) {
747c2c66affSColin Finck if (deleted_fcb) {
748c2c66affSColin Finck InterlockedIncrement(&deleted_fcb->refcount);
749c2c66affSColin Finck *pfcb = deleted_fcb;
750883b1f31SPierre Schweitzer release_fcb_lock(Vcb);
751c2c66affSColin Finck return STATUS_SUCCESS;
752c2c66affSColin Finck }
753c2c66affSColin Finck
754c2c66affSColin Finck lastle = le->Blink;
755883b1f31SPierre Schweitzer fcbs_version = subvol->fcbs_version;
756883b1f31SPierre Schweitzer
757c2c66affSColin Finck break;
758c2c66affSColin Finck }
759c2c66affSColin Finck
760c2c66affSColin Finck le = le->Flink;
761c2c66affSColin Finck }
762c2c66affSColin Finck }
763c2c66affSColin Finck
764883b1f31SPierre Schweitzer release_fcb_lock(Vcb);
765883b1f31SPierre Schweitzer
766c2c66affSColin Finck if (deleted_fcb) {
767c2c66affSColin Finck InterlockedIncrement(&deleted_fcb->refcount);
768c2c66affSColin Finck *pfcb = deleted_fcb;
769c2c66affSColin Finck return STATUS_SUCCESS;
770c2c66affSColin Finck }
771c2c66affSColin Finck
772c2c66affSColin Finck fcb = create_fcb(Vcb, pooltype);
773c2c66affSColin Finck if (!fcb) {
774c2c66affSColin Finck ERR("out of memory\n");
775c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
776c2c66affSColin Finck }
777c2c66affSColin Finck
778c2c66affSColin Finck fcb->Vcb = Vcb;
779c2c66affSColin Finck
780c2c66affSColin Finck fcb->subvol = subvol;
781c2c66affSColin Finck fcb->inode = inode;
782883b1f31SPierre Schweitzer fcb->hash = hash;
783c2c66affSColin Finck fcb->type = type;
784c2c66affSColin Finck
785c2c66affSColin Finck searchkey.obj_id = inode;
786c2c66affSColin Finck searchkey.obj_type = TYPE_INODE_ITEM;
787c2c66affSColin Finck searchkey.offset = 0xffffffffffffffff;
788c2c66affSColin Finck
789318da0c1SPierre Schweitzer Status = find_item(Vcb, subvol, &tp, &searchkey, false, Irp);
790c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
791194ea909SVictor Perevertkin ERR("error - find_item returned %08lx\n", Status);
792883b1f31SPierre Schweitzer reap_fcb(fcb);
793c2c66affSColin Finck return Status;
794c2c66affSColin Finck }
795c2c66affSColin Finck
796c2c66affSColin Finck if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
797318da0c1SPierre Schweitzer WARN("couldn't find INODE_ITEM for inode %I64x in subvol %I64x\n", inode, subvol->id);
798883b1f31SPierre Schweitzer reap_fcb(fcb);
799c2c66affSColin Finck return STATUS_INVALID_PARAMETER;
800c2c66affSColin Finck }
801c2c66affSColin Finck
802c2c66affSColin Finck if (tp.item->size > 0)
803c2c66affSColin Finck RtlCopyMemory(&fcb->inode_item, tp.item->data, min(sizeof(INODE_ITEM), tp.item->size));
804c2c66affSColin Finck
805c2c66affSColin Finck if (fcb->type == 0) { // guess the type from the inode mode, if the caller doesn't know already
806c2c66affSColin Finck if ((fcb->inode_item.st_mode & __S_IFDIR) == __S_IFDIR)
807c2c66affSColin Finck fcb->type = BTRFS_TYPE_DIRECTORY;
808c2c66affSColin Finck else if ((fcb->inode_item.st_mode & __S_IFCHR) == __S_IFCHR)
809c2c66affSColin Finck fcb->type = BTRFS_TYPE_CHARDEV;
810c2c66affSColin Finck else if ((fcb->inode_item.st_mode & __S_IFBLK) == __S_IFBLK)
811c2c66affSColin Finck fcb->type = BTRFS_TYPE_BLOCKDEV;
812c2c66affSColin Finck else if ((fcb->inode_item.st_mode & __S_IFIFO) == __S_IFIFO)
813c2c66affSColin Finck fcb->type = BTRFS_TYPE_FIFO;
814c2c66affSColin Finck else if ((fcb->inode_item.st_mode & __S_IFLNK) == __S_IFLNK)
815c2c66affSColin Finck fcb->type = BTRFS_TYPE_SYMLINK;
816c2c66affSColin Finck else if ((fcb->inode_item.st_mode & __S_IFSOCK) == __S_IFSOCK)
817c2c66affSColin Finck fcb->type = BTRFS_TYPE_SOCKET;
818c2c66affSColin Finck else
819c2c66affSColin Finck fcb->type = BTRFS_TYPE_FILE;
820c2c66affSColin Finck }
821c2c66affSColin Finck
822c2c66affSColin Finck no_data = fcb->inode_item.st_size == 0 || (fcb->type != BTRFS_TYPE_FILE && fcb->type != BTRFS_TYPE_SYMLINK);
823c2c66affSColin Finck
824318da0c1SPierre Schweitzer while (find_next_item(Vcb, &tp, &next_tp, false, Irp)) {
825c2c66affSColin Finck tp = next_tp;
826c2c66affSColin Finck
827c2c66affSColin Finck if (tp.item->key.obj_id > inode)
828c2c66affSColin Finck break;
829c2c66affSColin Finck
830c2c66affSColin Finck if ((no_data && tp.item->key.obj_type > TYPE_XATTR_ITEM) || tp.item->key.obj_type > TYPE_EXTENT_DATA)
831c2c66affSColin Finck break;
832c2c66affSColin Finck
833f381137cSPierre Schweitzer if ((always_add_hl || fcb->inode_item.st_nlink > 1) && tp.item->key.obj_type == TYPE_INODE_REF) {
834c2c66affSColin Finck ULONG len;
835c2c66affSColin Finck INODE_REF* ir;
836c2c66affSColin Finck
837c2c66affSColin Finck len = tp.item->size;
838c2c66affSColin Finck ir = (INODE_REF*)tp.item->data;
839c2c66affSColin Finck
840c2c66affSColin Finck while (len >= sizeof(INODE_REF) - 1) {
841c2c66affSColin Finck hardlink* hl;
842c2c66affSColin Finck ULONG stringlen;
843c2c66affSColin Finck
844c2c66affSColin Finck hl = ExAllocatePoolWithTag(pooltype, sizeof(hardlink), ALLOC_TAG);
845c2c66affSColin Finck if (!hl) {
846c2c66affSColin Finck ERR("out of memory\n");
847883b1f31SPierre Schweitzer reap_fcb(fcb);
848c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
849c2c66affSColin Finck }
850c2c66affSColin Finck
851c2c66affSColin Finck hl->parent = tp.item->key.offset;
852c2c66affSColin Finck hl->index = ir->index;
853c2c66affSColin Finck
854c2c66affSColin Finck hl->utf8.Length = hl->utf8.MaximumLength = ir->n;
855c2c66affSColin Finck
856c2c66affSColin Finck if (hl->utf8.Length > 0) {
857c2c66affSColin Finck hl->utf8.Buffer = ExAllocatePoolWithTag(pooltype, hl->utf8.MaximumLength, ALLOC_TAG);
858c2c66affSColin Finck RtlCopyMemory(hl->utf8.Buffer, ir->name, ir->n);
859c2c66affSColin Finck }
860c2c66affSColin Finck
861318da0c1SPierre Schweitzer Status = utf8_to_utf16(NULL, 0, &stringlen, ir->name, ir->n);
862c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
863194ea909SVictor Perevertkin ERR("utf8_to_utf16 1 returned %08lx\n", Status);
864c2c66affSColin Finck ExFreePool(hl);
865883b1f31SPierre Schweitzer reap_fcb(fcb);
866c2c66affSColin Finck return Status;
867c2c66affSColin Finck }
868c2c66affSColin Finck
869318da0c1SPierre Schweitzer hl->name.Length = hl->name.MaximumLength = (uint16_t)stringlen;
870c2c66affSColin Finck
871c2c66affSColin Finck if (stringlen == 0)
872c2c66affSColin Finck hl->name.Buffer = NULL;
873c2c66affSColin Finck else {
874c2c66affSColin Finck hl->name.Buffer = ExAllocatePoolWithTag(pooltype, hl->name.MaximumLength, ALLOC_TAG);
875c2c66affSColin Finck
876c2c66affSColin Finck if (!hl->name.Buffer) {
877c2c66affSColin Finck ERR("out of memory\n");
878c2c66affSColin Finck ExFreePool(hl);
879883b1f31SPierre Schweitzer reap_fcb(fcb);
880c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
881c2c66affSColin Finck }
882c2c66affSColin Finck
883318da0c1SPierre Schweitzer Status = utf8_to_utf16(hl->name.Buffer, stringlen, &stringlen, ir->name, ir->n);
884c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
885194ea909SVictor Perevertkin ERR("utf8_to_utf16 2 returned %08lx\n", Status);
886c2c66affSColin Finck ExFreePool(hl->name.Buffer);
887c2c66affSColin Finck ExFreePool(hl);
888883b1f31SPierre Schweitzer reap_fcb(fcb);
889c2c66affSColin Finck return Status;
890c2c66affSColin Finck }
891c2c66affSColin Finck }
892c2c66affSColin Finck
893c2c66affSColin Finck InsertTailList(&fcb->hardlinks, &hl->list_entry);
894c2c66affSColin Finck
895c2c66affSColin Finck len -= sizeof(INODE_REF) - 1 + ir->n;
896c2c66affSColin Finck ir = (INODE_REF*)&ir->name[ir->n];
897c2c66affSColin Finck }
898f381137cSPierre Schweitzer } else if ((always_add_hl || fcb->inode_item.st_nlink > 1) && tp.item->key.obj_type == TYPE_INODE_EXTREF) {
899c2c66affSColin Finck ULONG len;
900c2c66affSColin Finck INODE_EXTREF* ier;
901c2c66affSColin Finck
902c2c66affSColin Finck len = tp.item->size;
903c2c66affSColin Finck ier = (INODE_EXTREF*)tp.item->data;
904c2c66affSColin Finck
905c2c66affSColin Finck while (len >= sizeof(INODE_EXTREF) - 1) {
906c2c66affSColin Finck hardlink* hl;
907c2c66affSColin Finck ULONG stringlen;
908c2c66affSColin Finck
909c2c66affSColin Finck hl = ExAllocatePoolWithTag(pooltype, sizeof(hardlink), ALLOC_TAG);
910c2c66affSColin Finck if (!hl) {
911c2c66affSColin Finck ERR("out of memory\n");
912883b1f31SPierre Schweitzer reap_fcb(fcb);
913c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
914c2c66affSColin Finck }
915c2c66affSColin Finck
916c2c66affSColin Finck hl->parent = ier->dir;
917c2c66affSColin Finck hl->index = ier->index;
918c2c66affSColin Finck
919c2c66affSColin Finck hl->utf8.Length = hl->utf8.MaximumLength = ier->n;
920c2c66affSColin Finck
921c2c66affSColin Finck if (hl->utf8.Length > 0) {
922c2c66affSColin Finck hl->utf8.Buffer = ExAllocatePoolWithTag(pooltype, hl->utf8.MaximumLength, ALLOC_TAG);
923c2c66affSColin Finck RtlCopyMemory(hl->utf8.Buffer, ier->name, ier->n);
924c2c66affSColin Finck }
925c2c66affSColin Finck
926318da0c1SPierre Schweitzer Status = utf8_to_utf16(NULL, 0, &stringlen, ier->name, ier->n);
927c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
928194ea909SVictor Perevertkin ERR("utf8_to_utf16 1 returned %08lx\n", Status);
929c2c66affSColin Finck ExFreePool(hl);
930883b1f31SPierre Schweitzer reap_fcb(fcb);
931c2c66affSColin Finck return Status;
932c2c66affSColin Finck }
933c2c66affSColin Finck
934318da0c1SPierre Schweitzer hl->name.Length = hl->name.MaximumLength = (uint16_t)stringlen;
935c2c66affSColin Finck
936c2c66affSColin Finck if (stringlen == 0)
937c2c66affSColin Finck hl->name.Buffer = NULL;
938c2c66affSColin Finck else {
939c2c66affSColin Finck hl->name.Buffer = ExAllocatePoolWithTag(pooltype, hl->name.MaximumLength, ALLOC_TAG);
940c2c66affSColin Finck
941c2c66affSColin Finck if (!hl->name.Buffer) {
942c2c66affSColin Finck ERR("out of memory\n");
943c2c66affSColin Finck ExFreePool(hl);
944883b1f31SPierre Schweitzer reap_fcb(fcb);
945c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
946c2c66affSColin Finck }
947c2c66affSColin Finck
948318da0c1SPierre Schweitzer Status = utf8_to_utf16(hl->name.Buffer, stringlen, &stringlen, ier->name, ier->n);
949c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
950194ea909SVictor Perevertkin ERR("utf8_to_utf16 2 returned %08lx\n", Status);
951c2c66affSColin Finck ExFreePool(hl->name.Buffer);
952c2c66affSColin Finck ExFreePool(hl);
953883b1f31SPierre Schweitzer reap_fcb(fcb);
954c2c66affSColin Finck return Status;
955c2c66affSColin Finck }
956c2c66affSColin Finck }
957c2c66affSColin Finck
958c2c66affSColin Finck InsertTailList(&fcb->hardlinks, &hl->list_entry);
959c2c66affSColin Finck
960c2c66affSColin Finck len -= sizeof(INODE_EXTREF) - 1 + ier->n;
961c2c66affSColin Finck ier = (INODE_EXTREF*)&ier->name[ier->n];
962c2c66affSColin Finck }
963c2c66affSColin Finck } else if (tp.item->key.obj_type == TYPE_XATTR_ITEM) {
964c2c66affSColin Finck ULONG len;
965c2c66affSColin Finck DIR_ITEM* di;
966c2c66affSColin Finck
967eb7fbc25SPierre Schweitzer static const char xapref[] = "user.";
968c2c66affSColin Finck
969c2c66affSColin Finck if (tp.item->size < offsetof(DIR_ITEM, name[0])) {
970194ea909SVictor Perevertkin ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, offsetof(DIR_ITEM, name[0]));
971c2c66affSColin Finck continue;
972c2c66affSColin Finck }
973c2c66affSColin Finck
974c2c66affSColin Finck len = tp.item->size;
975c2c66affSColin Finck di = (DIR_ITEM*)tp.item->data;
976c2c66affSColin Finck
977c2c66affSColin Finck do {
978c2c66affSColin Finck if (len < offsetof(DIR_ITEM, name[0]) + di->m + di->n)
979c2c66affSColin Finck break;
980c2c66affSColin Finck
981eb7fbc25SPierre Schweitzer if (tp.item->key.offset == EA_REPARSE_HASH && di->n == sizeof(EA_REPARSE) - 1 && RtlCompareMemory(EA_REPARSE, di->name, di->n) == di->n) {
982c2c66affSColin Finck if (di->m > 0) {
983c2c66affSColin Finck fcb->reparse_xattr.Buffer = ExAllocatePoolWithTag(PagedPool, di->m, ALLOC_TAG);
984c2c66affSColin Finck if (!fcb->reparse_xattr.Buffer) {
985c2c66affSColin Finck ERR("out of memory\n");
986883b1f31SPierre Schweitzer reap_fcb(fcb);
987c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
988c2c66affSColin Finck }
989c2c66affSColin Finck
990c2c66affSColin Finck RtlCopyMemory(fcb->reparse_xattr.Buffer, &di->name[di->n], di->m);
991c2c66affSColin Finck } else
992c2c66affSColin Finck fcb->reparse_xattr.Buffer = NULL;
993c2c66affSColin Finck
994c2c66affSColin Finck fcb->reparse_xattr.Length = fcb->reparse_xattr.MaximumLength = di->m;
995eb7fbc25SPierre 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) {
996c2c66affSColin Finck if (di->m > 0) {
997c2c66affSColin Finck ULONG offset;
998c2c66affSColin Finck
999c2c66affSColin Finck Status = IoCheckEaBufferValidity((FILE_FULL_EA_INFORMATION*)&di->name[di->n], di->m, &offset);
1000c2c66affSColin Finck
1001c2c66affSColin Finck if (!NT_SUCCESS(Status))
1002194ea909SVictor Perevertkin WARN("IoCheckEaBufferValidity returned %08lx (error at offset %lu)\n", Status, offset);
1003c2c66affSColin Finck else {
1004c2c66affSColin Finck FILE_FULL_EA_INFORMATION* eainfo;
1005c2c66affSColin Finck
1006c2c66affSColin Finck fcb->ea_xattr.Buffer = ExAllocatePoolWithTag(PagedPool, di->m, ALLOC_TAG);
1007c2c66affSColin Finck if (!fcb->ea_xattr.Buffer) {
1008c2c66affSColin Finck ERR("out of memory\n");
1009883b1f31SPierre Schweitzer reap_fcb(fcb);
1010c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
1011c2c66affSColin Finck }
1012c2c66affSColin Finck
1013c2c66affSColin Finck RtlCopyMemory(fcb->ea_xattr.Buffer, &di->name[di->n], di->m);
1014c2c66affSColin Finck
1015c2c66affSColin Finck fcb->ea_xattr.Length = fcb->ea_xattr.MaximumLength = di->m;
1016c2c66affSColin Finck
1017c2c66affSColin Finck fcb->ealen = 4;
1018c2c66affSColin Finck
1019c2c66affSColin Finck // calculate ealen
1020c2c66affSColin Finck eainfo = (FILE_FULL_EA_INFORMATION*)&di->name[di->n];
1021c2c66affSColin Finck do {
1022c2c66affSColin Finck fcb->ealen += 5 + eainfo->EaNameLength + eainfo->EaValueLength;
1023c2c66affSColin Finck
1024c2c66affSColin Finck if (eainfo->NextEntryOffset == 0)
1025c2c66affSColin Finck break;
1026c2c66affSColin Finck
1027318da0c1SPierre Schweitzer eainfo = (FILE_FULL_EA_INFORMATION*)(((uint8_t*)eainfo) + eainfo->NextEntryOffset);
1028318da0c1SPierre Schweitzer } while (true);
1029c2c66affSColin Finck }
1030c2c66affSColin Finck }
1031eb7fbc25SPierre 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) {
1032c2c66affSColin Finck if (di->m > 0) {
1033c2c66affSColin Finck if (get_file_attributes_from_xattr(&di->name[di->n], di->m, &fcb->atts)) {
1034318da0c1SPierre Schweitzer atts_set = true;
1035c2c66affSColin Finck
1036c2c66affSColin Finck if (fcb->type == BTRFS_TYPE_DIRECTORY)
1037c2c66affSColin Finck fcb->atts |= FILE_ATTRIBUTE_DIRECTORY;
1038c2c66affSColin Finck else if (fcb->type == BTRFS_TYPE_SYMLINK)
1039c2c66affSColin Finck fcb->atts |= FILE_ATTRIBUTE_REPARSE_POINT;
1040c2c66affSColin Finck
1041c2c66affSColin Finck if (fcb->type != BTRFS_TYPE_DIRECTORY)
1042c2c66affSColin Finck fcb->atts &= ~FILE_ATTRIBUTE_DIRECTORY;
1043c2c66affSColin Finck
1044c2c66affSColin Finck if (inode == SUBVOL_ROOT_INODE) {
1045c2c66affSColin Finck if (subvol->root_item.flags & BTRFS_SUBVOL_READONLY)
1046c2c66affSColin Finck fcb->atts |= FILE_ATTRIBUTE_READONLY;
1047c2c66affSColin Finck else
1048c2c66affSColin Finck fcb->atts &= ~FILE_ATTRIBUTE_READONLY;
1049c2c66affSColin Finck }
1050c2c66affSColin Finck }
1051c2c66affSColin Finck }
1052eb7fbc25SPierre 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) {
1053c2c66affSColin Finck if (di->m > 0) {
1054c2c66affSColin Finck fcb->sd = ExAllocatePoolWithTag(PagedPool, di->m, ALLOC_TAG);
1055c2c66affSColin Finck if (!fcb->sd) {
1056c2c66affSColin Finck ERR("out of memory\n");
1057883b1f31SPierre Schweitzer reap_fcb(fcb);
1058c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
1059c2c66affSColin Finck }
1060c2c66affSColin Finck
1061c2c66affSColin Finck RtlCopyMemory(fcb->sd, &di->name[di->n], di->m);
1062c2c66affSColin Finck
1063c2c66affSColin Finck // We have to test against our copy rather than the source, as RtlValidRelativeSecurityDescriptor
1064c2c66affSColin Finck // will fail if the ACLs aren't 32-bit aligned.
1065c2c66affSColin Finck if (!RtlValidRelativeSecurityDescriptor(fcb->sd, di->m, 0))
1066c2c66affSColin Finck ExFreePool(fcb->sd);
1067c2c66affSColin Finck else
1068318da0c1SPierre Schweitzer sd_set = true;
1069c2c66affSColin Finck }
1070eb7fbc25SPierre 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) {
1071c2c66affSColin Finck if (di->m > 0) {
1072eb7fbc25SPierre Schweitzer static const char lzo[] = "lzo";
1073eb7fbc25SPierre Schweitzer static const char zlib[] = "zlib";
1074eb7fbc25SPierre Schweitzer static const char zstd[] = "zstd";
1075c2c66affSColin Finck
1076eb7fbc25SPierre Schweitzer if (di->m == sizeof(lzo) - 1 && RtlCompareMemory(&di->name[di->n], lzo, di->m) == di->m)
1077c2c66affSColin Finck fcb->prop_compression = PropCompression_LZO;
1078eb7fbc25SPierre Schweitzer else if (di->m == sizeof(zlib) - 1 && RtlCompareMemory(&di->name[di->n], zlib, di->m) == di->m)
1079c2c66affSColin Finck fcb->prop_compression = PropCompression_Zlib;
1080eb7fbc25SPierre Schweitzer else if (di->m == sizeof(zstd) - 1 && RtlCompareMemory(&di->name[di->n], zstd, di->m) == di->m)
1081eb7fbc25SPierre Schweitzer fcb->prop_compression = PropCompression_ZSTD;
1082c2c66affSColin Finck else
1083c2c66affSColin Finck fcb->prop_compression = PropCompression_None;
1084c2c66affSColin Finck }
1085f381137cSPierre Schweitzer } else if (tp.item->key.offset == EA_CASE_SENSITIVE_HASH && di->n == sizeof(EA_CASE_SENSITIVE) - 1 && RtlCompareMemory(EA_CASE_SENSITIVE, di->name, di->n) == di->n) {
1086f381137cSPierre Schweitzer if (di->m > 0) {
1087f381137cSPierre Schweitzer fcb->case_sensitive = di->m == 1 && di->name[di->n] == '1';
1088318da0c1SPierre Schweitzer fcb->case_sensitive_set = true;
1089f381137cSPierre Schweitzer }
1090eb7fbc25SPierre Schweitzer } else if (di->n > sizeof(xapref) - 1 && RtlCompareMemory(xapref, di->name, sizeof(xapref) - 1) == sizeof(xapref) - 1) {
1091c2c66affSColin Finck dir_child* dc;
1092c2c66affSColin Finck ULONG utf16len;
1093c2c66affSColin Finck
1094318da0c1SPierre Schweitzer Status = utf8_to_utf16(NULL, 0, &utf16len, &di->name[sizeof(xapref) - 1], di->n + 1 - sizeof(xapref));
1095c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
1096194ea909SVictor Perevertkin ERR("utf8_to_utf16 1 returned %08lx\n", Status);
1097883b1f31SPierre Schweitzer reap_fcb(fcb);
1098c2c66affSColin Finck return Status;
1099c2c66affSColin Finck }
1100c2c66affSColin Finck
1101c2c66affSColin Finck dc = ExAllocatePoolWithTag(PagedPool, sizeof(dir_child), ALLOC_TAG);
1102c2c66affSColin Finck if (!dc) {
1103c2c66affSColin Finck ERR("out of memory\n");
1104883b1f31SPierre Schweitzer reap_fcb(fcb);
1105c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
1106c2c66affSColin Finck }
1107c2c66affSColin Finck
1108c2c66affSColin Finck RtlZeroMemory(dc, sizeof(dir_child));
1109c2c66affSColin Finck
1110eb7fbc25SPierre Schweitzer dc->utf8.MaximumLength = dc->utf8.Length = di->n + 1 - sizeof(xapref);
1111c2c66affSColin Finck dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, dc->utf8.MaximumLength, ALLOC_TAG);
1112c2c66affSColin Finck if (!dc->utf8.Buffer) {
1113c2c66affSColin Finck ERR("out of memory\n");
1114c2c66affSColin Finck ExFreePool(dc);
1115883b1f31SPierre Schweitzer reap_fcb(fcb);
1116c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
1117c2c66affSColin Finck }
1118c2c66affSColin Finck
1119eb7fbc25SPierre Schweitzer RtlCopyMemory(dc->utf8.Buffer, &di->name[sizeof(xapref) - 1], dc->utf8.Length);
1120c2c66affSColin Finck
1121318da0c1SPierre Schweitzer dc->name.MaximumLength = dc->name.Length = (uint16_t)utf16len;
1122c2c66affSColin Finck dc->name.Buffer = ExAllocatePoolWithTag(PagedPool, dc->name.MaximumLength, ALLOC_TAG);
1123c2c66affSColin Finck if (!dc->name.Buffer) {
1124c2c66affSColin Finck ERR("out of memory\n");
1125c2c66affSColin Finck ExFreePool(dc->utf8.Buffer);
1126c2c66affSColin Finck ExFreePool(dc);
1127883b1f31SPierre Schweitzer reap_fcb(fcb);
1128c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
1129c2c66affSColin Finck }
1130c2c66affSColin Finck
1131318da0c1SPierre Schweitzer Status = utf8_to_utf16(dc->name.Buffer, utf16len, &utf16len, dc->utf8.Buffer, dc->utf8.Length);
1132c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
1133194ea909SVictor Perevertkin ERR("utf8_to_utf16 2 returned %08lx\n", Status);
1134c2c66affSColin Finck ExFreePool(dc->utf8.Buffer);
1135c2c66affSColin Finck ExFreePool(dc->name.Buffer);
1136c2c66affSColin Finck ExFreePool(dc);
1137883b1f31SPierre Schweitzer reap_fcb(fcb);
1138c2c66affSColin Finck return Status;
1139c2c66affSColin Finck }
1140c2c66affSColin Finck
1141318da0c1SPierre Schweitzer Status = RtlUpcaseUnicodeString(&dc->name_uc, &dc->name, true);
1142c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
1143194ea909SVictor Perevertkin ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
1144c2c66affSColin Finck ExFreePool(dc->utf8.Buffer);
1145c2c66affSColin Finck ExFreePool(dc->name.Buffer);
1146c2c66affSColin Finck ExFreePool(dc);
1147883b1f31SPierre Schweitzer reap_fcb(fcb);
1148c2c66affSColin Finck return Status;
1149c2c66affSColin Finck }
1150c2c66affSColin Finck
1151c2c66affSColin Finck dc->size = di->m;
1152c2c66affSColin Finck
1153c2c66affSColin Finck InsertTailList(&fcb->dir_children_index, &dc->list_entry_index);
1154c2c66affSColin Finck } else {
1155c2c66affSColin Finck xattr* xa;
1156c2c66affSColin Finck
1157c2c66affSColin Finck xa = ExAllocatePoolWithTag(PagedPool, offsetof(xattr, data[0]) + di->m + di->n, ALLOC_TAG);
1158c2c66affSColin Finck if (!xa) {
1159c2c66affSColin Finck ERR("out of memory\n");
1160883b1f31SPierre Schweitzer reap_fcb(fcb);
1161c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
1162c2c66affSColin Finck }
1163c2c66affSColin Finck
1164c2c66affSColin Finck xa->namelen = di->n;
1165c2c66affSColin Finck xa->valuelen = di->m;
1166318da0c1SPierre Schweitzer xa->dirty = false;
1167c2c66affSColin Finck RtlCopyMemory(xa->data, di->name, di->m + di->n);
1168c2c66affSColin Finck
1169c2c66affSColin Finck InsertTailList(&fcb->xattrs, &xa->list_entry);
1170c2c66affSColin Finck }
1171c2c66affSColin Finck
1172c2c66affSColin Finck len -= (ULONG)offsetof(DIR_ITEM, name[0]) + di->m + di->n;
1173c2c66affSColin Finck
1174c2c66affSColin Finck if (len < offsetof(DIR_ITEM, name[0]))
1175c2c66affSColin Finck break;
1176c2c66affSColin Finck
1177c2c66affSColin Finck di = (DIR_ITEM*)&di->name[di->m + di->n];
1178318da0c1SPierre Schweitzer } while (true);
1179c2c66affSColin Finck } else if (tp.item->key.obj_type == TYPE_EXTENT_DATA) {
1180c2c66affSColin Finck extent* ext;
1181318da0c1SPierre Schweitzer bool unique = false;
1182c2c66affSColin Finck
1183c2c66affSColin Finck ed = (EXTENT_DATA*)tp.item->data;
1184c2c66affSColin Finck
1185c2c66affSColin Finck if (tp.item->size < sizeof(EXTENT_DATA)) {
1186194ea909SVictor Perevertkin ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset,
1187c2c66affSColin Finck tp.item->size, sizeof(EXTENT_DATA));
1188c2c66affSColin Finck
1189883b1f31SPierre Schweitzer reap_fcb(fcb);
1190c2c66affSColin Finck return STATUS_INTERNAL_ERROR;
1191c2c66affSColin Finck }
1192c2c66affSColin Finck
1193c2c66affSColin Finck if (ed->type == EXTENT_TYPE_REGULAR || ed->type == EXTENT_TYPE_PREALLOC) {
1194c2c66affSColin Finck EXTENT_DATA2* ed2 = (EXTENT_DATA2*)&ed->data[0];
1195c2c66affSColin Finck
1196c2c66affSColin Finck if (tp.item->size < sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2)) {
1197194ea909SVictor Perevertkin ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset,
1198c2c66affSColin Finck tp.item->size, sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2));
1199c2c66affSColin Finck
1200883b1f31SPierre Schweitzer reap_fcb(fcb);
1201c2c66affSColin Finck return STATUS_INTERNAL_ERROR;
1202c2c66affSColin Finck }
1203c2c66affSColin Finck
1204c2c66affSColin Finck if (ed2->address == 0 || ed2->size == 0) // sparse
1205c2c66affSColin Finck continue;
1206c2c66affSColin Finck
1207c2c66affSColin Finck if (ed2->size != 0 && is_tree_unique(Vcb, tp.tree, Irp))
1208c2c66affSColin Finck unique = is_extent_unique(Vcb, ed2->address, ed2->size, Irp);
1209c2c66affSColin Finck }
1210c2c66affSColin Finck
1211c2c66affSColin Finck ext = ExAllocatePoolWithTag(pooltype, offsetof(extent, extent_data) + tp.item->size, ALLOC_TAG);
1212c2c66affSColin Finck if (!ext) {
1213c2c66affSColin Finck ERR("out of memory\n");
1214883b1f31SPierre Schweitzer reap_fcb(fcb);
1215c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
1216c2c66affSColin Finck }
1217c2c66affSColin Finck
1218c2c66affSColin Finck ext->offset = tp.item->key.offset;
1219c2c66affSColin Finck RtlCopyMemory(&ext->extent_data, tp.item->data, tp.item->size);
1220c2c66affSColin Finck ext->datalen = tp.item->size;
1221c2c66affSColin Finck ext->unique = unique;
1222318da0c1SPierre Schweitzer ext->ignore = false;
1223318da0c1SPierre Schweitzer ext->inserted = false;
1224c2c66affSColin Finck ext->csum = NULL;
1225c2c66affSColin Finck
1226c2c66affSColin Finck InsertTailList(&fcb->extents, &ext->list_entry);
1227c2c66affSColin Finck }
1228c2c66affSColin Finck }
1229c2c66affSColin Finck
1230c2c66affSColin Finck if (fcb->type == BTRFS_TYPE_DIRECTORY) {
1231318da0c1SPierre Schweitzer Status = load_dir_children(Vcb, fcb, false, Irp);
1232c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
1233194ea909SVictor Perevertkin ERR("load_dir_children returned %08lx\n", Status);
1234883b1f31SPierre Schweitzer reap_fcb(fcb);
1235c2c66affSColin Finck return Status;
1236c2c66affSColin Finck }
1237c2c66affSColin Finck }
1238c2c66affSColin Finck
1239c2c66affSColin Finck if (no_data) {
1240c2c66affSColin Finck fcb->Header.AllocationSize.QuadPart = 0;
1241c2c66affSColin Finck fcb->Header.FileSize.QuadPart = 0;
1242c2c66affSColin Finck fcb->Header.ValidDataLength.QuadPart = 0;
1243c2c66affSColin Finck } else {
1244c2c66affSColin Finck if (ed && ed->type == EXTENT_TYPE_INLINE)
1245c2c66affSColin Finck fcb->Header.AllocationSize.QuadPart = fcb->inode_item.st_size;
1246c2c66affSColin Finck else
1247c2c66affSColin Finck fcb->Header.AllocationSize.QuadPart = sector_align(fcb->inode_item.st_size, fcb->Vcb->superblock.sector_size);
1248c2c66affSColin Finck
1249c2c66affSColin Finck fcb->Header.FileSize.QuadPart = fcb->inode_item.st_size;
1250c2c66affSColin Finck fcb->Header.ValidDataLength.QuadPart = fcb->inode_item.st_size;
1251c2c66affSColin Finck }
1252c2c66affSColin Finck
1253c2c66affSColin Finck if (!atts_set)
1254318da0c1SPierre Schweitzer fcb->atts = get_file_attributes(Vcb, fcb->subvol, fcb->inode, fcb->type, utf8 && utf8->Buffer[0] == '.', true, Irp);
1255c2c66affSColin Finck
1256c2c66affSColin Finck if (!sd_set)
1257318da0c1SPierre Schweitzer fcb_get_sd(fcb, parent, false, Irp);
1258c2c66affSColin Finck
1259883b1f31SPierre Schweitzer acquire_fcb_lock_exclusive(Vcb);
1260883b1f31SPierre Schweitzer
1261318da0c1SPierre Schweitzer if (lastle && subvol->fcbs_version == fcbs_version) {
1262883b1f31SPierre Schweitzer InsertHeadList(lastle, &fcb->list_entry);
1263318da0c1SPierre Schweitzer
1264318da0c1SPierre Schweitzer if (!subvol->fcbs_ptrs[hash >> 24] || CONTAINING_RECORD(subvol->fcbs_ptrs[hash >> 24], struct _fcb, list_entry)->hash > hash)
1265318da0c1SPierre Schweitzer subvol->fcbs_ptrs[hash >> 24] = &fcb->list_entry;
1266318da0c1SPierre Schweitzer } else {
1267318da0c1SPierre Schweitzer lastle = NULL;
1268318da0c1SPierre Schweitzer
1269883b1f31SPierre Schweitzer if (subvol->fcbs_ptrs[hash >> 24]) {
1270883b1f31SPierre Schweitzer LIST_ENTRY* le = subvol->fcbs_ptrs[hash >> 24];
1271883b1f31SPierre Schweitzer
1272883b1f31SPierre Schweitzer while (le != &subvol->fcbs) {
1273883b1f31SPierre Schweitzer struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, list_entry);
1274883b1f31SPierre Schweitzer
1275883b1f31SPierre Schweitzer if (fcb2->inode == inode) {
1276883b1f31SPierre Schweitzer if (!fcb2->ads) {
1277883b1f31SPierre Schweitzer if (fcb2->deleted)
1278883b1f31SPierre Schweitzer deleted_fcb = fcb2;
1279883b1f31SPierre Schweitzer else {
1280883b1f31SPierre Schweitzer #ifdef DEBUG_FCB_REFCOUNTS
1281883b1f31SPierre Schweitzer LONG rc = InterlockedIncrement(&fcb2->refcount);
1282883b1f31SPierre Schweitzer
1283318da0c1SPierre Schweitzer WARN("fcb %p: refcount now %i (subvol %I64x, inode %I64x)\n", fcb2, rc, fcb2->subvol->id, fcb2->inode);
1284883b1f31SPierre Schweitzer #else
1285883b1f31SPierre Schweitzer InterlockedIncrement(&fcb2->refcount);
1286883b1f31SPierre Schweitzer #endif
1287883b1f31SPierre Schweitzer
1288883b1f31SPierre Schweitzer *pfcb = fcb2;
1289883b1f31SPierre Schweitzer reap_fcb(fcb);
1290f381137cSPierre Schweitzer release_fcb_lock(Vcb);
1291883b1f31SPierre Schweitzer return STATUS_SUCCESS;
1292883b1f31SPierre Schweitzer }
1293883b1f31SPierre Schweitzer }
1294883b1f31SPierre Schweitzer } else if (fcb2->hash > hash) {
1295883b1f31SPierre Schweitzer if (deleted_fcb) {
1296883b1f31SPierre Schweitzer InterlockedIncrement(&deleted_fcb->refcount);
1297883b1f31SPierre Schweitzer *pfcb = deleted_fcb;
1298883b1f31SPierre Schweitzer reap_fcb(fcb);
1299f381137cSPierre Schweitzer release_fcb_lock(Vcb);
1300883b1f31SPierre Schweitzer return STATUS_SUCCESS;
1301883b1f31SPierre Schweitzer }
1302883b1f31SPierre Schweitzer
1303883b1f31SPierre Schweitzer lastle = le->Blink;
1304883b1f31SPierre Schweitzer break;
1305883b1f31SPierre Schweitzer }
1306883b1f31SPierre Schweitzer
1307883b1f31SPierre Schweitzer le = le->Flink;
1308883b1f31SPierre Schweitzer }
1309883b1f31SPierre Schweitzer }
1310883b1f31SPierre Schweitzer
1311c2c66affSColin Finck if (fcb->type == BTRFS_TYPE_DIRECTORY && fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT && fcb->reparse_xattr.Length == 0) {
1312c2c66affSColin Finck fcb->atts &= ~FILE_ATTRIBUTE_REPARSE_POINT;
1313c2c66affSColin Finck
1314c2c66affSColin Finck if (!Vcb->readonly && !is_subvol_readonly(subvol, Irp)) {
1315318da0c1SPierre Schweitzer fcb->atts_changed = true;
1316c2c66affSColin Finck mark_fcb_dirty(fcb);
1317c2c66affSColin Finck }
1318c2c66affSColin Finck }
1319c2c66affSColin Finck
1320883b1f31SPierre Schweitzer if (!lastle) {
1321318da0c1SPierre Schweitzer uint8_t c = hash >> 24;
1322883b1f31SPierre Schweitzer
1323883b1f31SPierre Schweitzer if (c != 0xff) {
1324318da0c1SPierre Schweitzer uint8_t d = c + 1;
1325883b1f31SPierre Schweitzer
1326883b1f31SPierre Schweitzer do {
1327883b1f31SPierre Schweitzer if (subvol->fcbs_ptrs[d]) {
1328883b1f31SPierre Schweitzer lastle = subvol->fcbs_ptrs[d]->Blink;
1329883b1f31SPierre Schweitzer break;
1330883b1f31SPierre Schweitzer }
1331883b1f31SPierre Schweitzer
1332883b1f31SPierre Schweitzer d++;
1333883b1f31SPierre Schweitzer } while (d != 0);
1334883b1f31SPierre Schweitzer }
1335883b1f31SPierre Schweitzer }
1336883b1f31SPierre Schweitzer
1337883b1f31SPierre Schweitzer if (lastle) {
1338c2c66affSColin Finck InsertHeadList(lastle, &fcb->list_entry);
1339883b1f31SPierre Schweitzer
1340883b1f31SPierre Schweitzer if (lastle == &subvol->fcbs || (CONTAINING_RECORD(lastle, struct _fcb, list_entry)->hash >> 24) != (hash >> 24))
1341883b1f31SPierre Schweitzer subvol->fcbs_ptrs[hash >> 24] = &fcb->list_entry;
1342883b1f31SPierre Schweitzer } else {
1343c2c66affSColin Finck InsertTailList(&subvol->fcbs, &fcb->list_entry);
1344c2c66affSColin Finck
1345883b1f31SPierre Schweitzer if (fcb->list_entry.Blink == &subvol->fcbs || (CONTAINING_RECORD(fcb->list_entry.Blink, struct _fcb, list_entry)->hash >> 24) != (hash >> 24))
1346883b1f31SPierre Schweitzer subvol->fcbs_ptrs[hash >> 24] = &fcb->list_entry;
1347883b1f31SPierre Schweitzer }
1348883b1f31SPierre Schweitzer }
1349883b1f31SPierre Schweitzer
1350194ea909SVictor Perevertkin if (fcb->inode == SUBVOL_ROOT_INODE && fcb->subvol->id == BTRFS_ROOT_FSTREE && fcb->subvol != Vcb->root_fileref->fcb->subvol)
135162e630deSPierre Schweitzer fcb->atts |= FILE_ATTRIBUTE_HIDDEN;
135262e630deSPierre Schweitzer
1353883b1f31SPierre Schweitzer subvol->fcbs_version++;
1354883b1f31SPierre Schweitzer
1355c2c66affSColin Finck InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
1356c2c66affSColin Finck
1357883b1f31SPierre Schweitzer release_fcb_lock(Vcb);
1358883b1f31SPierre Schweitzer
1359c2c66affSColin Finck fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
1360c2c66affSColin Finck
1361c2c66affSColin Finck *pfcb = fcb;
1362883b1f31SPierre Schweitzer
1363c2c66affSColin Finck return STATUS_SUCCESS;
1364c2c66affSColin Finck }
1365c2c66affSColin Finck
1366c2c66affSColin Finck static NTSTATUS open_fcb_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension* Vcb,
1367c2c66affSColin Finck dir_child* dc, fcb* parent, fcb** pfcb, PIRP Irp) {
1368c2c66affSColin Finck fcb* fcb;
1369318da0c1SPierre Schweitzer uint8_t* xattrdata;
1370318da0c1SPierre Schweitzer uint16_t xattrlen, overhead;
1371c2c66affSColin Finck NTSTATUS Status;
1372c2c66affSColin Finck KEY searchkey;
1373c2c66affSColin Finck traverse_ptr tp;
1374eb7fbc25SPierre Schweitzer static const char xapref[] = "user.";
1375c2c66affSColin Finck ANSI_STRING xattr;
1376318da0c1SPierre Schweitzer uint32_t crc32;
1377c2c66affSColin Finck
1378eb7fbc25SPierre Schweitzer xattr.Length = sizeof(xapref) - 1 + dc->utf8.Length;
1379c2c66affSColin Finck xattr.MaximumLength = xattr.Length + 1;
1380c2c66affSColin Finck xattr.Buffer = ExAllocatePoolWithTag(PagedPool, xattr.MaximumLength, ALLOC_TAG);
1381c2c66affSColin Finck if (!xattr.Buffer) {
1382c2c66affSColin Finck ERR("out of memory\n");
1383c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
1384c2c66affSColin Finck }
1385c2c66affSColin Finck
1386eb7fbc25SPierre Schweitzer RtlCopyMemory(xattr.Buffer, xapref, sizeof(xapref) - 1);
1387eb7fbc25SPierre Schweitzer RtlCopyMemory(&xattr.Buffer[sizeof(xapref) - 1], dc->utf8.Buffer, dc->utf8.Length);
1388c2c66affSColin Finck xattr.Buffer[xattr.Length] = 0;
1389c2c66affSColin Finck
1390c2c66affSColin Finck fcb = create_fcb(Vcb, PagedPool);
1391c2c66affSColin Finck if (!fcb) {
1392c2c66affSColin Finck ERR("out of memory\n");
1393c2c66affSColin Finck ExFreePool(xattr.Buffer);
1394c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
1395c2c66affSColin Finck }
1396c2c66affSColin Finck
1397c2c66affSColin Finck fcb->Vcb = Vcb;
1398c2c66affSColin Finck
1399318da0c1SPierre Schweitzer crc32 = calc_crc32c(0xfffffffe, (uint8_t*)xattr.Buffer, xattr.Length);
1400c2c66affSColin Finck
1401c2c66affSColin Finck if (!get_xattr(Vcb, parent->subvol, parent->inode, xattr.Buffer, crc32, &xattrdata, &xattrlen, Irp)) {
1402c2c66affSColin Finck ERR("get_xattr failed\n");
1403883b1f31SPierre Schweitzer reap_fcb(fcb);
1404c2c66affSColin Finck ExFreePool(xattr.Buffer);
1405c2c66affSColin Finck return STATUS_INTERNAL_ERROR;
1406c2c66affSColin Finck }
1407c2c66affSColin Finck
1408c2c66affSColin Finck fcb->subvol = parent->subvol;
1409c2c66affSColin Finck fcb->inode = parent->inode;
1410c2c66affSColin Finck fcb->type = parent->type;
1411318da0c1SPierre Schweitzer fcb->ads = true;
1412c2c66affSColin Finck fcb->adshash = crc32;
1413c2c66affSColin Finck fcb->adsxattr = xattr;
1414c2c66affSColin Finck
1415c2c66affSColin Finck // find XATTR_ITEM overhead and hence calculate maximum length
1416c2c66affSColin Finck
1417c2c66affSColin Finck searchkey.obj_id = parent->inode;
1418c2c66affSColin Finck searchkey.obj_type = TYPE_XATTR_ITEM;
1419c2c66affSColin Finck searchkey.offset = crc32;
1420c2c66affSColin Finck
1421318da0c1SPierre Schweitzer Status = find_item(Vcb, parent->subvol, &tp, &searchkey, false, Irp);
1422c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
1423194ea909SVictor Perevertkin ERR("find_item returned %08lx\n", Status);
1424883b1f31SPierre Schweitzer reap_fcb(fcb);
1425c2c66affSColin Finck return Status;
1426c2c66affSColin Finck }
1427c2c66affSColin Finck
1428c2c66affSColin Finck if (keycmp(tp.item->key, searchkey)) {
1429c2c66affSColin Finck ERR("error - could not find key for xattr\n");
1430883b1f31SPierre Schweitzer reap_fcb(fcb);
1431c2c66affSColin Finck return STATUS_INTERNAL_ERROR;
1432c2c66affSColin Finck }
1433c2c66affSColin Finck
1434c2c66affSColin Finck if (tp.item->size < xattrlen) {
1435318da0c1SPierre Schweitzer ERR("(%I64x,%x,%I64x) 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);
1436883b1f31SPierre Schweitzer reap_fcb(fcb);
1437c2c66affSColin Finck return STATUS_INTERNAL_ERROR;
1438c2c66affSColin Finck }
1439c2c66affSColin Finck
1440c2c66affSColin Finck overhead = tp.item->size - xattrlen;
1441c2c66affSColin Finck
1442c2c66affSColin Finck fcb->adsmaxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - overhead;
1443c2c66affSColin Finck
1444c2c66affSColin Finck fcb->adsdata.Buffer = (char*)xattrdata;
1445c2c66affSColin Finck fcb->adsdata.Length = fcb->adsdata.MaximumLength = xattrlen;
1446c2c66affSColin Finck
1447c2c66affSColin Finck fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
1448c2c66affSColin Finck fcb->Header.AllocationSize.QuadPart = xattrlen;
1449c2c66affSColin Finck fcb->Header.FileSize.QuadPart = xattrlen;
1450c2c66affSColin Finck fcb->Header.ValidDataLength.QuadPart = xattrlen;
1451c2c66affSColin Finck
1452c2c66affSColin Finck TRACE("stream found: size = %x, hash = %08x\n", xattrlen, fcb->adshash);
1453c2c66affSColin Finck
1454c2c66affSColin Finck *pfcb = fcb;
1455c2c66affSColin Finck
1456c2c66affSColin Finck return STATUS_SUCCESS;
1457c2c66affSColin Finck }
1458c2c66affSColin Finck
1459c2c66affSColin Finck NTSTATUS open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb,
1460318da0c1SPierre Schweitzer _In_ file_ref* sf, _In_ PUNICODE_STRING name, _In_ bool case_sensitive, _In_ bool lastpart, _In_ bool streampart,
1461c2c66affSColin Finck _In_ POOL_TYPE pooltype, _Out_ file_ref** psf2, _In_opt_ PIRP Irp) {
1462c2c66affSColin Finck NTSTATUS Status;
1463c2c66affSColin Finck file_ref* sf2;
1464c2c66affSColin Finck
1465c2c66affSColin Finck if (sf->fcb == Vcb->dummy_fcb)
1466c2c66affSColin Finck return STATUS_OBJECT_NAME_NOT_FOUND;
1467c2c66affSColin Finck
1468c2c66affSColin Finck if (streampart) {
1469318da0c1SPierre Schweitzer bool locked = false;
1470c2c66affSColin Finck LIST_ENTRY* le;
1471c2c66affSColin Finck UNICODE_STRING name_uc;
1472c2c66affSColin Finck dir_child* dc = NULL;
1473c2c66affSColin Finck fcb* fcb;
1474883b1f31SPierre Schweitzer struct _fcb* duff_fcb = NULL;
1475883b1f31SPierre Schweitzer file_ref* duff_fr = NULL;
1476c2c66affSColin Finck
1477c2c66affSColin Finck if (!case_sensitive) {
1478318da0c1SPierre Schweitzer Status = RtlUpcaseUnicodeString(&name_uc, name, true);
1479c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
1480194ea909SVictor Perevertkin ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
1481c2c66affSColin Finck return Status;
1482c2c66affSColin Finck }
1483c2c66affSColin Finck }
1484c2c66affSColin Finck
1485c2c66affSColin Finck if (!ExIsResourceAcquiredSharedLite(&sf->fcb->nonpaged->dir_children_lock)) {
1486318da0c1SPierre Schweitzer ExAcquireResourceSharedLite(&sf->fcb->nonpaged->dir_children_lock, true);
1487318da0c1SPierre Schweitzer locked = true;
1488c2c66affSColin Finck }
1489c2c66affSColin Finck
1490c2c66affSColin Finck le = sf->fcb->dir_children_index.Flink;
1491c2c66affSColin Finck while (le != &sf->fcb->dir_children_index) {
1492c2c66affSColin Finck dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_index);
1493c2c66affSColin Finck
1494c2c66affSColin Finck if (dc2->index == 0) {
1495c2c66affSColin Finck if ((case_sensitive && dc2->name.Length == name->Length && RtlCompareMemory(dc2->name.Buffer, name->Buffer, dc2->name.Length) == dc2->name.Length) ||
1496c2c66affSColin 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)
1497c2c66affSColin Finck ) {
1498c2c66affSColin Finck dc = dc2;
1499c2c66affSColin Finck break;
1500c2c66affSColin Finck }
1501c2c66affSColin Finck } else
1502c2c66affSColin Finck break;
1503c2c66affSColin Finck
1504c2c66affSColin Finck le = le->Flink;
1505c2c66affSColin Finck }
1506c2c66affSColin Finck
1507883b1f31SPierre Schweitzer if (!dc) {
1508c2c66affSColin Finck if (locked)
1509c2c66affSColin Finck ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock);
1510c2c66affSColin Finck
1511883b1f31SPierre Schweitzer if (!case_sensitive)
1512883b1f31SPierre Schweitzer ExFreePool(name_uc.Buffer);
1513883b1f31SPierre Schweitzer
1514c2c66affSColin Finck return STATUS_OBJECT_NAME_NOT_FOUND;
1515883b1f31SPierre Schweitzer }
1516c2c66affSColin Finck
1517c2c66affSColin Finck if (dc->fileref) {
1518883b1f31SPierre Schweitzer if (locked)
1519883b1f31SPierre Schweitzer ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock);
1520883b1f31SPierre Schweitzer
1521883b1f31SPierre Schweitzer if (!case_sensitive)
1522883b1f31SPierre Schweitzer ExFreePool(name_uc.Buffer);
1523883b1f31SPierre Schweitzer
1524c2c66affSColin Finck increase_fileref_refcount(dc->fileref);
1525c2c66affSColin Finck *psf2 = dc->fileref;
1526c2c66affSColin Finck return STATUS_SUCCESS;
1527c2c66affSColin Finck }
1528c2c66affSColin Finck
1529883b1f31SPierre Schweitzer if (locked)
1530883b1f31SPierre Schweitzer ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock);
1531883b1f31SPierre Schweitzer
1532883b1f31SPierre Schweitzer if (!case_sensitive)
1533883b1f31SPierre Schweitzer ExFreePool(name_uc.Buffer);
1534883b1f31SPierre Schweitzer
1535c2c66affSColin Finck Status = open_fcb_stream(Vcb, dc, sf->fcb, &fcb, Irp);
1536c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
1537194ea909SVictor Perevertkin ERR("open_fcb_stream returned %08lx\n", Status);
1538c2c66affSColin Finck return Status;
1539c2c66affSColin Finck }
1540c2c66affSColin Finck
1541883b1f31SPierre Schweitzer fcb->hash = sf->fcb->hash;
1542883b1f31SPierre Schweitzer
1543883b1f31SPierre Schweitzer acquire_fcb_lock_exclusive(Vcb);
1544883b1f31SPierre Schweitzer
1545883b1f31SPierre Schweitzer if (sf->fcb->subvol->fcbs_ptrs[fcb->hash >> 24]) {
1546318da0c1SPierre Schweitzer le = sf->fcb->subvol->fcbs_ptrs[fcb->hash >> 24];
1547883b1f31SPierre Schweitzer
1548883b1f31SPierre Schweitzer while (le != &sf->fcb->subvol->fcbs) {
1549883b1f31SPierre Schweitzer struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, list_entry);
1550883b1f31SPierre Schweitzer
1551883b1f31SPierre Schweitzer if (fcb2->inode == fcb->inode) {
1552883b1f31SPierre Schweitzer if (fcb2->ads && fcb2->adshash == fcb->adshash) { // FIXME - handle hash collisions
1553883b1f31SPierre Schweitzer duff_fcb = fcb;
1554883b1f31SPierre Schweitzer fcb = fcb2;
1555883b1f31SPierre Schweitzer break;
1556883b1f31SPierre Schweitzer }
1557883b1f31SPierre Schweitzer } else if (fcb2->hash > fcb->hash)
1558883b1f31SPierre Schweitzer break;
1559883b1f31SPierre Schweitzer
1560883b1f31SPierre Schweitzer le = le->Flink;
1561883b1f31SPierre Schweitzer }
1562883b1f31SPierre Schweitzer }
1563883b1f31SPierre Schweitzer
1564883b1f31SPierre Schweitzer if (!duff_fcb) {
1565883b1f31SPierre Schweitzer InsertHeadList(&sf->fcb->list_entry, &fcb->list_entry);
1566883b1f31SPierre Schweitzer InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
1567883b1f31SPierre Schweitzer fcb->subvol->fcbs_version++;
1568883b1f31SPierre Schweitzer }
1569883b1f31SPierre Schweitzer
1570883b1f31SPierre Schweitzer release_fcb_lock(Vcb);
1571883b1f31SPierre Schweitzer
1572883b1f31SPierre Schweitzer if (duff_fcb) {
1573883b1f31SPierre Schweitzer reap_fcb(duff_fcb);
1574883b1f31SPierre Schweitzer InterlockedIncrement(&fcb->refcount);
1575883b1f31SPierre Schweitzer }
1576883b1f31SPierre Schweitzer
1577c2c66affSColin Finck sf2 = create_fileref(Vcb);
1578c2c66affSColin Finck if (!sf2) {
1579c2c66affSColin Finck ERR("out of memory\n");
1580883b1f31SPierre Schweitzer free_fcb(fcb);
1581c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
1582c2c66affSColin Finck }
1583c2c66affSColin Finck
1584318da0c1SPierre Schweitzer ExAcquireResourceExclusiveLite(&sf->fcb->nonpaged->dir_children_lock, true);
1585883b1f31SPierre Schweitzer
1586883b1f31SPierre Schweitzer if (dc->fileref) {
1587883b1f31SPierre Schweitzer duff_fr = sf2;
1588883b1f31SPierre Schweitzer sf2 = dc->fileref;
1589883b1f31SPierre Schweitzer increase_fileref_refcount(sf2);
1590883b1f31SPierre Schweitzer } else {
1591c2c66affSColin Finck sf2->fcb = fcb;
1592c2c66affSColin Finck sf2->parent = (struct _file_ref*)sf;
1593c2c66affSColin Finck sf2->dc = dc;
1594c2c66affSColin Finck dc->fileref = sf2;
1595c2c66affSColin Finck increase_fileref_refcount(sf);
1596883b1f31SPierre Schweitzer InsertTailList(&sf->children, &sf2->list_entry);
1597883b1f31SPierre Schweitzer }
1598883b1f31SPierre Schweitzer
1599883b1f31SPierre Schweitzer ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock);
1600883b1f31SPierre Schweitzer
1601883b1f31SPierre Schweitzer if (duff_fr)
1602c982533eSVincent Franchomme ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, duff_fr);
1603c2c66affSColin Finck } else {
1604c2c66affSColin Finck root* subvol;
1605318da0c1SPierre Schweitzer uint64_t inode;
1606c2c66affSColin Finck dir_child* dc;
1607c2c66affSColin Finck
1608c2c66affSColin Finck Status = find_file_in_dir(name, sf->fcb, &subvol, &inode, &dc, case_sensitive);
1609c2c66affSColin Finck if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
1610194ea909SVictor Perevertkin TRACE("could not find %.*S\n", (int)(name->Length / sizeof(WCHAR)), name->Buffer);
1611c2c66affSColin Finck
1612c2c66affSColin Finck return lastpart ? STATUS_OBJECT_NAME_NOT_FOUND : STATUS_OBJECT_PATH_NOT_FOUND;
161398654b54SVincent Franchomme } else if (Status == STATUS_OBJECT_NAME_INVALID) {
161498654b54SVincent Franchomme TRACE("invalid filename: %.*S\n", (int)(name->Length / sizeof(WCHAR)), name->Buffer);
161598654b54SVincent Franchomme return Status;
1616c2c66affSColin Finck } else if (!NT_SUCCESS(Status)) {
1617194ea909SVictor Perevertkin ERR("find_file_in_dir returned %08lx\n", Status);
1618c2c66affSColin Finck return Status;
1619c2c66affSColin Finck } else {
1620c2c66affSColin Finck fcb* fcb;
1621883b1f31SPierre Schweitzer file_ref* duff_fr = NULL;
1622c2c66affSColin Finck
1623c2c66affSColin Finck if (dc->fileref) {
1624c2c66affSColin Finck if (!lastpart && dc->type != BTRFS_TYPE_DIRECTORY) {
1625c2c66affSColin Finck TRACE("passed path including file as subdirectory\n");
1626c2c66affSColin Finck return STATUS_OBJECT_PATH_NOT_FOUND;
1627c2c66affSColin Finck }
1628c2c66affSColin Finck
1629c2c66affSColin Finck InterlockedIncrement(&dc->fileref->refcount);
1630c2c66affSColin Finck *psf2 = dc->fileref;
1631c2c66affSColin Finck return STATUS_SUCCESS;
1632c2c66affSColin Finck }
1633c2c66affSColin Finck
163462e630deSPierre Schweitzer if (!subvol || (subvol != Vcb->root_fileref->fcb->subvol && inode == SUBVOL_ROOT_INODE && subvol->parent != sf->fcb->subvol->id && !dc->root_dir)) {
1635c2c66affSColin Finck fcb = Vcb->dummy_fcb;
1636c2c66affSColin Finck InterlockedIncrement(&fcb->refcount);
1637c2c66affSColin Finck } else {
1638318da0c1SPierre Schweitzer Status = open_fcb(Vcb, subvol, inode, dc->type, &dc->utf8, false, sf->fcb, &fcb, pooltype, Irp);
1639c2c66affSColin Finck
1640c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
1641194ea909SVictor Perevertkin ERR("open_fcb returned %08lx\n", Status);
1642c2c66affSColin Finck return Status;
1643c2c66affSColin Finck }
1644c2c66affSColin Finck }
1645c2c66affSColin Finck
1646c2c66affSColin Finck if (dc->type != BTRFS_TYPE_DIRECTORY && !lastpart && !(fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT)) {
1647c2c66affSColin Finck TRACE("passed path including file as subdirectory\n");
1648883b1f31SPierre Schweitzer free_fcb(fcb);
1649c2c66affSColin Finck return STATUS_OBJECT_PATH_NOT_FOUND;
1650c2c66affSColin Finck }
1651c2c66affSColin Finck
1652c2c66affSColin Finck sf2 = create_fileref(Vcb);
1653c2c66affSColin Finck if (!sf2) {
1654c2c66affSColin Finck ERR("out of memory\n");
1655883b1f31SPierre Schweitzer free_fcb(fcb);
1656c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
1657c2c66affSColin Finck }
1658c2c66affSColin Finck
1659c2c66affSColin Finck sf2->fcb = fcb;
1660c2c66affSColin Finck
1661318da0c1SPierre Schweitzer ExAcquireResourceExclusiveLite(&sf->fcb->nonpaged->dir_children_lock, true);
1662883b1f31SPierre Schweitzer
1663883b1f31SPierre Schweitzer if (!dc->fileref) {
1664883b1f31SPierre Schweitzer sf2->parent = (struct _file_ref*)sf;
1665c2c66affSColin Finck sf2->dc = dc;
1666c2c66affSColin Finck dc->fileref = sf2;
1667c2c66affSColin Finck InsertTailList(&sf->children, &sf2->list_entry);
1668c2c66affSColin Finck increase_fileref_refcount(sf);
1669c982533eSVincent Franchomme
1670c982533eSVincent Franchomme if (dc->type == BTRFS_TYPE_DIRECTORY)
1671c982533eSVincent Franchomme fcb->fileref = sf2;
1672883b1f31SPierre Schweitzer } else {
1673883b1f31SPierre Schweitzer duff_fr = sf2;
1674883b1f31SPierre Schweitzer sf2 = dc->fileref;
1675883b1f31SPierre Schweitzer increase_fileref_refcount(sf2);
1676883b1f31SPierre Schweitzer }
1677883b1f31SPierre Schweitzer
1678883b1f31SPierre Schweitzer ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock);
1679883b1f31SPierre Schweitzer
1680883b1f31SPierre Schweitzer if (duff_fr)
1681883b1f31SPierre Schweitzer reap_fileref(Vcb, duff_fr);
1682c2c66affSColin Finck }
1683c2c66affSColin Finck }
1684c2c66affSColin Finck
1685c2c66affSColin Finck *psf2 = sf2;
1686c2c66affSColin Finck
1687c2c66affSColin Finck return STATUS_SUCCESS;
1688c2c66affSColin Finck }
1689c2c66affSColin Finck
1690c2c66affSColin 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,
1691318da0c1SPierre Schweitzer _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,
1692318da0c1SPierre Schweitzer _In_ bool case_sensitive, _In_opt_ PIRP Irp) {
1693c2c66affSColin Finck UNICODE_STRING fnus2;
1694c2c66affSColin Finck file_ref *dir, *sf, *sf2;
1695c2c66affSColin Finck LIST_ENTRY parts;
169606042735SVincent Franchomme bool has_stream = false;
1697c2c66affSColin Finck NTSTATUS Status;
1698c2c66affSColin Finck LIST_ENTRY* le;
1699c2c66affSColin Finck
1700c2c66affSColin Finck TRACE("(%p, %p, %p, %u, %p)\n", Vcb, pfr, related, parent, parsed);
1701c2c66affSColin Finck
1702c2c66affSColin Finck if (Vcb->removing || Vcb->locked)
1703c2c66affSColin Finck return STATUS_ACCESS_DENIED;
1704c2c66affSColin Finck
1705c2c66affSColin Finck fnus2 = *fnus;
1706c2c66affSColin Finck
1707c2c66affSColin Finck if (fnus2.Length < sizeof(WCHAR) && !related) {
1708c2c66affSColin Finck ERR("error - fnus was too short\n");
1709c2c66affSColin Finck return STATUS_INTERNAL_ERROR;
1710c2c66affSColin Finck }
1711c2c66affSColin Finck
1712c2c66affSColin Finck if (related && fnus->Length == 0) {
1713c2c66affSColin Finck increase_fileref_refcount(related);
1714c2c66affSColin Finck
1715c2c66affSColin Finck *pfr = related;
1716c2c66affSColin Finck return STATUS_SUCCESS;
1717c2c66affSColin Finck }
1718c2c66affSColin Finck
1719c2c66affSColin Finck if (related) {
1720c2c66affSColin Finck dir = related;
1721c2c66affSColin Finck } else {
1722c2c66affSColin Finck if (fnus2.Buffer[0] != '\\') {
1723194ea909SVictor Perevertkin ERR("error - filename %.*S did not begin with \\\n", (int)(fnus2.Length / sizeof(WCHAR)), fnus2.Buffer);
1724c2c66affSColin Finck return STATUS_OBJECT_PATH_NOT_FOUND;
1725c2c66affSColin Finck }
1726c2c66affSColin Finck
17274672b2baSPierre Schweitzer // if path starts with two backslashes, ignore one of them
17284672b2baSPierre Schweitzer if (fnus2.Length >= 2 * sizeof(WCHAR) && fnus2.Buffer[1] == '\\') {
17294672b2baSPierre Schweitzer fnus2.Buffer++;
17304672b2baSPierre Schweitzer fnus2.Length -= sizeof(WCHAR);
17314672b2baSPierre Schweitzer fnus2.MaximumLength -= sizeof(WCHAR);
17324672b2baSPierre Schweitzer }
17334672b2baSPierre Schweitzer
1734c2c66affSColin Finck if (fnus2.Length == sizeof(WCHAR)) {
1735c2c66affSColin Finck if (Vcb->root_fileref->open_count == 0 && !(Vcb->Vpb->Flags & VPB_MOUNTED)) // don't allow root to be opened on unmounted FS
1736c2c66affSColin Finck return STATUS_DEVICE_NOT_READY;
1737c2c66affSColin Finck
1738c2c66affSColin Finck increase_fileref_refcount(Vcb->root_fileref);
1739c2c66affSColin Finck *pfr = Vcb->root_fileref;
1740c2c66affSColin Finck
1741c2c66affSColin Finck if (fn_offset)
1742c2c66affSColin Finck *fn_offset = 0;
1743c2c66affSColin Finck
1744c2c66affSColin Finck return STATUS_SUCCESS;
1745883b1f31SPierre Schweitzer } else if (fnus2.Length >= 2 * sizeof(WCHAR) && fnus2.Buffer[1] == '\\')
1746883b1f31SPierre Schweitzer return STATUS_OBJECT_NAME_INVALID;
1747c2c66affSColin Finck
1748c2c66affSColin Finck dir = Vcb->root_fileref;
1749c2c66affSColin Finck
1750c2c66affSColin Finck fnus2.Buffer++;
1751c2c66affSColin Finck fnus2.Length -= sizeof(WCHAR);
1752c2c66affSColin Finck fnus2.MaximumLength -= sizeof(WCHAR);
1753c2c66affSColin Finck }
1754c2c66affSColin Finck
1755c2c66affSColin Finck if (dir->fcb->type != BTRFS_TYPE_DIRECTORY && (fnus->Length < sizeof(WCHAR) || fnus->Buffer[0] != ':')) {
175662e630deSPierre Schweitzer WARN("passed related fileref which isn't a directory (fnus = %.*S)\n",
1757194ea909SVictor Perevertkin (int)(fnus->Length / sizeof(WCHAR)), fnus->Buffer);
1758c2c66affSColin Finck return STATUS_OBJECT_PATH_NOT_FOUND;
1759c2c66affSColin Finck }
1760c2c66affSColin Finck
1761c2c66affSColin Finck InitializeListHead(&parts);
1762c2c66affSColin Finck
1763c2c66affSColin Finck if (fnus->Length != 0 &&
1764eb7fbc25SPierre Schweitzer (fnus->Length != sizeof(datastring) - sizeof(WCHAR) || RtlCompareMemory(fnus->Buffer, datastring, sizeof(datastring) - sizeof(WCHAR)) != sizeof(datastring) - sizeof(WCHAR))) {
1765c2c66affSColin Finck Status = split_path(Vcb, &fnus2, &parts, &has_stream);
1766c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
1767194ea909SVictor Perevertkin ERR("split_path returned %08lx\n", Status);
1768c2c66affSColin Finck return Status;
1769c2c66affSColin Finck }
1770c2c66affSColin Finck }
1771c2c66affSColin Finck
1772c2c66affSColin Finck sf = dir;
1773c2c66affSColin Finck increase_fileref_refcount(dir);
1774c2c66affSColin Finck
1775c2c66affSColin Finck if (parent && !IsListEmpty(&parts)) {
1776c2c66affSColin Finck name_bit* nb;
1777c2c66affSColin Finck
1778c2c66affSColin Finck nb = CONTAINING_RECORD(RemoveTailList(&parts), name_bit, list_entry);
1779f5556fdcSVincent Franchomme ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb);
1780c2c66affSColin Finck
1781c2c66affSColin Finck if (has_stream && !IsListEmpty(&parts)) {
1782c2c66affSColin Finck nb = CONTAINING_RECORD(RemoveTailList(&parts), name_bit, list_entry);
1783f5556fdcSVincent Franchomme ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb);
1784c2c66affSColin Finck
1785318da0c1SPierre Schweitzer has_stream = false;
1786c2c66affSColin Finck }
1787c2c66affSColin Finck }
1788c2c66affSColin Finck
1789c2c66affSColin Finck if (IsListEmpty(&parts)) {
1790c2c66affSColin Finck Status = STATUS_SUCCESS;
1791c2c66affSColin Finck *pfr = dir;
1792c2c66affSColin Finck
1793c2c66affSColin Finck if (fn_offset)
1794c2c66affSColin Finck *fn_offset = 0;
1795c2c66affSColin Finck
1796c2c66affSColin Finck goto end2;
1797c2c66affSColin Finck }
1798c2c66affSColin Finck
1799c2c66affSColin Finck le = parts.Flink;
1800c2c66affSColin Finck do {
1801c2c66affSColin Finck name_bit* nb = CONTAINING_RECORD(le, name_bit, list_entry);
1802318da0c1SPierre Schweitzer bool lastpart = le->Flink == &parts || (has_stream && le->Flink->Flink == &parts);
1803318da0c1SPierre Schweitzer bool streampart = has_stream && le->Flink == &parts;
1804318da0c1SPierre Schweitzer bool cs = case_sensitive;
1805f381137cSPierre Schweitzer
1806f381137cSPierre Schweitzer if (!cs) {
180762e630deSPierre Schweitzer if (streampart && sf->parent)
1808f381137cSPierre Schweitzer cs = sf->parent->fcb->case_sensitive;
1809f381137cSPierre Schweitzer else
1810f381137cSPierre Schweitzer cs = sf->fcb->case_sensitive;
1811f381137cSPierre Schweitzer }
1812f381137cSPierre Schweitzer
1813f381137cSPierre Schweitzer Status = open_fileref_child(Vcb, sf, &nb->us, cs, lastpart, streampart, pooltype, &sf2, Irp);
1814318da0c1SPierre Schweitzer
1815c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
181698654b54SVincent Franchomme if (Status == STATUS_OBJECT_PATH_NOT_FOUND || Status == STATUS_OBJECT_NAME_NOT_FOUND || Status == STATUS_OBJECT_NAME_INVALID)
1817194ea909SVictor Perevertkin TRACE("open_fileref_child returned %08lx\n", Status);
1818c2c66affSColin Finck else
1819194ea909SVictor Perevertkin ERR("open_fileref_child returned %08lx\n", Status);
1820c2c66affSColin Finck
1821c2c66affSColin Finck goto end;
1822c2c66affSColin Finck }
1823c2c66affSColin Finck
1824c2c66affSColin Finck if (le->Flink == &parts) { // last entry
1825c2c66affSColin Finck if (fn_offset) {
1826c2c66affSColin Finck if (has_stream)
1827c2c66affSColin Finck nb = CONTAINING_RECORD(le->Blink, name_bit, list_entry);
1828c2c66affSColin Finck
1829c2c66affSColin Finck *fn_offset = (ULONG)(nb->us.Buffer - fnus->Buffer);
1830c2c66affSColin Finck }
1831c2c66affSColin Finck
1832c2c66affSColin Finck break;
1833c2c66affSColin Finck }
1834c2c66affSColin Finck
1835c2c66affSColin Finck if (sf2->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT) {
1836c2c66affSColin Finck Status = STATUS_REPARSE;
1837c2c66affSColin Finck
1838c2c66affSColin Finck if (parsed) {
1839c2c66affSColin Finck name_bit* nb2 = CONTAINING_RECORD(le->Flink, name_bit, list_entry);
1840c2c66affSColin Finck
1841c2c66affSColin Finck *parsed = (USHORT)(nb2->us.Buffer - fnus->Buffer - 1) * sizeof(WCHAR);
1842c2c66affSColin Finck }
1843c2c66affSColin Finck
1844c2c66affSColin Finck break;
1845c2c66affSColin Finck }
1846c2c66affSColin Finck
1847883b1f31SPierre Schweitzer free_fileref(sf);
1848c2c66affSColin Finck sf = sf2;
1849c2c66affSColin Finck
1850c2c66affSColin Finck le = le->Flink;
1851c2c66affSColin Finck } while (le != &parts);
1852c2c66affSColin Finck
1853c2c66affSColin Finck if (Status != STATUS_REPARSE)
1854c2c66affSColin Finck Status = STATUS_SUCCESS;
1855c2c66affSColin Finck *pfr = sf2;
1856c2c66affSColin Finck
1857c2c66affSColin Finck end:
1858883b1f31SPierre Schweitzer free_fileref(sf);
1859c2c66affSColin Finck
1860c2c66affSColin Finck while (!IsListEmpty(&parts)) {
1861c2c66affSColin Finck name_bit* nb = CONTAINING_RECORD(RemoveHeadList(&parts), name_bit, list_entry);
1862c2c66affSColin Finck ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb);
1863c2c66affSColin Finck }
1864c2c66affSColin Finck
1865c2c66affSColin Finck end2:
1866194ea909SVictor Perevertkin TRACE("returning %08lx\n", Status);
1867c2c66affSColin Finck
1868c2c66affSColin Finck return Status;
1869c2c66affSColin Finck }
1870c2c66affSColin Finck
add_dir_child(fcb * fcb,uint64_t inode,bool subvol,PANSI_STRING utf8,PUNICODE_STRING name,uint8_t type,dir_child ** pdc)1871318da0c1SPierre Schweitzer NTSTATUS add_dir_child(fcb* fcb, uint64_t inode, bool subvol, PANSI_STRING utf8, PUNICODE_STRING name, uint8_t type, dir_child** pdc) {
1872c2c66affSColin Finck NTSTATUS Status;
1873c2c66affSColin Finck dir_child* dc;
1874318da0c1SPierre Schweitzer bool locked;
1875c2c66affSColin Finck
1876c2c66affSColin Finck dc = ExAllocatePoolWithTag(PagedPool, sizeof(dir_child), ALLOC_TAG);
1877c2c66affSColin Finck if (!dc) {
1878c2c66affSColin Finck ERR("out of memory\n");
1879c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
1880c2c66affSColin Finck }
1881c2c66affSColin Finck
1882f5556fdcSVincent Franchomme RtlZeroMemory(dc, sizeof(dir_child));
1883f5556fdcSVincent Franchomme
1884c2c66affSColin Finck dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, utf8->Length, ALLOC_TAG);
1885c2c66affSColin Finck if (!dc->utf8.Buffer) {
1886c2c66affSColin Finck ERR("out of memory\n");
1887c2c66affSColin Finck ExFreePool(dc);
1888c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
1889c2c66affSColin Finck }
1890c2c66affSColin Finck
1891c2c66affSColin Finck dc->name.Buffer = ExAllocatePoolWithTag(PagedPool, name->Length, ALLOC_TAG);
1892c2c66affSColin Finck if (!dc->name.Buffer) {
1893c2c66affSColin Finck ERR("out of memory\n");
1894c2c66affSColin Finck ExFreePool(dc->utf8.Buffer);
1895c2c66affSColin Finck ExFreePool(dc);
1896c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
1897c2c66affSColin Finck }
1898c2c66affSColin Finck
1899c2c66affSColin Finck dc->key.obj_id = inode;
1900c2c66affSColin Finck dc->key.obj_type = subvol ? TYPE_ROOT_ITEM : TYPE_INODE_ITEM;
1901c2c66affSColin Finck dc->key.offset = subvol ? 0xffffffffffffffff : 0;
1902c2c66affSColin Finck dc->type = type;
1903c2c66affSColin Finck dc->fileref = NULL;
1904c2c66affSColin Finck
1905c2c66affSColin Finck dc->utf8.Length = dc->utf8.MaximumLength = utf8->Length;
1906c2c66affSColin Finck RtlCopyMemory(dc->utf8.Buffer, utf8->Buffer, utf8->Length);
1907c2c66affSColin Finck
1908c2c66affSColin Finck dc->name.Length = dc->name.MaximumLength = name->Length;
1909c2c66affSColin Finck RtlCopyMemory(dc->name.Buffer, name->Buffer, name->Length);
1910c2c66affSColin Finck
1911318da0c1SPierre Schweitzer Status = RtlUpcaseUnicodeString(&dc->name_uc, name, true);
1912c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
1913194ea909SVictor Perevertkin ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
1914c2c66affSColin Finck ExFreePool(dc->utf8.Buffer);
1915c2c66affSColin Finck ExFreePool(dc->name.Buffer);
1916c2c66affSColin Finck ExFreePool(dc);
1917c2c66affSColin Finck return Status;
1918c2c66affSColin Finck }
1919c2c66affSColin Finck
1920318da0c1SPierre Schweitzer dc->hash = calc_crc32c(0xffffffff, (uint8_t*)dc->name.Buffer, dc->name.Length);
1921318da0c1SPierre Schweitzer dc->hash_uc = calc_crc32c(0xffffffff, (uint8_t*)dc->name_uc.Buffer, dc->name_uc.Length);
1922c2c66affSColin Finck
1923883b1f31SPierre Schweitzer locked = ExIsResourceAcquiredExclusive(&fcb->nonpaged->dir_children_lock);
1924883b1f31SPierre Schweitzer
1925883b1f31SPierre Schweitzer if (!locked)
1926318da0c1SPierre Schweitzer ExAcquireResourceExclusiveLite(&fcb->nonpaged->dir_children_lock, true);
1927c2c66affSColin Finck
1928c2c66affSColin Finck if (IsListEmpty(&fcb->dir_children_index))
1929c2c66affSColin Finck dc->index = 2;
1930c2c66affSColin Finck else {
1931c2c66affSColin Finck dir_child* dc2 = CONTAINING_RECORD(fcb->dir_children_index.Blink, dir_child, list_entry_index);
1932c2c66affSColin Finck
1933c2c66affSColin Finck dc->index = max(2, dc2->index + 1);
1934c2c66affSColin Finck }
1935c2c66affSColin Finck
1936c2c66affSColin Finck InsertTailList(&fcb->dir_children_index, &dc->list_entry_index);
1937c2c66affSColin Finck
1938c2c66affSColin Finck insert_dir_child_into_hash_lists(fcb, dc);
1939c2c66affSColin Finck
1940883b1f31SPierre Schweitzer if (!locked)
1941c2c66affSColin Finck ExReleaseResourceLite(&fcb->nonpaged->dir_children_lock);
1942c2c66affSColin Finck
1943c2c66affSColin Finck *pdc = dc;
1944c2c66affSColin Finck
1945c2c66affSColin Finck return STATUS_SUCCESS;
1946c2c66affSColin Finck }
1947c2c66affSColin Finck
inherit_mode(fcb * parfcb,bool is_dir)1948318da0c1SPierre Schweitzer uint32_t inherit_mode(fcb* parfcb, bool is_dir) {
1949318da0c1SPierre Schweitzer uint32_t mode;
1950c2c66affSColin Finck
1951c2c66affSColin Finck if (!parfcb)
1952c2c66affSColin Finck return 0755;
1953c2c66affSColin Finck
1954c2c66affSColin Finck mode = parfcb->inode_item.st_mode & ~S_IFDIR;
1955c2c66affSColin Finck mode &= ~S_ISVTX; // clear sticky bit
1956c2c66affSColin Finck mode &= ~S_ISUID; // clear setuid bit
1957c2c66affSColin Finck
1958c2c66affSColin Finck if (!is_dir)
1959c2c66affSColin Finck mode &= ~S_ISGID; // if not directory, clear setgid bit
1960c2c66affSColin Finck
1961c2c66affSColin Finck return mode;
1962c2c66affSColin Finck }
1963c2c66affSColin Finck
file_create_parse_ea(fcb * fcb,FILE_FULL_EA_INFORMATION * ea)1964eb7fbc25SPierre Schweitzer static NTSTATUS file_create_parse_ea(fcb* fcb, FILE_FULL_EA_INFORMATION* ea) {
1965eb7fbc25SPierre Schweitzer NTSTATUS Status;
1966eb7fbc25SPierre Schweitzer LIST_ENTRY ealist, *le;
1967318da0c1SPierre Schweitzer uint16_t size = 0;
1968eb7fbc25SPierre Schweitzer char* buf;
1969eb7fbc25SPierre Schweitzer
1970eb7fbc25SPierre Schweitzer InitializeListHead(&ealist);
1971eb7fbc25SPierre Schweitzer
1972eb7fbc25SPierre Schweitzer do {
1973eb7fbc25SPierre Schweitzer STRING s;
1974318da0c1SPierre Schweitzer bool found = false;
1975eb7fbc25SPierre Schweitzer
1976eb7fbc25SPierre Schweitzer s.Length = s.MaximumLength = ea->EaNameLength;
1977eb7fbc25SPierre Schweitzer s.Buffer = ea->EaName;
1978eb7fbc25SPierre Schweitzer
1979eb7fbc25SPierre Schweitzer RtlUpperString(&s, &s);
1980eb7fbc25SPierre Schweitzer
1981eb7fbc25SPierre Schweitzer le = ealist.Flink;
1982eb7fbc25SPierre Schweitzer while (le != &ealist) {
1983eb7fbc25SPierre Schweitzer ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry);
1984eb7fbc25SPierre Schweitzer
1985eb7fbc25SPierre Schweitzer if (item->name.Length == s.Length && RtlCompareMemory(item->name.Buffer, s.Buffer, s.Length) == s.Length) {
1986eb7fbc25SPierre Schweitzer item->flags = ea->Flags;
1987eb7fbc25SPierre Schweitzer item->value.Length = item->value.MaximumLength = ea->EaValueLength;
1988eb7fbc25SPierre Schweitzer item->value.Buffer = &ea->EaName[ea->EaNameLength + 1];
1989318da0c1SPierre Schweitzer found = true;
1990eb7fbc25SPierre Schweitzer break;
1991eb7fbc25SPierre Schweitzer }
1992eb7fbc25SPierre Schweitzer
1993eb7fbc25SPierre Schweitzer le = le->Flink;
1994eb7fbc25SPierre Schweitzer }
1995eb7fbc25SPierre Schweitzer
1996eb7fbc25SPierre Schweitzer if (!found) {
1997eb7fbc25SPierre Schweitzer ea_item* item = ExAllocatePoolWithTag(PagedPool, sizeof(ea_item), ALLOC_TAG);
1998eb7fbc25SPierre Schweitzer if (!item) {
1999eb7fbc25SPierre Schweitzer ERR("out of memory\n");
2000eb7fbc25SPierre Schweitzer Status = STATUS_INSUFFICIENT_RESOURCES;
2001eb7fbc25SPierre Schweitzer goto end;
2002eb7fbc25SPierre Schweitzer }
2003eb7fbc25SPierre Schweitzer
2004eb7fbc25SPierre Schweitzer item->name.Length = item->name.MaximumLength = ea->EaNameLength;
2005eb7fbc25SPierre Schweitzer item->name.Buffer = ea->EaName;
2006eb7fbc25SPierre Schweitzer
2007eb7fbc25SPierre Schweitzer item->value.Length = item->value.MaximumLength = ea->EaValueLength;
2008eb7fbc25SPierre Schweitzer item->value.Buffer = &ea->EaName[ea->EaNameLength + 1];
2009eb7fbc25SPierre Schweitzer
2010eb7fbc25SPierre Schweitzer item->flags = ea->Flags;
2011eb7fbc25SPierre Schweitzer
2012eb7fbc25SPierre Schweitzer InsertTailList(&ealist, &item->list_entry);
2013eb7fbc25SPierre Schweitzer }
2014eb7fbc25SPierre Schweitzer
2015eb7fbc25SPierre Schweitzer if (ea->NextEntryOffset == 0)
2016eb7fbc25SPierre Schweitzer break;
2017eb7fbc25SPierre Schweitzer
2018318da0c1SPierre Schweitzer ea = (FILE_FULL_EA_INFORMATION*)(((uint8_t*)ea) + ea->NextEntryOffset);
2019318da0c1SPierre Schweitzer } while (true);
2020eb7fbc25SPierre Schweitzer
2021eb7fbc25SPierre Schweitzer // handle LXSS values
2022eb7fbc25SPierre Schweitzer le = ealist.Flink;
2023eb7fbc25SPierre Schweitzer while (le != &ealist) {
2024eb7fbc25SPierre Schweitzer LIST_ENTRY* le2 = le->Flink;
2025eb7fbc25SPierre Schweitzer ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry);
2026eb7fbc25SPierre Schweitzer
2027eb7fbc25SPierre Schweitzer if (item->name.Length == sizeof(lxuid) - 1 && RtlCompareMemory(item->name.Buffer, lxuid, item->name.Length) == item->name.Length) {
2028318da0c1SPierre Schweitzer if (item->value.Length < sizeof(uint32_t)) {
2029eb7fbc25SPierre Schweitzer ERR("uid value was shorter than expected\n");
2030eb7fbc25SPierre Schweitzer Status = STATUS_INVALID_PARAMETER;
2031eb7fbc25SPierre Schweitzer goto end;
2032eb7fbc25SPierre Schweitzer }
2033eb7fbc25SPierre Schweitzer
2034318da0c1SPierre Schweitzer RtlCopyMemory(&fcb->inode_item.st_uid, item->value.Buffer, sizeof(uint32_t));
2035318da0c1SPierre Schweitzer fcb->sd_dirty = true;
2036318da0c1SPierre Schweitzer fcb->sd_deleted = false;
2037eb7fbc25SPierre Schweitzer
2038eb7fbc25SPierre Schweitzer RemoveEntryList(&item->list_entry);
2039eb7fbc25SPierre Schweitzer ExFreePool(item);
2040eb7fbc25SPierre Schweitzer } else if (item->name.Length == sizeof(lxgid) - 1 && RtlCompareMemory(item->name.Buffer, lxgid, item->name.Length) == item->name.Length) {
2041318da0c1SPierre Schweitzer if (item->value.Length < sizeof(uint32_t)) {
2042eb7fbc25SPierre Schweitzer ERR("gid value was shorter than expected\n");
2043eb7fbc25SPierre Schweitzer Status = STATUS_INVALID_PARAMETER;
2044eb7fbc25SPierre Schweitzer goto end;
2045eb7fbc25SPierre Schweitzer }
2046eb7fbc25SPierre Schweitzer
2047318da0c1SPierre Schweitzer RtlCopyMemory(&fcb->inode_item.st_gid, item->value.Buffer, sizeof(uint32_t));
2048eb7fbc25SPierre Schweitzer
2049eb7fbc25SPierre Schweitzer RemoveEntryList(&item->list_entry);
2050eb7fbc25SPierre Schweitzer ExFreePool(item);
2051eb7fbc25SPierre Schweitzer } else if (item->name.Length == sizeof(lxmod) - 1 && RtlCompareMemory(item->name.Buffer, lxmod, item->name.Length) == item->name.Length) {
2052318da0c1SPierre Schweitzer uint32_t 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;
2053318da0c1SPierre Schweitzer uint32_t val;
2054eb7fbc25SPierre Schweitzer
2055318da0c1SPierre Schweitzer if (item->value.Length < sizeof(uint32_t)) {
2056eb7fbc25SPierre Schweitzer ERR("mode value was shorter than expected\n");
2057eb7fbc25SPierre Schweitzer Status = STATUS_INVALID_PARAMETER;
2058eb7fbc25SPierre Schweitzer goto end;
2059eb7fbc25SPierre Schweitzer }
2060eb7fbc25SPierre Schweitzer
2061174dfab6SVincent Franchomme val = *(uint32_t*)item->value.Buffer;
2062eb7fbc25SPierre Schweitzer
2063eb7fbc25SPierre Schweitzer fcb->inode_item.st_mode &= ~allowed;
2064eb7fbc25SPierre Schweitzer fcb->inode_item.st_mode |= val & allowed;
2065eb7fbc25SPierre Schweitzer
2066eb7fbc25SPierre Schweitzer if (fcb->type != BTRFS_TYPE_DIRECTORY) {
2067174dfab6SVincent Franchomme if (__S_ISTYPE(val, __S_IFCHR)) {
2068eb7fbc25SPierre Schweitzer fcb->type = BTRFS_TYPE_CHARDEV;
2069174dfab6SVincent Franchomme fcb->inode_item.st_mode &= ~__S_IFMT;
2070174dfab6SVincent Franchomme fcb->inode_item.st_mode |= __S_IFCHR;
2071174dfab6SVincent Franchomme } else if (__S_ISTYPE(val, __S_IFBLK)) {
2072eb7fbc25SPierre Schweitzer fcb->type = BTRFS_TYPE_BLOCKDEV;
2073174dfab6SVincent Franchomme fcb->inode_item.st_mode &= ~__S_IFMT;
2074174dfab6SVincent Franchomme fcb->inode_item.st_mode |= __S_IFBLK;
2075174dfab6SVincent Franchomme } else if (__S_ISTYPE(val, __S_IFIFO)) {
2076eb7fbc25SPierre Schweitzer fcb->type = BTRFS_TYPE_FIFO;
2077174dfab6SVincent Franchomme fcb->inode_item.st_mode &= ~__S_IFMT;
2078174dfab6SVincent Franchomme fcb->inode_item.st_mode |= __S_IFIFO;
2079174dfab6SVincent Franchomme } else if (__S_ISTYPE(val, __S_IFSOCK)) {
2080eb7fbc25SPierre Schweitzer fcb->type = BTRFS_TYPE_SOCKET;
2081174dfab6SVincent Franchomme fcb->inode_item.st_mode &= ~__S_IFMT;
2082174dfab6SVincent Franchomme fcb->inode_item.st_mode |= __S_IFSOCK;
2083174dfab6SVincent Franchomme }
2084eb7fbc25SPierre Schweitzer }
2085eb7fbc25SPierre Schweitzer
2086eb7fbc25SPierre Schweitzer RemoveEntryList(&item->list_entry);
2087eb7fbc25SPierre Schweitzer ExFreePool(item);
2088eb7fbc25SPierre Schweitzer } else if (item->name.Length == sizeof(lxdev) - 1 && RtlCompareMemory(item->name.Buffer, lxdev, item->name.Length) == item->name.Length) {
2089318da0c1SPierre Schweitzer uint32_t major, minor;
2090eb7fbc25SPierre Schweitzer
2091318da0c1SPierre Schweitzer if (item->value.Length < sizeof(uint64_t)) {
2092eb7fbc25SPierre Schweitzer ERR("dev value was shorter than expected\n");
2093eb7fbc25SPierre Schweitzer Status = STATUS_INVALID_PARAMETER;
2094eb7fbc25SPierre Schweitzer goto end;
2095eb7fbc25SPierre Schweitzer }
2096eb7fbc25SPierre Schweitzer
2097318da0c1SPierre Schweitzer major = *(uint32_t*)item->value.Buffer;
2098318da0c1SPierre Schweitzer minor = *(uint32_t*)&item->value.Buffer[sizeof(uint32_t)];
2099eb7fbc25SPierre Schweitzer
2100eb7fbc25SPierre Schweitzer fcb->inode_item.st_rdev = (minor & 0xFFFFF) | ((major & 0xFFFFFFFFFFF) << 20);
2101eb7fbc25SPierre Schweitzer
2102eb7fbc25SPierre Schweitzer RemoveEntryList(&item->list_entry);
2103eb7fbc25SPierre Schweitzer ExFreePool(item);
2104eb7fbc25SPierre Schweitzer }
2105eb7fbc25SPierre Schweitzer
2106eb7fbc25SPierre Schweitzer le = le2;
2107eb7fbc25SPierre Schweitzer }
2108eb7fbc25SPierre Schweitzer
2109eb7fbc25SPierre Schweitzer if (fcb->type != BTRFS_TYPE_CHARDEV && fcb->type != BTRFS_TYPE_BLOCKDEV)
2110eb7fbc25SPierre Schweitzer fcb->inode_item.st_rdev = 0;
2111eb7fbc25SPierre Schweitzer
2112eb7fbc25SPierre Schweitzer if (IsListEmpty(&ealist))
2113eb7fbc25SPierre Schweitzer return STATUS_SUCCESS;
2114eb7fbc25SPierre Schweitzer
2115eb7fbc25SPierre Schweitzer le = ealist.Flink;
2116eb7fbc25SPierre Schweitzer while (le != &ealist) {
2117eb7fbc25SPierre Schweitzer ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry);
2118eb7fbc25SPierre Schweitzer
2119eb7fbc25SPierre Schweitzer if (size % 4 > 0)
2120eb7fbc25SPierre Schweitzer size += 4 - (size % 4);
2121eb7fbc25SPierre Schweitzer
2122318da0c1SPierre Schweitzer size += (uint16_t)offsetof(FILE_FULL_EA_INFORMATION, EaName[0]) + item->name.Length + 1 + item->value.Length;
2123eb7fbc25SPierre Schweitzer
2124eb7fbc25SPierre Schweitzer le = le->Flink;
2125eb7fbc25SPierre Schweitzer }
2126eb7fbc25SPierre Schweitzer
2127eb7fbc25SPierre Schweitzer buf = ExAllocatePoolWithTag(PagedPool, size, ALLOC_TAG);
2128eb7fbc25SPierre Schweitzer if (!buf) {
2129eb7fbc25SPierre Schweitzer ERR("out of memory\n");
2130eb7fbc25SPierre Schweitzer Status = STATUS_INSUFFICIENT_RESOURCES;
2131eb7fbc25SPierre Schweitzer goto end;
2132eb7fbc25SPierre Schweitzer }
2133eb7fbc25SPierre Schweitzer
2134eb7fbc25SPierre Schweitzer fcb->ea_xattr.Length = fcb->ea_xattr.MaximumLength = size;
2135eb7fbc25SPierre Schweitzer fcb->ea_xattr.Buffer = buf;
2136eb7fbc25SPierre Schweitzer
2137eb7fbc25SPierre Schweitzer fcb->ealen = 4;
2138eb7fbc25SPierre Schweitzer ea = NULL;
2139eb7fbc25SPierre Schweitzer
2140eb7fbc25SPierre Schweitzer le = ealist.Flink;
2141eb7fbc25SPierre Schweitzer while (le != &ealist) {
2142eb7fbc25SPierre Schweitzer ea_item* item = CONTAINING_RECORD(le, ea_item, list_entry);
2143eb7fbc25SPierre Schweitzer
2144eb7fbc25SPierre Schweitzer if (ea) {
2145eb7fbc25SPierre Schweitzer ea->NextEntryOffset = (ULONG)offsetof(FILE_FULL_EA_INFORMATION, EaName[0]) + ea->EaNameLength + ea->EaValueLength;
2146eb7fbc25SPierre Schweitzer
2147eb7fbc25SPierre Schweitzer if (ea->NextEntryOffset % 4 > 0)
2148eb7fbc25SPierre Schweitzer ea->NextEntryOffset += 4 - (ea->NextEntryOffset % 4);
2149eb7fbc25SPierre Schweitzer
2150318da0c1SPierre Schweitzer ea = (FILE_FULL_EA_INFORMATION*)(((uint8_t*)ea) + ea->NextEntryOffset);
2151eb7fbc25SPierre Schweitzer } else
2152eb7fbc25SPierre Schweitzer ea = (FILE_FULL_EA_INFORMATION*)fcb->ea_xattr.Buffer;
2153eb7fbc25SPierre Schweitzer
2154eb7fbc25SPierre Schweitzer ea->NextEntryOffset = 0;
2155eb7fbc25SPierre Schweitzer ea->Flags = item->flags;
2156eb7fbc25SPierre Schweitzer ea->EaNameLength = (UCHAR)item->name.Length;
2157eb7fbc25SPierre Schweitzer ea->EaValueLength = item->value.Length;
2158eb7fbc25SPierre Schweitzer
2159eb7fbc25SPierre Schweitzer RtlCopyMemory(ea->EaName, item->name.Buffer, item->name.Length);
2160eb7fbc25SPierre Schweitzer ea->EaName[item->name.Length] = 0;
2161eb7fbc25SPierre Schweitzer RtlCopyMemory(&ea->EaName[item->name.Length + 1], item->value.Buffer, item->value.Length);
2162eb7fbc25SPierre Schweitzer
2163eb7fbc25SPierre Schweitzer fcb->ealen += 5 + item->name.Length + item->value.Length;
2164eb7fbc25SPierre Schweitzer
2165eb7fbc25SPierre Schweitzer le = le->Flink;
2166eb7fbc25SPierre Schweitzer }
2167eb7fbc25SPierre Schweitzer
2168318da0c1SPierre Schweitzer fcb->ea_changed = true;
2169eb7fbc25SPierre Schweitzer
2170eb7fbc25SPierre Schweitzer Status = STATUS_SUCCESS;
2171eb7fbc25SPierre Schweitzer
2172eb7fbc25SPierre Schweitzer end:
2173eb7fbc25SPierre Schweitzer while (!IsListEmpty(&ealist)) {
2174eb7fbc25SPierre Schweitzer ea_item* item = CONTAINING_RECORD(RemoveHeadList(&ealist), ea_item, list_entry);
2175eb7fbc25SPierre Schweitzer
2176eb7fbc25SPierre Schweitzer ExFreePool(item);
2177eb7fbc25SPierre Schweitzer }
2178eb7fbc25SPierre Schweitzer
2179eb7fbc25SPierre Schweitzer return Status;
2180eb7fbc25SPierre Schweitzer }
2181eb7fbc25SPierre Schweitzer
2182c2c66affSColin Finck static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension* Vcb, _In_ PUNICODE_STRING fpus,
2183c2c66affSColin Finck _In_ file_ref* parfileref, _In_ ULONG options, _In_reads_bytes_opt_(ealen) FILE_FULL_EA_INFORMATION* ea, _In_ ULONG ealen,
2184318da0c1SPierre Schweitzer _Out_ file_ref** pfr, bool case_sensitive, _In_ LIST_ENTRY* rollback) {
2185c2c66affSColin Finck NTSTATUS Status;
2186c2c66affSColin Finck fcb* fcb;
2187c2c66affSColin Finck ULONG utf8len;
2188c2c66affSColin Finck char* utf8 = NULL;
2189318da0c1SPierre Schweitzer uint64_t inode;
2190318da0c1SPierre Schweitzer uint8_t type;
2191c2c66affSColin Finck LARGE_INTEGER time;
2192c2c66affSColin Finck BTRFS_TIME now;
2193c2c66affSColin Finck PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
2194c2c66affSColin Finck POOL_TYPE pool_type = IrpSp->Flags & SL_OPEN_PAGING_FILE ? NonPagedPool : PagedPool;
2195c2c66affSColin Finck USHORT defda;
2196c2c66affSColin Finck file_ref* fileref;
2197c2c66affSColin Finck dir_child* dc;
2198c2c66affSColin Finck ANSI_STRING utf8as;
2199883b1f31SPierre Schweitzer LIST_ENTRY* lastle = NULL;
2200883b1f31SPierre Schweitzer file_ref* existing_fileref = NULL;
2201c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
2202c2c66affSColin Finck LONG rc;
2203c2c66affSColin Finck #endif
2204c2c66affSColin Finck
2205c2c66affSColin Finck if (parfileref->fcb == Vcb->dummy_fcb)
2206c2c66affSColin Finck return STATUS_ACCESS_DENIED;
2207c2c66affSColin Finck
22084672b2baSPierre Schweitzer if (options & FILE_DIRECTORY_FILE && IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_TEMPORARY)
22094672b2baSPierre Schweitzer return STATUS_INVALID_PARAMETER;
22104672b2baSPierre Schweitzer
2211318da0c1SPierre Schweitzer Status = utf16_to_utf8(NULL, 0, &utf8len, fpus->Buffer, fpus->Length);
2212c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
2213194ea909SVictor Perevertkin ERR("utf16_to_utf8 returned %08lx\n", Status);
2214c2c66affSColin Finck return Status;
2215c2c66affSColin Finck }
2216c2c66affSColin Finck
2217c2c66affSColin Finck utf8 = ExAllocatePoolWithTag(pool_type, utf8len + 1, ALLOC_TAG);
2218c2c66affSColin Finck if (!utf8) {
2219c2c66affSColin Finck ERR("out of memory\n");
2220c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
2221c2c66affSColin Finck }
2222c2c66affSColin Finck
2223318da0c1SPierre Schweitzer Status = utf16_to_utf8(utf8, utf8len, &utf8len, fpus->Buffer, fpus->Length);
2224c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
2225194ea909SVictor Perevertkin ERR("utf16_to_utf8 returned %08lx\n", Status);
2226c2c66affSColin Finck ExFreePool(utf8);
2227c2c66affSColin Finck return Status;
2228c2c66affSColin Finck }
2229c2c66affSColin Finck
2230c2c66affSColin Finck utf8[utf8len] = 0;
2231c2c66affSColin Finck
2232c2c66affSColin Finck KeQuerySystemTime(&time);
2233c2c66affSColin Finck win_time_to_unix(time, &now);
2234c2c66affSColin Finck
2235194ea909SVictor Perevertkin TRACE("create file %.*S\n", (int)(fpus->Length / sizeof(WCHAR)), fpus->Buffer);
2236318da0c1SPierre Schweitzer ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2237318da0c1SPierre Schweitzer TRACE("parfileref->fcb->inode_item.st_size (inode %I64x) was %I64x\n", parfileref->fcb->inode, parfileref->fcb->inode_item.st_size);
2238c2c66affSColin Finck parfileref->fcb->inode_item.st_size += utf8len * 2;
2239318da0c1SPierre Schweitzer TRACE("parfileref->fcb->inode_item.st_size (inode %I64x) now %I64x\n", parfileref->fcb->inode, parfileref->fcb->inode_item.st_size);
2240c2c66affSColin Finck parfileref->fcb->inode_item.transid = Vcb->superblock.generation;
2241c2c66affSColin Finck parfileref->fcb->inode_item.sequence++;
2242c2c66affSColin Finck parfileref->fcb->inode_item.st_ctime = now;
2243c2c66affSColin Finck parfileref->fcb->inode_item.st_mtime = now;
2244c2c66affSColin Finck ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2245c2c66affSColin Finck
2246318da0c1SPierre Schweitzer parfileref->fcb->inode_item_changed = true;
2247c2c66affSColin Finck mark_fcb_dirty(parfileref->fcb);
2248c2c66affSColin Finck
2249c2c66affSColin Finck inode = InterlockedIncrement64(&parfileref->fcb->subvol->lastinode);
2250c2c66affSColin Finck
2251c2c66affSColin Finck type = options & FILE_DIRECTORY_FILE ? BTRFS_TYPE_DIRECTORY : BTRFS_TYPE_FILE;
2252c2c66affSColin Finck
2253c2c66affSColin Finck // FIXME - link FILE_ATTRIBUTE_READONLY to st_mode
2254c2c66affSColin Finck
2255c2c66affSColin Finck TRACE("requested attributes = %x\n", IrpSp->Parameters.Create.FileAttributes);
2256c2c66affSColin Finck
22574672b2baSPierre Schweitzer defda = 0;
2258c2c66affSColin Finck
2259c2c66affSColin Finck if (utf8[0] == '.')
2260c2c66affSColin Finck defda |= FILE_ATTRIBUTE_HIDDEN;
2261c2c66affSColin Finck
2262c2c66affSColin Finck if (options & FILE_DIRECTORY_FILE) {
2263c2c66affSColin Finck defda |= FILE_ATTRIBUTE_DIRECTORY;
2264c2c66affSColin Finck IrpSp->Parameters.Create.FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2265c2c66affSColin Finck } else
2266c2c66affSColin Finck IrpSp->Parameters.Create.FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
2267c2c66affSColin Finck
22684672b2baSPierre Schweitzer if (!(IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
22694672b2baSPierre Schweitzer IrpSp->Parameters.Create.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
22704672b2baSPierre Schweitzer defda |= FILE_ATTRIBUTE_ARCHIVE;
22714672b2baSPierre Schweitzer }
22724672b2baSPierre Schweitzer
2273c2c66affSColin Finck TRACE("defda = %x\n", defda);
2274c2c66affSColin Finck
2275c2c66affSColin Finck if (IrpSp->Parameters.Create.FileAttributes == FILE_ATTRIBUTE_NORMAL)
2276c2c66affSColin Finck IrpSp->Parameters.Create.FileAttributes = defda;
2277c2c66affSColin Finck
2278c2c66affSColin Finck fcb = create_fcb(Vcb, pool_type);
2279c2c66affSColin Finck if (!fcb) {
2280c2c66affSColin Finck ERR("out of memory\n");
2281c2c66affSColin Finck ExFreePool(utf8);
2282c2c66affSColin Finck
2283318da0c1SPierre Schweitzer ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2284c2c66affSColin Finck parfileref->fcb->inode_item.st_size -= utf8len * 2;
2285c2c66affSColin Finck ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2286c2c66affSColin Finck
2287c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
2288c2c66affSColin Finck }
2289c2c66affSColin Finck
2290c2c66affSColin Finck fcb->Vcb = Vcb;
2291c2c66affSColin Finck
2292318da0c1SPierre Schweitzer if (IrpSp->Flags & SL_OPEN_PAGING_FILE)
2293c2c66affSColin Finck fcb->Header.Flags2 |= FSRTL_FLAG2_IS_PAGING_FILE;
2294c2c66affSColin Finck
2295c2c66affSColin Finck fcb->inode_item.generation = Vcb->superblock.generation;
2296c2c66affSColin Finck fcb->inode_item.transid = Vcb->superblock.generation;
2297c2c66affSColin Finck fcb->inode_item.st_size = 0;
2298c2c66affSColin Finck fcb->inode_item.st_blocks = 0;
2299c2c66affSColin Finck fcb->inode_item.block_group = 0;
2300c2c66affSColin Finck fcb->inode_item.st_nlink = 1;
2301c2c66affSColin Finck fcb->inode_item.st_gid = GID_NOBODY; // FIXME?
2302c2c66affSColin Finck fcb->inode_item.st_mode = inherit_mode(parfileref->fcb, type == BTRFS_TYPE_DIRECTORY); // use parent's permissions by default
2303c2c66affSColin Finck fcb->inode_item.st_rdev = 0;
2304c2c66affSColin Finck fcb->inode_item.flags = 0;
2305c2c66affSColin Finck fcb->inode_item.sequence = 1;
2306c2c66affSColin Finck fcb->inode_item.st_atime = now;
2307c2c66affSColin Finck fcb->inode_item.st_ctime = now;
2308c2c66affSColin Finck fcb->inode_item.st_mtime = now;
2309c2c66affSColin Finck fcb->inode_item.otime = now;
2310c2c66affSColin Finck
2311c2c66affSColin Finck if (type == BTRFS_TYPE_DIRECTORY)
2312c2c66affSColin Finck fcb->inode_item.st_mode |= S_IFDIR;
2313c2c66affSColin Finck else {
2314c2c66affSColin Finck fcb->inode_item.st_mode |= S_IFREG;
2315c2c66affSColin Finck fcb->inode_item.st_mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH); // remove executable bit if not directory
2316c2c66affSColin Finck }
2317c2c66affSColin Finck
2318c2c66affSColin Finck if (IrpSp->Flags & SL_OPEN_PAGING_FILE) {
2319c2c66affSColin Finck fcb->inode_item.flags = BTRFS_INODE_NODATACOW | BTRFS_INODE_NODATASUM | BTRFS_INODE_NOCOMPRESS;
2320c2c66affSColin Finck } else {
2321c2c66affSColin Finck // inherit nodatacow flag from parent directory
2322*29d19382SJohannes Obermayr if (parfileref->fcb->inode_item.flags & BTRFS_INODE_NODATACOW || Vcb->options.nodatacow) {
2323c2c66affSColin Finck fcb->inode_item.flags |= BTRFS_INODE_NODATACOW;
2324c2c66affSColin Finck
2325c2c66affSColin Finck if (type != BTRFS_TYPE_DIRECTORY)
2326c2c66affSColin Finck fcb->inode_item.flags |= BTRFS_INODE_NODATASUM;
2327c2c66affSColin Finck }
2328c2c66affSColin Finck
2329*29d19382SJohannes Obermayr if (parfileref->fcb->inode_item.flags & BTRFS_INODE_COMPRESS &&
2330*29d19382SJohannes Obermayr !(fcb->inode_item.flags & BTRFS_INODE_NODATACOW)) {
2331c2c66affSColin Finck fcb->inode_item.flags |= BTRFS_INODE_COMPRESS;
2332c2c66affSColin Finck }
2333*29d19382SJohannes Obermayr }
2334c2c66affSColin Finck
2335*29d19382SJohannes Obermayr if (!(fcb->inode_item.flags & BTRFS_INODE_NODATACOW)) {
2336c2c66affSColin Finck fcb->prop_compression = parfileref->fcb->prop_compression;
2337c2c66affSColin Finck fcb->prop_compression_changed = fcb->prop_compression != PropCompression_None;
2338*29d19382SJohannes Obermayr } else
2339*29d19382SJohannes Obermayr fcb->prop_compression = PropCompression_None;
2340c2c66affSColin Finck
2341318da0c1SPierre Schweitzer fcb->inode_item_changed = true;
2342c2c66affSColin Finck
2343c2c66affSColin Finck fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
2344c2c66affSColin Finck fcb->Header.AllocationSize.QuadPart = 0;
2345c2c66affSColin Finck fcb->Header.FileSize.QuadPart = 0;
2346c2c66affSColin Finck fcb->Header.ValidDataLength.QuadPart = 0;
2347c2c66affSColin Finck
2348c2c66affSColin Finck fcb->atts = IrpSp->Parameters.Create.FileAttributes & ~FILE_ATTRIBUTE_NORMAL;
2349c2c66affSColin Finck fcb->atts_changed = fcb->atts != defda;
2350c2c66affSColin Finck
2351c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
2352c2c66affSColin Finck rc = InterlockedIncrement(&parfileref->fcb->refcount);
235362e630deSPierre Schweitzer WARN("fcb %p: refcount now %i\n", parfileref->fcb, rc);
2354c2c66affSColin Finck #else
2355c2c66affSColin Finck InterlockedIncrement(&parfileref->fcb->refcount);
2356c2c66affSColin Finck #endif
2357c2c66affSColin Finck fcb->subvol = parfileref->fcb->subvol;
2358c2c66affSColin Finck fcb->inode = inode;
2359c2c66affSColin Finck fcb->type = type;
2360318da0c1SPierre Schweitzer fcb->created = true;
2361318da0c1SPierre Schweitzer fcb->deleted = true;
2362c2c66affSColin Finck
2363318da0c1SPierre Schweitzer fcb->hash = calc_crc32c(0xffffffff, (uint8_t*)&inode, sizeof(uint64_t));
2364883b1f31SPierre Schweitzer
2365883b1f31SPierre Schweitzer acquire_fcb_lock_exclusive(Vcb);
2366883b1f31SPierre Schweitzer
2367883b1f31SPierre Schweitzer if (fcb->subvol->fcbs_ptrs[fcb->hash >> 24]) {
2368883b1f31SPierre Schweitzer LIST_ENTRY* le = fcb->subvol->fcbs_ptrs[fcb->hash >> 24];
2369883b1f31SPierre Schweitzer
2370883b1f31SPierre Schweitzer while (le != &fcb->subvol->fcbs) {
2371883b1f31SPierre Schweitzer struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, list_entry);
2372883b1f31SPierre Schweitzer
2373883b1f31SPierre Schweitzer if (fcb2->hash > fcb->hash) {
2374883b1f31SPierre Schweitzer lastle = le->Blink;
2375883b1f31SPierre Schweitzer break;
2376883b1f31SPierre Schweitzer }
2377883b1f31SPierre Schweitzer
2378883b1f31SPierre Schweitzer le = le->Flink;
2379883b1f31SPierre Schweitzer }
2380883b1f31SPierre Schweitzer }
2381883b1f31SPierre Schweitzer
2382883b1f31SPierre Schweitzer if (!lastle) {
2383318da0c1SPierre Schweitzer uint8_t c = fcb->hash >> 24;
2384883b1f31SPierre Schweitzer
2385883b1f31SPierre Schweitzer if (c != 0xff) {
2386318da0c1SPierre Schweitzer uint8_t d = c + 1;
2387883b1f31SPierre Schweitzer
2388883b1f31SPierre Schweitzer do {
2389883b1f31SPierre Schweitzer if (fcb->subvol->fcbs_ptrs[d]) {
2390883b1f31SPierre Schweitzer lastle = fcb->subvol->fcbs_ptrs[d]->Blink;
2391883b1f31SPierre Schweitzer break;
2392883b1f31SPierre Schweitzer }
2393883b1f31SPierre Schweitzer
2394883b1f31SPierre Schweitzer d++;
2395883b1f31SPierre Schweitzer } while (d != 0);
2396883b1f31SPierre Schweitzer }
2397883b1f31SPierre Schweitzer }
2398883b1f31SPierre Schweitzer
2399883b1f31SPierre Schweitzer if (lastle) {
2400883b1f31SPierre Schweitzer InsertHeadList(lastle, &fcb->list_entry);
2401883b1f31SPierre Schweitzer
2402883b1f31SPierre Schweitzer if (lastle == &fcb->subvol->fcbs || (CONTAINING_RECORD(lastle, struct _fcb, list_entry)->hash >> 24) != (fcb->hash >> 24))
2403883b1f31SPierre Schweitzer fcb->subvol->fcbs_ptrs[fcb->hash >> 24] = &fcb->list_entry;
2404883b1f31SPierre Schweitzer } else {
2405883b1f31SPierre Schweitzer InsertTailList(&fcb->subvol->fcbs, &fcb->list_entry);
2406883b1f31SPierre Schweitzer
2407883b1f31SPierre Schweitzer if (fcb->list_entry.Blink == &fcb->subvol->fcbs || (CONTAINING_RECORD(fcb->list_entry.Blink, struct _fcb, list_entry)->hash >> 24) != (fcb->hash >> 24))
2408883b1f31SPierre Schweitzer fcb->subvol->fcbs_ptrs[fcb->hash >> 24] = &fcb->list_entry;
2409883b1f31SPierre Schweitzer }
2410883b1f31SPierre Schweitzer
2411883b1f31SPierre Schweitzer InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
2412883b1f31SPierre Schweitzer
2413883b1f31SPierre Schweitzer fcb->subvol->fcbs_version++;
2414883b1f31SPierre Schweitzer
2415883b1f31SPierre Schweitzer release_fcb_lock(Vcb);
2416883b1f31SPierre Schweitzer
2417c2c66affSColin Finck mark_fcb_dirty(fcb);
2418c2c66affSColin Finck
2419c2c66affSColin Finck Status = fcb_get_new_sd(fcb, parfileref, IrpSp->Parameters.Create.SecurityContext->AccessState);
2420c2c66affSColin Finck
2421c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
2422194ea909SVictor Perevertkin ERR("fcb_get_new_sd returned %08lx\n", Status);
2423883b1f31SPierre Schweitzer free_fcb(fcb);
2424c2c66affSColin Finck
2425318da0c1SPierre Schweitzer ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2426c2c66affSColin Finck parfileref->fcb->inode_item.st_size -= utf8len * 2;
2427c2c66affSColin Finck ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2428c2c66affSColin Finck
2429883b1f31SPierre Schweitzer ExFreePool(utf8);
2430883b1f31SPierre Schweitzer
2431c2c66affSColin Finck return Status;
2432c2c66affSColin Finck }
2433c2c66affSColin Finck
2434318da0c1SPierre Schweitzer fcb->sd_dirty = true;
2435c2c66affSColin Finck
2436c2c66affSColin Finck if (ea && ealen > 0) {
2437eb7fbc25SPierre Schweitzer Status = file_create_parse_ea(fcb, ea);
2438eb7fbc25SPierre Schweitzer if (!NT_SUCCESS(Status)) {
2439194ea909SVictor Perevertkin ERR("file_create_parse_ea returned %08lx\n", Status);
2440883b1f31SPierre Schweitzer free_fcb(fcb);
2441c2c66affSColin Finck
2442318da0c1SPierre Schweitzer ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2443c2c66affSColin Finck parfileref->fcb->inode_item.st_size -= utf8len * 2;
2444c2c66affSColin Finck ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2445c2c66affSColin Finck
2446883b1f31SPierre Schweitzer ExFreePool(utf8);
2447883b1f31SPierre Schweitzer
2448eb7fbc25SPierre Schweitzer return Status;
2449c2c66affSColin Finck }
2450c2c66affSColin Finck }
2451c2c66affSColin Finck
2452c2c66affSColin Finck fileref = create_fileref(Vcb);
2453c2c66affSColin Finck if (!fileref) {
2454c2c66affSColin Finck ERR("out of memory\n");
2455883b1f31SPierre Schweitzer free_fcb(fcb);
2456c2c66affSColin Finck
2457318da0c1SPierre Schweitzer ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2458c2c66affSColin Finck parfileref->fcb->inode_item.st_size -= utf8len * 2;
2459c2c66affSColin Finck ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2460c2c66affSColin Finck
2461883b1f31SPierre Schweitzer ExFreePool(utf8);
2462883b1f31SPierre Schweitzer
2463c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
2464c2c66affSColin Finck }
2465c2c66affSColin Finck
2466c2c66affSColin Finck fileref->fcb = fcb;
2467c2c66affSColin Finck
24686e0cf03dSVincent Franchomme if (Irp->Overlay.AllocationSize.QuadPart > 0 && !write_fcb_compressed(fcb) && fcb->type != BTRFS_TYPE_DIRECTORY) {
2469318da0c1SPierre Schweitzer Status = extend_file(fcb, fileref, Irp->Overlay.AllocationSize.QuadPart, true, NULL, rollback);
2470c2c66affSColin Finck
2471c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
2472194ea909SVictor Perevertkin ERR("extend_file returned %08lx\n", Status);
2473883b1f31SPierre Schweitzer reap_fileref(Vcb, fileref);
2474c2c66affSColin Finck
2475318da0c1SPierre Schweitzer ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2476c2c66affSColin Finck parfileref->fcb->inode_item.st_size -= utf8len * 2;
2477c2c66affSColin Finck ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2478c2c66affSColin Finck
2479883b1f31SPierre Schweitzer ExFreePool(utf8);
2480883b1f31SPierre Schweitzer
2481c2c66affSColin Finck return Status;
2482c2c66affSColin Finck }
2483c2c66affSColin Finck }
2484c2c66affSColin Finck
2485c2c66affSColin Finck if (fcb->type == BTRFS_TYPE_DIRECTORY) {
2486c2c66affSColin Finck fcb->hash_ptrs = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG);
2487c2c66affSColin Finck if (!fcb->hash_ptrs) {
2488c2c66affSColin Finck ERR("out of memory\n");
2489883b1f31SPierre Schweitzer reap_fileref(Vcb, fileref);
2490c2c66affSColin Finck
2491318da0c1SPierre Schweitzer ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2492c2c66affSColin Finck parfileref->fcb->inode_item.st_size -= utf8len * 2;
2493c2c66affSColin Finck ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2494c2c66affSColin Finck
2495883b1f31SPierre Schweitzer ExFreePool(utf8);
2496883b1f31SPierre Schweitzer
2497c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
2498c2c66affSColin Finck }
2499c2c66affSColin Finck
2500c2c66affSColin Finck RtlZeroMemory(fcb->hash_ptrs, sizeof(LIST_ENTRY*) * 256);
2501c2c66affSColin Finck
2502c2c66affSColin Finck fcb->hash_ptrs_uc = ExAllocatePoolWithTag(PagedPool, sizeof(LIST_ENTRY*) * 256, ALLOC_TAG);
2503c2c66affSColin Finck if (!fcb->hash_ptrs_uc) {
2504c2c66affSColin Finck ERR("out of memory\n");
2505883b1f31SPierre Schweitzer reap_fileref(Vcb, fileref);
2506c2c66affSColin Finck
2507318da0c1SPierre Schweitzer ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2508c2c66affSColin Finck parfileref->fcb->inode_item.st_size -= utf8len * 2;
2509c2c66affSColin Finck ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2510c2c66affSColin Finck
2511883b1f31SPierre Schweitzer ExFreePool(utf8);
2512883b1f31SPierre Schweitzer
2513c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
2514c2c66affSColin Finck }
2515c2c66affSColin Finck
2516c2c66affSColin Finck RtlZeroMemory(fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256);
2517c2c66affSColin Finck }
2518c2c66affSColin Finck
2519318da0c1SPierre Schweitzer fcb->deleted = false;
2520c2c66affSColin Finck
2521318da0c1SPierre Schweitzer fileref->created = true;
2522c2c66affSColin Finck
2523c2c66affSColin Finck fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
2524c2c66affSColin Finck fcb->subvol->root_item.ctime = now;
2525c2c66affSColin Finck
2526c2c66affSColin Finck utf8as.Buffer = utf8;
2527318da0c1SPierre Schweitzer utf8as.Length = utf8as.MaximumLength = (uint16_t)utf8len;
2528c2c66affSColin Finck
2529318da0c1SPierre Schweitzer ExAcquireResourceExclusiveLite(&parfileref->fcb->nonpaged->dir_children_lock, true);
2530883b1f31SPierre Schweitzer
2531883b1f31SPierre Schweitzer // check again doesn't already exist
2532883b1f31SPierre Schweitzer if (case_sensitive) {
2533318da0c1SPierre Schweitzer uint32_t dc_hash = calc_crc32c(0xffffffff, (uint8_t*)fpus->Buffer, fpus->Length);
2534883b1f31SPierre Schweitzer
2535883b1f31SPierre Schweitzer if (parfileref->fcb->hash_ptrs[dc_hash >> 24]) {
2536883b1f31SPierre Schweitzer LIST_ENTRY* le = parfileref->fcb->hash_ptrs[dc_hash >> 24];
2537883b1f31SPierre Schweitzer while (le != &parfileref->fcb->dir_children_hash) {
2538318da0c1SPierre Schweitzer dc = CONTAINING_RECORD(le, dir_child, list_entry_hash);
2539883b1f31SPierre Schweitzer
2540883b1f31SPierre Schweitzer if (dc->hash == dc_hash && dc->name.Length == fpus->Length && RtlCompareMemory(dc->name.Buffer, fpus->Buffer, fpus->Length) == fpus->Length) {
2541883b1f31SPierre Schweitzer existing_fileref = dc->fileref;
2542883b1f31SPierre Schweitzer break;
2543883b1f31SPierre Schweitzer } else if (dc->hash > dc_hash)
2544883b1f31SPierre Schweitzer break;
2545883b1f31SPierre Schweitzer
2546883b1f31SPierre Schweitzer le = le->Flink;
2547883b1f31SPierre Schweitzer }
2548883b1f31SPierre Schweitzer }
2549883b1f31SPierre Schweitzer } else {
2550883b1f31SPierre Schweitzer UNICODE_STRING fpusuc;
2551883b1f31SPierre Schweitzer
2552318da0c1SPierre Schweitzer Status = RtlUpcaseUnicodeString(&fpusuc, fpus, true);
2553883b1f31SPierre Schweitzer if (!NT_SUCCESS(Status)) {
2554883b1f31SPierre Schweitzer ExReleaseResourceLite(&parfileref->fcb->nonpaged->dir_children_lock);
2555194ea909SVictor Perevertkin ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
2556883b1f31SPierre Schweitzer reap_fileref(Vcb, fileref);
2557883b1f31SPierre Schweitzer
2558318da0c1SPierre Schweitzer ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2559883b1f31SPierre Schweitzer parfileref->fcb->inode_item.st_size -= utf8len * 2;
2560883b1f31SPierre Schweitzer ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2561c2c66affSColin Finck
2562c2c66affSColin Finck ExFreePool(utf8);
2563c2c66affSColin Finck
2564883b1f31SPierre Schweitzer return Status;
2565883b1f31SPierre Schweitzer }
2566883b1f31SPierre Schweitzer
256762e630deSPierre Schweitzer uint32_t dc_hash = calc_crc32c(0xffffffff, (uint8_t*)fpusuc.Buffer, fpusuc.Length);
2568883b1f31SPierre Schweitzer
2569883b1f31SPierre Schweitzer if (parfileref->fcb->hash_ptrs_uc[dc_hash >> 24]) {
2570883b1f31SPierre Schweitzer LIST_ENTRY* le = parfileref->fcb->hash_ptrs_uc[dc_hash >> 24];
2571883b1f31SPierre Schweitzer while (le != &parfileref->fcb->dir_children_hash_uc) {
2572318da0c1SPierre Schweitzer dc = CONTAINING_RECORD(le, dir_child, list_entry_hash_uc);
2573883b1f31SPierre Schweitzer
2574883b1f31SPierre Schweitzer if (dc->hash_uc == dc_hash && dc->name.Length == fpusuc.Length && RtlCompareMemory(dc->name.Buffer, fpusuc.Buffer, fpusuc.Length) == fpusuc.Length) {
2575883b1f31SPierre Schweitzer existing_fileref = dc->fileref;
2576883b1f31SPierre Schweitzer break;
2577883b1f31SPierre Schweitzer } else if (dc->hash_uc > dc_hash)
2578883b1f31SPierre Schweitzer break;
2579883b1f31SPierre Schweitzer
2580883b1f31SPierre Schweitzer le = le->Flink;
2581883b1f31SPierre Schweitzer }
2582883b1f31SPierre Schweitzer }
2583883b1f31SPierre Schweitzer
2584883b1f31SPierre Schweitzer ExFreePool(fpusuc.Buffer);
2585883b1f31SPierre Schweitzer }
2586883b1f31SPierre Schweitzer
2587883b1f31SPierre Schweitzer if (existing_fileref) {
2588883b1f31SPierre Schweitzer ExReleaseResourceLite(&parfileref->fcb->nonpaged->dir_children_lock);
2589883b1f31SPierre Schweitzer reap_fileref(Vcb, fileref);
2590883b1f31SPierre Schweitzer
2591318da0c1SPierre Schweitzer ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2592883b1f31SPierre Schweitzer parfileref->fcb->inode_item.st_size -= utf8len * 2;
2593883b1f31SPierre Schweitzer ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2594883b1f31SPierre Schweitzer
2595883b1f31SPierre Schweitzer ExFreePool(utf8);
2596883b1f31SPierre Schweitzer
2597883b1f31SPierre Schweitzer increase_fileref_refcount(existing_fileref);
2598883b1f31SPierre Schweitzer *pfr = existing_fileref;
2599883b1f31SPierre Schweitzer
2600883b1f31SPierre Schweitzer return STATUS_OBJECT_NAME_COLLISION;
2601883b1f31SPierre Schweitzer }
2602883b1f31SPierre Schweitzer
2603318da0c1SPierre Schweitzer Status = add_dir_child(parfileref->fcb, fcb->inode, false, &utf8as, fpus, fcb->type, &dc);
2604883b1f31SPierre Schweitzer if (!NT_SUCCESS(Status)) {
2605883b1f31SPierre Schweitzer ExReleaseResourceLite(&parfileref->fcb->nonpaged->dir_children_lock);
2606194ea909SVictor Perevertkin ERR("add_dir_child returned %08lx\n", Status);
2607883b1f31SPierre Schweitzer reap_fileref(Vcb, fileref);
2608883b1f31SPierre Schweitzer
2609318da0c1SPierre Schweitzer ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2610883b1f31SPierre Schweitzer parfileref->fcb->inode_item.st_size -= utf8len * 2;
2611883b1f31SPierre Schweitzer ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2612883b1f31SPierre Schweitzer
2613883b1f31SPierre Schweitzer ExFreePool(utf8);
2614883b1f31SPierre Schweitzer
2615883b1f31SPierre Schweitzer return Status;
2616883b1f31SPierre Schweitzer }
2617883b1f31SPierre Schweitzer
2618883b1f31SPierre Schweitzer fileref->parent = parfileref;
2619c2c66affSColin Finck fileref->dc = dc;
2620c2c66affSColin Finck dc->fileref = fileref;
2621c2c66affSColin Finck
2622c2c66affSColin Finck if (type == BTRFS_TYPE_DIRECTORY)
2623c2c66affSColin Finck fileref->fcb->fileref = fileref;
2624c2c66affSColin Finck
2625883b1f31SPierre Schweitzer InsertTailList(&parfileref->children, &fileref->list_entry);
2626883b1f31SPierre Schweitzer ExReleaseResourceLite(&parfileref->fcb->nonpaged->dir_children_lock);
2627883b1f31SPierre Schweitzer
2628883b1f31SPierre Schweitzer ExFreePool(utf8);
2629883b1f31SPierre Schweitzer
2630883b1f31SPierre Schweitzer mark_fileref_dirty(fileref);
2631883b1f31SPierre Schweitzer increase_fileref_refcount(parfileref);
2632883b1f31SPierre Schweitzer
2633883b1f31SPierre Schweitzer *pfr = fileref;
2634883b1f31SPierre Schweitzer
263562e630deSPierre Schweitzer TRACE("created new file in subvol %I64x, inode %I64x\n", fcb->subvol->id, fcb->inode);
2636c2c66affSColin Finck
2637c2c66affSColin Finck return STATUS_SUCCESS;
2638c2c66affSColin Finck }
2639c2c66affSColin Finck
2640c2c66affSColin Finck static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension* Vcb,
2641c2c66affSColin Finck file_ref** pfileref, file_ref** pparfileref, PUNICODE_STRING fpus, PUNICODE_STRING stream, PIRP Irp,
2642318da0c1SPierre Schweitzer ULONG options, POOL_TYPE pool_type, bool case_sensitive, LIST_ENTRY* rollback) {
2643c2c66affSColin Finck PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
2644c2c66affSColin Finck file_ref *fileref, *newpar, *parfileref;
2645c2c66affSColin Finck fcb* fcb;
2646eb7fbc25SPierre Schweitzer static const char xapref[] = "user.";
2647eb7fbc25SPierre Schweitzer static const WCHAR DOSATTRIB[] = L"DOSATTRIB";
2648eb7fbc25SPierre Schweitzer static const WCHAR EA[] = L"EA";
2649eb7fbc25SPierre Schweitzer static const WCHAR reparse[] = L"reparse";
2650f381137cSPierre Schweitzer static const WCHAR casesensitive_str[] = L"casesensitive";
2651c2c66affSColin Finck LARGE_INTEGER time;
2652c2c66affSColin Finck BTRFS_TIME now;
2653c2c66affSColin Finck ULONG utf8len, overhead;
2654c2c66affSColin Finck NTSTATUS Status;
2655c2c66affSColin Finck KEY searchkey;
2656c2c66affSColin Finck traverse_ptr tp;
2657c2c66affSColin Finck dir_child* dc;
2658883b1f31SPierre Schweitzer dir_child* existing_dc = NULL;
2659c2c66affSColin Finck ACCESS_MASK granted_access;
2660c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
2661c2c66affSColin Finck LONG rc;
2662c2c66affSColin Finck #endif
2663c2c66affSColin Finck
2664194ea909SVictor Perevertkin TRACE("fpus = %.*S\n", (int)(fpus->Length / sizeof(WCHAR)), fpus->Buffer);
2665194ea909SVictor Perevertkin TRACE("stream = %.*S\n", (int)(stream->Length / sizeof(WCHAR)), stream->Buffer);
2666c2c66affSColin Finck
2667c2c66affSColin Finck parfileref = *pparfileref;
2668c2c66affSColin Finck
2669c2c66affSColin Finck if (parfileref->fcb == Vcb->dummy_fcb)
2670c2c66affSColin Finck return STATUS_ACCESS_DENIED;
2671c2c66affSColin Finck
26726e0cf03dSVincent Franchomme Status = check_file_name_valid(stream, false, true);
26736e0cf03dSVincent Franchomme if (!NT_SUCCESS(Status))
26746e0cf03dSVincent Franchomme return Status;
26756e0cf03dSVincent Franchomme
2676318da0c1SPierre Schweitzer Status = open_fileref(Vcb, &newpar, fpus, parfileref, false, NULL, NULL, PagedPool, case_sensitive, Irp);
2677c2c66affSColin Finck
2678c2c66affSColin Finck if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
2679c2c66affSColin Finck UNICODE_STRING fpus2;
2680c2c66affSColin Finck
26816e0cf03dSVincent Franchomme Status = check_file_name_valid(fpus, false, false);
2682c982533eSVincent Franchomme if (!NT_SUCCESS(Status))
2683c982533eSVincent Franchomme return Status;
2684c2c66affSColin Finck
2685c2c66affSColin Finck fpus2.Length = fpus2.MaximumLength = fpus->Length;
2686c2c66affSColin Finck fpus2.Buffer = ExAllocatePoolWithTag(pool_type, fpus2.MaximumLength, ALLOC_TAG);
2687c2c66affSColin Finck
2688c2c66affSColin Finck if (!fpus2.Buffer) {
2689c2c66affSColin Finck ERR("out of memory\n");
2690c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
2691c2c66affSColin Finck }
2692c2c66affSColin Finck
2693c2c66affSColin Finck RtlCopyMemory(fpus2.Buffer, fpus->Buffer, fpus2.Length);
2694c2c66affSColin Finck
2695c2c66affSColin Finck SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2696c2c66affSColin Finck
2697c2c66affSColin Finck if (!SeAccessCheck(parfileref->fcb->sd, &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
2698318da0c1SPierre Schweitzer true, options & FILE_DIRECTORY_FILE ? FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE, 0, NULL,
2699c2c66affSColin Finck IoGetFileObjectGenericMapping(), IrpSp->Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode,
2700c2c66affSColin Finck &granted_access, &Status)) {
2701c2c66affSColin Finck SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2702c2c66affSColin Finck return Status;
2703c2c66affSColin Finck }
2704c2c66affSColin Finck
2705c2c66affSColin Finck SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2706c2c66affSColin Finck
2707883b1f31SPierre Schweitzer Status = file_create2(Irp, Vcb, &fpus2, parfileref, options, NULL, 0, &newpar, case_sensitive, rollback);
2708c2c66affSColin Finck
2709c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
2710194ea909SVictor Perevertkin ERR("file_create2 returned %08lx\n", Status);
2711c2c66affSColin Finck ExFreePool(fpus2.Buffer);
2712c2c66affSColin Finck return Status;
2713883b1f31SPierre Schweitzer } else if (Status != STATUS_OBJECT_NAME_COLLISION) {
2714c2c66affSColin Finck send_notification_fileref(newpar, options & FILE_DIRECTORY_FILE ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, NULL);
271562e630deSPierre Schweitzer queue_notification_fcb(newpar->parent, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL);
2716883b1f31SPierre Schweitzer }
2717883b1f31SPierre Schweitzer
2718883b1f31SPierre Schweitzer ExFreePool(fpus2.Buffer);
2719c2c66affSColin Finck } else if (!NT_SUCCESS(Status)) {
2720194ea909SVictor Perevertkin ERR("open_fileref returned %08lx\n", Status);
2721c2c66affSColin Finck return Status;
2722c2c66affSColin Finck }
2723c2c66affSColin Finck
2724c2c66affSColin Finck parfileref = newpar;
2725c2c66affSColin Finck *pparfileref = parfileref;
2726c2c66affSColin Finck
2727c2c66affSColin Finck if (parfileref->fcb->type != BTRFS_TYPE_FILE && parfileref->fcb->type != BTRFS_TYPE_SYMLINK && parfileref->fcb->type != BTRFS_TYPE_DIRECTORY) {
2728c2c66affSColin Finck WARN("parent not file, directory, or symlink\n");
2729883b1f31SPierre Schweitzer free_fileref(parfileref);
2730c2c66affSColin Finck return STATUS_INVALID_PARAMETER;
2731c2c66affSColin Finck }
2732c2c66affSColin Finck
2733c2c66affSColin Finck if (options & FILE_DIRECTORY_FILE) {
2734c2c66affSColin Finck WARN("tried to create directory as stream\n");
2735883b1f31SPierre Schweitzer free_fileref(parfileref);
2736c2c66affSColin Finck return STATUS_INVALID_PARAMETER;
2737c2c66affSColin Finck }
2738c2c66affSColin Finck
2739174dfab6SVincent Franchomme if (parfileref->fcb->atts & FILE_ATTRIBUTE_READONLY && !(IrpSp->Flags & SL_IGNORE_READONLY_ATTRIBUTE)) {
2740883b1f31SPierre Schweitzer free_fileref(parfileref);
2741c2c66affSColin Finck return STATUS_ACCESS_DENIED;
2742883b1f31SPierre Schweitzer }
2743c2c66affSColin Finck
2744c2c66affSColin Finck SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2745c2c66affSColin Finck
2746c2c66affSColin Finck if (!SeAccessCheck(parfileref->fcb->sd, &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
2747318da0c1SPierre Schweitzer true, FILE_WRITE_DATA, 0, NULL, IoGetFileObjectGenericMapping(), IrpSp->Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode,
2748c2c66affSColin Finck &granted_access, &Status)) {
2749c2c66affSColin Finck SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2750883b1f31SPierre Schweitzer free_fileref(parfileref);
2751c2c66affSColin Finck return Status;
2752c2c66affSColin Finck }
2753c2c66affSColin Finck
2754c2c66affSColin Finck SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2755c2c66affSColin Finck
2756eb7fbc25SPierre Schweitzer if ((stream->Length == sizeof(DOSATTRIB) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, DOSATTRIB, stream->Length) == stream->Length) ||
2757eb7fbc25SPierre Schweitzer (stream->Length == sizeof(EA) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, EA, stream->Length) == stream->Length) ||
2758f381137cSPierre Schweitzer (stream->Length == sizeof(reparse) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, reparse, stream->Length) == stream->Length) ||
2759f381137cSPierre Schweitzer (stream->Length == sizeof(casesensitive_str) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, casesensitive_str, stream->Length) == stream->Length)) {
2760883b1f31SPierre Schweitzer free_fileref(parfileref);
2761c2c66affSColin Finck return STATUS_OBJECT_NAME_INVALID;
2762c2c66affSColin Finck }
2763c2c66affSColin Finck
2764c2c66affSColin Finck fcb = create_fcb(Vcb, pool_type);
2765c2c66affSColin Finck if (!fcb) {
2766c2c66affSColin Finck ERR("out of memory\n");
2767883b1f31SPierre Schweitzer free_fileref(parfileref);
2768c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
2769c2c66affSColin Finck }
2770c2c66affSColin Finck
2771c2c66affSColin Finck fcb->Vcb = Vcb;
2772c2c66affSColin Finck
2773c2c66affSColin Finck fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
2774c2c66affSColin Finck fcb->Header.AllocationSize.QuadPart = 0;
2775c2c66affSColin Finck fcb->Header.FileSize.QuadPart = 0;
2776c2c66affSColin Finck fcb->Header.ValidDataLength.QuadPart = 0;
2777c2c66affSColin Finck
2778c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
2779c2c66affSColin Finck rc = InterlockedIncrement(&parfileref->fcb->refcount);
278062e630deSPierre Schweitzer WARN("fcb %p: refcount now %i\n", parfileref->fcb, rc);
2781c2c66affSColin Finck #else
2782c2c66affSColin Finck InterlockedIncrement(&parfileref->fcb->refcount);
2783c2c66affSColin Finck #endif
2784c2c66affSColin Finck fcb->subvol = parfileref->fcb->subvol;
2785c2c66affSColin Finck fcb->inode = parfileref->fcb->inode;
2786c982533eSVincent Franchomme fcb->hash = parfileref->fcb->hash;
2787c2c66affSColin Finck fcb->type = parfileref->fcb->type;
2788c2c66affSColin Finck
2789318da0c1SPierre Schweitzer fcb->ads = true;
2790c2c66affSColin Finck
2791318da0c1SPierre Schweitzer Status = utf16_to_utf8(NULL, 0, &utf8len, stream->Buffer, stream->Length);
2792c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
2793194ea909SVictor Perevertkin ERR("utf16_to_utf8 1 returned %08lx\n", Status);
2794883b1f31SPierre Schweitzer reap_fcb(fcb);
2795883b1f31SPierre Schweitzer free_fileref(parfileref);
2796c2c66affSColin Finck return Status;
2797c2c66affSColin Finck }
2798c2c66affSColin Finck
2799318da0c1SPierre Schweitzer fcb->adsxattr.Length = (uint16_t)utf8len + sizeof(xapref) - 1;
2800c2c66affSColin Finck fcb->adsxattr.MaximumLength = fcb->adsxattr.Length + 1;
2801c2c66affSColin Finck fcb->adsxattr.Buffer = ExAllocatePoolWithTag(pool_type, fcb->adsxattr.MaximumLength, ALLOC_TAG);
2802c2c66affSColin Finck if (!fcb->adsxattr.Buffer) {
2803c2c66affSColin Finck ERR("out of memory\n");
2804883b1f31SPierre Schweitzer reap_fcb(fcb);
2805883b1f31SPierre Schweitzer free_fileref(parfileref);
2806c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
2807c2c66affSColin Finck }
2808c2c66affSColin Finck
2809eb7fbc25SPierre Schweitzer RtlCopyMemory(fcb->adsxattr.Buffer, xapref, sizeof(xapref) - 1);
2810c2c66affSColin Finck
2811318da0c1SPierre Schweitzer Status = utf16_to_utf8(&fcb->adsxattr.Buffer[sizeof(xapref) - 1], utf8len, &utf8len, stream->Buffer, stream->Length);
2812c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
2813194ea909SVictor Perevertkin ERR("utf16_to_utf8 2 returned %08lx\n", Status);
2814883b1f31SPierre Schweitzer reap_fcb(fcb);
2815883b1f31SPierre Schweitzer free_fileref(parfileref);
2816c2c66affSColin Finck return Status;
2817c2c66affSColin Finck }
2818c2c66affSColin Finck
2819c2c66affSColin Finck fcb->adsxattr.Buffer[fcb->adsxattr.Length] = 0;
2820c2c66affSColin Finck
2821c2c66affSColin Finck TRACE("adsxattr = %s\n", fcb->adsxattr.Buffer);
2822c2c66affSColin Finck
2823318da0c1SPierre Schweitzer fcb->adshash = calc_crc32c(0xfffffffe, (uint8_t*)fcb->adsxattr.Buffer, fcb->adsxattr.Length);
2824c2c66affSColin Finck TRACE("adshash = %08x\n", fcb->adshash);
2825c2c66affSColin Finck
2826c2c66affSColin Finck searchkey.obj_id = parfileref->fcb->inode;
2827c2c66affSColin Finck searchkey.obj_type = TYPE_XATTR_ITEM;
2828c2c66affSColin Finck searchkey.offset = fcb->adshash;
2829c2c66affSColin Finck
2830318da0c1SPierre Schweitzer Status = find_item(Vcb, parfileref->fcb->subvol, &tp, &searchkey, false, Irp);
2831c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
2832194ea909SVictor Perevertkin ERR("find_item returned %08lx\n", Status);
2833883b1f31SPierre Schweitzer reap_fcb(fcb);
2834883b1f31SPierre Schweitzer free_fileref(parfileref);
2835c2c66affSColin Finck return Status;
2836c2c66affSColin Finck }
2837c2c66affSColin Finck
2838c2c66affSColin Finck if (!keycmp(tp.item->key, searchkey))
2839c2c66affSColin Finck overhead = tp.item->size;
2840c2c66affSColin Finck else
2841c2c66affSColin Finck overhead = 0;
2842c2c66affSColin Finck
2843c2c66affSColin Finck fcb->adsmaxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - (sizeof(DIR_ITEM) - 1);
2844c2c66affSColin Finck
2845eb7fbc25SPierre Schweitzer if (utf8len + sizeof(xapref) - 1 + overhead > fcb->adsmaxlen) {
2846*29d19382SJohannes Obermayr WARN("not enough room for new DIR_ITEM (%Iu + %lu > %lu)\n", utf8len + sizeof(xapref) - 1, overhead, fcb->adsmaxlen);
2847883b1f31SPierre Schweitzer reap_fcb(fcb);
2848883b1f31SPierre Schweitzer free_fileref(parfileref);
2849c2c66affSColin Finck return STATUS_DISK_FULL;
2850c2c66affSColin Finck } else
2851eb7fbc25SPierre Schweitzer fcb->adsmaxlen -= overhead + utf8len + sizeof(xapref) - 1;
2852c2c66affSColin Finck
2853318da0c1SPierre Schweitzer fcb->created = true;
2854318da0c1SPierre Schweitzer fcb->deleted = true;
2855883b1f31SPierre Schweitzer
2856883b1f31SPierre Schweitzer acquire_fcb_lock_exclusive(Vcb);
2857883b1f31SPierre Schweitzer InsertHeadList(&parfileref->fcb->list_entry, &fcb->list_entry); // insert in list after parent fcb
2858883b1f31SPierre Schweitzer InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
2859883b1f31SPierre Schweitzer parfileref->fcb->subvol->fcbs_version++;
2860883b1f31SPierre Schweitzer release_fcb_lock(Vcb);
2861883b1f31SPierre Schweitzer
2862883b1f31SPierre Schweitzer mark_fcb_dirty(fcb);
2863883b1f31SPierre Schweitzer
2864c2c66affSColin Finck fileref = create_fileref(Vcb);
2865c2c66affSColin Finck if (!fileref) {
2866c2c66affSColin Finck ERR("out of memory\n");
2867883b1f31SPierre Schweitzer free_fcb(fcb);
2868883b1f31SPierre Schweitzer free_fileref(parfileref);
2869c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
2870c2c66affSColin Finck }
2871c2c66affSColin Finck
2872c2c66affSColin Finck fileref->fcb = fcb;
2873c2c66affSColin Finck
2874c2c66affSColin Finck dc = ExAllocatePoolWithTag(PagedPool, sizeof(dir_child), ALLOC_TAG);
2875c2c66affSColin Finck if (!dc) {
2876c2c66affSColin Finck ERR("out of memory\n");
2877883b1f31SPierre Schweitzer reap_fileref(Vcb, fileref);
2878883b1f31SPierre Schweitzer free_fileref(parfileref);
2879c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
2880c2c66affSColin Finck }
2881c2c66affSColin Finck
2882c2c66affSColin Finck RtlZeroMemory(dc, sizeof(dir_child));
2883c2c66affSColin Finck
2884eb7fbc25SPierre Schweitzer dc->utf8.MaximumLength = dc->utf8.Length = fcb->adsxattr.Length + 1 - sizeof(xapref);
2885c2c66affSColin Finck dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, dc->utf8.MaximumLength, ALLOC_TAG);
2886c2c66affSColin Finck if (!dc->utf8.Buffer) {
2887c2c66affSColin Finck ERR("out of memory\n");
2888c2c66affSColin Finck ExFreePool(dc);
2889883b1f31SPierre Schweitzer reap_fileref(Vcb, fileref);
2890883b1f31SPierre Schweitzer free_fileref(parfileref);
2891c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
2892c2c66affSColin Finck }
2893c2c66affSColin Finck
2894eb7fbc25SPierre Schweitzer RtlCopyMemory(dc->utf8.Buffer, &fcb->adsxattr.Buffer[sizeof(xapref) - 1], fcb->adsxattr.Length + 1 - sizeof(xapref));
2895c2c66affSColin Finck
2896c2c66affSColin Finck dc->name.MaximumLength = dc->name.Length = stream->Length;
2897c2c66affSColin Finck dc->name.Buffer = ExAllocatePoolWithTag(pool_type, dc->name.MaximumLength, ALLOC_TAG);
2898c2c66affSColin Finck if (!dc->name.Buffer) {
2899c2c66affSColin Finck ERR("out of memory\n");
2900c2c66affSColin Finck ExFreePool(dc->utf8.Buffer);
2901c2c66affSColin Finck ExFreePool(dc);
2902883b1f31SPierre Schweitzer reap_fileref(Vcb, fileref);
2903883b1f31SPierre Schweitzer free_fileref(parfileref);
2904c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
2905c2c66affSColin Finck }
2906c2c66affSColin Finck
2907c2c66affSColin Finck RtlCopyMemory(dc->name.Buffer, stream->Buffer, stream->Length);
2908c2c66affSColin Finck
2909318da0c1SPierre Schweitzer Status = RtlUpcaseUnicodeString(&dc->name_uc, &dc->name, true);
2910c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
2911194ea909SVictor Perevertkin ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
2912c2c66affSColin Finck ExFreePool(dc->utf8.Buffer);
2913c2c66affSColin Finck ExFreePool(dc->name.Buffer);
2914c2c66affSColin Finck ExFreePool(dc);
2915883b1f31SPierre Schweitzer reap_fileref(Vcb, fileref);
2916883b1f31SPierre Schweitzer free_fileref(parfileref);
2917c2c66affSColin Finck return Status;
2918c2c66affSColin Finck }
2919c2c66affSColin Finck
2920883b1f31SPierre Schweitzer KeQuerySystemTime(&time);
2921883b1f31SPierre Schweitzer win_time_to_unix(time, &now);
2922883b1f31SPierre Schweitzer
2923318da0c1SPierre Schweitzer ExAcquireResourceExclusiveLite(&parfileref->fcb->nonpaged->dir_children_lock, true);
2924883b1f31SPierre Schweitzer
2925883b1f31SPierre Schweitzer LIST_ENTRY* le = parfileref->fcb->dir_children_index.Flink;
2926883b1f31SPierre Schweitzer while (le != &parfileref->fcb->dir_children_index) {
2927883b1f31SPierre Schweitzer dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_index);
2928883b1f31SPierre Schweitzer
2929883b1f31SPierre Schweitzer if (dc2->index == 0) {
2930883b1f31SPierre Schweitzer if ((case_sensitive && dc2->name.Length == dc->name.Length && RtlCompareMemory(dc2->name.Buffer, dc->name.Buffer, dc2->name.Length) == dc2->name.Length) ||
2931883b1f31SPierre Schweitzer (!case_sensitive && dc2->name_uc.Length == dc->name_uc.Length && RtlCompareMemory(dc2->name_uc.Buffer, dc->name_uc.Buffer, dc2->name_uc.Length) == dc2->name_uc.Length)
2932883b1f31SPierre Schweitzer ) {
2933883b1f31SPierre Schweitzer existing_dc = dc2;
2934883b1f31SPierre Schweitzer break;
2935883b1f31SPierre Schweitzer }
2936883b1f31SPierre Schweitzer } else
2937883b1f31SPierre Schweitzer break;
2938883b1f31SPierre Schweitzer
2939883b1f31SPierre Schweitzer le = le->Flink;
2940883b1f31SPierre Schweitzer }
2941883b1f31SPierre Schweitzer
2942883b1f31SPierre Schweitzer if (existing_dc) {
2943883b1f31SPierre Schweitzer ExFreePool(dc->utf8.Buffer);
2944883b1f31SPierre Schweitzer ExFreePool(dc->name.Buffer);
2945883b1f31SPierre Schweitzer ExFreePool(dc);
2946883b1f31SPierre Schweitzer reap_fileref(Vcb, fileref);
2947883b1f31SPierre Schweitzer free_fileref(parfileref);
2948883b1f31SPierre Schweitzer
2949883b1f31SPierre Schweitzer increase_fileref_refcount(existing_dc->fileref);
2950883b1f31SPierre Schweitzer *pfileref = existing_dc->fileref;
2951883b1f31SPierre Schweitzer
2952883b1f31SPierre Schweitzer return STATUS_OBJECT_NAME_COLLISION;
2953883b1f31SPierre Schweitzer }
2954883b1f31SPierre Schweitzer
2955c2c66affSColin Finck dc->fileref = fileref;
2956c2c66affSColin Finck fileref->dc = dc;
2957883b1f31SPierre Schweitzer fileref->parent = (struct _file_ref*)parfileref;
2958318da0c1SPierre Schweitzer fcb->deleted = false;
2959c2c66affSColin Finck
2960c2c66affSColin Finck InsertHeadList(&parfileref->fcb->dir_children_index, &dc->list_entry_index);
2961c2c66affSColin Finck
2962883b1f31SPierre Schweitzer InsertTailList(&parfileref->children, &fileref->list_entry);
2963883b1f31SPierre Schweitzer
2964883b1f31SPierre Schweitzer ExReleaseResourceLite(&parfileref->fcb->nonpaged->dir_children_lock);
2965883b1f31SPierre Schweitzer
2966c2c66affSColin Finck mark_fileref_dirty(fileref);
2967c2c66affSColin Finck
2968c2c66affSColin Finck parfileref->fcb->inode_item.transid = Vcb->superblock.generation;
2969c2c66affSColin Finck parfileref->fcb->inode_item.sequence++;
2970c2c66affSColin Finck parfileref->fcb->inode_item.st_ctime = now;
2971318da0c1SPierre Schweitzer parfileref->fcb->inode_item_changed = true;
2972c2c66affSColin Finck
2973c2c66affSColin Finck mark_fcb_dirty(parfileref->fcb);
2974c2c66affSColin Finck
2975c2c66affSColin Finck parfileref->fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
2976c2c66affSColin Finck parfileref->fcb->subvol->root_item.ctime = now;
2977c2c66affSColin Finck
2978c2c66affSColin Finck increase_fileref_refcount(parfileref);
2979c2c66affSColin Finck
2980c2c66affSColin Finck *pfileref = fileref;
2981c2c66affSColin Finck
29824672b2baSPierre Schweitzer send_notification_fileref(parfileref, FILE_NOTIFY_CHANGE_STREAM_NAME, FILE_ACTION_ADDED_STREAM, &fileref->dc->name);
2983c2c66affSColin Finck
2984c2c66affSColin Finck return STATUS_SUCCESS;
2985c2c66affSColin Finck }
2986c2c66affSColin Finck
2987c2c66affSColin Finck // LXSS programs can be distinguished by the fact they have a NULL PEB.
2988c2c66affSColin Finck #ifdef _AMD64_
called_from_lxss()2989318da0c1SPierre Schweitzer static __inline bool called_from_lxss() {
2990c2c66affSColin Finck NTSTATUS Status;
2991c2c66affSColin Finck PROCESS_BASIC_INFORMATION pbi;
2992c2c66affSColin Finck ULONG retlen;
2993c2c66affSColin Finck
2994c2c66affSColin Finck Status = ZwQueryInformationProcess(NtCurrentProcess(), ProcessBasicInformation, &pbi, sizeof(pbi), &retlen);
2995c2c66affSColin Finck
2996c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
2997194ea909SVictor Perevertkin ERR("ZwQueryInformationProcess returned %08lx\n", Status);
2998318da0c1SPierre Schweitzer return false;
2999c2c66affSColin Finck }
3000c2c66affSColin Finck
3001c2c66affSColin Finck return !pbi.PebBaseAddress;
3002c2c66affSColin Finck }
3003c2c66affSColin Finck #else
3004318da0c1SPierre Schweitzer #define called_from_lxss() false
3005c2c66affSColin Finck #endif
3006c2c66affSColin Finck
3007c2c66affSColin Finck static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension* Vcb,
3008318da0c1SPierre Schweitzer PFILE_OBJECT FileObject, file_ref* related, bool loaded_related, PUNICODE_STRING fnus, ULONG disposition, ULONG options,
3009883b1f31SPierre Schweitzer file_ref** existing_fileref, LIST_ENTRY* rollback) {
3010c2c66affSColin Finck NTSTATUS Status;
3011c2c66affSColin Finck file_ref *fileref, *parfileref = NULL;
3012c2c66affSColin Finck ULONG i, j;
3013c2c66affSColin Finck ccb* ccb;
3014eb7fbc25SPierre Schweitzer static const WCHAR datasuf[] = {':','$','D','A','T','A',0};
3015c2c66affSColin Finck UNICODE_STRING dsus, fpus, stream;
3016c2c66affSColin Finck PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
3017c2c66affSColin Finck POOL_TYPE pool_type = IrpSp->Flags & SL_OPEN_PAGING_FILE ? NonPagedPool : PagedPool;
3018eb7fbc25SPierre Schweitzer ECP_LIST* ecp_list;
3019eb7fbc25SPierre Schweitzer ATOMIC_CREATE_ECP_CONTEXT* acec = NULL;
3020c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
3021c2c66affSColin Finck LONG oc;
3022c2c66affSColin Finck #endif
3023c2c66affSColin Finck
3024194ea909SVictor Perevertkin TRACE("(%p, %p, %p, %.*S, %lx, %lx)\n", Irp, Vcb, FileObject, (int)(fnus->Length / sizeof(WCHAR)), fnus->Buffer, disposition, options);
3025c2c66affSColin Finck
3026c2c66affSColin Finck if (Vcb->readonly)
3027c2c66affSColin Finck return STATUS_MEDIA_WRITE_PROTECTED;
3028c2c66affSColin Finck
3029174dfab6SVincent Franchomme if (options & FILE_DELETE_ON_CLOSE && IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_READONLY &&
3030174dfab6SVincent Franchomme !(IrpSp->Flags & SL_IGNORE_READONLY_ATTRIBUTE)) {
30314672b2baSPierre Schweitzer return STATUS_CANNOT_DELETE;
3032174dfab6SVincent Franchomme }
30334672b2baSPierre Schweitzer
3034318da0c1SPierre Schweitzer if (fFsRtlGetEcpListFromIrp && fFsRtlGetNextExtraCreateParameter) {
3035318da0c1SPierre Schweitzer if (NT_SUCCESS(fFsRtlGetEcpListFromIrp(Irp, &ecp_list)) && ecp_list) {
3036eb7fbc25SPierre Schweitzer void* ctx = NULL;
3037eb7fbc25SPierre Schweitzer GUID type;
3038eb7fbc25SPierre Schweitzer ULONG ctxsize;
3039eb7fbc25SPierre Schweitzer
3040eb7fbc25SPierre Schweitzer do {
3041318da0c1SPierre Schweitzer Status = fFsRtlGetNextExtraCreateParameter(ecp_list, ctx, &type, &ctx, &ctxsize);
3042eb7fbc25SPierre Schweitzer
3043eb7fbc25SPierre Schweitzer if (NT_SUCCESS(Status)) {
304462e630deSPierre Schweitzer if (RtlCompareMemory(&type, &GUID_ECP_ATOMIC_CREATE, sizeof(GUID)) == sizeof(GUID)) {
304562e630deSPierre Schweitzer if (ctxsize >= sizeof(ATOMIC_CREATE_ECP_CONTEXT))
3046eb7fbc25SPierre Schweitzer acec = ctx;
304762e630deSPierre Schweitzer else {
3048194ea909SVictor Perevertkin ERR("GUID_ECP_ATOMIC_CREATE context was too short: %lu bytes, expected %Iu\n", ctxsize,
304962e630deSPierre Schweitzer sizeof(ATOMIC_CREATE_ECP_CONTEXT));
305062e630deSPierre Schweitzer }
3051194ea909SVictor Perevertkin } else if (RtlCompareMemory(&type, &GUID_ECP_QUERY_ON_CREATE, sizeof(GUID)) == sizeof(GUID))
3052194ea909SVictor Perevertkin WARN("unhandled ECP GUID_ECP_QUERY_ON_CREATE\n");
3053194ea909SVictor Perevertkin else if (RtlCompareMemory(&type, &GUID_ECP_CREATE_REDIRECTION, sizeof(GUID)) == sizeof(GUID))
3054194ea909SVictor Perevertkin WARN("unhandled ECP GUID_ECP_CREATE_REDIRECTION\n");
3055194ea909SVictor Perevertkin else {
3056194ea909SVictor Perevertkin WARN("unhandled ECP {%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", type.Data1, type.Data2,
305762e630deSPierre Schweitzer type.Data3, type.Data4[0], type.Data4[1], type.Data4[2], type.Data4[3], type.Data4[4], type.Data4[5],
305862e630deSPierre Schweitzer type.Data4[6], type.Data4[7]);
3059eb7fbc25SPierre Schweitzer }
3060eb7fbc25SPierre Schweitzer }
3061eb7fbc25SPierre Schweitzer } while (NT_SUCCESS(Status));
3062eb7fbc25SPierre Schweitzer }
3063318da0c1SPierre Schweitzer }
3064eb7fbc25SPierre Schweitzer
3065eb7fbc25SPierre Schweitzer dsus.Buffer = (WCHAR*)datasuf;
3066eb7fbc25SPierre Schweitzer dsus.Length = dsus.MaximumLength = sizeof(datasuf) - sizeof(WCHAR);
3067c2c66affSColin Finck fpus.Buffer = NULL;
3068c2c66affSColin Finck
3069c2c66affSColin Finck if (!loaded_related) {
3070318da0c1SPierre Schweitzer Status = open_fileref(Vcb, &parfileref, fnus, related, true, NULL, NULL, pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp);
3071c2c66affSColin Finck
3072c2c66affSColin Finck if (!NT_SUCCESS(Status))
3073c2c66affSColin Finck goto end;
3074c2c66affSColin Finck } else
3075c2c66affSColin Finck parfileref = related;
3076c2c66affSColin Finck
3077c2c66affSColin Finck if (parfileref->fcb->type != BTRFS_TYPE_DIRECTORY && (fnus->Length < sizeof(WCHAR) || fnus->Buffer[0] != ':')) {
3078c2c66affSColin Finck Status = STATUS_OBJECT_PATH_NOT_FOUND;
3079c2c66affSColin Finck goto end;
3080c2c66affSColin Finck }
3081c2c66affSColin Finck
3082c2c66affSColin Finck if (is_subvol_readonly(parfileref->fcb->subvol, Irp)) {
3083c2c66affSColin Finck Status = STATUS_ACCESS_DENIED;
3084c2c66affSColin Finck goto end;
3085c2c66affSColin Finck }
3086c2c66affSColin Finck
3087c2c66affSColin Finck i = (fnus->Length / sizeof(WCHAR))-1;
3088c2c66affSColin Finck while ((fnus->Buffer[i] == '\\' || fnus->Buffer[i] == '/') && i > 0) { i--; }
3089c2c66affSColin Finck
3090c2c66affSColin Finck j = i;
3091c2c66affSColin Finck
3092c2c66affSColin Finck while (i > 0 && fnus->Buffer[i-1] != '\\' && fnus->Buffer[i-1] != '/') { i--; }
3093c2c66affSColin Finck
3094c2c66affSColin Finck fpus.MaximumLength = (USHORT)((j - i + 2) * sizeof(WCHAR));
3095c2c66affSColin Finck fpus.Buffer = ExAllocatePoolWithTag(pool_type, fpus.MaximumLength, ALLOC_TAG);
3096c2c66affSColin Finck if (!fpus.Buffer) {
3097c2c66affSColin Finck ERR("out of memory\n");
3098c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES;
3099c2c66affSColin Finck goto end;
3100c2c66affSColin Finck }
3101c2c66affSColin Finck
3102c2c66affSColin Finck fpus.Length = (USHORT)((j - i + 1) * sizeof(WCHAR));
3103c2c66affSColin Finck
3104c2c66affSColin Finck RtlCopyMemory(fpus.Buffer, &fnus->Buffer[i], (j - i + 1) * sizeof(WCHAR));
3105c2c66affSColin Finck fpus.Buffer[j - i + 1] = 0;
3106c2c66affSColin Finck
3107c2c66affSColin Finck if (fpus.Length > dsus.Length) { // check for :$DATA suffix
3108c2c66affSColin Finck UNICODE_STRING lb;
3109c2c66affSColin Finck
3110c2c66affSColin Finck lb.Buffer = &fpus.Buffer[(fpus.Length - dsus.Length)/sizeof(WCHAR)];
3111c2c66affSColin Finck lb.Length = lb.MaximumLength = dsus.Length;
3112c2c66affSColin Finck
3113194ea909SVictor Perevertkin TRACE("lb = %.*S\n", (int)(lb.Length/sizeof(WCHAR)), lb.Buffer);
3114c2c66affSColin Finck
3115318da0c1SPierre Schweitzer if (FsRtlAreNamesEqual(&dsus, &lb, true, NULL)) {
3116c2c66affSColin Finck TRACE("ignoring :$DATA suffix\n");
3117c2c66affSColin Finck
3118c2c66affSColin Finck fpus.Length -= lb.Length;
3119c2c66affSColin Finck
3120c2c66affSColin Finck if (fpus.Length > sizeof(WCHAR) && fpus.Buffer[(fpus.Length-1)/sizeof(WCHAR)] == ':')
3121c2c66affSColin Finck fpus.Length -= sizeof(WCHAR);
3122c2c66affSColin Finck
3123194ea909SVictor Perevertkin TRACE("fpus = %.*S\n", (int)(fpus.Length / sizeof(WCHAR)), fpus.Buffer);
3124c2c66affSColin Finck }
3125c2c66affSColin Finck }
3126c2c66affSColin Finck
3127c2c66affSColin Finck stream.Length = 0;
3128c2c66affSColin Finck
3129c2c66affSColin Finck for (i = 0; i < fpus.Length / sizeof(WCHAR); i++) {
3130c2c66affSColin Finck if (fpus.Buffer[i] == ':') {
3131c2c66affSColin Finck stream.Length = (USHORT)(fpus.Length - (i * sizeof(WCHAR)) - sizeof(WCHAR));
3132c2c66affSColin Finck stream.Buffer = &fpus.Buffer[i+1];
3133c2c66affSColin Finck fpus.Buffer[i] = 0;
3134c2c66affSColin Finck fpus.Length = (USHORT)(i * sizeof(WCHAR));
3135c2c66affSColin Finck break;
3136c2c66affSColin Finck }
3137c2c66affSColin Finck }
3138c2c66affSColin Finck
3139c2c66affSColin Finck if (stream.Length > 0) {
3140c2c66affSColin Finck Status = create_stream(Vcb, &fileref, &parfileref, &fpus, &stream, Irp, options, pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, rollback);
3141c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
3142194ea909SVictor Perevertkin ERR("create_stream returned %08lx\n", Status);
3143c2c66affSColin Finck goto end;
3144c2c66affSColin Finck }
3145c2c66affSColin Finck
3146c2c66affSColin Finck IoSetShareAccess(IrpSp->Parameters.Create.SecurityContext->DesiredAccess, IrpSp->Parameters.Create.ShareAccess,
3147c2c66affSColin Finck FileObject, &fileref->fcb->share_access);
3148c2c66affSColin Finck } else {
3149c2c66affSColin Finck ACCESS_MASK granted_access;
3150c2c66affSColin Finck
3151c982533eSVincent Franchomme Status = check_file_name_valid(&fpus, false, false);
3152c982533eSVincent Franchomme if (!NT_SUCCESS(Status))
3153c2c66affSColin Finck goto end;
3154c2c66affSColin Finck
3155c2c66affSColin Finck SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
3156c2c66affSColin Finck
3157c2c66affSColin Finck if (!SeAccessCheck(parfileref->fcb->sd, &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
3158318da0c1SPierre Schweitzer true, options & FILE_DIRECTORY_FILE ? FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE, 0, NULL,
3159c2c66affSColin Finck IoGetFileObjectGenericMapping(), IrpSp->Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode,
3160c2c66affSColin Finck &granted_access, &Status)) {
3161c2c66affSColin Finck SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
3162c2c66affSColin Finck goto end;
3163c2c66affSColin Finck }
3164c2c66affSColin Finck
3165c2c66affSColin Finck SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
3166c2c66affSColin Finck
3167c2c66affSColin Finck if (Irp->AssociatedIrp.SystemBuffer && IrpSp->Parameters.Create.EaLength > 0) {
3168c2c66affSColin Finck ULONG offset;
3169c2c66affSColin Finck
3170c2c66affSColin Finck Status = IoCheckEaBufferValidity(Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.Create.EaLength, &offset);
3171c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
3172194ea909SVictor Perevertkin ERR("IoCheckEaBufferValidity returned %08lx (error at offset %lu)\n", Status, offset);
3173c2c66affSColin Finck goto end;
3174c2c66affSColin Finck }
3175c2c66affSColin Finck }
3176c2c66affSColin Finck
3177c2c66affSColin Finck Status = file_create2(Irp, Vcb, &fpus, parfileref, options, Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.Create.EaLength,
3178883b1f31SPierre Schweitzer &fileref, IrpSp->Flags & SL_CASE_SENSITIVE, rollback);
3179c2c66affSColin Finck
3180883b1f31SPierre Schweitzer if (Status == STATUS_OBJECT_NAME_COLLISION) {
3181883b1f31SPierre Schweitzer *existing_fileref = fileref;
3182883b1f31SPierre Schweitzer goto end;
3183883b1f31SPierre Schweitzer } else if (!NT_SUCCESS(Status)) {
3184194ea909SVictor Perevertkin ERR("file_create2 returned %08lx\n", Status);
3185c2c66affSColin Finck goto end;
3186c2c66affSColin Finck }
3187c2c66affSColin Finck
3188c2c66affSColin Finck IoSetShareAccess(IrpSp->Parameters.Create.SecurityContext->DesiredAccess, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access);
3189c2c66affSColin Finck
3190c2c66affSColin Finck send_notification_fileref(fileref, options & FILE_DIRECTORY_FILE ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_ADDED, NULL);
319162e630deSPierre Schweitzer queue_notification_fcb(fileref->parent, FILE_NOTIFY_CHANGE_LAST_WRITE, FILE_ACTION_MODIFIED, NULL);
3192c2c66affSColin Finck }
3193c2c66affSColin Finck
3194c2c66affSColin Finck FileObject->FsContext = fileref->fcb;
3195c2c66affSColin Finck
3196c2c66affSColin Finck ccb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ccb), ALLOC_TAG);
3197c2c66affSColin Finck if (!ccb) {
3198c2c66affSColin Finck ERR("out of memory\n");
3199c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES;
3200318da0c1SPierre Schweitzer fileref->deleted = true;
3201318da0c1SPierre Schweitzer fileref->fcb->deleted = true;
3202eb7fbc25SPierre Schweitzer
3203eb7fbc25SPierre Schweitzer if (stream.Length == 0) {
3204318da0c1SPierre Schweitzer ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
3205eb7fbc25SPierre Schweitzer parfileref->fcb->inode_item.st_size -= fileref->dc->utf8.Length * 2;
3206eb7fbc25SPierre Schweitzer ExReleaseResourceLite(parfileref->fcb->Header.Resource);
3207eb7fbc25SPierre Schweitzer }
3208eb7fbc25SPierre Schweitzer
3209883b1f31SPierre Schweitzer free_fileref(fileref);
3210c2c66affSColin Finck goto end;
3211c2c66affSColin Finck }
3212c2c66affSColin Finck
3213c2c66affSColin Finck RtlZeroMemory(ccb, sizeof(*ccb));
3214c2c66affSColin Finck
3215c2c66affSColin Finck ccb->fileref = fileref;
3216c2c66affSColin Finck
3217c2c66affSColin Finck ccb->NodeType = BTRFS_NODE_TYPE_CCB;
3218c2c66affSColin Finck ccb->NodeSize = sizeof(*ccb);
3219c2c66affSColin Finck ccb->disposition = disposition;
3220c2c66affSColin Finck ccb->options = options;
3221c2c66affSColin Finck ccb->query_dir_offset = 0;
3222c2c66affSColin Finck RtlInitUnicodeString(&ccb->query_string, NULL);
3223318da0c1SPierre Schweitzer ccb->has_wildcard = false;
3224318da0c1SPierre Schweitzer ccb->specific_file = false;
3225c2c66affSColin Finck ccb->access = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
3226c2c66affSColin Finck ccb->case_sensitive = IrpSp->Flags & SL_CASE_SENSITIVE;
3227318da0c1SPierre Schweitzer ccb->reserving = false;
3228c2c66affSColin Finck ccb->lxss = called_from_lxss();
3229c2c66affSColin Finck
3230c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
3231c2c66affSColin Finck oc = InterlockedIncrement(&fileref->open_count);
3232c2c66affSColin Finck ERR("fileref %p: open_count now %i\n", fileref, oc);
3233c2c66affSColin Finck #else
3234c2c66affSColin Finck InterlockedIncrement(&fileref->open_count);
3235c2c66affSColin Finck #endif
3236c2c66affSColin Finck InterlockedIncrement(&Vcb->open_files);
3237c2c66affSColin Finck
3238c2c66affSColin Finck FileObject->FsContext2 = ccb;
3239c2c66affSColin Finck
3240c2c66affSColin Finck FileObject->SectionObjectPointer = &fileref->fcb->nonpaged->segment_object;
3241c2c66affSColin Finck
3242eb7fbc25SPierre Schweitzer // FIXME - ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT
3243eb7fbc25SPierre Schweitzer if (acec && acec->InFlags & ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED) {
3244318da0c1SPierre Schweitzer if (acec->ReparseBufferLength > sizeof(uint32_t) && *(uint32_t*)acec->ReparseBuffer == IO_REPARSE_TAG_SYMLINK) {
3245eb7fbc25SPierre Schweitzer fileref->fcb->inode_item.st_mode &= ~(__S_IFIFO | __S_IFCHR | __S_IFBLK | __S_IFSOCK);
3246eb7fbc25SPierre Schweitzer fileref->fcb->type = BTRFS_TYPE_FILE;
3247174dfab6SVincent Franchomme fileref->fcb->atts &= ~FILE_ATTRIBUTE_DIRECTORY;
3248eb7fbc25SPierre Schweitzer }
3249eb7fbc25SPierre Schweitzer
3250eb7fbc25SPierre Schweitzer if (fileref->fcb->type == BTRFS_TYPE_SOCKET || fileref->fcb->type == BTRFS_TYPE_FIFO ||
3251eb7fbc25SPierre Schweitzer fileref->fcb->type == BTRFS_TYPE_CHARDEV || fileref->fcb->type == BTRFS_TYPE_BLOCKDEV) {
3252eb7fbc25SPierre Schweitzer // NOP. If called from LXSS, humour it - we hardcode the values elsewhere.
3253eb7fbc25SPierre Schweitzer } else {
3254eb7fbc25SPierre Schweitzer Status = set_reparse_point2(fileref->fcb, acec->ReparseBuffer, acec->ReparseBufferLength, NULL, NULL, Irp, rollback);
3255eb7fbc25SPierre Schweitzer if (!NT_SUCCESS(Status)) {
3256194ea909SVictor Perevertkin ERR("set_reparse_point2 returned %08lx\n", Status);
3257318da0c1SPierre Schweitzer fileref->deleted = true;
3258318da0c1SPierre Schweitzer fileref->fcb->deleted = true;
3259eb7fbc25SPierre Schweitzer
3260eb7fbc25SPierre Schweitzer if (stream.Length == 0) {
3261318da0c1SPierre Schweitzer ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
3262eb7fbc25SPierre Schweitzer parfileref->fcb->inode_item.st_size -= fileref->dc->utf8.Length * 2;
3263eb7fbc25SPierre Schweitzer ExReleaseResourceLite(parfileref->fcb->Header.Resource);
3264eb7fbc25SPierre Schweitzer }
3265eb7fbc25SPierre Schweitzer
3266883b1f31SPierre Schweitzer free_fileref(fileref);
3267eb7fbc25SPierre Schweitzer return Status;
3268eb7fbc25SPierre Schweitzer }
3269eb7fbc25SPierre Schweitzer }
3270eb7fbc25SPierre Schweitzer
3271eb7fbc25SPierre Schweitzer acec->OutFlags |= ATOMIC_CREATE_ECP_OUT_FLAG_REPARSE_POINT_SET;
3272eb7fbc25SPierre Schweitzer }
3273eb7fbc25SPierre Schweitzer
3274194ea909SVictor Perevertkin if (acec && acec->InFlags & ATOMIC_CREATE_ECP_IN_FLAG_OP_FLAGS_SPECIFIED) {
3275194ea909SVictor Perevertkin if (acec->InOpFlags & ATOMIC_CREATE_ECP_IN_OP_FLAG_CASE_SENSITIVE_FLAGS_SPECIFIED && fileref->fcb->atts & FILE_ATTRIBUTE_DIRECTORY) {
3276194ea909SVictor Perevertkin if ((acec->InCaseSensitiveFlags & acec->CaseSensitiveFlagsMask) & FILE_CS_FLAG_CASE_SENSITIVE_DIR) {
3277194ea909SVictor Perevertkin acec->OutCaseSensitiveFlags = FILE_CS_FLAG_CASE_SENSITIVE_DIR;
3278194ea909SVictor Perevertkin fileref->fcb->case_sensitive = true;
3279194ea909SVictor Perevertkin ccb->case_sensitive = true;
3280194ea909SVictor Perevertkin }
3281194ea909SVictor Perevertkin
3282194ea909SVictor Perevertkin acec->OutOpFlags |= ATOMIC_CREATE_ECP_OUT_OP_FLAG_CASE_SENSITIVE_FLAGS_SET;
3283194ea909SVictor Perevertkin }
3284194ea909SVictor Perevertkin
3285194ea909SVictor Perevertkin acec->OutFlags |= ATOMIC_CREATE_ECP_OUT_FLAG_OP_FLAGS_HONORED;
3286194ea909SVictor Perevertkin }
3287194ea909SVictor Perevertkin
3288eb7fbc25SPierre Schweitzer fileref->dc->type = fileref->fcb->type;
3289eb7fbc25SPierre Schweitzer
3290c2c66affSColin Finck end:
3291c2c66affSColin Finck if (fpus.Buffer)
3292c2c66affSColin Finck ExFreePool(fpus.Buffer);
3293c2c66affSColin Finck
3294c2c66affSColin Finck if (parfileref && !loaded_related)
3295883b1f31SPierre Schweitzer free_fileref(parfileref);
3296c2c66affSColin Finck
3297c2c66affSColin Finck return Status;
3298c2c66affSColin Finck }
3299c2c66affSColin Finck
debug_create_options(ULONG RequestedOptions)3300c2c66affSColin Finck static __inline void debug_create_options(ULONG RequestedOptions) {
3301c2c66affSColin Finck if (RequestedOptions != 0) {
3302c2c66affSColin Finck ULONG options = RequestedOptions;
3303c2c66affSColin Finck
3304c2c66affSColin Finck TRACE("requested options:\n");
3305c2c66affSColin Finck
3306c2c66affSColin Finck if (options & FILE_DIRECTORY_FILE) {
3307c2c66affSColin Finck TRACE(" FILE_DIRECTORY_FILE\n");
3308c2c66affSColin Finck options &= ~FILE_DIRECTORY_FILE;
3309c2c66affSColin Finck }
3310c2c66affSColin Finck
3311c2c66affSColin Finck if (options & FILE_WRITE_THROUGH) {
3312c2c66affSColin Finck TRACE(" FILE_WRITE_THROUGH\n");
3313c2c66affSColin Finck options &= ~FILE_WRITE_THROUGH;
3314c2c66affSColin Finck }
3315c2c66affSColin Finck
3316c2c66affSColin Finck if (options & FILE_SEQUENTIAL_ONLY) {
3317c2c66affSColin Finck TRACE(" FILE_SEQUENTIAL_ONLY\n");
3318c2c66affSColin Finck options &= ~FILE_SEQUENTIAL_ONLY;
3319c2c66affSColin Finck }
3320c2c66affSColin Finck
3321c2c66affSColin Finck if (options & FILE_NO_INTERMEDIATE_BUFFERING) {
3322c2c66affSColin Finck TRACE(" FILE_NO_INTERMEDIATE_BUFFERING\n");
3323c2c66affSColin Finck options &= ~FILE_NO_INTERMEDIATE_BUFFERING;
3324c2c66affSColin Finck }
3325c2c66affSColin Finck
3326c2c66affSColin Finck if (options & FILE_SYNCHRONOUS_IO_ALERT) {
3327c2c66affSColin Finck TRACE(" FILE_SYNCHRONOUS_IO_ALERT\n");
3328c2c66affSColin Finck options &= ~FILE_SYNCHRONOUS_IO_ALERT;
3329c2c66affSColin Finck }
3330c2c66affSColin Finck
3331c2c66affSColin Finck if (options & FILE_SYNCHRONOUS_IO_NONALERT) {
3332c2c66affSColin Finck TRACE(" FILE_SYNCHRONOUS_IO_NONALERT\n");
3333c2c66affSColin Finck options &= ~FILE_SYNCHRONOUS_IO_NONALERT;
3334c2c66affSColin Finck }
3335c2c66affSColin Finck
3336c2c66affSColin Finck if (options & FILE_NON_DIRECTORY_FILE) {
3337c2c66affSColin Finck TRACE(" FILE_NON_DIRECTORY_FILE\n");
3338c2c66affSColin Finck options &= ~FILE_NON_DIRECTORY_FILE;
3339c2c66affSColin Finck }
3340c2c66affSColin Finck
3341c2c66affSColin Finck if (options & FILE_CREATE_TREE_CONNECTION) {
3342c2c66affSColin Finck TRACE(" FILE_CREATE_TREE_CONNECTION\n");
3343c2c66affSColin Finck options &= ~FILE_CREATE_TREE_CONNECTION;
3344c2c66affSColin Finck }
3345c2c66affSColin Finck
3346c2c66affSColin Finck if (options & FILE_COMPLETE_IF_OPLOCKED) {
3347c2c66affSColin Finck TRACE(" FILE_COMPLETE_IF_OPLOCKED\n");
3348c2c66affSColin Finck options &= ~FILE_COMPLETE_IF_OPLOCKED;
3349c2c66affSColin Finck }
3350c2c66affSColin Finck
3351c2c66affSColin Finck if (options & FILE_NO_EA_KNOWLEDGE) {
3352c2c66affSColin Finck TRACE(" FILE_NO_EA_KNOWLEDGE\n");
3353c2c66affSColin Finck options &= ~FILE_NO_EA_KNOWLEDGE;
3354c2c66affSColin Finck }
3355c2c66affSColin Finck
3356c2c66affSColin Finck if (options & FILE_OPEN_REMOTE_INSTANCE) {
3357c2c66affSColin Finck TRACE(" FILE_OPEN_REMOTE_INSTANCE\n");
3358c2c66affSColin Finck options &= ~FILE_OPEN_REMOTE_INSTANCE;
3359c2c66affSColin Finck }
3360c2c66affSColin Finck
3361c2c66affSColin Finck if (options & FILE_RANDOM_ACCESS) {
3362c2c66affSColin Finck TRACE(" FILE_RANDOM_ACCESS\n");
3363c2c66affSColin Finck options &= ~FILE_RANDOM_ACCESS;
3364c2c66affSColin Finck }
3365c2c66affSColin Finck
3366c2c66affSColin Finck if (options & FILE_DELETE_ON_CLOSE) {
3367c2c66affSColin Finck TRACE(" FILE_DELETE_ON_CLOSE\n");
3368c2c66affSColin Finck options &= ~FILE_DELETE_ON_CLOSE;
3369c2c66affSColin Finck }
3370c2c66affSColin Finck
3371c2c66affSColin Finck if (options & FILE_OPEN_BY_FILE_ID) {
3372c2c66affSColin Finck TRACE(" FILE_OPEN_BY_FILE_ID\n");
3373c2c66affSColin Finck options &= ~FILE_OPEN_BY_FILE_ID;
3374c2c66affSColin Finck }
3375c2c66affSColin Finck
3376c2c66affSColin Finck if (options & FILE_OPEN_FOR_BACKUP_INTENT) {
3377c2c66affSColin Finck TRACE(" FILE_OPEN_FOR_BACKUP_INTENT\n");
3378c2c66affSColin Finck options &= ~FILE_OPEN_FOR_BACKUP_INTENT;
3379c2c66affSColin Finck }
3380c2c66affSColin Finck
3381c2c66affSColin Finck if (options & FILE_NO_COMPRESSION) {
3382c2c66affSColin Finck TRACE(" FILE_NO_COMPRESSION\n");
3383c2c66affSColin Finck options &= ~FILE_NO_COMPRESSION;
3384c2c66affSColin Finck }
3385c2c66affSColin Finck
3386c2c66affSColin Finck #if NTDDI_VERSION >= NTDDI_WIN7
3387c2c66affSColin Finck if (options & FILE_OPEN_REQUIRING_OPLOCK) {
3388c2c66affSColin Finck TRACE(" FILE_OPEN_REQUIRING_OPLOCK\n");
3389c2c66affSColin Finck options &= ~FILE_OPEN_REQUIRING_OPLOCK;
3390c2c66affSColin Finck }
3391c2c66affSColin Finck
3392c2c66affSColin Finck if (options & FILE_DISALLOW_EXCLUSIVE) {
3393c2c66affSColin Finck TRACE(" FILE_DISALLOW_EXCLUSIVE\n");
3394c2c66affSColin Finck options &= ~FILE_DISALLOW_EXCLUSIVE;
3395c2c66affSColin Finck }
3396c2c66affSColin Finck #endif
3397c2c66affSColin Finck
3398c2c66affSColin Finck if (options & FILE_RESERVE_OPFILTER) {
3399c2c66affSColin Finck TRACE(" FILE_RESERVE_OPFILTER\n");
3400c2c66affSColin Finck options &= ~FILE_RESERVE_OPFILTER;
3401c2c66affSColin Finck }
3402c2c66affSColin Finck
3403c2c66affSColin Finck if (options & FILE_OPEN_REPARSE_POINT) {
3404c2c66affSColin Finck TRACE(" FILE_OPEN_REPARSE_POINT\n");
3405c2c66affSColin Finck options &= ~FILE_OPEN_REPARSE_POINT;
3406c2c66affSColin Finck }
3407c2c66affSColin Finck
3408c2c66affSColin Finck if (options & FILE_OPEN_NO_RECALL) {
3409c2c66affSColin Finck TRACE(" FILE_OPEN_NO_RECALL\n");
3410c2c66affSColin Finck options &= ~FILE_OPEN_NO_RECALL;
3411c2c66affSColin Finck }
3412c2c66affSColin Finck
3413c2c66affSColin Finck if (options & FILE_OPEN_FOR_FREE_SPACE_QUERY) {
3414c2c66affSColin Finck TRACE(" FILE_OPEN_FOR_FREE_SPACE_QUERY\n");
3415c2c66affSColin Finck options &= ~FILE_OPEN_FOR_FREE_SPACE_QUERY;
3416c2c66affSColin Finck }
3417c2c66affSColin Finck
3418c2c66affSColin Finck if (options)
3419194ea909SVictor Perevertkin TRACE(" unknown options: %lx\n", options);
3420c2c66affSColin Finck } else {
3421c2c66affSColin Finck TRACE("requested options: (none)\n");
3422c2c66affSColin Finck }
3423c2c66affSColin Finck }
3424c2c66affSColin Finck
get_reparse_block(fcb * fcb,uint8_t ** data)3425318da0c1SPierre Schweitzer static NTSTATUS get_reparse_block(fcb* fcb, uint8_t** data) {
3426c2c66affSColin Finck NTSTATUS Status;
3427c2c66affSColin Finck
3428c2c66affSColin Finck if (fcb->type == BTRFS_TYPE_FILE || fcb->type == BTRFS_TYPE_SYMLINK) {
3429c2c66affSColin Finck ULONG size, bytes_read, i;
3430c2c66affSColin Finck
3431c2c66affSColin Finck if (fcb->type == BTRFS_TYPE_FILE && fcb->inode_item.st_size < sizeof(ULONG)) {
3432c2c66affSColin Finck WARN("file was too short to be a reparse point\n");
3433c2c66affSColin Finck return STATUS_INVALID_PARAMETER;
3434c2c66affSColin Finck }
3435c2c66affSColin Finck
3436c2c66affSColin Finck // 0x10007 = 0xffff (maximum length of data buffer) + 8 bytes header
3437c2c66affSColin Finck size = (ULONG)min(0x10007, fcb->inode_item.st_size);
3438c2c66affSColin Finck
3439c2c66affSColin Finck if (size == 0)
3440c2c66affSColin Finck return STATUS_INVALID_PARAMETER;
3441c2c66affSColin Finck
3442c2c66affSColin Finck *data = ExAllocatePoolWithTag(PagedPool, size, ALLOC_TAG);
3443c2c66affSColin Finck if (!*data) {
3444c2c66affSColin Finck ERR("out of memory\n");
3445c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
3446c2c66affSColin Finck }
3447c2c66affSColin Finck
3448c2c66affSColin Finck Status = read_file(fcb, *data, 0, size, &bytes_read, NULL);
3449c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
3450194ea909SVictor Perevertkin ERR("read_file_fcb returned %08lx\n", Status);
3451c2c66affSColin Finck ExFreePool(*data);
3452c2c66affSColin Finck return Status;
3453c2c66affSColin Finck }
3454c2c66affSColin Finck
3455c2c66affSColin Finck if (fcb->type == BTRFS_TYPE_SYMLINK) {
3456c2c66affSColin Finck ULONG stringlen, reqlen;
3457318da0c1SPierre Schweitzer uint16_t subnamelen, printnamelen;
3458c2c66affSColin Finck REPARSE_DATA_BUFFER* rdb;
3459c2c66affSColin Finck
3460318da0c1SPierre Schweitzer Status = utf8_to_utf16(NULL, 0, &stringlen, (char*)*data, bytes_read);
3461c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
3462194ea909SVictor Perevertkin ERR("utf8_to_utf16 1 returned %08lx\n", Status);
3463c2c66affSColin Finck ExFreePool(*data);
3464c2c66affSColin Finck return Status;
3465c2c66affSColin Finck }
3466c2c66affSColin Finck
3467c2c66affSColin Finck subnamelen = printnamelen = (USHORT)stringlen;
3468c2c66affSColin Finck
3469c2c66affSColin Finck reqlen = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + subnamelen + printnamelen;
3470c2c66affSColin Finck
3471c2c66affSColin Finck rdb = ExAllocatePoolWithTag(PagedPool, reqlen, ALLOC_TAG);
3472c2c66affSColin Finck
3473c2c66affSColin Finck if (!rdb) {
3474c2c66affSColin Finck ERR("out of memory\n");
3475c2c66affSColin Finck ExFreePool(*data);
3476c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
3477c2c66affSColin Finck }
3478c2c66affSColin Finck
3479c2c66affSColin Finck rdb->ReparseTag = IO_REPARSE_TAG_SYMLINK;
3480c2c66affSColin Finck rdb->ReparseDataLength = (USHORT)(reqlen - offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer));
3481c2c66affSColin Finck rdb->Reserved = 0;
3482c2c66affSColin Finck
3483c2c66affSColin Finck rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
3484c2c66affSColin Finck rdb->SymbolicLinkReparseBuffer.SubstituteNameLength = subnamelen;
3485c2c66affSColin Finck rdb->SymbolicLinkReparseBuffer.PrintNameOffset = subnamelen;
3486c2c66affSColin Finck rdb->SymbolicLinkReparseBuffer.PrintNameLength = printnamelen;
3487c2c66affSColin Finck rdb->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
3488c2c66affSColin Finck
3489318da0c1SPierre Schweitzer Status = utf8_to_utf16(&rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)],
3490c2c66affSColin Finck stringlen, &stringlen, (char*)*data, size);
3491c2c66affSColin Finck
3492c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
3493194ea909SVictor Perevertkin ERR("utf8_to_utf16 2 returned %08lx\n", Status);
3494c2c66affSColin Finck ExFreePool(rdb);
3495c2c66affSColin Finck ExFreePool(*data);
3496c2c66affSColin Finck return Status;
3497c2c66affSColin Finck }
3498c2c66affSColin Finck
3499c2c66affSColin Finck for (i = 0; i < stringlen / sizeof(WCHAR); i++) {
3500c2c66affSColin Finck if (rdb->SymbolicLinkReparseBuffer.PathBuffer[(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)) + i] == '/')
3501c2c66affSColin Finck rdb->SymbolicLinkReparseBuffer.PathBuffer[(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)) + i] = '\\';
3502c2c66affSColin Finck }
3503c2c66affSColin Finck
3504c2c66affSColin Finck RtlCopyMemory(&rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)],
3505c2c66affSColin Finck &rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)],
3506c2c66affSColin Finck rdb->SymbolicLinkReparseBuffer.SubstituteNameLength);
3507c2c66affSColin Finck
3508c2c66affSColin Finck ExFreePool(*data);
3509c2c66affSColin Finck
3510318da0c1SPierre Schweitzer *data = (uint8_t*)rdb;
3511c2c66affSColin Finck } else {
3512318da0c1SPierre Schweitzer Status = fFsRtlValidateReparsePointBuffer(bytes_read, (REPARSE_DATA_BUFFER*)*data);
3513c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
3514194ea909SVictor Perevertkin ERR("FsRtlValidateReparsePointBuffer returned %08lx\n", Status);
3515c2c66affSColin Finck ExFreePool(*data);
3516c2c66affSColin Finck return Status;
3517c2c66affSColin Finck }
3518c2c66affSColin Finck }
3519c2c66affSColin Finck } else if (fcb->type == BTRFS_TYPE_DIRECTORY) {
3520c2c66affSColin Finck if (!fcb->reparse_xattr.Buffer || fcb->reparse_xattr.Length == 0)
3521c2c66affSColin Finck return STATUS_INTERNAL_ERROR;
3522c2c66affSColin Finck
3523c2c66affSColin Finck if (fcb->reparse_xattr.Length < sizeof(ULONG)) {
3524c2c66affSColin Finck WARN("xattr was too short to be a reparse point\n");
3525c2c66affSColin Finck return STATUS_INTERNAL_ERROR;
3526c2c66affSColin Finck }
3527c2c66affSColin Finck
3528318da0c1SPierre Schweitzer Status = fFsRtlValidateReparsePointBuffer(fcb->reparse_xattr.Length, (REPARSE_DATA_BUFFER*)fcb->reparse_xattr.Buffer);
3529c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
3530194ea909SVictor Perevertkin ERR("FsRtlValidateReparsePointBuffer returned %08lx\n", Status);
3531c2c66affSColin Finck return Status;
3532c2c66affSColin Finck }
3533c2c66affSColin Finck
3534c2c66affSColin Finck *data = ExAllocatePoolWithTag(PagedPool, fcb->reparse_xattr.Length, ALLOC_TAG);
3535c2c66affSColin Finck if (!*data) {
3536c2c66affSColin Finck ERR("out of memory\n");
3537c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES;
3538c2c66affSColin Finck }
3539c2c66affSColin Finck
3540c2c66affSColin Finck RtlCopyMemory(*data, fcb->reparse_xattr.Buffer, fcb->reparse_xattr.Length);
3541eb7fbc25SPierre Schweitzer } else
3542eb7fbc25SPierre Schweitzer return STATUS_INVALID_PARAMETER;
3543c2c66affSColin Finck
3544c2c66affSColin Finck return STATUS_SUCCESS;
3545c2c66affSColin Finck }
3546c2c66affSColin Finck
3547c2c66affSColin Finck static void fcb_load_csums(_Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, fcb* fcb, PIRP Irp) {
3548c2c66affSColin Finck LIST_ENTRY* le;
3549c2c66affSColin Finck NTSTATUS Status;
3550c2c66affSColin Finck
3551c2c66affSColin Finck if (fcb->csum_loaded)
3552c2c66affSColin Finck return;
3553c2c66affSColin Finck
3554c2c66affSColin Finck if (IsListEmpty(&fcb->extents) || fcb->inode_item.flags & BTRFS_INODE_NODATASUM)
3555c2c66affSColin Finck goto end;
3556c2c66affSColin Finck
3557c2c66affSColin Finck le = fcb->extents.Flink;
3558c2c66affSColin Finck while (le != &fcb->extents) {
3559c2c66affSColin Finck extent* ext = CONTAINING_RECORD(le, extent, list_entry);
3560c2c66affSColin Finck
356162e630deSPierre Schweitzer if (!ext->ignore && ext->extent_data.type == EXTENT_TYPE_REGULAR) {
3562c2c66affSColin Finck EXTENT_DATA2* ed2 = (EXTENT_DATA2*)&ext->extent_data.data[0];
3563318da0c1SPierre Schweitzer uint64_t len;
3564c2c66affSColin Finck
3565174dfab6SVincent Franchomme len = (ext->extent_data.compression == BTRFS_COMPRESSION_NONE ? ed2->num_bytes : ed2->size) >> Vcb->sector_shift;
3566c2c66affSColin Finck
3567194ea909SVictor Perevertkin ext->csum = ExAllocatePoolWithTag(NonPagedPool, (ULONG)(len * Vcb->csum_size), ALLOC_TAG);
3568c2c66affSColin Finck if (!ext->csum) {
3569c2c66affSColin Finck ERR("out of memory\n");
3570c2c66affSColin Finck goto end;
3571c2c66affSColin Finck }
3572c2c66affSColin Finck
3573c2c66affSColin Finck Status = load_csum(Vcb, ext->csum, ed2->address + (ext->extent_data.compression == BTRFS_COMPRESSION_NONE ? ed2->offset : 0), len, Irp);
3574c2c66affSColin Finck
3575c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
3576194ea909SVictor Perevertkin ERR("load_csum returned %08lx\n", Status);
3577c2c66affSColin Finck goto end;
3578c2c66affSColin Finck }
3579c2c66affSColin Finck }
3580c2c66affSColin Finck
3581c2c66affSColin Finck le = le->Flink;
3582c2c66affSColin Finck }
3583c2c66affSColin Finck
3584c2c66affSColin Finck end:
3585318da0c1SPierre Schweitzer fcb->csum_loaded = true;
3586c2c66affSColin Finck }
3587c2c66affSColin Finck
open_file3(device_extension * Vcb,PIRP Irp,ACCESS_MASK granted_access,file_ref * fileref,LIST_ENTRY * rollback)3588c982533eSVincent Franchomme static NTSTATUS open_file3(device_extension* Vcb, PIRP Irp, ACCESS_MASK granted_access, file_ref* fileref, LIST_ENTRY* rollback) {
3589c982533eSVincent Franchomme NTSTATUS Status;
3590c982533eSVincent Franchomme PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
3591c982533eSVincent Franchomme ULONG options = IrpSp->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
3592c982533eSVincent Franchomme ULONG RequestedDisposition = ((IrpSp->Parameters.Create.Options >> 24) & 0xff);
3593c982533eSVincent Franchomme PFILE_OBJECT FileObject = IrpSp->FileObject;
3594c982533eSVincent Franchomme POOL_TYPE pool_type = IrpSp->Flags & SL_OPEN_PAGING_FILE ? NonPagedPool : PagedPool;
3595c982533eSVincent Franchomme ccb* ccb;
3596c982533eSVincent Franchomme
3597c982533eSVincent Franchomme if (granted_access & FILE_WRITE_DATA || options & FILE_DELETE_ON_CLOSE) {
3598c982533eSVincent Franchomme if (!MmFlushImageSection(&fileref->fcb->nonpaged->segment_object, MmFlushForWrite))
3599c982533eSVincent Franchomme return (options & FILE_DELETE_ON_CLOSE) ? STATUS_CANNOT_DELETE : STATUS_SHARING_VIOLATION;
3600c982533eSVincent Franchomme }
3601c982533eSVincent Franchomme
3602c982533eSVincent Franchomme if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF || RequestedDisposition == FILE_SUPERSEDE) {
3603c982533eSVincent Franchomme ULONG defda, oldatts, filter;
3604c982533eSVincent Franchomme LARGE_INTEGER time;
3605c982533eSVincent Franchomme BTRFS_TIME now;
3606c982533eSVincent Franchomme
3607c982533eSVincent Franchomme if (!fileref->fcb->ads && (IrpSp->Parameters.Create.FileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != ((fileref->fcb->atts & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN))))
3608c982533eSVincent Franchomme return STATUS_ACCESS_DENIED;
3609c982533eSVincent Franchomme
3610c982533eSVincent Franchomme if (fileref->fcb->ads) {
3611c982533eSVincent Franchomme Status = stream_set_end_of_file_information(Vcb, 0, fileref->fcb, fileref, false);
3612c982533eSVincent Franchomme if (!NT_SUCCESS(Status)) {
3613c982533eSVincent Franchomme ERR("stream_set_end_of_file_information returned %08lx\n", Status);
3614c982533eSVincent Franchomme return Status;
3615c982533eSVincent Franchomme }
3616c982533eSVincent Franchomme } else {
3617c982533eSVincent Franchomme Status = truncate_file(fileref->fcb, 0, Irp, rollback);
3618c982533eSVincent Franchomme if (!NT_SUCCESS(Status)) {
3619c982533eSVincent Franchomme ERR("truncate_file returned %08lx\n", Status);
3620c982533eSVincent Franchomme return Status;
3621c982533eSVincent Franchomme }
3622c982533eSVincent Franchomme }
3623c982533eSVincent Franchomme
3624c982533eSVincent Franchomme if (Irp->Overlay.AllocationSize.QuadPart > 0) {
3625c982533eSVincent Franchomme Status = extend_file(fileref->fcb, fileref, Irp->Overlay.AllocationSize.QuadPart, true, NULL, rollback);
3626c982533eSVincent Franchomme
3627c982533eSVincent Franchomme if (!NT_SUCCESS(Status)) {
3628c982533eSVincent Franchomme ERR("extend_file returned %08lx\n", Status);
3629c982533eSVincent Franchomme return Status;
3630c982533eSVincent Franchomme }
3631c982533eSVincent Franchomme }
3632c982533eSVincent Franchomme
3633c982533eSVincent Franchomme if (!fileref->fcb->ads) {
3634c982533eSVincent Franchomme LIST_ENTRY* le;
3635c982533eSVincent Franchomme
3636c982533eSVincent Franchomme if (Irp->AssociatedIrp.SystemBuffer && IrpSp->Parameters.Create.EaLength > 0) {
3637c982533eSVincent Franchomme ULONG offset;
3638c982533eSVincent Franchomme FILE_FULL_EA_INFORMATION* eainfo;
3639c982533eSVincent Franchomme
3640c982533eSVincent Franchomme Status = IoCheckEaBufferValidity(Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.Create.EaLength, &offset);
3641c982533eSVincent Franchomme if (!NT_SUCCESS(Status)) {
3642c982533eSVincent Franchomme ERR("IoCheckEaBufferValidity returned %08lx (error at offset %lu)\n", Status, offset);
3643c982533eSVincent Franchomme return Status;
3644c982533eSVincent Franchomme }
3645c982533eSVincent Franchomme
3646c982533eSVincent Franchomme fileref->fcb->ealen = 4;
3647c982533eSVincent Franchomme
3648c982533eSVincent Franchomme // capitalize EA name
3649c982533eSVincent Franchomme eainfo = Irp->AssociatedIrp.SystemBuffer;
3650c982533eSVincent Franchomme do {
3651c982533eSVincent Franchomme STRING s;
3652c982533eSVincent Franchomme
3653c982533eSVincent Franchomme s.Length = s.MaximumLength = eainfo->EaNameLength;
3654c982533eSVincent Franchomme s.Buffer = eainfo->EaName;
3655c982533eSVincent Franchomme
3656c982533eSVincent Franchomme RtlUpperString(&s, &s);
3657c982533eSVincent Franchomme
3658c982533eSVincent Franchomme fileref->fcb->ealen += 5 + eainfo->EaNameLength + eainfo->EaValueLength;
3659c982533eSVincent Franchomme
3660c982533eSVincent Franchomme if (eainfo->NextEntryOffset == 0)
3661c982533eSVincent Franchomme break;
3662c982533eSVincent Franchomme
3663c982533eSVincent Franchomme eainfo = (FILE_FULL_EA_INFORMATION*)(((uint8_t*)eainfo) + eainfo->NextEntryOffset);
3664c982533eSVincent Franchomme } while (true);
3665c982533eSVincent Franchomme
3666c982533eSVincent Franchomme if (fileref->fcb->ea_xattr.Buffer)
3667c982533eSVincent Franchomme ExFreePool(fileref->fcb->ea_xattr.Buffer);
3668c982533eSVincent Franchomme
3669c982533eSVincent Franchomme fileref->fcb->ea_xattr.Buffer = ExAllocatePoolWithTag(pool_type, IrpSp->Parameters.Create.EaLength, ALLOC_TAG);
3670c982533eSVincent Franchomme if (!fileref->fcb->ea_xattr.Buffer) {
3671c982533eSVincent Franchomme ERR("out of memory\n");
3672c982533eSVincent Franchomme return STATUS_INSUFFICIENT_RESOURCES;
3673c982533eSVincent Franchomme }
3674c982533eSVincent Franchomme
3675c982533eSVincent Franchomme fileref->fcb->ea_xattr.Length = fileref->fcb->ea_xattr.MaximumLength = (USHORT)IrpSp->Parameters.Create.EaLength;
3676c982533eSVincent Franchomme RtlCopyMemory(fileref->fcb->ea_xattr.Buffer, Irp->AssociatedIrp.SystemBuffer, fileref->fcb->ea_xattr.Length);
3677c982533eSVincent Franchomme } else {
3678c982533eSVincent Franchomme if (fileref->fcb->ea_xattr.Length > 0) {
3679c982533eSVincent Franchomme ExFreePool(fileref->fcb->ea_xattr.Buffer);
3680c982533eSVincent Franchomme fileref->fcb->ea_xattr.Buffer = NULL;
3681c982533eSVincent Franchomme fileref->fcb->ea_xattr.Length = fileref->fcb->ea_xattr.MaximumLength = 0;
3682c982533eSVincent Franchomme
3683c982533eSVincent Franchomme fileref->fcb->ea_changed = true;
3684c982533eSVincent Franchomme fileref->fcb->ealen = 0;
3685c982533eSVincent Franchomme }
3686c982533eSVincent Franchomme }
3687c982533eSVincent Franchomme
3688c982533eSVincent Franchomme // remove streams and send notifications
3689c982533eSVincent Franchomme le = fileref->fcb->dir_children_index.Flink;
3690c982533eSVincent Franchomme while (le != &fileref->fcb->dir_children_index) {
3691c982533eSVincent Franchomme dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index);
3692c982533eSVincent Franchomme LIST_ENTRY* le2 = le->Flink;
3693c982533eSVincent Franchomme
3694c982533eSVincent Franchomme if (dc->index == 0) {
3695c982533eSVincent Franchomme if (!dc->fileref) {
3696c982533eSVincent Franchomme file_ref* fr2;
3697c982533eSVincent Franchomme
3698c982533eSVincent Franchomme Status = open_fileref_child(Vcb, fileref, &dc->name, true, true, true, PagedPool, &fr2, NULL);
3699c982533eSVincent Franchomme if (!NT_SUCCESS(Status))
3700c982533eSVincent Franchomme WARN("open_fileref_child returned %08lx\n", Status);
3701c982533eSVincent Franchomme }
3702c982533eSVincent Franchomme
3703c982533eSVincent Franchomme if (dc->fileref) {
3704c982533eSVincent Franchomme queue_notification_fcb(fileref, FILE_NOTIFY_CHANGE_STREAM_NAME, FILE_ACTION_REMOVED_STREAM, &dc->name);
3705c982533eSVincent Franchomme
3706c982533eSVincent Franchomme Status = delete_fileref(dc->fileref, NULL, false, NULL, rollback);
3707c982533eSVincent Franchomme if (!NT_SUCCESS(Status)) {
3708c982533eSVincent Franchomme ERR("delete_fileref returned %08lx\n", Status);
3709c982533eSVincent Franchomme return Status;
3710c982533eSVincent Franchomme }
3711c982533eSVincent Franchomme }
3712c982533eSVincent Franchomme } else
3713c982533eSVincent Franchomme break;
3714c982533eSVincent Franchomme
3715c982533eSVincent Franchomme le = le2;
3716c982533eSVincent Franchomme }
3717c982533eSVincent Franchomme }
3718c982533eSVincent Franchomme
3719c982533eSVincent Franchomme KeQuerySystemTime(&time);
3720c982533eSVincent Franchomme win_time_to_unix(time, &now);
3721c982533eSVincent Franchomme
3722c982533eSVincent Franchomme filter = FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE;
3723c982533eSVincent Franchomme
3724c982533eSVincent Franchomme if (fileref->fcb->ads) {
3725c982533eSVincent Franchomme fileref->parent->fcb->inode_item.st_mtime = now;
3726c982533eSVincent Franchomme fileref->parent->fcb->inode_item_changed = true;
3727c982533eSVincent Franchomme mark_fcb_dirty(fileref->parent->fcb);
3728c982533eSVincent Franchomme
3729c982533eSVincent Franchomme queue_notification_fcb(fileref->parent, filter, FILE_ACTION_MODIFIED, &fileref->dc->name);
3730c982533eSVincent Franchomme } else {
3731c982533eSVincent Franchomme mark_fcb_dirty(fileref->fcb);
3732c982533eSVincent Franchomme
3733c982533eSVincent Franchomme oldatts = fileref->fcb->atts;
3734c982533eSVincent Franchomme
3735c982533eSVincent Franchomme defda = get_file_attributes(Vcb, fileref->fcb->subvol, fileref->fcb->inode, fileref->fcb->type,
3736c982533eSVincent Franchomme fileref->dc && fileref->dc->name.Length >= sizeof(WCHAR) && fileref->dc->name.Buffer[0] == '.', true, Irp);
3737c982533eSVincent Franchomme
3738c982533eSVincent Franchomme if (RequestedDisposition == FILE_SUPERSEDE)
3739c982533eSVincent Franchomme fileref->fcb->atts = IrpSp->Parameters.Create.FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
3740c982533eSVincent Franchomme else
3741c982533eSVincent Franchomme fileref->fcb->atts |= IrpSp->Parameters.Create.FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
3742c982533eSVincent Franchomme
3743c982533eSVincent Franchomme if (fileref->fcb->atts != oldatts) {
3744c982533eSVincent Franchomme fileref->fcb->atts_changed = true;
3745c982533eSVincent Franchomme fileref->fcb->atts_deleted = IrpSp->Parameters.Create.FileAttributes == defda;
3746c982533eSVincent Franchomme filter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
3747c982533eSVincent Franchomme }
3748c982533eSVincent Franchomme
3749c982533eSVincent Franchomme fileref->fcb->inode_item.transid = Vcb->superblock.generation;
3750c982533eSVincent Franchomme fileref->fcb->inode_item.sequence++;
3751c982533eSVincent Franchomme fileref->fcb->inode_item.st_ctime = now;
3752c982533eSVincent Franchomme fileref->fcb->inode_item.st_mtime = now;
3753c982533eSVincent Franchomme fileref->fcb->inode_item_changed = true;
3754c982533eSVincent Franchomme
3755c982533eSVincent Franchomme queue_notification_fcb(fileref, filter, FILE_ACTION_MODIFIED, NULL);
3756c982533eSVincent Franchomme }
3757c982533eSVincent Franchomme } else {
3758c982533eSVincent Franchomme if (options & FILE_NO_EA_KNOWLEDGE && fileref->fcb->ea_xattr.Length > 0) {
3759c982533eSVincent Franchomme FILE_FULL_EA_INFORMATION* ffei = (FILE_FULL_EA_INFORMATION*)fileref->fcb->ea_xattr.Buffer;
3760c982533eSVincent Franchomme
3761c982533eSVincent Franchomme do {
3762c982533eSVincent Franchomme if (ffei->Flags & FILE_NEED_EA) {
3763c982533eSVincent Franchomme WARN("returning STATUS_ACCESS_DENIED as no EA knowledge\n");
3764c982533eSVincent Franchomme
3765c982533eSVincent Franchomme return STATUS_ACCESS_DENIED;
3766c982533eSVincent Franchomme }
3767c982533eSVincent Franchomme
3768c982533eSVincent Franchomme if (ffei->NextEntryOffset == 0)
3769c982533eSVincent Franchomme break;
3770c982533eSVincent Franchomme
3771c982533eSVincent Franchomme ffei = (FILE_FULL_EA_INFORMATION*)(((uint8_t*)ffei) + ffei->NextEntryOffset);
3772c982533eSVincent Franchomme } while (true);
3773c982533eSVincent Franchomme }
3774c982533eSVincent Franchomme }
3775c982533eSVincent Franchomme
3776c982533eSVincent Franchomme FileObject->FsContext = fileref->fcb;
3777c982533eSVincent Franchomme
3778c982533eSVincent Franchomme ccb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ccb), ALLOC_TAG);
3779c982533eSVincent Franchomme if (!ccb) {
3780c982533eSVincent Franchomme ERR("out of memory\n");
3781c982533eSVincent Franchomme
3782c982533eSVincent Franchomme return STATUS_INSUFFICIENT_RESOURCES;
3783c982533eSVincent Franchomme }
3784c982533eSVincent Franchomme
3785c982533eSVincent Franchomme RtlZeroMemory(ccb, sizeof(*ccb));
3786c982533eSVincent Franchomme
3787c982533eSVincent Franchomme ccb->NodeType = BTRFS_NODE_TYPE_CCB;
3788c982533eSVincent Franchomme ccb->NodeSize = sizeof(*ccb);
3789c982533eSVincent Franchomme ccb->disposition = RequestedDisposition;
3790c982533eSVincent Franchomme ccb->options = options;
3791c982533eSVincent Franchomme ccb->query_dir_offset = 0;
3792c982533eSVincent Franchomme RtlInitUnicodeString(&ccb->query_string, NULL);
3793c982533eSVincent Franchomme ccb->has_wildcard = false;
3794c982533eSVincent Franchomme ccb->specific_file = false;
3795c982533eSVincent Franchomme ccb->access = granted_access;
3796c982533eSVincent Franchomme ccb->case_sensitive = IrpSp->Flags & SL_CASE_SENSITIVE;
3797c982533eSVincent Franchomme ccb->reserving = false;
3798c982533eSVincent Franchomme ccb->lxss = called_from_lxss();
3799c982533eSVincent Franchomme
3800c982533eSVincent Franchomme ccb->fileref = fileref;
3801c982533eSVincent Franchomme
3802c982533eSVincent Franchomme FileObject->FsContext2 = ccb;
3803c982533eSVincent Franchomme FileObject->SectionObjectPointer = &fileref->fcb->nonpaged->segment_object;
3804c982533eSVincent Franchomme
3805c982533eSVincent Franchomme switch (RequestedDisposition) {
3806c982533eSVincent Franchomme case FILE_SUPERSEDE:
3807c982533eSVincent Franchomme Irp->IoStatus.Information = FILE_SUPERSEDED;
3808c982533eSVincent Franchomme break;
3809c982533eSVincent Franchomme
3810c982533eSVincent Franchomme case FILE_OPEN:
3811c982533eSVincent Franchomme case FILE_OPEN_IF:
3812c982533eSVincent Franchomme Irp->IoStatus.Information = FILE_OPENED;
3813c982533eSVincent Franchomme break;
3814c982533eSVincent Franchomme
3815c982533eSVincent Franchomme case FILE_OVERWRITE:
3816c982533eSVincent Franchomme case FILE_OVERWRITE_IF:
3817c982533eSVincent Franchomme Irp->IoStatus.Information = FILE_OVERWRITTEN;
3818c982533eSVincent Franchomme break;
3819c982533eSVincent Franchomme }
3820c982533eSVincent Franchomme
3821c982533eSVincent Franchomme // Make sure paging files don't have any extents marked as being prealloc,
3822c982533eSVincent Franchomme // as this would mean we'd have to lock exclusively when writing.
3823c982533eSVincent Franchomme if (IrpSp->Flags & SL_OPEN_PAGING_FILE) {
3824c982533eSVincent Franchomme LIST_ENTRY* le;
3825c982533eSVincent Franchomme bool changed = false;
3826c982533eSVincent Franchomme
3827c982533eSVincent Franchomme ExAcquireResourceExclusiveLite(fileref->fcb->Header.Resource, true);
3828c982533eSVincent Franchomme
3829c982533eSVincent Franchomme le = fileref->fcb->extents.Flink;
3830c982533eSVincent Franchomme
3831c982533eSVincent Franchomme while (le != &fileref->fcb->extents) {
3832c982533eSVincent Franchomme extent* ext = CONTAINING_RECORD(le, extent, list_entry);
3833c982533eSVincent Franchomme
3834c982533eSVincent Franchomme if (ext->extent_data.type == EXTENT_TYPE_PREALLOC) {
3835c982533eSVincent Franchomme ext->extent_data.type = EXTENT_TYPE_REGULAR;
3836c982533eSVincent Franchomme changed = true;
3837c982533eSVincent Franchomme }
3838c982533eSVincent Franchomme
3839c982533eSVincent Franchomme le = le->Flink;
3840c982533eSVincent Franchomme }
3841c982533eSVincent Franchomme
3842c982533eSVincent Franchomme ExReleaseResourceLite(fileref->fcb->Header.Resource);
3843c982533eSVincent Franchomme
3844c982533eSVincent Franchomme if (changed) {
3845c982533eSVincent Franchomme fileref->fcb->extents_changed = true;
3846c982533eSVincent Franchomme mark_fcb_dirty(fileref->fcb);
3847c982533eSVincent Franchomme }
3848c982533eSVincent Franchomme
3849c982533eSVincent Franchomme fileref->fcb->Header.Flags2 |= FSRTL_FLAG2_IS_PAGING_FILE;
3850c982533eSVincent Franchomme }
3851c982533eSVincent Franchomme
3852c982533eSVincent Franchomme #ifdef DEBUG_FCB_REFCOUNTS
3853c982533eSVincent Franchomme LONG oc = InterlockedIncrement(&fileref->open_count);
3854c982533eSVincent Franchomme ERR("fileref %p: open_count now %i\n", fileref, oc);
3855c982533eSVincent Franchomme #else
3856c982533eSVincent Franchomme InterlockedIncrement(&fileref->open_count);
3857c982533eSVincent Franchomme #endif
3858c982533eSVincent Franchomme InterlockedIncrement(&Vcb->open_files);
3859c982533eSVincent Franchomme
3860c982533eSVincent Franchomme return STATUS_SUCCESS;
3861c982533eSVincent Franchomme }
3862c982533eSVincent Franchomme
oplock_complete(PVOID Context,PIRP Irp)38636e0cf03dSVincent Franchomme static void __stdcall oplock_complete(PVOID Context, PIRP Irp) {
3864c982533eSVincent Franchomme NTSTATUS Status;
3865c982533eSVincent Franchomme LIST_ENTRY rollback;
3866c982533eSVincent Franchomme bool skip_lock;
3867c982533eSVincent Franchomme oplock_context* ctx = Context;
3868c982533eSVincent Franchomme device_extension* Vcb = ctx->Vcb;
3869c982533eSVincent Franchomme
3870c982533eSVincent Franchomme TRACE("(%p, %p)\n", Context, Irp);
3871c982533eSVincent Franchomme
3872c982533eSVincent Franchomme InitializeListHead(&rollback);
3873c982533eSVincent Franchomme
3874c982533eSVincent Franchomme skip_lock = ExIsResourceAcquiredExclusiveLite(&Vcb->tree_lock);
3875c982533eSVincent Franchomme
3876c982533eSVincent Franchomme if (!skip_lock)
3877c982533eSVincent Franchomme ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
3878c982533eSVincent Franchomme
3879c982533eSVincent Franchomme ExAcquireResourceSharedLite(&Vcb->fileref_lock, true);
3880c982533eSVincent Franchomme
3881c982533eSVincent Franchomme // FIXME - trans
3882c982533eSVincent Franchomme Status = open_file3(Vcb, Irp, ctx->granted_access, ctx->fileref, &rollback);
3883c982533eSVincent Franchomme
3884c982533eSVincent Franchomme if (!NT_SUCCESS(Status)) {
3885c982533eSVincent Franchomme free_fileref(ctx->fileref);
3886c982533eSVincent Franchomme do_rollback(ctx->Vcb, &rollback);
3887c982533eSVincent Franchomme } else
3888c982533eSVincent Franchomme clear_rollback(&rollback);
3889c982533eSVincent Franchomme
3890c982533eSVincent Franchomme ExReleaseResourceLite(&Vcb->fileref_lock);
3891c982533eSVincent Franchomme
3892c982533eSVincent Franchomme if (Status == STATUS_SUCCESS) {
3893c982533eSVincent Franchomme fcb* fcb2;
3894c982533eSVincent Franchomme PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
3895c982533eSVincent Franchomme PFILE_OBJECT FileObject = IrpSp->FileObject;
3896c982533eSVincent Franchomme bool skip_fcb_lock;
3897c982533eSVincent Franchomme
3898c982533eSVincent Franchomme IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess |= ctx->granted_access;
3899c982533eSVincent Franchomme IrpSp->Parameters.Create.SecurityContext->AccessState->RemainingDesiredAccess &= ~(ctx->granted_access | MAXIMUM_ALLOWED);
3900c982533eSVincent Franchomme
3901c982533eSVincent Franchomme if (!FileObject->Vpb)
3902c982533eSVincent Franchomme FileObject->Vpb = Vcb->devobj->Vpb;
3903c982533eSVincent Franchomme
3904c982533eSVincent Franchomme fcb2 = FileObject->FsContext;
3905c982533eSVincent Franchomme
3906c982533eSVincent Franchomme if (fcb2->ads) {
3907c982533eSVincent Franchomme struct _ccb* ccb2 = FileObject->FsContext2;
3908c982533eSVincent Franchomme
3909c982533eSVincent Franchomme fcb2 = ccb2->fileref->parent->fcb;
3910c982533eSVincent Franchomme }
3911c982533eSVincent Franchomme
3912c982533eSVincent Franchomme skip_fcb_lock = ExIsResourceAcquiredExclusiveLite(fcb2->Header.Resource);
3913c982533eSVincent Franchomme
3914c982533eSVincent Franchomme if (!skip_fcb_lock)
3915c982533eSVincent Franchomme ExAcquireResourceExclusiveLite(fcb2->Header.Resource, true);
3916c982533eSVincent Franchomme
3917c982533eSVincent Franchomme fcb_load_csums(Vcb, fcb2, Irp);
3918c982533eSVincent Franchomme
3919c982533eSVincent Franchomme if (!skip_fcb_lock)
3920c982533eSVincent Franchomme ExReleaseResourceLite(fcb2->Header.Resource);
3921c982533eSVincent Franchomme }
3922c982533eSVincent Franchomme
3923c982533eSVincent Franchomme if (!skip_lock)
3924c982533eSVincent Franchomme ExReleaseResourceLite(&Vcb->tree_lock);
3925c982533eSVincent Franchomme
3926c982533eSVincent Franchomme // FIXME - call free_trans if failed and within transaction
3927c982533eSVincent Franchomme
3928c982533eSVincent Franchomme Irp->IoStatus.Status = Status;
3929c982533eSVincent Franchomme IoCompleteRequest(Irp, NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
3930c982533eSVincent Franchomme
39316e0cf03dSVincent Franchomme ctx->Status = Status;
39326e0cf03dSVincent Franchomme
39336e0cf03dSVincent Franchomme KeSetEvent(&ctx->event, 0, false);
3934c982533eSVincent Franchomme }
3935c982533eSVincent Franchomme
open_file2(device_extension * Vcb,ULONG RequestedDisposition,file_ref * fileref,ACCESS_MASK * granted_access,PFILE_OBJECT FileObject,UNICODE_STRING * fn,ULONG options,PIRP Irp,LIST_ENTRY * rollback,oplock_context ** opctx)3936c982533eSVincent Franchomme static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, file_ref* fileref, ACCESS_MASK* granted_access,
39376e0cf03dSVincent Franchomme PFILE_OBJECT FileObject, UNICODE_STRING* fn, ULONG options, PIRP Irp, LIST_ENTRY* rollback,
39386e0cf03dSVincent Franchomme oplock_context** opctx) {
3939883b1f31SPierre Schweitzer NTSTATUS Status;
3940883b1f31SPierre Schweitzer file_ref* sf;
3941318da0c1SPierre Schweitzer bool readonly;
3942883b1f31SPierre Schweitzer PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
3943883b1f31SPierre Schweitzer
3944883b1f31SPierre Schweitzer if (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF) {
3945883b1f31SPierre Schweitzer LARGE_INTEGER zero;
3946883b1f31SPierre Schweitzer
3947883b1f31SPierre Schweitzer if (fileref->fcb->type == BTRFS_TYPE_DIRECTORY || is_subvol_readonly(fileref->fcb->subvol, Irp)) {
3948b826992aSVincent Franchomme Status = STATUS_ACCESS_DENIED;
3949b826992aSVincent Franchomme goto end;
3950883b1f31SPierre Schweitzer }
3951883b1f31SPierre Schweitzer
3952883b1f31SPierre Schweitzer if (Vcb->readonly) {
3953b826992aSVincent Franchomme Status = STATUS_MEDIA_WRITE_PROTECTED;
3954b826992aSVincent Franchomme goto end;
3955883b1f31SPierre Schweitzer }
3956883b1f31SPierre Schweitzer
3957883b1f31SPierre Schweitzer zero.QuadPart = 0;
3958883b1f31SPierre Schweitzer if (!MmCanFileBeTruncated(&fileref->fcb->nonpaged->segment_object, &zero)) {
3959b826992aSVincent Franchomme Status = STATUS_USER_MAPPED_FILE;
3960b826992aSVincent Franchomme goto end;
3961883b1f31SPierre Schweitzer }
3962883b1f31SPierre Schweitzer }
3963883b1f31SPierre Schweitzer
3964883b1f31SPierre Schweitzer if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess != 0) {
3965883b1f31SPierre Schweitzer SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
3966883b1f31SPierre Schweitzer
3967883b1f31SPierre Schweitzer if (!SeAccessCheck((fileref->fcb->ads || fileref->fcb == Vcb->dummy_fcb) ? fileref->parent->fcb->sd : fileref->fcb->sd,
3968883b1f31SPierre Schweitzer &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
3969318da0c1SPierre Schweitzer true, IrpSp->Parameters.Create.SecurityContext->DesiredAccess, 0, NULL,
3970883b1f31SPierre Schweitzer IoGetFileObjectGenericMapping(), IrpSp->Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode,
3971883b1f31SPierre Schweitzer granted_access, &Status)) {
3972883b1f31SPierre Schweitzer SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
3973194ea909SVictor Perevertkin TRACE("SeAccessCheck failed, returning %08lx\n", Status);
3974b826992aSVincent Franchomme goto end;
3975883b1f31SPierre Schweitzer }
3976883b1f31SPierre Schweitzer
3977883b1f31SPierre Schweitzer SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
3978883b1f31SPierre Schweitzer } else
3979883b1f31SPierre Schweitzer *granted_access = 0;
3980883b1f31SPierre Schweitzer
3981318da0c1SPierre Schweitzer TRACE("deleted = %s\n", fileref->deleted ? "true" : "false");
3982883b1f31SPierre Schweitzer
3983883b1f31SPierre Schweitzer sf = fileref;
3984883b1f31SPierre Schweitzer while (sf) {
3985883b1f31SPierre Schweitzer if (sf->delete_on_close) {
3986883b1f31SPierre Schweitzer TRACE("could not open as deletion pending\n");
3987b826992aSVincent Franchomme Status = STATUS_DELETE_PENDING;
3988b826992aSVincent Franchomme goto end;
3989883b1f31SPierre Schweitzer }
3990883b1f31SPierre Schweitzer sf = sf->parent;
3991883b1f31SPierre Schweitzer }
3992883b1f31SPierre Schweitzer
3993174dfab6SVincent Franchomme readonly = (!fileref->fcb->ads && fileref->fcb->atts & FILE_ATTRIBUTE_READONLY && !(IrpSp->Flags & SL_IGNORE_READONLY_ATTRIBUTE)) ||
3994174dfab6SVincent Franchomme (fileref->fcb->ads && fileref->parent->fcb->atts & FILE_ATTRIBUTE_READONLY && !(IrpSp->Flags & SL_IGNORE_READONLY_ATTRIBUTE)) ||
3995883b1f31SPierre Schweitzer is_subvol_readonly(fileref->fcb->subvol, Irp) || fileref->fcb == Vcb->dummy_fcb || Vcb->readonly;
3996883b1f31SPierre Schweitzer
3997883b1f31SPierre Schweitzer if (options & FILE_DELETE_ON_CLOSE && (fileref == Vcb->root_fileref || readonly)) {
3998b826992aSVincent Franchomme Status = STATUS_CANNOT_DELETE;
3999b826992aSVincent Franchomme goto end;
4000883b1f31SPierre Schweitzer }
4001883b1f31SPierre Schweitzer
40026e0cf03dSVincent Franchomme readonly |= fileref->fcb->inode_item.flags_ro & BTRFS_INODE_RO_VERITY;
40036e0cf03dSVincent Franchomme
4004883b1f31SPierre Schweitzer if (readonly) {
4005883b1f31SPierre Schweitzer ACCESS_MASK allowed;
4006883b1f31SPierre Schweitzer
4007883b1f31SPierre Schweitzer allowed = READ_CONTROL | SYNCHRONIZE | ACCESS_SYSTEM_SECURITY | FILE_READ_DATA |
4008883b1f31SPierre Schweitzer FILE_READ_EA | FILE_READ_ATTRIBUTES | FILE_EXECUTE | FILE_LIST_DIRECTORY |
4009883b1f31SPierre Schweitzer FILE_TRAVERSE;
4010883b1f31SPierre Schweitzer
4011883b1f31SPierre Schweitzer if (!Vcb->readonly && (fileref->fcb == Vcb->dummy_fcb || fileref->fcb->inode == SUBVOL_ROOT_INODE))
4012883b1f31SPierre Schweitzer allowed |= DELETE;
4013883b1f31SPierre Schweitzer
4014883b1f31SPierre Schweitzer if (fileref->fcb != Vcb->dummy_fcb && !is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) {
4015883b1f31SPierre Schweitzer allowed |= DELETE | WRITE_OWNER | WRITE_DAC | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES;
4016883b1f31SPierre Schweitzer
4017883b1f31SPierre Schweitzer if (!fileref->fcb->ads && fileref->fcb->type == BTRFS_TYPE_DIRECTORY)
4018883b1f31SPierre Schweitzer allowed |= FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE | FILE_DELETE_CHILD;
4019883b1f31SPierre Schweitzer } else if (fileref->fcb->inode == SUBVOL_ROOT_INODE && is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) {
4020883b1f31SPierre Schweitzer // We allow a subvolume root to be opened read-write even if its readonly flag is set, so it can be cleared
4021883b1f31SPierre Schweitzer
4022883b1f31SPierre Schweitzer allowed |= FILE_WRITE_ATTRIBUTES;
4023883b1f31SPierre Schweitzer }
4024883b1f31SPierre Schweitzer
4025883b1f31SPierre Schweitzer if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess & MAXIMUM_ALLOWED) {
4026883b1f31SPierre Schweitzer *granted_access &= allowed;
4027883b1f31SPierre Schweitzer IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess &= allowed;
4028883b1f31SPierre Schweitzer } else if (*granted_access & ~allowed) {
4029b826992aSVincent Franchomme Status = Vcb->readonly ? STATUS_MEDIA_WRITE_PROTECTED : STATUS_ACCESS_DENIED;
4030b826992aSVincent Franchomme goto end;
4031883b1f31SPierre Schweitzer }
4032c982533eSVincent Franchomme
4033c982533eSVincent Franchomme if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF) {
4034c982533eSVincent Franchomme WARN("cannot overwrite readonly file\n");
4035c982533eSVincent Franchomme Status = STATUS_ACCESS_DENIED;
4036c982533eSVincent Franchomme goto end;
4037c982533eSVincent Franchomme }
4038883b1f31SPierre Schweitzer }
4039883b1f31SPierre Schweitzer
4040883b1f31SPierre Schweitzer if ((fileref->fcb->type == BTRFS_TYPE_SYMLINK || fileref->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT) && !(options & FILE_OPEN_REPARSE_POINT)) {
4041883b1f31SPierre Schweitzer REPARSE_DATA_BUFFER* data;
4042883b1f31SPierre Schweitzer
4043883b1f31SPierre Schweitzer /* How reparse points work from the point of view of the filesystem appears to
4044883b1f31SPierre Schweitzer * undocumented. When returning STATUS_REPARSE, MSDN encourages us to return
4045883b1f31SPierre Schweitzer * IO_REPARSE in Irp->IoStatus.Information, but that means we have to do our own
4046883b1f31SPierre Schweitzer * translation. If we instead return the reparse tag in Information, and store
4047883b1f31SPierre Schweitzer * a pointer to the reparse data buffer in Irp->Tail.Overlay.AuxiliaryBuffer,
4048883b1f31SPierre Schweitzer * IopSymlinkProcessReparse will do the translation for us. */
4049883b1f31SPierre Schweitzer
4050318da0c1SPierre Schweitzer Status = get_reparse_block(fileref->fcb, (uint8_t**)&data);
4051883b1f31SPierre Schweitzer if (!NT_SUCCESS(Status)) {
4052194ea909SVictor Perevertkin ERR("get_reparse_block returned %08lx\n", Status);
4053883b1f31SPierre Schweitzer Status = STATUS_SUCCESS;
4054883b1f31SPierre Schweitzer } else {
4055883b1f31SPierre Schweitzer Irp->IoStatus.Information = data->ReparseTag;
4056883b1f31SPierre Schweitzer
4057883b1f31SPierre Schweitzer if (fn->Buffer[(fn->Length / sizeof(WCHAR)) - 1] == '\\')
4058883b1f31SPierre Schweitzer data->Reserved = sizeof(WCHAR);
4059883b1f31SPierre Schweitzer
4060883b1f31SPierre Schweitzer Irp->Tail.Overlay.AuxiliaryBuffer = (void*)data;
4061883b1f31SPierre Schweitzer
4062b826992aSVincent Franchomme Status = STATUS_REPARSE;
4063b826992aSVincent Franchomme goto end;
4064883b1f31SPierre Schweitzer }
4065883b1f31SPierre Schweitzer }
4066883b1f31SPierre Schweitzer
4067883b1f31SPierre Schweitzer if (fileref->fcb->type == BTRFS_TYPE_DIRECTORY && !fileref->fcb->ads) {
4068883b1f31SPierre Schweitzer if (options & FILE_NON_DIRECTORY_FILE && !(fileref->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT)) {
4069b826992aSVincent Franchomme Status = STATUS_FILE_IS_A_DIRECTORY;
4070b826992aSVincent Franchomme goto end;
4071883b1f31SPierre Schweitzer }
4072883b1f31SPierre Schweitzer } else if (options & FILE_DIRECTORY_FILE) {
407362e630deSPierre Schweitzer TRACE("returning STATUS_NOT_A_DIRECTORY (type = %u)\n", fileref->fcb->type);
4074b826992aSVincent Franchomme Status = STATUS_NOT_A_DIRECTORY;
4075b826992aSVincent Franchomme goto end;
4076883b1f31SPierre Schweitzer }
4077883b1f31SPierre Schweitzer
4078883b1f31SPierre Schweitzer if (fileref->open_count > 0) {
4079c982533eSVincent Franchomme oplock_context* ctx;
4080c982533eSVincent Franchomme
4081318da0c1SPierre Schweitzer Status = IoCheckShareAccess(*granted_access, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access, false);
4082883b1f31SPierre Schweitzer
4083883b1f31SPierre Schweitzer if (!NT_SUCCESS(Status)) {
4084883b1f31SPierre Schweitzer if (Status == STATUS_SHARING_VIOLATION)
4085194ea909SVictor Perevertkin TRACE("IoCheckShareAccess failed, returning %08lx\n", Status);
4086883b1f31SPierre Schweitzer else
4087194ea909SVictor Perevertkin WARN("IoCheckShareAccess failed, returning %08lx\n", Status);
4088883b1f31SPierre Schweitzer
4089b826992aSVincent Franchomme goto end;
4090883b1f31SPierre Schweitzer }
4091883b1f31SPierre Schweitzer
4092c982533eSVincent Franchomme ctx = ExAllocatePoolWithTag(NonPagedPool, sizeof(oplock_context), ALLOC_TAG);
4093c982533eSVincent Franchomme if (!ctx) {
4094c982533eSVincent Franchomme ERR("out of memory\n");
4095c982533eSVincent Franchomme Status = STATUS_INSUFFICIENT_RESOURCES;
4096c982533eSVincent Franchomme goto end;
4097c982533eSVincent Franchomme }
4098c982533eSVincent Franchomme
4099c982533eSVincent Franchomme ctx->Vcb = Vcb;
4100c982533eSVincent Franchomme ctx->granted_access = *granted_access;
4101c982533eSVincent Franchomme ctx->fileref = fileref;
41026e0cf03dSVincent Franchomme KeInitializeEvent(&ctx->event, NotificationEvent, false);
4103c982533eSVincent Franchomme #ifdef __REACTOS__
4104c982533eSVincent Franchomme Status = FsRtlCheckOplock(fcb_oplock(fileref->fcb), Irp, ctx, (POPLOCK_WAIT_COMPLETE_ROUTINE) oplock_complete, NULL);
4105c982533eSVincent Franchomme #else
4106c982533eSVincent Franchomme Status = FsRtlCheckOplock(fcb_oplock(fileref->fcb), Irp, ctx, oplock_complete, NULL);
4107c982533eSVincent Franchomme #endif /* __REACTOS__ */
41086e0cf03dSVincent Franchomme if (Status == STATUS_PENDING) {
41096e0cf03dSVincent Franchomme *opctx = ctx;
4110c982533eSVincent Franchomme return Status;
41116e0cf03dSVincent Franchomme }
4112c982533eSVincent Franchomme
4113c982533eSVincent Franchomme ExFreePool(ctx);
4114c982533eSVincent Franchomme
4115c982533eSVincent Franchomme if (!NT_SUCCESS(Status)) {
4116c982533eSVincent Franchomme WARN("FsRtlCheckOplock returned %08lx\n", Status);
4117c982533eSVincent Franchomme goto end;
4118c982533eSVincent Franchomme }
4119c982533eSVincent Franchomme
4120883b1f31SPierre Schweitzer IoUpdateShareAccess(FileObject, &fileref->fcb->share_access);
4121883b1f31SPierre Schweitzer } else
4122883b1f31SPierre Schweitzer IoSetShareAccess(*granted_access, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access);
4123883b1f31SPierre Schweitzer
4124c982533eSVincent Franchomme Status = open_file3(Vcb, Irp, *granted_access, fileref, rollback);
4125883b1f31SPierre Schweitzer
4126b826992aSVincent Franchomme if (!NT_SUCCESS(Status))
4127b826992aSVincent Franchomme IoRemoveShareAccess(FileObject, &fileref->fcb->share_access);
4128b826992aSVincent Franchomme
4129b826992aSVincent Franchomme end:
4130b826992aSVincent Franchomme if (!NT_SUCCESS(Status))
4131b826992aSVincent Franchomme free_fileref(fileref);
4132b826992aSVincent Franchomme
4133b826992aSVincent Franchomme return Status;
4134883b1f31SPierre Schweitzer }
4135883b1f31SPierre Schweitzer
4136883b1f31SPierre Schweitzer NTSTATUS open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension* Vcb,
4137318da0c1SPierre Schweitzer root* subvol, uint64_t inode, file_ref** pfr, PIRP Irp) {
4138883b1f31SPierre Schweitzer NTSTATUS Status;
4139883b1f31SPierre Schweitzer fcb* fcb;
4140318da0c1SPierre Schweitzer uint64_t parent = 0;
4141883b1f31SPierre Schweitzer UNICODE_STRING name;
4142318da0c1SPierre Schweitzer bool hl_alloc = false;
4143883b1f31SPierre Schweitzer file_ref *parfr, *fr;
4144883b1f31SPierre Schweitzer
4145318da0c1SPierre Schweitzer Status = open_fcb(Vcb, subvol, inode, 0, NULL, true, NULL, &fcb, PagedPool, Irp);
4146883b1f31SPierre Schweitzer if (!NT_SUCCESS(Status)) {
4147194ea909SVictor Perevertkin ERR("open_fcb returned %08lx\n", Status);
4148883b1f31SPierre Schweitzer return Status;
4149883b1f31SPierre Schweitzer }
4150883b1f31SPierre Schweitzer
4151318da0c1SPierre Schweitzer ExAcquireResourceSharedLite(fcb->Header.Resource, true);
4152f381137cSPierre Schweitzer
4153f381137cSPierre Schweitzer if (fcb->inode_item.st_nlink == 0 || fcb->deleted) {
4154f381137cSPierre Schweitzer ExReleaseResourceLite(fcb->Header.Resource);
4155f381137cSPierre Schweitzer free_fcb(fcb);
4156f381137cSPierre Schweitzer return STATUS_OBJECT_NAME_NOT_FOUND;
4157f381137cSPierre Schweitzer }
4158f381137cSPierre Schweitzer
4159883b1f31SPierre Schweitzer if (fcb->fileref) {
4160883b1f31SPierre Schweitzer *pfr = fcb->fileref;
4161883b1f31SPierre Schweitzer increase_fileref_refcount(fcb->fileref);
4162f381137cSPierre Schweitzer free_fcb(fcb);
4163f381137cSPierre Schweitzer ExReleaseResourceLite(fcb->Header.Resource);
4164883b1f31SPierre Schweitzer return STATUS_SUCCESS;
4165883b1f31SPierre Schweitzer }
4166883b1f31SPierre Schweitzer
4167f381137cSPierre Schweitzer if (IsListEmpty(&fcb->hardlinks)) {
4168f381137cSPierre Schweitzer ExReleaseResourceLite(fcb->Header.Resource);
4169f381137cSPierre Schweitzer
4170318da0c1SPierre Schweitzer ExAcquireResourceSharedLite(&Vcb->dirty_filerefs_lock, true);
4171f381137cSPierre Schweitzer
4172f381137cSPierre Schweitzer if (!IsListEmpty(&Vcb->dirty_filerefs)) {
4173f381137cSPierre Schweitzer LIST_ENTRY* le = Vcb->dirty_filerefs.Flink;
4174f381137cSPierre Schweitzer while (le != &Vcb->dirty_filerefs) {
4175318da0c1SPierre Schweitzer fr = CONTAINING_RECORD(le, file_ref, list_entry_dirty);
4176f381137cSPierre Schweitzer
4177f381137cSPierre Schweitzer if (fr->fcb == fcb) {
4178f381137cSPierre Schweitzer ExReleaseResourceLite(&Vcb->dirty_filerefs_lock);
4179f381137cSPierre Schweitzer increase_fileref_refcount(fr);
4180f381137cSPierre Schweitzer free_fcb(fcb);
4181f381137cSPierre Schweitzer *pfr = fr;
4182f381137cSPierre Schweitzer return STATUS_SUCCESS;
4183f381137cSPierre Schweitzer }
4184f381137cSPierre Schweitzer
4185f381137cSPierre Schweitzer le = le->Flink;
4186f381137cSPierre Schweitzer }
4187f381137cSPierre Schweitzer }
4188f381137cSPierre Schweitzer
4189f381137cSPierre Schweitzer ExReleaseResourceLite(&Vcb->dirty_filerefs_lock);
4190f381137cSPierre Schweitzer
4191f381137cSPierre Schweitzer {
4192f381137cSPierre Schweitzer KEY searchkey;
4193f381137cSPierre Schweitzer traverse_ptr tp;
4194f381137cSPierre Schweitzer
4195f381137cSPierre Schweitzer searchkey.obj_id = fcb->inode;
4196f381137cSPierre Schweitzer searchkey.obj_type = TYPE_INODE_REF;
4197f381137cSPierre Schweitzer searchkey.offset = 0;
4198f381137cSPierre Schweitzer
4199318da0c1SPierre Schweitzer Status = find_item(Vcb, subvol, &tp, &searchkey, false, Irp);
4200f381137cSPierre Schweitzer if (!NT_SUCCESS(Status)) {
4201194ea909SVictor Perevertkin ERR("find_item returned %08lx\n", Status);
4202f381137cSPierre Schweitzer free_fcb(fcb);
4203f381137cSPierre Schweitzer return Status;
4204f381137cSPierre Schweitzer }
4205f381137cSPierre Schweitzer
4206f381137cSPierre Schweitzer do {
4207f381137cSPierre Schweitzer traverse_ptr next_tp;
4208f381137cSPierre Schweitzer
4209f381137cSPierre Schweitzer if (tp.item->key.obj_id > fcb->inode || (tp.item->key.obj_id == fcb->inode && tp.item->key.obj_type > TYPE_INODE_EXTREF))
4210f381137cSPierre Schweitzer break;
4211f381137cSPierre Schweitzer
4212f381137cSPierre Schweitzer if (tp.item->key.obj_id == fcb->inode) {
4213f381137cSPierre Schweitzer if (tp.item->key.obj_type == TYPE_INODE_REF) {
4214f381137cSPierre Schweitzer INODE_REF* ir = (INODE_REF*)tp.item->data;
4215883b1f31SPierre Schweitzer
4216f381137cSPierre Schweitzer if (tp.item->size < offsetof(INODE_REF, name[0]) || tp.item->size < offsetof(INODE_REF, name[0]) + ir->n) {
4217f381137cSPierre Schweitzer ERR("INODE_REF was too short\n");
4218f381137cSPierre Schweitzer free_fcb(fcb);
4219f381137cSPierre Schweitzer return STATUS_INTERNAL_ERROR;
4220f381137cSPierre Schweitzer }
4221f381137cSPierre Schweitzer
4222f381137cSPierre Schweitzer ULONG stringlen;
4223f381137cSPierre Schweitzer
4224318da0c1SPierre Schweitzer Status = utf8_to_utf16(NULL, 0, &stringlen, ir->name, ir->n);
4225f381137cSPierre Schweitzer if (!NT_SUCCESS(Status)) {
4226194ea909SVictor Perevertkin ERR("utf8_to_utf16 1 returned %08lx\n", Status);
4227f381137cSPierre Schweitzer free_fcb(fcb);
4228f381137cSPierre Schweitzer return Status;
4229f381137cSPierre Schweitzer }
4230f381137cSPierre Schweitzer
4231318da0c1SPierre Schweitzer name.Length = name.MaximumLength = (uint16_t)stringlen;
4232f381137cSPierre Schweitzer
4233f381137cSPierre Schweitzer if (stringlen == 0)
4234f381137cSPierre Schweitzer name.Buffer = NULL;
4235f381137cSPierre Schweitzer else {
4236f381137cSPierre Schweitzer name.Buffer = ExAllocatePoolWithTag(PagedPool, name.MaximumLength, ALLOC_TAG);
4237f381137cSPierre Schweitzer
4238f381137cSPierre Schweitzer if (!name.Buffer) {
4239f381137cSPierre Schweitzer ERR("out of memory\n");
4240f381137cSPierre Schweitzer free_fcb(fcb);
4241f381137cSPierre Schweitzer return STATUS_INSUFFICIENT_RESOURCES;
4242f381137cSPierre Schweitzer }
4243f381137cSPierre Schweitzer
4244318da0c1SPierre Schweitzer Status = utf8_to_utf16(name.Buffer, stringlen, &stringlen, ir->name, ir->n);
4245f381137cSPierre Schweitzer if (!NT_SUCCESS(Status)) {
4246194ea909SVictor Perevertkin ERR("utf8_to_utf16 2 returned %08lx\n", Status);
4247f381137cSPierre Schweitzer ExFreePool(name.Buffer);
4248f381137cSPierre Schweitzer free_fcb(fcb);
4249f381137cSPierre Schweitzer return Status;
4250f381137cSPierre Schweitzer }
4251f381137cSPierre Schweitzer
4252318da0c1SPierre Schweitzer hl_alloc = true;
4253f381137cSPierre Schweitzer }
4254f381137cSPierre Schweitzer
4255f381137cSPierre Schweitzer parent = tp.item->key.offset;
4256f381137cSPierre Schweitzer
4257f381137cSPierre Schweitzer break;
4258f381137cSPierre Schweitzer } else if (tp.item->key.obj_type == TYPE_INODE_EXTREF) {
4259f381137cSPierre Schweitzer INODE_EXTREF* ier = (INODE_EXTREF*)tp.item->data;
4260f381137cSPierre Schweitzer
4261f381137cSPierre Schweitzer if (tp.item->size < offsetof(INODE_EXTREF, name[0]) || tp.item->size < offsetof(INODE_EXTREF, name[0]) + ier->n) {
4262f381137cSPierre Schweitzer ERR("INODE_EXTREF was too short\n");
4263f381137cSPierre Schweitzer free_fcb(fcb);
4264f381137cSPierre Schweitzer return STATUS_INTERNAL_ERROR;
4265f381137cSPierre Schweitzer }
4266f381137cSPierre Schweitzer
4267f381137cSPierre Schweitzer ULONG stringlen;
4268f381137cSPierre Schweitzer
4269318da0c1SPierre Schweitzer Status = utf8_to_utf16(NULL, 0, &stringlen, ier->name, ier->n);
4270f381137cSPierre Schweitzer if (!NT_SUCCESS(Status)) {
4271194ea909SVictor Perevertkin ERR("utf8_to_utf16 1 returned %08lx\n", Status);
4272f381137cSPierre Schweitzer free_fcb(fcb);
4273f381137cSPierre Schweitzer return Status;
4274f381137cSPierre Schweitzer }
4275f381137cSPierre Schweitzer
4276318da0c1SPierre Schweitzer name.Length = name.MaximumLength = (uint16_t)stringlen;
4277f381137cSPierre Schweitzer
4278f381137cSPierre Schweitzer if (stringlen == 0)
4279f381137cSPierre Schweitzer name.Buffer = NULL;
4280f381137cSPierre Schweitzer else {
4281f381137cSPierre Schweitzer name.Buffer = ExAllocatePoolWithTag(PagedPool, name.MaximumLength, ALLOC_TAG);
4282f381137cSPierre Schweitzer
4283f381137cSPierre Schweitzer if (!name.Buffer) {
4284f381137cSPierre Schweitzer ERR("out of memory\n");
4285f381137cSPierre Schweitzer free_fcb(fcb);
4286f381137cSPierre Schweitzer return STATUS_INSUFFICIENT_RESOURCES;
4287f381137cSPierre Schweitzer }
4288f381137cSPierre Schweitzer
4289318da0c1SPierre Schweitzer Status = utf8_to_utf16(name.Buffer, stringlen, &stringlen, ier->name, ier->n);
4290f381137cSPierre Schweitzer if (!NT_SUCCESS(Status)) {
4291194ea909SVictor Perevertkin ERR("utf8_to_utf16 2 returned %08lx\n", Status);
4292f381137cSPierre Schweitzer ExFreePool(name.Buffer);
4293f381137cSPierre Schweitzer free_fcb(fcb);
4294f381137cSPierre Schweitzer return Status;
4295f381137cSPierre Schweitzer }
4296f381137cSPierre Schweitzer
4297318da0c1SPierre Schweitzer hl_alloc = true;
4298f381137cSPierre Schweitzer }
4299f381137cSPierre Schweitzer
4300f381137cSPierre Schweitzer parent = ier->dir;
4301f381137cSPierre Schweitzer
4302f381137cSPierre Schweitzer break;
4303f381137cSPierre Schweitzer }
4304f381137cSPierre Schweitzer }
4305f381137cSPierre Schweitzer
4306318da0c1SPierre Schweitzer if (find_next_item(Vcb, &tp, &next_tp, false, Irp))
4307f381137cSPierre Schweitzer tp = next_tp;
4308f381137cSPierre Schweitzer else
4309f381137cSPierre Schweitzer break;
4310318da0c1SPierre Schweitzer } while (true);
4311f381137cSPierre Schweitzer }
4312f381137cSPierre Schweitzer
4313f381137cSPierre Schweitzer if (parent == 0) {
4314f381137cSPierre Schweitzer WARN("trying to open inode with no references\n");
4315f381137cSPierre Schweitzer free_fcb(fcb);
4316f381137cSPierre Schweitzer return STATUS_INVALID_PARAMETER;
4317f381137cSPierre Schweitzer }
4318f381137cSPierre Schweitzer } else {
4319f381137cSPierre Schweitzer hardlink* hl = CONTAINING_RECORD(fcb->hardlinks.Flink, hardlink, list_entry);
4320f381137cSPierre Schweitzer
4321883b1f31SPierre Schweitzer name = hl->name;
4322883b1f31SPierre Schweitzer parent = hl->parent;
4323883b1f31SPierre Schweitzer
4324f381137cSPierre Schweitzer ExReleaseResourceLite(fcb->Header.Resource);
4325f381137cSPierre Schweitzer }
4326f381137cSPierre Schweitzer
4327883b1f31SPierre Schweitzer if (parent == inode) { // subvolume root
4328883b1f31SPierre Schweitzer KEY searchkey;
4329883b1f31SPierre Schweitzer traverse_ptr tp;
4330883b1f31SPierre Schweitzer
4331883b1f31SPierre Schweitzer searchkey.obj_id = subvol->id;
4332883b1f31SPierre Schweitzer searchkey.obj_type = TYPE_ROOT_BACKREF;
4333883b1f31SPierre Schweitzer searchkey.offset = 0xffffffffffffffff;
4334883b1f31SPierre Schweitzer
4335318da0c1SPierre Schweitzer Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, false, Irp);
4336883b1f31SPierre Schweitzer if (!NT_SUCCESS(Status)) {
4337194ea909SVictor Perevertkin ERR("find_item returned %08lx\n", Status);
4338883b1f31SPierre Schweitzer free_fcb(fcb);
4339883b1f31SPierre Schweitzer return Status;
4340883b1f31SPierre Schweitzer }
4341883b1f31SPierre Schweitzer
4342883b1f31SPierre Schweitzer if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
4343883b1f31SPierre Schweitzer ROOT_REF* rr = (ROOT_REF*)tp.item->data;
4344883b1f31SPierre Schweitzer LIST_ENTRY* le;
4345883b1f31SPierre Schweitzer root* r = NULL;
4346883b1f31SPierre Schweitzer ULONG stringlen;
4347883b1f31SPierre Schweitzer
4348883b1f31SPierre Schweitzer if (tp.item->size < sizeof(ROOT_REF)) {
4349194ea909SVictor Perevertkin ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(ROOT_REF));
4350883b1f31SPierre Schweitzer free_fcb(fcb);
4351883b1f31SPierre Schweitzer return STATUS_INTERNAL_ERROR;
4352883b1f31SPierre Schweitzer }
4353883b1f31SPierre Schweitzer
4354883b1f31SPierre Schweitzer if (tp.item->size < offsetof(ROOT_REF, name[0]) + rr->n) {
4355194ea909SVictor Perevertkin ERR("(%I64x,%x,%I64x) was %u bytes, expected %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, offsetof(ROOT_REF, name[0]) + rr->n);
4356883b1f31SPierre Schweitzer free_fcb(fcb);
4357883b1f31SPierre Schweitzer return STATUS_INTERNAL_ERROR;
4358883b1f31SPierre Schweitzer }
4359883b1f31SPierre Schweitzer
4360883b1f31SPierre Schweitzer le = Vcb->roots.Flink;
4361883b1f31SPierre Schweitzer while (le != &Vcb->roots) {
4362883b1f31SPierre Schweitzer root* r2 = CONTAINING_RECORD(le, root, list_entry);
4363883b1f31SPierre Schweitzer
4364883b1f31SPierre Schweitzer if (r2->id == tp.item->key.offset) {
4365883b1f31SPierre Schweitzer r = r2;
4366883b1f31SPierre Schweitzer break;
4367883b1f31SPierre Schweitzer }
4368883b1f31SPierre Schweitzer
4369883b1f31SPierre Schweitzer le = le->Flink;
4370883b1f31SPierre Schweitzer }
4371883b1f31SPierre Schweitzer
4372883b1f31SPierre Schweitzer if (!r) {
4373318da0c1SPierre Schweitzer ERR("couldn't find subvol %I64x\n", tp.item->key.offset);
4374883b1f31SPierre Schweitzer free_fcb(fcb);
4375883b1f31SPierre Schweitzer return STATUS_INTERNAL_ERROR;
4376883b1f31SPierre Schweitzer }
4377883b1f31SPierre Schweitzer
4378883b1f31SPierre Schweitzer Status = open_fileref_by_inode(Vcb, r, rr->dir, &parfr, Irp);
4379883b1f31SPierre Schweitzer if (!NT_SUCCESS(Status)) {
4380194ea909SVictor Perevertkin ERR("open_fileref_by_inode returned %08lx\n", Status);
4381883b1f31SPierre Schweitzer free_fcb(fcb);
4382883b1f31SPierre Schweitzer return Status;
4383883b1f31SPierre Schweitzer }
4384883b1f31SPierre Schweitzer
4385318da0c1SPierre Schweitzer Status = utf8_to_utf16(NULL, 0, &stringlen, rr->name, rr->n);
4386883b1f31SPierre Schweitzer if (!NT_SUCCESS(Status)) {
4387194ea909SVictor Perevertkin ERR("utf8_to_utf16 1 returned %08lx\n", Status);
4388883b1f31SPierre Schweitzer free_fcb(fcb);
4389883b1f31SPierre Schweitzer return Status;
4390883b1f31SPierre Schweitzer }
4391883b1f31SPierre Schweitzer
4392318da0c1SPierre Schweitzer name.Length = name.MaximumLength = (uint16_t)stringlen;
4393883b1f31SPierre Schweitzer
4394883b1f31SPierre Schweitzer if (stringlen == 0)
4395883b1f31SPierre Schweitzer name.Buffer = NULL;
4396883b1f31SPierre Schweitzer else {
4397f381137cSPierre Schweitzer if (hl_alloc)
4398f381137cSPierre Schweitzer ExFreePool(name.Buffer);
4399f381137cSPierre Schweitzer
4400883b1f31SPierre Schweitzer name.Buffer = ExAllocatePoolWithTag(PagedPool, name.MaximumLength, ALLOC_TAG);
4401883b1f31SPierre Schweitzer
4402883b1f31SPierre Schweitzer if (!name.Buffer) {
4403883b1f31SPierre Schweitzer ERR("out of memory\n");
4404883b1f31SPierre Schweitzer free_fcb(fcb);
4405883b1f31SPierre Schweitzer return STATUS_INSUFFICIENT_RESOURCES;
4406883b1f31SPierre Schweitzer }
4407883b1f31SPierre Schweitzer
4408318da0c1SPierre Schweitzer Status = utf8_to_utf16(name.Buffer, stringlen, &stringlen, rr->name, rr->n);
4409883b1f31SPierre Schweitzer if (!NT_SUCCESS(Status)) {
4410194ea909SVictor Perevertkin ERR("utf8_to_utf16 2 returned %08lx\n", Status);
4411883b1f31SPierre Schweitzer ExFreePool(name.Buffer);
4412883b1f31SPierre Schweitzer free_fcb(fcb);
4413883b1f31SPierre Schweitzer return Status;
4414883b1f31SPierre Schweitzer }
4415883b1f31SPierre Schweitzer
4416318da0c1SPierre Schweitzer hl_alloc = true;
4417883b1f31SPierre Schweitzer }
4418883b1f31SPierre Schweitzer } else {
441962e630deSPierre Schweitzer if (!Vcb->options.no_root_dir && subvol->id == BTRFS_ROOT_FSTREE && Vcb->root_fileref->fcb->subvol != subvol) {
442062e630deSPierre Schweitzer Status = open_fileref_by_inode(Vcb, Vcb->root_fileref->fcb->subvol, SUBVOL_ROOT_INODE, &parfr, Irp);
442162e630deSPierre Schweitzer if (!NT_SUCCESS(Status)) {
4422194ea909SVictor Perevertkin ERR("open_fileref_by_inode returned %08lx\n", Status);
442362e630deSPierre Schweitzer free_fcb(fcb);
442462e630deSPierre Schweitzer return Status;
442562e630deSPierre Schweitzer }
442662e630deSPierre Schweitzer
442762e630deSPierre Schweitzer name.Length = name.MaximumLength = sizeof(root_dir_utf16) - sizeof(WCHAR);
442862e630deSPierre Schweitzer name.Buffer = (WCHAR*)root_dir_utf16;
442962e630deSPierre Schweitzer } else {
4430318da0c1SPierre Schweitzer ERR("couldn't find parent for subvol %I64x\n", subvol->id);
4431883b1f31SPierre Schweitzer free_fcb(fcb);
4432883b1f31SPierre Schweitzer return STATUS_INTERNAL_ERROR;
4433883b1f31SPierre Schweitzer }
443462e630deSPierre Schweitzer }
4435883b1f31SPierre Schweitzer } else {
4436883b1f31SPierre Schweitzer Status = open_fileref_by_inode(Vcb, subvol, parent, &parfr, Irp);
4437883b1f31SPierre Schweitzer if (!NT_SUCCESS(Status)) {
4438194ea909SVictor Perevertkin ERR("open_fileref_by_inode returned %08lx\n", Status);
4439883b1f31SPierre Schweitzer free_fcb(fcb);
4440883b1f31SPierre Schweitzer return Status;
4441883b1f31SPierre Schweitzer }
4442883b1f31SPierre Schweitzer }
4443883b1f31SPierre Schweitzer
4444318da0c1SPierre Schweitzer Status = open_fileref_child(Vcb, parfr, &name, true, true, false, PagedPool, &fr, Irp);
4445883b1f31SPierre Schweitzer
4446883b1f31SPierre Schweitzer if (hl_alloc)
4447883b1f31SPierre Schweitzer ExFreePool(name.Buffer);
4448883b1f31SPierre Schweitzer
4449883b1f31SPierre Schweitzer if (!NT_SUCCESS(Status)) {
4450194ea909SVictor Perevertkin ERR("open_fileref_child returned %08lx\n", Status);
4451883b1f31SPierre Schweitzer
4452883b1f31SPierre Schweitzer free_fcb(fcb);
4453883b1f31SPierre Schweitzer free_fileref(parfr);
4454883b1f31SPierre Schweitzer
4455883b1f31SPierre Schweitzer return Status;
4456883b1f31SPierre Schweitzer }
4457883b1f31SPierre Schweitzer
4458883b1f31SPierre Schweitzer *pfr = fr;
4459883b1f31SPierre Schweitzer
4460883b1f31SPierre Schweitzer free_fcb(fcb);
4461883b1f31SPierre Schweitzer free_fileref(parfr);
4462883b1f31SPierre Schweitzer
4463883b1f31SPierre Schweitzer return STATUS_SUCCESS;
4464883b1f31SPierre Schweitzer }
4465883b1f31SPierre Schweitzer
44666e0cf03dSVincent Franchomme static NTSTATUS open_file(PDEVICE_OBJECT DeviceObject, _Requires_lock_held_(_Curr_->tree_lock) device_extension* Vcb, PIRP Irp,
44676e0cf03dSVincent Franchomme LIST_ENTRY* rollback, oplock_context** opctx) {
4468c2c66affSColin Finck PFILE_OBJECT FileObject = NULL;
4469c2c66affSColin Finck ULONG RequestedDisposition;
4470c2c66affSColin Finck ULONG options;
4471c2c66affSColin Finck NTSTATUS Status;
4472c2c66affSColin Finck PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
4473c2c66affSColin Finck USHORT parsed;
4474c2c66affSColin Finck ULONG fn_offset = 0;
4475c2c66affSColin Finck file_ref *related, *fileref = NULL;
4476c2c66affSColin Finck POOL_TYPE pool_type = IrpSp->Flags & SL_OPEN_PAGING_FILE ? NonPagedPool : PagedPool;
4477c2c66affSColin Finck ACCESS_MASK granted_access;
4478318da0c1SPierre Schweitzer bool loaded_related = false;
4479c2c66affSColin Finck UNICODE_STRING fn;
4480c2c66affSColin Finck
4481c2c66affSColin Finck Irp->IoStatus.Information = 0;
4482c2c66affSColin Finck
4483c2c66affSColin Finck RequestedDisposition = ((IrpSp->Parameters.Create.Options >> 24) & 0xff);
4484c2c66affSColin Finck options = IrpSp->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
4485c2c66affSColin Finck
4486c2c66affSColin Finck if (options & FILE_DIRECTORY_FILE && RequestedDisposition == FILE_SUPERSEDE) {
4487c2c66affSColin Finck WARN("error - supersede requested with FILE_DIRECTORY_FILE\n");
4488c2c66affSColin Finck return STATUS_INVALID_PARAMETER;
4489c2c66affSColin Finck }
4490c2c66affSColin Finck
4491c2c66affSColin Finck FileObject = IrpSp->FileObject;
4492c2c66affSColin Finck
4493c2c66affSColin Finck if (!FileObject) {
4494c2c66affSColin Finck ERR("FileObject was NULL\n");
4495c2c66affSColin Finck return STATUS_INVALID_PARAMETER;
4496c2c66affSColin Finck }
4497c2c66affSColin Finck
4498c2c66affSColin Finck if (FileObject->RelatedFileObject && FileObject->RelatedFileObject->FsContext2) {
4499c2c66affSColin Finck struct _ccb* relatedccb = FileObject->RelatedFileObject->FsContext2;
4500c2c66affSColin Finck
4501c2c66affSColin Finck related = relatedccb->fileref;
4502c2c66affSColin Finck } else
4503c2c66affSColin Finck related = NULL;
4504c2c66affSColin Finck
4505c2c66affSColin Finck debug_create_options(options);
4506c2c66affSColin Finck
4507c2c66affSColin Finck switch (RequestedDisposition) {
4508c2c66affSColin Finck case FILE_SUPERSEDE:
4509c2c66affSColin Finck TRACE("requested disposition: FILE_SUPERSEDE\n");
4510c2c66affSColin Finck break;
4511c2c66affSColin Finck
4512c2c66affSColin Finck case FILE_CREATE:
4513c2c66affSColin Finck TRACE("requested disposition: FILE_CREATE\n");
4514c2c66affSColin Finck break;
4515c2c66affSColin Finck
4516c2c66affSColin Finck case FILE_OPEN:
4517c2c66affSColin Finck TRACE("requested disposition: FILE_OPEN\n");
4518c2c66affSColin Finck break;
4519c2c66affSColin Finck
4520c2c66affSColin Finck case FILE_OPEN_IF:
4521c2c66affSColin Finck TRACE("requested disposition: FILE_OPEN_IF\n");
4522c2c66affSColin Finck break;
4523c2c66affSColin Finck
4524c2c66affSColin Finck case FILE_OVERWRITE:
4525c2c66affSColin Finck TRACE("requested disposition: FILE_OVERWRITE\n");
4526c2c66affSColin Finck break;
4527c2c66affSColin Finck
4528c2c66affSColin Finck case FILE_OVERWRITE_IF:
4529c2c66affSColin Finck TRACE("requested disposition: FILE_OVERWRITE_IF\n");
4530c2c66affSColin Finck break;
4531c2c66affSColin Finck
4532c2c66affSColin Finck default:
4533194ea909SVictor Perevertkin ERR("unknown disposition: %lx\n", RequestedDisposition);
4534c2c66affSColin Finck Status = STATUS_NOT_IMPLEMENTED;
4535c2c66affSColin Finck goto exit;
4536c2c66affSColin Finck }
4537c2c66affSColin Finck
4538c2c66affSColin Finck fn = FileObject->FileName;
4539c2c66affSColin Finck
4540194ea909SVictor Perevertkin TRACE("(%.*S)\n", (int)(fn.Length / sizeof(WCHAR)), fn.Buffer);
4541c2c66affSColin Finck TRACE("FileObject = %p\n", FileObject);
4542c2c66affSColin Finck
4543c2c66affSColin Finck if (Vcb->readonly && (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == FILE_CREATE || RequestedDisposition == FILE_OVERWRITE)) {
4544c2c66affSColin Finck Status = STATUS_MEDIA_WRITE_PROTECTED;
4545c2c66affSColin Finck goto exit;
4546c2c66affSColin Finck }
4547c2c66affSColin Finck
4548c2c66affSColin Finck if (options & FILE_OPEN_BY_FILE_ID) {
4549f381137cSPierre Schweitzer if (RequestedDisposition != FILE_OPEN) {
4550f381137cSPierre Schweitzer WARN("FILE_OPEN_BY_FILE_ID not supported for anything other than FILE_OPEN\n");
4551f381137cSPierre Schweitzer Status = STATUS_INVALID_PARAMETER;
4552f381137cSPierre Schweitzer goto exit;
4553f381137cSPierre Schweitzer }
4554f381137cSPierre Schweitzer
4555318da0c1SPierre Schweitzer if (fn.Length == sizeof(uint64_t)) {
4556318da0c1SPierre Schweitzer uint64_t inode;
4557c2c66affSColin Finck
4558f381137cSPierre Schweitzer if (!related) {
4559*29d19382SJohannes Obermayr WARN("cannot open by short file ID unless related fileref also provided"\n);
4560f381137cSPierre Schweitzer Status = STATUS_INVALID_PARAMETER;
4561f381137cSPierre Schweitzer goto exit;
4562f381137cSPierre Schweitzer }
4563f381137cSPierre Schweitzer
4564194ea909SVictor Perevertkin inode = (*(uint64_t*)fn.Buffer) & 0xffffffffff;
4565c2c66affSColin Finck
4566c2c66affSColin Finck if (related->fcb == Vcb->root_fileref->fcb && inode == 0)
4567c2c66affSColin Finck inode = Vcb->root_fileref->fcb->inode;
4568c2c66affSColin Finck
4569c2c66affSColin Finck if (inode == 0) { // we use 0 to mean the parent of a subvolume
4570c2c66affSColin Finck fileref = related->parent;
4571c2c66affSColin Finck increase_fileref_refcount(fileref);
4572c2c66affSColin Finck Status = STATUS_SUCCESS;
4573883b1f31SPierre Schweitzer } else
4574c2c66affSColin Finck Status = open_fileref_by_inode(Vcb, related->fcb->subvol, inode, &fileref, Irp);
4575883b1f31SPierre Schweitzer
4576883b1f31SPierre Schweitzer goto loaded;
4577f381137cSPierre Schweitzer } else if (fn.Length == sizeof(FILE_ID_128)) {
4578318da0c1SPierre Schweitzer uint64_t inode, subvol_id;
4579f381137cSPierre Schweitzer root* subvol = NULL;
4580f381137cSPierre Schweitzer
4581318da0c1SPierre Schweitzer RtlCopyMemory(&inode, fn.Buffer, sizeof(uint64_t));
4582318da0c1SPierre Schweitzer RtlCopyMemory(&subvol_id, (uint8_t*)fn.Buffer + sizeof(uint64_t), sizeof(uint64_t));
4583f381137cSPierre Schweitzer
4584f381137cSPierre Schweitzer if (subvol_id == BTRFS_ROOT_FSTREE || (subvol_id >= 0x100 && subvol_id < 0x8000000000000000)) {
4585f381137cSPierre Schweitzer LIST_ENTRY* le = Vcb->roots.Flink;
4586f381137cSPierre Schweitzer while (le != &Vcb->roots) {
4587f381137cSPierre Schweitzer root* r = CONTAINING_RECORD(le, root, list_entry);
4588f381137cSPierre Schweitzer
4589f381137cSPierre Schweitzer if (r->id == subvol_id) {
4590f381137cSPierre Schweitzer subvol = r;
4591f381137cSPierre Schweitzer break;
4592f381137cSPierre Schweitzer }
4593f381137cSPierre Schweitzer
4594f381137cSPierre Schweitzer le = le->Flink;
4595f381137cSPierre Schweitzer }
4596f381137cSPierre Schweitzer }
4597f381137cSPierre Schweitzer
4598f381137cSPierre Schweitzer if (!subvol) {
4599318da0c1SPierre Schweitzer WARN("subvol %I64x not found\n", subvol_id);
4600f381137cSPierre Schweitzer Status = STATUS_OBJECT_NAME_NOT_FOUND;
4601f381137cSPierre Schweitzer } else
4602f381137cSPierre Schweitzer Status = open_fileref_by_inode(Vcb, subvol, inode, &fileref, Irp);
4603f381137cSPierre Schweitzer
4604f381137cSPierre Schweitzer goto loaded;
4605c2c66affSColin Finck } else {
4606f381137cSPierre Schweitzer WARN("invalid ID size for FILE_OPEN_BY_FILE_ID\n");
4607f381137cSPierre Schweitzer Status = STATUS_INVALID_PARAMETER;
4608c2c66affSColin Finck goto exit;
4609c2c66affSColin Finck }
4610883b1f31SPierre Schweitzer }
4611883b1f31SPierre Schweitzer
4612c2c66affSColin Finck if (related && fn.Length != 0 && fn.Buffer[0] == '\\') {
46134672b2baSPierre Schweitzer Status = STATUS_INVALID_PARAMETER;
4614c2c66affSColin Finck goto exit;
4615c2c66affSColin Finck }
4616c2c66affSColin Finck
4617c2c66affSColin Finck if (!related && RequestedDisposition != FILE_OPEN && !(IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY)) {
4618c2c66affSColin Finck ULONG fnoff;
4619c2c66affSColin Finck
4620318da0c1SPierre Schweitzer Status = open_fileref(Vcb, &related, &fn, NULL, true, &parsed, &fnoff,
4621c2c66affSColin Finck pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp);
4622c2c66affSColin Finck
4623c2c66affSColin Finck if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
4624c2c66affSColin Finck Status = STATUS_OBJECT_PATH_NOT_FOUND;
4625c2c66affSColin Finck else if (Status == STATUS_REPARSE)
4626c2c66affSColin Finck fileref = related;
4627c2c66affSColin Finck else if (NT_SUCCESS(Status)) {
4628c2c66affSColin Finck fnoff *= sizeof(WCHAR);
4629c2c66affSColin Finck fnoff += (related->dc ? related->dc->name.Length : 0) + sizeof(WCHAR);
4630c2c66affSColin Finck
4631c2c66affSColin Finck if (related->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT) {
4632c2c66affSColin Finck Status = STATUS_REPARSE;
4633c2c66affSColin Finck fileref = related;
4634c2c66affSColin Finck parsed = (USHORT)fnoff - sizeof(WCHAR);
4635c2c66affSColin Finck } else {
4636c2c66affSColin Finck fn.Buffer = &fn.Buffer[fnoff / sizeof(WCHAR)];
4637c2c66affSColin Finck fn.Length -= (USHORT)fnoff;
4638c2c66affSColin Finck
4639c2c66affSColin Finck Status = open_fileref(Vcb, &fileref, &fn, related, IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY, &parsed, &fn_offset,
4640c2c66affSColin Finck pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp);
4641c2c66affSColin Finck
4642318da0c1SPierre Schweitzer loaded_related = true;
4643c2c66affSColin Finck }
4644c2c66affSColin Finck }
4645c2c66affSColin Finck } else {
4646c2c66affSColin Finck Status = open_fileref(Vcb, &fileref, &fn, related, IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY, &parsed, &fn_offset,
4647c2c66affSColin Finck pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp);
4648c2c66affSColin Finck }
4649c2c66affSColin Finck
4650883b1f31SPierre Schweitzer loaded:
4651c2c66affSColin Finck if (Status == STATUS_REPARSE) {
4652c2c66affSColin Finck REPARSE_DATA_BUFFER* data;
4653c2c66affSColin Finck
4654318da0c1SPierre Schweitzer ExAcquireResourceSharedLite(fileref->fcb->Header.Resource, true);
4655318da0c1SPierre Schweitzer Status = get_reparse_block(fileref->fcb, (uint8_t**)&data);
4656c2c66affSColin Finck ExReleaseResourceLite(fileref->fcb->Header.Resource);
4657c2c66affSColin Finck
4658c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
4659194ea909SVictor Perevertkin ERR("get_reparse_block returned %08lx\n", Status);
4660c2c66affSColin Finck
4661c2c66affSColin Finck Status = STATUS_SUCCESS;
4662c2c66affSColin Finck } else {
4663c2c66affSColin Finck Status = STATUS_REPARSE;
4664c2c66affSColin Finck RtlCopyMemory(&Irp->IoStatus.Information, data, sizeof(ULONG));
4665c2c66affSColin Finck
4666c2c66affSColin Finck data->Reserved = FileObject->FileName.Length - parsed;
4667c2c66affSColin Finck
4668c2c66affSColin Finck Irp->Tail.Overlay.AuxiliaryBuffer = (void*)data;
4669c2c66affSColin Finck
4670883b1f31SPierre Schweitzer free_fileref(fileref);
4671c2c66affSColin Finck
4672c2c66affSColin Finck goto exit;
4673c2c66affSColin Finck }
4674c2c66affSColin Finck }
4675c2c66affSColin Finck
4676c2c66affSColin Finck if (NT_SUCCESS(Status) && fileref->deleted)
4677c2c66affSColin Finck Status = STATUS_OBJECT_NAME_NOT_FOUND;
4678c2c66affSColin Finck
4679c2c66affSColin Finck if (NT_SUCCESS(Status)) {
4680c2c66affSColin Finck if (RequestedDisposition == FILE_CREATE) {
468162e630deSPierre Schweitzer TRACE("file already exists, returning STATUS_OBJECT_NAME_COLLISION\n");
4682c2c66affSColin Finck Status = STATUS_OBJECT_NAME_COLLISION;
4683c2c66affSColin Finck
4684883b1f31SPierre Schweitzer free_fileref(fileref);
4685c2c66affSColin Finck
4686c2c66affSColin Finck goto exit;
4687c2c66affSColin Finck }
4688c2c66affSColin Finck } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
4689c2c66affSColin Finck if (RequestedDisposition == FILE_OPEN || RequestedDisposition == FILE_OVERWRITE) {
4690c2c66affSColin Finck TRACE("file doesn't exist, returning STATUS_OBJECT_NAME_NOT_FOUND\n");
4691c2c66affSColin Finck goto exit;
4692c2c66affSColin Finck }
469398654b54SVincent Franchomme } else if (Status == STATUS_OBJECT_PATH_NOT_FOUND || Status == STATUS_OBJECT_NAME_INVALID) {
4694194ea909SVictor Perevertkin TRACE("open_fileref returned %08lx\n", Status);
4695c2c66affSColin Finck goto exit;
4696c2c66affSColin Finck } else {
4697194ea909SVictor Perevertkin ERR("open_fileref returned %08lx\n", Status);
4698c2c66affSColin Finck goto exit;
4699c2c66affSColin Finck }
4700c2c66affSColin Finck
47016e0cf03dSVincent Franchomme if (NT_SUCCESS(Status)) { // file already exists
47026e0cf03dSVincent Franchomme Status = open_file2(Vcb, RequestedDisposition, fileref, &granted_access, FileObject, &fn,
47036e0cf03dSVincent Franchomme options, Irp, rollback, opctx);
47046e0cf03dSVincent Franchomme } else {
470506042735SVincent Franchomme file_ref* existing_file = NULL;
4706c2c66affSColin Finck
4707883b1f31SPierre Schweitzer Status = file_create(Irp, Vcb, FileObject, related, loaded_related, &fn, RequestedDisposition, options, &existing_file, rollback);
4708c2c66affSColin Finck
4709883b1f31SPierre Schweitzer if (Status == STATUS_OBJECT_NAME_COLLISION) { // already exists
4710883b1f31SPierre Schweitzer fileref = existing_file;
4711883b1f31SPierre Schweitzer
47126e0cf03dSVincent Franchomme Status = open_file2(Vcb, RequestedDisposition, fileref, &granted_access, FileObject, &fn,
47136e0cf03dSVincent Franchomme options, Irp, rollback, opctx);
4714883b1f31SPierre Schweitzer } else {
4715c2c66affSColin Finck Irp->IoStatus.Information = NT_SUCCESS(Status) ? FILE_CREATED : 0;
471657293803SMark Harmstone granted_access = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
4717c2c66affSColin Finck }
4718883b1f31SPierre Schweitzer }
4719c2c66affSColin Finck
4720c2c66affSColin Finck if (NT_SUCCESS(Status) && !(options & FILE_NO_INTERMEDIATE_BUFFERING))
4721c2c66affSColin Finck FileObject->Flags |= FO_CACHE_SUPPORTED;
4722c2c66affSColin Finck
4723c2c66affSColin Finck exit:
4724883b1f31SPierre Schweitzer if (loaded_related)
4725883b1f31SPierre Schweitzer free_fileref(related);
4726c2c66affSColin Finck
4727c2c66affSColin Finck if (Status == STATUS_SUCCESS) {
4728c2c66affSColin Finck fcb* fcb2;
4729c2c66affSColin Finck
4730c2c66affSColin Finck IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess |= granted_access;
4731c2c66affSColin Finck IrpSp->Parameters.Create.SecurityContext->AccessState->RemainingDesiredAccess &= ~(granted_access | MAXIMUM_ALLOWED);
4732c2c66affSColin Finck
4733c2c66affSColin Finck if (!FileObject->Vpb)
4734c2c66affSColin Finck FileObject->Vpb = DeviceObject->Vpb;
4735c2c66affSColin Finck
4736c2c66affSColin Finck fcb2 = FileObject->FsContext;
4737c2c66affSColin Finck
4738c2c66affSColin Finck if (fcb2->ads) {
4739c2c66affSColin Finck struct _ccb* ccb2 = FileObject->FsContext2;
4740c2c66affSColin Finck
4741c2c66affSColin Finck fcb2 = ccb2->fileref->parent->fcb;
4742c2c66affSColin Finck }
4743c2c66affSColin Finck
4744318da0c1SPierre Schweitzer ExAcquireResourceExclusiveLite(fcb2->Header.Resource, true);
4745c2c66affSColin Finck fcb_load_csums(Vcb, fcb2, Irp);
4746c2c66affSColin Finck ExReleaseResourceLite(fcb2->Header.Resource);
4747c2c66affSColin Finck } else if (Status != STATUS_REPARSE && Status != STATUS_OBJECT_NAME_NOT_FOUND && Status != STATUS_OBJECT_PATH_NOT_FOUND)
4748194ea909SVictor Perevertkin TRACE("returning %08lx\n", Status);
4749c2c66affSColin Finck
4750c2c66affSColin Finck return Status;
4751c2c66affSColin Finck }
4752c2c66affSColin Finck
verify_vcb(device_extension * Vcb,PIRP Irp)4753c2c66affSColin Finck static NTSTATUS verify_vcb(device_extension* Vcb, PIRP Irp) {
4754c2c66affSColin Finck NTSTATUS Status;
4755c2c66affSColin Finck LIST_ENTRY* le;
4756318da0c1SPierre Schweitzer bool need_verify = false;
4757c2c66affSColin Finck
4758318da0c1SPierre Schweitzer ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
4759c2c66affSColin Finck
4760c2c66affSColin Finck le = Vcb->devices.Flink;
4761c2c66affSColin Finck while (le != &Vcb->devices) {
4762c2c66affSColin Finck device* dev = CONTAINING_RECORD(le, device, list_entry);
4763c2c66affSColin Finck
4764c2c66affSColin Finck if (dev->devobj && dev->removable) {
4765c2c66affSColin Finck ULONG cc;
4766c2c66affSColin Finck IO_STATUS_BLOCK iosb;
4767c2c66affSColin Finck
4768318da0c1SPierre Schweitzer Status = dev_ioctl(dev->devobj, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, &cc, sizeof(ULONG), true, &iosb);
4769c2c66affSColin Finck
4770c2c66affSColin Finck if (IoIsErrorUserInduced(Status)) {
4771194ea909SVictor Perevertkin ERR("IOCTL_STORAGE_CHECK_VERIFY returned %08lx (user-induced)\n", Status);
4772318da0c1SPierre Schweitzer need_verify = true;
4773c2c66affSColin Finck } else if (!NT_SUCCESS(Status)) {
4774194ea909SVictor Perevertkin ERR("IOCTL_STORAGE_CHECK_VERIFY returned %08lx\n", Status);
4775c2c66affSColin Finck goto end;
4776c2c66affSColin Finck } else if (iosb.Information < sizeof(ULONG)) {
4777c2c66affSColin Finck ERR("iosb.Information was too short\n");
4778c2c66affSColin Finck Status = STATUS_INTERNAL_ERROR;
4779c2c66affSColin Finck } else if (cc != dev->change_count) {
4780c2c66affSColin Finck dev->devobj->Flags |= DO_VERIFY_VOLUME;
4781318da0c1SPierre Schweitzer need_verify = true;
4782c2c66affSColin Finck }
4783c2c66affSColin Finck }
4784c2c66affSColin Finck
4785c2c66affSColin Finck le = le->Flink;
4786c2c66affSColin Finck }
4787c2c66affSColin Finck
4788c2c66affSColin Finck Status = STATUS_SUCCESS;
4789c2c66affSColin Finck
4790c2c66affSColin Finck end:
4791c2c66affSColin Finck ExReleaseResourceLite(&Vcb->tree_lock);
4792c2c66affSColin Finck
4793c2c66affSColin Finck if (need_verify) {
4794c2c66affSColin Finck PDEVICE_OBJECT devobj;
4795c2c66affSColin Finck
4796c2c66affSColin Finck devobj = IoGetDeviceToVerify(Irp->Tail.Overlay.Thread);
4797c2c66affSColin Finck IoSetDeviceToVerify(Irp->Tail.Overlay.Thread, NULL);
4798c2c66affSColin Finck
4799c2c66affSColin Finck if (!devobj) {
4800c2c66affSColin Finck devobj = IoGetDeviceToVerify(PsGetCurrentThread());
4801c2c66affSColin Finck IoSetDeviceToVerify(PsGetCurrentThread(), NULL);
4802c2c66affSColin Finck }
4803c2c66affSColin Finck
4804c2c66affSColin Finck devobj = Vcb->Vpb ? Vcb->Vpb->RealDevice : NULL;
4805c2c66affSColin Finck
4806c2c66affSColin Finck if (devobj)
4807318da0c1SPierre Schweitzer Status = IoVerifyVolume(devobj, false);
4808c2c66affSColin Finck else
4809c2c66affSColin Finck Status = STATUS_VERIFY_REQUIRED;
4810c2c66affSColin Finck }
4811c2c66affSColin Finck
4812c2c66affSColin Finck return Status;
4813c2c66affSColin Finck }
4814c2c66affSColin Finck
has_manage_volume_privilege(ACCESS_STATE * access_state,KPROCESSOR_MODE processor_mode)4815318da0c1SPierre Schweitzer static bool has_manage_volume_privilege(ACCESS_STATE* access_state, KPROCESSOR_MODE processor_mode) {
4816c2c66affSColin Finck PRIVILEGE_SET privset;
4817c2c66affSColin Finck
4818c2c66affSColin Finck privset.PrivilegeCount = 1;
4819c2c66affSColin Finck privset.Control = PRIVILEGE_SET_ALL_NECESSARY;
4820c2c66affSColin Finck privset.Privilege[0].Luid = RtlConvertLongToLuid(SE_MANAGE_VOLUME_PRIVILEGE);
4821c2c66affSColin Finck privset.Privilege[0].Attributes = 0;
4822c2c66affSColin Finck
4823318da0c1SPierre Schweitzer return SePrivilegeCheck(&privset, &access_state->SubjectSecurityContext, processor_mode) ? true : false;
4824c2c66affSColin Finck }
4825c2c66affSColin Finck
4826c2c66affSColin Finck _Dispatch_type_(IRP_MJ_CREATE)
_Function_class_(DRIVER_DISPATCH)4827c2c66affSColin Finck _Function_class_(DRIVER_DISPATCH)
4828318da0c1SPierre Schweitzer NTSTATUS __stdcall drv_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
4829c2c66affSColin Finck NTSTATUS Status;
4830c2c66affSColin Finck PIO_STACK_LOCATION IrpSp;
4831c2c66affSColin Finck device_extension* Vcb = DeviceObject->DeviceExtension;
4832318da0c1SPierre Schweitzer bool top_level, locked = false;
48336e0cf03dSVincent Franchomme oplock_context* opctx = NULL;
4834c2c66affSColin Finck
4835c2c66affSColin Finck FsRtlEnterFileSystem();
4836c2c66affSColin Finck
4837194ea909SVictor Perevertkin TRACE("create (flags = %lx)\n", Irp->Flags);
4838c2c66affSColin Finck
4839c2c66affSColin Finck top_level = is_top_level(Irp);
4840c2c66affSColin Finck
4841c2c66affSColin Finck /* return success if just called for FS device object */
4842c2c66affSColin Finck if (DeviceObject == master_devobj) {
4843c2c66affSColin Finck TRACE("create called for FS device object\n");
4844c2c66affSColin Finck
4845c2c66affSColin Finck Irp->IoStatus.Information = FILE_OPENED;
4846c2c66affSColin Finck Status = STATUS_SUCCESS;
4847c2c66affSColin Finck
4848c2c66affSColin Finck goto exit;
4849c2c66affSColin Finck } else if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
4850c2c66affSColin Finck Status = vol_create(DeviceObject, Irp);
4851c2c66affSColin Finck goto exit;
4852c2c66affSColin Finck } else if (!Vcb || Vcb->type != VCB_TYPE_FS) {
4853c2c66affSColin Finck Status = STATUS_INVALID_PARAMETER;
4854c2c66affSColin Finck goto exit;
4855c2c66affSColin Finck }
4856c2c66affSColin Finck
4857c2c66affSColin Finck if (!(Vcb->Vpb->Flags & VPB_MOUNTED)) {
4858c2c66affSColin Finck Status = STATUS_DEVICE_NOT_READY;
4859c2c66affSColin Finck goto exit;
4860c2c66affSColin Finck }
4861c2c66affSColin Finck
4862c2c66affSColin Finck if (Vcb->removing) {
4863c2c66affSColin Finck Status = STATUS_ACCESS_DENIED;
4864c2c66affSColin Finck goto exit;
4865c2c66affSColin Finck }
4866c2c66affSColin Finck
4867c2c66affSColin Finck Status = verify_vcb(Vcb, Irp);
4868c2c66affSColin Finck if (!NT_SUCCESS(Status)) {
4869194ea909SVictor Perevertkin ERR("verify_vcb returned %08lx\n", Status);
4870c2c66affSColin Finck goto exit;
4871c2c66affSColin Finck }
4872c2c66affSColin Finck
4873318da0c1SPierre Schweitzer ExAcquireResourceSharedLite(&Vcb->load_lock, true);
4874318da0c1SPierre Schweitzer locked = true;
4875c2c66affSColin Finck
4876c2c66affSColin Finck IrpSp = IoGetCurrentIrpStackLocation(Irp);
4877c2c66affSColin Finck
4878c2c66affSColin Finck if (IrpSp->Flags != 0) {
4879318da0c1SPierre Schweitzer uint32_t flags = IrpSp->Flags;
4880c2c66affSColin Finck
4881c2c66affSColin Finck TRACE("flags:\n");
4882c2c66affSColin Finck
4883c2c66affSColin Finck if (flags & SL_CASE_SENSITIVE) {
4884c2c66affSColin Finck TRACE("SL_CASE_SENSITIVE\n");
4885c2c66affSColin Finck flags &= ~SL_CASE_SENSITIVE;
4886c2c66affSColin Finck }
4887c2c66affSColin Finck
4888c2c66affSColin Finck if (flags & SL_FORCE_ACCESS_CHECK) {
4889c2c66affSColin Finck TRACE("SL_FORCE_ACCESS_CHECK\n");
4890c2c66affSColin Finck flags &= ~SL_FORCE_ACCESS_CHECK;
4891c2c66affSColin Finck }
4892c2c66affSColin Finck
4893c2c66affSColin Finck if (flags & SL_OPEN_PAGING_FILE) {
4894c2c66affSColin Finck TRACE("SL_OPEN_PAGING_FILE\n");
4895c2c66affSColin Finck flags &= ~SL_OPEN_PAGING_FILE;
4896c2c66affSColin Finck }
4897c2c66affSColin Finck
4898c2c66affSColin Finck if (flags & SL_OPEN_TARGET_DIRECTORY) {
4899c2c66affSColin Finck TRACE("SL_OPEN_TARGET_DIRECTORY\n");
4900c2c66affSColin Finck flags &= ~SL_OPEN_TARGET_DIRECTORY;
4901c2c66affSColin Finck }
4902c2c66affSColin Finck
4903c2c66affSColin Finck if (flags & SL_STOP_ON_SYMLINK) {
4904c2c66affSColin Finck TRACE("SL_STOP_ON_SYMLINK\n");
4905c2c66affSColin Finck flags &= ~SL_STOP_ON_SYMLINK;
4906c2c66affSColin Finck }
4907c2c66affSColin Finck
4908174dfab6SVincent Franchomme if (flags & SL_IGNORE_READONLY_ATTRIBUTE) {
4909174dfab6SVincent Franchomme TRACE("SL_IGNORE_READONLY_ATTRIBUTE\n");
4910174dfab6SVincent Franchomme flags &= ~SL_IGNORE_READONLY_ATTRIBUTE;
4911174dfab6SVincent Franchomme }
4912174dfab6SVincent Franchomme
4913c2c66affSColin Finck if (flags)
4914c2c66affSColin Finck WARN("unknown flags: %x\n", flags);
4915c2c66affSColin Finck } else {
4916c2c66affSColin Finck TRACE("flags: (none)\n");
4917c2c66affSColin Finck }
4918c2c66affSColin Finck
4919c2c66affSColin Finck if (!IrpSp->FileObject) {
4920c2c66affSColin Finck ERR("FileObject was NULL\n");
4921c2c66affSColin Finck Status = STATUS_INVALID_PARAMETER;
4922c2c66affSColin Finck goto exit;
4923c2c66affSColin Finck }
4924c2c66affSColin Finck
4925c2c66affSColin Finck if (IrpSp->FileObject->RelatedFileObject) {
4926c2c66affSColin Finck fcb* relatedfcb = IrpSp->FileObject->RelatedFileObject->FsContext;
4927c2c66affSColin Finck
4928c2c66affSColin Finck if (relatedfcb && relatedfcb->Vcb != Vcb) {
4929c2c66affSColin Finck WARN("RelatedFileObject was for different device\n");
4930c2c66affSColin Finck Status = STATUS_INVALID_PARAMETER;
4931c2c66affSColin Finck goto exit;
4932c2c66affSColin Finck }
4933c2c66affSColin Finck }
4934c2c66affSColin Finck
4935c2c66affSColin Finck // opening volume
4936c2c66affSColin Finck if (IrpSp->FileObject->FileName.Length == 0 && !IrpSp->FileObject->RelatedFileObject) {
4937c2c66affSColin Finck ULONG RequestedDisposition = ((IrpSp->Parameters.Create.Options >> 24) & 0xff);
4938c2c66affSColin Finck ULONG RequestedOptions = IrpSp->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
4939c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
4940c2c66affSColin Finck LONG rc;
4941c2c66affSColin Finck #endif
4942c2c66affSColin Finck ccb* ccb;
4943c2c66affSColin Finck
4944c2c66affSColin Finck TRACE("open operation for volume\n");
4945c2c66affSColin Finck
4946c2c66affSColin Finck if (RequestedDisposition != FILE_OPEN && RequestedDisposition != FILE_OPEN_IF) {
4947c2c66affSColin Finck Status = STATUS_ACCESS_DENIED;
4948c2c66affSColin Finck goto exit;
4949c2c66affSColin Finck }
4950c2c66affSColin Finck
4951c2c66affSColin Finck if (RequestedOptions & FILE_DIRECTORY_FILE) {
4952c2c66affSColin Finck Status = STATUS_NOT_A_DIRECTORY;
4953c2c66affSColin Finck goto exit;
4954c2c66affSColin Finck }
4955c2c66affSColin Finck
4956c2c66affSColin Finck ccb = ExAllocatePoolWithTag(NonPagedPool, sizeof(*ccb), ALLOC_TAG);
4957c2c66affSColin Finck if (!ccb) {
4958c2c66affSColin Finck ERR("out of memory\n");
4959c2c66affSColin Finck Status = STATUS_INSUFFICIENT_RESOURCES;
4960c2c66affSColin Finck goto exit;
4961c2c66affSColin Finck }
4962c2c66affSColin Finck
4963c2c66affSColin Finck RtlZeroMemory(ccb, sizeof(*ccb));
4964c2c66affSColin Finck
4965c2c66affSColin Finck ccb->NodeType = BTRFS_NODE_TYPE_CCB;
4966c2c66affSColin Finck ccb->NodeSize = sizeof(*ccb);
4967c2c66affSColin Finck ccb->disposition = RequestedDisposition;
4968c2c66affSColin Finck ccb->options = RequestedOptions;
4969c2c66affSColin Finck ccb->access = IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess;
4970c2c66affSColin Finck ccb->manage_volume_privilege = has_manage_volume_privilege(IrpSp->Parameters.Create.SecurityContext->AccessState,
4971c2c66affSColin Finck IrpSp->Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode);
4972318da0c1SPierre Schweitzer ccb->reserving = false;
4973c2c66affSColin Finck ccb->lxss = called_from_lxss();
4974c2c66affSColin Finck
4975c2c66affSColin Finck #ifdef DEBUG_FCB_REFCOUNTS
4976c2c66affSColin Finck rc = InterlockedIncrement(&Vcb->volume_fcb->refcount);
4977c2c66affSColin Finck WARN("fcb %p: refcount now %i (volume)\n", Vcb->volume_fcb, rc);
4978c2c66affSColin Finck #else
4979c2c66affSColin Finck InterlockedIncrement(&Vcb->volume_fcb->refcount);
4980c2c66affSColin Finck #endif
4981c2c66affSColin Finck IrpSp->FileObject->FsContext = Vcb->volume_fcb;
4982c2c66affSColin Finck IrpSp->FileObject->FsContext2 = ccb;
4983c2c66affSColin Finck
4984c2c66affSColin Finck IrpSp->FileObject->SectionObjectPointer = &Vcb->volume_fcb->nonpaged->segment_object;
4985c2c66affSColin Finck
4986c2c66affSColin Finck if (!IrpSp->FileObject->Vpb)
4987c2c66affSColin Finck IrpSp->FileObject->Vpb = DeviceObject->Vpb;
4988c2c66affSColin Finck
4989c2c66affSColin Finck InterlockedIncrement(&Vcb->open_files);
4990c2c66affSColin Finck
4991c2c66affSColin Finck Irp->IoStatus.Information = FILE_OPENED;
4992c2c66affSColin Finck Status = STATUS_SUCCESS;
4993c2c66affSColin Finck } else {
4994c2c66affSColin Finck LIST_ENTRY rollback;
4995318da0c1SPierre Schweitzer bool skip_lock;
4996c2c66affSColin Finck
4997c2c66affSColin Finck InitializeListHead(&rollback);
4998c2c66affSColin Finck
4999194ea909SVictor Perevertkin TRACE("file name: %.*S\n", (int)(IrpSp->FileObject->FileName.Length / sizeof(WCHAR)), IrpSp->FileObject->FileName.Buffer);
5000c2c66affSColin Finck
5001c2c66affSColin Finck if (IrpSp->FileObject->RelatedFileObject)
500262e630deSPierre Schweitzer TRACE("related file = %p\n", IrpSp->FileObject->RelatedFileObject);
5003c2c66affSColin Finck
5004c2c66affSColin Finck // Don't lock again if we're being called from within CcCopyRead etc.
5005c2c66affSColin Finck skip_lock = ExIsResourceAcquiredExclusiveLite(&Vcb->tree_lock);
5006c2c66affSColin Finck
5007c2c66affSColin Finck if (!skip_lock)
5008318da0c1SPierre Schweitzer ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
5009c2c66affSColin Finck
5010318da0c1SPierre Schweitzer ExAcquireResourceSharedLite(&Vcb->fileref_lock, true);
5011883b1f31SPierre Schweitzer
50126e0cf03dSVincent Franchomme Status = open_file(DeviceObject, Vcb, Irp, &rollback, &opctx);
5013c2c66affSColin Finck
5014c2c66affSColin Finck if (!NT_SUCCESS(Status))
5015c2c66affSColin Finck do_rollback(Vcb, &rollback);
5016c2c66affSColin Finck else
5017c2c66affSColin Finck clear_rollback(&rollback);
5018c2c66affSColin Finck
5019883b1f31SPierre Schweitzer ExReleaseResourceLite(&Vcb->fileref_lock);
5020883b1f31SPierre Schweitzer
5021c2c66affSColin Finck if (!skip_lock)
5022c2c66affSColin Finck ExReleaseResourceLite(&Vcb->tree_lock);
5023c2c66affSColin Finck }
5024c2c66affSColin Finck
5025c2c66affSColin Finck exit:
50266e0cf03dSVincent Franchomme if (Status != STATUS_PENDING) {
5027c2c66affSColin Finck Irp->IoStatus.Status = Status;
5028c2c66affSColin Finck IoCompleteRequest(Irp, NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT);
50296e0cf03dSVincent Franchomme }
5030c2c66affSColin Finck
5031c2c66affSColin Finck if (locked)
5032c2c66affSColin Finck ExReleaseResourceLite(&Vcb->load_lock);
5033c2c66affSColin Finck
50346e0cf03dSVincent Franchomme if (Status == STATUS_PENDING) {
50356e0cf03dSVincent Franchomme KeWaitForSingleObject(&opctx->event, Executive, KernelMode, false, NULL);
50366e0cf03dSVincent Franchomme Status = opctx->Status;
50376e0cf03dSVincent Franchomme ExFreePool(opctx);
50386e0cf03dSVincent Franchomme }
50396e0cf03dSVincent Franchomme
50406e0cf03dSVincent Franchomme TRACE("create returning %08lx\n", Status);
50416e0cf03dSVincent Franchomme
5042c2c66affSColin Finck if (top_level)
5043c2c66affSColin Finck IoSetTopLevelIrp(NULL);
5044c2c66affSColin Finck
5045c2c66affSColin Finck FsRtlExitFileSystem();
5046c2c66affSColin Finck
5047c2c66affSColin Finck return Status;
5048c2c66affSColin Finck }
5049