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