NFSv4: Add support (and tests) for open(O_APPEND)
Signed-off-by: Ronnie Sahlberg <ronniesahlberg@gmail.com>libnfs-4.0.0-vitalif
parent
2ce8890458
commit
65de83140a
|
@ -498,6 +498,9 @@ int nfs4_stat64_async(struct nfs_context *nfs, const char *path,
|
||||||
int no_follow, nfs_cb cb, void *private_data);
|
int no_follow, nfs_cb cb, void *private_data);
|
||||||
int nfs4_symlink_async(struct nfs_context *nfs, const char *oldpath,
|
int nfs4_symlink_async(struct nfs_context *nfs, const char *oldpath,
|
||||||
const char *newpath, nfs_cb cb, void *private_data);
|
const char *newpath, nfs_cb cb, void *private_data);
|
||||||
|
int nfs4_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh,
|
||||||
|
uint64_t count, const void *buf, nfs_cb cb,
|
||||||
|
void *private_data);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -513,8 +513,6 @@ EXTERN uint16_t nfs_umask(struct nfs_context *nfs, uint16_t mask);
|
||||||
* mode is a combination of the flags :
|
* mode is a combination of the flags :
|
||||||
* O_RDONLY, O_WRONLY, O_RDWR , O_SYNC, O_APPEND, O_TRUNC, O_NOFOLLOW
|
* O_RDONLY, O_WRONLY, O_RDWR , O_SYNC, O_APPEND, O_TRUNC, O_NOFOLLOW
|
||||||
*
|
*
|
||||||
* ( O_APPEND is not yet supported for NFSv4. )
|
|
||||||
*
|
|
||||||
* Function returns
|
* Function returns
|
||||||
* 0 : The command was queued successfully. The callback will be invoked once
|
* 0 : The command was queued successfully. The callback will be invoked once
|
||||||
* the command completes.
|
* the command completes.
|
||||||
|
|
|
@ -1052,9 +1052,8 @@ nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count,
|
||||||
return nfs3_write_async(nfs, nfsfh, count, buf,
|
return nfs3_write_async(nfs, nfsfh, count, buf,
|
||||||
cb, private_data);
|
cb, private_data);
|
||||||
case NFS_V4:
|
case NFS_V4:
|
||||||
return nfs4_pwrite_async_internal(nfs, nfsfh, nfsfh->offset,
|
return nfs4_write_async(nfs, nfsfh, count, buf,
|
||||||
(size_t)count, buf,
|
cb, private_data);
|
||||||
cb, private_data, 1);
|
|
||||||
default:
|
default:
|
||||||
nfs_set_error(nfs, "%s does not support NFSv%d",
|
nfs_set_error(nfs, "%s does not support NFSv%d",
|
||||||
__FUNCTION__, nfs->version);
|
__FUNCTION__, nfs->version);
|
||||||
|
|
125
lib/nfs_v4.c
125
lib/nfs_v4.c
|
@ -1535,6 +1535,10 @@ nfs4_open_cb(struct rpc_context *rpc, int status, void *command_data,
|
||||||
fh->is_sync = 1;
|
fh->is_sync = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data->filler.flags & O_APPEND) {
|
||||||
|
fh->is_append = 1;
|
||||||
|
}
|
||||||
|
|
||||||
fh->fh.len = gresok->object.nfs_fh4_len;
|
fh->fh.len = gresok->object.nfs_fh4_len;
|
||||||
fh->fh.val = malloc(fh->fh.len);
|
fh->fh.val = malloc(fh->fh.len);
|
||||||
if (fh->fh.val == NULL) {
|
if (fh->fh.val == NULL) {
|
||||||
|
@ -1779,6 +1783,10 @@ nfs4_open_async(struct nfs_context *nfs, const char *orig_path, int flags,
|
||||||
flags &= ~O_TRUNC;
|
flags &= ~O_TRUNC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flags & O_APPEND && !(flags & (O_RDWR|O_WRONLY))) {
|
||||||
|
flags &= ~O_APPEND;
|
||||||
|
}
|
||||||
|
|
||||||
data = malloc(sizeof(*data));
|
data = malloc(sizeof(*data));
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
nfs_set_error(nfs, "Out of memory. Failed to allocate "
|
nfs_set_error(nfs, "Out of memory. Failed to allocate "
|
||||||
|
@ -2322,3 +2330,120 @@ nfs4_pwrite_async_internal(struct nfs_context *nfs, struct nfsfh *nfsfh,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nfs4_write_append_cb(struct rpc_context *rpc, int status, void *command_data,
|
||||||
|
void *private_data)
|
||||||
|
{
|
||||||
|
struct nfs4_cb_data *data = private_data;
|
||||||
|
struct nfs_context *nfs = data->nfs;
|
||||||
|
COMPOUND4res *res = command_data;
|
||||||
|
GETATTR4resok *garesok = NULL;
|
||||||
|
struct nfsfh *nfsfh;
|
||||||
|
int i;
|
||||||
|
uint64_t offset;
|
||||||
|
char *buf;
|
||||||
|
uint32_t count;
|
||||||
|
|
||||||
|
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||||
|
|
||||||
|
nfsfh = data->filler.blob0.val;
|
||||||
|
data->filler.blob0.val = NULL;
|
||||||
|
|
||||||
|
buf = data->filler.blob1.val;
|
||||||
|
count = data->filler.blob1.len;
|
||||||
|
data->filler.blob1.val = NULL;
|
||||||
|
|
||||||
|
if (check_nfs4_error(nfs, status, data, res, "GETATTR")) {
|
||||||
|
free_nfs4_cb_data(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((i = nfs4_find_op(nfs, data, res, OP_GETATTR, "GETATTR")) < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
garesok = &res->resarray.resarray_val[i].nfs_resop4_u.opgetattr.GETATTR4res_u.resok4;
|
||||||
|
if (garesok->obj_attributes.attr_vals.attrlist4_len < 8) {
|
||||||
|
data->cb(-EINVAL, nfs, nfs_get_error(nfs), data->private_data);
|
||||||
|
free_nfs4_cb_data(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = nfs_pntoh64((uint32_t *)(void *)garesok->obj_attributes.attr_vals.attrlist4_val);
|
||||||
|
|
||||||
|
if (nfs4_pwrite_async_internal(nfs, nfsfh, offset,
|
||||||
|
(size_t)count, buf,
|
||||||
|
data->cb, data->private_data, 1) < 0) {
|
||||||
|
free_nfs4_cb_data(data);
|
||||||
|
data->cb(-ENOMEM, nfs, nfs_get_error(nfs), data->private_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_nfs4_cb_data(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
nfs4_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count,
|
||||||
|
const void *buf, nfs_cb cb, void *private_data)
|
||||||
|
{
|
||||||
|
if (nfsfh->is_append) {
|
||||||
|
COMPOUND4args args;
|
||||||
|
nfs_argop4 op[2];
|
||||||
|
PUTFH4args *pfargs;
|
||||||
|
GETATTR4args *gaargs;
|
||||||
|
static uint32_t attributes = 1 << FATTR4_SIZE;
|
||||||
|
struct nfs4_cb_data *data;
|
||||||
|
|
||||||
|
data = malloc(sizeof(*data));
|
||||||
|
if (data == NULL) {
|
||||||
|
nfs_set_error(nfs, "Out of memory. Failed to allocate "
|
||||||
|
"cb data");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memset(data, 0, sizeof(*data));
|
||||||
|
|
||||||
|
data->nfs = nfs;
|
||||||
|
data->cb = cb;
|
||||||
|
data->private_data = private_data;
|
||||||
|
|
||||||
|
data->filler.blob0.val = nfsfh;
|
||||||
|
|
||||||
|
memset(op, 0, sizeof(op));
|
||||||
|
|
||||||
|
op[0].argop = OP_PUTFH;
|
||||||
|
pfargs = &op[0].nfs_argop4_u.opputfh;
|
||||||
|
pfargs->object.nfs_fh4_len = nfsfh->fh.len;
|
||||||
|
pfargs->object.nfs_fh4_val = nfsfh->fh.val;
|
||||||
|
|
||||||
|
op[1].argop = OP_GETATTR;
|
||||||
|
gaargs = &op[1].nfs_argop4_u.opgetattr;
|
||||||
|
memset(gaargs, 0, sizeof(*gaargs));
|
||||||
|
|
||||||
|
gaargs->attr_request.bitmap4_len = 1;
|
||||||
|
gaargs->attr_request.bitmap4_val = &attributes;
|
||||||
|
|
||||||
|
memset(&args, 0, sizeof(args));
|
||||||
|
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
|
||||||
|
args.argarray.argarray_val = op;
|
||||||
|
|
||||||
|
data->filler.blob0.val = nfsfh;
|
||||||
|
data->filler.blob1.val = discard_const(buf);
|
||||||
|
data->filler.blob1.len = count;
|
||||||
|
|
||||||
|
if (rpc_nfs4_compound_async(nfs->rpc, nfs4_write_append_cb,
|
||||||
|
&args, data) != 0) {
|
||||||
|
data->filler.blob0.val = NULL;
|
||||||
|
data->filler.blob1.val = NULL;
|
||||||
|
free_nfs4_cb_data(data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nfs4_pwrite_async_internal(nfs, nfsfh, nfsfh->offset,
|
||||||
|
(size_t)count, buf,
|
||||||
|
cb, private_data, 1);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
. ./functions.sh
|
||||||
|
|
||||||
|
echo "NFSv${VERS} Open(O_APPEND) test."
|
||||||
|
|
||||||
|
start_share
|
||||||
|
|
||||||
|
mkdir "${TESTDIR}/subdir"
|
||||||
|
|
||||||
|
echo -n "test open(O_APPEND) (1) ... "
|
||||||
|
echo -n "GOAT:" > "${TESTDIR}/open1"
|
||||||
|
./prog_open_write "${TESTURL}/?version=${VERS}" "." /open1 O_WRONLY,O_APPEND "NieR" >/dev/null || failure
|
||||||
|
./prog_open_write "${TESTURL}/?version=${VERS}" "." /open1 O_WRONLY,O_APPEND "Automata" >/dev/null || failure
|
||||||
|
success
|
||||||
|
|
||||||
|
echo -n "verify it got appended ... "
|
||||||
|
grep "GOAT:NieRAutomata" "${TESTDIR}/open1" >/dev/null || failure
|
||||||
|
success
|
||||||
|
|
||||||
|
stop_share
|
||||||
|
|
||||||
|
exit 0
|
Loading…
Reference in New Issue