ReactOS  0.4.14-dev-50-g13bb5e2
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 = %S, attributes = %x\n", file_desc(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 %S (fcb %p)\n", flags & FILE_DISPOSITION_DELETE ? "true" : "false", file_desc(FileObject), 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  // FIXME - can we skip this bit for subvols?
401  if (fcb->type == BTRFS_TYPE_DIRECTORY && fcb->inode_item.st_size > 0 && (!fileref || fileref->fcb != Vcb->dummy_fcb)) {
402  TRACE("directory not empty\n");
404  goto end;
405  }
406 
407  if (!MmFlushImageSection(&fcb->nonpaged->segment_object, MmFlushForDelete)) {
409  TRACE("trying to delete file which is being mapped as an image\n");
411  goto end;
412  }
413  }
414 
416 
417  FileObject->DeletePending = flags & FILE_DISPOSITION_DELETE;
418 
420  ccb->fileref->posix_delete = true;
421 
423 
424 end:
425  ExReleaseResourceLite(fcb->Header.Resource);
426 
427  // send notification that directory is about to be deleted
429  FsRtlNotifyFullChangeDirectory(Vcb->NotifySync, &Vcb->DirNotifyList, FileObject->FsContext,
430  NULL, false, false, 0, NULL, NULL, NULL);
431  }
432 
433  return Status;
434 }
435 
436 bool has_open_children(file_ref* fileref) {
437  LIST_ENTRY* le = fileref->children.Flink;
438 
439  if (IsListEmpty(&fileref->children))
440  return false;
441 
442  while (le != &fileref->children) {
444 
445  if (c->open_count > 0)
446  return true;
447 
448  if (has_open_children(c))
449  return true;
450 
451  le = le->Flink;
452  }
453 
454  return false;
455 }
456 
457 static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
458  device_extension* Vcb = oldfcb->Vcb;
459  fcb* fcb;
460  LIST_ENTRY* le;
461 
462  // FIXME - we can skip a lot of this if the inode is about to be deleted
463 
464  fcb = create_fcb(Vcb, PagedPool); // FIXME - what if we duplicate the paging file?
465  if (!fcb) {
466  ERR("out of memory\n");
468  }
469 
470  fcb->Vcb = Vcb;
471 
472  fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
473  fcb->Header.AllocationSize = oldfcb->Header.AllocationSize;
474  fcb->Header.FileSize = oldfcb->Header.FileSize;
475  fcb->Header.ValidDataLength = oldfcb->Header.ValidDataLength;
476 
477  fcb->type = oldfcb->type;
478 
479  if (oldfcb->ads) {
480  fcb->ads = true;
481  fcb->adshash = oldfcb->adshash;
482  fcb->adsmaxlen = oldfcb->adsmaxlen;
483 
484  if (oldfcb->adsxattr.Buffer && oldfcb->adsxattr.Length > 0) {
485  fcb->adsxattr.Length = oldfcb->adsxattr.Length;
488 
489  if (!fcb->adsxattr.Buffer) {
490  ERR("out of memory\n");
491  free_fcb(fcb);
493  }
494 
497  }
498 
499  if (oldfcb->adsdata.Buffer && oldfcb->adsdata.Length > 0) {
502 
503  if (!fcb->adsdata.Buffer) {
504  ERR("out of memory\n");
505  free_fcb(fcb);
507  }
508 
510  }
511 
512  goto end;
513  }
514 
515  RtlCopyMemory(&fcb->inode_item, &oldfcb->inode_item, sizeof(INODE_ITEM));
516  fcb->inode_item_changed = true;
517 
518  if (oldfcb->sd && RtlLengthSecurityDescriptor(oldfcb->sd) > 0) {
520  if (!fcb->sd) {
521  ERR("out of memory\n");
522  free_fcb(fcb);
524  }
525 
526  RtlCopyMemory(fcb->sd, oldfcb->sd, RtlLengthSecurityDescriptor(oldfcb->sd));
527  }
528 
529  fcb->atts = oldfcb->atts;
530 
531  le = oldfcb->extents.Flink;
532  while (le != &oldfcb->extents) {
534 
535  if (!ext->ignore) {
536  extent* ext2 = ExAllocatePoolWithTag(PagedPool, offsetof(extent, extent_data) + ext->datalen, ALLOC_TAG);
537 
538  if (!ext2) {
539  ERR("out of memory\n");
540  free_fcb(fcb);
542  }
543 
544  ext2->offset = ext->offset;
545  ext2->datalen = ext->datalen;
546 
547  if (ext2->datalen > 0)
548  RtlCopyMemory(&ext2->extent_data, &ext->extent_data, ext2->datalen);
549 
550  ext2->unique = false;
551  ext2->ignore = false;
552  ext2->inserted = true;
553 
554  if (ext->csum) {
555  ULONG len;
556  EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ext->extent_data.data;
557 
558  if (ext->extent_data.compression == BTRFS_COMPRESSION_NONE)
559  len = (ULONG)ed2->num_bytes;
560  else
561  len = (ULONG)ed2->size;
562 
563  len = len * sizeof(uint32_t) / Vcb->superblock.sector_size;
564 
566  if (!ext2->csum) {
567  ERR("out of memory\n");
568  free_fcb(fcb);
570  }
571 
572  RtlCopyMemory(ext2->csum, ext->csum, len);
573  } else
574  ext2->csum = NULL;
575 
576  InsertTailList(&fcb->extents, &ext2->list_entry);
577  }
578 
579  le = le->Flink;
580  }
581 
582  le = oldfcb->hardlinks.Flink;
583  while (le != &oldfcb->hardlinks) {
584  hardlink *hl = CONTAINING_RECORD(le, hardlink, list_entry), *hl2;
585 
587 
588  if (!hl2) {
589  ERR("out of memory\n");
590  free_fcb(fcb);
592  }
593 
594  hl2->parent = hl->parent;
595  hl2->index = hl->index;
596 
597  hl2->name.Length = hl2->name.MaximumLength = hl->name.Length;
598  hl2->name.Buffer = ExAllocatePoolWithTag(PagedPool, hl2->name.MaximumLength, ALLOC_TAG);
599 
600  if (!hl2->name.Buffer) {
601  ERR("out of memory\n");
602  ExFreePool(hl2);
603  free_fcb(fcb);
605  }
606 
607  RtlCopyMemory(hl2->name.Buffer, hl->name.Buffer, hl->name.Length);
608 
609  hl2->utf8.Length = hl2->utf8.MaximumLength = hl->utf8.Length;
610  hl2->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, hl2->utf8.MaximumLength, ALLOC_TAG);
611 
612  if (!hl2->utf8.Buffer) {
613  ERR("out of memory\n");
614  ExFreePool(hl2->name.Buffer);
615  ExFreePool(hl2);
616  free_fcb(fcb);
618  }
619 
620  RtlCopyMemory(hl2->utf8.Buffer, hl->utf8.Buffer, hl->utf8.Length);
621 
622  InsertTailList(&fcb->hardlinks, &hl2->list_entry);
623 
624  le = le->Flink;
625  }
626 
627  if (oldfcb->reparse_xattr.Buffer && oldfcb->reparse_xattr.Length > 0) {
629 
631  if (!fcb->reparse_xattr.Buffer) {
632  ERR("out of memory\n");
633  free_fcb(fcb);
635  }
636 
638  }
639 
640  if (oldfcb->ea_xattr.Buffer && oldfcb->ea_xattr.Length > 0) {
642 
644  if (!fcb->ea_xattr.Buffer) {
645  ERR("out of memory\n");
646  free_fcb(fcb);
648  }
649 
651  }
652 
654 
655  le = oldfcb->xattrs.Flink;
656  while (le != &oldfcb->xattrs) {
658 
659  if (xa->valuelen > 0) {
660  xattr* xa2;
661 
663 
664  if (!xa2) {
665  ERR("out of memory\n");
666  free_fcb(fcb);
668  }
669 
670  xa2->namelen = xa->namelen;
671  xa2->valuelen = xa->valuelen;
672  xa2->dirty = xa->dirty;
673  memcpy(xa2->data, xa->data, xa->namelen + xa->valuelen);
674 
676  }
677 
678  le = le->Flink;
679  }
680 
681 end:
682  *pfcb = fcb;
683 
684  return STATUS_SUCCESS;
685 }
686 
687 typedef struct _move_entry {
693 } move_entry;
694 
697  LIST_ENTRY* le;
698 
699  ExAcquireResourceSharedLite(&me->fileref->fcb->nonpaged->dir_children_lock, true);
700 
701  le = me->fileref->fcb->dir_children_index.Flink;
702 
703  while (le != &me->fileref->fcb->dir_children_index) {
704  dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index);
705  file_ref* fr;
706  move_entry* me2;
707 
708  Status = open_fileref_child(Vcb, me->fileref, &dc->name, true, true, dc->index == 0 ? true : false, PagedPool, &fr, Irp);
709 
710  if (!NT_SUCCESS(Status)) {
711  ERR("open_fileref_child returned %08x\n", Status);
712  ExReleaseResourceLite(&me->fileref->fcb->nonpaged->dir_children_lock);
713  return Status;
714  }
715 
717  if (!me2) {
718  ERR("out of memory\n");
719  ExReleaseResourceLite(&me->fileref->fcb->nonpaged->dir_children_lock);
721  }
722 
723  me2->fileref = fr;
724  me2->dummyfcb = NULL;
725  me2->dummyfileref = NULL;
726  me2->parent = me;
727 
728  InsertHeadList(&me->list_entry, &me2->list_entry);
729 
730  le = le->Flink;
731  }
732 
733  ExReleaseResourceLite(&me->fileref->fcb->nonpaged->dir_children_lock);
734 
735  return STATUS_SUCCESS;
736 }
737 
739  uint8_t c;
740 
741  c = dc->hash >> 24;
742 
743  if (fcb->hash_ptrs[c] == &dc->list_entry_hash) {
744  if (dc->list_entry_hash.Flink == &fcb->dir_children_hash)
745  fcb->hash_ptrs[c] = NULL;
746  else {
747  dir_child* dc2 = CONTAINING_RECORD(dc->list_entry_hash.Flink, dir_child, list_entry_hash);
748 
749  if (dc2->hash >> 24 == c)
750  fcb->hash_ptrs[c] = &dc2->list_entry_hash;
751  else
752  fcb->hash_ptrs[c] = NULL;
753  }
754  }
755 
756  RemoveEntryList(&dc->list_entry_hash);
757 
758  c = dc->hash_uc >> 24;
759 
760  if (fcb->hash_ptrs_uc[c] == &dc->list_entry_hash_uc) {
761  if (dc->list_entry_hash_uc.Flink == &fcb->dir_children_hash_uc)
762  fcb->hash_ptrs_uc[c] = NULL;
763  else {
764  dir_child* dc2 = CONTAINING_RECORD(dc->list_entry_hash_uc.Flink, dir_child, list_entry_hash_uc);
765 
766  if (dc2->hash_uc >> 24 == c)
768  else
769  fcb->hash_ptrs_uc[c] = NULL;
770  }
771  }
772 
773  RemoveEntryList(&dc->list_entry_hash_uc);
774 }
775 
778  fcb* fcb;
779  SECURITY_SUBJECT_CONTEXT subjcont;
780  PSID owner;
781  BOOLEAN defaulted;
783  BTRFS_TIME now;
784 
786  if (!fcb) {
787  ERR("out of memory\n");
789  }
790 
793 
794  fcb->Vcb = Vcb;
795 
796  fcb->subvol = r;
797  fcb->inode = InterlockedIncrement64(&r->lastinode);
799 
800  fcb->inode_item.generation = Vcb->superblock.generation;
801  fcb->inode_item.transid = Vcb->superblock.generation;
802  fcb->inode_item.st_nlink = 1;
803  fcb->inode_item.st_mode = __S_IFDIR | inherit_mode(parfcb, true);
806 
807  fcb->atts = get_file_attributes(Vcb, fcb->subvol, fcb->inode, fcb->type, false, true, NULL);
808 
809  SeCaptureSubjectContext(&subjcont);
810 
811  Status = SeAssignSecurity(parfcb->sd, NULL, (void**)&fcb->sd, true, &subjcont, IoGetFileObjectGenericMapping(), PagedPool);
812 
813  if (!NT_SUCCESS(Status)) {
814  reap_fcb(fcb);
815  ERR("SeAssignSecurity returned %08x\n", Status);
816  return Status;
817  }
818 
819  if (!fcb->sd) {
820  reap_fcb(fcb);
821  ERR("SeAssignSecurity returned NULL security descriptor\n");
822  return STATUS_INTERNAL_ERROR;
823  }
824 
825  Status = RtlGetOwnerSecurityDescriptor(fcb->sd, &owner, &defaulted);
826  if (!NT_SUCCESS(Status)) {
827  ERR("RtlGetOwnerSecurityDescriptor returned %08x\n", Status);
829  fcb->sd_dirty = true;
830  } else {
831  fcb->inode_item.st_uid = sid_to_uid(owner);
833  }
834 
835  find_gid(fcb, parfcb, &subjcont);
836 
837  fcb->inode_item_changed = true;
838 
839  fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
840  fcb->Header.AllocationSize.QuadPart = 0;
841  fcb->Header.FileSize.QuadPart = 0;
842  fcb->Header.ValidDataLength.QuadPart = 0;
843 
844  fcb->created = true;
845 
846  if (parfcb->inode_item.flags & BTRFS_INODE_COMPRESS)
848 
851 
853  if (!fcb->hash_ptrs) {
854  ERR("out of memory\n");
856  }
857 
858  RtlZeroMemory(fcb->hash_ptrs, sizeof(LIST_ENTRY*) * 256);
859 
861  if (!fcb->hash_ptrs_uc) {
862  ERR("out of memory\n");
864  }
865 
866  RtlZeroMemory(fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256);
867 
868  acquire_fcb_lock_exclusive(Vcb);
869  InsertTailList(&r->fcbs, &fcb->list_entry);
870  InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
871  r->fcbs_version++;
872  release_fcb_lock(Vcb);
873 
875 
876  *pfcb = fcb;
877 
878  return STATUS_SUCCESS;
879 }
880 
883  LIST_ENTRY move_list, *le;
884  move_entry* me;
886  BTRFS_TIME now;
887  file_ref* origparent;
888 
889  // FIXME - make sure me->dummyfileref and me->dummyfcb get freed properly
890 
892 
895 
896  acquire_fcb_lock_exclusive(fileref->fcb->Vcb);
897 
899 
900  if (!me) {
901  ERR("out of memory\n");
903  goto end;
904  }
905 
906  origparent = fileref->parent;
907 
908  me->fileref = fileref;
910  me->dummyfcb = NULL;
911  me->dummyfileref = NULL;
912  me->parent = NULL;
913 
915 
916  le = move_list.Flink;
917  while (le != &move_list) {
919 
920  ExAcquireResourceSharedLite(me->fileref->fcb->Header.Resource, true);
921 
922  if (!me->fileref->fcb->ads && me->fileref->fcb->subvol == origparent->fcb->subvol) {
924 
925  if (!NT_SUCCESS(Status)) {
926  ERR("add_children_to_move_list returned %08x\n", Status);
927  goto end;
928  }
929  }
930 
931  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
932 
933  le = le->Flink;
934  }
935 
937 
938  // loop through list and create new inodes
939 
940  le = move_list.Flink;
941  while (le != &move_list) {
943 
944  if (me->fileref->fcb->inode != SUBVOL_ROOT_INODE && me->fileref->fcb != fileref->fcb->Vcb->dummy_fcb) {
945  if (!me->dummyfcb) {
946  ULONG defda;
947  bool inserted = false;
948  LIST_ENTRY* le3;
949 
950  ExAcquireResourceExclusiveLite(me->fileref->fcb->Header.Resource, true);
951 
952  Status = duplicate_fcb(me->fileref->fcb, &me->dummyfcb);
953  if (!NT_SUCCESS(Status)) {
954  ERR("duplicate_fcb returned %08x\n", Status);
955  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
956  goto end;
957  }
958 
959  me->dummyfcb->subvol = me->fileref->fcb->subvol;
960  me->dummyfcb->inode = me->fileref->fcb->inode;
961 
962  if (!me->dummyfcb->ads) {
963  me->dummyfcb->sd_dirty = me->fileref->fcb->sd_dirty;
969  }
970 
971  me->dummyfcb->created = me->fileref->fcb->created;
972  me->dummyfcb->deleted = me->fileref->fcb->deleted;
974 
975  if (!me->fileref->fcb->ads) {
976  LIST_ENTRY* le2;
977 
978  me->fileref->fcb->subvol = destdir->fcb->subvol;
979  me->fileref->fcb->inode = InterlockedIncrement64(&destdir->fcb->subvol->lastinode);
980  me->fileref->fcb->inode_item.st_nlink = 1;
981 
982  defda = get_file_attributes(me->fileref->fcb->Vcb, me->fileref->fcb->subvol, me->fileref->fcb->inode,
983  me->fileref->fcb->type, me->fileref->dc && me->fileref->dc->name.Length >= sizeof(WCHAR) && me->fileref->dc->name.Buffer[0] == '.',
984  true, Irp);
985 
986  me->fileref->fcb->sd_dirty = !!me->fileref->fcb->sd;
987  me->fileref->fcb->atts_changed = defda != me->fileref->fcb->atts;
990  me->fileref->fcb->ea_changed = !!me->fileref->fcb->ea_xattr.Buffer;
992  me->fileref->fcb->inode_item_changed = true;
993 
994  le2 = me->fileref->fcb->xattrs.Flink;
995  while (le2 != &me->fileref->fcb->xattrs) {
997 
998  xa->dirty = true;
999 
1000  le2 = le2->Flink;
1001  }
1002 
1003  if (le == move_list.Flink) { // first entry
1004  me->fileref->fcb->inode_item.transid = me->fileref->fcb->Vcb->superblock.generation;
1005  me->fileref->fcb->inode_item.sequence++;
1006 
1007  if (!ccb->user_set_change_time)
1008  me->fileref->fcb->inode_item.st_ctime = now;
1009  }
1010 
1011  le2 = me->fileref->fcb->extents.Flink;
1012  while (le2 != &me->fileref->fcb->extents) {
1014 
1015  if (!ext->ignore && (ext->extent_data.type == EXTENT_TYPE_REGULAR || ext->extent_data.type == EXTENT_TYPE_PREALLOC)) {
1016  EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ext->extent_data.data;
1017 
1018  if (ed2->size != 0) {
1020 
1021  if (!c) {
1022  ERR("get_chunk_from_address(%I64x) failed\n", ed2->address);
1023  } else {
1025  ext->offset - ed2->offset, 1, me->fileref->fcb->inode_item.flags & BTRFS_INODE_NODATASUM, false, Irp);
1026 
1027  if (!NT_SUCCESS(Status)) {
1028  ERR("update_changed_extent_ref returned %08x\n", Status);
1029  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
1030  goto end;
1031  }
1032  }
1033 
1034  }
1035  }
1036 
1037  le2 = le2->Flink;
1038  }
1039  } else {
1040  me->fileref->fcb->subvol = me->parent->fileref->fcb->subvol;
1041  me->fileref->fcb->inode = me->parent->fileref->fcb->inode;
1042  }
1043 
1044  me->fileref->fcb->created = true;
1045 
1048 
1049  le3 = destdir->fcb->subvol->fcbs.Flink;
1050  while (le3 != &destdir->fcb->subvol->fcbs) {
1051  fcb* fcb = CONTAINING_RECORD(le3, struct _fcb, list_entry);
1052 
1053  if (fcb->inode > me->fileref->fcb->inode) {
1054  InsertHeadList(le3->Blink, &me->fileref->fcb->list_entry);
1055  inserted = true;
1056  break;
1057  }
1058 
1059  le3 = le3->Flink;
1060  }
1061 
1062  if (!inserted)
1063  InsertTailList(&destdir->fcb->subvol->fcbs, &me->fileref->fcb->list_entry);
1064 
1065  InsertTailList(&me->fileref->fcb->Vcb->all_fcbs, &me->dummyfcb->list_entry_all);
1066 
1067  while (!IsListEmpty(&me->fileref->fcb->hardlinks)) {
1069 
1070  if (hl->name.Buffer)
1071  ExFreePool(hl->name.Buffer);
1072 
1073  if (hl->utf8.Buffer)
1074  ExFreePool(hl->utf8.Buffer);
1075 
1076  ExFreePool(hl);
1077  }
1078 
1079  me->fileref->fcb->inode_item_changed = true;
1080  mark_fcb_dirty(me->fileref->fcb);
1081 
1082  if ((!me->dummyfcb->ads && me->dummyfcb->inode_item.st_nlink > 1) || (me->dummyfcb->ads && me->parent->dummyfcb->inode_item.st_nlink > 1)) {
1083  LIST_ENTRY* le2 = le->Flink;
1084 
1085  while (le2 != &move_list) {
1087 
1088  if (me2->fileref->fcb == me->fileref->fcb && !me2->fileref->fcb->ads) {
1089  me2->dummyfcb = me->dummyfcb;
1091  }
1092 
1093  le2 = le2->Flink;
1094  }
1095  }
1096 
1097  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
1098  } else {
1099  ExAcquireResourceExclusiveLite(me->fileref->fcb->Header.Resource, true);
1100  me->fileref->fcb->inode_item.st_nlink++;
1101  me->fileref->fcb->inode_item_changed = true;
1102  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
1103  }
1104  }
1105 
1106  le = le->Flink;
1107  }
1108 
1109  fileref->fcb->subvol->root_item.ctransid = fileref->fcb->Vcb->superblock.generation;
1110  fileref->fcb->subvol->root_item.ctime = now;
1111 
1112  // loop through list and create new filerefs
1113 
1114  le = move_list.Flink;
1115  while (le != &move_list) {
1116  hardlink* hl;
1117  bool name_changed = false;
1118 
1120 
1122  if (!me->dummyfileref) {
1123  ERR("out of memory\n");
1125  goto end;
1126  }
1127 
1128  if (me->fileref->fcb == me->fileref->fcb->Vcb->dummy_fcb) {
1129  root* r = me->parent ? me->parent->fileref->fcb->subvol : destdir->fcb->subvol;
1130 
1131  Status = create_directory_fcb(me->fileref->fcb->Vcb, r, me->fileref->parent->fcb, &me->fileref->fcb);
1132  if (!NT_SUCCESS(Status)) {
1133  ERR("create_directory_fcb returnd %08x\n", Status);
1134  goto end;
1135  }
1136 
1137  me->fileref->dc->key.obj_id = me->fileref->fcb->inode;
1139 
1140  me->dummyfileref->fcb = me->fileref->fcb->Vcb->dummy_fcb;
1141  } else if (me->fileref->fcb->inode == SUBVOL_ROOT_INODE) {
1142  me->dummyfileref->fcb = me->fileref->fcb;
1143 
1144  me->fileref->fcb->subvol->parent = le == move_list.Flink ? destdir->fcb->subvol->id : me->parent->fileref->fcb->subvol->id;
1145  } else
1146  me->dummyfileref->fcb = me->dummyfcb;
1147 
1149 
1150  me->dummyfileref->oldutf8 = me->fileref->oldutf8;
1151  me->dummyfileref->oldindex = me->fileref->dc->index;
1152 
1153  if (le == move_list.Flink && (me->fileref->dc->utf8.Length != utf8->Length || RtlCompareMemory(me->fileref->dc->utf8.Buffer, utf8->Buffer, utf8->Length) != utf8->Length))
1154  name_changed = true;
1155 
1156  if ((le == move_list.Flink || me->fileref->fcb->inode == SUBVOL_ROOT_INODE) && !me->dummyfileref->oldutf8.Buffer) {
1158  if (!me->dummyfileref->oldutf8.Buffer) {
1159  ERR("out of memory\n");
1161  goto end;
1162  }
1163 
1165 
1167  }
1168 
1170  me->dummyfileref->deleted = me->fileref->deleted;
1171 
1172  me->dummyfileref->created = me->fileref->created;
1173  me->fileref->created = true;
1174 
1175  me->dummyfileref->parent = me->parent ? me->parent->dummyfileref : origparent;
1177 
1178  ExAcquireResourceExclusiveLite(&me->dummyfileref->parent->fcb->nonpaged->dir_children_lock, true);
1179  InsertTailList(&me->dummyfileref->parent->children, &me->dummyfileref->list_entry);
1180  ExReleaseResourceLite(&me->dummyfileref->parent->fcb->nonpaged->dir_children_lock);
1181 
1183 
1185  me->dummyfileref->fcb->fileref = me->dummyfileref;
1186 
1187  if (!me->parent) {
1189 
1190  increase_fileref_refcount(destdir);
1191 
1192  if (me->fileref->dc) {
1193  // remove from old parent
1194  ExAcquireResourceExclusiveLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock, true);
1197  ExReleaseResourceLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock);
1198 
1199  me->fileref->parent->fcb->inode_item.st_size -= me->fileref->dc->utf8.Length * 2;
1200  me->fileref->parent->fcb->inode_item.transid = me->fileref->fcb->Vcb->superblock.generation;
1201  me->fileref->parent->fcb->inode_item.sequence++;
1202  me->fileref->parent->fcb->inode_item.st_ctime = now;
1203  me->fileref->parent->fcb->inode_item.st_mtime = now;
1204  me->fileref->parent->fcb->inode_item_changed = true;
1205  mark_fcb_dirty(me->fileref->parent->fcb);
1206 
1207  if (name_changed) {
1208  ExFreePool(me->fileref->dc->utf8.Buffer);
1209  ExFreePool(me->fileref->dc->name.Buffer);
1211 
1213  if (!me->fileref->dc->utf8.Buffer) {
1214  ERR("out of memory\n");
1216  goto end;
1217  }
1218 
1219  me->fileref->dc->utf8.Length = me->fileref->dc->utf8.MaximumLength = utf8->Length;
1220  RtlCopyMemory(me->fileref->dc->utf8.Buffer, utf8->Buffer, utf8->Length);
1221 
1223  if (!me->fileref->dc->name.Buffer) {
1224  ERR("out of memory\n");
1226  goto end;
1227  }
1228 
1229  me->fileref->dc->name.Length = me->fileref->dc->name.MaximumLength = fnus->Length;
1230  RtlCopyMemory(me->fileref->dc->name.Buffer, fnus->Buffer, fnus->Length);
1231 
1233  if (!NT_SUCCESS(Status)) {
1234  ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
1235  goto end;
1236  }
1237 
1238  me->fileref->dc->hash = calc_crc32c(0xffffffff, (uint8_t*)me->fileref->dc->name.Buffer, me->fileref->dc->name.Length);
1239  me->fileref->dc->hash_uc = calc_crc32c(0xffffffff, (uint8_t*)me->fileref->dc->name_uc.Buffer, me->fileref->dc->name_uc.Length);
1240  }
1241 
1242  if (me->fileref->dc->key.obj_type == TYPE_INODE_ITEM)
1243  me->fileref->dc->key.obj_id = me->fileref->fcb->inode;
1244 
1245  // add to new parent
1246 
1247  ExAcquireResourceExclusiveLite(&destdir->fcb->nonpaged->dir_children_lock, true);
1248 
1249  if (IsListEmpty(&destdir->fcb->dir_children_index))
1250  me->fileref->dc->index = 2;
1251  else {
1252  dir_child* dc2 = CONTAINING_RECORD(destdir->fcb->dir_children_index.Blink, dir_child, list_entry_index);
1253 
1254  me->fileref->dc->index = max(2, dc2->index + 1);
1255  }
1256 
1259  ExReleaseResourceLite(&destdir->fcb->nonpaged->dir_children_lock);
1260  }
1261 
1262  free_fileref(me->fileref->parent);
1263  me->fileref->parent = destdir;
1264 
1265  ExAcquireResourceExclusiveLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock, true);
1266  InsertTailList(&me->fileref->parent->children, &me->fileref->list_entry);
1267  ExReleaseResourceLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock);
1268 
1269  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);
1270  me->fileref->parent->fcb->inode_item.st_size += me->fileref->dc->utf8.Length * 2;
1271  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);
1272  me->fileref->parent->fcb->inode_item.transid = me->fileref->fcb->Vcb->superblock.generation;
1273  me->fileref->parent->fcb->inode_item.sequence++;
1274  me->fileref->parent->fcb->inode_item.st_ctime = now;
1275  me->fileref->parent->fcb->inode_item.st_mtime = now;
1276  me->fileref->parent->fcb->inode_item_changed = true;
1277  mark_fcb_dirty(me->fileref->parent->fcb);
1278  } else {
1279  if (me->fileref->dc) {
1280  ExAcquireResourceExclusiveLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock, true);
1282 
1283  if (!me->fileref->fcb->ads)
1285 
1286  ExReleaseResourceLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock);
1287 
1288  ExAcquireResourceExclusiveLite(&me->parent->fileref->fcb->nonpaged->dir_children_lock, true);
1289 
1290  if (me->fileref->fcb->ads)
1291  InsertHeadList(&me->parent->fileref->fcb->dir_children_index, &me->fileref->dc->list_entry_index);
1292  else {
1293  if (me->fileref->fcb->inode != SUBVOL_ROOT_INODE)
1294  me->fileref->dc->key.obj_id = me->fileref->fcb->inode;
1295 
1296  if (IsListEmpty(&me->parent->fileref->fcb->dir_children_index))
1297  me->fileref->dc->index = 2;
1298  else {
1299  dir_child* dc2 = CONTAINING_RECORD(me->parent->fileref->fcb->dir_children_index.Blink, dir_child, list_entry_index);
1300 
1301  me->fileref->dc->index = max(2, dc2->index + 1);
1302  }
1303 
1304  InsertTailList(&me->parent->fileref->fcb->dir_children_index, &me->fileref->dc->list_entry_index);
1305  insert_dir_child_into_hash_lists(me->parent->fileref->fcb, me->fileref->dc);
1306  }
1307 
1308  ExReleaseResourceLite(&me->parent->fileref->fcb->nonpaged->dir_children_lock);
1309  }
1310  }
1311 
1312  if (!me->dummyfileref->fcb->ads) {
1314  if (!NT_SUCCESS(Status)) {
1315  ERR("delete_fileref returned %08x\n", Status);
1316  goto end;
1317  }
1318  }
1319 
1320  if (me->fileref->fcb->inode_item.st_nlink > 1) {
1322  if (!hl) {
1323  ERR("out of memory\n");
1325  goto end;
1326  }
1327 
1328  hl->parent = me->fileref->parent->fcb->inode;
1329  hl->index = me->fileref->dc->index;
1330 
1331  hl->utf8.Length = hl->utf8.MaximumLength = me->fileref->dc->utf8.Length;
1333  if (!hl->utf8.Buffer) {
1334  ERR("out of memory\n");
1336  ExFreePool(hl);
1337  goto end;
1338  }
1339 
1341 
1342  hl->name.Length = hl->name.MaximumLength = me->fileref->dc->name.Length;
1344  if (!hl->name.Buffer) {
1345  ERR("out of memory\n");
1347  ExFreePool(hl->utf8.Buffer);
1348  ExFreePool(hl);
1349  goto end;
1350  }
1351 
1353 
1355  }
1356 
1358 
1359  le = le->Flink;
1360  }
1361 
1362  // loop through, and only mark streams as deleted if their parent inodes are also deleted
1363 
1364  le = move_list.Flink;
1365  while (le != &move_list) {
1367 
1368  if (me->dummyfileref->fcb->ads && me->parent->dummyfileref->fcb->deleted) {
1370  if (!NT_SUCCESS(Status)) {
1371  ERR("delete_fileref returned %08x\n", Status);
1372  goto end;
1373  }
1374  }
1375 
1376  le = le->Flink;
1377  }
1378 
1379  destdir->fcb->subvol->root_item.ctransid = destdir->fcb->Vcb->superblock.generation;
1380  destdir->fcb->subvol->root_item.ctime = now;
1381 
1386 
1388 
1389 end:
1390  while (!IsListEmpty(&move_list)) {
1391  le = RemoveHeadList(&move_list);
1393 
1394  if (me->dummyfcb)
1395  free_fcb(me->dummyfcb);
1396 
1397  if (me->dummyfileref)
1399 
1400  free_fileref(me->fileref);
1401 
1402  ExFreePool(me);
1403  }
1404 
1405  destdir->fcb->subvol->fcbs_version++;
1406  fileref->fcb->subvol->fcbs_version++;
1407 
1408  release_fcb_lock(fileref->fcb->Vcb);
1409 
1410  return Status;
1411 }
1412 
1414  bool inserted;
1415  LIST_ENTRY* le;
1416  uint8_t c, d;
1417 
1418  c = dc->hash >> 24;
1419 
1420  inserted = false;
1421 
1422  d = c;
1423  do {
1424  le = fcb->hash_ptrs[d];
1425 
1426  if (d == 0)
1427  break;
1428 
1429  d--;
1430  } while (!le);
1431 
1432  if (!le)
1433  le = fcb->dir_children_hash.Flink;
1434 
1435  while (le != &fcb->dir_children_hash) {
1436  dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_hash);
1437 
1438  if (dc2->hash > dc->hash) {
1439  InsertHeadList(le->Blink, &dc->list_entry_hash);
1440  inserted = true;
1441  break;
1442  }
1443 
1444  le = le->Flink;
1445  }
1446 
1447  if (!inserted)
1448  InsertTailList(&fcb->dir_children_hash, &dc->list_entry_hash);
1449 
1450  if (!fcb->hash_ptrs[c])
1451  fcb->hash_ptrs[c] = &dc->list_entry_hash;
1452  else {
1453  dir_child* dc2 = CONTAINING_RECORD(fcb->hash_ptrs[c], dir_child, list_entry_hash);
1454 
1455  if (dc2->hash > dc->hash)
1456  fcb->hash_ptrs[c] = &dc->list_entry_hash;
1457  }
1458 
1459  c = dc->hash_uc >> 24;
1460 
1461  inserted = false;
1462 
1463  d = c;
1464  do {
1465  le = fcb->hash_ptrs_uc[d];
1466 
1467  if (d == 0)
1468  break;
1469 
1470  d--;
1471  } while (!le);
1472 
1473  if (!le)
1475 
1476  while (le != &fcb->dir_children_hash_uc) {
1477  dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_hash_uc);
1478 
1479  if (dc2->hash_uc > dc->hash_uc) {
1480  InsertHeadList(le->Blink, &dc->list_entry_hash_uc);
1481  inserted = true;
1482  break;
1483  }
1484 
1485  le = le->Flink;
1486  }
1487 
1488  if (!inserted)
1489  InsertTailList(&fcb->dir_children_hash_uc, &dc->list_entry_hash_uc);
1490 
1491  if (!fcb->hash_ptrs_uc[c])
1492  fcb->hash_ptrs_uc[c] = &dc->list_entry_hash_uc;
1493  else {
1494  dir_child* dc2 = CONTAINING_RECORD(fcb->hash_ptrs_uc[c], dir_child, list_entry_hash_uc);
1495 
1496  if (dc2->hash_uc > dc->hash_uc)
1497  fcb->hash_ptrs_uc[c] = &dc->list_entry_hash_uc;
1498  }
1499 }
1500 
1502  FILE_RENAME_INFORMATION_EX* fri = Irp->AssociatedIrp.SystemBuffer;
1503  fcb *fcb = FileObject->FsContext;
1504  ccb* ccb = FileObject->FsContext2;
1505  file_ref *fileref = ccb ? ccb->fileref : NULL, *oldfileref = NULL, *related = NULL, *fr2 = NULL;
1506  WCHAR* fn;
1507  ULONG fnlen, utf8len, origutf8len;
1508  UNICODE_STRING fnus;
1509  ANSI_STRING utf8;
1510  NTSTATUS Status;
1512  BTRFS_TIME now;
1513  LIST_ENTRY rollback, *le;
1514  hardlink* hl;
1515  SECURITY_SUBJECT_CONTEXT subjcont;
1517  ULONG flags;
1518 
1520 
1521  if (ex)
1522  flags = fri->Flags;
1523  else
1525 
1526  TRACE("tfo = %p\n", tfo);
1527  TRACE("Flags = %x\n", flags);
1528  TRACE("RootDirectory = %p\n", fri->RootDirectory);
1529  TRACE("FileName = %.*S\n", fri->FileNameLength / sizeof(WCHAR), fri->FileName);
1530 
1531  fn = fri->FileName;
1532  fnlen = fri->FileNameLength / sizeof(WCHAR);
1533 
1534  if (!tfo) {
1535  if (!fileref || !fileref->parent) {
1536  ERR("no fileref set and no directory given\n");
1537  return STATUS_INVALID_PARAMETER;
1538  }
1539  } else {
1540  LONG i;
1541 
1542  while (fnlen > 0 && (fri->FileName[fnlen - 1] == '/' || fri->FileName[fnlen - 1] == '\\'))
1543  fnlen--;
1544 
1545  if (fnlen == 0)
1546  return STATUS_INVALID_PARAMETER;
1547 
1548  for (i = fnlen - 1; i >= 0; i--) {
1549  if (fri->FileName[i] == '\\' || fri->FileName[i] == '/') {
1550  fn = &fri->FileName[i+1];
1551  fnlen = (fri->FileNameLength / sizeof(WCHAR)) - i - 1;
1552  break;
1553  }
1554  }
1555  }
1556 
1557  ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
1558  ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, true);
1559  ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
1560 
1561  if (fcb->ads) {
1562  // MSDN says that NTFS data streams can be renamed (https://msdn.microsoft.com/en-us/library/windows/hardware/ff540344.aspx),
1563  // but if you try it always seems to return STATUS_INVALID_PARAMETER. There is a function in ntfs.sys called NtfsStreamRename,
1564  // but it never seems to get invoked... If you know what's going on here, I'd appreciate it if you let me know.
1566  goto end;
1567  }
1568 
1569  fnus.Buffer = fn;
1570  fnus.Length = fnus.MaximumLength = (uint16_t)(fnlen * sizeof(WCHAR));
1571 
1572  TRACE("fnus = %.*S\n", fnus.Length / sizeof(WCHAR), fnus.Buffer);
1573 
1574  origutf8len = fileref->dc->utf8.Length;
1575 
1576  Status = utf16_to_utf8(NULL, 0, &utf8len, fn, (ULONG)fnlen * sizeof(WCHAR));
1577  if (!NT_SUCCESS(Status))
1578  goto end;
1579 
1580  utf8.MaximumLength = utf8.Length = (uint16_t)utf8len;
1582  if (!utf8.Buffer) {
1583  ERR("out of memory\n");
1585  goto end;
1586  }
1587 
1588  Status = utf16_to_utf8(utf8.Buffer, utf8len, &utf8len, fn, (ULONG)fnlen * sizeof(WCHAR));
1589  if (!NT_SUCCESS(Status))
1590  goto end;
1591 
1592  if (tfo && tfo->FsContext2) {
1593  struct _ccb* relatedccb = tfo->FsContext2;
1594 
1595  related = relatedccb->fileref;
1596  increase_fileref_refcount(related);
1597  } else if (fnus.Length >= sizeof(WCHAR) && fnus.Buffer[0] != '\\') {
1598  related = fileref->parent;
1599  increase_fileref_refcount(related);
1600  }
1601 
1602  Status = open_fileref(Vcb, &oldfileref, &fnus, related, false, NULL, NULL, PagedPool, ccb->case_sensitive, Irp);
1603 
1604  if (NT_SUCCESS(Status)) {
1605  TRACE("destination file %S already exists\n", file_desc_fileref(oldfileref));
1606 
1607  if (fileref != oldfileref && !oldfileref->deleted) {
1610  goto end;
1611  } else if (fileref == oldfileref) {
1613  goto end;
1614  } else if (!(flags & FILE_RENAME_POSIX_SEMANTICS) && (oldfileref->open_count > 0 || has_open_children(oldfileref)) && !oldfileref->deleted) {
1615  WARN("trying to overwrite open file\n");
1617  goto end;
1618  } else if (!(flags & FILE_RENAME_IGNORE_READONLY_ATTRIBUTE) && oldfileref->fcb->atts & FILE_ATTRIBUTE_READONLY) {
1619  WARN("trying to overwrite readonly file\n");
1621  goto end;
1622  } else if (oldfileref->fcb->type == BTRFS_TYPE_DIRECTORY) {
1623  WARN("trying to overwrite directory\n");
1625  goto end;
1626  }
1627  }
1628 
1629  if (fileref == oldfileref || oldfileref->deleted) {
1630  free_fileref(oldfileref);
1631  oldfileref = NULL;
1632  }
1633  }
1634 
1635  if (!related) {
1636  Status = open_fileref(Vcb, &related, &fnus, NULL, true, NULL, NULL, PagedPool, ccb->case_sensitive, Irp);
1637 
1638  if (!NT_SUCCESS(Status)) {
1639  ERR("open_fileref returned %08x\n", Status);
1640  goto end;
1641  }
1642  }
1643 
1644  if (related->fcb == Vcb->dummy_fcb) {
1646  goto end;
1647  }
1648 
1649  SeCaptureSubjectContext(&subjcont);
1650 
1651  if (!SeAccessCheck(related->fcb->sd, &subjcont, false, fcb->type == BTRFS_TYPE_DIRECTORY ? FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE, 0, NULL,
1652  IoGetFileObjectGenericMapping(), Irp->RequestorMode, &access, &Status)) {
1653  SeReleaseSubjectContext(&subjcont);
1654  TRACE("SeAccessCheck failed, returning %08x\n", Status);
1655  goto end;
1656  }
1657 
1658  SeReleaseSubjectContext(&subjcont);
1659 
1660  if (has_open_children(fileref)) {
1661  WARN("trying to rename file with open children\n");
1663  goto end;
1664  }
1665 
1666  if (oldfileref) {
1667  SeCaptureSubjectContext(&subjcont);
1668 
1669  if (!SeAccessCheck(oldfileref->fcb->sd, &subjcont, false, DELETE, 0, NULL,
1670  IoGetFileObjectGenericMapping(), Irp->RequestorMode, &access, &Status)) {
1671  SeReleaseSubjectContext(&subjcont);
1672  TRACE("SeAccessCheck failed, returning %08x\n", Status);
1673  goto end;
1674  }
1675 
1676  SeReleaseSubjectContext(&subjcont);
1677 
1678  if (oldfileref->open_count > 0 && flags & FILE_RENAME_POSIX_SEMANTICS) {
1679  oldfileref->delete_on_close = true;
1680  oldfileref->posix_delete = true;
1681  }
1682 
1683  Status = delete_fileref(oldfileref, NULL, oldfileref->open_count > 0 && flags & FILE_RENAME_POSIX_SEMANTICS, Irp, &rollback);
1684  if (!NT_SUCCESS(Status)) {
1685  ERR("delete_fileref returned %08x\n", Status);
1686  goto end;
1687  }
1688  }
1689 
1690  if (fileref->parent->fcb->subvol != related->fcb->subvol && (fileref->fcb->subvol == fileref->parent->fcb->subvol || fileref->fcb == Vcb->dummy_fcb)) {
1691  Status = move_across_subvols(fileref, ccb, related, &utf8, &fnus, Irp, &rollback);
1692  if (!NT_SUCCESS(Status)) {
1693  ERR("move_across_subvols returned %08x\n", Status);
1694  }
1695  goto end;
1696  }
1697 
1698  if (related == fileref->parent) { // keeping file in same directory
1699  UNICODE_STRING oldfn, newfn;
1700  USHORT name_offset;
1701  ULONG reqlen, oldutf8len;
1702 
1703  oldfn.Length = oldfn.MaximumLength = 0;
1704 
1705  Status = fileref_get_filename(fileref, &oldfn, &name_offset, &reqlen);
1706  if (Status != STATUS_BUFFER_OVERFLOW) {
1707  ERR("fileref_get_filename returned %08x\n", Status);
1708  goto end;
1709  }
1710 
1711  oldfn.Buffer = ExAllocatePoolWithTag(PagedPool, reqlen, ALLOC_TAG);
1712  if (!oldfn.Buffer) {
1713  ERR("out of memory\n");
1715  goto end;
1716  }
1717 
1718  oldfn.MaximumLength = (uint16_t)reqlen;
1719 
1720  Status = fileref_get_filename(fileref, &oldfn, &name_offset, &reqlen);
1721  if (!NT_SUCCESS(Status)) {
1722  ERR("fileref_get_filename returned %08x\n", Status);
1723  ExFreePool(oldfn.Buffer);
1724  goto end;
1725  }
1726 
1727  oldutf8len = fileref->dc->utf8.Length;
1728 
1729  if (!fileref->created && !fileref->oldutf8.Buffer) {
1731  if (!fileref->oldutf8.Buffer) {
1732  ERR("out of memory\n");
1734  goto end;
1735  }
1736 
1739  }
1740 
1741  TRACE("renaming %.*S to %.*S\n", fileref->dc->name.Length / sizeof(WCHAR), fileref->dc->name.Buffer, fnus.Length / sizeof(WCHAR), fnus.Buffer);
1742 
1744 
1745  if (fileref->dc) {
1746  ExAcquireResourceExclusiveLite(&fileref->parent->fcb->nonpaged->dir_children_lock, true);
1747 
1751 
1753  if (!fileref->dc->utf8.Buffer) {
1754  ERR("out of memory\n");
1756  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
1757  ExFreePool(oldfn.Buffer);
1758  goto end;
1759  }
1760 
1762  RtlCopyMemory(fileref->dc->utf8.Buffer, utf8.Buffer, utf8.Length);
1763 
1765  if (!fileref->dc->name.Buffer) {
1766  ERR("out of memory\n");
1768  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
1769  ExFreePool(oldfn.Buffer);
1770  goto end;
1771  }
1772 
1774  RtlCopyMemory(fileref->dc->name.Buffer, fnus.Buffer, fnus.Length);
1775 
1777  if (!NT_SUCCESS(Status)) {
1778  ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
1779  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
1780  ExFreePool(oldfn.Buffer);
1781  goto end;
1782  }
1783 
1785 
1788 
1790 
1791  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
1792  }
1793 
1794  newfn.Length = newfn.MaximumLength = 0;
1795 
1796  Status = fileref_get_filename(fileref, &newfn, &name_offset, &reqlen);
1797  if (Status != STATUS_BUFFER_OVERFLOW) {
1798  ERR("fileref_get_filename returned %08x\n", Status);
1799  ExFreePool(oldfn.Buffer);
1800  goto end;
1801  }
1802 
1803  newfn.Buffer = ExAllocatePoolWithTag(PagedPool, reqlen, ALLOC_TAG);
1804  if (!newfn.Buffer) {
1805  ERR("out of memory\n");
1807  ExFreePool(oldfn.Buffer);
1808  goto end;
1809  }
1810 
1811  newfn.MaximumLength = (uint16_t)reqlen;
1812 
1813  Status = fileref_get_filename(fileref, &newfn, &name_offset, &reqlen);
1814  if (!NT_SUCCESS(Status)) {
1815  ERR("fileref_get_filename returned %08x\n", Status);
1816  ExFreePool(oldfn.Buffer);
1817  ExFreePool(newfn.Buffer);
1818  goto end;
1819  }
1820 
1823 
1824  if (fcb != Vcb->dummy_fcb && (fileref->parent->fcb->subvol == fcb->subvol || !is_subvol_readonly(fcb->subvol, Irp))) {
1825  fcb->inode_item.transid = Vcb->superblock.generation;
1826  fcb->inode_item.sequence++;
1827 
1828  if (!ccb->user_set_change_time)
1830 
1831  fcb->inode_item_changed = true;
1833  }
1834 
1835  // update parent's INODE_ITEM
1836 
1837  related->fcb->inode_item.transid = Vcb->superblock.generation;
1838  TRACE("related->fcb->inode_item.st_size (inode %I64x) was %I64x\n", related->fcb->inode, related->fcb->inode_item.st_size);
1839  related->fcb->inode_item.st_size = related->fcb->inode_item.st_size + (2 * utf8.Length) - (2* oldutf8len);
1840  TRACE("related->fcb->inode_item.st_size (inode %I64x) now %I64x\n", related->fcb->inode, related->fcb->inode_item.st_size);
1841  related->fcb->inode_item.sequence++;
1842  related->fcb->inode_item.st_ctime = now;
1843  related->fcb->inode_item.st_mtime = now;
1844 
1845  related->fcb->inode_item_changed = true;
1846  mark_fcb_dirty(related->fcb);
1848 
1849  FsRtlNotifyFilterReportChange(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, (PSTRING)&oldfn, name_offset, NULL, NULL,
1851  FsRtlNotifyFilterReportChange(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, (PSTRING)&newfn, name_offset, NULL, NULL,
1853 
1854  ExFreePool(oldfn.Buffer);
1855  ExFreePool(newfn.Buffer);
1856 
1858  goto end;
1859  }
1860 
1861  // We move files by moving the existing fileref to the new directory, and
1862  // replacing it with a dummy fileref with the same original values, but marked as deleted.
1863 
1865 
1866  fr2 = create_fileref(Vcb);
1867 
1868  fr2->fcb = fileref->fcb;
1869  fr2->fcb->refcount++;
1870 
1871  fr2->oldutf8 = fileref->oldutf8;
1872  fr2->oldindex = fileref->dc->index;
1873  fr2->delete_on_close = fileref->delete_on_close;
1874  fr2->deleted = true;
1875  fr2->created = fileref->created;
1876  fr2->parent = fileref->parent;
1877  fr2->dc = NULL;
1878 
1879  if (!fr2->oldutf8.Buffer) {
1880  fr2->oldutf8.Buffer = ExAllocatePoolWithTag(PagedPool, fileref->dc->utf8.Length, ALLOC_TAG);
1881  if (!fr2->oldutf8.Buffer) {
1882  ERR("out of memory\n");
1884  goto end;
1885  }
1886 
1887  RtlCopyMemory(fr2->oldutf8.Buffer, fileref->dc->utf8.Buffer, fileref->dc->utf8.Length);
1888 
1889  fr2->oldutf8.Length = fr2->oldutf8.MaximumLength = fileref->dc->utf8.Length;
1890  }
1891 
1892  if (fr2->fcb->type == BTRFS_TYPE_DIRECTORY)
1893  fr2->fcb->fileref = fr2;
1894 
1896  fileref->fcb->subvol->parent = related->fcb->subvol->id;
1897 
1900  fileref->deleted = false;
1901  fileref->created = true;
1902  fileref->parent = related;
1903 
1904  ExAcquireResourceExclusiveLite(&fileref->parent->fcb->nonpaged->dir_children_lock, true);
1905  InsertHeadList(&fileref->list_entry, &fr2->list_entry);
1907  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
1908 
1909  mark_fileref_dirty(fr2);
1911 
1912  if (fileref->dc) {
1913  // remove from old parent
1914  ExAcquireResourceExclusiveLite(&fr2->parent->fcb->nonpaged->dir_children_lock, true);
1916  remove_dir_child_from_hash_lists(fr2->parent->fcb, fileref->dc);
1917  ExReleaseResourceLite(&fr2->parent->fcb->nonpaged->dir_children_lock);
1918 
1919  if (fileref->dc->utf8.Length != utf8.Length || RtlCompareMemory(fileref->dc->utf8.Buffer, utf8.Buffer, utf8.Length) != utf8.Length) {
1920  // handle changed name
1921 
1925 
1927  if (!fileref->dc->utf8.Buffer) {
1928  ERR("out of memory\n");
1930  goto end;
1931  }
1932 
1934  RtlCopyMemory(fileref->dc->utf8.Buffer, utf8.Buffer, utf8.Length);
1935 
1937  if (!fileref->dc->name.Buffer) {
1938  ERR("out of memory\n");
1940  goto end;
1941  }
1942 
1944  RtlCopyMemory(fileref->dc->name.Buffer, fnus.Buffer, fnus.Length);
1945 
1947  if (!NT_SUCCESS(Status)) {
1948  ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
1949  goto end;
1950  }
1951 
1954  }
1955 
1956  // add to new parent
1957  ExAcquireResourceExclusiveLite(&related->fcb->nonpaged->dir_children_lock, true);
1958 
1959  if (IsListEmpty(&related->fcb->dir_children_index))
1960  fileref->dc->index = 2;
1961  else {
1962  dir_child* dc2 = CONTAINING_RECORD(related->fcb->dir_children_index.Blink, dir_child, list_entry_index);
1963 
1964  fileref->dc->index = max(2, dc2->index + 1);
1965  }
1966 
1967  InsertTailList(&related->fcb->dir_children_index, &fileref->dc->list_entry_index);
1969  ExReleaseResourceLite(&related->fcb->nonpaged->dir_children_lock);
1970  }
1971 
1972  ExAcquireResourceExclusiveLite(&related->fcb->nonpaged->dir_children_lock, true);
1973  InsertTailList(&related->children, &fileref->list_entry);
1974  ExReleaseResourceLite(&related->fcb->nonpaged->dir_children_lock);
1975 
1976  if (fcb->inode_item.st_nlink > 1) {
1977  // add new hardlink entry to fcb
1978 
1980  if (!hl) {
1981  ERR("out of memory\n");
1983  goto end;
1984  }
1985 
1986  hl->parent = related->fcb->inode;
1987  hl->index = fileref->dc->index;
1988 
1989  hl->name.Length = hl->name.MaximumLength = fnus.Length;
1991 
1992  if (!hl->name.Buffer) {
1993  ERR("out of memory\n");
1994  ExFreePool(hl);
1996  goto end;
1997  }
1998 
1999  RtlCopyMemory(hl->name.Buffer, fnus.Buffer, fnus.Length);
2000 
2003 
2004  if (!hl->utf8.Buffer) {
2005  ERR("out of memory\n");
2006  ExFreePool(hl->name.Buffer);
2007  ExFreePool(hl);
2009  goto end;
2010  }
2011 
2013 
2015  }
2016 
2017  // delete old hardlink entry from fcb
2018 
2019  le = fcb->hardlinks.Flink;
2020  while (le != &fcb->hardlinks) {
2022 
2023  if (hl->parent == fr2->parent->fcb->inode && hl->index == fr2->oldindex) {
2025 
2026  if (hl->utf8.Buffer)
2027  ExFreePool(hl->utf8.Buffer);
2028 
2029  if (hl->name.Buffer)
2030  ExFreePool(hl->name.Buffer);
2031 
2032  ExFreePool(hl);
2033  break;
2034  }
2035 
2036  le = le->Flink;
2037  }
2038 
2039  // update inode's INODE_ITEM
2040 
2043 
2044  if (fcb != Vcb->dummy_fcb && (fileref->parent->fcb->subvol == fcb->subvol || !is_subvol_readonly(fcb->subvol, Irp))) {
2045  fcb->inode_item.transid = Vcb->superblock.generation;
2046  fcb->inode_item.sequence++;
2047 
2048  if (!ccb->user_set_change_time)
2050 
2051  fcb->inode_item_changed = true;
2053  }
2054 
2055  // update new parent's INODE_ITEM
2056 
2057  related->fcb->inode_item.transid = Vcb->superblock.generation;
2058  TRACE("related->fcb->inode_item.st_size (inode %I64x) was %I64x\n", related->fcb->inode, related->fcb->inode_item.st_size);
2059  related->fcb->inode_item.st_size += 2 * utf8len;
2060  TRACE("related->fcb->inode_item.st_size (inode %I64x) now %I64x\n", related->fcb->inode, related->fcb->inode_item.st_size);
2061  related->fcb->inode_item.sequence++;
2062  related->fcb->inode_item.st_ctime = now;
2063  related->fcb->inode_item.st_mtime = now;
2064 
2065  related->fcb->inode_item_changed = true;
2066  mark_fcb_dirty(related->fcb);
2067 
2068  // update old parent's INODE_ITEM
2069 
2070  fr2->parent->fcb->inode_item.transid = Vcb->superblock.generation;
2071  TRACE("fr2->parent->fcb->inode_item.st_size (inode %I64x) was %I64x\n", fr2->parent->fcb->inode, fr2->parent->fcb->inode_item.st_size);
2072  fr2->parent->fcb->inode_item.st_size -= 2 * origutf8len;
2073  TRACE("fr2->parent->fcb->inode_item.st_size (inode %I64x) now %I64x\n", fr2->parent->fcb->inode, fr2->parent->fcb->inode_item.st_size);
2074  fr2->parent->fcb->inode_item.sequence++;
2075  fr2->parent->fcb->inode_item.st_ctime = now;
2076  fr2->parent->fcb->inode_item.st_mtime = now;
2077 
2078  free_fileref(fr2);
2079 
2080  fr2->parent->fcb->inode_item_changed = true;
2081  mark_fcb_dirty(fr2->parent->fcb);
2082 
2086 
2088 
2089 end:
2090  if (oldfileref)
2091  free_fileref(oldfileref);
2092 
2093  if (!NT_SUCCESS(Status) && related)
2094  free_fileref(related);
2095 
2096  if (!NT_SUCCESS(Status) && fr2)
2097  free_fileref(fr2);
2098 
2099  if (NT_SUCCESS(Status))
2101  else
2103 
2104  ExReleaseResourceLite(fcb->Header.Resource);
2105  ExReleaseResourceLite(&Vcb->fileref_lock);
2106  ExReleaseResourceLite(&Vcb->tree_lock);
2107 
2108  return Status;
2109 }
2110 
2113  BTRFS_TIME now;
2114 
2115  TRACE("setting new end to %I64x bytes (currently %x)\n", end, fcb->adsdata.Length);
2116 
2117  if (!fileref || !fileref->parent) {
2118  ERR("no fileref for stream\n");
2119  return STATUS_INTERNAL_ERROR;
2120  }
2121 
2122  if (end < fcb->adsdata.Length) {
2123  if (advance_only)
2124  return STATUS_SUCCESS;
2125 
2126  TRACE("truncating stream to %I64x bytes\n", end);
2127 
2128  fcb->adsdata.Length = end;
2129  } else if (end > fcb->adsdata.Length) {
2130  TRACE("extending stream to %I64x bytes\n", end);
2131 
2132  if (end > fcb->adsmaxlen) {
2133  ERR("error - xattr too long (%u > %u)\n", end, fcb->adsmaxlen);
2134  return STATUS_DISK_FULL;
2135  }
2136 
2137  if (end > fcb->adsdata.MaximumLength) {
2139  if (!data) {
2140  ERR("out of memory\n");
2141  ExFreePool(data);
2143  }
2144 
2145  if (fcb->adsdata.Buffer) {
2148  }
2149 
2150  fcb->adsdata.Buffer = data;
2152  }
2153 
2155 
2156  fcb->adsdata.Length = end;
2157  }
2158 
2160 
2161  fcb->Header.AllocationSize.QuadPart = end;
2162  fcb->Header.FileSize.QuadPart = end;
2163  fcb->Header.ValidDataLength.QuadPart = end;
2164 
2167 
2168  fileref->parent->fcb->inode_item.transid = Vcb->superblock.generation;
2169  fileref->parent->fcb->inode_item.sequence++;
2170  fileref->parent->fcb->inode_item.st_ctime = now;
2171 
2172  fileref->parent->fcb->inode_item_changed = true;
2173  mark_fcb_dirty(fileref->parent->fcb);
2174 
2175  fileref->parent->fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
2176  fileref->parent->fcb->subvol->root_item.ctime = now;
2177 
2178  return STATUS_SUCCESS;
2179 }
2180 
2182  FILE_END_OF_FILE_INFORMATION* feofi = Irp->AssociatedIrp.SystemBuffer;
2183  fcb* fcb = FileObject->FsContext;
2184  ccb* ccb = FileObject->FsContext2;
2185  file_ref* fileref = ccb ? ccb->fileref : NULL;
2186  NTSTATUS Status;
2188  CC_FILE_SIZES ccfs;
2190  bool set_size = false;
2191  ULONG filter;
2192 
2193  if (!fileref) {
2194  ERR("fileref is NULL\n");
2195  return STATUS_INVALID_PARAMETER;
2196  }
2197 
2199 
2200  ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
2201 
2202  ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
2203 
2204  if (fileref ? fileref->deleted : fcb->deleted) {
2206  goto end;
2207  }
2208 
2209  if (fcb->ads) {
2210  if (feofi->EndOfFile.QuadPart > 0xffff) {
2212  goto end;
2213  }
2214 
2215  if (feofi->EndOfFile.QuadPart < 0) {
2217  goto end;
2218  }
2219 
2221 
2222  if (NT_SUCCESS(Status)) {
2223  ccfs.AllocationSize = fcb->Header.AllocationSize;
2224  ccfs.FileSize = fcb->Header.FileSize;
2225  ccfs.ValidDataLength = fcb->Header.ValidDataLength;
2226  set_size = true;
2227  }
2228 
2230 
2231  if (!ccb->user_set_write_time) {
2233  win_time_to_unix(time, &fileref->parent->fcb->inode_item.st_mtime);
2235 
2236  fileref->parent->fcb->inode_item_changed = true;
2237  mark_fcb_dirty(fileref->parent->fcb);
2238  }
2239 
2241 
2242  goto end;
2243  }
2244 
2245  TRACE("file: %S\n", file_desc(FileObject));
2246  TRACE("paging IO: %s\n", Irp->Flags & IRP_PAGING_IO ? "true" : "false");
2247  TRACE("FileObject: AllocationSize = %I64x, FileSize = %I64x, ValidDataLength = %I64x\n",
2248  fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart);
2249 
2250  TRACE("setting new end to %I64x bytes (currently %I64x)\n", feofi->EndOfFile.QuadPart, fcb->inode_item.st_size);
2251 
2252  if ((uint64_t)feofi->EndOfFile.QuadPart < fcb->inode_item.st_size) {
2253  if (advance_only) {
2255  goto end;
2256  }
2257 
2258  TRACE("truncating file to %I64x bytes\n", feofi->EndOfFile.QuadPart);
2259 
2260  if (!MmCanFileBeTruncated(&fcb->nonpaged->segment_object, &feofi->EndOfFile)) {
2262  goto end;
2263  }
2264 
2266  if (!NT_SUCCESS(Status)) {
2267  ERR("error - truncate_file failed\n");
2268  goto end;
2269  }
2270  } else if ((uint64_t)feofi->EndOfFile.QuadPart > fcb->inode_item.st_size) {
2271  if (Irp->Flags & IRP_PAGING_IO) {
2272  TRACE("paging IO tried to extend file size\n");
2274  goto end;
2275  }
2276 
2277  TRACE("extending file to %I64x bytes\n", feofi->EndOfFile.QuadPart);
2278 
2280  if (!NT_SUCCESS(Status)) {
2281  ERR("error - extend_file failed\n");
2282  goto end;
2283  }
2284  } else if ((uint64_t)feofi->EndOfFile.QuadPart == fcb->inode_item.st_size && advance_only) {
2286  goto end;
2287  }
2288 
2289  ccfs.AllocationSize = fcb->Header.AllocationSize;
2290  ccfs.FileSize = fcb->Header.FileSize;
2291  ccfs.ValidDataLength = fcb->Header.ValidDataLength;
2292  set_size = true;
2293 
2295 
2296  if (!ccb->user_set_write_time) {
2300  }
2301 
2302  fcb->inode_item_changed = true;
2305 
2307 
2308 end:
2309  if (NT_SUCCESS(Status))
2311  else
2313 
2314  ExReleaseResourceLite(fcb->Header.Resource);
2315 
2316  if (set_size) {
2317  _SEH2_TRY {
2318  CcSetFileSizes(FileObject, &ccfs);
2321  } _SEH2_END;
2322 
2323  if (!NT_SUCCESS(Status))
2324  ERR("CcSetFileSizes threw exception %08x\n", Status);
2325  }
2326 
2327  ExReleaseResourceLite(&Vcb->tree_lock);
2328 
2329  return Status;
2330 }
2331 
2333  FILE_POSITION_INFORMATION* fpi = (FILE_POSITION_INFORMATION*)Irp->AssociatedIrp.SystemBuffer;
2334 
2335  TRACE("setting the position on %S to %I64x\n", file_desc(FileObject), fpi->CurrentByteOffset.QuadPart);
2336 
2337  // FIXME - make sure aligned for FO_NO_INTERMEDIATE_BUFFERING
2338 
2339  FileObject->CurrentByteOffset = fpi->CurrentByteOffset;
2340 
2341  return STATUS_SUCCESS;
2342 }
2343 
2345  FILE_LINK_INFORMATION_EX* fli = Irp->AssociatedIrp.SystemBuffer;
2346  fcb *fcb = FileObject->FsContext, *tfofcb, *parfcb;
2347  ccb* ccb = FileObject->FsContext2;
2348  file_ref *fileref = ccb ? ccb->fileref : NULL, *oldfileref = NULL, *related = NULL, *fr2 = NULL;
2349  WCHAR* fn;
2350  ULONG fnlen, utf8len;
2351  UNICODE_STRING fnus;
2352  ANSI_STRING utf8;
2353  NTSTATUS Status;
2355  BTRFS_TIME now;
2357  hardlink* hl;
2359  SECURITY_SUBJECT_CONTEXT subjcont;
2360  dir_child* dc = NULL;
2361  ULONG flags;
2362 
2364 
2365  // FIXME - check fli length
2366  // FIXME - don't ignore fli->RootDirectory
2367 
2368  if (ex)
2369  flags = fli->Flags;
2370  else
2372 
2373  TRACE("flags = %x\n", flags);
2374  TRACE("RootDirectory = %p\n", fli->RootDirectory);
2375  TRACE("FileNameLength = %x\n", fli->FileNameLength);
2376  TRACE("FileName = %.*S\n", fli->FileNameLength / sizeof(WCHAR), fli->FileName);
2377 
2378  fn = fli->FileName;
2379  fnlen = fli->FileNameLength / sizeof(WCHAR);
2380 
2381  if (!tfo) {
2382  if (!fileref || !fileref->parent) {
2383  ERR("no fileref set and no directory given\n");
2384  return STATUS_INVALID_PARAMETER;
2385  }
2386 
2387  parfcb = fileref->parent->fcb;
2388  tfofcb = NULL;
2389  } else {
2390  LONG i;
2391 
2392  tfofcb = tfo->FsContext;
2393  parfcb = tfofcb;
2394 
2395  while (fnlen > 0 && (fli->FileName[fnlen - 1] == '/' || fli->FileName[fnlen - 1] == '\\'))
2396  fnlen--;
2397 
2398  if (fnlen == 0)
2399  return STATUS_INVALID_PARAMETER;
2400 
2401  for (i = fnlen - 1; i >= 0; i--) {
2402  if (fli->FileName[i] == '\\' || fli->FileName[i] == '/') {
2403  fn = &fli->FileName[i+1];
2404  fnlen = (fli->FileNameLength / sizeof(WCHAR)) - i - 1;
2405  break;
2406  }
2407  }
2408  }
2409 
2410  ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
2411  ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, true);
2412  ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
2413 
2414  if (fcb->type == BTRFS_TYPE_DIRECTORY) {
2415  WARN("tried to create hard link on directory\n");
2417  goto end;
2418  }
2419 
2420  if (fcb->ads) {
2421  WARN("tried to create hard link on stream\n");
2423  goto end;
2424  }
2425 
2426  if (fcb->inode_item.st_nlink >= 65535) {
2428  goto end;
2429  }
2430 
2431  fnus.Buffer = fn;
2432  fnus.Length = fnus.MaximumLength = (uint16_t)(fnlen * sizeof(WCHAR));
2433 
2434  TRACE("fnus = %.*S\n", fnus.Length / sizeof(WCHAR), fnus.Buffer);
2435 
2436  Status = utf16_to_utf8(NULL, 0, &utf8len, fn, (ULONG)fnlen * sizeof(WCHAR));
2437  if (!NT_SUCCESS(Status))
2438  goto end;
2439 
2440  utf8.MaximumLength = utf8.Length = (uint16_t)utf8len;
2442  if (!utf8.Buffer) {
2443  ERR("out of memory\n");
2445  goto end;
2446  }
2447 
2448  Status = utf16_to_utf8(utf8.Buffer, utf8len, &utf8len, fn, (ULONG)fnlen * sizeof(WCHAR));
2449  if (!NT_SUCCESS(Status))
2450  goto end;
2451 
2452  if (tfo && tfo->FsContext2) {
2453  struct _ccb* relatedccb = tfo->FsContext2;
2454 
2455  related = relatedccb->fileref;
2456  increase_fileref_refcount(related);
2457  }
2458 
2459  Status = open_fileref(Vcb, &oldfileref, &fnus, related, false, NULL, NULL, PagedPool, ccb->case_sensitive, Irp);
2460 
2461  if (NT_SUCCESS(Status)) {
2462  if (!oldfileref->deleted) {
2463  WARN("destination file %S already exists\n", file_desc_fileref(oldfileref));
2464 
2467  goto end;
2468  } else if (fileref == oldfileref) {
2470  goto end;
2471  } else if (!(flags & FILE_LINK_POSIX_SEMANTICS) && (oldfileref->open_count > 0 || has_open_children(oldfileref)) && !oldfileref->deleted) {
2472  WARN("trying to overwrite open file\n");
2474  goto end;
2475  } else if (!(flags & FILE_LINK_IGNORE_READONLY_ATTRIBUTE) && oldfileref->fcb->atts & FILE_ATTRIBUTE_READONLY) {
2476  WARN("trying to overwrite readonly file\n");
2478  goto end;
2479  } else if (oldfileref->fcb->type == BTRFS_TYPE_DIRECTORY) {
2480  WARN("trying to overwrite directory\n");
2482  goto end;
2483  }
2484  } else {
2485  free_fileref(oldfileref);
2486  oldfileref = NULL;
2487  }
2488  }
2489 
2490  if (!related) {
2491  Status = open_fileref(Vcb, &related, &fnus, NULL, true, NULL, NULL, PagedPool, ccb->case_sensitive, Irp);
2492 
2493  if (!NT_SUCCESS(Status)) {
2494  ERR("open_fileref returned %08x\n", Status);
2495  goto end;
2496  }
2497  }
2498 
2499  SeCaptureSubjectContext(&subjcont);
2500 
2501  if (!SeAccessCheck(related->fcb->sd, &subjcont, false, FILE_ADD_FILE, 0, NULL,
2502  IoGetFileObjectGenericMapping(), Irp->RequestorMode, &access, &Status)) {
2503  SeReleaseSubjectContext(&subjcont);
2504  TRACE("SeAccessCheck failed, returning %08x\n", Status);
2505  goto end;
2506  }
2507 
2508  SeReleaseSubjectContext(&subjcont);
2509 
2510  if (fcb->subvol != parfcb->subvol) {
2511  WARN("can't create hard link over subvolume boundary\n");
2513  goto end;
2514  }
2515 
2516  if (oldfileref) {
2517  SeCaptureSubjectContext(&subjcont);
2518 
2519  if (!SeAccessCheck(oldfileref->fcb->sd, &subjcont, false, DELETE, 0, NULL,
2520  IoGetFileObjectGenericMapping(), Irp->RequestorMode, &access, &Status)) {
2521  SeReleaseSubjectContext(&subjcont);
2522  TRACE("SeAccessCheck failed, returning %08x\n", Status);
2523  goto end;
2524  }
2525 
2526  SeReleaseSubjectContext(&subjcont);
2527 
2528  if (oldfileref->open_count > 0 && flags & FILE_RENAME_POSIX_SEMANTICS) {
2529  oldfileref->delete_on_close = true;
2530  oldfileref->posix_delete = true;
2531  }
2532 
2533  Status = delete_fileref(oldfileref, NULL, oldfileref->open_count > 0 && flags & FILE_RENAME_POSIX_SEMANTICS, Irp, &rollback);
2534  if (!NT_SUCCESS(Status)) {
2535  ERR("delete_fileref returned %08x\n", Status);
2536  goto end;
2537  }
2538  }
2539 
2540  fr2 = create_fileref(Vcb);
2541 
2542  fr2->fcb = fcb;
2543  fcb->refcount++;
2544 
2545  fr2->created = true;
2546  fr2->parent = related;
2547 
2548  Status = add_dir_child(related->fcb, fcb->inode, false, &utf8, &fnus, fcb->type, &dc);
2549  if (!NT_SUCCESS(Status))
2550  WARN("add_dir_child returned %08x\n", Status);
2551 
2552  fr2->dc = dc;
2553  dc->fileref = fr2;
2554 
2555  ExAcquireResourceExclusiveLite(&related->fcb->nonpaged->dir_children_lock, true);
2556  InsertTailList(&related->children, &fr2->list_entry);
2557  ExReleaseResourceLite(&related->fcb->nonpaged->dir_children_lock);
2558 
2559  // add hardlink for existing fileref, if it's not there already
2560  if (IsListEmpty(&fcb->hardlinks)) {
2562  if (!hl) {
2563  ERR("out of memory\n");
2565  goto end;
2566  }
2567 
2568  hl->parent = fileref->parent->fcb->inode;
2569  hl->index = fileref->dc->index;
2570 
2571  hl->name.Length = hl->name.MaximumLength = fnus.Length;
2573 
2574  if (!hl->name.Buffer) {
2575  ERR("out of memory\n");
2576  ExFreePool(hl);
2578  goto end;
2579  }
2580 
2581  RtlCopyMemory(hl->name.Buffer, fnus.Buffer, fnus.Length);
2582 
2585 
2586  if (!hl->utf8.Buffer) {
2587  ERR("out of memory\n");
2588  ExFreePool(hl->name.Buffer);
2589  ExFreePool(hl);
2591  goto end;
2592  }
2593 
2595 
2597  }
2598 
2600  if (!hl) {
2601  ERR("out of memory\n");
2603  goto end;
2604  }
2605 
2606  hl->parent = related->fcb->inode;
2607  hl->index = dc->index;
2608 
2609  hl->name.Length = hl->name.MaximumLength = fnus.Length;
2611 
2612  if (!hl->name.Buffer) {
2613  ERR("out of memory\n");
2614  ExFreePool(hl);
2616  goto end;
2617  }
2618 
2619  RtlCopyMemory(hl->name.Buffer, fnus.Buffer, fnus.Length);
2620 
2621  hl->utf8.Length = hl->utf8.MaximumLength = utf8.Length;
2623 
2624  if (!hl->utf8.Buffer) {
2625  ERR("out of memory\n");
2626  ExFreePool(hl->name.Buffer);
2627  ExFreePool(hl);
2629  goto end;
2630  }
2631 
2632  RtlCopyMemory(hl->utf8.Buffer, utf8.Buffer, utf8.Length);
2633  ExFreePool(utf8.Buffer);
2634 
2636 
2637  mark_fileref_dirty(fr2);
2638  free_fileref(fr2);
2639 
2640  // update inode's INODE_ITEM
2641 
2644 
2645  fcb->inode_item.transid = Vcb->superblock.generation;
2646  fcb->inode_item.sequence++;
2647  fcb->inode_item.st_nlink++;
2648 
2649  if (!ccb->user_set_change_time)
2651 
2652  fcb->inode_item_changed = true;
2654 
2655  // update parent's INODE_ITEM
2656 
2657  parfcb->inode_item.transid = Vcb->superblock.generation;
2658  TRACE("parfcb->inode_item.st_size (inode %I64x) was %I64x\n", parfcb->inode, parfcb->inode_item.st_size);
2659  parfcb->inode_item.st_size += 2 * utf8len;
2660  TRACE("parfcb->inode_item.st_size (inode %I64x) now %I64x\n", parfcb->inode, parfcb->inode_item.st_size);
2661  parfcb->inode_item.sequence++;
2662  parfcb->inode_item.st_ctime = now;
2663 
2664  parfcb->inode_item_changed = true;
2665  mark_fcb_dirty(parfcb);
2666 
2668 
2670 
2671 end:
2672  if (oldfileref)
2673  free_fileref(oldfileref);
2674 
2675  if (!NT_SUCCESS(Status) && related)
2676  free_fileref(related);
2677 
2678  if (!NT_SUCCESS(Status) && fr2)
2679  free_fileref(fr2);
2680 
2681  if (NT_SUCCESS(Status))
2683  else
2685 
2686  ExReleaseResourceLite(fcb->Header.Resource);
2687  ExReleaseResourceLite(&Vcb->fileref_lock);
2688  ExReleaseResourceLite(&Vcb->tree_lock);
2689 
2690  return Status;
2691 }
2692 
2694  FILE_VALID_DATA_LENGTH_INFORMATION* fvdli = Irp->AssociatedIrp.SystemBuffer;
2696  fcb* fcb = FileObject->FsContext;
2697  ccb* ccb = FileObject->FsContext2;
2698  file_ref* fileref = ccb ? ccb->fileref : NULL;
2699  NTSTATUS Status;
2701  CC_FILE_SIZES ccfs;
2703  bool set_size = false;
2704  ULONG filter;
2705 
2706  if (IrpSp->Parameters.SetFile.Length < sizeof(FILE_VALID_DATA_LENGTH_INFORMATION)) {
2707  ERR("input buffer length was %u, expected %u\n", IrpSp->Parameters.SetFile.Length, sizeof(FILE_VALID_DATA_LENGTH_INFORMATION));
2708  return STATUS_INVALID_PARAMETER;
2709  }
2710 
2711  if (!fileref) {
2712  ERR("fileref is NULL\n");
2713  return STATUS_INVALID_PARAMETER;
2714  }
2715 
2717 
2718  ExAcquireResourceSharedLite(&Vcb->tree_lock, true);
2719 
2720  ExAcquireResourceExclusiveLite(fcb->Header.Resource, true);
2721 
2724  goto end;
2725  }
2726 
2727  if (fvdli->ValidDataLength.QuadPart <= fcb->Header.ValidDataLength.QuadPart || fvdli->ValidDataLength.QuadPart > fcb->Header.FileSize.QuadPart) {
2728  TRACE("invalid VDL of %I64u (current VDL = %I64u, file size = %I64u)\n", fvdli->ValidDataLength.QuadPart,
2729  fcb->Header.ValidDataLength.QuadPart, fcb->Header.FileSize.QuadPart);
2731  goto end;
2732  }
2733 
2734  if (fileref ? fileref->deleted : fcb->deleted) {
2736  goto end;
2737  }
2738 
2739  // This function doesn't really do anything - the fsctl can only increase the value of ValidDataLength,
2740  // and we set it to the max anyway.
2741 
2742  ccfs.AllocationSize = fcb->Header.AllocationSize;
2743  ccfs.FileSize = fcb->Header.FileSize;
2744  ccfs.ValidDataLength = fvdli->ValidDataLength;
2745  set_size = true;
2746 
2748 
2749  if (!ccb->user_set_write_time) {
2753  }
2754 
2755  fcb->inode_item_changed = true;
2757 
2759 
2761 
2762 end:
2763  if (NT_SUCCESS(Status))
2765  else
2767 
2768  ExReleaseResourceLite(fcb->Header.Resource);
2769 
2770  if (set_size) {
2771  _SEH2_TRY {
2772  CcSetFileSizes(FileObject, &ccfs);
2775  } _SEH2_END;
2776 
2777  if (!NT_SUCCESS(Status))
2778  ERR("CcSetFileSizes threw exception %08x\n", Status);
2779  else
2780  fcb->Header.AllocationSize = ccfs.AllocationSize;
2781  }
2782 
2783  ExReleaseResourceLite(&Vcb->tree_lock);
2784 
2785  return Status;
2786 }
2787 
2788 #ifndef __REACTOS__
2790  FILE_CASE_SENSITIVE_INFORMATION* fcsi = (FILE_CASE_SENSITIVE_INFORMATION*)Irp->AssociatedIrp.SystemBuffer;
2792 
2793  if (IrpSp->Parameters.FileSystemControl.InputBufferLength < sizeof(FILE_CASE_SENSITIVE_INFORMATION))
2795 
2797 
2798  if (!FileObject)
2799  return STATUS_INVALID_PARAMETER;
2800 
2801  fcb* fcb = FileObject->FsContext;
2802 
2803  if (!fcb)
2804  return STATUS_INVALID_PARAMETER;
2805 
2806  if (!(fcb->atts & FILE_ATTRIBUTE_DIRECTORY)) {
2807  WARN("cannot set case-sensitive flag on anything other than directory\n");
2808  return STATUS_INVALID_PARAMETER;
2809  }
2810 
2811  ExAcquireResourceSharedLite(&fcb->Vcb->tree_lock, true);
2812 
2815 
2816  ExReleaseResourceLite(&fcb->Vcb->tree_lock);
2817 
2818  return STATUS_SUCCESS;
2819 }
2820 #endif
2821 
2824 NTSTATUS __stdcall drv_set_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
2825  NTSTATUS Status;
2828  fcb* fcb = IrpSp->FileObject->FsContext;
2829  ccb* ccb = IrpSp->FileObject->FsContext2;
2830  bool top_level;
2831 
2833 
2834  top_level = is_top_level(Irp);
2835 
2836  Irp->IoStatus.Information = 0;
2837 
2838  if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
2840  goto end;
2841  } else if (!Vcb || Vcb->type != VCB_TYPE_FS) {
2843  goto end;
2844  }
2845 
2846  if (!(Vcb->Vpb->Flags & VPB_MOUNTED)) {
2848  goto end;
2849  }
2850 
2851  if (Vcb->readonly && IrpSp->Parameters.SetFile.FileInformationClass != FilePositionInformation) {
2853  goto end;
2854  }
2855 
2856  if (!fcb) {
2857  ERR("no fcb\n");
2859  goto end;
2860  }
2861 
2862  if (!ccb) {
2863  ERR("no ccb\n");
2865  goto end;
2866  }
2867 
2868  if (fcb != Vcb->dummy_fcb && is_subvol_readonly(fcb->subvol, Irp) && IrpSp->Parameters.SetFile.FileInformationClass != FilePositionInformation &&
2869 #ifndef __REACTOS__
2870  (fcb->inode != SUBVOL_ROOT_INODE || (IrpSp->Parameters.SetFile.FileInformationClass != FileBasicInformation && IrpSp->Parameters.SetFile.FileInformationClass != FileRenameInformation && IrpSp->Parameters.SetFile.FileInformationClass != FileRenameInformationEx))) {
2871 #else
2872  (fcb->inode != SUBVOL_ROOT_INODE || (IrpSp->Parameters.SetFile.FileInformationClass != FileBasicInformation && IrpSp->Parameters.SetFile.FileInformationClass != FileRenameInformation))) {
2873 #endif
2875  goto end;
2876  }
2877 
2879 
2880  TRACE("set information\n");
2881 
2882  switch (IrpSp->Parameters.SetFile.FileInformationClass) {
2884  {
2885  TRACE("FileAllocationInformation\n");
2886 
2887  if (Irp->RequestorMode == UserMode && !(ccb->access & FILE_WRITE_DATA)) {
2888  WARN("insufficient privileges\n");
2890  break;
2891  }
2892 
2894  break;
2895  }
2896 
2897  case FileBasicInformation:
2898  {
2899  TRACE("FileBasicInformation\n");
2900 
2901  if (Irp->RequestorMode == UserMode && !(ccb->access & FILE_WRITE_ATTRIBUTES)) {
2902  WARN("insufficient privileges\n");
2904  break;
2905  }
2906 
2908 
2909  break;
2910  }
2911 
2913  {
2914  TRACE("FileDispositionInformation\n");
2915 
2916  if (Irp->RequestorMode == UserMode && !(ccb->access & DELETE)) {
2917  WARN("insufficient privileges\n");
2919  break;
2920  }
2921 
2923 
2924  break;
2925  }
2926 
2928  {
2929  TRACE("FileEndOfFileInformation\n");
2930 
2931  if (Irp->RequestorMode == UserMode && !(ccb->access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) {
2932  WARN("insufficient privileges\n");
2934  break;
2935  }
2936 
2937  Status = set_end_of_file_information(Vcb, Irp, IrpSp->FileObject, IrpSp->Parameters.SetFile.AdvanceOnly, false);
2938 
2939  break;
2940  }
2941 
2942  case FileLinkInformation:
2943  TRACE("FileLinkInformation\n");
2944  Status = set_link_information(Vcb, Irp, IrpSp->FileObject, IrpSp->Parameters.SetFile.FileObject, false);
2945  break;
2946 
2948  TRACE("FilePositionInformation\n");
2950  break;
2951 
2952  case FileRenameInformation:
2953  TRACE("FileRenameInformation\n");
2954  // FIXME - make this work with streams
2955  Status = set_rename_information(Vcb, Irp, IrpSp->FileObject, IrpSp->Parameters.SetFile.FileObject, false);
2956  break;
2957 
2959  {
2960  TRACE("FileValidDataLengthInformation\n");
2961 
2962  if (Irp->RequestorMode == UserMode && !(ccb->access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) {
2963  WARN("insufficient privileges\n");
2965  break;
2966  }
2967 
2969 
2970  break;
2971  }
2972 
2973 #ifndef __REACTOS__
2974 #ifndef _MSC_VER
2975 #pragma GCC diagnostic push
2976 #pragma GCC diagnostic ignored "-Wswitch"
2977 #endif
2979  {
2980  TRACE("FileDispositionInformationEx\n");
2981 
2982  if (Irp->RequestorMode == UserMode && !(ccb->access & DELETE)) {
2983  WARN("insufficient privileges\n");
2985  break;
2986  }
2987 
2989 
2990  break;
2991  }
2992 
2994  TRACE("FileRenameInformationEx\n");
2995  Status = set_rename_information(Vcb, Irp, IrpSp->FileObject, IrpSp->Parameters.SetFile.FileObject, true);
2996  break;
2997 
2998  case FileLinkInformationEx:
2999  TRACE("FileLinkInformationEx\n");
3000  Status = set_link_information(Vcb, Irp, IrpSp->FileObject, IrpSp->Parameters.SetFile.FileObject, true);
3001  break;
3002 
3004  TRACE("FileCaseSensitiveInformation\n");
3005 
3006  if (Irp->RequestorMode == UserMode && !(ccb->access & FILE_WRITE_ATTRIBUTES)) {
3007  WARN("insufficient privileges\n");
3009  break;
3010  }
3011 
3013  break;
3014 #ifndef _MSC_VER
3015 #pragma GCC diagnostic pop
3016 #endif
3017 #endif
3018 
3019  default:
3020  WARN("unknown FileInformationClass %u\n", IrpSp->Parameters.SetFile.FileInformationClass);
3021  }
3022 
3023 end:
3024  Irp->IoStatus.Status = Status;
3025 
3026  TRACE("returning %08x\n", Status);
3027 
3029 
3030  if (top_level)
3032 
3034 
3035  return Status;
3036 }
3037 
3039  RtlZeroMemory(fbi, sizeof(FILE_BASIC_INFORMATION));
3040 
3041  *length -= sizeof(FILE_BASIC_INFORMATION);
3042 
3043  if (fcb == fcb->Vcb->dummy_fcb) {
3045 
3047  fbi->CreationTime = fbi->LastAccessTime = fbi->LastWriteTime = fbi->ChangeTime = time;
3048  } else {
3053  }
3054 
3055  if (fcb->ads) {
3056  if (!fileref || !fileref->parent) {
3057  ERR("no fileref for stream\n");
3058  return STATUS_INTERNAL_ERROR;
3059  } else
3060  fbi->FileAttributes = fileref->parent->fcb->atts == 0 ? FILE_ATTRIBUTE_NORMAL : fileref->parent->fcb->atts;
3061  } else
3063 
3064  return STATUS_SUCCESS;
3065 }
3066 
3068  INODE_ITEM* ii;
3069 
3070  if (*length < (LONG)sizeof(FILE_NETWORK_OPEN_INFORMATION)) {
3071  WARN("overflow\n");
3072  return STATUS_BUFFER_OVERFLOW;
3073  }
3074 
3076 
3078 
3079  if (fcb->ads) {
3080  if (!fileref || !fileref->parent) {
3081  ERR("no fileref for stream\n");
3082  return STATUS_INTERNAL_ERROR;
3083  }
3084 
3085  ii = &fileref->parent->fcb->inode_item;
3086  } else
3087  ii = &fcb->inode_item;
3088 
3089  if (fcb == fcb->Vcb->dummy_fcb) {
3091 
3093  fnoi->CreationTime = fnoi->LastAccessTime = fnoi->LastWriteTime = fnoi->ChangeTime = time;
3094  } else {
3099  }
3100 
3101  if (fcb->ads) {
3103  fnoi->FileAttributes = fileref->parent->fcb->atts == 0 ? FILE_ATTRIBUTE_NORMAL : fileref->parent->fcb->atts;
3104  } else {
3107  fnoi->FileAttributes = fcb->atts == 0 ? FILE_ATTRIBUTE_NORMAL : fcb->atts;
3108  }
3109 
3110  return STATUS_SUCCESS;
3111 }
3112 
3115 
3116  *length -= sizeof(FILE_STANDARD_INFORMATION);
3117 
3118  if (fcb->ads) {
3119  if (!fileref || !fileref->parent) {
3120  ERR("no fileref for stream\n");
3121  return STATUS_INTERNAL_ERROR;
3122  }
3123 
3125  fsi->NumberOfLinks = fileref->parent->fcb->inode_item.st_nlink;
3126  fsi->Directory = false;
3127  } else {
3132  }
3133 
3134  TRACE("length = %I64u\n", fsi->EndOfFile.QuadPart);
3135 
3136  fsi->DeletePending = fileref ? fileref->delete_on_close : false;
3137 
3138  return STATUS_SUCCESS;
3139 }
3140 
3142  *length -= sizeof(FILE_INTERNAL_INFORMATION);
3143 
3145 
3146  return STATUS_SUCCESS;
3147 }
3148 
3150  *length -= sizeof(FILE_EA_INFORMATION);
3151 
3152  /* This value appears to be the size of the structure NTFS stores on disk, and not,
3153  * as might be expected, the size of FILE_FULL_EA_INFORMATION (which is what we store).
3154  * The formula is 4 bytes as a header, followed by 5 + NameLength + ValueLength for each
3155  * item. */
3156 
3157  eai->EaSize = fcb->ealen;
3158 
3159  return STATUS_SUCCESS;
3160 }
3161 
3164 
3165  *length -= sizeof(FILE_POSITION_INFORMATION);
3166 
3167  fpi->CurrentByteOffset = FileObject->CurrentByteOffset;
3168 
3169  return STATUS_SUCCESS;
3170 }
3171 
3173  file_ref* fr;
3174  NTSTATUS Status;
3175  ULONG reqlen = 0;
3176  USHORT offset;
3177  bool overflow = false;
3178 
3179  // FIXME - we need a lock on filerefs' filepart
3180 
3181  if (fileref == fileref->fcb->Vcb->root_fileref) {
3182  if (fn->MaximumLength >= sizeof(WCHAR)) {
3183  fn->Buffer[0] = '\\';
3184  fn->Length = sizeof(WCHAR);
3185 
3186  if (name_offset)
3187  *name_offset = 0;
3188 
3189  return STATUS_SUCCESS;
3190  } else {
3191  if (preqlen)
3192  *preqlen = sizeof(WCHAR);
3193  fn->Length = 0;
3194 
3195  return STATUS_BUFFER_OVERFLOW;
3196  }
3197  }
3198 
3199  fr = fileref;
3200  offset = 0;
3201 
3202  while (fr->parent) {
3203  USHORT movelen;
3204 
3205  if (!fr->dc)
3206  return STATUS_INTERNAL_ERROR;
3207 
3208  if (!overflow) {
3209  if (fr->dc->name.Length + sizeof(WCHAR) + fn->Length > fn->MaximumLength)
3210  overflow = true;
3211  }
3212 
3213  if (overflow)
3214  movelen = fn->MaximumLength - fr->dc->name.Length - sizeof(WCHAR);
3215  else
3216  movelen = fn->Length;
3217 
3218  if ((!overflow || fn->MaximumLength > fr->dc->name.Length + sizeof(WCHAR)) && movelen > 0) {
3219  RtlMoveMemory(&fn->Buffer[(fr->dc->name.Length / sizeof(WCHAR)) + 1], fn->Buffer, movelen);
3220  offset += fr->dc->name.Length + sizeof(WCHAR);
3221  }
3222 
3223  if (fn->MaximumLength >= sizeof(WCHAR)) {
3224  fn->Buffer[0] = fr->fcb->ads ? ':' : '\\';
3225  fn->Length += sizeof(WCHAR);
3226 
3227  if (fn->MaximumLength > sizeof(WCHAR)) {
3228  RtlCopyMemory(&fn->Buffer[1], fr->dc->name.Buffer, min(fr->dc->name.Length, fn->MaximumLength - sizeof(WCHAR)));
3229  fn->Length += fr->dc->name.Length;
3230  }
3231 
3232  if (fn->Length > fn->MaximumLength) {
3233  fn->Length = fn->MaximumLength;
3234  overflow = true;
3235  }
3236  }
3237 
3238  reqlen += sizeof(WCHAR) + fr->dc->name.Length;
3239 
3240  fr = fr->parent;
3241  }
3242 
3243  offset += sizeof(WCHAR);
3244 
3245  if (overflow) {
3246  if (preqlen)
3247  *preqlen = reqlen;
3249  } else {
3250  if (name_offset)
3251  *name_offset = offset;
3252 
3254  }
3255 
3256  return Status;
3257 }
3258 
3260  ULONG reqlen;
3262  NTSTATUS Status;
3263  static const WCHAR datasuf[] = {':','$','D','A','T','A',0};
3264  uint16_t datasuflen = sizeof(datasuf) - sizeof(WCHAR);
3265 
3266  if (!fileref) {
3267  ERR("called without fileref\n");
3268  return STATUS_INVALID_PARAMETER;
3269  }
3270 
3272 
3273  TRACE("maximum length is %u\n", *length);
3274  fni->FileNameLength = 0;
3275 
3276  fni->FileName[0] = 0;
3277 
3278  fn.Buffer = fni->FileName;
3279  fn.Length = 0;
3280  fn.MaximumLength = (uint16_t)*length;
3281 
3282  Status = fileref_get_filename(fileref, &fn, NULL, &reqlen);
3284  ERR("fileref_get_filename returned %08x\n", Status);
3285  return Status;
3286  }
3287 
3288  if (fcb->ads) {
3290  reqlen += datasuflen;
3291  else {
3292  if (fn.Length + datasuflen > fn.MaximumLength) {
3293  RtlCopyMemory(&fn.Buffer[fn.Length / sizeof(WCHAR)], datasuf, fn.MaximumLength - fn.Length);
3294  reqlen += datasuflen;
3296  } else {
3297  RtlCopyMemory(&fn.Buffer[fn.Length / sizeof(WCHAR)], datasuf, datasuflen);
3298  fn.Length += datasuflen;
3299  }
3300  }
3301  }
3302 
3303  if (Status == STATUS_BUFFER_OVERFLOW) {
3304  *length = -1;
3305  fni->FileNameLength = reqlen;
3306  TRACE("%.*S (truncated)\n", fn.Length / sizeof(WCHAR), fn.Buffer);
3307  } else {
3308  *length -= fn.Length;
3309  fni->FileNameLength = fn.Length;
3310  TRACE("%.*S\n", fn.Length / sizeof(WCHAR), fn.Buffer);
3311  }
3312 
3313  return Status;
3314 }
3315 
3318 
3319  if (fcb->ads) {
3320  if (!ccb->fileref || !ccb->fileref->parent) {
3321  ERR("no fileref for stream\n");
3322  return STATUS_INTERNAL_ERROR;
3323  }
3324 
3325  ati->FileAttributes = ccb->fileref->parent->fcb->atts;
3326  } else
3327  ati->FileAttributes = fcb->atts;
3328 
3330  ati->ReparseTag = 0;
3331  else
3333 
3334  return STATUS_SUCCESS;
3335 }
3336 
3338  LONG reqsize;
3339  LIST_ENTRY* le;
3340  FILE_STREAM_INFORMATION *entry, *lastentry;
3341  NTSTATUS Status;
3342 
3343  static const WCHAR datasuf[] = L":$DATA";
3344  UNICODE_STRING suf;
3345 
3346  if (!fileref) {
3347  ERR("fileref was NULL\n");
3348  return STATUS_INVALID_PARAMETER;
3349  }
3350 
3351  suf.Buffer = (WCHAR*)datasuf;
3352  suf.Length = suf.MaximumLength = sizeof(datasuf) - sizeof(WCHAR);
3353 
3355  reqsize = sizeof(FILE_STREAM_INFORMATION) - sizeof(WCHAR) + suf.Length + sizeof(WCHAR);
3356  else
3357  reqsize = 0;
3358 
3359  ExAcquireResourceSharedLite(&fileref->fcb->nonpaged->dir_children_lock, true);
3360 
3362  while (le != &fileref->fcb->dir_children_index) {
3363  dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index);
3364 
3365  if (dc->index == 0) {
3366  reqsize = (ULONG)sector_align(reqsize, sizeof(LONGLONG));
3367  reqsize += sizeof(FILE_STREAM_INFORMATION) - sizeof(WCHAR) + suf.Length + sizeof(WCHAR) + dc->name.Length;
3368  } else
3369  break;
3370 
3371  le = le->Flink;
3372  }
3373 
3374  TRACE("length = %i, reqsize = %u\n", *length, reqsize);
3375 
3376  if (reqsize > *length) {
3378  goto end;
3379  }
3380 
3381  entry = fsi;
3382  lastentry = NULL;
3383 
3384  if (fileref->fcb->type != BTRFS_TYPE_DIRECTORY) {
3385  ULONG off;
3386 
3387  entry->NextEntryOffset = 0;
3388  entry->StreamNameLength = suf.Length + sizeof(WCHAR);
3389  entry->StreamSize.QuadPart = fileref->fcb->inode_item.st_size;
3390  entry->StreamAllocationSize.QuadPart = fcb_alloc_size(fileref->fcb);
3391 
3392  entry->StreamName[0] = ':';
3393  RtlCopyMemory(&entry->StreamName[1], suf.Buffer, suf.Length);
3394 
3395  off = (ULONG)sector_align(sizeof(FILE_STREAM_INFORMATION) - sizeof(WCHAR) + suf.Length + sizeof(WCHAR), sizeof(LONGLONG));
3396 
3397  lastentry = entry;
3399  }
3400 
3402  while (le != &fileref->fcb->dir_children_index) {
3403  dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index);
3404 
3405  if (dc->index == 0) {
3406  ULONG off;
3407 
3408  entry->NextEntryOffset = 0;
3409  entry->StreamNameLength = dc->name.Length + suf.Length + sizeof(WCHAR);
3410 
3411  if (dc->fileref)
3412  entry->StreamSize.QuadPart = dc->fileref->fcb->adsdata.Length;
3413  else
3414  entry->StreamSize.QuadPart = dc->size;
3415 
3416  entry->StreamAllocationSize.QuadPart = entry->StreamSize.QuadPart;
3417 
3418  entry->StreamName[0] = ':';
3419 
3420  RtlCopyMemory(&entry->StreamName[1], dc->name.Buffer, dc->name.Length);
3421  RtlCopyMemory(&entry->StreamName[1 + (dc->name.Length / sizeof(WCHAR))], suf.Buffer, suf.Length);
3422 
3423  if (lastentry)
3424  lastentry->NextEntryOffset = (uint32_t)((uint8_t*)entry - (uint8_t*)lastentry);
3425 
3426  off = (ULONG)sector_align(sizeof(FILE_STREAM_INFORMATION) - sizeof(WCHAR) + suf.Length + sizeof(WCHAR) + dc->name.Length, sizeof(LONGLONG));
3427 
3428  lastentry = entry;
3430  } else
3431  break;
3432 
3433  le = le->Flink;
3434  }
3435 
3436  *length -= reqsize;
3437 
3439 
3440 end:
3441  ExReleaseResourceLite(&fileref->fcb->nonpaged->dir_children_lock);
3442 
3443  return Status;
3444 }
3445 
3446 #ifndef __REACTOS__
3448  TRACE("FileStandardLinkInformation\n");
3449 
3450  // FIXME - NumberOfAccessibleLinks should subtract open links which have been marked as delete_on_close
3451 
3454  fsli->DeletePending = fileref ? fileref->delete_on_close : false;
3455  fsli->Directory = (!fcb->ads && fcb->type == BTRFS_TYPE_DIRECTORY) ? true : false;
3456 
3458 
3459  return STATUS_SUCCESS;
3460 }
3461 
3463  NTSTATUS Status;
3464  LIST_ENTRY* le;
3465  LONG bytes_needed;
3467  bool overflow = false;
3468  fcb* fcb = fileref->fcb;
3469  ULONG len;
3470 
3471  if (fcb->ads)
3472  return STATUS_INVALID_PARAMETER;
3473 
3475  return STATUS_INVALID_PARAMETER;
3476 
3477  RtlZeroMemory(fli, *length);
3478 
3479  bytes_needed = offsetof(FILE_LINKS_INFORMATION, Entry);
3480  len = bytes_needed;
3481  feli = NULL;
3482 
3483  ExAcquireResourceSharedLite(fcb->Header.Resource, true);
3484 
3485  if (fcb->inode == SUBVOL_ROOT_INODE) {
3486  ULONG namelen;
3487 
3488  if (fcb == fcb->Vcb->root_fileref->fcb)
3489  namelen = sizeof(WCHAR);
3490  else
3492 
3493  bytes_needed += sizeof(FILE_LINK_ENTRY_INFORMATION) - sizeof(WCHAR) + namelen;
3494 
3495  if (bytes_needed > *length)
3496  overflow = true;
3497 
3498  if (!overflow) {
3499  feli = &fli->Entry;
3500 
3501  feli->NextEntryOffset = 0;
3502  feli->ParentFileId = 0; // we use an inode of 0 to mean the parent of a subvolume
3503 
3504  if (fcb == fcb->Vcb->root_fileref->fcb) {
3505  feli->FileNameLength = 1;
3506  feli->FileName[0] = '.';
3507  } else {
3508  feli->FileNameLength = fileref->dc->name.Length / sizeof(WCHAR);
3510  }
3511 
3512  fli->EntriesReturned++;
3513 
3514  len = bytes_needed;
3515  }
3516  } else {
3517  ExAcquireResourceExclusiveLite(&fcb->Vcb->fileref_lock, true);
3518 
3519  if (IsListEmpty(&fcb->hardlinks)) {
3520  bytes_needed += sizeof(FILE_LINK_ENTRY_INFORMATION) + fileref->dc->name.Length - sizeof(WCHAR);
3521 
3522  if (bytes_needed > *length)
3523  overflow = true;
3524 
3525  if (!overflow) {
3526  feli = &fli->Entry;
3527 
3528  feli->NextEntryOffset = 0;
3529  feli->ParentFileId = fileref->parent->fcb->inode;
3530  feli->FileNameLength = fileref->dc->name.Length / sizeof(WCHAR);
3532 
3533  fli->EntriesReturned++;
3534 
3535  len = bytes_needed;
3536  }
3537  } else {
3538  le =