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 nfs4_symlink_async(struct nfs_context *nfs, const char *oldpath,
|
||||
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
|
||||
}
|
||||
|
|
|
@ -513,8 +513,6 @@ EXTERN uint16_t nfs_umask(struct nfs_context *nfs, uint16_t mask);
|
|||
* mode is a combination of the flags :
|
||||
* O_RDONLY, O_WRONLY, O_RDWR , O_SYNC, O_APPEND, O_TRUNC, O_NOFOLLOW
|
||||
*
|
||||
* ( O_APPEND is not yet supported for NFSv4. )
|
||||
*
|
||||
* Function returns
|
||||
* 0 : The command was queued successfully. The callback will be invoked once
|
||||
* 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,
|
||||
cb, private_data);
|
||||
case NFS_V4:
|
||||
return nfs4_pwrite_async_internal(nfs, nfsfh, nfsfh->offset,
|
||||
(size_t)count, buf,
|
||||
cb, private_data, 1);
|
||||
return nfs4_write_async(nfs, nfsfh, count, buf,
|
||||
cb, private_data);
|
||||
default:
|
||||
nfs_set_error(nfs, "%s does not support NFSv%d",
|
||||
__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;
|
||||
}
|
||||
|
||||
if (data->filler.flags & O_APPEND) {
|
||||
fh->is_append = 1;
|
||||
}
|
||||
|
||||
fh->fh.len = gresok->object.nfs_fh4_len;
|
||||
fh->fh.val = malloc(fh->fh.len);
|
||||
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;
|
||||
}
|
||||
|
||||
if (flags & O_APPEND && !(flags & (O_RDWR|O_WRONLY))) {
|
||||
flags &= ~O_APPEND;
|
||||
}
|
||||
|
||||
data = malloc(sizeof(*data));
|
||||
if (data == NULL) {
|
||||
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;
|
||||
}
|
||||
|
||||
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