ReactOS  0.4.13-dev-92-gf251225
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 <ntddstor.h>
23 
25 
26 static const WCHAR datastring[] = L"::$DATA";
27 
28 // Windows 10
29 #define ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED 0x0002
30 #define ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT 0x0100
31 #define ATOMIC_CREATE_ECP_OUT_FLAG_REPARSE_POINT_SET 0x0002
32 
42 
43 static const GUID GUID_ECP_ATOMIC_CREATE = { 0x4720bd83, 0x52ac, 0x4104, { 0xa1, 0x30, 0xd1, 0xec, 0x6a, 0x8c, 0xc8, 0xe5 } };
44 
46  fcb* fcb;
47 
48  if (pool_type == NonPagedPool) {
49  fcb = ExAllocatePoolWithTag(pool_type, sizeof(struct _fcb), ALLOC_TAG);
50  if (!fcb) {
51  ERR("out of memory\n");
52  return NULL;
53  }
54  } else {
55  fcb = ExAllocateFromPagedLookasideList(&Vcb->fcb_lookaside);
56  if (!fcb) {
57  ERR("out of memory\n");
58  return NULL;
59  }
60  }
61 
62 #ifdef DEBUG_FCB_REFCOUNTS
63  WARN("allocating fcb %p\n", fcb);
64 #endif
65  RtlZeroMemory(fcb, sizeof(struct _fcb));
66  fcb->pool_type = pool_type;
67 
68  fcb->Header.NodeTypeCode = BTRFS_NODE_TYPE_FCB;
69  fcb->Header.NodeByteSize = sizeof(struct _fcb);
70 
71  fcb->nonpaged = ExAllocateFromNPagedLookasideList(&Vcb->fcb_np_lookaside);
72  if (!fcb->nonpaged) {
73  ERR("out of memory\n");
74 
75  if (pool_type == NonPagedPool)
76  ExFreePool(fcb);
77  else
78  ExFreeToPagedLookasideList(&Vcb->fcb_lookaside, fcb);
79 
80  return NULL;
81  }
82  RtlZeroMemory(fcb->nonpaged, sizeof(struct _fcb_nonpaged));
83 
84  ExInitializeResourceLite(&fcb->nonpaged->paging_resource);
85  fcb->Header.PagingIoResource = &fcb->nonpaged->paging_resource;
86 
87  ExInitializeFastMutex(&fcb->nonpaged->HeaderMutex);
88  FsRtlSetupAdvancedHeader(&fcb->Header, &fcb->nonpaged->HeaderMutex);
89 
90  fcb->refcount = 1;
91 #ifdef DEBUG_FCB_REFCOUNTS
92  WARN("fcb %p: refcount now %i\n", fcb, fcb->refcount);
93 #endif
94 
96  fcb->Header.Resource = &fcb->nonpaged->resource;
97 
98  ExInitializeResourceLite(&fcb->nonpaged->dir_children_lock);
99 
101 
105 
109 
110  return fcb;
111 }
112 
114  file_ref* fr;
115 
116  fr = ExAllocateFromPagedLookasideList(&Vcb->fileref_lookaside);
117  if (!fr) {
118  ERR("out of memory\n");
119  return NULL;
120  }
121 
122  RtlZeroMemory(fr, sizeof(file_ref));
123 
124  fr->nonpaged = ExAllocateFromNPagedLookasideList(&Vcb->fileref_np_lookaside);
125  if (!fr->nonpaged) {
126  ERR("out of memory\n");
127  ExFreeToPagedLookasideList(&Vcb->fileref_lookaside, fr);
128  return NULL;
129  }
130 
131  fr->refcount = 1;
132 
133 #ifdef DEBUG_FCB_REFCOUNTS
134  WARN("fileref %p: refcount now 1\n", fr);
135 #endif
136 
138 
141 
142  return fr;
143 }
144 
147  UNICODE_STRING fnus;
148  UINT32 hash;
149  LIST_ENTRY* le;
150  UINT8 c;
151  BOOL locked = FALSE;
152 
153  if (!case_sensitive) {
155 
156  if (!NT_SUCCESS(Status)) {
157  ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
158  return Status;
159  }
160  } else
161  fnus = *filename;
162 
163  hash = calc_crc32c(0xffffffff, (UINT8*)fnus.Buffer, fnus.Length);
164 
165  c = hash >> 24;
166 
167  if (!ExIsResourceAcquiredSharedLite(&fcb->nonpaged->dir_children_lock)) {
168  ExAcquireResourceSharedLite(&fcb->nonpaged->dir_children_lock, TRUE);
169  locked = TRUE;
170  }
171 
172  if (case_sensitive) {
173  if (!fcb->hash_ptrs[c]) {
175  goto end;
176  }
177 
178  le = fcb->hash_ptrs[c];
179  while (le != &fcb->dir_children_hash) {
180  dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_hash);
181 
182  if (dc->hash == hash) {
183  if (dc->name.Length == fnus.Length && RtlCompareMemory(dc->name.Buffer, fnus.Buffer, fnus.Length) == fnus.Length) {
184  if (dc->key.obj_type == TYPE_ROOT_ITEM) {
185  LIST_ENTRY* le2;
186 
187  *subvol = NULL;
188 
189  le2 = fcb->Vcb->roots.Flink;
190  while (le2 != &fcb->Vcb->roots) {
192 
193  if (r2->id == dc->key.obj_id) {
194  *subvol = r2;
195  break;
196  }
197 
198  le2 = le2->Flink;
199  }
200 
202  } else {
203  *subvol = fcb->subvol;
204  *inode = dc->key.obj_id;
205  }
206 
207  *pdc = dc;
208 
210  goto end;
211  }
212  } else if (dc->hash > hash) {
214  goto end;
215  }
216 
217  le = le->Flink;
218  }
219  } else {
220  if (!fcb->hash_ptrs_uc[c]) {
222  goto end;
223  }
224 
225  le = fcb->hash_ptrs_uc[c];
226  while (le != &fcb->dir_children_hash_uc) {
227  dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_hash_uc);
228 
229  if (dc->hash_uc == hash) {
230  if (dc->name_uc.Length == fnus.Length && RtlCompareMemory(dc->name_uc.Buffer, fnus.Buffer, fnus.Length) == fnus.Length) {
231  if (dc->key.obj_type == TYPE_ROOT_ITEM) {
232  LIST_ENTRY* le2;
233 
234  *subvol = NULL;
235 
236  le2 = fcb->Vcb->roots.Flink;
237  while (le2 != &fcb->Vcb->roots) {
239 
240  if (r2->id == dc->key.obj_id) {
241  *subvol = r2;
242  break;
243  }
244 
245  le2 = le2->Flink;
246  }
247 
249  } else {
250  *subvol = fcb->subvol;
251  *inode = dc->key.obj_id;
252  }
253 
254  *pdc = dc;
255 
257  goto end;
258  }
259  } else if (dc->hash_uc > hash) {
261  goto end;
262  }
263 
264  le = le->Flink;
265  }
266  }
267 
269 
270 end:
271  if (locked)
272  ExReleaseResourceLite(&fcb->nonpaged->dir_children_lock);
273 
274  if (!case_sensitive)
275  ExFreePool(fnus.Buffer);
276 
277  return Status;
278 }
279 
281  ULONG len, i;
282  BOOL has_stream;
283  WCHAR* buf;
284  name_bit* nb;
285 
286  len = path->Length / sizeof(WCHAR);
287  if (len > 0 && (path->Buffer[len - 1] == '/' || path->Buffer[len - 1] == '\\'))
288  len--;
289 
290  has_stream = FALSE;
291  for (i = 0; i < len; i++) {
292  if (path->Buffer[i] == '/' || path->Buffer[i] == '\\') {
293  has_stream = FALSE;
294  } else if (path->Buffer[i] == ':') {
295  has_stream = TRUE;
296  }
297  }
298 
299  buf = path->Buffer;
300 
301  for (i = 0; i < len; i++) {
302  if (path->Buffer[i] == '/' || path->Buffer[i] == '\\') {
303  nb = ExAllocateFromPagedLookasideList(&Vcb->name_bit_lookaside);
304  if (!nb) {
305  ERR("out of memory\n");
307  }
308 
309  nb->us.Buffer = buf;
310  nb->us.Length = nb->us.MaximumLength = (USHORT)(&path->Buffer[i] - buf) * sizeof(WCHAR);
311  InsertTailList(parts, &nb->list_entry);
312 
313  buf = &path->Buffer[i+1];
314  }
315  }
316 
317  nb = ExAllocateFromPagedLookasideList(&Vcb->name_bit_lookaside);
318  if (!nb) {
319  ERR("out of memory\n");
321  }
322 
323  nb->us.Buffer = buf;
324  nb->us.Length = nb->us.MaximumLength = (USHORT)(&path->Buffer[i] - buf) * sizeof(WCHAR);
325  InsertTailList(parts, &nb->list_entry);
326 
327  if (has_stream) {
328  static const WCHAR datasuf[] = {':','$','D','A','T','A',0};
329  UNICODE_STRING dsus;
330 
331  dsus.Buffer = (WCHAR*)datasuf;
332  dsus.Length = dsus.MaximumLength = sizeof(datasuf) - sizeof(WCHAR);
333 
334  for (i = 0; i < nb->us.Length / sizeof(WCHAR); i++) {
335  if (nb->us.Buffer[i] == ':') {
336  name_bit* nb2;
337 
338  nb2 = ExAllocateFromPagedLookasideList(&Vcb->name_bit_lookaside);
339  if (!nb2) {
340  ERR("out of memory\n");
342  }
343 
344  nb2->us.Buffer = &nb->us.Buffer[i+1];
345  nb2->us.Length = nb2->us.MaximumLength = (UINT16)(nb->us.Length - (i * sizeof(WCHAR)) - sizeof(WCHAR));
346  InsertTailList(parts, &nb2->list_entry);
347 
348  nb->us.Length = (UINT16)i * sizeof(WCHAR);
349  nb->us.MaximumLength = nb->us.Length;
350 
351  nb = nb2;
352 
353  break;
354  }
355  }
356 
357  // FIXME - should comparison be case-insensitive?
358  // remove :$DATA suffix
359  if (nb->us.Length >= dsus.Length && RtlCompareMemory(&nb->us.Buffer[(nb->us.Length - dsus.Length)/sizeof(WCHAR)], dsus.Buffer, dsus.Length) == dsus.Length)
360  nb->us.Length -= dsus.Length;
361 
362  if (nb->us.Length == 0) {
363  RemoveTailList(parts);
364  ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb);
365 
366  has_stream = FALSE;
367  }
368  }
369 
370  // if path is just stream name, remove first empty item
371  if (has_stream && path->Length >= sizeof(WCHAR) && path->Buffer[0] == ':') {
373 
374  ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb1);
375  }
376 
377  *stream = has_stream;
378 
379  return STATUS_SUCCESS;
380 }
381 
384  KEY searchkey;
385  traverse_ptr tp, next_tp;
386  UINT64 i, j;
387  BOOL b;
388 
389  searchkey.obj_id = EXTENT_CSUM_ID;
390  searchkey.obj_type = TYPE_EXTENT_CSUM;
391  searchkey.offset = start;
392 
393  Status = find_item(Vcb, Vcb->checksum_root, &tp, &searchkey, FALSE, Irp);
394  if (!NT_SUCCESS(Status)) {
395  ERR("error - find_item returned %08x\n", Status);
396  return Status;
397  }
398 
399  i = 0;
400  do {
401  if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
402  ULONG readlen;
403 
404  if (start < tp.item->key.offset)
405  j = 0;
406  else
407  j = ((start - tp.item->key.offset) / Vcb->superblock.sector_size) + i;
408 
409  if (j * sizeof(UINT32) > tp.item->size || tp.item->key.offset > start + (i * Vcb->superblock.sector_size)) {
410  ERR("checksum not found for %llx\n", start + (i * Vcb->superblock.sector_size));
411  return STATUS_INTERNAL_ERROR;
412  }
413 
414  readlen = (ULONG)min((tp.item->size / sizeof(UINT32)) - j, length - i);
415  RtlCopyMemory(&csum[i], tp.item->data + (j * sizeof(UINT32)), readlen * sizeof(UINT32));
416  i += readlen;
417 
418  if (i == length)
419  break;
420  }
421 
422  b = find_next_item(Vcb, &tp, &next_tp, FALSE, Irp);
423 
424  if (b)
425  tp = next_tp;
426  } while (b);
427 
428  if (i < length) {
429  ERR("could not read checksums: offset %llx, length %llx sectors\n", start, length);
430  return STATUS_INTERNAL_ERROR;
431  }
432 
433  return STATUS_SUCCESS;
434 }
435 
437  KEY searchkey;
438  traverse_ptr tp, next_tp;
440  ULONG num_children = 0;
441 
443  if (!fcb->hash_ptrs) {
444  ERR("out of memory\n");
446  }
447 
448  RtlZeroMemory(fcb->hash_ptrs, sizeof(LIST_ENTRY*) * 256);
449 
451  if (!fcb->hash_ptrs_uc) {
452  ERR("out of memory\n");
454  }
455 
456  RtlZeroMemory(fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256);
457 
458  if (!ignore_size && fcb->inode_item.st_size == 0)
459  return STATUS_SUCCESS;
460 
461  searchkey.obj_id = fcb->inode;
462  searchkey.obj_type = TYPE_DIR_INDEX;
463  searchkey.offset = 2;
464 
465  Status = find_item(Vcb, fcb->subvol, &tp, &searchkey, FALSE, Irp);
466  if (!NT_SUCCESS(Status)) {
467  ERR("find_item returned %08x\n", Status);
468  return Status;
469  }
470 
471  if (keycmp(tp.item->key, searchkey) == -1) {
472  if (find_next_item(Vcb, &tp, &next_tp, FALSE, Irp)) {
473  tp = next_tp;
474  TRACE("moving on to %llx,%x,%llx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
475  }
476  }
477 
478  while (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
479  DIR_ITEM* di = (DIR_ITEM*)tp.item->data;
480  dir_child* dc;
481  ULONG utf16len;
482 
483  if (tp.item->size < sizeof(DIR_ITEM)) {
484  WARN("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(DIR_ITEM));
485  goto cont;
486  }
487 
488  if (di->n == 0) {
489  WARN("(%llx,%x,%llx): DIR_ITEM name length is zero\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
490  goto cont;
491  }
492 
493  Status = RtlUTF8ToUnicodeN(NULL, 0, &utf16len, di->name, di->n);
494  if (!NT_SUCCESS(Status)) {
495  ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
496  goto cont;
497  }
498 
500  if (!dc) {
501  ERR("out of memory\n");
503  }
504 
505  dc->key = di->key;
506  dc->index = tp.item->key.offset;
507  dc->type = di->type;
508  dc->fileref = NULL;
509 
510  dc->utf8.MaximumLength = dc->utf8.Length = di->n;
511  dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, di->n, ALLOC_TAG);
512  if (!dc->utf8.Buffer) {
513  ERR("out of memory\n");
514  ExFreePool(dc);
516  }
517 
518  RtlCopyMemory(dc->utf8.Buffer, di->name, di->n);
519 
520  dc->name.MaximumLength = dc->name.Length = (UINT16)utf16len;
521  dc->name.Buffer = ExAllocatePoolWithTag(PagedPool, dc->name.MaximumLength, ALLOC_TAG);
522  if (!dc->name.Buffer) {
523  ERR("out of memory\n");
524  ExFreePool(dc->utf8.Buffer);
525  ExFreePool(dc);
527  }
528 
529  Status = RtlUTF8ToUnicodeN(dc->name.Buffer, utf16len, &utf16len, di->name, di->n);
530  if (!NT_SUCCESS(Status)) {
531  ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
532  ExFreePool(dc->utf8.Buffer);
533  ExFreePool(dc->name.Buffer);
534  ExFreePool(dc);
535  goto cont;
536  }
537 
538  Status = RtlUpcaseUnicodeString(&dc->name_uc, &dc->name, TRUE);
539  if (!NT_SUCCESS(Status)) {
540  ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
541  ExFreePool(dc->utf8.Buffer);
542  ExFreePool(dc->name.Buffer);
543  ExFreePool(dc);
544  goto cont;
545  }
546 
547  dc->hash = calc_crc32c(0xffffffff, (UINT8*)dc->name.Buffer, dc->name.Length);
548  dc->hash_uc = calc_crc32c(0xffffffff, (UINT8*)dc->name_uc.Buffer, dc->name_uc.Length);
549 
550  InsertTailList(&fcb->dir_children_index, &dc->list_entry_index);
551 
553 
554  num_children++;
555 
556 cont:
557  if (find_next_item(Vcb, &tp, &next_tp, FALSE, Irp))
558  tp = next_tp;
559  else
560  break;
561  }
562 
563  // If a directory has a lot of files, force it to stick around until the next flush
564  // so we aren't constantly re-reading.
565  if (num_children >= 100)
567 
568  return STATUS_SUCCESS;
569 }
570 
572  root* subvol, UINT64 inode, UINT8 type, PANSI_STRING utf8, fcb* parent, fcb** pfcb, POOL_TYPE pooltype, PIRP Irp) {
573  KEY searchkey;
574  traverse_ptr tp, next_tp;
576  fcb *fcb, *deleted_fcb = NULL;
577  BOOL atts_set = FALSE, sd_set = FALSE, no_data;
578  LIST_ENTRY* lastle = NULL;
579  EXTENT_DATA* ed = NULL;
580 
581  if (!IsListEmpty(&subvol->fcbs)) {
582  LIST_ENTRY* le = subvol->fcbs.Flink;
583 
584  while (le != &subvol->fcbs) {
585  fcb = CONTAINING_RECORD(le, struct _fcb, list_entry);
586 
587  if (fcb->inode == inode) {
588  if (!fcb->ads) {
589  if (fcb->deleted)
590  deleted_fcb = fcb;
591  else {
592 #ifdef DEBUG_FCB_REFCOUNTS
594 
595  WARN("fcb %p: refcount now %i (subvol %llx, inode %llx)\n", fcb, rc, fcb->subvol->id, fcb->inode);
596 #else
598 #endif
599 
600  *pfcb = fcb;
601  return STATUS_SUCCESS;
602  }
603  }
604  } else if (fcb->inode > inode) {
605  if (deleted_fcb) {
606  InterlockedIncrement(&deleted_fcb->refcount);
607  *pfcb = deleted_fcb;
608  return STATUS_SUCCESS;
609  }
610 
611  lastle = le->Blink;
612  break;
613  }
614 
615  le = le->Flink;
616  }
617  }
618 
619  if (deleted_fcb) {
620  InterlockedIncrement(&deleted_fcb->refcount);
621  *pfcb = deleted_fcb;
622  return STATUS_SUCCESS;
623  }
624 
625  fcb = create_fcb(Vcb, pooltype);
626  if (!fcb) {
627  ERR("out of memory\n");
629  }
630 
631  fcb->Vcb = Vcb;
632 
633  fcb->subvol = subvol;
634  fcb->inode = inode;
635  fcb->type = type;
636 
637  searchkey.obj_id = inode;
638  searchkey.obj_type = TYPE_INODE_ITEM;
639  searchkey.offset = 0xffffffffffffffff;
640 
641  Status = find_item(Vcb, subvol, &tp, &searchkey, FALSE, Irp);
642  if (!NT_SUCCESS(Status)) {
643  ERR("error - find_item returned %08x\n", Status);
644  free_fcb(Vcb, fcb);
645  return Status;
646  }
647 
648  if (tp.item->key.obj_id != searchkey.obj_id || tp.item->key.obj_type != searchkey.obj_type) {
649  WARN("couldn't find INODE_ITEM for inode %llx in subvol %llx\n", inode, subvol->id);
650  free_fcb(Vcb, fcb);
652  }
653 
654  if (tp.item->size > 0)
656 
657  if (fcb->type == 0) { // guess the type from the inode mode, if the caller doesn't know already
660  else if ((fcb->inode_item.st_mode & __S_IFCHR) == __S_IFCHR)
662  else if ((fcb->inode_item.st_mode & __S_IFBLK) == __S_IFBLK)
664  else if ((fcb->inode_item.st_mode & __S_IFIFO) == __S_IFIFO)
666  else if ((fcb->inode_item.st_mode & __S_IFLNK) == __S_IFLNK)
668  else if ((fcb->inode_item.st_mode & __S_IFSOCK) == __S_IFSOCK)
670  else
672  }
673 
674  no_data = fcb->inode_item.st_size == 0 || (fcb->type != BTRFS_TYPE_FILE && fcb->type != BTRFS_TYPE_SYMLINK);
675 
676  while (find_next_item(Vcb, &tp, &next_tp, FALSE, Irp)) {
677  tp = next_tp;
678 
679  if (tp.item->key.obj_id > inode)
680  break;
681 
683  break;
684 
686  ULONG len;
687  INODE_REF* ir;
688 
689  len = tp.item->size;
690  ir = (INODE_REF*)tp.item->data;
691 
692  while (len >= sizeof(INODE_REF) - 1) {
693  hardlink* hl;
695 
696  hl = ExAllocatePoolWithTag(pooltype, sizeof(hardlink), ALLOC_TAG);
697  if (!hl) {
698  ERR("out of memory\n");
699  free_fcb(Vcb, fcb);
701  }
702 
703  hl->parent = tp.item->key.offset;
704  hl->index = ir->index;
705 
706  hl->utf8.Length = hl->utf8.MaximumLength = ir->n;
707 
708  if (hl->utf8.Length > 0) {
710  RtlCopyMemory(hl->utf8.Buffer, ir->name, ir->n);
711  }
712 
713  Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, ir->name, ir->n);
714  if (!NT_SUCCESS(Status)) {
715  ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
716  ExFreePool(hl);
717  free_fcb(Vcb, fcb);
718  return Status;
719  }
720 
722 
723  if (stringlen == 0)
724  hl->name.Buffer = NULL;
725  else {
727 
728  if (!hl->name.Buffer) {
729  ERR("out of memory\n");
730  ExFreePool(hl);
731  free_fcb(Vcb, fcb);
733  }
734 
736  if (!NT_SUCCESS(Status)) {
737  ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
738  ExFreePool(hl->name.Buffer);
739  ExFreePool(hl);
740  free_fcb(Vcb, fcb);
741  return Status;
742  }
743  }
744 
746 
747  len -= sizeof(INODE_REF) - 1 + ir->n;
748  ir = (INODE_REF*)&ir->name[ir->n];
749  }
750  } else if (fcb->inode_item.st_nlink > 1 && tp.item->key.obj_type == TYPE_INODE_EXTREF) {
751  ULONG len;
752  INODE_EXTREF* ier;
753 
754  len = tp.item->size;
755  ier = (INODE_EXTREF*)tp.item->data;
756 
757  while (len >= sizeof(INODE_EXTREF) - 1) {
758  hardlink* hl;
760 
761  hl = ExAllocatePoolWithTag(pooltype, sizeof(hardlink), ALLOC_TAG);
762  if (!hl) {
763  ERR("out of memory\n");
764  free_fcb(Vcb, fcb);
766  }
767 
768  hl->parent = ier->dir;
769  hl->index = ier->index;
770 
771  hl->utf8.Length = hl->utf8.MaximumLength = ier->n;
772 
773  if (hl->utf8.Length > 0) {
775  RtlCopyMemory(hl->utf8.Buffer, ier->name, ier->n);
776  }
777 
778  Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, ier->name, ier->n);
779  if (!NT_SUCCESS(Status)) {
780  ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
781  ExFreePool(hl);
782  free_fcb(Vcb, fcb);
783  return Status;
784  }
785 
787 
788  if (stringlen == 0)
789  hl->name.Buffer = NULL;
790  else {
792 
793  if (!hl->name.Buffer) {
794  ERR("out of memory\n");
795  ExFreePool(hl);
796  free_fcb(Vcb, fcb);
798  }
799 
801  if (!NT_SUCCESS(Status)) {
802  ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
803  ExFreePool(hl->name.Buffer);
804  ExFreePool(hl);
805  free_fcb(Vcb, fcb);
806  return Status;
807  }
808  }
809 
811 
812  len -= sizeof(INODE_EXTREF) - 1 + ier->n;
813  ier = (INODE_EXTREF*)&ier->name[ier->n];
814  }
815  } else if (tp.item->key.obj_type == TYPE_XATTR_ITEM) {
816  ULONG len;
817  DIR_ITEM* di;
818 
819  static const char xapref[] = "user.";
820 
821  if (tp.item->size < offsetof(DIR_ITEM, name[0])) {
822  ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, offsetof(DIR_ITEM, name[0]));
823  continue;
824  }
825 
826  len = tp.item->size;
827  di = (DIR_ITEM*)tp.item->data;
828 
829  do {
830  if (len < offsetof(DIR_ITEM, name[0]) + di->m + di->n)
831  break;
832 
833  if (tp.item->key.offset == EA_REPARSE_HASH && di->n == sizeof(EA_REPARSE) - 1 && RtlCompareMemory(EA_REPARSE, di->name, di->n) == di->n) {
834  if (di->m > 0) {
836  if (!fcb->reparse_xattr.Buffer) {
837  ERR("out of memory\n");
838  free_fcb(Vcb, fcb);
840  }
841 
842  RtlCopyMemory(fcb->reparse_xattr.Buffer, &di->name[di->n], di->m);
843  } else
845 
847  } else if (tp.item->key.offset == EA_EA_HASH && di->n == sizeof(EA_EA) - 1 && RtlCompareMemory(EA_EA, di->name, di->n) == di->n) {
848  if (di->m > 0) {
849  ULONG offset;
850 
852 
853  if (!NT_SUCCESS(Status))
854  WARN("IoCheckEaBufferValidity returned %08x (error at offset %u)\n", Status, offset);
855  else {
856  FILE_FULL_EA_INFORMATION* eainfo;
857 
859  if (!fcb->ea_xattr.Buffer) {
860  ERR("out of memory\n");
861  free_fcb(Vcb, fcb);
863  }
864 
865  RtlCopyMemory(fcb->ea_xattr.Buffer, &di->name[di->n], di->m);
866 
868 
869  fcb->ealen = 4;
870 
871  // calculate ealen
872  eainfo = (FILE_FULL_EA_INFORMATION*)&di->name[di->n];
873  do {
874  fcb->ealen += 5 + eainfo->EaNameLength + eainfo->EaValueLength;
875 
876  if (eainfo->NextEntryOffset == 0)
877  break;
878 
879  eainfo = (FILE_FULL_EA_INFORMATION*)(((UINT8*)eainfo) + eainfo->NextEntryOffset);
880  } while (TRUE);
881  }
882  }
883  } else if (tp.item->key.offset == EA_DOSATTRIB_HASH && di->n == sizeof(EA_DOSATTRIB) - 1 && RtlCompareMemory(EA_DOSATTRIB, di->name, di->n) == di->n) {
884  if (di->m > 0) {
885  if (get_file_attributes_from_xattr(&di->name[di->n], di->m, &fcb->atts)) {
886  atts_set = TRUE;
887 
888  if (fcb->type == BTRFS_TYPE_DIRECTORY)
890  else if (fcb->type == BTRFS_TYPE_SYMLINK)
892 
893  if (fcb->type != BTRFS_TYPE_DIRECTORY)
895 
896  if (inode == SUBVOL_ROOT_INODE) {
897  if (subvol->root_item.flags & BTRFS_SUBVOL_READONLY)
899  else
901  }
902  }
903  }
904  } else if (tp.item->key.offset == EA_NTACL_HASH && di->n == sizeof(EA_NTACL) - 1 && RtlCompareMemory(EA_NTACL, di->name, di->n) == di->n) {
905  if (di->m > 0) {
907  if (!fcb->sd) {
908  ERR("out of memory\n");
909  free_fcb(Vcb, fcb);
911  }
912 
913  RtlCopyMemory(fcb->sd, &di->name[di->n], di->m);
914 
915  // We have to test against our copy rather than the source, as RtlValidRelativeSecurityDescriptor
916  // will fail if the ACLs aren't 32-bit aligned.
917  if (!RtlValidRelativeSecurityDescriptor(fcb->sd, di->m, 0))
918  ExFreePool(fcb->sd);
919  else
920  sd_set = TRUE;
921  }
922  } 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) {
923  if (di->m > 0) {
924  static const char lzo[] = "lzo";
925  static const char zlib[] = "zlib";
926  static const char zstd[] = "zstd";
927 
928  if (di->m == sizeof(lzo) - 1 && RtlCompareMemory(&di->name[di->n], lzo, di->m) == di->m)
930  else if (di->m == sizeof(zlib) - 1 && RtlCompareMemory(&di->name[di->n], zlib, di->m) == di->m)
932  else if (di->m == sizeof(zstd) - 1 && RtlCompareMemory(&di->name[di->n], zstd, di->m) == di->m)
934  else
936  }
937  } else if (di->n > sizeof(xapref) - 1 && RtlCompareMemory(xapref, di->name, sizeof(xapref) - 1) == sizeof(xapref) - 1) {
938  dir_child* dc;
939  ULONG utf16len;
940 
941  Status = RtlUTF8ToUnicodeN(NULL, 0, &utf16len, &di->name[sizeof(xapref) - 1], di->n + 1 - sizeof(xapref));
942  if (!NT_SUCCESS(Status)) {
943  ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
944  free_fcb(Vcb, fcb);
945  return Status;
946  }
947 
949  if (!dc) {
950  ERR("out of memory\n");
951  free_fcb(Vcb, fcb);
953  }
954 
955  RtlZeroMemory(dc, sizeof(dir_child));
956 
957  dc->utf8.MaximumLength = dc->utf8.Length = di->n + 1 - sizeof(xapref);
958  dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, dc->utf8.MaximumLength, ALLOC_TAG);
959  if (!dc->utf8.Buffer) {
960  ERR("out of memory\n");
961  ExFreePool(dc);
962  free_fcb(Vcb, fcb);
964  }
965 
966  RtlCopyMemory(dc->utf8.Buffer, &di->name[sizeof(xapref) - 1], dc->utf8.Length);
967 
968  dc->name.MaximumLength = dc->name.Length = (UINT16)utf16len;
969  dc->name.Buffer = ExAllocatePoolWithTag(PagedPool, dc->name.MaximumLength, ALLOC_TAG);
970  if (!dc->name.Buffer) {
971  ERR("out of memory\n");
972  ExFreePool(dc->utf8.Buffer);
973  ExFreePool(dc);
974  free_fcb(Vcb, fcb);
976  }
977 
978  Status = RtlUTF8ToUnicodeN(dc->name.Buffer, utf16len, &utf16len, dc->utf8.Buffer, dc->utf8.Length);
979  if (!NT_SUCCESS(Status)) {
980  ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
981  ExFreePool(dc->utf8.Buffer);
982  ExFreePool(dc->name.Buffer);
983  ExFreePool(dc);
984  free_fcb(Vcb, fcb);
985  return Status;
986  }
987 
988  Status = RtlUpcaseUnicodeString(&dc->name_uc, &dc->name, TRUE);
989  if (!NT_SUCCESS(Status)) {
990  ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
991  ExFreePool(dc->utf8.Buffer);
992  ExFreePool(dc->name.Buffer);
993  ExFreePool(dc);
994  free_fcb(Vcb, fcb);
995  return Status;
996  }
997 
998  dc->size = di->m;
999 
1000  InsertTailList(&fcb->dir_children_index, &dc->list_entry_index);
1001  } else {
1002  xattr* xa;
1003 
1004  xa = ExAllocatePoolWithTag(PagedPool, offsetof(xattr, data[0]) + di->m + di->n, ALLOC_TAG);
1005  if (!xa) {
1006  ERR("out of memory\n");
1007  free_fcb(Vcb, fcb);
1009  }
1010 
1011  xa->namelen = di->n;
1012  xa->valuelen = di->m;
1013  xa->dirty = FALSE;
1014  RtlCopyMemory(xa->data, di->name, di->m + di->n);
1015 
1017  }
1018 
1019  len -= (ULONG)offsetof(DIR_ITEM, name[0]) + di->m + di->n;
1020 
1021  if (len < offsetof(DIR_ITEM, name[0]))
1022  break;
1023 
1024  di = (DIR_ITEM*)&di->name[di->m + di->n];
1025  } while (TRUE);
1026  } else if (tp.item->key.obj_type == TYPE_EXTENT_DATA) {
1027  extent* ext;
1028  BOOL unique = FALSE;
1029 
1030  ed = (EXTENT_DATA*)tp.item->data;
1031 
1032  if (tp.item->size < sizeof(EXTENT_DATA)) {
1033  ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset,
1034  tp.item->size, sizeof(EXTENT_DATA));
1035 
1036  free_fcb(Vcb, fcb);
1037  return STATUS_INTERNAL_ERROR;
1038  }
1039 
1041  EXTENT_DATA2* ed2 = (EXTENT_DATA2*)&ed->data[0];
1042 
1043  if (tp.item->size < sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2)) {
1044  ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset,
1045  tp.item->size, sizeof(EXTENT_DATA) - 1 + sizeof(EXTENT_DATA2));
1046 
1047  free_fcb(Vcb, fcb);
1048  return STATUS_INTERNAL_ERROR;
1049  }
1050 
1051  if (ed2->address == 0 || ed2->size == 0) // sparse
1052  continue;
1053 
1054  if (ed2->size != 0 && is_tree_unique(Vcb, tp.tree, Irp))
1056  }
1057 
1058  ext = ExAllocatePoolWithTag(pooltype, offsetof(extent, extent_data) + tp.item->size, ALLOC_TAG);
1059  if (!ext) {
1060  ERR("out of memory\n");
1061  free_fcb(Vcb, fcb);
1063  }
1064 
1065  ext->offset = tp.item->key.offset;
1066  RtlCopyMemory(&ext->extent_data, tp.item->data, tp.item->size);
1067  ext->datalen = tp.item->size;
1068  ext->unique = unique;
1069  ext->ignore = FALSE;
1070  ext->inserted = FALSE;
1071  ext->csum = NULL;
1072 
1073  InsertTailList(&fcb->extents, &ext->list_entry);
1074  }
1075  }
1076 
1077  if (fcb->type == BTRFS_TYPE_DIRECTORY) {
1079  if (!NT_SUCCESS(Status)) {
1080  ERR("load_dir_children returned %08x\n", Status);
1081  free_fcb(Vcb, fcb);
1082  return Status;
1083  }
1084  }
1085 
1086  if (no_data) {
1087  fcb->Header.AllocationSize.QuadPart = 0;
1088  fcb->Header.FileSize.QuadPart = 0;
1089  fcb->Header.ValidDataLength.QuadPart = 0;
1090  } else {
1091  if (ed && ed->type == EXTENT_TYPE_INLINE)
1092  fcb->Header.AllocationSize.QuadPart = fcb->inode_item.st_size;
1093  else
1094  fcb->Header.AllocationSize.QuadPart = sector_align(fcb->inode_item.st_size, fcb->Vcb->superblock.sector_size);
1095 
1096  fcb->Header.FileSize.QuadPart = fcb->inode_item.st_size;
1097  fcb->Header.ValidDataLength.QuadPart = fcb->inode_item.st_size;
1098  }
1099 
1100  if (!atts_set)
1101  fcb->atts = get_file_attributes(Vcb, fcb->subvol, fcb->inode, fcb->type, utf8 && utf8->Buffer[0] == '.', TRUE, Irp);
1102 
1103  if (!sd_set)
1105 
1108 
1109  if (!Vcb->readonly && !is_subvol_readonly(subvol, Irp)) {
1110  fcb->atts_changed = TRUE;
1112  }
1113  }
1114 
1115  if (lastle)
1116  InsertHeadList(lastle, &fcb->list_entry);
1117  else
1118  InsertTailList(&subvol->fcbs, &fcb->list_entry);
1119 
1120  InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
1121 
1122  fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
1123 
1124  *pfcb = fcb;
1125  return STATUS_SUCCESS;
1126 }
1127 
1129  dir_child* dc, fcb* parent, fcb** pfcb, PIRP Irp) {
1130  fcb* fcb;
1131  UINT8* xattrdata;
1132  UINT16 xattrlen, overhead;
1133  NTSTATUS Status;
1134  KEY searchkey;
1135  traverse_ptr tp;
1136  static const char xapref[] = "user.";
1138  UINT32 crc32;
1139 
1140  xattr.Length = sizeof(xapref) - 1 + dc->utf8.Length;
1141  xattr.MaximumLength = xattr.Length + 1;
1142  xattr.Buffer = ExAllocatePoolWithTag(PagedPool, xattr.MaximumLength, ALLOC_TAG);
1143  if (!xattr.Buffer) {
1144  ERR("out of memory\n");
1146  }
1147 
1148  RtlCopyMemory(xattr.Buffer, xapref, sizeof(xapref) - 1);
1149  RtlCopyMemory(&xattr.Buffer[sizeof(xapref) - 1], dc->utf8.Buffer, dc->utf8.Length);
1150  xattr.Buffer[xattr.Length] = 0;
1151 
1153  if (!fcb) {
1154  ERR("out of memory\n");
1155  ExFreePool(xattr.Buffer);
1157  }
1158 
1159  fcb->Vcb = Vcb;
1160 
1161  crc32 = calc_crc32c(0xfffffffe, (UINT8*)xattr.Buffer, xattr.Length);
1162 
1163  if (!get_xattr(Vcb, parent->subvol, parent->inode, xattr.Buffer, crc32, &xattrdata, &xattrlen, Irp)) {
1164  ERR("get_xattr failed\n");
1165  free_fcb(Vcb, fcb);
1166  ExFreePool(xattr.Buffer);
1167  return STATUS_INTERNAL_ERROR;
1168  }
1169 
1170  fcb->subvol = parent->subvol;
1171  fcb->inode = parent->inode;
1172  fcb->type = parent->type;
1173  fcb->ads = TRUE;
1174  fcb->adshash = crc32;
1175  fcb->adsxattr = xattr;
1176 
1177  // find XATTR_ITEM overhead and hence calculate maximum length
1178 
1179  searchkey.obj_id = parent->inode;
1180  searchkey.obj_type = TYPE_XATTR_ITEM;
1181  searchkey.offset = crc32;
1182 
1183  Status = find_item(Vcb, parent->subvol, &tp, &searchkey, FALSE, Irp);
1184  if (!NT_SUCCESS(Status)) {
1185  ERR("find_item returned %08x\n", Status);
1186  free_fcb(Vcb, fcb);
1187  return Status;
1188  }
1189 
1190  if (keycmp(tp.item->key, searchkey)) {
1191  ERR("error - could not find key for xattr\n");
1192  free_fcb(Vcb, fcb);
1193  return STATUS_INTERNAL_ERROR;
1194  }
1195 
1196  if (tp.item->size < xattrlen) {
1197  ERR("(%llx,%x,%llx) was %u bytes, expected at least %u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, xattrlen);
1198  free_fcb(Vcb, fcb);
1199  return STATUS_INTERNAL_ERROR;
1200  }
1201 
1202  overhead = tp.item->size - xattrlen;
1203 
1204  fcb->adsmaxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - overhead;
1205 
1206  fcb->adsdata.Buffer = (char*)xattrdata;
1207  fcb->adsdata.Length = fcb->adsdata.MaximumLength = xattrlen;
1208 
1209  fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
1210  fcb->Header.AllocationSize.QuadPart = xattrlen;
1211  fcb->Header.FileSize.QuadPart = xattrlen;
1212  fcb->Header.ValidDataLength.QuadPart = xattrlen;
1213 
1214  TRACE("stream found: size = %x, hash = %08x\n", xattrlen, fcb->adshash);
1215 
1216  InsertHeadList(&parent->list_entry, &fcb->list_entry);
1217 
1218  InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
1219 
1220  *pfcb = fcb;
1221 
1222  return STATUS_SUCCESS;
1223 }
1224 
1226  _In_ file_ref* sf, _In_ PUNICODE_STRING name, _In_ BOOL case_sensitive, _In_ BOOL lastpart, _In_ BOOL streampart,
1227  _In_ POOL_TYPE pooltype, _Out_ file_ref** psf2, _In_opt_ PIRP Irp) {
1228  NTSTATUS Status;
1229  file_ref* sf2;
1230 
1231  if (sf->fcb == Vcb->dummy_fcb)
1233 
1234  if (streampart) {
1235  BOOL locked = FALSE;
1236  LIST_ENTRY* le;
1237  UNICODE_STRING name_uc;
1238  dir_child* dc = NULL;
1239  fcb* fcb;
1240 
1241  if (!case_sensitive) {
1242  Status = RtlUpcaseUnicodeString(&name_uc, name, TRUE);
1243  if (!NT_SUCCESS(Status)) {
1244  ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
1245  return Status;
1246  }
1247  }
1248 
1249  if (!ExIsResourceAcquiredSharedLite(&sf->fcb->nonpaged->dir_children_lock)) {
1250  ExAcquireResourceSharedLite(&sf->fcb->nonpaged->dir_children_lock, TRUE);
1251  locked = TRUE;
1252  }
1253 
1254  le = sf->fcb->dir_children_index.Flink;
1255  while (le != &sf->fcb->dir_children_index) {
1256  dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_index);
1257 
1258  if (dc2->index == 0) {
1259  if ((case_sensitive && dc2->name.Length == name->Length && RtlCompareMemory(dc2->name.Buffer, name->Buffer, dc2->name.Length) == dc2->name.Length) ||
1260  (!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)
1261  ) {
1262  dc = dc2;
1263  break;
1264  }
1265  } else
1266  break;
1267 
1268  le = le->Flink;
1269  }
1270 
1271  if (!case_sensitive)
1272  ExFreePool(name_uc.Buffer);
1273 
1274  if (locked)
1275  ExReleaseResourceLite(&sf->fcb->nonpaged->dir_children_lock);
1276 
1277  if (!dc)
1279 
1280  if (dc->fileref) {
1281  increase_fileref_refcount(dc->fileref);
1282  *psf2 = dc->fileref;
1283  return STATUS_SUCCESS;
1284  }
1285 
1286  Status = open_fcb_stream(Vcb, dc, sf->fcb, &fcb, Irp);
1287  if (!NT_SUCCESS(Status)) {
1288  ERR("open_fcb_stream returned %08x\n", Status);
1289  return Status;
1290  }
1291 
1292  sf2 = create_fileref(Vcb);
1293  if (!sf2) {
1294  ERR("out of memory\n");
1295  free_fcb(Vcb, fcb);
1297  }
1298 
1299  sf2->fcb = fcb;
1300 
1301  sf2->parent = (struct _file_ref*)sf;
1302 
1303  sf2->dc = dc;
1304  dc->fileref = sf2;
1305 
1306  ExAcquireResourceExclusiveLite(&sf->nonpaged->children_lock, TRUE);
1307  InsertTailList(&sf->children, &sf2->list_entry);
1308  ExReleaseResourceLite(&sf->nonpaged->children_lock);
1309 
1311  } else {
1312  root* subvol;
1313  UINT64 inode;
1314  dir_child* dc;
1315 
1316  Status = find_file_in_dir(name, sf->fcb, &subvol, &inode, &dc, case_sensitive);
1318  TRACE("could not find %.*S\n", name->Length / sizeof(WCHAR), name->Buffer);
1319 
1321  } else if (!NT_SUCCESS(Status)) {
1322  ERR("find_file_in_dir returned %08x\n", Status);
1323  return Status;
1324  } else {
1325  fcb* fcb;
1326 #ifdef DEBUG_STATS
1327  LARGE_INTEGER time1, time2;
1328 #endif
1329 
1330  if (dc->fileref) {
1331  if (!lastpart && dc->type != BTRFS_TYPE_DIRECTORY) {
1332  TRACE("passed path including file as subdirectory\n");
1334  }
1335 
1336  InterlockedIncrement(&dc->fileref->refcount);
1337  *psf2 = dc->fileref;
1338  return STATUS_SUCCESS;
1339  }
1340 
1341  if (!subvol || (subvol != Vcb->root_fileref->fcb->subvol && inode == SUBVOL_ROOT_INODE && subvol->parent != sf->fcb->subvol->id)) {
1342  fcb = Vcb->dummy_fcb;
1344  } else {
1345 #ifdef DEBUG_STATS
1347 #endif
1348  Status = open_fcb(Vcb, subvol, inode, dc->type, &dc->utf8, sf->fcb, &fcb, pooltype, Irp);
1349 #ifdef DEBUG_STATS
1351  Vcb->stats.open_fcb_calls++;
1352  Vcb->stats.open_fcb_time += time2.QuadPart - time1.QuadPart;
1353 #endif
1354 
1355  if (!NT_SUCCESS(Status)) {
1356  ERR("open_fcb returned %08x\n", Status);
1357  return Status;
1358  }
1359  }
1360 
1361  if (dc->type != BTRFS_TYPE_DIRECTORY && !lastpart && !(fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT)) {
1362  TRACE("passed path including file as subdirectory\n");
1363  free_fcb(Vcb, fcb);
1365  }
1366 
1367  sf2 = create_fileref(Vcb);
1368  if (!sf2) {
1369  ERR("out of memory\n");
1370  free_fcb(Vcb, fcb);
1372  }
1373 
1374  sf2->fcb = fcb;
1375 
1376  if (dc->type == BTRFS_TYPE_DIRECTORY)
1377  fcb->fileref = sf2;
1378 
1379  sf2->dc = dc;
1380  dc->fileref = sf2;
1381 
1382  sf2->parent = (struct _file_ref*)sf;
1383 
1384  ExAcquireResourceExclusiveLite(&sf->nonpaged->children_lock, TRUE);
1385  InsertTailList(&sf->children, &sf2->list_entry);
1386  ExReleaseResourceLite(&sf->nonpaged->children_lock);
1387 
1389  }
1390  }
1391 
1392  *psf2 = sf2;
1393 
1394  return STATUS_SUCCESS;
1395 }
1396 
1398  _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,
1399  _In_ BOOL case_sensitive, _In_opt_ PIRP Irp) {
1400  UNICODE_STRING fnus2;
1401  file_ref *dir, *sf, *sf2;
1402  LIST_ENTRY parts;
1403  BOOL has_stream;
1404  NTSTATUS Status;
1405  LIST_ENTRY* le;
1406 
1407  TRACE("(%p, %p, %p, %u, %p)\n", Vcb, pfr, related, parent, parsed);
1408 
1409 #ifdef DEBUG
1410  if (!ExIsResourceAcquiredExclusiveLite(&Vcb->fcb_lock) && !ExIsResourceAcquiredExclusiveLite(&Vcb->tree_lock)) {
1411  ERR("fcb_lock not acquired exclusively\n");
1412  int3;
1413  }
1414 #endif
1415 
1416  if (Vcb->removing || Vcb->locked)
1417  return STATUS_ACCESS_DENIED;
1418 
1419  fnus2 = *fnus;
1420 
1421  if (fnus2.Length < sizeof(WCHAR) && !related) {
1422  ERR("error - fnus was too short\n");
1423  return STATUS_INTERNAL_ERROR;
1424  }
1425 
1426  if (related && fnus->Length == 0) {
1427  increase_fileref_refcount(related);
1428 
1429  *pfr = related;
1430  return STATUS_SUCCESS;
1431  }
1432 
1433  if (related) {
1434  dir = related;
1435  } else {
1436  if (fnus2.Buffer[0] != '\\') {
1437  ERR("error - filename %.*S did not begin with \\\n", fnus2.Length / sizeof(WCHAR), fnus2.Buffer);
1439  }
1440 
1441  // if path starts with two backslashes, ignore one of them
1442  if (fnus2.Length >= 2 * sizeof(WCHAR) && fnus2.Buffer[1] == '\\') {
1443  fnus2.Buffer++;
1444  fnus2.Length -= sizeof(WCHAR);
1445  fnus2.MaximumLength -= sizeof(WCHAR);
1446  }
1447 
1448  if (fnus2.Length == sizeof(WCHAR)) {
1449  if (Vcb->root_fileref->open_count == 0 && !(Vcb->Vpb->Flags & VPB_MOUNTED)) // don't allow root to be opened on unmounted FS
1450  return STATUS_DEVICE_NOT_READY;
1451 
1452  increase_fileref_refcount(Vcb->root_fileref);
1453  *pfr = Vcb->root_fileref;
1454 
1455  if (fn_offset)
1456  *fn_offset = 0;
1457 
1458  return STATUS_SUCCESS;
1459  }
1460 
1461  dir = Vcb->root_fileref;
1462 
1463  fnus2.Buffer++;
1464  fnus2.Length -= sizeof(WCHAR);
1465  fnus2.MaximumLength -= sizeof(WCHAR);
1466  }
1467 
1468  if (dir->fcb->type != BTRFS_TYPE_DIRECTORY && (fnus->Length < sizeof(WCHAR) || fnus->Buffer[0] != ':')) {
1469  WARN("passed related fileref which isn't a directory (%S) (fnus = %.*S)\n",
1470  file_desc_fileref(related), fnus->Length / sizeof(WCHAR), fnus->Buffer);
1472  }
1473 
1474  InitializeListHead(&parts);
1475 
1476  if (fnus->Length != 0 &&
1477  (fnus->Length != sizeof(datastring) - sizeof(WCHAR) || RtlCompareMemory(fnus->Buffer, datastring, sizeof(datastring) - sizeof(WCHAR)) != sizeof(datastring) - sizeof(WCHAR))) {
1478  Status = split_path(Vcb, &fnus2, &parts, &has_stream);
1479  if (!NT_SUCCESS(Status)) {
1480  ERR("split_path returned %08x\n", Status);
1481  return Status;
1482  }
1483  }
1484 
1485  sf = dir;
1487 
1488  if (parent && !IsListEmpty(&parts)) {
1489  name_bit* nb;
1490 
1492  ExFreePool(nb);
1493 
1494  if (has_stream && !IsListEmpty(&parts)) {
1496  ExFreePool(nb);
1497 
1498  has_stream = FALSE;
1499  }
1500  }
1501 
1502  if (IsListEmpty(&parts)) {
1504  *pfr = dir;
1505 
1506  if (fn_offset)
1507  *fn_offset = 0;
1508 
1509  goto end2;
1510  }
1511 
1512  le = parts.Flink;
1513  do {
1515  BOOL lastpart = le->Flink == &parts || (has_stream && le->Flink->Flink == &parts);
1516  BOOL streampart = has_stream && le->Flink == &parts;
1517 #ifdef DEBUG_STATS
1518  LARGE_INTEGER time1, time2;
1519 #endif
1520 
1521 #ifdef DEBUG_STATS
1523 #endif
1524  Status = open_fileref_child(Vcb, sf, &nb->us, case_sensitive, lastpart, streampart, pooltype, &sf2, Irp);
1525 #ifdef DEBUG_STATS
1527  Vcb->stats.open_fileref_child_calls++;
1528  Vcb->stats.open_fileref_child_time += time2.QuadPart - time1.QuadPart;
1529 #endif
1530  if (!NT_SUCCESS(Status)) {
1532  TRACE("open_fileref_child returned %08x\n", Status);
1533  else
1534  ERR("open_fileref_child returned %08x\n", Status);
1535 
1536  goto end;
1537  }
1538 
1539  if (le->Flink == &parts) { // last entry
1540  if (fn_offset) {
1541  if (has_stream)
1543 
1544  *fn_offset = (ULONG)(nb->us.Buffer - fnus->Buffer);
1545  }
1546 
1547  break;
1548  }
1549 
1550  if (sf2->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT) {
1552 
1553  if (parsed) {
1555 
1556  *parsed = (USHORT)(nb2->us.Buffer - fnus->Buffer - 1) * sizeof(WCHAR);
1557  }
1558 
1559  break;
1560  }
1561 
1562  free_fileref(Vcb, sf);
1563  sf = sf2;
1564 
1565  le = le->Flink;
1566  } while (le != &parts);
1567 
1568  if (Status != STATUS_REPARSE)
1570  *pfr = sf2;
1571 
1572 end:
1573  free_fileref(Vcb, sf);
1574 
1575  while (!IsListEmpty(&parts)) {
1577  ExFreeToPagedLookasideList(&Vcb->name_bit_lookaside, nb);
1578  }
1579 
1580 end2:
1581  TRACE("returning %08x\n", Status);
1582 
1583  return Status;
1584 }
1585 
1587  NTSTATUS Status;
1588  dir_child* dc;
1589 
1591  if (!dc) {
1592  ERR("out of memory\n");
1594  }
1595 
1596  dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, utf8->Length, ALLOC_TAG);
1597  if (!dc->utf8.Buffer) {
1598  ERR("out of memory\n");
1599  ExFreePool(dc);
1601  }
1602 
1603  dc->name.Buffer = ExAllocatePoolWithTag(PagedPool, name->Length, ALLOC_TAG);
1604  if (!dc->name.Buffer) {
1605  ERR("out of memory\n");
1606  ExFreePool(dc->utf8.Buffer);
1607  ExFreePool(dc);
1609  }
1610 
1611  dc->key.obj_id = inode;
1612  dc->key.obj_type = subvol ? TYPE_ROOT_ITEM : TYPE_INODE_ITEM;
1613  dc->key.offset = subvol ? 0xffffffffffffffff : 0;
1614  dc->type = type;
1615  dc->fileref = NULL;
1616 
1617  dc->utf8.Length = dc->utf8.MaximumLength = utf8->Length;
1618  RtlCopyMemory(dc->utf8.Buffer, utf8->Buffer, utf8->Length);
1619 
1620  dc->name.Length = dc->name.MaximumLength = name->Length;
1621  RtlCopyMemory(dc->name.Buffer, name->Buffer, name->Length);
1622 
1623  Status = RtlUpcaseUnicodeString(&dc->name_uc, name, TRUE);
1624  if (!NT_SUCCESS(Status)) {
1625  ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
1626  ExFreePool(dc->utf8.Buffer);
1627  ExFreePool(dc->name.Buffer);
1628  ExFreePool(dc);
1629  return Status;
1630  }
1631 
1632  dc->hash = calc_crc32c(0xffffffff, (UINT8*)dc->name.Buffer, dc->name.Length);
1633  dc->hash_uc = calc_crc32c(0xffffffff, (UINT8*)dc->name_uc.Buffer, dc->name_uc.Length);
1634 
1635  ExAcquireResourceExclusiveLite(&fcb->nonpaged->dir_children_lock, TRUE);
1636 
1638  dc->index = 2;
1639  else {
1640  dir_child* dc2 = CONTAINING_RECORD(fcb->dir_children_index.Blink, dir_child, list_entry_index);
1641 
1642  dc->index = max(2, dc2->index + 1);
1643  }
1644 
1645  InsertTailList(&fcb->dir_children_index, &dc->list_entry_index);
1646 
1648 
1649  ExReleaseResourceLite(&fcb->nonpaged->dir_children_lock);
1650 
1651  *pdc = dc;
1652 
1653  return STATUS_SUCCESS;
1654 }
1655 
1656 UINT32 inherit_mode(fcb* parfcb, BOOL is_dir) {
1657  UINT32 mode;
1658 
1659  if (!parfcb)
1660  return 0755;
1661 
1662  mode = parfcb->inode_item.st_mode & ~S_IFDIR;
1663  mode &= ~S_ISVTX; // clear sticky bit
1664  mode &= ~S_ISUID; // clear setuid bit
1665 
1666  if (!is_dir)
1667  mode &= ~S_ISGID; // if not directory, clear setgid bit
1668 
1669  return mode;
1670 }
1671 
1673  NTSTATUS Status;
1674  LIST_ENTRY ealist, *le;
1675  UINT16 size = 0;
1676  char* buf;
1677 
1678  InitializeListHead(&ealist);
1679 
1680  do {
1681  STRING s;
1682  BOOL found = FALSE;
1683 
1684  s.Length = s.MaximumLength = ea->EaNameLength;
1685  s.Buffer = ea->EaName;
1686 
1687  RtlUpperString(&s, &s);
1688 
1689  le = ealist.Flink;
1690  while (le != &ealist) {
1692 
1693  if (item->name.Length == s.Length && RtlCompareMemory(item->name.Buffer, s.Buffer, s.Length) == s.Length) {
1694  item->flags = ea->Flags;
1695  item->value.Length = item->value.MaximumLength = ea->EaValueLength;
1696  item->value.Buffer = &ea->EaName[ea->EaNameLength + 1];
1697  found = TRUE;
1698  break;
1699  }
1700 
1701  le = le->Flink;
1702  }
1703 
1704  if (!found) {
1706  if (!item) {
1707  ERR("out of memory\n");
1709  goto end;
1710  }
1711 
1712  item->name.Length = item->name.MaximumLength = ea->EaNameLength;
1713  item->name.Buffer = ea->EaName;
1714 
1715  item->value.Length = item->value.MaximumLength = ea->EaValueLength;
1716  item->value.Buffer = &ea->EaName[ea->EaNameLength + 1];
1717 
1718  item->flags = ea->Flags;
1719 
1720  InsertTailList(&ealist, &item->list_entry);
1721  }
1722 
1723  if (ea->NextEntryOffset == 0)
1724  break;
1725 
1726  ea = (FILE_FULL_EA_INFORMATION*)(((UINT8*)ea) + ea->NextEntryOffset);
1727  } while (TRUE);
1728 
1729  // handle LXSS values
1730  le = ealist.Flink;
1731  while (le != &ealist) {
1732  LIST_ENTRY* le2 = le->Flink;
1734 
1735  if (item->name.Length == sizeof(lxuid) - 1 && RtlCompareMemory(item->name.Buffer, lxuid, item->name.Length) == item->name.Length) {
1736  if (item->value.Length < sizeof(UINT32)) {
1737  ERR("uid value was shorter than expected\n");
1739  goto end;
1740  }
1741 
1742  RtlCopyMemory(&fcb->inode_item.st_uid, item->value.Buffer, sizeof(UINT32));
1743  fcb->sd_dirty = TRUE;
1744  fcb->sd_deleted = FALSE;
1745 
1746  RemoveEntryList(&item->list_entry);
1747  ExFreePool(item);
1748  } else if (item->name.Length == sizeof(lxgid) - 1 && RtlCompareMemory(item->name.Buffer, lxgid, item->name.Length) == item->name.Length) {
1749  if (item->value.Length < sizeof(UINT32)) {
1750  ERR("gid value was shorter than expected\n");
1752  goto end;
1753  }
1754 
1755  RtlCopyMemory(&fcb->inode_item.st_gid, item->value.Buffer, sizeof(UINT32));
1756 
1757  RemoveEntryList(&item->list_entry);
1758  ExFreePool(item);
1759  } else if (item->name.Length == sizeof(lxmod) - 1 && RtlCompareMemory(item->name.Buffer, lxmod, item->name.Length) == item->name.Length) {
1761  UINT32 val;
1762 
1763  if (item->value.Length < sizeof(UINT32)) {
1764  ERR("mode value was shorter than expected\n");
1766  goto end;
1767  }
1768 
1769  RtlCopyMemory(&val, item->value.Buffer, sizeof(UINT32));
1770 
1771  if (fcb->type != BTRFS_TYPE_DIRECTORY)
1772  allowed |= __S_IFIFO | __S_IFCHR | __S_IFBLK | __S_IFSOCK;
1773 
1774  fcb->inode_item.st_mode &= ~allowed;
1775  fcb->inode_item.st_mode |= val & allowed;
1776 
1777  if (fcb->type != BTRFS_TYPE_DIRECTORY) {
1780  else if ((fcb->inode_item.st_mode & __S_IFBLK) == __S_IFBLK)
1782  else if ((fcb->inode_item.st_mode & __S_IFIFO) == __S_IFIFO)
1784  else if ((fcb->inode_item.st_mode & __S_IFSOCK) == __S_IFSOCK)
1786  }
1787 
1788  RemoveEntryList(&item->list_entry);
1789  ExFreePool(item);
1790  } else if (item->name.Length == sizeof(lxdev) - 1 && RtlCompareMemory(item->name.Buffer, lxdev, item->name.Length) == item->name.Length) {
1791  UINT32 major, minor;
1792 
1793  if (item->value.Length < sizeof(UINT64)) {
1794  ERR("dev value was shorter than expected\n");
1796  goto end;
1797  }
1798 
1799  major = *(UINT32*)item->value.Buffer;
1800  minor = *(UINT32*)&item->value.Buffer[sizeof(UINT32)];
1801 
1802  fcb->inode_item.st_rdev = (minor & 0xFFFFF) | ((major & 0xFFFFFFFFFFF) << 20);
1803 
1804  RemoveEntryList(&item->list_entry);
1805  ExFreePool(item);
1806  }
1807 
1808  le = le2;
1809  }
1810 
1812  fcb->inode_item.st_rdev = 0;
1813 
1814  if (IsListEmpty(&ealist))
1815  return STATUS_SUCCESS;
1816 
1817  le = ealist.Flink;
1818  while (le != &ealist) {
1820 
1821  if (size % 4 > 0)
1822  size += 4 - (size % 4);
1823 
1824  size += (UINT16)offsetof(FILE_FULL_EA_INFORMATION, EaName[0]) + item->name.Length + 1 + item->value.Length;
1825 
1826  le = le->Flink;
1827  }
1828 
1830  if (!buf) {
1831  ERR("out of memory\n");
1833  goto end;
1834  }
1835 
1837  fcb->ea_xattr.Buffer = buf;
1838 
1839  fcb->ealen = 4;
1840  ea = NULL;
1841 
1842  le = ealist.Flink;
1843  while (le != &ealist) {
1845 
1846  if (ea) {
1848 
1849  if (ea->NextEntryOffset % 4 > 0)
1850  ea->NextEntryOffset += 4 - (ea->NextEntryOffset % 4);
1851 
1852  ea = (FILE_FULL_EA_INFORMATION*)(((UINT8*)ea) + ea->NextEntryOffset);
1853  } else
1855 
1856  ea->NextEntryOffset = 0;
1857  ea->Flags = item->flags;
1858  ea->EaNameLength = (UCHAR)item->name.Length;
1859  ea->EaValueLength = item->value.Length;
1860 
1861  RtlCopyMemory(ea->EaName, item->name.Buffer, item->name.Length);
1862  ea->EaName[item->name.Length] = 0;
1863  RtlCopyMemory(&ea->EaName[item->name.Length + 1], item->value.Buffer, item->value.Length);
1864 
1865  fcb->ealen += 5 + item->name.Length + item->value.Length;
1866 
1867  le = le->Flink;
1868  }
1869 
1870  fcb->ea_changed = TRUE;
1871 
1873 
1874 end:
1875  while (!IsListEmpty(&ealist)) {
1877 
1878  ExFreePool(item);
1879  }
1880 
1881  return Status;
1882 }
1883 
1887  NTSTATUS Status;
1888  fcb* fcb;
1889  ULONG utf8len;
1890  char* utf8 = NULL;
1891  UINT64 inode;
1892  UINT8 type;
1894  BTRFS_TIME now;
1897  USHORT defda;
1898  file_ref* fileref;
1899  dir_child* dc;
1900  ANSI_STRING utf8as;
1901 #ifdef DEBUG_FCB_REFCOUNTS
1902  LONG rc;
1903 #endif
1904 
1905  if (parfileref->fcb == Vcb->dummy_fcb)
1906  return STATUS_ACCESS_DENIED;
1907 
1909  return STATUS_INVALID_PARAMETER;
1910 
1911  Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, fpus->Buffer, fpus->Length);
1912  if (!NT_SUCCESS(Status)) {
1913  ERR("RtlUnicodeToUTF8N returned %08x\n", Status);
1914  return Status;
1915  }
1916 
1917  utf8 = ExAllocatePoolWithTag(pool_type, utf8len + 1, ALLOC_TAG);
1918  if (!utf8) {
1919  ERR("out of memory\n");
1921  }
1922 
1923  Status = RtlUnicodeToUTF8N(utf8, utf8len, &utf8len, fpus->Buffer, fpus->Length);
1924  if (!NT_SUCCESS(Status)) {
1925  ERR("RtlUnicodeToUTF8N returned %08x\n", Status);
1926  ExFreePool(utf8);
1927  return Status;
1928  }
1929 
1930  utf8[utf8len] = 0;
1931 
1934 
1935  TRACE("create file %.*S\n", fpus->Length / sizeof(WCHAR), fpus->Buffer);
1936  ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
1937  TRACE("parfileref->fcb->inode_item.st_size (inode %llx) was %llx\n", parfileref->fcb->inode, parfileref->fcb->inode_item.st_size);
1938  parfileref->fcb->inode_item.st_size += utf8len * 2;
1939  TRACE("parfileref->fcb->inode_item.st_size (inode %llx) now %llx\n", parfileref->fcb->inode, parfileref->fcb->inode_item.st_size);
1940  parfileref->fcb->inode_item.transid = Vcb->superblock.generation;
1941  parfileref->fcb->inode_item.sequence++;
1942  parfileref->fcb->inode_item.st_ctime = now;
1943  parfileref->fcb->inode_item.st_mtime = now;
1944  ExReleaseResourceLite(parfileref->fcb->Header.Resource);
1945 
1946  parfileref->fcb->inode_item_changed = TRUE;
1947  mark_fcb_dirty(parfileref->fcb);
1948 
1949  inode = InterlockedIncrement64(&parfileref->fcb->subvol->lastinode);
1950 
1952 
1953  // FIXME - link FILE_ATTRIBUTE_READONLY to st_mode
1954 
1955  TRACE("requested attributes = %x\n", IrpSp->Parameters.Create.FileAttributes);
1956 
1957  defda = 0;
1958 
1959  if (utf8[0] == '.')
1960  defda |= FILE_ATTRIBUTE_HIDDEN;
1961 
1962  if (options & FILE_DIRECTORY_FILE) {
1963  defda |= FILE_ATTRIBUTE_DIRECTORY;
1964  IrpSp->Parameters.Create.FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
1965  } else
1966  IrpSp->Parameters.Create.FileAttributes &= ~FILE_ATTRIBUTE_DIRECTORY;
1967 
1968  if (!(IrpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
1969  IrpSp->Parameters.Create.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
1970  defda |= FILE_ATTRIBUTE_ARCHIVE;
1971  }
1972 
1973  TRACE("defda = %x\n", defda);
1974 
1975  if (IrpSp->Parameters.Create.FileAttributes == FILE_ATTRIBUTE_NORMAL)
1976  IrpSp->Parameters.Create.FileAttributes = defda;
1977 
1978  fcb = create_fcb(Vcb, pool_type);
1979  if (!fcb) {
1980  ERR("out of memory\n");
1981  ExFreePool(utf8);
1982 
1983  ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
1984  parfileref->fcb->inode_item.st_size -= utf8len * 2;
1985  ExReleaseResourceLite(parfileref->fcb->Header.Resource);
1986 
1988  }
1989 
1990  fcb->Vcb = Vcb;
1991 
1992  if (IrpSp->Flags & SL_OPEN_PAGING_FILE) {
1994  Vcb->disallow_dismount = TRUE;
1995  }
1996 
1997  fcb->inode_item.generation = Vcb->superblock.generation;
1998  fcb->inode_item.transid = Vcb->superblock.generation;
1999  fcb->inode_item.st_size = 0;
2000  fcb->inode_item.st_blocks = 0;
2001  fcb->inode_item.block_group = 0;
2002  fcb->inode_item.st_nlink = 1;
2003  fcb->inode_item.st_gid = GID_NOBODY; // FIXME?
2004  fcb->inode_item.st_mode = inherit_mode(parfileref->fcb, type == BTRFS_TYPE_DIRECTORY); // use parent's permissions by default
2005  fcb->inode_item.st_rdev = 0;
2006  fcb->inode_item.flags = 0;
2007  fcb->inode_item.sequence = 1;
2011  fcb->inode_item.otime = now;
2012 
2013  if (type == BTRFS_TYPE_DIRECTORY)
2015  else {
2017  fcb->inode_item.st_mode &= ~(S_IXUSR | S_IXGRP | S_IXOTH); // remove executable bit if not directory
2018  }
2019 
2020  if (IrpSp->Flags & SL_OPEN_PAGING_FILE) {
2022  } else {
2023  // inherit nodatacow flag from parent directory
2024  if (parfileref->fcb->inode_item.flags & BTRFS_INODE_NODATACOW) {
2026 
2027  if (type != BTRFS_TYPE_DIRECTORY)
2029  }
2030 
2031  if (parfileref->fcb->inode_item.flags & BTRFS_INODE_COMPRESS)
2033  }
2034 
2035  fcb->prop_compression = parfileref->fcb->prop_compression;
2037 
2039 
2040  fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
2041  fcb->Header.AllocationSize.QuadPart = 0;
2042  fcb->Header.FileSize.QuadPart = 0;
2043  fcb->Header.ValidDataLength.QuadPart = 0;
2044 
2045  fcb->atts = IrpSp->Parameters.Create.FileAttributes & ~FILE_ATTRIBUTE_NORMAL;
2046  fcb->atts_changed = fcb->atts != defda;
2047 
2048 #ifdef DEBUG_FCB_REFCOUNTS
2049  rc = InterlockedIncrement(&parfileref->fcb->refcount);
2050  WARN("fcb %p: refcount now %i (%S)\n", parfileref->fcb, rc, file_desc_fileref(parfileref));
2051 #else
2052  InterlockedIncrement(&parfileref->fcb->refcount);
2053 #endif
2054  fcb->subvol = parfileref->fcb->subvol;
2055  fcb->inode = inode;
2056  fcb->type = type;
2057  fcb->created = TRUE;
2058  fcb->deleted = TRUE;
2059 
2061 
2062  Status = fcb_get_new_sd(fcb, parfileref, IrpSp->Parameters.Create.SecurityContext->AccessState);
2063 
2064  if (!NT_SUCCESS(Status)) {
2065  ERR("fcb_get_new_sd returned %08x\n", Status);
2066  free_fcb(Vcb, fcb);
2067 
2068  ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
2069  parfileref->fcb->inode_item.st_size -= utf8len * 2;
2070  ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2071 
2072  return Status;
2073  }
2074 
2075  fcb->sd_dirty = TRUE;
2076 
2077  if (ea && ealen > 0) {
2079  if (!NT_SUCCESS(Status)) {
2080  ERR("file_create_parse_ea returned %08x\n", Status);
2081  free_fcb(Vcb, fcb);
2082 
2083  ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
2084  parfileref->fcb->inode_item.st_size -= utf8len * 2;
2085  ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2086 
2087  return Status;
2088  }
2089  }
2090 
2091  fileref = create_fileref(Vcb);
2092  if (!fileref) {
2093  ERR("out of memory\n");
2094  free_fcb(Vcb, fcb);
2095 
2096  ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
2097  parfileref->fcb->inode_item.st_size -= utf8len * 2;
2098  ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2099 
2101  }
2102 
2103  fileref->fcb = fcb;
2104 
2105  if (Irp->Overlay.AllocationSize.QuadPart > 0 && !write_fcb_compressed(fcb)) {
2106  Status = extend_file(fcb, fileref, Irp->Overlay.AllocationSize.QuadPart, TRUE, NULL, rollback);
2107 
2108  if (!NT_SUCCESS(Status)) {
2109  ERR("extend_file returned %08x\n", Status);
2110  free_fileref(Vcb, fileref);
2111 
2112  ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
2113  parfileref->fcb->inode_item.st_size -= utf8len * 2;
2114  ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2115 
2116  return Status;
2117  }
2118  }
2119 
2120  if (fcb->type == BTRFS_TYPE_DIRECTORY) {
2122  if (!fcb->hash_ptrs) {
2123  ERR("out of memory\n");
2124  free_fileref(Vcb, fileref);
2125 
2126  ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
2127  parfileref->fcb->inode_item.st_size -= utf8len * 2;
2128  ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2129 
2131  }
2132 
2133  RtlZeroMemory(fcb->hash_ptrs, sizeof(LIST_ENTRY*) * 256);
2134 
2136  if (!fcb->hash_ptrs_uc) {
2137  ERR("out of memory\n");
2138  free_fileref(Vcb, fileref);
2139 
2140  ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
2141  parfileref->fcb->inode_item.st_size -= utf8len * 2;
2142  ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2143 
2145  }
2146 
2147  RtlZeroMemory(fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256);
2148  }
2149 
2150  fcb->deleted = FALSE;
2151 
2152  fileref->created = TRUE;
2153  mark_fileref_dirty(fileref);
2154 
2155  fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
2156  fcb->subvol->root_item.ctime = now;
2157 
2158  fileref->parent = parfileref;
2159 
2160  utf8as.Buffer = utf8;
2161  utf8as.Length = utf8as.MaximumLength = (UINT16)utf8len;
2162 
2163  Status = add_dir_child(fileref->parent->fcb, fcb->inode, FALSE, &utf8as, fpus, fcb->type, &dc);
2164  if (!NT_SUCCESS(Status))
2165  WARN("add_dir_child returned %08x\n", Status);
2166 
2167  ExFreePool(utf8);
2168 
2169  fileref->dc = dc;
2170  dc->fileref = fileref;
2171 
2172  ExAcquireResourceExclusiveLite(&parfileref->nonpaged->children_lock, TRUE);
2173  InsertTailList(&parfileref->children, &fileref->list_entry);
2174  ExReleaseResourceLite(&parfileref->nonpaged->children_lock);
2175 
2176  increase_fileref_refcount(parfileref);
2177 
2178  InsertTailList(&fcb->subvol->fcbs, &fcb->list_entry);
2179  InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
2180 
2181  *pfr = fileref;
2182 
2183  if (type == BTRFS_TYPE_DIRECTORY)
2184  fileref->fcb->fileref = fileref;
2185 
2186  TRACE("created new file %S in subvol %llx, inode %llx\n", file_desc_fileref(fileref), fcb->subvol->id, fcb->inode);
2187 
2188  return STATUS_SUCCESS;
2189 }
2190 
2192  file_ref** pfileref, file_ref** pparfileref, PUNICODE_STRING fpus, PUNICODE_STRING stream, PIRP Irp,
2193  ULONG options, POOL_TYPE pool_type, BOOL case_sensitive, LIST_ENTRY* rollback) {
2195  file_ref *fileref, *newpar, *parfileref;
2196  fcb* fcb;
2197  static const char xapref[] = "user.";
2198  static const WCHAR DOSATTRIB[] = L"DOSATTRIB";
2199  static const WCHAR EA[] = L"EA";
2200  static const WCHAR reparse[] = L"reparse";
2202  BTRFS_TIME now;
2203  ULONG utf8len, overhead;
2204  NTSTATUS Status;
2205  KEY searchkey;
2206  traverse_ptr tp;
2207  dir_child* dc;
2208  ACCESS_MASK granted_access;
2209 #ifdef DEBUG_FCB_REFCOUNTS
2210  LONG rc;
2211 #endif
2212 
2213  TRACE("fpus = %.*S\n", fpus->Length / sizeof(WCHAR), fpus->Buffer);
2214  TRACE("stream = %.*S\n", stream->Length / sizeof(WCHAR), stream->Buffer);
2215 
2216  parfileref = *pparfileref;
2217 
2218  if (parfileref->fcb == Vcb->dummy_fcb)
2219  return STATUS_ACCESS_DENIED;
2220 
2221  Status = open_fileref(Vcb, &newpar, fpus, parfileref, FALSE, NULL, NULL, PagedPool, case_sensitive, Irp);
2222 
2224  UNICODE_STRING fpus2;
2225 
2226  if (!is_file_name_valid(fpus, FALSE))
2228 
2229  fpus2.Length = fpus2.MaximumLength = fpus->Length;
2230  fpus2.Buffer = ExAllocatePoolWithTag(pool_type, fpus2.MaximumLength, ALLOC_TAG);
2231 
2232  if (!fpus2.Buffer) {
2233  ERR("out of memory\n");
2235  }
2236 
2237  RtlCopyMemory(fpus2.Buffer, fpus->Buffer, fpus2.Length);
2238 
2239  SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2240 
2241  if (!SeAccessCheck(parfileref->fcb->sd, &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
2244  &granted_access, &Status)) {
2245  SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2246  return Status;
2247  }
2248 
2249  SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2250 
2251  Status = file_create2(Irp, Vcb, &fpus2, parfileref, options, NULL, 0, &newpar, rollback);
2252 
2253  if (!NT_SUCCESS(Status)) {
2254  ERR("file_create2 returned %08x\n", Status);
2255  ExFreePool(fpus2.Buffer);
2256  return Status;
2257  }
2258 
2261  } else if (!NT_SUCCESS(Status)) {
2262  ERR("open_fileref returned %08x\n", Status);
2263  return Status;
2264  }
2265 
2266  parfileref = newpar;
2267  *pparfileref = parfileref;
2268 
2269  if (parfileref->fcb->type != BTRFS_TYPE_FILE && parfileref->fcb->type != BTRFS_TYPE_SYMLINK && parfileref->fcb->type != BTRFS_TYPE_DIRECTORY) {
2270  WARN("parent not file, directory, or symlink\n");
2271  return STATUS_INVALID_PARAMETER;
2272  }
2273 
2274  if (options & FILE_DIRECTORY_FILE) {
2275  WARN("tried to create directory as stream\n");
2276  return STATUS_INVALID_PARAMETER;
2277  }
2278 
2279  if (parfileref->fcb->atts & FILE_ATTRIBUTE_READONLY)
2280  return STATUS_ACCESS_DENIED;
2281 
2282  SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2283 
2284  if (!SeAccessCheck(parfileref->fcb->sd, &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
2286  &granted_access, &Status)) {
2287  SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2288  return Status;
2289  }
2290 
2291  SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2292 
2293  if ((stream->Length == sizeof(DOSATTRIB) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, DOSATTRIB, stream->Length) == stream->Length) ||
2294  (stream->Length == sizeof(EA) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, EA, stream->Length) == stream->Length) ||
2295  (stream->Length == sizeof(reparse) - sizeof(WCHAR) && RtlCompareMemory(stream->Buffer, reparse, stream->Length) == stream->Length)) {
2297  }
2298 
2299  fcb = create_fcb(Vcb, pool_type);
2300  if (!fcb) {
2301  ERR("out of memory\n");
2303  }
2304 
2305  fcb->Vcb = Vcb;
2306 
2307  fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
2308  fcb->Header.AllocationSize.QuadPart = 0;
2309  fcb->Header.FileSize.QuadPart = 0;
2310  fcb->Header.ValidDataLength.QuadPart = 0;
2311 
2312 #ifdef DEBUG_FCB_REFCOUNTS
2313  rc = InterlockedIncrement(&parfileref->fcb->refcount);
2314  WARN("fcb %p: refcount now %i (%S)\n", parfileref->fcb, rc, file_desc_fileref(parfileref));
2315 #else
2316  InterlockedIncrement(&parfileref->fcb->refcount);
2317 #endif
2318  fcb->subvol = parfileref->fcb->subvol;
2319  fcb->inode = parfileref->fcb->inode;
2320  fcb->type = parfileref->fcb->type;
2321 
2322  fcb->ads = TRUE;
2323 
2324  Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, stream->Buffer, stream->Length);
2325  if (!NT_SUCCESS(Status)) {
2326  ERR("RtlUnicodeToUTF8N 1 returned %08x\n", Status);
2327  free_fcb(Vcb, fcb);
2328  return Status;
2329  }
2330 
2331  fcb->adsxattr.Length = (UINT16)utf8len + sizeof(xapref) - 1;
2334  if (!fcb->adsxattr.Buffer) {
2335  ERR("out of memory\n");
2336  free_fcb(Vcb, fcb);
2338  }
2339 
2340  RtlCopyMemory(fcb->adsxattr.Buffer, xapref, sizeof(xapref) - 1);
2341 
2342  Status = RtlUnicodeToUTF8N(&fcb->adsxattr.Buffer[sizeof(xapref) - 1], utf8len, &utf8len, stream->Buffer, stream->Length);
2343  if (!NT_SUCCESS(Status)) {
2344  ERR("RtlUnicodeToUTF8N 2 returned %08x\n", Status);
2345  free_fcb(Vcb, fcb);
2346  return Status;
2347  }
2348 
2350 
2351  TRACE("adsxattr = %s\n", fcb->adsxattr.Buffer);
2352 
2354  TRACE("adshash = %08x\n", fcb->adshash);
2355 
2356  searchkey.obj_id = parfileref->fcb->inode;
2357  searchkey.obj_type = TYPE_XATTR_ITEM;
2358  searchkey.offset = fcb->adshash;
2359 
2360  Status = find_item(Vcb, parfileref->fcb->subvol, &tp, &searchkey, FALSE, Irp);
2361  if (!NT_SUCCESS(Status)) {
2362  ERR("find_item returned %08x\n", Status);
2363  free_fcb(Vcb, fcb);
2364  return Status;
2365  }
2366 
2367  if (!keycmp(tp.item->key, searchkey))
2368  overhead = tp.item->size;
2369  else
2370  overhead = 0;
2371 
2372  fcb->adsmaxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) - (sizeof(DIR_ITEM) - 1);
2373 
2374  if (utf8len + sizeof(xapref) - 1 + overhead > fcb->adsmaxlen) {
2375  WARN("not enough room for new DIR_ITEM (%u + %u > %u)", utf8len + sizeof(xapref) - 1, overhead, fcb->adsmaxlen);
2376  free_fcb(Vcb, fcb);
2377  return STATUS_DISK_FULL;
2378  } else
2379  fcb->adsmaxlen -= overhead + utf8len + sizeof(xapref) - 1;
2380 
2381  fileref = create_fileref(Vcb);
2382  if (!fileref) {
2383  ERR("out of memory\n");
2384  free_fcb(Vcb, fcb);
2386  }
2387 
2388  fileref->fcb = fcb;
2389 
2391  if (!dc) {
2392  ERR("out of memory\n");
2393  free_fileref(Vcb, fileref);
2395  }
2396 
2397  RtlZeroMemory(dc, sizeof(dir_child));
2398 
2399  dc->utf8.MaximumLength = dc->utf8.Length = fcb->adsxattr.Length + 1 - sizeof(xapref);
2400  dc->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, dc->utf8.MaximumLength, ALLOC_TAG);
2401  if (!dc->utf8.Buffer) {
2402  ERR("out of memory\n");
2403  ExFreePool(dc);
2404  free_fileref(Vcb, fileref);
2406  }
2407 
2408  RtlCopyMemory(dc->utf8.Buffer, &fcb->adsxattr.Buffer[sizeof(xapref) - 1], fcb->adsxattr.Length + 1 - sizeof(xapref));
2409 
2410  dc->name.MaximumLength = dc->name.Length = stream->Length;
2411  dc->name.Buffer = ExAllocatePoolWithTag(pool_type, dc->name.MaximumLength, ALLOC_TAG);
2412  if (!dc->name.Buffer) {
2413  ERR("out of memory\n");
2414  ExFreePool(dc->utf8.Buffer);
2415  ExFreePool(dc);
2416  free_fileref(Vcb, fileref);
2418  }
2419 
2420  RtlCopyMemory(dc->name.Buffer, stream->Buffer, stream->Length);
2421 
2422  Status = RtlUpcaseUnicodeString(&dc->name_uc, &dc->name, TRUE);
2423  if (!NT_SUCCESS(Status)) {
2424  ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
2425  ExFreePool(dc->utf8.Buffer);
2426  ExFreePool(dc->name.Buffer);
2427  ExFreePool(dc);
2428  free_fileref(Vcb, fileref);
2429  return Status;
2430  }
2431 
2432  dc->fileref = fileref;
2433  fileref->dc = dc;
2434 
2435  InsertHeadList(&parfileref->fcb->dir_children_index, &dc->list_entry_index);
2436 
2438  mark_fileref_dirty(fileref);
2439 
2440  InsertHeadList(&parfileref->fcb->list_entry, &fcb->list_entry); // insert in list after parent fcb
2441  InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
2442 
2445 
2446  parfileref->fcb->inode_item.transid = Vcb->superblock.generation;
2447  parfileref->fcb->inode_item.sequence++;
2448  parfileref->fcb->inode_item.st_ctime = now;
2449  parfileref->fcb->inode_item_changed = TRUE;
2450 
2451  mark_fcb_dirty(parfileref->fcb);
2452 
2453  parfileref->fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
2454  parfileref->fcb->subvol->root_item.ctime = now;
2455 
2456  fileref->parent = (struct _file_ref*)parfileref;
2457 
2459  InsertTailList(&parfileref->children, &fileref->list_entry);
2461 
2462  increase_fileref_refcount(parfileref);
2463 
2464  *pfileref = fileref;
2465 
2467 
2468  return STATUS_SUCCESS;
2469 }
2470 
2471 // LXSS programs can be distinguished by the fact they have a NULL PEB.
2472 #ifdef _AMD64_
2473 #ifdef __REACTOS__
2474 NTSYSAPI
2475 NTSTATUS
2476 NTAPI
2479  _In_ PROCESSINFOCLASS ProcessInformationClass,
2480  _Out_ PVOID ProcessInformation,
2481  _In_ ULONG ProcessInformationLength,
2483 );
2484 #endif
2485 static __inline BOOL called_from_lxss() {
2486  NTSTATUS Status;
2488  ULONG retlen;
2489 
2491 
2492  if (!NT_SUCCESS(Status)) {
2493  ERR("ZwQueryInformationProcess returned %08x\n", Status);
2494  return FALSE;
2495  }
2496 
2497  return !pbi.PebBaseAddress;
2498 }
2499 #else
2500 #define called_from_lxss() FALSE
2501 #endif
2502 
2504  PFILE_OBJECT FileObject, file_ref* related, BOOL loaded_related, PUNICODE_STRING fnus, ULONG disposition, ULONG options, LIST_ENTRY* rollback) {
2505  NTSTATUS Status;
2506  file_ref *fileref, *parfileref = NULL;
2507  ULONG i, j;
2508  ccb* ccb;
2509  static const WCHAR datasuf[] = {':','$','D','A','T','A',0};
2510  UNICODE_STRING dsus, fpus, stream;
2513  ECP_LIST* ecp_list;
2515 #ifdef DEBUG_FCB_REFCOUNTS
2516  LONG oc;
2517 #endif
2518 
2519  TRACE("(%p, %p, %p, %.*S, %x, %x)\n", Irp, Vcb, FileObject, fnus->Length / sizeof(WCHAR), fnus->Buffer, disposition, options);
2520 
2521  if (Vcb->readonly)
2523 
2525  return STATUS_CANNOT_DELETE;
2526 
2527  if (NT_SUCCESS(FsRtlGetEcpListFromIrp(Irp, &ecp_list)) && ecp_list) {
2528  void* ctx = NULL;
2529  GUID type;
2530  ULONG ctxsize;
2531 
2532  do {
2533  Status = FsRtlGetNextExtraCreateParameter(ecp_list, ctx, &type, &ctx, &ctxsize);
2534 
2535  if (NT_SUCCESS(Status)) {
2536  if (RtlCompareMemory(&type, &GUID_ECP_ATOMIC_CREATE, sizeof(GUID)) == sizeof(GUID) && ctxsize >= sizeof(ATOMIC_CREATE_ECP_CONTEXT)) {
2537  acec = ctx;
2538  break;
2539  }
2540  }
2541  } while (NT_SUCCESS(Status));
2542  }
2543 
2544  dsus.Buffer = (WCHAR*)datasuf;
2545  dsus.Length = dsus.MaximumLength = sizeof(datasuf) - sizeof(WCHAR);
2546  fpus.Buffer = NULL;
2547 
2548  if (!loaded_related) {
2549  Status = open_fileref(Vcb, &parfileref, fnus, related, TRUE, NULL, NULL, pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp);
2550 
2551  if (!NT_SUCCESS(Status))
2552  goto end;
2553  } else
2554  parfileref = related;
2555 
2556  if (parfileref->fcb->type != BTRFS_TYPE_DIRECTORY && (fnus->Length < sizeof(WCHAR) || fnus->Buffer[0] != ':')) {
2558  goto end;
2559  }
2560 
2561  if (is_subvol_readonly(parfileref->fcb->subvol, Irp)) {
2563  goto end;
2564  }
2565 
2566  i = (fnus->Length / sizeof(WCHAR))-1;
2567  while ((fnus->Buffer[i] == '\\' || fnus->Buffer[i] == '/') && i > 0) { i--; }
2568 
2569  j = i;
2570 
2571  while (i > 0 && fnus->Buffer[i-1] != '\\' && fnus->Buffer[i-1] != '/') { i--; }
2572 
2573  fpus.MaximumLength = (USHORT)((j - i + 2) * sizeof(WCHAR));
2574  fpus.Buffer = ExAllocatePoolWithTag(pool_type, fpus.MaximumLength, ALLOC_TAG);
2575  if (!fpus.Buffer) {
2576  ERR("out of memory\n");
2578  goto end;
2579  }
2580 
2581  fpus.Length = (USHORT)((j - i + 1) * sizeof(WCHAR));
2582 
2583  RtlCopyMemory(fpus.Buffer, &fnus->Buffer[i], (j - i + 1) * sizeof(WCHAR));
2584  fpus.Buffer[j - i + 1] = 0;
2585 
2586  if (fpus.Length > dsus.Length) { // check for :$DATA suffix
2587  UNICODE_STRING lb;
2588 
2589  lb.Buffer = &fpus.Buffer[(fpus.Length - dsus.Length)/sizeof(WCHAR)];
2590  lb.Length = lb.MaximumLength = dsus.Length;
2591 
2592  TRACE("lb = %.*S\n", lb.Length/sizeof(WCHAR), lb.Buffer);
2593 
2594  if (FsRtlAreNamesEqual(&dsus, &lb, TRUE, NULL)) {
2595  TRACE("ignoring :$DATA suffix\n");
2596 
2597  fpus.Length -= lb.Length;
2598 
2599  if (fpus.Length > sizeof(WCHAR) && fpus.Buffer[(fpus.Length-1)/sizeof(WCHAR)] == ':')
2600  fpus.Length -= sizeof(WCHAR);
2601 
2602  TRACE("fpus = %.*S\n", fpus.Length / sizeof(WCHAR), fpus.Buffer);
2603  }
2604  }
2605 
2606  stream.Length = 0;
2607 
2608  for (i = 0; i < fpus.Length / sizeof(WCHAR); i++) {
2609  if (fpus.Buffer[i] == ':') {
2610  stream.Length = (USHORT)(fpus.Length - (i * sizeof(WCHAR)) - sizeof(WCHAR));
2611  stream.Buffer = &fpus.Buffer[i+1];
2612  fpus.Buffer[i] = 0;
2613  fpus.Length = (USHORT)(i * sizeof(WCHAR));
2614  break;
2615  }
2616  }
2617 
2618  if (stream.Length > 0) {
2619  Status = create_stream(Vcb, &fileref, &parfileref, &fpus, &stream, Irp, options, pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, rollback);
2620  if (!NT_SUCCESS(Status)) {
2621  ERR("create_stream returned %08x\n", Status);
2622  goto end;
2623  }
2624 
2625  IoSetShareAccess(IrpSp->Parameters.Create.SecurityContext->DesiredAccess, IrpSp->Parameters.Create.ShareAccess,
2626  FileObject, &fileref->fcb->share_access);
2627  } else {
2628  ACCESS_MASK granted_access;
2629 
2630  if (!is_file_name_valid(&fpus, FALSE)) {
2632  goto end;
2633  }
2634 
2635  SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2636 
2637  if (!SeAccessCheck(parfileref->fcb->sd, &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
2640  &granted_access, &Status)) {
2641  SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2642  goto end;
2643  }
2644 
2645  SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
2646 
2647  if (Irp->AssociatedIrp.SystemBuffer && IrpSp->Parameters.Create.EaLength > 0) {
2648  ULONG offset;
2649 
2650  Status = IoCheckEaBufferValidity(Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.Create.EaLength, &offset);
2651  if (!NT_SUCCESS(Status)) {
2652  ERR("IoCheckEaBufferValidity returned %08x (error at offset %u)\n", Status, offset);
2653  goto end;
2654  }
2655  }
2656 
2657  Status = file_create2(Irp, Vcb, &fpus, parfileref, options, Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.Create.EaLength,
2658  &fileref, rollback);
2659 
2660  if (!NT_SUCCESS(Status)) {
2661  ERR("file_create2 returned %08x\n", Status);
2662  goto end;
2663  }
2664 
2665  IoSetShareAccess(IrpSp->Parameters.Create.SecurityContext->DesiredAccess, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access);
2666 
2669  }
2670 
2671  FileObject->FsContext = fileref->fcb;
2672 
2674  if (!ccb) {
2675  ERR("out of memory\n");
2677  fileref->deleted = TRUE;
2678  fileref->fcb->deleted = TRUE;
2679 
2680  if (stream.Length == 0) {
2681  ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
2682  parfileref->fcb->inode_item.st_size -= fileref->dc->utf8.Length * 2;
2683  ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2684  }
2685 
2686  free_fileref(Vcb, fileref);
2687  goto end;
2688  }
2689 
2690  RtlZeroMemory(ccb, sizeof(*ccb));
2691 
2692  ccb->fileref = fileref;
2693 
2695  ccb->NodeSize = sizeof(*ccb);
2696  ccb->disposition = disposition;
2697  ccb->options = options;
2698  ccb->query_dir_offset = 0;
2700  ccb->has_wildcard = FALSE;
2701  ccb->specific_file = FALSE;
2702  ccb->access = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
2704  ccb->reserving = FALSE;
2705  ccb->lxss = called_from_lxss();
2706 
2707 #ifdef DEBUG_FCB_REFCOUNTS
2708  oc = InterlockedIncrement(&fileref->open_count);
2709  ERR("fileref %p: open_count now %i\n", fileref, oc);
2710 #else
2711  InterlockedIncrement(&fileref->open_count);
2712 #endif
2713  InterlockedIncrement(&Vcb->open_files);
2714 
2715  FileObject->FsContext2 = ccb;
2716 
2717  FileObject->SectionObjectPointer = &fileref->fcb->nonpaged->segment_object;
2718 
2719  // FIXME - ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT
2721  if (acec->ReparseBufferLength > sizeof(UINT32) && *(UINT32*)acec->ReparseBuffer == IO_REPARSE_TAG_SYMLINK) {
2723  fileref->fcb->type = BTRFS_TYPE_FILE;
2724  }
2725 
2726  if (fileref->fcb->type == BTRFS_TYPE_SOCKET || fileref->fcb->type == BTRFS_TYPE_FIFO ||
2727  fileref->fcb->type == BTRFS_TYPE_CHARDEV || fileref->fcb->type == BTRFS_TYPE_BLOCKDEV) {
2728  // NOP. If called from LXSS, humour it - we hardcode the values elsewhere.
2729  } else {
2731  if (!NT_SUCCESS(Status)) {
2732  ERR("set_reparse_point2 returned %08x\n", Status);
2733  fileref->deleted = TRUE;
2734  fileref->fcb->deleted = TRUE;
2735 
2736  if (stream.Length == 0) {
2737  ExAcquireResourceExclusiveLite(parfileref->fcb->Header.Resource, TRUE);
2738  parfileref->fcb->inode_item.st_size -= fileref->dc->utf8.Length * 2;
2739  ExReleaseResourceLite(parfileref->fcb->Header.Resource);
2740  }
2741 
2742  free_fileref(Vcb, fileref);
2743  return Status;
2744  }
2745  }
2746 
2748  }
2749 
2750  fileref->dc->type = fileref->fcb->type;
2751 
2752  goto end2;
2753 
2754 end:
2755  if (fpus.Buffer)
2756  ExFreePool(fpus.Buffer);
2757 
2758 end2:
2759  if (parfileref && !loaded_related)
2760  free_fileref(Vcb, parfileref);
2761 
2762  return Status;
2763 }
2764 
2765 static __inline void debug_create_options(ULONG RequestedOptions) {
2766  if (RequestedOptions != 0) {
2767  ULONG options = RequestedOptions;
2768 
2769  TRACE("requested options:\n");
2770 
2771  if (options & FILE_DIRECTORY_FILE) {
2772  TRACE(" FILE_DIRECTORY_FILE\n");
2774  }
2775 
2776  if (options & FILE_WRITE_THROUGH) {
2777  TRACE(" FILE_WRITE_THROUGH\n");
2779  }
2780 
2781  if (options & FILE_SEQUENTIAL_ONLY) {
2782  TRACE(" FILE_SEQUENTIAL_ONLY\n");
2784  }
2785 
2787  TRACE(" FILE_NO_INTERMEDIATE_BUFFERING\n");
2789  }
2790 
2792  TRACE(" FILE_SYNCHRONOUS_IO_ALERT\n");
2794  }
2795 
2797  TRACE(" FILE_SYNCHRONOUS_IO_NONALERT\n");
2799  }
2800 
2802  TRACE(" FILE_NON_DIRECTORY_FILE\n");
2804  }
2805 
2807  TRACE(" FILE_CREATE_TREE_CONNECTION\n");
2809  }
2810 
2812  TRACE(" FILE_COMPLETE_IF_OPLOCKED\n");
2814  }
2815 
2816  if (options & FILE_NO_EA_KNOWLEDGE) {
2817  TRACE(" FILE_NO_EA_KNOWLEDGE\n");
2819  }
2820 
2822  TRACE(" FILE_OPEN_REMOTE_INSTANCE\n");
2824  }
2825 
2826  if (options & FILE_RANDOM_ACCESS) {
2827  TRACE(" FILE_RANDOM_ACCESS\n");
2829  }
2830 
2831  if (options & FILE_DELETE_ON_CLOSE) {
2832  TRACE(" FILE_DELETE_ON_CLOSE\n");
2834  }
2835 
2836  if (options & FILE_OPEN_BY_FILE_ID) {
2837  TRACE(" FILE_OPEN_BY_FILE_ID\n");
2839  }
2840 
2842  TRACE(" FILE_OPEN_FOR_BACKUP_INTENT\n");
2844  }
2845 
2846  if (options & FILE_NO_COMPRESSION) {
2847  TRACE(" FILE_NO_COMPRESSION\n");
2849  }
2850 
2851 #if NTDDI_VERSION >= NTDDI_WIN7
2853  TRACE(" FILE_OPEN_REQUIRING_OPLOCK\n");
2855  }
2856 
2858  TRACE(" FILE_DISALLOW_EXCLUSIVE\n");
2860  }
2861 #endif
2862 
2864  TRACE(" FILE_RESERVE_OPFILTER\n");
2866  }
2867 
2869  TRACE(" FILE_OPEN_REPARSE_POINT\n");
2871  }
2872 
2873  if (options & FILE_OPEN_NO_RECALL) {
2874  TRACE(" FILE_OPEN_NO_RECALL\n");
2876  }
2877 
2879  TRACE(" FILE_OPEN_FOR_FREE_SPACE_QUERY\n");
2881  }
2882 
2883  if (options)
2884  TRACE(" unknown options: %x\n", options);
2885  } else {
2886  TRACE("requested options: (none)\n");
2887  }
2888 }
2889 
2891  NTSTATUS Status;
2892 
2894  ULONG size, bytes_read, i;
2895 
2896  if (fcb->type == BTRFS_TYPE_FILE && fcb->inode_item.st_size < sizeof(ULONG)) {
2897  WARN("file was too short to be a reparse point\n");
2898  return STATUS_INVALID_PARAMETER;
2899  }
2900 
2901  // 0x10007 = 0xffff (maximum length of data buffer) + 8 bytes header
2902  size = (ULONG)min(0x10007, fcb->inode_item.st_size);
2903 
2904  if (size == 0)
2905  return STATUS_INVALID_PARAMETER;
2906 
2908  if (!*data) {
2909  ERR("out of memory\n");
2911  }
2912 
2913  Status = read_file(fcb, *data, 0, size, &bytes_read, NULL);
2914  if (!NT_SUCCESS(Status)) {
2915  ERR("read_file_fcb returned %08x\n", Status);
2916  ExFreePool(*data);
2917  return Status;
2918  }
2919 
2920  if (fcb->type == BTRFS_TYPE_SYMLINK) {
2921  ULONG stringlen, reqlen;
2922  UINT16 subnamelen, printnamelen;
2923  REPARSE_DATA_BUFFER* rdb;
2924 
2925  Status = RtlUTF8ToUnicodeN(NULL, 0, &stringlen, (char*)*data, bytes_read);
2926  if (!NT_SUCCESS(Status)) {
2927  ERR("RtlUTF8ToUnicodeN 1 returned %08x\n", Status);
2928  ExFreePool(*data);
2929  return Status;
2930  }
2931 
2932  subnamelen = printnamelen = (USHORT)stringlen;
2933 
2934  reqlen = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + subnamelen + printnamelen;
2935 
2936  rdb = ExAllocatePoolWithTag(PagedPool, reqlen, ALLOC_TAG);
2937 
2938  if (!rdb) {
2939  ERR("out of memory\n");
2940  ExFreePool(*data);
2942  }
2943 
2945  rdb->ReparseDataLength = (USHORT)(reqlen - offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer));
2946  rdb->Reserved = 0;
2947 
2948  rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
2949  rdb->SymbolicLinkReparseBuffer.SubstituteNameLength = subnamelen;
2950  rdb->SymbolicLinkReparseBuffer.PrintNameOffset = subnamelen;
2951  rdb->SymbolicLinkReparseBuffer.PrintNameLength = printnamelen;
2953 
2954  Status = RtlUTF8ToUnicodeN(&rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)],
2955  stringlen, &stringlen, (char*)*data, size);
2956 
2957  if (!NT_SUCCESS(Status)) {
2958  ERR("RtlUTF8ToUnicodeN 2 returned %08x\n", Status);
2959  ExFreePool(rdb);
2960  ExFreePool(*data);
2961  return Status;
2962  }
2963 
2964  for (i = 0; i < stringlen / sizeof(WCHAR); i++) {
2965  if (rdb->SymbolicLinkReparseBuffer.PathBuffer[(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)) + i] == '/')
2966  rdb->SymbolicLinkReparseBuffer.PathBuffer[(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)) + i] = '\\';
2967  }
2968 
2969  RtlCopyMemory(&rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.PrintNameOffset / sizeof(WCHAR)],
2970  &rdb->SymbolicLinkReparseBuffer.PathBuffer[rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR)],
2971  rdb->SymbolicLinkReparseBuffer.SubstituteNameLength);
2972 
2973  ExFreePool(*data);
2974 
2975  *data = (UINT8*)rdb;
2976  } else {
2978  if (!NT_SUCCESS(Status)) {
2979  ERR("FsRtlValidateReparsePointBuffer returned %08x\n", Status);
2980  ExFreePool(*data);
2981  return Status;
2982  }
2983  }
2984  } else if (fcb->type == BTRFS_TYPE_DIRECTORY) {
2986  return STATUS_INTERNAL_ERROR;
2987 
2988  if (fcb->reparse_xattr.Length < sizeof(ULONG)) {
2989  WARN("xattr was too short to be a reparse point\n");
2990  return STATUS_INTERNAL_ERROR;
2991  }
2992 
2994  if (!NT_SUCCESS(Status)) {
2995  ERR("FsRtlValidateReparsePointBuffer returned %08x\n", Status);
2996  return Status;
2997  }
2998 
3000  if (!*data) {
3001  ERR("out of memory\n");
3003  }
3004 
3006  } else
3007  return STATUS_INVALID_PARAMETER;
3008 
3009  return STATUS_SUCCESS;
3010 }
3011 
3013  LIST_ENTRY* le;
3014  NTSTATUS Status;
3015 
3016  if (fcb->csum_loaded)
3017  return;
3018 
3020  goto end;
3021 
3022  le = fcb->extents.Flink;
3023  while (le != &fcb->extents) {
3025 
3026  if (ext->extent_data.type == EXTENT_TYPE_REGULAR) {
3027  EXTENT_DATA2* ed2 = (EXTENT_DATA2*)&ext->extent_data.data[0];
3028  UINT64 len;
3029 
3030  len = (ext->extent_data.compression == BTRFS_COMPRESSION_NONE ? ed2->num_bytes : ed2->size) / Vcb->superblock.sector_size;
3031 
3033  if (!ext->csum) {
3034  ERR("out of memory\n");
3035  goto end;
3036  }
3037 
3038  Status = load_csum(Vcb, ext->csum, ed2->address + (ext->extent_data.compression == BTRFS_COMPRESSION_NONE ? ed2->offset : 0), len, Irp);
3039 
3040  if (!NT_SUCCESS(Status)) {
3041  ERR("load_csum returned %08x\n", Status);
3042  goto end;
3043  }
3044  }
3045 
3046  le = le->Flink;
3047  }
3048 
3049 end:
3050  fcb->csum_loaded = TRUE;
3051 }
3052 
3055  ULONG RequestedDisposition;
3056  ULONG options;
3057  NTSTATUS Status;
3058  ccb* ccb;
3060  USHORT parsed;
3061  ULONG fn_offset = 0;
3062  file_ref *related, *fileref = NULL;
3064  ACCESS_MASK granted_access;
3065  BOOL loaded_related = FALSE;
3067 #ifdef DEBUG_FCB_REFCOUNTS
3068  LONG oc;
3069 #endif
3070 #ifdef DEBUG_STATS
3071  LARGE_INTEGER time1, time2;
3072  UINT8 open_type = 0;
3073 
3075 #endif
3076 
3077  Irp->IoStatus.Information = 0;
3078 
3079  RequestedDisposition = ((IrpSp->Parameters.Create.Options >> 24) & 0xff);
3081 
3082  if (options & FILE_DIRECTORY_FILE && RequestedDisposition == FILE_SUPERSEDE) {
3083  WARN("error - supersede requested with FILE_DIRECTORY_FILE\n");
3084  return STATUS_INVALID_PARAMETER;
3085  }
3086 
3088 
3089  if (!FileObject) {
3090  ERR("FileObject was NULL\n");
3091  return STATUS_INVALID_PARAMETER;
3092  }
3093 
3094  if (FileObject->RelatedFileObject && FileObject->RelatedFileObject->FsContext2) {
3095  struct _ccb* relatedccb = FileObject->RelatedFileObject->FsContext2;
3096 
3097  related = relatedccb->fileref;
3098  } else
3099  related = NULL;
3100 
3102 
3103  switch (RequestedDisposition) {
3104  case FILE_SUPERSEDE:
3105  TRACE("requested disposition: FILE_SUPERSEDE\n");
3106  break;
3107 
3108  case FILE_CREATE:
3109  TRACE("requested disposition: FILE_CREATE\n");
3110  break;
3111 
3112  case FILE_OPEN:
3113  TRACE("requested disposition: FILE_OPEN\n");
3114  break;
3115 
3116  case FILE_OPEN_IF:
3117  TRACE("requested disposition: FILE_OPEN_IF\n");
3118  break;
3119 
3120  case FILE_OVERWRITE:
3121  TRACE("requested disposition: FILE_OVERWRITE\n");
3122  break;
3123 
3124  case FILE_OVERWRITE_IF:
3125  TRACE("requested disposition: FILE_OVERWRITE_IF\n");
3126  break;
3127 
3128  default:
3129  ERR("unknown disposition: %x\n", RequestedDisposition);
3131  goto exit;
3132  }
3133 
3134  fn = FileObject->FileName;
3135 
3136  TRACE("(%.*S)\n", fn.Length / sizeof(WCHAR), fn.Buffer);
3137  TRACE("FileObject = %p\n", FileObject);
3138 
3139  if (Vcb->readonly && (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == FILE_CREATE || RequestedDisposition == FILE_OVERWRITE)) {
3141  goto exit;
3142  }
3143 
3144  acquire_fcb_lock_exclusive(Vcb);
3145 
3146  if (options & FILE_OPEN_BY_FILE_ID) {
3147  if (fn.Length == sizeof(UINT64) && related && RequestedDisposition == FILE_OPEN) {
3148  UINT64 inode;
3149 
3150  RtlCopyMemory(&inode, fn.Buffer, sizeof(UINT64));
3151 
3152  if (related->fcb == Vcb->root_fileref->fcb && inode == 0)
3153  inode = Vcb->root_fileref->fcb->inode;
3154 
3155  if (inode == 0) { // we use 0 to mean the parent of a subvolume
3156  fileref = related->parent;
3159  } else {
3161  }
3162  } else {
3163  WARN("FILE_OPEN_BY_FILE_ID only supported for inodes\n");
3165  release_fcb_lock(Vcb);
3166  goto exit;
3167  }
3168  } else {
3169  if (related && fn.Length != 0 && fn.Buffer[0] == '\\') {
3171  release_fcb_lock(Vcb);
3172  goto exit;
3173  }
3174 
3175  if (!related && RequestedDisposition != FILE_OPEN && !(IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY)) {
3176  ULONG fnoff;
3177 
3178  Status = open_fileref(Vcb, &related, &fn, NULL, TRUE, &parsed, &fnoff,
3179  pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp);
3180 
3183  else if (Status == STATUS_REPARSE)
3184  fileref = related;
3185  else if (NT_SUCCESS(Status)) {
3186  fnoff *= sizeof(WCHAR);
3187  fnoff += (related->dc ? related->dc->name.Length : 0) + sizeof(WCHAR);
3188 
3189  if (related->fcb->atts & FILE_ATTRIBUTE_REPARSE_POINT) {
3191  fileref = related;
3192  parsed = (USHORT)fnoff - sizeof(WCHAR);
3193  } else {
3194  fn.Buffer = &fn.Buffer[fnoff / sizeof(WCHAR)];
3195  fn.Length -= (USHORT)fnoff;
3196 
3197  Status = open_fileref(Vcb, &fileref, &fn, related, IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY, &parsed, &fn_offset,
3198  pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp);
3199 
3200  loaded_related = TRUE;
3201  }
3202 
3203  }
3204  } else {
3205  Status = open_fileref(Vcb, &fileref, &fn, related, IrpSp->Flags & SL_OPEN_TARGET_DIRECTORY, &parsed, &fn_offset,
3206  pool_type, IrpSp->Flags & SL_CASE_SENSITIVE, Irp);
3207  }
3208  }
3209 
3210  if (Status == STATUS_REPARSE) {
3212 
3216 
3217  if (!NT_SUCCESS(Status)) {
3218  ERR("get_reparse_block returned %08x\n", Status);
3219 
3221  } else {
3223  RtlCopyMemory(&Irp->IoStatus.Information, data, sizeof(ULONG));
3224 
3225  data->Reserved = FileObject->FileName.Length - parsed;
3226 
3227  Irp->Tail.Overlay.AuxiliaryBuffer = (void*)data;
3228 
3230  release_fcb_lock(Vcb);
3231 
3232  goto exit;
3233  }
3234  }
3235 
3236  if (NT_SUCCESS(Status) && fileref->deleted)
3238 
3239  if (NT_SUCCESS(Status)) {
3240  if (RequestedDisposition == FILE_CREATE) {
3241  TRACE("file %S already exists, returning STATUS_OBJECT_NAME_COLLISION\n", file_desc_fileref(fileref));
3243 
3245  release_fcb_lock(Vcb);
3246 
3247  goto exit;
3248  }
3249  } else if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
3250  if (RequestedDisposition == FILE_OPEN || RequestedDisposition == FILE_OVERWRITE) {
3251  TRACE("file doesn't exist, returning STATUS_OBJECT_NAME_NOT_FOUND\n");
3252  release_fcb_lock(Vcb);
3253  goto exit;
3254  }
3255  } else if (Status == STATUS_OBJECT_PATH_NOT_FOUND) {
3256  TRACE("open_fileref returned %08x\n", Status);
3257  release_fcb_lock(Vcb);
3258  goto exit;
3259  } else {
3260  ERR("open_fileref returned %08x\n", Status);
3261  release_fcb_lock(Vcb);
3262  goto exit;
3263  }
3264 
3265  if (NT_SUCCESS(Status)) { // file already exists
3266  file_ref* sf;
3267  BOOL readonly;
3268 
3269  release_fcb_lock(Vcb);
3270 
3271  if (RequestedDisposition == FILE_SUPERSEDE || RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF) {
3273 
3274 #ifdef DEBUG_STATS
3275  open_type = 1;
3276 #endif
3279 
3280  acquire_fcb_lock_exclusive(Vcb);
3282  release_fcb_lock(Vcb);
3283 
3284  goto exit;
3285  }
3286 
3287  if (Vcb->readonly) {
3289 
3290  acquire_fcb_lock_exclusive(Vcb);
3292  release_fcb_lock(Vcb);
3293 
3294  goto exit;
3295  }
3296 
3297  zero.QuadPart = 0;
3298  if (!MmCanFileBeTruncated(&fileref->fcb->nonpaged->segment_object, &zero)) {
3300 
3301  acquire_fcb_lock_exclusive(Vcb);
3303  release_fcb_lock(Vcb);
3304 
3305  goto exit;
3306  }
3307  }
3308 
3309  if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess != 0) {
3310  SeLockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
3311 
3312  if (!SeAccessCheck((fileref->fcb->ads || fileref->fcb == Vcb->dummy_fcb) ? fileref->parent->fcb->sd : fileref->fcb->sd,
3313  &IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext,
3314  TRUE, IrpSp->Parameters.Create.SecurityContext->DesiredAccess, 0, NULL,
3316  &granted_access, &Status)) {
3317  SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
3318  TRACE("SeAccessCheck failed, returning %08x\n", Status);
3319 
3320  acquire_fcb_lock_exclusive(Vcb);
3322  release_fcb_lock(Vcb);
3323 
3324  goto exit;
3325  }
3326 
3327  SeUnlockSubjectContext(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
3328  } else
3329  granted_access = 0;
3330 
3331  TRACE("deleted = %s\n", fileref->deleted ? "TRUE" : "FALSE");
3332 
3333  sf = fileref;
3334  while (sf) {
3335  if (sf->delete_on_close) {
3336  TRACE("could not open as deletion pending\n");
3338 
3339  acquire_fcb_lock_exclusive(Vcb);
3341  release_fcb_lock(Vcb);
3342 
3343  goto exit;
3344  }
3345  sf = sf->parent;
3346  }
3347 
3348  readonly = (!fileref->fcb->ads && fileref->fcb->atts & FILE_ATTRIBUTE_READONLY) || (fileref->fcb->ads && fileref->parent->fcb->atts & FILE_ATTRIBUTE_READONLY) ||
3349  is_subvol_readonly(fileref->fcb->subvol, Irp) || fileref->fcb == Vcb->dummy_fcb || Vcb->readonly;
3350 
3351  if (options & FILE_DELETE_ON_CLOSE && (fileref == Vcb->root_fileref || readonly)) {
3353 
3354  acquire_fcb_lock_exclusive(Vcb);
3356  release_fcb_lock(Vcb);
3357 
3358  goto exit;
3359  }
3360 
3361  if (readonly) {
3362  ACCESS_MASK allowed;
3363 
3366  FILE_TRAVERSE;
3367 
3368  if (!Vcb->readonly && (fileref->fcb == Vcb->dummy_fcb || fileref->fcb->inode == SUBVOL_ROOT_INODE))
3369  allowed |= DELETE;
3370 
3371  if (fileref->fcb != Vcb->dummy_fcb && !is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) {
3373 
3376  } else if (fileref->fcb->inode == SUBVOL_ROOT_INODE && is_subvol_readonly(fileref->fcb->subvol, Irp) && !Vcb->readonly) {
3377  // We allow a subvolume root to be opened read-write even if its readonly flag is set, so it can be cleared
3378 
3379  allowed |= FILE_WRITE_ATTRIBUTES;
3380  }
3381 
3382  if (IrpSp->Parameters.Create.SecurityContext->DesiredAccess & MAXIMUM_ALLOWED) {
3383  granted_access &= allowed;
3384  IrpSp->Parameters.Create.SecurityContext->AccessState->PreviouslyGrantedAccess &= allowed;
3385  } else if (granted_access & ~allowed) {
3387 
3388  acquire_fcb_lock_exclusive(Vcb);
3390  release_fcb_lock(Vcb);
3391 
3392  goto exit;
3393  }
3394  }
3395 
3398 
3399  /* How reparse points work from the point of view of the filesystem appears to
3400  * undocumented. When returning STATUS_REPARSE, MSDN encourages us to return
3401  * IO_REPARSE in Irp->IoStatus.Information, but that means we have to do our own
3402  * translation. If we instead return the reparse tag in Information, and store
3403  * a pointer to the reparse data buffer in Irp->Tail.Overlay.AuxiliaryBuffer,
3404  * IopSymlinkProcessReparse will do the translation for us. */
3405 
3407  if (!NT_SUCCESS(Status)) {
3408  ERR("get_reparse_block returned %08x\n", Status);
3410  } else {
3412  Irp->IoStatus.Information = data->ReparseTag;
3413 
3414  if (fn.Buffer[(fn.Length / sizeof(WCHAR)) - 1] == '\\')
3415  data->Reserved = sizeof(WCHAR);
3416 
3417  Irp->Tail.Overlay.AuxiliaryBuffer = (void*)data;
3418 
3419  acquire_fcb_lock_exclusive(Vcb);
3421  release_fcb_lock(Vcb);
3422 
3423  goto exit;
3424  }
3425  }
3426 
3427  if (fileref->fcb->type == BTRFS_TYPE_DIRECTORY && !fileref->fcb->ads) {
3430 
3431  acquire_fcb_lock_exclusive(Vcb);
3433  release_fcb_lock(Vcb);
3434 
3435  goto exit;
3436  }
3437  } else if (options & FILE_DIRECTORY_FILE) {
3438  TRACE("returning STATUS_NOT_A_DIRECTORY (type = %u, %S)\n", fileref->fcb->type, file_desc_fileref(fileref));
3440 
3441  acquire_fcb_lock_exclusive(Vcb);
3443  release_fcb_lock(Vcb);
3444 
3445  goto exit;
3446  }
3447 
3448  if (fileref->open_count > 0) {
3449  Status = IoCheckShareAccess(granted_access, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access, FALSE);
3450 
3451  if (!NT_SUCCESS(Status)) {
3453  TRACE("IoCheckShareAccess failed, returning %08x\n", Status);
3454  else
3455  WARN("IoCheckShareAccess failed, returning %08x\n", Status);
3456 
3457  acquire_fcb_lock_exclusive(Vcb);
3459  release_fcb_lock(Vcb);
3460 
3461  goto exit;
3462  }
3463 
3465  } else
3466  IoSetShareAccess(granted_access, IrpSp->Parameters.Create.ShareAccess, FileObject, &fileref->fcb->share_access);
3467 
3468  if (granted_access & FILE_WRITE_DATA || options & FILE_DELETE_ON_CLOSE) {
3469  if (!MmFlushImageSection(&fileref->fcb->nonpaged->segment_object, MmFlushForWrite)) {
3471 
3473 
3474  acquire_fcb_lock_exclusive(Vcb);
3476  release_fcb_lock(Vcb);
3477 
3478  goto exit;
3479  }
3480  }
3481 
3482  if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF || RequestedDisposition == FILE_SUPERSEDE) {
3483  ULONG defda, oldatts, filter;
3485  BTRFS_TIME now;
3486 
3487  if ((RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF) && readonly) {
3488  WARN("cannot overwrite readonly file\n");
3490 
3492 
3493  acquire_fcb_lock_exclusive(Vcb);
3495  release_fcb_lock(Vcb);
3496 
3497  goto exit;
3498  }
3499 
3502 
3503  acquire_fcb_lock_exclusive(Vcb);
3505  release_fcb_lock(Vcb);
3506 
3508  goto exit;
3509  }
3510 
3511  if (fileref->fcb->ads) {
3513  if (!NT_SUCCESS(Status)) {
3514  ERR("stream_set_end_of_file_information returned %08x\n", Status);
3515 
3517 
3518  acquire_fcb_lock_exclusive(Vcb);
3520  release_fcb_lock(Vcb);
3521 
3522  goto exit;
3523  }
3524  } else {
3526  if (!NT_SUCCESS(Status)) {
3527  ERR("truncate_file returned %08x\n", Status);
3528 
3530 
3531  acquire_fcb_lock_exclusive(Vcb);
3533  release_fcb_lock(Vcb);
3534 
3535  goto exit;
3536  }
3537  }
3538 
3539  if (Irp->Overlay.AllocationSize.QuadPart > 0) {
3540  Status = extend_file(fileref->fcb, fileref, Irp->Overlay.AllocationSize.QuadPart, TRUE, NULL, rollback);
3541 
3542  if (!NT_SUCCESS(Status)) {
3543  ERR("extend_file returned %08x\n", Status);
3544 
3546 
3547  acquire_fcb_lock_exclusive(Vcb);
3549  release_fcb_lock(Vcb);
3550 
3551  goto exit;
3552  }
3553  }
3554 
3555  if (!fileref->fcb->ads) {
3556  LIST_ENTRY* le;
3557 
3558  if (Irp->AssociatedIrp.SystemBuffer && IrpSp->Parameters.Create.EaLength > 0) {
3559  ULONG offset;
3560  FILE_FULL_EA_INFORMATION* eainfo;
3561 
3562  Status = IoCheckEaBufferValidity(Irp->AssociatedIrp.SystemBuffer, IrpSp->Parameters.Create.EaLength, &offset);
3563  if (!NT_SUCCESS(Status)) {
3564  ERR("IoCheckEaBufferValidity returned %08x (error at offset %u)\n", Status, offset);
3565 
3567 
3568  acquire_fcb_lock_exclusive(Vcb);
3570  release_fcb_lock(Vcb);
3571 
3572  goto exit;
3573  }
3574 
3575  fileref->fcb->ealen = 4;
3576 
3577  // capitalize EA name
3578  eainfo = Irp->AssociatedIrp.SystemBuffer;
3579  do {
3580