Created
December 8, 2011 17:01
-
-
Save mariusae/1447612 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* $FreeBSD$ */ | |
| /* $Id: nfs4_subs.c,v 1.3 2004/05/14 18:37:20 marius Exp $ */ | |
| /* | |
| * nfs4client/nfs4_vfsops.c | |
| * | |
| * Copyright (c) 2003, 2004 The Regents of the University of Michigan. | |
| * All rights reserved. | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions | |
| * are met: | |
| * | |
| * 1. Redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer. | |
| * 2. Redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution. | |
| * 3. Neither the name of the University nor the names of its | |
| * contributors may be used to endorse or promote products derived | |
| * from this software without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
| * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | |
| * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
| * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
| * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| #include <sys/cdefs.h> | |
| #include <sys/param.h> | |
| #include <sys/systm.h> | |
| #include <sys/kernel.h> | |
| #ifndef __FreeBSD__ | |
| #include <sys/types.h> | |
| #endif | |
| /* XXX used? */ | |
| #ifndef __APPLE__ | |
| #include <sys/bio.h> | |
| #endif | |
| #include <sys/buf.h> | |
| #include <sys/proc.h> | |
| #include <sys/mount.h> | |
| #include <sys/vnode.h> | |
| #include <sys/namei.h> | |
| #include <sys/mbuf.h> | |
| #include <sys/socket.h> | |
| #include <sys/stat.h> | |
| #include <sys/malloc.h> | |
| #include <sys/syscall.h> | |
| #ifndef __APPLE__ | |
| #include <sys/sysent.h> | |
| #include <sys/sysproto.h> | |
| #endif | |
| #include <sys/fcntl.h> | |
| #ifdef __APPLE__ | |
| #include <stdarg.h> | |
| #else | |
| #include <machine/stdarg.h> | |
| /* XXX used? */ | |
| #include <vm/vm.h> | |
| #include <vm/vm_object.h> | |
| #include <vm/vm_extern.h> | |
| #include <vm/uma.h> | |
| #endif | |
| #include <rpcx/rpcclnt.h> | |
| #include <nfsx/rpcv2.h> | |
| #include <nfsx/nfsproto.h> | |
| #include <nfsxclient/nfs.h> | |
| #include <nfs4client/nfs4.h> | |
| #include <nfsxclient/nfsnode.h> | |
| #include <nfsxclient/nfsmount.h> | |
| #include <nfsx/xdr_subs.h> | |
| #include <nfsxclient/nfsm_subs.h> | |
| #include <rpcx/rpc_dev.h> | |
| #include <nfs4client/nfs4_idmap.h> | |
| #include <nfs4client/nfs4m_subs.h> | |
| #include <nfs4client/nfs4_glue.h> | |
| #include <nfs4client/nfs4m_glue.h> | |
| #include <netinet/in.h> | |
| #define NFSM_DISSECT(s) do { \ | |
| tl = nfsm_dissect_xx((s), md, dpos); \ | |
| if (tl == NULL) { \ | |
| printf("NFSM_DISSECT error; allocation (%s/%d) (%s:%d)\n", #s, \ | |
| s, __FILE__, __LINE__); \ | |
| return (EBADRPC); \ | |
| } \ | |
| } while (0) | |
| #define NFSM_ADV(s) do { \ | |
| t1 = nfsm_adv_xx((s), md, dpos); \ | |
| if (t1 != 0) { \ | |
| printf("NFSM_ADV error; allocation (%s/%d) (%s:%d)\n", \ | |
| #s, s, __FILE__, __LINE__); \ | |
| return (EBADRPC); \ | |
| } \ | |
| } while (0) | |
| #define NFSM_MTOTIME(t) do { \ | |
| NFSM_DISSECT(3 * NFSX_UNSIGNED); \ | |
| (t).tv_sec = fxdr_hyper(tl); \ | |
| tl += 2; \ | |
| (t).tv_nsec = fxdr_unsigned(long, *tl++); \ | |
| } while (0) | |
| static uint32_t __fsinfo_bm[2], __fsattr_bm[2], __getattr_bm[2], __readdir_bm[2]; | |
| nfsv4bitmap nfsv4_fsinfobm = { 2, __fsinfo_bm }; | |
| nfsv4bitmap nfsv4_fsattrbm = { 2, __fsattr_bm }; | |
| nfsv4bitmap nfsv4_getattrbm = { 2, __getattr_bm }; | |
| nfsv4bitmap nfsv4_readdirbm = { 2, __readdir_bm }; | |
| /* Helper routines */ | |
| int nfsm_v4build_attrs_xx(struct vattr *, struct mbuf **, caddr_t *); | |
| int nfsm_v4dissect_changeinfo_xx(nfsv4changeinfo *, struct mbuf **, caddr_t *); | |
| void | |
| nfsm_v4init(void) | |
| { | |
| /* Set up bitmasks */ | |
| FA4_SET(FA4_FSID, __fsinfo_bm); | |
| FA4_SET(FA4_MAXREAD, __fsinfo_bm); | |
| FA4_SET(FA4_MAXWRITE, __fsinfo_bm); | |
| FA4_SET(FA4_LEASE_TIME, __fsinfo_bm); | |
| FA4_SET(FA4_FSID, __fsattr_bm); | |
| FA4_SET(FA4_FILES_FREE, __fsattr_bm); | |
| FA4_SET(FA4_FILES_TOTAL, __fsattr_bm); | |
| FA4_SET(FA4_SPACE_AVAIL, __fsattr_bm); | |
| FA4_SET(FA4_SPACE_FREE, __fsattr_bm); | |
| FA4_SET(FA4_SPACE_TOTAL, __fsattr_bm); | |
| FA4_SET(FA4_TYPE, __getattr_bm); | |
| FA4_SET(FA4_FSID, __getattr_bm); | |
| FA4_SET(FA4_SIZE, __getattr_bm); | |
| FA4_SET(FA4_MODE, __getattr_bm); | |
| FA4_SET(FA4_RAWDEV, __getattr_bm); | |
| FA4_SET(FA4_NUMLINKS, __getattr_bm); | |
| FA4_SET(FA4_OWNER, __getattr_bm); | |
| FA4_SET(FA4_OWNER_GROUP, __getattr_bm); | |
| FA4_SET(FA4_FILEID, __getattr_bm); | |
| FA4_SET(FA4_TIME_MODIFY, __getattr_bm); | |
| FA4_SET(FA4_TIME_ACCESS, __getattr_bm); | |
| /* FA4_SET(FA4_TIME_CREATE, __getattr_bm);*/ | |
| FA4_SET(FA4_TYPE, __readdir_bm); | |
| FA4_SET(FA4_FSID, __readdir_bm); | |
| FA4_SET(FA4_FILEID, __readdir_bm); | |
| } | |
| /* | |
| * Util | |
| */ | |
| uint32_t | |
| nfs_v4fileid4_to_fileid(uint64_t fid) | |
| { | |
| return ((uint32_t)((fid >> 32) | fid)); | |
| } | |
| void | |
| nfs_v4initcompound(struct nfs4_compound *cp) | |
| { | |
| bzero(cp, sizeof(*cp)); | |
| } | |
| /* | |
| * Build/dissect XDR buffer with a format string. | |
| * | |
| * u - unsigned | |
| * h - hyper | |
| * s - stringlength, string | |
| * k - skip length (bytes) | |
| * a - arraylength, componentlenght, array | |
| * o - opaque fix length | |
| * O - opaque var length in bytes | |
| */ | |
| void | |
| nfsm_buildf_xx(struct mbuf **mb, caddr_t *bpos, char *fmt, ...) | |
| { | |
| uint32_t *tl, t1, len, uval; | |
| uint64_t hval; | |
| va_list args; | |
| char *p, *which; | |
| va_start(args, fmt); | |
| for (which = fmt; *which != '\0'; which++) | |
| switch (*which) { | |
| case 'u': /* Unsigned */ | |
| tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); | |
| uval = va_arg(args, uint32_t); | |
| *tl++ = txdr_unsigned(uval); | |
| break; | |
| case 'h': /* Hyper */ | |
| tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); | |
| hval = va_arg(args, uint64_t); | |
| txdr_hyper(hval, tl); | |
| break; | |
| case 'o': /* Fixed-length opaque */ | |
| len = va_arg(args, uint32_t); | |
| p = va_arg(args, char *); | |
| tl = nfsm_build_xx(nfsm_rndup(len), mb, bpos); | |
| bcopy(p, tl, len); | |
| break; | |
| case 'O': /* Variable-length opaque */ | |
| case 's': /* String */ | |
| len = va_arg(args, uint32_t); | |
| p = va_arg(args, char *); | |
| t1 = nfsm_strtom_xx(p, len, len, mb, bpos); | |
| break; | |
| case 'k': /* Skip */ | |
| len = va_arg(args, uint32_t); | |
| nfsm_build_xx(nfsm_rndup(len), mb, bpos); | |
| break; | |
| default: | |
| panic("Invalid buildf string %s[%c]", fmt, *which); | |
| break; | |
| } | |
| va_end(args); | |
| } | |
| int | |
| nfsm_dissectf_xx(struct mbuf **md, caddr_t *dpos, char *fmt, ...) | |
| { | |
| uint32_t *tl, t1, len, *uval; | |
| uint64_t *hval; | |
| va_list args; | |
| char *p, *which; | |
| va_start(args, fmt); | |
| for (which = fmt; *which != '\0'; which++) | |
| switch (*which) { | |
| case 'u': /* Unsigned */ | |
| tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); | |
| if (tl == NULL) | |
| return (EBADRPC); | |
| uval = va_arg(args, uint32_t *); | |
| *uval = fxdr_unsigned(uint32_t, *tl++); | |
| break; | |
| case 'h': /* Hyper */ | |
| tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); | |
| if (tl == NULL) | |
| return (EBADRPC); | |
| hval = va_arg(args, uint64_t *); | |
| *hval = fxdr_hyper(tl); | |
| break; | |
| case 'o': /* Fixed-length opaque */ | |
| len = va_arg(args, uint32_t); | |
| p = va_arg(args, void *); | |
| tl = nfsm_dissect_xx(nfsm_rndup(len), md, dpos); | |
| if (tl == NULL) | |
| return (EBADRPC); | |
| bcopy(tl, p, len); | |
| break; | |
| case 'O': /* Variable-length opaque */ | |
| case 's': /* String */ | |
| len = va_arg(args, uint32_t); | |
| p = va_arg(args, char *); | |
| tl = nfsm_dissect_xx(nfsm_rndup(len), md, dpos); | |
| if (tl == NULL) | |
| return (EBADRPC); | |
| bcopy(tl, p, len); | |
| break; | |
| case 'k': /* Skip bytes */ | |
| len = va_arg(args, uint32_t); | |
| t1 = nfsm_adv_xx(nfsm_rndup(len), md, dpos); | |
| break; | |
| default: | |
| panic("Invalid dissectf string %s[%c]", fmt, *which); | |
| break; | |
| } | |
| va_end(args); | |
| return (0); | |
| } | |
| /* | |
| * XXX - There are a few problems with the way the postops are places | |
| * in the code. Ideally, they should be taken care of immediately, as | |
| * to avoid uneceesary waits for mutexes, but then we would be | |
| * introducing even more complexity by having to handle two separate | |
| * cases. Also, since they are placed at the end of the vnops', there | |
| * may be operations which sleep in between, further extending this | |
| * wait. It is conceivable that there is a deadlock condition there, | |
| * too. | |
| * | |
| * Also, for vnops that do multiple operations, it's inconvenient | |
| * since on error, individual decoding will got nfsmout. | |
| */ | |
| int | |
| nfs_v4postop(struct nfs4_compound *cp, int status) | |
| { | |
| struct nfs4_fctx *fcp = cp->fcp; | |
| /* | |
| * XXX does the previous result need to be stores with the | |
| * lockowner? ack, spec is unclear .. | |
| */ | |
| if (fcp != NULL) | |
| if (cp->seqidused < cp->rep_nops || | |
| (cp->seqidused + 1 == cp->rep_nops && | |
| NFS4_SEQIDMUTATINGERROR(status))) | |
| fcp->lop->lo_seqid++; | |
| return (status); | |
| } | |
| int | |
| nfs_v4handlestatus(int status, struct nfs4_compound *cp) | |
| { | |
| return (status); | |
| } | |
| /* | |
| * Initial setup of compound. | |
| */ | |
| int | |
| nfsm_v4build_compound_xx(struct nfs4_compound *cp, char *tag, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| uint32_t t1, *tl, siz; | |
| /* Tag */ | |
| siz = strlen(tag); | |
| t1 = nfsm_rndup(siz) + NFSX_UNSIGNED; | |
| if (t1 <= M_TRAILINGSPACE(*mb)) { | |
| tl = nfsm_build_xx(t1, mb, bpos); | |
| *tl++ = txdr_unsigned(siz); | |
| *(tl + ((t1 >> 2) - 2)) = 0; | |
| bcopy(tag, tl, siz); | |
| } else { | |
| #ifdef __FreeBSD__ | |
| t1 = nfsm_strtmbuf(mb, bpos, (const char *)tag, siz); | |
| #else | |
| t1 = nfsm_strtmbuf(mb, bpos, tag, siz); | |
| #endif /* __FreeBSD__ */ | |
| if (t1 != 0) | |
| return (t1); | |
| } | |
| /* Minor version and argarray*/ | |
| tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); | |
| *tl++ = txdr_unsigned(NFS4_MINOR_VERSION); | |
| /* Save for backfill */ | |
| cp->req_nopsp = tl; | |
| *tl = txdr_unsigned(0); | |
| cp->curvp = NULL; | |
| cp->savevp = NULL; | |
| return (0); | |
| } | |
| /* | |
| * XXX | |
| * - backfill for stateid, and such | |
| */ | |
| int | |
| nfsm_v4build_finalize_xx(struct nfs4_compound *cp, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| *cp->req_nopsp = txdr_unsigned(cp->req_nops); | |
| return (0); | |
| } | |
| int | |
| nfsm_v4build_putfh_xx(struct nfs4_compound *cp, struct vnode *vp, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| uint32_t t1; | |
| /* Op */ | |
| nfsm_buildf_xx(mb, bpos, "u", NFSV4OP_PUTFH); | |
| /* FH */ | |
| t1 = nfsm_fhtom_xx(vp, 1, mb, bpos); | |
| if (t1 != 0) | |
| return (t1); | |
| cp->req_nops++; | |
| cp->curvp = vp; | |
| return (0); | |
| } | |
| int | |
| nfsm_v4build_putfh_nv_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| nfsm_buildf_xx(mb, bpos, "uuo", | |
| NFSV4OP_PUTFH, | |
| gfh->fh_len, | |
| gfh->fh_len, | |
| &gfh->fh_val); | |
| cp->req_nops++; | |
| return (0); | |
| } | |
| int | |
| nfsm_v4build_simple_xx(struct nfs4_compound *cp, uint32_t op, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| nfsm_buildf_xx(mb, bpos, "u", op); | |
| cp->req_nops++; | |
| return (0); | |
| } | |
| int | |
| nfsm_v4build_getattr_xx(struct nfs4_compound *cp, struct nfs4_oparg_getattr *ga, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| int i; | |
| /* Op + bitmap length + bitmap */ | |
| nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_GETATTR, ga->bm->bmlen); | |
| for (i = 0; i < ga->bm->bmlen; i++) | |
| nfsm_buildf_xx(mb, bpos, "u", ga->bm->bmval[i]); | |
| ga->vp = cp->curvp; | |
| cp->req_nops++; | |
| return (0); | |
| } | |
| int | |
| nfsm_v4build_setattr_xx(struct nfs4_compound *cp, struct vattr *vap, | |
| struct nfs4_fctx *fcp, struct mbuf **mb, caddr_t *bpos) | |
| { | |
| int error; | |
| static char zero_stateid[NFSX_V4STATEID]; | |
| nfsm_buildf_xx(mb, bpos, "uo", | |
| NFSV4OP_SETATTR, | |
| NFSX_V4STATEID, fcp ? fcp->stateid : zero_stateid); | |
| error = nfsm_v4build_attrs_xx(vap, mb, bpos); | |
| if (error == 0) | |
| cp->req_nops++; | |
| return (error); | |
| } | |
| int | |
| nfsm_v4build_getfh_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| nfsm_buildf_xx(mb, bpos, "u", NFSV4OP_GETFH); | |
| gfh->vp = cp->curvp; | |
| cp->req_nops++; | |
| return (0); | |
| } | |
| int | |
| nfsm_v4build_lookup_xx(struct nfs4_compound *cp, struct nfs4_oparg_lookup *l, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_LOOKUP, l->namelen, l->name); | |
| cp->curvp = l->vp; | |
| cp->req_nops++; | |
| return (0); | |
| } | |
| int | |
| nfsm_v4build_setclientid_xx(struct nfs4_compound *cp, | |
| struct nfs4_oparg_setclientid *sci, struct mbuf **mb, caddr_t *bpos) | |
| { | |
| struct timeval tv; | |
| microtime(&tv); | |
| nfsm_buildf_xx(mb, bpos, "uuusussu", | |
| NFSV4OP_SETCLIENTID, | |
| tv.tv_sec, tv.tv_usec, | |
| sci->namelen, sci->name, | |
| sci->cb_prog, | |
| sci->cb_netidlen, sci->cb_netid, | |
| sci->cb_univaddrlen, sci->cb_univaddr, | |
| 0xCA11BACC); | |
| cp->req_nops++; | |
| return (0); | |
| } | |
| int | |
| nfsm_v4build_setclientid_confirm_xx(struct nfs4_compound *cp, | |
| struct nfs4_oparg_setclientid *sci, struct mbuf **mb, caddr_t *bpos) | |
| { | |
| nfsm_buildf_xx(mb, bpos, "uho", | |
| NFSV4OP_SETCLIENTID_CONFIRM, | |
| sci->clientid, | |
| sizeof(sci->verf), sci->verf); | |
| cp->req_nops++; | |
| return (0); | |
| } | |
| int | |
| nfsm_v4build_open_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| int error = 0; | |
| struct nfs4_lowner *lop = op->fcp->lop; | |
| nfsm_buildf_xx(mb, bpos, "uuuuhuu", | |
| NFSV4OP_OPEN, | |
| lop->lo_seqid, | |
| op->flags & O_ACCMODE, | |
| NFSV4OPENSHARE_DENY_NONE, | |
| cp->nmp->nm_clientid, | |
| 4, lop->lo_id); | |
| if (op->flags & O_CREAT) { | |
| nfsm_buildf_xx(mb, bpos, "u", OTCREATE); | |
| /* openflag4: mode */ | |
| nfsm_buildf_xx(mb, bpos, "u", CMUNCHECKED); | |
| /* openflag4: createattrs... */ | |
| if (op->vap != NULL) { | |
| if (op->flags & O_TRUNC) | |
| op->vap->va_size = 0; | |
| error = nfsm_v4build_attrs_xx(op->vap, mb, bpos); | |
| if (error != 0) | |
| return (error); | |
| } else | |
| nfsm_buildf_xx(mb, bpos, "uu", 0, 0); | |
| } else | |
| nfsm_buildf_xx(mb, bpos, "u", OTNOCREATE); | |
| nfsm_buildf_xx(mb, bpos, "us", op->ctype, | |
| op->cnp->cn_namelen, op->cnp->cn_nameptr); | |
| cp->seqidused = cp->req_nops++; | |
| cp->fcp = op->fcp; | |
| return (error); | |
| } | |
| /* | |
| * XXX | |
| * - Wait on recovery | |
| */ | |
| int | |
| nfsm_v4build_open_confirm_xx(struct nfs4_compound *cp, | |
| struct nfs4_oparg_open *op, struct mbuf **mb, caddr_t *bpos) | |
| { | |
| nfsm_buildf_xx(mb, bpos, "uou", | |
| NFSV4OP_OPEN_CONFIRM, | |
| NFSX_V4STATEID, op->fcp->stateid, | |
| op->fcp->lop->lo_seqid); | |
| cp->seqidused = cp->req_nops++; | |
| cp->fcp = op->fcp; | |
| return (0); | |
| } | |
| /* | |
| * XXX | |
| * - Wait on recovery | |
| */ | |
| int | |
| nfsm_v4build_close_xx(struct nfs4_compound *cp, struct nfs4_fctx *fcp, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| struct nfs4_lowner *lop = fcp->lop; | |
| nfsm_buildf_xx(mb, bpos, "uuo", | |
| NFSV4OP_CLOSE, | |
| lop->lo_seqid, | |
| NFSX_V4STATEID, fcp->stateid); | |
| cp->seqidused = cp->req_nops++; | |
| cp->fcp = fcp; | |
| return (0); | |
| } | |
| int | |
| nfsm_v4build_access_xx(struct nfs4_compound *cp, struct nfs4_oparg_access *acc, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_ACCESS, acc->mode); | |
| cp->req_nops++; | |
| return (0); | |
| } | |
| int | |
| nfsm_v4build_read_xx(struct nfs4_compound *cp, struct nfs4_oparg_read *r, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| nfsm_buildf_xx(mb, bpos, "uohu", | |
| NFSV4OP_READ, | |
| NFSX_V4STATEID, r->fcp->stateid, | |
| r->off, | |
| r->maxcnt); | |
| cp->req_nops++; | |
| return (0); | |
| } | |
| int | |
| nfsm_v4build_write_xx(struct nfs4_compound *cp, struct nfs4_oparg_write *w, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| nfsm_buildf_xx(mb, bpos, "uohuu", | |
| NFSV4OP_WRITE, | |
| NFSX_V4STATEID, w->fcp->stateid, | |
| w->off, | |
| w->stable, | |
| w->cnt); | |
| cp->req_nops++; | |
| return (nfsm_uiotombuf(w->uiop, mb, w->cnt, bpos)); | |
| } | |
| int | |
| nfsm_v4build_commit_xx(struct nfs4_compound *cp, struct nfs4_oparg_commit *c, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| nfsm_buildf_xx(mb, bpos, "uhu", NFSV4OP_COMMIT, c->start, c->len); | |
| cp->req_nops++; | |
| return (0); | |
| } | |
| int | |
| nfsm_v4build_readdir_xx(struct nfs4_compound *cp, struct nfs4_oparg_readdir *r, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| int i; | |
| nfsm_buildf_xx(mb, bpos, "uhouuu", | |
| NFSV4OP_READDIR, | |
| r->cookie, | |
| sizeof(r->verf), r->verf, | |
| r->cnt >> 4, /* meaningless "dircount" field */ | |
| r->cnt, | |
| r->bm->bmlen); | |
| for (i = 0; i < r->bm->bmlen; i++) | |
| nfsm_buildf_xx(mb, bpos, "u", r->bm->bmval[i]); | |
| cp->req_nops++; | |
| return (0); | |
| } | |
| int | |
| nfsm_v4build_renew_xx(struct nfs4_compound *cp, uint64_t cid, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| nfsm_buildf_xx(mb, bpos, "uh", NFSV4OP_RENEW, cid); | |
| cp->req_nops++; | |
| return (0); | |
| } | |
| int | |
| nfsm_v4build_create_xx(struct nfs4_compound *cp, struct nfs4_oparg_create *c, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| uint32_t t1; | |
| nfsm_buildf_xx(mb, bpos, "uu", NFSV4OP_CREATE, c->type); | |
| if (c->type == NFLNK) | |
| /* XXX strlen */ | |
| nfsm_buildf_xx(mb, bpos, "s", strlen(c->linktext), c->linktext); | |
| else if (c->type == NFCHR || c->type == NFBLK) | |
| nfsm_buildf_xx(mb, bpos, "uu", | |
| umajor(c->vap->va_rdev), uminor(c->vap->va_rdev)); | |
| /* Name */ | |
| nfsm_buildf_xx(mb, bpos, "s", c->namelen, c->name); | |
| /* Attributes */ | |
| t1 = nfsm_v4build_attrs_xx(c->vap, mb, bpos); | |
| if (t1 != 0) | |
| return (t1); | |
| cp->req_nops++; | |
| return (0); | |
| } | |
| int | |
| nfsm_v4build_rename_xx(struct nfs4_compound *cp, struct nfs4_oparg_rename *r, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| nfsm_buildf_xx(mb, bpos, "uss", NFSV4OP_RENAME, r->fnamelen, r->fname, | |
| r->tnamelen, r->tname); | |
| cp->req_nops++; | |
| return (0); | |
| } | |
| int | |
| nfsm_v4build_link_xx(struct nfs4_compound *cp, struct nfs4_oparg_link *l, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_LINK, l->namelen, l->name); | |
| cp->req_nops++; | |
| return (0); | |
| } | |
| int | |
| nfsm_v4build_remove_xx(struct nfs4_compound *cp, const char *name, u_int namelen, | |
| struct mbuf **mb, caddr_t *bpos) | |
| { | |
| nfsm_buildf_xx(mb, bpos, "us", NFSV4OP_REMOVE, namelen, name); | |
| cp->req_nops++; | |
| return (0); | |
| } | |
| int | |
| nfsm_v4build_attrs_xx(struct vattr *vap, struct mbuf **mb, caddr_t *bpos) | |
| { | |
| uint32_t *tl, *attrlenp, *bmvalp, len; | |
| size_t siz; | |
| tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos); | |
| *tl++ = txdr_unsigned(2); /* bitmap length */ | |
| bmvalp = tl; | |
| bzero(bmvalp, 8); | |
| tl += 2; | |
| attrlenp = tl; | |
| len = 0; | |
| if (vap->va_size != VNOVAL) { | |
| tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); | |
| FA4_SET(FA4_SIZE, bmvalp); | |
| txdr_hyper(vap->va_size, tl); tl += 2; | |
| len += 2 * NFSX_UNSIGNED; | |
| } | |
| if (vap->va_mode != (u_short)VNOVAL) { | |
| tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); | |
| FA4_SET(FA4_MODE, bmvalp); | |
| *tl++ = txdr_unsigned(vap->va_mode); | |
| len += NFSX_UNSIGNED; | |
| } | |
| if (vap->va_uid != VNOVAL) { | |
| int error; | |
| char *name; | |
| error = idmap_uid_to_name(vap->va_uid, &name, &siz); | |
| if (error || name == NULL || siz == 0) { | |
| /* XXX */ | |
| siz = sizeof("nobody") - 1; | |
| tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb, | |
| bpos); | |
| *tl++ = txdr_unsigned(siz); | |
| bcopy("nobody", tl, siz); | |
| len += NFSX_UNSIGNED + nfsm_rndup(siz); | |
| } else { | |
| tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb, | |
| bpos); | |
| *tl++ = txdr_unsigned(siz); | |
| bcopy(name, tl, siz); | |
| len += NFSX_UNSIGNED + nfsm_rndup(siz); | |
| } | |
| FA4_SET(FA4_OWNER, bmvalp); | |
| } | |
| if (vap->va_gid != VNOVAL) { | |
| int error; | |
| char *name; | |
| error = idmap_gid_to_name(vap->va_gid, &name, &siz); | |
| if (error || name == NULL || siz == 0) { | |
| /* XXX */ | |
| siz = sizeof("nogroup") - 1; | |
| tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb, | |
| bpos); | |
| *tl++ = txdr_unsigned(siz); | |
| bcopy("nogroup", tl, siz); | |
| len += NFSX_UNSIGNED + nfsm_rndup(siz); | |
| } else { | |
| tl = nfsm_build_xx(NFSX_UNSIGNED + nfsm_rndup(siz), mb, | |
| bpos); | |
| *tl++ = txdr_unsigned(siz); | |
| bcopy(name, tl, siz); | |
| len += NFSX_UNSIGNED + nfsm_rndup(siz); | |
| } | |
| FA4_SET(FA4_OWNER_GROUP, bmvalp); | |
| } | |
| if (vap->va_atime.tv_sec != VNOVAL) { | |
| uint64_t val = vap->va_atime.tv_sec; | |
| tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos); | |
| FA4_SET(FA4_TIME_ACCESS_SET, bmvalp); | |
| *tl++ = txdr_unsigned(THCLIENTTIME); | |
| txdr_hyper(val, tl); tl += 2; | |
| *tl++ = txdr_unsigned(vap->va_atime.tv_nsec); | |
| len += 4 * NFSX_UNSIGNED; | |
| } | |
| if (vap->va_mtime.tv_sec != VNOVAL) { | |
| uint64_t val = vap->va_mtime.tv_sec; | |
| tl = nfsm_build_xx(4 * NFSX_UNSIGNED, mb, bpos); | |
| FA4_SET(FA4_TIME_MODIFY_SET, bmvalp); | |
| *tl++ = txdr_unsigned(THCLIENTTIME); | |
| txdr_hyper(val, tl); tl += 2; | |
| *tl++ = txdr_unsigned(vap->va_mtime.tv_nsec); | |
| len += 4 * NFSX_UNSIGNED; | |
| } | |
| bmvalp[0] = txdr_unsigned(bmvalp[0]); | |
| bmvalp[1] = txdr_unsigned(bmvalp[1]); | |
| *attrlenp = txdr_unsigned(len); | |
| return (0); | |
| } | |
| int | |
| nfsm_v4dissect_compound_xx(struct nfs4_compound *cp, struct mbuf **md, caddr_t *dpos) | |
| { | |
| uint32_t taglen, t1, *tl; | |
| tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); | |
| if (tl == NULL) | |
| return (EBADRPC); | |
| /* Reply status is handled by the RPC code */ | |
| taglen = fxdr_unsigned(uint32_t, *tl++); | |
| t1 = nfsm_adv_xx(nfsm_rndup(taglen), md, dpos); | |
| if (t1 != 0) | |
| return (EBADRPC); | |
| tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); | |
| if (tl == NULL) | |
| return (EBADRPC); | |
| cp->rep_nops = fxdr_unsigned(uint32_t, *tl++); | |
| return (0); | |
| } | |
| int | |
| nfsm_v4dissect_simple_xx(struct nfs4_compound *cp, uint32_t op, | |
| uint32_t skipbytes, struct mbuf **md, caddr_t *dpos) | |
| { | |
| uint32_t t1, dop, status; | |
| t1 = nfsm_dissectf_xx(md, dpos, "uu", &dop, &status); | |
| if (t1 != 0) | |
| return (t1); | |
| if (dop != op || status != 0) | |
| return (EBADRPC); | |
| if (skipbytes > 0) | |
| NFSM_ADV(nfsm_rndup(skipbytes)); | |
| return (0); | |
| } | |
| int | |
| nfsm_v4dissect_getattr_xx(struct nfs4_compound *cp, | |
| struct nfs4_oparg_getattr *ga, struct mbuf **md, caddr_t *dpos) | |
| { | |
| uint32_t *tl; | |
| tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); | |
| if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_GETATTR || | |
| *tl++ != 0) | |
| return (EBADRPC); | |
| return (nfsm_v4dissect_attrs_xx(&ga->fa, md, dpos)); | |
| } | |
| int | |
| nfsm_v4dissect_setattr_xx(struct nfs4_compound *cp, | |
| struct mbuf **md, caddr_t *dpos) | |
| { | |
| uint32_t t1, op, bmlen, status; | |
| t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status); | |
| if (t1 != 0) | |
| return (t1); | |
| if (op != NFSV4OP_SETATTR || status != 0) | |
| return (EBADRPC); | |
| t1 = nfsm_dissectf_xx(md, dpos, "u", &bmlen); | |
| if (t1 != 0) | |
| return (t1); | |
| return (nfsm_dissectf_xx(md, dpos, "k", bmlen << 2)); | |
| } | |
| int | |
| nfsm_v4dissect_getfh_xx(struct nfs4_compound *cp, struct nfs4_oparg_getfh *gfh, | |
| struct mbuf **md, caddr_t *dpos) | |
| { | |
| uint32_t *tl, len, xdrlen; | |
| tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); | |
| if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_GETFH) | |
| return (EBADRPC); | |
| if (*tl++ != 0) | |
| return (EBADRPC); | |
| NFSM_DISSECT(NFSX_UNSIGNED); | |
| len = fxdr_unsigned(uint32_t, *tl++); | |
| if (len > NFSX_V4FH) | |
| return (EBADRPC); | |
| /* XXX integrate this into nfs_mtofh()? */ | |
| gfh->fh_len = len; | |
| xdrlen = nfsm_rndup(len); | |
| NFSM_DISSECT(xdrlen); | |
| bcopy(tl, &gfh->fh_val, xdrlen); | |
| return (0); | |
| } | |
| int | |
| nfsm_v4dissect_setclientid_xx(struct nfs4_compound *cp, | |
| struct nfs4_oparg_setclientid *sci, struct mbuf **md, caddr_t *dpos) | |
| { | |
| uint32_t *tl; | |
| tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); | |
| if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_SETCLIENTID) | |
| return (EBADRPC); | |
| /* Handle NFS4ERR_CLID_INUSE specially */ | |
| if (*tl++ != 0) | |
| return (EBADRPC); | |
| NFSM_DISSECT(2 * NFSX_UNSIGNED); | |
| sci->clientid = fxdr_hyper(tl); | |
| NFSM_DISSECT(nfsm_rndup(NFSX_V4VERF)); | |
| bcopy(tl, sci->verf, NFSX_V4VERF); | |
| return (0); | |
| } | |
| int | |
| nfsm_v4dissect_close_xx(struct nfs4_compound *cp, struct nfs4_fctx *fcp, | |
| struct mbuf **md, caddr_t *dpos) | |
| { | |
| uint32_t *tl, t1; | |
| tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); | |
| if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_CLOSE || | |
| *tl++ != 0) | |
| return (EBADRPC); | |
| /* Copy stateid */ | |
| t1 = nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, fcp->stateid); | |
| if (t1 != 0) | |
| return (t1); | |
| return (0); | |
| } | |
| int | |
| nfsm_v4dissect_access_xx(struct nfs4_compound *cp, struct nfs4_oparg_access *acc, | |
| struct mbuf **md, caddr_t *dpos) | |
| { | |
| uint32_t *tl; | |
| tl = nfsm_dissect_xx(4 * NFSX_UNSIGNED, md, dpos); | |
| if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_ACCESS || | |
| *tl++ != 0) | |
| return (EBADRPC); | |
| acc->supported = fxdr_unsigned(uint32_t, *tl++); | |
| acc->rmode = fxdr_unsigned(uint32_t, *tl++); | |
| return (0); | |
| } | |
| int | |
| nfsm_v4dissect_open_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op, | |
| struct mbuf **md, caddr_t *dpos) | |
| { | |
| uint32_t *tl, t1, bmlen, delegtype = ODNONE; | |
| int error = 0; | |
| nfsv4changeinfo cinfo; | |
| struct nfs4_fctx *fcp = op->fcp; | |
| tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); | |
| if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != NFSV4OP_OPEN || | |
| *tl++ != 0) | |
| return (EBADRPC); | |
| t1 = nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, fcp->stateid); | |
| if (t1 != 0) | |
| return (t1); | |
| error = nfsm_v4dissect_changeinfo_xx(&cinfo, md, dpos); | |
| if (error != 0) | |
| goto nfsmout; | |
| NFSM_DISSECT(2 * NFSX_UNSIGNED); | |
| op->rflags = fxdr_unsigned(uint32_t, *tl++); | |
| bmlen = fxdr_unsigned(uint32_t, *tl++); | |
| if (bmlen > 2) { | |
| error = EBADRPC; | |
| goto nfsmout; | |
| } | |
| /* Skip */ | |
| NFSM_ADV(nfsm_rndup(bmlen << 2)); | |
| NFSM_DISSECT(NFSX_UNSIGNED); | |
| delegtype = fxdr_unsigned(uint32_t, *tl++); | |
| switch (delegtype) { | |
| case ODREAD: | |
| case ODWRITE: | |
| printf("nfs4: client delegation not yet supported\n"); | |
| error = EOPNOTSUPP; | |
| goto nfsmout; | |
| break; | |
| case ODNONE: | |
| default: | |
| break; | |
| } | |
| nfsmout: | |
| return (error); | |
| } | |
| int | |
| nfsm_v4dissect_open_confirm_xx(struct nfs4_compound *cp, struct nfs4_oparg_open *op, | |
| struct mbuf **md, caddr_t *dpos) | |
| { | |
| uint32_t *tl; | |
| tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos); | |
| if (tl == NULL || fxdr_unsigned(uint32_t, *tl++) != | |
| NFSV4OP_OPEN_CONFIRM || *tl++ != 0) | |
| return (EBADRPC); | |
| return nfsm_dissectf_xx(md, dpos, "o", NFSX_V4STATEID, op->fcp->stateid); | |
| } | |
| int | |
| nfsm_v4dissect_read_xx(struct nfs4_compound *cp, struct nfs4_oparg_read *r, | |
| struct mbuf **md, caddr_t *dpos) | |
| { | |
| uint32_t op, status, t1; | |
| t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status); | |
| if (t1 != 0) | |
| return (t1); | |
| if (op != NFSV4OP_READ || status != 0) | |
| return (EBADRPC); | |
| t1 = nfsm_dissectf_xx(md, dpos, "uu", &r->eof, &r->retlen); | |
| if (t1 != 0) | |
| return (t1); | |
| return (nfsm_mbuftouio(md, r->uiop, r->retlen, dpos)); | |
| } | |
| int | |
| nfsm_v4dissect_write_xx(struct nfs4_compound *cp, struct nfs4_oparg_write *w, | |
| struct mbuf **md, caddr_t *dpos) | |
| { | |
| uint32_t op, status, t1; | |
| t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status); | |
| if (t1 != 0) | |
| return (t1); | |
| if (op != NFSV4OP_WRITE || status != 0) | |
| return (EBADRPC); | |
| return (nfsm_dissectf_xx(md, dpos, "uuo", &w->retlen, &w->committed, | |
| NFSX_V4VERF, w->wverf)); | |
| } | |
| int | |
| nfsm_v4dissect_commit_xx(struct nfs4_compound *cp, struct nfs4_oparg_commit *c, | |
| struct mbuf **md, caddr_t *dpos) | |
| { | |
| uint32_t t1, op, status; | |
| t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status); | |
| if (t1 != 0) | |
| return (t1); | |
| if (op != NFSV4OP_COMMIT || status != 0) | |
| return (EBADRPC); | |
| return (nfsm_dissectf_xx(md, dpos, "o", NFSX_V4VERF, c->verf)); | |
| } | |
| int | |
| nfsm_v4dissect_create_xx(struct nfs4_compound *cp, struct nfs4_oparg_create *c, | |
| struct mbuf **md, caddr_t *dpos) | |
| { | |
| uint32_t t1, *tl, op, status, bmlen; | |
| nfsv4changeinfo ci; | |
| t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status); | |
| if (t1 != 0) | |
| return (t1); | |
| if (op != NFSV4OP_CREATE || status != 0) | |
| return (EBADRPC); | |
| /* Just throw this away for now */ | |
| t1 = nfsm_v4dissect_changeinfo_xx(&ci, md, dpos); | |
| if (t1 != 0) | |
| return (t1); | |
| /* Throw this away too */ | |
| NFSM_DISSECT(NFSX_UNSIGNED); | |
| bmlen = fxdr_unsigned(uint32_t, *tl++); | |
| NFSM_DISSECT(bmlen * NFSX_UNSIGNED); | |
| tl += bmlen; | |
| return 0; | |
| } | |
| int | |
| nfsm_v4dissect_readlink_xx(struct nfs4_compound *cp, struct uio *uiop, | |
| struct mbuf **md, caddr_t *dpos) | |
| { | |
| uint32_t t1, *tl, op, status, linklen; | |
| t1 = nfsm_dissectf_xx(md, dpos, "uu", &op, &status); | |
| if (t1 != 0) | |
| return (t1); | |
| if (op != NFSV4OP_READLINK || status != 0) | |
| return (EBADRPC); | |
| /* Do this one manually for careful checking of sizes. */ | |
| NFSM_DISSECT(NFSX_UNSIGNED); | |
| linklen = fxdr_unsigned(uint32_t, *tl++); | |
| if (linklen <= 0) | |
| return (EBADRPC); | |
| return (nfsm_mbuftouio(md, uiop, MIN(linklen, uiop->uio_resid), dpos)); | |
| } | |
| int | |
| nfsm_v4dissect_changeinfo_xx(nfsv4changeinfo *ci, | |
| struct mbuf **md, caddr_t *dpos) | |
| { | |
| uint32_t *tl; | |
| NFSM_DISSECT(5 * NFSX_UNSIGNED); | |
| ci->ciatomic = fxdr_unsigned(uint32_t, *tl++); | |
| ci->cibefore = fxdr_hyper(tl); tl += 2; | |
| ci->ciafter = fxdr_hyper(tl); tl += 2; | |
| return (0); | |
| } | |
| int | |
| nfsm_v4dissect_attrs_xx(struct nfsv4_fattr *fa, struct mbuf **md, caddr_t *dpos) | |
| { | |
| uint32_t t1, *tl, bmlen, bmval[2], attrlen, len = 0; | |
| /* Bitmap length + value */ | |
| NFSM_DISSECT(NFSX_UNSIGNED); | |
| bmlen = fxdr_unsigned(uint32_t, *tl++); | |
| if (bmlen > 2) | |
| return (EBADRPC); | |
| if (bmlen == 0) | |
| return (0); | |
| NFSM_DISSECT(nfsm_rndup(bmlen << 2) + NFSX_UNSIGNED); | |
| bmval[0] = bmlen > 0 ? fxdr_unsigned(uint32_t, *tl++) : 0; | |
| bmval[1] = bmlen > 1 ? fxdr_unsigned(uint32_t, *tl++) : 0; | |
| /* Attribute length */ | |
| attrlen = fxdr_unsigned(uint32_t, *tl++); | |
| /* | |
| * XXX check for correct (<=) attributes mask return from | |
| * server. need to pass this in. | |
| */ | |
| if (FA4_ISSET(FA4_TYPE, bmval)) { | |
| /* overflow check */ | |
| NFSM_DISSECT(NFSX_UNSIGNED); | |
| fa->fa4_type = fxdr_unsigned(uint32_t, *tl++); | |
| fa->fa4_valid |= FA4V_TYPE; | |
| len += NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_CHANGE, bmval)) { | |
| NFSM_DISSECT(2 * NFSX_UNSIGNED); | |
| fa->fa4_changeid = fxdr_hyper(tl); | |
| fa->fa4_valid |= FA4V_CHANGEID; | |
| len += 2 * NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_SIZE, bmval)) { | |
| NFSM_DISSECT(2 * NFSX_UNSIGNED); | |
| fa->fa4_size = fxdr_hyper(tl); | |
| fa->fa4_valid |= FA4V_SIZE; | |
| len += 2 * NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_FSID, bmval)) { | |
| NFSM_DISSECT(4 * NFSX_UNSIGNED); | |
| fa->fa4_fsid_major = fxdr_hyper(tl); tl += 2; | |
| fa->fa4_fsid_minor = fxdr_hyper(tl); | |
| fa->fa4_valid |= FA4V_SIZE; | |
| len += 4 * NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_LEASE_TIME, bmval)) { | |
| NFSM_DISSECT(NFSX_UNSIGNED); | |
| fa->fa4_lease_time = fxdr_unsigned(uint32_t, *tl++); | |
| fa->fa4_valid |= FA4V_LEASE_TIME; | |
| len += NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_FILEID, bmval)) { | |
| NFSM_DISSECT(2 * NFSX_UNSIGNED); | |
| fa->fa4_fileid = fxdr_hyper(tl); | |
| fa->fa4_valid |= FA4V_FILEID; | |
| len += 2 * NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_FILES_FREE, bmval)) { | |
| NFSM_DISSECT(2 * NFSX_UNSIGNED); | |
| fa->fa4_ffree = fxdr_hyper(tl); | |
| fa->fa4_valid |= FA4V_FFREE; | |
| len += 2 * NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_FILES_TOTAL, bmval)) { | |
| NFSM_DISSECT(2 * NFSX_UNSIGNED); | |
| fa->fa4_ftotal = fxdr_hyper(tl); | |
| fa->fa4_valid |= FA4V_FTOTAL; | |
| len += 2 * NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_MAXFILESIZE, bmval)) { | |
| NFSM_DISSECT(2 * NFSX_UNSIGNED); | |
| fa->fa4_maxfilesize = fxdr_hyper(tl); | |
| fa->fa4_valid |= FA4V_MAXFILESIZE; | |
| len += 2 * NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_MAXNAME, bmval)) { | |
| NFSM_DISSECT(NFSX_UNSIGNED); | |
| fa->fa4_maxname = fxdr_unsigned(uint32_t, *tl++); | |
| fa->fa4_valid |= FA4V_MAXNAME; | |
| len += NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_MAXREAD, bmval)) { | |
| NFSM_DISSECT(2 * NFSX_UNSIGNED); | |
| fa->fa4_maxread = fxdr_hyper(tl); | |
| fa->fa4_valid |= FA4V_MAXREAD; | |
| len += 2 * NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_MAXWRITE, bmval)) { | |
| NFSM_DISSECT(2 * NFSX_UNSIGNED); | |
| fa->fa4_maxwrite = fxdr_hyper(tl); | |
| fa->fa4_valid |= FA4V_MAXWRITE; | |
| len += 2 * NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_MODE, bmval)) { | |
| NFSM_DISSECT(NFSX_UNSIGNED); | |
| fa->fa4_mode = fxdr_unsigned(mode_t, *tl++); | |
| fa->fa4_valid |= FA4V_MODE; | |
| len += NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_NUMLINKS, bmval)) { | |
| NFSM_DISSECT(NFSX_UNSIGNED); | |
| fa->fa4_nlink = fxdr_unsigned(nlink_t, *tl++); | |
| fa->fa4_valid |= FA4V_NLINK; | |
| len += NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_OWNER, bmval)) { | |
| uint32_t ownerlen; | |
| int error; | |
| NFSM_DISSECT(NFSX_UNSIGNED); | |
| ownerlen = fxdr_unsigned(uint32_t, *tl++); | |
| NFSM_DISSECT(nfsm_rndup(ownerlen)); | |
| error = idmap_name_to_uid((char *)tl, ownerlen, &fa->fa4_uid); | |
| if (error) | |
| fa->fa4_uid = -2; | |
| fa->fa4_valid |= FA4V_UID; | |
| len += NFSX_UNSIGNED + nfsm_rndup(ownerlen); | |
| } | |
| if (FA4_ISSET(FA4_OWNER_GROUP, bmval)) { | |
| uint32_t ownergrouplen; | |
| int error; | |
| NFSM_DISSECT(NFSX_UNSIGNED); | |
| ownergrouplen = fxdr_unsigned(uint32_t, *tl++); | |
| NFSM_DISSECT(nfsm_rndup(ownergrouplen)); | |
| error = idmap_name_to_gid((char *)tl, | |
| ownergrouplen, &fa->fa4_gid); | |
| if (error) | |
| fa->fa4_gid = -2; | |
| fa->fa4_valid |= FA4V_GID; | |
| len += NFSX_UNSIGNED + nfsm_rndup(ownergrouplen); | |
| } | |
| if (FA4_ISSET(FA4_RAWDEV, bmval)) { | |
| NFSM_DISSECT(2 * NFSX_UNSIGNED); | |
| fa->fa4_rdev_major = fxdr_unsigned(uint32_t, *tl++); | |
| fa->fa4_rdev_minor = fxdr_unsigned(uint32_t, *tl++); | |
| fa->fa4_valid |= FA4V_RDEV; | |
| len += 2 * NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_SPACE_AVAIL, bmval)) { | |
| NFSM_DISSECT(2 * NFSX_UNSIGNED); | |
| fa->fa4_savail = fxdr_hyper(tl); | |
| fa->fa4_valid |= FA4V_SAVAIL; | |
| len += 2 * NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_SPACE_FREE, bmval)) { | |
| NFSM_DISSECT(2 * NFSX_UNSIGNED); | |
| fa->fa4_sfree = fxdr_hyper(tl); | |
| fa->fa4_valid |= FA4V_SFREE; | |
| len += 2 * NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_SPACE_TOTAL, bmval)) { | |
| NFSM_DISSECT(2 * NFSX_UNSIGNED); | |
| fa->fa4_stotal = fxdr_hyper(tl); | |
| fa->fa4_valid |= FA4V_STOTAL; | |
| len += 2 * NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_SPACE_USED, bmval)) { | |
| NFSM_ADV(2 * NFSX_UNSIGNED); | |
| len += 2 * NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_TIME_ACCESS, bmval)) { | |
| NFSM_MTOTIME(fa->fa4_atime); | |
| fa->fa4_valid |= FA4V_ATIME; | |
| len += 3 * NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_TIME_CREATE, bmval)) { | |
| NFSM_MTOTIME(fa->fa4_ctime); | |
| fa->fa4_valid |= FA4V_CTIME; | |
| len += 3 * NFSX_UNSIGNED; | |
| } | |
| if (FA4_ISSET(FA4_TIME_MODIFY, bmval)) { | |
| NFSM_MTOTIME(fa->fa4_mtime); | |
| fa->fa4_valid |= FA4V_MTIME; | |
| len += 3 * NFSX_UNSIGNED; | |
| } | |
| if (len != attrlen) | |
| return (EBADRPC); | |
| return (0); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment