3
This file is part of the extensible drawing editor Ipe.
4
Copyright (C) 1993-2009 Otfried Cheong
6
Ipe is free software; you can redistribute it and/or modify it
7
under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 3 of the License, or
9
(at your option) any later version.
11
As a special exception, you have permission to link Ipe with the
12
CGAL library and distribute executables, as long as you follow the
13
requirements of the Gnu General Public License in regard to all of
14
the software in the executable aside from CGAL.
16
Ipe is distributed in the hope that it will be useful, but WITHOUT
17
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
19
License for more details.
21
You should have received a copy of the GNU General Public License
22
along with Ipe; if not, you can find it at
23
"http://www.gnu.org/copyleft/gpl.html", or write to the Free
24
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29
** Copyright Kepler Project 2003 (http://www.keplerproject.org/luafilesystem)
31
** File system manipulation library.
32
** This library offers these functions:
33
** lfs.attributes (filepath [, attributename])
37
** lfs.lock (fh, mode)
40
** lfs.setmode (filepath, mode)
41
** lfs.symlinkattributes (filepath [, attributename]) -- thanks to Sam Roberts
42
** lfs.touch (filepath [, atime [, mtime]])
45
** $Id: lfs.c,v 1.53 2008/05/07 19:06:37 carregal Exp $
48
#define _LARGEFILE64_SOURCE
60
#include <sys/locking.h>
61
#include <sys/utime.h>
67
#include <sys/types.h>
78
/* Define 'strerror' for systems that do not implement it */
80
#define strerror(_) "System unable to describe the error"
83
/* Define 'getcwd' for systems that do not implement it */
85
#define getcwd(p,s) NULL
86
#define getcwd_error "Function 'getcwd' not provided by system"
88
#define getcwd_error strerror(errno)
91
#define DIR_METATABLE "directory metatable"
92
#define MAX_DIR_LENGTH 1023
93
typedef struct dir_data {
97
char pattern[MAX_DIR_LENGTH+1];
105
#define lfs_setmode(L,file,m) ((void)L, _setmode(_fileno(file), m))
106
#define STAT_STRUCT struct _stati64
107
#define STAT_FUNC _stati64
111
#define lfs_setmode(L,file,m) ((void)((void)file,m), \
112
luaL_error(L, LUA_QL("setmode") " not supported on this platform"), -1)
114
#define STAT_STRUCT struct stat64
115
#define STAT_FUNC stat64
116
#define LSTAT_FUNC lstat64
118
#define STAT_STRUCT struct stat
119
#define STAT_FUNC stat
120
#define LSTAT_FUNC lstat
125
** This function changes the working (current) directory
127
static int change_dir (lua_State *L) {
128
const char *path = luaL_checkstring(L, 1);
131
lua_pushfstring (L,"Unable to change working directory to '%s'\n%s\n",
135
lua_pushboolean (L, 1);
141
** This function returns the current directory
142
** If unable to get the current directory, it returns nil
143
** and a string describing the error
145
static int get_dir (lua_State *L) {
147
if ((path = getcwd(NULL, 0)) == NULL) {
149
lua_pushstring(L, getcwd_error);
153
lua_pushstring(L, path);
160
** Check if the given element on the stack is a file and returns it.
162
static FILE *check_file (lua_State *L, int idx, const char *funcname) {
163
FILE **fh = (FILE **)luaL_checkudata (L, idx, "FILE*");
165
luaL_error (L, "%s: not a file", funcname);
167
} else if (*fh == NULL) {
168
luaL_error (L, "%s: closed file", funcname);
178
static int _file_lock (lua_State *L, FILE *fh, const char *mode, const long start, long len, const char *funcname) {
181
/* lkmode valid values are:
182
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.
183
LK_NBLCK Locks the specified bytes. If the bytes cannot be locked, the constant returns an error.
184
LK_NBRLCK Same as _LK_NBLCK.
185
LK_RLCK Same as _LK_LOCK.
186
LK_UNLCK Unlocks the specified bytes, which must have been previously locked.
188
Regions should be locked only briefly and should be unlocked before closing a file or exiting the program.
190
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__locking.asp
194
case 'r': lkmode = LK_NBLCK; break;
195
case 'w': lkmode = LK_NBLCK; break;
196
case 'u': lkmode = LK_UNLCK; break;
197
default : return luaL_error (L, "%s: invalid mode", funcname);
200
fseek (fh, 0L, SEEK_END);
203
fseek (fh, start, SEEK_SET);
204
code = _locking (fileno(fh), lkmode, len);
208
case 'w': f.l_type = F_WRLCK; break;
209
case 'r': f.l_type = F_RDLCK; break;
210
case 'u': f.l_type = F_UNLCK; break;
211
default : return luaL_error (L, "%s: invalid mode", funcname);
213
f.l_whence = SEEK_SET;
214
f.l_start = (off_t)start;
215
f.l_len = (off_t)len;
216
code = fcntl (fileno(fh), F_SETLK, &f);
222
static int lfs_g_setmode (lua_State *L, FILE *f, int arg) {
223
static const int mode[] = {_O_TEXT, _O_BINARY};
224
static const char *const modenames[] = {"text", "binary", NULL};
225
int op = luaL_checkoption(L, arg, NULL, modenames);
226
int res = lfs_setmode(L, f, mode[op]);
229
lua_pushboolean(L, 1);
230
for (i = 0; modenames[i] != NULL; i++) {
231
if (mode[i] == res) {
232
lua_pushstring(L, modenames[i]);
242
lua_pushfstring(L, "%s", strerror(en));
243
lua_pushinteger(L, en);
248
static int lfs_g_setmode (lua_State *L, FILE *f, int arg) {
249
lua_pushboolean(L, 0);
250
lua_pushliteral(L, "setmode not supported on this platform");
255
static int lfs_f_setmode(lua_State *L) {
256
return lfs_g_setmode(L, check_file(L, 1, "setmode"), 2);
261
** @param #1 File handle.
262
** @param #2 String with lock mode ('w'rite, 'r'ead).
263
** @param #3 Number with start position (optional).
264
** @param #4 Number with length (optional).
266
static int file_lock (lua_State *L) {
267
FILE *fh = check_file (L, 1, "lock");
268
const char *mode = luaL_checkstring (L, 2);
269
const long start = luaL_optlong (L, 3, 0);
270
long len = luaL_optlong (L, 4, 0);
271
if (_file_lock (L, fh, mode, start, len, "lock")) {
272
lua_pushboolean (L, 1);
276
lua_pushfstring (L, "%s", strerror(errno));
284
** @param #1 File handle.
285
** @param #2 Number with start position (optional).
286
** @param #3 Number with length (optional).
288
static int file_unlock (lua_State *L) {
289
FILE *fh = check_file (L, 1, "unlock");
290
const long start = luaL_optlong (L, 2, 0);
291
long len = luaL_optlong (L, 3, 0);
292
if (_file_lock (L, fh, "u", start, len, "unlock")) {
293
lua_pushboolean (L, 1);
297
lua_pushfstring (L, "%s", strerror(errno));
303
static int make_dir (lua_State *L) {
304
const char *path = luaL_checkstring (L, 1);
307
int oldmask = umask (0);
308
fail = _mkdir (path);
310
mode_t oldmask = umask( (mode_t)0 );
311
fail = mkdir (path, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
312
S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH );
316
lua_pushfstring (L, "%s", strerror(errno));
320
lua_pushboolean (L, 1);
325
** Removes a directory.
326
** @param #1 Directory path.
328
static int remove_dir (lua_State *L) {
329
const char *path = luaL_checkstring (L, 1);
336
lua_pushfstring (L, "%s", strerror(errno));
339
lua_pushboolean (L, 1);
344
** Directory iterator
346
static int dir_iter (lua_State *L) {
348
struct _finddata_t c_file;
350
struct dirent *entry;
352
dir_data *d = (dir_data *)lua_touserdata (L, lua_upvalueindex (1));
353
luaL_argcheck (L, !d->closed, 1, "closed directory");
355
if (d->hFile == 0L) { /* first entry */
356
if ((d->hFile = _findfirst (d->pattern, &c_file)) == -1L) {
358
lua_pushstring (L, strerror (errno));
361
lua_pushstring (L, c_file.name);
364
} else { /* next entry */
365
if (_findnext (d->hFile, &c_file) == -1L) {
366
/* no more entries => close directory */
367
_findclose (d->hFile);
371
lua_pushstring (L, c_file.name);
376
if ((entry = readdir (d->dir)) != NULL) {
377
lua_pushstring (L, entry->d_name);
380
/* no more entries => close directory */
390
** Closes directory iterators
392
static int dir_close (lua_State *L) {
393
dir_data *d = (dir_data *)lua_touserdata (L, 1);
395
if (!d->closed && d->hFile) {
396
_findclose (d->hFile);
400
if (!d->closed && d->dir) {
410
** Factory of directory iterators
412
static int dir_iter_factory (lua_State *L) {
413
const char *path = luaL_checkstring (L, 1);
414
dir_data *d = (dir_data *) lua_newuserdata (L, sizeof(dir_data));
418
luaL_getmetatable (L, DIR_METATABLE);
419
lua_setmetatable (L, -2);
420
if (strlen(path) > MAX_DIR_LENGTH)
421
luaL_error (L, "path too long: %s", path);
423
sprintf (d->pattern, "%s/*", path);
425
luaL_getmetatable (L, DIR_METATABLE);
426
lua_setmetatable (L, -2);
427
d->dir = opendir (path);
429
luaL_error (L, "cannot open %s: %s", path, strerror (errno));
431
lua_pushcclosure (L, dir_iter, 1);
437
** Creates directory metatable.
439
static int dir_create_meta (lua_State *L) {
440
luaL_newmetatable (L, DIR_METATABLE);
441
/* set its __gc field */
442
lua_pushstring (L, "__gc");
443
lua_pushcfunction (L, dir_close);
444
lua_settable (L, -3);
452
#define S_ISDIR(mode) (mode&_S_IFDIR)
455
#define S_ISREG(mode) (mode&_S_IFREG)
458
#define S_ISLNK(mode) (0)
461
#define S_ISSOCK(mode) (0)
464
#define S_ISFIFO(mode) (0)
467
#define S_ISCHR(mode) (mode&_S_IFCHR)
470
#define S_ISBLK(mode) (0)
474
** Convert the inode protection mode to a string.
477
static const char *mode2string (unsigned short mode) {
479
static const char *mode2string (mode_t mode) {
483
else if ( S_ISDIR(mode) )
485
else if ( S_ISLNK(mode) )
487
else if ( S_ISSOCK(mode) )
489
else if ( S_ISFIFO(mode) )
491
else if ( S_ISCHR(mode) )
492
return "char device";
493
else if ( S_ISBLK(mode) )
494
return "block device";
501
** Set access time and modification values for file
503
static int file_utime (lua_State *L) {
504
const char *file = luaL_checkstring (L, 1);
505
struct utimbuf utb, *buf;
507
if (lua_gettop (L) == 1) /* set to current date/time */
510
utb.actime = (time_t)luaL_optnumber (L, 2, 0);
511
utb.modtime = (time_t)luaL_optnumber (L, 3, utb.actime);
514
if (utime (file, buf)) {
516
lua_pushfstring (L, "%s", strerror (errno));
519
lua_pushboolean (L, 1);
524
/* inode protection mode */
525
static void push_st_mode (lua_State *L, STAT_STRUCT *info) {
526
lua_pushstring (L, mode2string (info->st_mode));
528
/* device inode resides on */
529
static void push_st_dev (lua_State *L, STAT_STRUCT *info) {
530
lua_pushnumber (L, (lua_Number)info->st_dev);
533
static void push_st_ino (lua_State *L, STAT_STRUCT *info) {
534
lua_pushnumber (L, (lua_Number)info->st_ino);
536
/* number of hard links to the file */
537
static void push_st_nlink (lua_State *L, STAT_STRUCT *info) {
538
lua_pushnumber (L, (lua_Number)info->st_nlink);
540
/* user-id of owner */
541
static void push_st_uid (lua_State *L, STAT_STRUCT *info) {
542
lua_pushnumber (L, (lua_Number)info->st_uid);
544
/* group-id of owner */
545
static void push_st_gid (lua_State *L, STAT_STRUCT *info) {
546
lua_pushnumber (L, (lua_Number)info->st_gid);
548
/* device type, for special file inode */
549
static void push_st_rdev (lua_State *L, STAT_STRUCT *info) {
550
lua_pushnumber (L, (lua_Number)info->st_rdev);
552
/* time of last access */
553
static void push_st_atime (lua_State *L, STAT_STRUCT *info) {
554
lua_pushnumber (L, info->st_atime);
556
/* time of last data modification */
557
static void push_st_mtime (lua_State *L, STAT_STRUCT *info) {
558
lua_pushnumber (L, info->st_mtime);
560
/* time of last file status change */
561
static void push_st_ctime (lua_State *L, STAT_STRUCT *info) {
562
lua_pushnumber (L, info->st_ctime);
564
/* file size, in bytes */
565
static void push_st_size (lua_State *L, STAT_STRUCT *info) {
566
lua_pushnumber (L, (lua_Number)info->st_size);
569
/* blocks allocated for file */
570
static void push_st_blocks (lua_State *L, STAT_STRUCT *info) {
571
lua_pushnumber (L, (lua_Number)info->st_blocks);
573
/* optimal file system I/O blocksize */
574
static void push_st_blksize (lua_State *L, STAT_STRUCT *info) {
575
lua_pushnumber (L, (lua_Number)info->st_blksize);
578
static void push_invalid (lua_State *L, STAT_STRUCT *info) {
579
luaL_error(L, "invalid attribute name");
581
info->st_blksize = 0; /* never reached */
585
typedef void (*_push_function) (lua_State *L, STAT_STRUCT *info);
587
struct _stat_members {
592
struct _stat_members members[] = {
593
{ "mode", push_st_mode },
594
{ "dev", push_st_dev },
595
{ "ino", push_st_ino },
596
{ "nlink", push_st_nlink },
597
{ "uid", push_st_uid },
598
{ "gid", push_st_gid },
599
{ "rdev", push_st_rdev },
600
{ "access", push_st_atime },
601
{ "modification", push_st_mtime },
602
{ "change", push_st_ctime },
603
{ "size", push_st_size },
605
{ "blocks", push_st_blocks },
606
{ "blksize", push_st_blksize },
608
{ NULL, push_invalid }
612
** Get file or symbolic link information
614
static int _file_info_ (lua_State *L, int (*st)(const char*, STAT_STRUCT*)) {
617
const char *file = luaL_checkstring (L, 1);
619
if (st(file, &info)) {
621
lua_pushfstring (L, "cannot obtain information from file `%s'", file);
624
if (lua_isstring (L, 2)) {
626
const char *member = lua_tostring (L, 2);
627
if (strcmp (member, "mode") == 0) v = 0;
629
else if (strcmp (member, "blocks") == 0) v = 11;
630
else if (strcmp (member, "blksize") == 0) v = 12;
632
else /* look for member */
633
for (v = 1; members[v].name; v++)
634
if (*members[v].name == *member)
636
/* push member value and return */
637
members[v].push (L, &info);
639
} else if (!lua_istable (L, 2))
640
/* creates a table if none is given */
642
/* stores all members in table on top of the stack */
643
for (i = 0; members[i].name; i++) {
644
lua_pushstring (L, members[i].name);
645
members[i].push (L, &info);
653
** Get file information using stat.
655
static int file_info (lua_State *L) {
656
return _file_info_ (L, STAT_FUNC);
661
** Get symbolic link information using lstat.
664
static int link_info (lua_State *L) {
665
return _file_info_ (L, LSTAT_FUNC);
668
static int link_info (lua_State *L) {
669
lua_pushboolean(L, 0);
670
lua_pushliteral(L, "symlinkattributes not supported on this platform");
677
** Assumes the table is on top of the stack.
679
static void set_info (lua_State *L) {
680
lua_pushliteral (L, "_COPYRIGHT");
681
lua_pushliteral (L, "Copyright (C) 2003 Kepler Project");
682
lua_settable (L, -3);
683
lua_pushliteral (L, "_DESCRIPTION");
684
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");
685
lua_settable (L, -3);
686
lua_pushliteral (L, "_VERSION");
687
lua_pushliteral (L, "LuaFileSystem 1.4.1");
688
lua_settable (L, -3);
692
static const struct luaL_reg fslib[] = {
693
{"attributes", file_info},
694
{"chdir", change_dir},
695
{"currentdir", get_dir},
696
{"dir", dir_iter_factory},
699
{"rmdir", remove_dir},
700
{"symlinkattributes", link_info},
701
{"setmode", lfs_f_setmode},
702
{"touch", file_utime},
703
{"unlock", file_unlock},
707
extern "C" int luaopen_lfs (lua_State *L) {
709
luaL_register (L, "lfs", fslib);