From 65a01104768e33719d7e5684dfcb9e6dca6b6524 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sun, 6 Aug 2017 18:43:28 +1000 Subject: [PATCH] NFSv4: Add support for open(O_CREAT) Add support for O_CREAT for NFSv4. Note, it is not implemented for NFSv3. While it creates files we still need to add plumbing to get umask implemented or else all files created will have mode 0. Signed-off-by: Ronnie Sahlberg --- include/nfsc/libnfs.h | 4 +- lib/nfs_v4.c | 66 +++++++++++++++++++++++++++++++-- tests/prog_open_write.c | 3 ++ tests/test_0225_open_O_CREAT.sh | 16 ++++++++ 4 files changed, 84 insertions(+), 5 deletions(-) create mode 100755 tests/test_0225_open_O_CREAT.sh diff --git a/include/nfsc/libnfs.h b/include/nfsc/libnfs.h index 13c9e30..1e948d4 100755 --- a/include/nfsc/libnfs.h +++ b/include/nfsc/libnfs.h @@ -511,7 +511,8 @@ EXTERN uint16_t nfs_umask(struct nfs_context *nfs, uint16_t mask); * Async open() * * 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_CREAT * * Function returns * 0 : The command was queued successfully. The callback will be invoked once @@ -522,6 +523,7 @@ EXTERN uint16_t nfs_umask(struct nfs_context *nfs, uint16_t mask); * Supported flags are * O_NOFOLLOW * O_APPEND + * O_CREAT (Only NFSv4) * O_RDONLY * O_WRONLY * O_RDWR diff --git a/lib/nfs_v4.c b/lib/nfs_v4.c index c7e92b6..58839a5 100644 --- a/lib/nfs_v4.c +++ b/lib/nfs_v4.c @@ -125,6 +125,11 @@ struct lookup_filler { void *val; blob_free free; } blob1; + struct { + int len; + void *val; + blob_free free; + } blob2; }; struct rw_data { @@ -168,6 +173,9 @@ free_nfs4_cb_data(struct nfs4_cb_data *data) if (data->filler.blob1.val && data->filler.blob1.free) { data->filler.blob1.free(data->filler.blob1.val); } + if (data->filler.blob2.val && data->filler.blob2.free) { + data->filler.blob2.free(data->filler.blob2.val); + } free(data); } @@ -1486,8 +1494,6 @@ nfs4_open_confirm_cb(struct rpc_context *rpc, int status, void *command_data, free_nfs4_cb_data(data); } -/* Stores nfsfh in data.blob0. - */ static void nfs4_open_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data) @@ -1764,7 +1770,23 @@ nfs4_populate_open(struct nfs4_cb_data *data, nfs_argop4 *op) oargs->owner.clientid = nfs->clientid; oargs->owner.owner.owner_len = strlen(nfs->client_name); oargs->owner.owner.owner_val = nfs->client_name; - oargs->openhow.opentype = OPEN4_NOCREATE; + if (data->filler.flags & O_CREAT) { + createhow4 *ch; + fattr4 *fa; + + ch = &oargs->openhow.openflag4_u.how; + fa = &ch->createhow4_u.createattrs; + + oargs->openhow.opentype = OPEN4_CREATE; + ch->mode = UNCHECKED4; + fa->attrmask.bitmap4_len = data->filler.blob1.len; + fa->attrmask.bitmap4_val = data->filler.blob1.val; + + fa->attr_vals.attrlist4_len = data->filler.blob2.len; + fa->attr_vals.attrlist4_val = data->filler.blob2.val; + } else { + oargs->openhow.opentype = OPEN4_NOCREATE; + } oargs->claim.claim = CLAIM_NULL; oargs->claim.open_claim4_u.file.utf8string_len = strlen(data->filler.data); @@ -1777,7 +1799,11 @@ nfs4_populate_open(struct nfs4_cb_data *data, nfs_argop4 *op) return 3; } -/* TODO add the plumbing for mode */ +/* + * data.blob0 is used for nfsfh + * data.blob1 is used for the attribute mask in case on O_CREAT + * data.blob2 is the attribute value in case of O_CREAT + */ int nfs4_open_async(struct nfs_context *nfs, const char *orig_path, int flags, int mode, nfs_cb cb, void *private_data) @@ -1813,6 +1839,38 @@ nfs4_open_async(struct nfs_context *nfs, const char *orig_path, int flags, return -1; } + if (flags & O_CREAT) { + uint32_t *d; + + /* Attribute mask */ + d = malloc(2 * sizeof(uint32_t)); + if (d == NULL) { + nfs_set_error(nfs, "Out of memory"); + free_nfs4_cb_data(data); + return -1; + } + d[0] = 0; + d[1] = 1 << (FATTR4_MODE - 32); + + data->filler.blob1.val = d; + data->filler.blob1.len = 2; + data->filler.blob1.free = free; + + /* Attribute value */ + d = malloc(sizeof(uint32_t)); + if (d == NULL) { + nfs_set_error(nfs, "Out of memory"); + free_nfs4_cb_data(data); + return -1; + } + + *d = mode; + + data->filler.blob2.val = d; + data->filler.blob2.len = 4; + data->filler.blob2.free = free; + } + path = strrchr(data->path, '/'); if (path == data->path) { char *ptr; diff --git a/tests/prog_open_write.c b/tests/prog_open_write.c index 5d81e4f..86f5ee5 100644 --- a/tests/prog_open_write.c +++ b/tests/prog_open_write.c @@ -68,6 +68,9 @@ int main(int argc, char *argv[]) if (strstr(argv[4], "O_TRUNC")) { flags |= O_TRUNC; } + if (strstr(argv[4], "O_CREAT")) { + flags |= O_CREAT; + } nfs = nfs_init_context(); if (nfs == NULL) { diff --git a/tests/test_0225_open_O_CREAT.sh b/tests/test_0225_open_O_CREAT.sh new file mode 100755 index 0000000..7d20f8c --- /dev/null +++ b/tests/test_0225_open_O_CREAT.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +. ./functions.sh + +echo "NFSv${VERS} Open(O_CREAT) test." + +start_share + +echo -n "test open(O_RDWR|O_CREAT) (1) ... " +./prog_open_write "${TESTURL}/?version=${VERS}" "." /open1 O_WRONLY,O_CREAT "LordOfCinder" >/dev/null || failure +success + + +stop_share + +exit 0