Merge pull request #8 from rrthomas/master

New lfs.link and other goodies
This commit is contained in:
Fabio Mascarenhas
2011-06-09 14:09:31 -07:00
4 changed files with 97 additions and 58 deletions

View File

@@ -174,7 +174,7 @@ LuaFileSystem offers the following functions:
<dt><a name="chdir"></a><strong><code>lfs.lock_dir(path, [seconds_stale])</code></strong></dt>
<dd>Creates a lockfile (called lockfile.lfs) in <code>path</code> 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 <code>INT_MAX</code>, which in practice means the lock will never
be stale. To free the the lock call <code>lock:free()</code>. <br/>
@@ -206,6 +206,13 @@ LuaFileSystem offers the following functions:
Returns <code>true</code> if the operation was successful; in
case of error, it returns <code>nil</code> plus an error string.
</dd>
<dt><a name="link"></a><strong><code>lfs.link (old, new[, symlink])</code></strong></dt>
<dd>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).
</dd>
<dt><a name="mkdir"></a><strong><code>lfs.mkdir (dirname)</code></strong></dt>
<dd>Creates a new directory. The argument is the name of the new
@@ -221,15 +228,15 @@ LuaFileSystem offers the following functions:
<dt><a name="setmode"></a><strong><code>lfs.setmode (file, mode)</code></strong></dt>
<dd>Sets the writing mode for a file. The mode string can be either <code>binary</code> or <code>text</code>.
Returns the previous mode string for the file. This function is only available in Windows, so you may want to make sure that
<code>lfs.setmode</code> 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 <code>binary</code>.
</dd>
<dt><a name="symlinkattributes"></a><strong><code>lfs.symlinkattributes (filepath [, aname])</code></strong></dt>
<dd>Identical to <a href="#attributes">lfs.attributes</a> 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
<code>lfs.symlinkattributes</code> exists before using it.
On Windows this function does not yet support links, and is identical to
<code>lfs.attributes</code>.
</dd>
<dt><a name="touch"></a><strong><code>lfs.touch (filepath [, atime [, mtime]])</code></strong></dt>

2
src/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*.o
*.so

101
src/lfs.c
View File

@@ -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},

View File

@@ -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))