diff --git a/src/box/func.c b/src/box/func.c index 04b04b6adc88adb0d38d38ba72a395b9a3c13e97..c44da9971af657eb7b66de2ae7711f0d03d27da3 100644 --- a/src/box/func.c +++ b/src/box/func.c @@ -40,6 +40,8 @@ #include "port.h" #include "schema.h" #include "session.h" +#include "libeio/eio.h" +#include <fcntl.h> #include <dlfcn.h> /** @@ -269,10 +271,45 @@ module_load(const char *package, const char *package_end) char load_name[PATH_MAX + 1]; snprintf(load_name, sizeof(load_name), "%s/%.*s." TARANTOOL_LIBEXT, dir_name, package_len, package); - if (symlink(path, load_name) < 0) { - diag_set(SystemError, "failed to create dso link"); + + struct stat st; + if (stat(path, &st) < 0) { + diag_set(SystemError, "failed to stat() module %s", path); + goto error; + } + + int source_fd = open(path, O_RDONLY); + if (source_fd < 0) { + diag_set(SystemError, "failed to open module %s file for" \ + " reading", path); + goto error; + } + int dest_fd = open(load_name, O_WRONLY|O_CREAT|O_TRUNC, + st.st_mode & 0777); + if (dest_fd < 0) { + diag_set(SystemError, "failed to open file %s for writing ", + load_name); + close(source_fd); goto error; } + + off_t pos, left; + for (left = st.st_size, pos = 0; left > 0;) { + off_t ret = eio_sendfile_sync(dest_fd, source_fd, pos, + st.st_size); + if (ret < 0) { + diag_set(SystemError, "failed to copy DSO %s to %s", + path, load_name); + close(source_fd); + close(dest_fd); + goto error; + } + pos += ret; + left -= ret; + } + close(source_fd); + close(dest_fd); + module->handle = dlopen(load_name, RTLD_NOW | RTLD_LOCAL); if (unlink(load_name) != 0) say_warn("failed to unlink dso link %s", load_name); diff --git a/test/box/func_reload.result b/test/box/func_reload.result index b024cd143e0e2a57b742ad3294de3c280e48fea2..1313fdf1841310967b313b282943a0a929929884 100644 --- a/test/box/func_reload.result +++ b/test/box/func_reload.result @@ -46,7 +46,7 @@ box.schema.user.grant('guest', 'read,write', 'space', 'test') _ = fio.unlink(reload_path) --- ... -fio.symlink(reload1_path, reload_path) +fio.copyfile(reload1_path, reload_path) --- - true ... @@ -68,10 +68,7 @@ box.space.test:delete{0} --- - [0] ... -_ = fio.unlink(reload_path) ---- -... -fio.symlink(reload2_path, reload_path) +fio.copyfile(reload2_path, reload_path) --- - true ... @@ -92,10 +89,7 @@ box.space.test:truncate() --- ... -- test case with hanging calls -_ = fio.unlink(reload_path) ---- -... -fio.symlink(reload1_path, reload_path) +fio.copyfile(reload1_path, reload_path) --- - true ... @@ -115,10 +109,7 @@ while box.space.test:count() < fibers do fiber.sleep(0.001) end box.schema.func.reload("reload") --- ... -_ = fio.unlink(reload_path) ---- -... -fio.symlink(reload2_path, reload_path) +fio.copyfile(reload2_path, reload_path) --- - true ... @@ -162,10 +153,7 @@ box.schema.func.drop("reload.foo") box.space.test:drop() --- ... -_ = fio.unlink(reload_path) ---- -... -fio.symlink(reload1_path, reload_path) +fio.copyfile(reload1_path, reload_path) --- - true ... @@ -196,10 +184,7 @@ s:delete({1}) --- - [1, 2] ... -_ = fio.unlink(reload_path) ---- -... -fio.symlink(reload2_path, reload_path) +fio.copyfile(reload2_path, reload_path) --- - true ... @@ -236,10 +221,7 @@ c:call("reload.test_reload_fail") --- - [[2]] ... -_ = fio.unlink(reload_path) ---- -... -fio.symlink(reload1_path, reload_path) +fio.copyfile(reload1_path, reload_path) --- - true ... diff --git a/test/box/func_reload.test.lua b/test/box/func_reload.test.lua index 8906898ecb304dadbdc54ad2771cb75054af1ffc..4c062fd72a1f332b7d789e0391b3684ddfb1ee11 100644 --- a/test/box/func_reload.test.lua +++ b/test/box/func_reload.test.lua @@ -17,7 +17,7 @@ _ = box.schema.space.create('test') _ = box.space.test:create_index('primary', {parts = {1, "integer"}}) box.schema.user.grant('guest', 'read,write', 'space', 'test') _ = fio.unlink(reload_path) -fio.symlink(reload1_path, reload_path) +fio.copyfile(reload1_path, reload_path) --check not fail on non-load func box.schema.func.reload("reload") @@ -26,8 +26,7 @@ box.schema.func.reload("reload") box.space.test:insert{0} c:call("reload.foo", {1}) box.space.test:delete{0} -_ = fio.unlink(reload_path) -fio.symlink(reload2_path, reload_path) +fio.copyfile(reload2_path, reload_path) box.schema.func.reload("reload") c:call("reload.foo") @@ -35,8 +34,7 @@ box.space.test:select{} box.space.test:truncate() -- test case with hanging calls -_ = fio.unlink(reload_path) -fio.symlink(reload1_path, reload_path) +fio.copyfile(reload1_path, reload_path) box.schema.func.reload("reload") fibers = 10 @@ -46,8 +44,7 @@ while box.space.test:count() < fibers do fiber.sleep(0.001) end -- double reload doesn't fail waiting functions box.schema.func.reload("reload") -_ = fio.unlink(reload_path) -fio.symlink(reload2_path, reload_path) +fio.copyfile(reload2_path, reload_path) box.schema.func.reload("reload") c:call("reload.foo") @@ -55,9 +52,8 @@ while box.space.test:count() < 2 * fibers + 1 do fiber.sleep(0.001) end box.space.test:select{} box.schema.func.drop("reload.foo") box.space.test:drop() -_ = fio.unlink(reload_path) -fio.symlink(reload1_path, reload_path) +fio.copyfile(reload1_path, reload_path) box.schema.func.create('reload.test_reload', {language = "C"}) box.schema.user.grant('guest', 'execute', 'function', 'reload.test_reload') s = box.schema.space.create('test_reload') @@ -67,8 +63,7 @@ ch = fiber.channel(2) -- call first time to load function c:call("reload.test_reload") s:delete({1}) -_ = fio.unlink(reload_path) -fio.symlink(reload2_path, reload_path) +fio.copyfile(reload2_path, reload_path) _ = fiber.create(function() ch:put(c:call("reload.test_reload")) end) while s:get({1}) == nil do fiber.yield(0.0001) end box.schema.func.reload("reload") @@ -80,8 +75,7 @@ s:drop() box.schema.func.create('reload.test_reload_fail', {language = "C"}) box.schema.user.grant('guest', 'execute', 'function', 'reload.test_reload_fail') c:call("reload.test_reload_fail") -_ = fio.unlink(reload_path) -fio.symlink(reload1_path, reload_path) +fio.copyfile(reload1_path, reload_path) c:call("reload.test_reload") c:call("reload.test_reload_fail")