mirror of
https://github.com/isar/libmdbx.git
synced 2025-01-02 02:14:13 +08:00
mdbx: purpose-oriented openfile().
Change-Id: I657689dab538af9a27c27f58eeb4e5ca43bdbc38
This commit is contained in:
parent
116d14bb76
commit
2db5736554
@ -8597,8 +8597,7 @@ static int __cold mdbx_setup_lck(MDBX_env *env, char *lck_pathname,
|
||||
mdbx_assert(env, env->me_fd != INVALID_HANDLE_VALUE);
|
||||
mdbx_assert(env, env->me_lfd == INVALID_HANDLE_VALUE);
|
||||
|
||||
int err = mdbx_openfile(lck_pathname, O_RDWR | O_CREAT, mode, &env->me_lfd,
|
||||
(env->me_flags & MDBX_EXCLUSIVE) ? true : false);
|
||||
int err = mdbx_openfile(MDBX_OPEN_LCK, env, lck_pathname, &env->me_lfd, mode);
|
||||
if (err != MDBX_SUCCESS) {
|
||||
if (!(err == MDBX_ENOFILE && (env->me_flags & MDBX_EXCLUSIVE)) &&
|
||||
!((err == MDBX_EROFS || err == MDBX_EACCESS || err == MDBX_EPERM) &&
|
||||
@ -8908,9 +8907,9 @@ __cold int mdbx_is_readahead_reasonable(size_t volume, intptr_t redundancy) {
|
||||
#error "Persistent DB flags & env flags overlap, but both go in mm_flags"
|
||||
#endif
|
||||
|
||||
int __cold mdbx_env_open(MDBX_env *env, const char *path, unsigned flags,
|
||||
int __cold mdbx_env_open(MDBX_env *env, const char *pathname, unsigned flags,
|
||||
mode_t mode) {
|
||||
if (unlikely(!env || !path))
|
||||
if (unlikely(!env || !pathname))
|
||||
return MDBX_EINVAL;
|
||||
|
||||
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
|
||||
@ -8923,7 +8922,7 @@ int __cold mdbx_env_open(MDBX_env *env, const char *path, unsigned flags,
|
||||
(env->me_flags & MDBX_ENV_ACTIVE) != 0)
|
||||
return MDBX_EPERM;
|
||||
|
||||
size_t len_full, len = strlen(path);
|
||||
size_t len_full, len = strlen(pathname);
|
||||
if (flags & MDBX_NOSUBDIR) {
|
||||
len_full = len + sizeof(MDBX_LOCK_SUFFIX) + len + 1;
|
||||
} else {
|
||||
@ -8936,12 +8935,12 @@ int __cold mdbx_env_open(MDBX_env *env, const char *path, unsigned flags,
|
||||
char *dxb_pathname;
|
||||
if (flags & MDBX_NOSUBDIR) {
|
||||
dxb_pathname = lck_pathname + len + sizeof(MDBX_LOCK_SUFFIX);
|
||||
sprintf(lck_pathname, "%s" MDBX_LOCK_SUFFIX, path);
|
||||
strcpy(dxb_pathname, path);
|
||||
sprintf(lck_pathname, "%s" MDBX_LOCK_SUFFIX, pathname);
|
||||
strcpy(dxb_pathname, pathname);
|
||||
} else {
|
||||
dxb_pathname = lck_pathname + len + sizeof(MDBX_LOCKNAME);
|
||||
sprintf(lck_pathname, "%s" MDBX_LOCKNAME, path);
|
||||
sprintf(dxb_pathname, "%s" MDBX_DATANAME, path);
|
||||
sprintf(lck_pathname, "%s" MDBX_LOCKNAME, pathname);
|
||||
sprintf(dxb_pathname, "%s" MDBX_DATANAME, pathname);
|
||||
}
|
||||
|
||||
int rc = MDBX_SUCCESS;
|
||||
@ -8978,7 +8977,7 @@ int __cold mdbx_env_open(MDBX_env *env, const char *path, unsigned flags,
|
||||
if (rc)
|
||||
goto bailout;
|
||||
|
||||
env->me_path = mdbx_strdup(path);
|
||||
env->me_path = mdbx_strdup(pathname);
|
||||
env->me_dbxs = mdbx_calloc(env->me_maxdbs, sizeof(MDBX_dbx));
|
||||
env->me_dbflags = mdbx_calloc(env->me_maxdbs, sizeof(env->me_dbflags[0]));
|
||||
env->me_dbiseqs = mdbx_calloc(env->me_maxdbs, sizeof(env->me_dbiseqs[0]));
|
||||
@ -8989,37 +8988,39 @@ int __cold mdbx_env_open(MDBX_env *env, const char *path, unsigned flags,
|
||||
env->me_dbxs[FREE_DBI].md_cmp =
|
||||
mdbx_cmp_int_align4; /* aligned MDBX_INTEGERKEY */
|
||||
|
||||
int oflags;
|
||||
if (F_ISSET(flags, MDBX_RDONLY))
|
||||
oflags = O_RDONLY;
|
||||
else if (mode != 0) {
|
||||
if ((flags & MDBX_NOSUBDIR) == 0) {
|
||||
if ((flags & (MDBX_RDONLY | MDBX_NOSUBDIR)) == 0 && mode != 0) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
if (!CreateDirectoryA(path, nullptr)) {
|
||||
rc = GetLastError();
|
||||
if (rc != ERROR_ALREADY_EXISTS)
|
||||
goto bailout;
|
||||
}
|
||||
#else
|
||||
const mode_t dir_mode =
|
||||
(/* inherit read/write permissions for group and others */ mode &
|
||||
(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) |
|
||||
/* always add read/write/search for owner */ S_IRWXU |
|
||||
((mode & S_IRGRP) ? /* +search if readable by group */ S_IXGRP : 0) |
|
||||
((mode & S_IROTH) ? /* +search if readable by others */ S_IXOTH : 0);
|
||||
if (mkdir(path, dir_mode)) {
|
||||
rc = errno;
|
||||
if (rc != EEXIST)
|
||||
goto bailout;
|
||||
}
|
||||
#endif
|
||||
const size_t wlen = mbstowcs(nullptr, pathname, INT_MAX);
|
||||
if (wlen < 1 || wlen > /* MAX_PATH */ INT16_MAX)
|
||||
return ERROR_INVALID_NAME;
|
||||
wchar_t *const pathnameW = _alloca((wlen + 1) * sizeof(wchar_t));
|
||||
if (wlen != mbstowcs(pathnameW, pathname, wlen + 1)) {
|
||||
rc = ERROR_INVALID_NAME;
|
||||
goto bailout;
|
||||
}
|
||||
oflags = O_RDWR | O_CREAT;
|
||||
} else
|
||||
oflags = O_RDWR;
|
||||
if (!CreateDirectoryW(pathnameW, nullptr)) {
|
||||
rc = GetLastError();
|
||||
if (rc != ERROR_ALREADY_EXISTS)
|
||||
goto bailout;
|
||||
}
|
||||
#else
|
||||
const mode_t dir_mode =
|
||||
(/* inherit read/write permissions for group and others */ mode &
|
||||
(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) |
|
||||
/* always add read/write/search for owner */ S_IRWXU |
|
||||
((mode & S_IRGRP) ? /* +search if readable by group */ S_IXGRP : 0) |
|
||||
((mode & S_IROTH) ? /* +search if readable by others */ S_IXOTH : 0);
|
||||
if (mkdir(pathname, dir_mode)) {
|
||||
rc = errno;
|
||||
if (rc != EEXIST)
|
||||
goto bailout;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
rc = mdbx_openfile(dxb_pathname, oflags, mode, &env->me_fd,
|
||||
(env->me_flags & MDBX_EXCLUSIVE) ? true : false);
|
||||
rc = mdbx_openfile(F_ISSET(flags, MDBX_RDONLY) ? MDBX_OPEN_DXB_READ
|
||||
: MDBX_OPEN_DXB_LAZY,
|
||||
env, dxb_pathname, &env->me_fd, mode);
|
||||
if (rc != MDBX_SUCCESS)
|
||||
goto bailout;
|
||||
|
||||
@ -14443,49 +14444,28 @@ int __cold mdbx_env_copy(MDBX_env *env, const char *dest_path, unsigned flags) {
|
||||
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
char *dxb_pathname;
|
||||
mdbx_filehandle_t newfd = INVALID_HANDLE_VALUE;
|
||||
|
||||
if (env->me_flags & MDBX_NOSUBDIR) {
|
||||
dxb_pathname = (char *)dest_path;
|
||||
} else {
|
||||
size_t len = strlen(dest_path);
|
||||
len += sizeof(MDBX_DATANAME);
|
||||
dxb_pathname = mdbx_malloc(len);
|
||||
if (!dxb_pathname)
|
||||
return MDBX_ENOMEM;
|
||||
sprintf(dxb_pathname, "%s" MDBX_DATANAME, dest_path);
|
||||
}
|
||||
|
||||
/* The destination path must exist, but the destination file must not.
|
||||
* We don't want the OS to cache the writes, since the source data is
|
||||
* already in the OS cache. */
|
||||
int rc = mdbx_openfile(dxb_pathname, O_WRONLY | O_CREAT | O_EXCL, 0640,
|
||||
&newfd, true);
|
||||
if (rc == MDBX_SUCCESS) {
|
||||
if (env->me_psize >= env->me_os_psize) {
|
||||
#ifdef F_NOCACHE /* __APPLE__ */
|
||||
(void)fcntl(newfd, F_NOCACHE, 1);
|
||||
#elif defined(O_DIRECT) && defined(F_GETFL)
|
||||
/* Set O_DIRECT if the file system supports it */
|
||||
if ((rc = fcntl(newfd, F_GETFL)) != -1)
|
||||
(void)fcntl(newfd, F_SETFL, rc | O_DIRECT);
|
||||
mdbx_filehandle_t newfd;
|
||||
int rc = mdbx_openfile(MDBX_OPEN_COPY, env, dest_path, &newfd,
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
(mode_t)-1
|
||||
#else
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
|
||||
#endif
|
||||
}
|
||||
);
|
||||
if (rc == MDBX_SUCCESS)
|
||||
rc = mdbx_env_copy2fd(env, newfd, flags);
|
||||
}
|
||||
|
||||
if (newfd != INVALID_HANDLE_VALUE) {
|
||||
int err = mdbx_closefile(newfd);
|
||||
if (rc == MDBX_SUCCESS && err != rc)
|
||||
rc = err;
|
||||
if (rc != MDBX_SUCCESS)
|
||||
(void)mdbx_removefile(dxb_pathname);
|
||||
(void)mdbx_removefile(dest_path);
|
||||
}
|
||||
|
||||
if (dxb_pathname != dest_path)
|
||||
mdbx_free(dxb_pathname);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -512,106 +512,156 @@ MDBX_INTERNAL_FUNC int mdbx_fastmutex_release(mdbx_fastmutex_t *fastmutex) {
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
return DeleteFileA(pathname) ? MDBX_SUCCESS : GetLastError();
|
||||
const size_t wlen = mbstowcs(nullptr, pathname, INT_MAX);
|
||||
if (wlen < 1 || wlen > /* MAX_PATH */ INT16_MAX)
|
||||
return ERROR_INVALID_NAME;
|
||||
wchar_t *const pathnameW = _alloca((wlen + 1) * sizeof(wchar_t));
|
||||
if (wlen != mbstowcs(pathnameW, pathname, wlen + 1))
|
||||
return ERROR_INVALID_NAME;
|
||||
return DeleteFileW(pathnameW) ? MDBX_SUCCESS : GetLastError();
|
||||
#else
|
||||
return unlink(pathname) ? errno : MDBX_SUCCESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_openfile(const char *pathname, int flags,
|
||||
mode_t mode, mdbx_filehandle_t *fd,
|
||||
bool exclusive) {
|
||||
MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
|
||||
const MDBX_env *env, const char *pathname,
|
||||
mdbx_filehandle_t *fd,
|
||||
mode_t unix_mode_bits) {
|
||||
*fd = INVALID_HANDLE_VALUE;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
(void)mode;
|
||||
size_t wlen = mbstowcs(nullptr, pathname, INT_MAX);
|
||||
const size_t wlen = mbstowcs(nullptr, pathname, INT_MAX);
|
||||
if (wlen < 1 || wlen > /* MAX_PATH */ INT16_MAX)
|
||||
return ERROR_INVALID_NAME;
|
||||
wchar_t *const pathnameW = _alloca((wlen + 1) * sizeof(wchar_t));
|
||||
if (wlen != mbstowcs(pathnameW, pathname, wlen + 1))
|
||||
return ERROR_INVALID_NAME;
|
||||
|
||||
DWORD DesiredAccess, ShareMode;
|
||||
DWORD FlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
|
||||
switch (flags & (O_RDONLY | O_WRONLY | O_RDWR)) {
|
||||
DWORD CreationDisposition = unix_mode_bits ? OPEN_ALWAYS : OPEN_EXISTING;
|
||||
DWORD FlagsAndAttributes =
|
||||
FILE_FLAG_POSIX_SEMANTICS | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
|
||||
DWORD DesiredAccess = FILE_READ_ATTRIBUTES;
|
||||
DWORD ShareMode = (env->me_flags & MDBX_EXCLUSIVE)
|
||||
? 0
|
||||
: (FILE_SHARE_READ | FILE_SHARE_WRITE);
|
||||
|
||||
switch (purpose) {
|
||||
default:
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
case O_RDONLY:
|
||||
DesiredAccess = GENERIC_READ;
|
||||
ShareMode =
|
||||
exclusive ? FILE_SHARE_READ : (FILE_SHARE_READ | FILE_SHARE_WRITE);
|
||||
case MDBX_OPEN_LCK:
|
||||
CreationDisposition = OPEN_ALWAYS;
|
||||
DesiredAccess |= GENERIC_READ | GENERIC_WRITE;
|
||||
FlagsAndAttributes |= FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_TEMPORARY;
|
||||
break;
|
||||
case O_WRONLY: /* assume for MDBX_env_copy() and friends output */
|
||||
DesiredAccess = GENERIC_WRITE;
|
||||
ShareMode = 0;
|
||||
case MDBX_OPEN_DXB_READ:
|
||||
CreationDisposition = OPEN_EXISTING;
|
||||
DesiredAccess |= GENERIC_READ;
|
||||
ShareMode |= FILE_SHARE_READ;
|
||||
break;
|
||||
case MDBX_OPEN_DXB_LAZY:
|
||||
DesiredAccess |= GENERIC_READ | GENERIC_WRITE;
|
||||
break;
|
||||
case MDBX_OPEN_DXB_DSYNC:
|
||||
CreationDisposition = OPEN_EXISTING;
|
||||
DesiredAccess |= GENERIC_WRITE;
|
||||
FlagsAndAttributes |= FILE_FLAG_WRITE_THROUGH;
|
||||
break;
|
||||
case O_RDWR:
|
||||
DesiredAccess = GENERIC_READ | GENERIC_WRITE;
|
||||
ShareMode = exclusive ? 0 : (FILE_SHARE_READ | FILE_SHARE_WRITE);
|
||||
break;
|
||||
}
|
||||
|
||||
DWORD CreationDisposition;
|
||||
switch (flags & (O_EXCL | O_CREAT)) {
|
||||
default:
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
case 0:
|
||||
CreationDisposition = OPEN_EXISTING;
|
||||
break;
|
||||
case O_EXCL | O_CREAT:
|
||||
case MDBX_OPEN_COPY:
|
||||
CreationDisposition = CREATE_NEW;
|
||||
FlagsAndAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
|
||||
break;
|
||||
case O_CREAT:
|
||||
CreationDisposition = OPEN_ALWAYS;
|
||||
FlagsAndAttributes |= FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
|
||||
ShareMode = 0;
|
||||
DesiredAccess |= GENERIC_WRITE;
|
||||
FlagsAndAttributes |=
|
||||
(env->me_psize < env->me_os_psize) ? 0 : FILE_FLAG_NO_BUFFERING;
|
||||
break;
|
||||
}
|
||||
|
||||
*fd = CreateFileW(pathnameW, DesiredAccess, ShareMode, NULL,
|
||||
CreationDisposition, FlagsAndAttributes, NULL);
|
||||
|
||||
if (*fd == INVALID_HANDLE_VALUE)
|
||||
return GetLastError();
|
||||
if ((flags & O_CREAT) && GetLastError() != ERROR_ALREADY_EXISTS) {
|
||||
/* set FILE_ATTRIBUTE_NOT_CONTENT_INDEXED for new file */
|
||||
DWORD FileAttributes = GetFileAttributesA(pathname);
|
||||
if (FileAttributes == INVALID_FILE_ATTRIBUTES ||
|
||||
!SetFileAttributesA(pathname, FileAttributes |
|
||||
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)) {
|
||||
int rc = GetLastError();
|
||||
CloseHandle(*fd);
|
||||
*fd = INVALID_HANDLE_VALUE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
BY_HANDLE_FILE_INFORMATION info;
|
||||
if (!GetFileInformationByHandle(*fd, &info)) {
|
||||
int err = GetLastError();
|
||||
CloseHandle(*fd);
|
||||
*fd = INVALID_HANDLE_VALUE;
|
||||
return err;
|
||||
}
|
||||
const DWORD AttributesDiff =
|
||||
(info.dwFileAttributes ^ FlagsAndAttributes) &
|
||||
(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED |
|
||||
FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_COMPRESSED);
|
||||
if (AttributesDiff)
|
||||
(void)SetFileAttributesW(pathnameW, info.dwFileAttributes ^ AttributesDiff);
|
||||
|
||||
#else
|
||||
(void)exclusive;
|
||||
int flags = unix_mode_bits ? O_CREAT : 0;
|
||||
switch (purpose) {
|
||||
default:
|
||||
return EINVAL;
|
||||
case MDBX_OPEN_LCK:
|
||||
flags |= O_RDWR;
|
||||
break;
|
||||
case MDBX_OPEN_DXB_READ:
|
||||
flags = O_RDONLY;
|
||||
break;
|
||||
case MDBX_OPEN_DXB_LAZY:
|
||||
flags |= O_RDWR;
|
||||
break;
|
||||
case MDBX_OPEN_COPY:
|
||||
flags = O_CREAT | O_WRONLY | O_EXCL;
|
||||
break;
|
||||
case MDBX_OPEN_DXB_DSYNC:
|
||||
flags |= O_WRONLY;
|
||||
#if defined(O_DSYNC)
|
||||
flags |= O_DSYNC;
|
||||
#elif defined(O_SYNC)
|
||||
flags |= O_SYNC;
|
||||
#elif defined(O_FSYNC)
|
||||
flags |= O_FSYNC;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
const bool direct_nocache_for_copy =
|
||||
env->me_psize >= env->me_os_psize && purpose == MDBX_OPEN_COPY;
|
||||
if (direct_nocache_for_copy) {
|
||||
#if defined(O_DIRECT)
|
||||
flags |= O_DIRECT;
|
||||
#endif /* O_DIRECT */
|
||||
#if defined(O_NOCACHE)
|
||||
flags |= O_NOCACHE;
|
||||
#endif /* O_NOCACHE */
|
||||
}
|
||||
|
||||
#ifdef O_CLOEXEC
|
||||
flags |= O_CLOEXEC;
|
||||
#endif /* O_CLOEXEC */
|
||||
*fd = open(pathname, flags, mode);
|
||||
|
||||
*fd = open(pathname, flags, unix_mode_bits);
|
||||
#if defined(O_DIRECT)
|
||||
if (*fd < 0 && (flags & O_DIRECT) &&
|
||||
(errno == EINVAL || errno == EAFNOSUPPORT)) {
|
||||
flags &= ~(O_DIRECT | O_EXCL);
|
||||
*fd = open(pathname, flags, unix_mode_bits);
|
||||
}
|
||||
#endif /* O_DIRECT */
|
||||
if (*fd < 0)
|
||||
return errno;
|
||||
|
||||
#if defined(FD_CLOEXEC) && !defined(O_CLOEXEC)
|
||||
int fd_flags = fcntl(*fd, F_GETFD);
|
||||
const int fd_flags = fcntl(*fd, F_GETFD);
|
||||
if (fd_flags != -1)
|
||||
(void)fcntl(*fd, F_SETFD, fd_flags | FD_CLOEXEC);
|
||||
#endif /* FD_CLOEXEC && !O_CLOEXEC */
|
||||
|
||||
if ((flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_WRONLY) {
|
||||
/* assume for MDBX_env_copy() and friends output */
|
||||
#if defined(O_DIRECT)
|
||||
int fd_flags = fcntl(*fd, F_GETFD);
|
||||
if (fd_flags != -1)
|
||||
(void)fcntl(*fd, F_SETFL, fd_flags | O_DIRECT);
|
||||
#endif /* O_DIRECT */
|
||||
#if defined(F_NOCACHE)
|
||||
if (direct_nocache_for_copy) {
|
||||
#if defined(F_NOCACHE) && !defined(O_NOCACHE)
|
||||
(void)fcntl(*fd, F_NOCACHE, 1);
|
||||
#endif /* F_NOCACHE */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return MDBX_SUCCESS;
|
||||
|
@ -566,9 +566,19 @@ MDBX_INTERNAL_FUNC int mdbx_filesync(mdbx_filehandle_t fd,
|
||||
MDBX_INTERNAL_FUNC int mdbx_ftruncate(mdbx_filehandle_t fd, uint64_t length);
|
||||
MDBX_INTERNAL_FUNC int mdbx_fseek(mdbx_filehandle_t fd, uint64_t pos);
|
||||
MDBX_INTERNAL_FUNC int mdbx_filesize(mdbx_filehandle_t fd, uint64_t *length);
|
||||
MDBX_INTERNAL_FUNC int mdbx_openfile(const char *pathname, int flags,
|
||||
mode_t mode, mdbx_filehandle_t *fd,
|
||||
bool exclusive);
|
||||
|
||||
enum mdbx_openfile_purpose {
|
||||
MDBX_OPEN_DXB_READ = 0,
|
||||
MDBX_OPEN_DXB_LAZY = 1,
|
||||
MDBX_OPEN_DXB_DSYNC = 2,
|
||||
MDBX_OPEN_LCK = 3,
|
||||
MDBX_OPEN_COPY = 4
|
||||
};
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_openfile(const enum mdbx_openfile_purpose purpose,
|
||||
const MDBX_env *env, const char *pathname,
|
||||
mdbx_filehandle_t *fd,
|
||||
mode_t unix_mode_bits);
|
||||
MDBX_INTERNAL_FUNC int mdbx_closefile(mdbx_filehandle_t fd);
|
||||
MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname);
|
||||
MDBX_INTERNAL_FUNC int mdbx_is_pipe(mdbx_filehandle_t fd);
|
||||
|
Loading…
x
Reference in New Issue
Block a user