ReactOS  0.4.14-dev-608-gd495a4f
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 
20 #if (NTDDI_VERSION >= NTDDI_WIN10)
21 // not currently in mingw - introduced with Windows 10
22 #ifndef _MSC_VER
23 #define FileIdInformation (enum _FILE_INFORMATION_CLASS)59
24 #define FileHardLinkFullIdInformation (enum _FILE_INFORMATION_CLASS)62
25 #define FileDispositionInformationEx (enum _FILE_INFORMATION_CLASS)64
26 #define FileRenameInformationEx (enum _FILE_INFORMATION_CLASS)65
27 #define FileStatInformation (enum _FILE_INFORMATION_CLASS)68
28 #define FileStatLxInformation (enum _FILE_INFORMATION_CLASS)70
29 #define FileCaseSensitiveInformation (enum _FILE_INFORMATION_CLASS)71
30 #define FileLinkInformationEx (enum _FILE_INFORMATION_CLASS)72
31 
32 typedef struct _FILE_ID_INFORMATION {
36 
37 typedef struct _FILE_STAT_INFORMATION {
50 
51 typedef struct _FILE_STAT_LX_INFORMATION {
70 
71 #define LX_FILE_METADATA_HAS_UID 0x01
72 #define LX_FILE_METADATA_HAS_GID 0x02
73 #define LX_FILE_METADATA_HAS_MODE 0x04
74 #define LX_FILE_METADATA_HAS_DEVICE_ID 0x08
75 #define LX_FILE_CASE_SENSITIVE_DIR 0x10
76 
78  union {
81  };
86 
90 
91 typedef struct _FILE_LINK_INFORMATION_EX {
92  union {
95  };
100 
104 
111 
117 
118 #define FILE_RENAME_REPLACE_IF_EXISTS 0x001
119 #define FILE_RENAME_POSIX_SEMANTICS 0x002
120 #define FILE_RENAME_SUPPRESS_PIN_STATE_INHERITANCE 0x004
121 #define FILE_RENAME_SUPPRESS_STORAGE_RESERVE_INHERITANCE 0x008
122 #define FILE_RENAME_NO_INCREASE_AVAILABLE_SPACE 0x010
123 #define FILE_RENAME_NO_DECREASE_AVAILABLE_SPACE 0x020
124 #define FILE_RENAME_IGNORE_READONLY_ATTRIBUTE 0x040
125 #define FILE_RENAME_FORCE_RESIZE_TARGET_SR 0x080
126 #define FILE_RENAME_FORCE_RESIZE_SOURCE_SR 0x100
127 
128 #define FILE_DISPOSITION_DELETE 0x1
129 #define FILE_DISPOSITION_POSIX_SEMANTICS 0x2
130 #define FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK 0x4
131 #define FILE_DISPOSITION_ON_CLOSE 0x8
132 
133 #define FILE_LINK_REPLACE_IF_EXISTS 0x001
134 #define FILE_LINK_POSIX_SEMANTICS 0x002
135 #define FILE_LINK_SUPPRESS_STORAGE_RESERVE_INHERITANCE 0x008
136 #define FILE_LINK_NO_INCREASE_AVAILABLE_SPACE 0x010
137 #define FILE_LINK_NO_DECREASE_AVAILABLE_SPACE 0x020
138 #define FILE_LINK_IGNORE_READONLY_ATTRIBUTE 0x040
139 #define FILE_LINK_FORCE_RESIZE_TARGET_SR 0x080
140 #define FILE_LINK_FORCE_RESIZE_SOURCE_SR 0x100
141 
142 #define FILE_CS_FLAG_CASE_SENSITIVE_DIR 1
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 = %x\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 = %x\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->superblock.sector_size;
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 %08x\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);
805 
806  fcb->inode_item.generation = Vcb->superblock.generation;
807  fcb->inode_item.transid = Vcb->superblock.generation;
808  fcb->inode_item.st_nlink = 1;
809  fcb->inode_item.st_mode = __S_IFDIR | inherit_mode(parfcb, true);
812 
813  fcb->atts = get_file_attributes(Vcb, fcb->subvol, fcb->inode, fcb->type, false, true, NULL);
814 
815  SeCaptureSubjectContext(&subjcont);
816 
817  Status = SeAssignSecurity(parfcb->sd, NULL, (void**)&fcb->sd, true, &subjcont, IoGetFileObjectGenericMapping(), PagedPool);
818 
819  if (!NT_SUCCESS(Status)) {
820  reap_fcb(fcb);
821  ERR("SeAssignSecurity returned %08x\n", Status);
822  return Status;
823  }
824 
825  if (!fcb->sd) {
826  reap_fcb(fcb);
827  ERR("SeAssignSecurity returned NULL security descriptor\n");
828  return STATUS_INTERNAL_ERROR;
829  }
830 
831  Status = RtlGetOwnerSecurityDescriptor(fcb->sd, &owner, &defaulted);
832  if (!NT_SUCCESS(Status)) {
833  ERR("RtlGetOwnerSecurityDescriptor returned %08x\n", Status);
835  fcb->sd_dirty = true;
836  } else {
837  fcb->inode_item.st_uid = sid_to_uid(owner);
839  }
840 
841  find_gid(fcb, parfcb, &subjcont);
842 
843  fcb->inode_item_changed = true;
844 
845  fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
846  fcb->Header.AllocationSize.QuadPart = 0;
847  fcb->Header.FileSize.QuadPart = 0;
848  fcb->Header.ValidDataLength.QuadPart = 0;
849 
850  fcb->created = true;
851 
852  if (parfcb->inode_item.flags & BTRFS_INODE_COMPRESS)
854 
857 
859  if (!fcb->hash_ptrs) {
860  ERR("out of memory\n");
862  }
863 
864  RtlZeroMemory(fcb->hash_ptrs, sizeof(LIST_ENTRY*) * 256);
865 
867  if (!fcb->hash_ptrs_uc) {
868  ERR("out of memory\n");
870  }
871 
872  RtlZeroMemory(fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256);
873 
874  acquire_fcb_lock_exclusive(Vcb);
875  InsertTailList(&r->fcbs, &fcb->list_entry);
876  InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
877  r->fcbs_version++;
878  release_fcb_lock(Vcb);
879 
881 
882  *pfcb = fcb;
883 
884  return STATUS_SUCCESS;
885 }
886 
889  LIST_ENTRY move_list, *le;
890  move_entry* me;
892  BTRFS_TIME now;
893  file_ref* origparent;
894 
895  // FIXME - make sure me->dummyfileref and me->dummyfcb get freed properly
896 
898 
901 
902  acquire_fcb_lock_exclusive(fileref->fcb->Vcb);
903 
905 
906  if (!me) {
907  ERR("out of memory\n");
909  goto end;
910  }
911 
912  origparent = fileref->parent;
913 
914  me->fileref = fileref;
916  me->dummyfcb = NULL;
917  me->dummyfileref = NULL;
918  me->parent = NULL;
919 
921 
922  le = move_list.Flink;
923  while (le != &move_list) {
925 
926  ExAcquireResourceSharedLite(me->fileref->fcb->Header.Resource, true);
927 
928  if (!me->fileref->fcb->ads && me->fileref->fcb->subvol == origparent->fcb->subvol) {
930 
931  if (!NT_SUCCESS(Status)) {
932  ERR("add_children_to_move_list returned %08x\n", Status);
933  goto end;
934  }
935  }
936 
937  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
938 
939  le = le->Flink;
940  }
941 
943 
944  // loop through list and create new inodes
945 
946  le = move_list.Flink;
947  while (le != &move_list) {
949 
950  if (me->fileref->fcb->inode != SUBVOL_ROOT_INODE && me->fileref->fcb != fileref->fcb->Vcb->dummy_fcb) {
951  if (!me->dummyfcb) {
952  ULONG defda;
953  bool inserted = false;
954  LIST_ENTRY* le3;
955 
956  ExAcquireResourceExclusiveLite(me->fileref->fcb->Header.Resource, true);
957 
958  Status = duplicate_fcb(me->fileref->fcb, &me->dummyfcb);
959  if (!NT_SUCCESS(Status)) {
960  ERR("duplicate_fcb returned %08x\n", Status);
961  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
962  goto end;
963  }
964 
965  me->dummyfcb->subvol = me->fileref->fcb->subvol;
966  me->dummyfcb->inode = me->fileref->fcb->inode;
967 
968  if (!me->dummyfcb->ads) {
969  me->dummyfcb->sd_dirty = me->fileref->fcb->sd_dirty;
975  }
976 
977  me->dummyfcb->created = me->fileref->fcb->created;
978  me->dummyfcb->deleted = me->fileref->fcb->deleted;
980 
981  if (!me->fileref->fcb->ads) {
982  LIST_ENTRY* le2;
983 
984  me->fileref->fcb->subvol = destdir->fcb->subvol;
985  me->fileref->fcb->inode = InterlockedIncrement64(&destdir->fcb->subvol->lastinode);
986  me->fileref->fcb->inode_item.st_nlink = 1;
987 
988  defda = get_file_attributes(me->fileref->fcb->Vcb, me->fileref->fcb->subvol, me->fileref->fcb->inode,
989  me->fileref->fcb->type, me->fileref->dc && me->fileref->dc->name.Length >= sizeof(WCHAR) && me->fileref->dc->name.Buffer[0] == '.',
990  true, Irp);
991 
992  me->fileref->fcb->sd_dirty = !!me->fileref->fcb->sd;
993  me->fileref->fcb->atts_changed = defda != me->fileref->fcb->atts;
996  me->fileref->fcb->ea_changed = !!me->fileref->fcb->ea_xattr.Buffer;
998  me->fileref->fcb->inode_item_changed = true;
999 
1000  le2 = me->fileref->fcb->xattrs.Flink;
1001  while (le2 != &me->fileref->fcb->xattrs) {
1002  xattr* xa = CONTAINING_RECORD(le2, xattr, list_entry);
1003 
1004  xa->dirty = true;
1005 
1006  le2 = le2->Flink;
1007  }
1008 
1009  if (le == move_list.Flink) { // first entry
1010  me->fileref->fcb->inode_item.transid = me->fileref->fcb->Vcb->superblock.generation;
1011  me->fileref->fcb->inode_item.sequence++;
1012 
1013  if (!ccb->user_set_change_time)
1014  me->fileref->fcb->inode_item.st_ctime = now;
1015  }
1016 
1017  le2 = me->fileref->fcb->extents.Flink;
1018  while (le2 != &me->fileref->fcb->extents) {
1020 
1021  if (!ext->ignore && (ext->extent_data.type == EXTENT_TYPE_REGULAR || ext->extent_data.type == EXTENT_TYPE_PREALLOC)) {
1022  EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ext->extent_data.data;
1023 
1024  if (ed2->size != 0) {
1026 
1027  if (!c) {
1028  ERR("get_chunk_from_address(%I64x) failed\n", ed2->address);
1029  } else {
1031  ext->offset - ed2->offset, 1, me->fileref->fcb->inode_item.flags & BTRFS_INODE_NODATASUM, false, Irp);
1032 
1033  if (!NT_SUCCESS(Status)) {
1034  ERR("update_changed_extent_ref returned %08x\n", Status);
1035  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
1036  goto end;
1037  }
1038  }
1039 
1040  }
1041  }
1042 
1043  le2 = le2->Flink;
1044  }
1045  } else {
1046  me->fileref->fcb->subvol = me->parent->fileref->fcb->subvol;
1047  me->fileref->fcb->inode = me->parent->fileref->fcb->inode;
1048  }
1049 
1050  me->fileref->fcb->created = true;
1051 
1054 
1055  le3 = destdir->fcb->subvol->fcbs.Flink;
1056  while (le3 != &destdir->fcb->subvol->fcbs) {
1057  fcb* fcb = CONTAINING_RECORD(le3, struct _fcb, list_entry);
1058 
1059  if (fcb->inode > me->fileref->fcb->inode) {
1060  InsertHeadList(le3->Blink, &me->fileref->fcb->list_entry);
1061  inserted = true;
1062  break;
1063  }
1064 
1065  le3 = le3->Flink;
1066  }
1067 
1068  if (!inserted)
1069  InsertTailList(&destdir->fcb->subvol->fcbs, &me->fileref->fcb->list_entry);
1070 
1071  InsertTailList(&me->fileref->fcb->Vcb->all_fcbs, &me->dummyfcb->list_entry_all);
1072 
1073  while (!IsListEmpty(&me->fileref->fcb->hardlinks)) {
1075 
1076  if (hl->name.Buffer)
1077  ExFreePool(hl->name.Buffer);
1078 
1079  if (hl->utf8.Buffer)
1080  ExFreePool(hl->utf8.Buffer);
1081 
1082  ExFreePool(hl);
1083  }
1084 
1085  me->fileref->fcb->inode_item_changed = true;
1086  mark_fcb_dirty(me->fileref->fcb);
1087 
1088  if ((!me->dummyfcb->ads && me->dummyfcb->inode_item.st_nlink > 1) || (me->dummyfcb->ads && me->parent->dummyfcb->inode_item.st_nlink > 1)) {
1089  LIST_ENTRY* le2 = le->Flink;
1090 
1091  while (le2 != &move_list) {
1093 
1094  if (me2->fileref->fcb == me->fileref->fcb && !me2->fileref->fcb->ads) {
1095  me2->dummyfcb = me->dummyfcb;
1097  }
1098 
1099  le2 = le2->Flink;
1100  }
1101  }
1102 
1103  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
1104  } else {
1105  ExAcquireResourceExclusiveLite(me->fileref->fcb->Header.Resource, true);
1106  me->fileref->fcb->inode_item.st_nlink++;
1107  me->fileref->fcb->inode_item_changed = true;
1108  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
1109  }
1110  }
1111 
1112  le = le->Flink;
1113  }
1114 
1115  fileref->fcb->subvol->root_item.ctransid = fileref->fcb->Vcb->superblock.generation;
1116  fileref->fcb->subvol->root_item.ctime = now;
1117 
1118  // loop through list and create new filerefs
1119 
1120  le = move_list.Flink;
1121  while (le != &move_list) {
1122  hardlink* hl;
1123  bool name_changed = false;
1124 
1126 
1128  if (!me->dummyfileref) {
1129  ERR("out of memory\n");
1131  goto end;
1132  }
1133 
1134  if (me->fileref->fcb == me->fileref->fcb->Vcb->dummy_fcb) {
1135  root* r = me->parent ? me->parent->fileref->fcb->subvol : destdir->fcb->subvol;
1136 
1137  Status = create_directory_fcb(me->fileref->fcb->Vcb, r, me->fileref->parent->fcb, &me->fileref->fcb);
1138  if (!NT_SUCCESS(Status)) {
1139  ERR("create_directory_fcb returnd %08x\n", Status);
1140  goto end;
1141  }
1142 
1143  me->fileref->dc->key.obj_id = me->fileref->fcb->inode;
1145 
1146  me->dummyfileref->fcb = me->fileref->fcb->Vcb->dummy_fcb;
1147  } else if (me->fileref->fcb->inode == SUBVOL_ROOT_INODE) {
1148  me->dummyfileref->fcb = me->fileref->fcb;
1149 
1150  me->fileref->fcb->subvol->parent = le == move_list.Flink ? destdir->fcb->subvol->id : me->parent->fileref->fcb->subvol->id;
1151  } else
1152  me->dummyfileref->fcb = me->dummyfcb;
1153 
1155 
1156  me->dummyfileref->oldutf8 = me->fileref->oldutf8;
1157  me->dummyfileref->oldindex = me->fileref->dc->index;
1158 
1159  if (le == move_list.Flink && (me->fileref->dc->utf8.Length != utf8->Length || RtlCompareMemory(me->fileref->dc->utf8.Buffer, utf8->Buffer, utf8->Length) != utf8->Length))
1160  name_changed = true;
1161 
1162  if ((le == move_list.Flink || me->fileref->fcb->inode == SUBVOL_ROOT_INODE) && !me->dummyfileref->oldutf8.Buffer) {
1164  if (!me->dummyfileref->oldutf8.Buffer) {
1165  ERR("out of memory\n");
1167  goto end;
1168  }
1169 
1171 
1173  }
1174 
1176  me->dummyfileref->deleted = me->fileref->deleted;
1177 
1178  me->dummyfileref->created = me->fileref->created;
1179  me->fileref->created = true;
1180 
1181  me->dummyfileref->parent = me->parent ? me->parent->dummyfileref : origparent;
1183 
1184  ExAcquireResourceExclusiveLite(&me->dummyfileref->parent->fcb->nonpaged->dir_children_lock, true);
1185  InsertTailList(&me->dummyfileref->parent->children, &me->dummyfileref->list_entry);
1186  ExReleaseResourceLite(&me->dummyfileref->parent->fcb->nonpaged->dir_children_lock);
1187 
1189  me->dummyfileref->fcb->fileref = me->dummyfileref;
1190 
1191  if (!me->parent) {
1193 
1194  increase_fileref_refcount(destdir);
1195 
1196  if (me->fileref->dc) {
1197  // remove from old parent
1198  ExAcquireResourceExclusiveLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock, true);
1201  ExReleaseResourceLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock);
1202 
1203  me->fileref->parent->fcb->inode_item.st_size -= me->fileref->dc->utf8.Length * 2;
1204  me->fileref->parent->fcb->inode_item.transid = me->fileref->fcb->Vcb->superblock.generation;
1205  me->fileref->parent->fcb->inode_item.sequence++;
1206  me->fileref->parent->fcb->inode_item.st_ctime = now;
1207  me->fileref->parent->fcb->inode_item.st_mtime = now;
1208  me->fileref->parent->fcb->inode_item_changed = true;
1209  mark_fcb_dirty(me->fileref->parent->fcb);
1210 
1211  if (name_changed) {
1212  ExFreePool(me->fileref->dc->utf8.Buffer);
1213  ExFreePool(me->fileref->dc->name.Buffer);
1215 
1217  if (!me->fileref->dc->utf8.Buffer) {
1218  ERR("out of memory\n");
1220  goto end;
1221  }
1222 
1223  me->fileref->dc->utf8.Length = me->fileref->dc->utf8.MaximumLength = utf8->Length;
1224  RtlCopyMemory(me->fileref->dc->utf8.Buffer, utf8->Buffer, utf8->Length);
1225 
1227  if (!me->fileref->dc->name.Buffer) {
1228  ERR("out of memory\n");
1230  goto end;
1231  }
1232 
1233  me->fileref->dc->name.Length = me->fileref->dc->name.MaximumLength = fnus->Length;
1234  RtlCopyMemory(me->fileref->dc->name.Buffer, fnus->Buffer, fnus->Length);
1235 
1237  if (!NT_SUCCESS(Status)) {
1238  ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
1239  goto end;
1240  }
1241 
1242  me->fileref->dc->hash = calc_crc32c(0xffffffff, (uint8_t*)me->fileref->dc->name.Buffer, me->fileref->dc->name.Length);
1243  me->fileref->dc->hash_uc = calc_crc32c(0xffffffff, (uint8_t*)me->fileref->dc->name_uc.Buffer, me->fileref->dc->name_uc.Length);
1244  }
1245 
1246  if (me->fileref->dc->key.obj_type == TYPE_INODE_ITEM)
1247  me->fileref->dc->key.obj_id = me->fileref->fcb->inode;
1248 
1249  // add to new parent
1250 
1251  ExAcquireResourceExclusiveLite(&destdir->fcb->nonpaged->dir_children_lock, true);
1252 
1253  if (IsListEmpty(&destdir->fcb->dir_children_index))
1254  me->fileref->dc->index = 2;
1255  else {
1256  dir_child* dc2 = CONTAINING_RECORD(destdir->fcb->dir_children_index.Blink, dir_child, list_entry_index);
1257 
1258  me->fileref->dc->index = max(2, dc2->index + 1);
1259  }
1260 
1263  ExReleaseResourceLite(&destdir->fcb->nonpaged->dir_children_lock);
1264  }
1265 
1266  free_fileref(me->fileref->parent);
1267  me->fileref->parent = destdir;
1268 
1269  ExAcquireResourceExclusiveLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock, true);
1270  InsertTailList(&me->fileref->parent->children, &me->fileref->list_entry);
1271  ExReleaseResourceLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock);
1272 
1273  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);
1274  me->fileref->parent->fcb->inode_item.st_size += me->fileref->dc->utf8.Length * 2;
1275  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);
1276  me->fileref->parent->fcb->inode_item.transid = me->fileref->fcb->Vcb->superblock.generation;
1277  me->fileref->parent->fcb->inode_item.sequence++;
1278  me->fileref->parent->fcb->inode_item.st_ctime = now;
1279  me->fileref->parent->fcb->inode_item.st_mtime = now;
1280  me->fileref->parent->fcb->inode_item_changed = true;
1281  mark_fcb_dirty(me->fileref->parent->fcb);
1282  } else {
1283  if (me->fileref->dc) {
1284  ExAcquireResourceExclusiveLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock, true);
1286 
1287  if (!me->fileref->fcb->ads)
1289 
1290  ExReleaseResourceLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock);
1291 
1292  ExAcquireResourceExclusiveLite(&me->parent->fileref->fcb->nonpaged->dir_children_lock, true);
1293 
1294  if (me->fileref->fcb->ads)
1295  InsertHeadList(&me->parent->fileref->fcb->dir_children_index, &me->fileref->dc->list_entry_index);
1296  else {
1297  if (me->fileref->fcb->inode != SUBVOL_ROOT_INODE)
1298  me->fileref->dc->key.obj_id = me->fileref->fcb->inode;
1299 
1300  if (IsListEmpty(&me->parent->fileref->fcb->dir_children_index))
1301  me->fileref->dc->index = 2;
1302  else {
1303  dir_child* dc2 = CONTAINING_RECORD(me->parent->fileref->fcb->dir_children_index.Blink, dir_child, list_entry_index);
1304 
1305  me->fileref->dc->index = max(2, dc2->index + 1);
1306  }
1307 
1308  InsertTailList(&me->parent->fileref->fcb->dir_children_index, &me->fileref->dc->list_entry_index);
1309  insert_dir_child_into_hash_lists(me->parent->fileref->fcb, me->fileref->dc);
1310  }
1311 
1312  ExReleaseResourceLite(&me->parent->fileref->fcb->nonpaged->dir_children_lock);
1313  }
1314  }
1315 
1316  if (!me->dummyfileref->fcb->ads) {
1318  if (!NT_SUCCESS(Status)) {
1319  ERR("delete_fileref returned %08x\n", Status);
1320  goto end;
1321  }
1322  }
1323 
1324  if (me->fileref->fcb->inode_item.st_nlink > 1) {
1326  if (!hl) {
1327  ERR("out of memory\n");
1329  goto end;
1330  }
1331 
1332  hl->parent = me->fileref->parent->fcb->inode;
1333  hl->index = me->fileref->dc->index;
1334 
1335  hl->utf8.Length = hl->utf8.MaximumLength = me->fileref->dc->utf8.Length;
1337  if (!hl->utf8.Buffer) {
1338  ERR("out of memory\n");
1340  ExFreePool(hl);
1341  goto end;
1342  }
1343 
1345 
1346  hl->name.Length = hl->name.MaximumLength = me->fileref->dc->name.Length;
1348  if (!hl->name.Buffer) {
1349  ERR("out of memory\n");
1351  ExFreePool(hl->utf8.Buffer);
1352  ExFreePool(hl);
1353  goto end;
1354  }
1355 
1357 
1359  }
1360 
1362 
1363  le = le->Flink;
1364  }
1365 
1366  // loop through, and only mark streams as deleted if their parent inodes are also deleted
1367 
1368  le = move_list.Flink;
1369  while (le != &move_list) {
1371 
1372  if (me->dummyfileref->fcb->ads && me->parent->dummyfileref->fcb->deleted) {
1374  if (!NT_SUCCESS(Status)) {
1375  ERR("delete_fileref returned %08x\n", Status);
1376  goto end;
1377  }
1378  }
1379 
1380  le = le->Flink;
1381  }
1382 
1383  destdir->fcb->subvol->root_item.ctransid = destdir->fcb->Vcb->superblock.generation;
1384  destdir->fcb->subvol->root_item.ctime = now;
1385 
1390 
1392 
1393 end:
1394  while (!IsListEmpty(&move_list)) {
1395  le = RemoveHeadList(&move_list);
1397 
1398  if (me->dummyfcb)
1399  free_fcb(me->dummyfcb);
1400 
1401  if (me->dummyfileref)
1403 
1404  free_fileref(me->fileref);
1405 
1406  ExFreePool(me);
1407  }
1408 
1409  destdir->fcb->subvol->fcbs_version++;
1410  fileref->fcb->subvol->fcbs_version++;
1411 
1412  release_fcb_lock(fileref->fcb->Vcb);
1413 
1414  return Status;
1415 }
1416 
1418  bool inserted;
1419  LIST_ENTRY* le;
1420  uint8_t c, d;
1421 
1422  c = dc->hash >> 24;
1423 
1424  inserted = false;
1425 
1426  d = c;
1427  do {
1428  le = fcb->hash_ptrs[d];
1429 
1430  if (d == 0)
1431  break;
1432 
1433  d--;
1434  } while (!le);
1435 
1436  if (!le)
1437  le = fcb->dir_children_hash.Flink;
1438 
1439  while (le != &fcb->dir_children_hash) {
1440  dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_hash);
1441 
1442  if (dc2->hash > dc->hash) {
1443  InsertHeadList(le->Blink, &dc->list_entry_hash);
1444  inserted = true;
1445  break;
1446  }
1447 
1448  le = le->Flink;
1449  }
1450 
1451  if (!inserted)
1452  InsertTailList(&fcb->dir_children_hash, &dc->list_entry_hash);
1453 
1454  if (!fcb->hash_ptrs[c])
1455  fcb->hash_ptrs[c] = &dc->list_entry_hash;
1456  else {
1457  dir_child* dc2 = CONTAINING_RECORD(fcb->hash_ptrs[c], dir_child, list_entry_hash);
1458 
1459  if (dc2->hash > dc->hash)
1460  fcb->hash_ptrs[c] = &dc->list_entry_hash;
1461  }
1462 
1463  c = dc->hash_uc >> 24;
1464 
1465  inserted = false;
1466 
1467  d = c;
1468  do {
1469  le = fcb->hash_ptrs_uc[d];
1470 
1471  if (d == 0)
1472  break;
1473 
1474  d--;
1475  } while (!le);
1476 
1477  if (!le)
1479 
1480  while (le != &fcb->dir_children_hash_uc) {
1481  dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_hash_uc);
1482 
1483  if (dc2->hash_uc > dc->hash_uc) {
1484  InsertHeadList(le->Blink, &dc->list_entry_hash_uc);
1485  inserted = true;
1486  break;
1487  }
1488 
1489  le = le->Flink;
1490  }
1491 
1492  if (!inserted)
1493  InsertTailList(&fcb->dir_children_hash_uc, &dc->list_entry_hash_uc);
1494 
1495  if (!fcb->hash_ptrs_uc[c])
1496  fcb->hash_ptrs_uc[c] = &dc->list_entry_hash_uc;
1497  else {
1498  dir_child* dc2 = CONTAINING_RECORD(fcb->hash_ptrs_uc[c], dir_child, list_entry_hash_uc);
1499 
1500  if (dc2->hash_uc > dc->hash_uc)
1501  fcb->hash_ptrs_uc[c] = &dc->list_entry_hash_uc;
1502  }
1503 }
1504 
1507  NTSTATUS Status;
1508  file_ref* ofr;
1509  ANSI_STRING adsdata;
1510  dir_child* dc;
1511  fcb* dummyfcb;
1512 
1513  if (fileref->fcb->type != BTRFS_TYPE_FILE)
1514  return STATUS_INVALID_PARAMETER;
1515 
1517  WARN("trying to rename stream on readonly file\n");
1518  return STATUS_ACCESS_DENIED;
1519  }
1520 
1521  if (Irp->RequestorMode == UserMode && ccb && !(ccb->access & DELETE)) {
1522  WARN("insufficient permissions\n");
1523  return STATUS_ACCESS_DENIED;
1524  }
1525 
1526  if (!(flags & FILE_RENAME_REPLACE_IF_EXISTS)) // file will always exist
1528 
1529  // FIXME - POSIX overwrites of stream?
1530 
1531  ofr = fileref->parent;
1532 
1533  if (ofr->open_count > 0) {
1534  WARN("trying to overwrite open file\n");
1535  return STATUS_ACCESS_DENIED;
1536  }
1537 
1538  if (ofr->fcb->inode_item.st_size > 0) {
1539  WARN("can only overwrite existing stream if it is zero-length\n");
1540  return STATUS_INVALID_PARAMETER;
1541  }
1542 
1544  if (!dummyfcb) {
1545  ERR("out of memory\n");
1547  }
1548 
1549  // copy parent fcb onto this one
1550 
1551  fileref->fcb->subvol = ofr->fcb->subvol;
1552  fileref->fcb->inode = ofr->fcb->inode;
1553  fileref->fcb->hash = ofr->fcb->hash;
1554  fileref->fcb->type = ofr->fcb->type;
1555  fileref->fcb->inode_item = ofr->fcb->inode_item;
1556 
1557  fileref->fcb->sd = ofr->fcb->sd;
1558  ofr->fcb->sd = NULL;
1559 
1560  fileref->fcb->deleted = ofr->fcb->deleted;
1561  fileref->fcb->atts = ofr->fcb->atts;
1562 
1564  ofr->fcb->reparse_xattr.Buffer = NULL;
1566 
1567  fileref->fcb->ea_xattr = ofr->fcb->ea_xattr;
1568  ofr->fcb->ea_xattr.Buffer = NULL;
1569  ofr->fcb->ea_xattr.Length = ofr->fcb->ea_xattr.MaximumLength = 0;
1570 
1571  fileref->fcb->ealen = ofr->fcb->ealen;
1572 
1573  while (!IsListEmpty(&ofr->fcb->hardlinks)) {
1575  }
1576 
1577  fileref->fcb->inode_item_changed = true;
1579 
1580  while (!IsListEmpty(&ofr->fcb->xattrs)) {
1582  }
1583 
1587 
1588  while (!IsListEmpty(&ofr->fcb->dir_children_index)) {
1590  }
1591 
1592  while (!IsListEmpty(&ofr->fcb->dir_children_hash)) {
1594  }
1595 
1596  while (!IsListEmpty(&ofr->fcb->dir_children_hash_uc)) {
1598  }
1599 
1600  fileref->fcb->hash_ptrs = ofr->fcb->hash_ptrs;
1602 
1603  ofr->fcb->hash_ptrs = NULL;
1604  ofr->fcb->hash_ptrs_uc = NULL;
1605 
1606  fileref->fcb->sd_dirty = ofr->fcb->sd_dirty;
1607  fileref->fcb->sd_deleted = ofr->fcb->sd_deleted;
1610  fileref->fcb->extents_changed = true;
1612  fileref->fcb->ea_changed = ofr->fcb->ea_changed;
1615  fileref->fcb->created = ofr->fcb->created;
1616  fileref->fcb->ads = false;
1617 
1618  if (fileref->fcb->adsxattr.Buffer) {
1622  }
1623 
1624  adsdata = fileref->fcb->adsdata;
1625 
1628 
1630 
1631  if (fileref->fcb->subvol->fcbs_ptrs[fileref->fcb->hash >> 24] == &ofr->fcb->list_entry)
1632  fileref->fcb->subvol->fcbs_ptrs[fileref->fcb->hash >> 24] = &fileref->fcb->list_entry;
1633 
1634  RemoveEntryList(&ofr->fcb->list_entry);
1635  ofr->fcb->list_entry.Flink = ofr->fcb->list_entry.Blink = NULL;
1636 
1638 
1639  // mark old parent fcb so it gets ignored by flush_fcb
1640  ofr->fcb->created = true;
1641  ofr->fcb->deleted = true;
1642 
1643  mark_fcb_dirty(ofr->fcb);
1644 
1645  // copy parent fileref onto this one
1646 
1647  fileref->oldutf8 = ofr->oldutf8;
1648  ofr->oldutf8.Buffer = NULL;
1649  ofr->oldutf8.Length = ofr->oldutf8.MaximumLength = 0;
1650 
1651  fileref->oldindex = ofr->oldindex;
1654  fileref->deleted = ofr->deleted;
1655  fileref->created = ofr->created;
1656 
1657  fileref->parent = ofr->parent;
1658 
1661  RemoveEntryList(&ofr->list_entry);
1662  ofr->list_entry.Flink = ofr->list_entry.Blink = NULL;
1663 
1664  while (!IsListEmpty(&ofr->children)) {
1666 
1667  free_fileref(fr->parent);
1668 
1669  fr->parent = fileref;
1671 
1673  }
1674 
1675  dc = fileref->dc;
1676 
1677  fileref->dc = ofr->dc;
1678  fileref->dc->fileref = fileref;
1679 
1681 
1682  // mark old parent fileref so it gets ignored by flush_fileref
1683  ofr->created = true;
1684  ofr->deleted = true;
1685 
1686  // write file data
1687 
1688  fileref->fcb->inode_item.st_size = adsdata.Length;
1689 
1690  if (adsdata.Length > 0) {
1691  bool make_inline = adsdata.Length <= Vcb->options.max_inline;
1692 
1693  if (make_inline) {
1695  if (!ed) {
1696  ERR("out of memory\n");
1697  ExFreePool(adsdata.Buffer);
1698  reap_fcb(dummyfcb);
1700  }
1701 
1702  ed->generation = Vcb->superblock.generation;
1703  ed->decoded_size = adsdata.Length;
1708 
1709  RtlCopyMemory(ed->data, adsdata.Buffer, adsdata.Length);
1710 
1711  ExFreePool(adsdata.Buffer);
1712 
1713  Status = add_extent_to_fcb(fileref->fcb, 0, ed, (uint16_t)(offsetof(EXTENT_DATA, data[0]) + adsdata.Length), false, NULL, rollback);
1714  if (!NT_SUCCESS(Status)) {
1715  ERR("add_extent_to_fcb returned %08x\n", Status);
1716  ExFreePool(ed);
1717  reap_fcb(dummyfcb);
1718  return Status;
1719  }
1720 
1721  ExFreePool(ed);
1722  } else if (adsdata.Length % Vcb->superblock.sector_size) {
1723  char* newbuf = ExAllocatePoolWithTag(PagedPool, (uint16_t)sector_align(adsdata.Length, Vcb->superblock.sector_size), ALLOC_TAG);
1724  if (!newbuf) {
1725  ERR("out of memory\n");
1726  ExFreePool(adsdata.Buffer);
1727  reap_fcb(dummyfcb);
1729  }
1730 
1731  RtlCopyMemory(newbuf, adsdata.Buffer, adsdata.Length);
1732  RtlZeroMemory(newbuf + adsdata.Length, (uint16_t)(sector_align(adsdata.Length, Vcb->superblock.sector_size) - adsdata.Length));
1733 
1734  ExFreePool(adsdata.Buffer);
1735 
1736  adsdata.Buffer = newbuf;
1737  adsdata.Length = adsdata.MaximumLength = (uint16_t)sector_align(adsdata.Length, Vcb->superblock.sector_size);
1738  }
1739 
1740  if (!make_inline) {
1741  Status = do_write_file(fileref->fcb, 0, adsdata.Length, adsdata.Buffer, Irp, false, 0, rollback);
1742  if (!NT_SUCCESS(Status)) {
1743  ERR("do_write_file returned %08x\n", Status);
1744  ExFreePool(adsdata.Buffer);
1745  reap_fcb(dummyfcb);
1746  return Status;
1747  }
1748 
1749  ExFreePool(adsdata.Buffer);
1750  }
1751 
1752  fileref->fcb->inode_item.st_blocks = adsdata.Length;
1753  fileref->fcb->inode_item_changed = true;
1754  }
1755 
1756  RemoveEntryList(&dc->list_entry_index);
1757 
1758  if (dc->utf8.Buffer)
1759  ExFreePool(dc->utf8.Buffer);
1760 
1761  if (dc->name.Buffer)
1762  ExFreePool(dc->name.Buffer);
1763 
1764  if (dc->name_uc.Buffer)
1765  ExFreePool(dc->name_uc.Buffer);
1766 
1767  ExFreePool(dc);
1768 
1769  // FIXME - csums?
1770 
1771  // add dummy deleted xattr with old name
1772 
1773  dummyfcb->Vcb = Vcb;
1778  dummyfcb->ads = true;
1779  dummyfcb->deleted = true;
1780 
1781  // FIXME - dummyfileref as well?
1782 
1784 
1785  free_fcb(dummyfcb);
1786 
1787  return STATUS_SUCCESS;
1788 }
1789 
1792  NTSTATUS Status;
1794  file_ref* sf = NULL;
1795  uint16_t newmaxlen;
1796  ULONG utf8len;
1797  ANSI_STRING utf8;
1798  UNICODE_STRING utf16, utf16uc;
1799  ANSI_STRING adsxattr;
1800  uint32_t crc32;
1801  fcb* dummyfcb;
1802 
1803  static const WCHAR datasuf[] = L":$DATA";
1804  static const char xapref[] = "user.";
1805 
1806  if (!fileref) {
1807  ERR("fileref not set\n");
1808  return STATUS_INVALID_PARAMETER;
1809  }
1810 
1811  if (!fileref->parent) {
1812  ERR("fileref->parent not set\n");
1813  return STATUS_INVALID_PARAMETER;
1814  }
1815 
1816  if (fri->FileNameLength < sizeof(WCHAR)) {
1817  WARN("filename too short\n");
1819  }
1820 
1821  if (fri->FileName[0] != ':') {
1822  WARN("destination filename must begin with a colon\n");
1823  return STATUS_INVALID_PARAMETER;
1824  }
1825 
1826  if (Irp->RequestorMode == UserMode && ccb && !(ccb->access & DELETE)) {
1827  WARN("insufficient permissions\n");
1828  return STATUS_ACCESS_DENIED;
1829  }
1830 
1831  fn.Buffer = &fri->FileName[1];
1832  fn.Length = fn.MaximumLength = (USHORT)(fri->FileNameLength - sizeof(WCHAR));
1833 
1834  // remove :$DATA suffix
1835  if (fn.Length >= sizeof(datasuf) - sizeof(WCHAR) &&
1836  RtlCompareMemory(&fn.Buffer[(fn.Length - sizeof(datasuf) + sizeof(WCHAR))/sizeof(WCHAR)], datasuf, sizeof(datasuf) - sizeof(WCHAR)) == sizeof(datasuf) - sizeof(WCHAR))
1837  fn.Length -= sizeof(datasuf) - sizeof(WCHAR);
1838 
1839  if (fn.Length == 0)
1841 
1842  if (!is_file_name_valid(&fn, false, true)) {
1843  WARN("invalid stream name %.*S\n", fn.Length / sizeof(WCHAR), fn.Buffer);
1845  }
1846 
1848  WARN("trying to rename stream on readonly file\n");
1849  return STATUS_ACCESS_DENIED;
1850  }
1851 
1852  Status = open_fileref_child(Vcb, fileref->parent, &fn, fileref->parent->fcb->case_sensitive, true, true, PagedPool, &sf, Irp);
1854  if (Status == STATUS_SUCCESS) {
1855  if (fileref == sf || sf->deleted) {
1856  free_fileref(sf);
1857  sf = NULL;
1858  } else {
1861  goto end;
1862  }
1863 
1864  // FIXME - POSIX overwrites of stream?
1865 
1866  if (sf->open_count > 0) {
1867  WARN("trying to overwrite open file\n");
1869  goto end;
1870  }
1871 
1872  if (sf->fcb->adsdata.Length > 0) {
1873  WARN("can only overwrite existing stream if it is zero-length\n");
1875  goto end;
1876  }
1877 
1878  Status = delete_fileref(sf, NULL, false, Irp, rollback);
1879  if (!NT_SUCCESS(Status)) {
1880  ERR("delete_fileref returned %08x\n", Status);
1881  goto end;
1882  }
1883  }
1884  } else {
1885  ERR("open_fileref_child returned %08x\n", Status);
1886  goto end;
1887  }
1888  }
1889 
1890  Status = utf16_to_utf8(NULL, 0, &utf8len, fn.Buffer, fn.Length);
1891  if (!NT_SUCCESS(Status))
1892  goto end;
1893 
1894  utf8.MaximumLength = utf8.Length = (uint16_t)utf8len;
1896  if (!utf8.Buffer) {
1897  ERR("out of memory\n");
1899  goto end;
1900  }
1901 
1902  Status = utf16_to_utf8(utf8.Buffer, utf8len, &utf8len, fn.Buffer, fn.Length);
1903  if (!NT_SUCCESS(Status)) {
1904  ExFreePool(utf8.Buffer);
1905  goto end;
1906  }
1907 
1908  adsxattr.Length = adsxattr.MaximumLength = sizeof(xapref) - 1 + utf8.Length;
1910  if (!adsxattr.Buffer) {
1911  ERR("out of memory\n");
1913  ExFreePool(utf8.Buffer);
1914  goto end;
1915  }
1916 
1917  RtlCopyMemory(adsxattr.Buffer, xapref, sizeof(xapref) - 1);
1918  RtlCopyMemory(&adsxattr.Buffer[sizeof(xapref) - 1], utf8.Buffer, utf8.Length);
1919 
1920  // don't allow if it's one of our reserved names
1921 
1922  if ((adsxattr.Length == sizeof(EA_DOSATTRIB) - sizeof(WCHAR) && RtlCompareMemory(adsxattr.Buffer, EA_DOSATTRIB, adsxattr.Length) == adsxattr.Length) ||
1923  (adsxattr.Length == sizeof(EA_EA) - sizeof(WCHAR) && RtlCompareMemory(adsxattr.Buffer, EA_EA, adsxattr.Length) == adsxattr.Length) ||
1924  (adsxattr.Length == sizeof(EA_REPARSE) - sizeof(WCHAR) && RtlCompareMemory(adsxattr.Buffer, EA_REPARSE, adsxattr.Length) == adsxattr.Length) ||
1925  (adsxattr.Length == sizeof(EA_CASE_SENSITIVE) - sizeof(WCHAR) && RtlCompareMemory(adsxattr.Buffer, EA_CASE_SENSITIVE, adsxattr.Length) == adsxattr.Length)) {
1927  ExFreePool(utf8.Buffer);
1928  ExFreePool(adsxattr.Buffer);
1929  goto end;
1930  }
1931 
1932  utf16.Length = utf16.MaximumLength = fn.Length;
1934  if (!utf16.Buffer) {
1935  ERR("out of memory\n");
1937  ExFreePool(utf8.Buffer);
1938  ExFreePool(adsxattr.Buffer);
1939  goto end;
1940  }
1941 
1942  RtlCopyMemory(utf16.Buffer, fn.Buffer, fn.Length);
1943 
1944  newmaxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) -
1945  offsetof(DIR_ITEM, name[0]);
1946 
1947  if (newmaxlen < adsxattr.Length) {
1948  WARN("cannot rename as data too long\n");
1950  ExFreePool(utf8.Buffer);
1951  ExFreePool(utf16.Buffer);
1952  ExFreePool(adsxattr.Buffer);
1953  goto end;
1954  }
1955 
1956  newmaxlen -= adsxattr.Length;
1957 
1958  if (newmaxlen < fileref->fcb->adsdata.Length) {
1959  WARN("cannot rename as data too long\n");
1961  ExFreePool(utf8.Buffer);
1962  ExFreePool(utf16.Buffer);
1963  ExFreePool(adsxattr.Buffer);
1964  goto end;
1965  }
1966 
1967  Status = RtlUpcaseUnicodeString(&utf16uc, &fn, true);
1968  if (!NT_SUCCESS(Status)) {
1969  ERR("RtlUpcaseUnicodeString returned %08x\n");
1970  ExFreePool(utf8.Buffer);
1971  ExFreePool(utf16.Buffer);
1972  ExFreePool(adsxattr.Buffer);
1973  goto end;
1974  }
1975 
1976  // add dummy deleted xattr with old name
1977 
1979  if (!dummyfcb) {
1980  ERR("out of memory\n");
1982  ExFreePool(utf8.Buffer);
1983  ExFreePool(utf16.Buffer);
1984  ExFreePool(utf16uc.Buffer);
1985  ExFreePool(adsxattr.Buffer);
1986  goto end;
1987  }
1988 
1989  dummyfcb->Vcb = Vcb;
1994  dummyfcb->ads = true;
1995  dummyfcb->deleted = true;
1996 
1998 
1999  free_fcb(dummyfcb);
2000 
2001  // change fcb values
2002 
2003  fileref->dc->utf8 = utf8;
2004  fileref->dc->name = utf16;
2005  fileref->dc->name_uc = utf16uc;
2006 
2007  crc32 = calc_crc32c(0xfffffffe, (uint8_t*)adsxattr.Buffer, adsxattr.Length);
2008 
2009  fileref->fcb->adsxattr = adsxattr;
2010  fileref->fcb->adshash = crc32;
2011  fileref->fcb->adsmaxlen = newmaxlen;
2012 
2013  fileref->fcb->created = true;
2014 
2016 
2018 
2019 end:
2020  if (sf)
2021  free_fileref(sf);
2022 
2023  return Status;
2024 }
2025 
2028  NTSTATUS Status;
2030  file_ref* sf = NULL;
2031  uint16_t newmaxlen;
2032  ULONG utf8len;
2033  ANSI_STRING utf8;
2034  UNICODE_STRING utf16, utf16uc;
2035  ANSI_STRING adsxattr, adsdata;
2036  uint32_t crc32;
2037  fcb* dummyfcb;
2039  dir_child* dc;
2040  LIST_ENTRY* le;
2041 
2042  static const WCHAR datasuf[] = L":$DATA";
2043  static const char xapref[] = "user.";
2044 
2045  if (!fileref) {
2046  ERR("fileref not set\n");
2047  return STATUS_INVALID_PARAMETER;
2048  }
2049 
2050  if (fri->FileNameLength < sizeof(WCHAR)) {
2051  WARN("filename too short\n");
2053  }
2054 
2055  if (fri->FileName[0] != ':') {
2056  WARN("destination filename must begin with a colon\n");
2057  return STATUS_INVALID_PARAMETER;
2058  }
2059 
2060  if (Irp->RequestorMode == UserMode && ccb && !(ccb->access & DELETE)) {
2061  WARN("insufficient permissions\n");
2062  return STATUS_ACCESS_DENIED;
2063  }
2064 
2065  if (fileref->fcb->type != BTRFS_TYPE_FILE)
2066  return STATUS_INVALID_PARAMETER;
2067 
2068  fn.Buffer = &fri->FileName[1];
2069  fn.Length = fn.MaximumLength = (USHORT)(fri->FileNameLength - sizeof(WCHAR));
2070 
2071  // remove :$DATA suffix
2072  if (fn.Length >= sizeof(datasuf) - sizeof(WCHAR) &&
2073  RtlCompareMemory(&fn.Buffer[(fn.Length - sizeof(datasuf) + sizeof(WCHAR))/sizeof(WCHAR)], datasuf, sizeof(datasuf) - sizeof(WCHAR)) == sizeof(datasuf) - sizeof(WCHAR))
2074  fn.Length -= sizeof(datasuf) - sizeof(WCHAR);
2075 
2076  if (fn.Length == 0) {
2077  WARN("not allowing overwriting file with itself\n");
2078  return STATUS_INVALID_PARAMETER;
2079  }
2080 
2081  if (!is_file_name_valid(&fn, false, true)) {
2082  WARN("invalid stream name %.*S\n", fn.Length / sizeof(WCHAR), fn.Buffer);
2084  }
2085 
2087  WARN("trying to rename stream on readonly file\n");
2088  return STATUS_ACCESS_DENIED;
2089  }
2090 
2093  if (Status == STATUS_SUCCESS) {
2094  if (fileref == sf || sf->deleted) {
2095  free_fileref(sf);
2096  sf = NULL;
2097  } else {
2100  goto end;
2101  }
2102 
2103  // FIXME - POSIX overwrites of stream?
2104 
2105  if (sf->open_count > 0) {
2106  WARN("trying to overwrite open file\n");
2108  goto end;
2109  }
2110 
2111  if (sf->fcb->adsdata.Length > 0) {
2112  WARN("can only overwrite existing stream if it is zero-length\n");
2114  goto end;
2115  }
2116 
2117  Status = delete_fileref(sf, NULL, false, Irp, rollback);
2118  if (!NT_SUCCESS(Status)) {
2119  ERR("delete_fileref returned %08x\n", Status);
2120  goto end;
2121  }
2122  }
2123  } else {
2124  ERR("open_fileref_child returned %08x\n", Status);
2125  goto end;
2126  }
2127  }
2128 
2129  Status = utf16_to_utf8(NULL, 0, &utf8len, fn.Buffer, fn.Length);
2130  if (!NT_SUCCESS(Status))
2131  goto end;
2132 
2133  utf8.MaximumLength = utf8.Length = (uint16_t)utf8len;
2135  if (!utf8.Buffer) {
2136  ERR("out of memory\n");
2138  goto end;
2139  }
2140 
2141  Status = utf16_to_utf8(utf8.Buffer, utf8len, &utf8len, fn.Buffer, fn.Length);
2142  if (!NT_SUCCESS(Status)) {
2143  ExFreePool(utf8.Buffer);
2144  goto end;
2145  }
2146 
2147  adsxattr.Length = adsxattr.MaximumLength = sizeof(xapref) - 1 + utf8.Length;
2149  if (!adsxattr.Buffer) {
2150  ERR("out of memory\n");
2152  ExFreePool(utf8.Buffer);
2153  goto end;
2154  }
2155 
2156  RtlCopyMemory(adsxattr.Buffer, xapref, sizeof(xapref) - 1);
2157  RtlCopyMemory(&adsxattr.Buffer[sizeof(xapref) - 1], utf8.Buffer, utf8.Length);
2158 
2159  // don't allow if it's one of our reserved names
2160 
2161  if ((adsxattr.Length == sizeof(EA_DOSATTRIB) - sizeof(WCHAR) && RtlCompareMemory(adsxattr.Buffer, EA_DOSATTRIB, adsxattr.Length) == adsxattr.Length) ||
2162  (adsxattr.Length == sizeof(EA_EA) - sizeof(WCHAR) && RtlCompareMemory(adsxattr.Buffer, EA_EA, adsxattr.Length) == adsxattr.Length) ||
2163  (adsxattr.Length == sizeof(EA_REPARSE) - sizeof(WCHAR) && RtlCompareMemory(adsxattr.Buffer, EA_REPARSE, adsxattr.Length) == adsxattr.Length) ||
2164  (adsxattr.Length == sizeof(EA_CASE_SENSITIVE) - sizeof(WCHAR) && RtlCompareMemory(adsxattr.Buffer, EA_CASE_SENSITIVE, adsxattr.Length) == adsxattr.Length)) {
2166  ExFreePool(utf8.Buffer);
2167  ExFreePool(adsxattr.Buffer);
2168  goto end;
2169  }
2170 
2171  utf16.Length = utf16.MaximumLength = fn.Length;
2173  if (!utf16.Buffer) {
2174  ERR("out of memory\n");
2176  ExFreePool(utf8.Buffer);
2177  ExFreePool(adsxattr.Buffer);
2178  goto end;
2179  }
2180 
2181  RtlCopyMemory(utf16.Buffer, fn.Buffer, fn.Length);
2182 
2183  newmaxlen = Vcb->superblock.node_size - sizeof(tree_header) - sizeof(leaf_node) -
2184  offsetof(DIR_ITEM, name[0]);
2185 
2186  if (newmaxlen < adsxattr.Length) {
2187  WARN("cannot rename as data too long\n");
2189  ExFreePool(utf8.Buffer);
2190  ExFreePool(utf16.Buffer);
2191  ExFreePool(adsxattr.Buffer);
2192  goto end;
2193  }
2194 
2195  newmaxlen -= adsxattr.Length;
2196 
2197  if (newmaxlen < fileref->fcb->inode_item.st_size) {
2198  WARN("cannot rename as data too long\n");
2200  ExFreePool(utf8.Buffer);
2201  ExFreePool(utf16.Buffer);
2202  ExFreePool(adsxattr.Buffer);
2203  goto end;
2204  }
2205 
2206  Status = RtlUpcaseUnicodeString(&utf16uc, &fn, true);
2207  if (!NT_SUCCESS(Status)) {
2208  ERR("RtlUpcaseUnicodeString returned %08x\n");
2209  ExFreePool(utf8.Buffer);
2210  ExFreePool(utf16.Buffer);
2211  ExFreePool(adsxattr.Buffer);
2212  goto end;
2213  }
2214 
2215  // read existing file data
2216 
2217  if (fileref->fcb->inode_item.st_size > 0) {
2218  ULONG bytes_read;
2219 
2220  adsdata.Length = adsdata.MaximumLength = (uint16_t)fileref->fcb->inode_item.st_size;
2221 
2223  if (!adsdata.Buffer) {
2224  ERR("out of memory\n");
2226  ExFreePool(utf8.Buffer);
2227  ExFreePool(utf16.Buffer);
2228  ExFreePool(utf16uc.Buffer);
2229  ExFreePool(adsxattr.Buffer);
2230  goto end;
2231  }
2232 
2233  Status = read_file(fileref->fcb, (uint8_t*)adsdata.Buffer, 0, adsdata.Length, &bytes_read, Irp);
2234  if (!NT_SUCCESS(Status)) {
2235  ERR("out of memory\n");
2237  ExFreePool(utf8.Buffer);
2238  ExFreePool(utf16.Buffer);
2239  ExFreePool(utf16uc.Buffer);
2240  ExFreePool(adsxattr.Buffer);
2241  ExFreePool(adsdata.Buffer);
2242  goto end;
2243  }
2244 
2245  if (bytes_read < fileref->fcb->inode_item.st_size) {
2246  ERR("short read\n");
2248  ExFreePool(utf8.Buffer);
2249  ExFreePool(utf16.Buffer);
2250  ExFreePool(utf16uc.Buffer);
2251  ExFreePool(adsxattr.Buffer);
2252  ExFreePool(adsdata.Buffer);
2253  goto end;
2254  }
2255  } else
2256  adsdata.Buffer = NULL;
2257 
2259  if (!dc) {
2260  ERR("short read\n");
2262  ExFreePool(utf8.Buffer);
2263  ExFreePool(utf16.Buffer);
2264  ExFreePool(utf16uc.Buffer);
2265  ExFreePool(adsxattr.Buffer);
2266 
2267  if (adsdata.Buffer)
2268  ExFreePool(adsdata.Buffer);
2269 
2270  goto end;
2271  }
2272 
2273  // add dummy deleted fcb with old name
2274 
2276  if (!NT_SUCCESS(Status)) {
2277  ERR("duplicate_fcb returned %08x\n", Status);
2278  ExFreePool(utf8.Buffer);
2279  ExFreePool(utf16.Buffer);
2280  ExFreePool(utf16uc.Buffer);
2281  ExFreePool(adsxattr.Buffer);
2282 
2283  if (adsdata.Buffer)
2284  ExFreePool(adsdata.Buffer);
2285 
2286  ExFreePool(dc);
2287 
2288  goto end;
2289  }
2290 
2292  if (!dummyfileref) {
2293  ERR("out of memory\n");
2295  ExFreePool(utf8.Buffer);
2296  ExFreePool(utf16.Buffer);
2297  ExFreePool(utf16uc.Buffer);
2298  ExFreePool(adsxattr.Buffer);
2299 
2300  if (adsdata.Buffer)
2301  ExFreePool(adsdata.Buffer);
2302 
2303  ExFreePool(dc);
2304 
2305  reap_fcb(dummyfcb);
2306 
2307  goto end;
2308  }
2309 
2311 
2312  dummyfcb->Vcb = Vcb;
2315  dummyfcb->hash = fileref->fcb->hash;
2316 
2317  if (fileref->fcb->inode_item.st_size > 0) {
2318  Status = excise_extents(Vcb, dummyfcb, 0, sector_align(fileref->fcb->inode_item.st_size, Vcb->superblock.sector_size),
2319  Irp, rollback);
2320  if (!NT_SUCCESS(Status)) {
2321  ERR("excise_extents returned %08x\n", Status);
2322  ExFreePool(utf8.Buffer);
2323  ExFreePool(utf16.Buffer);
2324  ExFreePool(utf16uc.Buffer);
2325  ExFreePool(adsxattr.Buffer);
2326  ExFreePool(adsdata.Buffer);
2327  ExFreePool(dc);
2328 
2330  reap_fcb(dummyfcb);
2331 
2332  goto end;
2333  }
2334 
2336  dummyfcb->Header.AllocationSize.QuadPart = 0;
2337  dummyfcb->Header.FileSize.QuadPart = 0;
2338  dummyfcb->Header.ValidDataLength.QuadPart = 0;
2339  }
2340 
2344 
2345  le = fileref->fcb->extents.Flink;
2346  while (le != &fileref->fcb->extents) {
2348 
2349  ext->ignore = true;
2350 
2351  le = le->Flink;
2352  }
2353 
2354  while (!IsListEmpty(&fileref->fcb->dir_children_index)) {
2356  }
2357 
2358  while (!IsListEmpty(&fileref->fcb->dir_children_hash)) {
2360  }
2361 
2364  }
2365 
2366  InsertTailList(&Vcb->all_fcbs, &dummyfcb->list_entry_all);
2367 
2369 
2370  if (fileref->fcb->subvol->fcbs_ptrs[dummyfcb->hash >> 24] == &fileref->fcb->list_entry)
2371  fileref->fcb->subvol->fcbs_ptrs[dummyfcb->hash >> 24] = &dummyfcb->list_entry;
2372 
2375 
2377 
2378  // create dummy fileref
2379 
2387 
2388  while (!IsListEmpty(&fileref->children)) {
2390 
2391  free_fileref(fr->parent);
2392 
2393  fr->parent = dummyfileref;
2395 
2397  }
2398 
2400 
2403 
2404  dummyfileref->dc = fileref->dc;
2406 
2408 
2410 
2411  // change fcb values
2412 
2413  fileref->fcb->hash_ptrs = NULL;
2415 
2416  fileref->fcb->ads = true;
2417 
2420 
2421  RtlZeroMemory(dc, sizeof(dir_child));
2422 
2423  dc->utf8 = utf8;
2424  dc->name = utf16;
2425  dc->hash = calc_crc32c(0xffffffff, (uint8_t*)dc->name.Buffer, dc->name.Length);
2426  dc->name_uc = utf16uc;
2427  dc->hash_uc = calc_crc32c(0xffffffff, (uint8_t*)dc->name_uc.Buffer, dc->name_uc.Length);
2428  dc->fileref = fileref;
2429  InsertTailList(&dummyfcb->dir_children_index, &dc->list_entry_index);
2430 
2431  fileref->dc = dc;
2433 
2434  crc32 = calc_crc32c(0xfffffffe, (uint8_t*)adsxattr.Buffer, adsxattr.Length);
2435 
2436  fileref->fcb->adsxattr = adsxattr;
2437  fileref->fcb->adshash = crc32;
2438  fileref->fcb->adsmaxlen = newmaxlen;
2439  fileref->fcb->adsdata = adsdata;
2440 
2441  fileref->fcb->created = true;
2442 
2444 
2446 
2447 end:
2448  if (sf)
2449  free_fileref(sf);
2450 
2451  return Status;
2452 }
2453 
2455  FILE_RENAME_INFORMATION_EX* fri = Irp->AssociatedIrp.SystemBuffer;
2456  fcb* fcb = FileObject->FsContext;
2457  ccb* ccb = FileObject->FsContext2;
2458  file_ref *fileref = ccb ? ccb->fileref : NULL, *oldfileref = NULL, *related = NULL, *fr2 = NULL;
2459  WCHAR* fn;
2460  ULONG fnlen, utf8len, origutf8len;
2461  UNICODE_STRING fnus;
2462  ANSI_STRING utf8;
2463  NTSTATUS Status;
2465  BTRFS_TIME now;
2466  LIST_ENTRY rollback, *le;
2467  hardlink* hl;
2468  SECURITY_SUBJECT_CONTEXT subjcont;
2470  ULONG flags;
2471 #ifdef __REACTOS__
2472  unsigned int i;
2473 #endif
2474 
2476 
2477  if (ex)
2478  flags = fri->Flags;
2479  else
2481 
2482  TRACE("tfo = %p\n", tfo);
2483  TRACE("Flags = %x\n", flags);
2484  TRACE("RootDirectory = %p\n", fri->RootDirectory);
2485  TRACE("FileName = %.*S\n", fri->FileNameLength / sizeof(WCHAR), fri->FileName);
2486 
2487  fn = fri->FileName;
2488  fnlen = fri->FileNameLength / sizeof(WCHAR);
2489 
2490  if (!tfo) {
2491  if (!fileref || !fileref->parent) {
2492  ERR("no fileref set and no directory given\n");
2493  return STATUS_INVALID_PARAMETER;
2494  }
2495  } else {
2496  LONG i;
2497 
2498  while (fnlen > 0 && (fri->FileName[fnlen - 1] == '/' || fri->FileName[fnlen - 1] == '\\'))
2499  fnlen--;
2500 
2501  if (fnlen == 0)
2502  return STATUS_INVALID_PARAMETER;
2503 
2504  for (i = fnlen - 1; i >= 0; i--) {
2505  if (fri->FileName[i] == '\\' || fri->FileName[i] == '/') {
2506  fn = &fri->FileName[i+1];
2507  fnlen = (fri->FileNameLength / sizeof(WCHAR)) - i - 1;
2508  break;
2509  }
2510  }
2511  }
2512 
2513  ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
2514  ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, true);
2515  ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
2516 
2517  if (fcb->inode == SUBVOL_ROOT_INODE && fcb->subvol->id == BTRFS_ROOT_FSTREE) {
2518  WARN("not allowing \\$Root to be renamed\n");
2520  goto end;
2521  }
2522 
2523  if (fcb->ads) {
2524  if (FileObject->SectionObjectPointer && FileObject->SectionObjectPointer->DataSectionObject) {
2526 
2527  CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, &iosb);
2528  if (!NT_SUCCESS(iosb.Status)) {
2529  ERR("CcFlushCache returned %08x\n", iosb.Status);
2530  Status = iosb.Status;
2531  goto end;
2532  }
2533  }
2534 
2536  goto end;
2537  } else if (fnlen >= 1 && fn[0] == ':') {
2538  if (FileObject->SectionObjectPointer && FileObject->SectionObjectPointer->DataSectionObject) {
2540 
2541  CcFlushCache(FileObject->SectionObjectPointer, NULL, 0, &iosb);
2542  if (!NT_SUCCESS(iosb.Status)) {
2543  ERR("CcFlushCache returned %08x\n", iosb.Status);
2544  Status = iosb.Status;
2545  goto end;
2546  }
2547  }
2548 
2550  goto end;
2551  }
2552 
2553  fnus.Buffer = fn;
2554  fnus.Length = fnus.MaximumLength = (uint16_t)(fnlen * sizeof(WCHAR));
2555 
2556  TRACE("fnus = %.*S\n", fnus.Length / sizeof(WCHAR), fnus.Buffer);
2557 
2558 #ifndef __REACTOS__
2559  for (unsigned int i = 0 ; i < fnus.Length / sizeof(WCHAR); i++) {
2560 #else
2561  for (i = 0 ; i < fnus.Length / sizeof(WCHAR); i++) {
2562 #endif
2563  if (fnus.Buffer[i] == ':') {
2564  TRACE("colon in filename\n");
2566  goto end;
2567  }
2568  }
2569 
2570  origutf8len = fileref->dc->utf8.Length;
2571 
2572  Status = utf16_to_utf8(NULL, 0, &utf8len, fn, (ULONG)fnlen * sizeof(WCHAR));
2573  if (!NT_SUCCESS(Status))
2574  goto end;
2575 
2576  utf8.MaximumLength = utf8.Length = (uint16_t)utf8len;
2578  if (!utf8.Buffer) {
2579  ERR("out of memory\n");
2581  goto end;
2582  }
2583 
2584  Status = utf16_to_utf8(utf8.Buffer, utf8len, &utf8len, fn, (ULONG)fnlen * sizeof(WCHAR));
2585  if (!NT_SUCCESS(Status))
2586  goto end;
2587 
2588  if (tfo && tfo->FsContext2) {
2589  struct _ccb* relatedccb = tfo->FsContext2;
2590 
2591  related = relatedccb->fileref;
2592  increase_fileref_refcount(related);
2593  } else if (fnus.Length >= sizeof(WCHAR) && fnus.Buffer[0] != '\\') {
2594  related = fileref->parent;
2595  increase_fileref_refcount(related);
2596  }
2597 
2598  Status = open_fileref(Vcb, &oldfileref, &fnus, related, false, NULL, NULL, PagedPool, ccb->case_sensitive, Irp);
2599 
2600  if (NT_SUCCESS(Status)) {
2601  TRACE("destination file already exists\n");
2602 
2603  if (fileref != oldfileref && !oldfileref->deleted) {
2606  goto end;
2607  } else if (fileref == oldfileref) {
2609  goto end;
2610  } else if (!(flags & FILE_RENAME_POSIX_SEMANTICS) && (oldfileref->open_count > 0 || has_open_children(oldfileref)) && !oldfileref->deleted) {
2611  WARN("trying to overwrite open file\n");
2613  goto end;
2614  } else if (!(flags & FILE_RENAME_IGNORE_READONLY_ATTRIBUTE) && oldfileref->fcb->atts & FILE_ATTRIBUTE_READONLY) {
2615  WARN("trying to overwrite readonly file\n");
2617  goto end;
2618  } else if (oldfileref->fcb->type == BTRFS_TYPE_DIRECTORY) {
2619  WARN("trying to overwrite directory\n");
2621  goto end;
2622  }
2623  }
2624 
2625  if (fileref == oldfileref || oldfileref->deleted) {
2626  free_fileref(oldfileref);
2627  oldfileref = NULL;
2628  }
2629  }
2630 
2631  if (!related) {
2632  Status = open_fileref(Vcb, &related, &fnus, NULL, true, NULL, NULL, PagedPool, ccb->case_sensitive, Irp);
2633 
2634  if (!NT_SUCCESS(Status)) {
2635  ERR("open_fileref returned %08x\n", Status);
2636  goto end;
2637  }
2638  }
2639 
2640  if (related->fcb == Vcb->dummy_fcb) {
2642  goto end;
2643  }
2644 
2645  SeCaptureSubjectContext(&subjcont);
2646 
2647  if (!SeAccessCheck(related->fcb->sd, &subjcont, false, fcb->type == BTRFS_TYPE_DIRECTORY ? FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE, 0, NULL,
2648  IoGetFileObjectGenericMapping(), Irp->RequestorMode, &access, &Status)) {
2649  SeReleaseSubjectContext(&subjcont);
2650  TRACE("SeAccessCheck failed, returning %08x\n", Status);
2651  goto end;
2652  }
2653 
2654  SeReleaseSubjectContext(&subjcont);
2655 
2656  if (has_open_children(fileref)) {
2657  WARN("trying to rename file with open children\n");
2659  goto end;
2660  }
2661 
2662  if (oldfileref) {
2663  SeCaptureSubjectContext(&subjcont);
2664 
2665  if (!SeAccessCheck(oldfileref->fcb->sd, &subjcont, false, DELETE, 0, NULL,
2666  IoGetFileObjectGenericMapping(), Irp->RequestorMode, &access, &Status)) {
2667  SeReleaseSubjectContext(&subjcont);
2668  TRACE("SeAccessCheck failed, returning %08x\n", Status);
2669  goto end;
2670  }
2671 
2672  SeReleaseSubjectContext(&subjcont);
2673 
2674  if (oldfileref->open_count > 0 && flags & FILE_RENAME_POSIX_SEMANTICS) {
2675  oldfileref->delete_on_close = true;
2676  oldfileref->posix_delete = true;
2677  }
2678 
2679  Status = delete_fileref(oldfileref, NULL, oldfileref->open_count > 0 && flags & FILE_RENAME_POSIX_SEMANTICS, Irp, &rollback);
2680  if (!NT_SUCCESS(Status)) {
2681  ERR("delete_fileref returned %08x\n", Status);
2682  goto end;
2683  }
2684  }
2685 
2686  if (fileref->parent->fcb->subvol != related->fcb->subvol && (fileref->fcb->subvol == fileref->parent->fcb->subvol || fileref->fcb == Vcb->dummy_fcb)) {
2687  Status = move_across_subvols(fileref, ccb, related, &utf8, &fnus, Irp, &rollback);
2688  if (!NT_SUCCESS(Status)) {
2689  ERR("move_across_subvols returned %08x\n", Status);
2690  }
2691  goto end;
2692  }
2693 
2694  if (related == fileref->parent) { // keeping file in same directory
2695  UNICODE_STRING oldfn, newfn;
2696  USHORT name_offset;
2697  ULONG reqlen, oldutf8len;
2698 
2699  oldfn.Length = oldfn.MaximumLength = 0;
2700 
2701  Status = fileref_get_filename(fileref, &oldfn, &name_offset, &reqlen);
2702  if (Status != STATUS_BUFFER_OVERFLOW) {
2703  ERR("fileref_get_filename returned %08x\n", Status);
2704  goto end;
2705  }
2706 
2707  oldfn.Buffer = ExAllocatePoolWithTag(PagedPool, reqlen, ALLOC_TAG);
2708  if (!oldfn.Buffer) {
2709  ERR("out of memory\n");
2711  goto end;
2712  }
2713 
2714  oldfn.MaximumLength = (uint16_t)reqlen;
2715 
2716  Status = fileref_get_filename(fileref, &oldfn, &name_offset, &reqlen);
2717  if (!NT_SUCCESS(Status)) {
2718  ERR("fileref_get_filename returned %08x\n", Status);
2719  ExFreePool(oldfn.Buffer);
2720  goto end;
2721  }
2722 
2723  oldutf8len = fileref->dc->utf8.Length;
2724 
2725  if (!fileref->created && !fileref->oldutf8.Buffer) {
2727  if (!fileref->oldutf8.Buffer) {
2728  ERR("out of memory\n");
2730  goto end;
2731  }
2732 
2735  }
2736 
2737  TRACE("renaming %.*S to %.*S\n", fileref->dc->name.Length / sizeof(WCHAR), fileref->dc->name.Buffer, fnus.Length / sizeof(WCHAR), fnus.Buffer);
2738 
2740 
2741  if (fileref->dc) {
2742  ExAcquireResourceExclusiveLite(&fileref->parent->fcb->nonpaged->dir_children_lock, true);
2743 
2747 
2749  if (!fileref->dc->utf8.Buffer) {
2750  ERR("out of memory\n");
2752  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
2753  ExFreePool(oldfn.Buffer);
2754  goto end;
2755  }
2756 
2758  RtlCopyMemory(fileref->dc->utf8.Buffer, utf8.Buffer, utf8.Length);
2759 
2761  if (!fileref->dc->name.Buffer) {
2762  ERR("out of memory\n");
2764  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
2765  ExFreePool(oldfn.Buffer);
2766  goto end;
2767  }
2768 
2770  RtlCopyMemory(fileref->dc->name.Buffer, fnus.Buffer, fnus.Length);
2771 
2773  if (!NT_SUCCESS(Status)) {
2774  ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
2775  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
2776  ExFreePool(oldfn.Buffer);
2777  goto end;
2778  }
2779 
2781 
2784 
2786 
2787  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
2788  }
2789 
2790  newfn.Length = newfn.MaximumLength = 0;
2791 
2792  Status = fileref_get_filename(fileref, &newfn, &name_offset, &reqlen);
2793  if (Status != STATUS_BUFFER_OVERFLOW) {
2794  ERR("fileref_get_filename returned %08x\n", Status);
2795  ExFreePool(oldfn.Buffer);
2796  goto end;
2797  }
2798 
2799  newfn.Buffer = ExAllocatePoolWithTag(PagedPool, reqlen, ALLOC_TAG);
2800  if (!newfn.Buffer) {
2801  ERR("out of memory\n");
2803  ExFreePool(oldfn.Buffer);
2804  goto end;
2805  }
2806 
2807  newfn.MaximumLength = (uint16_t)reqlen;
2808 
2809  Status = fileref_get_filename(fileref, &newfn, &name_offset, &reqlen);
2810  if (!NT_SUCCESS(Status)) {
2811  ERR("fileref_get_filename returned %08x\n", Status);
2812  ExFreePool(oldfn.Buffer);
2813  ExFreePool(newfn.Buffer);
2814  goto end;
2815  }
2816 
2819 
2820  if (fcb != Vcb->dummy_fcb && (fileref->parent->fcb->subvol == fcb->subvol || !is_subvol_readonly(fcb->subvol, Irp))) {
2821  fcb->inode_item.transid = Vcb->superblock.generation;
2822  fcb->inode_item.sequence++;
2823 
2824  if (!ccb->user_set_change_time)
2826 
2827  fcb->inode_item_changed = true;
2829  }
2830 
2831  // update parent's INODE_ITEM
2832 
2833  related->fcb->inode_item.transid = Vcb->superblock.generation;
2834  TRACE("related->fcb->inode_item.st_size (inode %I64x) was %I64x\n", related->fcb->inode, related->fcb->inode_item.st_size);
2835  related->fcb->inode_item.st_size = related->fcb->inode_item.st_size + (2 * utf8.Length) - (2* oldutf8len);
2836  TRACE("related->fcb->inode_item.st_size (inode %I64x) now %I64x\n", related->fcb->inode, related->fcb->inode_item.st_size);
2837  related->fcb->inode_item.sequence++;
2838  related->fcb->inode_item.st_ctime = now;
2839  related->fcb->inode_item.st_mtime = now;
2840 
2841  related->fcb->inode_item_changed = true;
2842  mark_fcb_dirty(related->fcb);
2844 
2845  FsRtlNotifyFilterReportChange(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, (PSTRING)&oldfn, name_offset, NULL, NULL,
2847  FsRtlNotifyFilterReportChange(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, (PSTRING)&newfn, name_offset, NULL, NULL,
2849 
2850  ExFreePool(oldfn.Buffer);
2851  ExFreePool(newfn.Buffer);
2852 
2854  goto end;
2855  }
2856 
2857  // We move files by moving the existing fileref to the new directory, and
2858  // replacing it with a dummy fileref with the same original values, but marked as deleted.
2859 
2861 
2862  fr2 = create_fileref(Vcb);
2863 
2864  fr2->fcb = fileref->fcb;
2865  fr2->fcb->refcount++;
2866 
2867  fr2->oldutf8 = fileref->oldutf8;
2868  fr2->oldindex = fileref->dc->index;
2869  fr2->delete_on_close = fileref->delete_on_close;
2870  fr2->deleted = true;
2871  fr2->created = fileref->created;
2872  fr2->parent = fileref->parent;
2873  fr2->dc = NULL;
2874 
2875  if (!fr2->oldutf8.Buffer) {
2876  fr2->oldutf8.Buffer = ExAllocatePoolWithTag(PagedPool, fileref->dc->utf8.Length, ALLOC_TAG);
2877  if (!fr2->oldutf8.Buffer) {
2878  ERR("out of memory\n");
2880  goto end;
2881  }
2882 
2883  RtlCopyMemory(fr2->oldutf8.Buffer, fileref->dc->utf8.Buffer, fileref->dc->utf8.Length);
2884 
2885  fr2->oldutf8.Length = fr2->oldutf8.MaximumLength = fileref->dc->utf8.Length;
2886  }
2887 
2888  if (fr2->fcb->type == BTRFS_TYPE_DIRECTORY)
2889  fr2->fcb->fileref = fr2;
2890 
2892  fileref->fcb->subvol->parent = related->fcb->subvol->id;
2893 
2896  fileref->deleted = false;
2897  fileref->created = true;
2898  fileref->parent = related;
2899 
2900  ExAcquireResourceExclusiveLite(&fileref->parent->fcb->nonpaged->dir_children_lock, true);
2901  InsertHeadList(&fileref->list_entry, &fr2->list_entry);
2903  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
2904 
2905  mark_fileref_dirty(fr2);
2907 
2908  if (fileref->dc) {
2909  // remove from old parent
2910  ExAcquireResourceExclusiveLite(&fr2->parent->fcb->nonpaged->dir_children_lock, true);
2912  remove_dir_child_from_hash_lists(fr2->parent->fcb, fileref->dc);
2913  ExReleaseResourceLite(&fr2->parent->fcb->nonpaged->dir_children_lock);
2914 
2915  if (fileref->dc->utf8.Length != utf8.Length || RtlCompareMemory(fileref->dc->utf8.Buffer, utf8.Buffer, utf8.Length) != utf8.Length) {
2916  // handle changed name
2917 
2921 
2923  if (!fileref->dc->utf8.Buffer) {
2924  ERR("out of memory\n");
2926  goto end;
2927  }
2928 
2930  RtlCopyMemory(fileref->dc->utf8.Buffer, utf8.Buffer, utf8.Length);
2931 
2933  if (!fileref->dc->name.Buffer) {
2934  ERR("out of memory\n");
2936  goto end;
2937  }
2938 
2940  RtlCopyMemory(fileref->dc->name.Buffer, fnus.Buffer, fnus.Length);
2941 
2943  if (!NT_SUCCESS(Status)) {
2944  ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
2945  goto end;
2946  }
2947 
2950  }
2951 
2952  // add to new parent
2953  ExAcquireResourceExclusiveLite(&related->fcb->nonpaged->dir_children_lock, true);
2954 
2955  if (IsListEmpty(&related->fcb->dir_children_index))
2956  fileref->dc->index = 2;
2957  else {
2958  dir_child* dc2 = CONTAINING_RECORD(related->fcb->dir_children_index.Blink, dir_child, list_entry_index);
2959 
2960  fileref->dc->index = max(2, dc2->index + 1);
2961  }
2962 
2963  InsertTailList(&related->fcb->dir_children_index, &fileref->dc->list_entry_index);
2965  ExReleaseResourceLite(&related->fcb->nonpaged->dir_children_lock);
2966  }
2967 
2968  ExAcquireResourceExclusiveLite(&related->fcb->nonpaged->dir_children_lock, true);
2969  InsertTailList(&related->children, &fileref->list_entry);
2970  ExReleaseResourceLite(&related->fcb->nonpaged->dir_children_lock);
2971 
2972  if (fcb->inode_item.st_nlink > 1) {
2973  // add new hardlink entry to fcb
2974 
2976  if (!hl) {
2977  ERR("out of memory\n");
2979  goto end;
2980  }
2981 
2982  hl->parent = related->fcb->inode;
2983  hl->index = fileref->dc->index;
2984 
2985  hl->name.Length = hl->name.MaximumLength = fnus.Length;
2987 
2988  if (!hl->name.Buffer) {
2989  ERR("out of memory\n");
2990  ExFreePool(hl);
2992  goto end;
2993  }
2994 
2995  RtlCopyMemory(hl->name.Buffer, fnus.Buffer, fnus.Length);
2996 
2999 
3000  if (!hl->utf8.Buffer) {
3001  ERR("out of memory\n");
3002  ExFreePool(hl->name.Buffer);
3003  ExFreePool(hl);
3005  goto end;
3006  }
3007 
3009 
3011  }
3012 
3013  // delete old hardlink entry from fcb
3014 
3015  le = fcb->hardlinks.Flink;
3016  while (le != &fcb->hardlinks) {
3018 
3019  if (hl->parent == fr2->parent->fcb->inode && hl->index == fr2->oldindex) {
3021 
3022  if (hl->utf8.Buffer)
3023  ExFreePool(hl->utf8.Buffer);
3024 
3025  if (hl->name.Buffer)
3026  ExFreePool(hl->name.Buffer);
3027 
3028  ExFreePool(hl);
3029  break;
3030  }
3031 
3032  le = le->Flink;
3033  }
3034 
3035  // update inode's INODE_ITEM
3036 
3039 
3040  if (fcb != Vcb->dummy_fcb && (fileref->parent->fcb->subvol == fcb->subvol || !is_subvol_readonly(fcb->subvol, Irp))) {
3041  fcb->inode_item.transid = Vcb->superblock.generation;
3042  fcb->inode_item.sequence++;
3043 
3044  if (!ccb->user_set_change_time)
3046 
3047  fcb->inode_item_changed = true;
3049  }
3050 
3051  // update new parent's INODE_ITEM
3052 
3053  related->fcb->inode_item.transid = Vcb->superblock.generation;
3054  TRACE("related->fcb->inode_item.st_size (inode %I64x) was %I64x\n", related->fcb->inode, related->fcb->inode_item.st_size);
3055  related->fcb->inode_item.st_size += 2 * utf8len;
3056  TRACE("related->fcb->inode_item.st_size (inode %I64x) now %I64x\n", related->fcb->inode, related->fcb->inode_item.st_size);
3057  related->fcb->inode_item.sequence++;
3058  related->fcb->inode_item.st_ctime = now;
3059  related->fcb->inode_item.st_mtime = now;
3060 
3061  related->fcb->inode_item_changed = true;
3062  mark_fcb_dirty(related->fcb);
3063 
3064  // update old parent's INODE_ITEM
3065 
3066  fr2->parent->fcb->inode_item.transid = Vcb->superblock.generation;
3067  TRACE("fr2->parent->fcb->inode_item.st_size (inode %I64x) was %I64x\n", fr2->parent->fcb->inode, fr2->parent->fcb->inode_item.st_size);
3068  fr2->parent->fcb->inode_item.st_size -= 2 * origutf8len;
3069  TRACE("fr2->parent->fcb->inode_item.st_size (inode %I64x) now %I64x\n", fr2->parent->fcb->inode, fr2->parent->fcb->inode_item.st_size);
3070  fr2->parent->fcb->inode_item.sequence++;
3071  fr2->parent->fcb->inode_item.st_ctime = now;
3072  fr2->parent->fcb->inode_item.st_mtime = now;
3073 
3074  free_fileref(fr2);
3075 
3076  fr2->parent->fcb->inode_item_changed = true;
3077  mark_fcb_dirty(fr2->parent->fcb);
3078 
3082 
3084 
3085 end:
3086  if (oldfileref)
3087  free_fileref(oldfileref);
3088 
3089  if (!NT_SUCCESS(Status) && related)
3090  free_fileref(related);
3091 
3092  if (!NT_SUCCESS(Status) && fr2)
3093  free_fileref(fr2);
3094 
3095  if (NT_SUCCESS(Status))
3097  else
3099 
3100  ExReleaseResourceLite(fcb->Header.Resource);
3101  ExReleaseResourceLite(&Vcb->fileref_lock);
3102  ExReleaseResourceLite(&Vcb->tree_lock);
3103 
3104  return Status;
3105 }
3106 
3109  BTRFS_TIME now;
3110 
3111  TRACE("setting new end to %I64x bytes (currently %x)\n", end, fcb->adsdata.Length);
3112 
3113  if (!fileref || !fileref->parent) {
3114  ERR("no fileref for stream\n");
3115  return STATUS_INTERNAL_ERROR;
3116  }
3117 
3118  if (end < fcb->adsdata.Length) {
3119  if (advance_only)
3120  return STATUS_SUCCESS;
3121 
3122  TRACE("truncating stream to %I64x bytes\n", end);
3123 
3124  fcb->adsdata.Length = end;
3125  } else if (end > fcb->adsdata.Length) {
3126  TRACE("extending stream to %I64x bytes\n", end);
3127 
3128  if (end > fcb->adsmaxlen) {
3129  ERR("error - xattr too long (%u > %u)\n", end, fcb->adsmaxlen);
3130  return STATUS_DISK_FULL;
3131  }
3132 
3133  if (end > fcb->adsdata.MaximumLength) {
3135  if (!data) {
3136  ERR("out of memory\n");
3137  ExFreePool(data);
3139  }
3140 
3141  if (fcb->adsdata.Buffer) {
3144  }
3145 
3146  fcb->adsdata.Buffer = data;
3148  }
3149 
3151 
3152  fcb->adsdata.Length = end;
3153  }
3154 
3156 
3157  fcb->Header.AllocationSize.QuadPart = end;
3158  fcb->Header.FileSize.QuadPart = end;
3159  fcb->Header.ValidDataLength.QuadPart = end;
3160 
3163 
3164  fileref->parent->fcb->inode_item.transid = Vcb->superblock.generation;
3165  fileref->parent->fcb->inode_item.sequence++;
3166  fileref->parent->fcb->inode_item.st_ctime = now;
3167 
3168  fileref->parent->fcb->inode_item_changed = true;
3169  mark_fcb_dirty(fileref->parent->fcb);
3170 
3171  fileref->parent->fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
3172  fileref->parent->fcb->subvol->root_item.ctime = now;
3173 
3174  return STATUS_SUCCESS;
3175 }
3176 
3178  FILE_END_OF_FILE_INFORMATION* feofi = Irp->AssociatedIrp.SystemBuffer;
3179  fcb* fcb = FileObject->FsContext;
3180  ccb* ccb = FileObject->FsContext2;
3181  file_ref* fileref = ccb ? ccb->fileref : NULL;
3182  NTSTATUS Status;
3184  CC_FILE_SIZES ccfs;
3186  bool set_size = false;
3187  ULONG filter;
3188 
3189  if (!fileref) {
3190  ERR("fileref is NULL\n");
3191  return STATUS_INVALID_PARAMETER;
3192  }
3193 
3195 
3196  ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
3197 
3198  ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
3199 
3200  if (fileref ? fileref->deleted : fcb->deleted) {
3202  goto end;
3203  }
3204 
3205  if (fcb->ads) {
3206  if (feofi->EndOfFile.QuadPart > 0xffff) {
3208  goto end;
3209  }
3210 
3211  if (feofi->EndOfFile.QuadPart < 0) {
3213  goto end;
3214  }
3215 
3217 
3218  if (NT_SUCCESS(Status)) {
3219  ccfs.AllocationSize = fcb->Header.AllocationSize;
3220  ccfs.FileSize = fcb->Header.FileSize;
3221  ccfs.ValidDataLength = fcb->Header.ValidDataLength;
3222  set_size = true;
3223  }
3224 
3226 
3227  if (!ccb->user_set_write_time) {
3229  win_time_to_unix(time, &fileref->parent->fcb->inode_item.st_mtime);
3231 
3232  fileref->parent->fcb->inode_item_changed = true;
3233  mark_fcb_dirty(fileref->parent->fcb);
3234  }
3235 
3237 
3238  goto end;
3239  }
3240 
3241  TRACE("file: %p\n", FileObject);
3242  TRACE("paging IO: %s\n", Irp->Flags & IRP_PAGING_IO ? "true" : "false");
3243  TRACE("FileObject: AllocationSize = %I64x, FileSize = %I64x, ValidDataLength = %I64x\n",
3244  fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart);
3245 
3246  TRACE("setting new end to %I64x bytes (currently %I64x)\n", feofi->EndOfFile.QuadPart, fcb->inode_item.st_size);
3247 
3248  if ((uint64_t)feofi->EndOfFile.QuadPart < fcb->inode_item.st_size) {
3249  if (advance_only) {
3251  goto end;
3252  }
3253 
3254  TRACE("truncating file to %I64x bytes\n", feofi->EndOfFile.QuadPart);
3255 
3256  if (!MmCanFileBeTruncated(&fcb->nonpaged->segment_object, &feofi->EndOfFile)) {
3258  goto end;
3259  }
3260 
3262  if (!NT_SUCCESS(Status)) {
3263  ERR("error - truncate_file failed\n");
3264  goto end;
3265  }
3266  } else if ((uint64_t)feofi->EndOfFile.QuadPart > fcb->inode_item.st_size) {
3267  if (Irp->Flags & IRP_PAGING_IO) {
3268  TRACE("paging IO tried to extend file size\n");
3270  goto end;
3271  }
3272 
3273  TRACE("extending file to %I64x bytes\n", feofi->EndOfFile.QuadPart);
3274 
3276  if (!NT_SUCCESS(Status)) {
3277  ERR("error - extend_file failed\n");
3278  goto end;
3279  }
3280  } else if ((uint64_t)feofi->EndOfFile.QuadPart == fcb->inode_item.st_size && advance_only) {
3282  goto end;
3283  }
3284 
3285  ccfs.AllocationSize = fcb->Header.AllocationSize;
3286  ccfs.FileSize = fcb->Header.FileSize;
3287  ccfs.ValidDataLength = fcb->Header.ValidDataLength;
3288  set_size = true;
3289 
3291 
3292  if (!ccb->user_set_write_time) {
3296  }
3297 
3298  fcb->inode_item_changed = true;
3301 
3303 
3304 end:
3305  if (NT_SUCCESS(Status))
3307  else
3309 
3310  ExReleaseResourceLite(fcb->Header.Resource);
3311 
3312  if (set_size) {
3313  _SEH2_TRY {
3314  CcSetFileSizes(FileObject, &ccfs);
3317  } _SEH2_END;
3318 
3319  if (!NT_SUCCESS(Status))
3320  ERR("CcSetFileSizes threw exception %08x\n", Status);
3321  }
3322 
3323  ExReleaseResourceLite(&Vcb->tree_lock);
3324 
3325  return Status;
3326 }
3327 
3329  FILE_POSITION_INFORMATION* fpi = (FILE_POSITION_INFORMATION*)Irp->AssociatedIrp.SystemBuffer;
3330 
3331  TRACE("setting the position on %p to %I64x\n", FileObject, fpi->CurrentByteOffset.QuadPart);
3332 
3333  // FIXME - make sure aligned for FO_NO_INTERMEDIATE_BUFFERING
3334 
3335  FileObject->CurrentByteOffset = fpi->CurrentByteOffset;
3336 
3337  return STATUS_SUCCESS;
3338 }
3339 
3341  FILE_LINK_INFORMATION_EX* fli = Irp->AssociatedIrp.SystemBuffer;
3342  fcb *fcb = FileObject->FsContext, *tfofcb, *parfcb;
3343  ccb* ccb = FileObject->FsContext2;
3344  file_ref *fileref = ccb ? ccb->fileref : NULL, *oldfileref = NULL, *related = NULL, *fr2 = NULL;
3345  WCHAR* fn;
3346  ULONG fnlen, utf8len;
3347  UNICODE_STRING fnus;
3348  ANSI_STRING utf8;
3349  NTSTATUS Status;
3351  BTRFS_TIME now;
3353  hardlink* hl;
3355  SECURITY_SUBJECT_CONTEXT subjcont;
3356  dir_child* dc = NULL;
3357  ULONG flags;
3358 
3360 
3361  // FIXME - check fli length
3362  // FIXME - don't ignore fli->RootDirectory
3363 
3364  if (ex)
3365  flags = fli->Flags;
3366  else
3368 
3369  TRACE("flags = %x\n", flags);
3370  TRACE("RootDirectory = %p\n", fli->RootDirectory);
3371  TRACE("FileNameLength = %x\n", fli->FileNameLength);
3372  TRACE("FileName = %.*S\n", fli->FileNameLength / sizeof(WCHAR), fli->FileName);
3373 
3374  fn = fli->FileName;
3375  fnlen = fli->FileNameLength / sizeof(WCHAR);
3376 
3377  if (!tfo) {
3378  if (!fileref || !fileref->parent) {
3379  ERR("no fileref set and no directory given\n");
3380  return STATUS_INVALID_PARAMETER;
3381  }
3382 
3383  parfcb = fileref->parent->fcb;
3384  tfofcb = NULL;
3385  } else {
3386  LONG i;
3387 
3388  tfofcb = tfo->FsContext;
3389  parfcb = tfofcb;
3390 
3391  while (fnlen > 0 && (fli->FileName[fnlen - 1] == '/' || fli->FileName[fnlen - 1] == '\\'))
3392  fnlen--;
3393 
3394  if (fnlen == 0)
3395  return STATUS_INVALID_PARAMETER;
3396 
3397  for (i = fnlen - 1; i >= 0; i--) {
3398  if (fli->FileName[i] == '\\' || fli->FileName[i] == '/') {
3399  fn = &fli->FileName[i+1];
3400  fnlen = (fli->FileNameLength / sizeof(WCHAR)) - i - 1;
3401  break;
3402  }
3403  }
3404  }
3405 
3406  ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
3407  ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, true);