ReactOS 0.4.15-dev-7788-g1ad9096
send.c
Go to the documentation of this file.
1/* Copyright (c) Mark Harmstone 2017
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
21typedef struct send_dir {
24 bool dummy;
30 char* name;
33
34typedef struct {
37 bool dir;
39 char tmpname[64];
40} orphan;
41
42typedef struct {
45 char name[1];
47
48typedef struct {
52 char name[1];
53} ref;
54
55typedef struct {
60
61typedef struct {
66} send_ext;
67
68typedef struct {
82
83 struct {
86 bool new;
99 bool file;
100 char* path;
109
110#define MAX_SEND_WRITE 0xc000 // 48 KB
111#define SEND_BUFFER_LENGTH 0x100000 // 1 MB
112
115
118
119 bsc->cmd = cmd;
120 bsc->csum = 0;
121
122 context->datalen += sizeof(btrfs_send_command);
123}
124
127
128 bsc->length = context->datalen - pos - sizeof(btrfs_send_command);
129 bsc->csum = calc_crc32c(0, (uint8_t*)bsc, context->datalen - pos);
130}
131
133 btrfs_send_tlv* tlv = (btrfs_send_tlv*)&context->data[context->datalen];
134
135 tlv->type = type;
136 tlv->length = length;
137
138 if (length > 0 && data)
139 RtlCopyMemory(&tlv[1], data, length);
140
141 context->datalen += sizeof(btrfs_send_tlv) + length;
142}
143
144static char* uint64_to_char(uint64_t num, char* buf) {
145 char *tmp, tmp2[20];
146
147 if (num == 0) {
148 buf[0] = '0';
149 return buf + 1;
150 }
151
152 tmp = &tmp2[20];
153 while (num > 0) {
154 tmp--;
155 *tmp = (num % 10) + '0';
156 num /= 10;
157 }
158
159 RtlCopyMemory(buf, tmp, tmp2 + sizeof(tmp2) - tmp);
160
161 return &buf[tmp2 + sizeof(tmp2) - tmp];
162}
163
165 char *ptr, *ptr2;
166 uint64_t index = 0;
167 KEY searchkey;
168
169 name[0] = 'o';
170
172 *ptr = '-'; ptr++;
174 *ptr = '-'; ptr++;
175 ptr2 = ptr;
176
177 searchkey.obj_id = SUBVOL_ROOT_INODE;
178 searchkey.obj_type = TYPE_DIR_ITEM;
179
180 do {
183
185 *ptr = 0;
186
187 searchkey.offset = calc_crc32c(0xfffffffe, (uint8_t*)name, (ULONG)(ptr - name));
188
189 Status = find_item(context->Vcb, context->root, &tp, &searchkey, false, NULL);
190 if (!NT_SUCCESS(Status)) {
191 ERR("find_item returned %08lx\n", Status);
192 return Status;
193 }
194
195 if (!keycmp(searchkey, tp.item->key))
196 goto cont;
197
198 if (context->parent) {
199 Status = find_item(context->Vcb, context->parent, &tp, &searchkey, false, NULL);
200 if (!NT_SUCCESS(Status)) {
201 ERR("find_item returned %08lx\n", Status);
202 return Status;
203 }
204
205 if (!keycmp(searchkey, tp.item->key))
206 goto cont;
207 }
208
209 return STATUS_SUCCESS;
210
211cont:
212 index++;
213 ptr = ptr2;
214 } while (true);
215}
216
218 LIST_ENTRY* le;
219
220 le = context->orphans.Flink;
221 while (le != &context->orphans) {
223
224 if (o2->inode > o->inode) {
226 return;
227 }
228
229 le = le->Flink;
230 }
231
232 InsertTailList(&context->orphans, &o->list_entry);
233}
234
237 KEY searchkey;
239 EXTENT_DATA* ed;
240
241 searchkey.obj_id = inode;
242 searchkey.obj_type = TYPE_EXTENT_DATA;
243 searchkey.offset = 0;
244
245 Status = find_item(context->Vcb, context->root, &tp, &searchkey, false, NULL);
246 if (!NT_SUCCESS(Status)) {
247 ERR("find_item returned %08lx\n", Status);
248 return Status;
249 }
250
251 if (keycmp(tp.item->key, searchkey)) {
252 ERR("could not find (%I64x,%x,%I64x)\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
254 }
255
256 if (tp.item->size < sizeof(EXTENT_DATA)) {
257 ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset,
258 tp.item->size, sizeof(EXTENT_DATA));
260 }
261
262 ed = (EXTENT_DATA*)tp.item->data;
263
264 if (ed->type != EXTENT_TYPE_INLINE) {
265 WARN("symlink data was not inline, returning blank string\n");
266 *link = NULL;
267 *linklen = 0;
268 return STATUS_SUCCESS;
269 }
270
271 if (tp.item->size < offsetof(EXTENT_DATA, data[0]) + ed->decoded_size) {
272 ERR("(%I64x,%x,%I64x) was %u bytes, expected %I64u\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset,
275 }
276
277 *link = (char*)ed->data;
278 *linklen = (uint16_t)ed->decoded_size;
279
280 return STATUS_SUCCESS;
281}
282
285 INODE_ITEM* ii;
286
287 if (tp2 && !tp) {
288 INODE_ITEM* ii2 = (INODE_ITEM*)tp2->item->data;
289
290 if (tp2->item->size < sizeof(INODE_ITEM)) {
291 ERR("(%I64x,%x,%I64x) was %u bytes, expected %Iu\n", tp2->item->key.obj_id, tp2->item->key.obj_type, tp2->item->key.offset,
292 tp2->item->size, sizeof(INODE_ITEM));
294 }
295
296 context->lastinode.inode = tp2->item->key.obj_id;
297 context->lastinode.deleting = true;
298 context->lastinode.gen = ii2->generation;
299 context->lastinode.mode = ii2->st_mode;
300 context->lastinode.flags = ii2->flags;
301 context->lastinode.o = NULL;
302 context->lastinode.sd = NULL;
303
304 return STATUS_SUCCESS;
305 }
306
307 ii = (INODE_ITEM*)tp->item->data;
308
309 if (tp->item->size < sizeof(INODE_ITEM)) {
310 ERR("(%I64x,%x,%I64x) was %u bytes, expected %Iu\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset,
311 tp->item->size, sizeof(INODE_ITEM));
313 }
314
315 context->lastinode.inode = tp->item->key.obj_id;
316 context->lastinode.deleting = false;
317 context->lastinode.gen = ii->generation;
318 context->lastinode.uid = ii->st_uid;
319 context->lastinode.gid = ii->st_gid;
320 context->lastinode.mode = ii->st_mode;
321 context->lastinode.size = ii->st_size;
322 context->lastinode.atime = ii->st_atime;
323 context->lastinode.mtime = ii->st_mtime;
324 context->lastinode.ctime = ii->st_ctime;
325 context->lastinode.flags = ii->flags;
326 context->lastinode.file = false;
327 context->lastinode.o = NULL;
328 context->lastinode.sd = NULL;
329
330 if (context->lastinode.path) {
331 ExFreePool(context->lastinode.path);
332 context->lastinode.path = NULL;
333 }
334
335 if (tp2) {
336 INODE_ITEM* ii2 = (INODE_ITEM*)tp2->item->data;
337 LIST_ENTRY* le;
338
339 if (tp2->item->size < sizeof(INODE_ITEM)) {
340 ERR("(%I64x,%x,%I64x) was %u bytes, expected %Iu\n", tp2->item->key.obj_id, tp2->item->key.obj_type, tp2->item->key.offset,
341 tp2->item->size, sizeof(INODE_ITEM));
343 }
344
345 context->lastinode.oldmode = ii2->st_mode;
346 context->lastinode.olduid = ii2->st_uid;
347 context->lastinode.oldgid = ii2->st_gid;
348
349 if ((ii2->st_mode & __S_IFREG) == __S_IFREG && (ii2->st_mode & __S_IFLNK) != __S_IFLNK && (ii2->st_mode & __S_IFSOCK) != __S_IFSOCK)
350 context->lastinode.file = true;
351
352 context->lastinode.new = false;
353
354 le = context->orphans.Flink;
355 while (le != &context->orphans) {
357
358 if (o2->inode == tp->item->key.obj_id) {
359 context->lastinode.o = o2;
360 break;
361 } else if (o2->inode > tp->item->key.obj_id)
362 break;
363
364 le = le->Flink;
365 }
366 } else
367 context->lastinode.new = true;
368
370 send_dir* sd;
371
373 if (!NT_SUCCESS(Status)) {
374 ERR("find_send_dir returned %08lx\n", Status);
375 return Status;
376 }
377
378 sd->atime = ii->st_atime;
379 sd->mtime = ii->st_mtime;
380 sd->ctime = ii->st_ctime;
381 context->root_dir = sd;
382 } else if (!tp2) {
383 ULONG pos = context->datalen;
385 send_dir* sd;
386
387 char name[64];
388 orphan* o;
389
390 // skip creating orphan directory if we've already done so
391 if (ii->st_mode & __S_IFDIR) {
392 LIST_ENTRY* le;
393
394 le = context->orphans.Flink;
395 while (le != &context->orphans) {
397
398 if (o2->inode == tp->item->key.obj_id) {
399 context->lastinode.o = o2;
400 o2->sd->atime = ii->st_atime;
401 o2->sd->mtime = ii->st_mtime;
402 o2->sd->ctime = ii->st_ctime;
403 o2->sd->dummy = false;
404 return STATUS_SUCCESS;
405 } else if (o2->inode > tp->item->key.obj_id)
406 break;
407
408 le = le->Flink;
409 }
410 }
411
412 if ((ii->st_mode & __S_IFSOCK) == __S_IFSOCK)
414 else if ((ii->st_mode & __S_IFLNK) == __S_IFLNK)
416 else if ((ii->st_mode & __S_IFCHR) == __S_IFCHR || (ii->st_mode & __S_IFBLK) == __S_IFBLK)
418 else if ((ii->st_mode & __S_IFDIR) == __S_IFDIR)
420 else if ((ii->st_mode & __S_IFIFO) == __S_IFIFO)
422 else {
424 context->lastinode.file = true;
425 }
426
428
430 if (!NT_SUCCESS(Status)) {
431 ERR("get_orphan_name returned %08lx\n", Status);
432 return Status;
433 }
434
437
439 uint64_t rdev = makedev((ii->st_rdev & 0xFFFFFFFFFFF) >> 20, ii->st_rdev & 0xFFFFF), mode = ii->st_mode;
440
443 } else if (cmd == BTRFS_SEND_CMD_SYMLINK && ii->st_size > 0) {
444 char* link;
445 uint16_t linklen;
446
448 if (!NT_SUCCESS(Status)) {
449 ERR("send_read_symlink returned %08lx\n", Status);
450 return Status;
451 }
452
454 }
455
457
458 if (ii->st_mode & __S_IFDIR) {
460 if (!NT_SUCCESS(Status)) {
461 ERR("find_send_dir returned %08lx\n", Status);
462 return Status;
463 }
464
465 sd->dummy = false;
466 } else
467 sd = NULL;
468
469 context->lastinode.sd = sd;
470
472 if (!o) {
473 ERR("out of memory\n");
475 }
476
477 o->inode = tp->item->key.obj_id;
478 o->dir = (ii->st_mode & __S_IFDIR && ii->st_size > 0) ? true : false;
479 strcpy(o->tmpname, name);
480 o->sd = sd;
482
483 context->lastinode.path = ExAllocatePoolWithTag(PagedPool, strlen(o->tmpname) + 1, ALLOC_TAG);
484 if (!context->lastinode.path) {
485 ERR("out of memory\n");
487 }
488
489 strcpy(context->lastinode.path, o->tmpname);
490
491 context->lastinode.o = o;
492 }
493
494 return STATUS_SUCCESS;
495}
496
498 LIST_ENTRY* le;
500
501 if (!sd) {
502 ERR("out of memory\n");
504 }
505
506 sd->inode = inode;
507 sd->dummy = dummy;
508 sd->parent = parent;
509
510 if (!dummy) {
511 sd->atime = context->lastinode.atime;
512 sd->mtime = context->lastinode.mtime;
513 sd->ctime = context->lastinode.ctime;
514 }
515
516 if (namelen > 0) {
518 if (!sd->name) {
519 ERR("out of memory\n");
520 ExFreePool(sd);
522 }
523
524 memcpy(sd->name, name, namelen);
525 } else
526 sd->name = NULL;
527
528 sd->namelen = namelen;
529
530 InitializeListHead(&sd->deleted_children);
531
532 if (lastentry)
533 InsertHeadList(lastentry, &sd->list_entry);
534 else {
535 le = context->dirs.Flink;
536 while (le != &context->dirs) {
538
539 if (sd2->inode > sd->inode) {
540 InsertHeadList(sd2->list_entry.Blink, &sd->list_entry);
541
542 if (psd)
543 *psd = sd;
544
545 return STATUS_SUCCESS;
546 }
547
548 le = le->Flink;
549 }
550
551 InsertTailList(&context->dirs, &sd->list_entry);
552 }
553
554 if (psd)
555 *psd = sd;
556
557 return STATUS_SUCCESS;
558}
559
562
563 while (parent && parent->namelen > 0) {
564 len += parent->namelen + 1;
565 parent = parent->parent;
566 }
567
568 return len;
569}
570
571static void find_path(char* path, send_dir* parent, char* name, ULONG namelen) {
572 ULONG len = namelen;
573
575
576 while (parent && parent->namelen > 0) {
577 RtlMoveMemory(path + parent->namelen + 1, path, len);
578 RtlCopyMemory(path, parent->name, parent->namelen);
579 path[parent->namelen] = '/';
580 len += parent->namelen + 1;
581
582 parent = parent->parent;
583 }
584}
585
588
590
591 if (len > 0)
592 find_path((char*)&context->data[context->datalen - len], parent, name, namelen);
593}
594
596 ULONG pos = context->datalen;
597
598 if (context->lastinode.o) {
600
601 send_add_tlv_path(context, BTRFS_SEND_TLV_PATH, context->root_dir, context->lastinode.o->tmpname, (uint16_t)strlen(context->lastinode.o->tmpname));
602
604
606 } else {
608
610
611 send_add_tlv(context, BTRFS_SEND_TLV_PATH_LINK, context->lastinode.path, context->lastinode.path ? (uint16_t)strlen(context->lastinode.path) : 0);
612
614 }
615
616 if (context->lastinode.o) {
617 uint16_t pathlen;
618
619 if (context->lastinode.o->sd) {
620 if (context->lastinode.o->sd->name)
621 ExFreePool(context->lastinode.o->sd->name);
622
623 context->lastinode.o->sd->name = ExAllocatePoolWithTag(PagedPool, namelen, ALLOC_TAG);
624 if (!context->lastinode.o->sd->name) {
625 ERR("out of memory\n");
627 }
628
629 RtlCopyMemory(context->lastinode.o->sd->name, name, namelen);
630 context->lastinode.o->sd->namelen = namelen;
631 context->lastinode.o->sd->parent = parent;
632 }
633
634 if (context->lastinode.path)
635 ExFreePool(context->lastinode.path);
636
637 pathlen = find_path_len(parent, namelen);
638 context->lastinode.path = ExAllocatePoolWithTag(PagedPool, pathlen + 1, ALLOC_TAG);
639 if (!context->lastinode.path) {
640 ERR("out of memory\n");
642 }
643
644 find_path(context->lastinode.path, parent, name, namelen);
645 context->lastinode.path[pathlen] = 0;
646
647 RemoveEntryList(&context->lastinode.o->list_entry);
648 ExFreePool(context->lastinode.o);
649
650 context->lastinode.o = NULL;
651 }
652
653 return STATUS_SUCCESS;
654}
655
657 ULONG pos = context->datalen;
658
660
661 send_add_tlv_path(context, BTRFS_SEND_TLV_PATH, sd->parent, sd->name, sd->namelen);
662
666
668}
669
672 LIST_ENTRY* le;
673 char name[64];
674
675 le = context->dirs.Flink;
676 while (le != &context->dirs) {
678
679 if (sd2->inode > dir)
680 break;
681 else if (sd2->inode == dir) {
682 *psd = sd2;
683
684 if (added_dummy)
685 *added_dummy = false;
686
687 return STATUS_SUCCESS;
688 }
689
690 le = le->Flink;
691 }
692
693 if (dir == SUBVOL_ROOT_INODE) {
694 Status = send_add_dir(context, dir, NULL, NULL, 0, false, le, psd);
695 if (!NT_SUCCESS(Status)) {
696 ERR("send_add_dir returned %08lx\n", Status);
697 return Status;
698 }
699
700 if (added_dummy)
701 *added_dummy = false;
702
703 return STATUS_SUCCESS;
704 }
705
706 if (context->parent) {
707 KEY searchkey;
709
710 searchkey.obj_id = dir;
711 searchkey.obj_type = TYPE_INODE_REF; // directories should never have an extiref
712 searchkey.offset = 0xffffffffffffffff;
713
714 Status = find_item(context->Vcb, context->parent, &tp, &searchkey, false, NULL);
715 if (!NT_SUCCESS(Status)) {
716 ERR("find_item returned %08lx\n", Status);
717 return Status;
718 }
719
720 if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
721 INODE_REF* ir = (INODE_REF*)tp.item->data;
723
724 if (tp.item->size < sizeof(INODE_REF) || tp.item->size < offsetof(INODE_REF, name[0]) + ir->n) {
725 ERR("(%I64x,%x,%I64x) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
727 }
728
730 parent = context->root_dir;
731 else {
733 if (!NT_SUCCESS(Status)) {
734 ERR("find_send_dir returned %08lx\n", Status);
735 return Status;
736 }
737 }
738
739 Status = send_add_dir(context, dir, parent, ir->name, ir->n, true, NULL, psd);
740 if (!NT_SUCCESS(Status)) {
741 ERR("send_add_dir returned %08lx\n", Status);
742 return Status;
743 }
744
745 if (added_dummy)
746 *added_dummy = false;
747
748 return STATUS_SUCCESS;
749 }
750 }
751
753 if (!NT_SUCCESS(Status)) {
754 ERR("get_orphan_name returned %08lx\n", Status);
755 return Status;
756 }
757
758 Status = send_add_dir(context, dir, NULL, name, (uint16_t)strlen(name), true, le, psd);
759 if (!NT_SUCCESS(Status)) {
760 ERR("send_add_dir returned %08lx\n", Status);
761 return Status;
762 }
763
764 if (added_dummy)
765 *added_dummy = true;
766
767 return STATUS_SUCCESS;
768}
769
772 uint64_t inode = tp ? tp->item->key.obj_id : 0, dir = tp ? tp->item->key.offset : 0;
773 LIST_ENTRY* le;
774 INODE_REF* ir;
776 send_dir* sd = NULL;
777 orphan* o2 = NULL;
778
779 if (inode == dir) // root
780 return STATUS_SUCCESS;
781
782 if (tp->item->size < sizeof(INODE_REF)) {
783 ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset,
784 tp->item->size, sizeof(INODE_REF));
786 }
787
788 if (dir != SUBVOL_ROOT_INODE) {
789 bool added_dummy;
790
791 Status = find_send_dir(context, dir, context->root->root_item.ctransid, &sd, &added_dummy);
792 if (!NT_SUCCESS(Status)) {
793 ERR("find_send_dir returned %08lx\n", Status);
794 return Status;
795 }
796
797 // directory has higher inode number than file, so might need to be created
798 if (added_dummy) {
799 bool found = false;
800
801 le = context->orphans.Flink;
802 while (le != &context->orphans) {
804
805 if (o2->inode == dir) {
806 found = true;
807 break;
808 } else if (o2->inode > dir)
809 break;
810
811 le = le->Flink;
812 }
813
814 if (!found) {
815 ULONG pos = context->datalen;
816
818
820
822
824
826 if (!o2) {
827 ERR("out of memory\n");
829 }
830
831 o2->inode = dir;
832 o2->dir = true;
833 memcpy(o2->tmpname, sd->name, sd->namelen);
834 o2->tmpname[sd->namelen] = 0;
835 o2->sd = sd;
836 add_orphan(context, o2);
837 }
838 }
839 } else
840 sd = context->root_dir;
841
842 len = tp->item->size;
843 ir = (INODE_REF*)tp->item->data;
844
845 while (len > 0) {
846 ref* r;
847
848 if (len < sizeof(INODE_REF) || len < offsetof(INODE_REF, name[0]) + ir->n) {
849 ERR("(%I64x,%x,%I64x) was truncated\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset);
851 }
852
854 if (!r) {
855 ERR("out of memory\n");
857 }
858
859 r->sd = sd;
860 r->namelen = ir->n;
861 RtlCopyMemory(r->name, ir->name, ir->n);
862
863 InsertTailList(tree2 ? &context->lastinode.oldrefs : &context->lastinode.refs, &r->list_entry);
864
865 len -= (uint16_t)offsetof(INODE_REF, name[0]) + ir->n;
866 ir = (INODE_REF*)&ir->name[ir->n];
867 }
868
869 return STATUS_SUCCESS;
870}
871
873 INODE_EXTREF* ier;
875
876 if (tp->item->size < sizeof(INODE_EXTREF)) {
877 ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset,
878 tp->item->size, sizeof(INODE_EXTREF));
880 }
881
882 len = tp->item->size;
883 ier = (INODE_EXTREF*)tp->item->data;
884
885 while (len > 0) {
887 send_dir* sd = NULL;
888 orphan* o2 = NULL;
889 ref* r;
890
891 if (len < sizeof(INODE_EXTREF) || len < offsetof(INODE_EXTREF, name[0]) + ier->n) {
892 ERR("(%I64x,%x,%I64x) was truncated\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset);
894 }
895
896 if (ier->dir != SUBVOL_ROOT_INODE) {
897 LIST_ENTRY* le;
898 bool added_dummy;
899
900 Status = find_send_dir(context, ier->dir, context->root->root_item.ctransid, &sd, &added_dummy);
901 if (!NT_SUCCESS(Status)) {
902 ERR("find_send_dir returned %08lx\n", Status);
903 return Status;
904 }
905
906 // directory has higher inode number than file, so might need to be created
907 if (added_dummy) {
908 bool found = false;
909
910 le = context->orphans.Flink;
911 while (le != &context->orphans) {
913
914 if (o2->inode == ier->dir) {
915 found = true;
916 break;
917 } else if (o2->inode > ier->dir)
918 break;
919
920 le = le->Flink;
921 }
922
923 if (!found) {
924 ULONG pos = context->datalen;
925
927
930
932
934 if (!o2) {
935 ERR("out of memory\n");
937 }
938
939 o2->inode = ier->dir;
940 o2->dir = true;
941 memcpy(o2->tmpname, sd->name, sd->namelen);
942 o2->tmpname[sd->namelen] = 0;
943 o2->sd = sd;
944 add_orphan(context, o2);
945 }
946 }
947 } else
948 sd = context->root_dir;
949
951 if (!r) {
952 ERR("out of memory\n");
954 }
955
956 r->sd = sd;
957 r->namelen = ier->n;
958 RtlCopyMemory(r->name, ier->name, ier->n);
959
960 InsertTailList(tree2 ? &context->lastinode.oldrefs : &context->lastinode.refs, &r->list_entry);
961
962 len -= (uint16_t)offsetof(INODE_EXTREF, name[0]) + ier->n;
963 ier = (INODE_EXTREF*)&ier->name[ier->n];
964 }
965
966 return STATUS_SUCCESS;
967}
968
970 ULONG pos = context->datalen;
971
973
975
976 send_add_tlv(context, BTRFS_SEND_TLV_UUID, r->root_item.rtransid == 0 ? &r->root_item.uuid : &r->root_item.received_uuid, sizeof(BTRFS_UUID));
977 send_add_tlv(context, BTRFS_SEND_TLV_TRANSID, &r->root_item.ctransid, sizeof(uint64_t));
978
979 if (context->parent) {
981 context->parent->root_item.rtransid == 0 ? &context->parent->root_item.uuid : &context->parent->root_item.received_uuid, sizeof(BTRFS_UUID));
982 send_add_tlv(context, BTRFS_SEND_TLV_CLONE_CTRANSID, &context->parent->root_item.ctransid, sizeof(uint64_t));
983 }
984
986}
987
989 ULONG pos = context->datalen;
990
992
996
998}
999
1001 ULONG pos = context->datalen;
1002
1004
1005 mode &= 07777;
1006
1009
1011}
1012
1014 ULONG pos = context->datalen;
1015
1017
1022
1024}
1025
1027 ULONG pos = context->datalen;
1028
1030
1033
1035}
1036
1038 ULONG pos = context->datalen;
1039 uint16_t pathlen;
1040
1042
1043 pathlen = find_path_len(parent, namelen);
1045
1046 find_path((char*)&context->data[context->datalen - pathlen], parent, name, namelen);
1047
1049
1050 return STATUS_SUCCESS;
1051}
1052
1053static void send_rmdir_command(send_context* context, uint16_t pathlen, char* path) {
1054 ULONG pos = context->datalen;
1055
1059}
1060
1063 KEY searchkey;
1065
1066 *last_inode = 0;
1067
1068 searchkey.obj_id = context->lastinode.inode;
1069 searchkey.obj_type = TYPE_DIR_INDEX;
1070 searchkey.offset = 2;
1071
1072 Status = find_item(context->Vcb, context->parent, &tp, &searchkey, false, NULL);
1073 if (!NT_SUCCESS(Status)) {
1074 ERR("find_item returned %08lx\n", Status);
1075 return Status;
1076 }
1077
1078 do {
1079 traverse_ptr next_tp;
1080
1081 if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
1082 DIR_ITEM* di = (DIR_ITEM*)tp.item->data;
1083
1084 if (tp.item->size < sizeof(DIR_ITEM) || tp.item->size < offsetof(DIR_ITEM, name[0]) + di->m + di->n) {
1085 ERR("(%I64x,%x,%I64x) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
1086 return STATUS_INTERNAL_ERROR;
1087 }
1088
1089 if (di->key.obj_type == TYPE_INODE_ITEM)
1090 *last_inode = max(*last_inode, di->key.obj_id);
1091 } else
1092 break;
1093
1094 if (find_next_item(context->Vcb, &tp, &next_tp, false, NULL))
1095 tp = next_tp;
1096 else
1097 break;
1098 } while (true);
1099
1100 return STATUS_SUCCESS;
1101}
1102
1104 pending_rmdir* pr;
1105 LIST_ENTRY* le;
1106
1108 if (!pr) {
1109 ERR("out of memory\n");
1111 }
1112
1113 pr->sd = context->lastinode.sd;
1114 pr->last_child_inode = last_inode;
1115
1116 le = context->pending_rmdirs.Flink;
1117 while (le != &context->pending_rmdirs) {
1119
1120 if (pr2->last_child_inode > pr->last_child_inode) {
1121 InsertHeadList(pr2->list_entry.Blink, &pr->list_entry);
1122 return STATUS_SUCCESS;
1123 }
1124
1125 le = le->Flink;
1126 }
1127
1128 InsertTailList(&context->pending_rmdirs, &pr->list_entry);
1129
1130 return STATUS_SUCCESS;
1131}
1132
1135 KEY searchkey;
1137 DIR_ITEM* di;
1138 uint16_t len;
1139
1140 searchkey.obj_id = sd->inode;
1141 searchkey.obj_type = TYPE_DIR_ITEM;
1142 searchkey.offset = calc_crc32c(0xfffffffe, (uint8_t*)name, namelen);
1143
1144 Status = find_item(context->Vcb, context->parent, &tp, &searchkey, false, NULL);
1145 if (!NT_SUCCESS(Status)) {
1146 ERR("find_item returned %08lx\n", Status);
1147 return Status;
1148 }
1149
1150 if (keycmp(tp.item->key, searchkey))
1151 return STATUS_SUCCESS;
1152
1153 di = (DIR_ITEM*)tp.item->data;
1154 len = tp.item->size;
1155
1156 do {
1157 if (len < sizeof(DIR_ITEM) || len < offsetof(DIR_ITEM, name[0]) + di->m + di->n) {
1158 ERR("(%I64x,%x,%I64x) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
1159 return STATUS_INTERNAL_ERROR;
1160 }
1161
1162 if (di->n == namelen && RtlCompareMemory(di->name, name, namelen) == namelen) {
1163 *inode = di->key.obj_type == TYPE_INODE_ITEM ? di->key.obj_id : 0;
1164 *dir = di->type == BTRFS_TYPE_DIRECTORY ? true: false;
1166 }
1167
1168 di = (DIR_ITEM*)&di->name[di->m + di->n];
1169 len -= (uint16_t)offsetof(DIR_ITEM, name[0]) + di->m + di->n;
1170 } while (len > 0);
1171
1172 return STATUS_SUCCESS;
1173}
1174
1177 ULONG pos = context->datalen;
1178 send_dir* sd = NULL;
1179 orphan* o;
1180 LIST_ENTRY* le;
1181 char name[64];
1182
1183 if (!dir) {
1185
1187 if (!dc) {
1188 ERR("out of memory\n");
1190 }
1191
1192 dc->namelen = r->namelen;
1193 RtlCopyMemory(dc->name, r->name, r->namelen);
1194 InsertTailList(&r->sd->deleted_children, &dc->list_entry);
1195 }
1196
1197 le = context->orphans.Flink;
1198 while (le != &context->orphans) {
1200
1201 if (o2->inode == inode) {
1203
1205
1207
1208 return STATUS_SUCCESS;
1209 } else if (o2->inode > inode)
1210 break;
1211
1212 le = le->Flink;
1213 }
1214
1216 if (!NT_SUCCESS(Status)) {
1217 ERR("get_orphan_name returned %08lx\n", Status);
1218 return Status;
1219 }
1220
1221 if (dir) {
1223 if (!NT_SUCCESS(Status)) {
1224 ERR("find_send_dir returned %08lx\n", Status);
1225 return Status;
1226 }
1227
1228 sd->dummy = true;
1229
1231
1234
1236
1237 if (sd->name)
1238 ExFreePool(sd->name);
1239
1240 sd->namelen = (uint16_t)strlen(name);
1241 sd->name = ExAllocatePoolWithTag(PagedPool, sd->namelen, ALLOC_TAG);
1242 if (!sd->name) {
1243 ERR("out of memory\n");
1245 }
1246
1247 RtlCopyMemory(sd->name, name, sd->namelen);
1248 sd->parent = context->root_dir;
1249 } else {
1251
1253
1255
1257 }
1258
1260 if (!o) {
1261 ERR("out of memory\n");
1263 }
1264
1265 o->inode = inode;
1266 o->dir = true;
1267 strcpy(o->tmpname, name);
1268 o->sd = sd;
1269 add_orphan(context, o);
1270
1271 return STATUS_SUCCESS;
1272}
1273
1276 LIST_ENTRY* le;
1277 ref *nameref = NULL, *nameref2 = NULL;
1278
1279 if (context->lastinode.mode & __S_IFDIR) { // directory
1280 ref* r = IsListEmpty(&context->lastinode.refs) ? NULL : CONTAINING_RECORD(context->lastinode.refs.Flink, ref, list_entry);
1281 ref* or = IsListEmpty(&context->lastinode.oldrefs) ? NULL : CONTAINING_RECORD(context->lastinode.oldrefs.Flink, ref, list_entry);
1282
1283 if (or && !context->lastinode.o) {
1284 ULONG len = find_path_len(or->sd, or->namelen);
1285
1286 context->lastinode.path = ExAllocatePoolWithTag(PagedPool, len + 1, ALLOC_TAG);
1287 if (!context->lastinode.path) {
1288 ERR("out of memory\n");
1290 }
1291
1292 find_path(context->lastinode.path, or->sd, or->name, or->namelen);
1293 context->lastinode.path[len] = 0;
1294
1295 if (!context->lastinode.sd) {
1296 Status = find_send_dir(context, context->lastinode.inode, context->lastinode.gen, &context->lastinode.sd, false);
1297 if (!NT_SUCCESS(Status)) {
1298 ERR("find_send_dir returned %08lx\n", Status);
1299 return Status;
1300 }
1301 }
1302 }
1303
1304 if (r && or) {
1306 bool dir;
1307
1308 Status = look_for_collision(context, r->sd, r->name, r->namelen, &inode, &dir);
1310 ERR("look_for_collision returned %08lx\n", Status);
1311 return Status;
1312 }
1313
1314 if (Status == STATUS_OBJECT_NAME_COLLISION && inode > context->lastinode.inode) {
1315 Status = make_file_orphan(context, inode, dir, context->parent->root_item.ctransid, r);
1316 if (!NT_SUCCESS(Status)) {
1317 ERR("make_file_orphan returned %08lx\n", Status);
1318 return Status;
1319 }
1320 }
1321
1322 if (context->lastinode.o) {
1323 Status = found_path(context, r->sd, r->name, r->namelen);
1324 if (!NT_SUCCESS(Status)) {
1325 ERR("found_path returned %08lx\n", Status);
1326 return Status;
1327 }
1328
1329 if (!r->sd->dummy)
1330 send_utimes_command_dir(context, r->sd, &r->sd->atime, &r->sd->mtime, &r->sd->ctime);
1331 } else if (r->sd != or->sd || r->namelen != or->namelen || RtlCompareMemory(r->name, or->name, r->namelen) != r->namelen) { // moved or renamed
1332 ULONG pos = context->datalen, len;
1333
1335
1336 send_add_tlv(context, BTRFS_SEND_TLV_PATH, context->lastinode.path, (uint16_t)strlen(context->lastinode.path));
1337
1339
1341
1342 if (!r->sd->dummy)
1343 send_utimes_command_dir(context, r->sd, &r->sd->atime, &r->sd->mtime, &r->sd->ctime);
1344
1345 if (context->lastinode.sd->name)
1346 ExFreePool(context->lastinode.sd->name);
1347
1348 context->lastinode.sd->name = ExAllocatePoolWithTag(PagedPool, r->namelen, ALLOC_TAG);
1349 if (!context->lastinode.sd->name) {
1350 ERR("out of memory\n");
1352 }
1353
1354 RtlCopyMemory(context->lastinode.sd->name, r->name, r->namelen);
1355 context->lastinode.sd->parent = r->sd;
1356
1357 if (context->lastinode.path)
1358 ExFreePool(context->lastinode.path);
1359
1360 len = find_path_len(r->sd, r->namelen);
1361 context->lastinode.path = ExAllocatePoolWithTag(PagedPool, len + 1, ALLOC_TAG);
1362 if (!context->lastinode.path) {
1363 ERR("out of memory\n");
1365 }
1366
1367 find_path(context->lastinode.path, r->sd, r->name, r->namelen);
1368 context->lastinode.path[len] = 0;
1369 }
1370 } else if (r && !or) { // new
1371 Status = found_path(context, r->sd, r->name, r->namelen);
1372 if (!NT_SUCCESS(Status)) {
1373 ERR("found_path returned %08lx\n", Status);
1374 return Status;
1375 }
1376
1377 if (!r->sd->dummy)
1378 send_utimes_command_dir(context, r->sd, &r->sd->atime, &r->sd->mtime, &r->sd->ctime);
1379 } else { // deleted
1380 uint64_t last_inode;
1381
1382 Status = get_dir_last_child(context, &last_inode);
1383 if (!NT_SUCCESS(Status)) {
1384 ERR("get_dir_last_child returned %08lx\n", Status);
1385 return Status;
1386 }
1387
1388 if (last_inode <= context->lastinode.inode) {
1389 send_rmdir_command(context, (uint16_t)strlen(context->lastinode.path), context->lastinode.path);
1390
1391 if (!or->sd->dummy)
1392 send_utimes_command_dir(context, or->sd, &or->sd->atime, &or->sd->mtime, &or->sd->ctime);
1393 } else {
1394 char name[64];
1395 ULONG pos = context->datalen;
1396
1397 Status = get_orphan_name(context, context->lastinode.inode, context->lastinode.gen, name);
1398 if (!NT_SUCCESS(Status)) {
1399 ERR("get_orphan_name returned %08lx\n", Status);
1400 return Status;
1401 }
1402
1404 send_add_tlv(context, BTRFS_SEND_TLV_PATH, context->lastinode.path, (uint16_t)strlen(context->lastinode.path));
1407
1408 if (context->lastinode.sd->name)
1409 ExFreePool(context->lastinode.sd->name);
1410
1411 context->lastinode.sd->name = ExAllocatePoolWithTag(PagedPool, strlen(name), ALLOC_TAG);
1412 if (!context->lastinode.sd->name) {
1413 ERR("out of memory\n");
1415 }
1416
1417 RtlCopyMemory(context->lastinode.sd->name, name, strlen(name));
1418 context->lastinode.sd->namelen = (uint16_t)strlen(name);
1419 context->lastinode.sd->dummy = true;
1420 context->lastinode.sd->parent = NULL;
1421
1422 send_utimes_command(context, NULL, &context->root_dir->atime, &context->root_dir->mtime, &context->root_dir->ctime);
1423
1424 Status = add_pending_rmdir(context, last_inode);
1425 if (!NT_SUCCESS(Status)) {
1426 ERR("add_pending_rmdir returned %08lx\n", Status);
1427 return Status;
1428 }
1429 }
1430 }
1431
1432 while (!IsListEmpty(&context->lastinode.refs)) {
1433 r = CONTAINING_RECORD(RemoveHeadList(&context->lastinode.refs), ref, list_entry);
1434 ExFreePool(r);
1435 }
1436
1437 while (!IsListEmpty(&context->lastinode.oldrefs)) {
1438 or = CONTAINING_RECORD(RemoveHeadList(&context->lastinode.oldrefs), ref, list_entry);
1439 ExFreePool(or);
1440 }
1441
1442 return STATUS_SUCCESS;
1443 } else {
1444 if (!IsListEmpty(&context->lastinode.oldrefs)) {
1445 ref* or = CONTAINING_RECORD(context->lastinode.oldrefs.Flink, ref, list_entry);
1446 ULONG len = find_path_len(or->sd, or->namelen);
1447
1448 context->lastinode.path = ExAllocatePoolWithTag(PagedPool, len + 1, ALLOC_TAG);
1449 if (!context->lastinode.path) {
1450 ERR("out of memory\n");
1452 }
1453
1454 find_path(context->lastinode.path, or->sd, or->name, or->namelen);
1455 context->lastinode.path[len] = 0;
1456 nameref = or;
1457 }
1458
1459 // remove unchanged refs
1460 le = context->lastinode.oldrefs.Flink;
1461 while (le != &context->lastinode.oldrefs) {
1462 ref* or = CONTAINING_RECORD(le, ref, list_entry);
1463 LIST_ENTRY* le2;
1464 bool matched = false;
1465
1466 le2 = context->lastinode.refs.Flink;
1467 while (le2 != &context->lastinode.refs) {
1469
1470 if (r->sd == or->sd && r->namelen == or->namelen && RtlCompareMemory(r->name, or->name, r->namelen) == r->namelen) {
1471 RemoveEntryList(&r->list_entry);
1472 ExFreePool(r);
1473 matched = true;
1474 break;
1475 }
1476
1477 le2 = le2->Flink;
1478 }
1479
1480 if (matched) {
1481 le = le->Flink;
1483 ExFreePool(or);
1484 continue;
1485 }
1486
1487 le = le->Flink;
1488 }
1489
1490 while (!IsListEmpty(&context->lastinode.refs)) {
1491 ref* r = CONTAINING_RECORD(RemoveHeadList(&context->lastinode.refs), ref, list_entry);
1493 bool dir;
1494
1495 if (context->parent) {
1496 Status = look_for_collision(context, r->sd, r->name, r->namelen, &inode, &dir);
1498 ERR("look_for_collision returned %08lx\n", Status);
1499 return Status;
1500 }
1501
1502 if (Status == STATUS_OBJECT_NAME_COLLISION && inode > context->lastinode.inode) {
1503 Status = make_file_orphan(context, inode, dir, context->lastinode.gen, r);
1504 if (!NT_SUCCESS(Status)) {
1505 ERR("make_file_orphan returned %08lx\n", Status);
1506 return Status;
1507 }
1508 }
1509 }
1510
1511 if (context->datalen > SEND_BUFFER_LENGTH) {
1512 Status = wait_for_flush(context, tp1, tp2);
1513 if (!NT_SUCCESS(Status)) {
1514 ERR("wait_for_flush returned %08lx\n", Status);
1515 return Status;
1516 }
1517
1518 if (context->send->cancelling)
1519 return STATUS_SUCCESS;
1520 }
1521
1522 Status = found_path(context, r->sd, r->name, r->namelen);
1523 if (!NT_SUCCESS(Status)) {
1524 ERR("found_path returned %08lx\n", Status);
1525 return Status;
1526 }
1527
1528 if (!r->sd->dummy)
1529 send_utimes_command_dir(context, r->sd, &r->sd->atime, &r->sd->mtime, &r->sd->ctime);
1530
1531 if (nameref && !nameref2)
1532 nameref2 = r;
1533 else
1534 ExFreePool(r);
1535 }
1536
1537 while (!IsListEmpty(&context->lastinode.oldrefs)) {
1538 ref* or = CONTAINING_RECORD(RemoveHeadList(&context->lastinode.oldrefs), ref, list_entry);
1539 bool deleted = false;
1540
1541 le = or->sd->deleted_children.Flink;
1542 while (le != &or->sd->deleted_children) {
1544
1545 if (dc->namelen == or->namelen && RtlCompareMemory(dc->name, or->name, or->namelen) == or->namelen) {
1546 RemoveEntryList(&dc->list_entry);
1547 ExFreePool(dc);
1548 deleted = true;
1549 break;
1550 }
1551
1552 le = le->Flink;
1553 }
1554
1555 if (!deleted) {
1556 if (context->datalen > SEND_BUFFER_LENGTH) {
1557 Status = wait_for_flush(context, tp1, tp2);
1558 if (!NT_SUCCESS(Status)) {
1559 ERR("wait_for_flush returned %08lx\n", Status);
1560 return Status;
1561 }
1562
1563 if (context->send->cancelling)
1564 return STATUS_SUCCESS;
1565 }
1566
1567 Status = send_unlink_command(context, or->sd, or->namelen, or->name);
1568 if (!NT_SUCCESS(Status)) {
1569 ERR("send_unlink_command returned %08lx\n", Status);
1570 return Status;
1571 }
1572
1573 if (!or->sd->dummy)
1574 send_utimes_command_dir(context, or->sd, &or->sd->atime, &or->sd->mtime, &or->sd->ctime);
1575 }
1576
1577 if (or == nameref && nameref2) {
1578 uint16_t len = find_path_len(nameref2->sd, nameref2->namelen);
1579
1580 if (context->lastinode.path)
1581 ExFreePool(context->lastinode.path);
1582
1583 context->lastinode.path = ExAllocatePoolWithTag(PagedPool, len + 1, ALLOC_TAG);
1584 if (!context->lastinode.path) {
1585 ERR("out of memory\n");
1587 }
1588
1589 find_path(context->lastinode.path, nameref2->sd, nameref2->name, nameref2->namelen);
1590 context->lastinode.path[len] = 0;
1591
1592 ExFreePool(nameref2);
1593 }
1594
1595 ExFreePool(or);
1596 }
1597 }
1598
1599 return STATUS_SUCCESS;
1600}
1601
1604 KEY key1, key2;
1605
1606 if (tp1)
1607 key1 = tp1->item->key;
1608
1609 if (tp2)
1610 key2 = tp2->item->key;
1611
1612 ExReleaseResourceLite(&context->Vcb->tree_lock);
1613
1614 KeClearEvent(&context->send->cleared_event);
1615 KeSetEvent(&context->buffer_event, 0, true);
1616 KeWaitForSingleObject(&context->send->cleared_event, Executive, KernelMode, false, NULL);
1617
1618 ExAcquireResourceSharedLite(&context->Vcb->tree_lock, true);
1619
1620 if (context->send->cancelling)
1621 return STATUS_SUCCESS;
1622
1623 if (tp1) {
1624 Status = find_item(context->Vcb, context->root, tp1, &key1, false, NULL);
1625 if (!NT_SUCCESS(Status)) {
1626 ERR("find_item returned %08lx\n", Status);
1627 return Status;
1628 }
1629
1630 if (keycmp(tp1->item->key, key1)) {
1631 ERR("readonly subvolume changed\n");
1632 return STATUS_INTERNAL_ERROR;
1633 }
1634 }
1635
1636 if (tp2) {
1637 Status = find_item(context->Vcb, context->parent, tp2, &key2, false, NULL);
1638 if (!NT_SUCCESS(Status)) {
1639 ERR("find_item returned %08lx\n", Status);
1640 return Status;
1641 }
1642
1643 if (keycmp(tp2->item->key, key2)) {
1644 ERR("readonly subvolume changed\n");
1645 return STATUS_INTERNAL_ERROR;
1646 }
1647 }
1648
1649 return STATUS_SUCCESS;
1650}
1651
1653 uint64_t lastoff = 0;
1654 LIST_ENTRY* le;
1655
1656 le = exts->Flink;
1657 while (le != exts) {
1659
1660 if (ext->offset > lastoff) {
1662 EXTENT_DATA2* ed2;
1663
1664 if (!ext2) {
1665 ERR("out of memory\n");
1667 }
1668
1669 ed2 = (EXTENT_DATA2*)ext2->data.data;
1670
1671 ext2->offset = lastoff;
1672 ext2->datalen = offsetof(EXTENT_DATA, data) + sizeof(EXTENT_DATA2);
1673 ext2->data.decoded_size = ed2->num_bytes = ext->offset - lastoff;
1674 ext2->data.type = EXTENT_TYPE_REGULAR;
1675 ed2->address = ed2->size = ed2->offset = 0;
1676
1677 InsertHeadList(le->Blink, &ext2->list_entry);
1678 }
1679
1680 if (ext->data.type == EXTENT_TYPE_INLINE)
1681 lastoff = ext->offset + ext->data.decoded_size;
1682 else {
1683 EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ext->data.data;
1684 lastoff = ext->offset + ed2->num_bytes;
1685 }
1686
1687 le = le->Flink;
1688 }
1689
1690 if (size > lastoff) {
1692 EXTENT_DATA2* ed2;
1693
1694 if (!ext2) {
1695 ERR("out of memory\n");
1697 }
1698
1699 ed2 = (EXTENT_DATA2*)ext2->data.data;
1700
1701 ext2->offset = lastoff;
1702 ext2->datalen = offsetof(EXTENT_DATA, data) + sizeof(EXTENT_DATA2);
1703 ext2->data.decoded_size = ed2->num_bytes = sector_align(size - lastoff, Vcb->superblock.sector_size);
1704 ext2->data.type = EXTENT_TYPE_REGULAR;
1705 ed2->address = ed2->size = ed2->offset = 0;
1706
1707 InsertTailList(exts, &ext2->list_entry);
1708 }
1709
1710 return STATUS_SUCCESS;
1711}
1712
1714 send_ext* ext2;
1715 EXTENT_DATA2 *ed2a, *ed2b;
1716
1717 if (ext->data.type == EXTENT_TYPE_INLINE) {
1718 if (!trunc) {
1720
1721 if (!ext2) {
1722 ERR("out of memory\n");
1724 }
1725
1726 ext2->offset = ext->offset + len;
1727 ext2->datalen = (ULONG)(ext->data.decoded_size - len);
1728 ext2->data.decoded_size = ext->data.decoded_size - len;
1729 ext2->data.compression = ext->data.compression;
1730 ext2->data.encryption = ext->data.encryption;
1731 ext2->data.encoding = ext->data.encoding;
1732 ext2->data.type = ext->data.type;
1733 RtlCopyMemory(ext2->data.data, ext->data.data + len, (ULONG)(ext->data.decoded_size - len));
1734
1735 InsertHeadList(&ext->list_entry, &ext2->list_entry);
1736 }
1737
1738 ext->data.decoded_size = len;
1739
1740 return STATUS_SUCCESS;
1741 }
1742
1743 ed2a = (EXTENT_DATA2*)ext->data.data;
1744
1745 if (!trunc) {
1747
1748 if (!ext2) {
1749 ERR("out of memory\n");
1751 }
1752
1753 ed2b = (EXTENT_DATA2*)ext2->data.data;
1754
1755 ext2->offset = ext->offset + len;
1756 ext2->datalen = offsetof(EXTENT_DATA, data) + sizeof(EXTENT_DATA2);
1757
1758 ext2->data.compression = ext->data.compression;
1759 ext2->data.encryption = ext->data.encryption;
1760 ext2->data.encoding = ext->data.encoding;
1761 ext2->data.type = ext->data.type;
1762 ed2b->num_bytes = ed2a->num_bytes - len;
1763
1764 if (ed2a->size == 0) {
1765 ext2->data.decoded_size = ed2b->num_bytes;
1766 ext->data.decoded_size = len;
1767
1768 ed2b->address = ed2b->size = ed2b->offset = 0;
1769 } else {
1770 ext2->data.decoded_size = ext->data.decoded_size;
1771
1772 ed2b->address = ed2a->address;
1773 ed2b->size = ed2a->size;
1774 ed2b->offset = ed2a->offset + len;
1775 }
1776
1777 InsertHeadList(&ext->list_entry, &ext2->list_entry);
1778 }
1779
1780 ed2a->num_bytes = len;
1781
1782 return STATUS_SUCCESS;
1783}
1784
1787 send_ext *ext1, *ext2;
1788
1789 ext1 = CONTAINING_RECORD(context->lastinode.exts.Flink, send_ext, list_entry);
1790 ext2 = CONTAINING_RECORD(context->lastinode.oldexts.Flink, send_ext, list_entry);
1791
1792 do {
1793 uint64_t len1, len2;
1794 EXTENT_DATA2 *ed2a, *ed2b;
1795
1796 ed2a = ext1->data.type == EXTENT_TYPE_INLINE ? NULL : (EXTENT_DATA2*)ext1->data.data;
1797 ed2b = ext2->data.type == EXTENT_TYPE_INLINE ? NULL : (EXTENT_DATA2*)ext2->data.data;
1798
1799 len1 = ed2a ? ed2a->num_bytes : ext1->data.decoded_size;
1800 len2 = ed2b ? ed2b->num_bytes : ext2->data.decoded_size;
1801
1802 if (len1 < len2) {
1803 Status = divide_ext(ext2, len1, false);
1804 if (!NT_SUCCESS(Status)) {
1805 ERR("divide_ext returned %08lx\n", Status);
1806 return Status;
1807 }
1808 } else if (len2 < len1) {
1809 Status = divide_ext(ext1, len2, false);
1810 if (!NT_SUCCESS(Status)) {
1811 ERR("divide_ext returned %08lx\n", Status);
1812 return Status;
1813 }
1814 }
1815
1816 if (ext1->list_entry.Flink == &context->lastinode.exts || ext2->list_entry.Flink == &context->lastinode.oldexts)
1817 break;
1818
1819 ext1 = CONTAINING_RECORD(ext1->list_entry.Flink, send_ext, list_entry);
1820 ext2 = CONTAINING_RECORD(ext2->list_entry.Flink, send_ext, list_entry);
1821 } while (true);
1822
1823 ext1 = CONTAINING_RECORD(context->lastinode.exts.Blink, send_ext, list_entry);
1824 ext2 = CONTAINING_RECORD(context->lastinode.oldexts.Blink, send_ext, list_entry);
1825
1826 Status = divide_ext(ext1, context->lastinode.size - ext1->offset, true);
1827 if (!NT_SUCCESS(Status)) {
1828 ERR("divide_ext returned %08lx\n", Status);
1829 return Status;
1830 }
1831
1832 Status = divide_ext(ext2, context->lastinode.size - ext2->offset, true);
1833 if (!NT_SUCCESS(Status)) {
1834 ERR("divide_ext returned %08lx\n", Status);
1835 return Status;
1836 }
1837
1838 return STATUS_SUCCESS;
1839}
1840
1843 KEY searchkey;
1845 uint16_t len = 0;
1846 uint64_t num;
1847 uint8_t* ptr;
1848
1849 num = inode;
1850
1851 while (num != SUBVOL_ROOT_INODE) {
1852 searchkey.obj_id = num;
1853 searchkey.obj_type = TYPE_INODE_EXTREF;
1854 searchkey.offset = 0xffffffffffffffff;
1855
1856 Status = find_item(context->Vcb, r, &tp, &searchkey, false, NULL);
1857 if (!NT_SUCCESS(Status)) {
1858 ERR("find_item returned %08lx\n", Status);
1859 return false;
1860 }
1861
1863 ERR("could not find INODE_REF for inode %I64x\n", searchkey.obj_id);
1864 return false;
1865 }
1866
1867 if (len > 0)
1868 len++;
1869
1870 if (tp.item->key.obj_type == TYPE_INODE_REF) {
1871 INODE_REF* ir = (INODE_REF*)tp.item->data;
1872
1873 if (tp.item->size < sizeof(INODE_REF) || tp.item->size < offsetof(INODE_REF, name[0]) + ir->n) {
1874 ERR("(%I64x,%x,%I64x) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
1875 return false;
1876 }
1877
1878 len += ir->n;
1879 num = tp.item->key.offset;
1880 } else {
1882
1883 if (tp.item->size < sizeof(INODE_EXTREF) || tp.item->size < offsetof(INODE_EXTREF, name[0]) + ier->n) {
1884 ERR("(%I64x,%x,%I64x) was truncated\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
1885 return false;
1886 }
1887
1888 len += ier->n;
1889 num = ier->dir;
1890 }
1891 }
1892
1894 ptr = &context->data[context->datalen];
1895
1896 num = inode;
1897
1898 while (num != SUBVOL_ROOT_INODE) {
1899 searchkey.obj_id = num;
1900 searchkey.obj_type = TYPE_INODE_EXTREF;
1901 searchkey.offset = 0xffffffffffffffff;
1902
1903 Status = find_item(context->Vcb, r, &tp, &searchkey, false, NULL);
1904 if (!NT_SUCCESS(Status)) {
1905 ERR("find_item returned %08lx\n", Status);
1906 return false;
1907 }
1908
1910 ERR("could not find INODE_REF for inode %I64x\n", searchkey.obj_id);
1911 return false;
1912 }
1913
1914 if (num != inode) {
1915 ptr--;
1916 *ptr = '/';
1917 }
1918
1919 if (tp.item->key.obj_type == TYPE_INODE_REF) {
1920 INODE_REF* ir = (INODE_REF*)tp.item->data;
1921
1922 RtlCopyMemory(ptr - ir->n, ir->name, ir->n);
1923 ptr -= ir->n;
1924 num = tp.item->key.offset;
1925 } else {
1927
1928 RtlCopyMemory(ptr - ier->n, ier->name, ier->n);
1929 ptr -= ier->n;
1930 num = ier->dir;
1931 }
1932 }
1933
1934 return true;
1935}
1936
1939 root* r = NULL;
1940 KEY searchkey;
1942 EXTENT_DATA2* seed2 = (EXTENT_DATA2*)se->data.data;
1943
1944 if (context->parent && edr->root == context->parent->id)
1945 r = context->parent;
1946
1947 if (!r && context->num_clones > 0) {
1948 ULONG i;
1949
1950 for (i = 0; i < context->num_clones; i++) {
1951 if (context->clones[i]->id == edr->root && context->clones[i] != context->root) {
1952 r = context->clones[i];
1953 break;
1954 }
1955 }
1956 }
1957
1958 if (!r)
1959 return false;
1960
1961 searchkey.obj_id = edr->objid;
1962 searchkey.obj_type = TYPE_EXTENT_DATA;
1963 searchkey.offset = 0;
1964
1965 Status = find_item(context->Vcb, r, &tp, &searchkey, false, NULL);
1966 if (!NT_SUCCESS(Status)) {
1967 ERR("find_item returned %08lx\n", Status);
1968 return false;
1969 }
1970
1971 while (true) {
1972 traverse_ptr next_tp;
1973
1974 if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
1975 if (tp.item->size < sizeof(EXTENT_DATA))
1976 ERR("(%I64x,%x,%I64x) has size %u, not at least %Iu as expected\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_DATA));
1977 else {
1979
1980 if (ed->type == EXTENT_TYPE_REGULAR) {
1981 if (tp.item->size < offsetof(EXTENT_DATA, data[0]) + sizeof(EXTENT_DATA2))
1982 ERR("(%I64x,%x,%I64x) has size %u, not %Iu as expected\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset,
1983 tp.item->size, offsetof(EXTENT_DATA, data[0]) + sizeof(EXTENT_DATA2));
1984 else {
1985 EXTENT_DATA2* ed2 = (EXTENT_DATA2*)ed->data;
1986
1987 if (ed2->address == seed2->address && ed2->size == seed2->size && seed2->offset <= ed2->offset && seed2->offset + seed2->num_bytes >= ed2->offset + ed2->num_bytes) {
1988 uint64_t clone_offset = tp.item->key.offset + ed2->offset - seed2->offset;
1989 uint64_t clone_len = min(context->lastinode.size - se->offset, ed2->num_bytes);
1990
1991 if ((clone_offset & (context->Vcb->superblock.sector_size - 1)) == 0 && (clone_len & (context->Vcb->superblock.sector_size - 1)) == 0) {
1992 ULONG pos = context->datalen;
1993
1995
1998 send_add_tlv(context, BTRFS_SEND_TLV_PATH, context->lastinode.path, context->lastinode.path ? (uint16_t)strlen(context->lastinode.path) : 0);
1999 send_add_tlv(context, BTRFS_SEND_TLV_CLONE_UUID, r->root_item.rtransid == 0 ? &r->root_item.uuid : &r->root_item.received_uuid, sizeof(BTRFS_UUID));
2000 send_add_tlv(context, BTRFS_SEND_TLV_CLONE_CTRANSID, &r->root_item.ctransid, sizeof(uint64_t));
2001
2003 context->datalen = pos;
2004 else {
2005 send_add_tlv(context, BTRFS_SEND_TLV_CLONE_OFFSET, &clone_offset, sizeof(uint64_t));
2006
2008
2009 return true;
2010 }
2011 }
2012 }
2013 }
2014 }
2015 }
2016 } else if (tp.item->key.obj_id > searchkey.obj_id || (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type > searchkey.obj_type))
2017 break;
2018
2019 if (find_next_item(context->Vcb, &tp, &next_tp, false, NULL))
2020 tp = next_tp;
2021 else
2022 break;
2023 }
2024
2025 return false;
2026}
2027
2030 KEY searchkey;
2032 EXTENT_DATA2* ed2 = (EXTENT_DATA2*)se->data.data;
2033 EXTENT_ITEM* ei;
2034 uint64_t rc = 0;
2035
2036 searchkey.obj_id = ed2->address;
2037 searchkey.obj_type = TYPE_EXTENT_ITEM;
2038 searchkey.offset = ed2->size;
2039
2040 Status = find_item(context->Vcb, context->Vcb->extent_root, &tp, &searchkey, false, NULL);
2041 if (!NT_SUCCESS(Status)) {
2042 ERR("find_item returned %08lx\n", Status);
2043 return false;
2044 }
2045
2046 if (keycmp(tp.item->key, searchkey)) {
2047 ERR("(%I64x,%x,%I64x) not found\n", searchkey.obj_id, searchkey.obj_type, searchkey.offset);
2048 return false;
2049 }
2050
2051 if (tp.item->size < sizeof(EXTENT_ITEM)) {
2052 ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_ITEM));
2053 return false;
2054 }
2055
2056 ei = (EXTENT_ITEM*)tp.item->data;
2057
2058 if (tp.item->size > sizeof(EXTENT_ITEM)) {
2059 uint32_t len = tp.item->size - sizeof(EXTENT_ITEM);
2060 uint8_t* ptr = (uint8_t*)&ei[1];
2061
2062 while (len > 0) {
2063 uint8_t secttype = *ptr;
2064 ULONG sectlen = get_extent_data_len(secttype);
2065 uint64_t sectcount = get_extent_data_refcount(secttype, ptr + sizeof(uint8_t));
2066
2067 len--;
2068
2069 if (sectlen > len) {
2070 ERR("(%I64x,%x,%I64x): %x bytes left, expecting at least %lx\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, len, sectlen);
2071 return false;
2072 }
2073
2074 if (sectlen == 0) {
2075 ERR("(%I64x,%x,%I64x): unrecognized extent type %x\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, secttype);
2076 return false;
2077 }
2078
2079 rc += sectcount;
2080
2081 if (secttype == TYPE_EXTENT_DATA_REF) {
2082 EXTENT_DATA_REF* sectedr = (EXTENT_DATA_REF*)(ptr + sizeof(uint8_t));
2083
2084 if (try_clone_edr(context, se, sectedr))
2085 return true;
2086 }
2087
2088 len -= sectlen;
2089 ptr += sizeof(uint8_t) + sectlen;
2090 }
2091 }
2092
2093 if (rc >= ei->refcount)
2094 return false;
2095
2096 searchkey.obj_type = TYPE_EXTENT_DATA_REF;
2097 searchkey.offset = 0;
2098
2099 Status = find_item(context->Vcb, context->Vcb->extent_root, &tp, &searchkey, false, NULL);
2100 if (!NT_SUCCESS(Status)) {
2101 ERR("find_item returned %08lx\n", Status);
2102 return false;
2103 }
2104
2105 while (true) {
2106 traverse_ptr next_tp;
2107
2108 if (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type == searchkey.obj_type) {
2109 if (tp.item->size < sizeof(EXTENT_DATA_REF))
2110 ERR("(%I64x,%x,%I64x) has size %u, not %Iu as expected\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset, tp.item->size, sizeof(EXTENT_DATA_REF));
2111 else {
2113 return true;
2114 }
2115 } else if (tp.item->key.obj_id > searchkey.obj_id || (tp.item->key.obj_id == searchkey.obj_id && tp.item->key.obj_type > searchkey.obj_type))
2116 break;
2117
2118 if (find_next_item(context->Vcb, &tp, &next_tp, false, NULL))
2119 tp = next_tp;
2120 else
2121 break;
2122 }
2123
2124 return false;
2125}
2126
2129
2130 if ((IsListEmpty(&context->lastinode.exts) && IsListEmpty(&context->lastinode.oldexts)) || context->lastinode.size == 0)
2131 return STATUS_SUCCESS;
2132
2133 if (context->parent) {
2134 Status = add_ext_holes(context->Vcb, &context->lastinode.exts, context->lastinode.size);
2135 if (!NT_SUCCESS(Status)) {
2136 ERR("add_ext_holes returned %08lx\n", Status);
2137 return Status;
2138 }
2139
2140 Status = add_ext_holes(context->Vcb, &context->lastinode.oldexts, context->lastinode.size);
2141 if (!NT_SUCCESS(Status)) {
2142 ERR("add_ext_holes returned %08lx\n", Status);
2143 return Status;
2144 }
2145
2147 if (!NT_SUCCESS(Status)) {
2148 ERR("sync_ext_cutoff_points returned %08lx\n", Status);
2149 return Status;
2150 }
2151 }
2152
2153 while (!IsListEmpty(&context->lastinode.exts)) {
2155 send_ext* se2 = context->parent ? CONTAINING_RECORD(RemoveHeadList(&context->lastinode.oldexts), send_ext, list_entry) : NULL;
2156 ULONG pos;
2157 EXTENT_DATA2* ed2;
2158
2159 if (se2) {
2160 if (se->data.type == EXTENT_TYPE_INLINE && se2->data.type == EXTENT_TYPE_INLINE &&
2162 ExFreePool(se);
2163 ExFreePool(se2);
2164 continue;
2165 }
2166
2167 if (se->data.type == EXTENT_TYPE_REGULAR && se2->data.type == EXTENT_TYPE_REGULAR) {
2168 EXTENT_DATA2 *ed2a, *ed2b;
2169
2170 ed2a = (EXTENT_DATA2*)se->data.data;
2171 ed2b = (EXTENT_DATA2*)se2->data.data;
2172
2173 if (RtlCompareMemory(ed2a, ed2b, sizeof(EXTENT_DATA2)) == sizeof(EXTENT_DATA2)) {
2174 ExFreePool(se);
2175 ExFreePool(se2);
2176 continue;
2177 }
2178 }
2179 }
2180
2181 if (se->data.type == EXTENT_TYPE_INLINE) {
2182 pos = context->datalen;
2183
2185
2186 send_add_tlv(context, BTRFS_SEND_TLV_PATH, context->lastinode.path, context->lastinode.path ? (uint16_t)strlen(context->lastinode.path) : 0);
2188
2192 ULONG inlen = se->datalen - (ULONG)offsetof(EXTENT_DATA, data[0]);
2193
2195 RtlZeroMemory(&context->data[context->datalen - se->data.decoded_size], (ULONG)se->data.decoded_size);
2196
2198 Status = zlib_decompress(se->data.data, inlen, &context->data[context->datalen - se->data.decoded_size], (uint32_t)se->data.decoded_size);
2199 if (!NT_SUCCESS(Status)) {
2200 ERR("zlib_decompress returned %08lx\n", Status);
2201 ExFreePool(se);
2202 if (se2) ExFreePool(se2);
2203 return Status;
2204 }
2205 } else if (se->data.compression == BTRFS_COMPRESSION_LZO) {
2206 if (inlen < sizeof(uint32_t)) {
2207 ERR("extent data was truncated\n");
2208 ExFreePool(se);
2209 if (se2) ExFreePool(se2);
2210 return STATUS_INTERNAL_ERROR;
2211 } else
2212 inlen -= sizeof(uint32_t);
2213
2214 Status = lzo_decompress(se->data.data + sizeof(uint32_t), inlen, &context->data[context->datalen - se->data.decoded_size], (uint32_t)se->data.decoded_size, sizeof(uint32_t));
2215 if (!NT_SUCCESS(Status)) {
2216 ERR("lzo_decompress returned %08lx\n", Status);
2217 ExFreePool(se);
2218 if (se2) ExFreePool(se2);
2219 return Status;
2220 }
2221 } else if (se->data.compression == BTRFS_COMPRESSION_ZSTD) {
2222 Status = zstd_decompress(se->data.data, inlen, &context->data[context->datalen - se->data.decoded_size], (uint32_t)se->data.decoded_size);
2223 if (!NT_SUCCESS(Status)) {
2224 ERR("zlib_decompress returned %08lx\n", Status);
2225 ExFreePool(se);
2226 if (se2) ExFreePool(se2);
2227 return Status;
2228 }
2229 }
2230 } else {
2231 ERR("unhandled compression type %x\n", se->data.compression);
2232 ExFreePool(se);
2233 if (se2) ExFreePool(se2);
2235 }
2236
2238
2239 ExFreePool(se);
2240 if (se2) ExFreePool(se2);
2241 continue;
2242 }
2243
2244 ed2 = (EXTENT_DATA2*)se->data.data;
2245
2246 if (ed2->size != 0 && (context->parent || context->num_clones > 0)) {
2247 if (try_clone(context, se)) {
2248 ExFreePool(se);
2249 if (se2) ExFreePool(se2);
2250 continue;
2251 }
2252 }
2253
2254 if (ed2->size == 0) { // write sparse
2255 uint64_t off, offset;
2256
2257 for (off = ed2->offset; off < ed2->offset + ed2->num_bytes; off += MAX_SEND_WRITE) {
2258 uint16_t length = (uint16_t)min(min(ed2->offset + ed2->num_bytes - off, MAX_SEND_WRITE), context->lastinode.size - se->offset - off);
2259
2260 if (context->datalen > SEND_BUFFER_LENGTH) {
2261 Status = wait_for_flush(context, tp1, tp2);
2262 if (!NT_SUCCESS(Status)) {
2263 ERR("wait_for_flush returned %08lx\n", Status);
2264 ExFreePool(se);
2265 if (se2) ExFreePool(se2);
2266 return Status;
2267 }
2268
2269 if (context->send->cancelling) {
2270 ExFreePool(se);
2271 if (se2) ExFreePool(se2);
2272 return STATUS_SUCCESS;
2273 }
2274 }
2275
2276 pos = context->datalen;
2277
2279
2280 send_add_tlv(context, BTRFS_SEND_TLV_PATH, context->lastinode.path, context->lastinode.path ? (uint16_t)strlen(context->lastinode.path) : 0);
2281
2282 offset = se->offset + off;
2284
2286 RtlZeroMemory(&context->data[context->datalen - length], length);
2287
2289 }
2290 } else if (se->data.compression == BTRFS_COMPRESSION_NONE) {
2291 uint64_t off, offset;
2292 uint8_t* buf;
2293
2294 buf = ExAllocatePoolWithTag(NonPagedPool, MAX_SEND_WRITE + (2 * context->Vcb->superblock.sector_size), ALLOC_TAG);
2295 if (!buf) {
2296 ERR("out of memory\n");
2297 ExFreePool(se);
2298 if (se2) ExFreePool(se2);
2300 }
2301
2302 for (off = ed2->offset; off < ed2->offset + ed2->num_bytes; off += MAX_SEND_WRITE) {
2303 uint16_t length = (uint16_t)min(ed2->offset + ed2->num_bytes - off, MAX_SEND_WRITE);
2304 ULONG skip_start;
2305 uint64_t addr = ed2->address + off;
2306 void* csum;
2307
2308 if (context->datalen > SEND_BUFFER_LENGTH) {
2309 Status = wait_for_flush(context, tp1, tp2);
2310 if (!NT_SUCCESS(Status)) {
2311 ERR("wait_for_flush returned %08lx\n", Status);
2312 ExFreePool(buf);
2313 ExFreePool(se);
2314 if (se2) ExFreePool(se2);
2315 return Status;
2316 }
2317
2318 if (context->send->cancelling) {
2319 ExFreePool(buf);
2320 ExFreePool(se);
2321 if (se2) ExFreePool(se2);
2322 return STATUS_SUCCESS;
2323 }
2324 }
2325
2326 skip_start = addr & (context->Vcb->superblock.sector_size - 1);
2327 addr -= skip_start;
2328
2329 if (context->lastinode.flags & BTRFS_INODE_NODATASUM)
2330 csum = NULL;
2331 else {
2332 uint32_t len;
2333
2334 len = (uint32_t)sector_align(length + skip_start, context->Vcb->superblock.sector_size) >> context->Vcb->sector_shift;
2335
2337 if (!csum) {
2338 ERR("out of memory\n");
2339 ExFreePool(buf);
2340 ExFreePool(se);
2341 if (se2) ExFreePool(se2);
2343 }
2344
2345 Status = load_csum(context->Vcb, csum, addr, len, NULL);
2346 if (!NT_SUCCESS(Status)) {
2347 ERR("load_csum returned %08lx\n", Status);
2349 ExFreePool(buf);
2350 ExFreePool(se);
2351 if (se2) ExFreePool(se2);
2353 }
2354 }
2355
2356 Status = read_data(context->Vcb, addr, (uint32_t)sector_align(length + skip_start, context->Vcb->superblock.sector_size),
2357 csum, false, buf, NULL, NULL, NULL, 0, false, NormalPagePriority);
2358 if (!NT_SUCCESS(Status)) {
2359 ERR("read_data returned %08lx\n", Status);
2360 ExFreePool(buf);
2361 ExFreePool(se);
2362 if (se2) ExFreePool(se2);
2363 if (csum) ExFreePool(csum);
2364 return Status;
2365 }
2366
2367 if (csum)
2369
2370 pos = context->datalen;
2371
2373
2374 send_add_tlv(context, BTRFS_SEND_TLV_PATH, context->lastinode.path, context->lastinode.path ? (uint16_t)strlen(context->lastinode.path) : 0);
2375
2376 offset = se->offset + off;
2378
2379 length = (uint16_t)min(context->lastinode.size - se->offset - off, length);
2381
2383 }
2384
2385 ExFreePool(buf);
2386 } else {
2387 uint8_t *buf, *compbuf;
2388 uint64_t off;
2389 void* csum;
2390
2392 if (!buf) {
2393 ERR("out of memory\n");
2394 ExFreePool(se);
2395 if (se2) ExFreePool(se2);
2397 }
2398
2400 if (!compbuf) {
2401 ERR("out of memory\n");
2402 ExFreePool(buf);
2403 ExFreePool(se);
2404 if (se2) ExFreePool(se2);
2406 }
2407
2408 if (context->lastinode.flags & BTRFS_INODE_NODATASUM)
2409 csum = NULL;
2410 else {
2411 uint32_t len;
2412
2413 len = (uint32_t)(ed2->size >> context->Vcb->sector_shift);
2414
2416 if (!csum) {
2417 ERR("out of memory\n");
2418 ExFreePool(compbuf);
2419 ExFreePool(buf);
2420 ExFreePool(se);
2421 if (se2) ExFreePool(se2);
2423 }
2424
2425 Status = load_csum(context->Vcb, csum, ed2->address, len, NULL);
2426 if (!NT_SUCCESS(Status)) {
2427 ERR("load_csum returned %08lx\n", Status);
2429 ExFreePool(compbuf);
2430 ExFreePool(buf);
2431 ExFreePool(se);
2432 if (se2) ExFreePool(se2);
2433 return Status;
2434 }
2435 }
2436
2437 Status = read_data(context->Vcb, ed2->address, (uint32_t)ed2->size, csum, false, compbuf, NULL, NULL, NULL, 0, false, NormalPagePriority);
2438 if (!NT_SUCCESS(Status)) {
2439 ERR("read_data returned %08lx\n", Status);
2440 ExFreePool(compbuf);
2441 ExFreePool(buf);
2442 ExFreePool(se);
2443 if (se2) ExFreePool(se2);
2444 if (csum) ExFreePool(csum);
2445 return Status;
2446 }
2447
2448 if (csum)
2450
2453 if (!NT_SUCCESS(Status)) {
2454 ERR("zlib_decompress returned %08lx\n", Status);
2455 ExFreePool(compbuf);
2456 ExFreePool(buf);
2457 ExFreePool(se);
2458 if (se2) ExFreePool(se2);
2459 return Status;
2460 }
2461 } else if (se->data.compression == BTRFS_COMPRESSION_LZO) {
2462 Status = lzo_decompress(&compbuf[sizeof(uint32_t)], (uint32_t)ed2->size, buf, (uint32_t)se->data.decoded_size, sizeof(uint32_t));
2463 if (!NT_SUCCESS(Status)) {
2464 ERR("lzo_decompress returned %08lx\n", Status);
2465 ExFreePool(compbuf);
2466 ExFreePool(buf);
2467 ExFreePool(se);
2468 if (se2) ExFreePool(se2);
2469 return Status;
2470 }
2471 } else if (se->data.compression == BTRFS_COMPRESSION_ZSTD) {
2473 if (!NT_SUCCESS(Status)) {
2474 ERR("zstd_decompress returned %08lx\n", Status);
2475 ExFreePool(compbuf);
2476 ExFreePool(buf);
2477 ExFreePool(se);
2478 if (se2) ExFreePool(se2);
2479 return Status;
2480 }
2481 }
2482
2483 ExFreePool(compbuf);
2484
2485 for (off = ed2->offset; off < ed2->offset + ed2->num_bytes; off += MAX_SEND_WRITE) {
2486 uint16_t length = (uint16_t)min(ed2->offset + ed2->num_bytes - off, MAX_SEND_WRITE);
2488
2489 if (context->datalen > SEND_BUFFER_LENGTH) {
2490 Status = wait_for_flush(context, tp1, tp2);
2491 if (!NT_SUCCESS(Status)) {
2492 ERR("wait_for_flush returned %08lx\n", Status);
2493 ExFreePool(buf);
2494 ExFreePool(se);
2495 if (se2) ExFreePool(se2);
2496 return Status;
2497 }
2498
2499 if (context->send->cancelling) {
2500 ExFreePool(buf);
2501 ExFreePool(se);
2502 if (se2) ExFreePool(se2);
2503 return STATUS_SUCCESS;
2504 }
2505 }
2506
2507 pos = context->datalen;
2508
2510
2511 send_add_tlv(context, BTRFS_SEND_TLV_PATH, context->lastinode.path, context->lastinode.path ? (uint16_t)strlen(context->lastinode.path) : 0);
2512
2513 offset = se->offset + off;
2515
2516 length = (uint16_t)min(context->lastinode.size - se->offset - off, length);
2518
2520 }
2521
2522 ExFreePool(buf);
2523 }
2524
2525 ExFreePool(se);
2526 if (se2) ExFreePool(se2);
2527 }
2528
2529 return STATUS_SUCCESS;
2530}
2531
2533 LIST_ENTRY* le;
2534
2535 if (!IsListEmpty(&context->lastinode.refs) || !IsListEmpty(&context->lastinode.oldrefs)) {
2536 NTSTATUS Status = flush_refs(context, tp1, tp2);
2537 if (!NT_SUCCESS(Status)) {
2538 ERR("flush_refs returned %08lx\n", Status);
2539 return Status;
2540 }
2541
2542 if (context->send->cancelling)
2543 return STATUS_SUCCESS;
2544 }
2545
2546 if (!context->lastinode.deleting) {
2547 if (context->lastinode.file) {
2548 NTSTATUS Status = flush_extents(context, tp1, tp2);
2549 if (!NT_SUCCESS(Status)) {
2550 ERR("flush_extents returned %08lx\n", Status);
2551 return Status;
2552 }
2553
2554 if (context->send->cancelling)
2555 return STATUS_SUCCESS;
2556
2557 send_truncate_command(context, context->lastinode.path, context->lastinode.size);
2558 }
2559
2560 if (context->lastinode.new || context->lastinode.uid != context->lastinode.olduid || context->lastinode.gid != context->lastinode.oldgid)
2561 send_chown_command(context, context->lastinode.path, context->lastinode.uid, context->lastinode.gid);
2562
2563 if (((context->lastinode.mode & __S_IFLNK) != __S_IFLNK || ((context->lastinode.mode & 07777) != 0777)) &&
2564 (context->lastinode.new || context->lastinode.mode != context->lastinode.oldmode))
2565 send_chmod_command(context, context->lastinode.path, context->lastinode.mode);
2566
2567 send_utimes_command(context, context->lastinode.path, &context->lastinode.atime, &context->lastinode.mtime, &context->lastinode.ctime);
2568 }
2569
2570 while (!IsListEmpty(&context->lastinode.exts)) {
2572 }
2573
2574 while (!IsListEmpty(&context->lastinode.oldexts)) {
2576 }
2577
2578 if (context->parent) {
2579 le = context->pending_rmdirs.Flink;
2580
2581 while (le != &context->pending_rmdirs) {
2583
2584 if (pr->last_child_inode <= context->lastinode.inode) {
2585 le = le->Flink;
2586
2588
2590
2591 if (pr->sd->name)
2592 ExFreePool(pr->sd->name);
2593
2594 while (!IsListEmpty(&pr->sd->deleted_children)) {
2596 ExFreePool(dc);
2597 }
2598
2599 ExFreePool(pr->sd);
2600
2602 ExFreePool(pr);
2603 } else
2604 break;
2605 }
2606 }
2607
2608 context->lastinode.inode = 0;
2609 context->lastinode.o = NULL;
2610
2611 if (context->lastinode.path) {
2612 ExFreePool(context->lastinode.path);
2613 context->lastinode.path = NULL;
2614 }
2615
2616 return STATUS_SUCCESS;
2617}
2618
2621
2622 if (tp && tp2 && tp->item->size == tp2->item->size && RtlCompareMemory(tp->item->data, tp2->item->data, tp->item->size) == tp->item->size)
2623 return STATUS_SUCCESS;
2624
2625 if (!IsListEmpty(&context->lastinode.refs) || !IsListEmpty(&context->lastinode.oldrefs)) {
2626 Status = flush_refs(context, tp, tp2);
2627 if (!NT_SUCCESS(Status)) {
2628 ERR("flush_refs returned %08lx\n", Status);
2629 return Status;
2630 }
2631
2632 if (context->send->cancelling)
2633 return STATUS_SUCCESS;
2634 }
2635
2636 if ((context->lastinode.mode & __S_IFLNK) == __S_IFLNK)
2637 return STATUS_SUCCESS;
2638
2639 if (tp) {
2640 EXTENT_DATA* ed;
2641 EXTENT_DATA2* ed2 = NULL;
2642
2643 if (tp->item->size < sizeof(EXTENT_DATA)) {
2644 ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset,
2645 tp->item->size, sizeof(EXTENT_DATA));
2646 return STATUS_INTERNAL_ERROR;
2647 }
2648
2649 ed = (EXTENT_DATA*)tp->item->data;
2650
2652 ERR("unknown encryption type %u\n", ed->encryption);
2653 return STATUS_INTERNAL_ERROR;
2654 }
2655
2656 if (ed->encoding != BTRFS_ENCODING_NONE) {
2657 ERR("unknown encoding type %u\n", ed->encoding);
2658 return STATUS_INTERNAL_ERROR;
2659 }
2660
2663 ERR("unknown compression type %u\n", ed->compression);
2664 return STATUS_INTERNAL_ERROR;
2665 }
2666
2667 if (ed->type == EXTENT_TYPE_REGULAR) {
2668 if (tp->item->size < offsetof(EXTENT_DATA, data[0]) + sizeof(EXTENT_DATA2)) {
2669 ERR("(%I64x,%x,%I64x) was %u bytes, expected %Iu\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset,
2670 tp->item->size, offsetof(EXTENT_DATA, data[0]) + sizeof(EXTENT_DATA2));
2671 return STATUS_INTERNAL_ERROR;
2672 }
2673
2674 ed2 = (EXTENT_DATA2*)ed->data;
2675 } else if (ed->type == EXTENT_TYPE_INLINE) {
2677 ERR("(%I64x,%x,%I64x) was %u bytes, expected %I64u\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset,
2679 return STATUS_INTERNAL_ERROR;
2680 }
2681 }
2682
2683 if ((ed->type == EXTENT_TYPE_INLINE || (ed->type == EXTENT_TYPE_REGULAR && ed2->size != 0)) && ed->decoded_size != 0) {
2685
2686 if (!se) {
2687 ERR("out of memory\n");
2689 }
2690
2691 se->offset = tp->item->key.offset;
2692 se->datalen = tp->item->size;
2693 RtlCopyMemory(&se->data, tp->item->data, tp->item->size);
2694 InsertTailList(&context->lastinode.exts, &se->list_entry);
2695 }
2696 }
2697
2698 if (tp2) {
2699 EXTENT_DATA* ed;
2700 EXTENT_DATA2* ed2 = NULL;
2701
2702 if (tp2->item->size < sizeof(EXTENT_DATA)) {
2703 ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp2->item->key.obj_id, tp2->item->key.obj_type, tp2->item->key.offset,
2704 tp2->item->size, sizeof(EXTENT_DATA));
2705 return STATUS_INTERNAL_ERROR;
2706 }
2707
2708 ed = (EXTENT_DATA*)tp2->item->data;
2709
2711 ERR("unknown encryption type %u\n", ed->encryption);
2712 return STATUS_INTERNAL_ERROR;
2713 }
2714
2715 if (ed->encoding != BTRFS_ENCODING_NONE) {
2716 ERR("unknown encoding type %u\n", ed->encoding);
2717 return STATUS_INTERNAL_ERROR;
2718 }
2719
2722 ERR("unknown compression type %u\n", ed->compression);
2723 return STATUS_INTERNAL_ERROR;
2724 }
2725
2726 if (ed->type == EXTENT_TYPE_REGULAR) {
2727 if (tp2->item->size < offsetof(EXTENT_DATA, data[0]) + sizeof(EXTENT_DATA2)) {
2728 ERR("(%I64x,%x,%I64x) was %u bytes, expected %Iu\n", tp2->item->key.obj_id, tp2->item->key.obj_type, tp2->item->key.offset,
2729 tp2->item->size, offsetof(EXTENT_DATA, data[0]) + sizeof(EXTENT_DATA2));
2730 return STATUS_INTERNAL_ERROR;
2731 }
2732
2733 ed2 = (EXTENT_DATA2*)ed->data;
2734 } else if (ed->type == EXTENT_TYPE_INLINE) {
2735 if (tp2->item->size < offsetof(EXTENT_DATA, data[0]) + ed->decoded_size) {
2736 ERR("(%I64x,%x,%I64x) was %u bytes, expected %I64u\n", tp2->item->key.obj_id, tp2->item->key.obj_type, tp2->item->key.offset,
2737 tp2->item->size, offsetof(EXTENT_DATA, data[0]) + ed->decoded_size);
2738 return STATUS_INTERNAL_ERROR;
2739 }
2740 }
2741
2742 if ((ed->type == EXTENT_TYPE_INLINE || (ed->type == EXTENT_TYPE_REGULAR && ed2->size != 0)) && ed->decoded_size != 0) {
2744
2745 if (!se) {
2746 ERR("out of memory\n");
2748 }
2749
2750 se->offset = tp2->item->key.offset;
2751 se->datalen = tp2->item->size;
2752 RtlCopyMemory(&se->data, tp2->item->data, tp2->item->size);
2753 InsertTailList(&context->lastinode.oldexts, &se->list_entry);
2754 }
2755 }
2756
2757 return STATUS_SUCCESS;
2758}
2759
2760typedef struct {
2762 char* name;
2764 char* value1;
2766 char* value2;
2768} xattr_cmp;
2769
2771 if (tp && tp2 && tp->item->size == tp2->item->size && RtlCompareMemory(tp->item->data, tp2->item->data, tp->item->size) == tp->item->size)
2772 return STATUS_SUCCESS;
2773
2774 if (!IsListEmpty(&context->lastinode.refs) || !IsListEmpty(&context->lastinode.oldrefs)) {
2776 if (!NT_SUCCESS(Status)) {
2777 ERR("flush_refs returned %08lx\n", Status);
2778 return Status;
2779 }
2780
2781 if (context->send->cancelling)
2782 return STATUS_SUCCESS;
2783 }
2784
2785 if (tp && tp->item->size < sizeof(DIR_ITEM)) {
2786 ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset,
2787 tp->item->size, sizeof(DIR_ITEM));
2788 return STATUS_INTERNAL_ERROR;
2789 }
2790
2791 if (tp2 && tp2->item->size < sizeof(DIR_ITEM)) {
2792 ERR("(%I64x,%x,%I64x) was %u bytes, expected at least %Iu\n", tp2->item->key.obj_id, tp2->item->key.obj_type, tp2->item->key.offset,
2793 tp2->item->size, sizeof(DIR_ITEM));
2794 return STATUS_INTERNAL_ERROR;
2795 }
2796
2797 if (tp && !tp2) {
2798 ULONG len;
2799 DIR_ITEM* di;
2800
2801 len = tp->item->size;
2802 di = (DIR_ITEM*)tp->item->data;
2803
2804 do {
2805 ULONG pos;
2806
2807 if (len < sizeof(DIR_ITEM) || len < offsetof(DIR_ITEM, name[0]) + di->m + di->n) {
2808 ERR("(%I64x,%x,%I64x) was truncated\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset);
2809 return STATUS_INTERNAL_ERROR;
2810 }
2811
2812 pos = context->datalen;
2814 send_add_tlv(context, BTRFS_SEND_TLV_PATH, context->lastinode.path, context->lastinode.path ? (uint16_t)strlen(context->lastinode.path) : 0);
2818
2819 len -= (ULONG)offsetof(DIR_ITEM, name[0]) + di->m + di->n;
2820 di = (DIR_ITEM*)&di->name[di->m + di->n];
2821 } while (len > 0);
2822 } else if (!tp && tp2) {
2823 ULONG len;
2824 DIR_ITEM* di;
2825
2826 len = tp2->item->size;
2827 di = (DIR_ITEM*)tp2->item->data;
2828
2829 do {
2830 ULONG pos;
2831
2832 if (len < sizeof(DIR_ITEM) || len < offsetof(DIR_ITEM, name[0]) + di->m + di->n) {
2833 ERR("(%I64x,%x,%I64x) was truncated\n", tp2->item->key.obj_id, tp2->item->key.obj_type, tp2->item->key.offset);
2834 return STATUS_INTERNAL_ERROR;
2835 }
2836
2837 pos = context->datalen;
2839 send_add_tlv(context, BTRFS_SEND_TLV_PATH, context->lastinode.path, context->lastinode.path ? (uint16_t)strlen(context->lastinode.path) : 0);
2842
2843 len -= (ULONG)offsetof(DIR_ITEM, name[0]) + di->m + di->n;
2844 di = (DIR_ITEM*)&di->name[di->m + di->n];
2845 } while (len > 0);
2846 } else {
2847 ULONG len;
2848 DIR_ITEM* di;
2849 LIST_ENTRY xattrs;
2850
2851 InitializeListHead(&xattrs);
2852
2853 len = tp->item->size;
2854 di = (DIR_ITEM*)tp->item->data;
2855
2856 do {
2857 xattr_cmp* xa;
2858
2859 if (len < sizeof(DIR_ITEM) || len < offsetof(DIR_ITEM, name[0]) + di->m + di->n) {
2860 ERR("(%I64x,%x,%I64x) was truncated\n", tp->item->key.obj_id, tp->item->key.obj_type, tp->item->key.offset);
2861 return STATUS_INTERNAL_ERROR;
2862 }
2863
2865 if (!xa) {
2866 ERR("out of memory\n");
2867
2868 while (!IsListEmpty(&xattrs)) {
2870 }
2871
2873 }
2874
2875 xa->namelen = di->n;
2876 xa->name = di->name;
2877 xa->value1len = di->m;
2878 xa->value1 = di->name + di->n;
2879 xa->value2len = 0;
2880 xa->value2 = NULL;
2881
2882 InsertTailList(&xattrs, &xa->list_entry);
2883
2884 len -= (ULONG)offsetof(DIR_ITEM, name[0]) + di->m + di->n;
2885 di = (DIR_ITEM*)&di->name[di->m + di->n];
2886 } while (len > 0);
2887
2888 len = tp2->item->size;
2889 di = (DIR_ITEM*)tp2->item->data;
2890
2891 do {
2892 xattr_cmp* xa;
2893 LIST_ENTRY* le;
2894 bool found = false;
2895
2896 if (len < sizeof(DIR_ITEM) || len < offsetof(DIR_ITEM, name[0]) + di->m + di->n) {
2897 ERR("(%I64x,%x,%I64x) was truncated\n", tp2->item->key.obj_id, tp2->item->key.obj_type, tp2->item->key.offset);
2898 return STATUS_INTERNAL_ERROR;
2899 }
2900
2901 le = xattrs.Flink;
2902 while (le != &xattrs) {
2904
2905 if (xa->namelen == di->n && RtlCompareMemory(xa->name, di->name, di->n) == di->n) {
2906 xa->value2len = di->m;
2907 xa->value2 = di->name + di->n;
2908 found = true;
2909 break;
2910 }
2911
2912 le = le->Flink;
2913 }
2914
2915 if (!found) {
2917 if (!xa) {
2918 ERR("out of memory\n");
2919
2920 while (!IsListEmpty(&xattrs)) {
2922 }
2923
2925 }
2926
2927 xa->namelen = di->n;
2928 xa->name = di->name;
2929 xa->value1len = 0;
2930 xa->value1 = NULL;
2931 xa->value2len = di->m;
2932 xa->value2 = di->name + di->n;
2933
2934 InsertTailList(&xattrs, &xa->list_entry);
2935 }
2936
2937 len -= (ULONG)offsetof(DIR_ITEM, name[0]) + di->m + di->n;
2938 di = (DIR_ITEM*)&di->name[di->m + di->n];
2939 } while (len > 0);
2940
2941 while (!IsListEmpty(&xattrs)) {
2943
2944 if (xa->value1len != xa->value2len || !xa->value1 || !xa->value2 || RtlCompareMemory(xa->value1, xa->value2, xa->value1len) != xa->value1len) {
2945 ULONG pos;
2946
2947 if (!xa->value1) {
2948 pos = context->datalen;
2950 send_add_tlv(context, BTRFS_SEND_TLV_PATH, context->lastinode.path, context->lastinode.path ? (uint16_t)strlen(context->lastinode.path) : 0);
2953 } else {
2954 pos = context->datalen;
2956 send_add_tlv(context, BTRFS_SEND_TLV_PATH, context->lastinode.path, context->lastinode.path ? (uint16_t)strlen(context->lastinode.path) : 0);
2960 }
2961 }
2962
2963 ExFreePool(xa);
2964 }
2965 }
2966
2967 return STATUS_SUCCESS;
2968}
2969
2970_Function_class_(KSTART_ROUTINE)
2971static void __stdcall send_thread(void* ctx) {
2974 KEY searchkey;
2975 traverse_ptr tp, tp2;
2976
2977 InterlockedIncrement(&context->root->send_ops);
2978
2979 if (context->parent)
2980 InterlockedIncrement(&context->parent->send_ops);
2981
2982 if (context->clones) {
2983 ULONG i;
2984
2985 for (i = 0; i < context->num_clones; i++) {
2986 InterlockedIncrement(&context->clones[i]->send_ops);
2987 }
2988 }
2989
2990 ExAcquireResourceExclusiveLite(&context->Vcb->tree_lock, true);
2991
2993
2994 if (context->parent)
2995 flush_subvol_fcbs(context->parent);
2996
2997 if (context->Vcb->need_write)
2998 Status = do_write(context->Vcb, NULL);
2999 else
3001
3002 free_trees(context->Vcb);
3003
3004 if (!NT_SUCCESS(Status)) {
3005 ERR("do_write returned %08lx\n", Status);
3006 ExReleaseResourceLite(&context->Vcb->tree_lock);
3007 goto end;
3008 }
3009
3010 ExConvertExclusiveToSharedLite(&context->Vcb->tree_lock);
3011
3012 searchkey.obj_id = searchkey.offset = 0;
3013 searchkey.obj_type = 0;
3014
3015 Status = find_item(context->Vcb, context->root, &tp, &searchkey, false, NULL);
3016 if (!NT_SUCCESS(Status)) {
3017 ERR("find_item returned %08lx\n", Status);
3018 ExReleaseResourceLite(&context->Vcb->tree_lock);
3019 goto end;
3020 }
3021
3022 if (context->parent) {
3023 bool ended1 = false, ended2 = false;
3024 Status = find_item(context->Vcb, context->parent, &tp2, &searchkey, false, NULL);
3025 if (!NT_SUCCESS(Status)) {
3026 ERR("find_item returned %08lx\n", Status);
3027 ExReleaseResourceLite(&context->Vcb->tree_lock);
3028 goto end;
3029 }
3030
3031 do {
3032 traverse_ptr next_tp;
3033
3034 if (context->datalen > SEND_BUFFER_LENGTH) {
3035 KEY key1 = tp.item->key, key2 = tp2.item->key;
3036
3037 ExReleaseResourceLite(&context->Vcb->tree_lock);
3038
3039 KeClearEvent(&context->send->cleared_event);
3040 KeSetEvent(&context->buffer_event, 0, true);
3041 KeWaitForSingleObject(&context->send->cleared_event, Executive, KernelMode, false, NULL);
3042
3043 if (context->send->cancelling)
3044 goto end;
3045
3046 ExAcquireResourceSharedLite(&context->Vcb->tree_lock, true);
3047
3048 if (!ended1) {
3049 Status = find_item(context->Vcb, context->root, &tp, &key1, false, NULL);
3050 if (!NT_SUCCESS(Status)) {
3051 ERR("find_item returned %08lx\n", Status);
3052 ExReleaseResourceLite(&context->Vcb->tree_lock);
3053 goto end;
3054 }
3055
3056 if (keycmp(tp.item->key, key1)) {
3057 ERR("readonly subvolume changed\n");
3058 ExReleaseResourceLite(&context->Vcb->tree_lock);
3060 goto end;
3061 }
3062 }
3063
3064 if (!ended2) {
3065 Status = find_item(context->Vcb, context->parent, &tp2, &key2, false, NULL);
3066 if (!NT_SUCCESS(Status)) {
3067 ERR("find_item returned %08lx\n", Status);
3068 ExReleaseResourceLite(&context->Vcb->tree_lock);
3069 goto end;
3070 }
3071
3072 if (keycmp(tp2.item->key, key2)) {
3073 ERR("readonly subvolume changed\n");
3074 ExReleaseResourceLite(&context->Vcb->tree_lock);
3076 goto end;
3077 }
3078 }
3079 }
3080
3081 while (!ended1 && !ended2 && tp.tree->header.address == tp2.tree->header.address) {
3082 Status = skip_to_difference(context->Vcb, &tp, &tp2, &ended1, &ended2);
3083 if (!NT_SUCCESS(Status)) {
3084 ERR("skip_to_difference returned %08lx\n", Status);
3085 ExReleaseResourceLite(&context->Vcb->tree_lock);
3086 goto end;
3087 }
3088 }
3089
3090 if (!ended1 && !ended2 && !keycmp(tp.item->key, tp2.item->key)) {
3091 bool no_next = false, no_next2 = false;
3092
3093 TRACE("~ %I64x,%x,%I64x\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
3094
3095 if (context->lastinode.inode != 0 && tp.item->key.obj_id > context->lastinode.inode) {
3096 Status = finish_inode(context, ended1 ? NULL : &tp, ended2 ? NULL : &tp2);
3097 if (!NT_SUCCESS(Status)) {
3098 ERR("finish_inode returned %08lx\n", Status);
3099 ExReleaseResourceLite(&context->Vcb->tree_lock);
3100 goto end;
3101 }
3102
3103 if (context->send->cancelling) {
3104 ExReleaseResourceLite(&context->Vcb->tree_lock);
3105 goto end;
3106 }
3107 }
3108
3110 if (tp.item->size == tp2.item->size && tp.item->size > 0 && RtlCompareMemory(tp.item->data, tp2.item->data, tp.item->size) == tp.item->size) {
3112
3113 while (true) {
3114 if (!find_next_item(context->Vcb, &tp, &next_tp, false, NULL)) {
3115 ended1 = true;
3116 break;
3117 }
3118
3119 tp = next_tp;
3120
3121 if (tp.item->key.obj_id != inode)
3122 break;
3123 }
3124
3125 while (true) {
3126 if (!find_next_item(context->Vcb, &tp2, &next_tp, false, NULL)) {
3127 ended2 = true;
3128 break;
3129 }
3130
3131 tp2 = next_tp;
3132
3133 if (tp2.item->key.obj_id != inode)
3134 break;
3135 }
3136
3137 no_next = true;
3138 } else if (tp.item->size > sizeof(uint64_t) && tp2.item->size > sizeof(uint64_t) && *(uint64_t*)tp.item->data != *(uint64_t*)tp2.item->data) {
3140
3141 Status = send_inode(context, NULL, &tp2);
3142 if (!NT_SUCCESS(Status)) {
3143 ERR("send_inode returned %08lx\n", Status);
3144 ExReleaseResourceLite(&context->Vcb->tree_lock);
3145 goto end;
3146 }
3147
3148 while (true) {
3149 if (!find_next_item(context->Vcb, &tp2, &next_tp, false, NULL)) {
3150 ended2 = true;
3151 break;
3152 }
3153
3154 tp2 = next_tp;
3155
3156 if (tp2.item->key.obj_id != inode)
3157 break;
3158
3159 if (tp2.item->key.obj_type == TYPE_INODE_REF) {
3160 Status = send_inode_ref(context, &tp2, true);
3161 if (!NT_SUCCESS(Status)) {
3162 ERR("send_inode_ref returned %08lx\n", Status);
3163 ExReleaseResourceLite(&context->Vcb->tree_lock);
3164 goto end;
3165 }
3166 } else if (tp2.item->key.obj_type == TYPE_INODE_EXTREF) {
3167 Status = send_inode_extref(context, &tp2, true);
3168 if (!NT_SUCCESS(Status)) {
3169 ERR("send_inode_extref returned %08lx\n", Status);
3170 ExReleaseResourceLite(&context->Vcb->tree_lock);
3171 goto end;
3172 }
3173 }
3174 }
3175
3176 Status = finish_inode(context, ended1 ? NULL : &tp, ended2 ? NULL : &tp2);
3177 if (!NT_SUCCESS(Status)) {
3178 ERR("finish_inode returned %08lx\n", Status);
3179 ExReleaseResourceLite(&context->Vcb->tree_lock);
3180 goto end;
3181 }
3182
3183 if (context->send->cancelling) {
3184 ExReleaseResourceLite(&context->Vcb->tree_lock);
3185 goto end;
3186 }
3187
3188 no_next2 = true;
3189
3191 if (!NT_SUCCESS(Status)) {
3192 ERR("send_inode returned %08lx\n", Status);
3193 ExReleaseResourceLite(&context->Vcb->tree_lock);
3194 goto end;
3195 }
3196 } else {
3197 Status = send_inode(context, &tp, &tp2);
3198 if (!NT_SUCCESS(Status)) {
3199 ERR("send_inode returned %08lx\n", Status);
3200 ExReleaseResourceLite(&context->Vcb->tree_lock);
3201 goto end;
3202 }
3203 }
3204 } else if (tp.item->key.obj_type == TYPE_INODE_REF) {
3205 Status = send_inode_ref(context, &tp, false);
3206 if (!NT_SUCCESS(Status)) {
3207 ERR("send_inode_ref returned %08lx\n", Status);
3208 ExReleaseResourceLite(&context->Vcb->tree_lock);
3209 goto end;
3210 }
3211
3212 Status = send_inode_ref(context, &tp2, true);
3213 if (!NT_SUCCESS(Status)) {
3214 ERR("send_inode_ref returned %08lx\n", Status);
3215 ExReleaseResourceLite(&context->Vcb->tree_lock);
3216 goto end;
3217 }
3218 } else if (tp.item->key.obj_type == TYPE_INODE_EXTREF) {
3219 Status = send_inode_extref(context, &tp, false);
3220 if (!NT_SUCCESS(Status)) {
3221 ERR("send_inode_extref returned %08lx\n", Status);
3222 ExReleaseResourceLite(&context->Vcb->tree_lock);
3223 goto end;
3224 }
3225
3226 Status = send_inode_extref(context, &tp2, true);
3227 if (!NT_SUCCESS(Status)) {
3228 ERR("send_inode_extref returned %08lx\n", Status);
3229 ExReleaseResourceLite(&context->Vcb->tree_lock);
3230 goto end;
3231 }
3232 } else if (tp.item->key.obj_type == TYPE_EXTENT_DATA) {
3233 Status = send_extent_data(context, &tp, &tp2);
3234 if (!NT_SUCCESS(Status)) {
3235 ERR("send_extent_data returned %08lx\n", Status);
3236 ExReleaseResourceLite(&context->Vcb->tree_lock);
3237 goto end;
3238 }
3239
3240 if (context->send->cancelling) {
3241 ExReleaseResourceLite(&context->Vcb->tree_lock);
3242 goto end;
3243 }
3244 } else if (tp.item->key.obj_type == TYPE_XATTR_ITEM) {
3245 Status = send_xattr(context, &tp, &tp2);
3246 if (!NT_SUCCESS(Status)) {
3247 ERR("send_xattr returned %08lx\n", Status);
3248 ExReleaseResourceLite(&context->Vcb->tree_lock);
3249 goto end;
3250 }
3251
3252 if (context->send->cancelling) {
3253 ExReleaseResourceLite(&context->Vcb->tree_lock);
3254 goto end;
3255 }
3256 }
3257
3258 if (!no_next) {
3259 if (find_next_item(context->Vcb, &tp, &next_tp, false, NULL))
3260 tp = next_tp;
3261 else
3262 ended1 = true;
3263
3264 if (!no_next2) {
3265 if (find_next_item(context->Vcb, &tp2, &next_tp, false, NULL))
3266 tp2 = next_tp;
3267 else
3268 ended2 = true;
3269 }
3270 }
3271 } else if (ended2 || (!ended1 && !ended2 && keycmp(tp.item->key, tp2.item->key) == -1)) {
3272 TRACE("A %I64x,%x,%I64x\n", tp.item->key.obj_id, tp.item->key.obj_type, tp.item->key.offset);
3273
3274 if (context->lastinode.inode != 0 && tp.item->key.obj_id > context->lastinode.inode) {
3275 Status = finish_inode(context, ended1 ? NULL : &tp, ended2 ? NULL : &tp2);
3276 if (!NT_SUCCESS(Status)) {
3277 ERR("finish_inode returned %08lx\n", Status);
3278 ExReleaseResourceLite(&context->Vcb->tree_lock);
3279 goto end;
3280 }
3281
3282 if (context->send->cancelling) {
3283 ExReleaseResourceLite(&context->Vcb->tree_lock);
3284 goto end;
3285 }
3286 }
3287
3290 if (!NT_SUCCESS(Status)) {
3291 ERR("send_inode returned %08lx\n", Status);
3292 ExReleaseResourceLite(&context->Vcb->tree_lock);
3293 goto end;
3294 }
3295 } else if (tp.item->key.obj_type == TYPE_INODE_REF) {
3296 Status = send_inode_ref(context, &tp, false);
3297 if (!NT_SUCCESS(Status)) {
3298 ERR("send_inode_ref returned %08lx\n", Status);
3299 ExReleaseResourceLite(&context->Vcb->tree_lock);
3300 goto end;
3301 }
3302 } else if (tp.item->key.obj_type == TYPE_INODE_EXTREF) {
3303 Status = send_inode_extref(context, &tp, false);
3304 if (!NT_SUCCESS(Status)) {
3305 ERR("send_inode_extref returned %08lx\n", Status);
3306 ExReleaseResourceLite(&context->Vcb->tree_lock);
3307 goto end;
3308 }
3309 } else if (tp.item->key.obj_type == TYPE_EXTENT_DATA) {
3311 if (!NT_SUCCESS(Status)) {
3312 ERR("send_extent_data returned %08lx\n", Status);
3313 ExReleaseResourceLite(&context->Vcb->tree_lock);
3314 goto end;
3315 }
3316
3317 if (context->send->cancelling) {
3318 ExReleaseResourceLite(&context->Vcb->tree_lock);
3319 goto end;
3320 }
3321 } else if (tp.item->key.obj_type == TYPE_XATTR_ITEM) {
3323 if (!NT_SUCCESS(Status)) {
3324 ERR("send_xattr returned %08lx\n", Status);
3325 ExReleaseResourceLite(&context->Vcb->tree_lock);
3326 goto end;
3327 }
3328
3329 if (context->send->cancelling) {
3330 ExReleaseResourceLite(&context->Vcb->tree_lock);
3331 goto end;
3332 }
3333 }
3334
3335 if (find_next_item(context->Vcb, &tp, &next_tp, false, NULL))
3336 tp = next_tp;
3337 else
3338 ended1 = true;
3339 } else if (ended1 || (!ended1 && !ended2 && keycmp(tp.item->key, tp2.item->key) == 1)) {
3340 TRACE("B %I64x,%x,%I64x\n", tp2.item->key.obj_id, tp2.item->key.obj_type, tp2.item->key.offset);
3341
3342 if (context->lastinode.inode != 0 && tp2.item->key.obj_id > context->lastinode.inode) {
3343 Status = finish_inode(context, ended1 ? NULL : &tp, ended2 ? NULL : &tp2);
3344 if (!NT_SUCCESS(Status)) {
3345 ERR("finish_inode returned %08lx\n", Status);
3346 ExReleaseResourceLite(&context->Vcb->tree_lock);
3347 goto end;
3348 }
3349
3350 if (context->send->cancelling) {
3351 ExReleaseResourceLite(&context->Vcb->tree_lock);
3352 goto end;
3353 }
3354 }
3355
3356 if (tp2.item->key.obj_type == TYPE_INODE_ITEM) {
3357 Status = send_inode(context, NULL, &tp2);
3358 if (!NT_SUCCESS(Status)) {
3359 ERR("send_inode returned %08lx\n", Status);
3360 ExReleaseResourceLite(&context->Vcb->tree_lock);
3361 goto end;
3362 }
3363 } else if (tp2.item->key.obj_type == TYPE_INODE_REF) {
3364 Status = send_inode_ref(context, &tp2, true);
3365 if (!NT_SUCCESS(Status)) {
3366 ERR("send_inode_ref returned %08lx\n", Status);
3367 ExReleaseResourceLite(&context->Vcb->tree_lock);
3368 goto end;
3369 }
3370 } else if (tp2.item->key.obj_type == TYPE_INODE_EXTREF) {
3371 Status = send_inode_extref(context, &tp2, true);
3372 if (!NT_SUCCESS(Status)) {
3373 ERR("send_inode_extref returned %08lx\n", Status);
3374 ExReleaseResourceLite(&context->Vcb->tree_lock);
3375 goto end;
3376 }
3377 } else if (tp2.item->key.obj_type == TYPE_EXTENT_DATA && !context->lastinode.deleting) {
3379 if (!NT_SUCCESS(Status)) {
3380 ERR("send_extent_data returned %08lx\n", Status);
3381 ExReleaseResourceLite(&context->Vcb->tree_lock);
3382 goto end;
3383 }
3384
3385 if (context->send->cancelling) {
3386 ExReleaseResourceLite(&context->Vcb->tree_lock);
3387 goto end;
3388 }
3389 } else if (tp2.item->key.obj_type == TYPE_XATTR_ITEM && !context->lastinode.deleting) {
3390 Status = send_xattr(context, NULL, &tp2);
3391 if (!NT_SUCCESS(Status)) {
3392 ERR("send_xattr returned %08lx\n", Status);
3393 ExReleaseResourceLite(&context->Vcb->tree_lock);
3394 goto end;
3395 }
3396
3397 if (context->send->cancelling) {
3398 ExReleaseResourceLite(&context->Vcb->tree_lock);
3399 goto end;
3400 }
3401 }
3402
3403 if (find_next_item(context->Vcb, &tp2, &next_tp, false, NULL))
3404 tp2 = next_tp;
3405 else
3406 ended2 = true;
3407 }
3408 } while (!ended1 || !ended2);
3409 } else {
3410 do {
3411 traverse_ptr next_tp;
3412
3413 if (context->datalen > SEND_BUFFER_LENGTH) {
3414 KEY key = tp.item->key;
3415
3416 ExReleaseResourceLite(&context->Vcb->tree_lock);
3417
3418 KeClearEvent(&context->send->cleared_event);
3419 KeSetEvent(&context->buffer_event, 0, true);
3420 KeWaitForSingleObject(&context->send->cleared_event, Executive, KernelMode, false, NULL);
3421
3422 if (context->send->cancelling)
3423 goto end;
3424
3425 ExAcquireResourceSharedLite(&context->Vcb->tree_lock, true);
3426
3427 Status = find_item(context->Vcb, context->root, &tp, &key, false, NULL);
3428 if (!NT_SUCCESS(Status)) {
3429 ERR("find_item returned %08lx\n", Status);
3430 ExReleaseResourceLite(&context->Vcb->tree_lock);
3431 goto end;
3432 }
3433
3434 if (keycmp(tp.item->key, key)) {
3435 ERR("readonly subvolume changed\n");
3436 ExReleaseResourceLite(&context->Vcb->tree_lock);
3438 goto end;
3439 }
3440 }
3441
3442 if (context->lastinode.inode != 0 && tp.item->key.obj_id > context->lastinode.inode) {
3444 if (!NT_SUCCESS(Status)) {
3445 ERR("finish_inode returned %08lx\n", Status);
3446 ExReleaseResourceLite(&context->Vcb->tree_lock);
3447 goto end;
3448 }
3449
3450 if (context->send->cancelling) {
3451 ExReleaseResourceLite(&context->Vcb->tree_lock);
3452 goto end;
3453 }
3454 }
3455
3458 if (!NT_SUCCESS(Status)) {
3459 ERR("send_inode returned %08lx\n", Status);
3460 ExReleaseResourceLite(&context->Vcb->tree_lock);
3461 goto end;
3462 }
3463 } else if (tp.item->key.obj_type == TYPE_INODE_REF) {
3464 Status = send_inode_ref(context, &tp, false);
3465 if (!NT_SUCCESS(Status)) {
3466 ERR("send_inode_ref returned %08lx\n", Status);
3467 ExReleaseResourceLite(&context->Vcb->tree_lock);
3468 goto end;
3469 }
3470 } else if (tp.item->key.obj_type == TYPE_INODE_EXTREF) {
3471 Status = send_inode_extref(context, &tp, false);
3472 if (!NT_SUCCESS(Status)) {
3473 ERR("send_inode_extref returned %08lx\n", Status);
3474 ExReleaseResourceLite(&context->Vcb->tree_lock);
3475 goto end;
3476 }
3477 } else if (tp.item->key.obj_type == TYPE_EXTENT_DATA) {
3479 if (!NT_SUCCESS(Status)) {
3480 ERR("send_extent_data returned %08lx\n", Status);
3481 ExReleaseResourceLite(&context->Vcb->tree_lock);
3482 goto end;
3483 }
3484
3485 if (context->send->cancelling) {
3486 ExReleaseResourceLite(&context->Vcb->tree_lock);
3487 goto end;
3488 }
3489 } else if (tp.item->key.obj_type == TYPE_XATTR_ITEM) {
3491 if (!NT_SUCCESS(Status)) {
3492 ERR("send_xattr returned %08lx\n", Status);
3493 ExReleaseResourceLite(&context->Vcb->tree_lock);
3494 goto end;
3495 }
3496
3497 if (context->send->cancelling) {
3498 ExReleaseResourceLite(&context->Vcb->tree_lock);
3499 goto end;
3500 }
3501 }
3502
3503 if (find_next_item(context->Vcb, &tp, &next_tp, false, NULL))
3504 tp = next_tp;
3505 else
3506 break;
3507 } while (true);
3508 }
3509
3510 if (context->lastinode.inode != 0) {
3512 if (!NT_SUCCESS(Status)) {
3513 ERR("finish_inode returned %08lx\n", Status);
3514 ExReleaseResourceLite(&context->Vcb->tree_lock);
3515 goto end;
3516 }
3517
3518 ExReleaseResourceLite(&context->Vcb->tree_lock);
3519
3520 if (context->send->cancelling)
3521 goto end;
3522 } else
3523 ExReleaseResourceLite(&context->Vcb->tree_lock);
3524
3525 KeClearEvent(&context->send->cleared_event);
3526 KeSetEvent(&context->buffer_event, 0, true);
3527 KeWaitForSingleObject(&context->send->cleared_event, Executive, KernelMode, false, NULL);
3528
3530
3531end:
3532 if (!NT_SUCCESS(Status)) {
3533 KeSetEvent(&context->buffer_event, 0, false);
3534
3535 if (context->send->ccb)
3536 context->send->ccb->send_status = Status;
3537 }
3538
3539 ExAcquireResourceExclusiveLite(&context->Vcb->send_load_lock, true);
3540
3541 while (!IsListEmpty(&context->orphans)) {
3543 ExFreePool(o);
3544 }
3545
3546 while (!IsListEmpty(&context->dirs)) {
3548
3549 if (sd->name)
3550 ExFreePool(sd->name);
3551
3552 while (!IsListEmpty(&sd->deleted_children)) {
3554 ExFreePool(dc);
3555 }
3556
3557 ExFreePool(sd);
3558 }
3559
3560 ZwClose(context->send->thread);
3561 context->send->thread = NULL;
3562
3563 if (context->send->ccb)
3564 context->send->ccb->send = NULL;
3565
3566 RemoveEntryList(&context->send->list_entry);
3567 ExFreePool(context->send);
3568 ExFreePool(context->data);
3569
3570 InterlockedDecrement(&context->Vcb->running_sends);
3571 InterlockedDecrement(&context->root->send_ops);
3572
3573 if (context->parent)
3574 InterlockedDecrement(&context->parent->send_ops);
3575
3576 ExReleaseResourceLite(&context->Vcb->send_load_lock);
3577
3578 if (context->clones) {
3579 ULONG i;
3580
3581 for (i = 0; i < context->num_clones; i++) {
3582 InterlockedDecrement(&context->clones[i]->send_ops);
3583 }
3584
3585 ExFreePool(context->clones);
3586 }
3587
3589
3591}
3592
3595 fcb* fcb;
3596 ccb* ccb;
3597 root* parsubvol = NULL;
3599 send_info* send;
3600 ULONG num_clones = 0;
3601 root** clones = NULL;
3603
3604 if (!FileObject || !FileObject->FsContext || !FileObject->FsContext2 || FileObject->FsContext == Vcb->volume_fcb)
3606
3607 if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_MANAGE_VOLUME_PRIVILEGE), Irp->RequestorMode))
3609
3610 fcb = FileObject->FsContext;
3611 ccb = FileObject->FsContext2;
3612
3613 if (fcb->inode != SUBVOL_ROOT_INODE || fcb == Vcb->root_fileref->fcb)
3615
3616 if (!Vcb->readonly && !(fcb->subvol->root_item.flags & BTRFS_SUBVOL_READONLY))
3618
3619 if (data) {
3621 HANDLE parent;
3622
3623#if defined(_WIN64)
3624 if (IoIs32bitProcess(Irp)) {
3626
3627 if (datalen < offsetof(btrfs_send_subvol32, num_clones))
3629
3630 parent = Handle32ToHandle(bss32->parent);
3631
3632 if (datalen >= offsetof(btrfs_send_subvol32, clones[0]))
3633 num_clones = bss32->num_clones;
3634
3635 if (datalen < offsetof(btrfs_send_subvol32, clones[0]) + (num_clones * sizeof(uint32_t)))
3637 } else {
3638#endif
3639 if (datalen < offsetof(btrfs_send_subvol, num_clones))
3641
3642 parent = bss->parent;
3643
3644 if (datalen >= offsetof(btrfs_send_subvol, clones[0]))
3645 num_clones = bss->num_clones;
3646
3647 if (datalen < offsetof(btrfs_send_subvol, clones[0]) + (num_clones * sizeof(HANDLE)))
3649#if defined(_WIN64)
3650 }
3651#endif
3652
3653 if (parent) {
3654 PFILE_OBJECT fileobj;
3655 struct _fcb* parfcb;
3656
3657 Status = ObReferenceObjectByHandle(parent, 0, *IoFileObjectType, Irp->RequestorMode, (void**)&fileobj, NULL);
3658 if (!NT_SUCCESS(Status)) {
3659 ERR("ObReferenceObjectByHandle returned %08lx\n", Status);
3660 return Status;
3661 }
3662
3663 if (fileobj->DeviceObject != FileObject->DeviceObject) {
3664 ObDereferenceObject(fileobj);
3666 }
3667
3668 parfcb = fileobj->FsContext;
3669
3670 if (!parfcb || parfcb == Vcb->root_fileref->fcb || parfcb == Vcb->volume_fcb || parfcb->inode != SUBVOL_ROOT_INODE) {
3671 ObDereferenceObject(fileobj);
3673 }
3674
3675 parsubvol = parfcb->subvol;
3676 ObDereferenceObject(fileobj);
3677
3678 if (!Vcb->readonly && !(parsubvol->root_item.flags & BTRFS_SUBVOL_READONLY))
3680
3681 if (parsubvol == fcb->subvol)
3683 }
3684
3685 if (num_clones > 0) {
3686 ULONG i;
3687
3688 clones = ExAllocatePoolWithTag(PagedPool, sizeof(root*) * num_clones, ALLOC_TAG);
3689 if (!clones) {
3690 ERR("out of memory\n");
3692 }
3693
3694 for (i = 0; i < num_clones; i++) {
3695 HANDLE h;
3696 PFILE_OBJECT fileobj;
3697 struct _fcb* clonefcb;
3698
3699#if defined(_WIN64)
3700 if (IoIs32bitProcess(Irp)) {
3702
3703 h = Handle32ToHandle(bss32->clones[i]);
3704 } else
3705#endif
3706 h = bss->clones[i];
3707
3708 Status = ObReferenceObjectByHandle(h, 0, *IoFileObjectType, Irp->RequestorMode, (void**)&fileobj, NULL);
3709 if (!NT_SUCCESS(Status)) {
3710 ERR("ObReferenceObjectByHandle returned %08lx\n", Status);
3711 ExFreePool(clones);
3712 return Status;
3713 }
3714
3715 if (fileobj->DeviceObject != FileObject->DeviceObject) {
3716 ObDereferenceObject(fileobj);
3717 ExFreePool(clones);
3719 }
3720
3721 clonefcb = fileobj->FsContext;
3722
3723 if (!clonefcb || clonefcb == Vcb->root_fileref->fcb || clonefcb == Vcb->volume_fcb || clonefcb->inode != SUBVOL_ROOT_INODE) {
3724 ObDereferenceObject(fileobj);
3725 ExFreePool(clones);
3727 }
3728
3729 clones[i] = clonefcb->subvol;
3730 ObDereferenceObject(fileobj);
3731
3732 if (!Vcb->readonly && !(clones[i]->root_item.flags & BTRFS_SUBVOL_READONLY)) {
3733 ExFreePool(clones);
3735 }
3736 }
3737 }
3738 }
3739
3740 ExAcquireResourceExclusiveLite(&Vcb->send_load_lock, true);
3741
3742 if (ccb->send) {
3743 WARN("send operation already running\n");
3744 ExReleaseResourceLite(&Vcb->send_load_lock);
3746 }
3747
3749 if (!context) {
3750 ERR("out of memory\n");
3751
3752 if (clones)
3753 ExFreePool(clones);
3754
3755 ExReleaseResourceLite(&Vcb->send_load_lock);
3757 }
3758
3759 context->Vcb = Vcb;
3760 context->root = fcb->subvol;
3761 context->parent = parsubvol;
3762 InitializeListHead(&context->orphans);
3764 InitializeListHead(&context->pending_rmdirs);
3765 context->lastinode.inode = 0;
3766 context->lastinode.path = NULL;
3767 context->lastinode.sd = NULL;
3768 context->root_dir = NULL;
3769 context->num_clones = num_clones;
3770 context->clones = clones;
3771 InitializeListHead(&context->lastinode.refs);
3772 InitializeListHead(&context->lastinode.oldrefs);
3773 InitializeListHead(&context->lastinode.exts);
3774 InitializeListHead(&context->lastinode.oldexts);
3775
3776 context->data = ExAllocatePoolWithTag(PagedPool, SEND_BUFFER_LENGTH + (2 * MAX_SEND_WRITE), ALLOC_TAG); // give ourselves some wiggle room
3777 if (!context->data) {
3779 ExReleaseResourceLite(&Vcb->send_load_lock);
3781 }
3782
3783 context->datalen = 0;
3784
3785 send_subvol_header(context, fcb->subvol, ccb->fileref); // FIXME - fileref needs some sort of lock here
3786
3787 KeInitializeEvent(&context->buffer_event, NotificationEvent, false);
3788
3790 if (!send) {
3791 ERR("out of memory\n");
3792 ExFreePool(context->data);
3794
3795 if (clones)
3796 ExFreePool(clones);
3797
3798 ExReleaseResourceLite(&Vcb->send_load_lock);
3800 }
3801
3802 KeInitializeEvent(&send->cleared_event, NotificationEvent, false);
3803
3804 send->context = context;
3805 context->send = send;
3806
3807 ccb->send = send;
3808 send->ccb = ccb;
3810
3811 send->cancelling = false;
3812
3813 InterlockedIncrement(&Vcb->running_sends);
3814
3816
3818 if (!NT_SUCCESS(Status)) {
3819 ERR("PsCreateSystemThread returned %08lx\n", Status);
3820 ccb->send = NULL;
3821 InterlockedDecrement(&Vcb->running_sends);
3823 ExFreePool(context->data);
3825
3826 if (clones)
3827 ExFreePool(clones);
3828
3829 ExReleaseResourceLite(&Vcb->send_load_lock);
3830 return Status;
3831 }
3832
3833 InsertTailList(&Vcb->send_ops, &send->list_entry);
3834 ExReleaseResourceLite(&Vcb->send_load_lock);
3835
3836 return STATUS_SUCCESS;
3837}
3838
3840 ccb* ccb;
3842
3843 ccb = FileObject ? FileObject->FsContext2 : NULL;
3844 if (!ccb)
3846
3847 if (!SeSinglePrivilegeCheck(RtlConvertLongToLuid(SE_MANAGE_VOLUME_PRIVILEGE), processor_mode))
3849
3850 ExAcquireResourceExclusiveLite(&Vcb->send_load_lock, true);
3851
3852 if (!ccb->send) {
3853 ExReleaseResourceLite(&Vcb->send_load_lock);
3855 }
3856
3858
3859 KeWaitForSingleObject(&context->buffer_event, Executive, KernelMode, false, NULL);
3860
3861 if (datalen == 0) {
3862 ExReleaseResourceLite(&Vcb->send_load_lock);
3863 return STATUS_SUCCESS;
3864 }
3865
3866 RtlCopyMemory(data, context->data, min(datalen, context->datalen));
3867
3868 if (datalen < context->datalen) { // not empty yet
3869 *retlen = datalen;
3870 RtlMoveMemory(context->data, &context->data[datalen], context->datalen - datalen);
3871 context->datalen -= datalen;
3872 ExReleaseResourceLite(&Vcb->send_load_lock);
3873 } else {
3874 *retlen = context->datalen;
3875 context->datalen = 0;
3876 ExReleaseResourceLite(&Vcb->send_load_lock);
3877
3878 KeClearEvent(&context->buffer_event);
3879 KeSetEvent(&ccb->send->cleared_event, 0, false);
3880 }
3881
3882 return STATUS_SUCCESS;
3883}
#define STATUS_PRIVILEGE_NOT_HELD
Definition: DriverTester.h:9
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
unsigned short int uint16_t
Definition: acefiex.h:54
unsigned int dir
Definition: maze.c:112
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedDecrement
Definition: armddk.h:52
LONG NTSTATUS
Definition: precomp.h:26
#define WARN(fmt,...)
Definition: debug.h:112
#define ERR(fmt,...)
Definition: debug.h:110
static __inline uint32_t get_extent_data_refcount(uint8_t type, void *data)
Definition: btrfs_drv.h:1065
void void void NTSTATUS void NTSTATUS skip_to_difference(device_extension *Vcb, traverse_ptr *tp, traverse_ptr *tp2, bool *ended1, bool *ended2) __attribute__((nonnull(1
#define keycmp(key1, key2)
Definition: btrfs_drv.h:1016
#define __S_IFREG
Definition: btrfs_drv.h:1757
NTSTATUS zlib_decompress(uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf, uint32_t outlen)
Definition: compress.c:377
NTSTATUS zstd_decompress(uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf, uint32_t outlen)
Definition: compress.c:676
#define __S_IFDIR
Definition: btrfs_drv.h:1754
NTSTATUS lzo_decompress(uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf, uint32_t outlen, uint32_t inpageoff)
Definition: compress.c:278
void flush_subvol_fcbs(root *subvol)
Definition: fsctl.c:243
struct _fcb fcb
Definition: btrfs_drv.h:1364
#define __S_IFSOCK
Definition: btrfs_drv.h:1760
#define ALLOC_TAG
Definition: btrfs_drv.h:87
NTSTATUS load_csum(_Requires_lock_held_(_Curr_->tree_lock) device_extension *Vcb, void *csum, uint64_t start, uint64_t length, PIRP Irp)
Definition: create.c:453
NTSTATUS do_write(device_extension *Vcb, PIRP Irp)
Definition: flushthread.c:7877
#define __S_IFLNK
Definition: btrfs_drv.h:1759
#define makedev(major, minor)
Definition: btrfs_drv.h:1637
#define __S_IFIFO
Definition: btrfs_drv.h:1758
NTSTATUS NTSTATUS bool bool void free_trees(device_extension *Vcb) __attribute__((nonnull(1)))
struct _ccb ccb
static __inline uint16_t get_extent_data_len(uint8_t type)
Definition: btrfs_drv.h:1043
NTSTATUS NTSTATUS bool find_next_item(_Requires_lock_held_(_Curr_->tree_lock) device_extension *Vcb, const traverse_ptr *tp, traverse_ptr *next_tp, bool ignore, PIRP Irp) __attribute__((nonnull(1
#define __S_IFBLK
Definition: btrfs_drv.h:1756
#define __S_IFCHR
Definition: btrfs_drv.h:1755
while(CdLookupNextInitialFileDirent(IrpContext, Fcb, FileContext))
static uint64_t __inline sector_align(uint64_t n, uint64_t a)
crc_func calc_crc32c
Definition: crc32c.c:23
_In_ PIRP Irp
Definition: csq.h:116
const WCHAR * link
Definition: db.cpp:997
#define NULL
Definition: types.h:112
UINT32 uint32_t
Definition: types.h:75
UINT64 uint64_t
Definition: types.h:77
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
static const WCHAR *const ext[]
Definition: module.c:53
static LONG find_item(PropertyBag *This, LPCOLESTR name)
Definition: propertybag.c:110
INT WSAAPI send(IN SOCKET s, IN CONST CHAR FAR *buf, IN INT len, IN INT flags)
Definition: send.c:23
_In_ uint64_t _In_ uint64_t _In_ uint64_t _In_opt_ traverse_ptr * tp
Definition: btrfs.c:2996
r parent
Definition: btrfs.c:3010
r lastinode
Definition: btrfs.c:3027
_In_ uint64_t _In_ uint64_t _In_ uint64_t generation
Definition: btrfs.c:2996
#define BTRFS_COMPRESSION_LZO
Definition: btrfs.h:67
#define TYPE_EXTENT_DATA
Definition: btrfs.h:30
#define BTRFS_SEND_CMD_RMDIR
Definition: btrfs.h:556
#define BTRFS_SEND_TLV_PATH
Definition: btrfs.h:582
#define BTRFS_SEND_TLV_CLONE_UUID
Definition: btrfs.h:587
#define BTRFS_SEND_CMD_SET_XATTR
Definition: btrfs.h:557
#define BTRFS_SEND_CMD_MKFILE
Definition: btrfs.h:547
#define TYPE_EXTENT_DATA_REF
Definition: btrfs.h:38
#define BTRFS_SEND_TLV_CLONE_OFFSET
Definition: btrfs.h:590
#define TYPE_INODE_EXTREF
Definition: btrfs.h:25
#define BTRFS_SEND_TLV_XATTR_DATA
Definition: btrfs.h:581
#define TYPE_DIR_INDEX
Definition: btrfs.h:29
#define BTRFS_COMPRESSION_ZLIB
Definition: btrfs.h:66
#define BTRFS_COMPRESSION_ZSTD
Definition: btrfs.h:68
#define BTRFS_SEND_CMD_WRITE
Definition: btrfs.h:559
#define BTRFS_SEND_CMD_UTIMES
Definition: btrfs.h:564
#define BTRFS_SEND_CMD_CHMOD
Definition: btrfs.h:562
#define BTRFS_SUBVOL_READONLY
Definition: btrfs.h:109
#define BTRFS_ENCODING_NONE
Definition: btrfs.h:72
#define BTRFS_SEND_CMD_LINK
Definition: btrfs.h:554
#define BTRFS_SEND_CMD_RENAME
Definition: btrfs.h:553
#define BTRFS_SEND_TLV_TRANSID
Definition: btrfs.h:569
#define BTRFS_SEND_TLV_UUID
Definition: btrfs.h:568
#define BTRFS_SEND_TLV_GID
Definition: btrfs.h:574
#define TYPE_EXTENT_ITEM
Definition: btrfs.h:35
#define BTRFS_SEND_TLV_DATA
Definition: btrfs.h:586
#define BTRFS_SEND_CMD_MKFIFO
Definition: btrfs.h:550
#define BTRFS_SEND_CMD_SUBVOL
Definition: btrfs.h:545
#define BTRFS_SEND_TLV_MODE
Definition: btrfs.h:572
#define BTRFS_SEND_CMD_SNAPSHOT
Definition: btrfs.h:546
#define BTRFS_SEND_TLV_UID
Definition: btrfs.h:573
#define BTRFS_SEND_CMD_TRUNCATE
Definition: btrfs.h:561
#define EXTENT_TYPE_INLINE
Definition: btrfs.h:74
#define BTRFS_SEND_TLV_XATTR_NAME
Definition: btrfs.h:580
#define BTRFS_SEND_TLV_MTIME
Definition: btrfs.h:577
#define BTRFS_SEND_TLV_CLONE_PATH
Definition: btrfs.h:589
#define TYPE_XATTR_ITEM
Definition: btrfs.h:26
#define BTRFS_SEND_TLV_CLONE_LENGTH
Definition: btrfs.h:591
#define EXTENT_TYPE_REGULAR
Definition: btrfs.h:75
#define BTRFS_SEND_TLV_OFFSET
Definition: btrfs.h:585
#define BTRFS_COMPRESSION_NONE
Definition: btrfs.h:65
#define BTRFS_SEND_CMD_CHOWN
Definition: btrfs.h:563
#define BTRFS_SEND_TLV_CLONE_CTRANSID
Definition: btrfs.h:588
#define BTRFS_SEND_CMD_MKNOD
Definition: btrfs.h:549
#define BTRFS_SEND_TLV_SIZE
Definition: btrfs.h:571
#define BTRFS_SEND_CMD_UNLINK
Definition: btrfs.h:555
#define TYPE_INODE_REF
Definition: btrfs.h:24
#define BTRFS_SEND_CMD_REMOVE_XATTR
Definition: btrfs.h:558
#define BTRFS_SEND_CMD_SYMLINK
Definition: btrfs.h:552
#define BTRFS_SEND_CMD_CLONE
Definition: btrfs.h:560
#define BTRFS_SEND_CMD_MKSOCK
Definition: btrfs.h:551
#define BTRFS_SEND_TLV_PATH_LINK
Definition: btrfs.h:584
#define TYPE_DIR_ITEM
Definition: btrfs.h:28
#define BTRFS_ENCRYPTION_NONE
Definition: btrfs.h:70
#define BTRFS_SEND_TLV_INODE
Definition: btrfs.h:570
#define BTRFS_SEND_TLV_ATIME
Definition: btrfs.h:578
#define BTRFS_SEND_TLV_CTIME
Definition: btrfs.h:576
#define BTRFS_SEND_TLV_RDEV
Definition: btrfs.h:575
#define BTRFS_SEND_TLV_PATH_TO
Definition: btrfs.h:583
#define TYPE_INODE_ITEM
Definition: btrfs.h:23
#define BTRFS_SEND_CMD_MKDIR
Definition: btrfs.h:548
static NTSTATUS get_orphan_name(send_context *context, uint64_t inode, uint64_t generation, char *name)
Definition: send.c:164
static NTSTATUS sync_ext_cutoff_points(send_context *context)
Definition: send.c:1785
static NTSTATUS wait_for_flush(send_context *context, traverse_ptr *tp1, traverse_ptr *tp2)
Definition: send.c:1602
static __inline uint16_t find_path_len(send_dir *parent, uint16_t namelen)
Definition: send.c:560
static void add_orphan(send_context *context, orphan *o)
Definition: send.c:217
static NTSTATUS send_inode(send_context *context, traverse_ptr *tp, traverse_ptr *tp2)
Definition: send.c:283
static void find_path(char *path, send_dir *parent, char *name, ULONG namelen)
Definition: send.c:571
static bool try_clone(send_context *context, send_ext *se)
Definition: send.c:2028
static void send_chown_command(send_context *context, char *path, uint64_t uid, uint64_t gid)
Definition: send.c:988
static void send_chmod_command(send_context *context, char *path, uint64_t mode)
Definition: send.c:1000
NTSTATUS send_subvol(device_extension *Vcb, void *data, ULONG datalen, PFILE_OBJECT FileObject, PIRP Irp)
Definition: send.c:3593
static NTSTATUS divide_ext(send_ext *ext, uint64_t len, bool trunc)
Definition: send.c:1713
static NTSTATUS send_inode_extref(send_context *context, traverse_ptr *tp, bool tree2)
Definition: send.c:872
static void send_command_finish(send_context *context, ULONG pos)
Definition: send.c:125
static void send_truncate_command(send_context *context, char *path, uint64_t size)
Definition: send.c:1026
static NTSTATUS find_send_dir(send_context *context, uint64_t dir, uint64_t generation, send_dir **psd, bool *added_dummy)
Definition: send.c:670
static NTSTATUS send_inode_ref(send_context *context, traverse_ptr *tp, bool tree2)
Definition: send.c:770
static NTSTATUS send_read_symlink(send_context *context, uint64_t inode, char **link, uint16_t *linklen)
Definition: send.c:235
#define SEND_BUFFER_LENGTH
Definition: send.c:111
static NTSTATUS flush_extents(send_context *context, traverse_ptr *tp1, traverse_ptr *tp2)
Definition: send.c:2127
static NTSTATUS send_add_dir(send_context *context, uint64_t inode, send_dir *parent, char *name, uint16_t namelen, bool dummy, LIST_ENTRY *lastentry, send_dir **psd)
Definition: send.c:497
static void send_utimes_command(send_context *context, char *path, BTRFS_TIME *atime, BTRFS_TIME *mtime, BTRFS_TIME *ctime)
Definition: send.c:1013
static void send_command(send_context *context, uint16_t cmd)
Definition: send.c:116
static NTSTATUS make_file_orphan(send_context *context, uint64_t inode, bool dir, uint64_t generation, ref *r)
Definition: send.c:1175
static void send_add_tlv_path(send_context *context, uint16_t type, send_dir *parent, char *name, uint16_t namelen)
Definition: send.c:586
static void send_subvol_header(send_context *context, root *r, file_ref *fr)
Definition: send.c:969
static void send_utimes_command_dir(send_context *context, send_dir *sd, BTRFS_TIME *atime, BTRFS_TIME *mtime, BTRFS_TIME *ctime)
Definition: send.c:656
static NTSTATUS look_for_collision(send_context *context, send_dir *sd, char *name, ULONG namelen, uint64_t *inode, bool *dir)
Definition: send.c:1133
NTSTATUS read_send_buffer(device_extension *Vcb, PFILE_OBJECT FileObject, void *data, ULONG datalen, ULONG_PTR *retlen, KPROCESSOR_MODE processor_mode)
Definition: send.c:3839
static NTSTATUS send_extent_data(send_context *context, traverse_ptr *tp, traverse_ptr *tp2)
Definition: send.c:2619
#define MAX_SEND_WRITE
Definition: send.c:110
static NTSTATUS flush_refs(send_context *context, traverse_ptr *tp1, traverse_ptr *tp2)
Definition: send.c:1274
static NTSTATUS send_xattr(send_context *context, traverse_ptr *tp, traverse_ptr *tp2)
Definition: send.c:2770
static NTSTATUS finish_inode(send_context *context, traverse_ptr *tp1, traverse_ptr *tp2)
Definition: send.c:2532
static NTSTATUS add_ext_holes(device_extension *Vcb, LIST_ENTRY *exts, uint64_t size)
Definition: send.c:1652
static bool try_clone_edr(send_context *context, send_ext *se, EXTENT_DATA_REF *edr)
Definition: send.c:1937
static bool send_add_tlv_clone_path(send_context *context, root *r, uint64_t inode)
Definition: send.c:1841
static NTSTATUS get_dir_last_child(send_context *context, uint64_t *last_inode)
Definition: send.c:1061
static void send_rmdir_command(send_context *context, uint16_t pathlen, char *path)
Definition: send.c:1053
static char * uint64_to_char(uint64_t num, char *buf)
Definition: send.c:144
static void send_add_tlv(send_context *context, uint16_t type, void *data, uint16_t length)
Definition: send.c:132
static NTSTATUS add_pending_rmdir(send_context *context, uint64_t last_inode)
Definition: send.c:1103
static NTSTATUS found_path(send_context *context, send_dir *parent, char *name, uint16_t namelen)
Definition: send.c:595
static NTSTATUS send_unlink_command(send_context *context, send_dir *parent, uint16_t namelen, char *name)
Definition: send.c:1037
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
#define InsertHeadList(ListHead, Entry)
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define RtlCompareMemory(s1, s2, l)
Definition: env_spec_w32.h:465
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define ExConvertExclusiveToSharedLite(res)
Definition: env_spec_w32.h:652
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define ExAcquireResourceExclusiveLite(res, wait)
Definition: env_spec_w32.h:615
#define RemoveHeadList(ListHead)
Definition: env_spec_w32.h:964
#define NonPagedPool
Definition: env_spec_w32.h:307
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define ExAcquireResourceSharedLite(res, wait)
Definition: env_spec_w32.h:621
#define PagedPool
Definition: env_spec_w32.h:308
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
Status
Definition: gdiplustypes.h:25
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
GLuint GLuint end
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLsizeiptr size
Definition: glext.h:5919
GLint namelen
Definition: glext.h:7232
GLuint index
Definition: glext.h:6031
GLenum mode
Definition: glext.h:6217
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLenum const GLvoid * addr
Definition: glext.h:9621
GLuint64EXT GLuint GLuint GLenum GLenum GLuint GLuint GLenum GLuint GLuint key1
Definition: glext.h:10608
GLuint GLuint num
Definition: glext.h:9618
GLenum GLsizei len
Definition: glext.h:6722
GLintptr offset
Definition: glext.h:5920
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:7723
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
static double pr2[6]
Definition: j1_y1.c:326
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
POBJECT_TYPE IoFileObjectType
Definition: iomgr.c:36
int const JOCTET unsigned int datalen
Definition: jpeglib.h:1031
if(dx< 0)
Definition: linetemp.h:194
static const WCHAR dc[]
double __cdecl trunc(double)
__u16 ctime
Definition: mkdosfs.c:4
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
@ NormalPagePriority
Definition: imports.h:56
static PVOID ptr
Definition: dispmode.c:27
#define SE_MANAGE_VOLUME_PRIVILEGE
Definition: security.c:682
static const BYTE ext1[]
Definition: encode.c:2697
static const BYTE ext2[]
Definition: encode.c:2699
static const struct encodedExtensions exts[]
Definition: encode.c:2703
static const WCHAR sd[]
Definition: suminfo.c:286
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
static IBindStatusCallbackEx bsc
Definition: url.c:2150
#define min(a, b)
Definition: monoChain.cc:55
#define _Function_class_(x)
Definition: ms_sal.h:2946
BYTE uint8_t
Definition: msvideo1.c:66
#define KernelMode
Definition: asm.h:34
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
#define uint32_t
Definition: nsiface.idl:61
#define uint16_t
Definition: nsiface.idl:60
#define uint8_t
Definition: nsiface.idl:59
@ NotificationEvent
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1822
NTSTATUS NTAPI PsTerminateSystemThread(IN NTSTATUS ExitStatus)
Definition: kill.c:1145
NTSTATUS NTAPI PsCreateSystemThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE ProcessHandle, IN PCLIENT_ID ClientId, IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext)
Definition: thread.c:602
BOOLEAN NTAPI SeSinglePrivilegeCheck(_In_ LUID PrivilegeValue, _In_ KPROCESSOR_MODE PreviousMode)
Checks if a single privilege is present in the context of the calling thread.
Definition: priv.c:744
#define STATUS_INTERNAL_ERROR
Definition: ntstatus.h:465
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:239
NTSTATUS NTAPI ObReferenceObjectByHandle(IN HANDLE Handle, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, OUT PVOID *Object, OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
Definition: obref.c:494
#define Vcb
Definition: cdprocs.h:1415
#define SUBVOL_ROOT_INODE
Definition: propsheet.cpp:42
#define BTRFS_INODE_NODATASUM
Definition: propsheet.h:76
#define offsetof(TYPE, MEMBER)
static DWORD WINAPI send_thread(LPVOID lpParameter)
Definition: send.cpp:227
#define STATUS_DEVICE_NOT_READY
Definition: shellext.h:70
#define STATUS_END_OF_FILE
Definition: shellext.h:67
#define BTRFS_TYPE_DIRECTORY
Definition: shellext.h:86
#define STATUS_SUCCESS
Definition: shellext.h:65
#define TRACE(s)
Definition: solgame.cpp:4
uint16_t m
Definition: btrfs.h:275
uint8_t type
Definition: btrfs.h:277
char name[1]
Definition: btrfs.h:278
uint16_t n
Definition: btrfs.h:276
KEY key
Definition: btrfs.h:273
uint64_t num_bytes
Definition: btrfs.h:371
uint64_t address
Definition: btrfs.h:368
uint64_t size
Definition: btrfs.h:369
uint64_t offset
Definition: btrfs.h:370
uint64_t root
Definition: btrfs.h:417
uint64_t objid
Definition: btrfs.h:418
uint8_t data[1]
Definition: btrfs.h:364
uint8_t type
Definition: btrfs.h:363
uint16_t encoding
Definition: btrfs.h:362
uint8_t encryption
Definition: btrfs.h:361
uint8_t compression
Definition: btrfs.h:360
uint64_t decoded_size
Definition: btrfs.h:359
uint64_t dir
Definition: btrfs.h:381
char name[1]
Definition: btrfs.h:384
uint16_t n
Definition: btrfs.h:383
uint64_t st_rdev
Definition: btrfs.h:296
uint32_t st_mode
Definition: btrfs.h:295
uint32_t flags
Definition: btrfs.h:297
BTRFS_TIME st_mtime
Definition: btrfs.h:303
uint64_t st_size
Definition: btrfs.h:289
uint32_t st_uid
Definition: btrfs.h:293
BTRFS_TIME st_atime
Definition: btrfs.h:301
BTRFS_TIME st_ctime
Definition: btrfs.h:302
uint32_t st_gid
Definition: btrfs.h:294
uint64_t generation
Definition: btrfs.h:287
char name[1]
Definition: btrfs.h:377
uint16_t n
Definition: btrfs.h:376
Definition: btrfs.h:143
uint8_t obj_type
Definition: btrfs.h:145
uint64_t obj_id
Definition: btrfs.h:144
uint64_t offset
Definition: btrfs.h:146
uint64_t flags
Definition: btrfs.h:319
Definition: typedefs.h:120
struct _LIST_ENTRY * Blink
Definition: typedefs.h:122
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
NTSTATUS send_status
Definition: btrfs_drv.h:393
send_info * send
Definition: btrfs_drv.h:392
file_ref * fileref
Definition: btrfs_drv.h:383
uint64_t inode
Definition: btrfs_drv.h:289
struct _root * subvol
Definition: btrfs_drv.h:288
dir_child * dc
Definition: btrfs_drv.h:353
ROOT_ITEM root_item
Definition: btrfs_drv.h:455
uint8_t * data
Definition: btrfs_drv.h:415
uint16_t size
Definition: btrfs_drv.h:414
tree_header header
Definition: btrfs_drv.h:426
void *POINTER_32 parent
Definition: btrfsioctl.h:274
void *POINTER_32 clones[1]
Definition: btrfsioctl.h:276
HANDLE clones[1]
Definition: btrfsioctl.h:270
uint16_t type
Definition: btrfs.h:607
uint16_t length
Definition: btrfs.h:608
Definition: ftp_var.h:139
Definition: http.c:7252
Definition: ffs.h:52
char * name
Definition: compiler.c:66
LIST_ENTRY list_entry
Definition: send.c:43
ULONG namelen
Definition: send.c:44
ANSI_STRING utf8
Definition: btrfs_drv.h:254
Definition: fs.h:78
Definition: copy.c:22
Definition: list.h:27
Definition: name.c:39
Definition: send.c:34
uint64_t inode
Definition: send.c:36
char tmpname[64]
Definition: send.c:39
LIST_ENTRY list_entry
Definition: send.c:35
bool dir
Definition: send.c:37
send_dir * sd
Definition: send.c:38
LIST_ENTRY list_entry
Definition: send.c:58
uint64_t last_child_inode
Definition: send.c:57
send_dir * sd
Definition: send.c:56
Definition: send.c:48
uint16_t namelen
Definition: send.c:51
char name[1]
Definition: send.c:52
send_dir * sd
Definition: send.c:50
LIST_ENTRY list_entry
Definition: send.c:49
uint64_t gid
Definition: send.c:90
bool file
Definition: send.c:99
bool deleting
Definition: send.c:85
root * root
Definition: send.c:70
uint64_t olduid
Definition: send.c:89
char * path
Definition: send.c:100
root * parent
Definition: send.c:71
root ** clones
Definition: send.c:75
LIST_ENTRY oldexts
Definition: send.c:106
uint64_t mode
Definition: send.c:92
send_dir * root_dir
Definition: send.c:80
uint64_t oldmode
Definition: send.c:93
LIST_ENTRY exts
Definition: send.c:105
LIST_ENTRY pending_rmdirs
Definition: send.c:78
uint8_t * data
Definition: send.c:72
send_dir * sd
Definition: send.c:102
uint64_t size
Definition: send.c:94
orphan * o
Definition: send.c:101
device_extension * Vcb
Definition: send.c:69
uint64_t inode
Definition: send.c:84
uint64_t flags
Definition: send.c:95
BTRFS_TIME atime
Definition: send.c:96
LIST_ENTRY orphans
Definition: send.c:76
uint64_t gen
Definition: send.c:87
send_info * send
Definition: send.c:81
LIST_ENTRY refs
Definition: send.c:103
ULONG num_clones
Definition: send.c:74
LIST_ENTRY dirs
Definition: send.c:77
LIST_ENTRY oldrefs
Definition: send.c:104
uint64_t uid
Definition: send.c:88
uint64_t oldgid
Definition: send.c:91
BTRFS_TIME ctime
Definition: send.c:98
ULONG datalen
Definition: send.c:73
BTRFS_TIME mtime
Definition: send.c:97
KEVENT buffer_event
Definition: send.c:79
Definition: send.c:21
bool dummy
Definition: send.c:24
char * name
Definition: send.c:30
uint16_t namelen
Definition: send.c:29
LIST_ENTRY deleted_children
Definition: send.c:31
LIST_ENTRY list_entry
Definition: send.c:22
BTRFS_TIME atime
Definition: send.c:25
struct send_dir * parent
Definition: send.c:28
BTRFS_TIME ctime
Definition: send.c:27
BTRFS_TIME mtime
Definition: send.c:26
uint64_t inode
Definition: send.c:23
Definition: send.c:61
ULONG datalen
Definition: send.c:64
uint64_t offset
Definition: send.c:62
EXTENT_DATA data
Definition: send.c:65
LIST_ENTRY list_entry
Definition: send.c:63
KEVENT cleared_event
Definition: btrfs_drv.h:365
void * context
Definition: btrfs_drv.h:364
tree_data * item
Definition: btrfs_drv.h:509
tree * tree
Definition: btrfs_drv.h:508
uint64_t address
Definition: btrfs.h:156
char * value2
Definition: send.c:2766
char * value1
Definition: send.c:2764
uint16_t namelen
Definition: send.c:2761
uint16_t value2len
Definition: send.c:2765
LIST_ENTRY list_entry
Definition: send.c:2767
char * name
Definition: send.c:2762
uint16_t value1len
Definition: send.c:2763
#define max(a, b)
Definition: svc.c:63
#define __stdcall
Definition: typedefs.h:25
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_OBJECT_NAME_COLLISION
Definition: udferr_usr.h:150
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_In_ WDFREQUEST _In_ WDFFILEOBJECT FileObject
Definition: wdfdevice.h:550
* PFILE_OBJECT
Definition: iotypes.h:1998
@ Executive
Definition: ketypes.h:415
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
#define ObDereferenceObject
Definition: obfuncs.h:203