github.com/hbdrawn/golang@v0.0.0-20141214014649-6b835209aba2/src/cmd/dist/windows.c (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // These #ifdefs are being used as a substitute for 6 // build configuration, so that on any system, this 7 // tool can be built with the local equivalent of 8 // cc *.c 9 // 10 #ifdef WIN32 11 12 // Portability layer implemented for Windows. 13 // See unix.c for doc comments about exported functions. 14 15 #include "a.h" 16 #include <windows.h> 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <stdarg.h> 20 21 /* 22 * Windows uses 16-bit rune strings in the APIs. 23 * Define conversions between Rune* and UTF-8 char*. 24 */ 25 26 typedef unsigned char uchar; 27 typedef unsigned short Rune; // same as Windows 28 29 // encoderune encodes the rune r into buf and returns 30 // the number of bytes used. 31 static int 32 encoderune(char *buf, Rune r) 33 { 34 if(r < 0x80) { // 7 bits 35 buf[0] = r; 36 return 1; 37 } 38 if(r < 0x800) { // 5+6 bits 39 buf[0] = 0xc0 | (r>>6); 40 buf[1] = 0x80 | (r&0x3f); 41 return 2; 42 } 43 buf[0] = 0xe0 | (r>>12); 44 buf[1] = 0x80 | ((r>>6)&0x3f); 45 buf[2] = 0x80 | (r&0x3f); 46 return 3; 47 } 48 49 // decoderune decodes the rune encoding at sbuf into r 50 // and returns the number of bytes used. 51 static int 52 decoderune(Rune *r, char *sbuf) 53 { 54 uchar *buf; 55 56 buf = (uchar*)sbuf; 57 if(buf[0] < 0x80) { 58 *r = buf[0]; 59 return 1; 60 } 61 if((buf[0]&0xe0) == 0xc0 && (buf[1]&0xc0) == 0x80) { 62 *r = (buf[0]&~0xc0)<<6 | (buf[1]&~0x80); 63 if(*r < 0x80) 64 goto err; 65 return 2; 66 } 67 if((buf[0]&0xf0) == 0xe0 && (buf[1]&0xc0) == 0x80 && (buf[2]&0xc0) == 0x80) { 68 *r = (buf[0]&~0xc0)<<12 | (buf[1]&~0x80)<<6 | (buf[2]&~0x80); 69 if(*r < 0x800) 70 goto err; 71 return 3; 72 } 73 err: 74 *r = 0xfffd; 75 return 1; 76 } 77 78 // toutf replaces b with the UTF-8 encoding of the rune string r. 79 static void 80 toutf(Buf *b, Rune *r) 81 { 82 int i, n; 83 char buf[4]; 84 85 breset(b); 86 for(i=0; r[i]; i++) { 87 n = encoderune(buf, r[i]); 88 bwrite(b, buf, n); 89 } 90 } 91 92 // torune replaces *rp with a pointer to a newly allocated 93 // rune string equivalent of the UTF-8 string p. 94 static void 95 torune(Rune **rp, char *p) 96 { 97 Rune *r, *w; 98 99 r = xmalloc((strlen(p)+1) * sizeof r[0]); 100 w = r; 101 while(*p) 102 p += decoderune(w++, p); 103 *w = 0; 104 *rp = r; 105 } 106 107 // errstr returns the most recent Windows error, in string form. 108 static char* 109 errstr(void) 110 { 111 DWORD code; 112 Rune *r; 113 Buf b; 114 115 binit(&b); 116 code = GetLastError(); 117 r = nil; 118 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, 119 nil, code, 0, (Rune*)&r, 0, nil); 120 toutf(&b, r); 121 return bstr(&b); // leak but we're dying anyway 122 } 123 124 void 125 xgetenv(Buf *b, char *name) 126 { 127 Rune *buf; 128 int n; 129 Rune *r; 130 131 breset(b); 132 torune(&r, name); 133 n = GetEnvironmentVariableW(r, NULL, 0); 134 if(n > 0) { 135 buf = xmalloc((n+1)*sizeof buf[0]); 136 GetEnvironmentVariableW(r, buf, n+1); 137 buf[n] = '\0'; 138 toutf(b, buf); 139 xfree(buf); 140 } 141 xfree(r); 142 } 143 144 void 145 xsetenv(char *name, char *value) 146 { 147 Rune *rname, *rvalue; 148 149 torune(&rname, name); 150 torune(&rvalue, value); 151 SetEnvironmentVariableW(rname, rvalue); 152 xfree(rname); 153 xfree(rvalue); 154 } 155 156 char* 157 bprintf(Buf *b, char *fmt, ...) 158 { 159 va_list arg; 160 char buf[4096]; 161 162 breset(b); 163 va_start(arg, fmt); 164 vsnprintf(buf, sizeof buf, fmt, arg); 165 va_end(arg); 166 bwritestr(b, buf); 167 return bstr(b); 168 } 169 170 void 171 bwritef(Buf *b, char *fmt, ...) 172 { 173 va_list arg; 174 char buf[4096]; 175 176 // no reset 177 va_start(arg, fmt); 178 vsnprintf(buf, sizeof buf, fmt, arg); 179 va_end(arg); 180 bwritestr(b, buf); 181 } 182 183 // bpathf is like bprintf but replaces / with \ in the result, 184 // to make it a canonical windows file path. 185 char* 186 bpathf(Buf *b, char *fmt, ...) 187 { 188 int i; 189 va_list arg; 190 char buf[4096]; 191 192 breset(b); 193 va_start(arg, fmt); 194 vsnprintf(buf, sizeof buf, fmt, arg); 195 va_end(arg); 196 bwritestr(b, buf); 197 198 for(i=0; i<b->len; i++) 199 if(b->p[i] == '/') 200 b->p[i] = '\\'; 201 202 return bstr(b); 203 } 204 205 206 static void 207 breadfrom(Buf *b, HANDLE h) 208 { 209 DWORD n; 210 211 for(;;) { 212 if(b->len > 1<<22) 213 fatal("unlikely file size in readfrom"); 214 bgrow(b, 4096); 215 n = 0; 216 if(!ReadFile(h, b->p+b->len, 4096, &n, nil)) { 217 // Happens for pipe reads. 218 break; 219 } 220 if(n == 0) 221 break; 222 b->len += n; 223 } 224 } 225 226 void 227 run(Buf *b, char *dir, int mode, char *cmd, ...) 228 { 229 va_list arg; 230 Vec argv; 231 char *p; 232 233 vinit(&argv); 234 vadd(&argv, cmd); 235 va_start(arg, cmd); 236 while((p = va_arg(arg, char*)) != nil) 237 vadd(&argv, p); 238 va_end(arg); 239 240 runv(b, dir, mode, &argv); 241 242 vfree(&argv); 243 } 244 245 static void genrun(Buf*, char*, int, Vec*, int); 246 247 void 248 runv(Buf *b, char *dir, int mode, Vec *argv) 249 { 250 genrun(b, dir, mode, argv, 1); 251 } 252 253 void 254 bgrunv(char *dir, int mode, Vec *argv) 255 { 256 genrun(nil, dir, mode, argv, 0); 257 } 258 259 #define MAXBG 4 /* maximum number of jobs to run at once */ 260 261 static struct { 262 PROCESS_INFORMATION pi; 263 int mode; 264 char *cmd; 265 } bg[MAXBG]; 266 267 static int nbg; 268 269 static void bgwait1(void); 270 271 static void 272 genrun(Buf *b, char *dir, int mode, Vec *argv, int wait) 273 { 274 // Another copy of this logic is in ../../lib9/run_windows.c. 275 // If there's a bug here, fix the logic there too. 276 int i, j, nslash; 277 Buf cmd; 278 char *q; 279 Rune *rcmd, *rexe, *rdir; 280 STARTUPINFOW si; 281 PROCESS_INFORMATION pi; 282 HANDLE p[2]; 283 284 while(nbg >= nelem(bg)) 285 bgwait1(); 286 287 binit(&cmd); 288 289 for(i=0; i<argv->len; i++) { 290 q = argv->p[i]; 291 if(i == 0 && streq(q, "hg")) 292 bwritestr(&cmd, "cmd.exe /c "); 293 if(i > 0) 294 bwritestr(&cmd, " "); 295 if(contains(q, " ") || contains(q, "\t") || contains(q, "\"") || contains(q, "\\\\") || hassuffix(q, "\\")) { 296 bwritestr(&cmd, "\""); 297 nslash = 0; 298 for(; *q; q++) { 299 if(*q == '\\') { 300 nslash++; 301 continue; 302 } 303 if(*q == '"') { 304 for(j=0; j<2*nslash+1; j++) 305 bwritestr(&cmd, "\\"); 306 nslash = 0; 307 } 308 for(j=0; j<nslash; j++) 309 bwritestr(&cmd, "\\"); 310 nslash = 0; 311 bwrite(&cmd, q, 1); 312 } 313 for(j=0; j<2*nslash; j++) 314 bwritestr(&cmd, "\\"); 315 bwritestr(&cmd, "\""); 316 } else { 317 bwritestr(&cmd, q); 318 } 319 } 320 if(vflag > 1) 321 errprintf("%s\n", bstr(&cmd)); 322 323 torune(&rcmd, bstr(&cmd)); 324 rexe = nil; 325 rdir = nil; 326 if(dir != nil) 327 torune(&rdir, dir); 328 329 memset(&si, 0, sizeof si); 330 si.cb = sizeof si; 331 si.dwFlags = STARTF_USESTDHANDLES; 332 si.hStdInput = INVALID_HANDLE_VALUE; 333 if(b == nil) { 334 si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); 335 si.hStdError = GetStdHandle(STD_ERROR_HANDLE); 336 } else { 337 SECURITY_ATTRIBUTES seci; 338 339 memset(&seci, 0, sizeof seci); 340 seci.nLength = sizeof seci; 341 seci.bInheritHandle = 1; 342 breset(b); 343 if(!CreatePipe(&p[0], &p[1], &seci, 0)) 344 fatal("CreatePipe: %s", errstr()); 345 si.hStdOutput = p[1]; 346 si.hStdError = p[1]; 347 } 348 349 if(!CreateProcessW(rexe, rcmd, nil, nil, TRUE, 0, nil, rdir, &si, &pi)) { 350 if(mode!=CheckExit) 351 return; 352 fatal("%s: %s", argv->p[0], errstr()); 353 } 354 if(rexe != nil) 355 xfree(rexe); 356 xfree(rcmd); 357 if(rdir != nil) 358 xfree(rdir); 359 if(b != nil) { 360 CloseHandle(p[1]); 361 breadfrom(b, p[0]); 362 CloseHandle(p[0]); 363 } 364 365 if(nbg < 0) 366 fatal("bad bookkeeping"); 367 bg[nbg].pi = pi; 368 bg[nbg].mode = mode; 369 bg[nbg].cmd = btake(&cmd); 370 nbg++; 371 372 if(wait) 373 bgwait(); 374 375 bfree(&cmd); 376 } 377 378 // closes the background job for bgwait1 379 static void 380 bgwaitclose(int i) 381 { 382 if(i < 0 || i >= nbg) 383 return; 384 385 CloseHandle(bg[i].pi.hProcess); 386 CloseHandle(bg[i].pi.hThread); 387 388 bg[i] = bg[--nbg]; 389 } 390 391 // bgwait1 waits for a single background job 392 static void 393 bgwait1(void) 394 { 395 int i, mode; 396 char *cmd; 397 HANDLE bgh[MAXBG]; 398 DWORD code; 399 400 if(nbg == 0) 401 fatal("bgwait1: nothing left"); 402 403 for(i=0; i<nbg; i++) 404 bgh[i] = bg[i].pi.hProcess; 405 i = WaitForMultipleObjects(nbg, bgh, FALSE, INFINITE); 406 if(i < 0 || i >= nbg) 407 fatal("WaitForMultipleObjects: %s", errstr()); 408 409 cmd = bg[i].cmd; 410 mode = bg[i].mode; 411 if(!GetExitCodeProcess(bg[i].pi.hProcess, &code)) { 412 bgwaitclose(i); 413 fatal("GetExitCodeProcess: %s", errstr()); 414 return; 415 } 416 417 if(mode==CheckExit && code != 0) { 418 bgwaitclose(i); 419 fatal("FAILED: %s", cmd); 420 return; 421 } 422 423 bgwaitclose(i); 424 } 425 426 void 427 bgwait(void) 428 { 429 while(nbg > 0) 430 bgwait1(); 431 } 432 433 // rgetwd returns a rune string form of the current directory's path. 434 static Rune* 435 rgetwd(void) 436 { 437 int n; 438 Rune *r; 439 440 n = GetCurrentDirectoryW(0, nil); 441 r = xmalloc((n+1)*sizeof r[0]); 442 GetCurrentDirectoryW(n+1, r); 443 r[n] = '\0'; 444 return r; 445 } 446 447 void 448 xgetwd(Buf *b) 449 { 450 Rune *r; 451 452 r = rgetwd(); 453 breset(b); 454 toutf(b, r); 455 xfree(r); 456 } 457 458 void 459 xrealwd(Buf *b, char *path) 460 { 461 Rune *old; 462 Rune *rnew; 463 464 old = rgetwd(); 465 torune(&rnew, path); 466 if(!SetCurrentDirectoryW(rnew)) 467 fatal("chdir %s: %s", path, errstr()); 468 xfree(rnew); 469 xgetwd(b); 470 if(!SetCurrentDirectoryW(old)) { 471 breset(b); 472 toutf(b, old); 473 fatal("chdir %s: %s", bstr(b), errstr()); 474 } 475 } 476 477 bool 478 isdir(char *p) 479 { 480 DWORD attr; 481 Rune *r; 482 483 torune(&r, p); 484 attr = GetFileAttributesW(r); 485 xfree(r); 486 return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY); 487 } 488 489 bool 490 isfile(char *p) 491 { 492 DWORD attr; 493 Rune *r; 494 495 torune(&r, p); 496 attr = GetFileAttributesW(r); 497 xfree(r); 498 return attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY); 499 } 500 501 Time 502 mtime(char *p) 503 { 504 HANDLE h; 505 WIN32_FIND_DATAW data; 506 Rune *r; 507 FILETIME *ft; 508 509 torune(&r, p); 510 h = FindFirstFileW(r, &data); 511 xfree(r); 512 if(h == INVALID_HANDLE_VALUE) 513 return 0; 514 FindClose(h); 515 ft = &data.ftLastWriteTime; 516 return (Time)ft->dwLowDateTime + ((Time)ft->dwHighDateTime<<32); 517 } 518 519 bool 520 isabs(char *p) 521 { 522 // c:/ or c:\ at beginning 523 if(('A' <= p[0] && p[0] <= 'Z') || ('a' <= p[0] && p[0] <= 'z')) 524 return p[1] == ':' && (p[2] == '/' || p[2] == '\\'); 525 // / or \ at beginning 526 return p[0] == '/' || p[0] == '\\'; 527 } 528 529 void 530 readfile(Buf *b, char *file) 531 { 532 HANDLE h; 533 Rune *r; 534 535 breset(b); 536 if(vflag > 2) 537 errprintf("read %s\n", file); 538 torune(&r, file); 539 h = CreateFileW(r, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); 540 if(h == INVALID_HANDLE_VALUE) 541 fatal("open %s: %s", file, errstr()); 542 breadfrom(b, h); 543 CloseHandle(h); 544 } 545 546 void 547 writefile(Buf *b, char *file, int exec) 548 { 549 HANDLE h; 550 Rune *r; 551 DWORD n; 552 553 USED(exec); 554 555 if(vflag > 2) 556 errprintf("write %s\n", file); 557 torune(&r, file); 558 h = CreateFileW(r, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, nil, CREATE_ALWAYS, 0, 0); 559 if(h == INVALID_HANDLE_VALUE) 560 fatal("create %s: %s", file, errstr()); 561 n = 0; 562 if(!WriteFile(h, b->p, b->len, &n, 0)) 563 fatal("write %s: %s", file, errstr()); 564 CloseHandle(h); 565 } 566 567 568 void 569 xmkdir(char *p) 570 { 571 Rune *r; 572 573 torune(&r, p); 574 if(!CreateDirectoryW(r, nil)) 575 fatal("mkdir %s: %s", p, errstr()); 576 xfree(r); 577 } 578 579 void 580 xmkdirall(char *p) 581 { 582 int c; 583 char *q, *q2; 584 585 if(isdir(p)) 586 return; 587 q = strrchr(p, '/'); 588 q2 = strrchr(p, '\\'); 589 if(q2 != nil && (q == nil || q < q2)) 590 q = q2; 591 if(q != nil) { 592 c = *q; 593 *q = '\0'; 594 xmkdirall(p); 595 *q = c; 596 } 597 xmkdir(p); 598 } 599 600 void 601 xremove(char *p) 602 { 603 int attr; 604 Rune *r; 605 606 torune(&r, p); 607 attr = GetFileAttributesW(r); 608 if(attr >= 0) { 609 if(attr & FILE_ATTRIBUTE_DIRECTORY) 610 RemoveDirectoryW(r); 611 else 612 DeleteFileW(r); 613 } 614 xfree(r); 615 } 616 617 void 618 xreaddir(Vec *dst, char *dir) 619 { 620 Rune *r; 621 Buf b; 622 HANDLE h; 623 WIN32_FIND_DATAW data; 624 char *p, *q; 625 626 binit(&b); 627 vreset(dst); 628 629 bwritestr(&b, dir); 630 bwritestr(&b, "\\*"); 631 torune(&r, bstr(&b)); 632 633 h = FindFirstFileW(r, &data); 634 xfree(r); 635 if(h == INVALID_HANDLE_VALUE) 636 goto out; 637 do{ 638 toutf(&b, data.cFileName); 639 p = bstr(&b); 640 q = xstrrchr(p, '\\'); 641 if(q != nil) 642 p = q+1; 643 if(!streq(p, ".") && !streq(p, "..")) 644 vadd(dst, p); 645 }while(FindNextFileW(h, &data)); 646 FindClose(h); 647 648 out: 649 bfree(&b); 650 } 651 652 char* 653 xworkdir(void) 654 { 655 Rune buf[1024]; 656 Rune tmp[MAX_PATH]; 657 Rune go[3] = {'g', 'o', '\0'}; 658 int n; 659 Buf b; 660 661 n = GetTempPathW(nelem(buf), buf); 662 if(n <= 0) 663 fatal("GetTempPath: %s", errstr()); 664 buf[n] = '\0'; 665 666 if(GetTempFileNameW(buf, go, 0, tmp) == 0) 667 fatal("GetTempFileName: %s", errstr()); 668 DeleteFileW(tmp); 669 if(!CreateDirectoryW(tmp, nil)) 670 fatal("create tempdir: %s", errstr()); 671 672 binit(&b); 673 toutf(&b, tmp); 674 return btake(&b); 675 } 676 677 void 678 xremoveall(char *p) 679 { 680 int i; 681 Buf b; 682 Vec dir; 683 Rune *r; 684 685 binit(&b); 686 vinit(&dir); 687 688 torune(&r, p); 689 if(isdir(p)) { 690 xreaddir(&dir, p); 691 for(i=0; i<dir.len; i++) { 692 bprintf(&b, "%s/%s", p, dir.p[i]); 693 xremoveall(bstr(&b)); 694 } 695 RemoveDirectoryW(r); 696 } else { 697 DeleteFileW(r); 698 } 699 xfree(r); 700 701 bfree(&b); 702 vfree(&dir); 703 } 704 705 void 706 fatal(char *msg, ...) 707 { 708 static char buf1[1024]; 709 va_list arg; 710 711 va_start(arg, msg); 712 vsnprintf(buf1, sizeof buf1, msg, arg); 713 va_end(arg); 714 715 errprintf("go tool dist: %s\n", buf1); 716 717 bgwait(); 718 ExitProcess(1); 719 } 720 721 // HEAP is the persistent handle to the default process heap. 722 static HANDLE HEAP = INVALID_HANDLE_VALUE; 723 724 void* 725 xmalloc(int n) 726 { 727 void *p; 728 729 if(HEAP == INVALID_HANDLE_VALUE) 730 HEAP = GetProcessHeap(); 731 p = HeapAlloc(HEAP, 0, n); 732 if(p == nil) 733 fatal("out of memory allocating %d: %s", n, errstr()); 734 memset(p, 0, n); 735 return p; 736 } 737 738 char* 739 xstrdup(char *p) 740 { 741 char *q; 742 743 q = xmalloc(strlen(p)+1); 744 strcpy(q, p); 745 return q; 746 } 747 748 void 749 xfree(void *p) 750 { 751 if(HEAP == INVALID_HANDLE_VALUE) 752 HEAP = GetProcessHeap(); 753 HeapFree(HEAP, 0, p); 754 } 755 756 void* 757 xrealloc(void *p, int n) 758 { 759 if(p == nil) 760 return xmalloc(n); 761 if(HEAP == INVALID_HANDLE_VALUE) 762 HEAP = GetProcessHeap(); 763 p = HeapReAlloc(HEAP, 0, p, n); 764 if(p == nil) 765 fatal("out of memory reallocating %d", n); 766 return p; 767 } 768 769 bool 770 hassuffix(char *p, char *suffix) 771 { 772 int np, ns; 773 774 np = strlen(p); 775 ns = strlen(suffix); 776 return np >= ns && streq(p+np-ns, suffix); 777 } 778 779 bool 780 hasprefix(char *p, char *prefix) 781 { 782 return strncmp(p, prefix, strlen(prefix)) == 0; 783 } 784 785 bool 786 contains(char *p, char *sep) 787 { 788 return strstr(p, sep) != nil; 789 } 790 791 bool 792 streq(char *p, char *q) 793 { 794 return strcmp(p, q) == 0; 795 } 796 797 char* 798 lastelem(char *p) 799 { 800 char *out; 801 802 out = p; 803 for(; *p; p++) 804 if(*p == '/' || *p == '\\') 805 out = p+1; 806 return out; 807 } 808 809 void 810 xmemmove(void *dst, void *src, int n) 811 { 812 memmove(dst, src, n); 813 } 814 815 int 816 xmemcmp(void *a, void *b, int n) 817 { 818 return memcmp(a, b, n); 819 } 820 821 int 822 xstrlen(char *p) 823 { 824 return strlen(p); 825 } 826 827 void 828 xexit(int n) 829 { 830 ExitProcess(n); 831 } 832 833 void 834 xatexit(void (*f)(void)) 835 { 836 atexit(f); 837 } 838 839 void 840 xprintf(char *fmt, ...) 841 { 842 va_list arg; 843 844 va_start(arg, fmt); 845 vprintf(fmt, arg); 846 va_end(arg); 847 } 848 849 void 850 errprintf(char *fmt, ...) 851 { 852 va_list arg; 853 854 va_start(arg, fmt); 855 vfprintf(stderr, fmt, arg); 856 va_end(arg); 857 } 858 859 int 860 main(int argc, char **argv) 861 { 862 SYSTEM_INFO si; 863 864 setvbuf(stdout, nil, _IOLBF, 0); 865 setvbuf(stderr, nil, _IOLBF, 0); 866 867 slash = "\\"; 868 gohostos = "windows"; 869 870 GetSystemInfo(&si); 871 switch(si.wProcessorArchitecture) { 872 case PROCESSOR_ARCHITECTURE_AMD64: 873 gohostarch = "amd64"; 874 break; 875 case PROCESSOR_ARCHITECTURE_INTEL: 876 gohostarch = "386"; 877 break; 878 default: 879 fatal("unknown processor architecture"); 880 } 881 882 init(); 883 884 xmain(argc, argv); 885 return 0; 886 } 887 888 void 889 xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*)) 890 { 891 qsort(data, n, elemsize, cmp); 892 } 893 894 int 895 xstrcmp(char *a, char *b) 896 { 897 return strcmp(a, b); 898 } 899 900 char* 901 xstrstr(char *a, char *b) 902 { 903 return strstr(a, b); 904 } 905 906 char* 907 xstrrchr(char *p, int c) 908 { 909 char *ep; 910 911 ep = p+strlen(p); 912 for(ep=p+strlen(p); ep >= p; ep--) 913 if(*ep == c) 914 return ep; 915 return nil; 916 } 917 918 // xsamefile reports whether f1 and f2 are the same file (or dir) 919 int 920 xsamefile(char *f1, char *f2) 921 { 922 Rune *ru; 923 HANDLE fd1, fd2; 924 BY_HANDLE_FILE_INFORMATION fi1, fi2; 925 int r; 926 927 // trivial case 928 if(streq(f1, f2)) 929 return 1; 930 931 torune(&ru, f1); 932 // refer to ../../os/stat_windows.go:/sameFile 933 fd1 = CreateFileW(ru, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); 934 xfree(ru); 935 if(fd1 == INVALID_HANDLE_VALUE) 936 return 0; 937 torune(&ru, f2); 938 fd2 = CreateFileW(ru, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); 939 xfree(ru); 940 if(fd2 == INVALID_HANDLE_VALUE) { 941 CloseHandle(fd1); 942 return 0; 943 } 944 r = GetFileInformationByHandle(fd1, &fi1) != 0 && GetFileInformationByHandle(fd2, &fi2) != 0; 945 CloseHandle(fd2); 946 CloseHandle(fd1); 947 if(r != 0 && 948 fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber && 949 fi1.nFileIndexHigh == fi2.nFileIndexHigh && 950 fi1.nFileIndexLow == fi2.nFileIndexLow) 951 return 1; 952 return 0; 953 } 954 955 // xtryexecfunc tries to execute function f, if any illegal instruction 956 // signal received in the course of executing that function, it will 957 // return 0, otherwise it will return 1. 958 int 959 xtryexecfunc(void (*f)(void)) 960 { 961 return 0; // suffice for now 962 } 963 964 static void 965 cpuid(int dst[4], int ax) 966 { 967 // NOTE: This asm statement is for mingw. 968 // If we ever support MSVC, use __cpuid(dst, ax) 969 // to use the built-in. 970 #if defined(__i386__) || defined(__x86_64__) 971 asm volatile("cpuid" 972 : "=a" (dst[0]), "=b" (dst[1]), "=c" (dst[2]), "=d" (dst[3]) 973 : "0" (ax)); 974 #else 975 dst[0] = dst[1] = dst[2] = dst[3] = 0; 976 #endif 977 } 978 979 bool 980 cansse2(void) 981 { 982 int info[4]; 983 984 cpuid(info, 1); 985 return (info[3] & (1<<26)) != 0; // SSE2 986 } 987 988 989 #endif // __WINDOWS__