#include #include kern_status_t sys_kern_handle_close(kern_handle_t handle) { struct task *self = get_current_task(); kern_status_t status = task_close_handle(self, handle); put_current_task(self); return status; } kern_status_t sys_kern_handle_transfer( kern_handle_t src_task_handle, kern_handle_t src_handle, kern_handle_t dest_task_handle, kern_handle_t dest_handle, unsigned int mode, kern_handle_t *out_handle) { switch (mode) { case HANDLE_TRANSFER_MOVE: case HANDLE_TRANSFER_COPY: break; default: return KERN_INVALID_ARGUMENT; } struct task *self = get_current_task(); if (out_handle && !validate_access_w(self, out_handle, sizeof *out_handle)) { put_current_task(self); return KERN_MEMORY_FAULT; } unsigned long flags; task_lock_irqsave(self, &flags); struct object *src_object = NULL; struct task *src_task = NULL; struct task *dest_task = NULL; kern_status_t status = KERN_OK; struct object *obj = NULL; handle_flags_t handle_flags = 0; if (src_task_handle != KERN_HANDLE_INVALID) { status = task_resolve_handle( self, src_task_handle, &obj, &handle_flags); if (status != KERN_OK) { task_unlock_irqrestore(self, flags); goto cleanup; } src_task = task_cast(obj); if (!src_task) { status = KERN_INVALID_ARGUMENT; goto cleanup; } } else { src_task = self; } if (dest_task_handle != KERN_HANDLE_INVALID) { status = task_resolve_handle( self, dest_task_handle, &obj, &handle_flags); if (status != KERN_OK) { task_unlock_irqrestore(self, flags); goto cleanup; } dest_task = task_cast(obj); if (!dest_task) { status = KERN_INVALID_ARGUMENT; goto cleanup; } } else { dest_task = self; } status = task_resolve_handle( self, src_handle, &src_object, &handle_flags); if (status != KERN_OK) { goto cleanup; } task_unlock_irqrestore(self, flags); struct handle *dest = NULL; task_lock_irqsave(dest_task, &flags); status = handle_table_alloc_handle( dest_task->t_handles, dest_handle, &dest, &dest_handle); task_unlock_irqrestore(dest_task, flags); if (status != KERN_OK) { goto cleanup; } if (mode == HANDLE_TRANSFER_MOVE) { object_ref(src_object); task_lock_irqsave(src_task, &flags); handle_table_free_handle(src_task->t_handles, src_handle); task_unlock_irqrestore(src_task, flags); } dest->h_object = src_object; dest->h_flags = handle_flags; if (out_handle) { *out_handle = dest_handle; } put_current_task(self); return KERN_OK; cleanup: if (src_task && src_task_handle != KERN_HANDLE_INVALID) { object_unref(&src_task->t_base); } if (dest_task && dest_task_handle != KERN_HANDLE_INVALID) { object_unref(&dest_task->t_base); } if (src_object) { object_unref(src_object); } put_current_task(self); return status; }