Browse Source

libuv stubs, most fs functions

Aurel Bílý 6 years ago
parent
commit
bec9818ccb
4 changed files with 501 additions and 0 deletions
  1. 35 0
      libs/libuv/Makefile
  2. 107 0
      libs/libuv/libuv.ml
  3. 325 0
      libs/libuv/libuv_stubs.c
  4. 34 0
      libs/libuv/test.ml

+ 35 - 0
libs/libuv/Makefile

@@ -0,0 +1,35 @@
+ALL_CFLAGS = $(CFLAGS)
+OCAMLOPT=ocamlopt
+OCAMLC=ocamlc
+SRC = libuv.ml libuv_stubs.c test.ml
+
+all: bytecode test #native
+
+bytecode: libuv.cma
+
+#native: libuv.cmxa
+
+test: test.ml libuv.ml
+	ocamlfind $(OCAMLC) -o test -safe-string -package extlib libuv_stubs.c libuv.ml test.ml -dllib dlllibuv_stubs.so
+
+libuv.cma: libuv_stubs.so libuv.ml
+	ocamlfind $(OCAMLC) -safe-string -a -o libuv.cma libuv.ml -dllib dlllibuv_stubs.so
+
+#libuv.cmxa: libuv_stubs.so libuv.ml
+#	ocamlfind $(OCAMLOPT) -safe-string -a -o libuv.cmxa libuv.ml -dllib dlllibuv_stubs.so
+
+libuv_stubs.o: libuv_stubs.c
+	ocamlfind $(OCAMLC) -o libuv_stubs -safe-string $(ALL_CFLAGS) libuv_stubs.c
+
+libuv_stubs.so: libuv_stubs.o
+	ocamlfind ocamlmklib -o libuv_stubs $(ALL_CFLAGS) libuv_stubs.o -luv
+
+clean:
+	rm -f libuv.cma libuv.cmi libuv.cmx libuv.cmxa libuv.o libuv.obj libuv.lib libuv_stubs.obj libuv_stubs.o
+	rm -f libuv.a liblibuv.a liblibuv.lib libuv.cmo
+	rm -f test.cmi test.cmx test.cmo test
+	rm -f dlllibuv_stubs.so dlllibuv_stubs.a liblibuv_stubs.so liblibuv_stubs.a
+
+.PHONY: all bytecode clean # native
+Makefile: ;
+$(SRC): ;

+ 107 - 0
libs/libuv/libuv.ml

@@ -0,0 +1,107 @@
+(* ------------- TYPES ---------------------------------------------- *)
+
+(* Handle types *)
+
+type uv_loop_t
+type uv_handle_t
+type uv_dir_t
+type uv_stream_t
+type uv_tcp_t
+type uv_udp_t
+type uv_pipe_t
+type uv_tty_t
+type uv_poll_t
+type uv_timer_t
+type uv_prepare_t
+type uv_check_t
+type uv_idle_t
+type uv_async_t
+type uv_process_t
+type uv_fs_event_t
+type uv_fs_poll_t
+type uv_signal_t
+
+(* Request types *)
+
+type uv_req_t
+type uv_getaddrinfo_t
+type uv_getnameinfo_t
+type uv_shutdown_t
+type uv_write_t
+type uv_connect_t
+type uv_udp_send_t
+type uv_fs_t
+type uv_work_t
+
+(* Other types *)
+
+type uv_cpu_info_t
+type uv_interface_address_t
+type uv_dirent_t
+type uv_passwd_t
+type uv_utsname_t
+type uv_file
+(* type uv_stat_t *)
+type uv_buf_t
+
+(* ------------- LOOP ----------------------------------------------- *)
+
+external loop_init : unit -> uv_loop_t = "w_loop_init"
+external loop_close : uv_loop_t -> unit = "w_loop_close"
+external run : uv_loop_t -> int -> bool = "w_run"
+external loop_alive : uv_loop_t -> bool = "w_loop_alive"
+
+(* ------------- FILESYSTEM ----------------------------------------- *)
+
+type fs_cb = unit -> unit
+type fs_cb_bytes = string -> unit
+type fs_cb_path = string -> unit
+type fs_cb_file = uv_file -> unit
+type fs_cb_int = int -> unit
+type fs_cb_scandir = (string * int) list -> unit
+
+external fs_close : uv_loop_t -> uv_file -> fs_cb -> unit = "w_fs_close"
+external fs_open : uv_loop_t -> string -> int -> int -> fs_cb_file -> unit = "w_fs_open"
+external fs_unlink : uv_loop_t -> string -> fs_cb -> unit = "w_fs_unlink"
+external fs_mkdir : uv_loop_t -> string -> int -> fs_cb -> unit = "w_fs_mkdir"
+external fs_mkdtemp : uv_loop_t -> string -> fs_cb_path -> unit = "w_fs_mkdtemp"
+external fs_rmdir : uv_loop_t -> string -> fs_cb -> unit = "w_fs_rmdir"
+external fs_scandir : uv_loop_t -> string -> int -> fs_cb_scandir -> unit = "w_fs_scandir"
+external fs_rename : uv_loop_t -> string -> string -> fs_cb -> unit = "w_fs_rename"
+external fs_fsync : uv_loop_t -> uv_file -> fs_cb -> unit = "w_fs_fsync"
+external fs_fdatasync : uv_loop_t -> uv_file -> fs_cb -> unit = "w_fs_fdatasync"
+external fs_ftruncate : uv_loop_t -> uv_file -> int64 -> fs_cb -> unit = "w_fs_ftruncate"
+external fs_access : uv_loop_t -> string -> int -> fs_cb -> unit = "w_fs_access"
+external fs_chmod : uv_loop_t -> string -> int -> fs_cb -> unit = "w_fs_chmod"
+external fs_fchmod : uv_loop_t -> uv_file -> int -> fs_cb -> unit = "w_fs_fchmod"
+external fs_utime : uv_loop_t -> string -> float -> float -> fs_cb -> unit = "w_fs_utime"
+external fs_futime : uv_loop_t -> uv_file -> float -> float -> fs_cb -> unit = "w_fs_futime"
+external fs_link : uv_loop_t -> string -> string -> fs_cb -> unit = "w_fs_link"
+external fs_symlink : uv_loop_t -> string -> string -> int -> fs_cb -> unit = "w_fs_symlink"
+external fs_readlink : uv_loop_t -> string -> fs_cb_bytes -> unit = "w_fs_readlink"
+external fs_realpath : uv_loop_t -> string -> fs_cb_bytes -> unit = "w_fs_realpath"
+external fs_chown : uv_loop_t -> string -> int -> int -> fs_cb -> unit = "w_fs_chown"
+external fs_fchown : uv_loop_t -> uv_file -> int -> int -> fs_cb -> unit = "w_fs_fchown"
+
+external fs_close_sync : uv_loop_t -> uv_file -> unit = "w_fs_close_sync"
+external fs_open_sync : uv_loop_t -> string -> int -> int -> uv_file = "w_fs_open_sync"
+external fs_unlink_sync : uv_loop_t -> string -> unit = "w_fs_unlink_sync"
+external fs_mkdir_sync : uv_loop_t -> string -> int -> unit = "w_fs_mkdir_sync"
+external fs_mkdtemp_sync : uv_loop_t -> string -> string = "w_fs_mkdtemp_sync"
+external fs_rmdir_sync : uv_loop_t -> string -> unit = "w_fs_rmdir_sync"
+external fs_scandir_sync : uv_loop_t -> string -> int -> (string * int) list = "w_fs_scandir_sync"
+external fs_rename_sync : uv_loop_t -> string -> string -> unit = "w_fs_rename_sync"
+external fs_fsync_sync : uv_loop_t -> uv_file -> unit = "w_fs_fsync_sync"
+external fs_fdatasync_sync : uv_loop_t -> uv_file -> unit = "w_fs_fdatasync_sync"
+external fs_ftruncate_sync : uv_loop_t -> uv_file -> int64 -> unit = "w_fs_ftruncate_sync"
+external fs_access_sync : uv_loop_t -> string -> int -> unit = "w_fs_access_sync"
+external fs_chmod_sync : uv_loop_t -> string -> int -> unit = "w_fs_chmod_sync"
+external fs_fchmod_sync : uv_loop_t -> uv_file -> int -> unit = "w_fs_fchmod_sync"
+external fs_utime_sync : uv_loop_t -> string -> float -> float -> unit = "w_fs_utime_sync"
+external fs_futime_sync : uv_loop_t -> uv_file -> float -> float -> unit = "w_fs_futime_sync"
+external fs_link_sync : uv_loop_t -> string -> string -> unit = "w_fs_link_sync"
+external fs_symlink_sync : uv_loop_t -> string -> string -> int -> unit = "w_fs_symlink_sync"
+external fs_readlink_sync : uv_loop_t -> string -> string = "w_fs_readlink_sync"
+external fs_realpath_sync : uv_loop_t -> string -> string = "w_fs_realpath_sync"
+external fs_chown_sync : uv_loop_t -> string -> int -> int -> unit = "w_fs_chown_sync"
+external fs_fchown_sync : uv_loop_t -> uv_file -> int -> int -> unit = "w_fs_fchown_sync"

+ 325 - 0
libs/libuv/libuv_stubs.c

@@ -0,0 +1,325 @@
+#define CAML_NAME_SPACE
+#include <caml/alloc.h>
+#include <caml/callback.h>
+#include <caml/fail.h>
+#include <caml/memory.h>
+#include <caml/mlvalues.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <uv.h>
+
+#if (UV_VERSION_MAJOR <= 0)
+#	error "libuv1-dev required, uv version 0.x found"
+#endif
+
+// ------------- UTILITY MACROS -------------------------------------
+
+// access the data of a handle or request
+#define UV_HANDLE_DATA(h) (((uv_handle_t *)(h))->data)
+#define UV_HANDLE_DATA_SUB(h, t) ((t *)((uv_handle_t *)(h))->data)
+#define UV_REQ_DATA(r) (((uv_req_t *)(r))->data)
+#define UV_REQ_DATA_A(r) ((value *)(&UV_REQ_DATA(r)))
+
+#define UV_ALLOC(t) ((t *)malloc(sizeof(t)))
+
+// ------------- ERROR HANDLING -------------------------------------
+
+#define UV_ALLOC_CHECK(var, type) \
+	type *var = UV_ALLOC(type); \
+	if (var == NULL) { \
+		caml_failwith("malloc " #type " failed"); \
+	} else {}
+#define UV_ALLOC_CHECK_C(var, type, cleanup) \
+	type *var = UV_ALLOC(type); \
+	if (var == NULL) { \
+		cleanup; \
+		caml_failwith("malloc " #type " failed"); \
+	} else {}
+// TODO: proper exceptions for libuv errors
+#define UV_ERROR_CHECK(expr) do { \
+		int __tmp_result = expr; \
+		if (__tmp_result < 0) { \
+			caml_failwith(strdup(uv_strerror(__tmp_result))); \
+		} \
+	} while (0)
+#define UV_ERROR_CHECK_C(expr, cleanup) do { \
+		int __tmp_result = expr; \
+		if (__tmp_result < 0) { \
+			cleanup; \
+			caml_failwith(strdup(uv_strerror(__tmp_result))); \
+		} \
+	} while (0)
+
+// ------------- LOOP -----------------------------------------------
+
+CAMLprim value w_loop_init(value unit) {
+	CAMLparam1(unit);
+	UV_ALLOC_CHECK(loop, uv_loop_t);
+	UV_ERROR_CHECK_C(uv_loop_init(loop), free(loop));
+	CAMLreturn((value)loop);
+}
+
+CAMLprim value w_loop_close(value loop) {
+	CAMLparam1(loop);
+	UV_ERROR_CHECK(uv_loop_close((uv_loop_t *)loop));
+	free((uv_loop_t *)loop);
+	CAMLreturn(Val_unit);
+}
+
+CAMLprim value w_run(value loop, value mode) {
+	CAMLparam2(loop, mode);
+	CAMLreturn(Val_bool(uv_run((uv_loop_t *)loop, (uv_run_mode)mode) == 0));
+}
+
+CAMLprim value w_loop_alive(value loop) {
+	CAMLparam1(loop);
+	CAMLreturn(Val_bool(uv_loop_alive((uv_loop_t *)loop) != 0));
+}
+
+CAMLprim value w_stop(value loop) {
+	CAMLparam1(loop);
+	uv_stop((uv_loop_t *)loop);
+	CAMLreturn(Val_unit);
+}
+
+// ------------- FILESYSTEM -----------------------------------------
+
+// TODO: exception handling (optional arguments ...?)
+
+static void handle_fs_cb(uv_fs_t *req) {
+	CAMLparam0();
+	value cb = (value)UV_REQ_DATA(req);
+	if (req->result < 0)
+		caml_failwith(uv_strerror(req->result));
+		//hl_call1(void, cb, vdynamic *, construct_error((vbyte *)strdup(uv_strerror(req->result)), req->result));
+	else
+		caml_callback(cb, Val_unit);
+	uv_fs_req_cleanup(req);
+	caml_remove_global_root(UV_REQ_DATA_A(req));
+	free(req);
+	CAMLreturn0;
+}
+
+static value handle_fs_cb_sync(uv_fs_t *req) {
+	return Val_unit;
+}
+
+#define UV_FS_HANDLER(name, setup) \
+	static void name(uv_fs_t *req) { \
+		CAMLparam0(); \
+		value cb = (value)UV_REQ_DATA(req); \
+		if (req->result < 0) \
+			caml_failwith(uv_strerror(req->result)); \
+		else { \
+			value value2; \
+			do setup while (0); \
+			caml_callback(cb, value2); \
+		} \
+		uv_fs_req_cleanup(req); \
+		caml_remove_global_root(UV_REQ_DATA_A(req)); \
+		free(req); \
+		CAMLreturn0; \
+	} \
+	static value name ## _sync(uv_fs_t *req) { \
+		CAMLparam0(); \
+		value value2; \
+		do setup while (0); \
+		CAMLreturn(value2); \
+	}
+
+UV_FS_HANDLER(handle_fs_cb_bytes, value2 = caml_copy_string((const char *)req->ptr););
+UV_FS_HANDLER(handle_fs_cb_path, value2 = caml_copy_string((const char *)req->path););
+UV_FS_HANDLER(handle_fs_cb_int, value2 = (value)req->result;);
+UV_FS_HANDLER(handle_fs_cb_file, value2 = (value)req->result;);
+/*UV_FS_HANDLER(handle_fs_cb_stat, value2 = construct_fs_stat(
+		req->statbuf.st_dev,
+		req->statbuf.st_mode,
+		req->statbuf.st_nlink,
+		req->statbuf.st_uid,
+		req->statbuf.st_gid,
+		req->statbuf.st_rdev,
+		req->statbuf.st_ino,
+		req->statbuf.st_size,
+		req->statbuf.st_blksize,
+		req->statbuf.st_blocks,
+		req->statbuf.st_flags,
+		req->statbuf.st_gen
+	));*/
+UV_FS_HANDLER(handle_fs_cb_scandir, {
+		uv_dirent_t ent;
+		value2 = Val_int(0);
+		while (uv_fs_scandir_next(req, &ent) != UV_EOF) {
+			value dirent = caml_alloc(2, 0);
+			Store_field(dirent, 0, caml_copy_string(ent.name));
+			Store_field(dirent, 1, ent.type);
+			value node = caml_alloc(2, 0);
+			Store_field(node, 0, dirent); // car
+			Store_field(node, 1, value2); // cdr
+			value2 = node;
+		}
+	});
+
+	/*
+#define UV_REQ_WRAP(name, reqtype, sign, call, handler) \
+	CAMLprim value w_ ## name(sign, value cb) { \
+		UV_ALLOC_CHECK(req, reqtype); \
+		UV_REQ_DATA(req) = (void *)cb; \
+		UV_ERROR_CHECK_C(uv_ ## name(req, call, handler), free(req)); \
+		caml_register_global_root(UV_REQ_DATA(req)); \
+		CAMLreturn0; \
+	}
+#define UV_REQ_WRAP_LOOP(name, reqtype, sign, call, ffi, handler) \
+	CAMLprim value w_ ## name(value *loop, sign, value cb) { \
+		UV_ALLOC_CHECK(req, reqtype); \
+		UV_REQ_DATA(req) = (void *)cb; \
+		UV_ERROR_CHECK_C(uv_ ## name(loop, req, call, handler), free(req)); \
+		caml_register_global_root(UV_REQ_DATA(req)); \
+		CAMLreturn0; \
+	}
+#define UV_REQ_WRAP_LOOP_SYNC(name, ret, reqtype, sign, call, ffiret, ffi, handler, doret) \
+	CAMLprim value w_ ## name ## _sync(uv_loop_t *loop, sign) { \
+		UV_ALLOC_CHECK(req, reqtype); \
+		UV_ERROR_CHECK_C(uv_ ## name(loop, req, call, NULL), free(req)); \
+		doret handler ## _sync(req); \
+	}
+	*/
+/*
+#define COMMA ,
+#define FS_WRAP1_LOOP(name, ret, arg1, ffiret, ffi, ffihandler, handler, doret) \
+	UV_REQ_WRAP_LOOP(name, uv_fs_t, arg1 _arg1, _arg1, ffi ffihandler, handler); \
+	UV_REQ_WRAP_LOOP_SYNC(name, ret, uv_fs_t, arg1 _arg1, _arg1, ffiret, ffi, handler, doret)
+#define FS_WRAP2_LOOP(name, ret, arg1, arg2, ffiret, ffi, ffihandler, handler, doret) \
+	UV_REQ_WRAP_LOOP(name, uv_fs_t, arg1 _arg1 COMMA arg2 _arg2, _arg1 COMMA _arg2, ffi ffihandler, handler); \
+	UV_REQ_WRAP_LOOP_SYNC(name, ret, uv_fs_t, arg1 _arg1 COMMA arg2 _arg2, _arg1 COMMA _arg2, ffiret, ffi, handler, doret)
+#define FS_WRAP3_LOOP(name, ret, arg1, arg2, arg3, ffiret, ffi, ffihandler, handler, doret) \
+	UV_REQ_WRAP_LOOP(name, uv_fs_t, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3, _arg1 COMMA _arg2 COMMA _arg3, ffi ffihandler, handler); \
+	UV_REQ_WRAP_LOOP_SYNC(name, ret, uv_fs_t, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3, _arg1 COMMA _arg2 COMMA _arg3, ffiret, ffi, handler, doret)
+#define FS_WRAP4_LOOP(name, ret, arg1, arg2, arg3, arg4, ffiret, ffi, ffihandler, handler, doret) \
+	UV_REQ_WRAP_LOOP(name, uv_fs_t, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3 COMMA arg4 _arg4, _arg1 COMMA _arg2 COMMA _arg3 COMMA _arg4, ffi ffihandler, handler); \
+	UV_REQ_WRAP_LOOP_SYNC(name, ret, uv_fs_t, arg1 _arg1 COMMA arg2 _arg2 COMMA arg3 _arg3 COMMA arg4 _arg4, _arg1 COMMA _arg2 COMMA _arg3 COMMA _arg4, ffiret, ffi, handler, doret)
+*/
+
+#define FS_WRAP1(name, arg1conv, handler) \
+	CAMLprim value w_ ## name(value loop, value arg1, value cb) { \
+		CAMLparam3(loop, arg1, cb); \
+		UV_ALLOC_CHECK(req, uv_fs_t); \
+		UV_REQ_DATA(req) = (void *)cb; \
+		caml_register_global_root(UV_REQ_DATA_A(req)); \
+		UV_ERROR_CHECK_C(uv_ ## name((uv_loop_t *)loop, (uv_fs_t *)req, arg1conv(arg1), handler), free((uv_fs_t *)req)); \
+		CAMLreturn(Val_unit); \
+	} \
+	CAMLprim value w_ ## name ## _sync(value loop, value arg1) { \
+		CAMLparam2(loop, arg1); \
+		UV_ALLOC_CHECK(req, uv_fs_t); \
+		caml_register_global_root(UV_REQ_DATA_A(req)); \
+		UV_ERROR_CHECK_C(uv_ ## name((uv_loop_t *)loop, (uv_fs_t *)req, arg1conv(arg1), NULL), free((uv_fs_t *)req)); \
+			UV_ERROR_CHECK_C(req->result, free(req));/* TODO: cleanup? */ \
+		value ret = handler ## _sync(req); \
+		uv_fs_req_cleanup(req); \
+		free(req); \
+		CAMLreturn(ret); \
+	}
+
+#define FS_WRAP2(name, arg1conv, arg2conv, handler) \
+	CAMLprim value w_ ## name(value loop, value arg1, value arg2, value cb) { \
+		CAMLparam4(loop, arg1, arg2, cb); \
+		UV_ALLOC_CHECK(req, uv_fs_t); \
+		UV_REQ_DATA(req) = (void *)cb; \
+		caml_register_global_root(UV_REQ_DATA_A(req)); \
+		UV_ERROR_CHECK_C(uv_ ## name((uv_loop_t *)loop, (uv_fs_t *)req, arg1conv(arg1), arg2conv(arg2), handler), free((uv_fs_t *)req)); \
+		CAMLreturn(Val_unit); \
+	} \
+	CAMLprim value w_ ## name ## _sync(value loop, value arg1, value arg2) { \
+		CAMLparam3(loop, arg1, arg2); \
+		UV_ALLOC_CHECK(req, uv_fs_t); \
+		caml_register_global_root(UV_REQ_DATA_A(req)); \
+		UV_ERROR_CHECK_C(uv_ ## name((uv_loop_t *)loop, (uv_fs_t *)req, arg1conv(arg1), arg2conv(arg2), NULL), free((uv_fs_t *)req)); \
+		UV_ERROR_CHECK_C(req->result, free(req));/* TODO: cleanup? */ \
+		value ret = handler ## _sync(req); \
+		uv_fs_req_cleanup(req); \
+		free(req); \
+		CAMLreturn(ret); \
+	}
+
+#define FS_WRAP3(name, arg1conv, arg2conv, arg3conv, handler) \
+	CAMLprim value w_ ## name(value loop, value arg1, value arg2, value arg3, value cb) { \
+		CAMLparam5(loop, arg1, arg2, arg3, cb); \
+		UV_ALLOC_CHECK(req, uv_fs_t); \
+		UV_REQ_DATA(req) = (void *)cb; \
+		caml_register_global_root(UV_REQ_DATA_A(req)); \
+		UV_ERROR_CHECK_C(uv_ ## name((uv_loop_t *)loop, (uv_fs_t *)req, arg1conv(arg1), arg2conv(arg2), arg3conv(arg3), handler), free((uv_fs_t *)req)); \
+		CAMLreturn(Val_unit); \
+	} \
+	CAMLprim value w_ ## name ## _sync(value loop, value arg1, value arg2, value arg3) { \
+		CAMLparam4(loop, arg1, arg2, arg3); \
+		UV_ALLOC_CHECK(req, uv_fs_t); \
+		caml_register_global_root(UV_REQ_DATA_A(req)); \
+		UV_ERROR_CHECK_C(uv_ ## name((uv_loop_t *)loop, (uv_fs_t *)req, arg1conv(arg1), arg2conv(arg2), arg3conv(arg3), NULL), free((uv_fs_t *)req)); \
+		UV_ERROR_CHECK_C(req->result, free(req));/* TODO: cleanup? */ \
+		value ret = handler ## _sync(req); \
+		uv_fs_req_cleanup(req); \
+		free(req); \
+		CAMLreturn(ret); \
+	}
+
+/**
+	FIXME:
+		w_fs_read, w_fs_write, w_fs_read_sync, and w_fs_write_sync
+		have a signature different from libuv due to no struct passing support in
+		hashlink; currently only a single uv_buf_t can be passed at a time.
+**/
+	/*
+HL_PRIM void HL_NAME(w_fs_read)(uv_loop_t *loop, uv_file file, const uv_buf_t *buf, int32_t offset, vclosure *cb) {
+	UV_ALLOC_CHECK(req, uv_fs_t);
+	UV_REQ_DATA(req) = (void *)cb;
+	UV_ERROR_CHECK_C(uv_fs_read(loop, req, file, buf, 1, offset, handle_fs_cb_int), free(req));
+	hl_add_root(UV_REQ_DATA(req));
+}
+
+HL_PRIM int HL_NAME(w_fs_read_sync)(uv_loop_t *loop, uv_file file, const uv_buf_t *buf, int32_t offset) {
+	UV_ALLOC_CHECK(req, uv_fs_t);
+	UV_ERROR_CHECK_C(uv_fs_read(loop, req, file, buf, 1, offset, NULL), free(req));
+	return handle_fs_cb_int_sync(req);
+}
+
+HL_PRIM void HL_NAME(w_fs_write)(uv_loop_t *loop, uv_file file, const uv_buf_t *buf, int32_t offset, vclosure *cb) {
+	UV_ALLOC_CHECK(req, uv_fs_t);
+	UV_REQ_DATA(req) = (void *)cb;
+	UV_ERROR_CHECK_C(uv_fs_write(loop, req, file, buf, 1, offset, handle_fs_cb_int), free(req));
+	hl_add_root(UV_REQ_DATA(req));
+}
+
+HL_PRIM int HL_NAME(w_fs_write_sync)(uv_loop_t *loop, uv_file file, const uv_buf_t *buf, int32_t offset) {
+	UV_ALLOC_CHECK(req, uv_fs_t);
+	UV_ERROR_CHECK_C(uv_fs_write(loop, req, file, buf, 1, offset, NULL), free(req));
+	return handle_fs_cb_int_sync(req);
+}
+
+*/
+FS_WRAP1(fs_close, (uv_file), handle_fs_cb);
+FS_WRAP3(fs_open, String_val, (int), (int), handle_fs_cb_file);
+FS_WRAP1(fs_unlink, String_val, handle_fs_cb);
+FS_WRAP2(fs_mkdir, String_val, (int), handle_fs_cb);
+FS_WRAP1(fs_mkdtemp, String_val, handle_fs_cb_path);
+FS_WRAP1(fs_rmdir, String_val, handle_fs_cb);
+FS_WRAP2(fs_scandir, String_val, (int), handle_fs_cb_scandir);
+//FS_WRAP1(fs_stat, vdynamic *, const char*, _STAT, _BYTES, _CB_STAT, handle_fs_cb_stat, return);
+//FS_WRAP1(fs_fstat, vdynamic *, uv_file, _STAT, _FILE, _CB_STAT, handle_fs_cb_stat, return);
+//FS_WRAP1(fs_lstat, vdynamic *, const char*, _STAT, _BYTES, _CB_STAT, handle_fs_cb_stat, return);
+FS_WRAP2(fs_rename, String_val, String_val, handle_fs_cb);
+FS_WRAP1(fs_fsync, (uv_file), handle_fs_cb);
+FS_WRAP1(fs_fdatasync, (uv_file), handle_fs_cb);
+FS_WRAP2(fs_ftruncate, (uv_file), Int64_val, handle_fs_cb);
+//FS_WRAP4(fs_sendfile, void, uv_file, uv_file, int64_t, size_t, _VOID, _FILE _FILE _I32 _I32, _CB, handle_fs_cb, );
+FS_WRAP2(fs_access, String_val, (int), handle_fs_cb);
+FS_WRAP2(fs_chmod, String_val, (int), handle_fs_cb);
+FS_WRAP2(fs_fchmod, (uv_file), (int), handle_fs_cb);
+FS_WRAP3(fs_utime, String_val, Double_val, Double_val, handle_fs_cb);
+FS_WRAP3(fs_futime, (uv_file), Double_val, Double_val, handle_fs_cb);
+FS_WRAP2(fs_link, String_val, String_val, handle_fs_cb);
+FS_WRAP3(fs_symlink, String_val, String_val, (int), handle_fs_cb);
+FS_WRAP1(fs_readlink, String_val, handle_fs_cb_bytes);
+FS_WRAP1(fs_realpath, String_val, handle_fs_cb_bytes);
+FS_WRAP3(fs_chown, String_val, (uv_uid_t), (uv_gid_t), handle_fs_cb);
+FS_WRAP3(fs_fchown, (uv_file), (uv_uid_t), (uv_gid_t), handle_fs_cb);

+ 34 - 0
libs/libuv/test.ml

@@ -0,0 +1,34 @@
+open Libuv
+
+;;
+
+let loop = Libuv.loop_init () in
+(*let cb_c () = print_string "closed\n" in
+let cb file = print_string "hey I got a file I guess\n"; flush_all (); Libuv.fs_close loop file cb_c in*)
+let cb file =
+	print_string "hey I got a file I guess\n"; flush_all ();
+	Libuv.fs_close_sync loop file;
+	print_string "closed\n"; flush_all ();
+in
+print_string "open files...\n"; flush_all ();
+Libuv.fs_open loop "libuv.ml" 0 511 cb;
+Libuv.fs_open loop "Makefile" 0 511 cb;
+print_string "sync open...\n"; flush_all ();
+let other_file = Libuv.fs_open_sync loop "dummy2.txt" 0 511 in
+print_string "run gc...\n"; flush_all ();
+Gc.full_major ();
+Libuv.fs_close_sync loop other_file;
+print_string "scandir...\n"; flush_all ();
+let dirs = Libuv.fs_scandir_sync loop "." 0 in
+let rec pdirs = function
+	| [] -> ()
+	| (name, kind) :: rest -> print_string ("entry: " ^ name ^ "\n"); pdirs rest
+in
+pdirs dirs;
+print_string "run loop...\n"; flush_all ();
+while (Libuv.loop_alive loop) do
+	ignore (Libuv.run loop 0)
+done;
+print_string "close loop...\n"; flush_all ();
+Libuv.loop_close loop;
+print_string "done\n"