mmap.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /* Copyright (c) 2003-2004, Roger Dingledine
  2. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  3. * Copyright (c) 2007-2018, The Tor Project, Inc. */
  4. /* See LICENSE for licensing information */
  5. #include "lib/fs/mmap.h"
  6. #include "lib/fs/files.h"
  7. #include "lib/log/torlog.h"
  8. #include "lib/log/util_bug.h"
  9. #include "lib/log/win32err.h"
  10. #include "lib/string/compat_string.h"
  11. #include "lib/malloc/util_malloc.h"
  12. #ifdef HAVE_MMAP
  13. #include <sys/mman.h>
  14. #endif
  15. #ifdef HAVE_SYS_STAT_H
  16. #include <sys/stat.h>
  17. #endif
  18. #ifdef HAVE_UNISTD_H
  19. #include <unistd.h>
  20. #endif
  21. #ifdef HAVE_FCNTL_H
  22. #include <fcntl.h>
  23. #endif
  24. #ifdef _WIN32
  25. #include <windows.h>
  26. #endif
  27. #include <errno.h>
  28. #include <string.h>
  29. #if defined(HAVE_MMAP) || defined(RUNNING_DOXYGEN)
  30. /** Try to create a memory mapping for <b>filename</b> and return it. On
  31. * failure, return NULL. Sets errno properly, using ERANGE to mean
  32. * "empty file". Must only be called on trusted Tor-owned files, as changing
  33. * the underlying file's size causes unspecified behavior. */
  34. tor_mmap_t *
  35. tor_mmap_file(const char *filename)
  36. {
  37. int fd; /* router file */
  38. char *string;
  39. int result;
  40. tor_mmap_t *res;
  41. size_t size, filesize;
  42. struct stat st;
  43. tor_assert(filename);
  44. fd = tor_open_cloexec(filename, O_RDONLY, 0);
  45. if (fd<0) {
  46. int save_errno = errno;
  47. int severity = (errno == ENOENT) ? LOG_INFO : LOG_WARN;
  48. log_fn(severity, LD_FS,"Could not open \"%s\" for mmap(): %s",filename,
  49. strerror(errno));
  50. errno = save_errno;
  51. return NULL;
  52. }
  53. /* Get the size of the file */
  54. result = fstat(fd, &st);
  55. if (result != 0) {
  56. int save_errno = errno;
  57. log_warn(LD_FS,
  58. "Couldn't fstat opened descriptor for \"%s\" during mmap: %s",
  59. filename, strerror(errno));
  60. close(fd);
  61. errno = save_errno;
  62. return NULL;
  63. }
  64. size = filesize = (size_t)(st.st_size);
  65. if (st.st_size > SSIZE_T_CEILING || (off_t)size < st.st_size) {
  66. log_warn(LD_FS, "File \"%s\" is too large. Ignoring.",filename);
  67. errno = EFBIG;
  68. close(fd);
  69. return NULL;
  70. }
  71. if (!size) {
  72. /* Zero-length file. If we call mmap on it, it will succeed but
  73. * return NULL, and bad things will happen. So just fail. */
  74. log_info(LD_FS,"File \"%s\" is empty. Ignoring.",filename);
  75. errno = ERANGE;
  76. close(fd);
  77. return NULL;
  78. }
  79. string = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0);
  80. close(fd);
  81. if (string == MAP_FAILED) {
  82. int save_errno = errno;
  83. log_warn(LD_FS,"Could not mmap file \"%s\": %s", filename,
  84. strerror(errno));
  85. errno = save_errno;
  86. return NULL;
  87. }
  88. res = tor_malloc_zero(sizeof(tor_mmap_t));
  89. res->data = string;
  90. res->size = filesize;
  91. res->mapping_size = size;
  92. return res;
  93. }
  94. /** Release storage held for a memory mapping; returns 0 on success,
  95. * or -1 on failure (and logs a warning). */
  96. int
  97. tor_munmap_file(tor_mmap_t *handle)
  98. {
  99. int res;
  100. if (handle == NULL)
  101. return 0;
  102. res = munmap((char*)handle->data, handle->mapping_size);
  103. if (res == 0) {
  104. /* munmap() succeeded */
  105. tor_free(handle);
  106. } else {
  107. log_warn(LD_FS, "Failed to munmap() in tor_munmap_file(): %s",
  108. strerror(errno));
  109. res = -1;
  110. }
  111. return res;
  112. }
  113. #elif defined(_WIN32)
  114. tor_mmap_t *
  115. tor_mmap_file(const char *filename)
  116. {
  117. TCHAR tfilename[MAX_PATH]= {0};
  118. tor_mmap_t *res = tor_malloc_zero(sizeof(tor_mmap_t));
  119. int empty = 0;
  120. HANDLE file_handle = INVALID_HANDLE_VALUE;
  121. DWORD size_low, size_high;
  122. uint64_t real_size;
  123. res->mmap_handle = NULL;
  124. #ifdef UNICODE
  125. mbstowcs(tfilename,filename,MAX_PATH);
  126. #else
  127. strlcpy(tfilename,filename,MAX_PATH);
  128. #endif
  129. file_handle = CreateFile(tfilename,
  130. GENERIC_READ, FILE_SHARE_READ,
  131. NULL,
  132. OPEN_EXISTING,
  133. FILE_ATTRIBUTE_NORMAL,
  134. 0);
  135. if (file_handle == INVALID_HANDLE_VALUE)
  136. goto win_err;
  137. size_low = GetFileSize(file_handle, &size_high);
  138. if (size_low == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) {
  139. log_warn(LD_FS,"Error getting size of \"%s\".",filename);
  140. goto win_err;
  141. }
  142. if (size_low == 0 && size_high == 0) {
  143. log_info(LD_FS,"File \"%s\" is empty. Ignoring.",filename);
  144. empty = 1;
  145. goto err;
  146. }
  147. real_size = (((uint64_t)size_high)<<32) | size_low;
  148. if (real_size > SIZE_MAX) {
  149. log_warn(LD_FS,"File \"%s\" is too big to map; not trying.",filename);
  150. goto err;
  151. }
  152. res->size = real_size;
  153. res->mmap_handle = CreateFileMapping(file_handle,
  154. NULL,
  155. PAGE_READONLY,
  156. size_high,
  157. size_low,
  158. NULL);
  159. if (res->mmap_handle == NULL)
  160. goto win_err;
  161. res->data = (char*) MapViewOfFile(res->mmap_handle,
  162. FILE_MAP_READ,
  163. 0, 0, 0);
  164. if (!res->data)
  165. goto win_err;
  166. CloseHandle(file_handle);
  167. return res;
  168. win_err: {
  169. DWORD e = GetLastError();
  170. int severity = (e == ERROR_FILE_NOT_FOUND || e == ERROR_PATH_NOT_FOUND) ?
  171. LOG_INFO : LOG_WARN;
  172. char *msg = format_win32_error(e);
  173. log_fn(severity, LD_FS, "Couldn't mmap file \"%s\": %s", filename, msg);
  174. tor_free(msg);
  175. if (e == ERROR_FILE_NOT_FOUND || e == ERROR_PATH_NOT_FOUND)
  176. errno = ENOENT;
  177. else
  178. errno = EINVAL;
  179. }
  180. err:
  181. if (empty)
  182. errno = ERANGE;
  183. if (file_handle != INVALID_HANDLE_VALUE)
  184. CloseHandle(file_handle);
  185. tor_munmap_file(res);
  186. return NULL;
  187. }
  188. /* Unmap the file, and return 0 for success or -1 for failure */
  189. int
  190. tor_munmap_file(tor_mmap_t *handle)
  191. {
  192. if (handle == NULL)
  193. return 0;
  194. if (handle->data) {
  195. /* This is an ugly cast, but without it, "data" in struct tor_mmap_t would
  196. have to be redefined as non-const. */
  197. BOOL ok = UnmapViewOfFile( (LPVOID) handle->data);
  198. if (!ok) {
  199. log_warn(LD_FS, "Failed to UnmapViewOfFile() in tor_munmap_file(): %d",
  200. (int)GetLastError());
  201. }
  202. }
  203. if (handle->mmap_handle != NULL)
  204. CloseHandle(handle->mmap_handle);
  205. tor_free(handle);
  206. return 0;
  207. }
  208. #else
  209. #error "cannot implement tor_mmap_file"
  210. #endif /* defined(HAVE_MMAP) || ... || ... */