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