Skip to content

Commit

Permalink
Merge pull request #8 from rrthomas/master
Browse files Browse the repository at this point in the history
New lfs.link and other goodies
  • Loading branch information
mascarenhas committed Jun 9, 2011
2 parents d292b32 + 83faa7e commit 149e0fb
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 58 deletions.
17 changes: 12 additions & 5 deletions doc/us/manual.html
Expand Up @@ -174,7 +174,7 @@ <h2><a name="reference"></a>Reference</h2>

<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/>
Expand Down Expand Up @@ -206,6 +206,13 @@ <h2><a name="reference"></a>Reference</h2>
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
Expand All @@ -221,15 +228,15 @@ <h2><a name="reference"></a>Reference</h2>

<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>
Expand Down
2 changes: 2 additions & 0 deletions src/.gitignore
@@ -0,0 +1,2 @@
*.o
*.so
101 changes: 66 additions & 35 deletions src/lfs.c
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}

Expand All @@ -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");
Expand Down Expand Up @@ -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


/*
Expand All @@ -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},
Expand Down
35 changes: 17 additions & 18 deletions 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"
Expand Down Expand Up @@ -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))
Expand Down

0 comments on commit 149e0fb

Please sign in to comment.