File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / TSRM / tsrm_win32.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 14 08:02:46 2013 UTC (10 years, 8 months ago) by misho
Branches: php, MAIN
CVS tags: v5_4_29p0, v5_4_20p0, v5_4_20, HEAD
v 5.4.20

    1: /*
    2:    +----------------------------------------------------------------------+
    3:    | PHP Version 5                                                        |
    4:    +----------------------------------------------------------------------+
    5:    | Copyright (c) 1997-2013 The PHP Group                                |
    6:    +----------------------------------------------------------------------+
    7:    | This source file is subject to version 3.01 of the PHP license,      |
    8:    | that is bundled with this package in the file LICENSE, and is        |
    9:    | available through the world-wide-web at the following url:           |
   10:    | http://www.php.net/license/3_01.txt                                  |
   11:    | If you did not receive a copy of the PHP license and are unable to   |
   12:    | obtain it through the world-wide-web, please send a note to          |
   13:    | license@php.net so we can mail you a copy immediately.               |
   14:    +----------------------------------------------------------------------+
   15:    | Authors: Daniel Beulshausen <daniel@php4win.de>                      |
   16:    +----------------------------------------------------------------------+
   17: */
   18: 
   19: /* $Id: tsrm_win32.c,v 1.1.1.4 2013/10/14 08:02:46 misho Exp $ */
   20: 
   21: #include <stdio.h>
   22: #include <fcntl.h>
   23: #include <io.h>
   24: #include <process.h>
   25: #include <time.h>
   26: #include <errno.h>
   27: 
   28: #define TSRM_INCLUDE_FULL_WINDOWS_HEADERS
   29: #include "SAPI.h"
   30: #include "TSRM.h"
   31: 
   32: #ifdef TSRM_WIN32
   33: #include <Sddl.h>
   34: #include "tsrm_win32.h"
   35: #include "tsrm_virtual_cwd.h"
   36: 
   37: #ifdef ZTS
   38: static ts_rsrc_id win32_globals_id;
   39: #else
   40: static tsrm_win32_globals win32_globals;
   41: #endif
   42: 
   43: static void tsrm_win32_ctor(tsrm_win32_globals *globals TSRMLS_DC)
   44: {
   45: 	globals->process = NULL;
   46: 	globals->shm	 = NULL;
   47: 	globals->process_size = 0;
   48: 	globals->shm_size	  = 0;
   49: 	globals->comspec = _strdup((GetVersion()<0x80000000)?"cmd.exe":"command.com");
   50: 
   51: 	/* Set it to INVALID_HANDLE_VALUE
   52: 	 * It will be initialized correctly in tsrm_win32_access or set to 
   53: 	 * NULL if no impersonation has been done.
   54: 	 * the impersonated token can't be set here as the impersonation
   55: 	 * will happen later, in fcgi_accept_request (or whatever is the
   56: 	 * SAPI being used).
   57: 	 */
   58: 	globals->impersonation_token = INVALID_HANDLE_VALUE;
   59: 	globals->impersonation_token_sid = NULL;
   60: }
   61: 
   62: static void tsrm_win32_dtor(tsrm_win32_globals *globals TSRMLS_DC)
   63: {
   64: 	shm_pair *ptr;
   65: 
   66: 	if (globals->process) {
   67: 		free(globals->process);
   68: 	}
   69: 
   70: 	if (globals->shm) {
   71: 		for (ptr = globals->shm; ptr < (globals->shm + globals->shm_size); ptr++) {
   72: 			UnmapViewOfFile(ptr->addr);
   73: 			CloseHandle(ptr->segment);
   74: 			UnmapViewOfFile(ptr->descriptor);
   75: 			CloseHandle(ptr->info);
   76: 		}
   77: 		free(globals->shm);
   78: 	}
   79: 
   80: 	free(globals->comspec);
   81: 
   82: 	if (globals->impersonation_token && globals->impersonation_token != INVALID_HANDLE_VALUE	) {
   83: 		CloseHandle(globals->impersonation_token);
   84: 	}
   85: 	if (globals->impersonation_token_sid) {
   86: 		free(globals->impersonation_token_sid);
   87: 	}
   88: }
   89: 
   90: TSRM_API void tsrm_win32_startup(void)
   91: {
   92: #ifdef ZTS
   93: 	ts_allocate_id(&win32_globals_id, sizeof(tsrm_win32_globals), (ts_allocate_ctor)tsrm_win32_ctor, (ts_allocate_ctor)tsrm_win32_dtor);
   94: #else
   95: 	tsrm_win32_ctor(&win32_globals TSRMLS_CC);
   96: #endif
   97: }
   98: 
   99: TSRM_API void tsrm_win32_shutdown(void)
  100: {
  101: #ifndef ZTS
  102: 	tsrm_win32_dtor(&win32_globals TSRMLS_CC);
  103: #endif
  104: }
  105: 
  106: char * tsrm_win32_get_path_sid_key(const char *pathname TSRMLS_DC)
  107: {
  108: 	PSID pSid = TWG(impersonation_token_sid);
  109: 	DWORD sid_len = pSid ? GetLengthSid(pSid) : 0;
  110: 	TCHAR *ptcSid = NULL;
  111: 	char *bucket_key = NULL;
  112: 
  113: 	if (!pSid) {
  114: 		bucket_key = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, strlen(pathname) + 1);
  115: 		if (!bucket_key) {
  116: 			return NULL;
  117: 		}
  118: 		memcpy(bucket_key, pathname, strlen(pathname));
  119: 		return bucket_key;
  120: 	}
  121: 
  122: 	if (!ConvertSidToStringSid(pSid, &ptcSid)) {
  123: 		return NULL;
  124: 	}
  125: 
  126: 	bucket_key = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, strlen(pathname) + strlen(ptcSid) + 1);
  127: 	if (!bucket_key) {
  128: 		LocalFree(ptcSid);
  129: 		return NULL;
  130: 	}
  131: 
  132: 	memcpy(bucket_key, ptcSid, strlen(ptcSid));
  133: 	memcpy(bucket_key + strlen(ptcSid), pathname, strlen(pathname) + 1);
  134: 
  135: 	LocalFree(ptcSid);
  136: 	return bucket_key;
  137: }
  138: 
  139: 
  140: PSID tsrm_win32_get_token_sid(HANDLE hToken)
  141: {
  142: 	BOOL bSuccess = FALSE;
  143: 	DWORD dwLength = 0;
  144: 	PTOKEN_USER pTokenUser = NULL;
  145: 	PSID sid;
  146: 	PSID *ppsid = &sid;
  147: 	DWORD sid_len;
  148: 	PSID pResultSid = NULL;
  149: 
  150: 	/* Get the actual size of the TokenUser structure */
  151: 	if (!GetTokenInformation(
  152: 			hToken, TokenUser, (LPVOID) pTokenUser, 0, &dwLength))  {
  153: 		if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  154: 			goto Finished;
  155: 		}
  156: 
  157: 		pTokenUser = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
  158: 		if (pTokenUser == NULL) {
  159: 			goto Finished;
  160: 		}
  161: 	}
  162: 
  163: 	/* and fetch it now */
  164: 	if (!GetTokenInformation(
  165: 		hToken, TokenUser, (LPVOID) pTokenUser, dwLength, &dwLength)) {
  166: 		goto Finished;
  167: 	}
  168: 
  169: 	sid_len = GetLengthSid(pTokenUser->User.Sid);
  170: 
  171: 	/* ConvertSidToStringSid(pTokenUser->User.Sid, &ptcSidOwner); */
  172: 	pResultSid = malloc(sid_len);
  173: 	if (!pResultSid) {
  174: 		goto Finished;
  175: 	}
  176: 	if (!CopySid(sid_len, pResultSid, pTokenUser->User.Sid)) {
  177: 		goto Finished;
  178: 	}
  179: 	HeapFree(GetProcessHeap(), 0, (LPVOID)pTokenUser);
  180: 	return pResultSid;
  181: 
  182: Finished:
  183: 	if (pResultSid) {
  184: 		free(pResultSid);
  185: 	}
  186: 	/* Free the buffer for the token groups. */
  187: 	if (pTokenUser != NULL) {
  188: 		HeapFree(GetProcessHeap(), 0, (LPVOID)pTokenUser);
  189: 	}
  190: 	return NULL;
  191: }
  192: 
  193: TSRM_API int tsrm_win32_access(const char *pathname, int mode TSRMLS_DC)
  194: {
  195: 	time_t t;
  196: 	HANDLE thread_token = NULL;
  197: 	PSID token_sid;
  198: 	SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
  199: 	GENERIC_MAPPING gen_map = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS };
  200: 	DWORD priv_set_length = sizeof(PRIVILEGE_SET);
  201: 
  202: 	PRIVILEGE_SET privilege_set = {0};
  203: 	DWORD sec_desc_length = 0, desired_access = 0, granted_access = 0;
  204: 	BYTE * psec_desc = NULL;
  205: 	BOOL fAccess = FALSE;
  206: 
  207: 	BOOL bucket_key_alloc = FALSE;
  208: 	realpath_cache_bucket * bucket = NULL;
  209: 	char * real_path = NULL;
  210: 
  211: 	if (mode == 1 /*X_OK*/) {
  212: 		DWORD type;
  213: 		return GetBinaryType(pathname, &type) ? 0 : -1;
  214: 	} else {
  215: 		if(!IS_ABSOLUTE_PATH(pathname, strlen(pathname)+1)) {
  216: 			real_path = (char *)malloc(MAX_PATH);
  217: 			if(tsrm_realpath(pathname, real_path TSRMLS_CC) == NULL) {
  218: 				goto Finished;
  219: 			}
  220: 			pathname = real_path;
  221:  		}
  222: 
  223: 		if(access(pathname, mode)) {
  224: 			free(real_path);
  225: 			return errno;
  226: 		}
  227: 
  228:  		/* If only existence check is made, return now */
  229:  		if (mode == 0) {
  230: 			free(real_path);
  231: 			return 0;
  232: 		}
  233: 
  234: /* Only in NTS when impersonate==1 (aka FastCGI) */
  235: 
  236: 		/*
  237: 		 AccessCheck() requires an impersonation token.  We first get a primary
  238: 		 token and then create a duplicate impersonation token.  The
  239: 		 impersonation token is not actually assigned to the thread, but is
  240: 		 used in the call to AccessCheck.  Thus, this function itself never
  241: 		 impersonates, but does use the identity of the thread.  If the thread
  242: 		 was impersonating already, this function uses that impersonation context.
  243: 		*/
  244: 		if(!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
  245: 			DWORD err = GetLastError();
  246: 			if (GetLastError() == ERROR_NO_TOKEN) {
  247: 				if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &thread_token)) {
  248: 					 TWG(impersonation_token) = NULL;
  249: 					 goto Finished;
  250: 				 }
  251: 			}
  252: 		}
  253: 
  254: 		/* token_sid will be freed in tsrmwin32_dtor */
  255: 		token_sid = tsrm_win32_get_token_sid(thread_token);
  256: 		if (!token_sid) {
  257: 			if (TWG(impersonation_token_sid)) {
  258: 				free(TWG(impersonation_token_sid));
  259: 			}
  260: 			TWG(impersonation_token_sid) = NULL;
  261: 			goto Finished;
  262: 		}
  263: 
  264: 		/* Different identity, we need a new impersontated token as well */
  265: 		if (!TWG(impersonation_token_sid) || !EqualSid(token_sid, TWG(impersonation_token_sid))) {
  266: 			if (TWG(impersonation_token_sid)) {
  267: 				free(TWG(impersonation_token_sid));
  268: 			}
  269: 			TWG(impersonation_token_sid) = token_sid;
  270: 
  271: 			/* Duplicate the token as impersonated token */
  272: 			if (!DuplicateToken(thread_token, SecurityImpersonation, &TWG(impersonation_token))) {
  273: 				goto Finished;
  274: 			}
  275: 		} else {
  276: 			/* we already have it, free it then */
  277: 			free(token_sid);
  278: 		}
  279: 
  280: 		if (CWDG(realpath_cache_size_limit)) {
  281: 			t = time(0);
  282: 			bucket = realpath_cache_lookup(pathname, strlen(pathname), t TSRMLS_CC);
  283: 			if(bucket == NULL && real_path == NULL) {
  284: 				/* We used the pathname directly. Call tsrm_realpath */
  285: 				/* so that entry is created in realpath cache */
  286: 				real_path = (char *)malloc(MAX_PATH);
  287: 				if(tsrm_realpath(pathname, real_path TSRMLS_CC) != NULL) {
  288: 					pathname = real_path;
  289: 					bucket = realpath_cache_lookup(pathname, strlen(pathname), t TSRMLS_CC);
  290: 				}
  291: 			}
  292:  		}
  293: 
  294:  		/* Do a full access check because access() will only check read-only attribute */
  295:  		if(mode == 0 || mode > 6) {
  296: 			if(bucket != NULL && bucket->is_rvalid) {
  297: 				fAccess = bucket->is_readable;
  298: 				goto Finished;
  299: 			}
  300:  			desired_access = FILE_GENERIC_READ;
  301:  		} else if(mode <= 2) {
  302: 			if(bucket != NULL && bucket->is_wvalid) {
  303: 				fAccess = bucket->is_writable;
  304: 				goto Finished;
  305: 			}
  306: 			desired_access = FILE_GENERIC_WRITE;
  307:  		} else if(mode <= 4) {
  308: 			if(bucket != NULL && bucket->is_rvalid) {
  309: 				fAccess = bucket->is_readable;
  310: 				goto Finished;
  311: 			}
  312: 			desired_access = FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS;
  313:  		} else { // if(mode <= 6)
  314: 			if(bucket != NULL && bucket->is_rvalid && bucket->is_wvalid) {
  315: 				fAccess = bucket->is_readable & bucket->is_writable;
  316: 				goto Finished;
  317: 			}
  318: 			desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
  319:  		}
  320: 
  321: 		if(TWG(impersonation_token) == NULL) {
  322: 			goto Finished;
  323: 		}
  324: 
  325: 		/* Get size of security buffer. Call is expected to fail */
  326: 		if(GetFileSecurity(pathname, sec_info, NULL, 0, &sec_desc_length)) {
  327: 			goto Finished;
  328: 		}
  329: 
  330: 		psec_desc = (BYTE *)malloc(sec_desc_length);
  331: 		if(psec_desc == NULL ||
  332: 			 !GetFileSecurity(pathname, sec_info, (PSECURITY_DESCRIPTOR)psec_desc, sec_desc_length, &sec_desc_length)) {
  333: 			goto Finished;
  334: 		}
  335: 
  336: 		MapGenericMask(&desired_access, &gen_map);
  337: 
  338: 		if(!AccessCheck((PSECURITY_DESCRIPTOR)psec_desc, TWG(impersonation_token), desired_access, &gen_map, &privilege_set, &priv_set_length, &granted_access, &fAccess)) {
  339: 			goto Finished_Impersonate;
  340: 		}
  341: 
  342: 		/* Keep the result in realpath_cache */
  343: 		if(bucket != NULL) {
  344: 			if(desired_access == (FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS)) {
  345: 				bucket->is_rvalid = 1;
  346: 				bucket->is_readable = fAccess;
  347: 			}
  348: 			else if(desired_access == FILE_GENERIC_WRITE) {
  349: 				bucket->is_wvalid = 1;
  350: 				bucket->is_writable = fAccess;
  351: 			} else if (desired_access == (FILE_GENERIC_READ | FILE_GENERIC_WRITE)) {
  352: 				bucket->is_rvalid = 1;
  353: 				bucket->is_readable = fAccess;
  354: 				bucket->is_wvalid = 1;
  355: 				bucket->is_writable = fAccess;
  356: 			}
  357: 		}
  358: 
  359: Finished_Impersonate:
  360: 		if(psec_desc != NULL) {
  361: 			free(psec_desc);
  362: 			psec_desc = NULL;
  363: 		}
  364: 
  365: Finished:
  366: 		if(thread_token != NULL) {
  367: 			CloseHandle(thread_token);
  368: 		}
  369: 		if(real_path != NULL) {
  370: 			free(real_path);
  371: 			real_path = NULL;
  372: 		}
  373: 
  374: 		if(fAccess == FALSE) {
  375: 			errno = EACCES;
  376: 			return errno;
  377: 		} else {
  378: 			return 0;
  379: 		}
  380: 	}
  381: }
  382: 
  383: 
  384: static process_pair *process_get(FILE *stream TSRMLS_DC)
  385: {
  386: 	process_pair *ptr;
  387: 	process_pair *newptr;
  388: 
  389: 	for (ptr = TWG(process); ptr < (TWG(process) + TWG(process_size)); ptr++) {
  390: 		if (ptr->stream == stream) {
  391: 			break;
  392: 		}
  393: 	}
  394: 
  395: 	if (ptr < (TWG(process) + TWG(process_size))) {
  396: 		return ptr;
  397: 	}
  398: 
  399: 	newptr = (process_pair*)realloc((void*)TWG(process), (TWG(process_size)+1)*sizeof(process_pair));
  400: 	if (newptr == NULL) {
  401: 		return NULL;
  402: 	}
  403: 
  404: 	TWG(process) = newptr;
  405: 	ptr = newptr + TWG(process_size);
  406: 	TWG(process_size)++;
  407: 	return ptr;
  408: }
  409: 
  410: static shm_pair *shm_get(int key, void *addr)
  411: {
  412: 	shm_pair *ptr;
  413: 	shm_pair *newptr;
  414: 	TSRMLS_FETCH();
  415: 
  416: 	for (ptr = TWG(shm); ptr < (TWG(shm) + TWG(shm_size)); ptr++) {
  417: 		if (!ptr->descriptor) {
  418: 			continue;
  419: 		}
  420: 		if (!addr && ptr->descriptor->shm_perm.key == key) {
  421: 			break;
  422: 		} else if (ptr->addr == addr) {
  423: 			break;
  424: 		}
  425: 	}
  426: 
  427: 	if (ptr < (TWG(shm) + TWG(shm_size))) {
  428: 		return ptr;
  429: 	}
  430: 
  431: 	newptr = (shm_pair*)realloc((void*)TWG(shm), (TWG(shm_size)+1)*sizeof(shm_pair));
  432: 	if (newptr == NULL) {
  433: 		return NULL;
  434: 	}
  435: 
  436: 	TWG(shm) = newptr;
  437: 	ptr = newptr + TWG(shm_size);
  438: 	TWG(shm_size)++;
  439: 	return ptr;
  440: }
  441: 
  442: static HANDLE dupHandle(HANDLE fh, BOOL inherit) {
  443: 	HANDLE copy, self = GetCurrentProcess();
  444: 	if (!DuplicateHandle(self, fh, self, &copy, 0, inherit, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE)) {
  445: 		return NULL;
  446: 	}
  447: 	return copy;
  448: }
  449: 
  450: TSRM_API FILE *popen(const char *command, const char *type)
  451: {
  452: 	TSRMLS_FETCH();
  453: 
  454: 	return popen_ex(command, type, NULL, NULL TSRMLS_CC);
  455: }
  456: 
  457: TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd, char *env TSRMLS_DC)
  458: {
  459: 	FILE *stream = NULL;
  460: 	int fno, type_len = strlen(type), read, mode;
  461: 	STARTUPINFO startup;
  462: 	PROCESS_INFORMATION process;
  463: 	SECURITY_ATTRIBUTES security;
  464: 	HANDLE in, out;
  465: 	DWORD dwCreateFlags = 0;
  466: 	BOOL res;
  467: 	process_pair *proc;
  468: 	char *cmd;
  469: 	int i;
  470: 	char *ptype = (char *)type;
  471: 	HANDLE thread_token = NULL;
  472: 	HANDLE token_user = NULL;
  473: 	BOOL asuser = TRUE;
  474: 
  475: 	if (!type) {
  476: 		return NULL;
  477: 	}
  478: 
  479: 	/*The following two checks can be removed once we drop XP support */
  480: 	type_len = strlen(type);
  481: 	if (type_len <1 || type_len > 2) {
  482: 		return NULL;
  483: 	}
  484: 
  485: 	for (i=0; i < type_len; i++) {
  486: 		if (!(*ptype == 'r' || *ptype == 'w' || *ptype == 'b' || *ptype == 't')) {
  487: 			return NULL;
  488: 		}
  489: 		ptype++;
  490: 	}
  491: 
  492: 	security.nLength				= sizeof(SECURITY_ATTRIBUTES);
  493: 	security.bInheritHandle			= TRUE;
  494: 	security.lpSecurityDescriptor	= NULL;
  495: 
  496: 	if (!type_len || !CreatePipe(&in, &out, &security, 2048L)) {
  497: 		return NULL;
  498: 	}
  499: 
  500: 	memset(&startup, 0, sizeof(STARTUPINFO));
  501: 	memset(&process, 0, sizeof(PROCESS_INFORMATION));
  502: 
  503: 	startup.cb			= sizeof(STARTUPINFO);
  504: 	startup.dwFlags		= STARTF_USESTDHANDLES;
  505: 	startup.hStdError	= GetStdHandle(STD_ERROR_HANDLE);
  506: 
  507: 	read = (type[0] == 'r') ? TRUE : FALSE;
  508: 	mode = ((type_len == 2) && (type[1] == 'b')) ? O_BINARY : O_TEXT;
  509: 
  510: 	if (read) {
  511: 		in = dupHandle(in, FALSE);
  512: 		startup.hStdInput  = GetStdHandle(STD_INPUT_HANDLE);
  513: 		startup.hStdOutput = out;
  514: 	} else {
  515: 		out = dupHandle(out, FALSE);
  516: 		startup.hStdInput  = in;
  517: 		startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  518: 	}
  519: 
  520: 	dwCreateFlags = NORMAL_PRIORITY_CLASS;
  521: 	if (strcmp(sapi_module.name, "cli") != 0) {
  522: 		dwCreateFlags |= CREATE_NO_WINDOW;
  523: 	}
  524: 
  525: 	/* Get a token with the impersonated user. */
  526: 	if(OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
  527: 		DuplicateTokenEx(thread_token, MAXIMUM_ALLOWED, &security, SecurityImpersonation, TokenPrimary, &token_user);
  528: 	} else {
  529: 		DWORD err = GetLastError();
  530: 		if (err == ERROR_NO_TOKEN) {
  531: 			asuser = FALSE;
  532: 		}
  533: 	}
  534: 
  535: 	cmd = (char*)malloc(strlen(command)+strlen(TWG(comspec))+sizeof(" /c ")+2);
  536: 	if (!cmd) {
  537: 		return NULL;
  538: 	}
  539: 
  540: 	sprintf(cmd, "%s /c \"%s\"", TWG(comspec), command);
  541: 	if (asuser) {
  542: 		res = CreateProcessAsUser(token_user, NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process);
  543: 		CloseHandle(token_user);
  544: 	} else {
  545: 		res = CreateProcess(NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process);
  546: 	}
  547: 	free(cmd);
  548: 
  549: 	if (!res) {
  550: 		return NULL;
  551: 	}
  552: 
  553: 	CloseHandle(process.hThread);
  554: 	proc = process_get(NULL TSRMLS_CC);
  555: 
  556: 	if (read) {
  557: 		fno = _open_osfhandle((tsrm_intptr_t)in, _O_RDONLY | mode);
  558: 		CloseHandle(out);
  559: 	} else {
  560: 		fno = _open_osfhandle((tsrm_intptr_t)out, _O_WRONLY | mode);
  561: 		CloseHandle(in);
  562: 	}
  563: 
  564: 	stream = _fdopen(fno, type);
  565: 	proc->prochnd = process.hProcess;
  566: 	proc->stream = stream;
  567: 	return stream;
  568: }
  569: 
  570: TSRM_API int pclose(FILE *stream)
  571: {
  572: 	DWORD termstat = 0;
  573: 	process_pair *process;
  574: 	TSRMLS_FETCH();
  575: 
  576: 	if ((process = process_get(stream TSRMLS_CC)) == NULL) {
  577: 		return 0;
  578: 	}
  579: 
  580: 	fflush(process->stream);
  581: 	fclose(process->stream);
  582: 
  583: 	WaitForSingleObject(process->prochnd, INFINITE);
  584: 	GetExitCodeProcess(process->prochnd, &termstat);
  585: 	process->stream = NULL;
  586: 	CloseHandle(process->prochnd);
  587: 
  588: 	return termstat;
  589: }
  590: 
  591: TSRM_API int shmget(int key, int size, int flags)
  592: {
  593: 	shm_pair *shm;
  594: 	char shm_segment[26], shm_info[29];
  595: 	HANDLE shm_handle, info_handle;
  596: 	BOOL created = FALSE;
  597: 
  598: 	if (size < 0) {
  599: 		return -1;
  600: 	}
  601: 
  602: 	sprintf(shm_segment, "TSRM_SHM_SEGMENT:%d", key);
  603: 	sprintf(shm_info, "TSRM_SHM_DESCRIPTOR:%d", key);
  604: 
  605: 	shm_handle  = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_segment);
  606: 	info_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_info);
  607: 
  608: 	if ((!shm_handle && !info_handle)) {
  609: 		if (flags & IPC_CREAT) {
  610: 			shm_handle	= CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, shm_segment);
  611: 			info_handle	= CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(shm->descriptor), shm_info);
  612: 			created		= TRUE;
  613: 		}
  614: 		if ((!shm_handle || !info_handle)) {
  615: 			return -1;
  616: 		}
  617: 	} else {
  618: 		if (flags & IPC_EXCL) {
  619: 			return -1;
  620: 		}
  621: 	}
  622: 
  623: 	shm = shm_get(key, NULL);
  624: 	shm->segment = shm_handle;
  625: 	shm->info	 = info_handle;
  626: 	shm->descriptor = MapViewOfFileEx(shm->info, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
  627: 
  628: 	if (NULL != shm->descriptor && created) {
  629: 		shm->descriptor->shm_perm.key	= key;
  630: 		shm->descriptor->shm_segsz		= size;
  631: 		shm->descriptor->shm_ctime		= time(NULL);
  632: 		shm->descriptor->shm_cpid		= getpid();
  633: 		shm->descriptor->shm_perm.mode	= flags;
  634: 
  635: 		shm->descriptor->shm_perm.cuid	= shm->descriptor->shm_perm.cgid= 0;
  636: 		shm->descriptor->shm_perm.gid	= shm->descriptor->shm_perm.uid = 0;
  637: 		shm->descriptor->shm_atime		= shm->descriptor->shm_dtime	= 0;
  638: 		shm->descriptor->shm_lpid		= shm->descriptor->shm_nattch	= 0;
  639: 		shm->descriptor->shm_perm.mode	= shm->descriptor->shm_perm.seq	= 0;
  640: 	}
  641: 
  642: 	if (NULL != shm->descriptor && (shm->descriptor->shm_perm.key != key || size > shm->descriptor->shm_segsz)) {
  643: 		if (NULL != shm->segment) {
  644: 			CloseHandle(shm->segment);
  645: 		}
  646: 		UnmapViewOfFile(shm->descriptor);
  647: 		CloseHandle(shm->info);
  648: 		return -1;
  649: 	}
  650: 
  651: 	return key;
  652: }
  653: 
  654: TSRM_API void *shmat(int key, const void *shmaddr, int flags)
  655: {
  656: 	shm_pair *shm = shm_get(key, NULL);
  657: 
  658: 	if (!shm->segment) {
  659: 		return (void*)-1;
  660: 	}
  661: 
  662: 	shm->descriptor->shm_atime = time(NULL);
  663: 	shm->descriptor->shm_lpid  = getpid();
  664: 	shm->descriptor->shm_nattch++;
  665: 
  666: 	shm->addr = MapViewOfFileEx(shm->segment, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
  667: 
  668: 	return shm->addr;
  669: }
  670: 
  671: TSRM_API int shmdt(const void *shmaddr)
  672: {
  673: 	shm_pair *shm = shm_get(0, (void*)shmaddr);
  674: 
  675: 	if (!shm->segment) {
  676: 		return -1;
  677: 	}
  678: 
  679: 	shm->descriptor->shm_dtime = time(NULL);
  680: 	shm->descriptor->shm_lpid  = getpid();
  681: 	shm->descriptor->shm_nattch--;
  682: 
  683: 	return UnmapViewOfFile(shm->addr) ? 0 : -1;
  684: }
  685: 
  686: TSRM_API int shmctl(int key, int cmd, struct shmid_ds *buf) {
  687: 	shm_pair *shm = shm_get(key, NULL);
  688: 
  689: 	if (!shm->segment) {
  690: 		return -1;
  691: 	}
  692: 
  693: 	switch (cmd) {
  694: 		case IPC_STAT:
  695: 			memcpy(buf, shm->descriptor, sizeof(struct shmid_ds));
  696: 			return 0;
  697: 
  698: 		case IPC_SET:
  699: 			shm->descriptor->shm_ctime		= time(NULL);
  700: 			shm->descriptor->shm_perm.uid	= buf->shm_perm.uid;
  701: 			shm->descriptor->shm_perm.gid	= buf->shm_perm.gid;
  702: 			shm->descriptor->shm_perm.mode	= buf->shm_perm.mode;
  703: 			return 0;
  704: 
  705: 		case IPC_RMID:
  706: 			if (shm->descriptor->shm_nattch < 1) {
  707: 				shm->descriptor->shm_perm.key = -1;
  708: 			}
  709: 			return 0;
  710: 
  711: 		default:
  712: 			return -1;
  713: 	}
  714: }
  715: 
  716: TSRM_API char *realpath(char *orig_path, char *buffer)
  717: {
  718: 	int ret = GetFullPathName(orig_path, _MAX_PATH, buffer, NULL);
  719: 	if(!ret || ret > _MAX_PATH) {
  720: 		return NULL;
  721: 	}
  722: 	return buffer;
  723: }
  724: 
  725: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>