ReactOS  0.4.13-dev-242-g611e6d7
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 FileStatLxInformation (enum _FILE_INFORMATION_CLASS)70
25 
26 typedef struct _FILE_STAT_LX_INFORMATION {
45 
46 #define LX_FILE_METADATA_HAS_UID 0x01
47 #define LX_FILE_METADATA_HAS_GID 0x02
48 #define LX_FILE_METADATA_HAS_MODE 0x04
49 #define LX_FILE_METADATA_HAS_DEVICE_ID 0x08
50 #define LX_FILE_CASE_SENSITIVE_DIR 0x10
51 
52 #endif
53 #endif
54 
56  FILE_BASIC_INFORMATION* fbi = Irp->AssociatedIrp.SystemBuffer;
57  fcb* fcb = FileObject->FsContext;
58  ccb* ccb = FileObject->FsContext2;
59  file_ref* fileref = ccb ? ccb->fileref : NULL;
60  ULONG defda, filter = 0;
63 
64  if (fcb->ads) {
65  if (fileref && fileref->parent)
66  fcb = fileref->parent->fcb;
67  else {
68  ERR("stream did not have fileref\n");
69  return STATUS_INTERNAL_ERROR;
70  }
71  }
72 
73  if (!ccb) {
74  ERR("ccb was NULL\n");
76  }
77 
78  TRACE("file = %S, attributes = %x\n", file_desc(FileObject), fbi->FileAttributes);
79 
81 
83  WARN("attempted to set FILE_ATTRIBUTE_DIRECTORY on non-directory\n");
85  goto end;
86  }
87 
91  goto end;
92  }
93 
94  // don't allow readonly subvol to be made r/w if send operation running on it
95  if (fcb->inode == SUBVOL_ROOT_INODE && fcb->subvol->root_item.flags & BTRFS_SUBVOL_READONLY &&
96  fcb->subvol->send_ops > 0) {
98  goto end;
99  }
100 
101  // times of -2 are some sort of undocumented behaviour to do with LXSS
102 
103  if (fbi->CreationTime.QuadPart == -2)
104  fbi->CreationTime.QuadPart = 0;
105 
106  if (fbi->LastAccessTime.QuadPart == -2)
107  fbi->LastAccessTime.QuadPart = 0;
108 
109  if (fbi->LastWriteTime.QuadPart == -2)
110  fbi->LastWriteTime.QuadPart = 0;
111 
112  if (fbi->ChangeTime.QuadPart == -2)
113  fbi->ChangeTime.QuadPart = 0;
114 
115  if (fbi->CreationTime.QuadPart == -1)
117  else if (fbi->CreationTime.QuadPart != 0) {
121 
123  }
124 
125  if (fbi->LastAccessTime.QuadPart == -1)
127  else if (fbi->LastAccessTime.QuadPart != 0) {
131 
133  }
134 
135  if (fbi->LastWriteTime.QuadPart == -1)
137  else if (fbi->LastWriteTime.QuadPart != 0) {
141 
143  }
144 
145  if (fbi->ChangeTime.QuadPart == -1)
147  else if (fbi->ChangeTime.QuadPart != 0) {
150  // no filter for this
151 
153  }
154 
155  // FileAttributes == 0 means don't set - undocumented, but seen in fastfat
156  if (fbi->FileAttributes != 0) {
158  BTRFS_TIME now;
159 
161 
162  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] == '.',
163  TRUE, Irp);
164 
165  if (fcb->type == BTRFS_TYPE_DIRECTORY)
167  else if (fcb->type == BTRFS_TYPE_SYMLINK)
169 
170  fcb->atts_changed = TRUE;
171 
174 
175  if (defda == fbi->FileAttributes)
176  fcb->atts_deleted = TRUE;
178  fcb->atts_deleted = TRUE;
179 
180  fcb->atts = fbi->FileAttributes;
181 
184 
187 
188  fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
189  fcb->subvol->root_item.ctime = now;
190 
191  if (fcb->inode == SUBVOL_ROOT_INODE) {
193  fcb->subvol->root_item.flags |= BTRFS_SUBVOL_READONLY;
194  else
195  fcb->subvol->root_item.flags &= ~BTRFS_SUBVOL_READONLY;
196  }
197 
199 
201  }
202 
203  if (inode_item_changed) {
204  fcb->inode_item.transid = Vcb->superblock.generation;
207 
209  }
210 
211  if (filter != 0)
213 
215 
216 end:
217  ExReleaseResourceLite(fcb->Header.Resource);
218 
219  return Status;
220 }
221 
223  FILE_DISPOSITION_INFORMATION* fdi = Irp->AssociatedIrp.SystemBuffer;
224  fcb* fcb = FileObject->FsContext;
225  ccb* ccb = FileObject->FsContext2;
226  file_ref* fileref = ccb ? ccb->fileref : NULL;
227  ULONG atts;
229 
230  if (!fileref)
232 
234 
235  TRACE("changing delete_on_close to %s for %S (fcb %p)\n", fdi->DeleteFile ? "TRUE" : "FALSE", file_desc(FileObject), fcb);
236 
237  if (fcb->ads) {
238  if (fileref->parent)
239  atts = fileref->parent->fcb->atts;
240  else {
241  ERR("no fileref for stream\n");
243  goto end;
244  }
245  } else
246  atts = fcb->atts;
247 
248  TRACE("atts = %x\n", atts);
249 
251  TRACE("not allowing readonly file to be deleted\n");
253  goto end;
254  }
255 
256  // FIXME - can we skip this bit for subvols?
257  if (fcb->type == BTRFS_TYPE_DIRECTORY && fcb->inode_item.st_size > 0 && (!fileref || fileref->fcb != Vcb->dummy_fcb)) {
258  TRACE("directory not empty\n");
260  goto end;
261  }
262 
263  if (!MmFlushImageSection(&fcb->nonpaged->segment_object, MmFlushForDelete)) {
264  TRACE("trying to delete file which is being mapped as an image\n");
266  goto end;
267  }
268 
270 
271  FileObject->DeletePending = fdi->DeleteFile;
272 
274 
275 end:
276  ExReleaseResourceLite(fcb->Header.Resource);
277 
278  // send notification that directory is about to be deleted
280  FsRtlNotifyFullChangeDirectory(Vcb->NotifySync, &Vcb->DirNotifyList, FileObject->FsContext,
281  NULL, FALSE, FALSE, 0, NULL, NULL, NULL);
282  }
283 
284  return Status;
285 }
286 
288  LIST_ENTRY* le = fileref->children.Flink;
289 
290  if (IsListEmpty(&fileref->children))
291  return FALSE;
292 
293  while (le != &fileref->children) {
295 
296  if (c->open_count > 0)
297  return TRUE;
298 
299  if (has_open_children(c))
300  return TRUE;
301 
302  le = le->Flink;
303  }
304 
305  return FALSE;
306 }
307 
308 static NTSTATUS duplicate_fcb(fcb* oldfcb, fcb** pfcb) {
309  device_extension* Vcb = oldfcb->Vcb;
310  fcb* fcb;
311  LIST_ENTRY* le;
312 
313  // FIXME - we can skip a lot of this if the inode is about to be deleted
314 
315  fcb = create_fcb(Vcb, PagedPool); // FIXME - what if we duplicate the paging file?
316  if (!fcb) {
317  ERR("out of memory\n");
319  }
320 
321  fcb->Vcb = Vcb;
322 
323  fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
324  fcb->Header.AllocationSize = oldfcb->Header.AllocationSize;
325  fcb->Header.FileSize = oldfcb->Header.FileSize;
326  fcb->Header.ValidDataLength = oldfcb->Header.ValidDataLength;
327 
328  fcb->type = oldfcb->type;
329 
330  if (oldfcb->ads) {
331  fcb->ads = TRUE;
332  fcb->adshash = oldfcb->adshash;
333  fcb->adsmaxlen = oldfcb->adsmaxlen;
334 
335  if (oldfcb->adsxattr.Buffer && oldfcb->adsxattr.Length > 0) {
336  fcb->adsxattr.Length = oldfcb->adsxattr.Length;
339 
340  if (!fcb->adsxattr.Buffer) {
341  ERR("out of memory\n");
342  free_fcb(fcb);
344  }
345 
348  }
349 
350  if (oldfcb->adsdata.Buffer && oldfcb->adsdata.Length > 0) {
353 
354  if (!fcb->adsdata.Buffer) {
355  ERR("out of memory\n");
356  free_fcb(fcb);
358  }
359 
361  }
362 
363  goto end;
364  }
365 
366  RtlCopyMemory(&fcb->inode_item, &oldfcb->inode_item, sizeof(INODE_ITEM));
368 
369  if (oldfcb->sd && RtlLengthSecurityDescriptor(oldfcb->sd) > 0) {
371  if (!fcb->sd) {
372  ERR("out of memory\n");
373  free_fcb(fcb);
375  }
376 
377  RtlCopyMemory(fcb->sd, oldfcb->sd, RtlLengthSecurityDescriptor(oldfcb->sd));
378  }
379 
380  fcb->atts = oldfcb->atts;
381 
382  le = oldfcb->extents.Flink;
383  while (le != &oldfcb->extents) {
385 
386  if (!ext->ignore) {
387  extent* ext2 = ExAllocatePoolWithTag(PagedPool, offsetof(extent, extent_data) + ext->datalen, ALLOC_TAG);
388 
389  if (!ext2) {
390  ERR("out of memory\n");
391  free_fcb(fcb);
393  }
394 
395  ext2->offset = ext->offset;
396  ext2->datalen = ext->datalen;
397 
398  if (ext2->datalen > 0)
399  RtlCopyMemory(&ext2->extent_data, &ext->extent_data, ext2->datalen);
400 
401  ext2->unique = FALSE;
402  ext2->ignore = FALSE;
403  ext2->inserted = TRUE;
404 
405  if (ext->csum) {
406  ULONG len;
407  EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ext->extent_data.data;
408 
409  if (ext->extent_data.compression == BTRFS_COMPRESSION_NONE)
410  len = (ULONG)ed2->num_bytes;
411  else
412  len = (ULONG)ed2->size;
413 
414  len = len * sizeof(UINT32) / Vcb->superblock.sector_size;
415 
417  if (!ext2->csum) {
418  ERR("out of memory\n");
419  free_fcb(fcb);
421  }
422 
423  RtlCopyMemory(ext2->csum, ext->csum, len);
424  } else
425  ext2->csum = NULL;
426 
427  InsertTailList(&fcb->extents, &ext2->list_entry);
428  }
429 
430  le = le->Flink;
431  }
432 
433  le = oldfcb->hardlinks.Flink;
434  while (le != &oldfcb->hardlinks) {
435  hardlink *hl = CONTAINING_RECORD(le, hardlink, list_entry), *hl2;
436 
438 
439  if (!hl2) {
440  ERR("out of memory\n");
441  free_fcb(fcb);
443  }
444 
445  hl2->parent = hl->parent;
446  hl2->index = hl->index;
447 
448  hl2->name.Length = hl2->name.MaximumLength = hl->name.Length;
449  hl2->name.Buffer = ExAllocatePoolWithTag(PagedPool, hl2->name.MaximumLength, ALLOC_TAG);
450 
451  if (!hl2->name.Buffer) {
452  ERR("out of memory\n");
453  ExFreePool(hl2);
454  free_fcb(fcb);
456  }
457 
458  RtlCopyMemory(hl2->name.Buffer, hl->name.Buffer, hl->name.Length);
459 
460  hl2->utf8.Length = hl2->utf8.MaximumLength = hl->utf8.Length;
461  hl2->utf8.Buffer = ExAllocatePoolWithTag(PagedPool, hl2->utf8.MaximumLength, ALLOC_TAG);
462 
463  if (!hl2->utf8.Buffer) {
464  ERR("out of memory\n");
465  ExFreePool(hl2->name.Buffer);
466  ExFreePool(hl2);
467  free_fcb(fcb);
469  }
470 
471  RtlCopyMemory(hl2->utf8.Buffer, hl->utf8.Buffer, hl->utf8.Length);
472 
473  InsertTailList(&fcb->hardlinks, &hl2->list_entry);
474 
475  le = le->Flink;
476  }
477 
478  if (oldfcb->reparse_xattr.Buffer && oldfcb->reparse_xattr.Length > 0) {
480 
482  if (!fcb->reparse_xattr.Buffer) {
483  ERR("out of memory\n");
484  free_fcb(fcb);
486  }
487 
489  }
490 
491  if (oldfcb->ea_xattr.Buffer && oldfcb->ea_xattr.Length > 0) {
493 
495  if (!fcb->ea_xattr.Buffer) {
496  ERR("out of memory\n");
497  free_fcb(fcb);
499  }
500 
502  }
503 
505 
506  le = oldfcb->xattrs.Flink;
507  while (le != &oldfcb->xattrs) {
509 
510  if (xa->valuelen > 0) {
511  xattr* xa2;
512 
514 
515  if (!xa2) {
516  ERR("out of memory\n");
517  free_fcb(fcb);
519  }
520 
521  xa2->namelen = xa->namelen;
522  xa2->valuelen = xa->valuelen;
523  xa2->dirty = xa->dirty;
524  memcpy(xa2->data, xa->data, xa->namelen + xa->valuelen);
525 
527  }
528 
529  le = le->Flink;
530  }
531 
532 end:
533  *pfcb = fcb;
534 
535  return STATUS_SUCCESS;
536 }
537 
538 typedef struct _move_entry {
544 } move_entry;
545 
548  LIST_ENTRY* le;
549 
550  ExAcquireResourceSharedLite(&me->fileref->fcb->nonpaged->dir_children_lock, TRUE);
551 
552  le = me->fileref->fcb->dir_children_index.Flink;
553 
554  while (le != &me->fileref->fcb->dir_children_index) {
555  dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index);
556  file_ref* fr;
557  move_entry* me2;
558 
559  Status = open_fileref_child(Vcb, me->fileref, &dc->name, TRUE, TRUE, dc->index == 0 ? TRUE : FALSE, PagedPool, &fr, Irp);
560 
561  if (!NT_SUCCESS(Status)) {
562  ERR("open_fileref_child returned %08x\n", Status);
563  ExReleaseResourceLite(&me->fileref->fcb->nonpaged->dir_children_lock);
564  return Status;
565  }
566 
568  if (!me2) {
569  ERR("out of memory\n");
570  ExReleaseResourceLite(&me->fileref->fcb->nonpaged->dir_children_lock);
572  }
573 
574  me2->fileref = fr;
575  me2->dummyfcb = NULL;
576  me2->dummyfileref = NULL;
577  me2->parent = me;
578 
579  InsertHeadList(&me->list_entry, &me2->list_entry);
580 
581  le = le->Flink;
582  }
583 
584  ExReleaseResourceLite(&me->fileref->fcb->nonpaged->dir_children_lock);
585 
586  return STATUS_SUCCESS;
587 }
588 
590  UINT8 c;
591 
592  c = dc->hash >> 24;
593 
594  if (fcb->hash_ptrs[c] == &dc->list_entry_hash) {
595  if (dc->list_entry_hash.Flink == &fcb->dir_children_hash)
596  fcb->hash_ptrs[c] = NULL;
597  else {
598  dir_child* dc2 = CONTAINING_RECORD(dc->list_entry_hash.Flink, dir_child, list_entry_hash);
599 
600  if (dc2->hash >> 24 == c)
601  fcb->hash_ptrs[c] = &dc2->list_entry_hash;
602  else
603  fcb->hash_ptrs[c] = NULL;
604  }
605  }
606 
607  RemoveEntryList(&dc->list_entry_hash);
608 
609  c = dc->hash_uc >> 24;
610 
611  if (fcb->hash_ptrs_uc[c] == &dc->list_entry_hash_uc) {
612  if (dc->list_entry_hash_uc.Flink == &fcb->dir_children_hash_uc)
613  fcb->hash_ptrs_uc[c] = NULL;
614  else {
615  dir_child* dc2 = CONTAINING_RECORD(dc->list_entry_hash_uc.Flink, dir_child, list_entry_hash_uc);
616 
617  if (dc2->hash_uc >> 24 == c)
619  else
620  fcb->hash_ptrs_uc[c] = NULL;
621  }
622  }
623 
624  RemoveEntryList(&dc->list_entry_hash_uc);
625 }
626 
629  fcb* fcb;
630  SECURITY_SUBJECT_CONTEXT subjcont;
631  PSID owner;
632  BOOLEAN defaulted;
634  BTRFS_TIME now;
635 
637  if (!fcb) {
638  ERR("out of memory\n");
640  }
641 
644 
645  fcb->Vcb = Vcb;
646 
647  fcb->subvol = r;
648  fcb->inode = InterlockedIncrement64(&r->lastinode);
650 
651  fcb->inode_item.generation = Vcb->superblock.generation;
652  fcb->inode_item.transid = Vcb->superblock.generation;
653  fcb->inode_item.st_nlink = 1;
657 
659 
660  SeCaptureSubjectContext(&subjcont);
661 
662  Status = SeAssignSecurity(parfcb->sd, NULL, (void**)&fcb->sd, TRUE, &subjcont, IoGetFileObjectGenericMapping(), PagedPool);
663 
664  if (!NT_SUCCESS(Status)) {
665  reap_fcb(fcb);
666  ERR("SeAssignSecurity returned %08x\n", Status);
667  return Status;
668  }
669 
670  if (!fcb->sd) {
671  reap_fcb(fcb);
672  ERR("SeAssignSecurity returned NULL security descriptor\n");
673  return STATUS_INTERNAL_ERROR;
674  }
675 
676  Status = RtlGetOwnerSecurityDescriptor(fcb->sd, &owner, &defaulted);
677  if (!NT_SUCCESS(Status)) {
678  ERR("RtlGetOwnerSecurityDescriptor returned %08x\n", Status);
680  fcb->sd_dirty = TRUE;
681  } else {
682  fcb->inode_item.st_uid = sid_to_uid(owner);
684  }
685 
686  find_gid(fcb, parfcb, &subjcont);
687 
689 
690  fcb->Header.IsFastIoPossible = fast_io_possible(fcb);
691  fcb->Header.AllocationSize.QuadPart = 0;
692  fcb->Header.FileSize.QuadPart = 0;
693  fcb->Header.ValidDataLength.QuadPart = 0;
694 
695  fcb->created = TRUE;
696 
697  if (parfcb->inode_item.flags & BTRFS_INODE_COMPRESS)
699 
702 
704  if (!fcb->hash_ptrs) {
705  ERR("out of memory\n");
707  }
708 
709  RtlZeroMemory(fcb->hash_ptrs, sizeof(LIST_ENTRY*) * 256);
710 
712  if (!fcb->hash_ptrs_uc) {
713  ERR("out of memory\n");
715  }
716 
717  RtlZeroMemory(fcb->hash_ptrs_uc, sizeof(LIST_ENTRY*) * 256);
718 
719  acquire_fcb_lock_exclusive(Vcb);
720  InsertTailList(&r->fcbs, &fcb->list_entry);
721  InsertTailList(&Vcb->all_fcbs, &fcb->list_entry_all);
722  r->fcbs_version++;
723  release_fcb_lock(Vcb);
724 
726 
727  *pfcb = fcb;
728 
729  return STATUS_SUCCESS;
730 }
731 
734  LIST_ENTRY move_list, *le;
735  move_entry* me;
737  BTRFS_TIME now;
738  file_ref* origparent;
739 
740  // FIXME - make sure me->dummyfileref and me->dummyfcb get freed properly
741 
743 
746 
747  acquire_fcb_lock_exclusive(fileref->fcb->Vcb);
748 
750 
751  if (!me) {
752  ERR("out of memory\n");
754  goto end;
755  }
756 
757  origparent = fileref->parent;
758 
759  me->fileref = fileref;
761  me->dummyfcb = NULL;
762  me->dummyfileref = NULL;
763  me->parent = NULL;
764 
766 
767  le = move_list.Flink;
768  while (le != &move_list) {
770 
772 
773  if (!me->fileref->fcb->ads && me->fileref->fcb->subvol == origparent->fcb->subvol) {
775 
776  if (!NT_SUCCESS(Status)) {
777  ERR("add_children_to_move_list returned %08x\n", Status);
778  goto end;
779  }
780  }
781 
782  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
783 
784  le = le->Flink;
785  }
786 
788 
789  // loop through list and create new inodes
790 
791  le = move_list.Flink;
792  while (le != &move_list) {
794 
795  if (me->fileref->fcb->inode != SUBVOL_ROOT_INODE && me->fileref->fcb != fileref->fcb->Vcb->dummy_fcb) {
796  if (!me->dummyfcb) {
797  ULONG defda;
798  BOOL inserted = FALSE;
799  LIST_ENTRY* le3;
800 
802 
803  Status = duplicate_fcb(me->fileref->fcb, &me->dummyfcb);
804  if (!NT_SUCCESS(Status)) {
805  ERR("duplicate_fcb returned %08x\n", Status);
806  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
807  goto end;
808  }
809 
810  me->dummyfcb->subvol = me->fileref->fcb->subvol;
811  me->dummyfcb->inode = me->fileref->fcb->inode;
812 
813  if (!me->dummyfcb->ads) {
814  me->dummyfcb->sd_dirty = me->fileref->fcb->sd_dirty;
820  }
821 
822  me->dummyfcb->created = me->fileref->fcb->created;
823  me->dummyfcb->deleted = me->fileref->fcb->deleted;
825 
826  if (!me->fileref->fcb->ads) {
827  LIST_ENTRY* le2;
828 
829  me->fileref->fcb->subvol = destdir->fcb->subvol;
830  me->fileref->fcb->inode = InterlockedIncrement64(&destdir->fcb->subvol->lastinode);
831  me->fileref->fcb->inode_item.st_nlink = 1;
832 
833  defda = get_file_attributes(me->fileref->fcb->Vcb, me->fileref->fcb->subvol, me->fileref->fcb->inode,
834  me->fileref->fcb->type, me->fileref->dc && me->fileref->dc->name.Length >= sizeof(WCHAR) && me->fileref->dc->name.Buffer[0] == '.',
835  TRUE, Irp);
836 
837  me->fileref->fcb->sd_dirty = !!me->fileref->fcb->sd;
838  me->fileref->fcb->atts_changed = defda != me->fileref->fcb->atts;
841  me->fileref->fcb->ea_changed = !!me->fileref->fcb->ea_xattr.Buffer;
844 
845  le2 = me->fileref->fcb->xattrs.Flink;
846  while (le2 != &me->fileref->fcb->xattrs) {
848 
849  xa->dirty = TRUE;
850 
851  le2 = le2->Flink;
852  }
853 
854  if (le == move_list.Flink) { // first entry
855  me->fileref->fcb->inode_item.transid = me->fileref->fcb->Vcb->superblock.generation;
856  me->fileref->fcb->inode_item.sequence++;
857 
860  }
861 
862  le2 = me->fileref->fcb->extents.Flink;
863  while (le2 != &me->fileref->fcb->extents) {
865 
866  if (!ext->ignore && (ext->extent_data.type == EXTENT_TYPE_REGULAR || ext->extent_data.type == EXTENT_TYPE_PREALLOC)) {
867  EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ext->extent_data.data;
868 
869  if (ed2->size != 0) {
871 
872  if (!c) {
873  ERR("get_chunk_from_address(%llx) failed\n", ed2->address);
874  } else {
877 
878  if (!NT_SUCCESS(Status)) {
879  ERR("update_changed_extent_ref returned %08x\n", Status);
880  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
881  goto end;
882  }
883  }
884 
885  }
886  }
887 
888  le2 = le2->Flink;
889  }
890  } else {
891  me->fileref->fcb->subvol = me->parent->fileref->fcb->subvol;
892  me->fileref->fcb->inode = me->parent->fileref->fcb->inode;
893  }
894 
895  me->fileref->fcb->created = TRUE;
896 
899 
900  le3 = destdir->fcb->subvol->fcbs.Flink;
901  while (le3 != &destdir->fcb->subvol->fcbs) {
902  fcb* fcb = CONTAINING_RECORD(le3, struct _fcb, list_entry);
903 
904  if (fcb->inode > me->fileref->fcb->inode) {
905  InsertHeadList(le3->Blink, &me->fileref->fcb->list_entry);
906  inserted = TRUE;
907  break;
908  }
909 
910  le3 = le3->Flink;
911  }
912 
913  if (!inserted)
914  InsertTailList(&destdir->fcb->subvol->fcbs, &me->fileref->fcb->list_entry);
915 
916  InsertTailList(&me->fileref->fcb->Vcb->all_fcbs, &me->dummyfcb->list_entry_all);
917 
918  while (!IsListEmpty(&me->fileref->fcb->hardlinks)) {
920 
921  if (hl->name.Buffer)
922  ExFreePool(hl->name.Buffer);
923 
924  if (hl->utf8.Buffer)
925  ExFreePool(hl->utf8.Buffer);
926 
927  ExFreePool(hl);
928  }
929 
931  mark_fcb_dirty(me->fileref->fcb);
932 
933  if ((!me->dummyfcb->ads && me->dummyfcb->inode_item.st_nlink > 1) || (me->dummyfcb->ads && me->parent->dummyfcb->inode_item.st_nlink > 1)) {
934  LIST_ENTRY* le2 = le->Flink;
935 
936  while (le2 != &move_list) {
938 
939  if (me2->fileref->fcb == me->fileref->fcb && !me2->fileref->fcb->ads) {
940  me2->dummyfcb = me->dummyfcb;
942  }
943 
944  le2 = le2->Flink;
945  }
946  }
947 
948  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
949  } else {
951  me->fileref->fcb->inode_item.st_nlink++;
953  ExReleaseResourceLite(me->fileref->fcb->Header.Resource);
954  }
955  }
956 
957  le = le->Flink;
958  }
959 
960  fileref->fcb->subvol->root_item.ctransid = fileref->fcb->Vcb->superblock.generation;
961  fileref->fcb->subvol->root_item.ctime = now;
962 
963  // loop through list and create new filerefs
964 
965  le = move_list.Flink;
966  while (le != &move_list) {
967  hardlink* hl;
968  BOOL name_changed = FALSE;
969 
971 
973  if (!me->dummyfileref) {
974  ERR("out of memory\n");
976  goto end;
977  }
978 
979  if (me->fileref->fcb == me->fileref->fcb->Vcb->dummy_fcb) {
980  root* r = me->parent ? me->parent->fileref->fcb->subvol : destdir->fcb->subvol;
981 
982  Status = create_directory_fcb(me->fileref->fcb->Vcb, r, me->fileref->parent->fcb, &me->fileref->fcb);
983  if (!NT_SUCCESS(Status)) {
984  ERR("create_directory_fcb returnd %08x\n", Status);
985  goto end;
986  }
987 
988  me->fileref->dc->key.obj_id = me->fileref->fcb->inode;
990 
991  me->dummyfileref->fcb = me->fileref->fcb->Vcb->dummy_fcb;
992  } else if (me->fileref->fcb->inode == SUBVOL_ROOT_INODE) {
993  me->dummyfileref->fcb = me->fileref->fcb;
994 
995  me->fileref->fcb->subvol->parent = le == move_list.Flink ? destdir->fcb->subvol->id : me->parent->fileref->fcb->subvol->id;
996  } else
997  me->dummyfileref->fcb = me->dummyfcb;
998 
1000 
1001  me->dummyfileref->oldutf8 = me->fileref->oldutf8;
1002  me->dummyfileref->oldindex = me->fileref->dc->index;
1003 
1004  if (le == move_list.Flink && (me->fileref->dc->utf8.Length != utf8->Length || RtlCompareMemory(me->fileref->dc->utf8.Buffer, utf8->Buffer, utf8->Length) != utf8->Length))
1005  name_changed = TRUE;
1006 
1007  if ((le == move_list.Flink || me->fileref->fcb->inode == SUBVOL_ROOT_INODE) && !me->dummyfileref->oldutf8.Buffer) {
1009  if (!me->dummyfileref->oldutf8.Buffer) {
1010  ERR("out of memory\n");
1012  goto end;
1013  }
1014 
1016 
1018  }
1019 
1021  me->dummyfileref->deleted = me->fileref->deleted;
1022 
1023  me->dummyfileref->created = me->fileref->created;
1024  me->fileref->created = TRUE;
1025 
1026  me->dummyfileref->parent = me->parent ? me->parent->dummyfileref : origparent;
1028 
1029  ExAcquireResourceExclusiveLite(&me->dummyfileref->parent->fcb->nonpaged->dir_children_lock, TRUE);
1030  InsertTailList(&me->dummyfileref->parent->children, &me->dummyfileref->list_entry);
1031  ExReleaseResourceLite(&me->dummyfileref->parent->fcb->nonpaged->dir_children_lock);
1032 
1034 
1036  me->dummyfileref->fcb->fileref = me->dummyfileref;
1037 
1038  if (!me->parent) {
1040 
1041  increase_fileref_refcount(destdir);
1042 
1043  if (me->fileref->dc) {
1044  // remove from old parent
1045  ExAcquireResourceExclusiveLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock, TRUE);
1048  ExReleaseResourceLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock);
1049 
1050  me->fileref->parent->fcb->inode_item.st_size -= me->fileref->dc->utf8.Length * 2;
1051  me->fileref->parent->fcb->inode_item.transid = me->fileref->fcb->Vcb->superblock.generation;
1052  me->fileref->parent->fcb->inode_item.sequence++;
1053  me->fileref->parent->fcb->inode_item.st_ctime = now;
1054  me->fileref->parent->fcb->inode_item.st_mtime = now;
1055  me->fileref->parent->fcb->inode_item_changed = TRUE;
1056  mark_fcb_dirty(me->fileref->parent->fcb);
1057 
1058  if (name_changed) {
1059  ExFreePool(me->fileref->dc->utf8.Buffer);
1060  ExFreePool(me->fileref->dc->name.Buffer);
1062 
1064  if (!me->fileref->dc->utf8.Buffer) {
1065  ERR("out of memory\n");
1067  goto end;
1068  }
1069 
1070  me->fileref->dc->utf8.Length = me->fileref->dc->utf8.MaximumLength = utf8->Length;
1071  RtlCopyMemory(me->fileref->dc->utf8.Buffer, utf8->Buffer, utf8->Length);
1072 
1074  if (!me->fileref->dc->name.Buffer) {
1075  ERR("out of memory\n");
1077  goto end;
1078  }
1079 
1080  me->fileref->dc->name.Length = me->fileref->dc->name.MaximumLength = fnus->Length;
1081  RtlCopyMemory(me->fileref->dc->name.Buffer, fnus->Buffer, fnus->Length);
1082 
1084  if (!NT_SUCCESS(Status)) {
1085  ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
1086  goto end;
1087  }
1088 
1089  me->fileref->dc->hash = calc_crc32c(0xffffffff, (UINT8*)me->fileref->dc->name.Buffer, me->fileref->dc->name.Length);
1090  me->fileref->dc->hash_uc = calc_crc32c(0xffffffff, (UINT8*)me->fileref->dc->name_uc.Buffer, me->fileref->dc->name_uc.Length);
1091  }
1092 
1093  if (me->fileref->dc->key.obj_type == TYPE_INODE_ITEM)
1094  me->fileref->dc->key.obj_id = me->fileref->fcb->inode;
1095 
1096  // add to new parent
1097 
1098  ExAcquireResourceExclusiveLite(&destdir->fcb->nonpaged->dir_children_lock, TRUE);
1099 
1100  if (IsListEmpty(&destdir->fcb->dir_children_index))
1101  me->fileref->dc->index = 2;
1102  else {
1103  dir_child* dc2 = CONTAINING_RECORD(destdir->fcb->dir_children_index.Blink, dir_child, list_entry_index);
1104 
1105  me->fileref->dc->index = max(2, dc2->index + 1);
1106  }
1107 
1110  ExReleaseResourceLite(&destdir->fcb->nonpaged->dir_children_lock);
1111  }
1112 
1113  free_fileref(me->fileref->parent);
1114  me->fileref->parent = destdir;
1115 
1116  ExAcquireResourceExclusiveLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock, TRUE);
1117  InsertTailList(&me->fileref->parent->children, &me->fileref->list_entry);
1118  ExReleaseResourceLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock);
1119 
1120  TRACE("me->fileref->parent->fcb->inode_item.st_size (inode %llx) was %llx\n", me->fileref->parent->fcb->inode, me->fileref->parent->fcb->inode_item.st_size);
1121  me->fileref->parent->fcb->inode_item.st_size += me->fileref->dc->utf8.Length * 2;
1122  TRACE("me->fileref->parent->fcb->inode_item.st_size (inode %llx) now %llx\n", me->fileref->parent->fcb->inode, me->fileref->parent->fcb->inode_item.st_size);
1123  me->fileref->parent->fcb->inode_item.transid = me->fileref->fcb->Vcb->superblock.generation;
1124  me->fileref->parent->fcb->inode_item.sequence++;
1125  me->fileref->parent->fcb->inode_item.st_ctime = now;
1126  me->fileref->parent->fcb->inode_item.st_mtime = now;
1127  me->fileref->parent->fcb->inode_item_changed = TRUE;
1128  mark_fcb_dirty(me->fileref->parent->fcb);
1129  } else {
1130  if (me->fileref->dc) {
1131  ExAcquireResourceExclusiveLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock, TRUE);
1133 
1134  if (!me->fileref->fcb->ads)
1136 
1137  ExReleaseResourceLite(&me->fileref->parent->fcb->nonpaged->dir_children_lock);
1138 
1139  ExAcquireResourceExclusiveLite(&me->parent->fileref->fcb->nonpaged->dir_children_lock, TRUE);
1140 
1141  if (me->fileref->fcb->ads)
1142  InsertHeadList(&me->parent->fileref->fcb->dir_children_index, &me->fileref->dc->list_entry_index);
1143  else {
1144  if (me->fileref->fcb->inode != SUBVOL_ROOT_INODE)
1145  me->fileref->dc->key.obj_id = me->fileref->fcb->inode;
1146 
1147  if (IsListEmpty(&me->parent->fileref->fcb->dir_children_index))
1148  me->fileref->dc->index = 2;
1149  else {
1150  dir_child* dc2 = CONTAINING_RECORD(me->parent->fileref->fcb->dir_children_index.Blink, dir_child, list_entry_index);
1151 
1152  me->fileref->dc->index = max(2, dc2->index + 1);
1153  }
1154 
1155  InsertTailList(&me->parent->fileref->fcb->dir_children_index, &me->fileref->dc->list_entry_index);
1156  insert_dir_child_into_hash_lists(me->parent->fileref->fcb, me->fileref->dc);
1157  }
1158 
1159  ExReleaseResourceLite(&me->parent->fileref->fcb->nonpaged->dir_children_lock);
1160  }
1161  }
1162 
1163  if (!me->dummyfileref->fcb->ads) {
1165  if (!NT_SUCCESS(Status)) {
1166  ERR("delete_fileref returned %08x\n", Status);
1167  goto end;
1168  }
1169  }
1170 
1171  if (me->fileref->fcb->inode_item.st_nlink > 1) {
1173  if (!hl) {
1174  ERR("out of memory\n");
1176  goto end;
1177  }
1178 
1179  hl->parent = me->fileref->parent->fcb->inode;
1180  hl->index = me->fileref->dc->index;
1181 
1182  hl->utf8.Length = hl->utf8.MaximumLength = me->fileref->dc->utf8.Length;
1184  if (!hl->utf8.Buffer) {
1185  ERR("out of memory\n");
1187  ExFreePool(hl);
1188  goto end;
1189  }
1190 
1192 
1193  hl->name.Length = hl->name.MaximumLength = me->fileref->dc->name.Length;
1195  if (!hl->name.Buffer) {
1196  ERR("out of memory\n");
1198  ExFreePool(hl->utf8.Buffer);
1199  ExFreePool(hl);
1200  goto end;
1201  }
1202 
1204 
1206  }
1207 
1209 
1210  le = le->Flink;
1211  }
1212 
1213  // loop through, and only mark streams as deleted if their parent inodes are also deleted
1214 
1215  le = move_list.Flink;
1216  while (le != &move_list) {
1218 
1219  if (me->dummyfileref->fcb->ads && me->parent->dummyfileref->fcb->deleted) {
1221  if (!NT_SUCCESS(Status)) {
1222  ERR("delete_fileref returned %08x\n", Status);
1223  goto end;
1224  }
1225  }
1226 
1227  le = le->Flink;
1228  }
1229 
1230  destdir->fcb->subvol->root_item.ctransid = destdir->fcb->Vcb->superblock.generation;
1231  destdir->fcb->subvol->root_item.ctime = now;
1232 
1237 
1239 
1240 end:
1241  while (!IsListEmpty(&move_list)) {
1242  le = RemoveHeadList(&move_list);
1244 
1245  if (me->dummyfcb)
1246  free_fcb(me->dummyfcb);
1247 
1248  if (me->dummyfileref)
1250 
1251  free_fileref(me->fileref);
1252 
1253  ExFreePool(me);
1254  }
1255 
1256  destdir->fcb->subvol->fcbs_version++;
1257  fileref->fcb->subvol->fcbs_version++;
1258 
1259  release_fcb_lock(fileref->fcb->Vcb);
1260 
1261  return Status;
1262 }
1263 
1265  BOOL inserted;
1266  LIST_ENTRY* le;
1267  UINT8 c, d;
1268 
1269  c = dc->hash >> 24;
1270 
1271  inserted = FALSE;
1272 
1273  d = c;
1274  do {
1275  le = fcb->hash_ptrs[d];
1276 
1277  if (d == 0)
1278  break;
1279 
1280  d--;
1281  } while (!le);
1282 
1283  if (!le)
1284  le = fcb->dir_children_hash.Flink;
1285 
1286  while (le != &fcb->dir_children_hash) {
1287  dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_hash);
1288 
1289  if (dc2->hash > dc->hash) {
1290  InsertHeadList(le->Blink, &dc->list_entry_hash);
1291  inserted = TRUE;
1292  break;
1293  }
1294 
1295  le = le->Flink;
1296  }
1297 
1298  if (!inserted)
1299  InsertTailList(&fcb->dir_children_hash, &dc->list_entry_hash);
1300 
1301  if (!fcb->hash_ptrs[c])
1302  fcb->hash_ptrs[c] = &dc->list_entry_hash;
1303  else {
1304  dir_child* dc2 = CONTAINING_RECORD(fcb->hash_ptrs[c], dir_child, list_entry_hash);
1305 
1306  if (dc2->hash > dc->hash)
1307  fcb->hash_ptrs[c] = &dc->list_entry_hash;
1308  }
1309 
1310  c = dc->hash_uc >> 24;
1311 
1312  inserted = FALSE;
1313 
1314  d = c;
1315  do {
1316  le = fcb->hash_ptrs_uc[d];
1317 
1318  if (d == 0)
1319  break;
1320 
1321  d--;
1322  } while (!le);
1323 
1324  if (!le)
1326 
1327  while (le != &fcb->dir_children_hash_uc) {
1328  dir_child* dc2 = CONTAINING_RECORD(le, dir_child, list_entry_hash_uc);
1329 
1330  if (dc2->hash_uc > dc->hash_uc) {
1331  InsertHeadList(le->Blink, &dc->list_entry_hash_uc);
1332  inserted = TRUE;
1333  break;
1334  }
1335 
1336  le = le->Flink;
1337  }
1338 
1339  if (!inserted)
1340  InsertTailList(&fcb->dir_children_hash_uc, &dc->list_entry_hash_uc);
1341 
1342  if (!fcb->hash_ptrs_uc[c])
1343  fcb->hash_ptrs_uc[c] = &dc->list_entry_hash_uc;
1344  else {
1345  dir_child* dc2 = CONTAINING_RECORD(fcb->hash_ptrs_uc[c], dir_child, list_entry_hash_uc);
1346 
1347  if (dc2->hash_uc > dc->hash_uc)
1348  fcb->hash_ptrs_uc[c] = &dc->list_entry_hash_uc;
1349  }
1350 }
1351 
1354  FILE_RENAME_INFORMATION* fri = Irp->AssociatedIrp.SystemBuffer;
1355  fcb *fcb = FileObject->FsContext;
1356  ccb* ccb = FileObject->FsContext2;
1357  file_ref *fileref = ccb ? ccb->fileref : NULL, *oldfileref = NULL, *related = NULL, *fr2 = NULL;
1358  WCHAR* fn;
1359  ULONG fnlen, utf8len, origutf8len;
1360  UNICODE_STRING fnus;
1361  ANSI_STRING utf8;
1362  NTSTATUS Status;
1364  BTRFS_TIME now;
1365  LIST_ENTRY rollback, *le;
1366  hardlink* hl;
1367  SECURITY_SUBJECT_CONTEXT subjcont;
1369 
1371 
1372  TRACE("tfo = %p\n", tfo);
1373  TRACE("ReplaceIfExists = %u\n", IrpSp->Parameters.SetFile.ReplaceIfExists);
1374  TRACE("RootDirectory = %p\n", fri->RootDirectory);
1375  TRACE("FileName = %.*S\n", fri->FileNameLength / sizeof(WCHAR), fri->FileName);
1376 
1377  fn = fri->FileName;
1378  fnlen = fri->FileNameLength / sizeof(WCHAR);
1379 
1380  if (!tfo) {
1381  if (!fileref || !fileref->parent) {
1382  ERR("no fileref set and no directory given\n");
1383  return STATUS_INVALID_PARAMETER;
1384  }
1385  } else {
1386  LONG i;
1387 
1388  while (fnlen > 0 && (fri->FileName[fnlen - 1] == '/' || fri->FileName[fnlen - 1] == '\\'))
1389  fnlen--;
1390 
1391  if (fnlen == 0)
1392  return STATUS_INVALID_PARAMETER;
1393 
1394  for (i = fnlen - 1; i >= 0; i--) {
1395  if (fri->FileName[i] == '\\' || fri->FileName[i] == '/') {
1396  fn = &fri->FileName[i+1];
1397  fnlen = (fri->FileNameLength / sizeof(WCHAR)) - i - 1;
1398  break;
1399  }
1400  }
1401  }
1402 
1403  ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
1404  ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, TRUE);
1406 
1407  if (fcb->ads) {
1408  // MSDN says that NTFS data streams can be renamed (https://msdn.microsoft.com/en-us/library/windows/hardware/ff540344.aspx),
1409  // but if you try it always seems to return STATUS_INVALID_PARAMETER. There is a function in ntfs.sys called NtfsStreamRename,
1410  // but it never seems to get invoked... If you know what's going on here, I'd appreciate it if you let me know.
1412  goto end;
1413  }
1414 
1415  fnus.Buffer = fn;
1416  fnus.Length = fnus.MaximumLength = (UINT16)(fnlen * sizeof(WCHAR));
1417 
1418  TRACE("fnus = %.*S\n", fnus.Length / sizeof(WCHAR), fnus.Buffer);
1419 
1420  origutf8len = fileref->dc->utf8.Length;
1421 
1422  Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, fn, (ULONG)fnlen * sizeof(WCHAR));
1423  if (!NT_SUCCESS(Status))
1424  goto end;
1425 
1426  utf8.MaximumLength = utf8.Length = (UINT16)utf8len;
1428  if (!utf8.Buffer) {
1429  ERR("out of memory\n");
1431  goto end;
1432  }
1433 
1434  Status = RtlUnicodeToUTF8N(utf8.Buffer, utf8len, &utf8len, fn, (ULONG)fnlen * sizeof(WCHAR));
1435  if (!NT_SUCCESS(Status))
1436  goto end;
1437 
1438  if (tfo && tfo->FsContext2) {
1439  struct _ccb* relatedccb = tfo->FsContext2;
1440 
1441  related = relatedccb->fileref;
1442  increase_fileref_refcount(related);
1443  } else if (fnus.Length >= sizeof(WCHAR) && fnus.Buffer[0] != '\\') {
1444  related = fileref->parent;
1445  increase_fileref_refcount(related);
1446  }
1447 
1448  Status = open_fileref(Vcb, &oldfileref, &fnus, related, FALSE, NULL, NULL, PagedPool, ccb->case_sensitive, Irp);
1449 
1450  if (NT_SUCCESS(Status)) {
1451  TRACE("destination file %S already exists\n", file_desc_fileref(oldfileref));
1452 
1453  if (fileref != oldfileref && !oldfileref->deleted) {
1454  if (!IrpSp->Parameters.SetFile.ReplaceIfExists) {
1456  goto end;
1457  } else if ((oldfileref->open_count >= 1 || has_open_children(oldfileref)) && !oldfileref->deleted) {
1458  WARN("trying to overwrite open file\n");
1460  goto end;
1461  }
1462 
1463  if (oldfileref->fcb->type == BTRFS_TYPE_DIRECTORY) {
1464  WARN("trying to overwrite directory\n");
1466  goto end;
1467  }
1468  }
1469 
1470  if (fileref == oldfileref || oldfileref->deleted) {
1471  free_fileref(oldfileref);
1472  oldfileref = NULL;
1473  }
1474  }
1475 
1476  if (!related) {
1477  Status = open_fileref(Vcb, &related, &fnus, NULL, TRUE, NULL, NULL, PagedPool, ccb->case_sensitive, Irp);
1478 
1479  if (!NT_SUCCESS(Status)) {
1480  ERR("open_fileref returned %08x\n", Status);
1481  goto end;
1482  }
1483  }
1484 
1485  if (related->fcb == Vcb->dummy_fcb) {
1487  goto end;
1488  }
1489 
1490  SeCaptureSubjectContext(&subjcont);
1491 
1492  if (!SeAccessCheck(related->fcb->sd, &subjcont, FALSE, fcb->type == BTRFS_TYPE_DIRECTORY ? FILE_ADD_SUBDIRECTORY : FILE_ADD_FILE, 0, NULL,
1493  IoGetFileObjectGenericMapping(), Irp->RequestorMode, &access, &Status)) {
1494  SeReleaseSubjectContext(&subjcont);
1495  TRACE("SeAccessCheck failed, returning %08x\n", Status);
1496  goto end;
1497  }
1498 
1499  SeReleaseSubjectContext(&subjcont);
1500 
1501  if (has_open_children(fileref)) {
1502  WARN("trying to rename file with open children\n");
1504  goto end;
1505  }
1506 
1507  if (oldfileref) {
1508  SeCaptureSubjectContext(&subjcont);
1509 
1510  if (!SeAccessCheck(oldfileref->fcb->sd, &subjcont, FALSE, DELETE, 0, NULL,
1511  IoGetFileObjectGenericMapping(), Irp->RequestorMode, &access, &Status)) {
1512  SeReleaseSubjectContext(&subjcont);
1513  TRACE("SeAccessCheck failed, returning %08x\n", Status);
1514  goto end;
1515  }
1516 
1517  SeReleaseSubjectContext(&subjcont);
1518 
1519  Status = delete_fileref(oldfileref, NULL, Irp, &rollback);
1520  if (!NT_SUCCESS(Status)) {
1521  ERR("delete_fileref returned %08x\n", Status);
1522  goto end;
1523  }
1524  }
1525 
1526  if (fileref->parent->fcb->subvol != related->fcb->subvol && (fileref->fcb->subvol == fileref->parent->fcb->subvol || fileref->fcb == Vcb->dummy_fcb)) {
1527  Status = move_across_subvols(fileref, ccb, related, &utf8, &fnus, Irp, &rollback);
1528  if (!NT_SUCCESS(Status)) {
1529  ERR("move_across_subvols returned %08x\n", Status);
1530  }
1531  goto end;
1532  }
1533 
1534  if (related == fileref->parent) { // keeping file in same directory
1535  UNICODE_STRING oldfn, newfn;
1536  USHORT name_offset;
1537  ULONG reqlen, oldutf8len;
1538 
1539  oldfn.Length = oldfn.MaximumLength = 0;
1540 
1541  Status = fileref_get_filename(fileref, &oldfn, &name_offset, &reqlen);
1542  if (Status != STATUS_BUFFER_OVERFLOW) {
1543  ERR("fileref_get_filename returned %08x\n", Status);
1544  goto end;
1545  }
1546 
1547  oldfn.Buffer = ExAllocatePoolWithTag(PagedPool, reqlen, ALLOC_TAG);
1548  if (!oldfn.Buffer) {
1549  ERR("out of memory\n");
1551  goto end;
1552  }
1553 
1554  oldfn.MaximumLength = (UINT16)reqlen;
1555 
1556  Status = fileref_get_filename(fileref, &oldfn, &name_offset, &reqlen);
1557  if (!NT_SUCCESS(Status)) {
1558  ERR("fileref_get_filename returned %08x\n", Status);
1559  ExFreePool(oldfn.Buffer);
1560  goto end;
1561  }
1562 
1563  oldutf8len = fileref->dc->utf8.Length;
1564 
1565  if (!fileref->created && !fileref->oldutf8.Buffer) {
1567  if (!fileref->oldutf8.Buffer) {
1568  ERR("out of memory\n");
1570  goto end;
1571  }
1572 
1575  }
1576 
1577  TRACE("renaming %.*S to %.*S\n", fileref->dc->name.Length / sizeof(WCHAR), fileref->dc->name.Buffer, fnus.Length / sizeof(WCHAR), fnus.Buffer);
1578 
1580 
1581  if (fileref->dc) {
1582  ExAcquireResourceExclusiveLite(&fileref->parent->fcb->nonpaged->dir_children_lock, TRUE);
1583 
1587 
1589  if (!fileref->dc->utf8.Buffer) {
1590  ERR("out of memory\n");
1592  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
1593  ExFreePool(oldfn.Buffer);
1594  goto end;
1595  }
1596 
1598  RtlCopyMemory(fileref->dc->utf8.Buffer, utf8.Buffer, utf8.Length);
1599 
1601  if (!fileref->dc->name.Buffer) {
1602  ERR("out of memory\n");
1604  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
1605  ExFreePool(oldfn.Buffer);
1606  goto end;
1607  }
1608 
1610  RtlCopyMemory(fileref->dc->name.Buffer, fnus.Buffer, fnus.Length);
1611 
1613  if (!NT_SUCCESS(Status)) {
1614  ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
1615  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
1616  ExFreePool(oldfn.Buffer);
1617  goto end;
1618  }
1619 
1621 
1622  fileref->dc->hash = calc_crc32c(0xffffffff, (UINT8*)fileref->dc->name.Buffer, fileref->dc->name.Length);
1624 
1626 
1627  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
1628  }
1629 
1630  newfn.Length = newfn.MaximumLength = 0;
1631 
1632  Status = fileref_get_filename(fileref, &newfn, &name_offset, &reqlen);
1633  if (Status != STATUS_BUFFER_OVERFLOW) {
1634  ERR("fileref_get_filename returned %08x\n", Status);
1635  ExFreePool(oldfn.Buffer);
1636  goto end;
1637  }
1638 
1639  newfn.Buffer = ExAllocatePoolWithTag(PagedPool, reqlen, ALLOC_TAG);
1640  if (!newfn.Buffer) {
1641  ERR("out of memory\n");
1643  ExFreePool(oldfn.Buffer);
1644  goto end;
1645  }
1646 
1647  newfn.MaximumLength = (UINT16)reqlen;
1648 
1649  Status = fileref_get_filename(fileref, &newfn, &name_offset, &reqlen);
1650  if (!NT_SUCCESS(Status)) {
1651  ERR("fileref_get_filename returned %08x\n", Status);
1652  ExFreePool(oldfn.Buffer);
1653  ExFreePool(newfn.Buffer);
1654  goto end;
1655  }
1656 
1659 
1660  if (fcb != Vcb->dummy_fcb && (fileref->parent->fcb->subvol == fcb->subvol || !is_subvol_readonly(fcb->subvol, Irp))) {
1661  fcb->inode_item.transid = Vcb->superblock.generation;
1662  fcb->inode_item.sequence++;
1663 
1664  if (!ccb->user_set_change_time)
1666 
1669  }
1670 
1671  // update parent's INODE_ITEM
1672 
1673  related->fcb->inode_item.transid = Vcb->superblock.generation;
1674  TRACE("related->fcb->inode_item.st_size (inode %llx) was %llx\n", related->fcb->inode, related->fcb->inode_item.st_size);
1675  related->fcb->inode_item.st_size = related->fcb->inode_item.st_size + (2 * utf8.Length) - (2* oldutf8len);
1676  TRACE("related->fcb->inode_item.st_size (inode %llx) now %llx\n", related->fcb->inode, related->fcb->inode_item.st_size);
1677  related->fcb->inode_item.sequence++;
1678  related->fcb->inode_item.st_ctime = now;
1679  related->fcb->inode_item.st_mtime = now;
1680 
1681  related->fcb->inode_item_changed = TRUE;
1682  mark_fcb_dirty(related->fcb);
1684 
1685  FsRtlNotifyFilterReportChange(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, (PSTRING)&oldfn, name_offset, NULL, NULL,
1687  FsRtlNotifyFilterReportChange(fcb->Vcb->NotifySync, &fcb->Vcb->DirNotifyList, (PSTRING)&newfn, name_offset, NULL, NULL,
1689 
1690  ExFreePool(oldfn.Buffer);
1691  ExFreePool(newfn.Buffer);
1692 
1694  goto end;
1695  }
1696 
1697  // We move files by moving the existing fileref to the new directory, and
1698  // replacing it with a dummy fileref with the same original values, but marked as deleted.
1699 
1701 
1702  fr2 = create_fileref(Vcb);
1703 
1704  fr2->fcb = fileref->fcb;
1705  fr2->fcb->refcount++;
1706 
1707  fr2->oldutf8 = fileref->oldutf8;
1708  fr2->oldindex = fileref->dc->index;
1709  fr2->delete_on_close = fileref->delete_on_close;
1710  fr2->deleted = TRUE;
1711  fr2->created = fileref->created;
1712  fr2->parent = fileref->parent;
1713  fr2->dc = NULL;
1714 
1715  if (!fr2->oldutf8.Buffer) {
1716  fr2->oldutf8.Buffer = ExAllocatePoolWithTag(PagedPool, fileref->dc->utf8.Length, ALLOC_TAG);
1717  if (!fr2->oldutf8.Buffer) {
1718  ERR("out of memory\n");
1720  goto end;
1721  }
1722 
1723  RtlCopyMemory(fr2->oldutf8.Buffer, fileref->dc->utf8.Buffer, fileref->dc->utf8.Length);
1724 
1725  fr2->oldutf8.Length = fr2->oldutf8.MaximumLength = fileref->dc->utf8.Length;
1726  }
1727 
1728  if (fr2->fcb->type == BTRFS_TYPE_DIRECTORY)
1729  fr2->fcb->fileref = fr2;
1730 
1732  fileref->fcb->subvol->parent = related->fcb->subvol->id;
1733 
1736  fileref->deleted = FALSE;
1737  fileref->created = TRUE;
1738  fileref->parent = related;
1739 
1740  ExAcquireResourceExclusiveLite(&fileref->parent->fcb->nonpaged->dir_children_lock, TRUE);
1741  InsertHeadList(&fileref->list_entry, &fr2->list_entry);
1743  ExReleaseResourceLite(&fileref->parent->fcb->nonpaged->dir_children_lock);
1744 
1745  mark_fileref_dirty(fr2);
1747 
1748  if (fileref->dc) {
1749  // remove from old parent
1750  ExAcquireResourceExclusiveLite(&fr2->parent->fcb->nonpaged->dir_children_lock, TRUE);
1752  remove_dir_child_from_hash_lists(fr2->parent->fcb, fileref->dc);
1753  ExReleaseResourceLite(&fr2->parent->fcb->nonpaged->dir_children_lock);
1754 
1755  if (fileref->dc->utf8.Length != utf8.Length || RtlCompareMemory(fileref->dc->utf8.Buffer, utf8.Buffer, utf8.Length) != utf8.Length) {
1756  // handle changed name
1757 
1761 
1763  if (!fileref->dc->utf8.Buffer) {
1764  ERR("out of memory\n");
1766  goto end;
1767  }
1768 
1770  RtlCopyMemory(fileref->dc->utf8.Buffer, utf8.Buffer, utf8.Length);
1771 
1773  if (!fileref->dc->name.Buffer) {
1774  ERR("out of memory\n");
1776  goto end;
1777  }
1778 
1780  RtlCopyMemory(fileref->dc->name.Buffer, fnus.Buffer, fnus.Length);
1781 
1783  if (!NT_SUCCESS(Status)) {
1784  ERR("RtlUpcaseUnicodeString returned %08x\n", Status);
1785  goto end;
1786  }
1787 
1788  fileref->dc->hash = calc_crc32c(0xffffffff, (UINT8*)fileref->dc->name.Buffer, fileref->dc->name.Length);
1790  }
1791 
1792  // add to new parent
1793  ExAcquireResourceExclusiveLite(&related->fcb->nonpaged->dir_children_lock, TRUE);
1794 
1795  if (IsListEmpty(&related->fcb->dir_children_index))
1796  fileref->dc->index = 2;
1797  else {
1798  dir_child* dc2 = CONTAINING_RECORD(related->fcb->dir_children_index.Blink, dir_child, list_entry_index);
1799 
1800  fileref->dc->index = max(2, dc2->index + 1);
1801  }
1802 
1803  InsertTailList(&related->fcb->dir_children_index, &fileref->dc->list_entry_index);
1805  ExReleaseResourceLite(&related->fcb->nonpaged->dir_children_lock);
1806  }
1807 
1808  ExAcquireResourceExclusiveLite(&related->fcb->nonpaged->dir_children_lock, TRUE);
1809  InsertTailList(&related->children, &fileref->list_entry);
1810  ExReleaseResourceLite(&related->fcb->nonpaged->dir_children_lock);
1811 
1812  if (fcb->inode_item.st_nlink > 1) {
1813  // add new hardlink entry to fcb
1814 
1816  if (!hl) {
1817  ERR("out of memory\n");
1819  goto end;
1820  }
1821 
1822  hl->parent = related->fcb->inode;
1823  hl->index = fileref->dc->index;
1824 
1825  hl->name.Length = hl->name.MaximumLength = fnus.Length;
1827 
1828  if (!hl->name.Buffer) {
1829  ERR("out of memory\n");
1830  ExFreePool(hl);
1832  goto end;
1833  }
1834 
1835  RtlCopyMemory(hl->name.Buffer, fnus.Buffer, fnus.Length);
1836 
1839 
1840  if (!hl->utf8.Buffer) {
1841  ERR("out of memory\n");
1842  ExFreePool(hl->name.Buffer);
1843  ExFreePool(hl);
1845  goto end;
1846  }
1847 
1849 
1851  }
1852 
1853  // delete old hardlink entry from fcb
1854 
1855  le = fcb->hardlinks.Flink;
1856  while (le != &fcb->hardlinks) {
1858 
1859  if (hl->parent == fr2->parent->fcb->inode && hl->index == fr2->oldindex) {
1861 
1862  if (hl->utf8.Buffer)
1863  ExFreePool(hl->utf8.Buffer);
1864 
1865  if (hl->name.Buffer)
1866  ExFreePool(hl->name.Buffer);
1867 
1868  ExFreePool(hl);
1869  break;
1870  }
1871 
1872  le = le->Flink;
1873  }
1874 
1875  // update inode's INODE_ITEM
1876 
1879 
1880  if (fcb != Vcb->dummy_fcb && (fileref->parent->fcb->subvol == fcb->subvol || !is_subvol_readonly(fcb->subvol, Irp))) {
1881  fcb->inode_item.transid = Vcb->superblock.generation;
1882  fcb->inode_item.sequence++;
1883 
1884  if (!ccb->user_set_change_time)
1886 
1889  }
1890 
1891  // update new parent's INODE_ITEM
1892 
1893  related->fcb->inode_item.transid = Vcb->superblock.generation;
1894  TRACE("related->fcb->inode_item.st_size (inode %llx) was %llx\n", related->fcb->inode, related->fcb->inode_item.st_size);
1895  related->fcb->inode_item.st_size += 2 * utf8len;
1896  TRACE("related->fcb->inode_item.st_size (inode %llx) now %llx\n", related->fcb->inode, related->fcb->inode_item.st_size);
1897  related->fcb->inode_item.sequence++;
1898  related->fcb->inode_item.st_ctime = now;
1899  related->fcb->inode_item.st_mtime = now;
1900 
1901  related->fcb->inode_item_changed = TRUE;
1902  mark_fcb_dirty(related->fcb);
1903 
1904  // update old parent's INODE_ITEM
1905 
1906  fr2->parent->fcb->inode_item.transid = Vcb->superblock.generation;
1907  TRACE("fr2->parent->fcb->inode_item.st_size (inode %llx) was %llx\n", fr2->parent->fcb->inode, fr2->parent->fcb->inode_item.st_size);
1908  fr2->parent->fcb->inode_item.st_size -= 2 * origutf8len;
1909  TRACE("fr2->parent->fcb->inode_item.st_size (inode %llx) now %llx\n", fr2->parent->fcb->inode, fr2->parent->fcb->inode_item.st_size);
1910  fr2->parent->fcb->inode_item.sequence++;
1911  fr2->parent->fcb->inode_item.st_ctime = now;
1912  fr2->parent->fcb->inode_item.st_mtime = now;
1913 
1914  free_fileref(fr2);
1915 
1916  fr2->parent->fcb->inode_item_changed = TRUE;
1917  mark_fcb_dirty(fr2->parent->fcb);
1918 
1922 
1924 
1925 end:
1926  if (oldfileref)
1927  free_fileref(oldfileref);
1928 
1929  if (!NT_SUCCESS(Status) && related)
1930  free_fileref(related);
1931 
1932  if (!NT_SUCCESS(Status) && fr2)
1933  free_fileref(fr2);
1934 
1935  if (NT_SUCCESS(Status))
1937  else
1939 
1940  ExReleaseResourceLite(fcb->Header.Resource);
1941  ExReleaseResourceLite(&Vcb->fileref_lock);
1942  ExReleaseResourceLite(&Vcb->tree_lock);
1943 
1944  return Status;
1945 }
1946 
1949  BTRFS_TIME now;
1950 
1951  TRACE("setting new end to %llx bytes (currently %x)\n", end, fcb->adsdata.Length);
1952 
1953  if (!fileref || !fileref->parent) {
1954  ERR("no fileref for stream\n");
1955  return STATUS_INTERNAL_ERROR;
1956  }
1957 
1958  if (end < fcb->adsdata.Length) {
1959  if (advance_only)
1960  return STATUS_SUCCESS;
1961 
1962  TRACE("truncating stream to %llx bytes\n", end);
1963 
1964  fcb->adsdata.Length = end;
1965  } else if (end > fcb->adsdata.Length) {
1966  TRACE("extending stream to %llx bytes\n", end);
1967 
1968  if (end > fcb->adsmaxlen) {
1969  ERR("error - xattr too long (%u > %u)\n", end, fcb->adsmaxlen);
1970  return STATUS_DISK_FULL;
1971  }
1972 
1973  if (end > fcb->adsdata.MaximumLength) {
1975  if (!data) {
1976  ERR("out of memory\n");
1977  ExFreePool(data);
1979  }
1980 
1981  if (fcb->adsdata.Buffer) {
1984  }
1985 
1986  fcb->adsdata.Buffer = data;
1988  }
1989 
1991 
1992  fcb->adsdata.Length = end;
1993  }
1994 
1996 
1997  fcb->Header.AllocationSize.QuadPart = end;
1998  fcb->Header.FileSize.QuadPart = end;
1999  fcb->Header.ValidDataLength.QuadPart = end;
2000 
2003 
2004  fileref->parent->fcb->inode_item.transid = Vcb->superblock.generation;
2005  fileref->parent->fcb->inode_item.sequence++;
2006  fileref->parent->fcb->inode_item.st_ctime = now;
2007 
2008  fileref->parent->fcb->inode_item_changed = TRUE;
2009  mark_fcb_dirty(fileref->parent->fcb);
2010 
2011  fileref->parent->fcb->subvol->root_item.ctransid = Vcb->superblock.generation;
2012  fileref->parent->fcb->subvol->root_item.ctime = now;
2013 
2014  return STATUS_SUCCESS;
2015 }
2016 
2018  FILE_END_OF_FILE_INFORMATION* feofi = Irp->AssociatedIrp.SystemBuffer;
2019  fcb* fcb = FileObject->FsContext;
2020  ccb* ccb = FileObject->FsContext2;
2021  file_ref* fileref = ccb ? ccb->fileref : NULL;
2022  NTSTATUS Status;
2024  CC_FILE_SIZES ccfs;
2026  BOOL set_size = FALSE;
2027  ULONG filter;
2028 
2029  if (!fileref) {
2030  ERR("fileref is NULL\n");
2031  return STATUS_INVALID_PARAMETER;
2032  }
2033 
2035 
2036  ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
2037 
2039 
2040  if (fileref ? fileref->deleted : fcb->deleted) {
2042  goto end;
2043  }
2044 
2045  if (fcb->ads) {
2046  if (feofi->EndOfFile.QuadPart > 0xffff) {
2048  goto end;
2049  }
2050 
2051  if (feofi->EndOfFile.QuadPart < 0) {
2053  goto end;
2054  }
2055 
2057 
2058  if (NT_SUCCESS(Status)) {
2059  ccfs.AllocationSize = fcb->Header.AllocationSize;
2060  ccfs.FileSize = fcb->Header.FileSize;
2061  ccfs.ValidDataLength = fcb->Header.ValidDataLength;
2062  set_size = TRUE;
2063  }
2064 
2066 
2067  if (!ccb->user_set_write_time) {
2069  win_time_to_unix(time, &fileref->parent->fcb->inode_item.st_mtime);
2071 
2072  fileref->parent->fcb->inode_item_changed = TRUE;
2073  mark_fcb_dirty(fileref->parent->fcb);
2074  }
2075 
2077 
2078  goto end;
2079  }
2080 
2081  TRACE("file: %S\n", file_desc(FileObject));
2082  TRACE("paging IO: %s\n", Irp->Flags & IRP_PAGING_IO ? "TRUE" : "FALSE");
2083  TRACE("FileObject: AllocationSize = %llx, FileSize = %llx, ValidDataLength = %llx\n",
2084  fcb->Header.AllocationSize.QuadPart, fcb->Header.FileSize.QuadPart, fcb->Header.ValidDataLength.QuadPart);
2085 
2086  TRACE("setting new end to %llx bytes (currently %llx)\n", feofi->EndOfFile.QuadPart, fcb->inode_item.st_size);
2087 
2088  if ((UINT64)feofi->EndOfFile.QuadPart < fcb->inode_item.st_size) {
2089  if (advance_only) {
2091  goto end;
2092  }
2093 
2094  TRACE("truncating file to %llx bytes\n", feofi->EndOfFile.QuadPart);
2095 
2096  if (!MmCanFileBeTruncated(&fcb->nonpaged->segment_object, &feofi->EndOfFile)) {
2098  goto end;
2099  }
2100 
2102  if (!NT_SUCCESS(Status)) {
2103  ERR("error - truncate_file failed\n");
2104  goto end;
2105  }
2106  } else if ((UINT64)feofi->EndOfFile.QuadPart > fcb->inode_item.st_size) {
2107  if (Irp->Flags & IRP_PAGING_IO) {
2108  TRACE("paging IO tried to extend file size\n");
2110  goto end;
2111  }
2112 
2113  TRACE("extending file to %llx bytes\n", feofi->EndOfFile.QuadPart);
2114 
2116  if (!NT_SUCCESS(Status)) {
2117  ERR("error - extend_file failed\n");
2118  goto end;
2119  }
2120  } else if ((UINT64)feofi->EndOfFile.QuadPart == fcb->inode_item.st_size && advance_only) {
2122  goto end;
2123  }
2124 
2125  ccfs.AllocationSize = fcb->Header.AllocationSize;
2126  ccfs.FileSize = fcb->Header.FileSize;
2127  ccfs.ValidDataLength = fcb->Header.ValidDataLength;
2128  set_size = TRUE;
2129 
2131 
2132  if (!ccb->user_set_write_time) {
2136  }
2137 
2141 
2143 
2144 end:
2145  if (NT_SUCCESS(Status))
2147  else
2149 
2150  ExReleaseResourceLite(fcb->Header.Resource);
2151 
2152  if (set_size) {
2153  _SEH2_TRY {
2154  CcSetFileSizes(FileObject, &ccfs);
2157  } _SEH2_END;
2158 
2159  if (!NT_SUCCESS(Status))
2160  ERR("CcSetFileSizes threw exception %08x\n", Status);
2161  }
2162 
2163  ExReleaseResourceLite(&Vcb->tree_lock);
2164 
2165  return Status;
2166 }
2167 
2169  FILE_POSITION_INFORMATION* fpi = (FILE_POSITION_INFORMATION*)Irp->AssociatedIrp.SystemBuffer;
2170 
2171  TRACE("setting the position on %S to %llx\n", file_desc(FileObject), fpi->CurrentByteOffset.QuadPart);
2172 
2173  // FIXME - make sure aligned for FO_NO_INTERMEDIATE_BUFFERING
2174 
2175  FileObject->CurrentByteOffset = fpi->CurrentByteOffset;
2176 
2177  return STATUS_SUCCESS;
2178 }
2179 
2181  FILE_LINK_INFORMATION* fli = Irp->AssociatedIrp.SystemBuffer;
2182  fcb *fcb = FileObject->FsContext, *tfofcb, *parfcb;
2183  ccb* ccb = FileObject->FsContext2;
2184  file_ref *fileref = ccb ? ccb->fileref : NULL, *oldfileref = NULL, *related = NULL, *fr2 = NULL;
2185  WCHAR* fn;
2186  ULONG fnlen, utf8len;
2187  UNICODE_STRING fnus;
2188  ANSI_STRING utf8;
2189  NTSTATUS Status;
2191  BTRFS_TIME now;
2193  hardlink* hl;
2195  SECURITY_SUBJECT_CONTEXT subjcont;
2196  dir_child* dc = NULL;
2197 
2199 
2200  // FIXME - check fli length
2201  // FIXME - don't ignore fli->RootDirectory
2202 
2203  TRACE("ReplaceIfExists = %x\n", fli->ReplaceIfExists);
2204  TRACE("RootDirectory = %p\n", fli->RootDirectory);
2205  TRACE("FileNameLength = %x\n", fli->FileNameLength);
2206  TRACE("FileName = %.*S\n", fli->FileNameLength / sizeof(WCHAR), fli->FileName);
2207 
2208  fn = fli->FileName;
2209  fnlen = fli->FileNameLength / sizeof(WCHAR);
2210 
2211  if (!tfo) {
2212  if (!fileref || !fileref->parent) {
2213  ERR("no fileref set and no directory given\n");
2214  return STATUS_INVALID_PARAMETER;
2215  }
2216 
2217  parfcb = fileref->parent->fcb;
2218  tfofcb = NULL;
2219  } else {
2220  LONG i;
2221 
2222  tfofcb = tfo->FsContext;
2223  parfcb = tfofcb;
2224 
2225  while (fnlen > 0 && (fli->FileName[fnlen - 1] == '/' || fli->FileName[fnlen - 1] == '\\'))
2226  fnlen--;
2227 
2228  if (fnlen == 0)
2229  return STATUS_INVALID_PARAMETER;
2230 
2231  for (i = fnlen - 1; i >= 0; i--) {
2232  if (fli->FileName[i] == '\\' || fli->FileName[i] == '/') {
2233  fn = &fli->FileName[i+1];
2234  fnlen = (fli->FileNameLength / sizeof(WCHAR)) - i - 1;
2235  break;
2236  }
2237  }
2238  }
2239 
2240  ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
2241  ExAcquireResourceExclusiveLite(&Vcb->fileref_lock, TRUE);
2243 
2244  if (fcb->type == BTRFS_TYPE_DIRECTORY) {
2245  WARN("tried to create hard link on directory\n");
2247  goto end;
2248  }
2249 
2250  if (fcb->ads) {
2251  WARN("tried to create hard link on stream\n");
2253  goto end;
2254  }
2255 
2256  if (fcb->inode_item.st_nlink >= 65535) {
2258  goto end;
2259  }
2260 
2261  fnus.Buffer = fn;
2262  fnus.Length = fnus.MaximumLength = (UINT16)(fnlen * sizeof(WCHAR));
2263 
2264  TRACE("fnus = %.*S\n", fnus.Length / sizeof(WCHAR), fnus.Buffer);
2265 
2266  Status = RtlUnicodeToUTF8N(NULL, 0, &utf8len, fn, (ULONG)fnlen * sizeof(WCHAR));
2267  if (!NT_SUCCESS(Status))
2268  goto end;
2269 
2270  utf8.MaximumLength = utf8.Length = (UINT16)utf8len;
2272  if (!utf8.Buffer) {
2273  ERR("out of memory\n");
2275  goto end;
2276  }
2277 
2278  Status = RtlUnicodeToUTF8N(utf8.Buffer, utf8len, &utf8len, fn, (ULONG)fnlen * sizeof(WCHAR));
2279  if (!NT_SUCCESS(Status))
2280  goto end;
2281 
2282  if (tfo && tfo->FsContext2) {
2283  struct _ccb* relatedccb = tfo->FsContext2;
2284 
2285  related = relatedccb->fileref;
2286  increase_fileref_refcount(related);
2287  }
2288 
2289  Status = open_fileref(Vcb, &oldfileref, &fnus, related, FALSE, NULL, NULL, PagedPool, ccb->case_sensitive, Irp);
2290 
2291  if (NT_SUCCESS(Status)) {
2292  if (!oldfileref->deleted) {
2293  WARN("destination file %S already exists\n", file_desc_fileref(oldfileref));
2294 
2295  if (!fli->ReplaceIfExists) {
2297  goto end;
2298  } else if (oldfileref->open_count >= 1 && !oldfileref->deleted) {
2299  WARN("trying to overwrite open file\n");
2301  goto end;
2302  } else if (fileref == oldfileref) {
2304  goto end;
2305  }
2306 
2307  if (oldfileref->fcb->type == BTRFS_TYPE_DIRECTORY) {
2308  WARN("trying to overwrite directory\n");
2310  goto end;
2311  }
2312  } else {
2313  free_fileref(oldfileref);
2314  oldfileref = NULL;
2315  }
2316  }
2317 
2318  if (!related) {
2319  Status = open_fileref(Vcb, &related, &fnus, NULL, TRUE, NULL, NULL, PagedPool, ccb->case_sensitive, Irp);
2320 
2321  if (!NT_SUCCESS(Status)) {
2322  ERR("open_fileref returned %08x\n", Status);
2323  goto end;
2324  }
2325  }
2326 
2327  SeCaptureSubjectContext(&subjcont);
2328 
2329  if (!SeAccessCheck(related->fcb->sd, &subjcont, FALSE, FILE_ADD_FILE, 0, NULL,
2330  IoGetFileObjectGenericMapping(), Irp->RequestorMode, &access, &Status)) {
2331  SeReleaseSubjectContext(&subjcont);
2332  TRACE("SeAccessCheck failed, returning %08x\n", Status);
2333  goto end;
2334  }
2335 
2336  SeReleaseSubjectContext(&subjcont);
2337 
2338  if (fcb->subvol != parfcb->subvol) {
2339  WARN("can't create hard link over subvolume boundary\n");
2341  goto end;
2342  }
2343 
2344  if (oldfileref) {
2345  SeCaptureSubjectContext(&subjcont);
2346 
2347  if (!SeAccessCheck(oldfileref->fcb->sd, &subjcont, FALSE, DELETE, 0, NULL,
2348  IoGetFileObjectGenericMapping(), Irp->RequestorMode, &access, &Status)) {
2349  SeReleaseSubjectContext(&subjcont);
2350  TRACE("SeAccessCheck failed, returning %08x\n", Status);
2351  goto end;
2352  }
2353 
2354  SeReleaseSubjectContext(&subjcont);
2355 
2356  Status = delete_fileref(oldfileref, NULL, Irp, &rollback);
2357  if (!NT_SUCCESS(Status)) {
2358  ERR("delete_fileref returned %08x\n", Status);
2359  goto end;
2360  }
2361  }
2362 
2363  fr2 = create_fileref(Vcb);
2364 
2365  fr2->fcb = fcb;
2366  fcb->refcount++;
2367 
2368  fr2->created = TRUE;
2369  fr2->parent = related;
2370 
2371  Status = add_dir_child(related->fcb, fcb->inode, FALSE, &utf8, &fnus, fcb->type, &dc);
2372  if (!NT_SUCCESS(Status))
2373  WARN("add_dir_child returned %08x\n", Status);
2374 
2375  fr2->dc = dc;
2376  dc->fileref = fr2;
2377 
2378  ExAcquireResourceExclusiveLite(&related->fcb->nonpaged->dir_children_lock, TRUE);
2379  InsertTailList(&related->children, &fr2->list_entry);
2380  ExReleaseResourceLite(&related->fcb->nonpaged->dir_children_lock);
2381 
2382  // add hardlink for existing fileref, if it's not there already
2383  if (IsListEmpty(&fcb->hardlinks)) {
2385  if (!hl) {
2386  ERR("out of memory\n");
2388  goto end;
2389  }
2390 
2391  hl->parent = fileref->parent->fcb->inode;
2392  hl->index = fileref->dc->index;
2393 
2394  hl->name.Length = hl->name.MaximumLength = fnus.Length;
2396 
2397  if (!hl->name.Buffer) {
2398  ERR("out of memory\n");
2399  ExFreePool(hl);
2401  goto end;
2402  }
2403 
2404  RtlCopyMemory(hl->name.Buffer, fnus.Buffer, fnus.Length);
2405 
2408 
2409  if (!hl->utf8.Buffer) {
2410  ERR("out of memory\n");
2411  ExFreePool(hl->name.Buffer);
2412  ExFreePool(hl);
2414  goto end;
2415  }
2416 
2418 
2420  }
2421 
2423  if (!hl) {
2424  ERR("out of memory\n");
2426  goto end;
2427  }
2428 
2429  hl->parent = related->fcb->inode;
2430  hl->index = dc->index;
2431 
2432  hl->name.Length = hl->name.MaximumLength = fnus.Length;
2434 
2435  if (!hl->name.Buffer) {
2436  ERR("out of memory\n");
2437  ExFreePool(hl);
2439  goto end;
2440  }
2441 
2442  RtlCopyMemory(hl->name.Buffer, fnus.Buffer, fnus.Length);
2443 
2444  hl->utf8.Length = hl->utf8.MaximumLength = utf8.Length;
2446 
2447  if (!hl->utf8.Buffer) {
2448  ERR("out of memory\n");
2449  ExFreePool(hl->name.Buffer);
2450  ExFreePool(hl);
2452  goto end;
2453  }
2454 
2455  RtlCopyMemory(hl->utf8.Buffer, utf8.Buffer, utf8.Length);
2456  ExFreePool(utf8.Buffer);
2457 
2459 
2460  mark_fileref_dirty(fr2);
2461  free_fileref(fr2);
2462 
2463  // update inode's INODE_ITEM
2464 
2467 
2468  fcb->inode_item.transid = Vcb->superblock.generation;
2469  fcb->inode_item.sequence++;
2470  fcb->inode_item.st_nlink++;
2471 
2472  if (!ccb->user_set_change_time)
2474 
2477 
2478  // update parent's INODE_ITEM
2479 
2480  parfcb->inode_item.transid = Vcb->superblock.generation;
2481  TRACE("parfcb->inode_item.st_size (inode %llx) was %llx\n", parfcb->inode, parfcb->inode_item.st_size);
2482  parfcb->inode_item.st_size += 2 * utf8len;
2483  TRACE("parfcb->inode_item.st_size (inode %llx) now %llx\n", parfcb->inode, parfcb->inode_item.st_size);
2484  parfcb->inode_item.sequence++;
2485  parfcb->inode_item.st_ctime = now;
2486 
2487  parfcb->inode_item_changed = TRUE;
2488  mark_fcb_dirty(parfcb);
2489 
2491 
2493 
2494 end:
2495  if (oldfileref)
2496  free_fileref(oldfileref);
2497 
2498  if (!NT_SUCCESS(Status) && related)
2499  free_fileref(related);
2500 
2501  if (!NT_SUCCESS(Status) && fr2)
2502  free_fileref(fr2);
2503 
2504  if (NT_SUCCESS(Status))
2506  else
2508 
2509  ExReleaseResourceLite(fcb->Header.Resource);
2510  ExReleaseResourceLite(&Vcb->fileref_lock);
2511  ExReleaseResourceLite(&Vcb->tree_lock);
2512 
2513  return Status;
2514 }
2515 
2517  FILE_VALID_DATA_LENGTH_INFORMATION* fvdli = Irp->AssociatedIrp.SystemBuffer;
2519  fcb* fcb = FileObject->FsContext;
2520  ccb* ccb = FileObject->FsContext2;
2521  file_ref* fileref = ccb ? ccb->fileref : NULL;
2522  NTSTATUS Status;
2524  CC_FILE_SIZES ccfs;
2526  BOOL set_size = FALSE;
2527  ULONG filter;
2528 
2529  if (IrpSp->Parameters.SetFile.Length < sizeof(FILE_VALID_DATA_LENGTH_INFORMATION)) {
2530  ERR("input buffer length was %u, expected %u\n", IrpSp->Parameters.SetFile.Length, sizeof(FILE_VALID_DATA_LENGTH_INFORMATION));
2531  return STATUS_INVALID_PARAMETER;
2532  }
2533 
2534  if (!fileref) {
2535  ERR("fileref is NULL\n");
2536  return STATUS_INVALID_PARAMETER;
2537  }
2538 
2540 
2541  ExAcquireResourceSharedLite(&Vcb->tree_lock, TRUE);
2542 
2544 
2547  goto end;
2548  }
2549 
2550  if (fvdli->ValidDataLength.QuadPart <= fcb->Header.ValidDataLength.QuadPart || fvdli->ValidDataLength.QuadPart > fcb->Header.FileSize.QuadPart) {
2551  TRACE("invalid VDL of %llu (current VDL = %llu, file size = %llu)\n", fvdli->ValidDataLength.QuadPart,
2552  fcb->Header.ValidDataLength.QuadPart, fcb->Header.FileSize.QuadPart);
2554  goto end;
2555  }
2556 
2557  if (fileref ? fileref->deleted : fcb->deleted) {
2559  goto end;
2560  }
2561 
2562  // This function doesn't really do anything - the fsctl can only increase the value of ValidDataLength,
2563  // and we set it to the max anyway.
2564 
2565  ccfs.AllocationSize = fcb->Header.AllocationSize;
2566  ccfs.FileSize = fcb->Header.FileSize;
2567  ccfs.ValidDataLength = fvdli->ValidDataLength;
2568  set_size = TRUE;
2569 
2571 
2572  if (!ccb->user_set_write_time) {
2576  }
2577 
2580 
2582 
2584 
2585 end:
2586  if (NT_SUCCESS(Status))
2588  else
2590 
2591  ExReleaseResourceLite(fcb->Header.Resource);
2592 
2593  if (set_size) {
2594  _SEH2_TRY {
2595  CcSetFileSizes(FileObject, &ccfs);
2598  } _SEH2_END;
2599 
2600  if (!NT_SUCCESS(Status))
2601  ERR("CcSetFileSizes threw exception %08x\n", Status);
2602  else
2603  fcb->Header.AllocationSize = ccfs.AllocationSize;
2604  }
2605 
2606  ExReleaseResourceLite(&Vcb->tree_lock);
2607 
2608  return Status;
2609 }
2610 
2613 NTSTATUS NTAPI drv_set_information(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
2614  NTSTATUS Status;
2617  fcb* fcb = IrpSp->FileObject->FsContext;
2618  ccb* ccb = IrpSp->FileObject->FsContext2;
2619  BOOL top_level;
2620 
2622 
2623  top_level = is_top_level(Irp);
2624 
2625  Irp->IoStatus.Information = 0;
2626 
2627  if (Vcb && Vcb->type == VCB_TYPE_VOLUME) {
2629  goto end;
2630  } else if (!Vcb || Vcb->type != VCB_TYPE_FS) {
2632  goto end;
2633  }
2634 
2635  if (!(Vcb->Vpb->Flags & VPB_MOUNTED)) {
2637  goto end;
2638  }
2639 
2640  if (Vcb->readonly && IrpSp->Parameters.SetFile.FileInformationClass != FilePositionInformation) {
2642  goto end;
2643  }
2644 
2645  if (!fcb) {
2646  ERR("no fcb\n");
2648  goto end;
2649  }
2650 
2651  if (!ccb) {
2652  ERR("no ccb\n");
2654  goto end;
2655  }
2656 
2657  if (fcb != Vcb->dummy_fcb && is_subvol_readonly(fcb->subvol, Irp) && IrpSp->Parameters.SetFile.FileInformationClass != FilePositionInformation &&
2658  (fcb->inode != SUBVOL_ROOT_INODE || (IrpSp->Parameters.SetFile.FileInformationClass != FileBasicInformation && IrpSp->Parameters.SetFile.FileInformationClass != FileRenameInformation))) {
2660  goto end;
2661  }
2662 
2664 
2665  TRACE("set information\n");
2666 
2667  switch (IrpSp->Parameters.SetFile.FileInformationClass) {
2669  {
2670  TRACE("FileAllocationInformation\n");
2671 
2672  if (Irp->RequestorMode == UserMode && !(ccb->access & FILE_WRITE_DATA)) {
2673  WARN("insufficient privileges\n");
2675  break;
2676  }
2677 
2679  break;
2680  }
2681 
2682  case FileBasicInformation:
2683  {
2684  TRACE("FileBasicInformation\n");
2685 
2686  if (Irp->RequestorMode == UserMode && !(ccb->access & FILE_WRITE_ATTRIBUTES)) {
2687  WARN("insufficient privileges\n");
2689  break;
2690  }
2691 
2693 
2694  break;
2695  }
2696 
2698  {
2699  TRACE("FileDispositionInformation\n");
2700 
2701  if (Irp->RequestorMode == UserMode && !(ccb->access & DELETE)) {
2702  WARN("insufficient privileges\n");
2704  break;
2705  }
2706 
2708 
2709  break;
2710  }
2711 
2713  {
2714  TRACE("FileEndOfFileInformation\n");
2715 
2716  if (Irp->RequestorMode == UserMode && !(ccb->access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) {
2717  WARN("insufficient privileges\n");
2719  break;
2720  }
2721 
2723 
2724  break;
2725  }
2726 
2727  case FileLinkInformation:
2728  TRACE("FileLinkInformation\n");
2729  Status = set_link_information(Vcb, Irp, IrpSp->FileObject, IrpSp->Parameters.SetFile.FileObject);
2730  break;
2731 
2733  TRACE("FilePositionInformation\n");
2735  break;
2736 
2737  case FileRenameInformation:
2738  TRACE("FileRenameInformation\n");
2739  // FIXME - make this work with streams
2740  Status = set_rename_information(Vcb, Irp, IrpSp->FileObject, IrpSp->Parameters.SetFile.FileObject);
2741  break;
2742 
2744  {
2745  TRACE("FileValidDataLengthInformation\n");
2746 
2747  if (Irp->RequestorMode == UserMode && !(ccb->access & (FILE_WRITE_DATA | FILE_APPEND_DATA))) {
2748  WARN("insufficient privileges\n");
2750  break;
2751  }
2752 
2754 
2755  break;
2756  }
2757 
2758  default:
2759  WARN("unknown FileInformationClass %u\n", IrpSp->Parameters.SetFile.FileInformationClass);
2760  }
2761 
2762 end:
2763  Irp->IoStatus.Status = Status;
2764 
2765  TRACE("returning %08x\n", Status);
2766 
2768 
2769  if (top_level)
2771 
2773 
2774  return Status;
2775 }
2776 
2778  RtlZeroMemory(fbi, sizeof(FILE_BASIC_INFORMATION));
2779 
2780  *length -= sizeof(FILE_BASIC_INFORMATION);
2781 
2782  if (fcb == fcb->Vcb->dummy_fcb) {
2784 
2786  fbi->CreationTime = fbi->LastAccessTime = fbi->LastWriteTime = fbi->ChangeTime = time;
2787  } else {
2792  }
2793 
2794  if (fcb->ads) {
2795  if (!fileref || !fileref->parent) {
2796  ERR("no fileref for stream\n");
2797  return STATUS_INTERNAL_ERROR;
2798  } else
2799  fbi->FileAttributes = fileref->parent->fcb->atts == 0 ? FILE_ATTRIBUTE_NORMAL : fileref->parent->fcb->atts;
2800  } else
2802 
2803  return STATUS_SUCCESS;
2804 }
2805 
2807  INODE_ITEM* ii;
2808 
2809  if (*length < (LONG)sizeof(FILE_NETWORK_OPEN_INFORMATION)) {
2810  WARN("overflow\n");
2811  return STATUS_BUFFER_OVERFLOW;
2812  }
2813 
2815 
2817 
2818  if (fcb->ads) {
2819  if (!fileref || !fileref->parent) {
2820  ERR("no fileref for stream\n");
2821  return STATUS_INTERNAL_ERROR;
2822  }
2823 
2824  ii = &fileref->parent->fcb->inode_item;
2825  } else
2826  ii = &fcb->inode_item;
2827 
2828  if (fcb == fcb->Vcb->dummy_fcb) {
2830 
2832  fnoi->CreationTime = fnoi->LastAccessTime = fnoi->LastWriteTime = fnoi->ChangeTime = time;
2833  } else {
2838  }
2839 
2840  if (fcb->ads) {
2842  fnoi->FileAttributes = fileref->parent->fcb->atts == 0 ? FILE_ATTRIBUTE_NORMAL : fileref->parent->fcb->atts;
2843  } else {
2846  fnoi->FileAttributes = fcb->atts == 0 ? FILE_ATTRIBUTE_NORMAL : fcb->atts;
2847  }
2848 
2849  return STATUS_SUCCESS;
2850 }
2851 
2854 
2855  *length -= sizeof(FILE_STANDARD_INFORMATION);
2856 
2857  if (fcb->ads) {
2858  if (!fileref || !fileref->parent) {
2859  ERR("no fileref for stream\n");
2860  return STATUS_INTERNAL_ERROR;
2861  }
2862 
2864  fsi->NumberOfLinks = fileref->parent->fcb->inode_item.st_nlink;
2865  fsi->Directory = FALSE;
2866  } else {
2871  }
2872 
2873  TRACE("length = %llu\n", fsi->EndOfFile.QuadPart);
2874 
2876 
2877  return STATUS_SUCCESS;
2878 }
2879 
2881  *length -= sizeof(FILE_INTERNAL_INFORMATION);
2882 
2884 
2885  return STATUS_SUCCESS;
2886 }
2887 
2889  *length -= sizeof(FILE_EA_INFORMATION);
2890 
2891  /* This value appears to be the size of the structure NTFS stores on disk, and not,
2892  * as might be expected, the size of FILE_FULL_EA_INFORMATION (which is what we store).
2893  * The formula is 4 bytes as a header, followed by 5 + NameLength + ValueLength for each
2894  * item. */
2895 
2896  eai->EaSize = fcb->ealen;
2897 
2898  return STATUS_SUCCESS;
2899 }
2900 
2903 
2904  *length -= sizeof(FILE_POSITION_INFORMATION);
2905 
2906  fpi->CurrentByteOffset = FileObject->CurrentByteOffset;
2907 
2908  return STATUS_SUCCESS;
2909 }
2910 
2912  file_ref* fr;
2913  NTSTATUS Status;
2914  ULONG reqlen = 0;
2915  USHORT offset;
2916  BOOL overflow = FALSE;
2917 
2918  // FIXME - we need a lock on filerefs' filepart
2919 
2920  if (fileref == fileref->fcb->Vcb->root_fileref) {
2921  if (fn->MaximumLength >= sizeof(WCHAR)) {
2922  fn->Buffer[0] = '\\';
2923  fn->Length = sizeof(WCHAR);
2924 
2925  if (name_offset)
2926  *name_offset = 0;
2927 
2928  return STATUS_SUCCESS;
2929  } else {
2930  if (preqlen)
2931  *preqlen = sizeof(WCHAR);
2932  fn->Length = 0;
2933 
2934  return STATUS_BUFFER_OVERFLOW;
2935  }
2936  }
2937 
2938  fr = fileref;
2939  offset = 0;
2940 
2941  while (fr->parent) {
2942  USHORT movelen;
2943 
2944  if (!fr->dc)
2945  return STATUS_INTERNAL_ERROR;
2946 
2947  if (!overflow) {
2948  if (fr->dc->name.Length + sizeof(WCHAR) + fn->Length > fn->MaximumLength)
2949  overflow = TRUE;
2950  }
2951 
2952  if (overflow)
2953  movelen = fn->MaximumLength - fr->dc->name.Length - sizeof(WCHAR);
2954  else
2955  movelen = fn->Length;
2956 
2957  if ((!overflow || fn->MaximumLength > fr->dc->name.Length + sizeof(WCHAR)) && movelen > 0) {
2958  RtlMoveMemory(&fn->Buffer[(fr->dc->name.Length / sizeof(WCHAR)) + 1], fn->Buffer, movelen);
2959  offset += fr->dc->name.Length + sizeof(WCHAR);
2960  }
2961 
2962  if (fn->MaximumLength >= sizeof(WCHAR)) {
2963  fn->Buffer[0] = fr->fcb->ads ? ':' : '\\';
2964  fn->Length += sizeof(WCHAR);
2965 
2966  if (fn->MaximumLength > sizeof(WCHAR)) {
2967  RtlCopyMemory(&fn->Buffer[1], fr->dc->name.Buffer, min(fr->dc->name.Length, fn->MaximumLength - sizeof(WCHAR)));
2968  fn->Length += fr->dc->name.Length;
2969  }
2970 
2971  if (fn->Length > fn->MaximumLength) {
2972  fn->Length = fn->MaximumLength;
2973  overflow = TRUE;
2974  }
2975  }
2976 
2977  reqlen += sizeof(WCHAR) + fr->dc->name.Length;
2978 
2979  fr = fr->parent;
2980  }
2981 
2982  offset += sizeof(WCHAR);
2983 
2984  if (overflow) {
2985  if (preqlen)
2986  *preqlen = reqlen;
2988  } else {
2989  if (name_offset)
2990  *name_offset = offset;
2991 
2993  }
2994 
2995  return Status;
2996 }
2997 
2999  ULONG reqlen;
3001  NTSTATUS Status;
3002  static const WCHAR datasuf[] = {':','$','D','A','T','A',0};
3003  UINT16 datasuflen = sizeof(datasuf) - sizeof(WCHAR);
3004 
3005  if (!fileref) {
3006  ERR("called without fileref\n");
3007  return STATUS_INVALID_PARAMETER;
3008  }
3009 
3011 
3012  TRACE("maximum length is %u\n", *length);
3013  fni->FileNameLength = 0;
3014 
3015  fni->FileName[0] = 0;
3016 
3017  fn.Buffer = fni->FileName;
3018  fn.Length = 0;
3019  fn.MaximumLength = (UINT16)*length;
3020 
3021  Status = fileref_get_filename(fileref, &fn, NULL, &reqlen);
3023  ERR("fileref_get_filename returned %08x\n", Status);
3024  return Status;
3025  }
3026 
3027  if (fcb->ads) {
3029  reqlen += datasuflen;
3030  else {
3031  if (fn.Length + datasuflen > fn.MaximumLength) {
3032  RtlCopyMemory(&fn.Buffer[fn.Length / sizeof(WCHAR)], datasuf, fn.MaximumLength - fn.Length);
3033  reqlen += datasuflen;
3035  } else {
3036  RtlCopyMemory(&fn.Buffer[fn.Length / sizeof(WCHAR)], datasuf, datasuflen);
3037  fn.Length += datasuflen;
3038  }
3039  }
3040  }
3041 
3042  if (Status == STATUS_BUFFER_OVERFLOW) {
3043  *length = -1;
3044  fni->FileNameLength = reqlen;
3045  TRACE("%.*S (truncated)\n", fn.Length / sizeof(WCHAR), fn.Buffer);
3046  } else {
3047  *length -= fn.Length;
3048  fni->FileNameLength = fn.Length;
3049  TRACE("%.*S\n", fn.Length / sizeof(WCHAR), fn.Buffer);
3050  }
3051 
3052  return Status;
3053 }
3054 
3057 
3058  if (fcb->ads) {
3059  if (!ccb->fileref || !ccb->fileref->parent) {
3060  ERR("no fileref for stream\n");
3061  return STATUS_INTERNAL_ERROR;
3062  }
3063 
3064  ati->FileAttributes = ccb->fileref->parent->fcb->atts;
3065  } else
3066  ati->FileAttributes = fcb->atts;
3067 
3069  ati->ReparseTag = 0;
3070  else
3072 
3073  return STATUS_SUCCESS;
3074 }
3075 
3077  LONG reqsize;
3078  LIST_ENTRY* le;
3079  FILE_STREAM_INFORMATION *entry, *lastentry;
3080  NTSTATUS Status;
3081 
3082  static const WCHAR datasuf[] = L":$DATA";
3083  UNICODE_STRING suf;
3084 
3085  if (!fileref) {
3086  ERR("fileref was NULL\n");
3087  return STATUS_INVALID_PARAMETER;
3088  }
3089 
3090  suf.Buffer = (WCHAR*)datasuf;
3091  suf.Length = suf.MaximumLength = sizeof(datasuf) - sizeof(WCHAR);
3092 
3094  reqsize = sizeof(FILE_STREAM_INFORMATION) - sizeof(WCHAR) + suf.Length + sizeof(WCHAR);
3095  else
3096  reqsize = 0;
3097 
3098  ExAcquireResourceSharedLite(&fileref->fcb->nonpaged->dir_children_lock, TRUE);
3099 
3101  while (le != &fileref->fcb->dir_children_index) {
3102  dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index);
3103 
3104  if (dc->index == 0) {
3105  reqsize = (ULONG)sector_align(reqsize, sizeof(LONGLONG));
3106  reqsize += sizeof(FILE_STREAM_INFORMATION) - sizeof(WCHAR) + suf.Length + sizeof(WCHAR) + dc->name.Length;
3107  } else
3108  break;
3109 
3110  le = le->Flink;
3111  }
3112 
3113  TRACE("length = %i, reqsize = %u\n", *length, reqsize);
3114 
3115  if (reqsize > *length) {
3117  goto end;
3118  }
3119 
3120  entry = fsi;
3121  lastentry = NULL;
3122 
3123  if (fileref->fcb->type != BTRFS_TYPE_DIRECTORY) {
3124  ULONG off;
3125 
3126  entry->NextEntryOffset = 0;
3127  entry->StreamNameLength = suf.Length + sizeof(WCHAR);
3128  entry->StreamSize.QuadPart = fileref->fcb->inode_item.st_size;
3129  entry->StreamAllocationSize.QuadPart = fcb_alloc_size(fileref->fcb);
3130 
3131  entry->StreamName[0] = ':';
3132  RtlCopyMemory(&entry->StreamName[1], suf.Buffer, suf.Length);
3133 
3134  off = (ULONG)sector_align(sizeof(FILE_STREAM_INFORMATION) - sizeof(WCHAR) + suf.Length + sizeof(WCHAR), sizeof(LONGLONG));
3135 
3136  lastentry = entry;
3138  }
3139 
3141  while (le != &fileref->fcb->dir_children_index) {
3142  dir_child* dc = CONTAINING_RECORD(le, dir_child, list_entry_index);
3143 
3144  if (dc->index == 0) {
3145  ULONG off;
3146 
3147  entry->NextEntryOffset = 0;
3148  entry->StreamNameLength = dc->name.Length + suf.Length + sizeof(WCHAR);
3149 
3150  if (dc->fileref)
3151  entry->StreamSize.QuadPart = dc->fileref->fcb->adsdata.Length;
3152  else
3153  entry->StreamSize.QuadPart = dc->size;
3154 
3155  entry->StreamAllocationSize.QuadPart = entry->StreamSize.QuadPart;
3156 
3157  entry->StreamName[0] = ':';
3158 
3159  RtlCopyMemory(&entry->StreamName[1], dc->name.Buffer, dc->name.Length);
3160  RtlCopyMemory(&entry->StreamName[1 + (dc->name.Length / sizeof(WCHAR))], suf.Buffer, suf.Length);
3161 
3162  if (lastentry)
3163  lastentry->NextEntryOffset = (UINT32)((UINT8*)entry - (UINT8*)lastentry);
3164 
3165  off = (ULONG)sector_align(sizeof(FILE_STREAM_INFORMATION) - sizeof(WCHAR) + suf.Length + sizeof(WCHAR) + dc->name.Length, sizeof(LONGLONG));
3166 
3167  lastentry = entry;
3169  } else
3170  break;
3171 
3172  le = le->Flink;
3173  }
3174 
3175  *length -= reqsize;
3176 
3178 
3179 end:
3180  ExReleaseResourceLite(&fileref->fcb->nonpaged->dir_children_lock);
3181 
3182  return Status;
3183 }
3184 
3185 #ifndef __REACTOS__
3187  TRACE("FileStandardLinkInformation\n");
3188 
3189  // FIXME - NumberOfAccessibleLinks should subtract open links which have been marked as delete_on_close
3190 
3194  fsli->Directory = (!fcb->ads && fcb->type == BTRFS_TYPE_DIRECTORY) ? TRUE : FALSE;
3195 
3197 
3198  return STATUS_SUCCESS;
3199 }
3200 
3202  NTSTATUS Status;
3203  LIST_ENTRY* le;
3204  LONG bytes_needed;
3206  BOOL overflow = FALSE;
3207  fcb* fcb = fileref->fcb;
3208  ULONG len;
3209 
3210  if (fcb->ads)
3211  return STATUS_INVALID_PARAMETER;
3212 
3214  return STATUS_INVALID_PARAMETER;
3215 
3216  RtlZeroMemory(fli, *length);
3217 
3218  bytes_needed = offsetof(FILE_LINKS_INFORMATION, Entry);
3219  len = bytes_needed;
3220  feli = NULL;
3221 
3223 
3224  if (fcb->inode == SUBVOL_ROOT_INODE) {
3225  ULONG namelen;
3226 
3227  if (fcb == fcb->Vcb->root_fileref->fcb)
3228  namelen = sizeof(WCHAR);
3229  else
3231 
3232  bytes_needed += sizeof(FILE_LINK_ENTRY_INFORMATION) - sizeof(WCHAR) + namelen;
3233 
3234  if (bytes_needed > *length)
3235  overflow = TRUE;
3236 
3237  if (!overflow) {
3238  feli = &fli->Entry;
3239 
3240  feli->NextEntryOffset = 0;
3241  feli->ParentFileId = 0; // we use an inode of 0 to mean the parent of a subvolume
3242 
3243  if (fcb == fcb->Vcb->root_fileref->fcb) {
3244  feli->FileNameLength = 1;
3245  feli->FileName[0] = '.';
3246  } else {
3247  feli->FileNameLength = fileref->dc->name.Length / sizeof(WCHAR);
3249  }
3250 
3251  fli->EntriesReturned++;
3252 
3253  len = bytes_needed;
3254  }
3255  } else {
3256  ExAcquireResourceExclusiveLite(&fcb->Vcb->fileref_lock, TRUE);
3257 
3258  if (IsListEmpty(&fcb->hardlinks)) {
3259  bytes_needed += sizeof(FILE_LINK_ENTRY_INFORMATION) + fileref->dc->name.Length - sizeof(WCHAR);
3260 
3261  if (bytes_needed > *length)
3262  overflow = TRUE;
3263 
3264  if (!overflow) {
3265  feli = &fli->Entry;
3266 
3267  feli->NextEntryOffset = 0;
3268  feli->ParentFileId = fileref->parent->fcb->inode;
3269  feli->FileNameLength = fileref->dc->name.Length / sizeof(WCHAR);
3271 
3272  fli->EntriesReturned++;
3273 
3274  len = bytes_needed;
3275  }
3276  } else {
3277  le = fcb->hardlinks.Flink;
3278  while (le != &fcb->hardlinks) {
3280  file_ref* parfr;
3281 
3282  TRACE("parent %llx, index %llx, name %.*S\n", hl->parent, hl->index, hl->name.Length / sizeof(WCHAR), hl->name.Buffer);
3283 
3284  Status = open_fileref_by_inode(fcb->Vcb, fcb->subvol, hl->parent, &parfr, Irp);
3285 
3286  if (!NT_SUCCESS(Status)) {
3287  ERR("open_fileref_by_inode returned %08x\n", Status);
3288  } else if (!parfr->deleted) {
3289  LIST_ENTRY* le2;
3290  BOOL found = FALSE, deleted = FALSE;
3291  UNICODE_STRING* fn = NULL;
3292 
3293  le2 = parfr->children.Flink;
3294  while (le2 != &parfr->children) {
3296 
3297  if (fr2->dc->index == hl->index) {
3298  found = TRUE;
3299  deleted = fr2->deleted;
3300 
3301  if (!deleted)
3302  fn = &fr2->dc->name;
3303 
3304  break;
3305  }
3306 
3307  le2 = le2->Flink;
3308  }
3309 
3310  if (!found)
3311  fn = &hl->name;
3312 
3313  if (!deleted) {
3314  TRACE("fn = %.*S (found = %u)\n", fn->Length / sizeof(WCHAR), fn->Buffer, found);
3315 
3316  if (feli)
3317  bytes_needed = (LONG)sector_align(bytes_needed, 8);
3318 
3319  bytes_needed += sizeof(FILE_LINK_ENTRY_INFORMATION) + fn->Length - sizeof(WCHAR);
3320 
3321  if (bytes_needed > *length)
3322  overflow = TRUE;
3323 
3324  if (!overflow) {
3325  if (feli) {
3326  feli->NextEntryOffset = (ULONG)sector_align(sizeof(FILE_LINK_ENTRY_INFORMATION) + ((feli->FileNameLength - 1) * sizeof(WCHAR)), 8);
3327  feli = (FILE_LINK_ENTRY_INFORMATION*)((UINT8*)feli + feli->NextEntryOffset);
3328  } else
3329  feli = &fli->Entry;
3330 
3331  feli->NextEntryOffset = 0;
3332  feli->ParentFileId = parfr->fcb->inode;
3333  feli->FileNameLength = fn->Length / sizeof(WCHAR);
3334  RtlCopyMemory(feli->FileName, fn->Buffer, fn->Length);
3335 
3336  fli->EntriesReturned++;
3337 
3338  len = bytes_needed;
3339  }
3340  }
3341 
3342  free_fileref(parfr);
3343  }
3344 
3345  le = le->Flink;
3346  }
3347  }
3348 
3349  ExReleaseResourceLite(&fcb->Vcb->fileref_lock);
3350  }
3351 
3352  fli->BytesNeeded = bytes_needed;
3353 
3354  *length -= len;
3355 
3357 
3358  ExReleaseResourceLite(fcb->Header.Resource);
3359 
3360  return Status;
3361 }
3362 #endif /* __REACTOS__ */
3363 
3364 #if (NTDDI_VERSION >= NTDDI_WIN10)
3365 #ifdef __MINGW32__
3366 typedef struct _FILE_ID_128 {
3367  UCHAR Identifier[16];
3369 
3370 typedef struct _FILE_ID_INFORMATION {
3374 #endif
3375 
3377  RtlCopyMemory(&fii->VolumeSerialNumber, &fcb->Vcb->superblock.uuid.uuid[8], sizeof(UINT64));
3378  RtlCopyMemory(&fii->FileId.Identifier[0], &fcb->inode, sizeof(UINT64));
3379  RtlCopyMemory(&fii->FileId.Identifier[sizeof(UINT64)], &fcb->subvol->id, sizeof(UINT64));
3380 
3381  *length -= sizeof(FILE_ID_INFORMATION);
3382 
3383  return STATUS_SUCCESS;
3384 }
3385 #endif
3386 
3387 #ifndef __REACTOS__
3389  INODE_ITEM* ii;
3390 
3391  fsli->FileId.LowPart = (UINT32)fcb->inode;
3392  fsli->FileId.HighPart = (UINT32)fcb->subvol->id;
3393 
3394  if (fcb->ads)
3395  ii = &ccb->fileref->parent->fcb->inode_item;
3396  else
3397  ii = &fcb->inode_item;
3398 
3399  if (fcb == fcb->Vcb->dummy_fcb) {
3401 
3403  fsli->CreationTime = fsli->LastAccessTime = fsli->LastWriteTime = fsli->ChangeTime = time;
3404  } else {
3409  }
3410 
3411  if (fcb->ads) {
3413  fsli->FileAttributes = ccb->fileref->parent->fcb->atts == 0 ? FILE_ATTRIBUTE_NORMAL : ccb->fileref->parent->fcb->atts;
3414  } else {
3417  fsli->FileAttributes = fcb->atts == 0 ? FILE_ATTRIBUTE_NORMAL : fcb->atts;
3418  }
3419 
3420  if (fcb->type == BTRFS_TYPE_SOCKET)
3422  else if (fcb->type == BTRFS_TYPE_FIFO)
3424  else if (fcb->type == BTRFS_TYPE_CHARDEV)
3426  else if (fcb->type == BTRFS_TYPE_BLOCKDEV)
3428  else if (!(fsli->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
3429  fsli->ReparseTag = 0;
3430  else
3432 
3435 
3436  if (fcb->ads)
3437  fsli->NumberOfLinks = ccb->fileref->parent->fcb->inode_item.st_nlink;
3438  else
3440 
3441  fsli->EffectiveAccess = ccb->access;
3443  fsli->LxUid = ii->st_uid;
3444  fsli->LxGid = ii->st_gid;
3445  fsli->LxMode = ii->st_mode;
3446 
3447  if (ii->st_mode & __S_IFBLK || ii->st_mode & __S_IFCHR) {
3448  fsli->LxDeviceIdMajor = (ii->st_rdev & 0xFFFFFFFFFFF00000) >> 20;
3449  fsli->LxDeviceIdMinor = (ii->st_rdev & 0xFFFFF);
3450  } else {
3451  fsli->LxDeviceIdMajor = 0;
3452  fsli->LxDeviceIdMinor = 0;
3453  }
3454 
3455  *length -= sizeof(FILE_STAT_LX_INFORMATION);
3456 
3457  return STATUS_SUCCESS;
3458 }
3459 #endif
3460 
3463  LONG length = IrpSp->Parameters.QueryFile.Length;
3464  fcb* fcb = FileObject->FsContext;
3465  ccb* ccb = FileObject->FsContext2;
3466  file_ref* fileref = ccb ? ccb->fileref : NULL;
3467  NTSTATUS Status;
3468 
3469  TRACE("(%p, %p, %p)\n", Vcb, FileObject, Irp);
3470  TRACE("fcb = %p\n", fcb);
3471 
3472  if (fcb == Vcb->volume_fcb)
3473  return STATUS_INVALID_PARAMETER;
3474 
3475  if (!ccb) {
3476