Comparison

util/datamanager.lua @ 8015:ecb110f45c92

Merge 0.10->trunk
author Kim Alvefur <zash@zash.se>
date Tue, 28 Mar 2017 20:14:35 +0200
parent 8014:ff3787033abb
child 8092:0a1c0f1107d2
comparison
equal deleted inserted replaced
8009:1c311d8c1443 8015:ecb110f45c92
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)
218 -- Append a blob of data to a file 221 -- Append a blob of data to a file
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 f = io_open(filename, "r+");
224 local f, msg = io_open(filename, "r+");
225 if not f then 227 if not f then
226 return atomic_store(filename, data); 228 return atomic_store(filename, data);
227 -- File did probably not exist, let's create it 229 -- File did probably not exist, let's create it
228 end 230 end
229 231
230 local pos = f:seek("end"); 232 local pos = f:seek("end");
231 ok, msg = fallocate(f, pos, #data); 233
232 if not ok then 234 local ok, msg = atomic_append(f, data);
233 log("warn", "fallocate() failed: %s", tostring(msg)); 235
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 236 if not ok then
244 f:close(); 237 f:close();
245 return ok, msg, "write"; 238 return ok, msg, "write";
246 end 239 end
247 240
248 ok, msg = f:close(); 241 ok, msg = f:close();
249 if not ok then 242 if not ok then
250 return ok, msg; 243 return ok, msg, "close";
251 end 244 end
252 245
253 return true, pos; 246 return true, pos;
254 end 247 end
255 248
257 if not data then return; end 250 if not data then return; end
258 if callback(username, host, datastore) == false then return true; end 251 if callback(username, host, datastore) == false then return true; end
259 -- save the datastore 252 -- save the datastore
260 253
261 data = "item(" .. serialize(data) .. ");\n"; 254 data = "item(" .. serialize(data) .. ");\n";
262 local ok, msg = append(username, host, datastore, "list", data); 255 local ok, msg, where = append(username, host, datastore, "list", data);
263 if not ok then 256 if not ok then
264 log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil"); 257 log("error", "Unable to write to %s storage ('%s' in %s) for user: %s@%s",
258 datastore, msg, where, username or "nil", host or "nil");
265 return ok, msg; 259 return ok, msg;
266 end 260 end
267 return true; 261 return true;
268 end 262 end
269 263