platform.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. /*
  2. * Copyright 2005 - 2016 Zarafa and its licensors
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3,
  6. * as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. */
  17. #include <kopano/platform.h>
  18. #include <cerrno>
  19. #include <cstdlib>
  20. #include <fcntl.h>
  21. #include <mapidefs.h>
  22. #include <mapicode.h>
  23. #include <climits>
  24. #include <pthread.h>
  25. #include <unistd.h>
  26. #include <sys/stat.h>
  27. #include <sys/time.h> /* gettimeofday */
  28. #include <kopano/ECLogger.h>
  29. #include "TmpPath.h"
  30. namespace KC {
  31. HRESULT UnixTimeToFileTime(time_t t, FILETIME *ft)
  32. {
  33. __int64 l;
  34. l = (__int64)t * 10000000 + NANOSECS_BETWEEN_EPOCHS;
  35. ft->dwLowDateTime = (unsigned int)l;
  36. ft->dwHighDateTime = (unsigned int)(l >> 32);
  37. return hrSuccess;
  38. }
  39. HRESULT FileTimeToUnixTime(const FILETIME &ft, time_t *t)
  40. {
  41. __int64 l;
  42. l = ((__int64)ft.dwHighDateTime << 32) + ft.dwLowDateTime;
  43. l -= NANOSECS_BETWEEN_EPOCHS;
  44. l /= 10000000;
  45. if(sizeof(time_t) < 8) {
  46. // On 32-bit systems, we cap the values at MAXINT and MININT
  47. if(l < (__int64)INT_MIN) {
  48. l = INT_MIN;
  49. }
  50. if(l > (__int64)INT_MAX) {
  51. l = INT_MAX;
  52. }
  53. }
  54. *t = (time_t)l;
  55. return hrSuccess;
  56. }
  57. void UnixTimeToFileTime(time_t t, int *hi, unsigned int *lo)
  58. {
  59. __int64 ll;
  60. ll = (__int64)t * 10000000 + NANOSECS_BETWEEN_EPOCHS;
  61. *lo = (unsigned int)ll;
  62. *hi = (unsigned int)(ll >> 32);
  63. }
  64. time_t FileTimeToUnixTime(unsigned int hi, unsigned int lo)
  65. {
  66. time_t t = 0;
  67. FILETIME ft;
  68. ft.dwHighDateTime = hi;
  69. ft.dwLowDateTime = lo;
  70. if(FileTimeToUnixTime(ft, &t) != hrSuccess)
  71. return 0;
  72. return t;
  73. }
  74. static const LONGLONG UnitsPerMinute = 600000000;
  75. static const LONGLONG UnitsPerHalfMinute = 300000000;
  76. void RTimeToFileTime(LONG rtime, FILETIME *pft)
  77. {
  78. // assert(pft != NULL);
  79. ULONGLONG q = rtime;
  80. q *= UnitsPerMinute;
  81. pft->dwLowDateTime = q & 0xFFFFFFFF;
  82. pft->dwHighDateTime = q >> 32;
  83. }
  84. void FileTimeToRTime(const FILETIME *pft, LONG *prtime)
  85. {
  86. // assert(pft != NULL);
  87. // assert(prtime != NULL);
  88. ULONGLONG q = pft->dwHighDateTime;
  89. q <<= 32;
  90. q |= pft->dwLowDateTime;
  91. q += UnitsPerHalfMinute;
  92. q /= UnitsPerMinute;
  93. *prtime = q & 0x7FFFFFFF;
  94. }
  95. HRESULT RTimeToUnixTime(LONG rtime, time_t *unixtime)
  96. {
  97. FILETIME ft;
  98. if (unixtime == NULL)
  99. return MAPI_E_INVALID_PARAMETER;
  100. RTimeToFileTime(rtime, &ft);
  101. FileTimeToUnixTime(ft, unixtime);
  102. return hrSuccess;
  103. }
  104. HRESULT UnixTimeToRTime(time_t unixtime, LONG *rtime)
  105. {
  106. FILETIME ft;
  107. if (rtime == NULL)
  108. return MAPI_E_INVALID_PARAMETER;
  109. UnixTimeToFileTime(unixtime, &ft);
  110. FileTimeToRTime(&ft, rtime);
  111. return hrSuccess;
  112. }
  113. /* The 'IntDate' and 'IntTime' date and time encoding are used for some CDO calculations. They
  114. * are basically a date or time encoded in a bitshifted way, packed so that it uses the least amount
  115. * of bits. Eg. a date (day,month,year) is encoded as 5 bits for the day (1-31), 4 bits for the month (1-12),
  116. * and the rest of the bits (32-4-5 = 23) for the year. The same goes for time, with seconds and minutes
  117. * each using 6 bits and 32-6-6=20 bits for the hours.
  118. *
  119. * For dates, everything is 1-index (1st January is 1-1) and year is full (2008)
  120. */
  121. bool operator ==(const FILETIME &a, const FILETIME &b)
  122. {
  123. return a.dwLowDateTime == b.dwLowDateTime && a.dwHighDateTime == b.dwHighDateTime;
  124. }
  125. bool operator >(const FILETIME &a, const FILETIME &b)
  126. {
  127. return ((a.dwHighDateTime > b.dwHighDateTime) ||
  128. ((a.dwHighDateTime == b.dwHighDateTime) &&
  129. (a.dwLowDateTime > b.dwLowDateTime)));
  130. }
  131. bool operator >=(const FILETIME &a, const FILETIME &b)
  132. {
  133. return a > b || a == b;
  134. }
  135. bool operator <(const FILETIME &a, const FILETIME &b)
  136. {
  137. return ((a.dwHighDateTime < b.dwHighDateTime) ||
  138. ((a.dwHighDateTime == b.dwHighDateTime) &&
  139. (a.dwLowDateTime < b.dwLowDateTime)));
  140. }
  141. bool operator <=(const FILETIME &a, const FILETIME &b)
  142. {
  143. return a < b || a == b;
  144. }
  145. time_t operator -(const FILETIME &a, const FILETIME &b)
  146. {
  147. time_t aa, bb;
  148. FileTimeToUnixTime(a, &aa);
  149. FileTimeToUnixTime(b, &bb);
  150. return aa - bb;
  151. }
  152. #ifndef HAVE_TIMEGM
  153. time_t timegm(struct tm *t) {
  154. time_t convert;
  155. char *tz = NULL;
  156. char *s_tz = NULL;
  157. tz = getenv("TZ");
  158. if(tz)
  159. s_tz = strdup(tz);
  160. // SuSE 9.1 segfaults when putenv() is used in a detached thread on the next getenv() call.
  161. // so use setenv() on linux, putenv() on others.
  162. setenv("TZ", "UTC0", 1);
  163. tzset();
  164. convert = mktime(t);
  165. if (s_tz) {
  166. setenv("TZ", s_tz, 1);
  167. tzset();
  168. } else {
  169. unsetenv("TZ");
  170. tzset();
  171. }
  172. free(s_tz);
  173. return convert;
  174. }
  175. #endif
  176. struct tm* gmtime_safe(const time_t* timer, struct tm *result)
  177. {
  178. struct tm *tmp = NULL;
  179. tmp = gmtime_r(timer, result);
  180. if(tmp == NULL)
  181. memset(result, 0, sizeof(struct tm));
  182. return tmp;
  183. }
  184. double timespec2dbl(const struct timespec &t)
  185. {
  186. return (double)t.tv_sec + t.tv_nsec/1000000000.0;
  187. }
  188. struct timespec GetDeadline(unsigned int ulTimeoutMs)
  189. {
  190. struct timespec deadline;
  191. struct timeval now;
  192. gettimeofday(&now, NULL);
  193. now.tv_sec += ulTimeoutMs / 1000;
  194. now.tv_usec += 1000 * (ulTimeoutMs % 1000);
  195. if (now.tv_usec >= 1000000) {
  196. ++now.tv_sec;
  197. now.tv_usec -= 1000000;
  198. }
  199. deadline.tv_sec = now.tv_sec;
  200. deadline.tv_nsec = now.tv_usec * 1000;
  201. return deadline;
  202. }
  203. // Does mkdir -p <path>
  204. int CreatePath(const char *createpath)
  205. {
  206. struct stat s;
  207. char *path = strdup(createpath);
  208. // Remove trailing slashes
  209. size_t len = strlen(path);
  210. while (len > 0 && (path[len-1] == '/' || path[len-1] == '\\'))
  211. path[--len] = 0;
  212. if (stat(path, &s) == 0) {
  213. free(path);
  214. if (s.st_mode & S_IFDIR)
  215. return 0; // Directory is already there
  216. return -1; // Item is not a directory
  217. }
  218. // We need to create the directory
  219. // First, create parent directories
  220. char *trail = strrchr(path, '/') > strrchr(path, '\\') ?
  221. strrchr(path, '/') : strrchr(path, '\\');
  222. if (trail == NULL) {
  223. // Should only happen if you are trying to create /path/to/dir
  224. // in win32 or \path\to\dir in linux
  225. free(path);
  226. return -1;
  227. }
  228. *trail = '\0';
  229. if (CreatePath(path) != 0) {
  230. free(path);
  231. return -1;
  232. }
  233. // Create the actual directory
  234. int ret = mkdir(createpath, 0700);
  235. free(path);
  236. return ret;
  237. }
  238. double GetTimeOfDay()
  239. {
  240. struct timeval tv;
  241. gettimeofday(&tv, NULL);
  242. return (double)tv.tv_sec + ((double)tv.tv_usec / 1000000); // usec = microsec = 1 millionth of a second
  243. }
  244. void set_thread_name(pthread_t tid, const std::string & name)
  245. {
  246. #ifdef HAVE_PTHREAD_SETNAME_NP_2
  247. if (name.size() > 15)
  248. pthread_setname_np(tid, name.substr(0, 15).c_str());
  249. else
  250. pthread_setname_np(tid, name.c_str());
  251. #endif
  252. }
  253. ssize_t read_retry(int fd, void *data, size_t len)
  254. {
  255. auto buf = static_cast<char *>(data);
  256. size_t tread = 0;
  257. while (len > 0) {
  258. ssize_t ret = read(fd, buf, len);
  259. if (ret < 0 && (errno == EINTR || errno == EAGAIN))
  260. continue;
  261. if (ret < 0)
  262. return ret;
  263. if (ret == 0)
  264. break;
  265. len -= ret;
  266. buf += ret;
  267. tread += ret;
  268. }
  269. return tread;
  270. }
  271. ssize_t write_retry(int fd, const void *data, size_t len)
  272. {
  273. auto buf = static_cast<const char *>(data);
  274. size_t twrote = 0;
  275. while (len > 0) {
  276. ssize_t ret = write(fd, buf, len);
  277. if (ret < 0 && (errno == EINTR || errno == EAGAIN))
  278. continue;
  279. if (ret < 0)
  280. return ret;
  281. if (ret == 0)
  282. break;
  283. len -= ret;
  284. buf += ret;
  285. twrote += ret;
  286. }
  287. return twrote;
  288. }
  289. bool force_buffers_to_disk(const int fd)
  290. {
  291. return fsync(fd) != -1;
  292. }
  293. void my_readahead(const int fd)
  294. {
  295. #ifdef LINUX
  296. struct stat st;
  297. if (fstat(fd, &st) == 0)
  298. (void)readahead(fd, 0, st.st_size);
  299. #endif
  300. }
  301. void give_filesize_hint(const int fd, const off_t len)
  302. {
  303. #ifdef LINUX
  304. // this helps preventing filesystem fragmentation as the
  305. // kernel can now look for the best disk allocation
  306. // pattern as it knows how much date is going to be
  307. // inserted
  308. posix_fallocate(fd, 0, len);
  309. #endif
  310. }
  311. } /* namespace */