X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=util%2Fdatamanager.lua;h=4b722851233db27c4776469716a702e491e843bb;hb=a8958cbe5ebad3abc12efa7a76c8aedac8f21389;hp=9207f555d1bf0b0133d18f88e9715ccf3613fad6;hpb=151e6945b18579168d500a7863a43d4adcd9a64c;p=prosody.git diff --git a/util/datamanager.lua b/util/datamanager.lua index 9207f555..4b722851 100644 --- a/util/datamanager.lua +++ b/util/datamanager.lua @@ -43,7 +43,7 @@ pcall(function() fallocate = pposix.fallocate or fallocate; end); -module "datamanager" +local _ENV = nil; ---- utils ----- local encode, decode; @@ -74,7 +74,7 @@ local callbacks = {}; ------- API ------------- -function set_data_path(path) +local function set_data_path(path) log("debug", "Setting data path to: %s", path); data_path = path; end @@ -87,14 +87,14 @@ local function callback(username, host, datastore, data) return username, host, datastore, data; end -function add_callback(func) +local function add_callback(func) if not callbacks[func] then -- Would you really want to set the same callback more than once? callbacks[func] = true; callbacks[#callbacks+1] = func; return true; end end -function remove_callback(func) +local function remove_callback(func) if callbacks[func] then for i, f in ipairs(callbacks) do if f == func then @@ -106,23 +106,20 @@ function remove_callback(func) end end -function getpath(username, host, datastore, ext, create) +local function getpath(username, host, datastore, ext, create) ext = ext or "dat"; host = (host and encode(host)) or "_global"; username = username and encode(username); if username then if create then mkdir(mkdir(mkdir(data_path).."/"..host).."/"..datastore); end return format("%s/%s/%s/%s.%s", data_path, host, datastore, username, ext); - elseif host then + else if create then mkdir(mkdir(data_path).."/"..host); end return format("%s/%s/%s.%s", data_path, host, datastore, ext); - else - if create then mkdir(data_path); end - return format("%s/%s.%s", data_path, datastore, ext); end end -function load(username, host, datastore) +local function load(username, host, datastore) local data, ret = envloadfile(getpath(username, host, datastore), {}); if not data then local mode = lfs.attributes(getpath(username, host, datastore), "mode"); @@ -166,7 +163,7 @@ local function atomic_store(filename, data) return nil, msg; end -if prosody.platform ~= "posix" then +if prosody and prosody.platform ~= "posix" then -- os.rename does not overwrite existing files on Windows -- TODO We could use Transactional NTFS on Vista and above function atomic_store(filename, data) @@ -178,7 +175,7 @@ if prosody.platform ~= "posix" then end end -function store(username, host, datastore, data) +local function store(username, host, datastore, data) if not data then data = {}; end @@ -190,21 +187,29 @@ function store(username, host, datastore, data) -- save the datastore local d = "return " .. serialize(data) .. ";\n"; - local ok, msg = atomic_store(getpath(username, host, datastore, nil, true), d); - if not ok then - log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil"); - return nil, "Error saving to storage"; - end - if next(data) == nil then -- try to delete empty datastore - log("debug", "Removing empty %s datastore for user %s@%s", datastore, username or "nil", host or "nil"); - os_remove(getpath(username, host, datastore)); - end - -- we write data even when we are deleting because lua doesn't have a - -- platform independent way of checking for non-exisitng files + local mkdir_cache_cleared; + repeat + local ok, msg = atomic_store(getpath(username, host, datastore, nil, true), d); + if not ok then + if not mkdir_cache_cleared then -- We may need to recreate a removed directory + _mkdir = {}; + mkdir_cache_cleared = true; + else + log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil"); + return nil, "Error saving to storage"; + end + end + if next(data) == nil then -- try to delete empty datastore + log("debug", "Removing empty %s datastore for user %s@%s", datastore, username or "nil", host or "nil"); + os_remove(getpath(username, host, datastore)); + end + -- we write data even when we are deleting because lua doesn't have a + -- platform independent way of checking for non-exisitng files + until ok; return true; end -function list_append(username, host, datastore, data) +local 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 @@ -230,7 +235,7 @@ function list_append(username, host, datastore, data) return true; end -function list_store(username, host, datastore, data) +local function list_store(username, host, datastore, data) if not data then data = {}; end @@ -254,7 +259,7 @@ function list_store(username, host, datastore, data) return true; end -function list_load(username, host, datastore) +local function list_load(username, host, datastore) local items = {}; local data, ret = envloadfile(getpath(username, host, datastore, "list"), {item = function(i) t_insert(items, i); end}); if not data then @@ -282,7 +287,26 @@ local type_map = { list = "list"; } -function stores(username, host, typ) +local function users(host, store, typ) + typ = type_map[typ or "keyval"]; + local store_dir = format("%s/%s/%s", data_path, encode(host), store); + + local mode, err = lfs.attributes(store_dir, "mode"); + if not mode then + return function() log("debug", "%s", err or (store_dir .. " does not exist")) end + end + local next, state = lfs.dir(store_dir); + return function(state) + for node in next, state do + local file, ext = node:match("^(.*)%.([dalist]+)$"); + if file and ext == typ then + return decode(file); + end + end + end, state; +end + +local function stores(username, host, typ) typ = type_map[typ or "keyval"]; local store_dir = format("%s/%s/", data_path, encode(host)); @@ -322,11 +346,14 @@ local function do_remove(path) return true end -function purge(username, host) +local function purge(username, host) local host_dir = format("%s/%s/", data_path, encode(host)); - local deleted = 0; + local ok, iter, state, var = pcall(lfs.dir, host_dir); + if not ok then + return ok, iter; + end local errs = {}; - for file in lfs.dir(host_dir) do + for file in iter, state, var do if lfs.attributes(host_dir..file, "mode") == "directory" then local store = decode(file); local ok, err = do_remove(getpath(username, host, store)); @@ -339,4 +366,19 @@ function purge(username, host) return #errs == 0, t_concat(errs, ", "); end -return _M; +return { + set_data_path = set_data_path; + add_callback = add_callback; + remove_callback = remove_callback; + getpath = getpath; + load = load; + store = store; + list_append = list_append; + list_store = list_store; + list_load = list_load; + users = users; + stores = stores; + purge = purge; + path_decode = decode; + path_encode = encode; +};