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"
108 typedef 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 */
pusherror(lua_State * L,const char * info)142 static 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
pushresult(lua_State * L,int i,const char * info)153 static 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 */
change_dir(lua_State * L)165 static 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 */
get_dir(lua_State * L)183 static 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 */
check_file(lua_State * L,int idx,const char * funcname)201 static 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 */
_file_lock(lua_State * L,FILE * fh,const char * mode,const long start,long len,const char * funcname)217 static 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
265 typedef struct lfs_Lock {
266 HANDLE fd;
267 } lfs_Lock;
lfs_lock_dir(lua_State * L)268 static 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 }
lfs_unlock_dir(lua_State * L)296 static 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
305 typedef struct lfs_Lock {
306 char *ln;
307 } lfs_Lock;
lfs_lock_dir(lua_State * L)308 static 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 }
lfs_unlock_dir(lua_State * L)329 static 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
lfs_g_setmode(lua_State * L,FILE * f,int arg)340 static 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
lfs_f_setmode(lua_State * L)366 static 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 */
file_lock(lua_State * L)377 static 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 */
file_unlock(lua_State * L)399 static 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 */
make_link(lua_State * L)420 static 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 */
make_dir(lua_State * L)437 static 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 */
remove_dir(lua_State * L)460 static 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 */
dir_iter(lua_State * L)479 static 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 */
dir_close(lua_State * L)526 static 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 */
dir_iter_factory(lua_State * L)545 static 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 */
dir_create_meta(lua_State * L)571 static 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 */
lock_create_meta(lua_State * L)592 static 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
mode2string(unsigned short mode)635 static const char *mode2string (unsigned short mode) {
636 #else
637 static 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 */
661 static 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 */
683 static void push_st_mode (lua_State *L, STAT_STRUCT *info) {
684 lua_pushstring (L, mode2string (info->st_mode));
685 }
686 /* device inode resides on */
687 static void push_st_dev (lua_State *L, STAT_STRUCT *info) {
688 lua_pushinteger (L, (lua_Integer) info->st_dev);
689 }
690 /* inode's number */
691 static 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 */
695 static 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 */
699 static 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 */
703 static 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 */
707 static 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 */
711 static 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 */
715 static 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 */
719 static 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 */
723 static 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 */
728 static 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 */
732 static 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
742 static 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
755 static 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 */
773 static void push_st_perm (lua_State *L, STAT_STRUCT *info) {
774 lua_pushstring (L, perm2string (info->st_mode));
775 }
776
777 typedef void (*_push_function) (lua_State *L, STAT_STRUCT *info);
778
779 struct _stat_members {
780 const char *name;
781 _push_function push;
782 };
783
784 struct _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 */
807 static 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 */
846 static 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 */
854 static 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 */
862 static 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
875 static 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
892 int 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 }
901