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