25 Commits

Author SHA1 Message Date
Hisham Muhammad
7c6e1b013c Release 1.8.0 2020-04-22 22:16:42 -03:00
Hisham Muhammad
68c624c686 It does work on Windows now! 2020-04-22 22:12:23 -03:00
Hisham Muhammad
41e59da31b update copyrights 2020-04-22 22:09:38 -03:00
Hisham Muhammad
842505b6a3 Lua 5.4: use __close to close dir if you break the iterator 2020-04-22 11:30:28 -03:00
Hisham Muhammad
3e879ffba1 indent -kr -nut -i2 src/lfs.c src/lfs.h 2020-04-22 11:30:28 -03:00
Hisham Muhammad
4f7e1b5a49 Makefile: make it easier to switch Lua versions 2020-04-21 18:41:55 -03:00
云风
a5336d294d Use CREATE_ALWAYS instead of CREATE_NEW 2020-04-21 18:36:43 -03:00
Hisham Muhammad
6048863a96 tests: behavior test for hard links
Also check nlink on Unix only
and test if something is a symlink
2020-04-21 13:45:50 -03:00
Hisham Muhammad
1a61e5284d win32: strip UNC prefix if present 2020-04-21 13:45:50 -03:00
Hisham Muhammad
7cb7d86dc4 win32 lstat: if it's not a link, just do stat 2020-04-21 13:45:50 -03:00
Hisham Muhammad
94700f7c18 win32: obtain symlink attributes 2020-04-21 13:45:50 -03:00
Eroica
53d2acc517 Add Windows compatibility for lfs.link
Co-Authored-By: Hisham Muhammad <hisham@gobolinux.org>
2020-04-21 13:45:50 -03:00
Hisham Muhammad
6b11508ea9 tests: drop LuaJIT 2.0 from test matrix 2020-04-21 13:45:50 -03:00
Joshua Root
58cf8c9449 Make MACOSX_DEPLOYMENT_TARGET configurable
Also increase the default target to 10.5, since Xcode 10 can no longer
target 10.3.
2020-04-20 21:36:11 -03:00
Peter Melnichenko
04ba8d686a Support Lua 5.4 2020-04-20 18:50:38 -03:00
James McCoy
04bdaf9a1e Fallback to _POSIX_PATH_MAX when MAXPATHLEN isn't available (#130)
On systems where MAXPATHLEN isn't defined, like GNU/Hurd, use
_POSIX_PATH_MAX as the starting size for the getcwd() buffer.
2019-10-29 16:08:55 -04:00
Peter Melnichenko
1dfb8c41e8 Replace rockspecs/ with a single scm rockspec (#108)
There is no need to keep rockspecs for older versions - it's enough
to ensure that `luarocks make` builds currently checked out version.

`luarocks new-version <rockspec> <version> --tag=<tag>` generates
rockspecs for releases.

Use `scm` instead of `dev` as LuaRocks 2 thinks that `dev` versions
are less than normal versions like 1.6.3, making it tricky to
use bleeding-edge version as a dependency with a constraint
such as `luafilesystem >= 1.6.3`.
2018-03-15 20:38:32 -03:00
TsT
37d8524e7e lfs.attributes and lfs.symlinkattributes arguments renamed s/aname/request_name/ s/atable/result_table/ (#106) 2017-12-14 18:12:18 -02:00
Kıvanç Çakmak
e5f06c270a added extra include-dir to compile in ubuntu (#103) 2017-11-29 20:12:28 -02:00
Hisham Muhammad
884b52a3b2 Fix memory leak in case of realloc failure. (#102)
Fixes #101.
2017-11-27 14:03:38 -02:00
Hisham Muhammad
1b5073419f Merge branch 'master' of https://github.com/keplerproject/luafilesystem 2017-11-26 16:44:49 -02:00
Stephen E. Baker
fe964e013d Update version in lfs.def (#96)
Version number of current release is 1.7
2017-10-08 17:03:08 -03:00
Dan Church
12d1692f14 Support DESTDIR make install option (#98)
Useful for packagers to specify a build jail to install into.
2017-10-08 17:01:53 -03:00
Hisham Muhammad
de87218e97 Add rockspec for hotfix. 2017-09-15 20:07:33 -03:00
Hisham Muhammad
a23cadf009 Fix _VERSION entry
Thanks Milind Gupta for noting!
2017-09-15 20:04:43 -03:00
28 changed files with 837 additions and 994 deletions

View File

@@ -6,7 +6,6 @@ env:
- LUA="lua 5.1"
- LUA="lua 5.2"
- LUA="lua 5.3"
- LUA="luajit 2.0"
- LUA="luajit 2.1"
before_install:
@@ -20,7 +19,7 @@ before_install:
- luarocks install luacov-coveralls --server=https://luarocks.org/dev --deps-mode=none
install:
- luarocks make rockspecs/luafilesystem-cvs-3.rockspec CFLAGS="-O2 -fPIC -ftest-coverage -fprofile-arcs" LIBFLAG="-shared --coverage"
- luarocks make CFLAGS="-O2 -fPIC -ftest-coverage -fprofile-arcs" LIBFLAG="-shared --coverage"
script:
- lua -lluacov tests/test.lua

View File

@@ -12,14 +12,14 @@ OBJS= src/$T.o
lib: src/lfs.so
src/lfs.so: $(OBJS)
MACOSX_DEPLOYMENT_TARGET="10.3"; export MACOSX_DEPLOYMENT_TARGET; $(CC) $(LIB_OPTION) -o src/lfs.so $(OBJS)
MACOSX_DEPLOYMENT_TARGET=$(MACOSX_DEPLOYMENT_TARGET); export MACOSX_DEPLOYMENT_TARGET; $(CC) $(LIB_OPTION) -o src/lfs.so $(OBJS)
test: lib
LUA_CPATH=./src/?.so lua tests/test.lua
install:
mkdir -p $(LUA_LIBDIR)
cp src/lfs.so $(LUA_LIBDIR)
mkdir -p $(DESTDIR)$(LUA_LIBDIR)
cp src/lfs.so $(DESTDIR)$(LUA_LIBDIR)
clean:
rm -f src/lfs.so $(OBJS)

View File

@@ -5,7 +5,7 @@
# LuaFileSystem - File System Library for Lua
Copyright 2003-2017 Kepler Project
Copyright 2003-2020 Kepler Project
https://keplerproject.github.io/luafilesystem

View File

@@ -11,7 +11,6 @@ environment:
- LUA: "lua 5.1"
- LUA: "lua 5.2 --compat none"
- LUA: "lua 5.3 --compat none"
- LUA: "luajit 2.0"
- LUA: "luajit 2.1"
# Abuse this section so we can have a matrix with different Compiler versions
@@ -30,7 +29,7 @@ before_build:
- echo "Installing external deps"
build_script:
- luarocks make rockspecs/luafilesystem-cvs-3.rockspec
- luarocks make
before_test:

12
config
View File

@@ -3,21 +3,25 @@
# Default installation prefix
PREFIX=/usr/local
LUA_VERSION = 5.1
# System's libraries directory (where binary libraries are installed)
LUA_LIBDIR= $(PREFIX)/lib/lua/5.1
LUA_LIBDIR= $(PREFIX)/lib/lua/$(LUA_VERSION)
# Lua includes directory
LUA_INC= $(PREFIX)/include
LUA_INC += -I$(PREFIX)/include
LUA_INC += -I/usr/include/lua$(LUA_VERSION) -I/usr/include/lua/$(LUA_VERSION)
# OS dependent
LIB_OPTION= -shared #for Linux
#LIB_OPTION= -bundle -undefined dynamic_lookup #for MacOS X
LIBNAME= $T.so.$V
# Minimum runtime OS version on macOS
MACOSX_DEPLOYMENT_TARGET= 10.5
# Compilation directives
WARN= -O2 -Wall -fPIC -W -Waggregate-return -Wcast-align -Wmissing-prototypes -Wnested-externs -Wshadow -Wwrite-strings -pedantic
INCS= -I$(LUA_INC)
INCS= $(LUA_INC)
CFLAGS= $(WARN) $(INCS)
CC= gcc

View File

@@ -1,14 +1,14 @@
LUA_VERSION= 5.1
# Installation directories
# System's libraries directory (where binary libraries are installed)
LUA_LIBDIR= "c:\lua5.1"
LUA_LIBDIR= "c:\lua$(LUA_VERSION)"
# Lua includes directory
LUA_INC= "c:\lua5.1\include"
LUA_INC= "c:\lua$(LUA_VERSION)\include"
# Lua library
LUA_LIB= "c:\lua5.1\lua5.1.lib"
LIBNAME= $T.dll
LUA_LIB= "c:\lua$(LUA_VERSION)\lua$(LUA_VERSION).lib"
# Compilation directives
WARN= /O2

View File

@@ -70,7 +70,7 @@ the underlying directory structure and file attributes.</p>
<h2><a name="status"></a>Status</h2>
<p>Current version is 1.7.0. It works with Lua 5.1, 5.2 and 5.3, and it runs on various
<p>Current version is 1.8.0. It works with Lua 5.1, 5.2, 5.3 and 5.4, and it runs on various
flavors of Unix (including Linux, BSDs, macOS) and Windows.</p>
<h2><a name="download"></a>Download</h2>
@@ -86,6 +86,15 @@ $ luarocks install luafilesystem
<h2><a name="history"></a>History</h2>
<dl class="history">
<dt><strong>Version 1.8.0</strong> [22/Apr/2020]</dt>
<dd><ul>
<li>Lua 5.4 support</li>
<li>lfs.link and lfs.symlinkattributes now work on Windows</li>
<li>MACOSX_DEPLOYMENT_TARGET is configurable in the Makefile</li>
<li>Fallback to _POSIX_PATH_MAX when MAXPATHLEN is not avaliable</li>
<li>Fixed memory leak in case of realloc failure</li>
</ul></dd>
<dt><strong>Version 1.7.0</strong> [15/Sep/2017]</dt>
<dd><ul>
<li>symlinkattributes function now provides 'target' field, containing name of the file that the symlink points to.</li>

View File

@@ -84,7 +84,7 @@ Ierusalimschy, Andr&eacute; Carregal and Tom&aacute;s Guisasola.
The implementation is not derived from licensed software.</p>
<hr/>
<p>Copyright &copy; 2003 - 2017 Kepler Project.</p>
<p>Copyright &copy; 2003 - 2020 Kepler Project.</p>
<p>Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation

View File

@@ -102,15 +102,15 @@ LuaFileSystem offers the following functions:
</p>
<dl class="reference">
<dt><a name="attributes"></a><strong><code>lfs.attributes (filepath [, aname | atable])</code></strong></dt>
<dt><a name="attributes"></a><strong><code>lfs.attributes (filepath [, request_name | result_table])</code></strong></dt>
<dd>Returns a table with the file attributes corresponding to
<code>filepath</code> (or <code>nil</code> followed by an error message and a system-dependent error code
in case of error).
If the second optional argument is given and is a string, then only the value of the
named attribute is returned (this use is equivalent to
<code>lfs.attributes(filepath)[aname]</code>, but the table is not created
<code>lfs.attributes(filepath)[request_name]</code>, but the table is not created
and only one attribute is retrieved from the O.S.).
if a table is passed as the second argument, it is filled with attributes and returned instead of a new table.
if a table is passed as the second argument, it (<code>result_table</code>) is filled with attributes and returned instead of a new table.
The attributes are described as follows;
attribute <code>mode</code> is a string, all the others are numbers,
and the time related attributes use the same time reference of
@@ -239,7 +239,7 @@ LuaFileSystem offers the following functions:
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>
<dt><a name="symlinkattributes"></a><strong><code>lfs.symlinkattributes (filepath [, request_name])</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).
It also adds a <strong><code>target</code></strong> field, containing

View File

@@ -1,8 +1,7 @@
package = "LuaFileSystem"
version = "1.7.0-1"
package = "luafilesystem"
version = "scm-1"
source = {
url = "git://github.com/keplerproject/luafilesystem",
tag = "v1_7_0",
url = "git://github.com/keplerproject/luafilesystem"
}
description = {
summary = "File System Library for the Lua Programming Language",
@@ -12,7 +11,7 @@ description = {
distribution. LuaFileSystem offers a portable way to access the
underlying directory structure and file attributes.
]],
license = "MIT/X11",
license = "MIT/X11"
}
dependencies = {
"lua >= 5.1"
@@ -23,6 +22,7 @@ build = {
lfs = "src/lfs.c"
},
copy_directories = {
"doc", "tests"
"doc",
"tests"
}
}

View File

@@ -1,27 +0,0 @@
package = "LuaFileSystem"
version = "1.3.0-1"
source = {
url = "http://luaforge.net/frs/download.php/2679/luafilesystem-1.3.0.tar.gz"
}
description = {
summary = "File System Library for the Lua Programming Language",
detailed = [[
LuaFileSystem is a Lua library developed to complement the set of
functions related to file systems offered by the standard Lua
distribution. LuaFileSystem offers a portable way to access the
underlying directory structure and file attributes.
]]
}
dependencies = {
"lua >= 5.1"
}
build = {
type = "make",
build_variables = {
LUA_INC = "$(LUA_INCDIR)",
LIB_OPTION = "$(LIBFLAG)"
},
install_variables = {
LUA_LIBDIR = "$(LIBDIR)"
}
}

View File

@@ -1,27 +0,0 @@
package = "LuaFileSystem"
version = "1.4.0-1"
source = {
url = "http://luaforge.net/frs/download.php/3158/luafilesystem-1.4.0.tar.gz"
}
description = {
summary = "File System Library for the Lua Programming Language",
detailed = [[
LuaFileSystem is a Lua library developed to complement the set of
functions related to file systems offered by the standard Lua
distribution. LuaFileSystem offers a portable way to access the
underlying directory structure and file attributes.
]]
}
dependencies = {
"lua >= 5.1"
}
build = {
type = "make",
build_variables = {
LUA_INC = "$(LUA_INCDIR)",
LIB_OPTION = "$(LIBFLAG)"
},
install_variables = {
LUA_LIBDIR = "$(LIBDIR)"
}
}

View File

@@ -1,43 +0,0 @@
package = "LuaFileSystem"
version = "1.4.0-2"
source = {
url = "http://luaforge.net/frs/download.php/3158/luafilesystem-1.4.0.tar.gz"
}
description = {
summary = "File System Library for the Lua Programming Language",
detailed = [[
LuaFileSystem is a Lua library developed to complement the set of
functions related to file systems offered by the standard Lua
distribution. LuaFileSystem offers a portable way to access the
underlying directory structure and file attributes.
]]
}
dependencies = {
"lua >= 5.1"
}
build = {
platforms = {
unix = {
type = "make",
build_variables = {
LIB_OPTION = "$(LIBFLAG)",
CFLAGS = "$(CFLAGS) -I$(LUA_INCDIR)",
},
install_variables = {
LUA_LIBDIR = "$(LIBDIR)"
}
},
win32 = {
type = "make",
build_variables = {
LUA_LIB = "$(LUA_LIBDIR)\\lua5.1.lib",
CFLAGS = "/MD $(CFLAGS) /I$(LUA_INCDIR)",
},
install_variables = {
LUA_LIBDIR = "$(LIBDIR)",
LUA_DIR = "$(LUADIR)",
BIN_DIR = "$(BINDIR)"
}
}
}
}

View File

@@ -1,43 +0,0 @@
package = "LuaFileSystem"
version = "1.4.1-1"
source = {
url = "http://luaforge.net/frs/download.php/3345/luafilesystem-1.4.1.tar.gz",
}
description = {
summary = "File System Library for the Lua Programming Language",
detailed = [[
LuaFileSystem is a Lua library developed to complement the set of
functions related to file systems offered by the standard Lua
distribution. LuaFileSystem offers a portable way to access the
underlying directory structure and file attributes.
]]
}
dependencies = {
"lua >= 5.1"
}
build = {
platforms = {
unix = {
type = "make",
build_variables = {
LIB_OPTION = "$(LIBFLAG)",
CFLAGS = "$(CFLAGS) -I$(LUA_INCDIR) $(STAT64)",
},
install_variables = {
LUA_LIBDIR = "$(LIBDIR)"
}
},
win32 = {
type = "make",
build_variables = {
LUA_LIB = "$(LUA_LIBDIR)\\lua5.1.lib",
CFLAGS = "/MD $(CFLAGS) /I$(LUA_INCDIR)",
},
install_variables = {
LUA_LIBDIR = "$(LIBDIR)",
LUA_DIR = "$(LUADIR)",
BIN_DIR = "$(BINDIR)"
}
}
}
}

View File

@@ -1,43 +0,0 @@
package = "LuaFileSystem"
version = "1.4.1rc1-1"
source = {
url = "http://luafilesystem.luaforge.net/luafilesystem-1.4.1rc1.tar.gz",
}
description = {
summary = "File System Library for the Lua Programming Language",
detailed = [[
LuaFileSystem is a Lua library developed to complement the set of
functions related to file systems offered by the standard Lua
distribution. LuaFileSystem offers a portable way to access the
underlying directory structure and file attributes.
]]
}
dependencies = {
"lua >= 5.1"
}
build = {
platforms = {
unix = {
type = "make",
build_variables = {
LIB_OPTION = "$(LIBFLAG)",
CFLAGS = "$(CFLAGS) -I$(LUA_INCDIR) $(STAT64)",
},
install_variables = {
LUA_LIBDIR = "$(LIBDIR)"
}
},
win32 = {
type = "make",
build_variables = {
LUA_LIB = "$(LUA_LIBDIR)\\lua5.1.lib",
CFLAGS = "/MD $(CFLAGS) /I$(LUA_INCDIR)",
},
install_variables = {
LUA_LIBDIR = "$(LIBDIR)",
LUA_DIR = "$(LUADIR)",
BIN_DIR = "$(BINDIR)"
}
}
}
}

View File

@@ -1,26 +0,0 @@
package = "LuaFileSystem"
version = "1.4.2-1"
source = {
url = "http://luaforge.net/frs/download.php/3931/luafilesystem-1.4.2.tar.gz",
}
description = {
summary = "File System Library for the Lua Programming Language",
detailed = [[
LuaFileSystem is a Lua library developed to complement the set of
functions related to file systems offered by the standard Lua
distribution. LuaFileSystem offers a portable way to access the
underlying directory structure and file attributes.
]]
}
dependencies = {
"lua >= 5.1"
}
build = {
type = "module",
modules = { lfs = "src/lfs.c" }
}

View File

@@ -1,27 +0,0 @@
package = "LuaFileSystem"
version = "1.5.0-1"
source = {
url = "http://cloud.github.com/downloads/keplerproject/luafilesystem/luafilesystem-1.5.0.tar.gz",
}
description = {
summary = "File System Library for the Lua Programming Language",
detailed = [[
LuaFileSystem is a Lua library developed to complement the set of
functions related to file systems offered by the standard Lua
distribution. LuaFileSystem offers a portable way to access the
underlying directory structure and file attributes.
]]
}
dependencies = {
"lua >= 5.1"
}
build = {
type = "module",
modules = { lfs = "src/lfs.c" },
copy_directories = { "doc", "tests" }
}

View File

@@ -1,27 +0,0 @@
package = "LuaFileSystem"
version = "1.6.0-1"
source = {
url = "https://github.com/downloads/keplerproject/luafilesystem/luafilesystem-1.6.0.tar.gz",
}
description = {
summary = "File System Library for the Lua Programming Language",
detailed = [[
LuaFileSystem is a Lua library developed to complement the set of
functions related to file systems offered by the standard Lua
distribution. LuaFileSystem offers a portable way to access the
underlying directory structure and file attributes.
]]
}
dependencies = {
"lua >= 5.1"
}
build = {
type = "builtin",
modules = { lfs = "src/lfs.c" },
copy_directories = { "doc", "tests" }
}

View File

@@ -1,27 +0,0 @@
package = "LuaFileSystem"
version = "1.6.1-1"
source = {
url = "https://github.com/downloads/keplerproject/luafilesystem/luafilesystem-1.6.1.tar.gz",
}
description = {
summary = "File System Library for the Lua Programming Language",
detailed = [[
LuaFileSystem is a Lua library developed to complement the set of
functions related to file systems offered by the standard Lua
distribution. LuaFileSystem offers a portable way to access the
underlying directory structure and file attributes.
]]
}
dependencies = {
"lua >= 5.1"
}
build = {
type = "builtin",
modules = { lfs = "src/lfs.c" },
copy_directories = { "doc", "tests" }
}

View File

@@ -1,27 +0,0 @@
package = "LuaFileSystem"
version = "1.6.2-1"
source = {
url = "https://github.com/downloads/keplerproject/luafilesystem/luafilesystem-1.6.2.tar.gz",
}
description = {
summary = "File System Library for the Lua Programming Language",
detailed = [[
LuaFileSystem is a Lua library developed to complement the set of
functions related to file systems offered by the standard Lua
distribution. LuaFileSystem offers a portable way to access the
underlying directory structure and file attributes.
]]
}
dependencies = {
"lua >= 5.1"
}
build = {
type = "builtin",
modules = { lfs = "src/lfs.c" },
copy_directories = { "doc", "tests" }
}

View File

@@ -1,28 +0,0 @@
package = "LuaFileSystem"
version = "1.6.3-1"
source = {
url = "git://github.com/keplerproject/luafilesystem",
tag = "v_1_6_3",
}
description = {
summary = "File System Library for the Lua Programming Language",
detailed = [[
LuaFileSystem is a Lua library developed to complement the set of
functions related to file systems offered by the standard Lua
distribution. LuaFileSystem offers a portable way to access the
underlying directory structure and file attributes.
]],
license = "MIT/X11",
}
dependencies = {
"lua >= 5.1"
}
build = {
type = "builtin",
modules = {
lfs = "src/lfs.c"
},
copy_directories = {
"doc", "tests"
}
}

View File

@@ -1,44 +0,0 @@
package = "LuaFileSystem"
version = "cvs-1"
source = {
url = "cvs://:pserver:anonymous:@cvs.luaforge.net:/cvsroot/luafilesystem",
cvs_tag = "HEAD"
}
description = {
summary = "File System Library for the Lua Programming Language",
detailed = [[
LuaFileSystem is a Lua library developed to complement the set of
functions related to file systems offered by the standard Lua
distribution. LuaFileSystem offers a portable way to access the
underlying directory structure and file attributes.
]]
}
dependencies = {
"lua >= 5.1"
}
build = {
platforms = {
unix = {
type = "make",
build_variables = {
LIB_OPTION = "$(LIBFLAG)",
CFLAGS = "$(CFLAGS) -I$(LUA_INCDIR)",
},
install_variables = {
LUA_LIBDIR = "$(LIBDIR)"
}
},
win32 = {
type = "make",
build_variables = {
LUA_LIB = "$(LUA_LIBDIR)\\lua5.1.lib",
CFLAGS = "$(CFLAGS) /I$(LUA_INCDIR)",
},
install_variables = {
LUA_LIBDIR = "$(LIBDIR)",
LUA_DIR = "$(LUADIR)",
BIN_DIR = "$(BINDIR)"
}
}
}
}

View File

@@ -1,26 +0,0 @@
package = "LuaFileSystem"
version = "cvs-2"
source = {
url = "git://github.com/keplerproject/luafilesystem.git",
}
description = {
summary = "File System Library for the Lua Programming Language",
detailed = [[
LuaFileSystem is a Lua library developed to complement the set of
functions related to file systems offered by the standard Lua
distribution. LuaFileSystem offers a portable way to access the
underlying directory structure and file attributes.
]]
}
dependencies = {
"lua >= 5.1"
}
build = {
type = "module",
modules = { lfs = "src/lfs.c" }
}

View File

@@ -1,27 +0,0 @@
package = "LuaFileSystem"
version = "cvs-3"
source = {
url = "git://github.com/keplerproject/luafilesystem.git",
}
description = {
summary = "File System Library for the Lua Programming Language",
detailed = [[
LuaFileSystem is a Lua library developed to complement the set of
functions related to file systems offered by the standard Lua
distribution. LuaFileSystem offers a portable way to access the
underlying directory structure and file attributes.
]]
}
dependencies = {
"lua >= 5.1, < 5.4"
}
build = {
type = "builtin",
modules = { lfs = "src/lfs.c" },
copy_directories = { "doc", "tests" }
}

543
src/lfs.c
View File

@@ -1,6 +1,7 @@
/*
** LuaFileSystem
** Copyright Kepler Project 2003 - 2017 (http://keplerproject.github.io/luafilesystem)
** Copyright Kepler Project 2003 - 2020
** (http://keplerproject.github.io/luafilesystem)
**
** File system manipulation library.
** This library offers these functions:
@@ -29,6 +30,10 @@
#endif
#endif
#ifdef _WIN32
#define _WIN32_WINNT 0x600
#endif
#ifndef LFS_DO_NOT_USE_LARGE_FILE
#define _LARGEFILE64_SOURCE
#endif
@@ -41,26 +46,39 @@
#include <sys/stat.h>
#ifdef _WIN32
#include <direct.h>
#include <windows.h>
#include <io.h>
#include <sys/locking.h>
#ifdef __BORLANDC__
#include <utime.h>
#else
#include <sys/utime.h>
#endif
#include <fcntl.h>
/* MAX_PATH seems to be 260. Seems kind of small. Is there a better one? */
#define LFS_MAXPATHLEN MAX_PATH
#else
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/types.h>
#include <utime.h>
#include <sys/param.h> /* for MAXPATHLEN */
#ifdef MAXPATHLEN
#define LFS_MAXPATHLEN MAXPATHLEN
#else
#include <limits.h> /* for _POSIX_PATH_MAX */
#define LFS_MAXPATHLEN _POSIX_PATH_MAX
#endif
#endif
#include <lua.h>
@@ -69,10 +87,10 @@
#include "lfs.h"
#define LFS_VERSION "1.6.3"
#define LFS_VERSION "1.8.0"
#define LFS_LIBNAME "lfs"
#if LUA_VERSION_NUM >= 503 /* Lua 5.3 */
#if LUA_VERSION_NUM >= 503 /* Lua 5.3+ */
#ifndef luaL_optlong
#define luaL_optlong luaL_optinteger
@@ -105,6 +123,7 @@ typedef struct dir_data {
#define LOCK_METATABLE "lock metatable"
#ifdef _WIN32
#ifdef __BORLANDC__
#define lfs_setmode(file, m) (setmode(_fileno(file), m))
#define STAT_STRUCT struct stati64
@@ -112,15 +131,45 @@ typedef struct dir_data {
#define lfs_setmode(file, m) (_setmode(_fileno(file), m))
#define STAT_STRUCT struct _stati64
#endif
#ifndef _S_IFLNK
#define _S_IFLNK 0x400
#endif
#ifndef S_ISDIR
#define S_ISDIR(mode) (mode&_S_IFDIR)
#endif
#ifndef S_ISREG
#define S_ISREG(mode) (mode&_S_IFREG)
#endif
#ifndef S_ISLNK
#define S_ISLNK(mode) (mode&_S_IFLNK)
#endif
#ifndef S_ISSOCK
#define S_ISSOCK(mode) (0)
#endif
#ifndef S_ISFIFO
#define S_ISFIFO(mode) (0)
#endif
#ifndef S_ISCHR
#define S_ISCHR(mode) (mode&_S_IFCHR)
#endif
#ifndef S_ISBLK
#define S_ISBLK(mode) (0)
#endif
#define STAT_FUNC _stati64
#define LSTAT_FUNC STAT_FUNC
#define LSTAT_FUNC lfs_win32_lstat
#else
#define _O_TEXT 0
#define _O_BINARY 0
#define lfs_setmode(file, m) ((void)file, (void)m, 0)
#define STAT_STRUCT struct stat
#define STAT_FUNC stat
#define LSTAT_FUNC lstat
#endif
#ifdef _WIN32
@@ -130,6 +179,55 @@ typedef struct dir_data {
S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH))
#endif
#ifdef _WIN32
int lfs_win32_pusherror(lua_State * L)
{
int en = GetLastError();
lua_pushnil(L);
if (en == ERROR_FILE_EXISTS || en == ERROR_SHARING_VIOLATION)
lua_pushstring(L, "File exists");
else
lua_pushstring(L, strerror(en));
return 2;
}
#define TICKS_PER_SECOND 10000000
#define EPOCH_DIFFERENCE 11644473600LL
time_t windowsToUnixTime(FILETIME ft)
{
ULARGE_INTEGER uli;
uli.LowPart = ft.dwLowDateTime;
uli.HighPart = ft.dwHighDateTime;
return (time_t) (uli.QuadPart / TICKS_PER_SECOND - EPOCH_DIFFERENCE);
}
int lfs_win32_lstat(const char *path, STAT_STRUCT * buffer)
{
WIN32_FILE_ATTRIBUTE_DATA win32buffer;
if (GetFileAttributesEx(path, GetFileExInfoStandard, &win32buffer)) {
if (!(win32buffer.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
return STAT_FUNC(path, buffer);
}
buffer->st_mode = _S_IFLNK;
buffer->st_dev = 0;
buffer->st_ino = 0;
buffer->st_nlink = 0;
buffer->st_uid = 0;
buffer->st_gid = 0;
buffer->st_rdev = 0;
buffer->st_atime = windowsToUnixTime(win32buffer.ftLastAccessTime);
buffer->st_mtime = windowsToUnixTime(win32buffer.ftLastWriteTime);
buffer->st_ctime = windowsToUnixTime(win32buffer.ftCreationTime);
buffer->st_size = 0;
return 0;
} else {
return 1;
}
}
#endif
/*
** Utility functions
*/
@@ -144,7 +242,8 @@ static int pusherror(lua_State *L, const char *info)
return 3;
}
static int pushresult(lua_State *L, int res, const char *info) {
static int pushresult(lua_State * L, int res, const char *info)
{
if (res == -1) {
return pusherror(L, info);
} else {
@@ -157,7 +256,8 @@ static int pushresult(lua_State *L, int res, const char *info) {
/*
** This function changes the working (current) directory
*/
static int change_dir (lua_State *L) {
static int change_dir(lua_State * L)
{
const char *path = luaL_checkstring(L, 1);
if (chdir(path)) {
lua_pushnil(L);
@@ -175,20 +275,25 @@ static int change_dir (lua_State *L) {
** If unable to get the current directory, it returns nil
** and a string describing the error
*/
static int get_dir (lua_State *L) {
static int get_dir(lua_State * L)
{
#ifdef NO_GETCWD
lua_pushnil(L);
lua_pushstring(L, "Function 'getcwd' not provided by system");
return 2;
#else
char *path = NULL;
/* Passing (NULL, 0) is not guaranteed to work. Use a temp buffer and size instead. */
/* Passing (NULL, 0) is not guaranteed to work.
Use a temp buffer and size instead. */
size_t size = LFS_MAXPATHLEN; /* initial buffer size */
int result;
while (1) {
path = realloc(path, size);
if (!path) /* failed to allocate */
return pusherror(L, "get_dir realloc() failed");
char *path2 = realloc(path, size);
if (!path2) { /* failed to allocate */
result = pusherror(L, "get_dir realloc() failed");
break;
}
path = path2;
if (getcwd(path, size) != NULL) {
/* success, push the path to the Lua stack */
lua_pushstring(L, path);
@@ -210,7 +315,8 @@ static int get_dir (lua_State *L) {
/*
** Check if the given element on the stack is a file and returns it.
*/
static FILE *check_file (lua_State *L, int idx, const char *funcname) {
static FILE *check_file(lua_State * L, int idx, const char *funcname)
{
#if LUA_VERSION_NUM == 501
FILE **fh = (FILE **) luaL_checkudata(L, idx, "FILE*");
if (*fh == NULL) {
@@ -218,7 +324,7 @@ static FILE *check_file (lua_State *L, int idx, const char *funcname) {
return 0;
} else
return *fh;
#elif LUA_VERSION_NUM >= 502 && LUA_VERSION_NUM <= 503
#elif LUA_VERSION_NUM >= 502 && LUA_VERSION_NUM <= 504
luaL_Stream *fh = (luaL_Stream *) luaL_checkudata(L, idx, "FILE*");
if (fh->closef == 0 || fh->f == NULL) {
luaL_error(L, "%s: closed file", funcname);
@@ -234,26 +340,41 @@ static FILE *check_file (lua_State *L, int idx, const char *funcname) {
/*
**
*/
static int _file_lock (lua_State *L, FILE *fh, const char *mode, const long start, long len, const char *funcname) {
static int _file_lock(lua_State * L, FILE * fh, const char *mode,
const long start, long len, const char *funcname)
{
int code;
#ifdef _WIN32
/* lkmode valid values are:
LK_LOCK Locks the specified bytes. If the bytes cannot be locked, the program immediately tries again after 1 second. If, after 10 attempts, the bytes cannot be locked, the constant returns an error.
LK_NBLCK Locks the specified bytes. If the bytes cannot be locked, the constant returns an error.
LK_LOCK Locks the specified bytes. If the bytes cannot be locked,
the program immediately tries again after 1 second.
If, after 10 attempts, the bytes cannot be locked,
the constant returns an error.
LK_NBLCK Locks the specified bytes. If the bytes cannot be locked,
the constant returns an error.
LK_NBRLCK Same as _LK_NBLCK.
LK_RLCK Same as _LK_LOCK.
LK_UNLCK Unlocks the specified bytes, which must have been previously locked.
LK_UNLCK Unlocks the specified bytes, which must have been
previously locked.
Regions should be locked only briefly and should be unlocked before closing a file or exiting the program.
Regions should be locked only briefly and should be unlocked
before closing a file or exiting the program.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__locking.asp
*/
int lkmode;
switch (*mode) {
case 'r': lkmode = LK_NBLCK; break;
case 'w': lkmode = LK_NBLCK; break;
case 'u': lkmode = LK_UNLCK; break;
default : return luaL_error (L, "%s: invalid mode", funcname);
case 'r':
lkmode = LK_NBLCK;
break;
case 'w':
lkmode = LK_NBLCK;
break;
case 'u':
lkmode = LK_UNLCK;
break;
default:
return luaL_error(L, "%s: invalid mode", funcname);
}
if (!len) {
fseek(fh, 0L, SEEK_END);
@@ -268,10 +389,17 @@ static int _file_lock (lua_State *L, FILE *fh, const char *mode, const long star
#else
struct flock f;
switch (*mode) {
case 'w': f.l_type = F_WRLCK; break;
case 'r': f.l_type = F_RDLCK; break;
case 'u': f.l_type = F_UNLCK; break;
default : return luaL_error (L, "%s: invalid mode", funcname);
case 'w':
f.l_type = F_WRLCK;
break;
case 'r':
f.l_type = F_RDLCK;
break;
case 'u':
f.l_type = F_UNLCK;
break;
default:
return luaL_error(L, "%s: invalid mode", funcname);
}
f.l_whence = SEEK_SET;
f.l_start = (off_t) start;
@@ -285,35 +413,37 @@ static int _file_lock (lua_State *L, FILE *fh, const char *mode, const long star
typedef struct lfs_Lock {
HANDLE fd;
} lfs_Lock;
static int lfs_lock_dir(lua_State *L) {
size_t pathl; HANDLE fd;
static int lfs_lock_dir(lua_State * L)
{
size_t pathl;
HANDLE fd;
lfs_Lock *lock;
char *ln;
const char *lockfile = "/lockfile.lfs";
const char *path = luaL_checklstring(L, 1, &pathl);
ln = (char *) malloc(pathl + strlen(lockfile) + 1);
if (!ln) {
lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2;
}
strcpy(ln, path); strcat(ln, lockfile);
if((fd = CreateFile(ln, GENERIC_WRITE, 0, NULL, CREATE_NEW,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL)) == INVALID_HANDLE_VALUE) {
int en = GetLastError();
free(ln); lua_pushnil(L);
if(en == ERROR_FILE_EXISTS || en == ERROR_SHARING_VIOLATION)
lua_pushstring(L, "File exists");
else
lua_pushstring(L, strerror(en));
lua_pushnil(L);
lua_pushstring(L, strerror(errno));
return 2;
}
strcpy(ln, path);
strcat(ln, lockfile);
fd = CreateFile(ln, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL);
free(ln);
if (fd == INVALID_HANDLE_VALUE) {
return lfs_win32_pusherror(L);
}
lock = (lfs_Lock *) lua_newuserdata(L, sizeof(lfs_Lock));
lock->fd = fd;
luaL_getmetatable(L, LOCK_METATABLE);
lua_setmetatable(L, -2);
return 1;
}
static int lfs_unlock_dir(lua_State *L) {
static int lfs_unlock_dir(lua_State * L)
{
lfs_Lock *lock = (lfs_Lock *) luaL_checkudata(L, 1, LOCK_METATABLE);
if (lock->fd != INVALID_HANDLE_VALUE) {
CloseHandle(lock->fd);
@@ -325,7 +455,8 @@ static int lfs_unlock_dir(lua_State *L) {
typedef struct lfs_Lock {
char *ln;
} lfs_Lock;
static int lfs_lock_dir(lua_State *L) {
static int lfs_lock_dir(lua_State * L)
{
lfs_Lock *lock;
size_t pathl;
char *ln;
@@ -334,19 +465,26 @@ static int lfs_lock_dir(lua_State *L) {
lock = (lfs_Lock *) lua_newuserdata(L, sizeof(lfs_Lock));
ln = (char *) malloc(pathl + strlen(lockfile) + 1);
if (!ln) {
lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2;
lua_pushnil(L);
lua_pushstring(L, strerror(errno));
return 2;
}
strcpy(ln, path); strcat(ln, lockfile);
strcpy(ln, path);
strcat(ln, lockfile);
if (symlink("lock", ln) == -1) {
free(ln); lua_pushnil(L);
lua_pushstring(L, strerror(errno)); return 2;
free(ln);
lua_pushnil(L);
lua_pushstring(L, strerror(errno));
return 2;
}
lock->ln = ln;
luaL_getmetatable(L, LOCK_METATABLE);
lua_setmetatable(L, -2);
return 1;
}
static int lfs_unlock_dir(lua_State *L) {
static int lfs_unlock_dir(lua_State * L)
{
lfs_Lock *lock = (lfs_Lock *) luaL_checkudata(L, 1, LOCK_METATABLE);
if (lock->ln) {
unlink(lock->ln);
@@ -357,7 +495,8 @@ static int lfs_unlock_dir(lua_State *L) {
}
#endif
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_BINARY, _O_TEXT };
static const char *const modenames[] = { "binary", "text", NULL };
int op = luaL_checkoption(L, arg, NULL, modenames);
@@ -378,7 +517,8 @@ static int lfs_g_setmode (lua_State *L, FILE *f, int arg) {
}
}
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);
}
@@ -389,7 +529,8 @@ static int lfs_f_setmode(lua_State *L) {
** @param #3 Number with start position (optional).
** @param #4 Number with length (optional).
*/
static int file_lock (lua_State *L) {
static int file_lock(lua_State * L)
{
FILE *fh = check_file(L, 1, "lock");
const char *mode = luaL_checkstring(L, 2);
const long start = (long) luaL_optinteger(L, 3, 0);
@@ -411,7 +552,8 @@ static int file_lock (lua_State *L) {
** @param #2 Number with start position (optional).
** @param #3 Number with length (optional).
*/
static int file_unlock (lua_State *L) {
static int file_unlock(lua_State * L)
{
FILE *fh = check_file(L, 1, "unlock");
const long start = (long) luaL_optinteger(L, 2, 0);
long len = (long) luaL_optinteger(L, 3, 0);
@@ -432,20 +574,40 @@ static int file_unlock (lua_State *L) {
** @param #2 Name of link.
** @param #3 True if link is symbolic (optional).
*/
static int make_link (lua_State *L) {
#ifndef _WIN32
static int make_link(lua_State * L)
{
const char *oldpath = luaL_checkstring(L, 1);
const char *newpath = luaL_checkstring(L, 2);
int res = (lua_toboolean(L,3) ? symlink : link)(oldpath, newpath);
if (res == -1) {
return pusherror(L, NULL);
} else {
lua_pushinteger(L, 0);
return 1;
}
#ifndef _WIN32
return pushresult(L,
(lua_toboolean(L, 3) ? symlink : link) (oldpath,
newpath),
NULL);
#else
errno = ENOSYS; /* = "Function not implemented" */
return pushresult(L, -1, "make_link is not supported on Windows");
int symbolic = lua_toboolean(L, 3);
STAT_STRUCT oldpathinfo;
int is_dir = 0;
if (STAT_FUNC(oldpath, &oldpathinfo) == 0) {
is_dir = S_ISDIR(oldpathinfo.st_mode) != 0;
}
if (!symbolic && is_dir) {
lua_pushnil(L);
lua_pushstring(L,
"hard links to directories are not supported on Windows");
return 2;
}
int result = symbolic ? CreateSymbolicLink(newpath, oldpath, is_dir)
: CreateHardLink(newpath, oldpath, NULL);
if (result) {
return pushresult(L, result, NULL);
} else {
lua_pushnil(L);
lua_pushstring(L, symbolic ? "make_link CreateSymbolicLink() failed"
: "make_link CreateHardLink() failed");
return 2;
}
#endif
}
@@ -454,7 +616,8 @@ static int make_link (lua_State *L) {
** 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);
return pushresult(L, lfs_mkdir(path), NULL);
}
@@ -464,7 +627,8 @@ static int make_dir (lua_State *L) {
** Removes a directory.
** @param #1 Directory path.
*/
static int remove_dir (lua_State *L) {
static int remove_dir(lua_State * L)
{
const char *path = luaL_checkstring(L, 1);
return pushresult(L, rmdir(path), NULL);
}
@@ -473,7 +637,8 @@ static int remove_dir (lua_State *L) {
/*
** Directory iterator
*/
static int dir_iter (lua_State *L) {
static int dir_iter(lua_State * L)
{
#ifdef _WIN32
struct _finddata_t c_file;
#else
@@ -520,7 +685,8 @@ static int dir_iter (lua_State *L) {
/*
** Closes directory iterators
*/
static int dir_close (lua_State *L) {
static int dir_close(lua_State * L)
{
dir_data *d = (dir_data *) lua_touserdata(L, 1);
#ifdef _WIN32
if (!d->closed && d->hFile) {
@@ -539,7 +705,8 @@ static int dir_close (lua_State *L) {
/*
** Factory of directory iterators
*/
static int dir_iter_factory (lua_State *L) {
static int dir_iter_factory(lua_State * L)
{
const char *path = luaL_checkstring(L, 1);
dir_data *d;
lua_pushcfunction(L, dir_iter);
@@ -558,14 +725,21 @@ static int dir_iter_factory (lua_State *L) {
if (d->dir == NULL)
luaL_error(L, "cannot open %s: %s", path, strerror(errno));
#endif
#if LUA_VERSION_NUM >= 504
lua_pushnil(L);
lua_pushvalue(L, -2);
return 4;
#else
return 2;
#endif
}
/*
** Creates directory metatable.
*/
static int dir_create_meta (lua_State *L) {
static int dir_create_meta(lua_State * L)
{
luaL_newmetatable(L, DIR_METATABLE);
/* Method table */
@@ -579,6 +753,11 @@ static int dir_create_meta (lua_State *L) {
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, dir_close);
lua_setfield(L, -2, "__gc");
#if LUA_VERSION_NUM >= 504
lua_pushcfunction(L, dir_close);
lua_setfield(L, -2, "__close");
#endif
return 1;
}
@@ -586,7 +765,8 @@ static int dir_create_meta (lua_State *L) {
/*
** Creates lock metatable.
*/
static int lock_create_meta (lua_State *L) {
static int lock_create_meta(lua_State * L)
{
luaL_newmetatable(L, LOCK_METATABLE);
/* Method table */
@@ -602,36 +782,15 @@ static int lock_create_meta (lua_State *L) {
}
#ifdef _WIN32
#ifndef S_ISDIR
#define S_ISDIR(mode) (mode&_S_IFDIR)
#endif
#ifndef S_ISREG
#define S_ISREG(mode) (mode&_S_IFREG)
#endif
#ifndef S_ISLNK
#define S_ISLNK(mode) (0)
#endif
#ifndef S_ISSOCK
#define S_ISSOCK(mode) (0)
#endif
#ifndef S_ISFIFO
#define S_ISFIFO(mode) (0)
#endif
#ifndef S_ISCHR
#define S_ISCHR(mode) (mode&_S_IFCHR)
#endif
#ifndef S_ISBLK
#define S_ISBLK(mode) (0)
#endif
#endif
/*
** Convert the inode protection mode to a string.
*/
#ifdef _WIN32
static const char *mode2string (unsigned short mode) {
static const char *mode2string(unsigned short mode)
{
#else
static const char *mode2string (mode_t mode) {
static const char *mode2string(mode_t mode)
{
#endif
if (S_ISREG(mode))
return "file";
@@ -658,7 +817,8 @@ static const char *mode2string (mode_t mode) {
** @param #2 Access time in seconds, current time is used if missing.
** @param #3 Modification time in seconds, access time is used if missing.
*/
static int file_utime (lua_State *L) {
static int file_utime(lua_State * L)
{
const char *file = luaL_checkstring(L, 1);
struct utimbuf utb, *buf;
@@ -675,56 +835,81 @@ static int file_utime (lua_State *L) {
/* inode protection mode */
static void push_st_mode (lua_State *L, STAT_STRUCT *info) {
static void push_st_mode(lua_State * L, STAT_STRUCT * info)
{
lua_pushstring(L, mode2string(info->st_mode));
}
/* device inode resides on */
static void push_st_dev (lua_State *L, STAT_STRUCT *info) {
static void push_st_dev(lua_State * L, STAT_STRUCT * info)
{
lua_pushinteger(L, (lua_Integer) info->st_dev);
}
/* inode's number */
static void push_st_ino (lua_State *L, STAT_STRUCT *info) {
static void push_st_ino(lua_State * L, STAT_STRUCT * info)
{
lua_pushinteger(L, (lua_Integer) info->st_ino);
}
/* number of hard links to the file */
static void push_st_nlink (lua_State *L, STAT_STRUCT *info) {
static void push_st_nlink(lua_State * L, STAT_STRUCT * info)
{
lua_pushinteger(L, (lua_Integer) info->st_nlink);
}
/* user-id of owner */
static void push_st_uid (lua_State *L, STAT_STRUCT *info) {
static void push_st_uid(lua_State * L, STAT_STRUCT * info)
{
lua_pushinteger(L, (lua_Integer) info->st_uid);
}
/* group-id of owner */
static void push_st_gid (lua_State *L, STAT_STRUCT *info) {
static void push_st_gid(lua_State * L, STAT_STRUCT * info)
{
lua_pushinteger(L, (lua_Integer) info->st_gid);
}
/* device type, for special file inode */
static void push_st_rdev (lua_State *L, STAT_STRUCT *info) {
static void push_st_rdev(lua_State * L, STAT_STRUCT * info)
{
lua_pushinteger(L, (lua_Integer) info->st_rdev);
}
/* time of last access */
static void push_st_atime (lua_State *L, STAT_STRUCT *info) {
static void push_st_atime(lua_State * L, STAT_STRUCT * info)
{
lua_pushinteger(L, (lua_Integer) info->st_atime);
}
/* time of last data modification */
static void push_st_mtime (lua_State *L, STAT_STRUCT *info) {
static void push_st_mtime(lua_State * L, STAT_STRUCT * info)
{
lua_pushinteger(L, (lua_Integer) info->st_mtime);
}
/* time of last file status change */
static void push_st_ctime (lua_State *L, STAT_STRUCT *info) {
static void push_st_ctime(lua_State * L, STAT_STRUCT * info)
{
lua_pushinteger(L, (lua_Integer) info->st_ctime);
}
/* file size, in bytes */
static void push_st_size (lua_State *L, STAT_STRUCT *info) {
static void push_st_size(lua_State * L, STAT_STRUCT * info)
{
lua_pushinteger(L, (lua_Integer) info->st_size);
}
#ifndef _WIN32
/* blocks allocated for file */
static void push_st_blocks (lua_State *L, STAT_STRUCT *info) {
static void push_st_blocks(lua_State * L, STAT_STRUCT * info)
{
lua_pushinteger(L, (lua_Integer) info->st_blocks);
}
/* optimal file system I/O blocksize */
static void push_st_blksize (lua_State *L, STAT_STRUCT *info) {
static void push_st_blksize(lua_State * L, STAT_STRUCT * info)
{
lua_pushinteger(L, (lua_Integer) info->st_blksize);
}
#endif
@@ -734,38 +919,61 @@ static void push_st_blksize (lua_State *L, STAT_STRUCT *info) {
*/
#ifdef _WIN32
static const char *perm2string (unsigned short mode) {
static const char *perm2string(unsigned short mode)
{
static char perms[10] = "---------";
int i;
for (i=0;i<9;i++) perms[i]='-';
if (mode & _S_IREAD)
{ perms[0] = 'r'; perms[3] = 'r'; perms[6] = 'r'; }
if (mode & _S_IWRITE)
{ perms[1] = 'w'; perms[4] = 'w'; perms[7] = 'w'; }
if (mode & _S_IEXEC)
{ perms[2] = 'x'; perms[5] = 'x'; perms[8] = 'x'; }
for (i = 0; i < 9; i++)
perms[i] = '-';
if (mode & _S_IREAD) {
perms[0] = 'r';
perms[3] = 'r';
perms[6] = 'r';
}
if (mode & _S_IWRITE) {
perms[1] = 'w';
perms[4] = 'w';
perms[7] = 'w';
}
if (mode & _S_IEXEC) {
perms[2] = 'x';
perms[5] = 'x';
perms[8] = 'x';
}
return perms;
}
#else
static const char *perm2string (mode_t mode) {
static const char *perm2string(mode_t mode)
{
static char perms[10] = "---------";
int i;
for (i=0;i<9;i++) perms[i]='-';
if (mode & S_IRUSR) perms[0] = 'r';
if (mode & S_IWUSR) perms[1] = 'w';
if (mode & S_IXUSR) perms[2] = 'x';
if (mode & S_IRGRP) perms[3] = 'r';
if (mode & S_IWGRP) perms[4] = 'w';
if (mode & S_IXGRP) perms[5] = 'x';
if (mode & S_IROTH) perms[6] = 'r';
if (mode & S_IWOTH) perms[7] = 'w';
if (mode & S_IXOTH) perms[8] = 'x';
for (i = 0; i < 9; i++)
perms[i] = '-';
if (mode & S_IRUSR)
perms[0] = 'r';
if (mode & S_IWUSR)
perms[1] = 'w';
if (mode & S_IXUSR)
perms[2] = 'x';
if (mode & S_IRGRP)
perms[3] = 'r';
if (mode & S_IWGRP)
perms[4] = 'w';
if (mode & S_IXGRP)
perms[5] = 'x';
if (mode & S_IROTH)
perms[6] = 'r';
if (mode & S_IWOTH)
perms[7] = 'w';
if (mode & S_IXOTH)
perms[8] = 'x';
return perms;
}
#endif
/* permssions string */
static void push_st_perm (lua_State *L, STAT_STRUCT *info) {
static void push_st_perm(lua_State * L, STAT_STRUCT * info)
{
lua_pushstring(L, perm2string(info->st_mode));
}
@@ -799,14 +1007,17 @@ struct _stat_members members[] = {
/*
** Get file or symbolic link information
*/
static int _file_info_ (lua_State *L, int (*st)(const char*, STAT_STRUCT*)) {
static int _file_info_(lua_State * L,
int (*st)(const char *, STAT_STRUCT *))
{
STAT_STRUCT info;
const char *file = luaL_checkstring(L, 1);
int i;
if (st(file, &info)) {
lua_pushnil(L);
lua_pushfstring(L, "cannot obtain information from file '%s': %s", file, strerror(errno));
lua_pushfstring(L, "cannot obtain information from file '%s': %s",
file, strerror(errno));
lua_pushinteger(L, errno);
return 3;
}
@@ -840,7 +1051,8 @@ static int _file_info_ (lua_State *L, int (*st)(const char*, STAT_STRUCT*)) {
/*
** Get file information using stat.
*/
static int file_info (lua_State *L) {
static int file_info(lua_State * L)
{
return _file_info_(L, STAT_FUNC);
}
@@ -851,39 +1063,63 @@ static int file_info (lua_State *L) {
** Returns 1 if successful (with the target on top of the stack),
** 0 on failure (with stack unchanged, and errno set).
*/
static int push_link_target(lua_State *L) {
#ifdef _WIN32
errno = ENOSYS;
return 0;
#else
static int push_link_target(lua_State * L)
{
const char *file = luaL_checkstring(L, 1);
#ifdef _WIN32
HANDLE h = CreateFile(file, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE) {
return lfs_win32_pusherror(L);
}
#endif
char *target = NULL;
int tsize, size = 256; /* size = initial buffer capacity */
while (1) {
target = realloc(target, size);
if (!target) /* failed to allocate */
return 0;
tsize = readlink(file, target, size);
if (tsize < 0) { /* a readlink() error occurred */
free(target);
return 0;
}
if (tsize < size)
int ok = 0;
while (!ok) {
char *target2 = realloc(target, size);
if (!target2) { /* failed to allocate */
break;
}
target = target2;
#ifdef _WIN32
tsize = GetFinalPathNameByHandle(h, target, size, FILE_NAME_OPENED);
#else
tsize = readlink(file, target, size);
#endif
if (tsize < 0) { /* a readlink() error occurred */
break;
}
if (tsize < size) {
#ifdef _WIN32
if (tsize > 4 && strncmp(target, "\\\\?\\", 4) == 0) {
memmove_s(target, tsize - 3, target + 4, tsize - 3);
tsize -= 4;
}
#endif
ok = 1;
break;
}
/* possibly truncated readlink() result, double size and retry */
size *= 2;
}
if (ok) {
target[tsize] = '\0';
lua_pushlstring(L, target, tsize);
free(target);
return 1;
}
#ifdef _WIN32
CloseHandle(h);
#endif
free(target);
return ok;
}
/*
** Get symbolic link information using lstat.
*/
static int link_info (lua_State *L) {
static int link_info(lua_State * L)
{
int ret;
if (lua_isstring(L, 2) && (strcmp(lua_tostring(L, 2), "target") == 0)) {
int ok = push_link_target(L);
@@ -903,10 +1139,14 @@ static int link_info (lua_State *L) {
/*
** Assumes the table is on top of the stack.
*/
static void set_info (lua_State *L) {
static void set_info(lua_State * L)
{
lua_pushliteral(L, "Copyright (C) 2003-2017 Kepler Project");
lua_setfield(L, -2, "_COPYRIGHT");
lua_pushliteral(L, "LuaFileSystem is a Lua library developed to complement the set of functions related to file systems offered by the standard Lua distribution");
lua_pushliteral(L,
"LuaFileSystem is a Lua library developed to complement "
"the set of functions related to file systems offered by "
"the standard Lua distribution");
lua_setfield(L, -2, "_DESCRIPTION");
lua_pushliteral(L, "LuaFileSystem " LFS_VERSION);
lua_setfield(L, -2, "_VERSION");
@@ -930,7 +1170,8 @@ static const struct luaL_Reg fslib[] = {
{ NULL, NULL },
};
LFS_EXPORT int luaopen_lfs (lua_State *L) {
LFS_EXPORT int luaopen_lfs(lua_State * L)
{
dir_create_meta(L);
lock_create_meta(L);
new_lib(L, fslib);

View File

@@ -1,4 +1,4 @@
LIBRARY lfs.dll
VERSION 1.6
VERSION 1.8
EXPORTS
luaopen_lfs

View File

@@ -1,6 +1,7 @@
/*
** LuaFileSystem
** Copyright Kepler Project 2003 - 2017 (http://keplerproject.github.io/luafilesystem)
** Copyright Kepler Project 2003 - 2020
** (http://keplerproject.github.io/luafilesystem)
*/
/* Define 'chdir' for systems that do not implement it */

View File

@@ -4,6 +4,8 @@ local tmp = "/tmp"
local sep = string.match (package.config, "[^\n]+")
local upper = ".."
local is_unix = package.config:sub(1,1) == "/"
local lfs = require"lfs"
print (lfs._VERSION)
@@ -60,6 +62,8 @@ if not attrib then
error ("could not get attributes of file `"..tmpdir.."':\n"..errmsg)
end
local f = io.open(tmpfile, "w")
local data = "hello, file!"
f:write(data)
f:close()
io.write(".")
@@ -87,14 +91,42 @@ assert (new_att.modification == testdate1, "could not set modification time")
io.write(".")
io.flush()
-- 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.symlinkattributes"_a_link_for_test_".target == tmpfile)
assert (lfs.symlinkattributes("_a_link_for_test_", "target") == tmpfile)
assert (lfs.symlinkattributes(tmpfile).mode == "file")
assert (lfs.link (tmpfile, "_a_hard_link_for_test_"))
assert (lfs.symlinkattributes"_a_hard_link_for_test_".mode == "file")
local fd = io.open(tmpfile)
assert(fd:read("*a") == data)
fd:close()
fd = io.open("_a_link_for_test_")
assert(fd:read("*a") == data)
fd:close()
fd = io.open("_a_hard_link_for_test_")
assert(fd:read("*a") == data)
fd:close()
fd = io.open("_a_hard_link_for_test_", "w+")
local data2 = "write in hard link"
fd:write(data2)
fd:close()
fd = io.open(tmpfile)
assert(fd:read("*a") == data2)
fd:close()
if is_unix then
assert (lfs.attributes (tmpfile, "nlink") == 2)
end
assert (os.remove"_a_link_for_test_")
assert (os.remove"_a_hard_link_for_test_")
end