diff --git a/kernel/handle.c b/kernel/handle.c index 464b28c..e435964 100644 --- a/kernel/handle.c +++ b/kernel/handle.c @@ -185,5 +185,129 @@ struct handle *handle_table_get_handle( return NULL; } + if (!tab->t_handles.t_handle_list[handle_index].h_object) { + return NULL; + } + return &tab->t_handles.t_handle_list[handle_index]; } + +struct handle_list_iterator { + struct handle_list *it_list; + size_t it_list_count; + size_t it_list_ptr; + + kern_handle_t *it_handles; + size_t it_nr_handles; +}; + +static void handle_list_iterator_begin( + struct handle_list_iterator *it, + struct handle_list *list, + size_t list_count) +{ + memset(it, 0x0, sizeof *it); + it->it_list = list; + it->it_list_count = list_count; + + while (it->it_list_ptr < list_count) { + if (list[it->it_list_ptr].l_nr_handles > 0) { + break; + } + + it->it_list_ptr++; + } + + if (it->it_list_ptr >= list_count) { + return; + } + + it->it_handles = list[it->it_list_ptr].l_handles; + it->it_nr_handles = list[it->it_list_ptr].l_nr_handles; +} + +static void handle_list_iterator_seek( + struct handle_list_iterator *it, + size_t nr_handles) +{ + if (nr_handles > it->it_nr_handles) { + nr_handles = it->it_nr_handles; + } + + if (nr_handles < it->it_nr_handles) { + it->it_handles += nr_handles; + it->it_nr_handles -= nr_handles; + return; + } + + it->it_list_ptr++; + while (it->it_list_ptr < it->it_list_count) { + if (it->it_list[it->it_list_ptr].l_nr_handles > 0) { + break; + } + + it->it_list_ptr++; + } + + if (it->it_list_ptr >= it->it_list_count) { + return; + } + + it->it_handles = it->it_list[it->it_list_ptr].l_handles; + it->it_nr_handles = it->it_list[it->it_list_ptr].l_nr_handles; +} + +kern_status_t handle_list_transfer( + struct handle_table *dest_table, + struct handle_list *dest_list, + size_t dest_list_count, + struct handle_table *src_table, + const struct handle_list *src_list, + size_t src_list_count) +{ + struct handle_list_iterator src, dest; + handle_list_iterator_begin( + &src, + (struct handle_list *)src_list, + src_list_count); + handle_list_iterator_begin(&dest, dest_list, dest_list_count); + + while (src.it_nr_handles && dest.it_nr_handles) { + size_t to_copy = MIN(src.it_nr_handles, dest.it_nr_handles); + for (size_t i = 0; i < to_copy; i++) { + kern_handle_t handle_v = src.it_handles[i]; + struct handle *handle + = handle_table_get_handle(src_table, handle_v); + if (!handle) { + return KERN_HANDLE_INVALID; + } + + struct object *obj = object_ref(handle->h_object); + handle_flags_t flags = handle->h_flags; + + handle_table_free_handle(src_table, handle_v); + + struct handle *dest_slot = NULL; + kern_status_t status = handle_table_alloc_handle( + dest_table, + &dest_slot, + &handle_v); + if (status != KERN_OK) { + return status; + } + + dest_slot->h_object = obj; + dest_slot->h_flags = flags; + + object_add_handle(obj); + object_unref(obj); + + dest.it_handles[i] = handle_v; + } + + handle_list_iterator_seek(&src, to_copy); + handle_list_iterator_seek(&dest, to_copy); + } + + return KERN_OK; +}