diff --git a/include/libnfs-private.h b/include/libnfs-private.h index 3d8a233..e906636 100644 --- a/include/libnfs-private.h +++ b/include/libnfs-private.h @@ -463,6 +463,8 @@ int nfs3_stat64_async(struct nfs_context *nfs, const char *path, int no_follow, nfs_cb cb, void *private_data); int nfs3_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data); +int nfs3_statvfs64_async(struct nfs_context *nfs, const char *path, nfs_cb cb, + void *private_data); int nfs3_symlink_async(struct nfs_context *nfs, const char *oldpath, const char *newpath, nfs_cb cb, void *private_data); int nfs3_truncate_async(struct nfs_context *nfs, const char *path, @@ -540,6 +542,8 @@ int nfs4_stat64_async(struct nfs_context *nfs, const char *path, int no_follow, nfs_cb cb, void *private_data); int nfs4_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data); +int nfs4_statvfs64_async(struct nfs_context *nfs, const char *path, nfs_cb cb, + void *private_data); int nfs4_symlink_async(struct nfs_context *nfs, const char *oldpath, const char *newpath, nfs_cb cb, void *private_data); int nfs4_truncate_async(struct nfs_context *nfs, const char *path, diff --git a/include/nfsc/libnfs.h b/include/nfsc/libnfs.h index e9d2821..e82681e 100755 --- a/include/nfsc/libnfs.h +++ b/include/nfsc/libnfs.h @@ -1292,8 +1292,23 @@ EXTERN void nfs_getcwd(struct nfs_context *nfs, const char **cwd); /* * STATVFS() */ +struct nfs_statvfs_64 { + uint64_t f_bsize; + uint64_t f_frsize; + uint64_t f_blocks; + uint64_t f_bfree; + uint64_t f_bavail; + uint64_t f_files; + uint64_t f_ffree; + uint64_t f_favail; + uint64_t f_fsid; + uint64_t f_flag; + uint64_t f_namemax; +}; /* * Async statvfs() + * This function is deprecated. Use nfs_statvfs64_async() instead. + * * Function returns * 0 : The command was queued successfully. The callback will be invoked once * the command completes. @@ -1311,13 +1326,40 @@ EXTERN int nfs_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data); /* * Sync statvfs() + * This function is deprecated. Use nfs_statvfs64() instead. + * * Function returns * 0 : The operation was successful. * -errno : The command failed. */ EXTERN int nfs_statvfs(struct nfs_context *nfs, const char *path, struct statvfs *svfs); - +/* + * Async statvfs64() + * + * Function returns + * 0 : The command was queued successfully. The callback will be invoked once + * the command completes. + * <0 : An error occured when trying to queue the command. + * The callback will not be invoked. + * + * When the callback is invoked, status indicates the result: + * 0 : Success. + * data is struct nfs_statvfs_64 * + * -errno : An error occured. + * data is the error string. + */ +EXTERN int nfs_statvfs64_async(struct nfs_context *nfs, const char *path, + nfs_cb cb, void *private_data); +/* + * Sync statvfs64() + * + * Function returns + * 0 : The operation was successful. + * -errno : The command failed. + */ +EXTERN int nfs_statvfs64(struct nfs_context *nfs, const char *path, + struct nfs_statvfs_64 *svfs); /* * READLINK() @@ -1338,7 +1380,6 @@ EXTERN int nfs_statvfs(struct nfs_context *nfs, const char *path, * -errno : An error occured. * data is the error string. */ -struct statvfs; EXTERN int nfs_readlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data); /* diff --git a/lib/libnfs-sync.c b/lib/libnfs-sync.c index 13413c2..4947eba 100644 --- a/lib/libnfs-sync.c +++ b/lib/libnfs-sync.c @@ -1166,6 +1166,46 @@ nfs_statvfs(struct nfs_context *nfs, const char *path, struct statvfs *svfs) return cb_data.status; } +/* + * statvfs64() + */ +static void +statvfs64_cb(int status, struct nfs_context *nfs, void *data, + void *private_data) +{ + struct sync_cb_data *cb_data = private_data; + + cb_data->is_finished = 1; + cb_data->status = status; + + if (status < 0) { + nfs_set_error(nfs, "statvfs64 call failed with \"%s\"", + (char *)data); + return; + } + + memcpy(cb_data->return_data, data, sizeof(struct nfs_statvfs_64)); +} + +int +nfs_statvfs64(struct nfs_context *nfs, const char *path, + struct nfs_statvfs_64 *svfs) +{ + struct sync_cb_data cb_data; + + cb_data.is_finished = 0; + cb_data.return_data = svfs; + + if (nfs_statvfs64_async(nfs, path, statvfs64_cb, &cb_data) != 0) { + nfs_set_error(nfs, "nfs_statvfs64_async failed. %s", + nfs_get_error(nfs)); + return -1; + } + + wait_for_nfs_reply(nfs, &cb_data); + + return cb_data.status; +} /* * readlink() diff --git a/lib/libnfs-win32.def b/lib/libnfs-win32.def index 8d49892..c00ec43 100644 --- a/lib/libnfs-win32.def +++ b/lib/libnfs-win32.def @@ -95,6 +95,8 @@ nfs_stat64 nfs_stat64_async nfs_statvfs nfs_statvfs_async +nfs_statvfs64 +nfs_statvfs64_async nfs_symlink nfs_symlink_async nfs_truncate diff --git a/lib/libnfs.c b/lib/libnfs.c index 85a0bfd..a32aff1 100755 --- a/lib/libnfs.c +++ b/lib/libnfs.c @@ -1471,6 +1471,22 @@ nfs_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb, } } +int +nfs_statvfs64_async(struct nfs_context *nfs, const char *path, nfs_cb cb, + void *private_data) +{ + switch (nfs->version) { + case NFS_V3: + return nfs3_statvfs64_async(nfs, path, cb, private_data); + case NFS_V4: + return nfs4_statvfs64_async(nfs, path, cb, private_data); + default: + nfs_set_error(nfs, "%s does not support NFSv%d", + __FUNCTION__, nfs->version); + return -1; + } +} + int nfs_readlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data) diff --git a/lib/nfs_v3.c b/lib/nfs_v3.c index 984cbfb..74cf358 100644 --- a/lib/nfs_v3.c +++ b/lib/nfs_v3.c @@ -2272,6 +2272,7 @@ nfs3_statvfs_1_cb(struct rpc_context *rpc, int status, void *command_data, struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; struct statvfs svfs; + struct nfs_statvfs_64 svfs64; assert(rpc->magic == RPC_CONTEXT_MAGIC); @@ -2292,21 +2293,39 @@ nfs3_statvfs_1_cb(struct rpc_context *rpc, int status, void *command_data, return; } - svfs.f_bsize = NFS_BLKSIZE; - svfs.f_frsize = NFS_BLKSIZE; - svfs.f_blocks = res->FSSTAT3res_u.resok.tbytes/NFS_BLKSIZE; - svfs.f_bfree = res->FSSTAT3res_u.resok.fbytes/NFS_BLKSIZE; - svfs.f_bavail = res->FSSTAT3res_u.resok.abytes/NFS_BLKSIZE; - svfs.f_files = (uint32_t)res->FSSTAT3res_u.resok.tfiles; - svfs.f_ffree = (uint32_t)res->FSSTAT3res_u.resok.ffiles; + if (data->continue_int == 0) { + /* statvfs */ + svfs.f_bsize = NFS_BLKSIZE; + svfs.f_frsize = NFS_BLKSIZE; + svfs.f_blocks = res->FSSTAT3res_u.resok.tbytes/NFS_BLKSIZE; + svfs.f_bfree = res->FSSTAT3res_u.resok.fbytes/NFS_BLKSIZE; + svfs.f_bavail = res->FSSTAT3res_u.resok.abytes/NFS_BLKSIZE; + svfs.f_files = (uint32_t)res->FSSTAT3res_u.resok.tfiles; + svfs.f_ffree = (uint32_t)res->FSSTAT3res_u.resok.ffiles; #if !defined(__ANDROID__) - svfs.f_favail = (uint32_t)res->FSSTAT3res_u.resok.afiles; - svfs.f_fsid = 0; - svfs.f_flag = 0; - svfs.f_namemax = 256; + svfs.f_favail = (uint32_t)res->FSSTAT3res_u.resok.afiles; + svfs.f_fsid = 0; + svfs.f_flag = 0; + svfs.f_namemax = 256; #endif + data->cb(0, nfs, &svfs, data->private_data); + } else { + /* statvfs64 */ + svfs64.f_bsize = NFS_BLKSIZE; + svfs64.f_frsize = NFS_BLKSIZE; + svfs64.f_blocks = res->FSSTAT3res_u.resok.tbytes/NFS_BLKSIZE; + svfs64.f_bfree = res->FSSTAT3res_u.resok.fbytes/NFS_BLKSIZE; + svfs64.f_bavail = res->FSSTAT3res_u.resok.abytes/NFS_BLKSIZE; + svfs64.f_files = res->FSSTAT3res_u.resok.tfiles; + svfs64.f_ffree = res->FSSTAT3res_u.resok.ffiles; + svfs64.f_favail = res->FSSTAT3res_u.resok.afiles; + svfs64.f_fsid = 0; + svfs64.f_flag = 0; + svfs64.f_namemax = 256; + + data->cb(0, nfs, &svfs64, data->private_data); + } - data->cb(0, nfs, &svfs, data->private_data); free_nfs_cb_data(data); } @@ -2344,6 +2363,19 @@ nfs3_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb, return 0; } +int +nfs3_statvfs64_async(struct nfs_context *nfs, const char *path, nfs_cb cb, + void *private_data) +{ + if (nfs3_lookuppath_async(nfs, path, 0, cb, private_data, + nfs3_statvfs_continue_internal, + NULL, NULL, 1) != 0) { + return -1; + } + + return 0; +} + static void nfs3_lseek_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) diff --git a/lib/nfs_v4.c b/lib/nfs_v4.c index 9c886ef..2829703 100644 --- a/lib/nfs_v4.c +++ b/lib/nfs_v4.c @@ -141,7 +141,8 @@ struct nfs4_cb_data { /* Do not follow symlinks for the final component on a lookup. * I.e. stat vs lstat */ -#define LOOKUP_FLAG_NO_FOLLOW 0x0001 +#define LOOKUP_FLAG_NO_FOLLOW 0x0001 +#define LOOKUP_FLAG_IS_STATVFS64 0x0002 int flags; /* Internal callback for open-with-continuation use */ @@ -4389,6 +4390,83 @@ nfs_parse_statvfs(struct nfs_context *nfs, struct nfs4_cb_data *data, return 0; } +static int +nfs_parse_statvfs64(struct nfs_context *nfs, struct nfs4_cb_data *data, + struct nfs_statvfs_64 *svfs64, const char *buf, int len) +{ + uint64_t u64; + uint32_t u32; + + svfs64->f_bsize = NFS_BLKSIZE; + svfs64->f_frsize = NFS_BLKSIZE; + svfs64->f_flag = 0; + + /* FSID + * NFSv4 FSID is 2*64 bit but statvfs fsid is just an + * unsigmed long. Mix the 2*64 bits and hope for the best. + */ + CHECK_GETATTR_BUF_SPACE(len, 16); + memcpy(&u64, buf, 8); + svfs64->f_fsid = nfs_ntoh64(u64); + buf += 8; + len -= 8; + memcpy(&u64, buf, 8); + svfs64->f_fsid |= nfs_ntoh64(u64); + buf += 8; + len -= 8; + + /* Files Avail */ + CHECK_GETATTR_BUF_SPACE(len, 8); + memcpy(&u64, buf, 8); + svfs64->f_favail = nfs_ntoh64(u64); + buf += 8; + len -= 8; + + /* Files Free */ + CHECK_GETATTR_BUF_SPACE(len, 8); + memcpy(&u64, buf, 8); + svfs64->f_ffree = nfs_ntoh64(u64); + buf += 8; + len -= 8; + + /* Files Total */ + CHECK_GETATTR_BUF_SPACE(len, 8); + memcpy(&u64, buf, 8); + svfs64->f_files = nfs_ntoh64(u64); + buf += 8; + len -= 8; + + /* Max Name */ + CHECK_GETATTR_BUF_SPACE(len, 4); + memcpy(&u32, buf, 4); + svfs64->f_namemax = ntohl(u32); + buf += 4; + len -= 4; + + /* Space Avail */ + CHECK_GETATTR_BUF_SPACE(len, 8); + memcpy(&u64, buf, 8); + svfs64->f_bavail = nfs_ntoh64(u64) / svfs64->f_frsize; + buf += 8; + len -= 8; + + /* Space Free */ + CHECK_GETATTR_BUF_SPACE(len, 8); + memcpy(&u64, buf, 8); + svfs64->f_bfree = nfs_ntoh64(u64) / svfs64->f_frsize; + buf += 8; + len -= 8; + + /* Space Total */ + CHECK_GETATTR_BUF_SPACE(len, 8); + memcpy(&u64, buf, 8); + svfs64->f_blocks = nfs_ntoh64(u64) / svfs64->f_frsize; + buf += 8; + len -= 8; + + return 0; +} + static void nfs4_statvfs_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) @@ -4398,6 +4476,7 @@ nfs4_statvfs_cb(struct rpc_context *rpc, int status, void *command_data, COMPOUND4res *res = command_data; GETATTR4resok *garesok; struct statvfs svfs; + struct nfs_statvfs_64 svfs64; int i; assert(rpc->magic == RPC_CONTEXT_MAGIC); @@ -4413,21 +4492,37 @@ nfs4_statvfs_cb(struct rpc_context *rpc, int status, void *command_data, } garesok = &res->resarray.resarray_val[i].nfs_resop4_u.opgetattr.GETATTR4res_u.resok4; - if (nfs_parse_statvfs(nfs, data, &svfs, + if (data->flags & LOOKUP_FLAG_IS_STATVFS64) { + /* statvfs64 */ + if (nfs_parse_statvfs64(nfs, data, &svfs64, garesok->obj_attributes.attr_vals.attrlist4_val, garesok->obj_attributes.attr_vals.attrlist4_len) < 0) { - data->cb(-EINVAL, nfs, nfs_get_error(nfs), data->private_data); - free_nfs4_cb_data(data); - return; + data->cb(-EINVAL, nfs, nfs_get_error(nfs), data->private_data); + free_nfs4_cb_data(data); + return; + } + + data->cb(0, nfs, &svfs64, data->private_data); + } else { + /* statvfs */ + if (nfs_parse_statvfs(nfs, data, &svfs, + garesok->obj_attributes.attr_vals.attrlist4_val, + garesok->obj_attributes.attr_vals.attrlist4_len) < 0) { + data->cb(-EINVAL, nfs, nfs_get_error(nfs), data->private_data); + free_nfs4_cb_data(data); + return; + } + + data->cb(0, nfs, &svfs, data->private_data); } - data->cb(0, nfs, &svfs, data->private_data); free_nfs4_cb_data(data); } -int -nfs4_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb, - void *private_data) +static int +nfs4_statvfs_async_internal(struct nfs_context *nfs, const char *path, + int is_statvfs64, + nfs_cb cb, void *private_data) { struct nfs4_cb_data *data; COMPOUND4args args; @@ -4445,6 +4540,9 @@ nfs4_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb, data->nfs = nfs; data->cb = cb; data->private_data = private_data; + if (is_statvfs64) { + data->flags |= LOOKUP_FLAG_IS_STATVFS64; + } fh.fh.len = nfs->rootfh.len; fh.fh.val = nfs->rootfh.val; @@ -4465,6 +4563,22 @@ nfs4_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb, return 0; } +int +nfs4_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb, + void *private_data) +{ + return nfs4_statvfs_async_internal(nfs, path, 0, + cb, private_data); +} + +int +nfs4_statvfs64_async(struct nfs_context *nfs, const char *path, nfs_cb cb, + void *private_data) +{ + return nfs4_statvfs_async_internal(nfs, path, 1, + cb, private_data); +} + static void nfs4_chmod_open_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) diff --git a/tests/prog_statvfs.c b/tests/prog_statvfs.c index 2f3cc34..dbe977a 100644 --- a/tests/prog_statvfs.c +++ b/tests/prog_statvfs.c @@ -40,7 +40,7 @@ int main(int argc, char *argv[]) { struct nfs_context *nfs = NULL; struct nfs_url *url = NULL; - struct statvfs svfs; + struct nfs_statvfs_64 svfs; int ret = 0; if (argc != 4) { @@ -75,23 +75,23 @@ int main(int argc, char *argv[]) goto finished; } - if (nfs_statvfs(nfs, argv[3], &svfs)) { - fprintf(stderr, "statvfs failed : %s\n", + if (nfs_statvfs64(nfs, argv[3], &svfs)) { + fprintf(stderr, "statvfs64 failed : %s\n", nfs_get_error(nfs)); ret = 1; goto finished; } - printf("bsize:%lu\n", svfs.f_bsize); - printf("frsize:%lu\n", svfs.f_frsize); - printf("blocks:%lu\n", svfs.f_blocks); - printf("bfree:%lu\n", svfs.f_bfree); - printf("bavail:%lu\n", svfs.f_bavail); - printf("files:%lu\n", svfs.f_files); - printf("ffree:%lu\n", svfs.f_ffree); - printf("favail:%lu\n", svfs.f_favail); - printf("fsid:%lu\n", svfs.f_fsid); - printf("namemax:%lu\n", svfs.f_namemax); + printf("bsize:%" PRIu64 "\n", svfs.f_bsize); + printf("frsize:%" PRIu64 "\n", svfs.f_frsize); + printf("blocks:%" PRIu64 "\n", svfs.f_blocks); + printf("bfree:%" PRIu64 "\n", svfs.f_bfree); + printf("bavail:%" PRIu64 "\n", svfs.f_bavail); + printf("files:%" PRIu64 "\n", svfs.f_files); + printf("ffree:%" PRIu64 "\n", svfs.f_ffree); + printf("favail:%" PRIu64 "\n", svfs.f_favail); + printf("fsid:%" PRIu64 "\n", svfs.f_fsid); + printf("namemax:%" PRIu64 "\n", svfs.f_namemax); finished: nfs_destroy_url(url);