cgi-bin/tek/os/posix.c
author Timm S. Mueller <tmueller@neoscientists.org>
Fri, 05 Oct 2007 01:41:59 +0200
changeset 198 87a4de7c7457
parent 193 80a1a4eb0bb7
child 241 c6c81629f54e
permissions -rw-r--r--
Editing and re-publishing is now supported in public profile (configurable via
new option); checkpath() fixed, did not properly take into account the full
path; isdynamic() takes into account existance of the addressed link now; if a
link target does not exist, it is no longer referenced as static HTML in an
unrolled site (allows unknown link targets to be processed by other webserver
handlers); an userdata argument can now be passed to LOona; variables fixed
that were misplaced in global namespace; tek.os.posix.abspath() now handles
paths that were absolute already; added fastcgi external server launcher;
inheritance is now based on tek.class.atom; added lua.cgi cgi wrapper; added
fine-grained permissive rights; request, document and post classes overhauled;
underscore now permitted in cgi arguments; quotation marks now handled in
serialization; added checkpw method that can be used as a login hook; improved
buffer logic, setheader renamed to addheader; site template is more flexible
and uses config.defname as the logo's link target now
     1 
     2 /*
     3 **	tek.os.posix - tek POSIX library
     4 **	Written by Timm S. Mueller <tmueller at neoscientists.org>
     5 **	See copyright notice in COPYRIGHT
     6 */
     7 
     8 #include <stdlib.h>
     9 #include <string.h>
    10 #include <sys/types.h>
    11 #include <sys/stat.h>
    12 #include <unistd.h>
    13 #include <dirent.h>
    14 #include <errno.h>
    15 #include <math.h>
    16 #include <time.h>
    17 #include <lua.h>
    18 #include <lualib.h>
    19 #include <lauxlib.h>
    20 
    21 
    22 #define DIRCLASSNAME "dir*"
    23 
    24 
    25 static void
    26 setfield(lua_State *L, const char *attr, const char *key, lua_Integer n)
    27 {
    28 	if (attr == NULL || strcmp(attr, key) == 0)
    29 		lua_pushinteger(L, n);
    30 	if (attr == NULL)
    31 		lua_setfield(L, -2, key);
    32 }
    33 
    34 
    35 static int
    36 setstat(lua_State *L, int result, struct stat *s, const char *attr)
    37 {
    38 	if (result != 0)
    39 	{
    40 		lua_pushnil(L);
    41 		lua_pushstring(L, strerror(errno));
    42 		return 2;
    43 	}
    44 
    45 	if (attr == NULL)
    46 		lua_newtable(L);
    47 
    48 	setfield(L, attr, "dev", s->st_dev);
    49 	setfield(L, attr, "ino", s->st_ino);
    50 
    51 	if (attr == NULL || strcmp(attr, "mode") == 0)
    52 	{
    53 		if (S_ISREG(s->st_mode))
    54 			lua_pushstring(L, "file");
    55 		else if (S_ISDIR(s->st_mode))
    56 			lua_pushstring(L, "directory");
    57 		else if (S_ISLNK(s->st_mode))
    58 			lua_pushstring(L, "link");
    59 		else if (S_ISSOCK(s->st_mode))
    60 			lua_pushstring(L, "socket");
    61 		else if (S_ISFIFO(s->st_mode))
    62 			lua_pushstring(L, "named pipe");
    63 		else if (S_ISCHR(s->st_mode))
    64 			lua_pushstring(L, "char device");
    65 		else if (S_ISBLK(s->st_mode))
    66 			lua_pushstring(L, "block device");
    67 		else
    68 			lua_pushstring(L, "other");
    69 		if (attr == NULL)
    70 			lua_setfield(L, -2, "mode");
    71 	}
    72 
    73 	setfield(L, attr, "nlink", s->st_nlink);
    74 	setfield(L, attr, "uid", s->st_uid);
    75 	setfield(L, attr, "gid", s->st_gid);
    76 	setfield(L, attr, "rdev", s->st_rdev);
    77 	setfield(L, attr, "access", s->st_atime);
    78 	setfield(L, attr, "modifications", s->st_mtime);
    79 	setfield(L, attr, "change", s->st_ctime);
    80 	setfield(L, attr, "size", s->st_size);
    81 	setfield(L, attr, "blocks", s->st_blocks);
    82 	setfield(L, attr, "blksize", s->st_blksize);
    83 
    84 	return 1;
    85 }
    86 
    87 
    88 static int
    89 posix_stat(lua_State *L)
    90 {
    91 	const char *path = luaL_checkstring(L, 1);
    92 	const char *attr = luaL_optstring(L, 2, NULL);
    93 	struct stat s;
    94 	return setstat(L, stat(path, &s), &s, attr);
    95 }
    96 
    97 
    98 static int
    99 posix_lstat(lua_State *L)
   100 {
   101 	const char *path = luaL_checkstring(L, 1);
   102 	const char *attr = luaL_optstring(L, 2, NULL);
   103 	struct stat s;
   104 	return setstat(L, lstat(path, &s), &s, attr);
   105 }
   106 
   107 
   108 static int
   109 posix_opendir(lua_State *L)
   110 {
   111 	const char *path = luaL_checkstring(L, 1);
   112 	DIR **pdir = lua_newuserdata(L, sizeof(void *));
   113 	*pdir = NULL;
   114 	lua_pushvalue(L, lua_upvalueindex(2)); /* class metatable */
   115 	/* attach metatable to the userdata object */
   116 	lua_setmetatable(L, -2); /* s: udata */
   117 	/* create class instance */
   118 	*pdir = opendir(path);
   119 	if (*pdir == NULL)
   120 	{
   121 		lua_pushnil(L);
   122 		lua_pushstring(L, strerror(errno));
   123 		return 2;
   124 	}
   125 	return 1;
   126 }
   127 
   128 
   129 static DIR **
   130 getinstptr(lua_State *L, int narg, const char *classname)
   131 {
   132 	DIR **pinst = luaL_checkudata(L, narg, classname);
   133 	if (*pinst) return pinst;
   134 	luaL_argerror(L, narg, "Closed handle");
   135 	return NULL;
   136 }
   137 
   138 
   139 static int
   140 posix_closedir(lua_State *L)
   141 {
   142 	DIR **pdir = getinstptr(L, 1, DIRCLASSNAME);
   143 	closedir(*pdir);
   144 	*pdir = NULL;
   145 	return 0;
   146 }
   147 
   148 
   149 static int
   150 posix_readdir(lua_State *L)
   151 {
   152 	DIR *dir = *getinstptr(L, 1, DIRCLASSNAME);
   153 	struct dirent *de = readdir(dir);
   154 	if (de)
   155 		lua_pushstring(L, de->d_name);
   156 	else
   157 		lua_pushnil(L);
   158 	return 1;
   159 }
   160 
   161 
   162 static int
   163 posix_readlink(lua_State *L)
   164 {
   165 	const char *path = luaL_checkstring(L, 1);
   166 	char buf[PATH_MAX + 1];
   167 	ssize_t len = readlink(path, buf, sizeof(buf) - 1);
   168 	if (len < 0)
   169 	{
   170 		lua_pushnil(L);
   171 		lua_pushstring(L, strerror(errno));
   172 		return 2;
   173 	}
   174 	buf[len] = 0;
   175 	lua_pushstring(L, buf);
   176 	return 1;
   177 }
   178 
   179 
   180 static int
   181 posix_mkdir(lua_State *L)
   182 {
   183 	const char *path = luaL_checkstring(L, 1);
   184 	if (mkdir(path, 0775) == 0)
   185 	{
   186 		lua_pushboolean(L, 1);
   187 		return 1;
   188 	}
   189 	lua_pushnil(L);
   190 	lua_pushstring(L, strerror(errno));
   191 	return 2;
   192 }
   193 
   194 
   195 static int
   196 posix_symlink(lua_State *L)
   197 {
   198 	const char *oldpath = luaL_checkstring(L, 1);
   199 	const char *newpath = luaL_checkstring(L, 2);
   200 	if (symlink(oldpath, newpath) == 0)
   201 	{
   202 		lua_pushboolean(L, 1);
   203 		return 1;
   204 	}
   205 	lua_pushnil(L);
   206 	lua_pushstring(L, strerror(errno));
   207 	return 2;
   208 }
   209 
   210 
   211 static int
   212 resolvepath(const char *src, char *dest)
   213 {
   214 	int len = strlen(src);
   215 	const char *sp = src + len;
   216 	char *dp = dest;
   217 	int dc = 0, slc = 0, eac = 0, wc = 0;
   218 	int i, c;
   219 
   220 	while (len--)
   221 	{
   222 		c = *(--sp);
   223 		switch (c)
   224 		{
   225 			case '/':
   226 				if (dc == 2)
   227 					eac++;
   228 				dc = 0;
   229 				slc = 1;
   230 				wc = 0;
   231 				break;
   232 
   233 			case '.':
   234 				if (slc)
   235 				{
   236 					dc++;
   237 					break;
   238 				}
   239 				/* fallthru: */
   240 
   241 			default:
   242 				if (wc)
   243 					break;
   244 
   245 				if (slc)
   246 				{
   247 					slc = 0;
   248 
   249 					if (eac > 0)
   250 					{
   251 						/* resolve one eatcount */
   252 						eac--;
   253 						/* now wait for next path part */
   254 						wc = 1;
   255 						break;
   256 					}
   257 
   258 					*dp++ = '/';
   259 				}
   260 
   261 				while (dc == 2 || dc == 1)
   262 				{
   263 					*dp++ = '.';
   264 					dc--;
   265 				}
   266 				dc = 0;
   267 
   268 				*dp++ = c;
   269 				break;
   270 		}
   271 	}
   272 
   273 	/* unresolved eatcount */
   274 	if (eac)
   275 		return 0;
   276 
   277 	/* resolve remaining slash */
   278 	if (slc)
   279 		*dp++ = '/';
   280 
   281 	*dp = 0;
   282 
   283 	len = dp - dest;
   284 	for (i = 0; i < len / 2; ++i)
   285 	{
   286 		char t = dest[i];
   287 		dest[i] = dest[len - i - 1];
   288 		dest[len - i - 1] = t;
   289 	}
   290 
   291 	return 1;
   292 }
   293 
   294 
   295 static int
   296 posix_abspath(lua_State *L)
   297 {
   298 	const char *path = luaL_checkstring(L, 1);
   299 	char *pwd = NULL;
   300 	size_t pwdsize = 16;
   301 	size_t len1, len2;
   302 	char *srcpath, *dstpath;
   303 
   304 	for (;;)
   305 	{
   306 		if (path[0] == '/')
   307 		{
   308 			pwd = malloc(2);
   309 			if (pwd == NULL)
   310 				break;
   311 			pwd[0] = '/';
   312 			pwd[1] = 0;
   313 		}
   314 		else
   315 		{
   316 			char *newpwd = realloc(pwd, pwdsize);
   317 			if (newpwd == NULL)
   318 				break;
   319 			pwd = newpwd;
   320 
   321 			if (!getcwd(pwd, pwdsize))
   322 			{
   323 				if (errno == ERANGE)
   324 				{
   325 					pwdsize <<= 1;
   326 					continue;
   327 				}
   328 				lua_pushnil(L);
   329 				lua_pushstring(L, strerror(errno));
   330 				return 2;
   331 			}
   332 		}
   333 
   334 		len1 = strlen(pwd);
   335 		len2 = strlen(path);
   336 		srcpath = malloc(len1 + 1 + len2 + 1);
   337 		dstpath = malloc(len1 + 1 + len2 + 1);
   338 
   339 		if (srcpath && dstpath)
   340 		{
   341 			int res;
   342 
   343 			strcpy(srcpath, pwd);
   344 			free(pwd);
   345 			srcpath[len1] = '/';
   346 			strcpy(srcpath + len1 + 1, path);
   347 			res = resolvepath(srcpath, dstpath);
   348 			free(srcpath);
   349 
   350 			if (res)
   351 			{
   352 				lua_pushstring(L, dstpath);
   353 				free(dstpath);
   354 				return 1;
   355 			}
   356 
   357 			free(dstpath);
   358 			lua_pushnil(L);
   359 			lua_pushstring(L, "Not a valid path");
   360 			return 2;
   361 		}
   362 
   363 		free(srcpath);
   364 		free(dstpath);
   365 		break;
   366 	}
   367 
   368 	free(pwd);
   369 	luaL_error(L, "Out of memory");
   370 	return 0;
   371 }
   372 
   373 
   374 static int
   375 posix_nanosleep(lua_State *L)
   376 {
   377 	struct timespec req;
   378 	lua_Number d = luaL_checknumber(L, 1);
   379 
   380 	req.tv_sec = (time_t) d;
   381 	req.tv_nsec = (long) ((d - req.tv_sec) * 1000000000);
   382 
   383 	if (nanosleep(&req, NULL) == 0)
   384 	{
   385 		lua_pushboolean(L, 1);
   386 		return 1;
   387 	}
   388 
   389 	lua_pushnil(L);
   390 	lua_pushstring(L, strerror(errno));
   391 	return 2;
   392 }
   393 
   394 
   395 static const luaL_Reg lib[] =
   396 {
   397 	{ "stat", posix_stat },
   398 	{ "lstat", posix_lstat },
   399 	{ "opendir", posix_opendir },
   400 	{ "closedir", posix_closedir },
   401 	{ "readdir", posix_readdir },
   402 	{ "mkdir", posix_mkdir },
   403 	{ "readlink", posix_readlink },
   404 	{ "symlink", posix_symlink },
   405 	{ "abspath", posix_abspath },
   406 	{ "nanosleep", posix_nanosleep },
   407 	{ NULL, NULL }
   408 };
   409 
   410 
   411 static const luaL_Reg methods[] =
   412 {
   413 	{"read", posix_readdir },
   414 	{"close", posix_closedir },
   415 	{"__gc", posix_closedir },
   416 	{NULL, NULL}
   417 };
   418 
   419 
   420 static void
   421 addclass(lua_State *L, const char *libname, const char *classname,
   422 	luaL_Reg *functions, luaL_Reg *methods, void *userdata)
   423 {
   424 	luaL_newmetatable(L, classname); /* classtab */
   425 	lua_pushliteral(L, "__index"); /* classtab, "__index" */
   426 
   427 	/* insert self: classtab.__index = classtab */
   428 	lua_pushvalue(L, -2); /* classtab, "__index", classtab */
   429 	lua_rawset(L, -3); /* classtab */
   430 
   431 	/* insert methods. consume 1 userdata. do not create a new tab */
   432 	lua_pushlightuserdata(L, userdata); /* classtab, userdata */
   433 	luaL_openlib(L, NULL, methods, 1); /* classtab */
   434 
   435 	/* first upvalue: userdata */
   436 	lua_pushlightuserdata(L, userdata); /* classtab, userdata */
   437 
   438 	/* duplicate table argument to be used as second upvalue for cclosure */
   439 	lua_pushvalue(L, -2); /* classtab, userdata, classtab */
   440 
   441 	/* insert functions */
   442 	luaL_openlib(L, libname, functions, 2);	/* classtab, libtab */
   443 
   444 	/* adjust stack */
   445 	lua_pop(L, 2);
   446 }
   447 
   448 
   449 int luaopen_tek_os_posix(lua_State *L)
   450 {
   451 	addclass(L, "tek.os.posix", DIRCLASSNAME,
   452 		(luaL_Reg *) lib, (luaL_Reg *) methods, NULL);
   453 	return 0;
   454 }