1 /* 2 * compat.cpp 3 * swift 4 * 5 * Created by Arno Bakker, Victor Grishchenko 6 * Copyright 2009-2016 TECHNISCHE UNIVERSITEIT DELFT. All rights reserved. 7 * 8 */ 9 10 #include "compat.h" 11 #include "swift.h" 12 #include <sys/stat.h> 13 #include <stdio.h> 14 #include <assert.h> 15 #ifdef _WIN32 16 #include <tchar.h> 17 #include <io.h> 18 #include <sys/timeb.h> 19 #include <vector> 20 #include <stdexcept> 21 #include <atlbase.h> 22 #else 23 #include <unistd.h> 24 #include <sys/time.h> 25 #endif 26 #include <iostream> 27 #include <sstream> 28 29 #ifdef DEBUG 30 # ifdef _WIN32 31 # include <windows.h> 32 # include <Dbghelp.h> 33 # endif // _WIN32 34 #endif // DEBUG 35 36 37 namespace swift 38 { 39 40 #ifdef _WIN32 41 static HANDLE map_handles[1024]; 42 43 // Arno, 2013-10-16: For improved usec_time() 44 LARGE_INTEGER epochcounter; 45 #endif 46 print_backtrace(void)47 void print_backtrace(void) 48 { 49 #ifdef DEBUG 50 # ifdef _WIN32 51 unsigned int i; 52 void * stack[100]; 53 unsigned short frames; 54 SYMBOL_INFO * symbol; 55 HANDLE process; 56 57 process = GetCurrentProcess(); 58 59 SymInitialize( process, NULL, TRUE ); 60 61 frames = CaptureStackBackTrace(0, 100, stack, NULL); 62 symbol = (SYMBOL_INFO *)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1); 63 symbol->MaxNameLen = 255; 64 symbol->SizeOfStruct = sizeof(SYMBOL_INFO); 65 66 for (i = 0; i < frames; i++) { 67 SymFromAddr(process, (DWORD64)(stack[ i ]), 0, symbol); 68 fprintf(stderr, "%i: %s - 0x%0X\n", frames - i - 1, symbol->Name, symbol->Address); 69 } 70 fflush(stderr); 71 72 free(symbol); 73 # endif // _WIN32 74 #endif // DEBUG 75 } 76 file_size(int fd)77 int64_t file_size(int fd) 78 { 79 80 #ifdef WIN32 81 struct _stat32i64 st; 82 _fstat32i64(fd, &st); 83 #else 84 struct stat st; 85 st.st_size = 0; 86 fstat(fd, &st); 87 #endif 88 return st.st_size; 89 } 90 file_seek(int fd,int64_t offset)91 int file_seek(int fd, int64_t offset) 92 { 93 #ifndef _WIN32 94 return lseek(fd,offset,SEEK_SET); 95 #else 96 return _lseeki64(fd,offset,SEEK_SET); 97 #endif 98 } 99 file_resize(int fd,int64_t new_size)100 int file_resize(int fd, int64_t new_size) 101 { 102 #ifndef _WIN32 103 return ftruncate(fd, new_size); 104 #else 105 // Arno, 2011-10-27: Use 64-bit version 106 if (_chsize_s(fd,new_size) != 0) 107 return -1; 108 else 109 return 0; 110 #endif 111 } 112 113 print_error(const char * msg)114 void print_error(const char* msg) 115 { 116 perror(msg); 117 #ifdef _WIN32 118 int e = WSAGetLastError(); 119 if (e) 120 fprintf(stderr,"windows error #%" PRIu32 "\n",e); 121 #endif 122 #ifdef DEBUG 123 print_backtrace(); 124 #endif 125 } 126 memory_map(int fd,size_t size)127 void* memory_map(int fd, size_t size) 128 { 129 if (!size) 130 size = file_size(fd); 131 void *mapping; 132 #ifndef _WIN32 133 mapping = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 134 if (mapping==MAP_FAILED) 135 return NULL; 136 return mapping; 137 #else 138 HANDLE fhandle = (HANDLE)_get_osfhandle(fd); 139 HANDLE maphandle = CreateFileMapping(fhandle, 140 NULL, 141 PAGE_READWRITE, 142 0, 143 0, 144 NULL); 145 if (maphandle == NULL) 146 return NULL; 147 map_handles[fd] = maphandle; 148 149 mapping = MapViewOfFile(maphandle, 150 FILE_MAP_WRITE, 151 0, 152 0, 153 0); 154 155 return mapping; 156 #endif 157 } 158 memory_unmap(int fd,void * mapping,size_t size)159 void memory_unmap(int fd, void* mapping, size_t size) 160 { 161 #ifndef _WIN32 162 munmap(mapping,size); 163 close(fd); 164 #else 165 UnmapViewOfFile(mapping); 166 CloseHandle(map_handles[fd]); 167 #endif 168 } 169 170 #ifdef _WIN32 171 pread(int fildes,void * buf,size_t nbyte,__int64 offset)172 size_t pread(int fildes, void *buf, size_t nbyte, __int64 offset) 173 { 174 int64_t ret = _lseeki64(fildes,offset,SEEK_SET); 175 if (ret == -1L) 176 return -1; 177 else 178 return read(fildes,buf,nbyte); 179 } 180 pwrite(int fildes,const void * buf,size_t nbyte,__int64 offset)181 size_t pwrite(int fildes, const void *buf, size_t nbyte, __int64 offset) 182 { 183 int64_t ret = _lseeki64(fildes,offset,SEEK_SET); 184 if (ret == -1L) 185 return -1; 186 else 187 return write(fildes,buf,nbyte); 188 } 189 190 inet_aton(const char * cp,struct in_addr * inp)191 int inet_aton(const char *cp, struct in_addr *inp) 192 { 193 inp->S_un.S_addr = inet_addr(cp); 194 return 1; 195 } 196 197 #endif 198 199 #ifdef _WIN32 200 get_freq()201 static LARGE_INTEGER get_freq() 202 { 203 LARGE_INTEGER proc_freq; 204 if (!::QueryPerformanceFrequency(&proc_freq)) 205 print_error("HiResTimeOfDay: QueryPerformanceFrequency() failed"); 206 return proc_freq; 207 } 208 get_ftime()209 static tint get_ftime() 210 { 211 struct timeb t; 212 ftime(&t); 213 tint usec; 214 usec = t.time * 1000000; 215 usec += t.millitm * 1000; 216 return usec; 217 } 218 usec_time(void)219 tint usec_time(void) 220 { 221 static LARGE_INTEGER last_time; 222 LARGE_INTEGER cur_time; 223 QueryPerformanceCounter(&cur_time); 224 if (cur_time.QuadPart<last_time.QuadPart) 225 print_error("QueryPerformanceCounter wrapped"); // does this happen? 226 last_time = cur_time; 227 static float freq = 1000000.0/get_freq().QuadPart; 228 // Arno, 2013-10-16: As these are now used for signature timestamps 229 // it can no longer be a local clock. 230 tint usec = get_ftime(); 231 usec += (cur_time.QuadPart - swift::epochcounter.QuadPart) * freq; 232 233 return usec; 234 } 235 236 237 #else 238 usec_time(void)239 tint usec_time(void) 240 { 241 struct timeval t; 242 gettimeofday(&t,NULL); 243 tint ret; 244 ret = t.tv_sec; 245 ret *= TINT_SEC; 246 ret += t.tv_usec; 247 return ret; 248 } 249 250 #endif 251 LibraryInit(void)252 void LibraryInit(void) 253 { 254 #ifdef _WIN32 255 static WSADATA _WSAData; 256 // win32 requires you to initialize the Winsock DLL with the desired 257 // specification version 258 WORD wVersionRequested; 259 wVersionRequested = MAKEWORD(2, 2); 260 WSAStartup(wVersionRequested, &_WSAData); 261 262 // Arno, 2013-10-16: As usec_time() is now used for signature timestamps 263 // it can no longer be a local clock on Win32. 264 DWORD_PTR oldmask = ::SetThreadAffinityMask(::GetCurrentThread(), 0); 265 if (!::QueryPerformanceCounter(&swift::epochcounter)) 266 std::cerr << "LibraryInit: QueryPerformanceCounter() failed"; 267 ::SetThreadAffinityMask(::GetCurrentThread(), oldmask); 268 269 // Arno, 2013-10-16: Why o why 270 Channel::epoch = Channel::Time()/360000000LL*360000000LL; 271 272 #endif 273 } 274 275 276 /* 277 * UNICODE 278 */ 279 280 utf8to16(std::string utf8str)281 wchar_t* utf8to16(std::string utf8str) 282 { 283 #ifdef _WIN32 284 CA2W utf16obj(utf8str.c_str(), CP_UTF8); 285 286 size_t utf16bytelen = (wcslen(utf16obj.m_psz)+1) * sizeof(wchar_t); 287 wchar_t *utf16str = (wchar_t *)malloc(utf16bytelen); 288 wcscpy(utf16str,utf16obj.m_psz); 289 290 //std::wcerr << "utf8to16: return <" << utf16str << ">" << std::endl; 291 292 return utf16str; 293 #else 294 return NULL; 295 #endif 296 } 297 utf16to8(wchar_t * utf16str)298 std::string utf16to8(wchar_t* utf16str) 299 { 300 #ifdef _WIN32 301 //std::wcerr << "utf16to8: in " << utf16str << std::endl; 302 CW2A utf8obj(utf16str, CP_UTF8); 303 return std::string(utf8obj.m_psz); 304 #else 305 return "(nul)"; 306 #endif 307 } 308 309 310 open_utf8(const char * filename,int flags,mode_t mode)311 int open_utf8(const char *filename, int flags, mode_t mode) 312 { 313 #ifdef _WIN32 314 wchar_t *utf16fn = utf8to16(filename); 315 int ret = _wopen(utf16fn,flags,mode); 316 free(utf16fn); 317 return ret; 318 #else 319 return open(filename,flags,mode); // TODO: UNIX with locale != UTF-8 320 #endif 321 } 322 323 fopen_utf8(const char * filename,const char * mode)324 FILE *fopen_utf8(const char *filename, const char *mode) 325 { 326 #ifdef _WIN32 327 wchar_t *utf16fn = utf8to16(filename); 328 wchar_t *utf16mode = utf8to16(mode); 329 FILE *fp = _wfopen(utf16fn,utf16mode); 330 free(utf16fn); 331 free(utf16mode); 332 return fp; 333 #else 334 return fopen(filename,mode); // TODO: UNIX with locale != UTF-8 335 #endif 336 } 337 338 339 340 file_size_by_path_utf8(std::string pathname)341 int64_t file_size_by_path_utf8(std::string pathname) 342 { 343 int ret = 0; 344 #ifdef WIN32 345 struct __stat64 st; 346 wchar_t *utf16c = utf8to16(pathname); 347 ret = _wstat64(utf16c, &st); 348 free(utf16c); 349 #else 350 struct stat st; 351 ret = stat(pathname.c_str(), &st); // TODO: UNIX with locale != UTF-8 352 #endif 353 if (ret < 0) 354 return ret; 355 else 356 return st.st_size; 357 } 358 file_exists_utf8(std::string pathname)359 int file_exists_utf8(std::string pathname) 360 { 361 int ret = 0; 362 #ifdef WIN32 363 struct __stat64 st; 364 wchar_t *utf16c = utf8to16(pathname); 365 ret = _wstat64(utf16c, &st); 366 free(utf16c); 367 #else 368 struct stat st; 369 ret = stat(pathname.c_str(), &st); // TODO: UNIX with locale != UTF-8 370 #endif 371 if (ret < 0) { 372 if (errno == ENOENT) 373 return 0; 374 else 375 return ret; 376 } else if (st.st_mode & S_IFDIR) 377 return 2; 378 else 379 return 1; 380 } 381 382 mkdir_utf8(std::string dirname)383 int mkdir_utf8(std::string dirname) 384 { 385 #ifdef WIN32 386 wchar_t *utf16c = utf8to16(dirname); 387 int ret = _wmkdir(utf16c); 388 free(utf16c); 389 #else 390 int ret = mkdir(dirname.c_str(), 391 S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); // TODO: UNIX with locale != UTF-8 392 #endif 393 return ret; 394 } 395 396 remove_utf8(std::string pathname)397 int remove_utf8(std::string pathname) 398 { 399 #ifdef WIN32 400 wchar_t *utf16c = utf8to16(pathname); 401 int ret = _wremove(utf16c); 402 free(utf16c); 403 #else 404 int ret = remove(pathname.c_str()); // TODO: UNIX with locale != UTF-8 405 #endif 406 return ret; 407 } 408 409 410 #if _DIR_ENT_HAVE_D_TYPE 411 #define TEST_IS_DIR(unixde, st) ((bool)(unixde->d_type & DT_DIR)) 412 #else 413 #define TEST_IS_DIR(unixde, st) ((bool)(S_ISDIR(st.st_mode))) 414 #endif 415 opendir_utf8(std::string pathname)416 DirEntry *opendir_utf8(std::string pathname) 417 { 418 #ifdef _WIN32 419 HANDLE hFind; 420 WIN32_FIND_DATAW ffd; 421 422 std::string pathsearch = pathname + "\\*.*"; 423 wchar_t *pathsearch_utf16 = utf8to16(pathsearch); 424 hFind = FindFirstFileW(pathsearch_utf16, &ffd); 425 free(pathsearch_utf16); 426 if (hFind != INVALID_HANDLE_VALUE) { 427 std::string utf8fn = utf16to8(ffd.cFileName); 428 DirEntry *de = new DirEntry(utf8fn,(bool)((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)); 429 de->hFind_ = hFind; 430 return de; 431 } else 432 return NULL; 433 #else 434 DIR *dirp = opendir(pathname.c_str()); // TODO: UNIX with locale != UTF-8 435 if (dirp == NULL) 436 return NULL; 437 struct dirent *unixde = readdir(dirp); 438 if (unixde == NULL) 439 return NULL; 440 else { 441 #if _DIR_ENT_HAVE_D_TYPE 442 if (unixde->d_type == DT_UNKNOWN) { 443 #endif 444 std::string fullpath = pathname + FILE_SEP; 445 struct stat st; 446 st.st_mode = 0; 447 int ret = stat(fullpath.append(unixde->d_name).c_str(), &st); 448 if (ret < 0) { 449 print_error("failed to stat file in directory"); 450 return NULL; 451 } 452 #if _DIR_ENT_HAVE_D_TYPE 453 if (S_ISDIR(st.st_mode)) 454 unixde->d_type = DT_DIR; 455 } 456 #endif 457 DirEntry *de = new DirEntry(unixde->d_name,TEST_IS_DIR(unixde, st)); 458 de->dirp_ = dirp; 459 de->basename_ = pathname; 460 return de; 461 } 462 #endif 463 } 464 465 readdir_utf8(DirEntry * prevde)466 DirEntry *readdir_utf8(DirEntry *prevde) 467 { 468 #ifdef _WIN32 469 WIN32_FIND_DATAW ffd; 470 BOOL ret = FindNextFileW(prevde->hFind_, &ffd); 471 if (!ret) { 472 FindClose(prevde->hFind_); 473 return NULL; 474 } else { 475 std::string utf8fn = utf16to8(ffd.cFileName); 476 DirEntry *de = new DirEntry(utf8fn,(bool)((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)); 477 de->hFind_ = prevde->hFind_; 478 return de; 479 } 480 #else 481 struct dirent *unixde = readdir(prevde->dirp_); 482 if (unixde == NULL) { 483 closedir(prevde->dirp_); 484 return NULL; 485 } else { 486 #if _DIR_ENT_HAVE_D_TYPE 487 if (unixde->d_type == DT_UNKNOWN) { 488 #endif 489 std::string fullpath = prevde->basename_ + FILE_SEP; 490 struct stat st; 491 st.st_mode = 0; 492 int ret = stat(fullpath.append(unixde->d_name).c_str(), &st); 493 if (ret < 0) { 494 print_error("failed to stat file in directory"); 495 return NULL; 496 } 497 #if _DIR_ENT_HAVE_D_TYPE 498 if (S_ISDIR(st.st_mode)) 499 unixde->d_type = DT_DIR; 500 } 501 #endif 502 DirEntry *de = new DirEntry(unixde->d_name,TEST_IS_DIR(unixde, st)); 503 de->dirp_ = prevde->dirp_; 504 de->basename_ = prevde->basename_; 505 return de; 506 } 507 #endif 508 } 509 510 511 512 513 gettmpdir_utf8(void)514 std::string gettmpdir_utf8(void) 515 { 516 #ifdef _WIN32 517 DWORD ret = 0; 518 wchar_t utf16c[MAX_PATH]; 519 ret = GetTempPathW(MAX_PATH,utf16c); 520 if (ret == 0 || ret > MAX_PATH) { 521 return "./"; 522 } else { 523 return utf16to8(utf16c); 524 } 525 #else 526 return "/tmp/"; 527 #endif 528 } 529 chdir_utf8(std::string dirname)530 int chdir_utf8(std::string dirname) 531 { 532 #ifdef _WIN32 533 wchar_t *utf16c = utf8to16(dirname); 534 int ret = !::SetCurrentDirectoryW(utf16c); 535 free(utf16c); 536 return ret; 537 #else 538 return chdir(dirname.c_str()); // TODO: UNIX with locale != UTF-8 539 #endif 540 } 541 542 getcwd_utf8(void)543 std::string getcwd_utf8(void) 544 { 545 #ifdef _WIN32 546 wchar_t szDirectory[MAX_PATH]; 547 !::GetCurrentDirectoryW(sizeof(szDirectory) - 1, szDirectory); 548 return utf16to8(szDirectory); 549 #else 550 char *cwd = getcwd(NULL,0); 551 std::string cwdstr(cwd); 552 free(cwd); 553 return cwdstr; 554 #endif 555 } 556 557 dirname_utf8(std::string pathname)558 std::string dirname_utf8(std::string pathname) 559 { 560 int idx = pathname.rfind(FILE_SEP); 561 if (idx != std::string::npos) { 562 return pathname.substr(0,idx); 563 } else 564 return ""; 565 } 566 567 basename_utf8(std::string pathname)568 std::string basename_utf8(std::string pathname) 569 { 570 int idx = pathname.rfind(FILE_SEP); 571 if (idx != std::string::npos) { 572 return pathname.substr(idx); 573 } else 574 return pathname; 575 } 576 577 make_socket_nonblocking(evutil_socket_t fd)578 bool make_socket_nonblocking(evutil_socket_t fd) 579 { 580 #ifdef _WIN32 581 u_long enable = 1; 582 return 0==ioctlsocket(fd, FIONBIO, &enable); 583 #else 584 return 0==fcntl(fd, F_SETFL, O_NONBLOCK); 585 #endif 586 } 587 close_socket(evutil_socket_t sock)588 bool close_socket(evutil_socket_t sock) 589 { 590 #ifdef _WIN32 591 return 0==closesocket(sock); 592 #else 593 return 0==::close(sock); 594 #endif 595 } 596 597 598 // Arno: not thread safe! tint2tv(tint t)599 struct timeval* tint2tv(tint t) 600 { 601 static struct timeval tv; 602 tv.tv_usec = t%TINT_SEC; 603 tv.tv_sec = t/TINT_SEC; 604 return &tv; 605 } 606 tv2tint(struct timeval * tv)607 tint tv2tint(struct timeval* tv) 608 { 609 return ((int64_t)tv->tv_sec * 1000000 + tv->tv_usec) ; 610 } 611 612 hex2bin(std::string input)613 std::string hex2bin(std::string input) 614 { 615 std::string res; 616 res.reserve(input.size() / 2); 617 for (int i = 0; i < input.size(); i += 2) { 618 std::istringstream iss(input.substr(i, 2)); 619 int temp; 620 iss >> std::hex >> temp; 621 res += static_cast<char>(temp); 622 } 623 return res; 624 } 625 626 } //E-O-Swift 627