ReactOS 0.4.15-dev-7788-g1ad9096
create.c
Go to the documentation of this file.
1/* Copyright (c) Mark Harmstone 2016-17
2 *
3 * This file is part of WinBtrfs.
4 *
5 * WinBtrfs is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public Licence as published by
7 * the Free Software Foundation, either version 3 of the Licence, or
8 * (at your option) any later version.
9 *
10 * WinBtrfs is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public Licence for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public Licence
16 * along with WinBtrfs. If not, see <http://www.gnu.org/licenses/>. */
17
18#ifndef __REACTOS__
19#include <sys/stat.h>
20#endif /* __REACTOS__ */
21#include "btrfs_drv.h"
22#include "crc32c.h"
23#include <ntddstor.h>
24
29
30static const WCHAR datastring[] = L"::$DATA";
31
32static const char root_dir[] = "$Root";
33static const WCHAR root_dir_utf16[] = L"$Root";
34
35// Windows 10
36#define ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED 0x0002
37#define ATOMIC_CREATE_ECP_IN_FLAG_OP_FLAGS_SPECIFIED 0x0080
38#define ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT 0x0100
39
40#define ATOMIC_CREATE_ECP_OUT_FLAG_REPARSE_POINT_SET 0x0002
41#define ATOMIC_CREATE_ECP_OUT_FLAG_OP_FLAGS_HONORED 0x0080
42
43#define ATOMIC_CREATE_ECP_IN_OP_FLAG_CASE_SENSITIVE_FLAGS_SPECIFIED 1
44#define ATOMIC_CREATE_ECP_OUT_OP_FLAG_CASE_SENSITIVE_FLAGS_SET 1
45
46#ifndef SL_IGNORE_READONLY_ATTRIBUTE
47#define SL_IGNORE_READONLY_ATTRIBUTE 0x40 // introduced in Windows 10, not in mingw
48#endif
49
50typedef struct _FILE_TIMESTAMPS {
56
78
79static const GUID GUID_ECP_ATOMIC_CREATE = { 0x4720bd83, 0x52ac, 0x4104, { 0xa1, 0x30, 0xd1, 0xec, 0x6a, 0x8c, 0xc8, 0xe5 } };
80static const GUID GUID_ECP_QUERY_ON_CREATE = { 0x1aca62e9, 0xabb4, 0x4ff2, { 0xbb, 0x5c, 0x1c, 0x79, 0x02, 0x5e, 0x41, 0x7f } };
81static const GUID GUID_ECP_CREATE_REDIRECTION = { 0x188d6bd6, 0xa126, 0x4fa8, { 0xbd, 0xf2, 0x1c, 0xcd, 0xf8, 0x96, 0xf3, 0xe0 } };
82
83typedef struct {
90
92 fcb* fcb;
93
94 if (pool_type == NonPagedPool) {
95 fcb = ExAllocatePoolWithTag(pool_type, sizeof(struct _fcb), ALLOC_TAG);
96 if (!fcb) {
97 ERR("out of memory\n");
98 return NULL;
99 }
100 } else {
101 fcb = ExAllocateFromPagedLookasideList(&Vcb->fcb_lookaside);
102 if (!fcb) {
103 ERR("out of memory\n");
104 return NULL;
105 }
106 }
107
108#ifdef DEBUG_FCB_REFCOUNTS
109 WARN("allocating fcb %p\n", fcb);
110#endif
111 RtlZeroMemory(fcb, sizeof(struct _fcb));
112 fcb->pool_type = pool_type;
113
114 fcb->Header.NodeTypeCode = BTRFS_NODE_TYPE_FCB;
115 fcb->Header.NodeByteSize = sizeof(struct _fcb);
116
117 fcb->nonpaged = ExAllocateFromNPagedLookasideList(&Vcb->fcb_np_lookaside);
118 if (!fcb->nonpaged) {
119 ERR("out of memory\n");
120
121 if (pool_type == NonPagedPool)
123 else
124 ExFreeToPagedLookasideList(&Vcb->fcb_lookaside, fcb);
125
126 return NULL;
127 }
128 RtlZeroMemory(fcb->nonpaged, sizeof(struct _fcb_nonpaged));
129
130 ExInitializeResourceLite(&fcb->nonpaged->paging_resource);
131 fcb->Header.PagingIoResource = &fcb->nonpaged->paging_resource;
132
133 ExInitializeFastMutex(&fcb->nonpaged->HeaderMutex);
134 FsRtlSetupAdvancedHeader(&fcb->Header, &fcb->nonpaged->HeaderMutex);
135
136 fcb->refcount = 1;
137#ifdef DEBUG_FCB_REFCOUNTS
138 WARN("fcb %p: refcount now %i\n", fcb, fcb->refcount);
139#endif
140
142 fcb->Header.Resource = &fcb->nonpaged->resource;
143
144 ExInitializeResourceLite(&fcb->nonpaged->dir_children_lock);
145
148
152
156
157 return fcb;
158}
159
161 file_ref* fr;
162
163 fr = ExAllocateFromPagedLookasideList(&Vcb->fileref_lookaside);
164 if (!fr) {
165 ERR("out of memory\n");
166 return NULL;
167 }
168
169 RtlZeroMemory(fr, sizeof(file_ref));
170
171 fr->refcount = 1;
172
173#ifdef DEBUG_FCB_REFCOUNTS
174 WARN("fileref %p: refcount now 1\n", fr);
175#endif
176
178
179 return fr;
180}
181
184 UNICODE_STRING fnus;
186 LIST_ENTRY* le;
187 uint8_t c;
188 bool locked = false;
189
190 if (!case_sensitive) {
191 Status = RtlUpcaseUnicodeString(&fnus, filename, true);
192
193 if (!NT_SUCCESS(Status)) {
194 ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
195 return Status;
196 }
197 } else
198 fnus = *filename;
199
200 Status = check_file_name_valid(filename, false, false);
201 if (!NT_SUCCESS(Status))
202 return Status;
203
204 hash = calc_crc32c(0xffffffff, (uint8_t*)fnus.Buffer, fnus.Length);
205
206 c = hash >> 24;
207
208 if (!ExIsResourceAcquiredSharedLite(&fcb->nonpaged->dir_children_lock)) {
209 ExAcquireResourceSharedLite(&fcb->nonpaged->dir_children_lock, true);
210 locked = true;
211 }
212
213 if (case_sensitive) {
214 if (!fcb->hash_ptrs[c]) {
216 goto end;
217 }
218
219 le = fcb->hash_ptrs[c];
220 while (le != &fcb->dir_children_hash) {
221 dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_hash);
222
223 if (dc->hash == hash) {
224 if (dc->name.Length == fnus.Length && RtlCompareMemory(dc->name.Buffer, fnus.Buffer, fnus.Length) == fnus.Length) {
225 if (dc->key.obj_type == TYPE_ROOT_ITEM) {
226 LIST_ENTRY* le2;
227
228 *subvol = NULL;
229
230 le2 = fcb->Vcb->roots.Flink;
231 while (le2 != &fcb->Vcb->roots) {
233
234 if (r2->id == dc->key.obj_id) {
235 *subvol = r2;
236 break;
237 }
238
239 le2 = le2->Flink;
240 }
241
243 } else {
244 *subvol = fcb->subvol;
245 *inode = dc->key.obj_id;
246 }
247
248 *pdc = dc;
249
251 goto end;
252 }
253 } else if (dc->hash > hash) {
255 goto end;
256 }
257
258 le = le->Flink;
259 }
260 } else {
261 if (!fcb->hash_ptrs_uc[c]) {
263 goto end;
264 }
265
266 le = fcb->hash_ptrs_uc[c];
267 while (le != &fcb->dir_children_hash_uc) {
268 dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_hash_uc);
269
270 if (dc->hash_uc == hash) {
271 if (dc->name_uc.Length == fnus.Length && RtlCompareMemory(dc->name_uc.Buffer, fnus.Buffer, fnus.Length) == fnus.Length) {
272 if (dc->key.obj_type == TYPE_ROOT_ITEM) {
273 LIST_ENTRY* le2;
274
275 *subvol = NULL;
276
277 le2 = fcb->Vcb->roots.Flink;
278 while (le2 != &fcb->Vcb->roots) {
280
281 if (r2->id == dc->key.obj_id) {
282 *subvol = r2;
283 break;
284 }
285
286 le2 = le2->Flink;
287 }
288
290 } else {
291 *subvol = fcb->subvol;
292 *inode = dc->key.obj_id;
293 }
294
295 *pdc = dc;
296
298 goto end;
299 }
300 } else if (dc->hash_uc > hash) {
302 goto end;
303 }
304
305 le = le->Flink;
306 }
307 }
308
310
311end:
312 if (locked)
313 ExReleaseResourceLite(&fcb->nonpaged->dir_children_lock);
314
315 if (!case_sensitive)
316 ExFreePool(fnus.Buffer);
317
318 return Status;
319}
320
322 ULONG len, i;
323 bool has_stream;
324 WCHAR* buf;
325 name_bit* nb;
327
328 len = path->Length / sizeof(WCHAR);
329 if (len > 0 && (path->Buffer[len - 1] == '/' || path->Buffer[len - 1] == '\\'))
330 len--;
331
332 if (len == 0 || (path->Buffer[len - 1] == '/' || path->Buffer[len - 1] == '\\')) {
333 WARN("zero-length filename part\n");
335 }
336
337 has_stream = false;
338 for (i = 0; i < len; i++) {
339 if (path->Buffer[i] == '/' || path->Buffer[i] == '\\') {
340 has_stream = false;
341 } else if (path->Buffer[i] == ':') {
342 has_stream = true;
343 }
344 }
345
346 buf = path->Buffer;
347
348 for (i = 0; i < len; i++) {
349 if (path->Buffer[i] == '/' || path->Buffer[i] == '\\') {
350 if (buf[0] == '/' || buf[0] == '\\') {
351 WARN("zero-length filename part\n");
353 goto cleanup;
354 }
355
356 nb = ExAllocateFromPagedLookasideList(&Vcb->name_bit_lookaside);
357 if (!nb) {
358 ERR("out of memory\n");
360 goto cleanup;
361 }
362
363 nb->us.Buffer = buf;
364 nb->us.Length = nb->us.MaximumLength = (USHORT)(&path->Buffer[i] - buf) * sizeof(WCHAR);
366
367 buf = &path->Buffer[i+1];
368 }
369 }
370
371 nb = ExAllocateFromPagedLookasideList(&Vcb->name_bit_lookaside);
372 if (!nb) {
373 ERR("out of memory\n");
375 goto cleanup;
376 }
377
378 nb->us.Buffer = buf;
379 nb->us.Length = nb->us.MaximumLength = (USHORT)(&path->Buffer[i] - buf) * sizeof(WCHAR);
381
382 if (has_stream) {
383 static const WCHAR datasuf[] = {':','$','D','A','T','A',0};
384 UNICODE_STRING dsus;
385
386 dsus.Buffer = (WCHAR*)datasuf;
387 dsus.Length = dsus.MaximumLength = sizeof(datasuf) - sizeof(WCHAR);
388
389 for (i = 0; i < nb->us.Length / sizeof(WCHAR); i++) {
390 if (nb->us.Buffer[i] == ':') {
391 name_bit* nb2;
392
393 if (i + 1 == nb->us.Length / sizeof(WCHAR)) {
394 WARN("zero-length stream name\n");
396 goto cleanup;
397 }
398
399 nb2 = ExAllocateFromPagedLookasideList(&Vcb->name_bit_lookaside);
400 if (!nb2) {
401 ERR("out of memory\n");
403 goto cleanup;
404 }
405
406 nb2->us.Buffer = &nb->us.Buffer[i+1];
407 nb2->us.Length = nb2->us.MaximumLength = (uint16_t)(nb->us.Length - (i * sizeof(WCHAR)) - sizeof(WCHAR));
409
410 nb->us.Length = (uint16_t)i * sizeof(WCHAR);
411 nb->us.MaximumLength = nb->us.Length;
412
413 nb = nb2;
414
415 break;
416 }
417 }
418
419 // FIXME - should comparison be case-insensitive?
420 // remove :$DATA suffix
421 if (nb->us.Length >= dsus.Length && RtlCompareMemory(&nb->us.Buffer[(nb->us.Length - dsus.Length)/sizeof(WCHAR)], dsus.Buffer, dsus.Length) == dsus.Length)
422 nb->us.Length -= dsus.Length;
423
424 if (nb->us.Length == 0) {
426 ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb);
427
428 has_stream = false;
429 }
430 }
431
432 // if path is just stream name, remove first empty item
433 if (has_stream && path->Length >= sizeof(WCHAR) && path->Buffer[0] == ':') {
435
436 ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb1);
437 }
438
439 *stream = has_stream;
440
441 return STATUS_SUCCESS;
442
443cleanup:
444 while (!IsListEmpty(parts)) {
446
447 ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb);
448 }
449
450 return Status;
451}
452
455 KEY searchkey;
456 traverse_ptr tp, next_tp;
457 uint64_t i, j;
458 bool b;
459 void* ptr = csum;
460
461 searchkey.obj_id = EXTENT_CSUM_ID;
462 searchkey.obj_type = TYPE_EXTENT_CSUM;
463 searchkey.offset = start;
464
465 Status = find_item(Vcb, Vcb->checksum_root, &tp, &searchkey, false, Irp);
466 if (!NT_SUCCESS(Status)) {
467 ERR("error - find_item returned %08lx\n", Status);
468 return Status;
469 }
470
471 i = 0;
472 do {
473 if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
474 ULONG readlen;
475
476 if (start < tp.item->key.offset)
477 j = 0;
478 else
479 j = ((start - tp.item->key.offset) >> Vcb->sector_shift) + i;
480
481 if (j * Vcb->csum_size > tp.item->size || tp.item->key.offset > start + (i << Vcb->sector_shift)) {
482 ERR("checksum not found for %I64x\n", start + (i << Vcb->sector_shift));
484 }
485
486 readlen = (ULONG)min((tp.item->size / Vcb->csum_size) - j, length - i);
487 RtlCopyMemory(ptr, tp.item->data + (j * Vcb->csum_size), readlen * Vcb->csum_size);
488
489 ptr = (uint8_t*)ptr + (readlen * Vcb->csum_size);
490 i += readlen;
491
492 if (i == length)
493 break;
494 }
495
496 b = find_next_item(Vcb, &tp, &next_tp, false, Irp);
497
498 if (b)
499 tp = next_tp;
500 } while (b);
501
502 if (i < length) {
503 ERR("could not read checksums: offset %I64x, length %I64x sectors\n", start, length);
505 }
506
507 return STATUS_SUCCESS;
508}
509
511 KEY searchkey;
512 traverse_ptr tp, next_tp;
514 ULONG num_children = 0;
515 uint64_t max_index = 2;
516
518 if (!fcb->hash_ptrs) {
519 ERR("out of memory\n");
521 }
522
523 RtlZeroMemory(fcb->hash_ptrs, sizeof(LIST_ENTRY*) * 256);
524
526 if (!fcb->hash_ptrs_uc) {
527 ERR("out of memory\n");
529 }
530
531 RtlZeroMemory(fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256);
532
533 if (!ignore_size && fcb->inode_item.st_size == 0)
534 return STATUS_SUCCESS;
535
536 searchkey.obj_id = fcb->inode;
537 searchkey.obj_type = TYPE_DIR_INDEX;
538 searchkey.offset = 2;
539
540 Status = find_item(Vcb, fcb->subvol, &tp, &searchkey, false, Irp);
541 if (!NT_SUCCESS(Status)) {
542 ERR("find_item returned %08lx\n", Status);
543 return Status;
544 }
545
546 if (keycmp(tp.item->key, searchkey) == -1) {
547 if (find_next_item(Vcb, &tp, &next_tp, false, Irp)) {
548 tp = next_tp;
549 TRACE("moving on to %I64x,%x,%I64x\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
550 }
551 }
552
553 while (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
554 DIR_ITEM* di = (DIR_ITEM*)tp.item->data;
555 dir_child* dc;
556 ULONG utf16len;
557
558 if (tp.item->size < sizeof(DIR_ITEM)) {
559 WARN("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM));
560 goto cont;
561 }
562
563 if (di->n == 0) {
564 WARN("(%I64x,%x,%I64x): DIR_ITEM name length is zero\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
565 goto cont;
566 }
567
568 Status = utf8_to_utf16(NULL, 0, &utf16len, di->name, di->n);
569 if (!NT_SUCCESS(Status)) {
570 ERR("utf8_to_utf16 1 returned %08lx\n", Status);
571 goto cont;
572 }
573
575 if (!dc) {
576 ERR("out of memory\n");
578 }
579
580 dc->key = di->key;
581 dc->index = tp.item->key.offset;
582 dc->type = di->type;
583 dc->fileref = NULL;
584 dc->root_dir = false;
585
586 max_index = dc->index;
587
588 dc->utf8.MaximumLength = dc->utf8.Length = di->n;
589 dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, di->n, ALLOC_TAG);
590 if (!dc->utf8.Buffer) {
591 ERR("out of memory\n");
592 ExFreePool(dc);
594 }
595
596 RtlCopyMemory(dc->utf8.Buffer, di->name, di->n);
597
598 dc->name.MaximumLength = dc->name.Length = (uint16_t)utf16len;
599 dc->name.Buffer = ExAllocatePoolWithTag(PagedPool, dc->name.MaximumLength, ALLOC_TAG);
600 if (!dc->name.Buffer) {
601 ERR("out of memory\n");
602 ExFreePool(dc->utf8.Buffer);
603 ExFreePool(dc);
605 }
606
607 Status = utf8_to_utf16(dc->name.Buffer, utf16len, &utf16len, di->name, di->n);
608 if (!NT_SUCCESS(Status)) {
609 ERR("utf8_to_utf16 2 returned %08lx\n", Status);
610 ExFreePool(dc->utf8.Buffer);
611 ExFreePool(dc->name.Buffer);
612 ExFreePool(dc);
613 goto cont;
614 }
615
616 Status = RtlUpcaseUnicodeString(&dc->name_uc, &dc->name, true);
617 if (!NT_SUCCESS(Status)) {
618 ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
619 ExFreePool(dc->utf8.Buffer);
620 ExFreePool(dc->name.Buffer);
621 ExFreePool(dc);
622 goto cont;
623 }
624
625 dc->hash = calc_crc32c(0xffffffff, (uint8_t*)dc->name.Buffer, dc->name.Length);
626 dc->hash_uc = calc_crc32c(0xffffffff, (uint8_t*)dc->name_uc.Buffer, dc->name_uc.Length);
627
628 InsertTailList(&fcb->dir_children_index, &dc->list_entry_index);
629
631
632 num_children++;
633
634cont:
635 if (find_next_item(Vcb, &tp, &next_tp, false, Irp))
636 tp = next_tp;
637 else
638 break;
639 }
640
641 if (!Vcb->options.no_root_dir && fcb->inode == SUBVOL_ROOT_INODE) {
642 root* top_subvol;
643
644 if (Vcb->root_fileref && Vcb->root_fileref->fcb)
645 top_subvol = Vcb->root_fileref->fcb->subvol;
646 else
647 top_subvol = find_default_subvol(Vcb, NULL);
648
649 if (fcb->subvol == top_subvol && top_subvol->id != BTRFS_ROOT_FSTREE) {
651 if (!dc) {
652 ERR("out of memory\n");
654 }
655
656 dc->key.obj_id = BTRFS_ROOT_FSTREE;
657 dc->key.obj_type = TYPE_ROOT_ITEM;
658 dc->key.offset = 0;
659 dc->index = max_index + 1;
660 dc->type = BTRFS_TYPE_DIRECTORY;
661 dc->fileref = NULL;
662 dc->root_dir = true;
663
664 dc->utf8.MaximumLength = dc->utf8.Length = sizeof(root_dir) - sizeof(char);
665 dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(root_dir) - sizeof(char), ALLOC_TAG);
666 if (!dc->utf8.Buffer) {
667 ERR("out of memory\n");
668 ExFreePool(dc);
670 }
671
672 RtlCopyMemory(dc->utf8.Buffer, root_dir, sizeof(root_dir) - sizeof(char));
673
674 dc->name.MaximumLength = dc->name.Length = sizeof(root_dir_utf16) - sizeof(WCHAR);
675 dc->name.Buffer = ExAllocatePoolWithTag(PagedPool, sizeof(root_dir_utf16) - sizeof(WCHAR), ALLOC_TAG);
676 if (!dc->name.Buffer) {
677 ERR("out of memory\n");
678 ExFreePool(dc->utf8.Buffer);
679 ExFreePool(dc);
681 }
682
683 RtlCopyMemory(dc->name.Buffer, root_dir_utf16, sizeof(root_dir_utf16) - sizeof(WCHAR));
684
685 Status = RtlUpcaseUnicodeString(&dc->name_uc, &dc->name, true);
686 if (!NT_SUCCESS(Status)) {
687 ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
688 ExFreePool(dc->utf8.Buffer);
689 ExFreePool(dc->name.Buffer);
690 ExFreePool(dc);
691 goto cont;
692 }
693
694 dc->hash = calc_crc32c(0xffffffff, (uint8_t*)dc->name.Buffer, dc->name.Length);
695 dc->hash_uc = calc_crc32c(0xffffffff, (uint8_t*)dc->name_uc.Buffer, dc->name_uc.Length);
696
697 InsertTailList(&fcb->dir_children_index, &dc->list_entry_index);
698
700 }
701 }
702
703 return STATUS_SUCCESS;
704}
705
707 root* subvol, uint64_t inode, uint8_t type, PANSI_STRING utf8, bool always_add_hl, fcb* parent, fcb** pfcb, POOL_TYPE pooltype, PIRP Irp) {
708 KEY searchkey;
709 traverse_ptr tp, next_tp;
711 fcb *fcb, *deleted_fcb = NULL;
712 bool atts_set = false, sd_set = false, no_data;
713 LIST_ENTRY* lastle = NULL;
714 EXTENT_DATA* ed = NULL;
717
718 hash = calc_crc32c(0xffffffff, (uint8_t*)&inode, sizeof(uint64_t));
719
720 acquire_fcb_lock_shared(Vcb);
721
722 if (subvol->fcbs_ptrs[hash >> 24]) {
723 LIST_ENTRY* le = subvol->fcbs_ptrs[hash >> 24];
724
725 while (le != &subvol->fcbs) {
726 fcb = CONTAINING_RECORD(le, struct _fcb, list_entry);
727
728 if (fcb->inode == inode) {
729 if (!fcb->ads) {
730 if (fcb->deleted)
731 deleted_fcb = fcb;
732 else {
733#ifdef DEBUG_FCB_REFCOUNTS
735
736 WARN("fcb %p: refcount now %i (subvol %I64x, inode %I64x)\n", fcb, rc, fcb->subvol->id, fcb->inode);
737#else
739#endif
740
741 *pfcb = fcb;
742 release_fcb_lock(Vcb);
743 return STATUS_SUCCESS;
744 }
745 }
746 } else if (fcb->hash > hash) {
747 if (deleted_fcb) {
748 InterlockedIncrement(&deleted_fcb->refcount);
749 *pfcb = deleted_fcb;
750 release_fcb_lock(Vcb);
751 return STATUS_SUCCESS;
752 }
753
754 lastle = le->Blink;
755 fcbs_version = subvol->fcbs_version;
756
757 break;
758 }
759
760 le = le->Flink;
761 }
762 }
763
764 release_fcb_lock(Vcb);
765
766 if (deleted_fcb) {
767 InterlockedIncrement(&deleted_fcb->refcount);
768 *pfcb = deleted_fcb;
769 return STATUS_SUCCESS;
770 }
771
772 fcb = create_fcb(Vcb, pooltype);
773 if (!fcb) {
774 ERR("out of memory\n");
776 }
777
778 fcb->Vcb = Vcb;
779
780 fcb->subvol = subvol;
781 fcb->inode = inode;
782 fcb->hash = hash;
783 fcb->type = type;
784
785 searchkey.obj_id = inode;
786 searchkey.obj_type = TYPE_INODE_ITEM;
787 searchkey.offset = 0xffffffffffffffff;
788
789 Status = find_item(Vcb, subvol, &tp, &searchkey, false, Irp);
790 if (!NT_SUCCESS(Status)) {
791 ERR("error - find_item returned %08lx\n", Status);
792 reap_fcb(fcb);
793 return Status;
794 }
795
796 if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
797 WARN("couldn't find INODE_ITEM for inode %I64x in subvol %I64x\n", inode, subvol->id);
798 reap_fcb(fcb);
800 }
801
802 if (tp.item->size > 0)
804
805 if (fcb->type == 0) { // guess the type from the inode mode, if the caller doesn't know already
808 else if ((fcb->inode_item.st_mode & __S_IFCHR) == __S_IFCHR)
810 else if ((fcb->inode_item.st_mode & __S_IFBLK) == __S_IFBLK)
812 else if ((fcb->inode_item.st_mode & __S_IFIFO) == __S_IFIFO)
814 else if ((fcb->inode_item.st_mode & __S_IFLNK) == __S_IFLNK)
816 else if ((fcb->inode_item.st_mode & __S_IFSOCK) == __S_IFSOCK)
818 else
820 }
821
822 no_data = fcb->inode_item.st_size == 0 || (fcb->type != BTRFS_TYPE_FILE && fcb->type != BTRFS_TYPE_SYMLINK);
823
824 while (find_next_item(Vcb, &tp, &next_tp, false, Irp)) {
825 tp = next_tp;
826
827 if (tp.item->key.obj_id > inode)
828 break;
829
831 break;
832
833 if ((always_add_hl || fcb->inode_item.st_nlink > 1) && tp.item->key.obj_type == TYPE_INODE_REF) {
834 ULONG len;
835 INODE_REF* ir;
836
837 len = tp.item->size;
838 ir = (INODE_REF*)tp.item->data;
839
840 while (len >= sizeof(INODE_REF) - 1) {
841 hardlink* hl;
843
844 hl = ExAllocatePoolWithTag(pooltype, sizeof(hardlink), ALLOC_TAG);
845 if (!hl) {
846 ERR("out of memory\n");
847 reap_fcb(fcb);
849 }
850
851 hl->parent = tp.item->key.offset;
852 hl->index = ir->index;
853
854 hl->utf8.Length = hl->utf8.MaximumLength = ir->n;
855
856 if (hl->utf8.Length > 0) {
858 RtlCopyMemory(hl->utf8.Buffer, ir->name, ir->n);
859 }
860
861 Status = utf8_to_utf16(NULL, 0, &stringlen, ir->name, ir->n);
862 if (!NT_SUCCESS(Status)) {
863 ERR("utf8_to_utf16 1 returned %08lx\n", Status);
864 ExFreePool(hl);
865 reap_fcb(fcb);
866 return Status;
867 }
868
870
871 if (stringlen == 0)
872 hl->name.Buffer = NULL;
873 else {
875
876 if (!hl->name.Buffer) {
877 ERR("out of memory\n");
878 ExFreePool(hl);
879 reap_fcb(fcb);
881 }
882
884 if (!NT_SUCCESS(Status)) {
885 ERR("utf8_to_utf16 2 returned %08lx\n", Status);
887 ExFreePool(hl);
888 reap_fcb(fcb);
889 return Status;
890 }
891 }
892
894
895 len -= sizeof(INODE_REF) - 1 + ir->n;
896 ir = (INODE_REF*)&ir->name[ir->n];
897 }
898 } else if ((always_add_hl || fcb->inode_item.st_nlink > 1) && tp.item->key.obj_type == TYPE_INODE_EXTREF) {
899 ULONG len;
900 INODE_EXTREF* ier;
901
902 len = tp.item->size;
903 ier = (INODE_EXTREF*)tp.item->data;
904
905 while (len >= sizeof(INODE_EXTREF) - 1) {
906 hardlink* hl;
908
909 hl = ExAllocatePoolWithTag(pooltype, sizeof(hardlink), ALLOC_TAG);
910 if (!hl) {
911 ERR("out of memory\n");
912 reap_fcb(fcb);
914 }
915
916 hl->parent = ier->dir;
917 hl->index = ier->index;
918
919 hl->utf8.Length = hl->utf8.MaximumLength = ier->n;
920
921 if (hl->utf8.Length > 0) {
923 RtlCopyMemory(hl->utf8.Buffer, ier->name, ier->n);
924 }
925
926 Status = utf8_to_utf16(NULL, 0, &stringlen, ier->name, ier->n);
927 if (!NT_SUCCESS(Status)) {
928 ERR("utf8_to_utf16 1 returned %08lx\n", Status);
929 ExFreePool(hl);
930 reap_fcb(fcb);
931 return Status;
932 }
933
935
936 if (stringlen == 0)
937 hl->name.Buffer = NULL;
938 else {
940
941 if (!hl->name.Buffer) {
942 ERR("out of memory\n");
943 ExFreePool(hl);
944 reap_fcb(fcb);
946 }
947
948 Status = utf8_to_utf16(hl->name.Buffer, stringlen, &stringlen, ier->name, ier->n);
949 if (!NT_SUCCESS(Status)) {
950 ERR("utf8_to_utf16 2 returned %08lx\n", Status);
952 ExFreePool(hl);
953 reap_fcb(fcb);
954 return Status;
955 }
956 }
957
959
960 len -= sizeof(INODE_EXTREF) - 1 + ier->n;
961 ier = (INODE_EXTREF*)&ier->name[ier->n];
962 }
963 } else if (tp.item->key.obj_type == TYPE_XATTR_ITEM) {
964 ULONG len;
965 DIR_ITEM* di;
966
967 static const char xapref[] = "user.";
968
969 if (tp.item->size < offsetof(DIR_ITEM, name[0])) {
970 ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, offsetof(DIR_ITEM, name[0]));
971 continue;
972 }
973
974 len = tp.item->size;
975 di = (DIR_ITEM*)tp.item->data;
976
977 do {
978 if (len < offsetof(DIR_ITEM, name[0]) + di->m + di->n)
979 break;
980
981 if (tp.item->key.offset == EA_REPARSE_HASH && di->n == sizeof(EA_REPARSE) - 1 && RtlCompareMemory(EA_REPARSE, di->name, di->n) == di->n) {
982 if (di->m > 0) {
984 if (!fcb->reparse_xattr.Buffer) {
985 ERR("out of memory\n");
986 reap_fcb(fcb);
988 }
989
990 RtlCopyMemory(fcb->reparse_xattr.Buffer, &di->name[di->n], di->m);
991 } else
993
995 } else if (tp.item->key.offset == EA_EA_HASH && di->n == sizeof(EA_EA) - 1 && RtlCompareMemory(EA_EA, di->name, di->n) == di->n) {
996 if (di->m > 0) {
998
1000
1001 if (!NT_SUCCESS(Status))
1002 WARN("IoCheckEaBufferValidity returned %08lx (error at offset %lu)\n", Status, offset);
1003 else {
1005
1007 if (!fcb->ea_xattr.Buffer) {
1008 ERR("out of memory\n");
1009 reap_fcb(fcb);
1011 }
1012
1013 RtlCopyMemory(fcb->ea_xattr.Buffer, &di->name[di->n], di->m);
1014
1016
1017 fcb->ealen = 4;
1018
1019 // calculate ealen
1020 eainfo = (FILE_FULL_EA_INFORMATION*)&di->name[di->n];
1021 do {
1022 fcb->ealen += 5 + eainfo->EaNameLength + eainfo->EaValueLength;
1023
1024 if (eainfo->NextEntryOffset == 0)
1025 break;
1026
1027 eainfo = (FILE_FULL_EA_INFORMATION*)(((uint8_t*)eainfo) + eainfo->NextEntryOffset);
1028 } while (true);
1029 }
1030 }
1031 } else if (tp.item->key.offset == EA_DOSATTRIB_HASH && di->n == sizeof(EA_DOSATTRIB) - 1 && RtlCompareMemory(EA_DOSATTRIB, di->name, di->n) == di->n) {
1032 if (di->m > 0) {
1033 if (get_file_attributes_from_xattr(&di->name[di->n], di->m, &fcb->atts)) {
1034 atts_set = true;
1035
1038 else if (fcb->type == BTRFS_TYPE_SYMLINK)
1040
1042 fcb->atts &= ~FILE_ATTRIBUTE_DIRECTORY;
1043
1044 if (inode == SUBVOL_ROOT_INODE) {
1045 if (subvol->root_item.flags & BTRFS_SUBVOL_READONLY)
1047 else
1048 fcb->atts &= ~FILE_ATTRIBUTE_READONLY;
1049 }
1050 }
1051 }
1052 } else if (tp.item->key.offset == EA_NTACL_HASH && di->n == sizeof(EA_NTACL) - 1 && RtlCompareMemory(EA_NTACL, di->name, di->n) == di->n) {
1053 if (di->m > 0) {
1055 if (!fcb->sd) {
1056 ERR("out of memory\n");
1057 reap_fcb(fcb);
1059 }
1060
1061 RtlCopyMemory(fcb->sd, &di->name[di->n], di->m);
1062
1063 // We have to test against our copy rather than the source, as RtlValidRelativeSecurityDescriptor
1064 // will fail if the ACLs aren't 32-bit aligned.
1065 if (!RtlValidRelativeSecurityDescriptor(fcb->sd, di->m, 0))
1066 ExFreePool(fcb->sd);
1067 else
1068 sd_set = true;
1069 }
1070 } 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) {
1071 if (di->m > 0) {
1072 static const char lzo[] = "lzo";
1073 static const char zlib[] = "zlib";
1074 static const char zstd[] = "zstd";
1075
1076 if (di->m == sizeof(lzo) - 1 && RtlCompareMemory(&di->name[di->n], lzo, di->m) == di->m)
1078 else if (di->m == sizeof(zlib) - 1 && RtlCompareMemory(&di->name[di->n], zlib, di->m) == di->m)
1080 else if (di->m == sizeof(zstd) - 1 && RtlCompareMemory(&di->name[di->n], zstd, di->m) == di->m)
1082 else
1084 }
1085 } else if (tp.item->key.offset == EA_CASE_SENSITIVE_HASH && di->n == sizeof(EA_CASE_SENSITIVE) - 1 && RtlCompareMemory(EA_CASE_SENSITIVE, di->name, di->n) == di->n) {
1086 if (di->m > 0) {
1087 fcb->case_sensitive = di->m == 1 && di->name[di->n] == '1';
1088 fcb->case_sensitive_set = true;
1089 }
1090 } else if (di->n > sizeof(xapref) - 1 && RtlCompareMemory(xapref, di->name, sizeof(xapref) - 1) == sizeof(xapref) - 1) {
1091 dir_child* dc;
1092 ULONG utf16len;
1093
1094 Status = utf8_to_utf16(NULL, 0, &utf16len, &di->name[sizeof(xapref) - 1], di->n + 1 - sizeof(xapref));
1095 if (!NT_SUCCESS(Status)) {
1096 ERR("utf8_to_utf16 1 returned %08lx\n", Status);
1097 reap_fcb(fcb);
1098 return Status;
1099 }
1100
1102 if (!dc) {
1103 ERR("out of memory\n");
1104 reap_fcb(fcb);
1106 }
1107
1108 RtlZeroMemory(dc, sizeof(dir_child));
1109
1110 dc->utf8.MaximumLength = dc->utf8.Length = di->n + 1 - sizeof(xapref);
1111 dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, dc->utf8.MaximumLength, ALLOC_TAG);
1112 if (!dc->utf8.Buffer) {
1113 ERR("out of memory\n");
1114 ExFreePool(dc);
1115 reap_fcb(fcb);
1117 }
1118
1119 RtlCopyMemory(dc->utf8.Buffer, &di->name[sizeof(xapref) - 1], dc->utf8.Length);
1120
1121 dc->name.MaximumLength = dc->name.Length = (uint16_t)utf16len;
1122 dc->name.Buffer = ExAllocatePoolWithTag(PagedPool, dc->name.MaximumLength, ALLOC_TAG);
1123 if (!dc->name.Buffer) {
1124 ERR("out of memory\n");
1125 ExFreePool(dc->utf8.Buffer);
1126 ExFreePool(dc);
1127 reap_fcb(fcb);
1129 }
1130
1131 Status = utf8_to_utf16(dc->name.Buffer, utf16len, &utf16len, dc->utf8.Buffer, dc->utf8.Length);
1132 if (!NT_SUCCESS(Status)) {
1133 ERR("utf8_to_utf16 2 returned %08lx\n", Status);
1134 ExFreePool(dc->utf8.Buffer);
1135 ExFreePool(dc->name.Buffer);
1136 ExFreePool(dc);
1137 reap_fcb(fcb);
1138 return Status;
1139 }
1140
1141 Status = RtlUpcaseUnicodeString(&dc->name_uc, &dc->name, true);
1142 if (!NT_SUCCESS(Status)) {
1143 ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
1144 ExFreePool(dc->utf8.Buffer);
1145 ExFreePool(dc->name.Buffer);
1146 ExFreePool(dc);
1147 reap_fcb(fcb);
1148 return Status;
1149 }
1150
1151 dc->size = di->m;
1152
1153 InsertTailList(&fcb->dir_children_index, &dc->list_entry_index);
1154 } else {
1155 xattr* xa;
1156
1157 xa = ExAllocatePoolWithTag(PagedPool, offsetof(xattr, data[0]) + di->m + di->n, ALLOC_TAG);
1158 if (!xa) {
1159 ERR("out of memory\n");
1160 reap_fcb(fcb);
1162 }
1163
1164 xa->namelen = di->n;
1165 xa->valuelen = di->m;
1166 xa->dirty = false;
1167 RtlCopyMemory(xa->data, di->name, di->m + di->n);
1168
1170 }
1171
1172 len -= (ULONG)offsetof(DIR_ITEM, name[0]) + di->m + di->n;
1173
1174 if (len < offsetof(DIR_ITEM, name[0]))
1175 break;
1176
1177 di = (DIR_ITEM*)&di->name[di->m + di->n];
1178 } while (true);
1179 } else if (tp.item->key.obj_type == TYPE_EXTENT_DATA) {
1180 extent* ext;
1181 bool unique = false;
1182
1183 ed = (EXTENT_DATA*)tp.item->data;
1184
1185 if (tp.item->size < sizeof(EXTENT_DATA)) {
1186 ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset,
1187 tp.item->size, sizeof(EXTENT_DATA));
1188
1189 reap_fcb(fcb);
1190 return STATUS_INTERNAL_ERROR;
1191 }
1192
1193 if (ed->type == EXTENT_TYPE_REGULAR || ed->type == EXTENT_TYPE_PREALLOC) {
1194 EXTENT_DATA2* ed2 = (EXTENT_DATA2*)&ed->data[0];
1195
1196 if (tp.item->size < sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2)) {
1197 ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset,
1198 tp.item->size, sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2));
1199
1200 reap_fcb(fcb);
1201 return STATUS_INTERNAL_ERROR;
1202 }
1203
1204 if (ed2->address == 0 || ed2->size == 0) // sparse
1205 continue;
1206
1207 if (ed2->size != 0 && is_tree_unique(Vcb, tp.tree, Irp))
1208 unique = is_extent_unique(Vcb, ed2->address, ed2->size, Irp);
1209 }
1210
1211 ext = ExAllocatePoolWithTag(pooltype, offsetof(extent, extent_data) + tp.item->size, ALLOC_TAG);
1212 if (!ext) {
1213 ERR("out of memory\n");
1214 reap_fcb(fcb);
1216 }
1217
1218 ext->offset = tp.item->key.offset;
1219 RtlCopyMemory(&ext->extent_data, tp.item->data, tp.item->size);
1220 ext->datalen = tp.item->size;
1221 ext->unique = unique;
1222 ext->ignore = false;
1223 ext->inserted = false;
1224 ext->csum = NULL;
1225
1226 InsertTailList(&fcb->extents, &ext->list_entry);
1227 }
1228 }
1229
1230 if (fcb->type == BTRFS_TYPE_DIRECTORY) {
1231 Status = load_dir_children(Vcb, fcb, false, Irp);
1232 if (!NT_SUCCESS(Status)) {
1233 ERR("load_dir_children returned %08lx\n", Status);
1234 reap_fcb(fcb);
1235 return Status;
1236 }
1237 }
1238
1239 if (no_data) {
1240 fcb->Header.AllocationSize.QuadPart = 0;
1241 fcb->Header.FileSize.QuadPart = 0;
1242 fcb->Header.ValidDataLength.QuadPart = 0;
1243 } else {
1244 if (ed && ed->type == EXTENT_TYPE_INLINE)
1245 fcb->Header.AllocationSize.QuadPart = fcb->inode_item.st_size;
1246 else
1247 fcb->Header.AllocationSize.QuadPart = sector_align(fcb->inode_item.st_size, fcb->Vcb->superblock.sector_size);
1248
1249 fcb->Header.FileSize.QuadPart = fcb->inode_item.st_size;
1250 fcb->Header.ValidDataLength.QuadPart = fcb->inode_item.st_size;
1251 }
1252
1253 if (!atts_set)
1254 fcb->atts = get_file_attributes(Vcb, fcb->subvol, fcb->inode, fcb->type, utf8 && utf8->Buffer[0] == '.', true, Irp);
1255
1256 if (!sd_set)
1257 fcb_get_sd(fcb, parent, false, Irp);
1258
1259 acquire_fcb_lock_exclusive(Vcb);
1260
1261 if (lastle && subvol->fcbs_version == fcbs_version) {
1262 InsertHeadList(lastle, &fcb->list_entry);
1263
1264 if (!subvol->fcbs_ptrs[hash >> 24] || CONTAINING_RECORD(subvol->fcbs_ptrs[hash >> 24], struct _fcb, list_entry)->hash > hash)
1265 subvol->fcbs_ptrs[hash >> 24] = &fcb->list_entry;
1266 } else {
1267 lastle = NULL;
1268
1269 if (subvol->fcbs_ptrs[hash >> 24]) {
1270 LIST_ENTRY* le = subvol->fcbs_ptrs[hash >> 24];
1271
1272 while (le != &subvol->fcbs) {
1273 struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, list_entry);
1274
1275 if (fcb2->inode == inode) {
1276 if (!fcb2->ads) {
1277 if (fcb2->deleted)
1278 deleted_fcb = fcb2;
1279 else {
1280#ifdef DEBUG_FCB_REFCOUNTS
1281 LONG rc = InterlockedIncrement(&fcb2->refcount);
1282
1283 WARN("fcb %p: refcount now %i (subvol %I64x, inode %I64x)\n", fcb2, rc, fcb2->subvol->id, fcb2->inode);
1284#else
1286#endif
1287
1288 *pfcb = fcb2;
1289 reap_fcb(fcb);
1290 release_fcb_lock(Vcb);
1291 return STATUS_SUCCESS;
1292 }
1293 }
1294 } else if (fcb2->hash > hash) {
1295 if (deleted_fcb) {
1296 InterlockedIncrement(&deleted_fcb->refcount);
1297 *pfcb = deleted_fcb;
1298 reap_fcb(fcb);
1299 release_fcb_lock(Vcb);
1300 return STATUS_SUCCESS;
1301 }
1302
1303 lastle = le->Blink;
1304 break;
1305 }
1306
1307 le = le->Flink;
1308 }
1309 }
1310
1312 fcb->atts &= ~FILE_ATTRIBUTE_REPARSE_POINT;
1313
1314 if (!Vcb->readonly && !is_subvol_readonly(subvol, Irp)) {
1315 fcb->atts_changed = true;
1317 }
1318 }
1319
1320 if (!lastle) {
1321 uint8_t c = hash >> 24;
1322
1323 if (c != 0xff) {
1324 uint8_t d = c + 1;
1325
1326 do {
1327 if (subvol->fcbs_ptrs[d]) {
1328 lastle = subvol->fcbs_ptrs[d]->Blink;
1329 break;
1330 }
1331
1332 d++;
1333 } while (d != 0);
1334 }
1335 }
1336
1337 if (lastle) {
1338 InsertHeadList(lastle, &fcb->list_entry);
1339
1340 if (lastle == &subvol->fcbs || (CONTAINING_RECORD(lastle, struct _fcb, list_entry)->hash >> 24) != (hash >> 24))
1341 subvol->fcbs_ptrs[hash >> 24] = &fcb->list_entry;
1342 } else {
1344
1345 if (fcb->list_entry.Blink == &subvol->fcbs || (CONTAINING_RECORD(fcb->list_entry.Blink, struct _fcb, list_entry)->hash >> 24) != (hash >> 24))
1346 subvol->fcbs_ptrs[hash >> 24] = &fcb->list_entry;
1347 }
1348 }
1349
1350 if (fcb->inode == SUBVOL_ROOT_INODE && fcb->subvol->id == BTRFS_ROOT_FSTREE && fcb->subvol != Vcb->root_fileref->fcb->subvol)
1352
1353 subvol->fcbs_version++;
1354
1355 InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
1356
1357 release_fcb_lock(Vcb);
1358
1359 fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
1360
1361 *pfcb = fcb;
1362
1363 return STATUS_SUCCESS;
1364}
1365
1367 dir_child* dc, fcb* parent, fcb** pfcb, PIRP Irp) {
1368 fcb* fcb;
1369 uint8_t* xattrdata;
1370 uint16_t xattrlen, overhead;
1372 KEY searchkey;
1374 static const char xapref[] = "user.";
1377
1378 xattr.Length = sizeof(xapref) - 1 + dc->utf8.Length;
1379 xattr.MaximumLength = xattr.Length + 1;
1380 xattr.Buffer = ExAllocatePoolWithTag(PagedPool, xattr.MaximumLength, ALLOC_TAG);
1381 if (!xattr.Buffer) {
1382 ERR("out of memory\n");
1384 }
1385
1386 RtlCopyMemory(xattr.Buffer, xapref, sizeof(xapref) - 1);
1387 RtlCopyMemory(&xattr.Buffer[sizeof(xapref) - 1], dc->utf8.Buffer, dc->utf8.Length);
1388 xattr.Buffer[xattr.Length] = 0;
1389
1391 if (!fcb) {
1392 ERR("out of memory\n");
1393 ExFreePool(xattr.Buffer);
1395 }
1396
1397 fcb->Vcb = Vcb;
1398
1399 crc32 = calc_crc32c(0xfffffffe, (uint8_t*)xattr.Buffer, xattr.Length);
1400
1401 if (!get_xattr(Vcb, parent->subvol, parent->inode, xattr.Buffer, crc32, &xattrdata, &xattrlen, Irp)) {
1402 ERR("get_xattr failed\n");
1403 reap_fcb(fcb);
1404 ExFreePool(xattr.Buffer);
1405 return STATUS_INTERNAL_ERROR;
1406 }
1407
1408 fcb->subvol = parent->subvol;
1409 fcb->inode = parent->inode;
1410 fcb->type = parent->type;
1411 fcb->ads = true;
1412 fcb->adshash = crc32;
1413 fcb->adsxattr = xattr;
1414
1415 // find XATTR_ITEM overhead and hence calculate maximum length
1416
1417 searchkey.obj_id = parent->inode;
1418 searchkey.obj_type = TYPE_XATTR_ITEM;
1419 searchkey.offset = crc32;
1420
1421 Status = find_item(Vcb, parent->subvol, &tp, &searchkey, false, Irp);
1422 if (!NT_SUCCESS(Status)) {
1423 ERR("find_item returned %08lx\n", Status);
1424 reap_fcb(fcb);
1425 return Status;
1426 }
1427
1428 if (keycmp(tp.item->key, searchkey)) {
1429 ERR("error - could not find key for xattr\n");
1430 reap_fcb(fcb);
1431 return STATUS_INTERNAL_ERROR;
1432 }
1433
1434 if (tp.item->size < xattrlen) {
1435 ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, xattrlen);
1436 reap_fcb(fcb);
1437 return STATUS_INTERNAL_ERROR;
1438 }
1439
1440 overhead = tp.item->size - xattrlen;
1441
1442 fcb->adsmaxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - overhead;
1443
1444 fcb->adsdata.Buffer = (char*)xattrdata;
1445 fcb->adsdata.Length = fcb->adsdata.MaximumLength = xattrlen;
1446
1447 fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
1448 fcb->Header.AllocationSize.QuadPart = xattrlen;
1449 fcb->Header.FileSize.QuadPart = xattrlen;
1450 fcb->Header.ValidDataLength.QuadPart = xattrlen;
1451
1452 TRACE("stream found: size = %x, hash = %08x\n", xattrlen, fcb->adshash);
1453
1454 *pfcb = fcb;
1455
1456 return STATUS_SUCCESS;
1457}
1458
1460 _In_ file_ref* sf, _In_ PUNICODE_STRING name, _In_ bool case_sensitive, _In_ bool lastpart, _In_ bool streampart,
1461 _In_ POOL_TYPE pooltype, _Out_ file_ref** psf2, _In_opt_ PIRP Irp) {
1463 file_ref* sf2;
1464
1465 if (sf->fcb == Vcb->dummy_fcb)
1467
1468 if (streampart) {
1469 bool locked = false;
1470 LIST_ENTRY* le;
1471 UNICODE_STRING name_uc;
1472 dir_child* dc = NULL;
1473 fcb* fcb;
1474 struct _fcb* duff_fcb = NULL;
1475 file_ref* duff_fr = NULL;
1476
1477 if (!case_sensitive) {
1478 Status = RtlUpcaseUnicodeString(&name_uc, name, true);
1479 if (!NT_SUCCESS(Status)) {
1480 ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
1481 return Status;
1482 }
1483 }
1484
1485 if (!ExIsResourceAcquiredSharedLite(&sf->fcb->nonpaged->dir_children_lock)) {
1486 ExAcquireResourceSharedLite(&sf->fcb->nonpaged->dir_children_lock, true);
1487 locked = true;
1488 }
1489
1490 le = sf->fcb->dir_children_index.Flink;
1491 while (le != &sf->fcb->dir_children_index) {
1492 dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_index);
1493
1494 if (dc2->index == 0) {
1495 if ((case_sensitive && dc2->name.Length == name->Length && RtlCompareMemory(dc2->name.Buffer, name->Buffer, dc2->name.Length) == dc2->name.Length) ||
1496 (!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)
1497 ) {
1498 dc = dc2;
1499 break;
1500 }
1501 } else
1502 break;
1503
1504 le = le->Flink;
1505 }
1506
1507 if (!dc) {
1508 if (locked)
1509 ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock);
1510
1511 if (!case_sensitive)
1512 ExFreePool(name_uc.Buffer);
1513
1515 }
1516
1517 if (dc->fileref) {
1518 if (locked)
1519 ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock);
1520
1521 if (!case_sensitive)
1522 ExFreePool(name_uc.Buffer);
1523
1524 increase_fileref_refcount(dc->fileref);
1525 *psf2 = dc->fileref;
1526 return STATUS_SUCCESS;
1527 }
1528
1529 if (locked)
1530 ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock);
1531
1532 if (!case_sensitive)
1533 ExFreePool(name_uc.Buffer);
1534
1535 Status = open_fcb_stream(Vcb, dc, sf->fcb, &fcb, Irp);
1536 if (!NT_SUCCESS(Status)) {
1537 ERR("open_fcb_stream returned %08lx\n", Status);
1538 return Status;
1539 }
1540
1541 fcb->hash = sf->fcb->hash;
1542
1543 acquire_fcb_lock_exclusive(Vcb);
1544
1545 if (sf->fcb->subvol->fcbs_ptrs[fcb->hash >> 24]) {
1546 le = sf->fcb->subvol->fcbs_ptrs[fcb->hash >> 24];
1547
1548 while (le != &sf->fcb->subvol->fcbs) {
1549 struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, list_entry);
1550
1551 if (fcb2->inode == fcb->inode) {
1552 if (fcb2->ads && fcb2->adshash == fcb->adshash) { // FIXME - handle hash collisions
1553 duff_fcb = fcb;
1554 fcb = fcb2;
1555 break;
1556 }
1557 } else if (fcb2->hash > fcb->hash)
1558 break;
1559
1560 le = le->Flink;
1561 }
1562 }
1563
1564 if (!duff_fcb) {
1565 InsertHeadList(&sf->fcb->list_entry, &fcb->list_entry);
1566 InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
1567 fcb->subvol->fcbs_version++;
1568 }
1569
1570 release_fcb_lock(Vcb);
1571
1572 if (duff_fcb) {
1573 reap_fcb(duff_fcb);
1575 }
1576
1577 sf2 = create_fileref(Vcb);
1578 if (!sf2) {
1579 ERR("out of memory\n");
1580 free_fcb(fcb);
1582 }
1583
1584 ExAcquireResourceExclusiveLite(&sf->fcb->nonpaged->dir_children_lock, true);
1585
1586 if (dc->fileref) {
1587 duff_fr = sf2;
1588 sf2 = dc->fileref;
1590 } else {
1591 sf2->fcb = fcb;
1592 sf2->parent = (struct _file_ref*)sf;
1593 sf2->dc = dc;
1594 dc->fileref = sf2;
1596 InsertTailList(&sf->children, &sf2->list_entry);
1597 }
1598
1599 ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock);
1600
1601 if (duff_fr)
1602 ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, duff_fr);
1603 } else {
1604 root* subvol;
1606 dir_child* dc;
1607
1608 Status = find_file_in_dir(name, sf->fcb, &subvol, &inode, &dc, case_sensitive);
1610 TRACE("could not find %.*S\n", (int)(name->Length / sizeof(WCHAR)), name->Buffer);
1611
1613 } else if (Status == STATUS_OBJECT_NAME_INVALID) {
1614 TRACE("invalid filename: %.*S\n", (int)(name->Length / sizeof(WCHAR)), name->Buffer);
1615 return Status;
1616 } else if (!NT_SUCCESS(Status)) {
1617 ERR("find_file_in_dir returned %08lx\n", Status);
1618 return Status;
1619 } else {
1620 fcb* fcb;
1621 file_ref* duff_fr = NULL;
1622
1623 if (dc->fileref) {
1624 if (!lastpart && dc->type != BTRFS_TYPE_DIRECTORY) {
1625 TRACE("passed path including file as subdirectory\n");
1627 }
1628
1629 InterlockedIncrement(&dc->fileref->refcount);
1630 *psf2 = dc->fileref;
1631 return STATUS_SUCCESS;
1632 }
1633
1634 if (!subvol || (subvol != Vcb->root_fileref->fcb->subvol && inode == SUBVOL_ROOT_INODE && subvol->parent != sf->fcb->subvol->id && !dc->root_dir)) {
1635 fcb = Vcb->dummy_fcb;
1637 } else {
1638 Status = open_fcb(Vcb, subvol, inode, dc->type, &dc->utf8, false, sf->fcb, &fcb, pooltype, Irp);
1639
1640 if (!NT_SUCCESS(Status)) {
1641 ERR("open_fcb returned %08lx\n", Status);
1642 return Status;
1643 }
1644 }
1645
1646 if (dc->type != BTRFS_TYPE_DIRECTORY && !lastpart && !(fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT)) {
1647 TRACE("passed path including file as subdirectory\n");
1648 free_fcb(fcb);
1650 }
1651
1652 sf2 = create_fileref(Vcb);
1653 if (!sf2) {
1654 ERR("out of memory\n");
1655 free_fcb(fcb);
1657 }
1658
1659 sf2->fcb = fcb;
1660
1661 ExAcquireResourceExclusiveLite(&sf->fcb->nonpaged->dir_children_lock, true);
1662
1663 if (!dc->fileref) {
1664 sf2->parent = (struct _file_ref*)sf;
1665 sf2->dc = dc;
1666 dc->fileref = sf2;
1667 InsertTailList(&sf->children, &sf2->list_entry);
1669
1670 if (dc->type == BTRFS_TYPE_DIRECTORY)
1671 fcb->fileref = sf2;
1672 } else {
1673 duff_fr = sf2;
1674 sf2 = dc->fileref;
1676 }
1677
1678 ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock);
1679
1680 if (duff_fr)
1681 reap_fileref(Vcb, duff_fr);
1682 }
1683 }
1684
1685 *psf2 = sf2;
1686
1687 return STATUS_SUCCESS;
1688}
1689
1691 _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,
1692 _In_ bool case_sensitive, _In_opt_ PIRP Irp) {
1693 UNICODE_STRING fnus2;
1694 file_ref *dir, *sf, *sf2;
1696 bool has_stream = false;
1698 LIST_ENTRY* le;
1699
1700 TRACE("(%p, %p, %p, %u, %p)\n", Vcb, pfr, related, parent, parsed);
1701
1702 if (Vcb->removing || Vcb->locked)
1703 return STATUS_ACCESS_DENIED;
1704
1705 fnus2 = *fnus;
1706
1707 if (fnus2.Length < sizeof(WCHAR) && !related) {
1708 ERR("error - fnus was too short\n");
1709 return STATUS_INTERNAL_ERROR;
1710 }
1711
1712 if (related && fnus->Length == 0) {
1714
1715 *pfr = related;
1716 return STATUS_SUCCESS;
1717 }
1718
1719 if (related) {
1720 dir = related;
1721 } else {
1722 if (fnus2.Buffer[0] != '\\') {
1723 ERR("error - filename %.*S did not begin with \\\n", (int)(fnus2.Length / sizeof(WCHAR)), fnus2.Buffer);
1725 }
1726
1727 // if path starts with two backslashes, ignore one of them
1728 if (fnus2.Length >= 2 * sizeof(WCHAR) && fnus2.Buffer[1] == '\\') {
1729 fnus2.Buffer++;
1730 fnus2.Length -= sizeof(WCHAR);
1731 fnus2.MaximumLength -= sizeof(WCHAR);
1732 }
1733
1734 if (fnus2.Length == sizeof(WCHAR)) {
1735 if (Vcb->root_fileref->open_count == 0 && !(Vcb->Vpb->Flags & VPB_MOUNTED)) // don't allow root to be opened on unmounted FS
1737
1738 increase_fileref_refcount(Vcb->root_fileref);
1739 *pfr = Vcb->root_fileref;
1740
1741 if (fn_offset)
1742 *fn_offset = 0;
1743
1744 return STATUS_SUCCESS;
1745 } else if (fnus2.Length >= 2 * sizeof(WCHAR) && fnus2.Buffer[1] == '\\')
1747
1748 dir = Vcb->root_fileref;
1749
1750 fnus2.Buffer++;
1751 fnus2.Length -= sizeof(WCHAR);
1752 fnus2.MaximumLength -= sizeof(WCHAR);
1753 }
1754
1755 if (dir->fcb->type != BTRFS_TYPE_DIRECTORY && (fnus->Length < sizeof(WCHAR) || fnus->Buffer[0] != ':')) {
1756 WARN("passed related fileref which isn't a directory (fnus = %.*S)\n",
1757 (int)(fnus->Length / sizeof(WCHAR)), fnus->Buffer);
1759 }
1760
1762
1763 if (fnus->Length != 0 &&
1764 (fnus->Length != sizeof(datastring) - sizeof(WCHAR) || RtlCompareMemory(fnus->Buffer, datastring, sizeof(datastring) - sizeof(WCHAR)) != sizeof(datastring) - sizeof(WCHAR))) {
1765 Status = split_path(Vcb, &fnus2, &parts, &has_stream);
1766 if (!NT_SUCCESS(Status)) {
1767 ERR("split_path returned %08lx\n", Status);
1768 return Status;
1769 }
1770 }
1771
1772 sf = dir;
1774
1775 if (parent && !IsListEmpty(&parts)) {
1776 name_bit* nb;
1777
1779 ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb);
1780
1781 if (has_stream && !IsListEmpty(&parts)) {
1783 ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb);
1784
1785 has_stream = false;
1786 }
1787 }
1788
1789 if (IsListEmpty(&parts)) {
1791 *pfr = dir;
1792
1793 if (fn_offset)
1794 *fn_offset = 0;
1795
1796 goto end2;
1797 }
1798
1799 le = parts.Flink;
1800 do {
1802 bool lastpart = le->Flink == &parts || (has_stream && le->Flink->Flink == &parts);
1803 bool streampart = has_stream && le->Flink == &parts;
1804 bool cs = case_sensitive;
1805
1806 if (!cs) {
1807 if (streampart && sf->parent)
1808 cs = sf->parent->fcb->case_sensitive;
1809 else
1810 cs = sf->fcb->case_sensitive;
1811 }
1812
1813 Status = open_fileref_child(Vcb, sf, &nb->us, cs, lastpart, streampart, pooltype, &sf2, Irp);
1814
1815 if (!NT_SUCCESS(Status)) {
1817 TRACE("open_fileref_child returned %08lx\n", Status);
1818 else
1819 ERR("open_fileref_child returned %08lx\n", Status);
1820
1821 goto end;
1822 }
1823
1824 if (le->Flink == &parts) { // last entry
1825 if (fn_offset) {
1826 if (has_stream)
1828
1829 *fn_offset = (ULONG)(nb->us.Buffer - fnus->Buffer);
1830 }
1831
1832 break;
1833 }
1834
1837
1838 if (parsed) {
1840
1841 *parsed = (USHORT)(nb2->us.Buffer - fnus->Buffer - 1) * sizeof(WCHAR);
1842 }
1843
1844 break;
1845 }
1846
1847 free_fileref(sf);
1848 sf = sf2;
1849
1850 le = le->Flink;
1851 } while (le != &parts);
1852
1853 if (Status != STATUS_REPARSE)
1855 *pfr = sf2;
1856
1857end:
1858 free_fileref(sf);
1859
1860 while (!IsListEmpty(&parts)) {
1862 ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb);
1863 }
1864
1865end2:
1866 TRACE("returning %08lx\n", Status);
1867
1868 return Status;
1869}
1870
1873 dir_child* dc;
1874 bool locked;
1875
1877 if (!dc) {
1878 ERR("out of memory\n");
1880 }
1881
1882 RtlZeroMemory(dc, sizeof(dir_child));
1883
1884 dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, utf8->Length, ALLOC_TAG);
1885 if (!dc->utf8.Buffer) {
1886 ERR("out of memory\n");
1887 ExFreePool(dc);
1889 }
1890
1891 dc->name.Buffer = ExAllocatePoolWithTag(PagedPool, name->Length, ALLOC_TAG);
1892 if (!dc->name.Buffer) {
1893 ERR("out of memory\n");
1894 ExFreePool(dc->utf8.Buffer);
1895 ExFreePool(dc);
1897 }
1898
1899 dc->key.obj_id = inode;
1900 dc->key.obj_type = subvol ? TYPE_ROOT_ITEM : TYPE_INODE_ITEM;
1901 dc->key.offset = subvol ? 0xffffffffffffffff : 0;
1902 dc->type = type;
1903 dc->fileref = NULL;
1904
1905 dc->utf8.Length = dc->utf8.MaximumLength = utf8->Length;
1906 RtlCopyMemory(dc->utf8.Buffer, utf8->Buffer, utf8->Length);
1907
1908 dc->name.Length = dc->name.MaximumLength = name->Length;
1909 RtlCopyMemory(dc->name.Buffer, name->Buffer, name->Length);
1910
1911 Status = RtlUpcaseUnicodeString(&dc->name_uc, name, true);
1912 if (!NT_SUCCESS(Status)) {
1913 ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
1914 ExFreePool(dc->utf8.Buffer);
1915 ExFreePool(dc->name.Buffer);
1916 ExFreePool(dc);
1917 return Status;
1918 }
1919
1920 dc->hash = calc_crc32c(0xffffffff, (uint8_t*)dc->name.Buffer, dc->name.Length);
1921 dc->hash_uc = calc_crc32c(0xffffffff, (uint8_t*)dc->name_uc.Buffer, dc->name_uc.Length);
1922
1923 locked = ExIsResourceAcquiredExclusive(&fcb->nonpaged->dir_children_lock);
1924
1925 if (!locked)
1926 ExAcquireResourceExclusiveLite(&fcb->nonpaged->dir_children_lock, true);
1927
1929 dc->index = 2;
1930 else {
1932
1933 dc->index = max(2, dc2->index + 1);
1934 }
1935
1936 InsertTailList(&fcb->dir_children_index, &dc->list_entry_index);
1937
1939
1940 if (!locked)
1941 ExReleaseResourceLite(&fcb->nonpaged->dir_children_lock);
1942
1943 *pdc = dc;
1944
1945 return STATUS_SUCCESS;
1946}
1947
1948uint32_t inherit_mode(fcb* parfcb, bool is_dir) {
1949 uint32_t mode;
1950
1951 if (!parfcb)
1952 return 0755;
1953
1954 mode = parfcb->inode_item.st_mode & ~S_IFDIR;
1955 mode &= ~S_ISVTX; // clear sticky bit
1956 mode &= ~S_ISUID; // clear setuid bit
1957
1958 if (!is_dir)
1959 mode &= ~S_ISGID; // if not directory, clear setgid bit
1960
1961 return mode;
1962}
1963
1966 LIST_ENTRY ealist, *le;
1967 uint16_t size = 0;
1968 char* buf;
1969
1970 InitializeListHead(&ealist);
1971
1972 do {
1973 STRING s;
1974 bool found = false;
1975
1976 s.Length = s.MaximumLength = ea->EaNameLength;
1977 s.Buffer = ea->EaName;
1978
1979 RtlUpperString(&s, &s);
1980
1981 le = ealist.Flink;
1982 while (le != &ealist) {
1984
1985 if (item->name.Length == s.Length && RtlCompareMemory(item->name.Buffer, s.Buffer, s.Length) == s.Length) {
1986 item->flags = ea->Flags;
1987 item->value.Length = item->value.MaximumLength = ea->EaValueLength;
1988 item->value.Buffer = &ea->EaName[ea->EaNameLength + 1];
1989 found = true;
1990 break;
1991 }
1992
1993 le = le->Flink;
1994 }
1995
1996 if (!found) {
1998 if (!item) {
1999 ERR("out of memory\n");
2001 goto end;
2002 }
2003
2004 item->name.Length = item->name.MaximumLength = ea->EaNameLength;
2005 item->name.Buffer = ea->EaName;
2006
2007 item->value.Length = item->value.MaximumLength = ea->EaValueLength;
2008 item->value.Buffer = &ea->EaName[ea->EaNameLength + 1];
2009
2010 item->flags = ea->Flags;
2011
2012 InsertTailList(&ealist, &item->list_entry);
2013 }
2014
2015 if (ea->NextEntryOffset == 0)
2016 break;
2017
2018 ea = (FILE_FULL_EA_INFORMATION*)(((uint8_t*)ea) + ea->NextEntryOffset);
2019 } while (true);
2020
2021 // handle LXSS values
2022 le = ealist.Flink;
2023 while (le != &ealist) {
2024 LIST_ENTRY* le2 = le->Flink;
2026
2027 if (item->name.Length == sizeof(lxuid) - 1 && RtlCompareMemory(item->name.Buffer, lxuid, item->name.Length) == item->name.Length) {
2028 if (item->value.Length < sizeof(uint32_t)) {
2029 ERR("uid value was shorter than expected\n");
2031 goto end;
2032 }
2033
2034 RtlCopyMemory(&fcb->inode_item.st_uid, item->value.Buffer, sizeof(uint32_t));
2035 fcb->sd_dirty = true;
2036 fcb->sd_deleted = false;
2037
2038 RemoveEntryList(&item->list_entry);
2040 } else if (item->name.Length == sizeof(lxgid) - 1 && RtlCompareMemory(item->name.Buffer, lxgid, item->name.Length) == item->name.Length) {
2041 if (item->value.Length < sizeof(uint32_t)) {
2042 ERR("gid value was shorter than expected\n");
2044 goto end;
2045 }
2046
2047 RtlCopyMemory(&fcb->inode_item.st_gid, item->value.Buffer, sizeof(uint32_t));
2048
2049 RemoveEntryList(&item->list_entry);
2051 } else if (item->name.Length == sizeof(lxmod) - 1 && RtlCompareMemory(item->name.Buffer, lxmod, item->name.Length) == item->name.Length) {
2053 uint32_t val;
2054
2055 if (item->value.Length < sizeof(uint32_t)) {
2056 ERR("mode value was shorter than expected\n");
2058 goto end;
2059 }
2060
2061 val = *(uint32_t*)item->value.Buffer;
2062
2063 fcb->inode_item.st_mode &= ~allowed;
2064 fcb->inode_item.st_mode |= val & allowed;
2065
2067 if (__S_ISTYPE(val, __S_IFCHR)) {
2069 fcb->inode_item.st_mode &= ~__S_IFMT;
2071 } else if (__S_ISTYPE(val, __S_IFBLK)) {
2073 fcb->inode_item.st_mode &= ~__S_IFMT;
2075 } else if (__S_ISTYPE(val, __S_IFIFO)) {
2077 fcb->inode_item.st_mode &= ~__S_IFMT;
2079 } else if (__S_ISTYPE(val, __S_IFSOCK)) {
2081 fcb->inode_item.st_mode &= ~__S_IFMT;
2083 }
2084 }
2085
2086 RemoveEntryList(&item->list_entry);
2088 } else if (item->name.Length == sizeof(lxdev) - 1 && RtlCompareMemory(item->name.Buffer, lxdev, item->name.Length) == item->name.Length) {
2090
2091 if (item->value.Length < sizeof(uint64_t)) {
2092 ERR("dev value was shorter than expected\n");
2094 goto end;
2095 }
2096
2097 major = *(uint32_t*)item->value.Buffer;
2098 minor = *(uint32_t*)&item->value.Buffer[sizeof(uint32_t)];
2099
2100 fcb->inode_item.st_rdev = (minor & 0xFFFFF) | ((major & 0xFFFFFFFFFFF) << 20);
2101
2102 RemoveEntryList(&item->list_entry);
2104 }
2105
2106 le = le2;
2107 }
2108
2110 fcb->inode_item.st_rdev = 0;
2111
2112 if (IsListEmpty(&ealist))
2113 return STATUS_SUCCESS;
2114
2115 le = ealist.Flink;
2116 while (le != &ealist) {
2118
2119 if (size % 4 > 0)
2120 size += 4 - (size % 4);
2121
2122 size += (uint16_t)offsetof(FILE_FULL_EA_INFORMATION, EaName[0]) + item->name.Length + 1 + item->value.Length;
2123
2124 le = le->Flink;
2125 }
2126
2128 if (!buf) {
2129 ERR("out of memory\n");
2131 goto end;
2132 }
2133
2136
2137 fcb->ealen = 4;
2138 ea = NULL;
2139
2140 le = ealist.Flink;
2141 while (le != &ealist) {
2143
2144 if (ea) {
2146
2147 if (ea->NextEntryOffset % 4 > 0)
2148 ea->NextEntryOffset += 4 - (ea->NextEntryOffset % 4);
2149
2150 ea = (FILE_FULL_EA_INFORMATION*)(((uint8_t*)ea) + ea->NextEntryOffset);
2151 } else
2153
2154 ea->NextEntryOffset = 0;
2155 ea->Flags = item->flags;
2156 ea->EaNameLength = (UCHAR)item->name.Length;
2157 ea->EaValueLength = item->value.Length;
2158
2159 RtlCopyMemory(ea->EaName, item->name.Buffer, item->name.Length);
2160 ea->EaName[item->name.Length] = 0;
2161 RtlCopyMemory(&ea->EaName[item->name.Length + 1], item->value.Buffer, item->value.Length);
2162
2163 fcb->ealen += 5 + item->name.Length + item->value.Length;
2164
2165 le = le->Flink;
2166 }
2167
2168 fcb->ea_changed = true;
2169
2171
2172end:
2173 while (!IsListEmpty(&ealist)) {
2175
2177 }
2178
2179 return Status;
2180}
2181
2184 _Out_ file_ref** pfr, bool case_sensitive, _In_ LIST_ENTRY* rollback) {
2186 fcb* fcb;
2187 ULONG utf8len;
2188 char* utf8 = NULL;
2190 uint8_t type;
2195 USHORT defda;
2196 file_ref* fileref;
2197 dir_child* dc;
2198 ANSI_STRING utf8as;
2199 LIST_ENTRY* lastle = NULL;
2200 file_ref* existing_fileref = NULL;
2201#ifdef DEBUG_FCB_REFCOUNTS
2202 LONG rc;
2203#endif
2204
2205 if (parfileref->fcb == Vcb->dummy_fcb)
2206 return STATUS_ACCESS_DENIED;
2207
2210
2211 Status = utf16_to_utf8(NULL, 0, &utf8len, fpus->Buffer, fpus->Length);
2212 if (!NT_SUCCESS(Status)) {
2213 ERR("utf16_to_utf8 returned %08lx\n", Status);
2214 return Status;
2215 }
2216
2217 utf8 = ExAllocatePoolWithTag(pool_type, utf8len + 1, ALLOC_TAG);
2218 if (!utf8) {
2219 ERR("out of memory\n");
2221 }
2222
2223 Status = utf16_to_utf8(utf8, utf8len, &utf8len, fpus->Buffer, fpus->Length);
2224 if (!NT_SUCCESS(Status)) {
2225 ERR("utf16_to_utf8 returned %08lx\n", Status);
2226 ExFreePool(utf8);
2227 return Status;
2228 }
2229
2230 utf8[utf8len] = 0;
2231
2234
2235 TRACE("create file %.*S\n", (int)(fpus->Length / sizeof(WCHAR)), fpus->Buffer);
2236 ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2237 TRACE("parfileref->fcb->inode_item.st_size (inode %I64x) was %I64x\n", parfileref->fcb->inode, parfileref->fcb->inode_item.st_size);
2238 parfileref->fcb->inode_item.st_size += utf8len * 2;
2239 TRACE("parfileref->fcb->inode_item.st_size (inode %I64x) now %I64x\n", parfileref->fcb->inode, parfileref->fcb->inode_item.st_size);
2240 parfileref->fcb->inode_item.transid = Vcb->superblock.generation;
2241 parfileref->fcb->inode_item.sequence++;
2242 parfileref->fcb->inode_item.st_ctime = now;
2243 parfileref->fcb->inode_item.st_mtime = now;
2244 ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2245
2246 parfileref->fcb->inode_item_changed = true;
2247 mark_fcb_dirty(parfileref->fcb);
2248
2249 inode = InterlockedIncrement64(&parfileref->fcb->subvol->lastinode);
2250
2252
2253 // FIXME - link FILE_ATTRIBUTE_READONLY to st_mode
2254
2255 TRACE("requested attributes = %x\n", IrpSp->Parameters.Create.FileAttributes);
2256
2257 defda = 0;
2258
2259 if (utf8[0] == '.')
2260 defda |= FILE_ATTRIBUTE_HIDDEN;
2261
2263 defda |= FILE_ATTRIBUTE_DIRECTORY;
2265 } else
2266 IrpSp->Parameters.Create.FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
2267
2268 if (!(IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
2269 IrpSp->Parameters.Create.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
2270 defda |= FILE_ATTRIBUTE_ARCHIVE;
2271 }
2272
2273 TRACE("defda = %x\n", defda);
2274
2275 if (IrpSp->Parameters.Create.FileAttributes == FILE_ATTRIBUTE_NORMAL)
2276 IrpSp->Parameters.Create.FileAttributes = defda;
2277
2278 fcb = create_fcb(Vcb, pool_type);
2279 if (!fcb) {
2280 ERR("out of memory\n");
2281 ExFreePool(utf8);
2282
2283 ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2284 parfileref->fcb->inode_item.st_size -= utf8len * 2;
2285 ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2286
2288 }
2289
2290 fcb->Vcb = Vcb;
2291
2294
2295 fcb->inode_item.generation = Vcb->superblock.generation;
2296 fcb->inode_item.transid = Vcb->superblock.generation;
2297 fcb->inode_item.st_size = 0;
2300 fcb->inode_item.st_nlink = 1;
2301 fcb->inode_item.st_gid = GID_NOBODY; // FIXME?
2302 fcb->inode_item.st_mode = inherit_mode(parfileref->fcb, type == BTRFS_TYPE_DIRECTORY); // use parent's permissions by default
2303 fcb->inode_item.st_rdev = 0;
2304 fcb->inode_item.flags = 0;
2305 fcb->inode_item.sequence = 1;
2310
2313 else {
2315 fcb->inode_item.st_mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH); // remove executable bit if not directory
2316 }
2317
2320 } else {
2321 // inherit nodatacow flag from parent directory
2322 if (parfileref->fcb->inode_item.flags & BTRFS_INODE_NODATACOW || Vcb->options.nodatacow) {
2324
2327 }
2328
2329 if (parfileref->fcb->inode_item.flags & BTRFS_INODE_COMPRESS &&
2332 }
2333 }
2334
2336 fcb->prop_compression = parfileref->fcb->prop_compression;
2338 } else
2340
2341 fcb->inode_item_changed = true;
2342
2343 fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
2344 fcb->Header.AllocationSize.QuadPart = 0;
2345 fcb->Header.FileSize.QuadPart = 0;
2346 fcb->Header.ValidDataLength.QuadPart = 0;
2347
2348 fcb->atts = IrpSp->Parameters.Create.FileAttributes & ~FILE_ATTRIBUTE_NORMAL;
2349 fcb->atts_changed = fcb->atts != defda;
2350
2351#ifdef DEBUG_FCB_REFCOUNTS
2352 rc = InterlockedIncrement(&parfileref->fcb->refcount);
2353 WARN("fcb %p: refcount now %i\n", parfileref->fcb, rc);
2354#else
2355 InterlockedIncrement(&parfileref->fcb->refcount);
2356#endif
2357 fcb->subvol = parfileref->fcb->subvol;
2358 fcb->inode = inode;
2359 fcb->type = type;
2360 fcb->created = true;
2361 fcb->deleted = true;
2362
2363 fcb->hash = calc_crc32c(0xffffffff, (uint8_t*)&inode, sizeof(uint64_t));
2364
2365 acquire_fcb_lock_exclusive(Vcb);
2366
2367 if (fcb->subvol->fcbs_ptrs[fcb->hash >> 24]) {
2368 LIST_ENTRY* le = fcb->subvol->fcbs_ptrs[fcb->hash >> 24];
2369
2370 while (le != &fcb->subvol->fcbs) {
2371 struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, list_entry);
2372
2373 if (fcb2->hash > fcb->hash) {
2374 lastle = le->Blink;
2375 break;
2376 }
2377
2378 le = le->Flink;
2379 }
2380 }
2381
2382 if (!lastle) {
2383 uint8_t c = fcb->hash >> 24;
2384
2385 if (c != 0xff) {
2386 uint8_t d = c + 1;
2387
2388 do {
2389 if (fcb->subvol->fcbs_ptrs[d]) {
2390 lastle = fcb->subvol->fcbs_ptrs[d]->Blink;
2391 break;
2392 }
2393
2394 d++;
2395 } while (d != 0);
2396 }
2397 }
2398
2399 if (lastle) {
2400 InsertHeadList(lastle, &fcb->list_entry);
2401
2402 if (lastle == &fcb->subvol->fcbs || (CONTAINING_RECORD(lastle, struct _fcb, list_entry)->hash >> 24) != (fcb->hash >> 24))
2403 fcb->subvol->fcbs_ptrs[fcb->hash >> 24] = &fcb->list_entry;
2404 } else {
2406
2407 if (fcb->list_entry.Blink == &fcb->subvol->fcbs || (CONTAINING_RECORD(fcb->list_entry.Blink, struct _fcb, list_entry)->hash >> 24) != (fcb->hash >> 24))
2408 fcb->subvol->fcbs_ptrs[fcb->hash >> 24] = &fcb->list_entry;
2409 }
2410
2411 InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
2412
2413 fcb->subvol->fcbs_version++;
2414
2415 release_fcb_lock(Vcb);
2416
2418
2419 Status = fcb_get_new_sd(fcb, parfileref, IrpSp->Parameters.Create.SecurityContext->AccessState);
2420
2421 if (!NT_SUCCESS(Status)) {
2422 ERR("fcb_get_new_sd returned %08lx\n", Status);
2423 free_fcb(fcb);
2424
2425 ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2426 parfileref->fcb->inode_item.st_size -= utf8len * 2;
2427 ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2428
2429 ExFreePool(utf8);
2430
2431 return Status;
2432 }
2433
2434 fcb->sd_dirty = true;
2435
2436 if (ea && ealen > 0) {
2438 if (!NT_SUCCESS(Status)) {
2439 ERR("file_create_parse_ea returned %08lx\n", Status);
2440 free_fcb(fcb);
2441
2442 ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2443 parfileref->fcb->inode_item.st_size -= utf8len * 2;
2444 ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2445
2446 ExFreePool(utf8);
2447
2448 return Status;
2449 }
2450 }
2451
2453 if (!fileref) {
2454 ERR("out of memory\n");
2455 free_fcb(fcb);
2456
2457 ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2458 parfileref->fcb->inode_item.st_size -= utf8len * 2;
2459 ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2460
2461 ExFreePool(utf8);
2462
2464 }
2465
2466 fileref->fcb = fcb;
2467
2468 if (Irp->Overlay.AllocationSize.QuadPart > 0 && !write_fcb_compressed(fcb) && fcb->type != BTRFS_TYPE_DIRECTORY) {
2469 Status = extend_file(fcb, fileref, Irp->Overlay.AllocationSize.QuadPart, true, NULL, rollback);
2470
2471 if (!NT_SUCCESS(Status)) {
2472 ERR("extend_file returned %08lx\n", Status);
2474
2475 ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2476 parfileref->fcb->inode_item.st_size -= utf8len * 2;
2477 ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2478
2479 ExFreePool(utf8);
2480
2481 return Status;
2482 }
2483 }
2484
2485 if (fcb->type == BTRFS_TYPE_DIRECTORY) {
2487 if (!fcb->hash_ptrs) {
2488 ERR("out of memory\n");
2490
2491 ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2492 parfileref->fcb->inode_item.st_size -= utf8len * 2;
2493 ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2494
2495 ExFreePool(utf8);
2496
2498 }
2499
2500 RtlZeroMemory(fcb->hash_ptrs, sizeof(LIST_ENTRY*) * 256);
2501
2503 if (!fcb->hash_ptrs_uc) {
2504 ERR("out of memory\n");
2506
2507 ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2508 parfileref->fcb->inode_item.st_size -= utf8len * 2;
2509 ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2510
2511 ExFreePool(utf8);
2512
2514 }
2515
2516 RtlZeroMemory(fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256);
2517 }
2518
2519 fcb->deleted = false;
2520
2521 fileref->created = true;
2522
2523 fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
2524 fcb->subvol->root_item.ctime = now;
2525
2526 utf8as.Buffer = utf8;
2527 utf8as.Length = utf8as.MaximumLength = (uint16_t)utf8len;
2528
2529 ExAcquireResourceExclusiveLite(&parfileref->fcb->nonpaged->dir_children_lock, true);
2530
2531 // check again doesn't already exist
2532 if (case_sensitive) {
2533 uint32_t dc_hash = calc_crc32c(0xffffffff, (uint8_t*)fpus->Buffer, fpus->Length);
2534
2535 if (parfileref->fcb->hash_ptrs[dc_hash >> 24]) {
2536 LIST_ENTRY* le = parfileref->fcb->hash_ptrs[dc_hash >> 24];
2537 while (le != &parfileref->fcb->dir_children_hash) {
2538 dc = CONTAINING_RECORD(le, dir_child, list_entry_hash);
2539
2540 if (dc->hash == dc_hash && dc->name.Length == fpus->Length && RtlCompareMemory(dc->name.Buffer, fpus->Buffer, fpus->Length) == fpus->Length) {
2541 existing_fileref = dc->fileref;
2542 break;
2543 } else if (dc->hash > dc_hash)
2544 break;
2545
2546 le = le->Flink;
2547 }
2548 }
2549 } else {
2550 UNICODE_STRING fpusuc;
2551
2552 Status = RtlUpcaseUnicodeString(&fpusuc, fpus, true);
2553 if (!NT_SUCCESS(Status)) {
2554 ExReleaseResourceLite(&parfileref->fcb->nonpaged->dir_children_lock);
2555 ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
2557
2558 ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2559 parfileref->fcb->inode_item.st_size -= utf8len * 2;
2560 ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2561
2562 ExFreePool(utf8);
2563
2564 return Status;
2565 }
2566
2567 uint32_t dc_hash = calc_crc32c(0xffffffff, (uint8_t*)fpusuc.Buffer, fpusuc.Length);
2568
2569 if (parfileref->fcb->hash_ptrs_uc[dc_hash >> 24]) {
2570 LIST_ENTRY* le = parfileref->fcb->hash_ptrs_uc[dc_hash >> 24];
2571 while (le != &parfileref->fcb->dir_children_hash_uc) {
2572 dc = CONTAINING_RECORD(le, dir_child, list_entry_hash_uc);
2573
2574 if (dc->hash_uc == dc_hash && dc->name.Length == fpusuc.Length && RtlCompareMemory(dc->name.Buffer, fpusuc.Buffer, fpusuc.Length) == fpusuc.Length) {
2575 existing_fileref = dc->fileref;
2576 break;
2577 } else if (dc->hash_uc > dc_hash)
2578 break;
2579
2580 le = le->Flink;
2581 }
2582 }
2583
2584 ExFreePool(fpusuc.Buffer);
2585 }
2586
2587 if (existing_fileref) {
2588 ExReleaseResourceLite(&parfileref->fcb->nonpaged->dir_children_lock);
2590
2591 ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2592 parfileref->fcb->inode_item.st_size -= utf8len * 2;
2593 ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2594
2595 ExFreePool(utf8);
2596
2597 increase_fileref_refcount(existing_fileref);
2598 *pfr = existing_fileref;
2599
2601 }
2602
2603 Status = add_dir_child(parfileref->fcb, fcb->inode, false, &utf8as, fpus, fcb->type, &dc);
2604 if (!NT_SUCCESS(Status)) {
2605 ExReleaseResourceLite(&parfileref->fcb->nonpaged->dir_children_lock);
2606 ERR("add_dir_child returned %08lx\n", Status);
2608
2609 ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
2610 parfileref->fcb->inode_item.st_size -= utf8len * 2;
2611 ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2612
2613 ExFreePool(utf8);
2614
2615 return Status;
2616 }
2617
2618 fileref->parent = parfileref;
2619 fileref->dc = dc;
2620 dc->fileref = fileref;
2621
2623 fileref->fcb->fileref = fileref;
2624
2625 InsertTailList(&parfileref->children, &fileref->list_entry);
2626 ExReleaseResourceLite(&parfileref->fcb->nonpaged->dir_children_lock);
2627
2628 ExFreePool(utf8);
2629
2631 increase_fileref_refcount(parfileref);
2632
2633 *pfr = fileref;
2634
2635 TRACE("created new file in subvol %I64x, inode %I64x\n", fcb->subvol->id, fcb->inode);
2636
2637 return STATUS_SUCCESS;
2638}
2639
2641 file_ref** pfileref, file_ref** pparfileref, PUNICODE_STRING fpus, PUNICODE_STRING stream, PIRP Irp,
2644 file_ref *fileref, *newpar, *parfileref;
2645 fcb* fcb;
2646 static const char xapref[] = "user.";
2647 static const WCHAR DOSATTRIB[] = L"DOSATTRIB";
2648 static const WCHAR EA[] = L"EA";
2649 static const WCHAR reparse[] = L"reparse";
2650 static const WCHAR casesensitive_str[] = L"casesensitive";
2653 ULONG utf8len, overhead;
2655 KEY searchkey;
2657 dir_child* dc;
2658 dir_child* existing_dc = NULL;
2659 ACCESS_MASK granted_access;
2660#ifdef DEBUG_FCB_REFCOUNTS
2661 LONG rc;
2662#endif
2663
2664 TRACE("fpus = %.*S\n", (int)(fpus->Length / sizeof(WCHAR)), fpus->Buffer);
2665 TRACE("stream = %.*S\n", (int)(stream->Length / sizeof(WCHAR)), stream->Buffer);
2666
2667 parfileref = *pparfileref;
2668
2669 if (parfileref->fcb == Vcb->dummy_fcb)
2670 return STATUS_ACCESS_DENIED;
2671
2672 Status = check_file_name_valid(stream, false, true);
2673 if (!NT_SUCCESS(Status))
2674 return Status;
2675
2676 Status = open_fileref(Vcb, &newpar, fpus, parfileref, false, NULL, NULL, PagedPool, case_sensitive, Irp);
2677
2679 UNICODE_STRING fpus2;
2680
2681 Status = check_file_name_valid(fpus, false, false);
2682 if (!NT_SUCCESS(Status))
2683 return Status;
2684
2685 fpus2.Length = fpus2.MaximumLength = fpus->Length;
2687
2688 if (!fpus2.Buffer) {
2689 ERR("out of memory\n");
2691 }
2692
2693 RtlCopyMemory(fpus2.Buffer, fpus->Buffer, fpus2.Length);
2694
2695 SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2696
2697 if (!SeAccessCheck(parfileref->fcb->sd, &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
2700 &granted_access, &Status)) {
2701 SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2702 return Status;
2703 }
2704
2705 SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2706
2707 Status = file_create2(Irp, Vcb, &fpus2, parfileref, options, NULL, 0, &newpar, case_sensitive, rollback);
2708
2709 if (!NT_SUCCESS(Status)) {
2710 ERR("file_create2 returned %08lx\n", Status);
2711 ExFreePool(fpus2.Buffer);
2712 return Status;
2713 } else if (Status != STATUS_OBJECT_NAME_COLLISION) {
2716 }
2717
2718 ExFreePool(fpus2.Buffer);
2719 } else if (!NT_SUCCESS(Status)) {
2720 ERR("open_fileref returned %08lx\n", Status);
2721 return Status;
2722 }
2723
2724 parfileref = newpar;
2725 *pparfileref = parfileref;
2726
2727 if (parfileref->fcb->type != BTRFS_TYPE_FILE && parfileref->fcb->type != BTRFS_TYPE_SYMLINK && parfileref->fcb->type != BTRFS_TYPE_DIRECTORY) {
2728 WARN("parent not file, directory, or symlink\n");
2729 free_fileref(parfileref);
2731 }
2732
2734 WARN("tried to create directory as stream\n");
2735 free_fileref(parfileref);
2737 }
2738
2740 free_fileref(parfileref);
2741 return STATUS_ACCESS_DENIED;
2742 }
2743
2744 SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2745
2746 if (!SeAccessCheck(parfileref->fcb->sd, &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
2748 &granted_access, &Status)) {
2749 SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2750 free_fileref(parfileref);
2751 return Status;
2752 }
2753
2754 SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2755
2756 if ((stream->Length == sizeof(DOSATTRIB) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, DOSATTRIB, stream->Length) == stream->Length) ||
2757 (stream->Length == sizeof(EA) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, EA, stream->Length) == stream->Length) ||
2758 (stream->Length == sizeof(reparse) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, reparse, stream->Length) == stream->Length) ||
2759 (stream->Length == sizeof(casesensitive_str) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, casesensitive_str, stream->Length) == stream->Length)) {
2760 free_fileref(parfileref);
2762 }
2763
2765 if (!fcb) {
2766 ERR("out of memory\n");
2767 free_fileref(parfileref);
2769 }
2770
2771 fcb->Vcb = Vcb;
2772
2773 fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
2774 fcb->Header.AllocationSize.QuadPart = 0;
2775 fcb->Header.FileSize.QuadPart = 0;
2776 fcb->Header.ValidDataLength.QuadPart = 0;
2777
2778#ifdef DEBUG_FCB_REFCOUNTS
2779 rc = InterlockedIncrement(&parfileref->fcb->refcount);
2780 WARN("fcb %p: refcount now %i\n", parfileref->fcb, rc);
2781#else
2782 InterlockedIncrement(&parfileref->fcb->refcount);
2783#endif
2784 fcb->subvol = parfileref->fcb->subvol;
2785 fcb->inode = parfileref->fcb->inode;
2786 fcb->hash = parfileref->fcb->hash;
2787 fcb->type = parfileref->fcb->type;
2788
2789 fcb->ads = true;
2790
2791 Status = utf16_to_utf8(NULL, 0, &utf8len, stream->Buffer, stream->Length);
2792 if (!NT_SUCCESS(Status)) {
2793 ERR("utf16_to_utf8 1 returned %08lx\n", Status);
2794 reap_fcb(fcb);
2795 free_fileref(parfileref);
2796 return Status;
2797 }
2798
2799 fcb->adsxattr.Length = (uint16_t)utf8len + sizeof(xapref) - 1;
2802 if (!fcb->adsxattr.Buffer) {
2803 ERR("out of memory\n");
2804 reap_fcb(fcb);
2805 free_fileref(parfileref);
2807 }
2808
2809 RtlCopyMemory(fcb->adsxattr.Buffer, xapref, sizeof(xapref) - 1);
2810
2811 Status = utf16_to_utf8(&fcb->adsxattr.Buffer[sizeof(xapref) - 1], utf8len, &utf8len, stream->Buffer, stream->Length);
2812 if (!NT_SUCCESS(Status)) {
2813 ERR("utf16_to_utf8 2 returned %08lx\n", Status);
2814 reap_fcb(fcb);
2815 free_fileref(parfileref);
2816 return Status;
2817 }
2818
2820
2821 TRACE("adsxattr = %s\n", fcb->adsxattr.Buffer);
2822
2824 TRACE("adshash = %08x\n", fcb->adshash);
2825
2826 searchkey.obj_id = parfileref->fcb->inode;
2827 searchkey.obj_type = TYPE_XATTR_ITEM;
2828 searchkey.offset = fcb->adshash;
2829
2830 Status = find_item(Vcb, parfileref->fcb->subvol, &tp, &searchkey, false, Irp);
2831 if (!NT_SUCCESS(Status)) {
2832 ERR("find_item returned %08lx\n", Status);
2833 reap_fcb(fcb);
2834 free_fileref(parfileref);
2835 return Status;
2836 }
2837
2838 if (!keycmp(tp.item->key, searchkey))
2839 overhead = tp.item->size;
2840 else
2841 overhead = 0;
2842
2843 fcb->adsmaxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - (sizeof(DIR_ITEM) - 1);
2844
2845 if (utf8len + sizeof(xapref) - 1 + overhead > fcb->adsmaxlen) {
2846 WARN("not enough room for new DIR_ITEM (%Iu + %lu > %lu)\n", utf8len + sizeof(xapref) - 1, overhead, fcb->adsmaxlen);
2847 reap_fcb(fcb);
2848 free_fileref(parfileref);
2849 return STATUS_DISK_FULL;
2850 } else
2851 fcb->adsmaxlen -= overhead + utf8len + sizeof(xapref) - 1;
2852
2853 fcb->created = true;
2854 fcb->deleted = true;
2855
2856 acquire_fcb_lock_exclusive(Vcb);
2857 InsertHeadList(&parfileref->fcb->list_entry, &fcb->list_entry); // insert in list after parent fcb
2858 InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
2859 parfileref->fcb->subvol->fcbs_version++;
2860 release_fcb_lock(Vcb);
2861
2863
2865 if (!fileref) {
2866 ERR("out of memory\n");
2867 free_fcb(fcb);
2868 free_fileref(parfileref);
2870 }
2871
2872 fileref->fcb = fcb;
2873
2875 if (!dc) {
2876 ERR("out of memory\n");
2878 free_fileref(parfileref);
2880 }
2881
2882 RtlZeroMemory(dc, sizeof(dir_child));
2883
2884 dc->utf8.MaximumLength = dc->utf8.Length = fcb->adsxattr.Length + 1 - sizeof(xapref);
2885 dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, dc->utf8.MaximumLength, ALLOC_TAG);
2886 if (!dc->utf8.Buffer) {
2887 ERR("out of memory\n");
2888 ExFreePool(dc);
2890 free_fileref(parfileref);
2892 }
2893
2894 RtlCopyMemory(dc->utf8.Buffer, &fcb->adsxattr.Buffer[sizeof(xapref) - 1], fcb->adsxattr.Length + 1 - sizeof(xapref));
2895
2896 dc->name.MaximumLength = dc->name.Length = stream->Length;
2897 dc->name.Buffer = ExAllocatePoolWithTag(pool_type, dc->name.MaximumLength, ALLOC_TAG);
2898 if (!dc->name.Buffer) {
2899 ERR("out of memory\n");
2900 ExFreePool(dc->utf8.Buffer);
2901 ExFreePool(dc);
2903 free_fileref(parfileref);
2905 }
2906
2907 RtlCopyMemory(dc->name.Buffer, stream->Buffer, stream->Length);
2908
2909 Status = RtlUpcaseUnicodeString(&dc->name_uc, &dc->name, true);
2910 if (!NT_SUCCESS(Status)) {
2911 ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
2912 ExFreePool(dc->utf8.Buffer);
2913 ExFreePool(dc->name.Buffer);
2914 ExFreePool(dc);
2916 free_fileref(parfileref);
2917 return Status;
2918 }
2919
2922
2923 ExAcquireResourceExclusiveLite(&parfileref->fcb->nonpaged->dir_children_lock, true);
2924
2925 LIST_ENTRY* le = parfileref->fcb->dir_children_index.Flink;
2926 while (le != &parfileref->fcb->dir_children_index) {
2927 dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_index);
2928
2929 if (dc2->index == 0) {
2930 if ((case_sensitive && dc2->name.Length == dc->name.Length && RtlCompareMemory(dc2->name.Buffer, dc->name.Buffer, dc2->name.Length) == dc2->name.Length) ||
2931 (!case_sensitive && dc2->name_uc.Length == dc->name_uc.Length && RtlCompareMemory(dc2->name_uc.Buffer, dc->name_uc.Buffer, dc2->name_uc.Length) == dc2->name_uc.Length)
2932 ) {
2933 existing_dc = dc2;
2934 break;
2935 }
2936 } else
2937 break;
2938
2939 le = le->Flink;
2940 }
2941
2942 if (existing_dc) {
2943 ExFreePool(dc->utf8.Buffer);
2944 ExFreePool(dc->name.Buffer);
2945 ExFreePool(dc);
2947 free_fileref(parfileref);
2948
2949 increase_fileref_refcount(existing_dc->fileref);
2950 *pfileref = existing_dc->fileref;
2951
2953 }
2954
2955 dc->fileref = fileref;
2956 fileref->dc = dc;
2957 fileref->parent = (struct _file_ref*)parfileref;
2958 fcb->deleted = false;
2959
2960 InsertHeadList(&parfileref->fcb->dir_children_index, &dc->list_entry_index);
2961
2962 InsertTailList(&parfileref->children, &fileref->list_entry);
2963
2964 ExReleaseResourceLite(&parfileref->fcb->nonpaged->dir_children_lock);
2965
2966 mark_fileref_dirty(fileref);
2967
2968 parfileref->fcb->inode_item.transid = Vcb->superblock.generation;
2969 parfileref->fcb->inode_item.sequence++;
2970 parfileref->fcb->inode_item.st_ctime = now;
2971 parfileref->fcb->inode_item_changed = true;
2972
2973 mark_fcb_dirty(parfileref->fcb);
2974
2975 parfileref->fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
2976 parfileref->fcb->subvol->root_item.ctime = now;
2977
2978 increase_fileref_refcount(parfileref);
2979
2980 *pfileref = fileref;
2981
2983
2984 return STATUS_SUCCESS;
2985}
2986
2987// LXSS programs can be distinguished by the fact they have a NULL PEB.
2988#ifdef _AMD64_
2989static __inline bool called_from_lxss() {
2992 ULONG retlen;
2993
2995
2996 if (!NT_SUCCESS(Status)) {
2997 ERR("ZwQueryInformationProcess returned %08lx\n", Status);
2998 return false;
2999 }
3000
3001 return !pbi.PebBaseAddress;
3002}
3003#else
3004#define called_from_lxss() false
3005#endif
3006
3008 PFILE_OBJECT FileObject, file_ref* related, bool loaded_related, PUNICODE_STRING fnus, ULONG disposition, ULONG options,
3009 file_ref** existing_fileref, LIST_ENTRY* rollback) {
3011 file_ref *fileref, *parfileref = NULL;
3012 ULONG i, j;
3013 ccb* ccb;
3014 static const WCHAR datasuf[] = {':','$','D','A','T','A',0};
3015 UNICODE_STRING dsus, fpus, stream;
3018 ECP_LIST* ecp_list;
3020#ifdef DEBUG_FCB_REFCOUNTS
3021 LONG oc;
3022#endif
3023
3024 TRACE("(%p, %p, %p, %.*S, %lx, %lx)\n", Irp, Vcb, FileObject, (int)(fnus->Length / sizeof(WCHAR)), fnus->Buffer, disposition, options);
3025
3026 if (Vcb->readonly)
3028
3031 return STATUS_CANNOT_DELETE;
3032 }
3033
3035 if (NT_SUCCESS(fFsRtlGetEcpListFromIrp(Irp, &ecp_list)) && ecp_list) {
3036 void* ctx = NULL;
3037 GUID type;
3038 ULONG ctxsize;
3039
3040 do {
3041 Status = fFsRtlGetNextExtraCreateParameter(ecp_list, ctx, &type, &ctx, &ctxsize);
3042
3043 if (NT_SUCCESS(Status)) {
3044 if (RtlCompareMemory(&type, &GUID_ECP_ATOMIC_CREATE, sizeof(GUID)) == sizeof(GUID)) {
3045 if (ctxsize >= sizeof(ATOMIC_CREATE_ECP_CONTEXT))
3046 acec = ctx;
3047 else {
3048 ERR("GUID_ECP_ATOMIC_CREATE context was too short: %lu bytes, expected %Iu\n", ctxsize,
3050 }
3051 } else if (RtlCompareMemory(&type, &GUID_ECP_QUERY_ON_CREATE, sizeof(GUID)) == sizeof(GUID))
3052 WARN("unhandled ECP GUID_ECP_QUERY_ON_CREATE\n");
3053 else if (RtlCompareMemory(&type, &GUID_ECP_CREATE_REDIRECTION, sizeof(GUID)) == sizeof(GUID))
3054 WARN("unhandled ECP GUID_ECP_CREATE_REDIRECTION\n");
3055 else {
3056 WARN("unhandled ECP {%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\n", type.Data1, type.Data2,
3057 type.Data3, type.Data4[0], type.Data4[1], type.Data4[2], type.Data4[3], type.Data4[4], type.Data4[5],
3058 type.Data4[6], type.Data4[7]);
3059 }
3060 }
3061 } while (NT_SUCCESS(Status));
3062 }
3063 }
3064
3065 dsus.Buffer = (WCHAR*)datasuf;
3066 dsus.Length = dsus.MaximumLength = sizeof(datasuf) - sizeof(WCHAR);
3067 fpus.Buffer = NULL;
3068
3069 if (!loaded_related) {
3070 Status = open_fileref(Vcb, &parfileref, fnus, related, true, NULL, NULL, pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp);
3071
3072 if (!NT_SUCCESS(Status))
3073 goto end;
3074 } else
3075 parfileref = related;
3076
3077 if (parfileref->fcb->type != BTRFS_TYPE_DIRECTORY && (fnus->Length < sizeof(WCHAR) || fnus->Buffer[0] != ':')) {
3079 goto end;
3080 }
3081
3082 if (is_subvol_readonly(parfileref->fcb->subvol, Irp)) {
3084 goto end;
3085 }
3086
3087 i = (fnus->Length / sizeof(WCHAR))-1;
3088 while ((fnus->Buffer[i] == '\\' || fnus->Buffer[i] == '/') && i > 0) { i--; }
3089
3090 j = i;
3091
3092 while (i > 0 && fnus->Buffer[i-1] != '\\' && fnus->Buffer[i-1] != '/') { i--; }
3093
3094 fpus.MaximumLength = (USHORT)((j - i + 2) * sizeof(WCHAR));
3095 fpus.Buffer = ExAllocatePoolWithTag(pool_type, fpus.MaximumLength, ALLOC_TAG);
3096 if (!fpus.Buffer) {
3097 ERR("out of memory\n");
3099 goto end;
3100 }
3101
3102 fpus.Length = (USHORT)((j - i + 1) * sizeof(WCHAR));
3103
3104 RtlCopyMemory(fpus.Buffer, &fnus->Buffer[i], (j - i + 1) * sizeof(WCHAR));
3105 fpus.Buffer[j - i + 1] = 0;
3106
3107 if (fpus.Length > dsus.Length) { // check for :$DATA suffix
3108 UNICODE_STRING lb;
3109
3110 lb.Buffer = &fpus.Buffer[(fpus.Length - dsus.Length)/sizeof(WCHAR)];
3111 lb.Length = lb.MaximumLength = dsus.Length;
3112
3113 TRACE("lb = %.*S\n", (int)(lb.Length/sizeof(WCHAR)), lb.Buffer);
3114
3115 if (FsRtlAreNamesEqual(&dsus, &lb, true, NULL)) {
3116 TRACE("ignoring :$DATA suffix\n");
3117
3118 fpus.Length -= lb.Length;
3119
3120 if (fpus.Length > sizeof(WCHAR) && fpus.Buffer[(fpus.Length-1)/sizeof(WCHAR)] == ':')
3121 fpus.Length -= sizeof(WCHAR);
3122
3123 TRACE("fpus = %.*S\n", (int)(fpus.Length / sizeof(WCHAR)), fpus.Buffer);
3124 }
3125 }
3126
3127 stream.Length = 0;
3128
3129 for (i = 0; i < fpus.Length / sizeof(WCHAR); i++) {
3130 if (fpus.Buffer[i] == ':') {
3131 stream.Length = (USHORT)(fpus.Length - (i * sizeof(WCHAR)) - sizeof(WCHAR));
3132 stream.Buffer = &fpus.Buffer[i+1];
3133 fpus.Buffer[i] = 0;
3134 fpus.Length = (USHORT)(i * sizeof(WCHAR));
3135 break;
3136 }
3137 }
3138
3139 if (stream.Length > 0) {
3140 Status = create_stream(Vcb, &fileref, &parfileref, &fpus, &stream, Irp, options, pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, rollback);
3141 if (!NT_SUCCESS(Status)) {
3142 ERR("create_stream returned %08lx\n", Status);
3143 goto end;
3144 }
3145
3146 IoSetShareAccess(IrpSp->Parameters.Create.SecurityContext->DesiredAccess, IrpSp->Parameters.Create.ShareAccess,
3147 FileObject, &fileref->fcb->share_access);
3148 } else {
3149 ACCESS_MASK granted_access;
3150
3151 Status = check_file_name_valid(&fpus, false, false);
3152 if (!NT_SUCCESS(Status))
3153 goto end;
3154
3155 SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
3156
3157 if (!SeAccessCheck(parfileref->fcb->sd, &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
3160 &granted_access, &Status)) {
3161 SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
3162 goto end;
3163 }
3164
3165 SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
3166
3167 if (Irp->AssociatedIrp.SystemBuffer && IrpSp->Parameters.Create.EaLength > 0) {
3168 ULONG offset;
3169
3170 Status = IoCheckEaBufferValidity(Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.Create.EaLength, &offset);
3171 if (!NT_SUCCESS(Status)) {
3172 ERR("IoCheckEaBufferValidity returned %08lx (error at offset %lu)\n", Status, offset);
3173 goto end;
3174 }
3175 }
3176
3177 Status = file_create2(Irp, Vcb, &fpus, parfileref, options, Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.Create.EaLength,
3178 &fileref, IrpSp->Flags & SL_CASE_SENSITIVE, rollback);
3179
3181 *existing_fileref = fileref;
3182 goto end;
3183 } else if (!NT_SUCCESS(Status)) {
3184 ERR("file_create2 returned %08lx\n", Status);
3185 goto end;
3186 }
3187
3188 IoSetShareAccess(IrpSp->Parameters.Create.SecurityContext->DesiredAccess, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access);
3189
3192 }
3193
3194 FileObject->FsContext = fileref->fcb;
3195
3197 if (!ccb) {
3198 ERR("out of memory\n");
3200 fileref->deleted = true;
3201 fileref->fcb->deleted = true;
3202
3203 if (stream.Length == 0) {
3204 ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
3205 parfileref->fcb->inode_item.st_size -= fileref->dc->utf8.Length * 2;
3206 ExReleaseResourceLite(parfileref->fcb->Header.Resource);
3207 }
3208
3209 free_fileref(fileref);
3210 goto end;
3211 }
3212
3213 RtlZeroMemory(ccb, sizeof(*ccb));
3214
3215 ccb->fileref = fileref;
3216
3218 ccb->NodeSize = sizeof(*ccb);
3219 ccb->disposition = disposition;
3220 ccb->options = options;
3221 ccb->query_dir_offset = 0;
3223 ccb->has_wildcard = false;
3224 ccb->specific_file = false;
3225 ccb->access = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
3227 ccb->reserving = false;
3229
3230#ifdef DEBUG_FCB_REFCOUNTS
3231 oc = InterlockedIncrement(&fileref->open_count);
3232 ERR("fileref %p: open_count now %i\n", fileref, oc);
3233#else
3235#endif
3236 InterlockedIncrement(&Vcb->open_files);
3237
3238 FileObject->FsContext2 = ccb;
3239
3240 FileObject->SectionObjectPointer = &fileref->fcb->nonpaged->segment_object;
3241
3242 // FIXME - ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT
3244 if (acec->ReparseBufferLength > sizeof(uint32_t) && *(uint32_t*)acec->ReparseBuffer == IO_REPARSE_TAG_SYMLINK) {
3246 fileref->fcb->type = BTRFS_TYPE_FILE;
3247 fileref->fcb->atts &= ~FILE_ATTRIBUTE_DIRECTORY;
3248 }
3249
3250 if (fileref->fcb->type == BTRFS_TYPE_SOCKET || fileref->fcb->type == BTRFS_TYPE_FIFO ||
3251 fileref->fcb->type == BTRFS_TYPE_CHARDEV || fileref->fcb->type == BTRFS_TYPE_BLOCKDEV) {
3252 // NOP. If called from LXSS, humour it - we hardcode the values elsewhere.
3253 } else {
3255 if (!NT_SUCCESS(Status)) {
3256 ERR("set_reparse_point2 returned %08lx\n", Status);
3257 fileref->deleted = true;
3258 fileref->fcb->deleted = true;
3259
3260 if (stream.Length == 0) {
3261 ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, true);
3262 parfileref->fcb->inode_item.st_size -= fileref->dc->utf8.Length * 2;
3263 ExReleaseResourceLite(parfileref->fcb->Header.Resource);
3264 }
3265
3266 free_fileref(fileref);
3267 return Status;
3268 }
3269 }
3270
3272 }
3273
3278 fileref->fcb->case_sensitive = true;
3279 ccb->case_sensitive = true;
3280 }
3281
3283 }
3284
3286 }
3287
3288 fileref->dc->type = fileref->fcb->type;
3289
3290end:
3291 if (fpus.Buffer)
3292 ExFreePool(fpus.Buffer);
3293
3294 if (parfileref && !loaded_related)
3295 free_fileref(parfileref);
3296
3297 return Status;
3298}
3299
3300static __inline void debug_create_options(ULONG RequestedOptions) {
3301 if (RequestedOptions != 0) {
3302 ULONG options = RequestedOptions;
3303
3304 TRACE("requested options:\n");
3305
3307 TRACE(" FILE_DIRECTORY_FILE\n");
3308 options &= ~FILE_DIRECTORY_FILE;
3309 }
3310
3312 TRACE(" FILE_WRITE_THROUGH\n");
3313 options &= ~FILE_WRITE_THROUGH;
3314 }
3315
3317 TRACE(" FILE_SEQUENTIAL_ONLY\n");
3318 options &= ~FILE_SEQUENTIAL_ONLY;
3319 }
3320
3322 TRACE(" FILE_NO_INTERMEDIATE_BUFFERING\n");
3323 options &= ~FILE_NO_INTERMEDIATE_BUFFERING;
3324 }
3325
3327 TRACE(" FILE_SYNCHRONOUS_IO_ALERT\n");
3328 options &= ~FILE_SYNCHRONOUS_IO_ALERT;
3329 }
3330
3332 TRACE(" FILE_SYNCHRONOUS_IO_NONALERT\n");
3333 options &= ~FILE_SYNCHRONOUS_IO_NONALERT;
3334 }
3335
3337 TRACE(" FILE_NON_DIRECTORY_FILE\n");
3338 options &= ~FILE_NON_DIRECTORY_FILE;
3339 }
3340
3342 TRACE(" FILE_CREATE_TREE_CONNECTION\n");
3343 options &= ~FILE_CREATE_TREE_CONNECTION;
3344 }
3345
3347 TRACE(" FILE_COMPLETE_IF_OPLOCKED\n");
3348 options &= ~FILE_COMPLETE_IF_OPLOCKED;
3349 }
3350
3352 TRACE(" FILE_NO_EA_KNOWLEDGE\n");
3353 options &= ~FILE_NO_EA_KNOWLEDGE;
3354 }
3355
3357 TRACE(" FILE_OPEN_REMOTE_INSTANCE\n");
3358 options &= ~FILE_OPEN_REMOTE_INSTANCE;
3359 }
3360
3362 TRACE(" FILE_RANDOM_ACCESS\n");
3363 options &= ~FILE_RANDOM_ACCESS;
3364 }
3365
3367 TRACE(" FILE_DELETE_ON_CLOSE\n");
3368 options &= ~FILE_DELETE_ON_CLOSE;
3369 }
3370
3372 TRACE(" FILE_OPEN_BY_FILE_ID\n");
3373 options &= ~FILE_OPEN_BY_FILE_ID;
3374 }
3375
3377 TRACE(" FILE_OPEN_FOR_BACKUP_INTENT\n");
3378 options &= ~FILE_OPEN_FOR_BACKUP_INTENT;
3379 }
3380
3382 TRACE(" FILE_NO_COMPRESSION\n");
3383 options &= ~FILE_NO_COMPRESSION;
3384 }
3385
3386#if NTDDI_VERSION >= NTDDI_WIN7
3388 TRACE(" FILE_OPEN_REQUIRING_OPLOCK\n");
3389 options &= ~FILE_OPEN_REQUIRING_OPLOCK;
3390 }
3391
3393 TRACE(" FILE_DISALLOW_EXCLUSIVE\n");
3394 options &= ~FILE_DISALLOW_EXCLUSIVE;
3395 }
3396#endif
3397
3399 TRACE(" FILE_RESERVE_OPFILTER\n");
3400 options &= ~FILE_RESERVE_OPFILTER;
3401 }
3402
3404 TRACE(" FILE_OPEN_REPARSE_POINT\n");
3405 options &= ~FILE_OPEN_REPARSE_POINT;
3406 }
3407
3409 TRACE(" FILE_OPEN_NO_RECALL\n");
3410 options &= ~FILE_OPEN_NO_RECALL;
3411 }
3412
3414 TRACE(" FILE_OPEN_FOR_FREE_SPACE_QUERY\n");
3415 options &= ~FILE_OPEN_FOR_FREE_SPACE_QUERY;
3416 }
3417
3418 if (options)
3419 TRACE(" unknown options: %lx\n", options);
3420 } else {
3421 TRACE("requested options: (none)\n");
3422 }
3423}
3424
3427
3429 ULONG size, bytes_read, i;
3430
3431 if (fcb->type == BTRFS_TYPE_FILE && fcb->inode_item.st_size < sizeof(ULONG)) {
3432 WARN("file was too short to be a reparse point\n");
3434 }
3435
3436 // 0x10007 = 0xffff (maximum length of data buffer) + 8 bytes header
3437 size = (ULONG)min(0x10007, fcb->inode_item.st_size);
3438
3439 if (size == 0)
3441
3443 if (!*data) {
3444 ERR("out of memory\n");
3446 }
3447
3448 Status = read_file(fcb, *data, 0, size, &bytes_read, NULL);
3449 if (!NT_SUCCESS(Status)) {
3450 ERR("read_file_fcb returned %08lx\n", Status);
3451 ExFreePool(*data);
3452 return Status;
3453 }
3454
3455 if (fcb->type == BTRFS_TYPE_SYMLINK) {
3456 ULONG stringlen, reqlen;
3457 uint16_t subnamelen, printnamelen;
3459
3460 Status = utf8_to_utf16(NULL, 0, &stringlen, (char*)*data, bytes_read);
3461 if (!NT_SUCCESS(Status)) {
3462 ERR("utf8_to_utf16 1 returned %08lx\n", Status);
3463 ExFreePool(*data);
3464 return Status;
3465 }
3466
3467 subnamelen = printnamelen = (USHORT)stringlen;
3468
3469 reqlen = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + subnamelen + printnamelen;
3470
3472
3473 if (!rdb) {
3474 ERR("out of memory\n");
3475 ExFreePool(*data);
3477 }
3478
3480 rdb->ReparseDataLength = (USHORT)(reqlen - offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer));
3481 rdb->Reserved = 0;
3482
3483 rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
3484 rdb->SymbolicLinkReparseBuffer.SubstituteNameLength = subnamelen;
3485 rdb->SymbolicLinkReparseBuffer.PrintNameOffset = subnamelen;
3486 rdb->SymbolicLinkReparseBuffer.PrintNameLength = printnamelen;
3488
3489 Status = utf8_to_utf16(&rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)],
3490 stringlen, &stringlen, (char*)*data, size);
3491
3492 if (!NT_SUCCESS(Status)) {
3493 ERR("utf8_to_utf16 2 returned %08lx\n", Status);
3494 ExFreePool(rdb);
3495 ExFreePool(*data);
3496 return Status;
3497 }
3498
3499 for (i = 0; i < stringlen / sizeof(WCHAR); i++) {
3500 if (rdb->SymbolicLinkReparseBuffer.PathBuffer[(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)) + i] == '/')
3501 rdb->SymbolicLinkReparseBuffer.PathBuffer[(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)) + i] = '\\';
3502 }
3503
3504 RtlCopyMemory(&rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)],
3505 &rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)],
3506 rdb->SymbolicLinkReparseBuffer.SubstituteNameLength);
3507
3508 ExFreePool(*data);
3509
3510 *data = (uint8_t*)rdb;
3511 } else {
3513 if (!NT_SUCCESS(Status)) {
3514 ERR("FsRtlValidateReparsePointBuffer returned %08lx\n", Status);
3515 ExFreePool(*data);
3516 return Status;
3517 }
3518 }
3519 } else if (fcb->type == BTRFS_TYPE_DIRECTORY) {
3521 return STATUS_INTERNAL_ERROR;
3522
3523 if (fcb->reparse_xattr.Length < sizeof(ULONG)) {
3524 WARN("xattr was too short to be a reparse point\n");
3525 return STATUS_INTERNAL_ERROR;
3526 }
3527
3529 if (!NT_SUCCESS(Status)) {
3530 ERR("FsRtlValidateReparsePointBuffer returned %08lx\n", Status);
3531 return Status;
3532 }
3533
3535 if (!*data) {
3536 ERR("out of memory\n");
3538 }
3539
3541 } else
3543
3544 return STATUS_SUCCESS;
3545}
3546
3548 LIST_ENTRY* le;
3550
3551 if (fcb->csum_loaded)
3552 return;
3553
3555 goto end;
3556
3557 le = fcb->extents.Flink;
3558 while (le != &fcb->extents) {
3560
3561 if (!ext->ignore && ext->extent_data.type == EXTENT_TYPE_REGULAR) {
3562 EXTENT_DATA2* ed2 = (EXTENT_DATA2*)&ext->extent_data.data[0];
3563 uint64_t len;
3564
3565 len = (ext->extent_data.compression == BTRFS_COMPRESSION_NONE ? ed2->num_bytes : ed2->size) >> Vcb->sector_shift;
3566
3567 ext->csum = ExAllocatePoolWithTag(NonPagedPool, (ULONG)(len * Vcb->csum_size), ALLOC_TAG);
3568 if (!ext->csum) {
3569 ERR("out of memory\n");
3570 goto end;
3571 }
3572
3573 Status = load_csum(Vcb, ext->csum, ed2->address + (ext->extent_data.compression == BTRFS_COMPRESSION_NONE ? ed2->offset : 0), len, Irp);
3574
3575 if (!NT_SUCCESS(Status)) {
3576 ERR("load_csum returned %08lx\n", Status);
3577 goto end;
3578 }
3579 }
3580
3581 le = le->Flink;
3582 }
3583
3584end:
3585 fcb->csum_loaded = true;
3586}
3587
3592 ULONG RequestedDisposition = ((IrpSp->Parameters.Create.Options >> 24) & 0xff);
3595 ccb* ccb;
3596
3597 if (granted_access & FILE_WRITE_DATA || options & FILE_DELETE_ON_CLOSE) {
3598 if (!MmFlushImageSection(&fileref->fcb->nonpaged->segment_object, MmFlushForWrite))
3600 }
3601
3602 if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF || RequestedDisposition == FILE_SUPERSEDE) {
3603 ULONG defda, oldatts, filter;
3606
3607 if (!fileref->fcb->ads && (IrpSp->Parameters.Create.FileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != ((fileref->fcb->atts & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN))))
3608 return STATUS_ACCESS_DENIED;
3609
3610 if (fileref->fcb->ads) {
3611 Status = stream_set_end_of_file_information(Vcb, 0, fileref->fcb, fileref, false);
3612 if (!NT_SUCCESS(Status)) {
3613 ERR("stream_set_end_of_file_information returned %08lx\n", Status);
3614 return Status;
3615 }
3616 } else {
3617 Status = truncate_file(fileref->fcb, 0, Irp, rollback);
3618 if (!NT_SUCCESS(Status)) {
3619 ERR("truncate_file returned %08lx\n", Status);
3620 return Status;
3621 }
3622 }
3623
3624 if (Irp->Overlay.AllocationSize.QuadPart > 0) {
3625 Status = extend_file(fileref->fcb, fileref, Irp->Overlay.AllocationSize.QuadPart, true, NULL, rollback);
3626
3627 if (!NT_SUCCESS(Status)) {
3628 ERR("extend_file returned %08lx\n", Status);
3629 return Status;
3630 }
3631 }
3632
3633 if (!fileref->fcb->ads) {
3634 LIST_ENTRY* le;
3635
3636 if (Irp->AssociatedIrp.SystemBuffer && IrpSp->Parameters.Create.EaLength > 0) {
3637 ULONG offset;
3639
3640 Status = IoCheckEaBufferValidity(Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.Create.EaLength, &offset);
3641 if (!NT_SUCCESS(Status)) {
3642 ERR("IoCheckEaBufferValidity returned %08lx (error at offset %lu)\n", Status, offset);
3643 return Status;
3644 }
3645
3646 fileref->fcb->ealen = 4;
3647
3648 // capitalize EA name
3649 eainfo = Irp->AssociatedIrp.SystemBuffer;
3650 do {
3651 STRING s;
3652
3653 s.Length = s.MaximumLength = eainfo->EaNameLength;
3654 s.Buffer = eainfo->EaName;
3655
3656 RtlUpperString(&s, &s);
3657
3658 fileref->fcb->ealen += 5 + eainfo->EaNameLength + eainfo->EaValueLength;
3659
3660 if (eainfo->NextEntryOffset == 0)
3661 break;
3662
3663 eainfo = (FILE_FULL_EA_INFORMATION*)(((uint8_t*)eainfo) + eainfo->NextEntryOffset);
3664 } while (true);
3665
3666 if (fileref->fcb->ea_xattr.Buffer)
3667 ExFreePool(fileref->fcb->ea_xattr.Buffer);
3668
3669 fileref->fcb->ea_xattr.Buffer = ExAllocatePoolWithTag(pool_type, IrpSp->Parameters.Create.EaLength, ALLOC_TAG);
3670 if (!fileref->fcb->ea_xattr.Buffer) {
3671 ERR("out of memory\n");
3673 }
3674
3675 fileref->fcb->ea_xattr.Length = fileref->fcb->ea_xattr.MaximumLength = (USHORT)IrpSp->Parameters.Create.EaLength;
3676 RtlCopyMemory(fileref->fcb->ea_xattr.Buffer, Irp->AssociatedIrp.SystemBuffer, fileref->fcb->ea_xattr.Length);
3677 } else {
3678 if (fileref->fcb->ea_xattr.Length > 0) {
3679 ExFreePool(fileref->fcb->ea_xattr.Buffer);
3680 fileref->fcb->ea_xattr.Buffer = NULL;
3681 fileref->fcb->ea_xattr.Length = fileref->fcb->ea_xattr.MaximumLength = 0;
3682
3683 fileref->fcb->ea_changed = true;
3684 fileref->fcb->ealen = 0;
3685 }
3686 }
3687
3688 // remove streams and send notifications
3689 le = fileref->fcb->dir_children_index.Flink;
3690 while (le != &fileref->fcb->dir_children_index) {
3691 dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index);
3692 LIST_ENTRY* le2 = le->Flink;
3693
3694 if (dc->index == 0) {
3695 if (!dc->fileref) {
3696 file_ref* fr2;
3697
3698 Status = open_fileref_child(Vcb, fileref, &dc->name, true, true, true, PagedPool, &fr2, NULL);
3699 if (!NT_SUCCESS(Status))
3700 WARN("open_fileref_child returned %08lx\n", Status);
3701 }
3702
3703 if (dc->fileref) {
3705
3706 Status = delete_fileref(dc->fileref, NULL, false, NULL, rollback);
3707 if (!NT_SUCCESS(Status)) {
3708 ERR("delete_fileref returned %08lx\n", Status);
3709 return Status;
3710 }
3711 }
3712 } else
3713 break;
3714
3715 le = le2;
3716 }
3717 }
3718
3721
3723
3724 if (fileref->fcb->ads) {
3725 fileref->parent->fcb->inode_item.st_mtime = now;
3726 fileref->parent->fcb->inode_item_changed = true;
3727 mark_fcb_dirty(fileref->parent->fcb);
3728
3730 } else {
3731 mark_fcb_dirty(fileref->fcb);
3732
3733 oldatts = fileref->fcb->atts;
3734
3735 defda = get_file_attributes(Vcb, fileref->fcb->subvol, fileref->fcb->inode, fileref->fcb->type,
3736 fileref->dc && fileref->dc->name.Length >= sizeof(WCHAR) && fileref->dc->name.Buffer[0] == '.', true, Irp);
3737
3738 if (RequestedDisposition == FILE_SUPERSEDE)
3739 fileref->fcb->atts = IrpSp->Parameters.Create.FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
3740 else
3741 fileref->fcb->atts |= IrpSp->Parameters.Create.FileAttributes | FILE_ATTRIBUTE_ARCHIVE;
3742
3743 if (fileref->fcb->atts != oldatts) {
3744 fileref->fcb->atts_changed = true;
3745 fileref->fcb->atts_deleted = IrpSp->Parameters.Create.FileAttributes == defda;
3747 }
3748
3749 fileref->fcb->inode_item.transid = Vcb->superblock.generation;
3750 fileref->fcb->inode_item.sequence++;
3751 fileref->fcb->inode_item.st_ctime = now;
3752 fileref->fcb->inode_item.st_mtime = now;
3753 fileref->fcb->inode_item_changed = true;
3754
3756 }
3757 } else {
3758 if (options & FILE_NO_EA_KNOWLEDGE && fileref->fcb->ea_xattr.Length > 0) {
3760
3761 do {
3762 if (ffei->Flags & FILE_NEED_EA) {
3763 WARN("returning STATUS_ACCESS_DENIED as no EA knowledge\n");
3764
3765 return STATUS_ACCESS_DENIED;
3766 }
3767
3768 if (ffei->NextEntryOffset == 0)
3769 break;
3770
3771 ffei = (FILE_FULL_EA_INFORMATION*)(((uint8_t*)ffei) + ffei->NextEntryOffset);
3772 } while (true);
3773 }
3774 }
3775
3776 FileObject->FsContext = fileref->fcb;
3777
3779 if (!ccb) {
3780 ERR("out of memory\n");
3781
3783 }
3784
3785 RtlZeroMemory(ccb, sizeof(*ccb));
3786
3788 ccb->NodeSize = sizeof(*ccb);
3789 ccb->disposition = RequestedDisposition;
3790 ccb->options = options;
3791 ccb->query_dir_offset = 0;
3793 ccb->has_wildcard = false;
3794 ccb->specific_file = false;
3795 ccb->access = granted_access;
3797 ccb->reserving = false;
3799
3800 ccb->fileref = fileref;
3801
3802 FileObject->FsContext2 = ccb;
3803 FileObject->SectionObjectPointer = &fileref->fcb->nonpaged->segment_object;
3804
3805 switch (RequestedDisposition) {
3806 case FILE_SUPERSEDE:
3807 Irp->IoStatus.Information = FILE_SUPERSEDED;
3808 break;
3809
3810 case FILE_OPEN:
3811 case FILE_OPEN_IF:
3812 Irp->IoStatus.Information = FILE_OPENED;
3813 break;
3814
3815 case FILE_OVERWRITE:
3816 case FILE_OVERWRITE_IF:
3817 Irp->IoStatus.Information = FILE_OVERWRITTEN;
3818 break;
3819 }
3820
3821 // Make sure paging files don't have any extents marked as being prealloc,
3822 // as this would mean we'd have to lock exclusively when writing.
3824 LIST_ENTRY* le;
3825 bool changed = false;
3826
3827 ExAcquireResourceExclusiveLite(fileref->fcb->Header.Resource, true);
3828
3829 le = fileref->fcb->extents.Flink;
3830
3831 while (le != &fileref->fcb->extents) {
3833
3834 if (ext->extent_data.type == EXTENT_TYPE_PREALLOC) {
3835 ext->extent_data.type = EXTENT_TYPE_REGULAR;
3836 changed = true;
3837 }
3838
3839 le = le->Flink;
3840 }
3841
3842 ExReleaseResourceLite(fileref->fcb->Header.Resource);
3843
3844 if (changed) {
3845 fileref->fcb->extents_changed = true;
3846 mark_fcb_dirty(fileref->fcb);
3847 }
3848
3849 fileref->fcb->Header.Flags2 |= FSRTL_FLAG2_IS_PAGING_FILE;
3850 }
3851
3852#ifdef DEBUG_FCB_REFCOUNTS
3853 LONG oc = InterlockedIncrement(&fileref->open_count);
3854 ERR("fileref %p: open_count now %i\n", fileref, oc);
3855#else
3856 InterlockedIncrement(&fileref->open_count);
3857#endif
3858 InterlockedIncrement(&Vcb->open_files);
3859
3860 return STATUS_SUCCESS;
3861}
3862
3866 bool skip_lock;
3868 device_extension* Vcb = ctx->Vcb;
3869
3870 TRACE("(%p, %p)\n", Context, Irp);
3871
3873
3874 skip_lock = ExIsResourceAcquiredExclusiveLite(&Vcb->tree_lock);
3875
3876 if (!skip_lock)
3877 ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
3878
3879 ExAcquireResourceSharedLite(&Vcb->fileref_lock, true);
3880
3881 // FIXME - trans
3882 Status = open_file3(Vcb, Irp, ctx->granted_access, ctx->fileref, &rollback);
3883
3884 if (!NT_SUCCESS(Status)) {
3885 free_fileref(ctx->fileref);
3886 do_rollback(ctx->Vcb, &rollback);
3887 } else
3889
3890 ExReleaseResourceLite(&Vcb->fileref_lock);
3891
3892 if (Status == STATUS_SUCCESS) {
3893 fcb* fcb2;
3896 bool skip_fcb_lock;
3897
3898 IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess |= ctx->granted_access;
3899 IrpSp->Parameters.Create.SecurityContext->AccessState->RemainingDesiredAccess &= ~(ctx->granted_access | MAXIMUM_ALLOWED);
3900
3901 if (!FileObject->Vpb)
3902 FileObject->Vpb = Vcb->devobj->Vpb;
3903
3904 fcb2 = FileObject->FsContext;
3905
3906 if (fcb2->ads) {
3907 struct _ccb* ccb2 = FileObject->FsContext2;
3908
3909 fcb2 = ccb2->fileref->parent->fcb;
3910 }
3911
3912 skip_fcb_lock = ExIsResourceAcquiredExclusiveLite(fcb2->Header.Resource);
3913
3914 if (!skip_fcb_lock)
3915 ExAcquireResourceExclusiveLite(fcb2->Header.Resource, true);
3916
3917 fcb_load_csums(Vcb, fcb2, Irp);
3918
3919 if (!skip_fcb_lock)
3920 ExReleaseResourceLite(fcb2->Header.Resource);
3921 }
3922
3923 if (!skip_lock)
3924 ExReleaseResourceLite(&Vcb->tree_lock);
3925
3926 // FIXME - call free_trans if failed and within transaction
3927
3928 Irp->IoStatus.Status = Status;
3930
3931 ctx->Status = Status;
3932
3933 KeSetEvent(&ctx->event, 0, false);
3934}
3935
3936static NTSTATUS open_file2(device_extension* Vcb, ULONG RequestedDisposition, file_ref* fileref, ACCESS_MASK* granted_access,
3938 oplock_context** opctx) {
3940 file_ref* sf;
3941 bool readonly;
3943
3944 if (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF) {
3946
3949 goto end;
3950 }
3951
3952 if (Vcb->readonly) {
3954 goto end;
3955 }
3956
3957 zero.QuadPart = 0;
3958 if (!MmCanFileBeTruncated(&fileref->fcb->nonpaged->segment_object, &zero)) {
3960 goto end;
3961 }
3962 }
3963
3964 if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess != 0) {
3965 SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
3966
3967 if (!SeAccessCheck((fileref->fcb->ads || fileref->fcb == Vcb->dummy_fcb) ? fileref->parent->fcb->sd : fileref->fcb->sd,
3968 &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
3969 true, IrpSp->Parameters.Create.SecurityContext->DesiredAccess, 0, NULL,
3971 granted_access, &Status)) {
3972 SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
3973 TRACE("SeAccessCheck failed, returning %08lx\n", Status);
3974 goto end;
3975 }
3976
3977 SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
3978 } else
3979 *granted_access = 0;
3980
3981 TRACE("deleted = %s\n", fileref->deleted ? "true" : "false");
3982
3983 sf = fileref;
3984 while (sf) {
3985 if (sf->delete_on_close) {
3986 TRACE("could not open as deletion pending\n");
3988 goto end;
3989 }
3990 sf = sf->parent;
3991 }
3992
3995 is_subvol_readonly(fileref->fcb->subvol, Irp) || fileref->fcb == Vcb->dummy_fcb || Vcb->readonly;
3996
3997 if (options & FILE_DELETE_ON_CLOSE && (fileref == Vcb->root_fileref || readonly)) {
3999 goto end;
4000 }
4001
4003
4004 if (readonly) {
4005 ACCESS_MASK allowed;
4006
4010
4011 if (!Vcb->readonly && (fileref->fcb == Vcb->dummy_fcb || fileref->fcb->inode == SUBVOL_ROOT_INODE))
4012 allowed |= DELETE;
4013
4014 if (fileref->fcb != Vcb->dummy_fcb && !is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) {
4016
4019 } else if (fileref->fcb->inode == SUBVOL_ROOT_INODE && is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) {
4020 // We allow a subvolume root to be opened read-write even if its readonly flag is set, so it can be cleared
4021
4022 allowed |= FILE_WRITE_ATTRIBUTES;
4023 }
4024
4025 if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess & MAXIMUM_ALLOWED) {
4026 *granted_access &= allowed;
4027 IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess &= allowed;
4028 } else if (*granted_access & ~allowed) {
4030 goto end;
4031 }
4032
4033 if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF) {
4034 WARN("cannot overwrite readonly file\n");
4036 goto end;
4037 }
4038 }
4039
4042
4043 /* How reparse points work from the point of view of the filesystem appears to
4044 * undocumented. When returning STATUS_REPARSE, MSDN encourages us to return
4045 * IO_REPARSE in Irp->IoStatus.Information, but that means we have to do our own
4046 * translation. If we instead return the reparse tag in Information, and store
4047 * a pointer to the reparse data buffer in Irp->Tail.Overlay.AuxiliaryBuffer,
4048 * IopSymlinkProcessReparse will do the translation for us. */
4049
4051 if (!NT_SUCCESS(Status)) {
4052 ERR("get_reparse_block returned %08lx\n", Status);
4054 } else {
4055 Irp->IoStatus.Information = data->ReparseTag;
4056
4057 if (fn->Buffer[(fn->Length / sizeof(WCHAR)) - 1] == '\\')
4058 data->Reserved = sizeof(WCHAR);
4059
4060 Irp->Tail.Overlay.AuxiliaryBuffer = (void*)data;
4061
4063 goto end;
4064 }
4065 }
4066
4070 goto end;
4071 }
4072 } else if (options & FILE_DIRECTORY_FILE) {
4073 TRACE("returning STATUS_NOT_A_DIRECTORY (type = %u)\n", fileref->fcb->type);
4075 goto end;
4076 }
4077
4078 if (fileref->open_count > 0) {
4080
4081 Status = IoCheckShareAccess(*granted_access, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access, false);
4082
4083 if (!NT_SUCCESS(Status)) {
4085 TRACE("IoCheckShareAccess failed, returning %08lx\n", Status);
4086 else
4087 WARN("IoCheckShareAccess failed, returning %08lx\n", Status);
4088
4089 goto end;
4090 }
4091
4093 if (!ctx) {
4094 ERR("out of memory\n");
4096 goto end;
4097 }
4098
4099 ctx->Vcb = Vcb;
4100 ctx->granted_access = *granted_access;
4101 ctx->fileref = fileref;
4102 KeInitializeEvent(&ctx->event, NotificationEvent, false);
4103#ifdef __REACTOS__
4105#else
4107#endif /* __REACTOS__ */
4108 if (Status == STATUS_PENDING) {
4109 *opctx = ctx;
4110 return Status;
4111 }
4112
4113 ExFreePool(ctx);
4114
4115 if (!NT_SUCCESS(Status)) {
4116 WARN("FsRtlCheckOplock returned %08lx\n", Status);
4117 goto end;
4118 }
4119
4121 } else
4122 IoSetShareAccess(*granted_access, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access);
4123
4124 Status = open_file3(Vcb, Irp, *granted_access, fileref, rollback);
4125
4126 if (!NT_SUCCESS(Status))
4128
4129end:
4130 if (!NT_SUCCESS(Status))
4132
4133 return Status;
4134}
4135
4137 root* subvol, uint64_t inode, file_ref** pfr, PIRP Irp) {
4139 fcb* fcb;
4140 uint64_t parent = 0;
4142 bool hl_alloc = false;
4143 file_ref *parfr, *fr;
4144
4145 Status = open_fcb(Vcb, subvol, inode, 0, NULL, true, NULL, &fcb, PagedPool, Irp);
4146 if (!NT_SUCCESS(Status)) {
4147 ERR("open_fcb returned %08lx\n", Status);
4148 return Status;
4149 }
4150
4151 ExAcquireResourceSharedLite(fcb->Header.Resource, true);
4152
4153 if (fcb->inode_item.st_nlink == 0 || fcb->deleted) {
4154 ExReleaseResourceLite(fcb->Header.Resource);
4155 free_fcb(fcb);
4157 }
4158
4159 if (fcb->fileref) {
4160 *pfr = fcb->fileref;
4162 free_fcb(fcb);
4163 ExReleaseResourceLite(fcb->Header.Resource);
4164 return STATUS_SUCCESS;
4165 }
4166
4167 if (IsListEmpty(&fcb->hardlinks)) {
4168 ExReleaseResourceLite(fcb->Header.Resource);
4169
4170 ExAcquireResourceSharedLite(&Vcb->dirty_filerefs_lock, true);
4171
4172 if (!IsListEmpty(&Vcb->dirty_filerefs)) {
4173 LIST_ENTRY* le = Vcb->dirty_filerefs.Flink;
4174 while (le != &Vcb->dirty_filerefs) {
4175 fr = CONTAINING_RECORD(le, file_ref, list_entry_dirty);
4176
4177 if (fr->fcb == fcb) {
4178 ExReleaseResourceLite(&Vcb->dirty_filerefs_lock);
4180 free_fcb(fcb);
4181 *pfr = fr;
4182 return STATUS_SUCCESS;
4183 }
4184
4185 le = le->Flink;
4186 }
4187 }
4188
4189 ExReleaseResourceLite(&Vcb->dirty_filerefs_lock);
4190
4191 {
4192 KEY searchkey;
4194
4195 searchkey.obj_id = fcb->inode;
4196 searchkey.obj_type = TYPE_INODE_REF;
4197 searchkey.offset = 0;
4198
4199 Status = find_item(Vcb, subvol, &tp, &searchkey, false, Irp);
4200 if (!NT_SUCCESS(Status)) {
4201 ERR("find_item returned %08lx\n", Status);
4202 free_fcb(fcb);
4203 return Status;
4204 }
4205
4206 do {
4207 traverse_ptr next_tp;
4208
4210 break;
4211
4212 if (tp.item->key.obj_id == fcb->inode) {
4213 if (tp.item->key.obj_type == TYPE_INODE_REF) {
4214 INODE_REF* ir = (INODE_REF*)tp.item->data;
4215
4216 if (tp.item->size < offsetof(INODE_REF, name[0]) || tp.item->size < offsetof(INODE_REF, name[0]) + ir->n) {
4217 ERR("INODE_REF was too short\n");
4218 free_fcb(fcb);
4219 return STATUS_INTERNAL_ERROR;
4220 }
4221
4223
4224 Status = utf8_to_utf16(NULL, 0, &stringlen, ir->name, ir->n);
4225 if (!NT_SUCCESS(Status)) {
4226 ERR("utf8_to_utf16 1 returned %08lx\n", Status);
4227 free_fcb(fcb);
4228 return Status;
4229 }
4230
4231 name.Length = name.MaximumLength = (uint16_t)stringlen;
4232
4233 if (stringlen == 0)
4234 name.Buffer = NULL;
4235 else {
4236 name.Buffer = ExAllocatePoolWithTag(PagedPool, name.MaximumLength, ALLOC_TAG);
4237
4238 if (!name.Buffer) {
4239 ERR("out of memory\n");
4240 free_fcb(fcb);
4242 }
4243
4244 Status = utf8_to_utf16(name.Buffer, stringlen, &stringlen, ir->name, ir->n);
4245 if (!NT_SUCCESS(Status)) {
4246 ERR("utf8_to_utf16 2 returned %08lx\n", Status);
4247 ExFreePool(name.Buffer);
4248 free_fcb(fcb);
4249 return Status;
4250 }
4251
4252 hl_alloc = true;
4253 }
4254
4255 parent = tp.item->key.offset;
4256
4257 break;
4258 } else if (tp.item->key.obj_type == TYPE_INODE_EXTREF) {
4260
4261 if (tp.item->size < offsetof(INODE_EXTREF, name[0]) || tp.item->size < offsetof(INODE_EXTREF, name[0]) + ier->n) {
4262 ERR("INODE_EXTREF was too short\n");
4263 free_fcb(fcb);
4264 return STATUS_INTERNAL_ERROR;
4265 }
4266
4268
4269 Status = utf8_to_utf16(NULL, 0, &stringlen, ier->name, ier->n);
4270 if (!NT_SUCCESS(Status)) {
4271 ERR("utf8_to_utf16 1 returned %08lx\n", Status);
4272 free_fcb(fcb);
4273 return Status;
4274 }
4275
4276 name.Length = name.MaximumLength = (uint16_t)stringlen;
4277
4278 if (stringlen == 0)
4279 name.Buffer = NULL;
4280 else {
4281 name.Buffer = ExAllocatePoolWithTag(PagedPool, name.MaximumLength, ALLOC_TAG);
4282
4283 if (!name.Buffer) {
4284 ERR("out of memory\n");
4285 free_fcb(fcb);
4287 }
4288
4289 Status = utf8_to_utf16(name.Buffer, stringlen, &stringlen, ier->name, ier->n);
4290 if (!NT_SUCCESS(Status)) {
4291 ERR("utf8_to_utf16 2 returned %08lx\n", Status);
4292 ExFreePool(name.Buffer);
4293 free_fcb(fcb);
4294 return Status;
4295 }
4296
4297 hl_alloc = true;
4298 }
4299
4300 parent = ier->dir;
4301
4302 break;
4303 }
4304 }
4305
4306 if (find_next_item(Vcb, &tp, &next_tp, false, Irp))
4307 tp = next_tp;
4308 else
4309 break;
4310 } while (true);
4311 }
4312
4313 if (parent == 0) {
4314 WARN("trying to open inode with no references\n");
4315 free_fcb(fcb);
4317 }
4318 } else {
4320
4321 name = hl->name;
4322 parent = hl->parent;
4323
4324 ExReleaseResourceLite(fcb->Header.Resource);
4325 }
4326
4327 if (parent == inode) { // subvolume root
4328 KEY searchkey;
4330
4331 searchkey.obj_id = subvol->id;
4332 searchkey.obj_type = TYPE_ROOT_BACKREF;
4333 searchkey.offset = 0xffffffffffffffff;
4334
4335 Status = find_item(Vcb, Vcb->root_root, &tp, &searchkey, false, Irp);
4336 if (!NT_SUCCESS(Status)) {
4337 ERR("find_item returned %08lx\n", Status);
4338 free_fcb(fcb);
4339 return Status;
4340 }
4341
4342 if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
4343 ROOT_REF* rr = (ROOT_REF*)tp.item->data;
4344 LIST_ENTRY* le;
4345 root* r = NULL;
4347
4348 if (tp.item->size < sizeof(ROOT_REF)) {
4349 ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(ROOT_REF));
4350 free_fcb(fcb);
4351 return STATUS_INTERNAL_ERROR;
4352 }
4353
4354 if (tp.item->size < offsetof(ROOT_REF, name[0]) + rr->n) {
4355 ERR("(%I64x,%x,%I64x) was %u bytes, expected %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, offsetof(ROOT_REF, name[0]) + rr->n);
4356 free_fcb(fcb);
4357 return STATUS_INTERNAL_ERROR;
4358 }
4359
4360 le = Vcb->roots.Flink;
4361 while (le != &Vcb->roots) {
4363
4364 if (r2->id == tp.item->key.offset) {
4365 r = r2;
4366 break;
4367 }
4368
4369 le = le->Flink;
4370 }
4371
4372 if (!r) {
4373 ERR("couldn't find subvol %I64x\n", tp.item->key.offset);
4374 free_fcb(fcb);
4375 return STATUS_INTERNAL_ERROR;
4376 }
4377
4378 Status = open_fileref_by_inode(Vcb, r, rr->dir, &parfr, Irp);
4379 if (!NT_SUCCESS(Status)) {
4380 ERR("open_fileref_by_inode returned %08lx\n", Status);
4381 free_fcb(fcb);
4382 return Status;
4383 }
4384
4385 Status = utf8_to_utf16(NULL, 0, &stringlen, rr->name, rr->n);
4386 if (!NT_SUCCESS(Status)) {
4387 ERR("utf8_to_utf16 1 returned %08lx\n", Status);
4388 free_fcb(fcb);
4389 return Status;
4390 }
4391
4392 name.Length = name.MaximumLength = (uint16_t)stringlen;
4393
4394 if (stringlen == 0)
4395 name.Buffer = NULL;
4396 else {
4397 if (hl_alloc)
4398 ExFreePool(name.Buffer);
4399
4400 name.Buffer = ExAllocatePoolWithTag(PagedPool, name.MaximumLength, ALLOC_TAG);
4401
4402 if (!name.Buffer) {
4403 ERR("out of memory\n");
4404 free_fcb(fcb);
4406 }
4407
4408 Status = utf8_to_utf16(name.Buffer, stringlen, &stringlen, rr->name, rr->n);
4409 if (!NT_SUCCESS(Status)) {
4410 ERR("utf8_to_utf16 2 returned %08lx\n", Status);
4411 ExFreePool(name.Buffer);
4412 free_fcb(fcb);
4413 return Status;
4414 }
4415
4416 hl_alloc = true;
4417 }
4418 } else {
4419 if (!Vcb->options.no_root_dir && subvol->id == BTRFS_ROOT_FSTREE && Vcb->root_fileref->fcb->subvol != subvol) {
4420 Status = open_fileref_by_inode(Vcb, Vcb->root_fileref->fcb->subvol, SUBVOL_ROOT_INODE, &parfr, Irp);
4421 if (!NT_SUCCESS(Status)) {
4422 ERR("open_fileref_by_inode returned %08lx\n", Status);
4423 free_fcb(fcb);
4424 return Status;
4425 }
4426
4427 name.Length = name.MaximumLength = sizeof(root_dir_utf16) - sizeof(WCHAR);
4428 name.Buffer = (WCHAR*)root_dir_utf16;
4429 } else {
4430 ERR("couldn't find parent for subvol %I64x\n", subvol->id);
4431 free_fcb(fcb);
4432 return STATUS_INTERNAL_ERROR;
4433 }
4434 }
4435 } else {
4436 Status = open_fileref_by_inode(Vcb, subvol, parent, &parfr, Irp);
4437 if (!NT_SUCCESS(Status)) {
4438 ERR("open_fileref_by_inode returned %08lx\n", Status);
4439 free_fcb(fcb);
4440 return Status;
4441 }
4442 }
4443
4444 Status = open_fileref_child(Vcb, parfr, &name, true, true, false, PagedPool, &fr, Irp);
4445
4446 if (hl_alloc)
4447 ExFreePool(name.Buffer);
4448
4449 if (!NT_SUCCESS(Status)) {
4450 ERR("open_fileref_child returned %08lx\n", Status);
4451
4452 free_fcb(fcb);
4453 free_fileref(parfr);
4454
4455 return Status;
4456 }
4457
4458 *pfr = fr;
4459
4460 free_fcb(fcb);
4461 free_fileref(parfr);
4462
4463 return STATUS_SUCCESS;
4464}
4465
4469 ULONG RequestedDisposition;
4470 ULONG options;
4473 USHORT parsed;
4474 ULONG fn_offset = 0;
4475 file_ref *related, *fileref = NULL;
4477 ACCESS_MASK granted_access;
4478 bool loaded_related = false;
4480
4481 Irp->IoStatus.Information = 0;
4482
4483 RequestedDisposition = ((IrpSp->Parameters.Create.Options >> 24) & 0xff);
4485
4486 if (options & FILE_DIRECTORY_FILE && RequestedDisposition == FILE_SUPERSEDE) {
4487 WARN("error - supersede requested with FILE_DIRECTORY_FILE\n");
4489 }
4490
4492
4493 if (!FileObject) {
4494 ERR("FileObject was NULL\n");
4496 }
4497
4498 if (FileObject->RelatedFileObject && FileObject->RelatedFileObject->FsContext2) {
4499 struct _ccb* relatedccb = FileObject->RelatedFileObject->FsContext2;
4500
4501 related = relatedccb->fileref;
4502 } else
4503 related = NULL;
4504
4506
4507 switch (RequestedDisposition) {
4508 case FILE_SUPERSEDE:
4509 TRACE("requested disposition: FILE_SUPERSEDE\n");
4510 break;
4511
4512 case FILE_CREATE:
4513 TRACE("requested disposition: FILE_CREATE\n");
4514 break;
4515
4516 case FILE_OPEN:
4517 TRACE("requested disposition: FILE_OPEN\n");
4518 break;
4519
4520 case FILE_OPEN_IF:
4521 TRACE("requested disposition: FILE_OPEN_IF\n");
4522 break;
4523
4524 case FILE_OVERWRITE:
4525 TRACE("requested disposition: FILE_OVERWRITE\n");
4526 break;
4527
4528 case FILE_OVERWRITE_IF:
4529 TRACE("requested disposition: FILE_OVERWRITE_IF\n");
4530 break;
4531
4532 default:
4533 ERR("unknown disposition: %lx\n", RequestedDisposition);
4535 goto exit;
4536 }
4537
4538 fn = FileObject->FileName;
4539
4540 TRACE("(%.*S)\n", (int)(fn.Length / sizeof(WCHAR)), fn.Buffer);
4541 TRACE("FileObject = %p\n", FileObject);
4542
4543 if (Vcb->readonly && (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == FILE_CREATE || RequestedDisposition == FILE_OVERWRITE)) {
4545 goto exit;
4546 }
4547
4549 if (RequestedDisposition != FILE_OPEN) {
4550 WARN("FILE_OPEN_BY_FILE_ID not supported for anything other than FILE_OPEN\n");
4552 goto exit;
4553 }
4554
4555 if (fn.Length == sizeof(uint64_t)) {
4557
4558 if (!related) {
4559 WARN("cannot open by short file ID unless related fileref also provided"\n);
4561 goto exit;
4562 }
4563
4564 inode = (*(uint64_t*)fn.Buffer) & 0xffffffffff;
4565
4566 if (related->fcb == Vcb->root_fileref->fcb && inode == 0)
4567 inode = Vcb->root_fileref->fcb->inode;
4568
4569 if (inode == 0) { // we use 0 to mean the parent of a subvolume
4570 fileref = related->parent;
4573 } else
4575
4576 goto loaded;
4577 } else if (fn.Length == sizeof(FILE_ID_128)) {
4578 uint64_t inode, subvol_id;
4579 root* subvol = NULL;
4580
4581 RtlCopyMemory(&inode, fn.Buffer, sizeof(uint64_t));
4582 RtlCopyMemory(&subvol_id, (uint8_t*)fn.Buffer + sizeof(uint64_t), sizeof(uint64_t));
4583
4584 if (subvol_id == BTRFS_ROOT_FSTREE || (subvol_id >= 0x100 && subvol_id < 0x8000000000000000)) {
4585 LIST_ENTRY* le = Vcb->roots.Flink;
4586 while (le != &Vcb->roots) {
4588
4589 if (r->id == subvol_id) {
4590 subvol = r;
4591 break;
4592 }
4593
4594 le = le->Flink;
4595 }
4596 }
4597
4598 if (!subvol) {
4599 WARN("subvol %I64x not found\n", subvol_id);
4601 } else
4603
4604 goto loaded;
4605 } else {
4606 WARN("invalid ID size for FILE_OPEN_BY_FILE_ID\n");
4608 goto exit;
4609 }
4610 }
4611
4612 if (related && fn.Length != 0 && fn.Buffer[0] == '\\') {
4614 goto exit;
4615 }
4616
4617 if (!related && RequestedDisposition != FILE_OPEN && !(IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY)) {
4618 ULONG fnoff;
4619
4620 Status = open_fileref(Vcb, &related, &fn, NULL, true, &parsed, &fnoff,
4621 pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp);
4622
4625 else if (Status == STATUS_REPARSE)
4626 fileref = related;
4627 else if (NT_SUCCESS(Status)) {
4628 fnoff *= sizeof(WCHAR);
4629 fnoff += (related->dc ? related->dc->name.Length : 0) + sizeof(WCHAR);
4630
4631 if (related->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT) {
4633 fileref = related;
4634 parsed = (USHORT)fnoff - sizeof(WCHAR);
4635 } else {
4636 fn.Buffer = &fn.Buffer[fnoff / sizeof(WCHAR)];
4637 fn.Length -= (USHORT)fnoff;
4638
4639 Status = open_fileref(Vcb, &fileref, &fn, related, IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY, &parsed, &fn_offset,
4640 pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp);
4641
4642 loaded_related = true;
4643 }
4644 }
4645 } else {
4646 Status = open_fileref(Vcb, &fileref, &fn, related, IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY, &parsed, &fn_offset,
4647 pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp);
4648 }
4649
4650loaded:
4651 if (Status == STATUS_REPARSE) {
4653
4657
4658 if (!NT_SUCCESS(Status)) {
4659 ERR("get_reparse_block returned %08lx\n", Status);
4660
4662 } else {
4664 RtlCopyMemory(&Irp->IoStatus.Information, data, sizeof(ULONG));
4665
4666 data->Reserved = FileObject->FileName.Length - parsed;
4667
4668 Irp->Tail.Overlay.AuxiliaryBuffer = (void*)data;
4669
4671
4672 goto exit;
4673 }
4674 }
4675
4678
4679 if (NT_SUCCESS(Status)) {
4680 if (RequestedDisposition == FILE_CREATE) {
4681 TRACE("file already exists, returning STATUS_OBJECT_NAME_COLLISION\n");
4683
4685
4686 goto exit;
4687 }
4688 } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
4689 if (RequestedDisposition == FILE_OPEN || RequestedDisposition == FILE_OVERWRITE) {
4690 TRACE("file doesn't exist, returning STATUS_OBJECT_NAME_NOT_FOUND\n");
4691 goto exit;
4692 }
4694 TRACE("open_fileref returned %08lx\n", Status);
4695 goto exit;
4696 } else {
4697 ERR("open_fileref returned %08lx\n", Status);
4698 goto exit;
4699 }
4700
4701 if (NT_SUCCESS(Status)) { // file already exists
4702 Status = open_file2(Vcb, RequestedDisposition, fileref, &granted_access, FileObject, &fn,
4703 options, Irp, rollback, opctx);
4704 } else {
4705 file_ref* existing_file = NULL;
4706
4707 Status = file_create(Irp, Vcb, FileObject, related, loaded_related, &fn, RequestedDisposition, options, &existing_file, rollback);
4708
4709 if (Status == STATUS_OBJECT_NAME_COLLISION) { // already exists
4710 fileref = existing_file;
4711
4712 Status = open_file2(Vcb, RequestedDisposition, fileref, &granted_access, FileObject, &fn,
4713 options, Irp, rollback, opctx);
4714 } else {
4715 Irp->IoStatus.Information = NT_SUCCESS(Status) ? FILE_CREATED : 0;
4716 granted_access = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
4717 }
4718 }
4719
4722
4723exit:
4724 if (loaded_related)
4725 free_fileref(related);
4726
4727 if (Status == STATUS_SUCCESS) {
4728 fcb* fcb2;
4729
4730 IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess |= granted_access;
4731 IrpSp->Parameters.Create.SecurityContext->AccessState->RemainingDesiredAccess &= ~(granted_access | MAXIMUM_ALLOWED);
4732
4733 if (!FileObject->Vpb)
4734 FileObject->Vpb = DeviceObject->Vpb;
4735
4736 fcb2 = FileObject->FsContext;
4737
4738 if (fcb2->ads) {
4739 struct _ccb* ccb2 = FileObject->FsContext2;
4740
4741 fcb2 = ccb2->fileref->parent->fcb;
4742 }
4743
4744 ExAcquireResourceExclusiveLite(fcb2->Header.Resource, true);
4745 fcb_load_csums(Vcb, fcb2, Irp);
4746 ExReleaseResourceLite(fcb2->Header.Resource);
4748 TRACE("returning %08lx\n", Status);
4749
4750 return Status;
4751}
4752
4755 LIST_ENTRY* le;
4756 bool need_verify = false;
4757
4758 ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
4759
4760 le = Vcb->devices.Flink;
4761 while (le != &Vcb->devices) {
4763
4764 if (dev->devobj && dev->removable) {
4765 ULONG cc;
4767
4768 Status = dev_ioctl(dev->devobj, IOCTL_STORAGE_CHECK_VERIFY, NULL, 0, &cc, sizeof(ULONG), true, &iosb);
4769
4771 ERR("IOCTL_STORAGE_CHECK_VERIFY returned %08lx (user-induced)\n", Status);
4772 need_verify = true;
4773 } else if (!NT_SUCCESS(Status)) {
4774 ERR("IOCTL_STORAGE_CHECK_VERIFY returned %08lx\n", Status);
4775 goto end;
4776 } else if (iosb.Information < sizeof(ULONG)) {
4777 ERR("iosb.Information was too short\n");
4779 } else if (cc != dev->change_count) {
4780 dev->devobj->Flags |= DO_VERIFY_VOLUME;
4781 need_verify = true;
4782 }
4783 }
4784
4785 le = le->Flink;
4786 }
4787
4789
4790end:
4791 ExReleaseResourceLite(&Vcb->tree_lock);
4792
4793 if (need_verify) {
4794 PDEVICE_OBJECT devobj;
4795
4796 devobj = IoGetDeviceToVerify(Irp->Tail.Overlay.Thread);
4797 IoSetDeviceToVerify(Irp->Tail.Overlay.Thread, NULL);
4798
4799 if (!devobj) {
4802 }
4803
4804 devobj = Vcb->Vpb ? Vcb->Vpb->RealDevice : NULL;
4805
4806 if (devobj)
4807 Status = IoVerifyVolume(devobj, false);
4808 else
4810 }
4811
4812 return Status;
4813}
4814
4815static bool has_manage_volume_privilege(ACCESS_STATE* access_state, KPROCESSOR_MODE processor_mode) {
4816 PRIVILEGE_SET privset;
4817
4818 privset.PrivilegeCount = 1;
4820 privset.Privilege[0].Luid = RtlConvertLongToLuid(SE_MANAGE_VOLUME_PRIVILEGE);
4821 privset.Privilege[0].Attributes = 0;
4822
4823 return SePrivilegeCheck(&privset, &access_state->SubjectSecurityContext, processor_mode) ? true : false;
4824}
4825
4831 device_extension* Vcb = DeviceObject->DeviceExtension;
4832 bool top_level, locked = false;
4833 oplock_context* opctx = NULL;
4834
4836
4837 TRACE("create (flags = %lx)\n", Irp->Flags);
4838
4839 top_level = is_top_level(Irp);
4840
4841 /* return success if just called for FS device object */
4842 if (DeviceObject == master_devobj) {
4843 TRACE("create called for FS device object\n");
4844
4845 Irp->IoStatus.Information = FILE_OPENED;
4847
4848 goto exit;
4849 } else if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
4851 goto exit;
4852 } else if (!Vcb || Vcb->type != VCB_TYPE_FS) {
4854 goto exit;
4855 }
4856
4857 if (!(Vcb->Vpb->Flags & VPB_MOUNTED)) {
4859 goto exit;
4860 }
4861
4862 if (Vcb->removing) {
4864 goto exit;
4865 }
4866
4868 if (!NT_SUCCESS(Status)) {
4869 ERR("verify_vcb returned %08lx\n", Status);
4870 goto exit;
4871 }
4872
4873 ExAcquireResourceSharedLite(&Vcb->load_lock, true);
4874 locked = true;
4875
4877
4878 if (IrpSp->Flags != 0) {
4880
4881 TRACE("flags:\n");
4882
4883 if (flags & SL_CASE_SENSITIVE) {
4884 TRACE("SL_CASE_SENSITIVE\n");
4885 flags &= ~SL_CASE_SENSITIVE;
4886 }
4887
4889 TRACE("SL_FORCE_ACCESS_CHECK\n");
4890 flags &= ~SL_FORCE_ACCESS_CHECK;
4891 }
4892
4893 if (flags & SL_OPEN_PAGING_FILE) {
4894 TRACE("SL_OPEN_PAGING_FILE\n");
4895 flags &= ~SL_OPEN_PAGING_FILE;
4896 }
4897
4899 TRACE("SL_OPEN_TARGET_DIRECTORY\n");
4900 flags &= ~SL_OPEN_TARGET_DIRECTORY;
4901 }
4902
4903 if (flags & SL_STOP_ON_SYMLINK) {
4904 TRACE("SL_STOP_ON_SYMLINK\n");
4905 flags &= ~SL_STOP_ON_SYMLINK;
4906 }
4907
4909 TRACE("SL_IGNORE_READONLY_ATTRIBUTE\n");
4910 flags &= ~SL_IGNORE_READONLY_ATTRIBUTE;
4911 }
4912
4913 if (flags)
4914 WARN("unknown flags: %x\n", flags);
4915 } else {
4916 TRACE("flags: (none)\n");
4917 }
4918
4919 if (!IrpSp->FileObject) {
4920 ERR("FileObject was NULL\n");
4922 goto exit;
4923 }
4924
4925 if (IrpSp->FileObject->RelatedFileObject) {
4926 fcb* relatedfcb = IrpSp->FileObject->RelatedFileObject->FsContext;
4927
4928 if (relatedfcb && relatedfcb->Vcb != Vcb) {
4929 WARN("RelatedFileObject was for different device\n");
4931 goto exit;
4932 }
4933 }
4934
4935 // opening volume
4936 if (IrpSp->FileObject->FileName.Length == 0 && !IrpSp->FileObject->RelatedFileObject) {
4937 ULONG RequestedDisposition = ((IrpSp->Parameters.Create.Options >> 24) & 0xff);
4938 ULONG RequestedOptions = IrpSp->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
4939#ifdef DEBUG_FCB_REFCOUNTS
4940 LONG rc;
4941#endif
4942 ccb* ccb;
4943
4944 TRACE("open operation for volume\n");
4945
4946 if (RequestedDisposition != FILE_OPEN && RequestedDisposition != FILE_OPEN_IF) {
4948 goto exit;
4949 }
4950
4951 if (RequestedOptions & FILE_DIRECTORY_FILE) {
4953 goto exit;
4954 }
4955
4957 if (!ccb) {
4958 ERR("out of memory\n");
4960 goto exit;
4961 }
4962
4963 RtlZeroMemory(ccb, sizeof(*ccb));
4964
4966 ccb->NodeSize = sizeof(*ccb);
4967 ccb->disposition = RequestedDisposition;
4968 ccb->options = RequestedOptions;
4969 ccb->access = IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess;
4971 IrpSp->Flags & SL_FORCE_ACCESS_CHECK ? UserMode : Irp->RequestorMode);
4972 ccb->reserving = false;
4974
4975#ifdef DEBUG_FCB_REFCOUNTS
4976 rc = InterlockedIncrement(&Vcb->volume_fcb->refcount);
4977 WARN("fcb %p: refcount now %i (volume)\n", Vcb->volume_fcb, rc);
4978#else
4979 InterlockedIncrement(&Vcb->volume_fcb->refcount);
4980#endif
4981 IrpSp->FileObject->FsContext = Vcb->volume_fcb;
4982 IrpSp->FileObject->FsContext2 = ccb;
4983
4984 IrpSp->FileObject->SectionObjectPointer = &Vcb->volume_fcb->nonpaged->segment_object;
4985
4986 if (!IrpSp->FileObject->Vpb)
4987 IrpSp->FileObject->Vpb = DeviceObject->Vpb;
4988
4989 InterlockedIncrement(&Vcb->open_files);
4990
4991 Irp->IoStatus.Information = FILE_OPENED;
4993 } else {
4995 bool skip_lock;
4996
4998
4999 TRACE("file name: %.*S\n", (int)(IrpSp->FileObject->FileName.Length / sizeof(WCHAR)), IrpSp->FileObject->FileName.Buffer);
5000
5001 if (IrpSp->FileObject->RelatedFileObject)
5002 TRACE("related file = %p\n", IrpSp->FileObject->RelatedFileObject);
5003
5004 // Don't lock again if we're being called from within CcCopyRead etc.
5005 skip_lock = ExIsResourceAcquiredExclusiveLite(&Vcb->tree_lock);
5006
5007 if (!skip_lock)
5008 ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
5009
5010 ExAcquireResourceSharedLite(&Vcb->fileref_lock, true);
5011
5013
5014 if (!NT_SUCCESS(Status))
5016 else
5018
5019 ExReleaseResourceLite(&Vcb->fileref_lock);
5020
5021 if (!skip_lock)
5022 ExReleaseResourceLite(&Vcb->tree_lock);
5023 }
5024
5025exit:
5026 if (Status != STATUS_PENDING) {
5027 Irp->IoStatus.Status = Status;
5029 }
5030
5031 if (locked)
5032 ExReleaseResourceLite(&Vcb->load_lock);
5033
5034 if (Status == STATUS_PENDING) {
5036 Status = opctx->Status;
5037 ExFreePool(opctx);
5038 }
5039
5040 TRACE("create returning %08lx\n", Status);
5041
5042 if (top_level)
5044
5046
5047 return Status;
5048}
BOOLEAN NTAPI SeAccessCheck(_In_ PSECURITY_DESCRIPTOR SecurityDescriptor, _In_ PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext, _In_ BOOLEAN SubjectContextLocked, _In_ ACCESS_MASK DesiredAccess, _In_ ACCESS_MASK PreviouslyGrantedAccess, _Out_ PPRIVILEGE_SET *Privileges, _In_ PGENERIC_MAPPING GenericMapping, _In_ KPROCESSOR_MODE AccessMode, _Out_ PACCESS_MASK GrantedAccess, _Out_ PNTSTATUS AccessStatus)
Determines whether security access rights can be given to an object depending on the security descrip...
Definition: accesschk.c:1994
unsigned short int uint16_t
Definition: acefiex.h:54
#define S_IFDIR
Definition: acwin.h:115
unsigned int dir
Definition: maze.c:112
#define InterlockedIncrement
Definition: armddk.h:53
LONG NTSTATUS
Definition: precomp.h:26
#define FILE_DIRECTORY_FILE
Definition: constants.h:491
#define FILE_NON_DIRECTORY_FILE
Definition: constants.h:492
#define FILE_OPEN_FOR_FREE_SPACE_QUERY
Definition: constants.h:495
#define FILE_COMPLETE_IF_OPLOCKED
Definition: constants.h:493
#define FILE_DELETE_ON_CLOSE
Definition: constants.h:494
#define WARN(fmt,...)
Definition: debug.h:112
#define ERR(fmt,...)
Definition: debug.h:110
#define GID_NOBODY
Definition: btrfs_drv.h:91
#define VCB_TYPE_VOLUME
Definition: btrfs_drv.h:689
#define FILE_CS_FLAG_CASE_SENSITIVE_DIR
Definition: btrfs_drv.h:165
NTSTATUS read_file(fcb *fcb, uint8_t *data, uint64_t start, uint64_t length, ULONG *pbr, PIRP Irp) __attribute__((nonnull(1
NTSTATUS(__stdcall * tFsRtlValidateReparsePointBuffer)(ULONG BufferLength, PREPARSE_DATA_BUFFER ReparseBuffer)
Definition: btrfs_drv.h:1864
#define increase_fileref_refcount(fileref)
Definition: btrfs_drv.h:1739
PVOID Context
Definition: btrfs_drv.h:1326
#define InterlockedIncrement64(a)
Definition: btrfs_drv.h:143
_In_ fcb _In_ chunk _In_ uint64_t _In_ uint64_t _In_ bool _In_opt_ void _In_opt_ PIRP _In_ LIST_ENTRY * rollback
Definition: btrfs_drv.h:1365
#define EA_CASE_SENSITIVE
Definition: btrfs_drv.h:105
static __inline FAST_IO_POSSIBLE fast_io_possible(fcb *fcb)
Definition: btrfs_drv.h:1684
#define EA_EA
Definition: btrfs_drv.h:102
#define keycmp(key1, key2)
Definition: btrfs_drv.h:1016
#define EA_EA_HASH
Definition: btrfs_drv.h:103
#define EA_NTACL_HASH
Definition: btrfs_drv.h:94
#define _Dispatch_type_(a)
Definition: btrfs_drv.h:204
static const char lxgid[]
Definition: btrfs_drv.h:1288
#define __S_IFDIR
Definition: btrfs_drv.h:1754
#define EA_NTACL
Definition: btrfs_drv.h:93
#define EA_PROP_COMPRESSION_HASH
Definition: btrfs_drv.h:109
static __inline void win_time_to_unix(LARGE_INTEGER t, BTRFS_TIME *out)
Definition: btrfs_drv.h:989
#define BTRFS_NODE_TYPE_FCB
Definition: btrfs_drv.h:85
struct _fcb fcb
Definition: btrfs_drv.h:1364
#define VCB_TYPE_FS
Definition: btrfs_drv.h:687
void fcb_get_sd(fcb *fcb, struct _fcb *parent, bool look_for_xattr, PIRP Irp)
Definition: security.c:511
#define __S_IFSOCK
Definition: btrfs_drv.h:1760
#define EA_DOSATTRIB_HASH
Definition: btrfs_drv.h:97
#define ALLOC_TAG
Definition: btrfs_drv.h:87
NTSTATUS stream_set_end_of_file_information(device_extension *Vcb, uint16_t end, fcb *fcb, file_ref *fileref, bool advance_only)
Definition: fileinfo.c:3170
#define EA_REPARSE_HASH
Definition: btrfs_drv.h:100
static const char lxdev[]
Definition: btrfs_drv.h:1290
static __inline POPLOCK fcb_oplock(fcb *fcb)
Definition: btrfs_drv.h:1677
NTSTATUS NTSTATUS NTSTATUS NTSTATUS extend_file(fcb *fcb, file_ref *fileref, uint64_t end, bool prealloc, PIRP Irp, LIST_ENTRY *rollback) __attribute__((nonnull(1
void do_rollback(device_extension *Vcb, LIST_ENTRY *rollback) __attribute__((nonnull(1
#define __S_IFLNK
Definition: btrfs_drv.h:1759
NTSTATUS(__stdcall * tFsRtlGetEcpListFromIrp)(PIRP Irp, PECP_LIST *EcpList)
Definition: btrfs_drv.h:1859
#define EA_REPARSE
Definition: btrfs_drv.h:99
NTSTATUS NTSTATUS NTSTATUS truncate_file(fcb *fcb, uint64_t end, PIRP Irp, LIST_ENTRY *rollback) __attribute__((nonnull(1
#define EA_PROP_COMPRESSION
Definition: btrfs_drv.h:108
#define EA_DOSATTRIB
Definition: btrfs_drv.h:96
NTSTATUS set_reparse_point2(fcb *fcb, REPARSE_DATA_BUFFER *rdb, ULONG buflen, ccb *ccb, file_ref *fileref, PIRP Irp, LIST_ENTRY *rollback)
Definition: reparse.c:307
#define __S_IFIFO
Definition: btrfs_drv.h:1758
NTSTATUS(__stdcall * tFsRtlGetNextExtraCreateParameter)(PECP_LIST EcpList, PVOID CurrentEcpContext, LPGUID NextEcpType, PVOID *NextEcpContext, ULONG *NextEcpContextSize)
Definition: btrfs_drv.h:1861
static const char lxmod[]
Definition: btrfs_drv.h:1289
static const char lxuid[]
Definition: btrfs_drv.h:1287
struct _ccb ccb
#define EA_CASE_SENSITIVE_HASH
Definition: btrfs_drv.h:106
bool is_extent_unique(device_extension *Vcb, uint64_t address, uint64_t size, PIRP Irp)
Definition: extent-tree.c:1697
NTSTATUS NTSTATUS void clear_rollback(LIST_ENTRY *rollback) __attribute__((nonnull(1)))
#define __S_ISTYPE(mode, mask)
Definition: btrfs_drv.h:1761
void insert_dir_child_into_hash_lists(fcb *fcb, dir_child *dc)
Definition: fileinfo.c:1470
NTSTATUS NTSTATUS bool find_next_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension *Vcb, const traverse_ptr *tp, traverse_ptr *next_tp, bool ignore, PIRP Irp) __attribute__((nonnull(1
NTSTATUS fcb_get_new_sd(fcb *fcb, file_ref *parfileref, ACCESS_STATE *as)
Definition: security.c:988
@ PropCompression_None
Definition: btrfs_drv.h:268
@ PropCompression_LZO
Definition: btrfs_drv.h:270
@ PropCompression_Zlib
Definition: btrfs_drv.h:269
@ PropCompression_ZSTD
Definition: btrfs_drv.h:271
#define __S_IFBLK
Definition: btrfs_drv.h:1756
NTSTATUS vol_create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: volume.c:36
static __inline bool is_subvol_readonly(root *r, PIRP Irp)
Definition: btrfs_drv.h:1033
#define BTRFS_NODE_TYPE_CCB
Definition: btrfs_drv.h:84
bool is_tree_unique(device_extension *Vcb, tree *t, PIRP Irp)
Definition: flushthread.c:3243
#define __S_IFCHR
Definition: btrfs_drv.h:1755
static __inline bool write_fcb_compressed(fcb *fcb)
Definition: btrfs_drv.h:1706
while(CdLookupNextInitialFileDirent(IrpContext, Fcb, FileContext))
#define _Requires_lock_held_(lock)
#define _Requires_exclusive_lock_held_(lock)
static uint64_t __inline sector_align(uint64_t n, uint64_t a)
crc_func calc_crc32c
Definition: crc32c.c:23
_In_ PIRP Irp
Definition: csq.h:116
#define NULL
Definition: types.h:112
UINT32 uint32_t
Definition: types.h:75
UINT64 uint64_t
Definition: types.h:77
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
static string utf16_to_utf8(const wstring_view &utf16)
Definition: main.cpp:670
wstring utf8_to_utf16(const string_view &utf8)
Definition: main.cpp:734
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:137
#define crc32(crc, buf, len)
Definition: inflate.c:1081
static const WCHAR *const ext[]
Definition: module.c:53
static void cleanup(void)
Definition: main.c:1335
static LONG find_item(PropertyBag *This, LPCOLESTR name)
Definition: propertybag.c:110
void mark_fcb_dirty(_In_ fcb *fcb)
Definition: btrfs.c:1695
_In_ uint64_t _In_ uint64_t _In_ uint64_t _In_opt_ traverse_ptr * tp
Definition: btrfs.c:2996
NTSTATUS delete_fileref(_In_ file_ref *fileref, _In_opt_ PFILE_OBJECT FileObject, _In_ bool make_orphan, _In_opt_ PIRP Irp, _In_ LIST_ENTRY *rollback)
Definition: btrfs.c:2270
void free_fileref(_Inout_ file_ref *fr)
Definition: btrfs.c:1856
r parent
Definition: btrfs.c:3010
void reap_fileref(device_extension *Vcb, file_ref *fr)
Definition: btrfs.c:1875
void free_fcb(_Inout_ fcb *fcb)
Definition: btrfs.c:1734
void mark_fileref_dirty(_In_ file_ref *fileref)
Definition: btrfs.c:1717
ULONG get_file_attributes(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension *Vcb, _In_ root *r, _In_ uint64_t inode, _In_ uint8_t type, _In_ bool dotfile, _In_ bool ignore_xa, _In_opt_ PIRP Irp)
Definition: btrfs.c:2664
r fcbs_version
Definition: btrfs.c:3012
bool is_top_level(_In_ PIRP Irp)
Definition: btrfs.c:278
void queue_notification_fcb(_In_ file_ref *fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream)
Definition: btrfs.c:1667
_Ret_maybenull_ root * find_default_subvol(_In_ _Requires_lock_held_(_Curr_->tree_lock) device_extension *Vcb, _In_opt_ PIRP Irp)
Definition: btrfs.c:3981
NTSTATUS check_file_name_valid(_In_ PUNICODE_STRING us, _In_ bool posix, _In_ bool stream)
Definition: btrfs.c:5797
void send_notification_fileref(_In_ file_ref *fileref, _In_ ULONG filter_match, _In_ ULONG action, _In_opt_ PUNICODE_STRING stream)
Definition: btrfs.c:1517
NTSTATUS dev_ioctl(_In_ PDEVICE_OBJECT DeviceObject, _In_ ULONG ControlCode, _In_reads_bytes_opt_(InputBufferSize) PVOID InputBuffer, _In_ ULONG InputBufferSize, _Out_writes_bytes_opt_(OutputBufferSize) PVOID OutputBuffer, _In_ ULONG OutputBufferSize, _In_ bool Override, _Out_opt_ IO_STATUS_BLOCK *iosb)
Definition: btrfs.c:2954
void reap_fcb(fcb *fcb)
Definition: btrfs.c:1743
#define EXTENT_CSUM_ID
Definition: btrfs.h:91
#define TYPE_EXTENT_DATA
Definition: btrfs.h:30
#define TYPE_INODE_EXTREF
Definition: btrfs.h:25
#define TYPE_DIR_INDEX
Definition: btrfs.h:29
#define EXTENT_TYPE_PREALLOC
Definition: btrfs.h:76
#define BTRFS_SUBVOL_READONLY
Definition: btrfs.h:109
#define BTRFS_INODE_RO_VERITY
Definition: btrfs.h:107
#define EXTENT_TYPE_INLINE
Definition: btrfs.h:74
#define TYPE_XATTR_ITEM
Definition: btrfs.h:26
#define TYPE_ROOT_BACKREF
Definition: btrfs.h:33
#define EXTENT_TYPE_REGULAR
Definition: btrfs.h:75
#define BTRFS_COMPRESSION_NONE
Definition: btrfs.h:65
#define TYPE_EXTENT_CSUM
Definition: btrfs.h:31
#define TYPE_INODE_REF
Definition: btrfs.h:24
#define BTRFS_ROOT_FSTREE
Definition: btrfs.h:58
#define TYPE_ROOT_ITEM
Definition: btrfs.h:32
#define TYPE_INODE_ITEM
Definition: btrfs.h:23
#define SL_IGNORE_READONLY_ATTRIBUTE
Definition: create.c:47
static NTSTATUS open_file(PDEVICE_OBJECT DeviceObject, _Requires_lock_held_(_Curr_->tree_lock) device_extension *Vcb, PIRP Irp, LIST_ENTRY *rollback, oplock_context **opctx)
Definition: create.c:4466
static NTSTATUS open_file2(device_extension *Vcb, ULONG RequestedDisposition, file_ref *fileref, ACCESS_MASK *granted_access, PFILE_OBJECT FileObject, UNICODE_STRING *fn, ULONG options, PIRP Irp, LIST_ENTRY *rollback, oplock_context **opctx)
Definition: create.c:3936
static const WCHAR datastring[]
Definition: create.c:30
static void __stdcall oplock_complete(PVOID Context, PIRP Irp)
Definition: create.c:3863
#define ATOMIC_CREATE_ECP_OUT_FLAG_OP_FLAGS_HONORED
Definition: create.c:41
static const GUID GUID_ECP_ATOMIC_CREATE
Definition: create.c:79
struct _FILE_TIMESTAMPS * PFILE_TIMESTAMPS
#define ATOMIC_CREATE_ECP_IN_OP_FLAG_CASE_SENSITIVE_FLAGS_SPECIFIED
Definition: create.c:43
static NTSTATUS file_create2(_In_ PIRP Irp, _Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension *Vcb, _In_ PUNICODE_STRING fpus, _In_ file_ref *parfileref, _In_ ULONG options, _In_reads_bytes_opt_(ealen) FILE_FULL_EA_INFORMATION *ea, _In_ ULONG ealen, _Out_ file_ref **pfr, bool case_sensitive, _In_ LIST_ENTRY *rollback)
Definition: create.c:2182
static const char root_dir[]
Definition: create.c:32
static NTSTATUS get_reparse_block(fcb *fcb, uint8_t **data)
Definition: create.c:3425
uint32_t inherit_mode(fcb *parfcb, bool is_dir)
Definition: create.c:1948
static const WCHAR root_dir_utf16[]
Definition: create.c:33
#define ATOMIC_CREATE_ECP_OUT_OP_FLAG_CASE_SENSITIVE_FLAGS_SET
Definition: create.c:44
static __inline void debug_create_options(ULONG RequestedOptions)
Definition: create.c:3300
struct _ATOMIC_CREATE_ECP_CONTEXT ATOMIC_CREATE_ECP_CONTEXT
#define ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED
Definition: create.c:36
NTSTATUS open_fileref_child(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension *Vcb, _In_ file_ref *sf, _In_ PUNICODE_STRING name, _In_ bool case_sensitive, _In_ bool lastpart, _In_ bool streampart, _In_ POOL_TYPE pooltype, _Out_ file_ref **psf2, _In_opt_ PIRP Irp)
Definition: create.c:1459
static NTSTATUS create_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension *Vcb, file_ref **pfileref, file_ref **pparfileref, PUNICODE_STRING fpus, PUNICODE_STRING stream, PIRP Irp, ULONG options, POOL_TYPE pool_type, bool case_sensitive, LIST_ENTRY *rollback)
Definition: create.c:2640
NTSTATUS open_fileref(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) _In_ device_extension *Vcb, _Out_ file_ref **pfr, _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, _In_ bool case_sensitive, _In_opt_ PIRP Irp)
Definition: create.c:1690
struct _ATOMIC_CREATE_ECP_CONTEXT * PATOMIC_CREATE_ECP_CONTEXT
static const GUID GUID_ECP_QUERY_ON_CREATE
Definition: create.c:80
#define called_from_lxss()
Definition: create.c:3004
static NTSTATUS file_create_parse_ea(fcb *fcb, FILE_FULL_EA_INFORMATION *ea)
Definition: create.c:1964
static void fcb_load_csums(_Requires_lock_held_(_Curr_->tree_lock) device_extension *Vcb, fcb *fcb, PIRP Irp)
Definition: create.c:3547
NTSTATUS load_csum(_Requires_lock_held_(_Curr_->tree_lock) device_extension *Vcb, void *csum, uint64_t start, uint64_t length, PIRP Irp)
Definition: create.c:453
static NTSTATUS verify_vcb(device_extension *Vcb, PIRP Irp)
Definition: create.c:4753
tFsRtlGetEcpListFromIrp fFsRtlGetEcpListFromIrp
Definition: btrfs.c:96
NTSTATUS open_fileref_by_inode(_Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension *Vcb, root *subvol, uint64_t inode, file_ref **pfr, PIRP Irp)
Definition: create.c:4136
#define ATOMIC_CREATE_ECP_IN_FLAG_OP_FLAGS_SPECIFIED
Definition: create.c:37
PDEVICE_OBJECT master_devobj
Definition: btrfs.c:66
tFsRtlGetNextExtraCreateParameter fFsRtlGetNextExtraCreateParameter
Definition: btrfs.c:97
NTSTATUS open_fcb(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension *Vcb, root *subvol, uint64_t inode, uint8_t type, PANSI_STRING utf8, bool always_add_hl, fcb *parent, fcb **pfcb, POOL_TYPE pooltype, PIRP Irp)
Definition: create.c:706
struct _FILE_TIMESTAMPS FILE_TIMESTAMPS
static NTSTATUS open_file3(device_extension *Vcb, PIRP Irp, ACCESS_MASK granted_access, file_ref *fileref, LIST_ENTRY *rollback)
Definition: create.c:3588
static NTSTATUS split_path(device_extension *Vcb, PUNICODE_STRING path, LIST_ENTRY *parts, bool *stream)
Definition: create.c:321
static NTSTATUS open_fcb_stream(_Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension *Vcb, dir_child *dc, fcb *parent, fcb **pfcb, PIRP Irp)
Definition: create.c:1366
tFsRtlValidateReparsePointBuffer fFsRtlValidateReparsePointBuffer
Definition: btrfs.c:98
static bool has_manage_volume_privilege(ACCESS_STATE *access_state, KPROCESSOR_MODE processor_mode)
Definition: create.c:4815
#define ATOMIC_CREATE_ECP_OUT_FLAG_REPARSE_POINT_SET
Definition: create.c:40
fcb * create_fcb(device_extension *Vcb, POOL_TYPE pool_type)
Definition: create.c:91
NTSTATUS add_dir_child(fcb *fcb, uint64_t inode, bool subvol, PANSI_STRING utf8, PUNICODE_STRING name, uint8_t type, dir_child **pdc)
Definition: create.c:1871
file_ref * create_fileref(device_extension *Vcb)
Definition: create.c:160
static const GUID GUID_ECP_CREATE_REDIRECTION
Definition: create.c:81
NTSTATUS find_file_in_dir(PUNICODE_STRING filename, fcb *fcb, root **subvol, uint64_t *inode, dir_child **pdc, bool case_sensitive)
Definition: create.c:182
static NTSTATUS file_create(PIRP Irp, _Requires_lock_held_(_Curr_->tree_lock) _Requires_exclusive_lock_held_(_Curr_->fcb_lock) device_extension *Vcb, PFILE_OBJECT FileObject, file_ref *related, bool loaded_related, PUNICODE_STRING fnus, ULONG disposition, ULONG options, file_ref **existing_fileref, LIST_ENTRY *rollback)
Definition: create.c:3007
NTSTATUS load_dir_children(_Requires_lock_held_(_Curr_->tree_lock) device_extension *Vcb, fcb *fcb, bool ignore_size, PIRP Irp)
Definition: create.c:510
_In_ PIO_STACK_LOCATION IrpSp
Definition: create.c:4137
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
#define InsertHeadList(ListHead, Entry)
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
NTSTATUS ExInitializeResourceLite(PULONG res)
Definition: env_spec_w32.h:641
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define DO_VERIFY_VOLUME
Definition: env_spec_w32.h:393
NTSTATUS RtlUpcaseUnicodeString(PUNICODE_STRING dst, PUNICODE_STRING src, BOOLEAN Alloc)
Definition: string_lib.cpp:46
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define RemoveTailList(ListHead)
Definition: env_spec_w32.h:975
#define ExAcquireResourceExclusiveLite(res, wait)
Definition: env_spec_w32.h:615
#define RemoveHeadList(ListHead)
Definition: env_spec_w32.h:964
#define NonPagedPool
Definition: env_spec_w32.h:307
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define ExAcquireResourceSharedLite(res, wait)
Definition: env_spec_w32.h:621
#define PagedPool
Definition: env_spec_w32.h:308
#define S_IFREG
Definition: ext2fs.h:361
VOID NTAPI FsRtlInitializeFileLock(IN PFILE_LOCK FileLock, IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL, IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL)
Definition: filelock.c:1262
time_t now
Definition: finger.c:65
std::wstring STRING
Definition: fontsub.cpp:33
#define FILE_OPEN_BY_FILE_ID
Definition: from_kernel.h:41
#define FILE_NO_COMPRESSION
Definition: from_kernel.h:43
#define FILE_OPEN
Definition: from_kernel.h:54
#define FILE_CREATE
Definition: from_kernel.h:55
#define FILE_OVERWRITE_IF
Definition: from_kernel.h:58
#define FILE_OPEN_REPARSE_POINT
Definition: from_kernel.h:46
#define FILE_NO_EA_KNOWLEDGE
Definition: from_kernel.h:36
#define FILE_RESERVE_OPFILTER
Definition: from_kernel.h:45
#define FILE_SYNCHRONOUS_IO_NONALERT
Definition: from_kernel.h:31
#define FILE_NO_INTERMEDIATE_BUFFERING
Definition: from_kernel.h:28
#define FILE_RANDOM_ACCESS
Definition: from_kernel.h:38
#define FILE_OVERWRITE
Definition: from_kernel.h:57
#define FILE_WRITE_THROUGH
Definition: from_kernel.h:26
#define FILE_OPEN_NO_RECALL
Definition: from_kernel.h:47
#define FILE_OPEN_IF
Definition: from_kernel.h:56
#define FILE_SEQUENTIAL_ONLY
Definition: from_kernel.h:27
#define FILE_SYNCHRONOUS_IO_ALERT
Definition: from_kernel.h:30
#define FILE_SUPERSEDE
Definition: from_kernel.h:53
#define FILE_OPEN_REMOTE_INSTANCE
Definition: from_kernel.h:37
#define FILE_CREATE_TREE_CONNECTION
Definition: from_kernel.h:33
#define FILE_OPEN_FOR_BACKUP_INTENT
Definition: from_kernel.h:42
#define FsRtlEnterFileSystem
#define FsRtlExitFileSystem
#define FSRTL_FLAG2_IS_PAGING_FILE
Definition: fsrtltypes.h:57
VOID(NTAPI * POPLOCK_WAIT_COMPLETE_ROUTINE)(_In_ PVOID Context, _In_ PIRP Irp)
Definition: fsrtltypes.h:253
Status
Definition: gdiplustypes.h:25
GLuint start
Definition: gl.h:1545
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLdouble s
Definition: gl.h:2039
GLuint GLuint end
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLsizeiptr size
Definition: glext.h:5919
GLdouble n
Definition: glext.h:7729
GLint const GLchar GLint stringlen
Definition: glext.h:7232
const GLubyte * c
Definition: glext.h:8905
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLenum mode
Definition: glext.h:6217
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glext.h:7005
GLbitfield flags
Definition: glext.h:7161
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLuint GLfloat * val
Definition: glext.h:7180
GLenum GLsizei len
Definition: glext.h:6722
GLintptr offset
Definition: glext.h:5920
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
#define cs
Definition: i386-dis.c:442
#define FILE_OPEN_REQUIRING_OPLOCK
Definition: winternl.h:186
@ ProcessBasicInformation
Definition: winternl.h:394
NTSYSAPI BOOLEAN WINAPI RtlValidRelativeSecurityDescriptor(PSECURITY_DESCRIPTOR, ULONG, SECURITY_INFORMATION)
HRESULT Create([out]ITransactionReceiver **ppReceiver)
const char * filename
Definition: ioapi.h:137
uint32_t cc
Definition: isohybrid.c:75
#define d
Definition: ke_i.h:81
#define c
Definition: ke_i.h:80
#define b
Definition: ke_i.h:79
if(dx< 0)
Definition: linetemp.h:194
static const WCHAR dc[]
__u16 time
Definition: mkdosfs.c:8
static PVOID ptr
Definition: dispmode.c:27
#define SE_MANAGE_VOLUME_PRIVILEGE
Definition: security.c:682
static const D3D_BLOB_PART parts[]
Definition: blob.c:76
static DNS_RECORDW r2
Definition: record.c:38
BOOL loaded
Definition: xmlview.c:54
static PIO_STATUS_BLOCK iosb
Definition: file.c:98
static ATOM item
Definition: dde.c:856
#define min(a, b)
Definition: monoChain.cc:55
#define _Function_class_(x)
Definition: ms_sal.h:2946
#define _Out_opt_
Definition: ms_sal.h:346
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
#define _In_reads_bytes_opt_(size)
Definition: ms_sal.h:322
#define _In_opt_
Definition: ms_sal.h:309
BYTE uint8_t
Definition: msvideo1.c:66
#define KernelMode
Definition: asm.h:34
#define UserMode
Definition: asm.h:35
NTSYSAPI NTSTATUS NTAPI ZwQueryInformationProcess(_In_ HANDLE ProcessHandle, _In_ PROCESSINFOCLASS ProcessInformationClass, _Out_ PVOID ProcessInformation, _In_ ULONG ProcessInformationLength, _Out_opt_ PULONG ReturnLength)
DRIVER_DISPATCH(nfs41_FsdDispatch)
#define uint32_t
Definition: nsiface.idl:61
#define uint16_t
Definition: nsiface.idl:60
#define SYNCHRONIZE
Definition: nt_native.h:61
#define FILE_WRITE_DATA
Definition: nt_native.h:631
#define WRITE_DAC
Definition: nt_native.h:59
#define FILE_READ_DATA
Definition: nt_native.h:628
#define FILE_ATTRIBUTE_READONLY
Definition: nt_native.h:702
ULONG ACCESS_MASK
Definition: nt_native.h:40
#define ACCESS_SYSTEM_SECURITY
Definition: nt_native.h:77
#define FILE_READ_ATTRIBUTES
Definition: nt_native.h:647
#define FILE_LIST_DIRECTORY
Definition: nt_native.h:629
#define FILE_ATTRIBUTE_HIDDEN
Definition: nt_native.h:703
#define FILE_ATTRIBUTE_SYSTEM
Definition: nt_native.h:704
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define FILE_DELETE_CHILD
Definition: nt_native.h:645
#define FILE_CREATED
Definition: nt_native.h:770
#define NtCurrentProcess()
Definition: nt_native.h:1657
#define FILE_READ_EA
Definition: nt_native.h:638
#define FILE_OVERWRITTEN
Definition: nt_native.h:771
#define FILE_EXECUTE
Definition: nt_native.h:642
#define FILE_SUPERSEDED
Definition: nt_native.h:768
#define FILE_TRAVERSE
Definition: nt_native.h:643
#define FILE_WRITE_ATTRIBUTES
Definition: nt_native.h:649
#define FILE_VALID_OPTION_FLAGS
Definition: nt_native.h:759
#define FILE_ATTRIBUTE_ARCHIVE
Definition: nt_native.h:706
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
#define DELETE
Definition: nt_native.h:57
#define READ_CONTROL
Definition: nt_native.h:58
#define FILE_OPENED
Definition: nt_native.h:769
#define WRITE_OWNER
Definition: nt_native.h:60
#define FILE_ADD_SUBDIRECTORY
Definition: nt_native.h:635
NTSYSAPI VOID NTAPI RtlUpperString(PSTRING DestinationString, PSTRING SourceString)
#define FILE_ADD_FILE
Definition: nt_native.h:632
#define FILE_WRITE_EA
Definition: nt_native.h:640
#define MAXIMUM_ALLOWED
Definition: nt_native.h:83
#define FILE_ATTRIBUTE_TEMPORARY
Definition: nt_native.h:708
LONGLONG USN
Definition: ntbasedef.h:388
#define IOCTL_STORAGE_CHECK_VERIFY
Definition: ntddstor.h:98
@ NotificationEvent
#define FILE_ATTRIBUTE_REPARSE_POINT
Definition: ntifs_ex.h:381
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1822
BOOLEAN NTAPI ExIsResourceAcquiredExclusiveLite(IN PERESOURCE Resource)
Definition: resource.c:1624
ULONG NTAPI ExIsResourceAcquiredSharedLite(IN PERESOURCE Resource)
Definition: resource.c:1663
BOOLEAN NTAPI FsRtlAreNamesEqual(IN PCUNICODE_STRING Name1, IN PCUNICODE_STRING Name2, IN BOOLEAN IgnoreCase, IN PCWCH UpcaseTable OPTIONAL)
Definition: name.c:296
VOID NTAPI IoSetShareAccess(IN ACCESS_MASK DesiredAccess, IN ULONG DesiredShareAccess, IN PFILE_OBJECT FileObject, OUT PSHARE_ACCESS ShareAccess)
Definition: file.c:3517
NTSTATUS NTAPI IoCheckShareAccess(IN ACCESS_MASK DesiredAccess, IN ULONG DesiredShareAccess, IN PFILE_OBJECT FileObject, IN PSHARE_ACCESS ShareAccess, IN BOOLEAN Update)
Definition: file.c:3390
VOID NTAPI IoRemoveShareAccess(IN PFILE_OBJECT FileObject, IN PSHARE_ACCESS ShareAccess)
Definition: file.c:3478
PGENERIC_MAPPING NTAPI IoGetFileObjectGenericMapping(VOID)
Definition: file.c:3267
VOID NTAPI IoUpdateShareAccess(IN PFILE_OBJECT FileObject, OUT PSHARE_ACCESS ShareAccess)
Definition: file.c:3351
#define IoCompleteRequest
Definition: irp.c:1240
VOID NTAPI IoSetTopLevelIrp(IN PIRP Irp)
Definition: irp.c:2000
VOID NTAPI IoSetDeviceToVerify(IN PETHREAD Thread, IN PDEVICE_OBJECT DeviceObject)
Definition: util.c:304
PDEVICE_OBJECT NTAPI IoGetDeviceToVerify(IN PETHREAD Thread)
Definition: util.c:336
NTSTATUS NTAPI IoCheckEaBufferValidity(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: util.c:191
NTSTATUS NTAPI IoVerifyVolume(IN PDEVICE_OBJECT DeviceObject, IN BOOLEAN AllowRawMount)
Definition: volume.c:877
BOOLEAN NTAPI SePrivilegeCheck(_In_ PPRIVILEGE_SET Privileges, _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext, _In_ KPROCESSOR_MODE PreviousMode)
Checks if a set of privileges exist and match within a security subject context.
Definition: priv.c:698
#define STATUS_INTERNAL_ERROR
Definition: ntstatus.h:465
#define STATUS_DELETE_PENDING
Definition: ntstatus.h:322
#define STATUS_REPARSE
Definition: ntstatus.h:83
#define STATUS_PENDING
Definition: ntstatus.h:82
#define STATUS_USER_MAPPED_FILE
Definition: ntstatus.h:711
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:239
#define L(x)
Definition: ntvdm.h:50
NTSTATUS NTAPI FsRtlCheckOplock(IN POPLOCK Oplock, IN PIRP Irp, IN PVOID Context, IN POPLOCK_WAIT_COMPLETE_ROUTINE CompletionRoutine OPTIONAL, IN POPLOCK_FS_PREPOST_IRP PostIrpRoutine OPTIONAL)
Definition: oplock.c:1170
VOID NTAPI FsRtlInitializeOplock(IN OUT POPLOCK Oplock)
Definition: oplock.c:1400
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
#define Vcb
Definition: cdprocs.h:1415
#define SUBVOL_ROOT_INODE
Definition: propsheet.cpp:42
#define minor(rdev)
Definition: propsheet.cpp:929
#define major(rdev)
Definition: propsheet.cpp:928
#define S_IXGRP
Definition: propsheet.h:49
#define S_IROTH
Definition: propsheet.h:53
#define BTRFS_INODE_NOCOMPRESS
Definition: propsheet.h:79
#define BTRFS_INODE_COMPRESS
Definition: propsheet.h:87
#define S_ISUID
Definition: propsheet.h:65
#define S_IXOTH
Definition: propsheet.h:61
#define BTRFS_INODE_NODATASUM
Definition: propsheet.h:76
#define S_IRGRP
Definition: propsheet.h:41
#define S_IWOTH
Definition: propsheet.h:57
#define S_IRUSR
Definition: propsheet.h:29
#define S_ISVTX
Definition: propsheet.h:73
#define BTRFS_INODE_NODATACOW
Definition: propsheet.h:77
#define S_ISGID
Definition: propsheet.h:69
#define S_IWUSR
Definition: propsheet.h:33
#define S_IWGRP
Definition: propsheet.h:45
#define S_IXUSR
Definition: propsheet.h:37
#define IRP_MJ_CREATE
Definition: rdpdr.c:44
#define offsetof(TYPE, MEMBER)
#define exit(n)
Definition: config.h:202
BOOLEAN NTAPI MmCanFileBeTruncated(_In_ PSECTION_OBJECT_POINTERS SectionObjectPointer, _In_opt_ PLARGE_INTEGER NewFileSize)
Definition: section.c:4255
BOOLEAN NTAPI MmFlushImageSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer, IN MMFLUSH_TYPE FlushType)
Definition: section.c:4356
int zero
Definition: sehframes.cpp:29
#define STATUS_CANNOT_DELETE
Definition: shellext.h:71
#define BTRFS_TYPE_FILE
Definition: shellext.h:85
#define STATUS_DEVICE_NOT_READY
Definition: shellext.h:70
#define SYMLINK_FLAG_RELATIVE
Definition: shellext.h:193
#define BTRFS_TYPE_DIRECTORY
Definition: shellext.h:86
#define STATUS_SUCCESS
Definition: shellext.h:65
#define BTRFS_TYPE_SOCKET
Definition: shellext.h:90
#define BTRFS_TYPE_FIFO
Definition: shellext.h:89
#define BTRFS_TYPE_SYMLINK
Definition: shellext.h:91
#define BTRFS_TYPE_CHARDEV
Definition: shellext.h:87
#define BTRFS_TYPE_BLOCKDEV
Definition: shellext.h:88
#define TRACE(s)
Definition: solgame.cpp:4
#define true
Definition: stdbool.h:36
uint16_t m
Definition: btrfs.h:275
uint8_t type
Definition: btrfs.h:277
char name[1]
Definition: btrfs.h:278
uint16_t n
Definition: btrfs.h:276
KEY key
Definition: btrfs.h:273
uint64_t num_bytes
Definition: btrfs.h:371
uint64_t address
Definition: btrfs.h:368
uint64_t size
Definition: btrfs.h:369
uint64_t offset
Definition: btrfs.h:370
uint64_t dir
Definition: btrfs.h:381
uint64_t index
Definition: btrfs.h:382
char name[1]
Definition: btrfs.h:384
uint16_t n
Definition: btrfs.h:383
uint64_t st_rdev
Definition: btrfs.h:296
uint32_t st_mode
Definition: btrfs.h:295
uint32_t st_nlink
Definition: btrfs.h:292
uint64_t block_group
Definition: btrfs.h:291
uint32_t flags
Definition: btrfs.h:297
BTRFS_TIME otime
Definition: btrfs.h:304
BTRFS_TIME st_mtime
Definition: btrfs.h:303
uint64_t st_size
Definition: btrfs.h:289
uint32_t st_uid
Definition: btrfs.h:293
BTRFS_TIME st_atime
Definition: btrfs.h:301
uint64_t sequence
Definition: btrfs.h:299
uint64_t st_blocks
Definition: btrfs.h:290
BTRFS_TIME st_ctime
Definition: btrfs.h:302
uint32_t flags_ro
Definition: btrfs.h:298
uint64_t transid
Definition: btrfs.h:288
uint32_t st_gid
Definition: btrfs.h:294
uint64_t generation
Definition: btrfs.h:287
uint64_t index
Definition: btrfs.h:375
char name[1]
Definition: btrfs.h:377
uint16_t n
Definition: btrfs.h:376
Definition: btrfs.h:143
uint8_t obj_type
Definition: btrfs.h:145
uint64_t obj_id
Definition: btrfs.h:144
uint64_t offset
Definition: btrfs.h:146
uint64_t dir
Definition: btrfs.h:462
char name[1]
Definition: btrfs.h:465
uint16_t n
Definition: btrfs.h:464
SECURITY_SUBJECT_CONTEXT SubjectSecurityContext
Definition: setypes.h:234
USHORT MaximumLength
Definition: env_spec_w32.h:377
PREPARSE_DATA_BUFFER ReparseBuffer
Definition: create.c:62
ULONG SuppressFileAttributeInheritanceMask
Definition: create.c:69
LONGLONG ValidDataLength
Definition: create.c:64
PFILE_TIMESTAMPS FileTimestamps
Definition: create.c:65
LARGE_INTEGER ChangeTime
Definition: create.c:54
LARGE_INTEGER LastAccessTime
Definition: create.c:52
LARGE_INTEGER LastWriteTime
Definition: create.c:53
LARGE_INTEGER CreationTime
Definition: create.c:51
PFILE_OBJECT FileObject
Definition: iotypes.h:3169
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:3128
Definition: typedefs.h:120
struct _LIST_ENTRY * Blink
Definition: typedefs.h:122
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
LUID_AND_ATTRIBUTES Privilege[ANYSIZE_ARRAY]
Definition: setypes.h:88
$ULONG Control
Definition: setypes.h:87
$ULONG PrivilegeCount
Definition: setypes.h:86
WCHAR PathBuffer[1]
Definition: shellext.h:176
struct _REPARSE_DATA_BUFFER::@318::@320 SymbolicLinkReparseBuffer
USHORT ReparseDataLength
Definition: shellext.h:166
USHORT MaximumLength
Definition: env_spec_w32.h:370
CSHORT NodeSize
Definition: btrfs_drv.h:372
bool reserving
Definition: btrfs_drv.h:381
bool lxss
Definition: btrfs_drv.h:391
ULONG disposition
Definition: btrfs_drv.h:373
bool manage_volume_privilege
Definition: btrfs_drv.h:379
uint64_t query_dir_offset
Definition: btrfs_drv.h:375
ACCESS_MASK access
Definition: btrfs_drv.h:382
UNICODE_STRING query_string
Definition: btrfs_drv.h:376
USHORT NodeType
Definition: btrfs_drv.h:371
bool specific_file
Definition: btrfs_drv.h:378
file_ref * fileref
Definition: btrfs_drv.h:383
bool case_sensitive
Definition: btrfs_drv.h:386
bool has_wildcard
Definition: btrfs_drv.h:377
ULONG options
Definition: btrfs_drv.h:374
bool ads
Definition: btrfs_drv.h:330
LIST_ENTRY list_entry_all
Definition: btrfs_drv.h:337
ULONG ealen
Definition: btrfs_drv.h:303
LIST_ENTRY xattrs
Definition: btrfs_drv.h:308
LIST_ENTRY hardlinks
Definition: btrfs_drv.h:304
bool case_sensitive_set
Definition: btrfs_drv.h:311
FILE_LOCK lock
Definition: btrfs_drv.h:294
LIST_ENTRY dir_children_index
Definition: btrfs_drv.h:314
ULONG atts
Definition: btrfs_drv.h:297
bool atts_deleted
Definition: btrfs_drv.h:322
bool sd_dirty
Definition: btrfs_drv.h:321
bool deleted
Definition: btrfs_drv.h:295
POOL_TYPE pool_type
Definition: btrfs_drv.h:286
struct _file_ref * fileref
Definition: btrfs_drv.h:305
LIST_ENTRY extents
Definition: btrfs_drv.h:300
uint64_t inode
Definition: btrfs_drv.h:289
SECURITY_DESCRIPTOR * sd
Definition: btrfs_drv.h:293
bool case_sensitive
Definition: btrfs_drv.h:310
bool csum_loaded
Definition: btrfs_drv.h:299
ANSI_STRING adsdata
Definition: btrfs_drv.h:334
ANSI_STRING adsxattr
Definition: btrfs_drv.h:333
INODE_ITEM inode_item
Definition: btrfs_drv.h:292
bool created
Definition: btrfs_drv.h:328
LIST_ENTRY dir_children_hash
Definition: btrfs_drv.h:315
LIST_ENTRY ** hash_ptrs_uc
Definition: btrfs_drv.h:318
uint8_t type
Definition: btrfs_drv.h:291
struct _device_extension * Vcb
Definition: btrfs_drv.h:287
LIST_ENTRY dir_children_hash_uc
Definition: btrfs_drv.h:316
struct _root * subvol
Definition: btrfs_drv.h:288
ULONG adsmaxlen
Definition: btrfs_drv.h:332
LIST_ENTRY list_entry
Definition: btrfs_drv.h:336
ANSI_STRING reparse_xattr
Definition: btrfs_drv.h:301
LIST_ENTRY ** hash_ptrs
Definition: btrfs_drv.h:317
uint32_t hash
Definition: btrfs_drv.h:290
bool sd_deleted
Definition: btrfs_drv.h:321
uint32_t adshash
Definition: btrfs_drv.h:331
LONG refcount
Definition: btrfs_drv.h:285
bool atts_changed
Definition: btrfs_drv.h:322
enum prop_compression_type prop_compression
Definition: btrfs_drv.h:307
bool ea_changed
Definition: btrfs_drv.h:325
struct _fcb_nonpaged * nonpaged
Definition: btrfs_drv.h:284
SHARE_ACCESS share_access
Definition: btrfs_drv.h:298
ANSI_STRING ea_xattr
Definition: btrfs_drv.h:302
bool prop_compression_changed
Definition: btrfs_drv.h:326
bool inode_item_changed
Definition: btrfs_drv.h:306
FSRTL_ADVANCED_FCB_HEADER Header
Definition: btrfs_drv.h:283
bool deleted
Definition: btrfs_drv.h:347
LONG refcount
Definition: btrfs_drv.h:350
struct _file_ref * parent
Definition: btrfs_drv.h:352
fcb * fcb
Definition: btrfs_drv.h:342
dir_child * dc
Definition: btrfs_drv.h:353
LIST_ENTRY list_entry
Definition: btrfs_drv.h:357
LIST_ENTRY children
Definition: btrfs_drv.h:349
LONG open_count
Definition: btrfs_drv.h:351
bool delete_on_close
Definition: btrfs_drv.h:345
uint64_t id
Definition: btrfs_drv.h:451
uint64_t parent
Definition: btrfs_drv.h:459
uint8_t * data
Definition: btrfs_drv.h:415
uint16_t size
Definition: btrfs_drv.h:414
Definition: ffs.h:52
char * name
Definition: compiler.c:66
Definition: devices.h:37
UNICODE_STRING name
Definition: btrfs_drv.h:256
UNICODE_STRING name_uc
Definition: btrfs_drv.h:258
ANSI_STRING utf8
Definition: btrfs_drv.h:254
uint8_t type
Definition: btrfs_drv.h:253
struct _file_ref * fileref
Definition: btrfs_drv.h:260
uint64_t index
Definition: btrfs_drv.h:252
Definition: _hash_fun.h:40
Definition: fs.h:78
Definition: copy.c:22
Definition: list.h:27
LIST_ENTRY list_entry
Definition: btrfs_drv.h:956
UNICODE_STRING us
Definition: btrfs_drv.h:955
Definition: name.c:39
device_extension * Vcb
Definition: create.c:84
file_ref * fileref
Definition: create.c:86
ACCESS_MASK granted_access
Definition: create.c:85
NTSTATUS Status
Definition: create.c:87
KEVENT event
Definition: create.c:88
Definition: parse.h:23
tree_data * item
Definition: btrfs_drv.h:509
tree * tree
Definition: btrfs_drv.h:508
bool dirty
Definition: btrfs_drv.h:278
USHORT namelen
Definition: btrfs_drv.h:276
char data[1]
Definition: btrfs_drv.h:279
USHORT valuelen
Definition: btrfs_drv.h:277
LIST_ENTRY list_entry
Definition: btrfs_drv.h:275
VOID NTAPI SeLockSubjectContext(_In_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
Locks both the referenced primary and client access tokens of a security subject context.
Definition: subject.c:107
VOID NTAPI SeUnlockSubjectContext(_In_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
Unlocks both the referenced primary and client access tokens of a security subject context.
Definition: subject.c:138
#define max(a, b)
Definition: svc.c:63
INT POOL_TYPE
Definition: typedefs.h:78
int64_t LONGLONG
Definition: typedefs.h:68
#define __stdcall
Definition: typedefs.h:25
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define IN
Definition: typedefs.h:39
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_FILE_IS_A_DIRECTORY
Definition: udferr_usr.h:164
#define STATUS_NOT_A_DIRECTORY
Definition: udferr_usr.h:169
#define STATUS_MEDIA_WRITE_PROTECTED
Definition: udferr_usr.h:161
#define STATUS_ACCESS_DENIED
Definition: udferr_usr.h:145
#define STATUS_OBJECT_PATH_NOT_FOUND
Definition: udferr_usr.h:151
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_OBJECT_NAME_COLLISION
Definition: udferr_usr.h:150
#define STATUS_VERIFY_REQUIRED
Definition: udferr_usr.h:130
#define STATUS_SHARING_VIOLATION
Definition: udferr_usr.h:154
#define STATUS_DISK_FULL
Definition: udferr_usr.h:155
#define STATUS_OBJECT_NAME_INVALID
Definition: udferr_usr.h:148
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
_In_ WDFREQUEST _In_ WDFFILEOBJECT FileObject
Definition: wdfdevice.h:550
static GLenum _GLUfuncptr fn
Definition: wgl_font.c:159
_Inout_ PERBANDINFO * pbi
Definition: winddi.h:3917
#define ExIsResourceAcquiredExclusive
Definition: exfuncs.h:347
FORCEINLINE VOID ExInitializeFastMutex(_Out_ PFAST_MUTEX FastMutex)
Definition: exfuncs.h:274
#define IoIsErrorUserInduced(Status)
Definition: iofuncs.h:2817
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2793
#define SL_OPEN_PAGING_FILE
Definition: iotypes.h:1817
#define FILE_NOTIFY_CHANGE_SIZE
#define VPB_MOUNTED
Definition: iotypes.h:1807
#define FILE_ACTION_MODIFIED
#define FILE_DISALLOW_EXCLUSIVE
#define IO_NO_INCREMENT
Definition: iotypes.h:598
#define SL_FORCE_ACCESS_CHECK
Definition: iotypes.h:1816
#define FILE_NOTIFY_CHANGE_STREAM_NAME
#define FILE_ACTION_REMOVED_STREAM
#define FILE_NOTIFY_CHANGE_ATTRIBUTES
#define FILE_NEED_EA
#define FILE_NOTIFY_CHANGE_FILE_NAME
* PFILE_OBJECT
Definition: iotypes.h:1998
#define SL_STOP_ON_SYMLINK
Definition: iotypes.h:1819
#define IO_DISK_INCREMENT
Definition: iotypes.h:600
#define IO_REPARSE_TAG_SYMLINK
Definition: iotypes.h:7240
#define FO_CACHE_SUPPORTED
Definition: iotypes.h:1781
#define FILE_ACTION_ADDED_STREAM
#define FILE_NOTIFY_CHANGE_LAST_WRITE
#define SL_OPEN_TARGET_DIRECTORY
Definition: iotypes.h:1818
#define FILE_ACTION_ADDED
#define FILE_NOTIFY_CHANGE_DIR_NAME
#define SL_CASE_SENSITIVE
Definition: iotypes.h:1820
@ Executive
Definition: ketypes.h:415
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
#define PRIVILEGE_SET_ALL_NECESSARY
Definition: setypes.h:83
unsigned char UCHAR
Definition: xmlstorage.h:181
__wchar_t WCHAR
Definition: xmlstorage.h:180