diff --git a/doc/us/manual.html b/doc/us/manual.html index 217c249..996dc1f 100644 --- a/doc/us/manual.html +++ b/doc/us/manual.html @@ -174,7 +174,7 @@

Reference

lfs.lock_dir(path, [seconds_stale])
Creates a lockfile (called lockfile.lfs) in path if it does not - exist and returns the lock. If the lock already exists checks it + exist and returns the lock. If the lock already exists checks if it's stale, using the second parameter (default for the second parameter is INT_MAX, which in practice means the lock will never be stale. To free the the lock call lock:free().
@@ -206,6 +206,13 @@

Reference

Returns true if the operation was successful; in case of error, it returns nil plus an error string.
+ +
lfs.link (old, new[, symlink])
+
Creates a link. The first argument is the object to link to + and the second is the name of the link. If the optional third + argument is true, the link will by a symbolic link (by default, a + hard link is created). +
lfs.mkdir (dirname)
Creates a new directory. The argument is the name of the new @@ -221,15 +228,15 @@

Reference

lfs.setmode (file, mode)
Sets the writing mode for a file. The mode string can be either binary or text. - Returns the previous mode string for the file. This function is only available in Windows, so you may want to make sure that - lfs.setmode exists before using it. + Returns the previous mode string for the file. On non-Windows platforms, where the two modes are identical, + setting the mode has no effect, and the mode is always returned as binary.
lfs.symlinkattributes (filepath [, aname])
Identical to lfs.attributes except that it obtains information about the link itself (not the file it refers to). - This function is not available in Windows so you may want to make sure that - lfs.symlinkattributes exists before using it. + On Windows this function does not yet support links, and is identical to + lfs.attributes.
lfs.touch (filepath [, atime [, mtime]])
diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..9d22eb4 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,2 @@ +*.o +*.so diff --git a/src/lfs.c b/src/lfs.c index 8e94d4f..e95dcab 100644 --- a/src/lfs.c +++ b/src/lfs.c @@ -96,16 +96,39 @@ typedef struct dir_data { #define STAT_STRUCT struct _stati64 #endif #define STAT_FUNC _stati64 +#define LSTAT_FUNC STAT_FUNC #else #define _O_TEXT 0 #define _O_BINARY 0 -#define lfs_setmode(L,file,m) ((void)((void)file,m), \ - luaL_error(L, LUA_QL("setmode") " not supported on this platform"), -1) +#define lfs_setmode(L,file,m) 0 #define STAT_STRUCT struct stat #define STAT_FUNC stat #define LSTAT_FUNC lstat #endif +/* +** Utility functions +*/ +static int pusherror(lua_State *L, const char *info) +{ + lua_pushnil(L); + if (info==NULL) + lua_pushstring(L, strerror(errno)); + else + lua_pushfstring(L, "%s: %s", info, strerror(errno)); + lua_pushinteger(L, errno); + return 3; +} + +static int pushresult(lua_State *L, int i, const char *info) +{ + if (i==-1) + return pusherror(L, info); + lua_pushinteger(L, i); + return 1; +} + + /* ** This function changes the working (current) directory */ @@ -280,10 +303,9 @@ static int lfs_unlock_dir(lua_State *L) { } #endif -#ifdef _WIN32 static int lfs_g_setmode (lua_State *L, FILE *f, int arg) { - static const int mode[] = {_O_TEXT, _O_BINARY}; - static const char *const modenames[] = {"text", "binary", NULL}; + static const int mode[] = {_O_BINARY, _O_TEXT}; + static const char *const modenames[] = {"binary", "text", NULL}; int op = luaL_checkoption(L, arg, NULL, modenames); int res = lfs_setmode(L, f, mode[op]); if (res != -1) { @@ -306,13 +328,6 @@ static int lfs_g_setmode (lua_State *L, FILE *f, int arg) { return 3; } } -#else -static int lfs_g_setmode (lua_State *L, FILE *f, int arg) { - lua_pushboolean(L, 0); - lua_pushliteral(L, "setmode not supported on this platform"); - return 2; -} -#endif static int lfs_f_setmode(lua_State *L) { return lfs_g_setmode(L, check_file(L, 1, "setmode"), 2); @@ -362,6 +377,29 @@ static int file_unlock (lua_State *L) { } +/* +** Creates a link. +** @param #1 Object to link to. +** @param #2 Name of link. +** @param #3 True if link is symbolic (optional). +*/ +static int make_link(lua_State *L) +{ +#ifndef _WIN32 + const char *oldpath = luaL_checkstring(L, 1); + const char *newpath = luaL_checkstring(L, 2); + return pushresult(L, + (lua_toboolean(L,3) ? symlink : link)(oldpath, newpath), NULL); +#else + pusherror(L, "make_link is not supported on Windows"); +#endif +} + + +/* +** Creates a directory. +** @param #1 Directory path. +*/ static int make_dir (lua_State *L) { const char *path = luaL_checkstring (L, 1); int fail; @@ -473,21 +511,19 @@ static int dir_iter_factory (lua_State *L) { dir_data *d; lua_pushcfunction (L, dir_iter); d = (dir_data *) lua_newuserdata (L, sizeof(dir_data)); + luaL_getmetatable (L, DIR_METATABLE); + lua_setmetatable (L, -2); d->closed = 0; #ifdef _WIN32 d->hFile = 0L; - luaL_getmetatable (L, DIR_METATABLE); - lua_setmetatable (L, -2); if (strlen(path) > MAX_PATH-2) luaL_error (L, "path too long: %s", path); else sprintf (d->pattern, "%s/*", path); #else - luaL_getmetatable (L, DIR_METATABLE); - lua_setmetatable (L, -2); d->dir = opendir (path); if (d->dir == NULL) - luaL_error (L, "cannot open %s: %s", path, strerror (errno)); + luaL_error (L, "cannot open %s: %s", path, strerror (errno)); #endif return 2; } @@ -498,19 +534,18 @@ static int dir_iter_factory (lua_State *L) { */ static int dir_create_meta (lua_State *L) { luaL_newmetatable (L, DIR_METATABLE); - /* set its __gc field */ - lua_pushstring (L, "__index"); + + /* Method table */ lua_newtable(L); - lua_pushstring (L, "next"); lua_pushcfunction (L, dir_iter); - lua_settable(L, -3); - lua_pushstring (L, "close"); + lua_setfield(L, -2, "next"); lua_pushcfunction (L, dir_close); - lua_settable(L, -3); - lua_settable (L, -3); - lua_pushstring (L, "__gc"); + lua_setfield(L, -2, "close"); + + /* Metamethods */ + lua_setfield(L, -2, "__index"); lua_pushcfunction (L, dir_close); - lua_settable (L, -3); + lua_setfield (L, -2, "__gc"); return 1; } @@ -519,10 +554,13 @@ static int dir_create_meta (lua_State *L) { */ static int lock_create_meta (lua_State *L) { luaL_newmetatable (L, LOCK_METATABLE); - /* set its __gc field */ + + /* Method table */ lua_newtable(L); lua_pushcfunction(L, lfs_unlock_dir); lua_setfield(L, -2, "free"); + + /* Metamethods */ lua_setfield(L, -2, "__index"); lua_pushcfunction(L, lfs_unlock_dir); lua_setfield(L, -2, "__gc"); @@ -743,17 +781,9 @@ static int file_info (lua_State *L) { /* ** Get symbolic link information using lstat. */ -#ifndef _WIN32 static int link_info (lua_State *L) { return _file_info_ (L, LSTAT_FUNC); } -#else -static int link_info (lua_State *L) { - lua_pushboolean(L, 0); - lua_pushliteral(L, "symlinkattributes not supported on this platform"); - return 2; -} -#endif /* @@ -777,6 +807,7 @@ static const struct luaL_Reg fslib[] = { {"chdir", change_dir}, {"currentdir", get_dir}, {"dir", dir_iter_factory}, + {"link", make_link}, {"lock", file_lock}, {"mkdir", make_dir}, {"rmdir", remove_dir}, diff --git a/tests/test.lua b/tests/test.lua index 7111074..c4911c9 100644 --- a/tests/test.lua +++ b/tests/test.lua @@ -1,7 +1,7 @@ -#!/usr/local/bin/lua5.1 +#!/usr/bin/env lua5.1 local tmp = "/tmp" -local sep = "/" +local sep = string.match (package.config, "[^\n]+") local upper = ".." require"lfs" @@ -69,24 +69,23 @@ local new_att = assert (lfs.attributes (tmpfile)) assert (new_att.access == testdate2, "could not set access time") assert (new_att.modification == testdate1, "could not set modification time") -local res, err = lfs.symlinkattributes(tmpfile) -if err ~= "symlinkattributes not supported on this platform" then - -- Checking symbolic link information (does not work in Windows) - assert (os.execute ("ln -s "..tmpfile.." _a_link_for_test_")) - assert (lfs.attributes"_a_link_for_test_".mode == "file") - assert (lfs.symlinkattributes"_a_link_for_test_".mode == "link") - assert (os.remove"_a_link_for_test_") +-- Checking link (does not work on Windows) +if lfs.link (tmpfile, "_a_link_for_test_", true) then + assert (lfs.attributes"_a_link_for_test_".mode == "file") + assert (lfs.symlinkattributes"_a_link_for_test_".mode == "link") + assert (lfs.link (tmpfile, "_a_hard_link_for_test_")) + assert (lfs.attributes (tmpfile, "nlink") == 2) + assert (os.remove"_a_link_for_test_") + assert (os.remove"_a_hard_link_for_test_") end -if lfs.setmode then - -- Checking text/binary modes (works only in Windows) - local f = io.open(tmpfile, "w") - local result, mode = lfs.setmode(f, "binary") - assert((result and mode == "text") or (not result and mode == "setmode not supported on this platform")) - result, mode = lfs.setmode(f, "text") - assert((result and mode == "binary") or (not result and mode == "setmode not supported on this platform")) - f:close() -end +-- Checking text/binary modes (only has an effect in Windows) +local f = io.open(tmpfile, "w") +local result, mode = lfs.setmode(f, "binary") +assert(result) -- on non-Windows platforms, mode is always returned as "binary" +result, mode = lfs.setmode(f, "text") +assert(result and mode == "binary") +f:close() -- Restore access time to current value assert (lfs.touch (tmpfile, attrib.access, attrib.modification))