Software /
code /
prosody
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); |