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> <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 <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 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 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/> 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 Returns <code>true</code> if the operation was successful; in
case of error, it returns <code>nil</code> plus an error string. case of error, it returns <code>nil</code> plus an error string.
</dd> </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> <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 <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> <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>. <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 Returns the previous mode string for the file. On non-Windows platforms, where the two modes are identical,
<code>lfs.setmode</code> exists before using it. setting the mode has no effect, and the mode is always returned as <code>binary</code>.
</dd> </dd>
<dt><a name="symlinkattributes"></a><strong><code>lfs.symlinkattributes (filepath [, aname])</code></strong></dt> <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 <dd>Identical to <a href="#attributes">lfs.attributes</a> except that
it obtains information about the link itself (not the file it refers to). 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 On Windows this function does not yet support links, and is identical to
<code>lfs.symlinkattributes</code> exists before using it. <code>lfs.attributes</code>.
</dd> </dd>
<dt><a name="touch"></a><strong><code>lfs.touch (filepath [, atime [, mtime]])</code></strong></dt> <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 #define STAT_STRUCT struct _stati64
#endif #endif
#define STAT_FUNC _stati64 #define STAT_FUNC _stati64
#define LSTAT_FUNC STAT_FUNC
#else #else
#define _O_TEXT 0 #define _O_TEXT 0
#define _O_BINARY 0 #define _O_BINARY 0
#define lfs_setmode(L,file,m) ((void)((void)file,m), \ #define lfs_setmode(L,file,m) 0
luaL_error(L, LUA_QL("setmode") " not supported on this platform"), -1)
#define STAT_STRUCT struct stat #define STAT_STRUCT struct stat
#define STAT_FUNC stat #define STAT_FUNC stat
#define LSTAT_FUNC lstat #define LSTAT_FUNC lstat
#endif #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 ** This function changes the working (current) directory
*/ */
@@ -280,10 +303,9 @@ static int lfs_unlock_dir(lua_State *L) {
} }
#endif #endif
#ifdef _WIN32
static int lfs_g_setmode (lua_State *L, FILE *f, int arg) { static int lfs_g_setmode (lua_State *L, FILE *f, int arg) {
static const int mode[] = {_O_TEXT, _O_BINARY}; static const int mode[] = {_O_BINARY, _O_TEXT};
static const char *const modenames[] = {"text", "binary", NULL}; static const char *const modenames[] = {"binary", "text", NULL};
int op = luaL_checkoption(L, arg, NULL, modenames); int op = luaL_checkoption(L, arg, NULL, modenames);
int res = lfs_setmode(L, f, mode[op]); int res = lfs_setmode(L, f, mode[op]);
if (res != -1) { if (res != -1) {
@@ -306,13 +328,6 @@ static int lfs_g_setmode (lua_State *L, FILE *f, int arg) {
return 3; 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) { static int lfs_f_setmode(lua_State *L) {
return lfs_g_setmode(L, check_file(L, 1, "setmode"), 2); 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) { static int make_dir (lua_State *L) {
const char *path = luaL_checkstring (L, 1); const char *path = luaL_checkstring (L, 1);
int fail; int fail;
@@ -473,21 +511,19 @@ static int dir_iter_factory (lua_State *L) {
dir_data *d; dir_data *d;
lua_pushcfunction (L, dir_iter); lua_pushcfunction (L, dir_iter);
d = (dir_data *) lua_newuserdata (L, sizeof(dir_data)); d = (dir_data *) lua_newuserdata (L, sizeof(dir_data));
luaL_getmetatable (L, DIR_METATABLE);
lua_setmetatable (L, -2);
d->closed = 0; d->closed = 0;
#ifdef _WIN32 #ifdef _WIN32
d->hFile = 0L; d->hFile = 0L;
luaL_getmetatable (L, DIR_METATABLE);
lua_setmetatable (L, -2);
if (strlen(path) > MAX_PATH-2) if (strlen(path) > MAX_PATH-2)
luaL_error (L, "path too long: %s", path); luaL_error (L, "path too long: %s", path);
else else
sprintf (d->pattern, "%s/*", path); sprintf (d->pattern, "%s/*", path);
#else #else
luaL_getmetatable (L, DIR_METATABLE);
lua_setmetatable (L, -2);
d->dir = opendir (path); d->dir = opendir (path);
if (d->dir == NULL) 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 #endif
return 2; return 2;
} }
@@ -498,19 +534,18 @@ static int dir_iter_factory (lua_State *L) {
*/ */
static int dir_create_meta (lua_State *L) { static int dir_create_meta (lua_State *L) {
luaL_newmetatable (L, DIR_METATABLE); luaL_newmetatable (L, DIR_METATABLE);
/* set its __gc field */
lua_pushstring (L, "__index"); /* Method table */
lua_newtable(L); lua_newtable(L);
lua_pushstring (L, "next");
lua_pushcfunction (L, dir_iter); lua_pushcfunction (L, dir_iter);
lua_settable(L, -3); lua_setfield(L, -2, "next");
lua_pushstring (L, "close");
lua_pushcfunction (L, dir_close); lua_pushcfunction (L, dir_close);
lua_settable(L, -3); lua_setfield(L, -2, "close");
lua_settable (L, -3);
lua_pushstring (L, "__gc"); /* Metamethods */
lua_setfield(L, -2, "__index");
lua_pushcfunction (L, dir_close); lua_pushcfunction (L, dir_close);
lua_settable (L, -3); lua_setfield (L, -2, "__gc");
return 1; return 1;
} }
@@ -519,10 +554,13 @@ static int dir_create_meta (lua_State *L) {
*/ */
static int lock_create_meta (lua_State *L) { static int lock_create_meta (lua_State *L) {
luaL_newmetatable (L, LOCK_METATABLE); luaL_newmetatable (L, LOCK_METATABLE);
/* set its __gc field */
/* Method table */
lua_newtable(L); lua_newtable(L);
lua_pushcfunction(L, lfs_unlock_dir); lua_pushcfunction(L, lfs_unlock_dir);
lua_setfield(L, -2, "free"); lua_setfield(L, -2, "free");
/* Metamethods */
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
lua_pushcfunction(L, lfs_unlock_dir); lua_pushcfunction(L, lfs_unlock_dir);
lua_setfield(L, -2, "__gc"); lua_setfield(L, -2, "__gc");
@@ -743,17 +781,9 @@ static int file_info (lua_State *L) {
/* /*
** Get symbolic link information using lstat. ** Get symbolic link information using lstat.
*/ */
#ifndef _WIN32
static int link_info (lua_State *L) { static int link_info (lua_State *L) {
return _file_info_ (L, LSTAT_FUNC); 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}, {"chdir", change_dir},
{"currentdir", get_dir}, {"currentdir", get_dir},
{"dir", dir_iter_factory}, {"dir", dir_iter_factory},
{"link", make_link},
{"lock", file_lock}, {"lock", file_lock},
{"mkdir", make_dir}, {"mkdir", make_dir},
{"rmdir", remove_dir}, {"rmdir", remove_dir},

View File

@@ -1,7 +1,7 @@
#!/usr/local/bin/lua5.1 #!/usr/bin/env lua5.1
local tmp = "/tmp" local tmp = "/tmp"
local sep = "/" local sep = string.match (package.config, "[^\n]+")
local upper = ".." local upper = ".."
require"lfs" 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.access == testdate2, "could not set access time")
assert (new_att.modification == testdate1, "could not set modification time") assert (new_att.modification == testdate1, "could not set modification time")
local res, err = lfs.symlinkattributes(tmpfile) -- Checking link (does not work on Windows)
if err ~= "symlinkattributes not supported on this platform" then if lfs.link (tmpfile, "_a_link_for_test_", true) then
-- Checking symbolic link information (does not work in Windows) assert (lfs.attributes"_a_link_for_test_".mode == "file")
assert (os.execute ("ln -s "..tmpfile.." _a_link_for_test_")) assert (lfs.symlinkattributes"_a_link_for_test_".mode == "link")
assert (lfs.attributes"_a_link_for_test_".mode == "file") assert (lfs.link (tmpfile, "_a_hard_link_for_test_"))
assert (lfs.symlinkattributes"_a_link_for_test_".mode == "link") assert (lfs.attributes (tmpfile, "nlink") == 2)
assert (os.remove"_a_link_for_test_") assert (os.remove"_a_link_for_test_")
assert (os.remove"_a_hard_link_for_test_")
end end
if lfs.setmode then -- Checking text/binary modes (only has an effect in Windows)
-- Checking text/binary modes (works only in Windows) local f = io.open(tmpfile, "w")
local f = io.open(tmpfile, "w") local result, mode = lfs.setmode(f, "binary")
local result, mode = lfs.setmode(f, "binary") assert(result) -- on non-Windows platforms, mode is always returned as "binary"
assert((result and mode == "text") or (not result and mode == "setmode not supported on this platform")) result, mode = lfs.setmode(f, "text")
result, mode = lfs.setmode(f, "text") assert(result and mode == "binary")
assert((result and mode == "binary") or (not result and mode == "setmode not supported on this platform")) f:close()
f:close()
end
-- Restore access time to current value -- Restore access time to current value
assert (lfs.touch (tmpfile, attrib.access, attrib.modification)) assert (lfs.touch (tmpfile, attrib.access, attrib.modification))