From ce88f1c98c8ed5764681152ae3d3f66515da194a Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 28 Jul 2012 22:37:24 +0200 Subject: util.datamanager: Use pposix.fallocate() to make sure appends succeed. Also add a fallback fallocate() --- util/datamanager.lua | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'util') diff --git a/util/datamanager.lua b/util/datamanager.lua index 23a2d74f..29a5b994 100644 --- a/util/datamanager.lua +++ b/util/datamanager.lua @@ -21,17 +21,33 @@ local next = next; local t_insert = table.insert; local append = require "util.serialization".append; local envloadfile = require"util.envload".envloadfile; +local serialize = require "util.serialization".serialize; local path_separator = assert ( package.config:match ( "^([^\n]+)" ) , "package.config not in standard form" ) -- Extract directory seperator from package.config (an undocumented string that comes with lua) local lfs = require "lfs"; local prosody = prosody; local raw_mkdir; +local fallocate; if prosody.platform == "posix" then raw_mkdir = require "util.pposix".mkdir; -- Doesn't trample on umask + fallocate = require "util.pposix".fallocate; else raw_mkdir = lfs.mkdir; end +if not fallocate then -- Fallback + function fallocate(f, offset, len) + -- This assumes that current position == offset + local fake_data = (" "):rep(len); + local ok, msg = f:write(fake_data); + if not ok then + return ok, msg; + end + f:seek(offset); + return true; + end +end + module "datamanager" ---- utils ----- @@ -165,14 +181,21 @@ function list_append(username, host, datastore, data) if not data then return; end if callback(username, host, datastore) == false then return true; end -- save the datastore - local f, msg = io_open(getpath(username, host, datastore, "list", true), "a+"); + local f, msg = io_open(getpath(username, host, datastore, "list", true), "a"); if not f then log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil"); return; end - f:write("item("); - append(f, data); - f:write(");\n"); + local data = "item(" .. serialize(data) .. ");\n"; + local pos = f:seek("end"); + local ok, msg = fallocate(f, pos, #data); + f:seek("set", pos); + if ok then + f:write(data); + else + log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil"); + return ok, msg; + end f:close(); return true; end -- cgit v1.2.3