mdbx: initial mdbx_check_fs_rdonly() and mdbx_check_fs_local().

Change-Id: Iff48f1ad1ef54c1e51dceebce16097be030206bd
This commit is contained in:
Leonid Yuriev 2019-11-04 17:19:12 +03:00
parent b7ed67543f
commit 647d832556
4 changed files with 167 additions and 24 deletions

2
mdbx.h
View File

@ -555,6 +555,7 @@ typedef DWORD mdbx_tid_t;
#define MDBX_EPERM ERROR_INVALID_FUNCTION
#define MDBX_EINTR ERROR_CANCELLED
#define MDBX_ENOFILE ERROR_FILE_NOT_FOUND
#define MDBX_EREMOTE ERROR_REMOTE_STORAGE_MEDIA_ERROR
#else
@ -580,6 +581,7 @@ typedef pthread_t mdbx_tid_t;
#define MDBX_EPERM EPERM
#define MDBX_EINTR EINTR
#define MDBX_ENOFILE ENOENT
#define MDBX_EREMOTE ENOTBLK
#endif

View File

@ -1499,8 +1499,7 @@ static MDBX_PNL mdbx_pnl_alloc(size_t size) {
size_t bytes = pnl2bytes(size);
MDBX_PNL pl = mdbx_malloc(bytes);
if (likely(pl)) {
#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
defined(malloc_usable_size)
#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
bytes = malloc_usable_size(pl);
#endif /* malloc_usable_size */
pl[0] = bytes2pnl(bytes);
@ -1527,8 +1526,7 @@ static void mdbx_pnl_shrink(MDBX_PNL *ppl) {
size_t bytes = pnl2bytes(MDBX_PNL_INITIAL);
MDBX_PNL pl = mdbx_realloc(*ppl - 1, bytes);
if (likely(pl)) {
#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
defined(malloc_usable_size)
#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
bytes = malloc_usable_size(pl);
#endif /* malloc_usable_size */
*pl = bytes2pnl(bytes);
@ -1554,8 +1552,7 @@ static int mdbx_pnl_reserve(MDBX_PNL *ppl, const size_t wanna) {
size_t bytes = pnl2bytes(size);
MDBX_PNL pl = mdbx_realloc(*ppl - 1, bytes);
if (likely(pl)) {
#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
defined(malloc_usable_size)
#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
bytes = malloc_usable_size(pl);
#endif /* malloc_usable_size */
*pl = bytes2pnl(bytes);
@ -1767,8 +1764,7 @@ static MDBX_TXL mdbx_txl_alloc(void) {
size_t bytes = txl2bytes(MDBX_TXL_INITIAL);
MDBX_TXL tl = mdbx_malloc(bytes);
if (likely(tl)) {
#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
defined(malloc_usable_size)
#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
bytes = malloc_usable_size(tl);
#endif /* malloc_usable_size */
tl[0] = bytes2txl(bytes);
@ -1800,8 +1796,7 @@ static int mdbx_txl_reserve(MDBX_TXL *ptl, const size_t wanna) {
size_t bytes = txl2bytes(size);
MDBX_TXL tl = mdbx_realloc(*ptl - 1, bytes);
if (likely(tl)) {
#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
defined(malloc_usable_size)
#if __GLIBC_PREREQ(2, 12) || defined(__FreeBSD__) || defined(malloc_usable_size)
bytes = malloc_usable_size(tl);
#endif /* malloc_usable_size */
*tl = bytes2txl(bytes);
@ -8267,6 +8262,11 @@ static int __cold mdbx_setup_lck(MDBX_env *env, char *lck_pathname,
(env->me_flags & MDBX_RDONLY)))
return err;
/* ensure the file system is read-only */
err = mdbx_check_fs_rdonly(env->me_fd, lck_pathname, err);
if (err != MDBX_SUCCESS)
return err;
/* LY: without-lck mode (e.g. exclusive or on read-only filesystem) */
/* beginning of a locked section ---------------------------------------- */
lcklist_lock();

View File

@ -179,8 +179,19 @@ __extern_C void __assert_rtn(const char *function, const char *file, int line,
#define __assert_fail(assertion, file, line, function) \
__assert_rtn(function, file, line, assertion)
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
defined(__BSD__) || defined(__NETBSD__) || defined(__bsdi__) || \
#elif defined(__OpenBSD__)
__extern_C __dead void __assert2(const char *file, int line,
const char *function,
const char *assertion) /* __nothrow */;
#define __assert_fail(assertion, file, line, function) \
__assert2(file, line, function, assertion)
#elif defined(__NetBSD__)
__extern_C __dead void __assert13(const char *file, int line,
const char *function,
const char *assertion) /* __nothrow */;
#define __assert_fail(assertion, file, line, function) \
__assert13(file, line, function, assertion)
#elif defined(__FreeBSD__) || defined(__BSD__) || defined(__bsdi__) || \
defined(__DragonFly__)
__extern_C void __assert(const char *function, const char *file, int line,
const char *assertion) /* __nothrow */
@ -907,8 +918,36 @@ MDBX_INTERNAL_FUNC int mdbx_msync(mdbx_mmap_t *map, size_t offset,
#endif
}
MDBX_INTERNAL_FUNC int mdbx_check4nonlocal(mdbx_filehandle_t handle,
int flags) {
MDBX_INTERNAL_FUNC int mdbx_check_fs_rdonly(mdbx_filehandle_t handle,
const char *pathname, int err) {
#if defined(_WIN32) || defined(_WIN64)
(void)pathname;
(void)err;
if (!mdbx_GetVolumeInformationByHandleW)
return MDBX_ENOSYS;
DWORD unused, flags;
if (!mdbx_GetVolumeInformationByHandleW(handle, nullptr, 0, nullptr, &unused,
&flags, nullptr, 0))
return GetLastError();
if ((flags & FILE_READ_ONLY_VOLUME) == 0)
return MDBX_EACCESS;
#else
struct statvfs info;
if (err != MDBX_ENOFILE) {
if (statvfs(pathname, &info))
return errno;
if ((info.f_flag & ST_RDONLY) == 0)
return err;
}
if (fstatvfs(handle, &info))
return errno;
if ((info.f_flag & ST_RDONLY) == 0)
return (err == MDBX_ENOFILE) ? MDBX_EACCESS : err;
#endif /* !Windows */
return MDBX_SUCCESS;
}
static int mdbx_check_fs_local(mdbx_filehandle_t handle, int flags) {
#if defined(_WIN32) || defined(_WIN64)
if (GetFileType(handle) != FILE_TYPE_DISK)
return ERROR_FILE_OFFLINE;
@ -1019,10 +1058,109 @@ MDBX_INTERNAL_FUNC int mdbx_check4nonlocal(mdbx_filehandle_t handle,
return rc;
}
#else
(void)handle;
/* TODO: check for NFS handle ? */
(void)flags;
struct statvfs statvfs_info;
if (fstatvfs(handle, &statvfs_info))
return errno;
#if defined(ST_LOCAL) || defined(ST_EXPORTED)
const unsigned long st_flags = statvfs_info.f_flag;
#endif /* ST_LOCAL || ST_EXPORTED */
#if defined(__NetBSD__)
const unsigned type = 0;
const char *const name = statvfs_info.f_fstypename;
const size_t name_len = VFS_NAMELEN;
#elif defined(_AIX) || defined(__OS400__) || defined(FSTYPSZ) || \
defined(_FSTYPSZ)
const unsigned type = 0;
const char *const name = statfs_info.f_basetype;
const size_t name_len = sizeof(statfs_info.f_basetype);
#elif defined(__sun) || defined(__SVR4) || defined(__svr4__) || \
defined(ST_FSTYPSZ) || defined(_ST_FSTYPSZ)
const unsigned type = 0;
#if defined(_ST_FSTYPSZ) || defined(_ST_FSTYPSZ)
struct stat stat_info;
if (fstat(handle, &stat_info))
return errno;
const char *const name = stat_info.st_fstype;
const size_t name_len = strlen(name);
#else
const char *const name = "";
const size_t name_len = 0;
#endif
#else
struct statfs statfs_info;
if (fstatfs(handle, &statfs_info))
return errno;
#if defined(__OpenBSD__)
const unsigned type = 0;
#else
const unsigned type = statfs_info.f_type;
#endif
#if defined(MNT_LOCAL) || defined(MNT_EXPORTED)
const unsigned long mnt_flags = statfs_info.f_flags;
#endif /* MNT_LOCAL || MNT_EXPORTED */
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
defined(__BSD__) || defined(__bsdi__) || defined(__DragonFly__) || \
defined(__APPLE__) || defined(__MACH__) || defined(MFSNAMELEN) || \
defined(MFSTYPENAMELEN) || defined(VFS_NAMELEN)
const char *const name = statfs_info.f_fstypename;
const size_t name_len = sizeof(statfs_info.f_fstypename);
#else
const char *const name = "";
const unsigned name_len = 0;
#endif
#endif
if (name_len) {
if (((name_len > 2 && strncasecmp("nfs", name, 3) == 0) ||
strncasecmp("cifs", name, name_len) == 0 ||
strncasecmp("ncpfs", name, name_len) == 0 ||
strncasecmp("smbfs", name, name_len) == 0 ||
((name_len > 3 && strncasecmp("fuse", name, 4) == 0) &&
strncasecmp("fuseblk", name, name_len) != 0)) &&
!(flags & MDBX_EXCLUSIVE))
return MDBX_EREMOTE;
if (strcasecmp("ftp", name) == 0 || strcasecmp("http", name) == 0 ||
strcasecmp("sshfs", name) == 0)
return MDBX_EREMOTE;
}
#ifdef ST_LOCAL
if ((st_flags & ST_LOCAL) == 0 && !(flags & MDBX_EXCLUSIVE))
return MDBX_EREMOTE;
#elif defined(MNT_LOCAL)
if ((mnt_flags & MNT_LOCAL) == 0 && !(flags & MDBX_EXCLUSIVE))
return MDBX_EREMOTE;
#endif /* ST/MNT_LOCAL */
#ifdef ST_EXPORTED
if (st_flags & ST_EXPORTED)
return MDBX_EREMOTE;
#elif defined(MNT_EXPORTED)
if (mnt_flags & MNT_EXPORTED)
return MDBX_EREMOTE;
#endif /* ST/MNT_EXPORTED */
switch (type) {
case 0xFF534D42 /* CIFS_MAGIC_NUMBER */:
case 0x6969 /* NFS_SUPER_MAGIC */:
case 0x564c /* NCP_SUPER_MAGIC */:
case 0x517B /* SMB_SUPER_MAGIC */:
#if defined(__digital__) || defined(__osf__) || defined(__osf)
case 0x0E /* Tru64 NFS */:
#endif
#ifdef ST_FST_NFS
case ST_FST_NFS:
#endif
if ((flags & MDBX_EXCLUSIVE) == 0)
return MDBX_EREMOTE;
case 0:
default:
break;
}
#endif /* Unix */
return MDBX_SUCCESS;
}
@ -1038,7 +1176,7 @@ MDBX_INTERNAL_FUNC int mdbx_mmap(const int flags, mdbx_mmap_t *map,
map->filesize = 0;
#endif /* Windows */
int err = mdbx_check4nonlocal(map->fd, flags);
int err = mdbx_check_fs_local(map->fd, flags);
if (unlikely(err != MDBX_SUCCESS))
return err;
@ -1607,10 +1745,10 @@ __cold MDBX_INTERNAL_FUNC bin128_t mdbx_osal_bootid(void) {
const int fd =
open("/proc/sys/kernel/random/boot_id", O_RDONLY | O_NOFOLLOW);
if (fd != -1) {
struct statvfs fs;
struct statfs fs;
char buf[42];
const ssize_t len =
(fstatvfs(fd, &fs) == 0 && fs.f_fsid == /* procfs */ 0x00009FA0)
(fstatfs(fd, &fs) == 0 && fs.f_type == /* procfs */ 0x9FA0)
? read(fd, buf, sizeof(buf))
: -1;
close(fd);

View File

@ -74,6 +74,7 @@
defined(__BSD__) || defined(__NETBSD__) || defined(__bsdi__) || \
defined(__DragonFly__) || defined(__APPLE__) || defined(__MACH__)
#include <sys/cdefs.h>
#include <sys/mount.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#if defined(__FreeBSD__) || defined(__DragonFly__)
@ -95,7 +96,7 @@
#endif
#endif /* !xBSD */
#if defined(__FreeBSD__) || defined(__OpenBSD__) || __has_include(<malloc_np.h>)
#if defined(__FreeBSD__) || __has_include(<malloc_np.h>)
#include <malloc_np.h>
#endif
@ -114,7 +115,7 @@
#if defined(__linux__) || defined(__gnu_linux__)
#include <linux/sysctl.h>
#include <sys/sendfile.h>
#include <sys/statvfs.h>
#include <sys/statfs.h>
#endif /* Linux */
#ifndef _XOPEN_SOURCE
@ -200,6 +201,7 @@ static inline void *mdbx_realloc(void *ptr, size_t bytes) {
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/uio.h>
#include <unistd.h>
typedef pthread_t mdbx_thread_t;
@ -347,7 +349,7 @@ typedef pthread_mutex_t mdbx_fastmutex_t;
#include <sys/endian.h>
#include <sys/types.h>
#elif defined(__bsdi__) || defined(__DragonFly__) || defined(__FreeBSD__) || \
defined(__NETBSD__) || defined(__NetBSD__) || \
defined(__NetBSD__) || \
defined(HAVE_SYS_PARAM_H) || __has_include(<sys/param.h>)
#include <sys/param.h>
#endif /* OS */
@ -664,7 +666,8 @@ mdbx_resume_threads_after_remap(mdbx_handle_array_t *array);
#endif /* Windows */
MDBX_INTERNAL_FUNC int mdbx_msync(mdbx_mmap_t *map, size_t offset,
size_t length, int async);
MDBX_INTERNAL_FUNC int mdbx_check4nonlocal(mdbx_filehandle_t handle, int flags);
MDBX_INTERNAL_FUNC int mdbx_check_fs_rdonly(mdbx_filehandle_t handle,
const char *pathname, int err);
static __maybe_unused __inline uint32_t mdbx_getpid(void) {
STATIC_ASSERT(sizeof(mdbx_pid_t) <= sizeof(uint32_t));