a4611ab612
Inside the kernel, the minor() function was responsible for obtaining the device minor number of a character device. Because we made device numbers dynamically allocated and independent of the unit number passed to make_dev() a long time ago, it was actually a misnomer. If you really want to obtain the device number, you should use dev2udev(). We already converted all the drivers to use dev2unit() to obtain the device unit number, which is still used by a lot of drivers. I've noticed not a single driver passes NULL to dev2unit(). Even if they would, its behaviour would make little sense. This is why I've removed the NULL check. Ths commit removes minor(), minor2unit() and unit2minor() from the kernel. Because there was a naming collision with uminor(), we can rename umajor() and uminor() back to major() and minor(). This means that the makedev(3) manual page also applies to kernel space code now. I suspect umajor() and uminor() isn't used that often in external code, but to make it easier for other parties to port their code, I've increased __FreeBSD_version to 800062.
1368 lines
32 KiB
C
1368 lines
32 KiB
C
/* $FreeBSD$ */
|
|
/* $Id: nfs4_subs.c,v 1.52 2003/11/05 14:58:59 rees Exp $ */
|
|
|
|
/*-
|
|
* copyright (c) 2003
|
|
* the regents of the university of michigan
|
|
* all rights reserved
|
|
*
|
|
* permission is granted to use, copy, create derivative works and redistribute
|
|
* this software and such derivative works for any purpose, so long as the name
|
|
* of the university of michigan is not used in any advertising or publicity
|
|
* pertaining to the use or distribution of this software without specific,
|
|
* written prior authorization. if the above copyright notice or any other
|
|
* identification of the university of michigan is included in any copy of any
|
|
* portion of this software, then the disclaimer below must also be included.
|
|
*
|
|
* this software is provided as is, without representation from the university
|
|
* of michigan as to its fitness for any purpose, and without warranty by the
|
|
* university of michigan of any kind, either express or implied, including
|
|
* without limitation the implied warranties of merchantability and fitness for
|
|
* a particular purpose. the regents of the university of michigan shall not be
|
|
* liable for any damages, including special, indirect, incidental, or
|
|
* consequential damages, with respect to any claim arising out of or in
|
|
* connection with the use of the software, even if it has been or is hereafter
|
|
* advised of the possibility of such damages.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/bio.h>
|
|
#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/sysent.h>
|
|
#include <sys/syscall.h>
|
|
#include <sys/sysproto.h>
|
|
#include <sys/fcntl.h>
|
|
|
|
#include <machine/stdarg.h>
|
|
|
|
#include <vm/vm.h>
|
|
#include <vm/vm_object.h>
|
|
#include <vm/vm_extern.h>
|
|
#include <vm/uma.h>
|
|
|
|
#include <rpc/rpcclnt.h>
|
|
|
|
#include <nfs/rpcv2.h>
|
|
#include <nfs/nfsproto.h>
|
|
#include <nfsclient/nfs.h>
|
|
#include <nfs4client/nfs4.h>
|
|
#include <nfsclient/nfsnode.h>
|
|
#include <nfsclient/nfsmount.h>
|
|
#include <nfs/xdr_subs.h>
|
|
#include <nfsclient/nfsm_subs.h>
|
|
|
|
#include <nfs4client/nfs4_dev.h>
|
|
#include <nfs4client/nfs4_idmap.h>
|
|
#include <nfs4client/nfs4m_subs.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_ACCESS, __getattr_bm);
|
|
FA4_SET(FA4_TIME_CREATE, __getattr_bm);
|
|
FA4_SET(FA4_TIME_METADATA, __getattr_bm);
|
|
FA4_SET(FA4_TIME_MODIFY, __getattr_bm);
|
|
|
|
FA4_SET(FA4_TYPE, __readdir_bm);
|
|
FA4_SET(FA4_FSID, __readdir_bm);
|
|
FA4_SET(FA4_FILEID, __readdir_bm);
|
|
FA4_SET(FA4_RDATTR_ERROR, __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 {
|
|
t1 = nfsm_strtmbuf(mb, bpos, (const char *)tag, siz);
|
|
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",
|
|
major(c->vap->va_rdev), minor(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_RDATTR_ERROR, bmval)) {
|
|
/* ignore for now; we only ask for it so the compound won't fail */
|
|
NFSM_DISSECT(NFSX_UNSIGNED);
|
|
tl++;
|
|
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_btime);
|
|
fa->fa4_valid |= FA4V_BTIME;
|
|
len += 3 * NFSX_UNSIGNED;
|
|
}
|
|
if (FA4_ISSET(FA4_TIME_METADATA, 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);
|
|
}
|