ReactOS  0.4.15-dev-5137-g826bd41
fileinfo.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 #include "btrfs_drv.h"
19 #include "crc32c.h"
20 
21 #if (NTDDI_VERSION >= NTDDI_WIN10)
22 // not currently in mingw - introduced with Windows 10
23 #ifndef _MSC_VER
24 #define FileIdInformation (enum _FILE_INFORMATION_CLASS)59
25 #define FileHardLinkFullIdInformation (enum _FILE_INFORMATION_CLASS)62
26 #define FileDispositionInformationEx (enum _FILE_INFORMATION_CLASS)64
27 #define FileRenameInformationEx (enum _FILE_INFORMATION_CLASS)65
28 #define FileStatInformation (enum _FILE_INFORMATION_CLASS)68
29 #define FileStatLxInformation (enum _FILE_INFORMATION_CLASS)70
30 #define FileCaseSensitiveInformation (enum _FILE_INFORMATION_CLASS)71
31 #define FileLinkInformationEx (enum _FILE_INFORMATION_CLASS)72
32 #define FileStorageReserveIdInformation (enum _FILE_INFORMATION_CLASS)74
33 
34 typedef struct _FILE_ID_INFORMATION {
38 
39 typedef struct _FILE_STAT_INFORMATION {
52 
53 typedef struct _FILE_STAT_LX_INFORMATION {
72 
73 #define LX_FILE_METADATA_HAS_UID 0x01
74 #define LX_FILE_METADATA_HAS_GID 0x02
75 #define LX_FILE_METADATA_HAS_MODE 0x04
76 #define LX_FILE_METADATA_HAS_DEVICE_ID 0x08
77 #define LX_FILE_CASE_SENSITIVE_DIR 0x10
78 
80  union {
83  };
88 
92 
93 typedef struct _FILE_LINK_INFORMATION_EX {
94  union {
97  };
102 
106 
113 
119 
120 #define FILE_RENAME_REPLACE_IF_EXISTS 0x001
121 #define FILE_RENAME_POSIX_SEMANTICS 0x002
122 #define FILE_RENAME_SUPPRESS_PIN_STATE_INHERITANCE 0x004
123 #define FILE_RENAME_SUPPRESS_STORAGE_RESERVE_INHERITANCE 0x008
124 #define FILE_RENAME_NO_INCREASE_AVAILABLE_SPACE 0x010
125 #define FILE_RENAME_NO_DECREASE_AVAILABLE_SPACE 0x020
126 #define FILE_RENAME_IGNORE_READONLY_ATTRIBUTE 0x040
127 #define FILE_RENAME_FORCE_RESIZE_TARGET_SR 0x080
128 #define FILE_RENAME_FORCE_RESIZE_SOURCE_SR 0x100
129 
130 #define FILE_DISPOSITION_DELETE 0x1
131 #define FILE_DISPOSITION_POSIX_SEMANTICS 0x2
132 #define FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK 0x4
133 #define FILE_DISPOSITION_ON_CLOSE 0x8
134 
135 #define FILE_LINK_REPLACE_IF_EXISTS 0x001
136 #define FILE_LINK_POSIX_SEMANTICS 0x002
137 #define FILE_LINK_SUPPRESS_STORAGE_RESERVE_INHERITANCE 0x008
138 #define FILE_LINK_NO_INCREASE_AVAILABLE_SPACE 0x010
139 #define FILE_LINK_NO_DECREASE_AVAILABLE_SPACE 0x020
140 #define FILE_LINK_IGNORE_READONLY_ATTRIBUTE 0x040
141 #define FILE_LINK_FORCE_RESIZE_TARGET_SR 0x080
142 #define FILE_LINK_FORCE_RESIZE_SOURCE_SR 0x100
143 
144 #else
145 
146 #define FILE_RENAME_INFORMATION_EX FILE_RENAME_INFORMATION
147 #define FILE_LINK_INFORMATION_EX FILE_LINK_INFORMATION
148 
149 #endif
150 #endif
151 
152 #ifdef __REACTOS__
153 typedef struct _FILE_RENAME_INFORMATION_EX {
154  union {
156  ULONG Flags;
157  };
160  WCHAR FileName[1];
162 
163 typedef struct _FILE_DISPOSITION_INFORMATION_EX {
164  ULONG Flags;
166 
167 typedef struct _FILE_LINK_INFORMATION_EX {
168  union {
170  ULONG Flags;
171  };
174  WCHAR FileName[1];
176 
177 #define FILE_RENAME_REPLACE_IF_EXISTS 0x001
178 #define FILE_RENAME_POSIX_SEMANTICS 0x002
179 #define FILE_RENAME_IGNORE_READONLY_ATTRIBUTE 0x040
180 
181 #define FILE_DISPOSITION_DELETE 0x1
182 #define FILE_DISPOSITION_POSIX_SEMANTICS 0x2
183 #define FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK 0x4
184 
185 #define FILE_LINK_REPLACE_IF_EXISTS 0x001
186 #define FILE_LINK_POSIX_SEMANTICS 0x002
187 #define FILE_LINK_IGNORE_READONLY_ATTRIBUTE 0x040
188 #endif
189 
191  FILE_BASIC_INFORMATION* fbi = Irp->AssociatedIrp.SystemBuffer;
192  fcb* fcb = FileObject->FsContext;
193  ccb* ccb = FileObject->FsContext2;
194  file_ref* fileref = ccb ? ccb->fileref : NULL;
195  ULONG defda, filter = 0;
196  bool inode_item_changed = false;
198 
199  if (fcb->ads) {
200  if (fileref && fileref->parent)
201  fcb = fileref->parent->fcb;
202  else {
203  ERR("stream did not have fileref\n");
204  return STATUS_INTERNAL_ERROR;
205  }
206  }
207 
208  if (!ccb) {
209  ERR("ccb was NULL\n");
211  }
212 
213  TRACE("file = %p, attributes = %lx\n", FileObject, fbi->FileAttributes);
214 
215  ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
216 
218  WARN("attempted to set FILE_ATTRIBUTE_DIRECTORY on non-directory\n");
220  goto end;
221  }
222 
224  (fbi->FileAttributes == 0 || fbi->FileAttributes & FILE_ATTRIBUTE_READONLY)) {
226  goto end;
227  }
228 
229  // don't allow readonly subvol to be made r/w if send operation running on it
230  if (fcb->inode == SUBVOL_ROOT_INODE && fcb->subvol->root_item.flags & BTRFS_SUBVOL_READONLY &&
231  fcb->subvol->send_ops > 0) {
233  goto end;
234  }
235 
236  // times of -2 are some sort of undocumented behaviour to do with LXSS
237 
238  if (fbi->CreationTime.QuadPart == -2)
239  fbi->CreationTime.QuadPart = 0;
240 
241  if (fbi->LastAccessTime.QuadPart == -2)
242  fbi->LastAccessTime.QuadPart = 0;
243 
244  if (fbi->LastWriteTime.QuadPart == -2)
245  fbi->LastWriteTime.QuadPart = 0;
246 
247  if (fbi->ChangeTime.QuadPart == -2)
248  fbi->ChangeTime.QuadPart = 0;
249 
250  if (fbi->CreationTime.QuadPart == -1)
251  ccb->user_set_creation_time = true;
252  else if (fbi->CreationTime.QuadPart != 0) {
254  inode_item_changed = true;
256 
257  ccb->user_set_creation_time = true;
258  }
259 
260  if (fbi->LastAccessTime.QuadPart == -1)
261  ccb->user_set_access_time = true;
262  else if (fbi->LastAccessTime.QuadPart != 0) {
264  inode_item_changed = true;
266 
267  ccb->user_set_access_time = true;
268  }
269 
270  if (fbi->LastWriteTime.QuadPart == -1)
271  ccb->user_set_write_time = true;
272  else if (fbi->LastWriteTime.QuadPart != 0) {
274  inode_item_changed = true;
276 
277  ccb->user_set_write_time = true;
278  }
279 
280  if (fbi->ChangeTime.QuadPart == -1)
281  ccb->user_set_change_time = true;
282  else if (fbi->ChangeTime.QuadPart != 0) {
284  inode_item_changed = true;
285  // no filter for this
286 
287  ccb->user_set_change_time = true;
288  }
289 
290  // FileAttributes == 0 means don't set - undocumented, but seen in fastfat
291  if (fbi->FileAttributes != 0) {
293  BTRFS_TIME now;
294 
296 
297  defda = get_file_attributes(Vcb, fcb->subvol, fcb->inode, fcb->type, fileref && fileref->dc && fileref->dc->name.Length >= sizeof(WCHAR) && fileref->dc->name.Buffer[0] == '.',
298  true, Irp);
299 
300  if (fcb->type == BTRFS_TYPE_DIRECTORY)
302  else if (fcb->type == BTRFS_TYPE_SYMLINK)
304 
305  fcb->atts_changed = true;
306 
309 
310  if (defda == fbi->FileAttributes)
311  fcb->atts_deleted = true;
313  fcb->atts_deleted = true;
314 
315  fcb->atts = fbi->FileAttributes;
316 
319 
322 
323  fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
324  fcb->subvol->root_item.ctime = now;
325 
326  if (fcb->inode == SUBVOL_ROOT_INODE) {
328  fcb->subvol->root_item.flags |= BTRFS_SUBVOL_READONLY;
329  else
330  fcb->subvol->root_item.flags &= ~BTRFS_SUBVOL_READONLY;
331  }
332 
333  inode_item_changed = true;
334 
336  }
337 
338  if (inode_item_changed) {
339  fcb->inode_item.transid = Vcb->superblock.generation;
341  fcb->inode_item_changed = true;
342 
344  }
345 
346  if (filter != 0)
348 
350 
351 end:
352  ExReleaseResourceLite(fcb->Header.Resource);
353 
354  return Status;
355 }
356 
358  fcb* fcb = FileObject->FsContext;
359  ccb* ccb = FileObject->FsContext2;
360  file_ref* fileref = ccb ? ccb->fileref : NULL;
361  ULONG atts, flags;
363 
364  if (!fileref)
366 
367  if (ex) {
368  FILE_DISPOSITION_INFORMATION_EX* fdi = Irp->AssociatedIrp.SystemBuffer;
369 
370  flags = fdi->Flags;
371  } else {
372  FILE_DISPOSITION_INFORMATION* fdi = Irp->AssociatedIrp.SystemBuffer;
373 
375  }
376 
377  ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
378 
379  TRACE("changing delete_on_close to %s for fcb %p\n", flags & FILE_DISPOSITION_DELETE ? "true" : "false", fcb);
380 
381  if (fcb->ads) {
382  if (fileref->parent)
383  atts = fileref->parent->fcb->atts;
384  else {
385  ERR("no fileref for stream\n");
387  goto end;
388  }
389  } else
390  atts = fcb->atts;
391 
392  TRACE("atts = %lx\n", atts);
393 
395  TRACE("not allowing readonly file to be deleted\n");
397  goto end;
398  }
399 
400  if (fcb->inode == SUBVOL_ROOT_INODE && fcb->subvol->id == BTRFS_ROOT_FSTREE) {
401  WARN("not allowing \\$Root to be deleted\n");
403  goto end;
404  }
405 
406  // FIXME - can we skip this bit for subvols?
407  if (fcb->type == BTRFS_TYPE_DIRECTORY && fcb->inode_item.st_size > 0 && (!fileref || fileref->fcb != Vcb->dummy_fcb)) {
408  TRACE("directory not empty\n");
410  goto end;
411  }
412 
413  if (!MmFlushImageSection(&fcb->nonpaged->segment_object, MmFlushForDelete)) {
415  TRACE("trying to delete file which is being mapped as an image\n");
417  goto end;
418  }
419  }
420 
422 
423  FileObject->DeletePending = flags & FILE_DISPOSITION_DELETE;
424 
426  ccb->fileref->posix_delete = true;
427 
429 
430 end:
431  ExReleaseResourceLite(fcb->Header.Resource);
432 
433  // send notification that directory is about to be deleted
435  FsRtlNotifyFullChangeDirectory(Vcb->NotifySync, &Vcb->DirNotifyList, FileObject->FsContext,
436  NULL, false, false, 0, NULL, NULL, NULL);
437  }
438 
439  return Status;
440 }
441 
442 bool has_open_children(file_ref* fileref) {
443  LIST_ENTRY* le = fileref->children.Flink;
444 
445  if (IsListEmpty(&fileref->children))
446  return false;
447 
448  while (le != &fileref->children) {
450 
451  if (c->open_count > 0)
452  return true;
453 
454  if (has_open_children(c))
455  return true;
456 
457  le = le->Flink;
458  }
459 
460  return false;
461 }
462 
463 static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
464  device_extension* Vcb = oldfcb->Vcb;
465  fcb* fcb;
466  LIST_ENTRY* le;
467 
468  // FIXME - we can skip a lot of this if the inode is about to be deleted
469 
470  fcb = create_fcb(Vcb, PagedPool); // FIXME - what if we duplicate the paging file?
471  if (!fcb) {
472  ERR("out of memory\n");
474  }
475 
476  fcb->Vcb = Vcb;
477 
478  fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
479  fcb->Header.AllocationSize = oldfcb->Header.AllocationSize;
480  fcb->Header.FileSize = oldfcb->Header.FileSize;
481  fcb->Header.ValidDataLength = oldfcb->Header.ValidDataLength;
482 
483  fcb->type = oldfcb->type;
484 
485  if (oldfcb->ads) {
486  fcb->ads = true;
487  fcb->adshash = oldfcb->adshash;
488  fcb->adsmaxlen = oldfcb->adsmaxlen;
489 
490  if (oldfcb->adsxattr.Buffer && oldfcb->adsxattr.Length > 0) {
491  fcb->adsxattr.Length = oldfcb->adsxattr.Length;
494 
495  if (!fcb->adsxattr.Buffer) {
496  ERR("out of memory\n");
497  free_fcb(fcb);
499  }
500 
503  }
504 
505  if (oldfcb->adsdata.Buffer && oldfcb->adsdata.Length > 0) {
508 
509  if (!fcb->adsdata.Buffer) {
510  ERR("out of memory\n");
511  free_fcb(fcb);
513  }
514 
516  }
517 
518  goto end;
519  }
520 
521  RtlCopyMemory(&fcb->inode_item, &oldfcb->inode_item, sizeof(INODE_ITEM));
522  fcb->inode_item_changed = true;
523 
524  if (oldfcb->sd && RtlLengthSecurityDescriptor(oldfcb->sd) > 0) {
526  if (!fcb->sd) {
527  ERR("out of memory\n");
528  free_fcb(fcb);
530  }
531 
532  RtlCopyMemory(fcb->sd, oldfcb->sd, RtlLengthSecurityDescriptor(oldfcb->sd));
533  }
534 
535  fcb->atts = oldfcb->atts;
536 
537  le = oldfcb->extents.Flink;
538  while (le != &oldfcb->extents) {
540 
541  if (!ext->ignore) {
542  extent* ext2 = ExAllocatePoolWithTag(PagedPool, offsetof(extent, extent_data) + ext->datalen, ALLOC_TAG);
543 
544  if (!ext2) {
545  ERR("out of memory\n");
546  free_fcb(fcb);
548  }
549 
550  ext2->offset = ext->offset;
551  ext2->datalen = ext->datalen;
552 
553  if (ext2->datalen > 0)
554  RtlCopyMemory(&ext2->extent_data, &ext->extent_data, ext2->datalen);
555 
556  ext2->unique = false;
557  ext2->ignore = false;
558  ext2->inserted = true;
559 
560  if (ext->csum) {
561  ULONG len;
562  EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ext->extent_data.data;
563 
564  if (ext->extent_data.compression == BTRFS_COMPRESSION_NONE)
565  len = (ULONG)ed2->num_bytes;
566  else
567  len = (ULONG)ed2->size;
568 
569  len = (len * sizeof(uint32_t)) >> Vcb->sector_shift;
570 
572  if (!ext2->csum) {
573  ERR("out of memory\n");
574  free_fcb(fcb);
576  }
577 
578  RtlCopyMemory(ext2->csum, ext->csum, len);
579  } else
580  ext2->csum = NULL;
581 
582  InsertTailList(&fcb->extents, &ext2->list_entry);
583  }
584 
585  le = le->Flink;
586  }
587 
588  le = oldfcb->hardlinks.Flink;
589  while (le != &oldfcb->hardlinks) {
590  hardlink *hl = CONTAINING_RECORD(le, hardlink, list_entry), *hl2;
591 
593 
594  if (!hl2) {
595  ERR("out of memory\n");
596  free_fcb(fcb);
598  }
599 
600  hl2->parent = hl->parent;
601  hl2->index = hl->index;
602 
603  hl2->name.Length = hl2->name.MaximumLength = hl->name.Length;
604  hl2->name.Buffer = ExAllocatePoolWithTag(PagedPool, hl2->name.MaximumLength, ALLOC_TAG);
605 
606  if (!hl2->name.Buffer) {
607  ERR("out of memory\n");
608  ExFreePool(hl2);
609  free_fcb(fcb);
611  }
612 
613  RtlCopyMemory(hl2->name.Buffer, hl->name.Buffer, hl->name.Length);
614 
615  hl2->utf8.Length = hl2->utf8.MaximumLength = hl->utf8.Length;
616  hl2->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, hl2->utf8.MaximumLength, ALLOC_TAG);
617 
618  if (!hl2->utf8.Buffer) {
619  ERR("out of memory\n");
620  ExFreePool(hl2->name.Buffer);
621  ExFreePool(hl2);
622  free_fcb(fcb);
624  }
625 
626  RtlCopyMemory(hl2->utf8.Buffer, hl->utf8.Buffer, hl->utf8.Length);
627 
628  InsertTailList(&fcb->hardlinks, &hl2->list_entry);
629 
630  le = le->Flink;
631  }
632 
633  if (oldfcb->reparse_xattr.Buffer && oldfcb->reparse_xattr.Length > 0) {
635 
637  if (!fcb->reparse_xattr.Buffer) {
638  ERR("out of memory\n");
639  free_fcb(fcb);
641  }
642 
644  }
645 
646  if (oldfcb->ea_xattr.Buffer && oldfcb->ea_xattr.Length > 0) {
648 
650  if (!fcb->ea_xattr.Buffer) {
651  ERR("out of memory\n");
652  free_fcb(fcb);
654  }
655 
657  }
658 
660 
661  le = oldfcb->xattrs.Flink;
662  while (le != &oldfcb->xattrs) {
664 
665  if (xa->valuelen > 0) {
666  xattr* xa2;
667 
669 
670  if (!xa2) {
671  ERR("out of memory\n");
672  free_fcb(fcb);
674  }
675 
676  xa2->namelen = xa->namelen;
677  xa2->valuelen = xa->valuelen;
678  xa2->dirty = xa->dirty;
679  memcpy(xa2->data, xa->data, xa->namelen + xa->valuelen);
680 
682  }
683 
684  le = le->Flink;
685  }
686 
687 end:
688  *pfcb = fcb;
689 
690  return STATUS_SUCCESS;
691 }
692 
693 typedef struct _move_entry {
699 } move_entry;
700 
703  LIST_ENTRY* le;
704 
705  ExAcquireResourceSharedLite(&me->fileref->fcb->nonpaged->dir_children_lock, true);
706 
707  le = me->fileref->fcb->dir_children_index.Flink;
708 
709  while (le != &me->fileref->fcb->dir_children_index) {
710  dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index);
711  file_ref* fr;
712  move_entry* me2;
713 
714  Status = open_fileref_child(Vcb, me->fileref, &dc->name, true, true, dc->index == 0 ? true : false, PagedPool, &fr, Irp);
715 
716  if (!NT_SUCCESS(Status)) {
717  ERR("open_fileref_child returned %08lx\n", Status);
718  ExReleaseResourceLite(&me->fileref->fcb->nonpaged->dir_children_lock);
719  return Status;
720  }
721 
723  if (!me2) {
724  ERR("out of memory\n");
725  ExReleaseResourceLite(&me->fileref->fcb->nonpaged->dir_children_lock);
727  }
728 
729  me2->fileref = fr;
730  me2->dummyfcb = NULL;
731  me2->dummyfileref = NULL;
732  me2->parent = me;
733 
734  InsertHeadList(&me->list_entry, &me2->list_entry);
735 
736  le = le->Flink;
737  }
738 
739  ExReleaseResourceLite(&me->fileref->fcb->nonpaged->dir_children_lock);
740 
741  return STATUS_SUCCESS;
742 }
743 
745  uint8_t c;
746 
747  c = dc->hash >> 24;
748 
749  if (fcb->hash_ptrs[c] == &dc->list_entry_hash) {
750  if (dc->list_entry_hash.Flink == &fcb->dir_children_hash)
751  fcb->hash_ptrs[c] = NULL;
752  else {
753  dir_child* dc2 = CONTAINING_RECORD(dc->list_entry_hash.Flink, dir_child, list_entry_hash);
754 
755  if (dc2->hash >> 24 == c)
756  fcb->hash_ptrs[c] = &dc2->list_entry_hash;
757  else
758  fcb->hash_ptrs[c] = NULL;
759  }
760  }
761 
762  RemoveEntryList(&dc->list_entry_hash);
763 
764  c = dc->hash_uc >> 24;
765 
766  if (fcb->hash_ptrs_uc[c] == &dc->list_entry_hash_uc) {
767  if (dc->list_entry_hash_uc.Flink == &fcb->dir_children_hash_uc)
768  fcb->hash_ptrs_uc[c] = NULL;
769  else {
770  dir_child* dc2 = CONTAINING_RECORD(dc->list_entry_hash_uc.Flink, dir_child, list_entry_hash_uc);
771 
772  if (dc2->hash_uc >> 24 == c)
774  else
775  fcb->hash_ptrs_uc[c] = NULL;
776  }
777  }
778 
779  RemoveEntryList(&dc->list_entry_hash_uc);
780 }
781 
784  fcb* fcb;
785  SECURITY_SUBJECT_CONTEXT subjcont;
786  PSID owner;
787  BOOLEAN defaulted;
789  BTRFS_TIME now;
790 
792  if (!fcb) {
793  ERR("out of memory\n");
795  }
796 
799 
800  fcb->Vcb = Vcb;
801 
802  fcb->subvol = r;
803  fcb->inode = InterlockedIncrement64(&r->lastinode);
804  fcb->hash = calc_crc32c(0xffffffff, (uint8_t*)&fcb->inode, sizeof(uint64_t));
806 
807  fcb->inode_item.generation = Vcb->superblock.generation;
808  fcb->inode_item.transid = Vcb->superblock.generation;
809  fcb->inode_item.st_nlink = 1;
810  fcb->inode_item.st_mode = __S_IFDIR | inherit_mode(parfcb, true);
813 
814  fcb->atts = get_file_attributes(Vcb, fcb->subvol, fcb->inode, fcb->type, false, true, NULL);
815 
816  SeCaptureSubjectContext(&subjcont);
817 
818  Status = SeAssignSecurity(parfcb->sd, NULL, (void**)&fcb->sd, true, &subjcont, IoGetFileObjectGenericMapping(), PagedPool);
819 
820  if (!NT_SUCCESS(Status)) {
821  reap_fcb(fcb);
822  ERR("SeAssignSecurity returned %08lx\n", Status);
823  return Status;
824  }
825 
826  if (!fcb->sd) {
827  reap_fcb(fcb);
828  ERR("SeAssignSecurity returned NULL security descriptor\n");
829  return STATUS_INTERNAL_ERROR;
830  }
831 
832  Status = RtlGetOwnerSecurityDescriptor(fcb->sd, &owner, &defaulted);
833  if (!NT_SUCCESS(Status)) {
834  ERR("RtlGetOwnerSecurityDescriptor returned %08lx\n", Status);
836  fcb->sd_dirty = true;
837  } else {
838  fcb->inode_item.st_uid = sid_to_uid(owner);
840  }
841 
842  find_gid(fcb, parfcb, &subjcont);
843 
844  fcb->inode_item_changed = true;
845 
846  fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
847  fcb->Header.AllocationSize.QuadPart = 0;
848  fcb->Header.FileSize.QuadPart = 0;
849  fcb->Header.ValidDataLength.QuadPart = 0;
850 
851  fcb->created = true;
852 
853  if (parfcb->inode_item.flags & BTRFS_INODE_COMPRESS)
855 
858 
860  if (!fcb->hash_ptrs) {
861  ERR("out of memory\n");
863  }
864 
865  RtlZeroMemory(fcb->hash_ptrs, sizeof(LIST_ENTRY*) * 256);
866 
868  if (!fcb->hash_ptrs_uc) {
869  ERR("out of memory\n");
871  }
872 
873  RtlZeroMemory(fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256);
874 
875  acquire_fcb_lock_exclusive(Vcb);
877  InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
878  r->fcbs_version++;
879  release_fcb_lock(Vcb);
880 
882 
883  *pfcb = fcb;
884 
885  return STATUS_SUCCESS;
886 }
887 
889  LIST_ENTRY* lastle = NULL;
890  uint32_t hash = fcb->hash;
891 
892  if (fcb->subvol->fcbs_ptrs[hash >> 24]) {
893  LIST_ENTRY* le = fcb->subvol->fcbs_ptrs[hash >> 24];
894 
895  while (le != &fcb->subvol->fcbs) {
896  struct _fcb* fcb2 = CONTAINING_RECORD(le, struct _fcb, list_entry);
897 
898  if (fcb2->hash > hash) {
899  lastle = le->Blink;
900  break;
901  }
902 
903  le = le->Flink;
904  }
905  }
906 
907  if (!lastle) {
908  uint8_t c = hash >> 24;
909 
910  if (c != 0xff) {
911  uint8_t d = c + 1;
912 
913  do {
914  if (fcb->subvol->fcbs_ptrs[d]) {
915  lastle = fcb->subvol->fcbs_ptrs[d]->Blink;
916  break;
917  }
918 
919  d++;
920  } while (d != 0);
921  }
922  }
923 
924  if (lastle) {
925  InsertHeadList(lastle, &fcb->list_entry);
926 
927  if (lastle == &fcb->subvol->fcbs || (CONTAINING_RECORD(lastle, struct _fcb, list_entry)->hash >> 24) != (hash >> 24))
928  fcb->subvol->fcbs_ptrs[hash >> 24] = &fcb->list_entry;
929  } else {
930  InsertTailList(&fcb->subvol->fcbs, &fcb->list_entry);
931 
932  if (fcb->list_entry.Blink == &fcb->subvol->fcbs || (CONTAINING_RECORD(fcb->list_entry.Blink, struct _fcb, list_entry)->hash >> 24) != (hash >> 24))
933  fcb->subvol->fcbs_ptrs[hash >> 24] = &fcb->list_entry;
934  }
935 }
936 
938  uint8_t c = fcb->hash >> 24;
939 
940  if (fcb->subvol->fcbs_ptrs[c] == &fcb->list_entry) {
941  if (fcb->list_entry.Flink != &fcb->subvol->fcbs && (CONTAINING_RECORD(fcb->list_entry.Flink, struct _fcb, list_entry)->hash >> 24) == c)
942  fcb->subvol->fcbs_ptrs[c] = fcb->list_entry.Flink;
943  else
944  fcb->subvol->fcbs_ptrs[c] = NULL;
945  }
946 
948 }
949 
952  LIST_ENTRY move_list, *le;
953  move_entry* me;
955  BTRFS_TIME now;
956  file_ref* origparent;
957 
958  // FIXME - make sure me->dummyfileref and me->dummyfcb get freed properly
959 
961 
964 
965  acquire_fcb_lock_exclusive(fileref->fcb->Vcb);
966 
968 
969  if (!me) {
970  ERR("out of memory\n");
972  goto end;
973  }
974 
975  origparent = fileref->parent;
976 
977  me->fileref = fileref;
979  me->dummyfcb = NULL;
980  me->dummyfileref = NULL;
981  me->parent = NULL;
982 
984 
985  le = move_list.Flink;
986  while (le != &move_list) {
988 
989  ExAcquireResourceSharedLite(me->fileref->fcb->Header.Resource, true);
990 
991  if (!me->fileref->fcb->ads && me->fileref->fcb->subvol == origparent->fcb->subvol) {
992  Status = add_children_to_move_list(fileref->fcb->Vcb, me, Irp);
993 
994  if (!NT_SUCCESS(Status)) {
995  ERR("add_children_to_move_list returned %08lx\n", Status);
996  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
997  goto end;
998  }
999  }
1000 
1001  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
1002 
1003  le = le->Flink;
1004  }
1005 
1007 
1008  // loop through list and create new inodes
1009 
1010  le = move_list.Flink;
1011  while (le != &move_list) {
1013 
1014  if (me->fileref->fcb->inode != SUBVOL_ROOT_INODE && me->fileref->fcb != fileref->fcb->Vcb->dummy_fcb) {
1015  if (!me->dummyfcb) {
1016  ULONG defda;
1017 
1018  ExAcquireResourceExclusiveLite(me->fileref->fcb->Header.Resource, true);
1019 
1020  Status = duplicate_fcb(me->fileref->fcb, &me->dummyfcb);
1021  if (!NT_SUCCESS(Status)) {
1022  ERR("duplicate_fcb returned %08lx\n", Status);
1023  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
1024  goto end;
1025  }
1026 
1027  me->dummyfcb->subvol = me->fileref->fcb->subvol;
1028  me->dummyfcb->inode = me->fileref->fcb->inode;
1029  me->dummyfcb->hash = me->fileref->fcb->hash;
1030 
1031  if (!me->dummyfcb->ads) {
1032  me->dummyfcb->sd_dirty = me->fileref->fcb->sd_dirty;
1037  me->dummyfcb->ea_changed = me->fileref->fcb->ea_changed;
1038  }
1039 
1040  me->dummyfcb->created = me->fileref->fcb->created;
1041  me->dummyfcb->deleted = me->fileref->fcb->deleted;
1042  mark_fcb_dirty(me->dummyfcb);
1043 
1044  if (!me->fileref->fcb->ads) {
1045  LIST_ENTRY* le2;
1046 
1047  me->fileref->fcb->subvol = destdir->fcb->subvol;
1048  me->fileref->fcb->inode = InterlockedIncrement64(&destdir->fcb->subvol->lastinode);
1049  me->fileref->fcb->hash = calc_crc32c(0xffffffff, (uint8_t*)&me->fileref->fcb->inode, sizeof(uint64_t));
1050  me->fileref->fcb->inode_item.st_nlink = 1;
1051 
1052  defda = get_file_attributes(me->fileref->fcb->Vcb, me->fileref->fcb->subvol, me->fileref->fcb->inode,
1053  me->fileref->fcb->type, me->fileref->dc && me->fileref->dc->name.Length >= sizeof(WCHAR) && me->fileref->dc->name.Buffer[0] == '.',
1054  true, Irp);
1055 
1056  me->fileref->fcb->sd_dirty = !!me->fileref->fcb->sd;
1057  me->fileref->fcb->atts_changed = defda != me->fileref->fcb->atts;
1060  me->fileref->fcb->ea_changed = !!me->fileref->fcb->ea_xattr.Buffer;
1062  me->fileref->fcb->inode_item_changed = true;
1063 
1064  le2 = me->fileref->fcb->xattrs.Flink;
1065  while (le2 != &me->fileref->fcb->xattrs) {
1066  xattr* xa = CONTAINING_RECORD(le2, xattr, list_entry);
1067 
1068  xa->dirty = true;
1069 
1070  le2 = le2->Flink;
1071  }
1072 
1073  if (le == move_list.Flink) { // first entry
1074  me->fileref->fcb->inode_item.transid = me->fileref->fcb->Vcb->superblock.generation;
1075  me->fileref->fcb->inode_item.sequence++;
1076 
1077  if (!ccb->user_set_change_time)
1078  me->fileref->fcb->inode_item.st_ctime = now;
1079  }
1080 
1081  le2 = me->fileref->fcb->extents.Flink;
1082  while (le2 != &me->fileref->fcb->extents) {
1084 
1085  if (!ext->ignore && (ext->extent_data.type == EXTENT_TYPE_REGULAR || ext->extent_data.type == EXTENT_TYPE_PREALLOC)) {
1086  EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ext->extent_data.data;
1087 
1088  if (ed2->size != 0) {
1090 
1091  if (!c) {
1092  ERR("get_chunk_from_address(%I64x) failed\n", ed2->address);
1093  } else {
1094  Status = update_changed_extent_ref(me->fileref->fcb->Vcb, c, ed2->address, ed2->size, me->fileref->fcb->subvol->id, me->fileref->fcb->inode,
1095  ext->offset - ed2->offset, 1, me->fileref->fcb->inode_item.flags & BTRFS_INODE_NODATASUM, false, Irp);
1096 
1097  if (!NT_SUCCESS(Status)) {
1098  ERR("update_changed_extent_ref returned %08lx\n", Status);
1099  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
1100  goto end;
1101  }
1102  }
1103 
1104  }
1105  }
1106 
1107  le2 = le2->Flink;
1108  }
1109 
1113  } else {
1114  me->fileref->fcb->subvol = me->parent->fileref->fcb->subvol;
1115  me->fileref->fcb->inode = me->parent->fileref->fcb->inode;
1116  me->fileref->fcb->hash = me->parent->fileref->fcb->hash;
1117 
1118  // put stream after parent in FCB list
1119  InsertHeadList(&me->parent->fileref->fcb->list_entry, &me->fileref->fcb->list_entry);
1120  }
1121 
1122  me->fileref->fcb->created = true;
1123 
1124  InsertTailList(&me->fileref->fcb->Vcb->all_fcbs, &me->dummyfcb->list_entry_all);
1125 
1126  while (!IsListEmpty(&me->fileref->fcb->hardlinks)) {
1128 
1129  if (hl->name.Buffer)
1130  ExFreePool(hl->name.Buffer);
1131 
1132  if (hl->utf8.Buffer)
1133  ExFreePool(hl->utf8.Buffer);
1134 
1135  ExFreePool(hl);
1136  }
1137 
1138  me->fileref->fcb->inode_item_changed = true;
1139  mark_fcb_dirty(me->fileref->fcb);
1140 
1141  if ((!me->dummyfcb->ads && me->dummyfcb->inode_item.st_nlink > 1) || (me->dummyfcb->ads && me->parent->dummyfcb->inode_item.st_nlink > 1)) {
1142  LIST_ENTRY* le2 = le->Flink;
1143 
1144  while (le2 != &move_list) {
1146 
1147  if (me2->fileref->fcb == me->fileref->fcb && !me2->fileref->fcb->ads) {
1148  me2->dummyfcb = me->dummyfcb;
1150  }
1151 
1152  le2 = le2->Flink;
1153  }
1154  }
1155 
1156  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
1157  } else {
1158  ExAcquireResourceExclusiveLite(me->fileref->fcb->Header.Resource, true);
1159  me->fileref->fcb->inode_item.st_nlink++;
1160  me->fileref->fcb->inode_item_changed = true;
1161  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
1162  }
1163  }
1164 
1165  le = le->Flink;
1166  }
1167 
1168  fileref->fcb->subvol->root_item.ctransid = fileref->fcb->Vcb->superblock.generation;
1169  fileref->fcb->subvol->root_item.ctime = now;
1170 
1171  // loop through list and create new filerefs
1172 
1173  le = move_list.Flink;
1174  while (le != &move_list) {
1175  hardlink* hl;
1176  bool name_changed = false;
1177 
1179 
1180  me->dummyfileref = create_fileref(fileref->fcb->Vcb);
1181  if (!me->dummyfileref) {
1182  ERR("out of memory\n");
1184  goto end;
1185  }
1186 
1187  if (me->fileref->fcb == me->fileref->fcb->Vcb->dummy_fcb) {
1188  root* r = me->parent ? me->parent->fileref->fcb->subvol : destdir->fcb->subvol;
1189 
1190  Status = create_directory_fcb(me->fileref->fcb->Vcb, r, me->fileref->parent->fcb, &me->fileref->fcb);
1191  if (!NT_SUCCESS(Status)) {
1192  ERR("create_directory_fcb returned %08lx\n", Status);
1193  goto end;
1194  }
1195 
1196  me->fileref->dc->key.obj_id = me->fileref->fcb->inode;
1198 
1199  me->dummyfileref->fcb = me->fileref->fcb->Vcb->dummy_fcb;
1200  } else if (me->fileref->fcb->inode == SUBVOL_ROOT_INODE) {
1201  me->dummyfileref->fcb = me->fileref->fcb;
1202 
1203  me->fileref->fcb->subvol->parent = le == move_list.Flink ? destdir->fcb->subvol->id : me->parent->fileref->fcb->subvol->id;
1204  } else
1205  me->dummyfileref->fcb = me->dummyfcb;
1206 
1208 
1209  me->dummyfileref->oldutf8 = me->fileref->oldutf8;
1210  me->dummyfileref->oldindex = me->fileref->dc->index;
1211 
1212  if (le == move_list.Flink && (me->fileref->dc->utf8.Length != utf8->Length || RtlCompareMemory(me->fileref->dc->utf8.Buffer, utf8->Buffer, utf8->Length) != utf8->Length))
1213  name_changed = true;
1214 
1215  if (!me->dummyfileref->oldutf8.Buffer) {
1217  if (!me->dummyfileref->oldutf8.Buffer) {
1218  ERR("out of memory\n");
1220  goto end;
1221  }
1222 
1224 
1226  }
1227 
1229  me->dummyfileref->deleted = me->fileref->deleted;
1230 
1231  me->dummyfileref->created = me->fileref->created;
1232  me->fileref->created = true;
1233 
1234  me->dummyfileref->parent = me->parent ? me->parent->dummyfileref : origparent;
1236 
1237  ExAcquireResourceExclusiveLite(&me->dummyfileref->parent->fcb->nonpaged->dir_children_lock, true);
1238  InsertTailList(&me->dummyfileref->parent->children, &me->dummyfileref->list_entry);
1239  ExReleaseResourceLite(&me->dummyfileref->parent->fcb->nonpaged->dir_children_lock);
1240 
1242  me->dummyfileref->fcb->fileref = me->dummyfileref;
1243 
1244  if (!me->parent) {
1246 
1247  increase_fileref_refcount(destdir);
1248 
1249  if (me->fileref->dc) {
1250  // remove from old parent
1251  ExAcquireResourceExclusiveLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock, true);
1254  ExReleaseResourceLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock);
1255 
1256  me->fileref->parent->fcb->inode_item.st_size -= me->fileref->dc->utf8.Length * 2;
1257  me->fileref->parent->fcb->inode_item.transid = me->fileref->fcb->Vcb->superblock.generation;
1258  me->fileref->parent->fcb->inode_item.sequence++;
1259  me->fileref->parent->fcb->inode_item.st_ctime = now;
1260  me->fileref->parent->fcb->inode_item.st_mtime = now;
1261  me->fileref->parent->fcb->inode_item_changed = true;
1262  mark_fcb_dirty(me->fileref->parent->fcb);
1263 
1264  if (name_changed) {
1265  ExFreePool(me->fileref->dc->utf8.Buffer);
1266  ExFreePool(me->fileref->dc->name.Buffer);
1268 
1270  if (!me->fileref->dc->utf8.Buffer) {
1271  ERR("out of memory\n");
1273  goto end;
1274  }
1275 
1276  me->fileref->dc->utf8.Length = me->fileref->dc->utf8.MaximumLength = utf8->Length;
1277  RtlCopyMemory(me->fileref->dc->utf8.Buffer, utf8->Buffer, utf8->Length);
1278 
1280  if (!me->fileref->dc->name.Buffer) {
1281  ERR("out of memory\n");
1283  goto end;
1284  }
1285 
1286  me->fileref->dc->name.Length = me->fileref->dc->name.MaximumLength = fnus->Length;
1287  RtlCopyMemory(me->fileref->dc->name.Buffer, fnus->Buffer, fnus->Length);
1288 
1289  Status = RtlUpcaseUnicodeString(&fileref->dc->name_uc, &fileref->dc->name, true);
1290  if (!NT_SUCCESS(Status)) {
1291  ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
1292  goto end;
1293  }
1294 
1295  me->fileref->dc->hash = calc_crc32c(0xffffffff, (uint8_t*)me->fileref->dc->name.Buffer, me->fileref->dc->name.Length);
1296  me->fileref->dc->hash_uc = calc_crc32c(0xffffffff, (uint8_t*)me->fileref->dc->name_uc.Buffer, me->fileref->dc->name_uc.Length);
1297  }
1298 
1299  if (me->fileref->dc->key.obj_type == TYPE_INODE_ITEM)
1300  me->fileref->dc->key.obj_id = me->fileref->fcb->inode;
1301 
1302  // add to new parent
1303 
1304  ExAcquireResourceExclusiveLite(&destdir->fcb->nonpaged->dir_children_lock, true);
1305 
1306  if (IsListEmpty(&destdir->fcb->dir_children_index))
1307  me->fileref->dc->index = 2;
1308  else {
1309  dir_child* dc2 = CONTAINING_RECORD(destdir->fcb->dir_children_index.Blink, dir_child, list_entry_index);
1310 
1311  me->fileref->dc->index = max(2, dc2->index + 1);
1312  }
1313 
1316  ExReleaseResourceLite(&destdir->fcb->nonpaged->dir_children_lock);
1317  }
1318 
1319  free_fileref(me->fileref->parent);
1320  me->fileref->parent = destdir;
1321 
1322  ExAcquireResourceExclusiveLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock, true);
1323  InsertTailList(&me->fileref->parent->children, &me->fileref->list_entry);
1324  ExReleaseResourceLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock);
1325 
1326  TRACE("me->fileref->parent->fcb->inode_item.st_size (inode %I64x) was %I64x\n", me->fileref->parent->fcb->inode, me->fileref->parent->fcb->inode_item.st_size);
1327  me->fileref->parent->fcb->inode_item.st_size += me->fileref->dc->utf8.Length * 2;
1328  TRACE("me->fileref->parent->fcb->inode_item.st_size (inode %I64x) now %I64x\n", me->fileref->parent->fcb->inode, me->fileref->parent->fcb->inode_item.st_size);
1329  me->fileref->parent->fcb->inode_item.transid = me->fileref->fcb->Vcb->superblock.generation;
1330  me->fileref->parent->fcb->inode_item.sequence++;
1331  me->fileref->parent->fcb->inode_item.st_ctime = now;
1332  me->fileref->parent->fcb->inode_item.st_mtime = now;
1333  me->fileref->parent->fcb->inode_item_changed = true;
1334  mark_fcb_dirty(me->fileref->parent->fcb);
1335  } else {
1336  if (me->fileref->dc) {
1337  ExAcquireResourceExclusiveLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock, true);
1339 
1340  if (!me->fileref->fcb->ads)
1342 
1343  ExReleaseResourceLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock);
1344 
1345  ExAcquireResourceExclusiveLite(&me->parent->fileref->fcb->nonpaged->dir_children_lock, true);
1346 
1347  if (me->fileref->fcb->ads)
1348  InsertHeadList(&me->parent->fileref->fcb->dir_children_index, &me->fileref->dc->list_entry_index);
1349  else {
1350  if (me->fileref->fcb->inode != SUBVOL_ROOT_INODE)
1351  me->fileref->dc->key.obj_id = me->fileref->fcb->inode;
1352 
1353  if (IsListEmpty(&me->parent->fileref->fcb->dir_children_index))
1354  me->fileref->dc->index = 2;
1355  else {
1356  dir_child* dc2 = CONTAINING_RECORD(me->parent->fileref->fcb->dir_children_index.Blink, dir_child, list_entry_index);
1357 
1358  me->fileref->dc->index = max(2, dc2->index + 1);
1359  }
1360 
1361  InsertTailList(&me->parent->fileref->fcb->dir_children_index, &me->fileref->dc->list_entry_index);
1362  insert_dir_child_into_hash_lists(me->parent->fileref->fcb, me->fileref->dc);
1363  }
1364 
1365  ExReleaseResourceLite(&me->parent->fileref->fcb->nonpaged->dir_children_lock);
1366  }
1367  }
1368 
1369  if (!me->dummyfileref->fcb->ads) {
1371  if (!NT_SUCCESS(Status)) {
1372  ERR("delete_fileref returned %08lx\n", Status);
1373  goto end;
1374  }
1375  }
1376 
1377  if (me->fileref->fcb->inode_item.st_nlink > 1) {
1379  if (!hl) {
1380  ERR("out of memory\n");
1382  goto end;
1383  }
1384 
1385  hl->parent = me->fileref->parent->fcb->inode;
1386  hl->index = me->fileref->dc->index;
1387 
1388  hl->utf8.Length = hl->utf8.MaximumLength = me->fileref->dc->utf8.Length;
1390  if (!hl->utf8.Buffer) {
1391  ERR("out of memory\n");
1393  ExFreePool(hl);
1394  goto end;
1395  }
1396 
1398 
1399  hl->name.Length = hl->name.MaximumLength = me->fileref->dc->name.Length;
1401  if (!hl->name.Buffer) {
1402  ERR("out of memory\n");
1404  ExFreePool(hl->utf8.Buffer);
1405  ExFreePool(hl);
1406  goto end;
1407  }
1408 
1410 
1412  }
1413 
1415 
1416  le = le->Flink;
1417  }
1418 
1419  // loop through, and only mark streams as deleted if their parent inodes are also deleted
1420 
1421  le = move_list.Flink;
1422  while (le != &move_list) {
1424 
1425  if (me->dummyfileref->fcb->ads && me->parent->dummyfileref->fcb->deleted) {
1427  if (!NT_SUCCESS(Status)) {
1428  ERR("delete_fileref returned %08lx\n", Status);
1429  goto end;
1430  }
1431  }
1432 
1433  le = le->Flink;
1434  }
1435 
1436  destdir->fcb->subvol->root_item.ctransid = destdir->fcb->Vcb->superblock.generation;
1437  destdir->fcb->subvol->root_item.ctime = now;
1438 
1443 
1445 
1446 end:
1447  while (!IsListEmpty(&move_list)) {
1448  le = RemoveHeadList(&move_list);
1450 
1451  if (me->dummyfcb)
1452  free_fcb(me->dummyfcb);
1453 
1454  if (me->dummyfileref)
1456 
1457  free_fileref(me->fileref);
1458 
1459  ExFreePool(me);
1460  }
1461 
1462  destdir->fcb->subvol->fcbs_version++;
1463  fileref->fcb->subvol->fcbs_version++;
1464 
1465  release_fcb_lock(fileref->fcb->Vcb);
1466 
1467  return Status;
1468 }
1469 
1471  bool inserted;
1472  LIST_ENTRY* le;
1473  uint8_t c, d;
1474 
1475  c = dc->hash >> 24;
1476 
1477  inserted = false;
1478 
1479  d = c;
1480  do {
1481  le = fcb->hash_ptrs[d];
1482 
1483  if (d == 0)
1484  break;
1485 
1486  d--;
1487  } while (!le);
1488 
1489  if (!le)
1490  le = fcb->dir_children_hash.Flink;
1491 
1492  while (le != &fcb->dir_children_hash) {
1493  dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_hash);
1494 
1495  if (dc2->hash > dc->hash) {
1496  InsertHeadList(le->Blink, &dc->list_entry_hash);
1497  inserted = true;
1498  break;
1499  }
1500 
1501  le = le->Flink;
1502  }
1503 
1504  if (!inserted)
1505  InsertTailList(&fcb->dir_children_hash, &dc->list_entry_hash);
1506 
1507  if (!fcb->hash_ptrs[c])
1508  fcb->hash_ptrs[c] = &dc->list_entry_hash;
1509  else {
1510  dir_child* dc2 = CONTAINING_RECORD(fcb->hash_ptrs[c], dir_child, list_entry_hash);
1511 
1512  if (dc2->hash > dc->hash)
1513  fcb->hash_ptrs[c] = &dc->list_entry_hash;
1514  }
1515 
1516  c = dc->hash_uc >> 24;
1517 
1518  inserted = false;
1519 
1520  d = c;
1521  do {
1522  le = fcb->hash_ptrs_uc[d];
1523 
1524  if (d == 0)
1525  break;
1526 
1527  d--;
1528  } while (!le);
1529 
1530  if (!le)
1532 
1533  while (le != &fcb->dir_children_hash_uc) {
1534  dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_hash_uc);
1535 
1536  if (dc2->hash_uc > dc->hash_uc) {
1537  InsertHeadList(le->Blink, &dc->list_entry_hash_uc);
1538  inserted = true;
1539  break;
1540  }
1541 
1542  le = le->Flink;
1543  }
1544 
1545  if (!inserted)
1546  InsertTailList(&fcb->dir_children_hash_uc, &dc->list_entry_hash_uc);
1547 
1548  if (!fcb->hash_ptrs_uc[c])
1549  fcb->hash_ptrs_uc[c] = &dc->list_entry_hash_uc;
1550  else {
1551  dir_child* dc2 = CONTAINING_RECORD(fcb->hash_ptrs_uc[c], dir_child, list_entry_hash_uc);
1552 
1553  if (dc2->hash_uc > dc->hash_uc)
1554  fcb->hash_ptrs_uc[c] = &dc->list_entry_hash_uc;
1555  }
1556 }
1557 
1560  NTSTATUS Status;
1561  file_ref* ofr;
1563  dir_child* dc;
1564  fcb* dummyfcb;
1565 
1566  if (fileref->fcb->type != BTRFS_TYPE_FILE)
1567  return STATUS_INVALID_PARAMETER;
1568 
1570  WARN("trying to rename stream on readonly file\n");
1571  return STATUS_ACCESS_DENIED;
1572  }
1573 
1574  if (Irp->RequestorMode == UserMode && ccb && !(ccb->access & DELETE)) {
1575  WARN("insufficient permissions\n");
1576  return STATUS_ACCESS_DENIED;
1577  }
1578 
1579  if (!(flags & FILE_RENAME_REPLACE_IF_EXISTS)) // file will always exist
1581 
1582  // FIXME - POSIX overwrites of stream?
1583 
1584  ofr = fileref->parent;
1585 
1586  if (ofr->open_count > 0) {
1587  WARN("trying to overwrite open file\n");
1588  return STATUS_ACCESS_DENIED;
1589  }
1590 
1591  if (ofr->fcb->inode_item.st_size > 0) {
1592  WARN("can only overwrite existing stream if it is zero-length\n");
1593  return STATUS_INVALID_PARAMETER;
1594  }
1595 
1596  dummyfcb = create_fcb(Vcb, PagedPool);
1597  if (!dummyfcb) {
1598  ERR("out of memory\n");
1600  }
1601 
1602  // copy parent fcb onto this one
1603 
1604  fileref->fcb->subvol = ofr->fcb->subvol;
1605  fileref->fcb->inode = ofr->fcb->inode;
1606  fileref->fcb->hash = ofr->fcb->hash;
1607  fileref->fcb->type = ofr->fcb->type;
1608  fileref->fcb->inode_item = ofr->fcb->inode_item;
1609 
1610  fileref->fcb->sd = ofr->fcb->sd;
1611  ofr->fcb->sd = NULL;
1612 
1613  fileref->fcb->deleted = ofr->fcb->deleted;
1614  fileref->fcb->atts = ofr->fcb->atts;
1615 
1616  fileref->fcb->reparse_xattr = ofr->fcb->reparse_xattr;
1617  ofr->fcb->reparse_xattr.Buffer = NULL;
1619 
1620  fileref->fcb->ea_xattr = ofr->fcb->ea_xattr;
1621  ofr->fcb->ea_xattr.Buffer = NULL;
1622  ofr->fcb->ea_xattr.Length = ofr->fcb->ea_xattr.MaximumLength = 0;
1623 
1624  fileref->fcb->ealen = ofr->fcb->ealen;
1625 
1626  while (!IsListEmpty(&ofr->fcb->hardlinks)) {
1627  InsertTailList(&fileref->fcb->hardlinks, RemoveHeadList(&ofr->fcb->hardlinks));
1628  }
1629 
1630  fileref->fcb->inode_item_changed = true;
1631  fileref->fcb->prop_compression = ofr->fcb->prop_compression;
1632 
1633  while (!IsListEmpty(&ofr->fcb->xattrs)) {
1634  InsertTailList(&fileref->fcb->xattrs, RemoveHeadList(&ofr->fcb->xattrs));
1635  }
1636 
1637  fileref->fcb->marked_as_orphan = ofr->fcb->marked_as_orphan;
1638  fileref->fcb->case_sensitive = ofr->fcb->case_sensitive;
1639  fileref->fcb->case_sensitive_set = ofr->fcb->case_sensitive_set;
1640 
1641  while (!IsListEmpty(&ofr->fcb->dir_children_index)) {
1642  InsertTailList(&fileref->fcb->dir_children_index, RemoveHeadList(&ofr->fcb->dir_children_index));
1643  }
1644 
1645  while (!IsListEmpty(&ofr->fcb->dir_children_hash)) {
1646  InsertTailList(&fileref->fcb->dir_children_hash, RemoveHeadList(&ofr->fcb->dir_children_hash));
1647  }
1648 
1649  while (!IsListEmpty(&ofr->fcb->dir_children_hash_uc)) {
1650  InsertTailList(&fileref->fcb->dir_children_hash_uc, RemoveHeadList(&ofr->fcb->dir_children_hash_uc));
1651  }
1652 
1653  fileref->fcb->hash_ptrs = ofr->fcb->hash_ptrs;
1654  fileref->fcb->hash_ptrs_uc = ofr->fcb->hash_ptrs_uc;
1655 
1656  ofr->fcb->hash_ptrs = NULL;
1657  ofr->fcb->hash_ptrs_uc = NULL;
1658 
1659  fileref->fcb->sd_dirty = ofr->fcb->sd_dirty;
1660  fileref->fcb->sd_deleted = ofr->fcb->sd_deleted;
1661  fileref->fcb->atts_changed = ofr->fcb->atts_changed;
1662  fileref->fcb->atts_deleted = ofr->fcb->atts_deleted;
1663  fileref->fcb->extents_changed = true;
1664  fileref->fcb->reparse_xattr_changed = ofr->fcb->reparse_xattr_changed;
1665  fileref->fcb->ea_changed = ofr->fcb->ea_changed;
1666  fileref->fcb->prop_compression_changed = ofr->fcb->prop_compression_changed;
1667  fileref->fcb->xattrs_changed = ofr->fcb->xattrs_changed;
1668  fileref->fcb->created = ofr->fcb->created;
1669  fileref->fcb->ads = false;
1670 
1671  if (fileref->fcb->adsxattr.Buffer) {
1672  ExFreePool(fileref->fcb->adsxattr.Buffer);
1673  fileref->fcb->adsxattr.Length = fileref->fcb->adsxattr.MaximumLength = 0;
1674  fileref->fcb->adsxattr.Buffer = NULL;
1675  }
1676 
1677  adsdata = fileref->fcb->adsdata;
1678 
1679  fileref->fcb->adsdata.Buffer = NULL;
1680  fileref->fcb->adsdata.Length = fileref->fcb->adsdata.MaximumLength = 0;
1681 
1682  acquire_fcb_lock_exclusive(Vcb);
1683 
1684  RemoveEntryList(&fileref->fcb->list_entry);
1685  InsertHeadList(ofr->fcb->list_entry.Blink, &fileref->fcb->list_entry);
1686 
1687  if (fileref->fcb->subvol->fcbs_ptrs[fileref->fcb->hash >> 24] == &ofr->fcb->list_entry)
1688  fileref->fcb->subvol->fcbs_ptrs[fileref->fcb->hash >> 24] = &fileref->fcb->list_entry;
1689 
1690  RemoveEntryList(&ofr->fcb->list_entry);
1691 
1692  release_fcb_lock(Vcb);
1693 
1694  ofr->fcb->list_entry.Flink = ofr->fcb->list_entry.Blink = NULL;
1695 
1696  mark_fcb_dirty(fileref->fcb);
1697 
1698  // mark old parent fcb so it gets ignored by flush_fcb
1699  ofr->fcb->created = true;
1700  ofr->fcb->deleted = true;
1701 
1702  mark_fcb_dirty(ofr->fcb);
1703 
1704  // copy parent fileref onto this one
1705 
1706  fileref->oldutf8 = ofr->oldutf8;
1707  ofr->oldutf8.Buffer = NULL;
1708  ofr->oldutf8.Length = ofr->oldutf8.MaximumLength = 0;
1709 
1710  fileref->oldindex = ofr->oldindex;
1711  fileref->delete_on_close = ofr->delete_on_close;
1712  fileref->posix_delete = ofr->posix_delete;
1713  fileref->deleted = ofr->deleted;
1714  fileref->created = ofr->created;
1715 
1716  fileref->parent = ofr->parent;
1717 
1718  RemoveEntryList(&fileref->list_entry);
1719  InsertHeadList(ofr->list_entry.Blink, &fileref->list_entry);
1720  RemoveEntryList(&ofr->list_entry);
1721  ofr->list_entry.Flink = ofr->list_entry.Blink = NULL;
1722 
1723  while (!IsListEmpty(&ofr->children)) {
1725 
1726  free_fileref(fr->parent);
1727 
1728  fr->parent = fileref;
1729  InterlockedIncrement(&fileref->refcount);
1730 
1731  InsertTailList(&fileref->children, &fr->list_entry);
1732  }
1733 
1734  dc = fileref->dc;
1735 
1736  fileref->dc = ofr->dc;
1737  fileref->dc->fileref = fileref;
1738 
1740 
1741  // mark old parent fileref so it gets ignored by flush_fileref
1742  ofr->created = true;
1743  ofr->deleted = true;
1744 
1745  // write file data
1746 
1747  fileref->fcb->inode_item.st_size = adsdata.Length;
1748 
1749  if (adsdata.Length > 0) {
1750  bool make_inline = adsdata.Length <= Vcb->options.max_inline;
1751 
1752  if (make_inline) {
1754  if (!ed) {
1755  ERR("out of memory\n");
1757  reap_fcb(dummyfcb);
1759  }
1760 
1761  ed->generation = Vcb->superblock.generation;
1762  ed->decoded_size = adsdata.Length;
1766  ed->type = EXTENT_TYPE_INLINE;
1767 
1769 
1771 
1773  if (!NT_SUCCESS(Status)) {
1774  ERR("add_extent_to_fcb returned %08lx\n", Status);
1775  ExFreePool(ed);
1776  reap_fcb(dummyfcb);
1777  return Status;
1778  }
1779 
1780  ExFreePool(ed);
1781  } else if (adsdata.Length & (Vcb->superblock.sector_size - 1)) {
1782  char* newbuf = ExAllocatePoolWithTag(PagedPool, (uint16_t)sector_align(adsdata.Length, Vcb->superblock.sector_size), ALLOC_TAG);
1783  if (!newbuf) {
1784  ERR("out of memory\n");
1786  reap_fcb(dummyfcb);
1788  }
1789 
1791  RtlZeroMemory(newbuf + adsdata.Length, (uint16_t)(sector_align(adsdata.Length, Vcb->superblock.sector_size) - adsdata.Length));
1792 
1794 
1795  adsdata.Buffer = newbuf;
1796  adsdata.Length = adsdata.MaximumLength = (uint16_t)sector_align(adsdata.Length, Vcb->superblock.sector_size);
1797  }
1798 
1799  if (!make_inline) {
1800  Status = do_write_file(fileref->fcb, 0, adsdata.Length, adsdata.Buffer, Irp, false, 0, rollback);
1801  if (!NT_SUCCESS(Status)) {
1802  ERR("do_write_file returned %08lx\n", Status);
1804  reap_fcb(dummyfcb);
1805  return Status;
1806  }
1807 
1809  }
1810 
1811  fileref->fcb->inode_item.st_blocks = adsdata.Length;
1812  fileref->fcb->inode_item_changed = true;
1813  }
1814 
1815  RemoveEntryList(&dc->list_entry_index);
1816 
1817  if (dc->utf8.Buffer)
1818  ExFreePool(dc->utf8.Buffer);
1819 
1820  if (dc->name.Buffer)
1821  ExFreePool(dc->name.Buffer);
1822 
1823  if (dc->name_uc.Buffer)
1824  ExFreePool(dc->name_uc.Buffer);
1825 
1826  ExFreePool(dc);
1827 
1828  // FIXME - csums?
1829 
1830  // add dummy deleted xattr with old name
1831 
1832  dummyfcb->Vcb = Vcb;
1833  dummyfcb->subvol = fileref->fcb->subvol;
1834  dummyfcb->inode = fileref->fcb->inode;
1835  dummyfcb->hash = fileref->fcb->hash;
1836  dummyfcb->adsxattr = fileref->fcb->adsxattr;
1837  dummyfcb->adshash = fileref->fcb->adshash;
1838  dummyfcb->ads = true;
1839  dummyfcb->deleted = true;
1840 
1841  acquire_fcb_lock_exclusive(Vcb);
1842  add_fcb_to_subvol(dummyfcb);
1843  InsertTailList(&Vcb->all_fcbs, &dummyfcb->list_entry_all);
1844  dummyfcb->subvol->fcbs_version++;
1845  release_fcb_lock(Vcb);
1846 
1847  // FIXME - dummyfileref as well?
1848 
1849  mark_fcb_dirty(dummyfcb);
1850 
1851  free_fcb(dummyfcb);
1852 
1853  return STATUS_SUCCESS;
1854 }
1855 
1858  NTSTATUS Status;
1860  file_ref* sf = NULL;
1861  uint16_t newmaxlen;
1862  ULONG utf8len;
1863  ANSI_STRING utf8;
1864  UNICODE_STRING utf16, utf16uc;
1866  uint32_t crc32;
1867  fcb* dummyfcb;
1868 
1869  static const WCHAR datasuf[] = L":$DATA";
1870  static const char xapref[] = "user.";
1871 
1872  if (!fileref) {
1873  ERR("fileref not set\n");
1874  return STATUS_INVALID_PARAMETER;
1875  }
1876 
1877  if (!fileref->parent) {
1878  ERR("fileref->parent not set\n");
1879  return STATUS_INVALID_PARAMETER;
1880  }
1881 
1882  if (fri->FileNameLength < sizeof(WCHAR)) {
1883  WARN("filename too short\n");
1885  }
1886 
1887  if (fri->FileName[0] != ':') {
1888  WARN("destination filename must begin with a colon\n");
1889  return STATUS_INVALID_PARAMETER;
1890  }
1891 
1892  if (Irp->RequestorMode == UserMode && ccb && !(ccb->access & DELETE)) {
1893  WARN("insufficient permissions\n");
1894  return STATUS_ACCESS_DENIED;
1895  }
1896 
1897  fn.Buffer = &fri->FileName[1];
1898  fn.Length = fn.MaximumLength = (USHORT)(fri->FileNameLength - sizeof(WCHAR));
1899 
1900  // remove :$DATA suffix
1901  if (fn.Length >= sizeof(datasuf) - sizeof(WCHAR) &&
1902  RtlCompareMemory(&fn.Buffer[(fn.Length - sizeof(datasuf) + sizeof(WCHAR))/sizeof(WCHAR)], datasuf, sizeof(datasuf) - sizeof(WCHAR)) == sizeof(datasuf) - sizeof(WCHAR))
1903  fn.Length -= sizeof(datasuf) - sizeof(WCHAR);
1904 
1905  if (fn.Length == 0)
1907 
1908  Status = check_file_name_valid(&fn, false, true);
1909  if (!NT_SUCCESS(Status)) {
1910  WARN("invalid stream name %.*S\n", (int)(fn.Length / sizeof(WCHAR)), fn.Buffer);
1911  return Status;
1912  }
1913 
1915  WARN("trying to rename stream on readonly file\n");
1916  return STATUS_ACCESS_DENIED;
1917  }
1918 
1919  Status = open_fileref_child(Vcb, fileref->parent, &fn, fileref->parent->fcb->case_sensitive, true, true, PagedPool, &sf, Irp);
1921  if (Status == STATUS_SUCCESS) {
1922  if (fileref == sf || sf->deleted) {
1923  free_fileref(sf);
1924  sf = NULL;
1925  } else {
1928  goto end;
1929  }
1930 
1931  // FIXME - POSIX overwrites of stream?
1932 
1933  if (sf->open_count > 0) {
1934  WARN("trying to overwrite open file\n");
1936  goto end;
1937  }
1938 
1939  if (sf->fcb->adsdata.Length > 0) {
1940  WARN("can only overwrite existing stream if it is zero-length\n");
1942  goto end;
1943  }
1944 
1945  Status = delete_fileref(sf, NULL, false, Irp, rollback);
1946  if (!NT_SUCCESS(Status)) {
1947  ERR("delete_fileref returned %08lx\n", Status);
1948  goto end;
1949  }
1950  }
1951  } else {
1952  ERR("open_fileref_child returned %08lx\n", Status);
1953  goto end;
1954  }
1955  }
1956 
1957  Status = utf16_to_utf8(NULL, 0, &utf8len, fn.Buffer, fn.Length);
1958  if (!NT_SUCCESS(Status))
1959  goto end;
1960 
1961  utf8.MaximumLength = utf8.Length = (uint16_t)utf8len;
1963  if (!utf8.Buffer) {
1964  ERR("out of memory\n");
1966  goto end;
1967  }
1968 
1969  Status = utf16_to_utf8(utf8.Buffer, utf8len, &utf8len, fn.Buffer, fn.Length);
1970  if (!NT_SUCCESS(Status)) {
1971  ExFreePool(utf8.Buffer);
1972  goto end;
1973  }
1974 
1975  adsxattr.Length = adsxattr.MaximumLength = sizeof(xapref) - 1 + utf8.Length;
1977  if (!adsxattr.Buffer) {
1978  ERR("out of memory\n");
1980  ExFreePool(utf8.Buffer);
1981  goto end;
1982  }
1983 
1984  RtlCopyMemory(adsxattr.Buffer, xapref, sizeof(xapref) - 1);
1985  RtlCopyMemory(&adsxattr.Buffer[sizeof(xapref) - 1], utf8.Buffer, utf8.Length);
1986 
1987  // don't allow if it's one of our reserved names
1988 
1994  ExFreePool(utf8.Buffer);
1996  goto end;
1997  }
1998 
1999  utf16.Length = utf16.MaximumLength = fn.Length;
2001  if (!utf16.Buffer) {
2002  ERR("out of memory\n");
2004  ExFreePool(utf8.Buffer);
2006  goto end;
2007  }
2008 
2009  RtlCopyMemory(utf16.Buffer, fn.Buffer, fn.Length);
2010 
2011  newmaxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) -
2012  offsetof(DIR_ITEM, name[0]);
2013 
2014  if (newmaxlen < adsxattr.Length) {
2015  WARN("cannot rename as data too long\n");
2017  ExFreePool(utf8.Buffer);
2018  ExFreePool(utf16.Buffer);
2020  goto end;
2021  }
2022 
2023  newmaxlen -= adsxattr.Length;
2024 
2025  if (newmaxlen < fileref->fcb->adsdata.Length) {
2026  WARN("cannot rename as data too long\n");
2028  ExFreePool(utf8.Buffer);
2029  ExFreePool(utf16.Buffer);
2031  goto end;
2032  }
2033 
2034  Status = RtlUpcaseUnicodeString(&utf16uc, &fn, true);
2035  if (!NT_SUCCESS(Status)) {
2036  ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
2037  ExFreePool(utf8.Buffer);
2038  ExFreePool(utf16.Buffer);
2040  goto end;
2041  }
2042 
2043  // add dummy deleted xattr with old name
2044 
2045  dummyfcb = create_fcb(Vcb, PagedPool);
2046  if (!dummyfcb) {
2047  ERR("out of memory\n");
2049  ExFreePool(utf8.Buffer);
2050  ExFreePool(utf16.Buffer);
2051  ExFreePool(utf16uc.Buffer);
2053  goto end;
2054  }
2055 
2056  dummyfcb->Vcb = Vcb;
2057  dummyfcb->subvol = fileref->fcb->subvol;
2058  dummyfcb->inode = fileref->fcb->inode;
2059  dummyfcb->hash = fileref->fcb->hash;
2060  dummyfcb->adsxattr = fileref->fcb->adsxattr;
2061  dummyfcb->adshash = fileref->fcb->adshash;
2062  dummyfcb->ads = true;
2063  dummyfcb->deleted = true;
2064 
2065  acquire_fcb_lock_exclusive(Vcb);
2066  add_fcb_to_subvol(dummyfcb);
2067  InsertTailList(&Vcb->all_fcbs, &dummyfcb->list_entry_all);
2068  dummyfcb->subvol->fcbs_version++;
2069  release_fcb_lock(Vcb);
2070 
2071  mark_fcb_dirty(dummyfcb);
2072 
2073  free_fcb(dummyfcb);
2074 
2075  // change fcb values
2076 
2077  fileref->dc->utf8 = utf8;
2078  fileref->dc->name = utf16;
2079  fileref->dc->name_uc = utf16uc;
2080 
2082 
2083  fileref->fcb->adsxattr = adsxattr;
2084  fileref->fcb->adshash = crc32;
2085  fileref->fcb->adsmaxlen = newmaxlen;
2086 
2087  fileref->fcb->created = true;
2088 
2089  mark_fcb_dirty(fileref->fcb);
2090 
2092 
2093 end:
2094  if (sf)
2095  free_fileref(sf);
2096 
2097  return Status;
2098 }
2099 
2102  NTSTATUS Status;
2104  file_ref* sf = NULL;
2105  uint16_t newmaxlen;
2106  ULONG utf8len;
2107  ANSI_STRING utf8;
2108  UNICODE_STRING utf16, utf16uc;
2110  uint32_t crc32;
2111  fcb* dummyfcb;
2112  file_ref* dummyfileref;
2113  dir_child* dc;
2114  LIST_ENTRY* le;
2115 
2116  static const WCHAR datasuf[] = L":$DATA";
2117  static const char xapref[] = "user.";
2118 
2119  if (!fileref) {
2120  ERR("fileref not set\n");
2121  return STATUS_INVALID_PARAMETER;
2122  }
2123 
2124  if (fri->FileNameLength < sizeof(WCHAR)) {
2125  WARN("filename too short\n");
2127  }
2128 
2129  if (fri->FileName[0] != ':') {
2130  WARN("destination filename must begin with a colon\n");
2131  return STATUS_INVALID_PARAMETER;
2132  }
2133 
2134  if (Irp->RequestorMode == UserMode && ccb && !(ccb->access & DELETE)) {
2135  WARN("insufficient permissions\n");
2136  return STATUS_ACCESS_DENIED;
2137  }
2138 
2139  if (fileref->fcb->type != BTRFS_TYPE_FILE)
2140  return STATUS_INVALID_PARAMETER;
2141 
2142  fn.Buffer = &fri->FileName[1];
2143  fn.Length = fn.MaximumLength = (USHORT)(fri->FileNameLength - sizeof(WCHAR));
2144 
2145  // remove :$DATA suffix
2146  if (fn.Length >= sizeof(datasuf) - sizeof(WCHAR) &&
2147  RtlCompareMemory(&fn.Buffer[(fn.Length - sizeof(datasuf) + sizeof(WCHAR))/sizeof(WCHAR)], datasuf, sizeof(datasuf) - sizeof(WCHAR)) == sizeof(datasuf) - sizeof(WCHAR))
2148  fn.Length -= sizeof(datasuf) - sizeof(WCHAR);
2149 
2150  if (fn.Length == 0) {
2151  WARN("not allowing overwriting file with itself\n");
2152  return STATUS_INVALID_PARAMETER;
2153  }
2154 
2155  Status = check_file_name_valid(&fn, false, true);
2156  if (!NT_SUCCESS(Status)) {
2157  WARN("invalid stream name %.*S\n", (int)(fn.Length / sizeof(WCHAR)), fn.Buffer);
2158  return Status;
2159  }
2160 
2162  WARN("trying to rename stream on readonly file\n");
2163  return STATUS_ACCESS_DENIED;
2164  }
2165 
2166  Status = open_fileref_child(Vcb, fileref, &fn, fileref->fcb->case_sensitive, true, true, PagedPool, &sf, Irp);
2168  if (Status == STATUS_SUCCESS) {
2169  if (fileref == sf || sf->deleted) {
2170  free_fileref(sf);
2171  sf = NULL;
2172  } else {
2175  goto end;
2176  }
2177 
2178  // FIXME - POSIX overwrites of stream?
2179 
2180  if (sf->open_count > 0) {
2181  WARN("trying to overwrite open file\n");
2183  goto end;
2184  }
2185 
2186  if (sf->fcb->adsdata.Length > 0) {
2187  WARN("can only overwrite existing stream if it is zero-length\n");
2189  goto end;
2190  }
2191 
2192  Status = delete_fileref(sf, NULL, false, Irp, rollback);
2193  if (!NT_SUCCESS(Status)) {
2194  ERR("delete_fileref returned %08lx\n", Status);
2195  goto end;
2196  }
2197  }
2198  } else {
2199  ERR("open_fileref_child returned %08lx\n", Status);
2200  goto end;
2201  }
2202  }
2203 
2204  Status = utf16_to_utf8(NULL, 0, &utf8len, fn.Buffer, fn.Length);
2205  if (!NT_SUCCESS(Status))
2206  goto end;
2207 
2208  utf8.MaximumLength = utf8.Length = (uint16_t)utf8len;
2210  if (!utf8.Buffer) {
2211  ERR("out of memory\n");
2213  goto end;
2214  }
2215 
2216  Status = utf16_to_utf8(utf8.Buffer, utf8len, &utf8len, fn.Buffer, fn.Length);
2217  if (!NT_SUCCESS(Status)) {
2218  ExFreePool(utf8.Buffer);
2219  goto end;
2220  }
2221 
2222  adsxattr.Length = adsxattr.MaximumLength = sizeof(xapref) - 1 + utf8.Length;
2224  if (!adsxattr.Buffer) {
2225  ERR("out of memory\n");
2227  ExFreePool(utf8.Buffer);
2228  goto end;
2229  }
2230 
2231  RtlCopyMemory(adsxattr.Buffer, xapref, sizeof(xapref) - 1);
2232  RtlCopyMemory(&adsxattr.Buffer[sizeof(xapref) - 1], utf8.Buffer, utf8.Length);
2233 
2234  // don't allow if it's one of our reserved names
2235 
2241  ExFreePool(utf8.Buffer);
2243  goto end;
2244  }
2245 
2246  utf16.Length = utf16.MaximumLength = fn.Length;
2248  if (!utf16.Buffer) {
2249  ERR("out of memory\n");
2251  ExFreePool(utf8.Buffer);
2253  goto end;
2254  }
2255 
2256  RtlCopyMemory(utf16.Buffer, fn.Buffer, fn.Length);
2257 
2258  newmaxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) -
2259  offsetof(DIR_ITEM, name[0]);
2260 
2261  if (newmaxlen < adsxattr.Length) {
2262  WARN("cannot rename as data too long\n");
2264  ExFreePool(utf8.Buffer);
2265  ExFreePool(utf16.Buffer);
2267  goto end;
2268  }
2269 
2270  newmaxlen -= adsxattr.Length;
2271 
2272  if (newmaxlen < fileref->fcb->inode_item.st_size) {
2273  WARN("cannot rename as data too long\n");
2275  ExFreePool(utf8.Buffer);
2276  ExFreePool(utf16.Buffer);
2278  goto end;
2279  }
2280 
2281  Status = RtlUpcaseUnicodeString(&utf16uc, &fn, true);
2282  if (!NT_SUCCESS(Status)) {
2283  ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
2284  ExFreePool(utf8.Buffer);
2285  ExFreePool(utf16.Buffer);
2287  goto end;
2288  }
2289 
2290  // read existing file data
2291 
2292  if (fileref->fcb->inode_item.st_size > 0) {
2293  ULONG bytes_read;
2294 
2295  adsdata.Length = adsdata.MaximumLength = (uint16_t)fileref->fcb->inode_item.st_size;
2296 
2298  if (!adsdata.Buffer) {
2299  ERR("out of memory\n");
2301  ExFreePool(utf8.Buffer);
2302  ExFreePool(utf16.Buffer);
2303  ExFreePool(utf16uc.Buffer);
2305  goto end;
2306  }
2307 
2308  Status = read_file(fileref->fcb, (uint8_t*)adsdata.Buffer, 0, adsdata.Length, &bytes_read, Irp);
2309  if (!NT_SUCCESS(Status)) {
2310  ERR("out of memory\n");
2312  ExFreePool(utf8.Buffer);
2313  ExFreePool(utf16.Buffer);
2314  ExFreePool(utf16uc.Buffer);
2317  goto end;
2318  }
2319 
2320  if (bytes_read < fileref->fcb->inode_item.st_size) {
2321  ERR("short read\n");
2323  ExFreePool(utf8.Buffer);
2324  ExFreePool(utf16.Buffer);
2325  ExFreePool(utf16uc.Buffer);
2328  goto end;
2329  }
2330  } else
2331  adsdata.Buffer = NULL;
2332 
2334  if (!dc) {
2335  ERR("out of memory\n");
2337  ExFreePool(utf8.Buffer);
2338  ExFreePool(utf16.Buffer);
2339  ExFreePool(utf16uc.Buffer);
2341 
2342  if (adsdata.Buffer)
2344 
2345  goto end;
2346  }
2347 
2348  // add dummy deleted fcb with old name
2349 
2350  Status = duplicate_fcb(fileref->fcb, &dummyfcb);
2351  if (!NT_SUCCESS(Status)) {
2352  ERR("duplicate_fcb returned %08lx\n", Status);
2353  ExFreePool(utf8.Buffer);
2354  ExFreePool(utf16.Buffer);
2355  ExFreePool(utf16uc.Buffer);
2357 
2358  if (adsdata.Buffer)
2360 
2361  ExFreePool(dc);
2362 
2363  goto end;
2364  }
2365 
2366  dummyfileref = create_fileref(Vcb);
2367  if (!dummyfileref) {
2368  ERR("out of memory\n");
2370  ExFreePool(utf8.Buffer);
2371  ExFreePool(utf16.Buffer);
2372  ExFreePool(utf16uc.Buffer);
2374 
2375  if (adsdata.Buffer)
2377 
2378  ExFreePool(dc);
2379 
2380  reap_fcb(dummyfcb);
2381 
2382  goto end;
2383  }
2384 
2385  dummyfileref->fcb = dummyfcb;
2386 
2387  dummyfcb->Vcb = Vcb;
2388  dummyfcb->subvol = fileref->fcb->subvol;
2389  dummyfcb->inode = fileref->fcb->inode;
2390  dummyfcb->hash = fileref->fcb->hash;
2391 
2392  if (fileref->fcb->inode_item.st_size > 0) {
2393  Status = excise_extents(Vcb, dummyfcb, 0, sector_align(fileref->fcb->inode_item.st_size, Vcb->superblock.sector_size),
2394  Irp, rollback);
2395  if (!NT_SUCCESS(Status)) {
2396  ERR("excise_extents returned %08lx\n", Status);
2397  ExFreePool(utf8.Buffer);
2398  ExFreePool(utf16.Buffer);
2399  ExFreePool(utf16uc.Buffer);
2402  ExFreePool(dc);
2403 
2404  reap_fileref(Vcb, dummyfileref);
2405  reap_fcb(dummyfcb);
2406 
2407  goto end;
2408  }
2409 
2410  dummyfcb->inode_item.st_size = 0;
2411  dummyfcb->Header.AllocationSize.QuadPart = 0;
2412  dummyfcb->Header.FileSize.QuadPart = 0;
2413  dummyfcb->Header.ValidDataLength.QuadPart = 0;
2414  }
2415 
2416  dummyfcb->hash_ptrs = fileref->fcb->hash_ptrs;
2417  dummyfcb->hash_ptrs_uc = fileref->fcb->hash_ptrs_uc;
2418  dummyfcb->created = fileref->fcb->created;
2419 
2420  le = fileref->fcb->extents.Flink;
2421  while (le != &fileref->fcb->extents) {
2423 
2424  ext->ignore = true;
2425 
2426  le = le->Flink;
2427  }
2428 
2429  while (!IsListEmpty(&fileref->fcb->dir_children_index)) {
2430  InsertTailList(&dummyfcb->dir_children_index, RemoveHeadList(&fileref->fcb->dir_children_index));
2431  }
2432 
2433  while (!IsListEmpty(&fileref->fcb->dir_children_hash)) {
2434  InsertTailList(&dummyfcb->dir_children_hash, RemoveHeadList(&fileref->fcb->dir_children_hash));
2435  }
2436 
2437  while (!IsListEmpty(&fileref->fcb->dir_children_hash_uc)) {
2438  InsertTailList(&dummyfcb->dir_children_hash_uc, RemoveHeadList(&fileref->fcb->dir_children_hash_uc));
2439  }
2440 
2441  InsertTailList(&Vcb->all_fcbs, &dummyfcb->list_entry_all);
2442 
2443  InsertHeadList(fileref->fcb->list_entry.Blink, &dummyfcb->list_entry);
2444 
2445  if (fileref->fcb->subvol->fcbs_ptrs[dummyfcb->hash >> 24] == &fileref->fcb->list_entry)
2446  fileref->fcb->subvol->fcbs_ptrs[dummyfcb->hash >> 24] = &dummyfcb->list_entry;
2447 
2448  RemoveEntryList(&fileref->fcb->list_entry);
2449  fileref->fcb->list_entry.Flink = fileref->fcb->list_entry.Blink = NULL;
2450 
2451  mark_fcb_dirty(dummyfcb);
2452 
2453  // create dummy fileref
2454 
2455  dummyfileref->oldutf8 = fileref->oldutf8;
2456  dummyfileref->oldindex = fileref->oldindex;
2457  dummyfileref->delete_on_close = fileref->delete_on_close;
2458  dummyfileref->posix_delete = fileref->posix_delete;
2459  dummyfileref->deleted = fileref->deleted;
2460  dummyfileref->created = fileref->created;
2461  dummyfileref->parent = fileref->parent;
2462 
2463  while (!IsListEmpty(&fileref->children)) {
2465 
2466  free_fileref(fr->parent);
2467 
2468  fr->parent = dummyfileref;
2469  InterlockedIncrement(&dummyfileref->refcount);
2470 
2471  InsertTailList(&dummyfileref->children, &fr->list_entry);
2472  }
2473 
2474  InsertTailList(fileref->list_entry.Blink, &dummyfileref->list_entry);
2475 
2476  RemoveEntryList(&fileref->list_entry);
2477  InsertTailList(&dummyfileref->children, &fileref->list_entry);
2478 
2479  dummyfileref->dc = fileref->dc;
2480  dummyfileref->dc->fileref = dummyfileref;
2481 
2482  mark_fileref_dirty(dummyfileref);
2483 
2484  // change fcb values
2485 
2486  fileref->fcb->hash_ptrs = NULL;
2487  fileref->fcb->hash_ptrs_uc = NULL;
2488 
2489  fileref->fcb->ads = true;
2490 
2491  fileref->oldutf8.Length = fileref->oldutf8.MaximumLength = 0;
2492  fileref->oldutf8.Buffer = NULL;
2493 
2494  RtlZeroMemory(dc, sizeof(dir_child));
2495 
2496  dc->utf8 = utf8;
2497  dc->name = utf16;
2498  dc->hash = calc_crc32c(0xffffffff, (uint8_t*)dc->name.Buffer, dc->name.Length);
2499  dc->name_uc = utf16uc;
2500  dc->hash_uc = calc_crc32c(0xffffffff, (uint8_t*)dc->name_uc.Buffer, dc->name_uc.Length);
2501  dc->fileref = fileref;
2502  InsertTailList(&dummyfcb->dir_children_index, &dc->list_entry_index);
2503 
2504  fileref->dc = dc;
2505  fileref->parent = dummyfileref;
2506 
2508 
2509  fileref->fcb->adsxattr = adsxattr;
2510  fileref->fcb->adshash = crc32;
2511  fileref->fcb->adsmaxlen = newmaxlen;
2512  fileref->fcb->adsdata = adsdata;
2513 
2514  fileref->fcb->created = true;
2515 
2516  mark_fcb_dirty(fileref->fcb);
2517 
2519 
2520 end:
2521  if (sf)
2522  free_fileref(sf);
2523 
2524  return Status;
2525 }
2526 
2528  FILE_RENAME_INFORMATION_EX* fri = Irp->AssociatedIrp.SystemBuffer;
2529  fcb* fcb = FileObject->FsContext;
2530  ccb* ccb = FileObject->FsContext2;
2531  file_ref *fileref = ccb ? ccb->fileref : NULL, *oldfileref = NULL, *related = NULL, *fr2 = NULL;
2532  WCHAR* fn;
2533  ULONG fnlen, utf8len, origutf8len;
2534  UNICODE_STRING fnus;
2535  ANSI_STRING utf8;
2536  NTSTATUS Status;
2538  BTRFS_TIME now;
2539  LIST_ENTRY rollback, *le;
2540  hardlink* hl;
2541  SECURITY_SUBJECT_CONTEXT subjcont;
2543  ULONG flags;
2544 
2546 
2547  if (ex)
2548  flags = fri->Flags;
2549  else
2551 
2552  TRACE("tfo = %p\n", tfo);
2553  TRACE("Flags = %lx\n", flags);
2554  TRACE("RootDirectory = %p\n", fri->RootDirectory);
2555  TRACE("FileName = %.*S\n", (int)(fri->FileNameLength / sizeof(WCHAR)), fri->FileName);
2556 
2557  fn = fri->FileName;
2558  fnlen = fri->FileNameLength / sizeof(WCHAR);
2559 
2560  if (!tfo) {
2561  if (!fileref || !fileref->parent) {
2562  ERR("no fileref set and no directory given\n");
2563  return STATUS_INVALID_PARAMETER;
2564  }
2565  } else {
2566  LONG i;
2567 
2568  while (fnlen > 0 && (fri->FileName[fnlen - 1] == '/' || fri->FileName[fnlen - 1] == '\\')) {
2569  fnlen--;
2570  }
2571 
2572  if (fnlen == 0)
2573  return STATUS_INVALID_PARAMETER;
2574 
2575  for (i = fnlen - 1; i >= 0; i--) {
2576  if (fri->FileName[i] == '\\' || fri->FileName[i] == '/') {
2577  fn = &fri->FileName[i+1];
2578  fnlen -= i + 1;
2579  break;
2580  }
2581  }
2582  }
2583 
2584  ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
2585  ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, true);
2586  ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
2587 
2588  if (fcb->inode == SUBVOL_ROOT_INODE && fcb->subvol->id == BTRFS_ROOT_FSTREE) {
2589  WARN("not allowing \\$Root to be renamed\n");
2591  goto end;
2592  }
2593 
2594  if (fcb->ads) {
2595  if (FileObject->SectionObjectPointer && FileObject->SectionObjectPointer->DataSectionObject) {
2597 
2598  CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, &iosb);
2599  if (!NT_SUCCESS(iosb.Status)) {
2600  ERR("CcFlushCache returned %08lx\n", iosb.Status);
2601  Status = iosb.Status;
2602  goto end;
2603  }
2604  }
2605 
2607  goto end;
2608  } else if (fnlen >= 1 && fn[0] == ':') {
2609  if (FileObject->SectionObjectPointer && FileObject->SectionObjectPointer->DataSectionObject) {
2611 
2612  CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, &iosb);
2613  if (!NT_SUCCESS(iosb.Status)) {
2614  ERR("CcFlushCache returned %08lx\n", iosb.Status);
2615  Status = iosb.Status;
2616  goto end;
2617  }
2618  }
2619 
2621  goto end;
2622  }
2623 
2624  fnus.Buffer = fn;
2625  fnus.Length = fnus.MaximumLength = (uint16_t)(fnlen * sizeof(WCHAR));
2626 
2627  TRACE("fnus = %.*S\n", (int)(fnus.Length / sizeof(WCHAR)), fnus.Buffer);
2628 
2629  Status = check_file_name_valid(&fnus, false, false);
2630  if (!NT_SUCCESS(Status))
2631  goto end;
2632 
2633  origutf8len = fileref->dc->utf8.Length;
2634 
2635  Status = utf16_to_utf8(NULL, 0, &utf8len, fn, (ULONG)fnlen * sizeof(WCHAR));
2636  if (!NT_SUCCESS(Status))
2637  goto end;
2638 
2639  utf8.MaximumLength = utf8.Length = (uint16_t)utf8len;
2641  if (!utf8.Buffer) {
2642  ERR("out of memory\n");
2644  goto end;
2645  }
2646 
2647  Status = utf16_to_utf8(utf8.Buffer, utf8len, &utf8len, fn, (ULONG)fnlen * sizeof(WCHAR));
2648  if (!NT_SUCCESS(Status))
2649  goto end;
2650 
2651  if (tfo && tfo->FsContext2) {
2652  struct _ccb* relatedccb = tfo->FsContext2;
2653 
2654  related = relatedccb->fileref;
2655  increase_fileref_refcount(related);
2656  } else if (fnus.Length >= sizeof(WCHAR) && fnus.Buffer[0] != '\\') {
2657  related = fileref->parent;
2658  increase_fileref_refcount(related);
2659  }
2660 
2661  Status = open_fileref(Vcb, &oldfileref, &fnus, related, false, NULL, NULL, PagedPool, ccb->case_sensitive, Irp);
2662 
2663  if (NT_SUCCESS(Status)) {
2664  TRACE("destination file already exists\n");
2665 
2666  if (fileref != oldfileref && !oldfileref->deleted) {
2669  goto end;
2670  } else if (fileref == oldfileref) {
2672  goto end;
2673  } else if (!(flags & FILE_RENAME_POSIX_SEMANTICS) && (oldfileref->open_count > 0 || has_open_children(oldfileref)) && !oldfileref->deleted) {
2674  WARN("trying to overwrite open file\n");
2676  goto end;
2677  } else if (!(flags & FILE_RENAME_IGNORE_READONLY_ATTRIBUTE) && oldfileref->fcb->atts & FILE_ATTRIBUTE_READONLY) {
2678  WARN("trying to overwrite readonly file\n");
2680  goto end;
2681  } else if (oldfileref->fcb->type == BTRFS_TYPE_DIRECTORY) {
2682  WARN("trying to overwrite directory\n");
2684  goto end;
2685  }
2686  }
2687 
2688  if (fileref == oldfileref || oldfileref->deleted) {
2689  free_fileref(oldfileref);
2690  oldfileref = NULL;
2691  }
2692  }
2693 
2694  if (!related) {
2695  Status = open_fileref(Vcb, &related, &fnus, NULL, true, NULL, NULL, PagedPool, ccb->case_sensitive, Irp);
2696 
2697  if (!NT_SUCCESS(Status)) {
2698  ERR("open_fileref returned %08lx\n", Status);
2699  goto end;
2700  }
2701  }
2702 
2703  if (related->fcb == Vcb->dummy_fcb) {
2705  goto end;
2706  }
2707 
2708  SeCaptureSubjectContext(&subjcont);
2709 
2710  if (!SeAccessCheck(related->fcb->sd, &subjcont, false, fcb->type == BTRFS_TYPE_DIRECTORY ? FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE, 0, NULL,
2711  IoGetFileObjectGenericMapping(), Irp->RequestorMode, &access, &Status)) {
2712  SeReleaseSubjectContext(&subjcont);
2713  TRACE("SeAccessCheck failed, returning %08lx\n", Status);
2714  goto end;
2715  }
2716 
2717  SeReleaseSubjectContext(&subjcont);
2718 
2719  if (has_open_children(fileref)) {
2720  WARN("trying to rename file with open children\n");
2722  goto end;
2723  }
2724 
2725  if (oldfileref) {
2726  SeCaptureSubjectContext(&subjcont);
2727 
2728  if (!SeAccessCheck(oldfileref->fcb->sd, &subjcont, false, DELETE, 0, NULL,
2729  IoGetFileObjectGenericMapping(), Irp->RequestorMode, &access, &Status)) {
2730  SeReleaseSubjectContext(&subjcont);
2731  TRACE("SeAccessCheck failed, returning %08lx\n", Status);
2732  goto end;
2733  }
2734 
2735  SeReleaseSubjectContext(&subjcont);
2736 
2737  if (oldfileref->open_count > 0 && flags & FILE_RENAME_POSIX_SEMANTICS) {
2738  oldfileref->delete_on_close = true;
2739  oldfileref->posix_delete = true;
2740  }
2741 
2742  Status = delete_fileref(oldfileref, NULL, oldfileref->open_count > 0 && flags & FILE_RENAME_POSIX_SEMANTICS, Irp, &rollback);
2743  if (!NT_SUCCESS(Status)) {
2744  ERR("delete_fileref returned %08lx\n", Status);
2745  goto end;
2746  }
2747  }
2748 
2749  if (fileref->parent->fcb->subvol != related->fcb->subvol && (fileref->fcb->subvol == fileref->parent->fcb->subvol || fileref->fcb == Vcb->dummy_fcb)) {
2750  Status = move_across_subvols(fileref, ccb, related, &utf8, &fnus, Irp, &rollback);
2751  if (!NT_SUCCESS(Status)) {
2752  ERR("move_across_subvols returned %08lx\n", Status);
2753  }
2754  goto end;
2755  }
2756 
2757  if (related == fileref->parent) { // keeping file in same directory
2758  UNICODE_STRING oldfn, newfn;
2759  USHORT name_offset;
2760  ULONG reqlen, oldutf8len;
2761 
2762  oldfn.Length = oldfn.MaximumLength = 0;
2763 
2764  Status = fileref_get_filename(fileref, &oldfn, &name_offset, &reqlen);
2765  if (Status != STATUS_BUFFER_OVERFLOW) {
2766  ERR("fileref_get_filename returned %08lx\n", Status);
2767  goto end;
2768  }
2769 
2770  oldfn.Buffer = ExAllocatePoolWithTag(PagedPool, reqlen, ALLOC_TAG);
2771  if (!oldfn.Buffer) {
2772  ERR("out of memory\n");
2774  goto end;
2775  }
2776 
2777  oldfn.MaximumLength = (uint16_t)reqlen;
2778 
2779  Status = fileref_get_filename(fileref, &oldfn, &name_offset, &reqlen);
2780  if (!NT_SUCCESS(Status)) {
2781  ERR("fileref_get_filename returned %08lx\n", Status);
2782  ExFreePool(oldfn.Buffer);
2783  goto end;
2784  }
2785 
2786  oldutf8len = fileref->dc->utf8.Length;
2787 
2788  if (!fileref->created && !fileref->oldutf8.Buffer) {
2790  if (!fileref->oldutf8.Buffer) {
2791  ERR("out of memory\n");
2793  goto end;
2794  }
2795 
2798  }
2799 
2800  TRACE("renaming %.*S to %.*S\n", (int)(fileref->dc->name.Length / sizeof(WCHAR)), fileref->dc->name.Buffer, (int)(fnus.Length / sizeof(WCHAR)), fnus.Buffer);
2801 
2803 
2804  if (fileref->dc) {
2805  ExAcquireResourceExclusiveLite(&fileref->parent->fcb->nonpaged->dir_children_lock, true);
2806 
2810 
2812  if (!fileref->dc->utf8.Buffer) {
2813  ERR("out of memory\n");
2815  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
2816  ExFreePool(oldfn.Buffer);
2817  goto end;
2818  }
2819 
2821  RtlCopyMemory(fileref->dc->utf8.Buffer, utf8.Buffer, utf8.Length);
2822 
2824  if (!fileref->dc->name.Buffer) {
2825  ERR("out of memory\n");
2827  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
2828  ExFreePool(oldfn.Buffer);
2829  goto end;
2830  }
2831 
2833  RtlCopyMemory(fileref->dc->name.Buffer, fnus.Buffer, fnus.Length);
2834 
2836  if (!NT_SUCCESS(Status)) {
2837  ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
2838  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
2839  ExFreePool(oldfn.Buffer);
2840  goto end;
2841  }
2842 
2844 
2847 
2849 
2850  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
2851  }
2852 
2853  newfn.Length = newfn.MaximumLength = 0;
2854 
2855  Status = fileref_get_filename(fileref, &newfn, &name_offset, &reqlen);
2856  if (Status != STATUS_BUFFER_OVERFLOW) {
2857  ERR("fileref_get_filename returned %08lx\n", Status);
2858  ExFreePool(oldfn.Buffer);
2859  goto end;
2860  }
2861 
2862  newfn.Buffer = ExAllocatePoolWithTag(PagedPool, reqlen, ALLOC_TAG);
2863  if (!newfn.Buffer) {
2864  ERR("out of memory\n");
2866  ExFreePool(oldfn.Buffer);
2867  goto end;
2868  }
2869 
2870  newfn.MaximumLength = (uint16_t)reqlen;
2871 
2872  Status = fileref_get_filename(fileref, &newfn, &name_offset, &reqlen);
2873  if (!NT_SUCCESS(Status)) {
2874  ERR("fileref_get_filename returned %08lx\n", Status);
2875  ExFreePool(oldfn.Buffer);
2876  ExFreePool(newfn.Buffer);
2877  goto end;
2878  }
2879 
2882 
2883  if (fcb != Vcb->dummy_fcb && (fileref->parent->fcb->subvol == fcb->subvol || !is_subvol_readonly(fcb->subvol, Irp))) {
2884  fcb->inode_item.transid = Vcb->superblock.generation;
2885  fcb->inode_item.sequence++;
2886 
2887  if (!ccb->user_set_change_time)
2889 
2890  fcb->inode_item_changed = true;
2892  }
2893 
2894  // update parent's INODE_ITEM
2895 
2896  related->fcb->inode_item.transid = Vcb->superblock.generation;
2897  TRACE("related->fcb->inode_item.st_size (inode %I64x) was %I64x\n", related->fcb->inode, related->fcb->inode_item.st_size);
2898  related->fcb->inode_item.st_size = related->fcb->inode_item.st_size + (2 * utf8.Length) - (2* oldutf8len);
2899  TRACE("related->fcb->inode_item.st_size (inode %I64x) now %I64x\n", related->fcb->inode, related->fcb->inode_item.st_size);
2900  related->fcb->inode_item.sequence++;
2901  related->fcb->inode_item.st_ctime = now;
2902  related->fcb->inode_item.st_mtime = now;
2903 
2904  related->fcb->inode_item_changed = true;
2905  mark_fcb_dirty(related->fcb);
2907 
2908  FsRtlNotifyFilterReportChange(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, (PSTRING)&oldfn, name_offset, NULL, NULL,
2910  FsRtlNotifyFilterReportChange(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, (PSTRING)&newfn, name_offset, NULL, NULL,
2912 
2913  ExFreePool(oldfn.Buffer);
2914  ExFreePool(newfn.Buffer);
2915 
2917  goto end;
2918  }
2919 
2920  // We move files by moving the existing fileref to the new directory, and
2921  // replacing it with a dummy fileref with the same original values, but marked as deleted.
2922 
2924 
2925  fr2 = create_fileref(Vcb);
2926 
2927  fr2->fcb = fileref->fcb;
2928  fr2->fcb->refcount++;
2929 
2930  fr2->oldutf8 = fileref->oldutf8;
2931  fr2->oldindex = fileref->dc->index;
2932  fr2->delete_on_close = fileref->delete_on_close;
2933  fr2->deleted = true;
2934  fr2->created = fileref->created;
2935  fr2->parent = fileref->parent;
2936  fr2->dc = NULL;
2937 
2938  if (!fr2->oldutf8.Buffer) {
2939  fr2->oldutf8.Buffer = ExAllocatePoolWithTag(PagedPool, fileref->dc->utf8.Length, ALLOC_TAG);
2940  if (!fr2->oldutf8.Buffer) {
2941  ERR("out of memory\n");
2943  goto end;
2944  }
2945 
2946  RtlCopyMemory(fr2->oldutf8.Buffer, fileref->dc->utf8.Buffer, fileref->dc->utf8.Length);
2947 
2948  fr2->oldutf8.Length = fr2->oldutf8.MaximumLength = fileref->dc->utf8.Length;
2949  }
2950 
2951  if (fr2->fcb->type == BTRFS_TYPE_DIRECTORY)
2952  fr2->fcb->fileref = fr2;
2953 
2955  fileref->fcb->subvol->parent = related->fcb->subvol->id;
2956 
2959  fileref->deleted = false;
2960  fileref->created = true;
2961  fileref->parent = related;
2962 
2963  ExAcquireResourceExclusiveLite(&fileref->parent->fcb->nonpaged->dir_children_lock, true);
2964  InsertHeadList(&fileref->list_entry, &fr2->list_entry);
2966  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
2967 
2968  mark_fileref_dirty(fr2);
2970 
2971  if (fileref->dc) {
2972  // remove from old parent
2973  ExAcquireResourceExclusiveLite(&fr2->parent->fcb->nonpaged->dir_children_lock, true);
2975  remove_dir_child_from_hash_lists(fr2->parent->fcb, fileref->dc);
2976  ExReleaseResourceLite(&fr2->parent->fcb->nonpaged->dir_children_lock);
2977 
2978  if (fileref->dc->utf8.Length != utf8.Length || RtlCompareMemory(fileref->dc->utf8.Buffer, utf8.Buffer, utf8.Length) != utf8.Length) {
2979  // handle changed name
2980 
2984 
2986  if (!fileref->dc->utf8.Buffer) {
2987  ERR("out of memory\n");
2989  goto end;
2990  }
2991 
2993  RtlCopyMemory(fileref->dc->utf8.Buffer, utf8.Buffer, utf8.Length);
2994 
2996  if (!fileref->dc->name.Buffer) {
2997  ERR("out of memory\n");
2999  goto end;
3000  }
3001 
3003  RtlCopyMemory(fileref->dc->name.Buffer, fnus.Buffer, fnus.Length);
3004 
3006  if (!NT_SUCCESS(Status)) {
3007  ERR("RtlUpcaseUnicodeString returned %08lx\n", Status);
3008  goto end;
3009  }
3010 
3013  }
3014 
3015  // add to new parent
3016  ExAcquireResourceExclusiveLite(&related->fcb->nonpaged->dir_children_lock, true);
3017 
3018  if (IsListEmpty(&related->fcb->dir_children_index))
3019  fileref->dc->index = 2;
3020  else {
3021  dir_child* dc2 = CONTAINING_RECORD(related->fcb->dir_children_index.Blink, dir_child, list_entry_index);
3022 
3023  fileref->dc->index = max(2, dc2->index + 1);
3024  }
3025 
3026  InsertTailList(&related->fcb->dir_children_index, &fileref->dc->list_entry_index);
3028  ExReleaseResourceLite(&related->fcb->nonpaged->dir_children_lock);
3029  }
3030 
3031  ExAcquireResourceExclusiveLite(&related->fcb->nonpaged->dir_children_lock, true);
3032  InsertTailList(&related->children, &fileref->list_entry);
3033  ExReleaseResourceLite(&related->fcb->nonpaged->dir_children_lock);
3034 
3035  if (fcb->inode_item.st_nlink > 1) {
3036  // add new hardlink entry to fcb
3037 
3039  if (!hl) {
3040  ERR("out of memory\n");
3042  goto end;
3043  }
3044 
3045  hl->parent = related->fcb->inode;
3046  hl->index = fileref->dc->index;
3047 
3048  hl->name.Length = hl->name.MaximumLength = fnus.Length;
3050 
3051  if (!hl->name.Buffer) {
3052  ERR("out of memory\n");
3053  ExFreePool(hl);
3055  goto end;
3056  }
3057 
3058  RtlCopyMemory(hl->name.Buffer, fnus.Buffer, fnus.Length);
3059 
3062 
3063  if (!hl->utf8.Buffer) {
3064  ERR("out of memory\n");
3065  ExFreePool(hl->name.Buffer);
3066  ExFreePool(hl);
3068  goto end;
3069  }
3070 
3072 
3074  }
3075 
3076  // delete old hardlink entry from fcb
3077 
3078  le = fcb->hardlinks.Flink;
3079  while (le != &fcb->hardlinks) {
3081 
3082  if (hl->parent == fr2->parent->fcb->inode && hl->index == fr2->oldindex) {
3084 
3085  if (hl->utf8.Buffer)
3086  ExFreePool(hl->utf8.Buffer);
3087 
3088  if (hl->name.Buffer)
3089  ExFreePool(hl->name.Buffer);
3090 
3091  ExFreePool(hl);
3092  break;
3093  }
3094 
3095  le = le->Flink;
3096  }
3097 
3098  // update inode's INODE_ITEM
3099 
3102 
3103  if (fcb != Vcb->dummy_fcb && (fileref->parent->fcb->subvol == fcb->subvol || !is_subvol_readonly(fcb->subvol, Irp))) {
3104  fcb->inode_item.transid = Vcb->superblock.generation;
3105  fcb->inode_item.sequence++;
3106 
3107  if (!ccb->user_set_change_time)
3109 
3110  fcb->inode_item_changed = true;
3112  }
3113 
3114  // update new parent's INODE_ITEM
3115 
3116  related->fcb->inode_item.transid = Vcb->superblock.generation;
3117  TRACE("related->fcb->inode_item.st_size (inode %I64x) was %I64x\n", related->fcb->inode, related->fcb->inode_item.st_size);
3118  related->fcb->inode_item.st_size += 2 * utf8len;
3119  TRACE("related->fcb->inode_item.st_size (inode %I64x) now %I64x\n", related->fcb->inode, related->fcb->inode_item.st_size);
3120  related->fcb->inode_item.sequence++;
3121  related->fcb->inode_item.st_ctime = now;
3122  related->fcb->inode_item.st_mtime = now;
3123 
3124  related->fcb->inode_item_changed = true;
3125  mark_fcb_dirty(related->fcb);
3126 
3127  // update old parent's INODE_ITEM
3128 
3129  fr2->parent->fcb->inode_item.transid = Vcb->superblock.generation;
3130  TRACE("fr2->parent->fcb->inode_item.st_size (inode %I64x) was %I64x\n", fr2->parent->fcb->inode, fr2->parent->fcb->inode_item.st_size);
3131  fr2->parent->fcb->inode_item.st_size -= 2 * origutf8len;
3132  TRACE("fr2->parent->fcb->inode_item.st_size (inode %I64x) now %I64x\n", fr2->parent->fcb->inode, fr2->parent->fcb->inode_item.st_size);
3133  fr2->parent->fcb->inode_item.sequence++;
3134  fr2->parent->fcb->inode_item.st_ctime = now;
3135  fr2->parent->fcb->inode_item.st_mtime = now;
3136 
3137  free_fileref(fr2);
3138 
3139  fr2->parent->fcb->inode_item_changed = true;
3140  mark_fcb_dirty(fr2->parent->fcb);
3141 
3145 
3147 
3148 end:
3149  if (oldfileref)
3150  free_fileref(oldfileref);
3151 
3152  if (!NT_SUCCESS(Status) && related)
3153  free_fileref(related);
3154 
3155  if (!NT_SUCCESS(Status) && fr2)
3156  free_fileref(fr2);
3157 
3158  if (NT_SUCCESS(Status))
3160  else
3162 
3163  ExReleaseResourceLite(fcb->Header.Resource);
3164  ExReleaseResourceLite(&Vcb->fileref_lock);
3165  ExReleaseResourceLite(&Vcb->tree_lock);
3166 
3167  return Status;
3168 }
3169 
3172  BTRFS_TIME now;
3173 
3174  TRACE("setting new end to %x bytes (currently %x)\n", end, fcb->adsdata.Length);
3175 
3176  if (!fileref || !fileref->parent) {
3177  ERR("no fileref for stream\n");
3178  return STATUS_INTERNAL_ERROR;
3179  }
3180 
3181  if (end < fcb->adsdata.Length) {
3182  if (advance_only)
3183  return STATUS_SUCCESS;
3184 
3185  TRACE("truncating stream to %x bytes\n", end);
3186 
3187  fcb->adsdata.Length = end;
3188  } else if (end > fcb->adsdata.Length) {
3189  TRACE("extending stream to %x bytes\n", end);
3190 
3191  if (end > fcb->adsmaxlen) {
3192  ERR("error - xattr too long (%u > %lu)\n", end, fcb->adsmaxlen);
3193  return STATUS_DISK_FULL;
3194  }
3195 
3196  if (end > fcb->adsdata.MaximumLength) {
3198  if (!data) {
3199  ERR("out of memory\n");
3200  ExFreePool(data);
3202  }
3203 
3204  if (fcb->adsdata.Buffer) {
3207  }
3208 
3209  fcb->adsdata.Buffer = data;
3211  }
3212 
3214 
3215  fcb->adsdata.Length = end;
3216  }
3217 
3219 
3220  fcb->Header.AllocationSize.QuadPart = end;
3221  fcb->Header.FileSize.QuadPart = end;
3222  fcb->Header.ValidDataLength.QuadPart = end;
3223 
3226 
3227  fileref->parent->fcb->inode_item.transid = Vcb->superblock.generation;
3228  fileref->parent->fcb->inode_item.sequence++;
3229  fileref->parent->fcb->inode_item.st_ctime = now;
3230 
3231  fileref->parent->fcb->inode_item_changed = true;
3232  mark_fcb_dirty(fileref->parent->fcb);
3233 
3234  fileref->parent->fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
3235  fileref->parent->fcb->subvol->root_item.ctime = now;
3236 
3237  return STATUS_SUCCESS;
3238 }
3239 
3241  FILE_END_OF_FILE_INFORMATION* feofi = Irp->AssociatedIrp.SystemBuffer;
3242  fcb* fcb = FileObject->FsContext;
3243  ccb* ccb = FileObject->FsContext2;
3244  file_ref* fileref = ccb ? ccb->fileref : NULL;
3245  NTSTATUS Status;
3247  CC_FILE_SIZES ccfs;
3249  bool set_size = false;
3250  ULONG filter;
3251  uint64_t new_end_of_file;
3252 
3253  if (!fileref) {
3254  ERR("fileref is NULL\n");
3255  return STATUS_INVALID_PARAMETER;
3256  }
3257 
3259 
3260  ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
3261 
3262  ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
3263 
3264  if (fileref ? fileref->deleted : fcb->deleted) {
3266  goto end;
3267  }
3268 
3269  if (fcb->ads) {
3270  if (feofi->EndOfFile.QuadPart > 0xffff) {
3272  goto end;
3273  }
3274 
3275  if (feofi->EndOfFile.QuadPart < 0) {
3277  goto end;
3278  }
3279 
3281 
3282  if (NT_SUCCESS(Status)) {
3283  ccfs.AllocationSize = fcb->Header.AllocationSize;
3284  ccfs.FileSize = fcb->Header.FileSize;
3285  ccfs.ValidDataLength = fcb->Header.ValidDataLength;
3286  set_size = true;
3287  }
3288 
3290 
3291  if (!ccb->user_set_write_time) {
3293  win_time_to_unix(time, &fileref->parent->fcb->inode_item.st_mtime);
3295 
3296  fileref->parent->fcb->inode_item_changed = true;
3297  mark_fcb_dirty(fileref->parent->fcb);
3298  }
3299 
3301 
3302  goto end;
3303  }
3304 
3305  TRACE("file: %p\n", FileObject);
3306  TRACE("paging IO: %s\n", Irp->Flags & IRP_PAGING_IO ? "true" : "false");
3307  TRACE("FileObject: AllocationSize = %I64x, FileSize = %I64x, ValidDataLength = %I64x\n",
3308  fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart);
3309 
3310  new_end_of_file = feofi->EndOfFile.QuadPart;
3311 
3312  /* The lazy writer sometimes tries to round files to the next page size through CcSetValidData -
3313  * ignore these. See fastfat!FatSetEndOfFileInfo, where Microsoft does the same as we're
3314  * doing below. */
3315  if (advance_only && new_end_of_file >= (uint64_t)fcb->Header.FileSize.QuadPart)
3316  new_end_of_file = fcb->Header.FileSize.QuadPart;
3317 
3318  TRACE("setting new end to %I64x bytes (currently %I64x)\n", new_end_of_file, fcb->inode_item.st_size);
3319 
3320  if (new_end_of_file < fcb->inode_item.st_size) {
3321  if (advance_only) {
3323  goto end;
3324  }
3325 
3326  TRACE("truncating file to %I64x bytes\n", new_end_of_file);
3327 
3328  if (!MmCanFileBeTruncated(&fcb->nonpaged->segment_object, &feofi->EndOfFile)) {
3330  goto end;
3331  }
3332 
3333  Status = truncate_file(fcb, new_end_of_file, Irp, &rollback);
3334  if (!NT_SUCCESS(Status)) {
3335  ERR("error - truncate_file failed\n");
3336  goto end;
3337  }
3338  } else if (new_end_of_file > fcb->inode_item.st_size) {
3339  TRACE("extending file to %I64x bytes\n", new_end_of_file);
3340 
3341  Status = extend_file(fcb, fileref, new_end_of_file, prealloc, NULL, &rollback);
3342  if (!NT_SUCCESS(Status)) {
3343  ERR("error - extend_file failed\n");
3344  goto end;
3345  }
3346  } else if (new_end_of_file == fcb->inode_item.st_size && advance_only) {
3348  goto end;
3349  }
3350 
3351  ccfs.AllocationSize = fcb->Header.AllocationSize;
3352  ccfs.FileSize = fcb->Header.FileSize;
3353  ccfs.ValidDataLength = fcb->Header.ValidDataLength;
3354  set_size = true;
3355 
3357 
3358  if (!ccb->user_set_write_time) {
3362  }
3363 
3364  fcb->inode_item_changed = true;
3367 
3369 
3370 end:
3371  if (NT_SUCCESS(Status))
3373  else
3375 
3376  ExReleaseResourceLite(fcb->Header.Resource);
3377 
3378  if (set_size) {
3379  _SEH2_TRY {
3380  CcSetFileSizes(FileObject, &ccfs);
3383  } _SEH2_END;
3384 
3385  if (!NT_SUCCESS(Status))
3386  ERR("CcSetFileSizes threw exception %08lx\n", Status);
3387  }
3388 
3389  ExReleaseResourceLite(&Vcb->tree_lock);
3390 
3391  return Status;
3392 }
3393 
3395  FILE_POSITION_INFORMATION* fpi = (FILE_POSITION_INFORMATION*)Irp->AssociatedIrp.SystemBuffer;
3396 
3397  TRACE("setting the position on %p to %I64x\n", FileObject, fpi->CurrentByteOffset.QuadPart);
3398 
3399  // FIXME - make sure aligned for FO_NO_INTERMEDIATE_BUFFERING
3400 
3401  FileObject->CurrentByteOffset = fpi->CurrentByteOffset;
3402 
3403  return STATUS_SUCCESS;
3404 }
3405 
3407  FILE_LINK_INFORMATION_EX* fli = Irp->AssociatedIrp.SystemBuffer;
3408  fcb *fcb = FileObject->FsContext, *tfofcb, *parfcb;
3409  ccb* ccb = FileObject->FsContext2;
3410  file_ref *fileref = ccb ? ccb->fileref : NULL, *oldfileref = NULL, *related = NULL, *fr2 = NULL;
3411  WCHAR* fn;
3412  ULONG fnlen, utf8len;
3413  UNICODE_STRING fnus;
3414  ANSI_STRING utf8;
3415  NTSTATUS Status;
3417  BTRFS_TIME now;
3419  hardlink* hl;
3421  SECURITY_SUBJECT_CONTEXT subjcont;
3422  dir_child* dc = NULL;
3423  ULONG flags;
3424 
3426 
3427  // FIXME - check fli length
3428  // FIXME - don't ignore fli->RootDirectory
3429 
3430  if (ex)
3431  flags = fli->Flags;
3432  else
3434 
3435  TRACE("flags = %lx\n", flags);
3436  TRACE("RootDirectory = %p\n", fli->RootDirectory);
3437  TRACE("FileNameLength = %lx\n", fli->FileNameLength);
3438  TRACE("FileName = %.*S\n", (int)(fli->FileNameLength / sizeof(WCHAR)), fli->FileName);
3439 
3440  fn = fli->FileName;
3441  fnlen = fli->FileNameLength / sizeof(WCHAR);
3442 
3443  if (!tfo) {
3444  if (!fileref || !fileref->parent) {
3445  ERR("no fileref set and no directory given\n");
3446  return STATUS_INVALID_PARAMETER;
3447  }
3448 
3449  parfcb = fileref->parent->fcb;
3450  tfofcb = NULL;
3451  } else {
3452  LONG i;
3453 
3454  tfofcb = tfo->FsContext;
3455  parfcb = tfofcb;
3456 
3457  while (fnlen > 0 && (fli->FileName[fnlen - 1] == '/' || fli->FileName[fnlen - 1] == '\\')) {
3458  fnlen--;
3459  }
3460 
3461  if (fnlen == 0)
3462  return STATUS_INVALID_PARAMETER;
3463 
3464  for (i = fnlen - 1; i >= 0; i--) {
3465  if (fli->FileName[i] == '\\' || fli->FileName[i] == '/') {
3466  fn = &fli->FileName[i+1];
3467  fnlen = (fli->FileNameLength / sizeof(WCHAR)) - i - 1;
3468  break;
3469  }
3470  }
3471  }
3472 
3473  ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
3474  ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, true);
3475  ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
3476 
3477  if (fcb->type == BTRFS_TYPE_DIRECTORY) {
3478  WARN("tried to create hard link on directory\n");
3480  goto end;
3481  }
3482 
3483  if (fcb->ads) {
3484  WARN("tried to create hard link on stream\n");
3486  goto end;
3487  }
3488 
3489  if (fcb->inode_item.st_nlink >= 65535) {
3491  goto end;
3492  }
3493 
3494  fnus.Buffer = fn;
3495  fnus.Length = fnus.MaximumLength = (uint16_t)(fnlen * sizeof(WCHAR));
3496 
3497  TRACE("fnus = %.*S\n", (int)(fnus.Length / sizeof(WCHAR)), fnus.Buffer);
3498 
3499  Status = check_file_name_valid(&fnus, false, false);
3500  if (!NT_SUCCESS(Status))
3501  goto end;
3502 
3503  Status = utf16_to_utf8(NULL, 0, &utf8len, fn, (ULONG)fnlen * sizeof(WCHAR));
3504  if (!NT_SUCCESS(Status))
3505  goto end;
3506 
3507  utf8.MaximumLength = utf8.Length = (uint16_t)utf8len;
3509  if (!utf8.Buffer) {
3510  ERR("out of memory\n");
3512  goto