Comparison

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
comparison
equal deleted inserted replaced
8005:b472bccf8023 8010:49feb0da29e1
11 /* 11 /*
12 * pposix.c 12 * pposix.c
13 * POSIX support functions for Lua 13 * POSIX support functions for Lua
14 */ 14 */
15 15
16 #define MODULE_VERSION "0.3.6" 16 #define MODULE_VERSION "0.3.7"
17 17
18 18
19 #if defined(__linux__) 19 #if defined(__linux__)
20 #define _GNU_SOURCE 20 #define _GNU_SOURCE
21 #else 21 #else
786 786
787 return 2; 787 return 2;
788 } 788 }
789 } 789 }
790 790
791 /*
792 * Append some data to a file handle
793 * Attempt to allocate space first
794 * Truncate to original size on failure
795 */
796 int lc_atomic_append(lua_State *L) {
797 int err;
798 size_t len;
799
800 FILE *f = *(FILE **) luaL_checkudata(L, 1, LUA_FILEHANDLE);
801 const char *data = luaL_checklstring(L, 2, &len);
802
803 off_t offset = ftell(f);
804
805 #if defined(__linux__)
806 /* Try to allocate space without changing the file size. */
807 if((err = fallocate(fileno(f), FALLOC_FL_KEEP_SIZE, offset, len))) {
808 if(errno != 0) {
809 /* Some old versions of Linux apparently use the return value instead of errno */
810 err = errno;
811 }
812 switch(err) {
813 case ENOSYS: /* Kernel doesn't implement fallocate */
814 case EOPNOTSUPP: /* Filesystem doesn't support it */
815 /* Ignore and proceed to try to write */
816 break;
817
818 case ENOSPC: /* No space left */
819 default: /* Other issues */
820 lua_pushnil(L);
821 lua_pushstring(L, strerror(err));
822 lua_pushinteger(L, err);
823 return 3;
824 }
825 }
826 #endif
827
828 if(fwrite(data, sizeof(char), len, f) == len) {
829 if(fflush(f) == 0) {
830 lua_pushboolean(L, 1); /* Great success! */
831 return 1;
832 } else {
833 err = errno;
834 }
835 } else {
836 err = ferror(f);
837 }
838
839 fseek(f, offset, SEEK_SET);
840
841 /* Cut partially written data */
842 if(ftruncate(fileno(f), offset)) {
843 /* The file is now most likely corrupted, throw hard error */
844 return luaL_error(L, "atomic_append() failed in ftruncate(): %s", strerror(errno));
845 }
846
847 lua_pushnil(L);
848 lua_pushstring(L, strerror(err));
849 lua_pushinteger(L, err);
850 return 3;
851 }
852
791 /* Register functions */ 853 /* Register functions */
792 854
793 int luaopen_util_pposix(lua_State *L) { 855 int luaopen_util_pposix(lua_State *L) {
794 #if (LUA_VERSION_NUM > 501) 856 #if (LUA_VERSION_NUM > 501)
795 luaL_checkversion(L); 857 luaL_checkversion(L);
826 #ifdef WITH_MALLINFO 888 #ifdef WITH_MALLINFO
827 { "meminfo", lc_meminfo }, 889 { "meminfo", lc_meminfo },
828 #endif 890 #endif
829 891
830 { "fallocate", lc_fallocate }, 892 { "fallocate", lc_fallocate },
893 { "atomic_append", lc_atomic_append },
831 894
832 { NULL, NULL } 895 { NULL, NULL }
833 }; 896 };
834 897
835 lua_newtable(L); 898 lua_newtable(L);