NFSv4: Add support for open(O_TRUNC)
Signed-off-by: Ronnie Sahlberg <ronniesahlberg@gmail.com>libnfs-4.0.0-vitalif
parent
61e071d448
commit
42d14779b7
|
@ -513,7 +513,7 @@ 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_SYNC, O_APPEND, O_TRUNC are not yet supported for NFSv4. )
|
* ( O_SYNC, O_APPEND are 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
|
||||||
|
|
111
lib/nfs_v4.c
111
lib/nfs_v4.c
|
@ -1366,6 +1366,78 @@ nfs4_rmdir_async(struct nfs_context *nfs, const char *orig_path,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nfs4_open_truncate_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;
|
||||||
|
struct nfsfh *fh;
|
||||||
|
|
||||||
|
assert(rpc->magic == RPC_CONTEXT_MAGIC);
|
||||||
|
|
||||||
|
if (check_nfs4_error(nfs, status, data, res, "SETATTR")) {
|
||||||
|
free_nfs4_cb_data(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fh = data->filler.blob0.val;
|
||||||
|
|
||||||
|
data->filler.blob0.val = NULL;
|
||||||
|
data->filler.blob1.val = NULL;
|
||||||
|
data->cb(0, nfs, fh, data->private_data);
|
||||||
|
free_nfs4_cb_data(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
nfs4_open_truncate(struct rpc_context *rpc, struct nfs4_cb_data *data)
|
||||||
|
{
|
||||||
|
struct nfs_context *nfs = data->nfs;
|
||||||
|
struct nfsfh *nfsfh;
|
||||||
|
nfs_argop4 op[2];
|
||||||
|
COMPOUND4args args;
|
||||||
|
PUTFH4args *pfargs;
|
||||||
|
SETATTR4args *saargs;
|
||||||
|
static uint32_t mask[2] = {1 << (FATTR4_SIZE),
|
||||||
|
1 << (FATTR4_TIME_MODIFY_SET - 32)};
|
||||||
|
static char zero[12];
|
||||||
|
|
||||||
|
nfsfh = data->filler.blob0.val;
|
||||||
|
|
||||||
|
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_SETATTR;
|
||||||
|
saargs = &op[1].nfs_argop4_u.opsetattr;
|
||||||
|
saargs->stateid.seqid = nfsfh->stateid.seqid;
|
||||||
|
memcpy(saargs->stateid.other, nfsfh->stateid.other, 12);
|
||||||
|
|
||||||
|
saargs->obj_attributes.attrmask.bitmap4_len = 2;
|
||||||
|
saargs->obj_attributes.attrmask.bitmap4_val = mask;
|
||||||
|
|
||||||
|
saargs->obj_attributes.attr_vals.attrlist4_len = 12;
|
||||||
|
saargs->obj_attributes.attr_vals.attrlist4_val = zero;
|
||||||
|
|
||||||
|
|
||||||
|
memset(&args, 0, sizeof(args));
|
||||||
|
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
|
||||||
|
args.argarray.argarray_val = op;
|
||||||
|
|
||||||
|
if (rpc_nfs4_compound_async(rpc, nfs4_open_truncate_cb, &args,
|
||||||
|
data) != 0) {
|
||||||
|
nfs_set_error(nfs, "Failed to queue TRUNCATE. %s",
|
||||||
|
nfs_get_error(nfs));
|
||||||
|
data->cb(-ENOMEM, nfs, nfs_get_error(nfs), data->private_data);
|
||||||
|
free_nfs4_cb_data(data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nfs4_open_confirm_cb(struct rpc_context *rpc, int status, void *command_data,
|
nfs4_open_confirm_cb(struct rpc_context *rpc, int status, void *command_data,
|
||||||
void *private_data)
|
void *private_data)
|
||||||
|
@ -1391,16 +1463,23 @@ nfs4_open_confirm_cb(struct rpc_context *rpc, int status, void *command_data,
|
||||||
ocresok = &res->resarray.resarray_val[i].nfs_resop4_u.opopen_confirm.OPEN_CONFIRM4res_u.resok4;
|
ocresok = &res->resarray.resarray_val[i].nfs_resop4_u.opopen_confirm.OPEN_CONFIRM4res_u.resok4;
|
||||||
|
|
||||||
fh = data->filler.blob0.val;
|
fh = data->filler.blob0.val;
|
||||||
data->filler.blob0.val = NULL;
|
|
||||||
data->filler.blob1.val = NULL;
|
|
||||||
|
|
||||||
fh->stateid.seqid = ocresok->open_stateid.seqid;
|
fh->stateid.seqid = ocresok->open_stateid.seqid;
|
||||||
memcpy(fh->stateid.other, ocresok->open_stateid.other, 12);
|
memcpy(fh->stateid.other, ocresok->open_stateid.other, 12);
|
||||||
|
|
||||||
|
if (data->filler.flags & O_TRUNC) {
|
||||||
|
nfs4_open_truncate(rpc, data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->filler.blob0.val = NULL;
|
||||||
|
data->filler.blob1.val = NULL;
|
||||||
data->cb(0, nfs, fh, data->private_data);
|
data->cb(0, nfs, fh, data->private_data);
|
||||||
free_nfs4_cb_data(data);
|
free_nfs4_cb_data(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Stores nfsfh in data.blob0 and nfsfh->fh.val in data.blob1.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
nfs4_open_cb(struct rpc_context *rpc, int status, void *command_data,
|
nfs4_open_cb(struct rpc_context *rpc, int status, void *command_data,
|
||||||
void *private_data)
|
void *private_data)
|
||||||
|
@ -1504,6 +1583,11 @@ nfs4_open_cb(struct rpc_context *rpc, int status, void *command_data,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data->filler.flags & O_TRUNC) {
|
||||||
|
nfs4_open_truncate(rpc, data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
data->filler.blob0.val = NULL;
|
data->filler.blob0.val = NULL;
|
||||||
data->filler.blob1.val = NULL;
|
data->filler.blob1.val = NULL;
|
||||||
data->cb(0, nfs, fh, data->private_data);
|
data->cb(0, nfs, fh, data->private_data);
|
||||||
|
@ -1640,15 +1724,15 @@ nfs4_populate_open(struct nfs4_cb_data *data, nfs_argop4 *op)
|
||||||
aargs = &op[0].nfs_argop4_u.opaccess;
|
aargs = &op[0].nfs_argop4_u.opaccess;
|
||||||
memset(aargs, 0, sizeof(*aargs));
|
memset(aargs, 0, sizeof(*aargs));
|
||||||
|
|
||||||
if (data->filler.flags & O_WRONLY) {
|
if (data->filler.flags & O_WRONLY) {
|
||||||
aargs->access |= ACCESS4_MODIFY;
|
aargs->access |= ACCESS4_MODIFY;
|
||||||
}
|
}
|
||||||
if (data->filler.flags & O_RDWR) {
|
if (data->filler.flags & O_RDWR) {
|
||||||
aargs->access |= ACCESS4_READ|ACCESS4_MODIFY;
|
aargs->access |= ACCESS4_READ|ACCESS4_MODIFY;
|
||||||
}
|
}
|
||||||
if (!(data->filler.flags & (O_WRONLY|O_RDWR))) {
|
if (!(data->filler.flags & (O_WRONLY|O_RDWR))) {
|
||||||
aargs->access |= ACCESS4_READ;
|
aargs->access |= ACCESS4_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open */
|
/* Open */
|
||||||
op[1].argop = OP_OPEN;
|
op[1].argop = OP_OPEN;
|
||||||
|
@ -1686,6 +1770,11 @@ nfs4_open_async(struct nfs_context *nfs, const char *orig_path, int flags,
|
||||||
struct nfs4_cb_data *data;
|
struct nfs4_cb_data *data;
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
|
/* O_TRUNC is only valid for O_RDWR or O_WRONLY */
|
||||||
|
if (flags & O_TRUNC && !(flags & (O_RDWR|O_WRONLY))) {
|
||||||
|
flags &= ~O_TRUNC;
|
||||||
|
}
|
||||||
|
|
||||||
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 "
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
. ./functions.sh
|
||||||
|
|
||||||
|
echo "NFSv${VERS} Open(O_TRUNC) test."
|
||||||
|
|
||||||
|
start_share
|
||||||
|
|
||||||
|
mkdir "${TESTDIR}/subdir"
|
||||||
|
|
||||||
|
echo -n "test open(O_WRONLY|O_TRUNC) (1) ... "
|
||||||
|
echo -n "kangabanga" > "${TESTDIR}/open1"
|
||||||
|
./prog_open_write "${TESTURL}/?version=${VERS}" "." /open1 O_WRONLY,O_TRUNC "" >/dev/null || failure
|
||||||
|
success
|
||||||
|
|
||||||
|
echo -n "verify the file got truncated ... "
|
||||||
|
expr `stat --printf="%s" "${TESTDIR}/open1"` "==" "0" >/dev/null || failure
|
||||||
|
success
|
||||||
|
|
||||||
|
echo -n "test open(O_RDONLY|O_TRUNC) (2) ... "
|
||||||
|
echo -n "kangabanga" > "${TESTDIR}/open1"
|
||||||
|
./prog_open_write "${TESTURL}/?version=${VERS}" "." /open1 O_RDONLY,O_TRUNC "" >/dev/null || failure
|
||||||
|
success
|
||||||
|
|
||||||
|
echo -n "verify the file did not get truncated ... "
|
||||||
|
expr `stat --printf="%s" "${TESTDIR}/open1"` "==" "10" >/dev/null || failure
|
||||||
|
success
|
||||||
|
|
||||||
|
stop_share
|
||||||
|
|
||||||
|
exit 0
|
Loading…
Reference in New Issue