cgi-bin/tek/lib/posix.c
changeset 251 2de5931b723d
parent 241 c6c81629f54e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/cgi-bin/tek/lib/posix.c	Fri Oct 24 01:35:27 2008 +0200
     1.3 @@ -0,0 +1,467 @@
     1.4 +
     1.5 +/*
     1.6 +**	tek.lib.posix - tek POSIX library
     1.7 +**	Written by Timm S. Mueller <tmueller at neoscientists.org>
     1.8 +**	See copyright notice in COPYRIGHT
     1.9 +*/
    1.10 +
    1.11 +
    1.12 +#include <stdlib.h>
    1.13 +#include <string.h>
    1.14 +#include <sys/types.h>
    1.15 +#include <sys/stat.h>
    1.16 +#include <unistd.h>
    1.17 +#include <dirent.h>
    1.18 +#include <errno.h>
    1.19 +#include <math.h>
    1.20 +#include <time.h>
    1.21 +#include <lua.h>
    1.22 +#include <lualib.h>
    1.23 +#include <lauxlib.h>
    1.24 +
    1.25 +
    1.26 +#define DIRCLASSNAME "dir*"
    1.27 +
    1.28 +
    1.29 +static void
    1.30 +setfield(lua_State *L, const char *attr, const char *key, lua_Integer n)
    1.31 +{
    1.32 +	if (attr == NULL || strcmp(attr, key) == 0)
    1.33 +		lua_pushinteger(L, n);
    1.34 +	if (attr == NULL)
    1.35 +		lua_setfield(L, -2, key);
    1.36 +}
    1.37 +
    1.38 +
    1.39 +static int
    1.40 +setstat(lua_State *L, int result, struct stat *s, const char *attr)
    1.41 +{
    1.42 +	if (result != 0)
    1.43 +	{
    1.44 +		lua_pushnil(L);
    1.45 +		lua_pushstring(L, strerror(errno));
    1.46 +		return 2;
    1.47 +	}
    1.48 +
    1.49 +	if (attr == NULL)
    1.50 +		lua_newtable(L);
    1.51 +
    1.52 +	setfield(L, attr, "dev", s->st_dev);
    1.53 +	setfield(L, attr, "ino", s->st_ino);
    1.54 +
    1.55 +	if (attr == NULL || strcmp(attr, "mode") == 0)
    1.56 +	{
    1.57 +		if (S_ISREG(s->st_mode))
    1.58 +			lua_pushstring(L, "file");
    1.59 +		else if (S_ISDIR(s->st_mode))
    1.60 +			lua_pushstring(L, "directory");
    1.61 +		else if (S_ISLNK(s->st_mode))
    1.62 +			lua_pushstring(L, "link");
    1.63 +		else if (S_ISSOCK(s->st_mode))
    1.64 +			lua_pushstring(L, "socket");
    1.65 +		else if (S_ISFIFO(s->st_mode))
    1.66 +			lua_pushstring(L, "named pipe");
    1.67 +		else if (S_ISCHR(s->st_mode))
    1.68 +			lua_pushstring(L, "char device");
    1.69 +		else if (S_ISBLK(s->st_mode))
    1.70 +			lua_pushstring(L, "block device");
    1.71 +		else
    1.72 +			lua_pushstring(L, "other");
    1.73 +		if (attr == NULL)
    1.74 +			lua_setfield(L, -2, "mode");
    1.75 +	}
    1.76 +
    1.77 +	setfield(L, attr, "nlink", s->st_nlink);
    1.78 +	setfield(L, attr, "uid", s->st_uid);
    1.79 +	setfield(L, attr, "gid", s->st_gid);
    1.80 +	setfield(L, attr, "rdev", s->st_rdev);
    1.81 +	setfield(L, attr, "access", s->st_atime);
    1.82 +	setfield(L, attr, "modification", s->st_mtime);
    1.83 +	setfield(L, attr, "change", s->st_ctime);
    1.84 +	setfield(L, attr, "size", s->st_size);
    1.85 +	setfield(L, attr, "blocks", s->st_blocks);
    1.86 +	setfield(L, attr, "blksize", s->st_blksize);
    1.87 +
    1.88 +	return 1;
    1.89 +}
    1.90 +
    1.91 +
    1.92 +static int
    1.93 +posix_stat(lua_State *L)
    1.94 +{
    1.95 +	const char *path = luaL_checkstring(L, 1);
    1.96 +	const char *attr = luaL_optstring(L, 2, NULL);
    1.97 +	struct stat s;
    1.98 +	return setstat(L, stat(path, &s), &s, attr);
    1.99 +}
   1.100 +
   1.101 +
   1.102 +static int
   1.103 +posix_lstat(lua_State *L)
   1.104 +{
   1.105 +	const char *path = luaL_checkstring(L, 1);
   1.106 +	const char *attr = luaL_optstring(L, 2, NULL);
   1.107 +	struct stat s;
   1.108 +	return setstat(L, lstat(path, &s), &s, attr);
   1.109 +}
   1.110 +
   1.111 +
   1.112 +static int
   1.113 +posix_opendir(lua_State *L)
   1.114 +{
   1.115 +	const char *path = luaL_checkstring(L, 1);
   1.116 +	DIR **pdir = lua_newuserdata(L, sizeof(void *));
   1.117 +	/* s: udata */
   1.118 +	*pdir = opendir(path);
   1.119 +	if (*pdir == NULL)
   1.120 +	{
   1.121 +		lua_pushnil(L);
   1.122 +		lua_pushstring(L, strerror(errno));
   1.123 +		return 2;
   1.124 +	}
   1.125 +	lua_getfield(L, LUA_REGISTRYINDEX, DIRCLASSNAME);
   1.126 +	/* s: udata, meta */
   1.127 +	lua_setmetatable(L, -2);
   1.128 +	/* s: udata */
   1.129 +	return 1;
   1.130 +}
   1.131 +
   1.132 +
   1.133 +static DIR **
   1.134 +getinstptr(lua_State *L, int narg, const char *classname)
   1.135 +{
   1.136 +	DIR **pinst = luaL_checkudata(L, narg, classname);
   1.137 +	if (*pinst) return pinst;
   1.138 +	luaL_argerror(L, narg, "Closed handle");
   1.139 +	return NULL;
   1.140 +}
   1.141 +
   1.142 +
   1.143 +static int
   1.144 +posix_closedir(lua_State *L)
   1.145 +{
   1.146 +	DIR **pdir = getinstptr(L, 1, DIRCLASSNAME);
   1.147 +	closedir(*pdir);
   1.148 +	*pdir = NULL;
   1.149 +	return 0;
   1.150 +}
   1.151 +
   1.152 +
   1.153 +static int
   1.154 +posix_readdir(lua_State *L)
   1.155 +{
   1.156 +	DIR *dir = *getinstptr(L, 1, DIRCLASSNAME);
   1.157 +	struct dirent *de = readdir(dir);
   1.158 +	if (de)
   1.159 +		lua_pushstring(L, de->d_name);
   1.160 +	else
   1.161 +		lua_pushnil(L);
   1.162 +	return 1;
   1.163 +}
   1.164 +
   1.165 +
   1.166 +static int
   1.167 +posix_readlink(lua_State *L)
   1.168 +{
   1.169 +	const char *path = luaL_checkstring(L, 1);
   1.170 +	char buf[PATH_MAX + 1];
   1.171 +	ssize_t len = readlink(path, buf, sizeof(buf) - 1);
   1.172 +	if (len < 0)
   1.173 +	{
   1.174 +		lua_pushnil(L);
   1.175 +		lua_pushstring(L, strerror(errno));
   1.176 +		return 2;
   1.177 +	}
   1.178 +	buf[len] = 0;
   1.179 +	lua_pushstring(L, buf);
   1.180 +	return 1;
   1.181 +}
   1.182 +
   1.183 +
   1.184 +static int
   1.185 +posix_mkdir(lua_State *L)
   1.186 +{
   1.187 +	const char *path = luaL_checkstring(L, 1);
   1.188 +	if (mkdir(path, 0775) == 0)
   1.189 +	{
   1.190 +		lua_pushboolean(L, 1);
   1.191 +		return 1;
   1.192 +	}
   1.193 +	lua_pushnil(L);
   1.194 +	lua_pushstring(L, strerror(errno));
   1.195 +	return 2;
   1.196 +}
   1.197 +
   1.198 +
   1.199 +static int
   1.200 +posix_symlink(lua_State *L)
   1.201 +{
   1.202 +	const char *oldpath = luaL_checkstring(L, 1);
   1.203 +	const char *newpath = luaL_checkstring(L, 2);
   1.204 +	if (symlink(oldpath, newpath) == 0)
   1.205 +	{
   1.206 +		lua_pushboolean(L, 1);
   1.207 +		return 1;
   1.208 +	}
   1.209 +	lua_pushnil(L);
   1.210 +	lua_pushstring(L, strerror(errno));
   1.211 +	return 2;
   1.212 +}
   1.213 +
   1.214 +
   1.215 +static int
   1.216 +resolvepath(const char *src, char *dest)
   1.217 +{
   1.218 +	int len = strlen(src);
   1.219 +	const char *sp = src + len;
   1.220 +	char *dp = dest;
   1.221 +	int dc = 0, slc = 0, eac = 0, wc = 0;
   1.222 +	int i, c;
   1.223 +
   1.224 +	while (len--)
   1.225 +	{
   1.226 +		c = *(--sp);
   1.227 +		switch (c)
   1.228 +		{
   1.229 +			case '/':
   1.230 +				if (dc == 2)
   1.231 +					eac++;
   1.232 +				dc = 0;
   1.233 +				slc = 1;
   1.234 +				wc = 0;
   1.235 +				break;
   1.236 +
   1.237 +			case '.':
   1.238 +				if (slc)
   1.239 +				{
   1.240 +					dc++;
   1.241 +					break;
   1.242 +				}
   1.243 +				/* fallthru: */
   1.244 +
   1.245 +			default:
   1.246 +				if (wc)
   1.247 +					break;
   1.248 +
   1.249 +				if (slc)
   1.250 +				{
   1.251 +					slc = 0;
   1.252 +
   1.253 +					if (eac > 0)
   1.254 +					{
   1.255 +						/* resolve one eatcount */
   1.256 +						eac--;
   1.257 +						/* now wait for next path part */
   1.258 +						wc = 1;
   1.259 +						break;
   1.260 +					}
   1.261 +
   1.262 +					*dp++ = '/';
   1.263 +				}
   1.264 +
   1.265 +				while (dc == 2 || dc == 1)
   1.266 +				{
   1.267 +					*dp++ = '.';
   1.268 +					dc--;
   1.269 +				}
   1.270 +				dc = 0;
   1.271 +
   1.272 +				*dp++ = c;
   1.273 +				break;
   1.274 +		}
   1.275 +	}
   1.276 +
   1.277 +	/* unresolved eatcount */
   1.278 +	if (eac)
   1.279 +		return 0;
   1.280 +
   1.281 +	/* resolve remaining slash */
   1.282 +	if (slc)
   1.283 +		*dp++ = '/';
   1.284 +
   1.285 +	*dp = 0;
   1.286 +
   1.287 +	len = dp - dest;
   1.288 +	for (i = 0; i < len / 2; ++i)
   1.289 +	{
   1.290 +		char t = dest[i];
   1.291 +		dest[i] = dest[len - i - 1];
   1.292 +		dest[len - i - 1] = t;
   1.293 +	}
   1.294 +
   1.295 +	return 1;
   1.296 +}
   1.297 +
   1.298 +
   1.299 +static int
   1.300 +posix_abspath(lua_State *L)
   1.301 +{
   1.302 +	const char *path = luaL_checkstring(L, 1);
   1.303 +	char *pwd = NULL;
   1.304 +	size_t pwdsize = 16;
   1.305 +	size_t len1, len2;
   1.306 +	char *srcpath, *dstpath;
   1.307 +
   1.308 +	for (;;)
   1.309 +	{
   1.310 +		if (path[0] == '/')
   1.311 +		{
   1.312 +			pwd = malloc(2);
   1.313 +			if (pwd == NULL)
   1.314 +				break;
   1.315 +			pwd[0] = '/';
   1.316 +			pwd[1] = 0;
   1.317 +		}
   1.318 +		else
   1.319 +		{
   1.320 +			char *newpwd = realloc(pwd, pwdsize);
   1.321 +			if (newpwd == NULL)
   1.322 +				break;
   1.323 +			pwd = newpwd;
   1.324 +
   1.325 +			if (!getcwd(pwd, pwdsize))
   1.326 +			{
   1.327 +				if (errno == ERANGE)
   1.328 +				{
   1.329 +					pwdsize <<= 1;
   1.330 +					continue;
   1.331 +				}
   1.332 +				lua_pushnil(L);
   1.333 +				lua_pushstring(L, strerror(errno));
   1.334 +				return 2;
   1.335 +			}
   1.336 +		}
   1.337 +
   1.338 +		len1 = strlen(pwd);
   1.339 +		len2 = strlen(path);
   1.340 +		srcpath = malloc(len1 + 1 + len2 + 1);
   1.341 +		dstpath = malloc(len1 + 1 + len2 + 1);
   1.342 +
   1.343 +		if (srcpath && dstpath)
   1.344 +		{
   1.345 +			int res;
   1.346 +
   1.347 +			strcpy(srcpath, pwd);
   1.348 +			free(pwd);
   1.349 +			srcpath[len1] = '/';
   1.350 +			strcpy(srcpath + len1 + 1, path);
   1.351 +			res = resolvepath(srcpath, dstpath);
   1.352 +			free(srcpath);
   1.353 +
   1.354 +			if (res)
   1.355 +			{
   1.356 +				lua_pushstring(L, dstpath);
   1.357 +				free(dstpath);
   1.358 +				return 1;
   1.359 +			}
   1.360 +
   1.361 +			free(dstpath);
   1.362 +			lua_pushnil(L);
   1.363 +			lua_pushstring(L, "Not a valid path");
   1.364 +			return 2;
   1.365 +		}
   1.366 +
   1.367 +		free(srcpath);
   1.368 +		free(dstpath);
   1.369 +		break;
   1.370 +	}
   1.371 +
   1.372 +	free(pwd);
   1.373 +	luaL_error(L, "Out of memory");
   1.374 +	return 0;
   1.375 +}
   1.376 +
   1.377 +
   1.378 +static int
   1.379 +posix_nanosleep(lua_State *L)
   1.380 +{
   1.381 +	struct timespec req;
   1.382 +	lua_Number d = luaL_checknumber(L, 1);
   1.383 +
   1.384 +	req.tv_sec = (time_t) d;
   1.385 +	req.tv_nsec = (long) ((d - req.tv_sec) * 1000000000);
   1.386 +
   1.387 +	if (nanosleep(&req, NULL) == 0)
   1.388 +	{
   1.389 +		lua_pushboolean(L, 1);
   1.390 +		return 1;
   1.391 +	}
   1.392 +
   1.393 +	lua_pushnil(L);
   1.394 +	lua_pushstring(L, strerror(errno));
   1.395 +	return 2;
   1.396 +}
   1.397 +
   1.398 +#if defined(__linux)
   1.399 +#include <sys/statvfs.h>
   1.400 +
   1.401 +static int
   1.402 +posix_statvfs(lua_State *L)
   1.403 +{
   1.404 +	struct statvfs buf;
   1.405 +	const char *path = luaL_checkstring(L, 1);
   1.406 +	if (statvfs(path, &buf) == 0)
   1.407 +	{
   1.408 +		lua_newtable(L);
   1.409 +		lua_pushinteger(L, buf.f_bsize);
   1.410 +		lua_setfield(L, -2, "bsize");
   1.411 +		lua_pushinteger(L, buf.f_blocks);
   1.412 +		lua_setfield(L, -2, "blocks");
   1.413 +		lua_pushinteger(L, buf.f_bfree);
   1.414 +		lua_setfield(L, -2, "bfree");
   1.415 +		lua_pushinteger(L, buf.f_fsid);
   1.416 +		lua_setfield(L, -2, "fsid");
   1.417 +		lua_pushinteger(L, buf.f_namemax);
   1.418 +		lua_setfield(L, -2, "namemax");
   1.419 +		return 1;
   1.420 +	}
   1.421 +	lua_pushnil(L);
   1.422 +	lua_pushstring(L, strerror(errno));
   1.423 +	return 2;
   1.424 +}
   1.425 +
   1.426 +#endif
   1.427 +
   1.428 +static const luaL_Reg libfuncs[] =
   1.429 +{
   1.430 +	{ "stat", posix_stat },
   1.431 +	{ "lstat", posix_lstat },
   1.432 +	{ "opendir", posix_opendir },
   1.433 +	{ "closedir", posix_closedir },
   1.434 +	{ "readdir", posix_readdir },
   1.435 +	{ "mkdir", posix_mkdir },
   1.436 +	{ "readlink", posix_readlink },
   1.437 +	{ "symlink", posix_symlink },
   1.438 +	{ "abspath", posix_abspath },
   1.439 +	{ "nanosleep", posix_nanosleep },
   1.440 +#if defined(__linux)
   1.441 +	{ "statvfs", posix_statvfs },
   1.442 +#endif
   1.443 +	{ NULL, NULL }
   1.444 +};
   1.445 +
   1.446 +
   1.447 +static const luaL_Reg dirmethods[] =
   1.448 +{
   1.449 +	{"read", posix_readdir },
   1.450 +	{"close", posix_closedir },
   1.451 +	{"__gc", posix_closedir },
   1.452 +	{NULL, NULL}
   1.453 +};
   1.454 +
   1.455 +int luaopen_tek_lib_posix(lua_State *L)
   1.456 +{
   1.457 +	luaL_register(L, "tek.lib.posix", libfuncs);
   1.458 +	/* s: lib */
   1.459 +	luaL_newmetatable(L, DIRCLASSNAME);
   1.460 +	/* s: lib, meta */
   1.461 +	lua_pushvalue(L, -1);
   1.462 +	/* s: lib, meta, meta */
   1.463 +	lua_setfield(L, -2, "__index");
   1.464 +	/* s: lib, meta */
   1.465 +	luaL_register(L, NULL, dirmethods);
   1.466 +	/* s: lib, meta */
   1.467 +	lua_pop(L, 2);
   1.468 +	/* s: */
   1.469 +	return 0;
   1.470 +}