util/datamanager.lua
changeset 8014 f8ba814fe029
parent 7999 f4c0fb54e16c
child 8016 72cfbe377326
equal deleted inserted replaced
8013:49feb0da29e1 8014:f8ba814fe029
    15 local log = require "util.logger".init("datamanager");
    15 local log = require "util.logger".init("datamanager");
    16 local io_open = io.open;
    16 local io_open = io.open;
    17 local os_remove = os.remove;
    17 local os_remove = os.remove;
    18 local os_rename = os.rename;
    18 local os_rename = os.rename;
    19 local tonumber = tonumber;
    19 local tonumber = tonumber;
    20 local tostring = tostring;
       
    21 local next = next;
    20 local next = next;
    22 local type = type;
    21 local type = type;
    23 local t_insert = table.insert;
    22 local t_insert = table.insert;
    24 local t_concat = table.concat;
    23 local t_concat = table.concat;
    25 local envloadfile = require"util.envload".envloadfile;
    24 local envloadfile = require"util.envload".envloadfile;
    29 local path_separator = assert ( package.config:match ( "^([^\n]+)" ) , "package.config not in standard form" )
    28 local path_separator = assert ( package.config:match ( "^([^\n]+)" ) , "package.config not in standard form" )
    30 
    29 
    31 local prosody = prosody;
    30 local prosody = prosody;
    32 
    31 
    33 local raw_mkdir = lfs.mkdir;
    32 local raw_mkdir = lfs.mkdir;
    34 local function fallocate(f, offset, len)
    33 local atomic_append;
    35 	-- This assumes that current position == offset
       
    36 	local fake_data = (" "):rep(len);
       
    37 	local ok, msg = f:write(fake_data);
       
    38 	if not ok then
       
    39 		return ok, msg;
       
    40 	end
       
    41 	f:seek("set", offset);
       
    42 	return true;
       
    43 end;
       
    44 local ENOENT = 2;
    34 local ENOENT = 2;
    45 pcall(function()
    35 pcall(function()
    46 	local pposix = require "util.pposix";
    36 	local pposix = require "util.pposix";
    47 	raw_mkdir = pposix.mkdir or raw_mkdir; -- Doesn't trample on umask
    37 	raw_mkdir = pposix.mkdir or raw_mkdir; -- Doesn't trample on umask
    48 	fallocate = pposix.fallocate or fallocate;
    38 	atomic_append = pposix.atomic_append;
    49 	ENOENT = pposix.ENOENT or ENOENT;
    39 	ENOENT = pposix.ENOENT or ENOENT;
    50 end);
    40 end);
    51 
    41 
    52 local _ENV = nil;
    42 local _ENV = nil;
    53 
    43 
    60 		return s and (s:gsub("%%(%x%x)", urlcodes));
    50 		return s and (s:gsub("%%(%x%x)", urlcodes));
    61 	end
    51 	end
    62 
    52 
    63 	encode = function (s)
    53 	encode = function (s)
    64 		return s and (s:gsub("%W", function (c) return format("%%%02x", c:byte()); end));
    54 		return s and (s:gsub("%W", function (c) return format("%%%02x", c:byte()); end));
       
    55 	end
       
    56 end
       
    57 
       
    58 if not atomic_append then
       
    59 	function atomic_append(f, data)
       
    60 		local pos = f:seek();
       
    61 		if not f:write(data) or not f:flush() then
       
    62 			f:seek("set", pos);
       
    63 			f:write((" "):rep(#data));
       
    64 			f:flush();
       
    65 			return nil, "write-failed";
       
    66 		end
       
    67 		return true;
    65 	end
    68 	end
    66 end
    69 end
    67 
    70 
    68 local _mkdir = {};
    71 local _mkdir = {};
    69 local function mkdir(path)
    72 local function mkdir(path)
   219 local function append(username, host, datastore, ext, data)
   222 local function append(username, host, datastore, ext, data)
   220 	if type(data) ~= "string" then return; end
   223 	if type(data) ~= "string" then return; end
   221 	local filename = getpath(username, host, datastore, ext, true);
   224 	local filename = getpath(username, host, datastore, ext, true);
   222 
   225 
   223 	local ok;
   226 	local ok;
   224 	local f, msg = io_open(filename, "r+");
   227 	local f, msg, errno = io_open(filename, "r+");
   225 	if not f then
   228 	if not f then
   226 		return atomic_store(filename, data);
   229 		return atomic_store(filename, data);
   227 		-- File did probably not exist, let's create it
   230 		-- File did probably not exist, let's create it
   228 	end
   231 	end
   229 
   232 
   230 	local pos = f:seek("end");
   233 	local pos = f:seek("end");
   231 	ok, msg = fallocate(f, pos, #data);
   234 
   232 	if not ok then
   235 	ok, msg = atomic_append(f, data);
   233 		log("warn", "fallocate() failed: %s", tostring(msg));
   236 
   234 		-- This doesn't work on every file system
       
   235 	end
       
   236 
       
   237 	if f:seek() ~= pos then
       
   238 		log("debug", "fallocate() changed file position");
       
   239 		f:seek("set", pos);
       
   240 	end
       
   241 
       
   242 	ok, msg = f:write(data);
       
   243 	if not ok then
   237 	if not ok then
   244 		f:close();
   238 		f:close();
   245 		return ok, msg, "write";
   239 		return ok, msg, "write";
   246 	end
   240 	end
   247 
   241