/* * Copyright (c) 2017-2018 Dong Han * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the names of the authors or the names of any contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include //////////////////////////////////////////////////////////////////////////////// // fs, none thread pool version // // we wrappered non-threaded pool version functions, so that we can move the allocation // of uv_fs_t to stack, most of the functions can be optimized in this way. // in none thread pool version, req->result is directly returned. int32_t hs_uv_fs_open(const char* path, int flags, int mode){ uv_fs_t req; uv_fs_open(NULL, &req, path, flags, mode, NULL); uv_fs_req_cleanup(&req); // maybe not neccessary return (int32_t)req.result; } HsInt hs_uv_fs_close(int32_t file){ uv_fs_t req; uv_fs_close(NULL, &req, (uv_file)file, NULL); uv_fs_req_cleanup(&req); // maybe not neccessary return (HsInt)req.result; } HsInt hs_uv_fs_read(int32_t file, char* buffer, HsInt buffer_size, int64_t offset){ uv_fs_t req; uv_buf_t buf = { .base = buffer, .len = (size_t)buffer_size }; uv_fs_read(NULL, &req, (uv_file)file, &buf, 1, offset, NULL); uv_fs_req_cleanup(&req); // maybe not neccessary return (HsInt)req.result; } HsInt hs_uv_fs_write(int32_t file, char* buffer, HsInt buffer_size, int64_t offset){ uv_fs_t req; uv_buf_t buf = { .base = buffer, .len = (size_t)buffer_size }; uv_fs_write(NULL, &req, (uv_file)file, &buf, 1, offset, NULL); return (HsInt)req.result; } HsInt hs_uv_fs_unlink(const char* path){ uv_fs_t req; uv_fs_unlink(NULL, &req, path, NULL); uv_fs_req_cleanup(&req); // maybe not neccessary return (HsInt)req.result; } HsInt hs_uv_fs_mkdir(const char* path, int mode){ uv_fs_t req; uv_fs_mkdir(NULL, &req, path, mode, NULL); uv_fs_req_cleanup(&req); // maybe not neccessary return (HsInt)req.result; } HsInt hs_uv_fs_mkdtemp(const char* tpl, HsInt tpl_size, char* temp_path){ uv_fs_t req; strcpy(temp_path, tpl); strcpy(temp_path + tpl_size, "XXXXXX"); uv_fs_mkdtemp(NULL, &req, temp_path, NULL); strcpy(temp_path, req.path); // save the temp path uv_fs_req_cleanup(&req); // maybe not neccessary return (HsInt)req.result; } HsInt hs_uv_fs_mkstemp(const char* tpl, HsInt tpl_size, char* temp_path) { uv_fs_t req; strcpy(temp_path, tpl); strcpy(temp_path + tpl_size, "XXXXXX"); uv_fs_mkstemp(NULL, &req, temp_path, NULL); strcpy(temp_path, req.path); // save the temp path uv_fs_req_cleanup(&req); // maybe not neccessary return (HsInt)req.result; } HsInt hs_uv_fs_rmdir(const char* path){ uv_fs_t req; uv_fs_rmdir(NULL, &req, path, NULL); uv_fs_req_cleanup(&req); // maybe not neccessary return (HsInt)req.result; } void hs_uv_fs_scandir_cleanup(uv_dirent_t** dents, HsInt n){ int i; for (i=0; iloop; hs_loop_data* loop_data = loop->data; HsInt slot = (HsInt)req->data; // push the slot to event queue loop_data->buffer_size_table[slot] = (HsInt)req->result; loop_data->event_queue[loop_data->event_counter] = slot; loop_data->event_counter += 1; uv_fs_req_cleanup(req); free_slot(loop_data, slot); // free the uv_req_t } HsInt hs_uv_fs_open_threaded(const char* path, int flags, int mode, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_open(loop, req, path, flags, mode, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_close_threaded(int32_t file, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_close(loop, req, (uv_file)file, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_read_threaded(int32_t file, char* buffer, HsInt buffer_size, int64_t offset, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; uv_buf_t buf = { .base = buffer, .len = (size_t)buffer_size }; int r = uv_fs_read(loop, req, (uv_file)file, &buf, 1, offset, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_write_threaded(int32_t file, char* buffer, HsInt buffer_size, int64_t offset, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; uv_buf_t buf = { .base = buffer, .len = (size_t)buffer_size }; int r = uv_fs_write(loop, req, (uv_file)file, &buf, 1, offset, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_unlink_threaded(const char* path, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_unlink(loop, req, path, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_mkdir_threaded(const char* path, int mode, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_mkdir(loop, req, path, mode, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } void hs_uv_fs_mktemp_callback(uv_fs_t* req){ uv_loop_t* loop = req->loop; hs_loop_data* loop_data = loop->data; HsInt slot = (HsInt)req->data; char* path = loop_data->buffer_table[slot]; if (path != NULL) { // push the slot to event queue loop_data->buffer_size_table[slot] = (HsInt)req->result; loop_data->event_queue[loop_data->event_counter] = slot; loop_data->event_counter += 1; strcpy(path, req->path); // save the temp path } uv_fs_req_cleanup(req); free_slot(loop_data, slot); // free the uv_req_t } HsInt hs_uv_fs_mkdtemp_threaded(const char* tpl, HsInt tpl_size, char* temp_path, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; strcpy(temp_path, tpl); strcpy(temp_path + tpl_size, "XXXXXX"); loop_data->buffer_table[slot] = temp_path; int r = uv_fs_mkdtemp(loop, req, temp_path, hs_uv_fs_mktemp_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_mkstemp_threaded(const char* tpl, HsInt tpl_size, char* temp_path, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; strcpy(temp_path, tpl); strcpy(temp_path + tpl_size, "XXXXXX"); loop_data->buffer_table[slot] = temp_path; int r = uv_fs_mkstemp(loop, req, temp_path, hs_uv_fs_mktemp_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_rmdir_threaded(const char* path, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_rmdir(loop, req, path, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } void hs_uv_fs_scandir_callback(uv_fs_t* req){ uv_loop_t* loop = req->loop; hs_loop_data* loop_data = loop->data; HsInt slot = (HsInt)req->data; uv_dirent_t*** dents = (uv_dirent_t***)loop_data->buffer_table[slot]; if (dents != NULL) { *dents = req->ptr; // save the dent struct array pointer // push the slot to event queue loop_data->buffer_size_table[slot] = (HsInt)req->result; loop_data->event_queue[loop_data->event_counter] = slot; loop_data->event_counter += 1; } // we can't cleanup request here, because doing that will // destory our dents array, which we haven't copied in Haskell yet. // so we manually break down uv_fs_req_cleanup here: // we free path buffer first, then clean up dents later using // hs_uv_fs_scandir_cleanup, or hs_uv_fs_scandir_extra_cleanup // in case of async exception. #if defined(_WIN32) if (req->file.pathw != NULL) uv__free(req->file.pathw); #else if (req->path != NULL) uv__free((void*) req->path); #endif free_slot(loop_data, slot); // free the uv_req_t } void hs_uv_fs_scandir_extra_cleanup(uv_dirent_t*** dents_p, HsInt n){ int i; uv_dirent_t** dents = *dents_p; if (dents != NULL) { for (i=0; idata; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; loop_data->buffer_table[slot] = (char*)dents; int r = uv_fs_scandir(loop, req, path, 0, hs_uv_fs_scandir_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } void hs_uv_fs_stat_callback(uv_fs_t* req){ uv_loop_t* loop = req->loop; hs_loop_data* loop_data = loop->data; HsInt slot = (HsInt)req->data; uv_stat_t* stat = (uv_stat_t*)loop_data->buffer_table[slot]; if (stat != NULL) { // push the slot to event queue loop_data->buffer_size_table[slot] = (HsInt)req->result; loop_data->event_queue[loop_data->event_counter] = slot; loop_data->event_counter += 1; memcpy(stat, &req->statbuf, sizeof(uv_stat_t)); // save the temp path } uv_fs_req_cleanup(req); free_slot(loop_data, slot); // free the uv_req_t } HsInt hs_uv_fs_stat_threaded(const char* path, uv_stat_t* stat, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; loop_data->buffer_table[slot] = (char*)stat; int r = uv_fs_stat(loop, req, path, hs_uv_fs_stat_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_fstat_threaded(int32_t file, uv_stat_t* stat, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; loop_data->buffer_table[slot] = (char*)stat; int r = uv_fs_fstat(loop, req, file, hs_uv_fs_stat_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_lstat_threaded(const char* path, uv_stat_t* stat, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; loop_data->buffer_table[slot] = (char*)stat; int r = uv_fs_lstat(loop, req, path, hs_uv_fs_stat_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_rename_threaded(const char* path, const char* path2, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_rename(loop, req, path, path2, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_fsync_threaded(int32_t file, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_fsync(loop, req, file, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_fdatasync_threaded(int32_t file, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_fdatasync(loop, req, file, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_ftruncate_threaded(int32_t file, int64_t off, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_ftruncate(loop, req, file, off, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_copyfile_threaded(const char* path, const char* path2, int flag, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_copyfile(loop, req, path, path2, flag, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_access_threaded(const char* path, int mode, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_access(loop, req, path, mode, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_chmod_threaded(const char* path, int mode, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_chmod(loop, req, path, mode, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_fchmod_threaded(int32_t file, int mode, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_fchmod(loop, req, file, mode, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_utime_threaded(const char* path, double atime, double mtime, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_utime(loop, req, path, atime, mtime, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_futime_threaded(int32_t file, double atime, double mtime, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_futime(loop, req, file, atime, mtime, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_lutime_threaded(const char* path, double atime, double mtime, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_lutime(loop, req, path, atime, mtime, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_link_threaded(const char* path, const char* path2, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_link(loop, req, path, path2, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_symlink_threaded(const char* path, const char* path2, int flag, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_symlink(loop, req, path, path2, flag, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } void hs_uv_fs_readlink_callback(uv_fs_t* req){ uv_loop_t* loop = req->loop; hs_loop_data* loop_data = loop->data; HsInt slot = (HsInt)req->data; char** path = (char**)loop_data->buffer_table[slot]; if (path != NULL) { *path = req->ptr; // save the result path // push the slot to event queue loop_data->buffer_size_table[slot] = (HsInt)req->result; loop_data->event_queue[loop_data->event_counter] = slot; loop_data->event_counter += 1; } // for the same reason with 'scandir', we can't cleanup request here #if defined(_WIN32) if (req->file.pathw != NULL) uv__free(req->file.pathw); #else if (req->path != NULL) uv__free((void*) req->path); #endif free_slot(loop_data, slot); // free the uv_req_t } void hs_uv_fs_readlink_extra_cleanup(char** path){ if (*path != NULL) uv__free(*path); } HsInt hs_uv_fs_readlink_threaded(const char* path, char** result_path, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; loop_data->buffer_table[slot] = (char*)result_path; int r = uv_fs_readlink(loop, req, path, hs_uv_fs_readlink_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } // share cleanup and callback with readlink HsInt hs_uv_fs_realpath_threaded(const char* path, char** result_path, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; loop_data->buffer_table[slot] = (char*)result_path; int r = uv_fs_realpath(loop, req, path, hs_uv_fs_readlink_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_chown_threaded(const char* path, uv_uid_t uid, uv_gid_t gid, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_chown(loop, req, path, uid, gid, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_fchown_threaded(int32_t file, uv_uid_t uid, uv_gid_t gid, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_fchown(loop, req, file, uid, gid, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } HsInt hs_uv_fs_lchown_threaded(const char* path, uv_uid_t uid, uv_gid_t gid, uv_loop_t* loop){ hs_loop_data* loop_data = loop->data; HsInt slot = alloc_slot(loop_data); if (slot < 0) return UV_ENOMEM; uv_fs_t* req = (uv_fs_t*)fetch_uv_struct(loop_data, slot); req->data = (void*)slot; int r = uv_fs_lchown(loop, req, path, uid, gid, hs_uv_fs_callback); if (r < 0) { free_slot(loop_data, slot); return (HsInt)r; } else return slot; } int64_t hs_seek(int file, int64_t off, int origin){ #if defined(_WIN32) int64_t r = (int64_t)_lseeki64(file, off, origin); #else int64_t r = (int64_t)lseek(file, off, origin); #endif if (r < 0) { return uv_translate_sys_error(errno); } else { return r; } }