Home | History | Annotate | Download | only in src
      1 /*
      2 ** Code implementing read only functionality copied from
      3 ** src/lfs.c at commit 2fd989cd6c777583be1c93616018c55b2cbb1bcf:
      4 **
      5 ** LuaFileSystem 1.6.2
      6 ** Copyright 2003-2014 Kepler Project
      7 ** http://www.keplerproject.org/luafilesystem
      8 **
      9 ** File system manipulation library.
     10 ** This library offers these functions:
     11 ** lfs.attributes (filepath [, attributename])
     12 ** lfs.chdir (path)
     13 ** lfs.currentdir ()
     14 ** lfs.dir (path)
     15 **
     16 ** $Id: lfs.c,v 1.61 2009/07/04 02:10:16 mascarenhas Exp $
     17 */
     18 
     19 #include <dirent.h>
     20 #include <errno.h>
     21 #include <fcntl.h>
     22 #include <string.h>
     23 #include <sys/stat.h>
     24 #include <sys/types.h>
     25 #include <unistd.h>
     26 
     27 #include "lua.h"
     28 #include "lauxlib.h"
     29 #include "lualib.h"
     30 
     31 #define chdir_error	strerror(errno)
     32 
     33 /* Size of path buffer string, stolen from pwd.c */
     34 #ifndef PATH_MAX
     35 #  ifdef NAME_MAX
     36 #    define PATH_MAX   NAME_MAX
     37 #  elif FILENAME_MAX
     38 #    define PATH_MAX   FILENAME_MAX
     39 #  else
     40 #    define PATH_MAX   256
     41 #  endif       /* NAME_MAX */
     42 #endif /* PATH_MAX */
     43 
     44 
     45 #define DIR_METATABLE "directory metatable"
     46 typedef struct dir_data {
     47         int  closed;
     48         DIR *dir;
     49 } dir_data;
     50 
     51 
     52 #define STAT_STRUCT struct stat
     53 #define STAT_FUNC stat_via_fstat
     54 
     55 /* Emulate stat via fstat */
     56 int stat_via_fstat (const char *path, struct stat *buf)
     57 {
     58   int fd = open (path, O_RDONLY);
     59   if (fd == -1) {
     60     DIR *dir = opendir (path);
     61     if (!dir) return -1;
     62     closedir (dir);
     63     buf->st_mode=S_IFDIR;
     64     buf->st_size=0;
     65     return 0;
     66   }
     67   if (fstat (fd, buf) == -1) {
     68     int err = errno;
     69     close (fd);
     70     errno = err;
     71     return -1;
     72   }
     73   close (fd);
     74   return 0;
     75 }
     76 
     77 /*
     78 ** This function changes the working (current) directory
     79 */
     80 static int change_dir (lua_State *L) {
     81         const char *path = luaL_checkstring(L, 1);
     82         if (chdir(path)) {
     83                 lua_pushnil (L);
     84                 lua_pushfstring (L,"Unable to change working directory to '%s'\n%s\n",
     85                                 path, chdir_error);
     86                 return 2;
     87         } else {
     88                 lua_pushboolean (L, 1);
     89                 return 1;
     90         }
     91 }
     92 
     93 
     94 /*
     95 ** This function returns the current directory
     96 ** If unable to get the current directory, it returns nil
     97 ** and a string describing the error
     98 */
     99 static int get_dir (lua_State *L) {
    100   char *path;
    101   /* Passing (NULL, 0) is not guaranteed to work. Use a temp buffer and size instead. */
    102   char buf[PATH_MAX];
    103   if ((path = getcwd(buf, PATH_MAX)) == NULL) {
    104     lua_pushnil(L);
    105     lua_pushstring(L, strerror(errno));
    106     return 2;
    107   }
    108   else {
    109     lua_pushstring(L, path);
    110     return 1;
    111   }
    112 }
    113 
    114 
    115 /*
    116 ** Directory iterator
    117 */
    118 static int dir_iter (lua_State *L) {
    119         struct dirent *entry;
    120         dir_data *d = (dir_data *)luaL_checkudata (L, 1, DIR_METATABLE);
    121         luaL_argcheck (L, d->closed == 0, 1, "closed directory");
    122         if ((entry = readdir (d->dir)) != NULL) {
    123                 lua_pushstring (L, entry->d_name);
    124                 return 1;
    125         } else {
    126                 /* no more entries => close directory */
    127                 closedir (d->dir);
    128                 d->closed = 1;
    129                 return 0;
    130         }
    131 }
    132 
    133 
    134 /*
    135 ** Closes directory iterators
    136 */
    137 static int dir_close (lua_State *L) {
    138         dir_data *d = (dir_data *)lua_touserdata (L, 1);
    139         if (!d->closed && d->dir) {
    140                 closedir (d->dir);
    141         }
    142         d->closed = 1;
    143         return 0;
    144 }
    145 
    146 
    147 /*
    148 ** Factory of directory iterators
    149 */
    150 static int dir_iter_factory (lua_State *L) {
    151         const char *path = luaL_checkstring (L, 1);
    152         dir_data *d;
    153         lua_pushcfunction (L, dir_iter);
    154         d = (dir_data *) lua_newuserdata (L, sizeof(dir_data));
    155         luaL_getmetatable (L, DIR_METATABLE);
    156         lua_setmetatable (L, -2);
    157         d->closed = 0;
    158         d->dir = opendir (path);
    159         if (d->dir == NULL)
    160           luaL_error (L, "cannot open %s: %s", path, strerror (errno));
    161         return 2;
    162 }
    163 
    164 
    165 /*
    166 ** Creates directory metatable.
    167 */
    168 static int dir_create_meta (lua_State *L) {
    169         luaL_newmetatable (L, DIR_METATABLE);
    170 
    171         /* Method table */
    172         lua_newtable(L);
    173         lua_pushcfunction (L, dir_iter);
    174         lua_setfield(L, -2, "next");
    175         lua_pushcfunction (L, dir_close);
    176         lua_setfield(L, -2, "close");
    177 
    178         /* Metamethods */
    179         lua_setfield(L, -2, "__index");
    180         lua_pushcfunction (L, dir_close);
    181         lua_setfield (L, -2, "__gc");
    182         return 1;
    183 }
    184 
    185 
    186 /*
    187 ** Convert the inode protection mode to a string.
    188 */
    189 static const char *mode2string (mode_t mode) {
    190   if ( S_ISREG(mode) )
    191     return "file";
    192   else if ( S_ISDIR(mode) )
    193     return "directory";
    194   else if ( S_ISLNK(mode) )
    195         return "link";
    196   else if ( S_ISSOCK(mode) )
    197     return "socket";
    198   else if ( S_ISFIFO(mode) )
    199         return "named pipe";
    200   else if ( S_ISCHR(mode) )
    201         return "char device";
    202   else if ( S_ISBLK(mode) )
    203         return "block device";
    204   else
    205         return "other";
    206 }
    207 
    208 
    209 /* inode protection mode */
    210 static void push_st_mode (lua_State *L, STAT_STRUCT *info) {
    211         lua_pushstring (L, mode2string (info->st_mode));
    212 }
    213 /* file size, in bytes */
    214 static void push_st_size (lua_State *L, STAT_STRUCT *info) {
    215         lua_pushnumber (L, (lua_Number)info->st_size);
    216 }
    217 static void push_invalid (lua_State *L, STAT_STRUCT *info) {
    218   luaL_error(L, "invalid attribute name");
    219   info->st_size = 0; /* never reached */
    220 }
    221 
    222 typedef void (*_push_function) (lua_State *L, STAT_STRUCT *info);
    223 
    224 struct _stat_members {
    225         const char *name;
    226         _push_function push;
    227 };
    228 
    229 struct _stat_members members[] = {
    230         { "mode",         push_st_mode },
    231         { "size",         push_st_size },
    232         { NULL, push_invalid }
    233 };
    234 
    235 /*
    236 ** Get file or symbolic link information
    237 */
    238 static int _file_info_ (lua_State *L, int (*st)(const char*, STAT_STRUCT*)) {
    239         int i;
    240         STAT_STRUCT info;
    241         const char *file = luaL_checkstring (L, 1);
    242 
    243         if (st(file, &info)) {
    244                 lua_pushnil (L);
    245                 lua_pushfstring (L, "cannot obtain information from file `%s'", file);
    246                 return 2;
    247         }
    248         if (lua_isstring (L, 2)) {
    249                 int v;
    250                 const char *member = lua_tostring (L, 2);
    251                 if (strcmp (member, "mode") == 0) v = 0;
    252 #ifndef _WIN32
    253                 else if (strcmp (member, "blocks")  == 0) v = 11;
    254                 else if (strcmp (member, "blksize") == 0) v = 12;
    255 #endif
    256                 else /* look for member */
    257                         for (v = 1; members[v].name; v++)
    258                                 if (*members[v].name == *member)
    259                                         break;
    260                 /* push member value and return */
    261                 members[v].push (L, &info);
    262                 return 1;
    263         } else if (!lua_istable (L, 2))
    264                 /* creates a table if none is given */
    265                 lua_newtable (L);
    266         /* stores all members in table on top of the stack */
    267         for (i = 0; members[i].name; i++) {
    268                 lua_pushstring (L, members[i].name);
    269                 members[i].push (L, &info);
    270                 lua_rawset (L, -3);
    271         }
    272         return 1;
    273 }
    274 
    275 
    276 /*
    277 ** Get file information using stat.
    278 */
    279 static int file_info (lua_State *L) {
    280         return _file_info_ (L, STAT_FUNC);
    281 }
    282 
    283 
    284 static const struct luaL_Reg fslib[] = {
    285         {"attributes", file_info},
    286         {"chdir", change_dir},
    287         {"currentdir", get_dir},
    288         {"dir", dir_iter_factory},
    289         {NULL, NULL},
    290 };
    291 
    292 LUALIB_API int luaopen_lfs (lua_State *L) {
    293   dir_create_meta (L);
    294   luaL_newlib (L, fslib);
    295   return 1;
    296 }
    297