]> git.proxmox.com Git - ceph.git/blame - ceph/src/civetweb/src/third_party/lfs.c
buildsys: switch source download to quincy
[ceph.git] / ceph / src / civetweb / src / third_party / lfs.c
CommitLineData
7c673cae
FG
1/*
2** LuaFileSystem
3** Copyright Kepler Project 2003 (http://www.keplerproject.org/luafilesystem)
4**
5** File system manipulation library.
6** This library offers these functions:
7** lfs.attributes (filepath [, attributename])
8** lfs.chdir (path)
9** lfs.currentdir ()
10** lfs.dir (path)
11** lfs.lock (fh, mode)
12** lfs.lock_dir (path)
13** lfs.mkdir (path)
14** lfs.rmdir (path)
15** lfs.setmode (filepath, mode)
16** lfs.symlinkattributes (filepath [, attributename]) -- thanks to Sam Roberts
17** lfs.touch (filepath [, atime [, mtime]])
18** lfs.unlock (fh)
19**
20** $Id: lfs.c,v 1.61 2009/07/04 02:10:16 mascarenhas Exp $
21*/
22
23#if LUA_VERSION_NUM == 501
24#define lua_pushinteger lua_pushnumber
25#endif
26
27#ifndef LFS_DO_NOT_USE_LARGE_FILE
28#ifndef _WIN32
29#ifndef _AIX
30#define _FILE_OFFSET_BITS 64 /* Linux, Solaris and HP-UX */
31#else
32#define _LARGE_FILES 1 /* AIX */
33#endif
34#endif
35#endif
36
37#ifndef LFS_DO_NOT_USE_LARGE_FILE
38#define _LARGEFILE64_SOURCE
39#endif
40
41#include <errno.h>
42#include <stdio.h>
43#include <string.h>
44#include <stdlib.h>
45#include <time.h>
46#include <sys/stat.h>
47
48#ifdef _WIN32
49#include <direct.h>
50#include <windows.h>
51#include <io.h>
52#include <sys/locking.h>
53#ifdef __BORLANDC__
54 #include <utime.h>
55#else
56 #include <sys/utime.h>
57#endif
58#include <fcntl.h>
59#else
60#include <unistd.h>
61#include <dirent.h>
62#include <fcntl.h>
63#include <sys/types.h>
64#include <utime.h>
65#endif
66
67#include "civetweb_lua.h"
68
69#include "lfs.h"
70
71#define LFS_VERSION "1.6.3"
72#define LFS_LIBNAME "lfs"
73
74#if LUA_VERSION_NUM >= 503 /* Lua 5.3 */
75
76#ifndef luaL_optlong
77#define luaL_optlong luaL_optinteger
78#endif
79
80#endif
81
82#if LUA_VERSION_NUM < 502
83# define luaL_newlib(L,l) (lua_newtable(L), luaL_register(L,NULL,l))
84#endif
85
86/* Define 'strerror' for systems that do not implement it */
87#ifdef NO_STRERROR
88#define strerror(_) "System unable to describe the error"
89#endif
90
91/* Define 'getcwd' for systems that do not implement it */
92#ifdef NO_GETCWD
93#define getcwd(p,s) NULL
94#define getcwd_error "Function 'getcwd' not provided by system"
95#else
96#define getcwd_error strerror(errno)
97 #ifdef _WIN32
98 /* MAX_PATH seems to be 260. Seems kind of small. Is there a better one? */
99 #define LFS_MAXPATHLEN MAX_PATH
100 #else
101 /* For MAXPATHLEN: */
102 #include <sys/param.h>
103 #define LFS_MAXPATHLEN MAXPATHLEN
104 #endif
105#endif
106
107#define DIR_METATABLE "directory metatable"
108typedef struct dir_data {
109 int closed;
110#ifdef _WIN32
111 intptr_t hFile;
112 char pattern[MAX_PATH+1];
113#else
114 DIR *dir;
115#endif
116} dir_data;
117
118#define LOCK_METATABLE "lock metatable"
119
120#ifdef _WIN32
121 #ifdef __BORLANDC__
122 #define lfs_setmode(L,file,m) ((void)L, setmode(_fileno(file), m))
123 #define STAT_STRUCT struct stati64
124 #else
125 #define lfs_setmode(L,file,m) ((void)L, _setmode(_fileno(file), m))
126 #define STAT_STRUCT struct _stati64
127 #endif
128#define STAT_FUNC _stati64
129#define LSTAT_FUNC STAT_FUNC
130#else
131#define _O_TEXT 0
132#define _O_BINARY 0
133#define lfs_setmode(L,file,m) ((void)L, (void)file, (void)m, 0)
134#define STAT_STRUCT struct stat
135#define STAT_FUNC stat
136#define LSTAT_FUNC lstat
137#endif
138
139/*
140** Utility functions
141*/
142static int pusherror(lua_State *L, const char *info)
143{
144 lua_pushnil(L);
145 if (info==NULL)
146 lua_pushstring(L, strerror(errno));
147 else
148 lua_pushfstring(L, "%s: %s", info, strerror(errno));
149 lua_pushinteger(L, errno);
150 return 3;
151}
152
153static int pushresult(lua_State *L, int i, const char *info)
154{
155 if (i==-1)
156 return pusherror(L, info);
157 lua_pushinteger(L, i);
158 return 1;
159}
160
161
162/*
163** This function changes the working (current) directory
164*/
165static int change_dir (lua_State *L) {
166 const char *path = luaL_checkstring(L, 1);
167 if (chdir(path)) {
168 lua_pushnil (L);
169 lua_pushfstring (L,"Unable to change working directory to '%s'\n%s\n",
170 path, chdir_error);
171 return 2;
172 } else {
173 lua_pushboolean (L, 1);
174 return 1;
175 }
176}
177
178/*
179** This function returns the current directory
180** If unable to get the current directory, it returns nil
181** and a string describing the error
182*/
183static int get_dir (lua_State *L) {
184 char *path;
185 /* Passing (NULL, 0) is not guaranteed to work. Use a temp buffer and size instead. */
186 char buf[LFS_MAXPATHLEN];
187 if ((path = getcwd(buf, LFS_MAXPATHLEN)) == NULL) {
188 lua_pushnil(L);
189 lua_pushstring(L, getcwd_error);
190 return 2;
191 }
192 else {
193 lua_pushstring(L, path);
194 return 1;
195 }
196}
197
198/*
199** Check if the given element on the stack is a file and returns it.
200*/
201static FILE *check_file (lua_State *L, int idx, const char *funcname) {
202 FILE **fh = (FILE **)luaL_checkudata (L, idx, "FILE*");
203 if (fh == NULL) {
204 luaL_error (L, "%s: not a file", funcname);
205 return 0;
206 } else if (*fh == NULL) {
207 luaL_error (L, "%s: closed file", funcname);
208 return 0;
209 } else
210 return *fh;
211}
212
213
214/*
215**
216*/
217static int _file_lock (lua_State *L, FILE *fh, const char *mode, const long start, long len, const char *funcname) {
218 int code;
219#ifdef _WIN32
220 /* lkmode valid values are:
221 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.
222 LK_NBLCK Locks the specified bytes. If the bytes cannot be locked, the constant returns an error.
223 LK_NBRLCK Same as _LK_NBLCK.
224 LK_RLCK Same as _LK_LOCK.
225 LK_UNLCK Unlocks the specified bytes, which must have been previously locked.
226
227 Regions should be locked only briefly and should be unlocked before closing a file or exiting the program.
228
229 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__locking.asp
230 */
231 int lkmode;
232 switch (*mode) {
233 case 'r': lkmode = LK_NBLCK; break;
234 case 'w': lkmode = LK_NBLCK; break;
235 case 'u': lkmode = LK_UNLCK; break;
236 default : return luaL_error (L, "%s: invalid mode", funcname);
237 }
238 if (!len) {
239 fseek (fh, 0L, SEEK_END);
240 len = ftell (fh);
241 }
242 fseek (fh, start, SEEK_SET);
243#ifdef __BORLANDC__
244 code = locking (fileno(fh), lkmode, len);
245#else
246 code = _locking (fileno(fh), lkmode, len);
247#endif
248#else
249 struct flock f;
250 switch (*mode) {
251 case 'w': f.l_type = F_WRLCK; break;
252 case 'r': f.l_type = F_RDLCK; break;
253 case 'u': f.l_type = F_UNLCK; break;
254 default : return luaL_error (L, "%s: invalid mode", funcname);
255 }
256 f.l_whence = SEEK_SET;
257 f.l_start = (off_t)start;
258 f.l_len = (off_t)len;
259 code = fcntl (fileno(fh), F_SETLK, &f);
260#endif
261 return (code != -1);
262}
263
264#ifdef _WIN32
265typedef struct lfs_Lock {
266 HANDLE fd;
267} lfs_Lock;
268static int lfs_lock_dir(lua_State *L) {
269 size_t pathl; HANDLE fd;
270 lfs_Lock *lock;
271 char *ln;
272 const char *lockfile = "/lockfile.lfs";
273 const char *path = luaL_checklstring(L, 1, &pathl);
274 ln = (char*)malloc(pathl + strlen(lockfile) + 1);
275 if(!ln) {
276 lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2;
277 }
278 strcpy(ln, path); strcat(ln, lockfile);
279 if((fd = CreateFile(ln, GENERIC_WRITE, 0, NULL, CREATE_NEW,
280 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, NULL)) == INVALID_HANDLE_VALUE) {
281 int en = GetLastError();
282 free(ln); lua_pushnil(L);
283 if(en == ERROR_FILE_EXISTS || en == ERROR_SHARING_VIOLATION)
284 lua_pushstring(L, "File exists");
285 else
286 lua_pushstring(L, strerror(en));
287 return 2;
288 }
289 free(ln);
290 lock = (lfs_Lock*)lua_newuserdata(L, sizeof(lfs_Lock));
291 lock->fd = fd;
292 luaL_getmetatable (L, LOCK_METATABLE);
293 lua_setmetatable (L, -2);
294 return 1;
295}
296static int lfs_unlock_dir(lua_State *L) {
297 lfs_Lock *lock = (lfs_Lock *)luaL_checkudata(L, 1, LOCK_METATABLE);
298 if(lock->fd != INVALID_HANDLE_VALUE) {
299 CloseHandle(lock->fd);
300 lock->fd=INVALID_HANDLE_VALUE;
301 }
302 return 0;
303}
304#else
305typedef struct lfs_Lock {
306 char *ln;
307} lfs_Lock;
308static int lfs_lock_dir(lua_State *L) {
309 lfs_Lock *lock;
310 size_t pathl;
311 char *ln;
312 const char *lockfile = "/lockfile.lfs";
313 const char *path = luaL_checklstring(L, 1, &pathl);
314 lock = (lfs_Lock*)lua_newuserdata(L, sizeof(lfs_Lock));
315 ln = (char*)malloc(pathl + strlen(lockfile) + 1);
316 if(!ln) {
317 lua_pushnil(L); lua_pushstring(L, strerror(errno)); return 2;
318 }
319 strcpy(ln, path); strcat(ln, lockfile);
320 if(symlink("lock", ln) == -1) {
321 free(ln); lua_pushnil(L);
322 lua_pushstring(L, strerror(errno)); return 2;
323 }
324 lock->ln = ln;
325 luaL_getmetatable (L, LOCK_METATABLE);
326 lua_setmetatable (L, -2);
327 return 1;
328}
329static int lfs_unlock_dir(lua_State *L) {
330 lfs_Lock *lock = (lfs_Lock *)luaL_checkudata(L, 1, LOCK_METATABLE);
331 if(lock->ln) {
332 unlink(lock->ln);
333 free(lock->ln);
334 lock->ln = NULL;
335 }
336 return 0;
337}
338#endif
339
340static int lfs_g_setmode (lua_State *L, FILE *f, int arg) {
341 static const int mode[] = {_O_BINARY, _O_TEXT};
342 static const char *const modenames[] = {"binary", "text", NULL};
343 int op = luaL_checkoption(L, arg, NULL, modenames);
344 int res = lfs_setmode(L, f, mode[op]);
345 if (res != -1) {
346 int i;
347 lua_pushboolean(L, 1);
348 for (i = 0; modenames[i] != NULL; i++) {
349 if (mode[i] == res) {
350 lua_pushstring(L, modenames[i]);
351 goto exit;
352 }
353 }
354 lua_pushnil(L);
355 exit:
356 return 2;
357 } else {
358 int en = errno;
359 lua_pushnil(L);
360 lua_pushfstring(L, "%s", strerror(en));
361 lua_pushinteger(L, en);
362 return 3;
363 }
364}
365
366static int lfs_f_setmode(lua_State *L) {
367 return lfs_g_setmode(L, check_file(L, 1, "setmode"), 2);
368}
369
370/*
371** Locks a file.
372** @param #1 File handle.
373** @param #2 String with lock mode ('w'rite, 'r'ead).
374** @param #3 Number with start position (optional).
375** @param #4 Number with length (optional).
376*/
377static int file_lock (lua_State *L) {
378 FILE *fh = check_file (L, 1, "lock");
379 const char *mode = luaL_checkstring (L, 2);
380 const long start = (long) luaL_optinteger (L, 3, 0);
381 long len = (long) luaL_optinteger (L, 4, 0);
382 if (_file_lock (L, fh, mode, start, len, "lock")) {
383 lua_pushboolean (L, 1);
384 return 1;
385 } else {
386 lua_pushnil (L);
387 lua_pushfstring (L, "%s", strerror(errno));
388 return 2;
389 }
390}
391
392
393/*
394** Unlocks a file.
395** @param #1 File handle.
396** @param #2 Number with start position (optional).
397** @param #3 Number with length (optional).
398*/
399static int file_unlock (lua_State *L) {
400 FILE *fh = check_file (L, 1, "unlock");
401 const long start = (long) luaL_optinteger (L, 2, 0);
402 long len = (long) luaL_optinteger (L, 3, 0);
403 if (_file_lock (L, fh, "u", start, len, "unlock")) {
404 lua_pushboolean (L, 1);
405 return 1;
406 } else {
407 lua_pushnil (L);
408 lua_pushfstring (L, "%s", strerror(errno));
409 return 2;
410 }
411}
412
413
414/*
415** Creates a link.
416** @param #1 Object to link to.
417** @param #2 Name of link.
418** @param #3 True if link is symbolic (optional).
419*/
420static int make_link(lua_State *L)
421{
422#ifndef _WIN32
423 const char *oldpath = luaL_checkstring(L, 1);
424 const char *newpath = luaL_checkstring(L, 2);
425 return pushresult(L,
426 (lua_toboolean(L,3) ? symlink : link)(oldpath, newpath), NULL);
427#else
428 return pusherror(L, "make_link is not supported on Windows");
429#endif
430}
431
432
433/*
434** Creates a directory.
435** @param #1 Directory path.
436*/
437static int make_dir (lua_State *L) {
438 const char *path = luaL_checkstring (L, 1);
439 int fail;
440#ifdef _WIN32
441 fail = _mkdir (path);
442#else
443 fail = mkdir (path, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP |
444 S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH );
445#endif
446 if (fail) {
447 lua_pushnil (L);
448 lua_pushfstring (L, "%s", strerror(errno));
449 return 2;
450 }
451 lua_pushboolean (L, 1);
452 return 1;
453}
454
455
456/*
457** Removes a directory.
458** @param #1 Directory path.
459*/
460static int remove_dir (lua_State *L) {
461 const char *path = luaL_checkstring (L, 1);
462 int fail;
463
464 fail = rmdir (path);
465
466 if (fail) {
467 lua_pushnil (L);
468 lua_pushfstring (L, "%s", strerror(errno));
469 return 2;
470 }
471 lua_pushboolean (L, 1);
472 return 1;
473}
474
475
476/*
477** Directory iterator
478*/
479static int dir_iter (lua_State *L) {
480#ifdef _WIN32
481 struct _finddata_t c_file;
482#else
483 struct dirent *entry;
484#endif
485 dir_data *d = (dir_data *)luaL_checkudata (L, 1, DIR_METATABLE);
486 luaL_argcheck (L, d->closed == 0, 1, "closed directory");
487#ifdef _WIN32
488 if (d->hFile == 0L) { /* first entry */
489 if ((d->hFile = _findfirst (d->pattern, &c_file)) == -1L) {
490 lua_pushnil (L);
491 lua_pushstring (L, strerror (errno));
492 d->closed = 1;
493 return 2;
494 } else {
495 lua_pushstring (L, c_file.name);
496 return 1;
497 }
498 } else { /* next entry */
499 if (_findnext (d->hFile, &c_file) == -1L) {
500 /* no more entries => close directory */
501 _findclose (d->hFile);
502 d->closed = 1;
503 return 0;
504 } else {
505 lua_pushstring (L, c_file.name);
506 return 1;
507 }
508 }
509#else
510 if ((entry = readdir (d->dir)) != NULL) {
511 lua_pushstring (L, entry->d_name);
512 return 1;
513 } else {
514 /* no more entries => close directory */
515 closedir (d->dir);
516 d->closed = 1;
517 return 0;
518 }
519#endif
520}
521
522
523/*
524** Closes directory iterators
525*/
526static int dir_close (lua_State *L) {
527 dir_data *d = (dir_data *)lua_touserdata (L, 1);
528#ifdef _WIN32
529 if (!d->closed && d->hFile) {
530 _findclose (d->hFile);
531 }
532#else
533 if (!d->closed && d->dir) {
534 closedir (d->dir);
535 }
536#endif
537 d->closed = 1;
538 return 0;
539}
540
541
542/*
543** Factory of directory iterators
544*/
545static int dir_iter_factory (lua_State *L) {
546 const char *path = luaL_checkstring (L, 1);
547 dir_data *d;
548 lua_pushcfunction (L, dir_iter);
549 d = (dir_data *) lua_newuserdata (L, sizeof(dir_data));
550 luaL_getmetatable (L, DIR_METATABLE);
551 lua_setmetatable (L, -2);
552 d->closed = 0;
553#ifdef _WIN32
554 d->hFile = 0L;
555 if (strlen(path) > MAX_PATH-2)
556 luaL_error (L, "path too long: %s", path);
557 else
558 sprintf (d->pattern, "%s/*", path);
559#else
560 d->dir = opendir (path);
561 if (d->dir == NULL)
562 luaL_error (L, "cannot open %s: %s", path, strerror (errno));
563#endif
564 return 2;
565}
566
567
568/*
569** Creates directory metatable.
570*/
571static int dir_create_meta (lua_State *L) {
572 luaL_newmetatable (L, DIR_METATABLE);
573
574 /* Method table */
575 lua_newtable(L);
576 lua_pushcfunction (L, dir_iter);
577 lua_setfield(L, -2, "next");
578 lua_pushcfunction (L, dir_close);
579 lua_setfield(L, -2, "close");
580
581 /* Metamethods */
582 lua_setfield(L, -2, "__index");
583 lua_pushcfunction (L, dir_close);
584 lua_setfield (L, -2, "__gc");
585 return 1;
586}
587
588
589/*
590** Creates lock metatable.
591*/
592static int lock_create_meta (lua_State *L) {
593 luaL_newmetatable (L, LOCK_METATABLE);
594
595 /* Method table */
596 lua_newtable(L);
597 lua_pushcfunction(L, lfs_unlock_dir);
598 lua_setfield(L, -2, "free");
599
600 /* Metamethods */
601 lua_setfield(L, -2, "__index");
602 lua_pushcfunction(L, lfs_unlock_dir);
603 lua_setfield(L, -2, "__gc");
604 return 1;
605}
606
607
608#ifdef _WIN32
609 #ifndef S_ISDIR
610 #define S_ISDIR(mode) (mode&_S_IFDIR)
611 #endif
612 #ifndef S_ISREG
613 #define S_ISREG(mode) (mode&_S_IFREG)
614 #endif
615 #ifndef S_ISLNK
616 #define S_ISLNK(mode) (0)
617 #endif
618 #ifndef S_ISSOCK
619 #define S_ISSOCK(mode) (0)
620 #endif
621 #ifndef S_ISFIFO
622 #define S_ISFIFO(mode) (0)
623 #endif
624 #ifndef S_ISCHR
625 #define S_ISCHR(mode) (mode&_S_IFCHR)
626 #endif
627 #ifndef S_ISBLK
628 #define S_ISBLK(mode) (0)
629 #endif
630#endif
631/*
632** Convert the inode protection mode to a string.
633*/
634#ifdef _WIN32
635static const char *mode2string (unsigned short mode) {
636#else
637static const char *mode2string (mode_t mode) {
638#endif
639 if ( S_ISREG(mode) )
640 return "file";
641 else if ( S_ISDIR(mode) )
642 return "directory";
643 else if ( S_ISLNK(mode) )
644 return "link";
645 else if ( S_ISSOCK(mode) )
646 return "socket";
647 else if ( S_ISFIFO(mode) )
648 return "named pipe";
649 else if ( S_ISCHR(mode) )
650 return "char device";
651 else if ( S_ISBLK(mode) )
652 return "block device";
653 else
654 return "other";
655}
656
657
658/*
659** Set access time and modification values for file
660*/
661static int file_utime (lua_State *L) {
662 const char *file = luaL_checkstring (L, 1);
663 struct utimbuf utb, *buf;
664
665 if (lua_gettop (L) == 1) /* set to current date/time */
666 buf = NULL;
667 else {
668 utb.actime = (time_t)luaL_optnumber (L, 2, 0);
669 utb.modtime = (time_t) luaL_optinteger (L, 3, utb.actime);
670 buf = &utb;
671 }
672 if (utime (file, buf)) {
673 lua_pushnil (L);
674 lua_pushfstring (L, "%s", strerror (errno));
675 return 2;
676 }
677 lua_pushboolean (L, 1);
678 return 1;
679}
680
681
682/* inode protection mode */
683static void push_st_mode (lua_State *L, STAT_STRUCT *info) {
684 lua_pushstring (L, mode2string (info->st_mode));
685}
686/* device inode resides on */
687static void push_st_dev (lua_State *L, STAT_STRUCT *info) {
688 lua_pushinteger (L, (lua_Integer) info->st_dev);
689}
690/* inode's number */
691static void push_st_ino (lua_State *L, STAT_STRUCT *info) {
692 lua_pushinteger (L, (lua_Integer) info->st_ino);
693}
694/* number of hard links to the file */
695static void push_st_nlink (lua_State *L, STAT_STRUCT *info) {
696 lua_pushinteger (L, (lua_Integer)info->st_nlink);
697}
698/* user-id of owner */
699static void push_st_uid (lua_State *L, STAT_STRUCT *info) {
700 lua_pushinteger (L, (lua_Integer)info->st_uid);
701}
702/* group-id of owner */
703static void push_st_gid (lua_State *L, STAT_STRUCT *info) {
704 lua_pushinteger (L, (lua_Integer)info->st_gid);
705}
706/* device type, for special file inode */
707static void push_st_rdev (lua_State *L, STAT_STRUCT *info) {
708 lua_pushinteger (L, (lua_Integer) info->st_rdev);
709}
710/* time of last access */
711static void push_st_atime (lua_State *L, STAT_STRUCT *info) {
712 lua_pushinteger (L, (lua_Integer) info->st_atime);
713}
714/* time of last data modification */
715static void push_st_mtime (lua_State *L, STAT_STRUCT *info) {
716 lua_pushinteger (L, (lua_Integer) info->st_mtime);
717}
718/* time of last file status change */
719static void push_st_ctime (lua_State *L, STAT_STRUCT *info) {
720 lua_pushinteger (L, (lua_Integer) info->st_ctime);
721}
722/* file size, in bytes */
723static void push_st_size (lua_State *L, STAT_STRUCT *info) {
724 lua_pushinteger (L, (lua_Integer)info->st_size);
725}
726#ifndef _WIN32
727/* blocks allocated for file */
728static void push_st_blocks (lua_State *L, STAT_STRUCT *info) {
729 lua_pushinteger (L, (lua_Integer)info->st_blocks);
730}
731/* optimal file system I/O blocksize */
732static void push_st_blksize (lua_State *L, STAT_STRUCT *info) {
733 lua_pushinteger (L, (lua_Integer)info->st_blksize);
734}
735#endif
736
737 /*
738** Convert the inode protection mode to a permission list.
739*/
740
741#ifdef _WIN32
742static const char *perm2string (unsigned short mode) {
743 static char perms[10] = "---------";
744 int i;
745 for (i=0;i<9;i++) perms[i]='-';
746 if (mode & _S_IREAD)
747 { perms[0] = 'r'; perms[3] = 'r'; perms[6] = 'r'; }
748 if (mode & _S_IWRITE)
749 { perms[1] = 'w'; perms[4] = 'w'; perms[7] = 'w'; }
750 if (mode & _S_IEXEC)
751 { perms[2] = 'x'; perms[5] = 'x'; perms[8] = 'x'; }
752 return perms;
753}
754#else
755static const char *perm2string (mode_t mode) {
756 static char perms[10] = "---------";
757 int i;
758 for (i=0;i<9;i++) perms[i]='-';
759 if (mode & S_IRUSR) perms[0] = 'r';
760 if (mode & S_IWUSR) perms[1] = 'w';
761 if (mode & S_IXUSR) perms[2] = 'x';
762 if (mode & S_IRGRP) perms[3] = 'r';
763 if (mode & S_IWGRP) perms[4] = 'w';
764 if (mode & S_IXGRP) perms[5] = 'x';
765 if (mode & S_IROTH) perms[6] = 'r';
766 if (mode & S_IWOTH) perms[7] = 'w';
767 if (mode & S_IXOTH) perms[8] = 'x';
768 return perms;
769}
770#endif
771
772/* permssions string */
773static void push_st_perm (lua_State *L, STAT_STRUCT *info) {
774 lua_pushstring (L, perm2string (info->st_mode));
775}
776
777typedef void (*_push_function) (lua_State *L, STAT_STRUCT *info);
778
779struct _stat_members {
780 const char *name;
781 _push_function push;
782};
783
784struct _stat_members members[] = {
785 { "mode", push_st_mode },
786 { "dev", push_st_dev },
787 { "ino", push_st_ino },
788 { "nlink", push_st_nlink },
789 { "uid", push_st_uid },
790 { "gid", push_st_gid },
791 { "rdev", push_st_rdev },
792 { "access", push_st_atime },
793 { "modification", push_st_mtime },
794 { "change", push_st_ctime },
795 { "size", push_st_size },
796 { "permissions", push_st_perm },
797#ifndef _WIN32
798 { "blocks", push_st_blocks },
799 { "blksize", push_st_blksize },
800#endif
801 { NULL, NULL }
802};
803
804/*
805** Get file or symbolic link information
806*/
807static int _file_info_ (lua_State *L, int (*st)(const char*, STAT_STRUCT*)) {
808 STAT_STRUCT info;
809 const char *file = luaL_checkstring (L, 1);
810 int i;
811
812 if (st(file, &info)) {
813 lua_pushnil (L);
814 lua_pushfstring (L, "cannot obtain information from file `%s'", file);
815 return 2;
816 }
817 if (lua_isstring (L, 2)) {
818 const char *member = lua_tostring (L, 2);
819 for (i = 0; members[i].name; i++) {
820 if (strcmp(members[i].name, member) == 0) {
821 /* push member value and return */
822 members[i].push (L, &info);
823 return 1;
824 }
825 }
826 /* member not found */
827 return luaL_error(L, "invalid attribute name");
828 }
829 /* creates a table if none is given */
830 if (!lua_istable (L, 2)) {
831 lua_newtable (L);
832 }
833 /* stores all members in table on top of the stack */
834 for (i = 0; members[i].name; i++) {
835 lua_pushstring (L, members[i].name);
836 members[i].push (L, &info);
837 lua_rawset (L, -3);
838 }
839 return 1;
840}
841
842
843/*
844** Get file information using stat.
845*/
846static int file_info (lua_State *L) {
847 return _file_info_ (L, STAT_FUNC);
848}
849
850
851/*
852** Get symbolic link information using lstat.
853*/
854static int link_info (lua_State *L) {
855 return _file_info_ (L, LSTAT_FUNC);
856}
857
858
859/*
860** Assumes the table is on top of the stack.
861*/
862static void set_info (lua_State *L) {
863 lua_pushliteral (L, "_COPYRIGHT");
864 lua_pushliteral (L, "Copyright (C) 2003-2012 Kepler Project");
865 lua_settable (L, -3);
866 lua_pushliteral (L, "_DESCRIPTION");
867 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");
868 lua_settable (L, -3);
869 lua_pushliteral (L, "_VERSION");
870 lua_pushliteral (L, "LuaFileSystem "LFS_VERSION);
871 lua_settable (L, -3);
872}
873
874
875static const struct luaL_Reg fslib[] = {
876 {"attributes", file_info},
877 {"chdir", change_dir},
878 {"currentdir", get_dir},
879 {"dir", dir_iter_factory},
880 {"link", make_link},
881 {"lock", file_lock},
882 {"mkdir", make_dir},
883 {"rmdir", remove_dir},
884 {"symlinkattributes", link_info},
885 {"setmode", lfs_f_setmode},
886 {"touch", file_utime},
887 {"unlock", file_unlock},
888 {"lock_dir", lfs_lock_dir},
889 {NULL, NULL},
890};
891
892int luaopen_lfs (lua_State *L) {
893 dir_create_meta (L);
894 lock_create_meta (L);
895 luaL_newlib (L, fslib);
896 lua_pushvalue(L, -1);
897 lua_setglobal(L, LFS_LIBNAME);
898 set_info (L);
899 return 1;
900}