ReactOS 0.4.16-dev-117-g38f21f9
send.c File Reference
#include "btrfs_drv.h"
#include "crc32c.h"
Include dependency graph for send.c:

Go to the source code of this file.

Classes

struct  send_dir
 
struct  orphan
 
struct  deleted_child
 
struct  ref
 
struct  pending_rmdir
 
struct  send_ext
 
struct  send_context
 
struct  xattr_cmp
 

Macros

#define MAX_SEND_WRITE   0xc000
 
#define SEND_BUFFER_LENGTH   0x100000
 

Typedefs

typedef struct send_dir send_dir
 

Functions

static NTSTATUS find_send_dir (send_context *context, uint64_t dir, uint64_t generation, send_dir **psd, bool *added_dummy)
 
static NTSTATUS wait_for_flush (send_context *context, traverse_ptr *tp1, traverse_ptr *tp2)
 
static void send_command (send_context *context, uint16_t cmd)
 
static void send_command_finish (send_context *context, ULONG pos)
 
static void send_add_tlv (send_context *context, uint16_t type, void *data, uint16_t length)
 
static charuint64_to_char (uint64_t num, char *buf)
 
static NTSTATUS get_orphan_name (send_context *context, uint64_t inode, uint64_t generation, char *name)
 
static void add_orphan (send_context *context, orphan *o)
 
static NTSTATUS send_read_symlink (send_context *context, uint64_t inode, char **link, uint16_t *linklen)
 
static NTSTATUS send_inode (send_context *context, traverse_ptr *tp, traverse_ptr *tp2)
 
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)
 
static __inline uint16_t find_path_len (send_dir *parent, uint16_t namelen)
 
static void find_path (char *path, send_dir *parent, char *name, ULONG namelen)
 
static void send_add_tlv_path (send_context *context, uint16_t type, send_dir *parent, char *name, uint16_t namelen)
 
static NTSTATUS found_path (send_context *context, send_dir *parent, char *name, uint16_t namelen)
 
static void send_utimes_command_dir (send_context *context, send_dir *sd, BTRFS_TIME *atime, BTRFS_TIME *mtime, BTRFS_TIME *ctime)
 
static NTSTATUS send_inode_ref (send_context *context, traverse_ptr *tp, bool tree2)
 
static NTSTATUS send_inode_extref (send_context *context, traverse_ptr *tp, bool tree2)
 
static void send_subvol_header (send_context *context, root *r, file_ref *fr)
 
static void send_chown_command (send_context *context, char *path, uint64_t uid, uint64_t gid)
 
static void send_chmod_command (send_context *context, char *path, uint64_t mode)
 
static void send_utimes_command (send_context *context, char *path, BTRFS_TIME *atime, BTRFS_TIME *mtime, BTRFS_TIME *ctime)
 
static void send_truncate_command (send_context *context, char *path, uint64_t size)
 
static NTSTATUS send_unlink_command (send_context *context, send_dir *parent, uint16_t namelen, char *name)
 
static void send_rmdir_command (send_context *context, uint16_t pathlen, char *path)
 
static NTSTATUS get_dir_last_child (send_context *context, uint64_t *last_inode)
 
static NTSTATUS add_pending_rmdir (send_context *context, uint64_t last_inode)
 
static NTSTATUS look_for_collision (send_context *context, send_dir *sd, char *name, ULONG namelen, uint64_t *inode, bool *dir)
 
static NTSTATUS make_file_orphan (send_context *context, uint64_t inode, bool dir, uint64_t generation, ref *r)
 
static NTSTATUS flush_refs (send_context *context, traverse_ptr *tp1, traverse_ptr *tp2)
 
static NTSTATUS add_ext_holes (device_extension *Vcb, LIST_ENTRY *exts, uint64_t size)
 
static NTSTATUS divide_ext (send_ext *ext, uint64_t len, bool trunc)
 
static NTSTATUS sync_ext_cutoff_points (send_context *context)
 
static bool send_add_tlv_clone_path (send_context *context, root *r, uint64_t inode)
 
static bool try_clone_edr (send_context *context, send_ext *se, EXTENT_DATA_REF *edr)
 
static bool try_clone (send_context *context, send_ext *se)
 
static NTSTATUS flush_extents (send_context *context, traverse_ptr *tp1, traverse_ptr *tp2)
 
static NTSTATUS finish_inode (send_context *context, traverse_ptr *tp1, traverse_ptr *tp2)
 
static NTSTATUS send_extent_data (send_context *context, traverse_ptr *tp, traverse_ptr *tp2)
 
static NTSTATUS send_xattr (send_context *context, traverse_ptr *tp, traverse_ptr *tp2)
 
 _Function_class_ (KSTART_ROUTINE)
 
NTSTATUS send_subvol (device_extension *Vcb, void *data, ULONG datalen, PFILE_OBJECT FileObject, PIRP Irp)
 
NTSTATUS read_send_buffer (device_extension *Vcb, PFILE_OBJECT FileObject, void *data, ULONG datalen, ULONG_PTR *retlen, KPROCESSOR_MODE processor_mode)
 

Macro Definition Documentation

◆ MAX_SEND_WRITE

#define MAX_SEND_WRITE   0xc000

Definition at line 110 of file send.c.

◆ SEND_BUFFER_LENGTH

#define SEND_BUFFER_LENGTH   0x100000

Definition at line 111 of file send.c.

Typedef Documentation

◆ send_dir

Function Documentation

◆ _Function_class_()

_Function_class_ ( KSTART_ROUTINE  )

Definition at line 2970 of file send.c.

2971 {
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}
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedDecrement
Definition: armddk.h:52
LONG NTSTATUS
Definition: precomp.h:26
#define ERR(fmt,...)
Definition: precomp.h:57
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
void flush_subvol_fcbs(root *subvol)
Definition: fsctl.c:243
NTSTATUS do_write(device_extension *Vcb, PIRP Irp)
Definition: flushthread.c:7877
NTSTATUS NTSTATUS bool bool void free_trees(device_extension *Vcb) __attribute__((nonnull(1)))
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 NULL
Definition: types.h:112
UINT64 uint64_t
Definition: types.h:77
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
static LONG find_item(PropertyBag *This, LPCOLESTR name)
Definition: propertybag.c:110
_In_ uint64_t _In_ uint64_t _In_ uint64_t _In_opt_ traverse_ptr * tp
Definition: btrfs.c:2996
#define TYPE_EXTENT_DATA
Definition: btrfs.h:30
#define TYPE_INODE_EXTREF
Definition: btrfs.h:25
#define TYPE_XATTR_ITEM
Definition: btrfs.h:26
#define TYPE_INODE_REF
Definition: btrfs.h:24
#define TYPE_INODE_ITEM
Definition: btrfs.h:23
static NTSTATUS send_inode(send_context *context, traverse_ptr *tp, traverse_ptr *tp2)
Definition: send.c:283
static NTSTATUS send_inode_extref(send_context *context, traverse_ptr *tp, bool tree2)
Definition: send.c:872
static NTSTATUS send_inode_ref(send_context *context, traverse_ptr *tp, bool tree2)
Definition: send.c:770
#define SEND_BUFFER_LENGTH
Definition: send.c:111
static NTSTATUS send_extent_data(send_context *context, traverse_ptr *tp, traverse_ptr *tp2)
Definition: send.c:2619
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
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#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 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 ExAcquireResourceSharedLite(res, wait)
Definition: env_spec_w32.h:621
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
Status
Definition: gdiplustypes.h:25
GLuint GLuint end
Definition: gl.h:1545
GLuint64EXT GLuint GLuint GLenum GLenum GLuint GLuint GLenum GLuint GLuint key1
Definition: glext.h:10608
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 const WCHAR dc[]
static const WCHAR sd[]
Definition: suminfo.c:286
#define KernelMode
Definition: asm.h:34
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
VOID FASTCALL ExReleaseResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1822
NTSTATUS NTAPI PsTerminateSystemThread(IN NTSTATUS ExitStatus)
Definition: kill.c:1145
#define STATUS_INTERNAL_ERROR
Definition: ntstatus.h:465
#define STATUS_SUCCESS
Definition: shellext.h:65
#define TRACE(s)
Definition: solgame.cpp:4
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
uint8_t * data
Definition: btrfs_drv.h:415
uint16_t size
Definition: btrfs_drv.h:414
tree_header header
Definition: btrfs_drv.h:426
Definition: http.c:7252
Definition: fs.h:78
Definition: copy.c:22
Definition: list.h:27
Definition: send.c:34
Definition: send.c:21
tree_data * item
Definition: btrfs_drv.h:509
tree * tree
Definition: btrfs_drv.h:508
uint64_t address
Definition: btrfs.h:156
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
@ Executive
Definition: ketypes.h:415

◆ add_ext_holes()

static NTSTATUS add_ext_holes ( device_extension Vcb,
LIST_ENTRY exts,
uint64_t  size 
)
static

Definition at line 1652 of file send.c.

1652 {
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}
#define ALLOC_TAG
Definition: btrfs_drv.h:87
static uint64_t __inline sector_align(uint64_t n, uint64_t a)
static const WCHAR *const ext[]
Definition: module.c:53
#define EXTENT_TYPE_INLINE
Definition: btrfs.h:74
#define EXTENT_TYPE_REGULAR
Definition: btrfs.h:75
#define InsertTailList(ListHead, Entry)
#define InsertHeadList(ListHead, Entry)
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define PagedPool
Definition: env_spec_w32.h:308
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLsizeiptr size
Definition: glext.h:5919
static const BYTE ext2[]
Definition: encode.c:2699
static const struct encodedExtensions exts[]
Definition: encode.c:2703
#define Vcb
Definition: cdprocs.h:1415
#define offsetof(TYPE, MEMBER)
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
Definition: typedefs.h:120
struct _LIST_ENTRY * Blink
Definition: typedefs.h:122
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
Definition: send.c:61
EXTENT_DATA data
Definition: send.c:65
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158

Referenced by flush_extents().

◆ add_orphan()

static void add_orphan ( send_context context,
orphan o 
)
static

Definition at line 217 of file send.c.

217 {
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}
uint64_t inode
Definition: send.c:36
LIST_ENTRY list_entry
Definition: send.c:35

Referenced by make_file_orphan(), send_inode(), send_inode_extref(), and send_inode_ref().

◆ add_pending_rmdir()

static NTSTATUS add_pending_rmdir ( send_context context,
uint64_t  last_inode 
)
static

Definition at line 1103 of file send.c.

1103 {
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}
static double pr2[6]
Definition: j1_y1.c:326
LIST_ENTRY list_entry
Definition: send.c:58
uint64_t last_child_inode
Definition: send.c:57
send_dir * sd
Definition: send.c:56

Referenced by flush_refs().

◆ divide_ext()

static NTSTATUS divide_ext ( send_ext ext,
uint64_t  len,
bool  trunc 
)
static

Definition at line 1713 of file send.c.

1713 {
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}
GLenum GLsizei len
Definition: glext.h:6722
if(dx< 0)
Definition: linetemp.h:194
double __cdecl trunc(double)
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263

Referenced by sync_ext_cutoff_points().

◆ find_path()

static void find_path ( char path,
send_dir parent,
char name,
ULONG  namelen 
)
static

Definition at line 571 of file send.c.

571 {
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}
r parent
Definition: btrfs.c:3010
GLint namelen
Definition: glext.h:7232
Definition: name.c:39
#define RtlMoveMemory(Destination, Source, Length)
Definition: typedefs.h:264

Referenced by flush_refs(), found_path(), send_add_tlv_path(), and send_unlink_command().

◆ find_path_len()

static __inline uint16_t find_path_len ( send_dir parent,
uint16_t  namelen 
)
static

Definition at line 560 of file send.c.

560 {
562
563 while (parent && parent->namelen > 0) {
564 len += parent->namelen + 1;
565 parent = parent->parent;
566 }
567
568 return len;
569}
unsigned short int uint16_t
Definition: acefiex.h:54

Referenced by flush_refs(), found_path(), send_add_tlv_path(), and send_unlink_command().

◆ find_send_dir()

static NTSTATUS find_send_dir ( send_context context,
uint64_t  dir,
uint64_t  generation,
send_dir **  psd,
bool added_dummy 
)
static

Definition at line 670 of file send.c.

670 {
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}
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
unsigned int dir
Definition: maze.c:112
_In_ uint64_t _In_ uint64_t _In_ uint64_t generation
Definition: btrfs.c:2996
static NTSTATUS get_orphan_name(send_context *context, uint64_t inode, uint64_t generation, char *name)
Definition: send.c:164
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_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
#define SUBVOL_ROOT_INODE
Definition: propsheet.cpp:42
char name[1]
Definition: btrfs.h:377
uint16_t n
Definition: btrfs.h:376
uint64_t inode
Definition: send.c:23

Referenced by find_send_dir(), flush_refs(), make_file_orphan(), send_inode(), send_inode_extref(), and send_inode_ref().

◆ finish_inode()

static NTSTATUS finish_inode ( send_context context,
traverse_ptr tp1,
traverse_ptr tp2 
)
static

Definition at line 2532 of file send.c.

2532 {
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}
#define __S_IFLNK
Definition: btrfs_drv.h:1759
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
static void send_truncate_command(send_context *context, char *path, uint64_t size)
Definition: send.c:1026
static NTSTATUS flush_extents(send_context *context, traverse_ptr *tp1, traverse_ptr *tp2)
Definition: send.c:2127
static void send_utimes_command(send_context *context, char *path, BTRFS_TIME *atime, BTRFS_TIME *mtime, BTRFS_TIME *ctime)
Definition: send.c:1013
static NTSTATUS flush_refs(send_context *context, traverse_ptr *tp1, traverse_ptr *tp2)
Definition: send.c:1274
static void send_rmdir_command(send_context *context, uint16_t pathlen, char *path)
Definition: send.c:1053
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

Referenced by _Function_class_().

◆ flush_extents()

static NTSTATUS flush_extents ( send_context context,
traverse_ptr tp1,
traverse_ptr tp2 
)
static

Definition at line 2127 of file send.c.

2127 {
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}
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
NTSTATUS lzo_decompress(uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf, uint32_t outlen, uint32_t inpageoff)
Definition: compress.c:278
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
UINT32 uint32_t
Definition: types.h:75
#define BTRFS_COMPRESSION_LZO
Definition: btrfs.h:67
#define BTRFS_SEND_TLV_PATH
Definition: btrfs.h:582
#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_TLV_DATA
Definition: btrfs.h:586
#define BTRFS_SEND_TLV_OFFSET
Definition: btrfs.h:585
#define BTRFS_COMPRESSION_NONE
Definition: btrfs.h:65
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 bool try_clone(send_context *context, send_ext *se)
Definition: send.c:2028
static void send_command_finish(send_context *context, ULONG pos)
Definition: send.c:125
static void send_command(send_context *context, uint16_t cmd)
Definition: send.c:116
#define MAX_SEND_WRITE
Definition: send.c:110
static NTSTATUS add_ext_holes(device_extension *Vcb, LIST_ENTRY *exts, uint64_t size)
Definition: send.c:1652
static void send_add_tlv(send_context *context, uint16_t type, void *data, uint16_t length)
Definition: send.c:132
#define NonPagedPool
Definition: env_spec_w32.h:307
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
GLintptr offset
Definition: glext.h:5920
@ NormalPagePriority
Definition: imports.h:54
#define min(a, b)
Definition: monoChain.cc:55
BYTE uint8_t
Definition: msvideo1.c:66
#define uint32_t
Definition: nsiface.idl:61
#define uint16_t
Definition: nsiface.idl:60
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:239
#define BTRFS_INODE_NODATASUM
Definition: propsheet.h:76
uint8_t data[1]
Definition: btrfs.h:364
uint8_t type
Definition: btrfs.h:363
uint8_t compression
Definition: btrfs.h:360
uint64_t decoded_size
Definition: btrfs.h:359
Definition: ffs.h:52
ULONG datalen
Definition: send.c:64
uint64_t offset
Definition: send.c:62
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262

Referenced by finish_inode().

◆ flush_refs()

static NTSTATUS flush_refs ( send_context context,
traverse_ptr tp1,
traverse_ptr tp2 
)
static

Definition at line 1274 of file send.c.

1274 {
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}
#define __S_IFDIR
Definition: btrfs_drv.h:1754
r lastinode
Definition: btrfs.c:3027
#define BTRFS_SEND_CMD_RENAME
Definition: btrfs.h:553
#define BTRFS_SEND_TLV_PATH_TO
Definition: btrfs.h:583
static __inline uint16_t find_path_len(send_dir *parent, uint16_t namelen)
Definition: send.c:560
static void find_path(char *path, send_dir *parent, char *name, ULONG namelen)
Definition: send.c:571
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_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
static NTSTATUS get_dir_last_child(send_context *context, uint64_t *last_inode)
Definition: send.c:1061
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
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
char * name
Definition: compiler.c:66
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
bool dummy
Definition: send.c:24
BTRFS_TIME atime
Definition: send.c:25
BTRFS_TIME ctime
Definition: send.c:27
BTRFS_TIME mtime
Definition: send.c:26
#define STATUS_OBJECT_NAME_COLLISION
Definition: udferr_usr.h:150

Referenced by finish_inode(), send_extent_data(), and send_xattr().

◆ found_path()

static NTSTATUS found_path ( send_context context,
send_dir parent,
char name,
uint16_t  namelen 
)
static

Definition at line 595 of file send.c.

595 {
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}
#define BTRFS_SEND_CMD_LINK
Definition: btrfs.h:554
#define BTRFS_SEND_TLV_PATH_LINK
Definition: btrfs.h:584

Referenced by flush_refs().

◆ get_dir_last_child()

static NTSTATUS get_dir_last_child ( send_context context,
uint64_t last_inode 
)
static

Definition at line 1061 of file send.c.

1061 {
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}
#define TYPE_DIR_INDEX
Definition: btrfs.h:29
uint16_t m
Definition: btrfs.h:275
uint16_t n
Definition: btrfs.h:276
KEY key
Definition: btrfs.h:273
#define max(a, b)
Definition: svc.c:63

Referenced by flush_refs().

◆ get_orphan_name()

static NTSTATUS get_orphan_name ( send_context context,
uint64_t  inode,
uint64_t  generation,
char name 
)
static

Definition at line 164 of file send.c.

164 {
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}
crc_func calc_crc32c
Definition: crc32c.c:23
#define TYPE_DIR_ITEM
Definition: btrfs.h:28
static char * uint64_to_char(uint64_t num, char *buf)
Definition: send.c:144
GLuint index
Definition: glext.h:6031
static PVOID ptr
Definition: dispmode.c:27

Referenced by find_send_dir(), flush_refs(), make_file_orphan(), and send_inode().

◆ look_for_collision()

static NTSTATUS look_for_collision ( send_context context,
send_dir sd,
char name,
ULONG  namelen,
uint64_t inode,
bool dir 
)
static

Definition at line 1133 of file send.c.

1133 {
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}
#define BTRFS_TYPE_DIRECTORY
Definition: shellext.h:86
uint8_t type
Definition: btrfs.h:277
char name[1]
Definition: btrfs.h:278

Referenced by flush_refs().

◆ make_file_orphan()

static NTSTATUS make_file_orphan ( send_context context,
uint64_t  inode,
bool  dir,
uint64_t  generation,
ref r 
)
static

Definition at line 1175 of file send.c.

1175 {
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}
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
#define BTRFS_SEND_CMD_UNLINK
Definition: btrfs.h:555
static void add_orphan(send_context *context, orphan *o)
Definition: send.c:217
char tmpname[64]
Definition: send.c:39
bool dir
Definition: send.c:37
send_dir * sd
Definition: send.c:38

Referenced by flush_refs().

◆ read_send_buffer()

NTSTATUS read_send_buffer ( device_extension Vcb,
PFILE_OBJECT  FileObject,
void data,
ULONG  datalen,
ULONG_PTR retlen,
KPROCESSOR_MODE  processor_mode 
)

Definition at line 3839 of file send.c.

3839 {
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
struct _ccb ccb
int const JOCTET unsigned int datalen
Definition: jpeglib.h:1031
#define SE_MANAGE_VOLUME_PRIVILEGE
Definition: security.c:682
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_END_OF_FILE
Definition: shellext.h:67
NTSTATUS send_status
Definition: btrfs_drv.h:393
send_info * send
Definition: btrfs_drv.h:392
KEVENT cleared_event
Definition: btrfs_drv.h:365
void * context
Definition: btrfs_drv.h:364
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
_In_ WDFREQUEST _In_ WDFFILEOBJECT FileObject
Definition: wdfdevice.h:550

Referenced by fsctl_request().

◆ send_add_dir()

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 
)
static

Definition at line 497 of file send.c.

497 {
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}
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878

Referenced by find_send_dir().

◆ send_add_tlv()

static void send_add_tlv ( send_context context,
uint16_t  type,
void data,
uint16_t  length 
)
static

◆ send_add_tlv_clone_path()

static bool send_add_tlv_clone_path ( send_context context,
root r,
uint64_t  inode 
)
static

Definition at line 1841 of file send.c.

1841 {
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}
#define BTRFS_SEND_TLV_CLONE_PATH
Definition: btrfs.h:589
GLuint GLuint num
Definition: glext.h:9618
uint64_t dir
Definition: btrfs.h:381
char name[1]
Definition: btrfs.h:384
uint16_t n
Definition: btrfs.h:383

Referenced by try_clone_edr().

◆ send_add_tlv_path()

static void send_add_tlv_path ( send_context context,
uint16_t  type,
send_dir parent,
char name,
uint16_t  namelen 
)
static

Definition at line 586 of file send.c.

586 {
588
590
591 if (len > 0)
592 find_path((char*)&context->data[context->datalen - len], parent, name, namelen);
593}

Referenced by flush_refs(), found_path(), make_file_orphan(), send_inode_extref(), send_inode_ref(), and send_utimes_command_dir().

◆ send_chmod_command()

static void send_chmod_command ( send_context context,
char path,
uint64_t  mode 
)
static

Definition at line 1000 of file send.c.

1000 {
1001 ULONG pos = context->datalen;
1002
1004
1005 mode &= 07777;
1006
1009
1011}
#define BTRFS_SEND_CMD_CHMOD
Definition: btrfs.h:562
#define BTRFS_SEND_TLV_MODE
Definition: btrfs.h:572
GLenum mode
Definition: glext.h:6217

Referenced by finish_inode().

◆ send_chown_command()

static void send_chown_command ( send_context context,
char path,
uint64_t  uid,
uint64_t  gid 
)
static

Definition at line 988 of file send.c.

988 {
989 ULONG pos = context->datalen;
990
992
996
998}
#define BTRFS_SEND_TLV_GID
Definition: btrfs.h:574
#define BTRFS_SEND_TLV_UID
Definition: btrfs.h:573
#define BTRFS_SEND_CMD_CHOWN
Definition: btrfs.h:563

Referenced by finish_inode().

◆ send_command()

◆ send_command_finish()

◆ send_extent_data()

static NTSTATUS send_extent_data ( send_context context,
traverse_ptr tp,
traverse_ptr tp2 
)
static

Definition at line 2619 of file send.c.

2619 {
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}
#define BTRFS_ENCODING_NONE
Definition: btrfs.h:72
#define BTRFS_ENCRYPTION_NONE
Definition: btrfs.h:70
uint16_t encoding
Definition: btrfs.h:362
uint8_t encryption
Definition: btrfs.h:361
LIST_ENTRY list_entry
Definition: send.c:63

Referenced by _Function_class_().

◆ send_inode()

static NTSTATUS send_inode ( send_context context,
traverse_ptr tp,
traverse_ptr tp2 
)
static

Definition at line 283 of file send.c.

283 {
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}
#define __S_IFREG
Definition: btrfs_drv.h:1757
#define __S_IFSOCK
Definition: btrfs_drv.h:1760
#define makedev(major, minor)
Definition: btrfs_drv.h:1637
#define __S_IFIFO
Definition: btrfs_drv.h:1758
#define __S_IFBLK
Definition: btrfs_drv.h:1756
#define __S_IFCHR
Definition: btrfs_drv.h:1755
const WCHAR * link
Definition: db.cpp:997
#define BTRFS_SEND_CMD_MKFILE
Definition: btrfs.h:547
#define BTRFS_SEND_CMD_MKFIFO
Definition: btrfs.h:550
#define BTRFS_SEND_CMD_MKNOD
Definition: btrfs.h:549
#define BTRFS_SEND_CMD_SYMLINK
Definition: btrfs.h:552
#define BTRFS_SEND_CMD_MKSOCK
Definition: btrfs.h:551
#define BTRFS_SEND_TLV_INODE
Definition: btrfs.h:570
#define BTRFS_SEND_TLV_RDEV
Definition: btrfs.h:575
#define BTRFS_SEND_CMD_MKDIR
Definition: btrfs.h:548
static NTSTATUS send_read_symlink(send_context *context, uint64_t inode, char **link, uint16_t *linklen)
Definition: send.c:235
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

Referenced by _Function_class_().

◆ send_inode_extref()

static NTSTATUS send_inode_extref ( send_context context,
traverse_ptr tp,
bool  tree2 
)
static

Definition at line 872 of file send.c.

872 {
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}
while(CdLookupNextInitialFileDirent(IrpContext, Fcb, FileContext))

Referenced by _Function_class_().

◆ send_inode_ref()

static NTSTATUS send_inode_ref ( send_context context,
traverse_ptr tp,
bool  tree2 
)
static

Definition at line 770 of file send.c.

770 {
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);