unix,win: add uv_fs_statfs()
Fixes: https://github.com/libuv/libuv/issues/2386 PR-URL: https://github.com/libuv/libuv/pull/2396 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com> Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com> Reviewed-By: Bartosz Sosnowski <bartosz@janeasystems.com>
This commit is contained in:
parent
79c2d74058
commit
bf86d5fbaf
@ -102,6 +102,24 @@ Data types
|
||||
UV_FS_CLOSEDIR
|
||||
} uv_fs_type;
|
||||
|
||||
.. c:type:: uv_statfs_t
|
||||
|
||||
Reduced cross platform equivalent of ``struct statfs``.
|
||||
Used in :c:func:`uv_fs_statfs`.
|
||||
|
||||
::
|
||||
|
||||
typedef struct uv_statfs_s {
|
||||
uint64_t f_type;
|
||||
uint64_t f_bsize;
|
||||
uint64_t f_blocks;
|
||||
uint64_t f_bfree;
|
||||
uint64_t f_bavail;
|
||||
uint64_t f_files;
|
||||
uint64_t f_ffree;
|
||||
uint64_t f_spare[4];
|
||||
} uv_statfs_t;
|
||||
|
||||
.. c:type:: uv_dirent_t
|
||||
|
||||
Cross platform (reduced) equivalent of ``struct dirent``.
|
||||
@ -290,6 +308,17 @@ API
|
||||
|
||||
Equivalent to :man:`stat(2)`, :man:`fstat(2)` and :man:`lstat(2)` respectively.
|
||||
|
||||
.. c:function:: int uv_fs_statfs(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb)
|
||||
|
||||
Equivalent to :man:`statfs(2)`. On success, a `uv_statfs_t` is allocated
|
||||
and returned via `req->ptr`. This memory is freed by `uv_fs_req_cleanup()`.
|
||||
|
||||
.. note::
|
||||
Any fields in the resulting `uv_statfs_t` that are not supported by the
|
||||
underlying operating system are set to zero.
|
||||
|
||||
.. versionadded:: 1.31.0
|
||||
|
||||
.. c:function:: int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path, const char* new_path, uv_fs_cb cb)
|
||||
|
||||
Equivalent to :man:`rename(2)`.
|
||||
|
||||
19
include/uv.h
19
include/uv.h
@ -236,6 +236,7 @@ typedef struct uv_interface_address_s uv_interface_address_t;
|
||||
typedef struct uv_dirent_s uv_dirent_t;
|
||||
typedef struct uv_passwd_s uv_passwd_t;
|
||||
typedef struct uv_utsname_s uv_utsname_t;
|
||||
typedef struct uv_statfs_s uv_statfs_t;
|
||||
|
||||
typedef enum {
|
||||
UV_LOOP_BLOCK_SIGNAL
|
||||
@ -1070,6 +1071,17 @@ struct uv_utsname_s {
|
||||
to as meaningless in the docs. */
|
||||
};
|
||||
|
||||
struct uv_statfs_s {
|
||||
uint64_t f_type;
|
||||
uint64_t f_bsize;
|
||||
uint64_t f_blocks;
|
||||
uint64_t f_bfree;
|
||||
uint64_t f_bavail;
|
||||
uint64_t f_files;
|
||||
uint64_t f_ffree;
|
||||
uint64_t f_spare[4];
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
UV_DIRENT_UNKNOWN,
|
||||
UV_DIRENT_FILE,
|
||||
@ -1205,7 +1217,8 @@ typedef enum {
|
||||
UV_FS_LCHOWN,
|
||||
UV_FS_OPENDIR,
|
||||
UV_FS_READDIR,
|
||||
UV_FS_CLOSEDIR
|
||||
UV_FS_CLOSEDIR,
|
||||
UV_FS_STATFS
|
||||
} uv_fs_type;
|
||||
|
||||
struct uv_dir_s {
|
||||
@ -1433,6 +1446,10 @@ UV_EXTERN int uv_fs_lchown(uv_loop_t* loop,
|
||||
uv_uid_t uid,
|
||||
uv_gid_t gid,
|
||||
uv_fs_cb cb);
|
||||
UV_EXTERN int uv_fs_statfs(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
uv_fs_cb cb);
|
||||
|
||||
|
||||
enum uv_fs_event {
|
||||
|
||||
@ -70,6 +70,20 @@
|
||||
# include <utime.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || \
|
||||
defined(__DragonFly__) || \
|
||||
defined(__FreeBSD__) || \
|
||||
defined(__FreeBSD_kernel__) || \
|
||||
defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__)
|
||||
# include <sys/param.h>
|
||||
# include <sys/mount.h>
|
||||
#elif defined(__sun) || defined(__MVS__)
|
||||
# include <sys/statvfs.h>
|
||||
#else
|
||||
# include <sys/statfs.h>
|
||||
#endif
|
||||
|
||||
#if defined(_AIX) && _XOPEN_SOURCE <= 600
|
||||
extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */
|
||||
#endif
|
||||
@ -519,6 +533,40 @@ static int uv__fs_closedir(uv_fs_t* req) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uv__fs_statfs(uv_fs_t* req) {
|
||||
uv_statfs_t* stat_fs;
|
||||
#if defined(__sun) || defined(__MVS__)
|
||||
struct statvfs buf;
|
||||
|
||||
if (0 != statvfs(req->path, &buf))
|
||||
#else
|
||||
struct statfs buf;
|
||||
|
||||
if (0 != statfs(req->path, &buf))
|
||||
#endif /* defined(__sun) */
|
||||
return -1;
|
||||
|
||||
stat_fs = uv__malloc(sizeof(*stat_fs));
|
||||
if (stat_fs == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(__sun) || defined(__MVS__)
|
||||
stat_fs->f_type = 0; /* f_type is not supported. */
|
||||
#else
|
||||
stat_fs->f_type = buf.f_type;
|
||||
#endif
|
||||
stat_fs->f_bsize = buf.f_bsize;
|
||||
stat_fs->f_blocks = buf.f_blocks;
|
||||
stat_fs->f_bfree = buf.f_bfree;
|
||||
stat_fs->f_bavail = buf.f_bavail;
|
||||
stat_fs->f_files = buf.f_files;
|
||||
stat_fs->f_ffree = buf.f_ffree;
|
||||
req->ptr = stat_fs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t uv__fs_pathmax_size(const char* path) {
|
||||
ssize_t pathmax;
|
||||
|
||||
@ -1386,6 +1434,7 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
X(RMDIR, rmdir(req->path));
|
||||
X(SENDFILE, uv__fs_sendfile(req));
|
||||
X(STAT, uv__fs_stat(req->path, &req->statbuf));
|
||||
X(STATFS, uv__fs_statfs(req));
|
||||
X(SYMLINK, symlink(req->path, req->new_path));
|
||||
X(UNLINK, unlink(req->path));
|
||||
X(UTIME, uv__fs_utime(req));
|
||||
@ -1858,3 +1907,13 @@ int uv_fs_copyfile(uv_loop_t* loop,
|
||||
req->flags = flags;
|
||||
POST;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_statfs(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
uv_fs_cb cb) {
|
||||
INIT(STATFS);
|
||||
PATH;
|
||||
POST;
|
||||
}
|
||||
|
||||
51
src/win/fs.c
51
src/win/fs.c
@ -2548,6 +2548,41 @@ static void fs__lchown(uv_fs_t* req) {
|
||||
req->result = 0;
|
||||
}
|
||||
|
||||
|
||||
static void fs__statfs(uv_fs_t* req) {
|
||||
uv_statfs_t* stat_fs;
|
||||
DWORD sectors_per_cluster;
|
||||
DWORD bytes_per_sector;
|
||||
DWORD free_clusters;
|
||||
DWORD total_clusters;
|
||||
|
||||
if (0 == GetDiskFreeSpaceW(req->file.pathw,
|
||||
§ors_per_cluster,
|
||||
&bytes_per_sector,
|
||||
&free_clusters,
|
||||
&total_clusters)) {
|
||||
SET_REQ_WIN32_ERROR(req, GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
stat_fs = uv__malloc(sizeof(*stat_fs));
|
||||
if (stat_fs == NULL) {
|
||||
SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
stat_fs->f_type = 0;
|
||||
stat_fs->f_bsize = bytes_per_sector * sectors_per_cluster;
|
||||
stat_fs->f_blocks = total_clusters;
|
||||
stat_fs->f_bfree = free_clusters;
|
||||
stat_fs->f_bavail = free_clusters;
|
||||
stat_fs->f_files = 0;
|
||||
stat_fs->f_ffree = 0;
|
||||
req->ptr = stat_fs;
|
||||
SET_REQ_RESULT(req, 0);
|
||||
}
|
||||
|
||||
|
||||
static void uv__fs_work(struct uv__work* w) {
|
||||
uv_fs_t* req;
|
||||
|
||||
@ -2589,6 +2624,7 @@ static void uv__fs_work(struct uv__work* w) {
|
||||
XX(CHOWN, chown)
|
||||
XX(FCHOWN, fchown)
|
||||
XX(LCHOWN, lchown)
|
||||
XX(STATFS, statfs)
|
||||
default:
|
||||
assert(!"bad uv_fs_type");
|
||||
}
|
||||
@ -3100,3 +3136,18 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
|
||||
req->fs.time.mtime = mtime;
|
||||
POST;
|
||||
}
|
||||
|
||||
|
||||
int uv_fs_statfs(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
uv_fs_cb cb) {
|
||||
int err;
|
||||
|
||||
INIT(UV_FS_STATFS);
|
||||
err = fs__capture_path(req, path, NULL, cb != NULL);
|
||||
if (err)
|
||||
return uv_translate_sys_error(err);
|
||||
|
||||
POST;
|
||||
}
|
||||
|
||||
@ -94,6 +94,7 @@ static int readlink_cb_count;
|
||||
static int realpath_cb_count;
|
||||
static int utime_cb_count;
|
||||
static int futime_cb_count;
|
||||
static int statfs_cb_count;
|
||||
|
||||
static uv_loop_t* loop;
|
||||
|
||||
@ -330,6 +331,38 @@ static void fstat_cb(uv_fs_t* req) {
|
||||
}
|
||||
|
||||
|
||||
static void statfs_cb(uv_fs_t* req) {
|
||||
uv_statfs_t* stats;
|
||||
|
||||
ASSERT(req->fs_type == UV_FS_STATFS);
|
||||
ASSERT(req->result == 0);
|
||||
ASSERT(req->ptr != NULL);
|
||||
stats = req->ptr;
|
||||
|
||||
#if defined(_WIN32) || defined(__sun) || defined(_AIX) || defined(__MVS__)
|
||||
ASSERT(stats->f_type == 0);
|
||||
#else
|
||||
ASSERT(stats->f_type > 0);
|
||||
#endif
|
||||
|
||||
ASSERT(stats->f_bsize > 0);
|
||||
ASSERT(stats->f_blocks > 0);
|
||||
ASSERT(stats->f_bfree <= stats->f_blocks);
|
||||
ASSERT(stats->f_bavail <= stats->f_bfree);
|
||||
|
||||
#ifdef _WIN32
|
||||
ASSERT(stats->f_files == 0);
|
||||
ASSERT(stats->f_ffree == 0);
|
||||
#else
|
||||
ASSERT(stats->f_files > 0);
|
||||
ASSERT(stats->f_ffree <= stats->f_files);
|
||||
#endif
|
||||
uv_fs_req_cleanup(req);
|
||||
ASSERT(req->ptr == NULL);
|
||||
statfs_cb_count++;
|
||||
}
|
||||
|
||||
|
||||
static void close_cb(uv_fs_t* req) {
|
||||
int r;
|
||||
ASSERT(req == &close_req);
|
||||
@ -3817,6 +3850,9 @@ TEST_IMPL(fs_null_req) {
|
||||
r = uv_fs_futime(NULL, NULL, 0, 0.0, 0.0, NULL);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
|
||||
r = uv_fs_statfs(NULL, NULL, NULL, NULL);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
|
||||
/* This should be a no-op. */
|
||||
uv_fs_req_cleanup(NULL);
|
||||
|
||||
@ -4073,3 +4109,24 @@ TEST_IMPL(fs_invalid_mkdir_name) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_IMPL(fs_statfs) {
|
||||
uv_fs_t req;
|
||||
int r;
|
||||
|
||||
loop = uv_default_loop();
|
||||
|
||||
/* Test the synchronous version. */
|
||||
r = uv_fs_statfs(NULL, &req, ".", NULL);
|
||||
ASSERT(r == 0);
|
||||
statfs_cb(&req);
|
||||
ASSERT(statfs_cb_count == 1);
|
||||
|
||||
/* Test the asynchronous version. */
|
||||
r = uv_fs_statfs(loop, &req, ".", statfs_cb);
|
||||
ASSERT(r == 0);
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
ASSERT(statfs_cb_count == 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -329,6 +329,7 @@ TEST_DECLARE (fs_fd_hash)
|
||||
TEST_DECLARE (fs_utime)
|
||||
TEST_DECLARE (fs_futime)
|
||||
TEST_DECLARE (fs_file_open_append)
|
||||
TEST_DECLARE (fs_statfs)
|
||||
TEST_DECLARE (fs_stat_missing_path)
|
||||
TEST_DECLARE (fs_read_bufs)
|
||||
TEST_DECLARE (fs_read_file_eof)
|
||||
@ -924,6 +925,7 @@ TASK_LIST_START
|
||||
#if defined(_WIN32) && !defined(USING_UV_SHARED)
|
||||
TEST_ENTRY (fs_fd_hash)
|
||||
#endif
|
||||
TEST_ENTRY (fs_statfs)
|
||||
TEST_ENTRY (fs_stat_missing_path)
|
||||
TEST_ENTRY (fs_read_bufs)
|
||||
TEST_ENTRY (fs_read_file_eof)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user