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