Annotation of embedaddon/php/TSRM/tsrm_win32.c, revision 1.1.1.4
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
1.1.1.3 misho 5: | Copyright (c) 1997-2013 The PHP Group |
1.1 misho 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:
1.1.1.2 misho 19: /* $Id$ */
1.1 misho 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:
1.1.1.2 misho 193: TSRM_API int tsrm_win32_access(const char *pathname, int mode TSRMLS_DC)
1.1 misho 194: {
195: time_t t;
1.1.1.3 misho 196: HANDLE thread_token = NULL;
1.1 misho 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:
1.1.1.3 misho 366: if(thread_token != NULL) {
367: CloseHandle(thread_token);
368: }
1.1 misho 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, ©, 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: {
1.1.1.2 misho 452: TSRMLS_FETCH();
453:
454: return popen_ex(command, type, NULL, NULL TSRMLS_CC);
1.1 misho 455: }
456:
1.1.1.2 misho 457: TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd, char *env TSRMLS_DC)
1.1 misho 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:
1.1.1.4 ! misho 628: if (NULL != shm->descriptor && created) {
1.1 misho 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:
1.1.1.4 ! misho 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: }
1.1 misho 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>