1 /* Copyright (c) 2003-2004, Roger Dingledine
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2020, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
9 * \brief Cross-platform support for mapping files into our address space.
12 #include "lib/fs/mmap.h"
13 #include "lib/fs/files.h"
14 #include "lib/log/log.h"
15 #include "lib/log/util_bug.h"
16 #include "lib/log/win32err.h"
17 #include "lib/string/compat_string.h"
18 #include "lib/malloc/malloc.h"
23 #ifdef HAVE_SYS_STAT_H
40 #if defined(HAVE_MMAP) || defined(RUNNING_DOXYGEN)
41 /** Try to create a memory mapping for <b>filename</b> and return it. On
42 * failure, return NULL. Sets errno properly, using ERANGE to mean
43 * "empty file". Must only be called on trusted Tor-owned files, as changing
44 * the underlying file's size causes unspecified behavior. */
45 MOCK_IMPL(tor_mmap_t
*,
46 tor_mmap_file
,(const char *filename
))
48 int fd
; /* router file */
52 size_t size
, filesize
;
57 fd
= tor_open_cloexec(filename
, O_RDONLY
, 0);
59 int save_errno
= errno
;
60 int severity
= (errno
== ENOENT
) ? LOG_INFO
: LOG_WARN
;
61 log_fn(severity
, LD_FS
,"Could not open \"%s\" for mmap(): %s",filename
,
67 /* Get the size of the file */
68 result
= fstat(fd
, &st
);
70 int save_errno
= errno
;
72 "Couldn't fstat opened descriptor for \"%s\" during mmap: %s",
73 filename
, strerror(errno
));
78 size
= filesize
= (size_t)(st
.st_size
);
80 if (st
.st_size
> SSIZE_T_CEILING
|| (off_t
)size
< st
.st_size
) {
81 log_warn(LD_FS
, "File \"%s\" is too large. Ignoring.",filename
);
87 /* Zero-length file. If we call mmap on it, it will succeed but
88 * return NULL, and bad things will happen. So just fail. */
89 log_info(LD_FS
,"File \"%s\" is empty. Ignoring.",filename
);
95 string
= mmap(0, size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
97 if (string
== MAP_FAILED
) {
98 int save_errno
= errno
;
99 log_warn(LD_FS
,"Could not mmap file \"%s\": %s", filename
,
105 res
= tor_malloc_zero(sizeof(tor_mmap_t
));
107 res
->size
= filesize
;
108 res
->mapping_size
= size
;
112 /** Release storage held for a memory mapping; returns 0 on success,
113 * or -1 on failure (and logs a warning). */
115 tor_munmap_file
,(tor_mmap_t
*handle
))
122 res
= munmap((char*)handle
->data
, handle
->mapping_size
);
124 /* munmap() succeeded */
127 log_warn(LD_FS
, "Failed to munmap() in tor_munmap_file(): %s",
134 #elif defined(_WIN32)
135 MOCK_IMPL(tor_mmap_t
*,
136 tor_mmap_file
,(const char *filename
))
138 TCHAR tfilename
[MAX_PATH
]= {0};
139 tor_mmap_t
*res
= tor_malloc_zero(sizeof(tor_mmap_t
));
141 HANDLE file_handle
= INVALID_HANDLE_VALUE
;
142 DWORD size_low
, size_high
;
144 res
->mmap_handle
= NULL
;
146 mbstowcs(tfilename
,filename
,MAX_PATH
);
148 strlcpy(tfilename
,filename
,MAX_PATH
);
150 file_handle
= CreateFile(tfilename
,
151 GENERIC_READ
, FILE_SHARE_READ
,
154 FILE_ATTRIBUTE_NORMAL
,
157 if (file_handle
== INVALID_HANDLE_VALUE
)
160 size_low
= GetFileSize(file_handle
, &size_high
);
162 if (size_low
== INVALID_FILE_SIZE
&& GetLastError() != NO_ERROR
) {
163 log_warn(LD_FS
,"Error getting size of \"%s\".",filename
);
166 if (size_low
== 0 && size_high
== 0) {
167 log_info(LD_FS
,"File \"%s\" is empty. Ignoring.",filename
);
171 real_size
= (((uint64_t)size_high
)<<32) | size_low
;
172 if (real_size
> SIZE_MAX
) {
173 log_warn(LD_FS
,"File \"%s\" is too big to map; not trying.",filename
);
176 res
->size
= real_size
;
178 res
->mmap_handle
= CreateFileMapping(file_handle
,
184 if (res
->mmap_handle
== NULL
)
186 res
->data
= (char*) MapViewOfFile(res
->mmap_handle
,
192 CloseHandle(file_handle
);
195 DWORD e
= GetLastError();
196 int severity
= (e
== ERROR_FILE_NOT_FOUND
|| e
== ERROR_PATH_NOT_FOUND
) ?
198 char *msg
= format_win32_error(e
);
199 log_fn(severity
, LD_FS
, "Couldn't mmap file \"%s\": %s", filename
, msg
);
201 if (e
== ERROR_FILE_NOT_FOUND
|| e
== ERROR_PATH_NOT_FOUND
)
209 if (file_handle
!= INVALID_HANDLE_VALUE
)
210 CloseHandle(file_handle
);
211 tor_munmap_file(res
);
215 /* Unmap the file, and return 0 for success or -1 for failure */
217 tor_munmap_file
,(tor_mmap_t
*handle
))
223 /* This is an ugly cast, but without it, "data" in struct tor_mmap_t would
224 have to be redefined as non-const. */
225 BOOL ok
= UnmapViewOfFile( (LPVOID
) handle
->data
);
227 log_warn(LD_FS
, "Failed to UnmapViewOfFile() in tor_munmap_file(): %d",
228 (int)GetLastError());
232 if (handle
->mmap_handle
!= NULL
)
233 CloseHandle(handle
->mmap_handle
);
239 #error "cannot implement tor_mmap_file"
240 #endif /* defined(HAVE_MMAP) || defined(RUNNING_DOXYGEN) || ... */