Software /
code /
prosody
Diff
util-src/pposix.c @ 8010:49feb0da29e1
util.pposix: Add function for atomically appending data to a file
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Wed, 01 Mar 2017 01:33:00 +0100 |
parent | 7969:1c6a07606309 |
child | 8012:e898c8fda986 |
line wrap: on
line diff
--- a/util-src/pposix.c Sat Mar 25 17:32:42 2017 +0100 +++ b/util-src/pposix.c Wed Mar 01 01:33:00 2017 +0100 @@ -13,7 +13,7 @@ * POSIX support functions for Lua */ -#define MODULE_VERSION "0.3.6" +#define MODULE_VERSION "0.3.7" #if defined(__linux__) @@ -788,6 +788,68 @@ } } +/* + * Append some data to a file handle + * Attempt to allocate space first + * Truncate to original size on failure + */ +int lc_atomic_append(lua_State *L) { + int err; + size_t len; + + FILE *f = *(FILE **) luaL_checkudata(L, 1, LUA_FILEHANDLE); + const char *data = luaL_checklstring(L, 2, &len); + + off_t offset = ftell(f); + +#if defined(__linux__) + /* Try to allocate space without changing the file size. */ + if((err = fallocate(fileno(f), FALLOC_FL_KEEP_SIZE, offset, len))) { + if(errno != 0) { + /* Some old versions of Linux apparently use the return value instead of errno */ + err = errno; + } + switch(err) { + case ENOSYS: /* Kernel doesn't implement fallocate */ + case EOPNOTSUPP: /* Filesystem doesn't support it */ + /* Ignore and proceed to try to write */ + break; + + case ENOSPC: /* No space left */ + default: /* Other issues */ + lua_pushnil(L); + lua_pushstring(L, strerror(err)); + lua_pushinteger(L, err); + return 3; + } + } +#endif + + if(fwrite(data, sizeof(char), len, f) == len) { + if(fflush(f) == 0) { + lua_pushboolean(L, 1); /* Great success! */ + return 1; + } else { + err = errno; + } + } else { + err = ferror(f); + } + + fseek(f, offset, SEEK_SET); + + /* Cut partially written data */ + if(ftruncate(fileno(f), offset)) { + /* The file is now most likely corrupted, throw hard error */ + return luaL_error(L, "atomic_append() failed in ftruncate(): %s", strerror(errno)); + } + + lua_pushnil(L); + lua_pushstring(L, strerror(err)); + lua_pushinteger(L, err); + return 3; +} + /* Register functions */ int luaopen_util_pposix(lua_State *L) { @@ -828,6 +890,7 @@ #endif { "fallocate", lc_fallocate }, + { "atomic_append", lc_atomic_append }, { NULL, NULL } };