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