diff --git a/extra/dist.lua b/extra/dist.lua new file mode 100644 index 0000000000000000000000000000000000000000..851f32fc69b5bc4230f7a33d1f3f5a862039be38 --- /dev/null +++ b/extra/dist.lua @@ -0,0 +1,29 @@ +#!env tarantool + +local ffi = require 'ffi' +local yaml = require 'yaml' + +ffi.cdef[[ + int access(const char *path, int amode); +]] + +local function file_exists(name) + + +end + + + +local dist_cfg = { + snap_dir = '/usr/lib/tarantool', + xlog_dir = '/usr/lib/tarantool', + log_dir = '/var/log/tarantool', + pid_dir = '/var/run/tarantool', + username = 'tarantool' +} + + + + + +print(yaml.encode({arg, dist_cfg })) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 71c82e68f54c8024669db10032d5fb11a2091c80..85f5254a4db824ff6e5590a51bc3b0849469cc0f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,6 +27,7 @@ lua_source(lua_sources lua/log.lua) lua_source(lua_sources lua/box_net_box.lua) lua_source(lua_sources lua/help.lua) lua_source(lua_sources lua/tap.lua) +lua_source(lua_sources lua/fio.lua) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/third_party/luafun) lua_source(lua_sources ../third_party/luafun/fun.lua) @@ -75,6 +76,7 @@ set (common_sources tt_uuid.c ffisyms.cc uri.cc + disk_fiber_io.cc lua/init.cc lua/fiber.cc lua/trigger.cc @@ -87,6 +89,7 @@ set (common_sources lua/errno.c lua/bsdsocket.cc lua/pickle.cc + lua/fio.cc ${lua_sources} ) diff --git a/src/disk_fiber_io.cc b/src/disk_fiber_io.cc new file mode 100644 index 0000000000000000000000000000000000000000..cd064e628b1ee30d474493a8c5fc2c007541dccb --- /dev/null +++ b/src/disk_fiber_io.cc @@ -0,0 +1,98 @@ +/* + * 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. + * + * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``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 + * <COPYRIGHT HOLDER> 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 <disk_fiber_io.h> +#include <coeio.h> +#include <fiber.h> + +struct fiber_eio { + ssize_t result; + int errorno; + struct fiber *fiber; + bool done; +}; + + +int +dfio_complete(eio_req *req) +{ + struct fiber_eio *fio = (struct fiber_eio *)req->data; + + fio->result = req->result; + fio->errorno = req->errorno; + fio->done = true; + + fiber_wakeup(fio->fiber); + return 0; +} + +static ssize_t +dfio_wait_done(eio_req *req, struct fiber_eio *eio) +{ + if (!req) { + errno = ENOMEM; + return -1; + } + + while (!eio->done) + fiber_yield(); + errno = eio->errorno; + + say_info("Done evio operation"); + return eio->result; +} + +int +dfio_open(const char *path, int flags, mode_t mode) +{ + struct fiber_eio eio = { 0, 0, fiber(), false }; + + eio_req *req = eio_open(path, flags, mode, 0, dfio_complete, &eio); + return dfio_wait_done(req, &eio); +} + +ssize_t +dfio_pwrite(int fd, const void *buf, size_t count, off_t offset) +{ + struct fiber_eio eio = { 0, 0, fiber(), false }; + say_info("Write %s (%zu bytes)", (const char *)buf, count); + eio_req *req = eio_write(fd, + (void *)buf, count, offset, 0, dfio_complete, &eio); + return dfio_wait_done(req, &eio); +} + +ssize_t +dfio_pread(int fd, void *buf, size_t count, off_t offset) +{ + struct fiber_eio eio = { 0, 0, fiber(), false }; + say_info("Read %s (%zu bytes)", (const char *)buf, count); + eio_req *req = eio_read(fd, buf, count, + offset, 0, dfio_complete, &eio); + return dfio_wait_done(req, &eio); +} diff --git a/src/disk_fiber_io.h b/src/disk_fiber_io.h new file mode 100644 index 0000000000000000000000000000000000000000..74121ae6ade5de0f41cec5f7cf5e370caaa4ea8c --- /dev/null +++ b/src/disk_fiber_io.h @@ -0,0 +1,40 @@ +#ifndef INCLUDES_TARANTOOL_LUA_DISK_FIBER_IO_H +#define INCLUDES_TARANTOOL_LUA_DISK_FIBER_IO_H +/* + * 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. + * + * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``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 + * <COPYRIGHT HOLDER> 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 <sys/types.h> + +int dfio_open(const char *path, int flags, mode_t mode); + +ssize_t dfio_pwrite(int fd, const void *buf, size_t count, off_t offset); +ssize_t dfio_pread(int fd, void *buf, size_t count, off_t offset); + + +#endif /* INCLUDES_TARANTOOL_LUA_DISK_FIBER_IO_H */ diff --git a/src/lua/fio.cc b/src/lua/fio.cc new file mode 100644 index 0000000000000000000000000000000000000000..631b748c6eca23588091c31dd4f81a8a6c5f09ef --- /dev/null +++ b/src/lua/fio.cc @@ -0,0 +1,346 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <glob.h> +#include <time.h> +#include "lua/fio.h" +#include <coeio.h> +#include <fiber.h> + +extern "C" { +#include <lua.h> +#include <lauxlib.h> +#include <lualib.h> +} +#include "lua/utils.h" + +#include <disk_fiber_io.h> + + + +static int +fio_eio_open(struct lua_State *L) +{ + const char *path = lua_tostring(L, 1); + int flags = lua_tointeger(L, 2); + int mode = lua_tointeger(L, 3); + + int fh = dfio_open(path, flags, mode); + lua_pushinteger(L, fh); + return 1; +} + + +static int +fio_eio_pwrite(struct lua_State *L) +{ + int fh = lua_tointeger(L, 1); + const char *buf = lua_tostring(L, 2); + size_t len = lua_tonumber(L, 3); + size_t offset = lua_tonumber(L, 4); + + int res = dfio_pwrite(fh, buf, len, offset); + lua_pushinteger(L, res); + return 1; +} + + +static int +fio_eio_pread(struct lua_State *L) +{ + int fh = lua_tointeger(L, 1); + size_t len = lua_tonumber(L, 2); + size_t offset = lua_tonumber(L, 3); + + if (!len) { + lua_pushliteral(L, ""); + return 1; + } + + /* allocate buffer at lua stack */ + void *buf = lua_newuserdata(L, len); + if (!buf) { + errno = ENOMEM; + lua_pushnil(L); + return 1; + } + + + int res = dfio_pread(fh, buf, len, offset); + + if (res < 0) { + lua_pop(L, 1); + lua_pushnil(L); + return 1; + } + lua_pushlstring(L, (char *)buf, res); + lua_remove(L, -2); + return 1; +} + + + +#define ADD_CONST(c) { \ + lua_pushliteral(L, # c); \ + lua_pushinteger(L, c); \ + lua_settable(L, -3); \ + } + + +static int +fio_lua_glob(struct lua_State *L) +{ + if (lua_gettop(L) < 1) + luaL_error(L, "Usage: fio.glob('[pattern].*'"); + if (!lua_isstring(L, 1)) + luaL_error(L, "pattern must be string"); + const char *p = lua_tostring(L, 1); + + glob_t globbuf; + switch (glob(p, GLOB_NOESCAPE, NULL, &globbuf)) { + case 0: + break; + case GLOB_NOMATCH: + lua_newtable(L); + return 1; + + default: + case GLOB_NOSPACE: + errno = ENOMEM; + lua_pushnil(L); + return 1; + } + + lua_newtable(L); + + for (size_t i = 0; i < globbuf.gl_pathc; i++) { + lua_pushinteger(L, i + 1); + lua_pushstring(L, globbuf.gl_pathv[i]); + lua_settable(L, -3); + } + + globfree(&globbuf); + return 1; +} + +static int +lua_pushtimespec(struct lua_State *L, const struct timespec *ts) +{ + double nsec = ts->tv_nsec; + nsec /= 1000000000; + lua_pushnumber(L, ts->tv_sec + nsec); + return 1; +} + +static int +lua_pushstat(struct lua_State *L, const struct stat *stat) +{ + lua_newtable(L); + + lua_pushliteral(L, "dev"); + lua_pushinteger(L, stat->st_dev); + lua_settable(L, -3); + + lua_pushliteral(L, "inode"); + lua_pushinteger(L, stat->st_ino); + lua_settable(L, -3); + + lua_pushliteral(L, "mode"); + lua_pushinteger(L, stat->st_mode); + lua_settable(L, -3); + + lua_pushliteral(L, "nlink"); + lua_pushinteger(L, stat->st_nlink); + lua_settable(L, -3); + + lua_pushliteral(L, "uid"); + lua_pushinteger(L, stat->st_uid); + lua_settable(L, -3); + + lua_pushliteral(L, "gid"); + lua_pushinteger(L, stat->st_gid); + lua_settable(L, -3); + + lua_pushliteral(L, "rdev"); + lua_pushinteger(L, stat->st_rdev); + lua_settable(L, -3); + + lua_pushliteral(L, "size"); + lua_pushinteger(L, stat->st_size); + lua_settable(L, -3); + + lua_pushliteral(L, "blksize"); + lua_pushinteger(L, stat->st_blksize); + lua_settable(L, -3); + + lua_pushliteral(L, "blocks"); + lua_pushinteger(L, stat->st_blocks); + lua_settable(L, -3); + + + lua_pushliteral(L, "ctime"); + lua_pushtimespec(L, &stat->st_ctim); + lua_settable(L, -3); + + lua_pushliteral(L, "mtime"); + lua_pushtimespec(L, &stat->st_mtim); + lua_settable(L, -3); + + lua_pushliteral(L, "atime"); + lua_pushtimespec(L, &stat->st_atim); + lua_settable(L, -3); + + return 1; +} + +static int +fio_lua_lstat(struct lua_State *L) +{ + if (lua_gettop(L) < 1 || !lua_isstring(L, 1)) + luaL_error(L, "Usage: fio.stat(pathname)"); + struct stat stat; + if (lstat(lua_tostring(L, 1), &stat) < 0) { + lua_pushnil(L); + return 1; + } + return lua_pushstat(L, &stat); +} + + +static int +fio_lua_fstat(struct lua_State *L) +{ + if (lua_gettop(L) < 1 || !lua_isnumber(L, 1)) + luaL_error(L, "Usage: fio.fstat(fd)"); + struct stat stat; + if (fstat(lua_tointeger(L, 1), &stat) < 0) { + lua_pushnil(L); + return 1; + } + return lua_pushstat(L, &stat); +} + +void +fio_lua_init(struct lua_State *L) +{ + static const struct luaL_Reg fio_methods[] = { + { "stat", fio_lua_lstat }, + { "fstat", fio_lua_fstat }, + { "glob", fio_lua_glob }, + { NULL, NULL } + }; + + luaL_register_module(L, "fio", fio_methods); + + + + /* internal table */ + lua_pushliteral(L, "internal"); + lua_newtable(L); + static const struct luaL_Reg internal_methods[] = { + { "open", fio_eio_open }, + { "pwrite", fio_eio_pwrite }, + { "pread", fio_eio_pread }, + { NULL, NULL } + }; + luaL_register(L, NULL, internal_methods); + lua_settable(L, -3); + + + lua_pushliteral(L, "c"); + lua_newtable(L); + + + lua_pushliteral(L, "flag"); + lua_newtable(L); + #ifdef O_APPEND + ADD_CONST(O_APPEND) + #endif + #ifdef O_ASYNC + ADD_CONST(O_ASYNC) + #endif + #ifdef O_CLOEXEC + ADD_CONST(O_CLOEXEC) + #endif + #ifdef O_CREAT + ADD_CONST(O_CREAT) + #endif + #ifdef O_DIRECT + ADD_CONST(O_DIRECT) + #endif + #ifdef O_DIRECTORY + ADD_CONST(O_DIRECTORY) + #endif + #ifdef O_EXCL + ADD_CONST(O_EXCL) + #endif + #ifdef O_LARGEFILE + ADD_CONST(O_LARGEFILE) + #endif + #ifdef O_NOATIME + ADD_CONST(O_NOATIME) + #endif + #ifdef O_NOCTTY + ADD_CONST(O_NOCTTY) + #endif + #ifdef O_NOFOLLOW + ADD_CONST(O_NOFOLLOW) + #endif + #ifdef O_NONBLOCK + ADD_CONST(O_NONBLOCK) + #endif + #ifdef O_NDELAY + ADD_CONST(O_NDELAY) + #endif + #ifdef O_PATH + ADD_CONST(O_PATH) + #endif + #ifdef O_SYNC + ADD_CONST(O_SYNC) + #endif + #ifdef O_TMPFILE + ADD_CONST(O_TMPFILE) + #endif + #ifdef O_TRUNC + ADD_CONST(O_TRUNC) + #endif + ADD_CONST(O_RDONLY); + ADD_CONST(O_WRONLY); + ADD_CONST(O_RDWR); + lua_settable(L, -3); + + lua_pushliteral(L, "mode"); + lua_newtable(L); + ADD_CONST(S_IRWXU); + ADD_CONST(S_IRUSR); + ADD_CONST(S_IWUSR); + ADD_CONST(S_IXUSR); + ADD_CONST(S_IRWXG); + ADD_CONST(S_IRGRP); + ADD_CONST(S_IWGRP); + ADD_CONST(S_IXGRP); + ADD_CONST(S_IRWXO); + ADD_CONST(S_IROTH); + ADD_CONST(S_IWOTH); + ADD_CONST(S_IXOTH); + lua_settable(L, -3); + + + lua_pushliteral(L, "seek"); + lua_newtable(L); + ADD_CONST(SEEK_SET); + ADD_CONST(SEEK_CUR); + ADD_CONST(SEEK_END); + #ifdef SEEK_DATA + ADD_CONST(SEEK_DATA); + #endif + #ifdef SEEK_HOLE + ADD_CONST(SEEK_HOLE); + #endif + lua_settable(L, -3); + + + lua_settable(L, -3); + lua_pop(L, 1); +} diff --git a/src/lua/fio.h b/src/lua/fio.h new file mode 100644 index 0000000000000000000000000000000000000000..e1053551916a4de92b7c23f63dc644ddcdbe4c64 --- /dev/null +++ b/src/lua/fio.h @@ -0,0 +1,35 @@ +#ifndef INCLUDES_TARANTOOL_LUA_FIO_H +#define INCLUDES_TARANTOOL_LUA_FIO_H +/* + * 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. + * + * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``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 + * <COPYRIGHT HOLDER> 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. + */ + +struct lua_State; +void fio_lua_init(struct lua_State *L); + +#endif /* INCLUDES_TARANTOOL_LUA_FIO_H */ diff --git a/src/lua/fio.lua b/src/lua/fio.lua new file mode 100644 index 0000000000000000000000000000000000000000..51b240461a7c99dd9be69d191eed7712f956deb5 --- /dev/null +++ b/src/lua/fio.lua @@ -0,0 +1,247 @@ +local ffi = require 'ffi' +local log = require 'log' + +local fio = {} + +ffi.cdef[[ + + typedef ssize_t off_t; + + int open(const char *pathname, int flags, int mode); + int unlink(const char *pathname); + int close(int fd); + + int fsync(int fd); + int fdatasync(int fd); + ssize_t readlink(const char *pathname, char *buf, size_t bufsiz); + int symlink(const char *target, const char *linkpath); + int link(const char *oldpath, const char *newpath); + int rename(const char *oldpath, const char *newpath); + off_t lseek(int fd, off_t offset, int whence); + + ssize_t read(int fd, void *buf, size_t count); + ssize_t write(int fd, const void *buf, size_t count); + + int truncate(const char *path, off_t length); + int ftruncate(int fd, off_t length); +]] + +local bsize = 4096 +local buffer = ffi.new('char[?]', bsize) + +local function sprintf(fmt, ...) + if select('#', ...) == 0 then + return fmt + end + return string.format(fmt, ...) +end + +local fio_methods = {} + + +fio_methods.read = function(self, size) + local b = ffi.new('char[?]', size) + if b == nil then + return nil + end + local res = ffi.C.read(self.fh, b, size) + if res < 0 then + return nil + end + return ffi.string(b, res) +end + +fio_methods.write = function(self, data) + data = tostring(data) + local res = ffi.C.write(self.fh, data, #data) +-- local res = fio.internal.write(self.fh, data, #data) + return res >= 0 +end + +fio_methods.pwrite = function(self, data, len, offset) + data = tostring(data) + if len == nil then + len = #data + end + if offset == nil then + offset = 0 + else + offset = tonumber(offset) + end + + local res = fio.internal.pwrite(self.fh, data, len, offset) + return res >= 0 +end + +fio_methods.pread = function(self, len, offset) + if len == nil then + return '' + end + if offset == nil then + offset = 0 + end + + return fio.internal.pread(self.fh, tonumber(len), tonumber(offset)) +end + + +fio_methods.truncate = function(self, length) + local res = ffi.C.ftruncate(self.fh, length) + if res < 0 then + return nil + end + return true +end + +fio_methods.seek = function(self, offset, whence) + if whence == nil then + whence = 'SEEK_SET' + end + if type(whence) == 'string' then + if fio.c.seek[whence] == nil then + error(sprintf("Unknown whence: %s", whence)) + end + whence = fio.c.seek[whence] + else + whence = tonumber(whence) + end + + local res = ffi.C.lseek(self.fh, tonumber(offset), whence) + + if res < 0 then + return nil + end + return tonumber(res) +end + +fio_methods.close = function(self) + local res = ffi.C.close(self.fh) + if res < 0 then + return false + end + return true +end + +fio_methods.fsync = function(self) + local res = ffi.C.fsync(self.fh) + + if res < 0 then + return false + end + return true +end + +fio_methods.fdatasync = function(self) + local res = ffi.C.fdatasync(self.fh) + + if res < 0 then + return false + end + return true +end + + +fio_methods.stat = function(self) + return fio.fstat(self.fh) +end + + +local fio_mt = { __index = fio_methods } + +fio.open = function(path, flags, mode) + local iflag = 0 + local imode = 0 + + if type(flags) ~= 'table' then + flags = { flags } + end + if type(mode) ~= 'table' then + mode = { mode } + end + + + for _, flag in pairs(flags) do + if type(flag) == 'number' then + iflag = bit.bor(iflag, flag) + else + if fio.c.flag[ flag ] == nil then + error(sprintf("Unknown flag: %s", flag)) + end + iflag = bit.bor(iflag, fio.c.flag[ flag ]) + end + end + + for _, m in pairs(mode) do + if type(m) == 'string' then + if fio.c.mode[m] == nil then + error(sprintf("Unknown mode: %s", m)) + end + imode = bit.bor(imode, fio.c.mode[m]) + else + imode = bit.bor(imode, tonumber(m)) + end + end + + log.info("File: %s flag: %s, mode: %s", path, iflag, imode) + + + local fh = fio.internal.open(tostring(path), iflag, imode) + if fh < 0 then + return nil + end + + fh = { fh = fh } + setmetatable(fh, fio_mt) + return fh +end + +fio.readlink = function(path) + local res = ffi.C.readlink(tostring(path), buffer, bsize) + if res < 0 then + return nil + end + return ffi.string(buffer, res) +end + +fio.symlink = function(path, linkpath) + local res = ffi.C.symlink(tostring(path), tostring(linkpath)) + if res < 0 then + return false + end + return true +end + +fio.link = function(path, newpath) + local res = ffi.C.link(tostring(path), tostring(linkpath)) + if res < 0 then + return false + end + return true +end + +fio.unlink = function(path) + local res = ffi.C.unlink(tostring(path)) + if res == 0 then + return true + end + return false +end + +fio.rename = function(path, newpath) + local res = ffi.C.rename(path, newpath) + if res < 0 then + return false + end + return true +end + + +fio.truncate = function(path, length) + local res = ffi.C.truncate(tostring(path), tonumber(length)) + if res < 0 then + return false + end + return true +end + +return fio diff --git a/src/lua/init.cc b/src/lua/init.cc index 048575cb5b800a01eb9ba3b54974aad49919740f..0a857552238882f57928f4fa88e296e43ace202a 100644 --- a/src/lua/init.cc +++ b/src/lua/init.cc @@ -55,6 +55,7 @@ extern "C" { #include "lua/yaml.h" #include "lua/msgpack.h" #include "lua/pickle.h" +#include "lua/fio.h" #include <ctype.h> #include "small/region.h" @@ -75,7 +76,8 @@ extern char uuid_lua[], console_lua[], box_net_box_lua[], help_lua[], - tap_lua[]; + tap_lua[], + fio_lua[]; static const char *lua_sources[] = { init_lua, @@ -92,6 +94,7 @@ static const char *lua_modules[] = { "net.box", box_net_box_lua, "console", console_lua, "tap", tap_lua, + "fio", fio_lua, NULL }; @@ -313,6 +316,7 @@ tarantool_lua_init(const char *tarantool_bin, int argc, char **argv) } box_lua_init(L); + fio_lua_init(L); lua_newtable(L); diff --git a/test/box/fio.result b/test/box/fio.result new file mode 100644 index 0000000000000000000000000000000000000000..ecea3b6d6da3a66095dc52cb1d4f9aa36f9ac54e --- /dev/null +++ b/test/box/fio.result @@ -0,0 +1,146 @@ +fio = require 'fio' +--- +... +errno = require 'errno' +--- +... +fh1 = fio.open("/tmp/tarantool-test.fio.1", { 'O_RDWR', 'O_TRUNC', 'O_CREAT' }, { 'S_IRUSR', 'S_IWUSR' }) +--- +... +fh2 = fio.open("/tmp/tarantool-test.fio.2", { 'O_RDWR', 'O_TRUNC', 'O_CREAT' }, { 'S_IRUSR', 'S_IWUSR' }) +--- +... +type(fh1) +--- +- table +... +type(fh2) +--- +- table +... +fh1:seek(123) +--- +- 123 +... +fh1:write('Hello, world') +--- +- true +... +fh1:fdatasync() +--- +- true +... +fh1:fsync() +--- +- true +... +fio.stat("/tmp/tarantool-test.fio.1").size +--- +- 135 +... +fh1:seek(123) +--- +- 123 +... +fh1:read(500) +--- +- Hello, world +... +fh1:truncate(128) +--- +- true +... +fh1:seek(123) +--- +- 123 +... +fh1:read(3) +--- +- Hel +... +fh1:read(500) +--- +- lo +... +fh1:seek(123) +--- +- 123 +... +fio.truncate("/tmp/tarantool-test.fio.1", 127) +--- +- true +... +fio.stat("/tmp/tarantool-test.fio.1").size +--- +- 127 +... +fh1:stat().size +--- +- 127 +... +fh1:read(500) +--- +- Hell +... +fh1:close() +--- +- true +... +fh1:close() +--- +- false +... +fh2:close() +--- +- true +... +fio.symlink("/tmp/tarantool-test.fio.1", "/tmp/tarantool-test.fio.3") +--- +- true +... +fio.readlink("/tmp/tarantool-test.fio.3") +--- +- /tmp/tarantool-test.fio.1 +... +fio.symlink("/tmp/tarantool-test.fio.1", "/tmp/tarantool-test.fio.3") +--- +- false +... +errno.strerror(errno()) +--- +- File exists +... +fio.rename("/tmp/tarantool-test.fio.3", "/tmp/tarantool-test.fio.4") +--- +- true +... +fio.glob("/tmp/tarantool-test.fio.[1-4]") +--- +- - /tmp/tarantool-test.fio.1 + - /tmp/tarantool-test.fio.2 + - /tmp/tarantool-test.fio.4 +... +fio.unlink("/tmp/tarantool-test.fio.1") +--- +- true +... +fio.unlink("/tmp/tarantool-test.fio.2") +--- +- true +... +fio.unlink("/tmp/tarantool-test.fio.3") +--- +- false +... +fio.unlink("/tmp/tarantool-test.fio.4") +--- +- true +... +fio.stat("/tmp/tarantool-test.fio.1") +--- +- null +... +fio.glob("/tmp/tarantool-test.fio.[12]") +--- +- [] +... diff --git a/test/box/fio.test.lua b/test/box/fio.test.lua new file mode 100644 index 0000000000000000000000000000000000000000..09c625603cacb429835f26237877ab6287a54863 --- /dev/null +++ b/test/box/fio.test.lua @@ -0,0 +1,56 @@ +fio = require 'fio' +errno = require 'errno' + +fh1 = fio.open("/tmp/tarantool-test.fio.1", { 'O_RDWR', 'O_TRUNC', 'O_CREAT' }, { 'S_IRUSR', 'S_IWUSR' }) +fh2 = fio.open("/tmp/tarantool-test.fio.2", { 'O_RDWR', 'O_TRUNC', 'O_CREAT' }, { 'S_IRUSR', 'S_IWUSR' }) + +type(fh1) +type(fh2) + +fh1:seek(123) +fh1:write('Hello, world') + +fh1:fdatasync() +fh1:fsync() + +fio.stat("/tmp/tarantool-test.fio.1").size + +fh1:seek(123) +fh1:read(500) + +fh1:truncate(128) +fh1:seek(123) +fh1:read(3) +fh1:read(500) + +fh1:seek(123) +fio.truncate("/tmp/tarantool-test.fio.1", 127) +fio.stat("/tmp/tarantool-test.fio.1").size +fh1:stat().size +fh1:read(500) + + + +fh1:close() +fh1:close() +fh2:close() + +fio.symlink("/tmp/tarantool-test.fio.1", "/tmp/tarantool-test.fio.3") +fio.readlink("/tmp/tarantool-test.fio.3") +fio.symlink("/tmp/tarantool-test.fio.1", "/tmp/tarantool-test.fio.3") +errno.strerror(errno()) + +fio.rename("/tmp/tarantool-test.fio.3", "/tmp/tarantool-test.fio.4") +fio.glob("/tmp/tarantool-test.fio.[1-4]") + +fio.unlink("/tmp/tarantool-test.fio.1") +fio.unlink("/tmp/tarantool-test.fio.2") +fio.unlink("/tmp/tarantool-test.fio.3") +fio.unlink("/tmp/tarantool-test.fio.4") + +fio.stat("/tmp/tarantool-test.fio.1") + +fio.glob("/tmp/tarantool-test.fio.[12]") + + +fio