Annotation of embedaddon/php/TSRM/tsrm_win32.c, revision 1.1
1.1 ! misho 1: /*
! 2: +----------------------------------------------------------------------+
! 3: | PHP Version 5 |
! 4: +----------------------------------------------------------------------+
! 5: | Copyright (c) 1997-2012 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 321634 2012-01-01 13:15:04Z felipe $ */
! 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)
! 194: {
! 195: time_t t;
! 196: HANDLE thread_token;
! 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: TSRMLS_FETCH();
! 212:
! 213: if (mode == 1 /*X_OK*/) {
! 214: DWORD type;
! 215: return GetBinaryType(pathname, &type) ? 0 : -1;
! 216: } else {
! 217: if(!IS_ABSOLUTE_PATH(pathname, strlen(pathname)+1)) {
! 218: real_path = (char *)malloc(MAX_PATH);
! 219: if(tsrm_realpath(pathname, real_path TSRMLS_CC) == NULL) {
! 220: goto Finished;
! 221: }
! 222: pathname = real_path;
! 223: }
! 224:
! 225: if(access(pathname, mode)) {
! 226: free(real_path);
! 227: return errno;
! 228: }
! 229:
! 230: /* If only existence check is made, return now */
! 231: if (mode == 0) {
! 232: free(real_path);
! 233: return 0;
! 234: }
! 235:
! 236: /* Only in NTS when impersonate==1 (aka FastCGI) */
! 237:
! 238: /*
! 239: AccessCheck() requires an impersonation token. We first get a primary
! 240: token and then create a duplicate impersonation token. The
! 241: impersonation token is not actually assigned to the thread, but is
! 242: used in the call to AccessCheck. Thus, this function itself never
! 243: impersonates, but does use the identity of the thread. If the thread
! 244: was impersonating already, this function uses that impersonation context.
! 245: */
! 246: if(!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
! 247: DWORD err = GetLastError();
! 248: if (GetLastError() == ERROR_NO_TOKEN) {
! 249: if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &thread_token)) {
! 250: TWG(impersonation_token) = NULL;
! 251: goto Finished;
! 252: }
! 253: }
! 254: }
! 255:
! 256: /* token_sid will be freed in tsrmwin32_dtor */
! 257: token_sid = tsrm_win32_get_token_sid(thread_token);
! 258: if (!token_sid) {
! 259: if (TWG(impersonation_token_sid)) {
! 260: free(TWG(impersonation_token_sid));
! 261: }
! 262: TWG(impersonation_token_sid) = NULL;
! 263: goto Finished;
! 264: }
! 265:
! 266: /* Different identity, we need a new impersontated token as well */
! 267: if (!TWG(impersonation_token_sid) || !EqualSid(token_sid, TWG(impersonation_token_sid))) {
! 268: if (TWG(impersonation_token_sid)) {
! 269: free(TWG(impersonation_token_sid));
! 270: }
! 271: TWG(impersonation_token_sid) = token_sid;
! 272:
! 273: /* Duplicate the token as impersonated token */
! 274: if (!DuplicateToken(thread_token, SecurityImpersonation, &TWG(impersonation_token))) {
! 275: goto Finished;
! 276: }
! 277: } else {
! 278: /* we already have it, free it then */
! 279: free(token_sid);
! 280: }
! 281:
! 282: if (CWDG(realpath_cache_size_limit)) {
! 283: t = time(0);
! 284: bucket = realpath_cache_lookup(pathname, strlen(pathname), t TSRMLS_CC);
! 285: if(bucket == NULL && real_path == NULL) {
! 286: /* We used the pathname directly. Call tsrm_realpath */
! 287: /* so that entry is created in realpath cache */
! 288: real_path = (char *)malloc(MAX_PATH);
! 289: if(tsrm_realpath(pathname, real_path TSRMLS_CC) != NULL) {
! 290: pathname = real_path;
! 291: bucket = realpath_cache_lookup(pathname, strlen(pathname), t TSRMLS_CC);
! 292: }
! 293: }
! 294: }
! 295:
! 296: /* Do a full access check because access() will only check read-only attribute */
! 297: if(mode == 0 || mode > 6) {
! 298: if(bucket != NULL && bucket->is_rvalid) {
! 299: fAccess = bucket->is_readable;
! 300: goto Finished;
! 301: }
! 302: desired_access = FILE_GENERIC_READ;
! 303: } else if(mode <= 2) {
! 304: if(bucket != NULL && bucket->is_wvalid) {
! 305: fAccess = bucket->is_writable;
! 306: goto Finished;
! 307: }
! 308: desired_access = FILE_GENERIC_WRITE;
! 309: } else if(mode <= 4) {
! 310: if(bucket != NULL && bucket->is_rvalid) {
! 311: fAccess = bucket->is_readable;
! 312: goto Finished;
! 313: }
! 314: desired_access = FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS;
! 315: } else { // if(mode <= 6)
! 316: if(bucket != NULL && bucket->is_rvalid && bucket->is_wvalid) {
! 317: fAccess = bucket->is_readable & bucket->is_writable;
! 318: goto Finished;
! 319: }
! 320: desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
! 321: }
! 322:
! 323: if(TWG(impersonation_token) == NULL) {
! 324: goto Finished;
! 325: }
! 326:
! 327: /* Get size of security buffer. Call is expected to fail */
! 328: if(GetFileSecurity(pathname, sec_info, NULL, 0, &sec_desc_length)) {
! 329: goto Finished;
! 330: }
! 331:
! 332: psec_desc = (BYTE *)malloc(sec_desc_length);
! 333: if(psec_desc == NULL ||
! 334: !GetFileSecurity(pathname, sec_info, (PSECURITY_DESCRIPTOR)psec_desc, sec_desc_length, &sec_desc_length)) {
! 335: goto Finished;
! 336: }
! 337:
! 338: MapGenericMask(&desired_access, &gen_map);
! 339:
! 340: if(!AccessCheck((PSECURITY_DESCRIPTOR)psec_desc, TWG(impersonation_token), desired_access, &gen_map, &privilege_set, &priv_set_length, &granted_access, &fAccess)) {
! 341: goto Finished_Impersonate;
! 342: }
! 343:
! 344: /* Keep the result in realpath_cache */
! 345: if(bucket != NULL) {
! 346: if(desired_access == (FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS)) {
! 347: bucket->is_rvalid = 1;
! 348: bucket->is_readable = fAccess;
! 349: }
! 350: else if(desired_access == FILE_GENERIC_WRITE) {
! 351: bucket->is_wvalid = 1;
! 352: bucket->is_writable = fAccess;
! 353: } else if (desired_access == (FILE_GENERIC_READ | FILE_GENERIC_WRITE)) {
! 354: bucket->is_rvalid = 1;
! 355: bucket->is_readable = fAccess;
! 356: bucket->is_wvalid = 1;
! 357: bucket->is_writable = fAccess;
! 358: }
! 359: }
! 360:
! 361: Finished_Impersonate:
! 362: if(psec_desc != NULL) {
! 363: free(psec_desc);
! 364: psec_desc = NULL;
! 365: }
! 366:
! 367: Finished:
! 368: if(real_path != NULL) {
! 369: free(real_path);
! 370: real_path = NULL;
! 371: }
! 372:
! 373: if(fAccess == FALSE) {
! 374: errno = EACCES;
! 375: return errno;
! 376: } else {
! 377: return 0;
! 378: }
! 379: }
! 380: }
! 381:
! 382:
! 383: static process_pair *process_get(FILE *stream TSRMLS_DC)
! 384: {
! 385: process_pair *ptr;
! 386: process_pair *newptr;
! 387:
! 388: for (ptr = TWG(process); ptr < (TWG(process) + TWG(process_size)); ptr++) {
! 389: if (ptr->stream == stream) {
! 390: break;
! 391: }
! 392: }
! 393:
! 394: if (ptr < (TWG(process) + TWG(process_size))) {
! 395: return ptr;
! 396: }
! 397:
! 398: newptr = (process_pair*)realloc((void*)TWG(process), (TWG(process_size)+1)*sizeof(process_pair));
! 399: if (newptr == NULL) {
! 400: return NULL;
! 401: }
! 402:
! 403: TWG(process) = newptr;
! 404: ptr = newptr + TWG(process_size);
! 405: TWG(process_size)++;
! 406: return ptr;
! 407: }
! 408:
! 409: static shm_pair *shm_get(int key, void *addr)
! 410: {
! 411: shm_pair *ptr;
! 412: shm_pair *newptr;
! 413: TSRMLS_FETCH();
! 414:
! 415: for (ptr = TWG(shm); ptr < (TWG(shm) + TWG(shm_size)); ptr++) {
! 416: if (!ptr->descriptor) {
! 417: continue;
! 418: }
! 419: if (!addr && ptr->descriptor->shm_perm.key == key) {
! 420: break;
! 421: } else if (ptr->addr == addr) {
! 422: break;
! 423: }
! 424: }
! 425:
! 426: if (ptr < (TWG(shm) + TWG(shm_size))) {
! 427: return ptr;
! 428: }
! 429:
! 430: newptr = (shm_pair*)realloc((void*)TWG(shm), (TWG(shm_size)+1)*sizeof(shm_pair));
! 431: if (newptr == NULL) {
! 432: return NULL;
! 433: }
! 434:
! 435: TWG(shm) = newptr;
! 436: ptr = newptr + TWG(shm_size);
! 437: TWG(shm_size)++;
! 438: return ptr;
! 439: }
! 440:
! 441: static HANDLE dupHandle(HANDLE fh, BOOL inherit) {
! 442: HANDLE copy, self = GetCurrentProcess();
! 443: if (!DuplicateHandle(self, fh, self, ©, 0, inherit, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE)) {
! 444: return NULL;
! 445: }
! 446: return copy;
! 447: }
! 448:
! 449: TSRM_API FILE *popen(const char *command, const char *type)
! 450: {
! 451: return popen_ex(command, type, NULL, NULL);
! 452: }
! 453:
! 454: TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd, char *env)
! 455: {
! 456: FILE *stream = NULL;
! 457: int fno, type_len = strlen(type), read, mode;
! 458: STARTUPINFO startup;
! 459: PROCESS_INFORMATION process;
! 460: SECURITY_ATTRIBUTES security;
! 461: HANDLE in, out;
! 462: DWORD dwCreateFlags = 0;
! 463: BOOL res;
! 464: process_pair *proc;
! 465: char *cmd;
! 466: int i;
! 467: char *ptype = (char *)type;
! 468: HANDLE thread_token = NULL;
! 469: HANDLE token_user = NULL;
! 470: BOOL asuser = TRUE;
! 471:
! 472: TSRMLS_FETCH();
! 473:
! 474: if (!type) {
! 475: return NULL;
! 476: }
! 477:
! 478: /*The following two checks can be removed once we drop XP support */
! 479: type_len = strlen(type);
! 480: if (type_len <1 || type_len > 2) {
! 481: return NULL;
! 482: }
! 483:
! 484: for (i=0; i < type_len; i++) {
! 485: if (!(*ptype == 'r' || *ptype == 'w' || *ptype == 'b' || *ptype == 't')) {
! 486: return NULL;
! 487: }
! 488: ptype++;
! 489: }
! 490:
! 491: security.nLength = sizeof(SECURITY_ATTRIBUTES);
! 492: security.bInheritHandle = TRUE;
! 493: security.lpSecurityDescriptor = NULL;
! 494:
! 495: if (!type_len || !CreatePipe(&in, &out, &security, 2048L)) {
! 496: return NULL;
! 497: }
! 498:
! 499: memset(&startup, 0, sizeof(STARTUPINFO));
! 500: memset(&process, 0, sizeof(PROCESS_INFORMATION));
! 501:
! 502: startup.cb = sizeof(STARTUPINFO);
! 503: startup.dwFlags = STARTF_USESTDHANDLES;
! 504: startup.hStdError = GetStdHandle(STD_ERROR_HANDLE);
! 505:
! 506: read = (type[0] == 'r') ? TRUE : FALSE;
! 507: mode = ((type_len == 2) && (type[1] == 'b')) ? O_BINARY : O_TEXT;
! 508:
! 509: if (read) {
! 510: in = dupHandle(in, FALSE);
! 511: startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
! 512: startup.hStdOutput = out;
! 513: } else {
! 514: out = dupHandle(out, FALSE);
! 515: startup.hStdInput = in;
! 516: startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
! 517: }
! 518:
! 519: dwCreateFlags = NORMAL_PRIORITY_CLASS;
! 520: if (strcmp(sapi_module.name, "cli") != 0) {
! 521: dwCreateFlags |= CREATE_NO_WINDOW;
! 522: }
! 523:
! 524: /* Get a token with the impersonated user. */
! 525: if(OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
! 526: DuplicateTokenEx(thread_token, MAXIMUM_ALLOWED, &security, SecurityImpersonation, TokenPrimary, &token_user);
! 527: } else {
! 528: DWORD err = GetLastError();
! 529: if (err == ERROR_NO_TOKEN) {
! 530: asuser = FALSE;
! 531: }
! 532: }
! 533:
! 534: cmd = (char*)malloc(strlen(command)+strlen(TWG(comspec))+sizeof(" /c ")+2);
! 535: if (!cmd) {
! 536: return NULL;
! 537: }
! 538:
! 539: sprintf(cmd, "%s /c \"%s\"", TWG(comspec), command);
! 540: if (asuser) {
! 541: res = CreateProcessAsUser(token_user, NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process);
! 542: CloseHandle(token_user);
! 543: } else {
! 544: res = CreateProcess(NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process);
! 545: }
! 546: free(cmd);
! 547:
! 548: if (!res) {
! 549: return NULL;
! 550: }
! 551:
! 552: CloseHandle(process.hThread);
! 553: proc = process_get(NULL TSRMLS_CC);
! 554:
! 555: if (read) {
! 556: fno = _open_osfhandle((tsrm_intptr_t)in, _O_RDONLY | mode);
! 557: CloseHandle(out);
! 558: } else {
! 559: fno = _open_osfhandle((tsrm_intptr_t)out, _O_WRONLY | mode);
! 560: CloseHandle(in);
! 561: }
! 562:
! 563: stream = _fdopen(fno, type);
! 564: proc->prochnd = process.hProcess;
! 565: proc->stream = stream;
! 566: return stream;
! 567: }
! 568:
! 569: TSRM_API int pclose(FILE *stream)
! 570: {
! 571: DWORD termstat = 0;
! 572: process_pair *process;
! 573: TSRMLS_FETCH();
! 574:
! 575: if ((process = process_get(stream TSRMLS_CC)) == NULL) {
! 576: return 0;
! 577: }
! 578:
! 579: fflush(process->stream);
! 580: fclose(process->stream);
! 581:
! 582: WaitForSingleObject(process->prochnd, INFINITE);
! 583: GetExitCodeProcess(process->prochnd, &termstat);
! 584: process->stream = NULL;
! 585: CloseHandle(process->prochnd);
! 586:
! 587: return termstat;
! 588: }
! 589:
! 590: TSRM_API int shmget(int key, int size, int flags)
! 591: {
! 592: shm_pair *shm;
! 593: char shm_segment[26], shm_info[29];
! 594: HANDLE shm_handle, info_handle;
! 595: BOOL created = FALSE;
! 596:
! 597: if (size < 0) {
! 598: return -1;
! 599: }
! 600:
! 601: sprintf(shm_segment, "TSRM_SHM_SEGMENT:%d", key);
! 602: sprintf(shm_info, "TSRM_SHM_DESCRIPTOR:%d", key);
! 603:
! 604: shm_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_segment);
! 605: info_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_info);
! 606:
! 607: if ((!shm_handle && !info_handle)) {
! 608: if (flags & IPC_CREAT) {
! 609: shm_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, shm_segment);
! 610: info_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(shm->descriptor), shm_info);
! 611: created = TRUE;
! 612: }
! 613: if ((!shm_handle || !info_handle)) {
! 614: return -1;
! 615: }
! 616: } else {
! 617: if (flags & IPC_EXCL) {
! 618: return -1;
! 619: }
! 620: }
! 621:
! 622: shm = shm_get(key, NULL);
! 623: shm->segment = shm_handle;
! 624: shm->info = info_handle;
! 625: shm->descriptor = MapViewOfFileEx(shm->info, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
! 626:
! 627: if (created) {
! 628: shm->descriptor->shm_perm.key = key;
! 629: shm->descriptor->shm_segsz = size;
! 630: shm->descriptor->shm_ctime = time(NULL);
! 631: shm->descriptor->shm_cpid = getpid();
! 632: shm->descriptor->shm_perm.mode = flags;
! 633:
! 634: shm->descriptor->shm_perm.cuid = shm->descriptor->shm_perm.cgid= 0;
! 635: shm->descriptor->shm_perm.gid = shm->descriptor->shm_perm.uid = 0;
! 636: shm->descriptor->shm_atime = shm->descriptor->shm_dtime = 0;
! 637: shm->descriptor->shm_lpid = shm->descriptor->shm_nattch = 0;
! 638: shm->descriptor->shm_perm.mode = shm->descriptor->shm_perm.seq = 0;
! 639: }
! 640:
! 641: if (shm->descriptor->shm_perm.key != key || size > shm->descriptor->shm_segsz ) {
! 642: CloseHandle(shm->segment);
! 643: UnmapViewOfFile(shm->descriptor);
! 644: CloseHandle(shm->info);
! 645: return -1;
! 646: }
! 647:
! 648: return key;
! 649: }
! 650:
! 651: TSRM_API void *shmat(int key, const void *shmaddr, int flags)
! 652: {
! 653: shm_pair *shm = shm_get(key, NULL);
! 654:
! 655: if (!shm->segment) {
! 656: return (void*)-1;
! 657: }
! 658:
! 659: shm->descriptor->shm_atime = time(NULL);
! 660: shm->descriptor->shm_lpid = getpid();
! 661: shm->descriptor->shm_nattch++;
! 662:
! 663: shm->addr = MapViewOfFileEx(shm->segment, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
! 664:
! 665: return shm->addr;
! 666: }
! 667:
! 668: TSRM_API int shmdt(const void *shmaddr)
! 669: {
! 670: shm_pair *shm = shm_get(0, (void*)shmaddr);
! 671:
! 672: if (!shm->segment) {
! 673: return -1;
! 674: }
! 675:
! 676: shm->descriptor->shm_dtime = time(NULL);
! 677: shm->descriptor->shm_lpid = getpid();
! 678: shm->descriptor->shm_nattch--;
! 679:
! 680: return UnmapViewOfFile(shm->addr) ? 0 : -1;
! 681: }
! 682:
! 683: TSRM_API int shmctl(int key, int cmd, struct shmid_ds *buf) {
! 684: shm_pair *shm = shm_get(key, NULL);
! 685:
! 686: if (!shm->segment) {
! 687: return -1;
! 688: }
! 689:
! 690: switch (cmd) {
! 691: case IPC_STAT:
! 692: memcpy(buf, shm->descriptor, sizeof(struct shmid_ds));
! 693: return 0;
! 694:
! 695: case IPC_SET:
! 696: shm->descriptor->shm_ctime = time(NULL);
! 697: shm->descriptor->shm_perm.uid = buf->shm_perm.uid;
! 698: shm->descriptor->shm_perm.gid = buf->shm_perm.gid;
! 699: shm->descriptor->shm_perm.mode = buf->shm_perm.mode;
! 700: return 0;
! 701:
! 702: case IPC_RMID:
! 703: if (shm->descriptor->shm_nattch < 1) {
! 704: shm->descriptor->shm_perm.key = -1;
! 705: }
! 706: return 0;
! 707:
! 708: default:
! 709: return -1;
! 710: }
! 711: }
! 712:
! 713: TSRM_API char *realpath(char *orig_path, char *buffer)
! 714: {
! 715: int ret = GetFullPathName(orig_path, _MAX_PATH, buffer, NULL);
! 716: if(!ret || ret > _MAX_PATH) {
! 717: return NULL;
! 718: }
! 719: return buffer;
! 720: }
! 721:
! 722: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>