diff options
author | Nick Mathewson <nickm@torproject.org> | 2018-06-27 09:40:21 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2018-06-27 12:30:11 -0400 |
commit | 1e2e0f7e461b4518b123c4050c3dbc786ac422c4 (patch) | |
tree | 65fd14c74582fe2edccba0cc865c347d8b79712b /src/common/compat.c | |
parent | 3246c114a20da44064f7fae8eb6b6712e708a700 (diff) | |
download | tor-1e2e0f7e461b4518b123c4050c3dbc786ac422c4.tar.gz tor-1e2e0f7e461b4518b123c4050c3dbc786ac422c4.zip |
Extract functions from compat.c and util.h into a new fs library
Diffstat (limited to 'src/common/compat.c')
-rw-r--r-- | src/common/compat.c | 556 |
1 files changed, 0 insertions, 556 deletions
diff --git a/src/common/compat.c b/src/common/compat.c index b462ee1b4c..e26591776e 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -131,267 +131,6 @@ SecureZeroMemory(PVOID ptr, SIZE_T cnt) #include "lib/net/address.h" #include "lib/sandbox/sandbox.h" -/** As open(path, flags, mode), but return an fd with the close-on-exec mode - * set. */ -int -tor_open_cloexec(const char *path, int flags, unsigned mode) -{ - int fd; - const char *p = sandbox_intern_string(path); -#ifdef O_CLOEXEC - fd = open(p, flags|O_CLOEXEC, mode); - if (fd >= 0) - return fd; - /* If we got an error, see if it is EINVAL. EINVAL might indicate that, - * even though we were built on a system with O_CLOEXEC support, we - * are running on one without. */ - if (errno != EINVAL) - return -1; -#endif /* defined(O_CLOEXEC) */ - - log_debug(LD_FS, "Opening %s with flags %x", p, flags); - fd = open(p, flags, mode); -#ifdef FD_CLOEXEC - if (fd >= 0) { - if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { - log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); - close(fd); - return -1; - } - } -#endif /* defined(FD_CLOEXEC) */ - return fd; -} - -/** As fopen(path,mode), but ensures that the O_CLOEXEC bit is set on the - * underlying file handle. */ -FILE * -tor_fopen_cloexec(const char *path, const char *mode) -{ - FILE *result = fopen(path, mode); -#ifdef FD_CLOEXEC - if (result != NULL) { - if (fcntl(fileno(result), F_SETFD, FD_CLOEXEC) == -1) { - log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); - fclose(result); - return NULL; - } - } -#endif /* defined(FD_CLOEXEC) */ - return result; -} - -/** As rename(), but work correctly with the sandbox. */ -int -tor_rename(const char *path_old, const char *path_new) -{ - log_debug(LD_FS, "Renaming %s to %s", path_old, path_new); - return rename(sandbox_intern_string(path_old), - sandbox_intern_string(path_new)); -} - -#if defined(HAVE_MMAP) || defined(RUNNING_DOXYGEN) -/** Try to create a memory mapping for <b>filename</b> and return it. On - * failure, return NULL. Sets errno properly, using ERANGE to mean - * "empty file". Must only be called on trusted Tor-owned files, as changing - * the underlying file's size causes unspecified behavior. */ -tor_mmap_t * -tor_mmap_file(const char *filename) -{ - int fd; /* router file */ - char *string; - int result; - tor_mmap_t *res; - size_t size, filesize; - struct stat st; - - tor_assert(filename); - - fd = tor_open_cloexec(filename, O_RDONLY, 0); - if (fd<0) { - int save_errno = errno; - int severity = (errno == ENOENT) ? LOG_INFO : LOG_WARN; - log_fn(severity, LD_FS,"Could not open \"%s\" for mmap(): %s",filename, - strerror(errno)); - errno = save_errno; - return NULL; - } - - /* Get the size of the file */ - result = fstat(fd, &st); - if (result != 0) { - int save_errno = errno; - log_warn(LD_FS, - "Couldn't fstat opened descriptor for \"%s\" during mmap: %s", - filename, strerror(errno)); - close(fd); - errno = save_errno; - return NULL; - } - size = filesize = (size_t)(st.st_size); - - if (st.st_size > SSIZE_T_CEILING || (off_t)size < st.st_size) { - log_warn(LD_FS, "File \"%s\" is too large. Ignoring.",filename); - errno = EFBIG; - close(fd); - return NULL; - } - if (!size) { - /* Zero-length file. If we call mmap on it, it will succeed but - * return NULL, and bad things will happen. So just fail. */ - log_info(LD_FS,"File \"%s\" is empty. Ignoring.",filename); - errno = ERANGE; - close(fd); - return NULL; - } - - string = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0); - close(fd); - if (string == MAP_FAILED) { - int save_errno = errno; - log_warn(LD_FS,"Could not mmap file \"%s\": %s", filename, - strerror(errno)); - errno = save_errno; - return NULL; - } - - res = tor_malloc_zero(sizeof(tor_mmap_t)); - res->data = string; - res->size = filesize; - res->mapping_size = size; - - return res; -} -/** Release storage held for a memory mapping; returns 0 on success, - * or -1 on failure (and logs a warning). */ -int -tor_munmap_file(tor_mmap_t *handle) -{ - int res; - - if (handle == NULL) - return 0; - - res = munmap((char*)handle->data, handle->mapping_size); - if (res == 0) { - /* munmap() succeeded */ - tor_free(handle); - } else { - log_warn(LD_FS, "Failed to munmap() in tor_munmap_file(): %s", - strerror(errno)); - res = -1; - } - - return res; -} -#elif defined(_WIN32) -tor_mmap_t * -tor_mmap_file(const char *filename) -{ - TCHAR tfilename[MAX_PATH]= {0}; - tor_mmap_t *res = tor_malloc_zero(sizeof(tor_mmap_t)); - int empty = 0; - HANDLE file_handle = INVALID_HANDLE_VALUE; - DWORD size_low, size_high; - uint64_t real_size; - res->mmap_handle = NULL; -#ifdef UNICODE - mbstowcs(tfilename,filename,MAX_PATH); -#else - strlcpy(tfilename,filename,MAX_PATH); -#endif - file_handle = CreateFile(tfilename, - GENERIC_READ, FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - 0); - - if (file_handle == INVALID_HANDLE_VALUE) - goto win_err; - - size_low = GetFileSize(file_handle, &size_high); - - if (size_low == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) { - log_warn(LD_FS,"Error getting size of \"%s\".",filename); - goto win_err; - } - if (size_low == 0 && size_high == 0) { - log_info(LD_FS,"File \"%s\" is empty. Ignoring.",filename); - empty = 1; - goto err; - } - real_size = (((uint64_t)size_high)<<32) | size_low; - if (real_size > SIZE_MAX) { - log_warn(LD_FS,"File \"%s\" is too big to map; not trying.",filename); - goto err; - } - res->size = real_size; - - res->mmap_handle = CreateFileMapping(file_handle, - NULL, - PAGE_READONLY, - size_high, - size_low, - NULL); - if (res->mmap_handle == NULL) - goto win_err; - res->data = (char*) MapViewOfFile(res->mmap_handle, - FILE_MAP_READ, - 0, 0, 0); - if (!res->data) - goto win_err; - - CloseHandle(file_handle); - return res; - win_err: { - DWORD e = GetLastError(); - int severity = (e == ERROR_FILE_NOT_FOUND || e == ERROR_PATH_NOT_FOUND) ? - LOG_INFO : LOG_WARN; - char *msg = format_win32_error(e); - log_fn(severity, LD_FS, "Couldn't mmap file \"%s\": %s", filename, msg); - tor_free(msg); - if (e == ERROR_FILE_NOT_FOUND || e == ERROR_PATH_NOT_FOUND) - errno = ENOENT; - else - errno = EINVAL; - } - err: - if (empty) - errno = ERANGE; - if (file_handle != INVALID_HANDLE_VALUE) - CloseHandle(file_handle); - tor_munmap_file(res); - return NULL; -} - -/* Unmap the file, and return 0 for success or -1 for failure */ -int -tor_munmap_file(tor_mmap_t *handle) -{ - if (handle == NULL) - return 0; - - if (handle->data) { - /* This is an ugly cast, but without it, "data" in struct tor_mmap_t would - have to be redefined as non-const. */ - BOOL ok = UnmapViewOfFile( (LPVOID) handle->data); - if (!ok) { - log_warn(LD_FS, "Failed to UnmapViewOfFile() in tor_munmap_file(): %d", - (int)GetLastError()); - } - } - - if (handle->mmap_handle != NULL) - CloseHandle(handle->mmap_handle); - tor_free(handle); - - return 0; -} -#else -#error "cannot implement tor_mmap_file" -#endif /* defined(HAVE_MMAP) || ... || ... */ - /** Given <b>hlen</b> bytes at <b>haystack</b> and <b>nlen</b> bytes at * <b>needle</b>, return a pointer to the first occurrence of the needle * within the haystack, or NULL if there is no such occurrence. @@ -553,45 +292,6 @@ set_uint64(void *cp, uint64_t v) memcpy(cp,&v,8); } -/** - * Rename the file <b>from</b> to the file <b>to</b>. On Unix, this is - * the same as rename(2). On windows, this removes <b>to</b> first if - * it already exists. - * Returns 0 on success. Returns -1 and sets errno on failure. - */ -int -replace_file(const char *from, const char *to) -{ -#ifndef _WIN32 - return tor_rename(from, to); -#else - switch (file_status(to)) - { - case FN_NOENT: - break; - case FN_FILE: - case FN_EMPTY: - if (unlink(to)) return -1; - break; - case FN_ERROR: - return -1; - case FN_DIR: - errno = EISDIR; - return -1; - } - return tor_rename(from,to); -#endif /* !defined(_WIN32) */ -} - -/** Change <b>fname</b>'s modification time to now. */ -int -touch_file(const char *fname) -{ - if (utime(fname, NULL)!=0) - return -1; - return 0; -} - /** Represents a lockfile on which we hold the lock. */ struct tor_lockfile_t { /** Name of the file */ @@ -928,109 +628,6 @@ log_credential_status(void) } #endif /* !defined(_WIN32) */ -#ifndef _WIN32 -/** Cached struct from the last getpwname() call we did successfully. */ -static struct passwd *passwd_cached = NULL; - -/** Helper: copy a struct passwd object. - * - * We only copy the fields pw_uid, pw_gid, pw_name, pw_dir. Tor doesn't use - * any others, and I don't want to run into incompatibilities. - */ -static struct passwd * -tor_passwd_dup(const struct passwd *pw) -{ - struct passwd *new_pw = tor_malloc_zero(sizeof(struct passwd)); - if (pw->pw_name) - new_pw->pw_name = tor_strdup(pw->pw_name); - if (pw->pw_dir) - new_pw->pw_dir = tor_strdup(pw->pw_dir); - new_pw->pw_uid = pw->pw_uid; - new_pw->pw_gid = pw->pw_gid; - - return new_pw; -} - -#define tor_passwd_free(pw) \ - FREE_AND_NULL(struct passwd, tor_passwd_free_, (pw)) - -/** Helper: free one of our cached 'struct passwd' values. */ -static void -tor_passwd_free_(struct passwd *pw) -{ - if (!pw) - return; - - tor_free(pw->pw_name); - tor_free(pw->pw_dir); - tor_free(pw); -} - -/** Wrapper around getpwnam() that caches result. Used so that we don't need - * to give the sandbox access to /etc/passwd. - * - * The following fields alone will definitely be copied in the output: pw_uid, - * pw_gid, pw_name, pw_dir. Other fields are not present in cached values. - * - * When called with a NULL argument, this function clears storage associated - * with static variables it uses. - **/ -const struct passwd * -tor_getpwnam(const char *username) -{ - struct passwd *pw; - - if (username == NULL) { - tor_passwd_free(passwd_cached); - passwd_cached = NULL; - return NULL; - } - - if ((pw = getpwnam(username))) { - tor_passwd_free(passwd_cached); - passwd_cached = tor_passwd_dup(pw); - log_info(LD_GENERAL, "Caching new entry %s for %s", - passwd_cached->pw_name, username); - return pw; - } - - /* Lookup failed */ - if (! passwd_cached || ! passwd_cached->pw_name) - return NULL; - - if (! strcmp(username, passwd_cached->pw_name)) - return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky - - return NULL; -} - -/** Wrapper around getpwnam() that can use cached result from - * tor_getpwnam(). Used so that we don't need to give the sandbox access to - * /etc/passwd. - * - * The following fields alone will definitely be copied in the output: pw_uid, - * pw_gid, pw_name, pw_dir. Other fields are not present in cached values. - */ -const struct passwd * -tor_getpwuid(uid_t uid) -{ - struct passwd *pw; - - if ((pw = getpwuid(uid))) { - return pw; - } - - /* Lookup failed */ - if (! passwd_cached) - return NULL; - - if (uid == passwd_cached->pw_uid) - return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky - - return NULL; -} -#endif /* !defined(_WIN32) */ - /** Return true iff we were compiled with capability support, and capabilities * seem to work. **/ int @@ -1322,159 +919,6 @@ tor_disable_debugger_attach(void) return r; } -#ifdef HAVE_PWD_H -/** Allocate and return a string containing the home directory for the - * user <b>username</b>. Only works on posix-like systems. */ -char * -get_user_homedir(const char *username) -{ - const struct passwd *pw; - tor_assert(username); - - if (!(pw = tor_getpwnam(username))) { - log_err(LD_CONFIG,"User \"%s\" not found.", username); - return NULL; - } - return tor_strdup(pw->pw_dir); -} -#endif /* defined(HAVE_PWD_H) */ - -/** Modify <b>fname</b> to contain the name of its parent directory. Doesn't - * actually examine the filesystem; does a purely syntactic modification. - * - * The parent of the root director is considered to be iteself. - * - * Path separators are the forward slash (/) everywhere and additionally - * the backslash (\) on Win32. - * - * Cuts off any number of trailing path separators but otherwise ignores - * them for purposes of finding the parent directory. - * - * Returns 0 if a parent directory was successfully found, -1 otherwise (fname - * did not have any path separators or only had them at the end). - * */ -int -get_parent_directory(char *fname) -{ - char *cp; - int at_end = 1; - tor_assert(fname); -#ifdef _WIN32 - /* If we start with, say, c:, then don't consider that the start of the path - */ - if (fname[0] && fname[1] == ':') { - fname += 2; - } -#endif /* defined(_WIN32) */ - /* Now we want to remove all path-separators at the end of the string, - * and to remove the end of the string starting with the path separator - * before the last non-path-separator. In perl, this would be - * s#[/]*$##; s#/[^/]*$##; - * on a unixy platform. - */ - cp = fname + strlen(fname); - at_end = 1; - while (--cp >= fname) { - int is_sep = (*cp == '/' -#ifdef _WIN32 - || *cp == '\\' -#endif - ); - if (is_sep) { - if (cp == fname) { - /* This is the first separator in the file name; don't remove it! */ - cp[1] = '\0'; - return 0; - } - *cp = '\0'; - if (! at_end) - return 0; - } else { - at_end = 0; - } - } - return -1; -} - -#ifndef _WIN32 -/** Return a newly allocated string containing the output of getcwd(). Return - * NULL on failure. (We can't just use getcwd() into a PATH_MAX buffer, since - * Hurd hasn't got a PATH_MAX.) - */ -static char * -alloc_getcwd(void) -{ -#ifdef HAVE_GET_CURRENT_DIR_NAME - /* Glibc makes this nice and simple for us. */ - char *cwd = get_current_dir_name(); - char *result = NULL; - if (cwd) { - /* We make a copy here, in case tor_malloc() is not malloc(). */ - result = tor_strdup(cwd); - raw_free(cwd); // alias for free to avoid tripping check-spaces. - } - return result; -#else /* !(defined(HAVE_GET_CURRENT_DIR_NAME)) */ - size_t size = 1024; - char *buf = NULL; - char *ptr = NULL; - - while (ptr == NULL) { - buf = tor_realloc(buf, size); - ptr = getcwd(buf, size); - - if (ptr == NULL && errno != ERANGE) { - tor_free(buf); - return NULL; - } - - size *= 2; - } - return buf; -#endif /* defined(HAVE_GET_CURRENT_DIR_NAME) */ -} -#endif /* !defined(_WIN32) */ - -/** Expand possibly relative path <b>fname</b> to an absolute path. - * Return a newly allocated string, possibly equal to <b>fname</b>. */ -char * -make_path_absolute(char *fname) -{ -#ifdef _WIN32 - char *absfname_malloced = _fullpath(NULL, fname, 1); - - /* We don't want to assume that tor_free can free a string allocated - * with malloc. On failure, return fname (it's better than nothing). */ - char *absfname = tor_strdup(absfname_malloced ? absfname_malloced : fname); - if (absfname_malloced) raw_free(absfname_malloced); - - return absfname; -#else /* !(defined(_WIN32)) */ - char *absfname = NULL, *path = NULL; - - tor_assert(fname); - - if (fname[0] == '/') { - absfname = tor_strdup(fname); - } else { - path = alloc_getcwd(); - if (path) { - tor_asprintf(&absfname, "%s/%s", path, fname); - tor_free(path); - } else { - /* LCOV_EXCL_START Can't make getcwd fail. */ - /* If getcwd failed, the best we can do here is keep using the - * relative path. (Perhaps / isn't readable by this UID/GID.) */ - log_warn(LD_GENERAL, "Unable to find current working directory: %s", - strerror(errno)); - absfname = tor_strdup(fname); - /* LCOV_EXCL_STOP */ - } - } - return absfname; -#endif /* defined(_WIN32) */ -} - #ifndef HAVE__NSGETENVIRON #ifndef HAVE_EXTERN_ENVIRON_DECLARED /* Some platforms declare environ under some circumstances, others don't. */ |