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