1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 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$ */
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 "zend_virtual_cwd.h"
36 #include "win32/ioutil.h"
37
38 #ifdef ZTS
39 static ts_rsrc_id win32_globals_id;
40 #else
41 static tsrm_win32_globals win32_globals;
42 #endif
43
tsrm_win32_ctor(tsrm_win32_globals * globals)44 static void tsrm_win32_ctor(tsrm_win32_globals *globals)
45 {/*{{{*/
46 #ifdef ZTS
47 TSRMLS_CACHE_UPDATE();
48 #endif
49 globals->process = NULL;
50 globals->shm = NULL;
51 globals->process_size = 0;
52 globals->shm_size = 0;
53 globals->comspec = _strdup("cmd.exe");
54
55 /* Set it to INVALID_HANDLE_VALUE
56 * It will be initialized correctly in tsrm_win32_access or set to
57 * NULL if no impersonation has been done.
58 * the impersonated token can't be set here as the impersonation
59 * will happen later, in fcgi_accept_request (or whatever is the
60 * SAPI being used).
61 */
62 globals->impersonation_token = INVALID_HANDLE_VALUE;
63 globals->impersonation_token_sid = NULL;
64 }/*}}}*/
65
tsrm_win32_dtor(tsrm_win32_globals * globals)66 static void tsrm_win32_dtor(tsrm_win32_globals *globals)
67 {/*{{{*/
68 shm_pair *ptr;
69
70 if (globals->process) {
71 free(globals->process);
72 }
73
74 if (globals->shm) {
75 for (ptr = globals->shm; ptr < (globals->shm + globals->shm_size); ptr++) {
76 UnmapViewOfFile(ptr->addr);
77 CloseHandle(ptr->segment);
78 UnmapViewOfFile(ptr->descriptor);
79 CloseHandle(ptr->info);
80 }
81 free(globals->shm);
82 }
83
84 free(globals->comspec);
85
86 if (globals->impersonation_token && globals->impersonation_token != INVALID_HANDLE_VALUE ) {
87 CloseHandle(globals->impersonation_token);
88 }
89 if (globals->impersonation_token_sid) {
90 free(globals->impersonation_token_sid);
91 }
92 }/*}}}*/
93
tsrm_win32_startup(void)94 TSRM_API void tsrm_win32_startup(void)
95 {/*{{{*/
96 #ifdef ZTS
97 ts_allocate_id(&win32_globals_id, sizeof(tsrm_win32_globals), (ts_allocate_ctor)tsrm_win32_ctor, (ts_allocate_ctor)tsrm_win32_dtor);
98 #else
99 tsrm_win32_ctor(&win32_globals);
100 #endif
101 }/*}}}*/
102
tsrm_win32_shutdown(void)103 TSRM_API void tsrm_win32_shutdown(void)
104 {/*{{{*/
105 #ifndef ZTS
106 tsrm_win32_dtor(&win32_globals);
107 #endif
108 }/*}}}*/
109
tsrm_win32_get_path_sid_key(const char * pathname,size_t pathname_len,size_t * key_len)110 char * tsrm_win32_get_path_sid_key(const char *pathname, size_t pathname_len, size_t *key_len)
111 {/*{{{*/
112 PSID pSid = TWG(impersonation_token_sid);
113 char *ptcSid = NULL;
114 char *bucket_key = NULL;
115 size_t ptc_sid_len;
116
117 if (!pSid) {
118 *key_len = pathname_len;
119 return pathname;
120 }
121
122 if (!ConvertSidToStringSid(pSid, &ptcSid)) {
123 *key_len = 0;
124 return NULL;
125 }
126
127
128 ptc_sid_len = strlen(ptcSid);
129 *key_len = pathname_len + ptc_sid_len;
130 bucket_key = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *key_len + 1);
131 if (!bucket_key) {
132 LocalFree(ptcSid);
133 *key_len = 0;
134 return NULL;
135 }
136
137 memcpy(bucket_key, ptcSid, ptc_sid_len);
138 memcpy(bucket_key + ptc_sid_len, pathname, pathname_len + 1);
139
140 LocalFree(ptcSid);
141 return bucket_key;
142 }/*}}}*/
143
144
tsrm_win32_get_token_sid(HANDLE hToken)145 PSID tsrm_win32_get_token_sid(HANDLE hToken)
146 {/*{{{*/
147 DWORD dwLength = 0;
148 PTOKEN_USER pTokenUser = NULL;
149 DWORD sid_len;
150 PSID pResultSid = NULL;
151
152 /* Get the actual size of the TokenUser structure */
153 if (!GetTokenInformation(
154 hToken, TokenUser, (LPVOID) pTokenUser, 0, &dwLength)) {
155 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
156 goto Finished;
157 }
158
159 pTokenUser = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
160 if (pTokenUser == NULL) {
161 goto Finished;
162 }
163 }
164
165 /* and fetch it now */
166 if (!GetTokenInformation(
167 hToken, TokenUser, (LPVOID) pTokenUser, dwLength, &dwLength)) {
168 goto Finished;
169 }
170
171 sid_len = GetLengthSid(pTokenUser->User.Sid);
172
173 /* ConvertSidToStringSid(pTokenUser->User.Sid, &ptcSidOwner); */
174 pResultSid = malloc(sid_len);
175 if (!pResultSid) {
176 goto Finished;
177 }
178 if (!CopySid(sid_len, pResultSid, pTokenUser->User.Sid)) {
179 goto Finished;
180 }
181 HeapFree(GetProcessHeap(), 0, (LPVOID)pTokenUser);
182 return pResultSid;
183
184 Finished:
185 if (pResultSid) {
186 free(pResultSid);
187 }
188 /* Free the buffer for the token groups. */
189 if (pTokenUser != NULL) {
190 HeapFree(GetProcessHeap(), 0, (LPVOID)pTokenUser);
191 }
192 return NULL;
193 }/*}}}*/
194
tsrm_win32_access(const char * pathname,int mode)195 TSRM_API int tsrm_win32_access(const char *pathname, int mode)
196 {/*{{{*/
197 time_t t;
198 HANDLE thread_token = NULL;
199 PSID token_sid;
200 SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
201 GENERIC_MAPPING gen_map = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS };
202 DWORD priv_set_length = sizeof(PRIVILEGE_SET);
203
204 PRIVILEGE_SET privilege_set = {0};
205 DWORD sec_desc_length = 0, desired_access = 0, granted_access = 0;
206 BYTE * psec_desc = NULL;
207 BOOL fAccess = FALSE;
208
209 realpath_cache_bucket * bucket = NULL;
210 char * real_path = NULL;
211
212 PHP_WIN32_IOUTIL_INIT_W(pathname)
213 if (!pathw) {
214 return -1;
215 }
216
217 if (mode == 1 /*X_OK*/) {
218 DWORD type;
219 int ret;
220
221 ret = GetBinaryTypeW(pathw, &type) ? 0 : -1;
222
223 PHP_WIN32_IOUTIL_CLEANUP_W()
224
225 return ret;
226 } else {
227 if(!IS_ABSOLUTE_PATH(pathname, strlen(pathname)+1)) {
228 real_path = (char *)malloc(MAXPATHLEN);
229 if(tsrm_realpath(pathname, real_path) == NULL) {
230 goto Finished;
231 }
232 pathname = real_path;
233 PHP_WIN32_IOUTIL_REINIT_W(pathname);
234 }
235
236 if(php_win32_ioutil_access(pathname, mode)) {
237 PHP_WIN32_IOUTIL_CLEANUP_W()
238 free(real_path);
239 return errno;
240 }
241
242 /* If only existence check is made, return now */
243 if (mode == 0) {
244 PHP_WIN32_IOUTIL_CLEANUP_W()
245 free(real_path);
246 return 0;
247 }
248
249 /* Only in NTS when impersonate==1 (aka FastCGI) */
250
251 /*
252 AccessCheck() requires an impersonation token. We first get a primary
253 token and then create a duplicate impersonation token. The
254 impersonation token is not actually assigned to the thread, but is
255 used in the call to AccessCheck. Thus, this function itself never
256 impersonates, but does use the identity of the thread. If the thread
257 was impersonating already, this function uses that impersonation context.
258 */
259 if(!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
260 if (GetLastError() == ERROR_NO_TOKEN) {
261 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &thread_token)) {
262 TWG(impersonation_token) = NULL;
263 goto Finished;
264 }
265 }
266 }
267
268 /* token_sid will be freed in tsrmwin32_dtor */
269 token_sid = tsrm_win32_get_token_sid(thread_token);
270 if (!token_sid) {
271 if (TWG(impersonation_token_sid)) {
272 free(TWG(impersonation_token_sid));
273 }
274 TWG(impersonation_token_sid) = NULL;
275 goto Finished;
276 }
277
278 /* Different identity, we need a new impersontated token as well */
279 if (!TWG(impersonation_token_sid) || !EqualSid(token_sid, TWG(impersonation_token_sid))) {
280 if (TWG(impersonation_token_sid)) {
281 free(TWG(impersonation_token_sid));
282 }
283 TWG(impersonation_token_sid) = token_sid;
284
285 /* Duplicate the token as impersonated token */
286 if (!DuplicateToken(thread_token, SecurityImpersonation, &TWG(impersonation_token))) {
287 goto Finished;
288 }
289 } else {
290 /* we already have it, free it then */
291 free(token_sid);
292 }
293
294 if (CWDG(realpath_cache_size_limit)) {
295 t = time(0);
296 bucket = realpath_cache_lookup(pathname, strlen(pathname), t);
297 if(bucket == NULL && real_path == NULL) {
298 /* We used the pathname directly. Call tsrm_realpath */
299 /* so that entry is created in realpath cache */
300 real_path = (char *)malloc(MAXPATHLEN);
301 if(tsrm_realpath(pathname, real_path) != NULL) {
302 pathname = real_path;
303 bucket = realpath_cache_lookup(pathname, strlen(pathname), t);
304 PHP_WIN32_IOUTIL_REINIT_W(pathname);
305 }
306 }
307 }
308
309 /* Do a full access check because access() will only check read-only attribute */
310 if(mode == 0 || mode > 6) {
311 if(bucket != NULL && bucket->is_rvalid) {
312 fAccess = bucket->is_readable;
313 goto Finished;
314 }
315 desired_access = FILE_GENERIC_READ;
316 } else if(mode <= 2) {
317 if(bucket != NULL && bucket->is_wvalid) {
318 fAccess = bucket->is_writable;
319 goto Finished;
320 }
321 desired_access = FILE_GENERIC_WRITE;
322 } else if(mode <= 4) {
323 if(bucket != NULL && bucket->is_rvalid) {
324 fAccess = bucket->is_readable;
325 goto Finished;
326 }
327 desired_access = FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS;
328 } else { // if(mode <= 6)
329 if(bucket != NULL && bucket->is_rvalid && bucket->is_wvalid) {
330 fAccess = bucket->is_readable & bucket->is_writable;
331 goto Finished;
332 }
333 desired_access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
334 }
335
336 if(TWG(impersonation_token) == NULL) {
337 goto Finished;
338 }
339
340 /* Get size of security buffer. Call is expected to fail */
341 if(GetFileSecurityW(pathw, sec_info, NULL, 0, &sec_desc_length)) {
342 goto Finished;
343 }
344
345 psec_desc = (BYTE *)malloc(sec_desc_length);
346 if(psec_desc == NULL ||
347 !GetFileSecurityW(pathw, sec_info, (PSECURITY_DESCRIPTOR)psec_desc, sec_desc_length, &sec_desc_length)) {
348 goto Finished;
349 }
350
351 MapGenericMask(&desired_access, &gen_map);
352
353 if(!AccessCheck((PSECURITY_DESCRIPTOR)psec_desc, TWG(impersonation_token), desired_access, &gen_map, &privilege_set, &priv_set_length, &granted_access, &fAccess)) {
354 goto Finished_Impersonate;
355 }
356
357 /* Keep the result in realpath_cache */
358 if(bucket != NULL) {
359 if(desired_access == (FILE_GENERIC_READ|FILE_FLAG_BACKUP_SEMANTICS)) {
360 bucket->is_rvalid = 1;
361 bucket->is_readable = fAccess;
362 }
363 else if(desired_access == FILE_GENERIC_WRITE) {
364 bucket->is_wvalid = 1;
365 bucket->is_writable = fAccess;
366 } else if (desired_access == (FILE_GENERIC_READ | FILE_GENERIC_WRITE)) {
367 bucket->is_rvalid = 1;
368 bucket->is_readable = fAccess;
369 bucket->is_wvalid = 1;
370 bucket->is_writable = fAccess;
371 }
372 }
373
374 Finished_Impersonate:
375 if(psec_desc != NULL) {
376 free(psec_desc);
377 psec_desc = NULL;
378 }
379
380 Finished:
381 if(thread_token != NULL) {
382 CloseHandle(thread_token);
383 }
384 if(real_path != NULL) {
385 free(real_path);
386 real_path = NULL;
387 }
388
389 PHP_WIN32_IOUTIL_CLEANUP_W()
390 if(fAccess == FALSE) {
391 errno = EACCES;
392 return errno;
393 } else {
394 return 0;
395 }
396 }
397 }/*}}}*/
398
399
process_get(FILE * stream)400 static process_pair *process_get(FILE *stream)
401 {/*{{{*/
402 process_pair *ptr;
403 process_pair *newptr;
404
405 for (ptr = TWG(process); ptr < (TWG(process) + TWG(process_size)); ptr++) {
406 if (ptr->stream == stream) {
407 break;
408 }
409 }
410
411 if (ptr < (TWG(process) + TWG(process_size))) {
412 return ptr;
413 }
414
415 newptr = (process_pair*)realloc((void*)TWG(process), (TWG(process_size)+1)*sizeof(process_pair));
416 if (newptr == NULL) {
417 return NULL;
418 }
419
420 TWG(process) = newptr;
421 ptr = newptr + TWG(process_size);
422 TWG(process_size)++;
423 return ptr;
424 }/*}}}*/
425
shm_get(key_t key,void * addr)426 static shm_pair *shm_get(key_t key, void *addr)
427 {/*{{{*/
428 shm_pair *ptr;
429 shm_pair *newptr;
430
431 for (ptr = TWG(shm); ptr < (TWG(shm) + TWG(shm_size)); ptr++) {
432 if (!ptr->descriptor) {
433 continue;
434 }
435 if (!addr && ptr->descriptor->shm_perm.key == key) {
436 break;
437 } else if (ptr->addr == addr) {
438 break;
439 }
440 }
441
442 if (ptr < (TWG(shm) + TWG(shm_size))) {
443 return ptr;
444 }
445
446 newptr = (shm_pair*)realloc((void*)TWG(shm), (TWG(shm_size)+1)*sizeof(shm_pair));
447 if (newptr == NULL) {
448 return NULL;
449 }
450
451 TWG(shm) = newptr;
452 ptr = newptr + TWG(shm_size);
453 TWG(shm_size)++;
454 memset(ptr, 0, sizeof(*ptr));
455 return ptr;
456 }/*}}}*/
457
dupHandle(HANDLE fh,BOOL inherit)458 static HANDLE dupHandle(HANDLE fh, BOOL inherit)
459 {/*{{{*/
460 HANDLE copy, self = GetCurrentProcess();
461 if (!DuplicateHandle(self, fh, self, ©, 0, inherit, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE)) {
462 return NULL;
463 }
464 return copy;
465 }/*}}}*/
466
popen(const char * command,const char * type)467 TSRM_API FILE *popen(const char *command, const char *type)
468 {/*{{{*/
469
470 return popen_ex(command, type, NULL, NULL);
471 }/*}}}*/
472
popen_ex(const char * command,const char * type,const char * cwd,char * env)473 TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd, char *env)
474 {/*{{{*/
475 FILE *stream = NULL;
476 int fno, type_len, read, mode;
477 STARTUPINFOW startup;
478 PROCESS_INFORMATION process;
479 SECURITY_ATTRIBUTES security;
480 HANDLE in, out;
481 DWORD dwCreateFlags = 0;
482 BOOL res;
483 process_pair *proc;
484 char *cmd = NULL;
485 wchar_t *cmdw = NULL, *cwdw = NULL, *envw = NULL;
486 int i;
487 char *ptype = (char *)type;
488 HANDLE thread_token = NULL;
489 HANDLE token_user = NULL;
490 BOOL asuser = TRUE;
491
492 if (!type) {
493 return NULL;
494 }
495
496 /*The following two checks can be removed once we drop XP support */
497 type_len = (int)strlen(type);
498 if (type_len <1 || type_len > 2) {
499 return NULL;
500 }
501
502 for (i=0; i < type_len; i++) {
503 if (!(*ptype == 'r' || *ptype == 'w' || *ptype == 'b' || *ptype == 't')) {
504 return NULL;
505 }
506 ptype++;
507 }
508
509 cmd = (char*)malloc(strlen(command)+strlen(TWG(comspec))+sizeof(" /c ")+2);
510 if (!cmd) {
511 return NULL;
512 }
513
514 sprintf(cmd, "%s /c \"%s\"", TWG(comspec), command);
515 cmdw = php_win32_cp_any_to_w(cmd);
516 if (!cmdw) {
517 free(cmd);
518 return NULL;
519 }
520
521 if (cwd) {
522 cwdw = php_win32_ioutil_any_to_w(cwd);
523 if (!cwdw) {
524 free(cmd);
525 free(cmdw);
526 return NULL;
527 }
528 }
529
530 security.nLength = sizeof(SECURITY_ATTRIBUTES);
531 security.bInheritHandle = TRUE;
532 security.lpSecurityDescriptor = NULL;
533
534 if (!type_len || !CreatePipe(&in, &out, &security, 2048L)) {
535 free(cmdw);
536 free(cwdw);
537 free(cmd);
538 return NULL;
539 }
540
541 memset(&startup, 0, sizeof(STARTUPINFOW));
542 memset(&process, 0, sizeof(PROCESS_INFORMATION));
543
544 startup.cb = sizeof(STARTUPINFOW);
545 startup.dwFlags = STARTF_USESTDHANDLES;
546 startup.hStdError = GetStdHandle(STD_ERROR_HANDLE);
547
548 read = (type[0] == 'r') ? TRUE : FALSE;
549 mode = ((type_len == 2) && (type[1] == 'b')) ? O_BINARY : O_TEXT;
550
551 if (read) {
552 in = dupHandle(in, FALSE);
553 startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
554 startup.hStdOutput = out;
555 } else {
556 out = dupHandle(out, FALSE);
557 startup.hStdInput = in;
558 startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
559 }
560
561 dwCreateFlags = NORMAL_PRIORITY_CLASS;
562 if (strcmp(sapi_module.name, "cli") != 0) {
563 dwCreateFlags |= CREATE_NO_WINDOW;
564 }
565
566 /* Get a token with the impersonated user. */
567 if(OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
568 DuplicateTokenEx(thread_token, MAXIMUM_ALLOWED, &security, SecurityImpersonation, TokenPrimary, &token_user);
569 } else {
570 DWORD err = GetLastError();
571 if (err == ERROR_NO_TOKEN) {
572 asuser = FALSE;
573 }
574 }
575
576 envw = php_win32_cp_env_any_to_w(env);
577 if (envw) {
578 dwCreateFlags |= CREATE_UNICODE_ENVIRONMENT;
579 } else {
580 if (env) {
581 free(cmd);
582 free(cmdw);
583 free(cwdw);
584 return NULL;
585 }
586 }
587
588 if (asuser) {
589 res = CreateProcessAsUserW(token_user, NULL, cmdw, &security, &security, security.bInheritHandle, dwCreateFlags, envw, cwdw, &startup, &process);
590 CloseHandle(token_user);
591 } else {
592 res = CreateProcessW(NULL, cmdw, &security, &security, security.bInheritHandle, dwCreateFlags, envw, cwdw, &startup, &process);
593 }
594 free(cmd);
595 free(cmdw);
596 free(cwdw);
597 free(envw);
598
599 if (!res) {
600 return NULL;
601 }
602
603 CloseHandle(process.hThread);
604 proc = process_get(NULL);
605
606 if (read) {
607 fno = _open_osfhandle((tsrm_intptr_t)in, _O_RDONLY | mode);
608 CloseHandle(out);
609 } else {
610 fno = _open_osfhandle((tsrm_intptr_t)out, _O_WRONLY | mode);
611 CloseHandle(in);
612 }
613
614 stream = _fdopen(fno, type);
615 proc->prochnd = process.hProcess;
616 proc->stream = stream;
617 return stream;
618 }/*}}}*/
619
pclose(FILE * stream)620 TSRM_API int pclose(FILE *stream)
621 {/*{{{*/
622 DWORD termstat = 0;
623 process_pair *process;
624
625 if ((process = process_get(stream)) == NULL) {
626 return 0;
627 }
628
629 fflush(process->stream);
630 fclose(process->stream);
631
632 WaitForSingleObject(process->prochnd, INFINITE);
633 GetExitCodeProcess(process->prochnd, &termstat);
634 process->stream = NULL;
635 CloseHandle(process->prochnd);
636
637 return termstat;
638 }/*}}}*/
639
shmget(key_t key,size_t size,int flags)640 TSRM_API int shmget(key_t key, size_t size, int flags)
641 {/*{{{*/
642 shm_pair *shm;
643 char shm_segment[26], shm_info[29];
644 HANDLE shm_handle, info_handle;
645 BOOL created = FALSE;
646
647 snprintf(shm_segment, sizeof(shm_segment), "TSRM_SHM_SEGMENT:%d", key);
648 snprintf(shm_info, sizeof(shm_info), "TSRM_SHM_DESCRIPTOR:%d", key);
649
650 shm_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_segment);
651 info_handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, shm_info);
652
653 if (!shm_handle && !info_handle) {
654 if (flags & IPC_CREAT) {
655 #if SIZEOF_SIZE_T == 8
656 DWORD high = size >> 32;
657 DWORD low = (DWORD)size;
658 #else
659 DWORD high = 0;
660 DWORD low = size;
661 #endif
662 shm_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, high, low, shm_segment);
663 info_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(shm->descriptor), shm_info);
664 created = TRUE;
665 }
666 if (!shm_handle || !info_handle) {
667 if (shm_handle) {
668 CloseHandle(shm_handle);
669 }
670 if (info_handle) {
671 CloseHandle(info_handle);
672 }
673 return -1;
674 }
675 } else {
676 if (flags & IPC_EXCL) {
677 if (shm_handle) {
678 CloseHandle(shm_handle);
679 }
680 if (info_handle) {
681 CloseHandle(info_handle);
682 }
683 return -1;
684 }
685 }
686
687 shm = shm_get(key, NULL);
688 if (!shm) {
689 CloseHandle(shm_handle);
690 CloseHandle(info_handle);
691 return -1;
692 }
693 shm->segment = shm_handle;
694 shm->info = info_handle;
695 shm->descriptor = MapViewOfFileEx(shm->info, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
696
697 if (NULL != shm->descriptor && created) {
698 shm->descriptor->shm_perm.key = key;
699 shm->descriptor->shm_segsz = size;
700 shm->descriptor->shm_ctime = time(NULL);
701 shm->descriptor->shm_cpid = getpid();
702 shm->descriptor->shm_perm.mode = flags;
703
704 shm->descriptor->shm_perm.cuid = shm->descriptor->shm_perm.cgid= 0;
705 shm->descriptor->shm_perm.gid = shm->descriptor->shm_perm.uid = 0;
706 shm->descriptor->shm_atime = shm->descriptor->shm_dtime = 0;
707 shm->descriptor->shm_lpid = shm->descriptor->shm_nattch = 0;
708 shm->descriptor->shm_perm.mode = shm->descriptor->shm_perm.seq = 0;
709 }
710
711 if (NULL != shm->descriptor && (shm->descriptor->shm_perm.key != key || size > shm->descriptor->shm_segsz)) {
712 if (NULL != shm->segment) {
713 CloseHandle(shm->segment);
714 }
715 UnmapViewOfFile(shm->descriptor);
716 CloseHandle(shm->info);
717 return -1;
718 }
719
720 return key;
721 }/*}}}*/
722
shmat(int key,const void * shmaddr,int flags)723 TSRM_API void *shmat(int key, const void *shmaddr, int flags)
724 {/*{{{*/
725 shm_pair *shm = shm_get(key, NULL);
726
727 if (!shm->segment) {
728 return (void*)-1;
729 }
730
731 shm->addr = MapViewOfFileEx(shm->segment, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
732
733 if (NULL == shm->addr) {
734 int err = GetLastError();
735 SET_ERRNO_FROM_WIN32_CODE(err);
736 return (void*)-1;
737 }
738
739 shm->descriptor->shm_atime = time(NULL);
740 shm->descriptor->shm_lpid = getpid();
741 shm->descriptor->shm_nattch++;
742
743 return shm->addr;
744 }/*}}}*/
745
shmdt(const void * shmaddr)746 TSRM_API int shmdt(const void *shmaddr)
747 {/*{{{*/
748 shm_pair *shm = shm_get(0, (void*)shmaddr);
749
750 if (!shm->segment) {
751 return -1;
752 }
753
754 shm->descriptor->shm_dtime = time(NULL);
755 shm->descriptor->shm_lpid = getpid();
756 shm->descriptor->shm_nattch--;
757
758 return UnmapViewOfFile(shm->addr) ? 0 : -1;
759 }/*}}}*/
760
shmctl(int key,int cmd,struct shmid_ds * buf)761 TSRM_API int shmctl(int key, int cmd, struct shmid_ds *buf)
762 {/*{{{*/
763 shm_pair *shm = shm_get(key, NULL);
764
765 if (!shm->segment) {
766 return -1;
767 }
768
769 switch (cmd) {
770 case IPC_STAT:
771 memcpy(buf, shm->descriptor, sizeof(struct shmid_ds));
772 return 0;
773
774 case IPC_SET:
775 shm->descriptor->shm_ctime = time(NULL);
776 shm->descriptor->shm_perm.uid = buf->shm_perm.uid;
777 shm->descriptor->shm_perm.gid = buf->shm_perm.gid;
778 shm->descriptor->shm_perm.mode = buf->shm_perm.mode;
779 return 0;
780
781 case IPC_RMID:
782 if (shm->descriptor->shm_nattch < 1) {
783 shm->descriptor->shm_perm.key = -1;
784 }
785 return 0;
786
787 default:
788 return -1;
789 }
790 }/*}}}*/
791
realpath(char * orig_path,char * buffer)792 TSRM_API char *realpath(char *orig_path, char *buffer)
793 {/*{{{*/
794 int ret = GetFullPathName(orig_path, _MAX_PATH, buffer, NULL);
795 if(!ret || ret > _MAX_PATH) {
796 return NULL;
797 }
798 return buffer;
799 }/*}}}*/
800
801 #if HAVE_UTIME
UnixTimeToFileTime(time_t t,LPFILETIME pft)802 static zend_always_inline void UnixTimeToFileTime(time_t t, LPFILETIME pft) /* {{{ */
803 {
804 // Note that LONGLONG is a 64-bit value
805 LONGLONG ll;
806
807 ll = t * 10000000LL + 116444736000000000LL;
808 pft->dwLowDateTime = (DWORD)ll;
809 pft->dwHighDateTime = ll >> 32;
810 }
811 /* }}} */
812
win32_utime(const char * filename,struct utimbuf * buf)813 TSRM_API int win32_utime(const char *filename, struct utimbuf *buf) /* {{{ */
814 {
815 FILETIME mtime, atime;
816 HANDLE hFile;
817 PHP_WIN32_IOUTIL_INIT_W(filename)
818
819 if (!pathw) {
820 return -1;
821 }
822
823 hFile = CreateFileW(pathw, GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL,
824 OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, NULL);
825
826 PHP_WIN32_IOUTIL_CLEANUP_W()
827
828 /* OPEN_ALWAYS mode sets the last error to ERROR_ALREADY_EXISTS but
829 the CreateFile operation succeeds */
830 if (GetLastError() == ERROR_ALREADY_EXISTS) {
831 SetLastError(0);
832 }
833
834 if ( hFile == INVALID_HANDLE_VALUE ) {
835 return -1;
836 }
837
838 if (!buf) {
839 SYSTEMTIME st;
840 GetSystemTime(&st);
841 SystemTimeToFileTime(&st, &mtime);
842 atime = mtime;
843 } else {
844 UnixTimeToFileTime(buf->modtime, &mtime);
845 UnixTimeToFileTime(buf->actime, &atime);
846 }
847 if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
848 CloseHandle(hFile);
849 return -1;
850 }
851 CloseHandle(hFile);
852 return 1;
853 }
854 /* }}} */
855 #endif
856 #endif
857
858 /*
859 * Local variables:
860 * tab-width: 4
861 * c-basic-offset: 4
862 * End:
863 * vim600: sw=4 ts=4 fdm=marker
864 * vim<600: sw=4 ts=4
865 */
866