-- EFL LuaJIT bindings: Eina (file module) -- For use with Elua local ffi = require("ffi") local C = ffi.C local iterator = require("eina.iterator") require("eina.xattr") ffi.cdef [[ typedef unsigned char Eina_Bool; typedef long time_t; typedef struct _Eina_File_Direct_Info Eina_File_Direct_Info; typedef struct _Eina_Stat Eina_Stat; typedef struct _Eina_File_Line Eina_File_Line; typedef void (*Eina_File_Dir_List_Cb)(const char *name, const char *path, void *data); typedef Eina_Bool (*Eina_File_Copy_Progress)(void *data, unsigned long long done, unsigned long long total); typedef enum { EINA_FILE_UNKNOWN, EINA_FILE_FIFO, EINA_FILE_CHR, EINA_FILE_DIR, EINA_FILE_BLK, EINA_FILE_REG, EINA_FILE_LNK, EINA_FILE_SOCK, EINA_FILE_WHT } Eina_File_Type; typedef struct _Eina_File Eina_File; typedef enum { EINA_FILE_RANDOM, EINA_FILE_SEQUENTIAL, EINA_FILE_WILLNEED, EINA_FILE_POPULATE, EINA_FILE_DONTNEED, EINA_FILE_REMOVE } Eina_File_Populate; struct _Eina_File_Direct_Info { size_t path_length; size_t name_length; size_t name_start; Eina_File_Type type; char path[8192]; }; struct _Eina_Stat { unsigned long int dev; unsigned long int ino; unsigned int mode; unsigned int nlink; unsigned int uid; unsigned int gid; unsigned long int rdev; unsigned long int size; unsigned long int blksize; unsigned long int blocks; unsigned long int atime; unsigned long int atimensec; unsigned long int mtime; unsigned long int mtimensec; unsigned long int ctime; unsigned long int ctimensec; }; struct _Eina_File_Line { const char *start; const char *end; unsigned int index; unsigned long long length; }; Eina_Bool eina_file_dir_list(const char *dir, Eina_Bool recursive, Eina_File_Dir_List_Cb cb, void *data); Eina_Iterator *eina_file_ls(const char *dir); Eina_Iterator *eina_file_stat_ls(const char *dir); int eina_file_statat(void *container, Eina_File_Direct_Info *info, Eina_Stat *buf); Eina_Iterator *eina_file_direct_ls(const char *dir); char *eina_file_path_sanitize(const char *path); typedef enum { EINA_FILE_COPY_DATA = 0, EINA_FILE_COPY_PERMISSION = (1 << 0), EINA_FILE_COPY_XATTR = (1 << 1) } Eina_File_Copy_Flags; Eina_Bool eina_file_copy(const char *src, const char *dst, Eina_File_Copy_Flags flags, Eina_File_Copy_Progress cb, const void *cb_data); Eina_File *eina_file_open(const char *name, Eina_Bool shared); Eina_Bool eina_file_unlink(const char *pathname); Eina_File *eina_file_virtualize(const char *virtual_name, const void *data, unsigned long long length, Eina_Bool copy); Eina_Bool eina_file_virtual(Eina_File *file); Eina_Bool eina_file_refresh(Eina_File *file); Eina_File *eina_file_dup(const Eina_File *file); void eina_file_close(Eina_File *file); size_t eina_file_size_get(const Eina_File *file); time_t eina_file_mtime_get(const Eina_File *file); const char *eina_file_filename_get(const Eina_File *file); Eina_Iterator *eina_file_xattr_get(Eina_File *file); Eina_Iterator *eina_file_xattr_value_get(Eina_File *file); void *eina_file_map_all(Eina_File *file, Eina_File_Populate rule); void *eina_file_map_new(Eina_File *file, Eina_File_Populate rule, unsigned long int offset, unsigned long int length); void eina_file_map_free(Eina_File *file, void *map); void eina_file_map_populate(Eina_File *file, Eina_File_Populate rule, const void *map, unsigned long int offset, unsigned long int length); Eina_Iterator *eina_file_map_lines(Eina_File *file); Eina_Bool eina_file_map_faulted(Eina_File *file, void *map); void eina_stringshare_del (const char *str); int eina_stringshare_strlen(const char *str); char *strerror(int); void free(void*); ]] local cutil = require("cutil") local util = require("util") local Object = util.Object local M = {} local eina local init = function() eina = util.lib_load("eina") end local shutdown = function() util.lib_unload("eina") end cutil.init_module(init, shutdown) M.dir_list = function(dir, recursive, cb) if not cb or not dir then return false end local cbp = ffi.cast("Eina_File_Dir_List_Cb", function(name, path, data) return cb(name, path) end) local v = eina.eina_file_dir_list(dir, recursive or false, cbp, nil) cbp:free() return v ~= 0 end local Iterator = iterator.Iterator local Ls_Iterator = Iterator:clone { __ctor = function(self, selfmt, dir) return Iterator.__ctor(self, selfmt, eina.eina_file_ls(dir)) end, next = function(self) local v = Iterator.next(self) if not v then return nil end local r = ffi.string(v, eina.eina_stringshare_strlen(v)) eina.eina_stringshare_del(v) return r end } M.ls = function(dir) return Ls_Iterator(dir) end local file_type_map = { [C.EINA_FILE_UNKNOWN] = "unknown", [C.EINA_FILE_FIFO] = "fifo", [C.EINA_FILE_CHR] = "chr", [C.EINA_FILE_DIR] = "dir", [C.EINA_FILE_BLK] = "blk", [C.EINA_FILE_REG] = "reg", [C.EINA_FILE_LNK] = "lnk", [C.EINA_FILE_SOCK] = "sock", [C.EINA_FILE_WHT] = "wht", } local Direct_Info = Object:clone { __ctor = function(self, path, name_start, name_length, tp) self.path = path self.name_start = name_start self.name_length = name_length self.type = tp end, statat = function(self, container) if not container then return false, "invalid container" end local info = ffi.new("Eina_File_Direct_Info", #self.path, self.name_length, self.name_start - 1, C["EINA_FILE_" .. self.type:upper()], self.path) local buf = ffi.new("Eina_Stat") if eina.eina_file_statat(container, info, buf) ~= 0 then return false, ffi.string(C.strerror(ffi.errno())) end return buf end } local direct_info_iterator_next = function(self) local v = Iterator.next(self) if not v then return nil end local s = ffi.cast("Eina_File_Direct_Info*", v) local path = ffi.string(s.path, s.path_length) local ns = tonumber(s.name_start) local nl = tonumber(s.name_length) local tp = file_type_map[s.type] return Direct_Info(path, ns, nl, tp), self:container_get() end local Stat_Ls_Iterator = Iterator:clone { __ctor = function(self, selfmt, dir) return Iterator.__ctor(self, selfmt, eina.eina_file_stat_ls(dir)) end, next = direct_info_iterator_next } M.stat_ls = function(dir) return Stat_Ls_Iterator(dir) end local Direct_Ls_Iterator = Iterator:clone { __ctor = function(self, selfmt, dir) return Iterator.__ctor(self, selfmt, eina.eina_file_direct_ls(dir)) end, next = direct_info_iterator_next } M.direct_ls = function(dir) return Direct_Ls_Iterator(dir) end M.path_sanitize = function(path) local v = eina.eina_file_path_sanitize(path) if v == ffi.nullptr then return nil end local r = ffi.string(v) C.free(v) return r end M.copy_flags = { DATA = 0, PERMISION = 1, XATTR = 2 } M.copy = function(source, destination, flags, cb) if not source or not destination then return false end flags = flags or 0 local cbp if cb then cbp = ffi.cast("Eina_File_Copy_Progress", function(data, done, total) return not not cb(done, total) end) end local v = eina.eina_file_copy(source, destination, flags, cbp, nil) if cbp then cbp:free() end return v ~= 0 end local Xattr_Iterator = Iterator:clone { __ctor = function(self, selfmt, file) return Iterator.__ctor(self, selfmt, eina.eina_file_xattr_get(file)) end, next = function(self) local v = Iterator.next(self) if not v then return nil end return ffi.string(v) end } local Xattr_Value_Iterator = Iterator:clone { __ctor = function(self, selfmt, file) return Iterator.__ctor(self, selfmt, eina.eina_file_xattr_value_get(file)) end, next = function(self) local v = Iterator.next(self) if not v then return nil end v = ffi.cast(v, "Eina_Xattr*") return ffi.string(v.name), ffi.string(v.value, v.length) end } M.populate = { RANDOM = 0, SEQUENTIAL = 1, WILLNEED = 2, POPULATE = 3, DONTNEED = 4, REMOVE = 5 } local Line_Iterator = Iterator:clone { __ctor = function(self, selfmt, file) return Iterator.__ctor(self, selfmt, eina.eina_file_map_lines(file)) end, next = function(self) local v = Iterator.next(self) if not v then return nil end v = ffi.cast(v, "Eina_File_Line*") return ffi.string(v.start, v.length), tonumber(v.index) end } M.File = ffi.metatype("Eina_File", { __new = function(self, name, shared) return self.open(name, shared) end, __len = function(self) return self:size_get() end, __index = { open = function(name, shared) return eina.eina_file_open(name, shared) end, unlink = function(self) return eina.eina_file_unlink(pathname) end, virtualize = function(vname, data, length, copy) return eina.eina_file_virtualize(vname, data, length, copy or false) end, close = function(self) return eina.eina_file_close(self) end, dup = function(self) return eina.eina_file_dup(self) end, is_virtual = function(self) return eina.eina_file_virtual(self) ~= 0 end, refresh = function(self) return eina.eina_file_refresh(self) ~= 0 end, size_get = function(self) return tonumber(eina.eina_file_size_get(self)) end, mtime_get = function(self) return tonumber(eina.eina_file_mtime_get(self)) end, filename_get = function(self) return ffi.string(eina.eina_file_filename_get(self)) end, xattr_get = function(self) return Xattr_Iterator(self) end, xattr_value_get = function(self) Xattr_Value_Iterator(self) end, map_all = function(self, rule, raw) local v = ffi.cast("char*", eina.eina_file_map_all(self, rule or 0)) if v == ffi.nullptr then return nil end if not raw then local r = ffi.string(v) self:map_free(v) return r end return v end, map_new = function(self, rule, offset, length, raw) local v = ffi.cast("char*", eina.eina_file_map_new(self, rule or 0, offset or 0, length)) if v == ffi.nullptr then return nil end if not raw then local r = ffi.string(v, length) self:map_free(v) return r end return v end, map_free = function(self, map) return eina.eina_file_map_free(self, map) end, map_populate = function(self, rule, map, offset, length) return eina.eina_file_map_populate(self, rule or 0, offset or 0, length) end, map_faulted = function(self, map) return eina.eina_file_map_faulted(self, map) ~= 0 end, lines = function(self) return Line_Iterator(self) end } }) return M