/* Licensed under the Apache License, Version 2.0 (the "License"). You may not use * this file except in compliance with the License. A copy of the License is * located at * * http://aws.amazon.com/apache2.0/ * * or in the "license" file accompanying this file. This file is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include int aws_cryptosdk_transfer_list(struct aws_array_list *dest, struct aws_array_list *src) { AWS_ERROR_PRECONDITION(src != dest); AWS_ERROR_PRECONDITION(aws_array_list_is_valid(dest)); AWS_ERROR_PRECONDITION(aws_array_list_is_valid(src)); AWS_ERROR_PRECONDITION(dest->item_size == src->item_size); size_t src_len = aws_array_list_length(src); for (size_t src_idx = 0; src_idx < src_len; ++src_idx) { void *item_ptr; if (aws_array_list_get_at_ptr(src, &item_ptr, src_idx)) return AWS_OP_ERR; if (aws_array_list_push_back(dest, item_ptr)) return AWS_OP_ERR; } /* This clear is important. It does not free any memory, but it resets the length of the * source list to zero, so that the buffers or strings in its list elements will NOT get * freed when the list gets cleaned up. We do not want to free those buffers, because the * elements that were transferred to the new list were shallow copies using the same buffers * or strings. */ aws_array_list_clear(src); return AWS_OP_SUCCESS; } // allocator, dest, src typedef int (*clone_item_fn)(struct aws_allocator *, void *, const void *); typedef void (*clean_up_item_fn)(void *); static int list_copy_all( struct aws_allocator *alloc, struct aws_array_list *dest, const struct aws_array_list *src, clone_item_fn cloner, clean_up_item_fn cleaner) { AWS_ERROR_PRECONDITION(aws_allocator_is_valid(alloc)); AWS_ERROR_PRECONDITION(src != dest); AWS_ERROR_PRECONDITION(aws_array_list_is_valid(dest)); AWS_ERROR_PRECONDITION(aws_array_list_is_valid(src)); AWS_ERROR_PRECONDITION(dest->item_size == src->item_size); size_t initial_length = aws_array_list_length(dest); size_t src_length = aws_array_list_length(src); int lasterr; /* You can do this with a variable length uint8_t array everywhere except Windows, * but Microsoft forces us to do an allocation here. */ void *dest_item = aws_mem_acquire(alloc, dest->item_size); if (!dest_item) { return AWS_OP_ERR; } for (size_t i = 0; i < src_length; i++) { void *src_item; if (aws_array_list_get_at_ptr(src, &src_item, i)) { goto err; } if (cloner(alloc, dest_item, src_item)) { goto err; } if (aws_array_list_push_back(dest, dest_item)) { cleaner(dest_item); goto err; } } aws_mem_release(alloc, dest_item); return AWS_OP_SUCCESS; err: aws_mem_release(alloc, dest_item); lasterr = aws_last_error(); while (aws_array_list_length(dest) > initial_length) { void *dest_item_ptr; if (aws_array_list_get_at_ptr(dest, &dest_item_ptr, aws_array_list_length(dest) - 1)) { /* * We had elements at aws_array_list, but not anymore, it seems. * Someone must be mucking with the destination list from another thread; * abort before we do any more damage. */ abort(); } cleaner(dest_item_ptr); aws_array_list_pop_back(dest); } return aws_raise_error(lasterr); } int aws_cryptosdk_edk_list_copy_all( struct aws_allocator *alloc, struct aws_array_list *dest, const struct aws_array_list *src) { AWS_PRECONDITION(aws_array_list_is_valid(src)); AWS_PRECONDITION(aws_array_list_is_valid(dest)); AWS_PRECONDITION(src->item_size == sizeof(struct aws_cryptosdk_edk)); AWS_PRECONDITION(dest->item_size == sizeof(struct aws_cryptosdk_edk)); return list_copy_all( alloc, dest, src, (clone_item_fn)aws_cryptosdk_edk_init_clone, (clean_up_item_fn)aws_cryptosdk_edk_clean_up); } int aws_cryptosdk_keyring_trace_copy_all( struct aws_allocator *alloc, struct aws_array_list *dest, const struct aws_array_list *src) { AWS_PRECONDITION(aws_array_list_is_valid(dest)); AWS_PRECONDITION(aws_array_list_is_valid(src)); AWS_PRECONDITION(src->item_size == sizeof(struct aws_cryptosdk_keyring_trace_record)); AWS_PRECONDITION(dest->item_size == sizeof(struct aws_cryptosdk_keyring_trace_record)); return list_copy_all( alloc, dest, src, (clone_item_fn)aws_cryptosdk_keyring_trace_record_init_clone, (clean_up_item_fn)aws_cryptosdk_keyring_trace_record_clean_up); }