/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static bool_t xdr_fastshorten(XDR *, uint_t); /* * These are the XDR routines used to serialize and deserialize * the various structures passed as parameters accross the network * between NFS clients and servers. */ /* * File access handle * The fhandle struct is treated a opaque data on the wire */ bool_t xdr_fhandle(XDR *xdrs, fhandle_t *fh) { int32_t *ptr; int32_t *fhp; if (xdrs->x_op == XDR_FREE) return (TRUE); ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t))); if (ptr != NULL) { fhp = (int32_t *)fh; if (xdrs->x_op == XDR_DECODE) { *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp = *ptr; } else { *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr = *fhp; } return (TRUE); } return (xdr_opaque(xdrs, (caddr_t)fh, NFS_FHSIZE)); } bool_t xdr_fastfhandle(XDR *xdrs, fhandle_t **fh) { int32_t *ptr; if (xdrs->x_op != XDR_DECODE) return (FALSE); ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t))); if (ptr != NULL) { *fh = (fhandle_t *)ptr; return (TRUE); } return (FALSE); } /* * Arguments to remote write and writecache */ bool_t xdr_writeargs(XDR *xdrs, struct nfswriteargs *wa) { int32_t *ptr; int32_t *fhp; switch (xdrs->x_op) { case XDR_DECODE: wa->wa_args = &wa->wa_args_buf; ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t)) + 3 * BYTES_PER_XDR_UNIT); if (ptr != NULL) { fhp = (int32_t *)&wa->wa_fhandle; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp = *ptr++; wa->wa_begoff = IXDR_GET_U_INT32(ptr); wa->wa_offset = IXDR_GET_U_INT32(ptr); wa->wa_totcount = IXDR_GET_U_INT32(ptr); wa->wa_mblk = NULL; wa->wa_data = NULL; wa->wa_rlist = NULL; wa->wa_conn = NULL; if (xdrs->x_ops == &xdrmblk_ops) { return (xdrmblk_getmblk(xdrs, &wa->wa_mblk, &wa->wa_count)); } else { if (xdrs->x_ops == &xdrrdmablk_ops) { if (xdrrdma_getrdmablk(xdrs, &wa->wa_rlist, &wa->wa_count, &wa->wa_conn, NFS_MAXDATA) == TRUE) return (xdrrdma_read_from_client( wa->wa_rlist, &wa->wa_conn, wa->wa_count)); wa->wa_rlist = NULL; wa->wa_conn = NULL; } } /* * It is just as efficient to xdr_bytes * an array of unknown length as to inline copy it. */ return (xdr_bytes(xdrs, &wa->wa_data, &wa->wa_count, NFS_MAXDATA)); } if (xdr_fhandle(xdrs, &wa->wa_fhandle) && xdr_u_int(xdrs, &wa->wa_begoff) && xdr_u_int(xdrs, &wa->wa_offset) && xdr_u_int(xdrs, &wa->wa_totcount)) { /* deal with the variety of data transfer types */ wa->wa_mblk = NULL; wa->wa_data = NULL; wa->wa_rlist = NULL; wa->wa_conn = NULL; if (xdrs->x_ops == &xdrmblk_ops) { if (xdrmblk_getmblk(xdrs, &wa->wa_mblk, &wa->wa_count) == TRUE) return (TRUE); } else { if (xdrs->x_ops == &xdrrdmablk_ops) { if (xdrrdma_getrdmablk(xdrs, &wa->wa_rlist, &wa->wa_count, &wa->wa_conn, NFS_MAXDATA) == TRUE) return (xdrrdma_read_from_client( wa->wa_rlist, &wa->wa_conn, wa->wa_count)); wa->wa_rlist = NULL; wa->wa_conn = NULL; } } return (xdr_bytes(xdrs, &wa->wa_data, &wa->wa_count, NFS_MAXDATA)); } return (FALSE); case XDR_ENCODE: ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t)) + 3 * BYTES_PER_XDR_UNIT); if (ptr != NULL) { fhp = (int32_t *)&wa->wa_fhandle; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp; IXDR_PUT_U_INT32(ptr, wa->wa_begoff); IXDR_PUT_U_INT32(ptr, wa->wa_offset); IXDR_PUT_U_INT32(ptr, wa->wa_totcount); } else { if (!(xdr_fhandle(xdrs, &wa->wa_fhandle) && xdr_u_int(xdrs, &wa->wa_begoff) && xdr_u_int(xdrs, &wa->wa_offset) && xdr_u_int(xdrs, &wa->wa_totcount))) return (FALSE); } return (xdr_bytes(xdrs, &wa->wa_data, &wa->wa_count, NFS_MAXDATA)); case XDR_FREE: if (wa->wa_rlist) { (void) xdrrdma_free_clist(wa->wa_conn, wa->wa_rlist); wa->wa_rlist = NULL; } if (wa->wa_data != NULL) { kmem_free(wa->wa_data, wa->wa_count); wa->wa_data = NULL; } return (TRUE); } return (FALSE); } /* * File attributes */ bool_t xdr_fattr(XDR *xdrs, struct nfsfattr *na) { int32_t *ptr; if (xdrs->x_op == XDR_FREE) return (TRUE); ptr = XDR_INLINE(xdrs, 17 * BYTES_PER_XDR_UNIT); if (ptr != NULL) { if (xdrs->x_op == XDR_DECODE) { na->na_type = IXDR_GET_ENUM(ptr, enum nfsftype); na->na_mode = IXDR_GET_U_INT32(ptr); na->na_nlink = IXDR_GET_U_INT32(ptr); na->na_uid = IXDR_GET_U_INT32(ptr); na->na_gid = IXDR_GET_U_INT32(ptr); na->na_size = IXDR_GET_U_INT32(ptr); na->na_blocksize = IXDR_GET_U_INT32(ptr); na->na_rdev = IXDR_GET_U_INT32(ptr); na->na_blocks = IXDR_GET_U_INT32(ptr); na->na_fsid = IXDR_GET_U_INT32(ptr); na->na_nodeid = IXDR_GET_U_INT32(ptr); na->na_atime.tv_sec = IXDR_GET_U_INT32(ptr); na->na_atime.tv_usec = IXDR_GET_U_INT32(ptr); na->na_mtime.tv_sec = IXDR_GET_U_INT32(ptr); na->na_mtime.tv_usec = IXDR_GET_U_INT32(ptr); na->na_ctime.tv_sec = IXDR_GET_U_INT32(ptr); na->na_ctime.tv_usec = IXDR_GET_U_INT32(ptr); } else { IXDR_PUT_ENUM(ptr, na->na_type); IXDR_PUT_U_INT32(ptr, na->na_mode); IXDR_PUT_U_INT32(ptr, na->na_nlink); IXDR_PUT_U_INT32(ptr, na->na_uid); IXDR_PUT_U_INT32(ptr, na->na_gid); IXDR_PUT_U_INT32(ptr, na->na_size); IXDR_PUT_U_INT32(ptr, na->na_blocksize); IXDR_PUT_U_INT32(ptr, na->na_rdev); IXDR_PUT_U_INT32(ptr, na->na_blocks); IXDR_PUT_U_INT32(ptr, na->na_fsid); IXDR_PUT_U_INT32(ptr, na->na_nodeid); IXDR_PUT_U_INT32(ptr, na->na_atime.tv_sec); IXDR_PUT_U_INT32(ptr, na->na_atime.tv_usec); IXDR_PUT_U_INT32(ptr, na->na_mtime.tv_sec); IXDR_PUT_U_INT32(ptr, na->na_mtime.tv_usec); IXDR_PUT_U_INT32(ptr, na->na_ctime.tv_sec); IXDR_PUT_U_INT32(ptr, na->na_ctime.tv_usec); } return (TRUE); } if (xdr_enum(xdrs, (enum_t *)&na->na_type) && xdr_u_int(xdrs, &na->na_mode) && xdr_u_int(xdrs, &na->na_nlink) && xdr_u_int(xdrs, &na->na_uid) && xdr_u_int(xdrs, &na->na_gid) && xdr_u_int(xdrs, &na->na_size) && xdr_u_int(xdrs, &na->na_blocksize) && xdr_u_int(xdrs, &na->na_rdev) && xdr_u_int(xdrs, &na->na_blocks) && xdr_u_int(xdrs, &na->na_fsid) && xdr_u_int(xdrs, &na->na_nodeid) && xdr_nfs2_timeval(xdrs, &na->na_atime) && xdr_nfs2_timeval(xdrs, &na->na_mtime) && xdr_nfs2_timeval(xdrs, &na->na_ctime)) { return (TRUE); } return (FALSE); } #ifdef _LITTLE_ENDIAN bool_t xdr_fastfattr(XDR *xdrs, struct nfsfattr *na) { if (xdrs->x_op == XDR_FREE) return (TRUE); if (xdrs->x_op == XDR_DECODE) return (FALSE); na->na_type = htonl(na->na_type); na->na_mode = htonl(na->na_mode); na->na_nlink = htonl(na->na_nlink); na->na_uid = htonl(na->na_uid); na->na_gid = htonl(na->na_gid); na->na_size = htonl(na->na_size); na->na_blocksize = htonl(na->na_blocksize); na->na_rdev = htonl(na->na_rdev); na->na_blocks = htonl(na->na_blocks); na->na_fsid = htonl(na->na_fsid); na->na_nodeid = htonl(na->na_nodeid); na->na_atime.tv_sec = htonl(na->na_atime.tv_sec); na->na_atime.tv_usec = htonl(na->na_atime.tv_usec); na->na_mtime.tv_sec = htonl(na->na_mtime.tv_sec); na->na_mtime.tv_usec = htonl(na->na_mtime.tv_usec); na->na_ctime.tv_sec = htonl(na->na_ctime.tv_sec); na->na_ctime.tv_usec = htonl(na->na_ctime.tv_usec); return (TRUE); } #endif bool_t xdr_readlink(XDR *xdrs, fhandle_t *fh) { rdma_chunkinfo_t rci; struct xdr_ops *xops = xdrrdma_xops(); if (xdr_fhandle(xdrs, fh)) { if ((xdrs->x_ops == &xdrrdma_ops || xdrs->x_ops == xops) && xdrs->x_op == XDR_ENCODE) { rci.rci_type = RCI_REPLY_CHUNK; rci.rci_len = MAXPATHLEN; XDR_CONTROL(xdrs, XDR_RDMA_ADD_CHUNK, &rci); } return (TRUE); } return (FALSE); } /* * Arguments to remote read */ bool_t xdr_readargs(XDR *xdrs, struct nfsreadargs *ra) { int32_t *ptr; int32_t *fhp; rdma_chunkinfo_t rci; rdma_wlist_conn_info_t rwci; struct xdr_ops *xops = xdrrdma_xops(); if (xdrs->x_op == XDR_FREE) return (TRUE); ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t)) + 3 * BYTES_PER_XDR_UNIT); if (ptr != NULL) { if (xdrs->x_op == XDR_DECODE) { fhp = (int32_t *)&ra->ra_fhandle; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp = *ptr++; ra->ra_offset = IXDR_GET_INT32(ptr); ra->ra_count = IXDR_GET_INT32(ptr); ra->ra_totcount = IXDR_GET_INT32(ptr); } else { fhp = (int32_t *)&ra->ra_fhandle; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp; IXDR_PUT_INT32(ptr, ra->ra_offset); IXDR_PUT_INT32(ptr, ra->ra_count); IXDR_PUT_INT32(ptr, ra->ra_totcount); } } else { if (!xdr_fhandle(xdrs, &ra->ra_fhandle) || !xdr_u_int(xdrs, &ra->ra_offset) || !xdr_u_int(xdrs, &ra->ra_count) || !xdr_u_int(xdrs, &ra->ra_totcount)) { return (FALSE); } } if (ra->ra_count > NFS_MAXDATA) return (FALSE); ra->ra_wlist = NULL; ra->ra_conn = NULL; /* If this is xdrrdma_sizeof, record the expect response size */ if (xdrs->x_ops == xops && xdrs->x_op == XDR_ENCODE) { rci.rci_type = RCI_WRITE_ADDR_CHUNK; rci.rci_len = ra->ra_count; (void) XDR_CONTROL(xdrs, XDR_RDMA_ADD_CHUNK, &rci); } /* Nothing special to do, return */ if (xdrs->x_ops != &xdrrdma_ops || xdrs->x_op == XDR_FREE) return (TRUE); if (xdrs->x_op == XDR_ENCODE) { /* Place the target data location into the RDMA header */ rci.rci_type = RCI_WRITE_ADDR_CHUNK; rci.rci_a.rci_addr = ra->ra_data; rci.rci_len = ra->ra_count; rci.rci_clpp = &ra->ra_wlist; return (XDR_CONTROL(xdrs, XDR_RDMA_ADD_CHUNK, &rci)); } /* XDR_DECODE case */ (void) XDR_CONTROL(xdrs, XDR_RDMA_GET_WCINFO, &rwci); ra->ra_wlist = rwci.rwci_wlist; ra->ra_conn = rwci.rwci_conn; return (TRUE); } /* * Status OK portion of remote read reply */ bool_t xdr_rrok(XDR *xdrs, struct nfsrrok *rrok) { bool_t ret; mblk_t *mp; struct xdr_ops *xops = xdrrdma_xops(); if (xdr_fattr(xdrs, &rrok->rrok_attr) == FALSE) return (FALSE); /* deal with RDMA separately */ if (xdrs->x_ops == &xdrrdma_ops || xdrs->x_ops == xops) { if (xdrs->x_op == XDR_ENCODE && rrok->rrok_mp != NULL) { ret = xdr_bytes(xdrs, (char **)&rrok->rrok_data, &rrok->rrok_count, NFS_MAXDATA); return (ret); } if (xdrs->x_op == XDR_ENCODE) { if (xdr_u_int(xdrs, &rrok->rrok_count) == FALSE) { return (FALSE); } /* * If read data sent by wlist (RDMA_WRITE), don't do * xdr_bytes() below. RDMA_WRITE transfers the data. */ if (rrok->rrok_wlist) { if (rrok->rrok_count != 0) { return (xdrrdma_send_read_data( xdrs, rrok->rrok_count, rrok->rrok_wlist)); } return (TRUE); } if (rrok->rrok_count == 0) { return (TRUE); } } else { struct clist *cl; uint32_t count; XDR_CONTROL(xdrs, XDR_RDMA_GET_WLIST, &cl); if (cl) { if (!xdr_u_int(xdrs, &count)) return (FALSE); if (count == 0) { rrok->rrok_wlist_len = 0; rrok->rrok_count = 0; } else { rrok->rrok_wlist_len = clist_len(cl); if (rrok->rrok_wlist_len != roundup(count, BYTES_PER_XDR_UNIT)) { rrok->rrok_wlist_len = 0; rrok->rrok_count = 0; return (FALSE); } rrok->rrok_count = count; } return (TRUE); } } ret = xdr_bytes(xdrs, (char **)&rrok->rrok_data, &rrok->rrok_count, NFS_MAXDATA); return (ret); } if (xdrs->x_op == XDR_ENCODE) { int i, rndup; mp = rrok->rrok_mp; if (mp != NULL && xdrs->x_ops == &xdrmblk_ops) { mp->b_wptr += rrok->rrok_count; rndup = BYTES_PER_XDR_UNIT - (rrok->rrok_count % BYTES_PER_XDR_UNIT); if (rndup != BYTES_PER_XDR_UNIT) for (i = 0; i < rndup; i++) *mp->b_wptr++ = '\0'; if (xdrmblk_putmblk(xdrs, mp, rrok->rrok_count) == TRUE) { rrok->rrok_mp = NULL; return (TRUE); } } /* * Fall thru for the xdr_bytes() * * Note: the mblk mp will be freed in rfs_rdfree */ } ret = xdr_bytes(xdrs, (char **)&rrok->rrok_data, &rrok->rrok_count, NFS_MAXDATA); return (ret); } static struct xdr_discrim rdres_discrim[2] = { { NFS_OK, xdr_rrok }, { __dontcare__, NULL_xdrproc_t } }; /* * Reply from remote read */ bool_t xdr_rdresult(XDR *xdrs, struct nfsrdresult *rr) { return (xdr_union(xdrs, (enum_t *)&(rr->rr_status), (caddr_t)&(rr->rr_ok), rdres_discrim, xdr_void)); } /* * File attributes which can be set */ bool_t xdr_sattr(XDR *xdrs, struct nfssattr *sa) { if (xdr_u_int(xdrs, &sa->sa_mode) && xdr_u_int(xdrs, &sa->sa_uid) && xdr_u_int(xdrs, &sa->sa_gid) && xdr_u_int(xdrs, &sa->sa_size) && xdr_nfs2_timeval(xdrs, &sa->sa_atime) && xdr_nfs2_timeval(xdrs, &sa->sa_mtime)) { return (TRUE); } return (FALSE); } static struct xdr_discrim attrstat_discrim[2] = { { (int)NFS_OK, xdr_fattr }, { __dontcare__, NULL_xdrproc_t } }; /* * Reply status with file attributes */ bool_t xdr_attrstat(XDR *xdrs, struct nfsattrstat *ns) { return (xdr_union(xdrs, (enum_t *)&(ns->ns_status), (caddr_t)&(ns->ns_attr), attrstat_discrim, xdr_void)); } /* * Fast reply status with file attributes */ bool_t xdr_fastattrstat(XDR *xdrs, struct nfsattrstat *ns) { #if defined(_LITTLE_ENDIAN) /* * we deal with the discriminator; it's an enum */ if (!xdr_fastenum(xdrs, (enum_t *)&ns->ns_status)) return (FALSE); if (ns->ns_status == NFS_OK) return (xdr_fastfattr(xdrs, &ns->ns_attr)); #elif defined(_BIG_ENDIAN) if (ns->ns_status == NFS_OK) return (TRUE); #endif return (xdr_fastshorten(xdrs, sizeof (*ns))); } /* * NFS_OK part of read sym link reply union */ bool_t xdr_srok(XDR *xdrs, struct nfssrok *srok) { /* * It is just as efficient to xdr_bytes * an array of unknown length as to inline copy it. */ return (xdr_bytes(xdrs, &srok->srok_data, &srok->srok_count, NFS_MAXPATHLEN)); } static struct xdr_discrim rdlnres_discrim[2] = { { (int)NFS_OK, xdr_srok }, { __dontcare__, NULL_xdrproc_t } }; /* * Result of reading symbolic link */ bool_t xdr_rdlnres(XDR *xdrs, struct nfsrdlnres *rl) { return (xdr_union(xdrs, (enum_t *)&(rl->rl_status), (caddr_t)&(rl->rl_srok), rdlnres_discrim, xdr_void)); } /* * Arguments to readdir */ bool_t xdr_rddirargs(XDR *xdrs, struct nfsrddirargs *rda) { int32_t *ptr; int32_t *fhp; rdma_chunkinfo_t rci; struct xdr_ops *xops = xdrrdma_xops(); if (xdrs->x_op == XDR_FREE) return (TRUE); ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t)) + 2 * BYTES_PER_XDR_UNIT); if ((xdrs->x_ops == &xdrrdma_ops || xdrs->x_ops == xops) && xdrs->x_op == XDR_ENCODE) { rci.rci_type = RCI_REPLY_CHUNK; rci.rci_len = rda->rda_count; XDR_CONTROL(xdrs, XDR_RDMA_ADD_CHUNK, &rci); } if (ptr != NULL) { if (xdrs->x_op == XDR_DECODE) { fhp = (int32_t *)&rda->rda_fh; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp = *ptr++; rda->rda_offset = IXDR_GET_U_INT32(ptr); rda->rda_count = IXDR_GET_U_INT32(ptr); } else { fhp = (int32_t *)&rda->rda_fh; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp; IXDR_PUT_U_INT32(ptr, rda->rda_offset); IXDR_PUT_U_INT32(ptr, rda->rda_count); } return (TRUE); } if (xdr_fhandle(xdrs, &rda->rda_fh) && xdr_u_int(xdrs, &rda->rda_offset) && xdr_u_int(xdrs, &rda->rda_count)) { return (TRUE); } return (FALSE); } /* * Directory read reply: * union (enum status) { * NFS_OK: entlist; * boolean eof; * default: * } * * Directory entries * struct direct { * off_t d_off; * offset of next entry * * u_int d_fileno; * inode number of entry * * u_short d_reclen; * length of this record * * u_short d_namlen; * length of string in d_name * * char d_name[MAXNAMLEN + 1]; * name no longer than this * * }; * are on the wire as: * union entlist (boolean valid) { * TRUE: struct otw_dirent; * u_int nxtoffset; * union entlist; * FALSE: * } * where otw_dirent is: * struct dirent { * u_int de_fid; * string de_name; * } */ #ifdef nextdp #undef nextdp #endif #define nextdp(dp) ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen)) #ifdef roundup #undef roundup #endif #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) /* * ENCODE ONLY */ bool_t xdr_putrddirres(XDR *xdrs, struct nfsrddirres *rd) { struct dirent64 *dp; char *name; int size; uint_t namlen; bool_t true = TRUE; bool_t false = FALSE; int entrysz; int tofit; int bufsize; uint32_t ino, off; if (xdrs->x_op != XDR_ENCODE) return (FALSE); if (!xdr_enum(xdrs, (enum_t *)&rd->rd_status)) return (FALSE); if (rd->rd_status != NFS_OK) return (TRUE); bufsize = 1 * BYTES_PER_XDR_UNIT; for (size = rd->rd_size, dp = rd->rd_entries; size > 0; size -= dp->d_reclen, dp = nextdp(dp)) { if (dp->d_reclen == 0 /* || DIRSIZ(dp) > dp->d_reclen */) return (FALSE); if (dp->d_ino == 0) continue; ino = (uint32_t)dp->d_ino; /* for LP64 we clip the bits */ if (dp->d_ino != (ino64_t)ino) /* and they better be zeros */ return (FALSE); off = (uint32_t)dp->d_off; name = dp->d_name; namlen = (uint_t)strlen(name); entrysz = (1 + 1 + 1 + 1) * BYTES_PER_XDR_UNIT + roundup(namlen, BYTES_PER_XDR_UNIT); tofit = entrysz + 2 * BYTES_PER_XDR_UNIT; if (bufsize + tofit > rd->rd_bufsize) { rd->rd_eof = FALSE; break; } if (!xdr_bool(xdrs, &true) || !xdr_u_int(xdrs, &ino) || !xdr_bytes(xdrs, &name, &namlen, NFS_MAXNAMLEN) || !xdr_u_int(xdrs, &off)) { return (FALSE); } bufsize += entrysz; } if (!xdr_bool(xdrs, &false)) return (FALSE); if (!xdr_bool(xdrs, &rd->rd_eof)) return (FALSE); return (TRUE); } /* * DECODE ONLY */ bool_t xdr_getrddirres(XDR *xdrs, struct nfsrddirres *rd) { struct dirent64 *dp; uint_t namlen; int size; bool_t valid; uint32_t offset; uint_t fileid, this_reclen; if (xdrs->x_op != XDR_DECODE) return (FALSE); if (!xdr_enum(xdrs, (enum_t *)&rd->rd_status)) return (FALSE); if (rd->rd_status != NFS_OK) return (TRUE); size = rd->rd_size; dp = rd->rd_entries; offset = rd->rd_offset; for (;;) { if (!xdr_bool(xdrs, &valid)) return (FALSE); if (!valid) break; if (!xdr_u_int(xdrs, &fileid) || !xdr_u_int(xdrs, &namlen)) return (FALSE); this_reclen = DIRENT64_RECLEN(namlen); if (this_reclen > size) { rd->rd_eof = FALSE; goto bufovflw; } if (!xdr_opaque(xdrs, dp->d_name, namlen)|| !xdr_u_int(xdrs, &offset)) { return (FALSE); } bzero(&dp->d_name[namlen], DIRENT64_NAMELEN(this_reclen) - namlen); dp->d_ino = (ino64_t)fileid; dp->d_reclen = this_reclen; dp->d_off = (off64_t)offset; size -= dp->d_reclen; dp = nextdp(dp); } if (!xdr_bool(xdrs, &rd->rd_eof)) return (FALSE); bufovflw: rd->rd_size = (uint32_t)((char *)dp - (char *)(rd->rd_entries)); rd->rd_offset = offset; return (TRUE); } /* * Arguments for directory operations */ bool_t xdr_diropargs(XDR *xdrs, struct nfsdiropargs *da) { int32_t *ptr; int32_t *fhp; uint32_t size; uint32_t nodesize; int i; int rndup; char *cptr; if (xdrs->x_op == XDR_DECODE) { da->da_fhandle = &da->da_fhandle_buf; ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t)) + 1 * BYTES_PER_XDR_UNIT); if (ptr != NULL) { fhp = (int32_t *)da->da_fhandle; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp = *ptr++; size = IXDR_GET_U_INT32(ptr); if (size > NFS_MAXNAMLEN) return (FALSE); nodesize = size + 1; if (nodesize == 0) return (TRUE); if (da->da_name == NULL) { da->da_name = kmem_alloc(nodesize, KM_NOSLEEP); if (da->da_name == NULL) return (FALSE); da->da_flags |= DA_FREENAME; } ptr = XDR_INLINE(xdrs, RNDUP(size)); if (ptr == NULL) { if (!xdr_opaque(xdrs, da->da_name, size)) { if (da->da_flags & DA_FREENAME) { kmem_free(da->da_name, nodesize); da->da_name = NULL; } return (FALSE); } da->da_name[size] = '\0'; if (strlen(da->da_name) != size) { if (da->da_flags & DA_FREENAME) { kmem_free(da->da_name, nodesize); da->da_name = NULL; } return (FALSE); } return (TRUE); } bcopy(ptr, da->da_name, size); da->da_name[size] = '\0'; if (strlen(da->da_name) != size) { if (da->da_flags & DA_FREENAME) { kmem_free(da->da_name, nodesize); da->da_name = NULL; } return (FALSE); } return (TRUE); } if (da->da_name == NULL) da->da_flags |= DA_FREENAME; } if (xdrs->x_op == XDR_ENCODE) { size = (uint32_t)strlen(da->da_name); if (size > NFS_MAXNAMLEN) return (FALSE); ptr = XDR_INLINE(xdrs, (int)(RNDUP(sizeof (fhandle_t)) + 1 * BYTES_PER_XDR_UNIT + RNDUP(size))); if (ptr != NULL) { fhp = (int32_t *)da->da_fhandle; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp; IXDR_PUT_U_INT32(ptr, (uint32_t)size); bcopy(da->da_name, ptr, size); rndup = BYTES_PER_XDR_UNIT - (size % BYTES_PER_XDR_UNIT); if (rndup != BYTES_PER_XDR_UNIT) { cptr = (char *)ptr + size; for (i = 0; i < rndup; i++) *cptr++ = '\0'; } return (TRUE); } } if (xdrs->x_op == XDR_FREE) { if (da->da_name == NULL) return (TRUE); size = (uint32_t)strlen(da->da_name); if (size > NFS_MAXNAMLEN) return (FALSE); if (da->da_flags & DA_FREENAME) kmem_free(da->da_name, size + 1); da->da_name = NULL; return (TRUE); } if (xdr_fhandle(xdrs, da->da_fhandle) && xdr_string(xdrs, &da->da_name, NFS_MAXNAMLEN)) { return (TRUE); } return (FALSE); } /* * NFS_OK part of directory operation result */ bool_t xdr_drok(XDR *xdrs, struct nfsdrok *drok) { int32_t *ptr; int32_t *fhp; struct nfsfattr *na; if (xdrs->x_op == XDR_FREE) return (TRUE); ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t)) + 17 * BYTES_PER_XDR_UNIT); if (ptr != NULL) { if (xdrs->x_op == XDR_DECODE) { fhp = (int32_t *)&drok->drok_fhandle; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp++ = *ptr++; *fhp = *ptr++; na = &drok->drok_attr; na->na_type = IXDR_GET_ENUM(ptr, enum nfsftype); na->na_mode = IXDR_GET_U_INT32(ptr); na->na_nlink = IXDR_GET_U_INT32(ptr); na->na_uid = IXDR_GET_U_INT32(ptr); na->na_gid = IXDR_GET_U_INT32(ptr); na->na_size = IXDR_GET_U_INT32(ptr); na->na_blocksize = IXDR_GET_U_INT32(ptr); na->na_rdev = IXDR_GET_U_INT32(ptr); na->na_blocks = IXDR_GET_U_INT32(ptr); na->na_fsid = IXDR_GET_U_INT32(ptr); na->na_nodeid = IXDR_GET_U_INT32(ptr); na->na_atime.tv_sec = IXDR_GET_U_INT32(ptr); na->na_atime.tv_usec = IXDR_GET_U_INT32(ptr); na->na_mtime.tv_sec = IXDR_GET_U_INT32(ptr); na->na_mtime.tv_usec = IXDR_GET_U_INT32(ptr); na->na_ctime.tv_sec = IXDR_GET_U_INT32(ptr); na->na_ctime.tv_usec = IXDR_GET_U_INT32(ptr); } else { fhp = (int32_t *)&drok->drok_fhandle; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp++; *ptr++ = *fhp; na = &drok->drok_attr; IXDR_PUT_ENUM(ptr, na->na_type); IXDR_PUT_U_INT32(ptr, na->na_mode); IXDR_PUT_U_INT32(ptr, na->na_nlink); IXDR_PUT_U_INT32(ptr, na->na_uid); IXDR_PUT_U_INT32(ptr, na->na_gid); IXDR_PUT_U_INT32(ptr, na->na_size); IXDR_PUT_U_INT32(ptr, na->na_blocksize); IXDR_PUT_U_INT32(ptr, na->na_rdev); IXDR_PUT_U_INT32(ptr, na->na_blocks); IXDR_PUT_U_INT32(ptr, na->na_fsid); IXDR_PUT_U_INT32(ptr, na->na_nodeid); IXDR_PUT_U_INT32(ptr, na->na_atime.tv_sec); IXDR_PUT_U_INT32(ptr, na->na_atime.tv_usec); IXDR_PUT_U_INT32(ptr, na->na_mtime.tv_sec); IXDR_PUT_U_INT32(ptr, na->na_mtime.tv_usec); IXDR_PUT_U_INT32(ptr, na->na_ctime.tv_sec); IXDR_PUT_U_INT32(ptr, na->na_ctime.tv_usec); } return (TRUE); } if (xdr_fhandle(xdrs, &drok->drok_fhandle) && xdr_fattr(xdrs, &drok->drok_attr)) { return (TRUE); } return (FALSE); } #ifdef _LITTLE_ENDIAN bool_t xdr_fastdrok(XDR *xdrs, struct nfsdrok *drok) { struct nfsfattr *na; if (xdrs->x_op == XDR_FREE) return (TRUE); if (xdrs->x_op == XDR_DECODE) return (FALSE); na = &drok->drok_attr; na->na_type = (enum nfsftype)htonl(na->na_type); na->na_mode = (uint32_t)htonl(na->na_mode); na->na_nlink = (uint32_t)htonl(na->na_nlink); na->na_uid = (uint32_t)htonl(na->na_uid); na->na_gid = (uint32_t)htonl(na->na_gid); na->na_size = (uint32_t)htonl(na->na_size); na->na_blocksize = (uint32_t)htonl(na->na_blocksize); na->na_rdev = (uint32_t)htonl(na->na_rdev); na->na_blocks = (uint32_t)htonl(na->na_blocks); na->na_fsid = (uint32_t)htonl(na->na_fsid); na->na_nodeid = (uint32_t)htonl(na->na_nodeid); na->na_atime.tv_sec = htonl(na->na_atime.tv_sec); na->na_atime.tv_usec = htonl(na->na_atime.tv_usec); na->na_mtime.tv_sec = htonl(na->na_mtime.tv_sec); na->na_mtime.tv_usec = htonl(na->na_mtime.tv_usec); na->na_ctime.tv_sec = htonl(na->na_ctime.tv_sec); na->na_ctime.tv_usec = htonl(na->na_ctime.tv_usec); return (TRUE); } #endif static struct xdr_discrim diropres_discrim[2] = { { NFS_OK, xdr_drok }, { __dontcare__, NULL_xdrproc_t } }; /* * Results from directory operation */ bool_t xdr_diropres(XDR *xdrs, struct nfsdiropres *dr) { return (xdr_union(xdrs, (enum_t *)&(dr->dr_status), (caddr_t)&(dr->dr_drok), diropres_discrim, xdr_void)); } /* * Results from directory operation */ bool_t xdr_fastdiropres(XDR *xdrs, struct nfsdiropres *dr) { #if defined(_LITTLE_ENDIAN) /* * we deal with the discriminator; it's an enum */ if (!xdr_fastenum(xdrs, (enum_t *)&dr->dr_status)) return (FALSE); if (dr->dr_status == NFS_OK) return (xdr_fastdrok(xdrs, &dr->dr_drok)); #elif defined(_BIG_ENDIAN) if (dr->dr_status == NFS_OK) return (TRUE); #endif return (xdr_fastshorten(xdrs, sizeof (*dr))); } /* * Time Structure, unsigned */ bool_t xdr_nfs2_timeval(XDR *xdrs, struct nfs2_timeval *tv) { if (xdr_u_int(xdrs, &tv->tv_sec) && xdr_u_int(xdrs, &tv->tv_usec)) return (TRUE); return (FALSE); } /* * arguments to setattr */ bool_t xdr_saargs(XDR *xdrs, struct nfssaargs *argp) { int32_t *ptr; int32_t *arg; struct nfssattr *sa; if (xdrs->x_op == XDR_FREE) return (TRUE); ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t)) + 8 * BYTES_PER_XDR_UNIT); if (ptr != NULL) { if (xdrs->x_op == XDR_DECODE) { arg = (int32_t *)&argp->saa_fh; *arg++ = *ptr++; *arg++ = *ptr++; *arg++ = *ptr++; *arg++ = *ptr++; *arg++ = *ptr++; *arg++ = *ptr++; *arg++ = *ptr++; *arg = *ptr++; sa = &argp->saa_sa; sa->sa_mode = IXDR_GET_U_INT32(ptr); sa->sa_uid = IXDR_GET_U_INT32(ptr); sa->sa_gid = IXDR_GET_U_INT32(ptr); sa->sa_size = IXDR_GET_U_INT32(ptr); sa->sa_atime.tv_sec = IXDR_GET_U_INT32(ptr); sa->sa_atime.tv_usec = IXDR_GET_U_INT32(ptr); sa->sa_mtime.tv_sec = IXDR_GET_U_INT32(ptr); sa->sa_mtime.tv_usec = IXDR_GET_U_INT32(ptr); } else { arg = (int32_t *)&argp->saa_fh; *ptr++ = *arg++; *ptr++ = *arg++; *ptr++ = *arg++; *ptr++ = *arg++; *ptr++ = *arg++; *ptr++ = *arg++; *ptr++ = *arg++; *ptr++ = *arg; sa = &argp->saa_sa; IXDR_PUT_U_INT32(ptr, sa->sa_mode); IXDR_PUT_U_INT32(ptr, sa->sa_uid); IXDR_PUT_U_INT32(ptr, sa->sa_gid); IXDR_PUT_U_INT32(ptr, sa->sa_size); IXDR_PUT_U_INT32(ptr, sa->sa_atime.tv_sec); IXDR_PUT_U_INT32(ptr, sa->sa_atime.tv_usec); IXDR_PUT_U_INT32(ptr, sa->sa_mtime.tv_sec); IXDR_PUT_U_INT32(ptr, sa->sa_mtime.tv_usec); } return (TRUE); } if (xdr_fhandle(xdrs, &argp->saa_fh) && xdr_sattr(xdrs, &argp->saa_sa)) { return (TRUE); } return (FALSE); } /* * arguments to create and mkdir */ bool_t xdr_creatargs(XDR *xdrs, struct nfscreatargs *argp) { argp->ca_sa = &argp->ca_sa_buf; if (xdrs->x_op == XDR_DECODE) argp->ca_sa = &argp->ca_sa_buf; if (xdr_diropargs(xdrs, &argp->ca_da) && xdr_sattr(xdrs, argp->ca_sa)) { return (TRUE); } return (FALSE); } /* * arguments to link */ bool_t xdr_linkargs(XDR *xdrs, struct nfslinkargs *argp) { if (xdrs->x_op == XDR_DECODE) argp->la_from = &argp->la_from_buf; if (xdr_fhandle(xdrs, argp->la_from) && xdr_diropargs(xdrs, &argp->la_to)) { return (TRUE); } return (FALSE); } /* * arguments to rename */ bool_t xdr_rnmargs(XDR *xdrs, struct nfsrnmargs *argp) { if (xdr_diropargs(xdrs, &argp->rna_from) && xdr_diropargs(xdrs, &argp->rna_to)) return (TRUE); return (FALSE); } /* * arguments to symlink */ bool_t xdr_slargs(XDR *xdrs, struct nfsslargs *argp) { if (xdrs->x_op == XDR_FREE) { if (!xdr_diropargs(xdrs, &argp->sla_from)) return (FALSE); if ((argp->sla_tnm_flags & SLA_FREETNM) && !xdr_string(xdrs, &argp->sla_tnm, (uint_t)NFS_MAXPATHLEN)) return (FALSE); return (TRUE); } if (xdrs->x_op == XDR_DECODE) { argp->sla_sa = &argp->sla_sa_buf; if (argp->sla_tnm == NULL) argp->sla_tnm_flags |= SLA_FREETNM; } if (xdr_diropargs(xdrs, &argp->sla_from) && xdr_string(xdrs, &argp->sla_tnm, (uint_t)NFS_MAXPATHLEN) && xdr_sattr(xdrs, argp->sla_sa)) { return (TRUE); } return (FALSE); } /* * NFS_OK part of statfs operation */ bool_t xdr_fsok(XDR *xdrs, struct nfsstatfsok *fsok) { int32_t *ptr; if (xdrs->x_op == XDR_FREE) return (TRUE); ptr = XDR_INLINE(xdrs, 5 * BYTES_PER_XDR_UNIT); if (ptr != NULL) { if (xdrs->x_op == XDR_DECODE) { fsok->fsok_tsize = IXDR_GET_INT32(ptr); fsok->fsok_bsize = IXDR_GET_INT32(ptr); fsok->fsok_blocks = IXDR_GET_INT32(ptr); fsok->fsok_bfree = IXDR_GET_INT32(ptr); fsok->fsok_bavail = IXDR_GET_INT32(ptr); } else { IXDR_PUT_INT32(ptr, fsok->fsok_tsize); IXDR_PUT_INT32(ptr, fsok->fsok_bsize); IXDR_PUT_INT32(ptr, fsok->fsok_blocks); IXDR_PUT_INT32(ptr, fsok->fsok_bfree); IXDR_PUT_INT32(ptr, fsok->fsok_bavail); } return (TRUE); } if (xdr_u_int(xdrs, &fsok->fsok_tsize) && xdr_u_int(xdrs, &fsok->fsok_bsize) && xdr_u_int(xdrs, &fsok->fsok_blocks) && xdr_u_int(xdrs, &fsok->fsok_bfree) && xdr_u_int(xdrs, &fsok->fsok_bavail)) { return (TRUE); } return (FALSE); } #ifdef _LITTLE_ENDIAN bool_t xdr_fastfsok(XDR *xdrs, struct nfsstatfsok *fsok) { if (xdrs->x_op == XDR_FREE) return (TRUE); if (xdrs->x_op == XDR_DECODE) return (FALSE); fsok->fsok_tsize = htonl(fsok->fsok_tsize); fsok->fsok_bsize = htonl(fsok->fsok_bsize); fsok->fsok_blocks = htonl(fsok->fsok_blocks); fsok->fsok_bfree = htonl(fsok->fsok_bfree); fsok->fsok_bavail = htonl(fsok->fsok_bavail); return (TRUE); } #endif static struct xdr_discrim statfs_discrim[2] = { { NFS_OK, xdr_fsok }, { __dontcare__, NULL_xdrproc_t } }; /* * Results of statfs operation */ bool_t xdr_statfs(XDR *xdrs, struct nfsstatfs *fs) { return (xdr_union(xdrs, (enum_t *)&(fs->fs_status), (caddr_t)&(fs->fs_fsok), statfs_discrim, xdr_void)); } /* * Results of statfs operation */ bool_t xdr_faststatfs(XDR *xdrs, struct nfsstatfs *fs) { #if defined(_LITTLE_ENDIAN) /* * we deal with the discriminator; it's an enum */ if (!xdr_fastenum(xdrs, (enum_t *)&fs->fs_status)) return (FALSE); if (fs->fs_status == NFS_OK) return (xdr_fastfsok(xdrs, &fs->fs_fsok)); #elif defined(_BIG_ENDIAN) if (fs->fs_status == NFS_OK) return (TRUE); #endif return (xdr_fastshorten(xdrs, sizeof (*fs))); } #ifdef _LITTLE_ENDIAN /* * XDR enumerations */ #ifndef lint static enum sizecheck { SIZEVAL } sizecheckvar; /* used to find the size of */ /* an enum */ #endif bool_t xdr_fastenum(XDR *xdrs, enum_t *ep) { if (xdrs->x_op == XDR_FREE) return (TRUE); if (xdrs->x_op == XDR_DECODE) return (FALSE); #ifndef lint /* * enums are treated as ints */ if (sizeof (sizecheckvar) == sizeof (int32_t)) { *ep = (enum_t)htonl((int32_t)(*ep)); } else if (sizeof (sizecheckvar) == sizeof (short)) { *ep = (enum_t)htons((short)(*ep)); } else { return (FALSE); } return (TRUE); #else (void) (xdr_short(xdrs, (short *)ep)); return (xdr_int(xdrs, (int *)ep)); #endif } #endif static bool_t xdr_fastshorten(XDR *xdrs, uint_t ressize) { uint_t curpos; curpos = XDR_GETPOS(xdrs); ressize -= BYTES_PER_XDR_UNIT; curpos -= ressize; return (XDR_SETPOS(xdrs, curpos)); }