Net-LibNFS
view release on metacpan or search on metacpan
libnfs/lib/nfs_v3.c view on Meta::CPAN
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#else
#define PRIu64 "llu"
#endif
#ifdef HAVE_UTIME_H
#include <utime.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
#ifdef HAVE_SYS_STATVFS_H
#include <sys/statvfs.h>
#endif
#if defined(__ANDROID__) && !defined(HAVE_SYS_STATVFS_H)
#define statvfs statfs
#endif
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
#endif
#ifdef HAVE_SYS_SYSMACROS_H
#include <sys/sysmacros.h>
#endif
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "libnfs-zdr.h"
#include "slist.h"
#include "libnfs.h"
#include "libnfs-raw.h"
#include "libnfs-raw-mount.h"
#include "libnfs-private.h"
static dev_t
specdata3_to_rdev(struct specdata3 *rdev)
{
#ifdef makedev
return makedev(rdev->specdata1, rdev->specdata2);
#else
return 0;
#endif
}
struct mount_attr_cb {
int wait_count;
struct nfs_cb_data *data;
};
struct mount_attr_item_cb {
struct mount_attr_cb *ma;
struct nested_mounts *mnt;
};
struct nfs_mcb_data {
struct nfs_cb_data *data;
uint64_t offset;
size_t count;
};
static int
check_nfs3_error(struct nfs_context *nfs, int status,
struct nfs_cb_data *data, void *command_data)
{
if (status == RPC_STATUS_ERROR) {
data->cb(-EFAULT, nfs, command_data, data->private_data);
return 1;
}
if (status == RPC_STATUS_CANCEL) {
data->cb(-EINTR, nfs, "Command was cancelled",
data->private_data);
return 1;
}
if (status == RPC_STATUS_TIMEOUT) {
data->cb(-EINTR, nfs, "Command timed out",
data->private_data);
return 1;
}
return 0;
}
static int nfs3_lookup_path_async_internal(struct nfs_context *nfs,
struct nfs_attr *attr,
struct nfs_cb_data *data,
struct nfs_fh *fh);
/*
* Functions to first look up a path, component by component, and then finally
* call a specific function once the filehandle for the final component is
* found.
*/
static void
nfs3_lookup_path_2_cb(struct rpc_context *rpc, int status, void *command_data,
void *private_data)
{
struct nfs_cb_data *data = private_data;
struct nfs_context *nfs = data->nfs;
READLINK3res *res;
libnfs/lib/nfs_v3.c view on Meta::CPAN
return;
}
if (!newpath)
goto nomem;
} else {
/* Handle relative paths, both the case where the current
* component is an intermediate component and when it is the
* final component. */
if (data->path[0]) {
/* Since path points to a component and saved_path
* always starts with '/', path[-1] is valid. */
data->path[-1] = '\0';
newpath = malloc(strlen(data->saved_path) +
strlen(path) + strlen(data->path) + 6);
if (!newpath)
goto nomem;
sprintf(newpath, "%s/../%s/%s", data->saved_path, path,
data->path);
} else {
newpath = malloc(strlen(data->saved_path) +
strlen(path) + 5);
if (!newpath)
goto nomem;
sprintf(newpath, "%s/../%s", data->saved_path, path);
}
}
free(data->saved_path);
data->saved_path = newpath;
if (nfs_normalize_path(nfs, data->saved_path) != 0) {
data->cb(-ENOENT, nfs, "Symbolic link resolves to invalid "
"path", data->private_data);
free_nfs_cb_data(data);
return;
}
data->path = data->saved_path;
nfs3_lookup_path_async_internal(nfs, NULL, data, &nfs->nfsi->rootfh);
return;
nomem:
data->cb(-ENOMEM, nfs, "Failed to allocate memory for path",
data->private_data);
free_nfs_cb_data(data);
}
static void
fattr3_to_nfs_attr(struct nfs_attr *attr, fattr3 *fa3)
{
attr->type = fa3->type;
attr->mode = fa3->mode;
attr->uid = fa3->uid;
attr->gid = fa3->gid;
attr->nlink = fa3->nlink;
attr->size = fa3->size;
attr->used = fa3->used;
attr->fsid = fa3->fsid;
attr->rdev.specdata1 = fa3->rdev.specdata1;
attr->rdev.specdata2 = fa3->rdev.specdata2;
attr->atime.seconds = fa3->atime.seconds;
attr->atime.nseconds = fa3->atime.nseconds;
attr->mtime.seconds = fa3->mtime.seconds;
attr->mtime.nseconds = fa3->mtime.nseconds;
attr->ctime.seconds = fa3->ctime.seconds;
attr->ctime.nseconds = fa3->ctime.nseconds;
}
static void
nfs3_lookup_path_1_cb(struct rpc_context *rpc, int status, void *command_data,
void *private_data)
{
struct nfs_cb_data *data = private_data;
struct nfs_context *nfs = data->nfs;
LOOKUP3res *res;
struct nfs_attr attr;
struct nfs_fh fh;
assert(rpc->magic == RPC_CONTEXT_MAGIC);
if (check_nfs3_error(nfs, status, data, command_data)) {
free_nfs_cb_data(data);
return;
}
res = command_data;
if (res->status != NFS3_OK) {
nfs_set_error(nfs, "NFS: Lookup of %s failed with "
"%s(%d)", data->saved_path,
nfsstat3_to_str(res->status),
nfsstat3_to_errno(res->status));
data->cb(nfsstat3_to_errno(res->status), nfs,
nfs_get_error(nfs), data->private_data);
free_nfs_cb_data(data);
return;
}
memset(&attr, 0, sizeof(attr));
if (res->LOOKUP3res_u.resok.obj_attributes.attributes_follow) {
fattr3_to_nfs_attr(&attr, &res->LOOKUP3res_u.resok.obj_attributes.post_op_attr_u.attributes);
}
/* This function will always invoke the callback and cleanup
* for failures. So no need to check the return value.
*/
fh.val = res->LOOKUP3res_u.resok.object.data.data_val;
fh.len = res->LOOKUP3res_u.resok.object.data.data_len;
nfs3_lookup_path_async_internal(nfs, &attr, data, &fh);
}
static int
nfs3_lookup_path_async_internal(struct nfs_context *nfs, struct nfs_attr *attr,
struct nfs_cb_data *data, struct nfs_fh *fh)
{
char *path, *slash;
LOOKUP3args args;
while (*data->path == '/') {
data->path++;
}
libnfs/lib/nfs_v3.c view on Meta::CPAN
LOOKUP3res *res = command_data;
struct rdpe_lookup_cb_data *rdpe_lookup_cb_data = private_data;
struct rdpe_cb_data *rdpe_cb_data = rdpe_lookup_cb_data->rdpe_cb_data;
struct nfs_cb_data *data = rdpe_cb_data->data;
struct nfsdir *nfsdir = data->continue_data;
struct nfs_context *nfs = data->nfs;
struct nfsdirent *nfsdirent = rdpe_lookup_cb_data->nfsdirent;
assert(rpc->magic == RPC_CONTEXT_MAGIC);
free(rdpe_lookup_cb_data);
rdpe_cb_data->getattrcount--;
if (status == RPC_STATUS_ERROR) {
nfs_set_error(nfs, "LOOKUP during READDIRPLUS emulation "
"failed with RPC_STATUS_ERROR");
rdpe_cb_data->status = RPC_STATUS_ERROR;
}
if (status == RPC_STATUS_CANCEL) {
nfs_set_error(nfs, "LOOKUP during READDIRPLUS emulation "
"failed with RPC_STATUS_CANCEL");
rdpe_cb_data->status = RPC_STATUS_CANCEL;
}
if (status == RPC_STATUS_TIMEOUT) {
nfs_set_error(nfs, "LOOKUP during READDIRPLUS emulation "
"timed out");
rdpe_cb_data->status = RPC_STATUS_CANCEL;
}
if (status == RPC_STATUS_SUCCESS && res->status == NFS3_OK) {
if (res->LOOKUP3res_u.resok.obj_attributes.attributes_follow) {
fattr3 *attributes = &res->LOOKUP3res_u.resok.obj_attributes.post_op_attr_u.attributes;
nfsdirent->type = attributes->type;
nfsdirent->mode = attributes->mode;
switch (nfsdirent->type) {
case NF3REG: nfsdirent->mode |= S_IFREG; break;
case NF3DIR: nfsdirent->mode |= S_IFDIR; break;
case NF3BLK: nfsdirent->mode |= S_IFBLK; break;
case NF3CHR: nfsdirent->mode |= S_IFCHR; break;
case NF3LNK: nfsdirent->mode |= S_IFLNK; break;
case NF3SOCK: nfsdirent->mode |= S_IFSOCK; break;
case NF3FIFO: nfsdirent->mode |= S_IFIFO; break;
};
nfsdirent->size = attributes->size;
nfsdirent->atime.tv_sec = attributes->atime.seconds;
nfsdirent->atime.tv_usec = attributes->atime.nseconds/1000;
nfsdirent->atime_nsec = attributes->atime.nseconds;
nfsdirent->mtime.tv_sec = attributes->mtime.seconds;
nfsdirent->mtime.tv_usec = attributes->mtime.nseconds/1000;
nfsdirent->mtime_nsec = attributes->mtime.nseconds;
nfsdirent->ctime.tv_sec = attributes->ctime.seconds;
nfsdirent->ctime.tv_usec = attributes->ctime.nseconds/1000;
nfsdirent->ctime_nsec = attributes->ctime.nseconds;
nfsdirent->uid = attributes->uid;
nfsdirent->gid = attributes->gid;
nfsdirent->nlink = attributes->nlink;
nfsdirent->dev = attributes->fsid;
nfsdirent->rdev = specdata3_to_rdev(&attributes->rdev);
nfsdirent->blksize = NFS_BLKSIZE;
nfsdirent->blocks = (attributes->used + 512 - 1) / 512;
nfsdirent->used = attributes->used;
}
}
if (rdpe_cb_data->getattrcount == 0) {
if (rdpe_cb_data->status != RPC_STATUS_SUCCESS) {
nfs_set_error(nfs, "READDIRPLUS emulation "
"failed: %s", rpc_get_error(rpc));
data->cb(-ENOMEM, nfs, nfs_get_error(nfs),
data->private_data);
nfs_free_nfsdir(nfsdir);
} else {
data->cb(0, nfs, nfsdir, data->private_data);
}
free(rdpe_cb_data);
data->continue_data = NULL;
free_nfs_cb_data(data);
}
}
static int
lookup_missing_attributes(struct nfs_context *nfs,
struct nfsdir *nfsdir,
struct nfs_cb_data *data)
{
struct rdpe_cb_data *rdpe_cb_data = NULL;
struct nfsdirent *nfsdirent;
for (nfsdirent = nfsdir->entries;
nfsdirent;
nfsdirent = nfsdirent->next) {
struct rdpe_lookup_cb_data *rdpe_lookup_cb_data;
LOOKUP3args args;
/* If type == 0 we assume it is a case of the server not
* giving us the attributes for this entry during READIR[PLUS]
* so we fallback to LOOKUP3
*/
if (nfsdirent->type != 0) {
continue;
}
if (rdpe_cb_data == NULL) {
rdpe_cb_data = malloc(sizeof(struct rdpe_cb_data));
rdpe_cb_data->getattrcount = 0;
rdpe_cb_data->status = RPC_STATUS_SUCCESS;
rdpe_cb_data->data = data;
}
rdpe_lookup_cb_data = malloc(sizeof(struct rdpe_lookup_cb_data));
rdpe_lookup_cb_data->rdpe_cb_data = rdpe_cb_data;
rdpe_lookup_cb_data->nfsdirent = nfsdirent;
memset(&args, 0, sizeof(LOOKUP3args));
args.what.dir.data.data_len = data->fh.len;
args.what.dir.data.data_val = data->fh.val;
args.what.name = nfsdirent->name;
if (rpc_nfs3_lookup_async(nfs->rpc, nfs3_opendir_3_cb, &args,
libnfs/lib/nfs_v3.c view on Meta::CPAN
}
entry =res->READDIRPLUS3res_u.resok.reply.entries;
while (entry != NULL) {
struct nfsdirent *nfsdirent;
struct nfs_attr attr;
int has_attr = 0;
memset(&attr, 0, sizeof(attr));
nfsdirent = malloc(sizeof(struct nfsdirent));
if (nfsdirent == NULL) {
data->cb(-ENOMEM, nfs, "Failed to allocate dirent",
data->private_data);
nfs_free_nfsdir(nfsdir);
data->continue_data = NULL;
free_nfs_cb_data(data);
return;
}
memset(nfsdirent, 0, sizeof(struct nfsdirent));
nfsdirent->name = strdup(entry->name);
if (nfsdirent->name == NULL) {
data->cb(-ENOMEM, nfs, "Failed to allocate "
"dirent->name", data->private_data);
free(nfsdirent);
nfs_free_nfsdir(nfsdir);
data->continue_data = NULL;
free_nfs_cb_data(data);
return;
}
nfsdirent->inode = entry->fileid;
if (entry->name_attributes.attributes_follow) {
fattr3_to_nfs_attr(&attr, &entry->name_attributes.post_op_attr_u.attributes);
has_attr = 1;
}
if (!has_attr) {
struct nested_mounts *mnt;
int splen = strlen(data->saved_path);
/* A single '/' is a special case, treat it as
* zero-length below. */
if (splen == 1)
splen = 0;
/* No name attributes. Is it a nested mount then?*/
for(mnt = nfs->nfsi->nested_mounts; mnt; mnt = mnt->next) {
if (strncmp(data->saved_path, mnt->path, splen))
continue;
if (mnt->path[splen] != '/')
continue;
if (strcmp(mnt->path + splen + 1, entry->name))
continue;
attr = mnt->attr;
has_attr = 1;
break;
}
}
if (has_attr) {
struct specdata3 sd3 = { attr.rdev.specdata1,
attr.rdev.specdata2 };
nfsdirent->type = attr.type;
nfsdirent->mode = attr.mode;
switch (nfsdirent->type) {
case NF3REG: nfsdirent->mode |= S_IFREG; break;
case NF3DIR: nfsdirent->mode |= S_IFDIR; break;
case NF3BLK: nfsdirent->mode |= S_IFBLK; break;
case NF3CHR: nfsdirent->mode |= S_IFCHR; break;
case NF3LNK: nfsdirent->mode |= S_IFLNK; break;
case NF3SOCK: nfsdirent->mode |= S_IFSOCK; break;
case NF3FIFO: nfsdirent->mode |= S_IFIFO; break;
};
nfsdirent->size = attr.size;
nfsdirent->atime.tv_sec = attr.atime.seconds;
nfsdirent->atime.tv_usec = attr.atime.nseconds/1000;
nfsdirent->atime_nsec = attr.atime.nseconds;
nfsdirent->mtime.tv_sec = attr.mtime.seconds;
nfsdirent->mtime.tv_usec = attr.mtime.nseconds/1000;
nfsdirent->mtime_nsec = attr.mtime.nseconds;
nfsdirent->ctime.tv_sec = attr.ctime.seconds;
nfsdirent->ctime.tv_usec = attr.ctime.nseconds/1000;
nfsdirent->ctime_nsec = attr.ctime.nseconds;
nfsdirent->uid = attr.uid;
nfsdirent->gid = attr.gid;
nfsdirent->nlink = attr.nlink;
nfsdirent->dev = attr.fsid;
nfsdirent->rdev = specdata3_to_rdev(&sd3);
nfsdirent->blksize = NFS_BLKSIZE;
nfsdirent->blocks = (attr.used + 512 - 1) / 512;
nfsdirent->used = attr.used;
}
nfsdirent->next = nfsdir->entries;
nfsdir->entries = nfsdirent;
cookie = entry->cookie;
entry = entry->nextentry;
}
if (res->READDIRPLUS3res_u.resok.reply.eof == 0) {
READDIRPLUS3args args;
args.dir.data.data_len = data->fh.len;
args.dir.data.data_val = data->fh.val;
args.cookie = cookie;
memcpy(&args.cookieverf,
res->READDIRPLUS3res_u.resok.cookieverf,
sizeof(cookieverf3));
args.dircount = nfs->nfsi->readdir_dircount;
args.maxcount = nfs->nfsi->readdir_maxcount;
if (rpc_nfs3_readdirplus_async(nfs->rpc, nfs3_opendir_cb,
&args, data) != 0) {
nfs_set_error(nfs, "RPC error: Failed to send "
"READDIRPLUS call for %s", data->path);
data->cb(-ENOMEM, nfs, nfs_get_error(nfs),
data->private_data);
nfs_free_nfsdir(nfsdir);
data->continue_data = NULL;
free_nfs_cb_data(data);
return;
}
return;
}
if (res->READDIRPLUS3res_u.resok.dir_attributes.attributes_follow) {
fattr3_to_nfs_attr(&nfsdir->attr, &res->READDIRPLUS3res_u.resok.dir_attributes.post_op_attr_u.attributes);
}
/* steal the dirhandle */
nfsdir->current = nfsdir->entries;
if (lookup_missing_attributes(nfs, nfsdir, data) == 0) {
data->cb(0, nfs, nfsdir, data->private_data);
/* We can not free data->continue_data here */
data->continue_data = NULL;
free_nfs_cb_data(data);
return;
}
}
static int
nfs3_opendir_continue_internal(struct nfs_context *nfs,
struct nfs_attr *attr,
struct nfs_cb_data *data)
{
READDIRPLUS3args args;
libnfs/lib/nfs_v3.c view on Meta::CPAN
free(data->path);
free(data);
}
static void
nfs3_mknod_cb(struct rpc_context *rpc, int status, void *command_data,
void *private_data)
{
MKNOD3res *res;
struct nfs_cb_data *data = private_data;
struct nfs_context *nfs = data->nfs;
char *str = data->continue_data;
assert(rpc->magic == RPC_CONTEXT_MAGIC);
str = &str[strlen(str) + 1];
if (check_nfs3_error(nfs, status, data, command_data)) {
free_nfs_cb_data(data);
return;
}
res = command_data;
if (res->status != NFS3_OK) {
nfs_set_error(nfs, "NFS: MKNOD of %s/%s failed with "
"%s(%d)", data->saved_path, str,
nfsstat3_to_str(res->status),
nfsstat3_to_errno(res->status));
data->cb(nfsstat3_to_errno(res->status), nfs,
nfs_get_error(nfs), data->private_data);
free_nfs_cb_data(data);
return;
}
nfs_dircache_drop(nfs, &data->fh);
data->cb(0, nfs, NULL, data->private_data);
free_nfs_cb_data(data);
}
static int
nfs3_mknod_continue_internal(struct nfs_context *nfs,
struct nfs_attr *attr _U_,
struct nfs_cb_data *data)
{
struct mknod_cb_data *cb_data = data->continue_data;
char *str = cb_data->path;
MKNOD3args args;
memset(&args, 0, sizeof(args));
str = &str[strlen(str) + 1];
args.where.dir.data.data_len = data->fh.len;
args.where.dir.data.data_val = data->fh.val;
args.where.name = str;
switch (cb_data->mode & S_IFMT) {
case S_IFCHR:
args.what.type = NF3CHR;
args.what.mknoddata3_u.chr_device.dev_attributes.mode.set_it = 1;
args.what.mknoddata3_u.chr_device.dev_attributes.mode.set_mode3_u.mode = cb_data->mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
args.what.mknoddata3_u.chr_device.spec.specdata1 = cb_data->major;
args.what.mknoddata3_u.chr_device.spec.specdata2 = cb_data->minor;
break;
case S_IFBLK:
args.what.type = NF3BLK;
args.what.mknoddata3_u.blk_device.dev_attributes.mode.set_it = 1;
args.what.mknoddata3_u.blk_device.dev_attributes.mode.set_mode3_u.mode = cb_data->mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
args.what.mknoddata3_u.blk_device.spec.specdata1 = cb_data->major;
args.what.mknoddata3_u.blk_device.spec.specdata2 = cb_data->minor;
break;
case S_IFSOCK:
args.what.type = NF3SOCK;
args.what.mknoddata3_u.sock_attributes.mode.set_it = 1;
args.what.mknoddata3_u.sock_attributes.mode.set_mode3_u.mode = cb_data->mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
break;
case S_IFIFO:
args.what.type = NF3FIFO;
args.what.mknoddata3_u.pipe_attributes.mode.set_it = 1;
args.what.mknoddata3_u.pipe_attributes.mode.set_mode3_u.mode = cb_data->mode & (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
break;
default:
nfs_set_error(nfs, "Invalid file type for "
"NFS3/MKNOD call");
data->cb(-EINVAL, nfs, nfs_get_error(nfs),
data->private_data);
free_nfs_cb_data(data);
return -1;
}
if (rpc_nfs3_mknod_async(nfs->rpc, nfs3_mknod_cb, &args, data) != 0) {
data->cb(-ENOMEM, nfs, nfs_get_error(nfs),
data->private_data);
free_nfs_cb_data(data);
return -1;
}
return 0;
}
int
nfs3_mknod_async(struct nfs_context *nfs, const char *path, int mode, int dev,
nfs_cb cb, void *private_data)
{
char *ptr;
struct mknod_cb_data *cb_data;
cb_data = malloc(sizeof(struct mknod_cb_data));
if (cb_data == NULL) {
nfs_set_error(nfs, "Out of memory, failed to allocate "
"mode buffer for cb data");
return -1;
}
ptr = strrchr(path, '/');
if (ptr) {
cb_data->path = strdup(path);
if (cb_data->path == NULL) {
nfs_set_error(nfs, "Out of memory, failed to allocate "
"buffer for mknod path");
return -1;
}
ptr = strrchr(cb_data->path, '/');
*ptr = 0;
} else {
cb_data->path = malloc(strlen(path) + 2);
if (cb_data->path == NULL) {
nfs_set_error(nfs, "Out of memory, failed to allocate "
"buffer for mknod path");
return -1;
}
libnfs/lib/nfs_v3.c view on Meta::CPAN
nfs3_stat_1_cb(struct rpc_context *rpc, int status, void *command_data,
void *private_data)
{
GETATTR3res *res;
struct nfs_cb_data *data = private_data;
struct nfs_context *nfs = data->nfs;
#ifdef WIN32
struct __stat64 st;
#else
struct stat st;
#endif
assert(rpc->magic == RPC_CONTEXT_MAGIC);
if (check_nfs3_error(nfs, status, data, command_data)) {
free_nfs_cb_data(data);
return;
}
res = command_data;
if (res->status != NFS3_OK) {
nfs_set_error(nfs, "NFS: GETATTR of %s failed with "
"%s(%d)", data->saved_path,
nfsstat3_to_str(res->status),
nfsstat3_to_errno(res->status));
data->cb(nfsstat3_to_errno(res->status), nfs,
nfs_get_error(nfs), data->private_data);
free_nfs_cb_data(data);
return;
}
st.st_dev = (dev_t)res->GETATTR3res_u.resok.obj_attributes.fsid;
st.st_ino = (ino_t)res->GETATTR3res_u.resok.obj_attributes.fileid;
st.st_mode = res->GETATTR3res_u.resok.obj_attributes.mode;
switch (res->GETATTR3res_u.resok.obj_attributes.type) {
case NF3REG:
st.st_mode |= S_IFREG;
break;
case NF3DIR:
st.st_mode |= S_IFDIR;
break;
case NF3BLK:
st.st_mode |= S_IFBLK;
break;
case NF3CHR:
st.st_mode |= S_IFCHR;
break;
case NF3LNK:
st.st_mode |= S_IFLNK;
break;
case NF3SOCK:
st.st_mode |= S_IFSOCK;
break;
case NF3FIFO:
st.st_mode |= S_IFIFO;
break;
}
st.st_nlink = res->GETATTR3res_u.resok.obj_attributes.nlink;
st.st_uid = res->GETATTR3res_u.resok.obj_attributes.uid;
st.st_gid = res->GETATTR3res_u.resok.obj_attributes.gid;
st.st_rdev = specdata3_to_rdev(&res->GETATTR3res_u.resok.obj_attributes.rdev);
st.st_size = res->GETATTR3res_u.resok.obj_attributes.size;
#ifndef WIN32
st.st_blksize = NFS_BLKSIZE;
st.st_blocks = (res->GETATTR3res_u.resok.obj_attributes.used + 512 - 1) / 512;
#endif//WIN32
st.st_atime = res->GETATTR3res_u.resok.obj_attributes.atime.seconds;
st.st_mtime = res->GETATTR3res_u.resok.obj_attributes.mtime.seconds;
st.st_ctime = res->GETATTR3res_u.resok.obj_attributes.ctime.seconds;
#ifdef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
st.st_atim.tv_nsec = res->GETATTR3res_u.resok.obj_attributes.atime.nseconds;
st.st_mtim.tv_nsec = res->GETATTR3res_u.resok.obj_attributes.mtime.nseconds;
st.st_ctim.tv_nsec = res->GETATTR3res_u.resok.obj_attributes.ctime.nseconds;
#endif
data->cb(0, nfs, &st, data->private_data);
free_nfs_cb_data(data);
}
int
nfs3_fstat_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb,
void *private_data)
{
struct nfs_cb_data *data;
struct GETATTR3args args;
data = malloc(sizeof(struct nfs_cb_data));
if (data == NULL) {
nfs_set_error(nfs, "out of memory: failed to allocate "
"nfs_cb_data structure");
return -1;
}
memset(data, 0, sizeof(struct nfs_cb_data));
data->nfs = nfs;
data->cb = cb;
data->private_data = private_data;
memset(&args, 0, sizeof(GETATTR3args));
args.object.data.data_len = nfsfh->fh.len;
args.object.data.data_val = nfsfh->fh.val;
if (rpc_nfs3_getattr_async(nfs->rpc, nfs3_stat_1_cb, &args,
data) != 0) {
data->cb(-ENOMEM, nfs, nfs_get_error(nfs),
data->private_data);
free_nfs_cb_data(data);
return -1;
}
return 0;
}
static void
nfs3_stat64_1_cb(struct rpc_context *rpc, int status, void *command_data,
void *private_data)
{
GETATTR3res *res;
struct nfs_cb_data *data = private_data;
struct nfs_context *nfs = data->nfs;
struct nfs_stat_64 st;
assert(rpc->magic == RPC_CONTEXT_MAGIC);
if (check_nfs3_error(nfs, status, data, command_data)) {
free_nfs_cb_data(data);
return;
}
res = command_data;
if (res->status != NFS3_OK) {
nfs_set_error(nfs, "NFS: GETATTR of %s failed with "
"%s(%d)", data->saved_path,
nfsstat3_to_str(res->status),
nfsstat3_to_errno(res->status));
data->cb(nfsstat3_to_errno(res->status), nfs,
nfs_get_error(nfs), data->private_data);
free_nfs_cb_data(data);
return;
}
st.nfs_dev = res->GETATTR3res_u.resok.obj_attributes.fsid;
st.nfs_ino = res->GETATTR3res_u.resok.obj_attributes.fileid;
st.nfs_mode = res->GETATTR3res_u.resok.obj_attributes.mode;
switch (res->GETATTR3res_u.resok.obj_attributes.type) {
case NF3REG:
st.nfs_mode |= S_IFREG;
break;
case NF3DIR:
st.nfs_mode |= S_IFDIR;
break;
case NF3BLK:
st.nfs_mode |= S_IFBLK;
break;
case NF3CHR:
st.nfs_mode |= S_IFCHR;
break;
case NF3LNK:
st.nfs_mode |= S_IFLNK;
break;
case NF3SOCK:
st.nfs_mode |= S_IFSOCK;
break;
case NF3FIFO:
st.nfs_mode |= S_IFIFO;
break;
}
st.nfs_nlink = res->GETATTR3res_u.resok.obj_attributes.nlink;
st.nfs_uid = res->GETATTR3res_u.resok.obj_attributes.uid;
st.nfs_gid = res->GETATTR3res_u.resok.obj_attributes.gid;
st.nfs_rdev = specdata3_to_rdev(&res->GETATTR3res_u.resok.obj_attributes.rdev);
st.nfs_size = res->GETATTR3res_u.resok.obj_attributes.size;
st.nfs_blksize = NFS_BLKSIZE;
st.nfs_blocks = (res->GETATTR3res_u.resok.obj_attributes.used + 512 - 1) / 512;
st.nfs_atime = res->GETATTR3res_u.resok.obj_attributes.atime.seconds;
st.nfs_mtime = res->GETATTR3res_u.resok.obj_attributes.mtime.seconds;
st.nfs_ctime = res->GETATTR3res_u.resok.obj_attributes.ctime.seconds;
st.nfs_atime_nsec = res->GETATTR3res_u.resok.obj_attributes.atime.nseconds;
st.nfs_mtime_nsec = res->GETATTR3res_u.resok.obj_attributes.mtime.nseconds;
st.nfs_ctime_nsec = res->GETATTR3res_u.resok.obj_attributes.ctime.nseconds;
st.nfs_used = res->GETATTR3res_u.resok.obj_attributes.used;
data->cb(0, nfs, &st, data->private_data);
free_nfs_cb_data(data);
}
static int
nfs3_stat64_continue_internal(struct nfs_context *nfs,
struct nfs_attr *attr _U_,
struct nfs_cb_data *data)
{
struct GETATTR3args args;
memset(&args, 0, sizeof(GETATTR3args));
args.object.data.data_len = data->fh.len;
args.object.data.data_val = data->fh.val;
if (rpc_nfs3_getattr_async(nfs->rpc, nfs3_stat64_1_cb,
&args, data) != 0) {
data->cb(-ENOMEM, nfs, nfs_get_error(nfs),
data->private_data);
free_nfs_cb_data(data);
return -1;
}
return 0;
}
int
nfs3_stat64_async(struct nfs_context *nfs, const char *path,
int no_follow, nfs_cb cb, void *private_data)
{
if (nfs3_lookuppath_async(nfs, path, no_follow, cb, private_data,
nfs3_stat64_continue_internal,
NULL, NULL, 0) != 0) {
return -1;
}
return 0;
}
int
nfs3_fstat64_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb,
void *private_data)
{
struct nfs_cb_data *data;
struct GETATTR3args args;
data = malloc(sizeof(struct nfs_cb_data));
if (data == NULL) {
nfs_set_error(nfs, "out of memory: failed to allocate "
"nfs_cb_data structure");
libnfs/lib/nfs_v3.c view on Meta::CPAN
}
data->nfsfh->ra.fh_offset = data->max_offset;
nfs_pagecache_put(&data->nfsfh->pagecache, data->offset, data->buffer,
(size_t)(data->max_offset - data->offset));
if (data->max_offset > data->org_offset + data->org_count) {
data->max_offset = data->org_offset + data->org_count;
}
if (data->update_pos) {
data->nfsfh->offset = data->max_offset;
}
cb_err = (int)(data->max_offset - data->org_offset);
cb_data = data->buffer + (data->org_offset - data->offset);
data->cb(cb_err, nfs, cb_data, data->private_data);
free_nfs_cb_data(data);
return;
}
int
nfs3_pread_async_internal(struct nfs_context *nfs, struct nfsfh *nfsfh,
uint64_t offset, size_t count, nfs_cb cb,
void *private_data, int update_pos)
{
struct nfs_cb_data *data;
data = malloc(sizeof(struct nfs_cb_data));
if (data == NULL) {
nfs_set_error(nfs, "out of memory: failed to allocate "
"nfs_cb_data structure");
return -1;
}
memset(data, 0, sizeof(struct nfs_cb_data));
data->nfs = nfs;
data->cb = cb;
data->private_data = private_data;
data->nfsfh = nfsfh;
data->org_offset = offset;
data->org_count = count;
data->update_pos = update_pos;
assert(data->num_calls == 0);
if (nfsfh->pagecache.num_entries) {
/* align start offset to blocksize */
count += offset & (NFS_BLKSIZE - 1);
offset &= ~(NFS_BLKSIZE - 1);
/* align end offset to blocksize */
count += NFS_BLKSIZE - 1 ;
count &= ~(NFS_BLKSIZE - 1);
}
data->offset = offset;
data->count = (count3)count;
if (nfsfh->pagecache.num_entries) {
while (count > 0) {
char *cdata = nfs_pagecache_get(&nfsfh->pagecache,
offset);
if (!cdata) {
break;
}
/* we copy data from the pagecache so we need a
* reassembly buffer */
if (data->buffer == NULL) {
data->buffer = malloc(data->count);
if (data->buffer == NULL) {
free_nfs_cb_data(data);
return -ENOMEM;
}
}
memcpy(data->buffer + offset - data->offset, cdata,
NFS_BLKSIZE);
offset += NFS_BLKSIZE;
count -= NFS_BLKSIZE;
}
if (!count) {
data->nfsfh->ra.fh_offset = data->offset + data->count;
if (update_pos) {
data->nfsfh->offset = data->org_offset + data->org_count;
}
data->cb(data->org_count, nfs, data->buffer + (data->org_offset - data->offset), data->private_data);
free_nfs_cb_data(data);
return 0;
}
}
if (nfs->rpc->readahead) {
nfsfh->ra.cur_ra = MAX(NFS_BLKSIZE, nfsfh->ra.cur_ra);
if (offset >= nfsfh->ra.fh_offset &&
offset <= nfsfh->ra.fh_offset + nfsfh->ra.cur_ra + NFS_BLKSIZE) {
if (nfs->rpc->readahead > nfsfh->ra.cur_ra) {
nfsfh->ra.cur_ra <<= 1;
}
} else {
nfsfh->ra.cur_ra = 0;
}
count += nfsfh->ra.cur_ra;
data->count += nfsfh->ra.cur_ra;
}
if ((data->count > nfs_get_readmax(nfs) || data->count > data->org_count) &&
(data->buffer == NULL || nfsfh->ra.cur_ra > 0)) {
/* we do readahead, a big read or aligned out the request so we
* need a (bigger) reassembly buffer */
data->buffer = realloc(data->buffer, data->count + nfsfh->ra.cur_ra);
if (data->buffer == NULL) {
free_nfs_cb_data(data);
return -ENOMEM;
}
}
data->max_offset = data->offset;
/* chop requests into chunks of at most READMAX bytes if necessary.
* we send all reads in parallel so that performance is still good.
*/
do {
size_t readcount = count;
struct nfs_mcb_data *mdata;
READ3args args;
if (readcount > nfs_get_readmax(nfs)) {
readcount = (size_t)nfs_get_readmax(nfs);
}
mdata = malloc(sizeof(struct nfs_mcb_data));
if (mdata == NULL) {
nfs_set_error(nfs, "out of memory: failed to allocate nfs_mcb_data structure");
if (data->num_calls == 0) {
free_nfs_cb_data(data);
return -1;
( run in 1.591 second using v1.01-cache-2.11-cpan-39bf76dae61 )