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