This source file includes following definitions.
- tsrm_win32_ctor
- tsrm_win32_dtor
- tsrm_win32_startup
- tsrm_win32_shutdown
- tsrm_win32_get_path_sid_key
- tsrm_win32_get_token_sid
- tsrm_win32_access
- process_get
- shm_get
- dupHandle
- popen
- popen_ex
- pclose
- shmget
- shmat
- shmdt
- shmctl
- realpath
- UnixTimeToFileTime
- win32_utime
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
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)
44 {
45 #ifdef ZTS
46 TSRMLS_CACHE_UPDATE();
47 #endif
48 globals->process = NULL;
49 globals->shm = NULL;
50 globals->process_size = 0;
51 globals->shm_size = 0;
52 globals->comspec = _strdup("cmd.exe");
53
54
55
56
57
58
59
60
61 globals->impersonation_token = INVALID_HANDLE_VALUE;
62 globals->impersonation_token_sid = NULL;
63 }
64
65 static void tsrm_win32_dtor(tsrm_win32_globals *globals)
66 {
67 shm_pair *ptr;
68
69 if (globals->process) {
70 free(globals->process);
71 }
72
73 if (globals->shm) {
74 for (ptr = globals->shm; ptr < (globals->shm + globals->shm_size); ptr++) {
75 UnmapViewOfFile(ptr->addr);
76 CloseHandle(ptr->segment);
77 UnmapViewOfFile(ptr->descriptor);
78 CloseHandle(ptr->info);
79 }
80 free(globals->shm);
81 }
82
83 free(globals->comspec);
84
85 if (globals->impersonation_token && globals->impersonation_token != INVALID_HANDLE_VALUE ) {
86 CloseHandle(globals->impersonation_token);
87 }
88 if (globals->impersonation_token_sid) {
89 free(globals->impersonation_token_sid);
90 }
91 }
92
93 TSRM_API void tsrm_win32_startup(void)
94 {
95 #ifdef ZTS
96 ts_allocate_id(&win32_globals_id, sizeof(tsrm_win32_globals), (ts_allocate_ctor)tsrm_win32_ctor, (ts_allocate_ctor)tsrm_win32_dtor);
97 #else
98 tsrm_win32_ctor(&win32_globals);
99 #endif
100 }
101
102 TSRM_API void tsrm_win32_shutdown(void)
103 {
104 #ifndef ZTS
105 tsrm_win32_dtor(&win32_globals);
106 #endif
107 }
108
109 char * tsrm_win32_get_path_sid_key(const char *pathname)
110 {
111 PSID pSid = TWG(impersonation_token_sid);
112 TCHAR *ptcSid = NULL;
113 char *bucket_key = NULL;
114 size_t ptc_sid_len, pathname_len;
115
116 pathname_len = strlen(pathname);
117
118 if (!pSid) {
119 bucket_key = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pathname_len + 1);
120 if (!bucket_key) {
121 return NULL;
122 }
123 memcpy(bucket_key, pathname, pathname_len);
124 return bucket_key;
125 }
126
127 if (!ConvertSidToStringSid(pSid, &ptcSid)) {
128 return NULL;
129 }
130
131
132 ptc_sid_len = strlen(ptcSid);
133 bucket_key = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, pathname_len + ptc_sid_len + 1);
134 if (!bucket_key) {
135 LocalFree(ptcSid);
136 return NULL;
137 }
138
139 memcpy(bucket_key, ptcSid, ptc_sid_len);
140 memcpy(bucket_key + ptc_sid_len, pathname, pathname_len + 1);
141
142 LocalFree(ptcSid);
143 return bucket_key;
144 }
145
146
147 PSID tsrm_win32_get_token_sid(HANDLE hToken)
148 {
149 DWORD dwLength = 0;
150 PTOKEN_USER pTokenUser = NULL;
151 DWORD sid_len;
152 PSID pResultSid = NULL;
153
154
155 if (!GetTokenInformation(
156 hToken, TokenUser, (LPVOID) pTokenUser, 0, &dwLength)) {
157 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
158 goto Finished;
159 }
160
161 pTokenUser = (PTOKEN_USER)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength);
162 if (pTokenUser == NULL) {
163 goto Finished;
164 }
165 }
166
167
168 if (!GetTokenInformation(
169 hToken, TokenUser, (LPVOID) pTokenUser, dwLength, &dwLength)) {
170 goto Finished;
171 }
172
173 sid_len = GetLengthSid(pTokenUser->User.Sid);
174
175
176 pResultSid = malloc(sid_len);
177 if (!pResultSid) {
178 goto Finished;
179 }
180 if (!CopySid(sid_len, pResultSid, pTokenUser->User.Sid)) {
181 goto Finished;
182 }
183 HeapFree(GetProcessHeap(), 0, (LPVOID)pTokenUser);
184 return pResultSid;
185
186 Finished:
187 if (pResultSid) {
188 free(pResultSid);
189 }
190
191 if (pTokenUser != NULL) {
192 HeapFree(GetProcessHeap(), 0, (LPVOID)pTokenUser);
193 }
194 return NULL;
195 }
196
197 TSRM_API int tsrm_win32_access(const char *pathname, int mode)
198 {
199 time_t t;
200 HANDLE thread_token = NULL;
201 PSID token_sid;
202 SECURITY_INFORMATION sec_info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
203 GENERIC_MAPPING gen_map = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS };
204 DWORD priv_set_length = sizeof(PRIVILEGE_SET);
205
206 PRIVILEGE_SET privilege_set = {0};
207 DWORD sec_desc_length = 0, desired_access = 0, granted_access = 0;
208 BYTE * psec_desc = NULL;
209 BOOL fAccess = FALSE;
210
211 realpath_cache_bucket * bucket = NULL;
212 char * real_path = NULL;
213
214 if (mode == 1 ) {
215 DWORD type;
216 return GetBinaryType(pathname, &type) ? 0 : -1;
217 } else {
218 if(!IS_ABSOLUTE_PATH(pathname, strlen(pathname)+1)) {
219 real_path = (char *)malloc(MAX_PATH);
220 if(tsrm_realpath(pathname, real_path) == NULL) {
221 goto Finished;
222 }
223 pathname = real_path;
224 }
225
226 if(access(pathname, mode)) {
227 free(real_path);
228 return errno;
229 }
230
231
232 if (mode == 0) {
233 free(real_path);
234 return 0;
235 }
236
237
238
239
240
241
242
243
244
245
246
247 if(!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
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
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
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
274 if (!DuplicateToken(thread_token, SecurityImpersonation, &TWG(impersonation_token))) {
275 goto Finished;
276 }
277 } else {
278
279 free(token_sid);
280 }
281
282 if (CWDG(realpath_cache_size_limit)) {
283 t = time(0);
284 bucket = realpath_cache_lookup(pathname, (int)strlen(pathname), t);
285 if(bucket == NULL && real_path == NULL) {
286
287
288 real_path = (char *)malloc(MAX_PATH);
289 if(tsrm_realpath(pathname, real_path) != NULL) {
290 pathname = real_path;
291 bucket = realpath_cache_lookup(pathname, (int)strlen(pathname), t);
292 }
293 }
294 }
295
296
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 {
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
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
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(thread_token != NULL) {
369 CloseHandle(thread_token);
370 }
371 if(real_path != NULL) {
372 free(real_path);
373 real_path = NULL;
374 }
375
376 if(fAccess == FALSE) {
377 errno = EACCES;
378 return errno;
379 } else {
380 return 0;
381 }
382 }
383 }
384
385
386 static process_pair *process_get(FILE *stream)
387 {
388 process_pair *ptr;
389 process_pair *newptr;
390
391 for (ptr = TWG(process); ptr < (TWG(process) + TWG(process_size)); ptr++) {
392 if (ptr->stream == stream) {
393 break;
394 }
395 }
396
397 if (ptr < (TWG(process) + TWG(process_size))) {
398 return ptr;
399 }
400
401 newptr = (process_pair*)realloc((void*)TWG(process), (TWG(process_size)+1)*sizeof(process_pair));
402 if (newptr == NULL) {
403 return NULL;
404 }
405
406 TWG(process) = newptr;
407 ptr = newptr + TWG(process_size);
408 TWG(process_size)++;
409 return ptr;
410 }
411
412 static shm_pair *shm_get(int key, void *addr)
413 {
414 shm_pair *ptr;
415 shm_pair *newptr;
416
417 for (ptr = TWG(shm); ptr < (TWG(shm) + TWG(shm_size)); ptr++) {
418 if (!ptr->descriptor) {
419 continue;
420 }
421 if (!addr && ptr->descriptor->shm_perm.key == key) {
422 break;
423 } else if (ptr->addr == addr) {
424 break;
425 }
426 }
427
428 if (ptr < (TWG(shm) + TWG(shm_size))) {
429 return ptr;
430 }
431
432 newptr = (shm_pair*)realloc((void*)TWG(shm), (TWG(shm_size)+1)*sizeof(shm_pair));
433 if (newptr == NULL) {
434 return NULL;
435 }
436
437 TWG(shm) = newptr;
438 ptr = newptr + TWG(shm_size);
439 TWG(shm_size)++;
440 memset(ptr, 0, sizeof(*ptr));
441 return ptr;
442 }
443
444 static HANDLE dupHandle(HANDLE fh, BOOL inherit) {
445 HANDLE copy, self = GetCurrentProcess();
446 if (!DuplicateHandle(self, fh, self, ©, 0, inherit, DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE)) {
447 return NULL;
448 }
449 return copy;
450 }
451
452 TSRM_API FILE *popen(const char *command, const char *type)
453 {
454
455 return popen_ex(command, type, NULL, NULL);
456 }
457
458 TSRM_API FILE *popen_ex(const char *command, const char *type, const char *cwd, char *env)
459 {
460 FILE *stream = NULL;
461 int fno, type_len, read, mode;
462 STARTUPINFO startup;
463 PROCESS_INFORMATION process;
464 SECURITY_ATTRIBUTES security;
465 HANDLE in, out;
466 DWORD dwCreateFlags = 0;
467 BOOL res;
468 process_pair *proc;
469 char *cmd;
470 int i;
471 char *ptype = (char *)type;
472 HANDLE thread_token = NULL;
473 HANDLE token_user = NULL;
474 BOOL asuser = TRUE;
475
476 if (!type) {
477 return NULL;
478 }
479
480
481 type_len = (int)strlen(type);
482 if (type_len <1 || type_len > 2) {
483 return NULL;
484 }
485
486 for (i=0; i < type_len; i++) {
487 if (!(*ptype == 'r' || *ptype == 'w' || *ptype == 'b' || *ptype == 't')) {
488 return NULL;
489 }
490 ptype++;
491 }
492
493 security.nLength = sizeof(SECURITY_ATTRIBUTES);
494 security.bInheritHandle = TRUE;
495 security.lpSecurityDescriptor = NULL;
496
497 if (!type_len || !CreatePipe(&in, &out, &security, 2048L)) {
498 return NULL;
499 }
500
501 memset(&startup, 0, sizeof(STARTUPINFO));
502 memset(&process, 0, sizeof(PROCESS_INFORMATION));
503
504 startup.cb = sizeof(STARTUPINFO);
505 startup.dwFlags = STARTF_USESTDHANDLES;
506 startup.hStdError = GetStdHandle(STD_ERROR_HANDLE);
507
508 read = (type[0] == 'r') ? TRUE : FALSE;
509 mode = ((type_len == 2) && (type[1] == 'b')) ? O_BINARY : O_TEXT;
510
511 if (read) {
512 in = dupHandle(in, FALSE);
513 startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
514 startup.hStdOutput = out;
515 } else {
516 out = dupHandle(out, FALSE);
517 startup.hStdInput = in;
518 startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
519 }
520
521 dwCreateFlags = NORMAL_PRIORITY_CLASS;
522 if (strcmp(sapi_module.name, "cli") != 0) {
523 dwCreateFlags |= CREATE_NO_WINDOW;
524 }
525
526
527 if(OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, &thread_token)) {
528 DuplicateTokenEx(thread_token, MAXIMUM_ALLOWED, &security, SecurityImpersonation, TokenPrimary, &token_user);
529 } else {
530 DWORD err = GetLastError();
531 if (err == ERROR_NO_TOKEN) {
532 asuser = FALSE;
533 }
534 }
535
536 cmd = (char*)malloc(strlen(command)+strlen(TWG(comspec))+sizeof(" /c ")+2);
537 if (!cmd) {
538 return NULL;
539 }
540
541 sprintf(cmd, "%s /c \"%s\"", TWG(comspec), command);
542 if (asuser) {
543 res = CreateProcessAsUser(token_user, NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process);
544 CloseHandle(token_user);
545 } else {
546 res = CreateProcess(NULL, cmd, &security, &security, security.bInheritHandle, dwCreateFlags, env, cwd, &startup, &process);
547 }
548 free(cmd);
549
550 if (!res) {
551 return NULL;
552 }
553
554 CloseHandle(process.hThread);
555 proc = process_get(NULL);
556
557 if (read) {
558 fno = _open_osfhandle((tsrm_intptr_t)in, _O_RDONLY | mode);
559 CloseHandle(out);
560 } else {
561 fno = _open_osfhandle((tsrm_intptr_t)out, _O_WRONLY | mode);
562 CloseHandle(in);
563 }
564
565 stream = _fdopen(fno, type);
566 proc->prochnd = process.hProcess;
567 proc->stream = stream;
568 return stream;
569 }
570
571 TSRM_API int pclose(FILE *stream)
572 {
573 DWORD termstat = 0;
574 process_pair *process;
575
576 if ((process = process_get(stream)) == 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 snprintf(shm_segment, sizeof(shm_segment), "TSRM_SHM_SEGMENT:%d", key);
603 snprintf(shm_info, sizeof(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 if (shm_handle) {
616 CloseHandle(shm_handle);
617 }
618 if (info_handle) {
619 CloseHandle(info_handle);
620 }
621 return -1;
622 }
623 } else {
624 if (flags & IPC_EXCL) {
625 return -1;
626 }
627 }
628
629 shm = shm_get(key, NULL);
630 if (!shm) {
631 CloseHandle(shm_handle);
632 CloseHandle(info_handle);
633 return -1;
634 }
635 shm->segment = shm_handle;
636 shm->info = info_handle;
637 shm->descriptor = MapViewOfFileEx(shm->info, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
638
639 if (NULL != shm->descriptor && created) {
640 shm->descriptor->shm_perm.key = key;
641 shm->descriptor->shm_segsz = size;
642 shm->descriptor->shm_ctime = time(NULL);
643 shm->descriptor->shm_cpid = getpid();
644 shm->descriptor->shm_perm.mode = flags;
645
646 shm->descriptor->shm_perm.cuid = shm->descriptor->shm_perm.cgid= 0;
647 shm->descriptor->shm_perm.gid = shm->descriptor->shm_perm.uid = 0;
648 shm->descriptor->shm_atime = shm->descriptor->shm_dtime = 0;
649 shm->descriptor->shm_lpid = shm->descriptor->shm_nattch = 0;
650 shm->descriptor->shm_perm.mode = shm->descriptor->shm_perm.seq = 0;
651 }
652
653 if (NULL != shm->descriptor && (shm->descriptor->shm_perm.key != key || size > shm->descriptor->shm_segsz)) {
654 if (NULL != shm->segment) {
655 CloseHandle(shm->segment);
656 }
657 UnmapViewOfFile(shm->descriptor);
658 CloseHandle(shm->info);
659 return -1;
660 }
661
662 return key;
663 }
664
665 TSRM_API void *shmat(int key, const void *shmaddr, int flags)
666 {
667 shm_pair *shm = shm_get(key, NULL);
668
669 if (!shm->segment) {
670 return (void*)-1;
671 }
672
673 shm->descriptor->shm_atime = time(NULL);
674 shm->descriptor->shm_lpid = getpid();
675 shm->descriptor->shm_nattch++;
676
677 shm->addr = MapViewOfFileEx(shm->segment, FILE_MAP_ALL_ACCESS, 0, 0, 0, NULL);
678
679 return shm->addr;
680 }
681
682 TSRM_API int shmdt(const void *shmaddr)
683 {
684 shm_pair *shm = shm_get(0, (void*)shmaddr);
685
686 if (!shm->segment) {
687 return -1;
688 }
689
690 shm->descriptor->shm_dtime = time(NULL);
691 shm->descriptor->shm_lpid = getpid();
692 shm->descriptor->shm_nattch--;
693
694 return UnmapViewOfFile(shm->addr) ? 0 : -1;
695 }
696
697 TSRM_API int shmctl(int key, int cmd, struct shmid_ds *buf) {
698 shm_pair *shm = shm_get(key, NULL);
699
700 if (!shm->segment) {
701 return -1;
702 }
703
704 switch (cmd) {
705 case IPC_STAT:
706 memcpy(buf, shm->descriptor, sizeof(struct shmid_ds));
707 return 0;
708
709 case IPC_SET:
710 shm->descriptor->shm_ctime = time(NULL);
711 shm->descriptor->shm_perm.uid = buf->shm_perm.uid;
712 shm->descriptor->shm_perm.gid = buf->shm_perm.gid;
713 shm->descriptor->shm_perm.mode = buf->shm_perm.mode;
714 return 0;
715
716 case IPC_RMID:
717 if (shm->descriptor->shm_nattch < 1) {
718 shm->descriptor->shm_perm.key = -1;
719 }
720 return 0;
721
722 default:
723 return -1;
724 }
725 }
726
727 TSRM_API char *realpath(char *orig_path, char *buffer)
728 {
729 int ret = GetFullPathName(orig_path, _MAX_PATH, buffer, NULL);
730 if(!ret || ret > _MAX_PATH) {
731 return NULL;
732 }
733 return buffer;
734 }
735
736 #if HAVE_UTIME
737 static zend_always_inline void UnixTimeToFileTime(time_t t, LPFILETIME pft)
738 {
739
740 LONGLONG ll;
741
742 ll = Int32x32To64(t, 10000000) + 116444736000000000;
743 pft->dwLowDateTime = (DWORD)ll;
744 pft->dwHighDateTime = ll >> 32;
745 }
746
747
748 TSRM_API int win32_utime(const char *filename, struct utimbuf *buf)
749 {
750 FILETIME mtime, atime;
751 HANDLE hFile;
752
753 hFile = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_WRITE|FILE_SHARE_READ, NULL,
754 OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS, NULL);
755
756
757
758 if (GetLastError() == ERROR_ALREADY_EXISTS) {
759 SetLastError(0);
760 }
761
762 if ( hFile == INVALID_HANDLE_VALUE ) {
763 return -1;
764 }
765
766 if (!buf) {
767 SYSTEMTIME st;
768 GetSystemTime(&st);
769 SystemTimeToFileTime(&st, &mtime);
770 atime = mtime;
771 } else {
772 UnixTimeToFileTime(buf->modtime, &mtime);
773 UnixTimeToFileTime(buf->actime, &atime);
774 }
775 if (!SetFileTime(hFile, NULL, &atime, &mtime)) {
776 CloseHandle(hFile);
777 return -1;
778 }
779 CloseHandle(hFile);
780 return 1;
781 }
782
783 #endif
784 #endif