+ nfsm_chain_add_32(error, nmc, vap->va_rdev);
+ nfsm_chain_add_32(error, nmc, vap->va_data_alloc / NFS_FABLKSIZE);
+ nfsm_chain_add_32(error, nmc, vap->va_fsid);
+ nfsm_chain_add_32(error, nmc, vap->va_fileid);
+ }
+ nfsm_chain_add_time(error, nmc, nd->nd_vers, &vap->va_access_time);
+ nfsm_chain_add_time(error, nmc, nd->nd_vers, &vap->va_modify_time);
+ nfsm_chain_add_time(error, nmc, nd->nd_vers, &vap->va_change_time);
+
+ return (error);
+}
+
+int
+nfsm_chain_get_sattr(
+ struct nfsrv_descript *nd,
+ struct nfsm_chain *nmc,
+ struct vnode_attr *vap)
+{
+ int error = 0;
+ uint32_t val = 0;
+ uint64_t val64;
+ struct timespec now;
+
+ if (nd->nd_vers == NFS_VER2) {
+ /*
+ * There is/was a bug in the Sun client that puts 0xffff in the mode
+ * field of sattr when it should put in 0xffffffff. The u_short
+ * doesn't sign extend. So check the low order 2 bytes for 0xffff.
+ */
+ nfsm_chain_get_32(error, nmc, val);
+ if ((val & 0xffff) != 0xffff) {
+ VATTR_SET(vap, va_mode, val & 07777);
+ /* save the "type" bits for NFSv2 create */
+ VATTR_SET(vap, va_type, IFTOVT(val));
+ VATTR_CLEAR_ACTIVE(vap, va_type);
+ }
+ nfsm_chain_get_32(error, nmc, val);
+ if (val != (uint32_t)-1)
+ VATTR_SET(vap, va_uid, val);
+ nfsm_chain_get_32(error, nmc, val);
+ if (val != (uint32_t)-1)
+ VATTR_SET(vap, va_gid, val);
+ /* save the "size" bits for NFSv2 create (even if they appear unset) */
+ nfsm_chain_get_32(error, nmc, val);
+ VATTR_SET(vap, va_data_size, val);
+ if (val == (uint32_t)-1)
+ VATTR_CLEAR_ACTIVE(vap, va_data_size);
+ nfsm_chain_get_time(error, nmc, NFS_VER2,
+ vap->va_access_time.tv_sec,
+ vap->va_access_time.tv_nsec);
+ if (vap->va_access_time.tv_sec != -1)
+ VATTR_SET_ACTIVE(vap, va_access_time);
+ nfsm_chain_get_time(error, nmc, NFS_VER2,
+ vap->va_modify_time.tv_sec,
+ vap->va_modify_time.tv_nsec);
+ if (vap->va_modify_time.tv_sec != -1)
+ VATTR_SET_ACTIVE(vap, va_modify_time);
+ return (error);
+ }
+
+ /* NFSv3 */
+ nfsm_chain_get_32(error, nmc, val);
+ if (val) {
+ nfsm_chain_get_32(error, nmc, val);
+ VATTR_SET(vap, va_mode, val & 07777);
+ }
+ nfsm_chain_get_32(error, nmc, val);
+ if (val) {
+ nfsm_chain_get_32(error, nmc, val);
+ VATTR_SET(vap, va_uid, val);
+ }
+ nfsm_chain_get_32(error, nmc, val);
+ if (val) {
+ nfsm_chain_get_32(error, nmc, val);
+ VATTR_SET(vap, va_gid, val);
+ }
+ nfsm_chain_get_32(error, nmc, val);
+ if (val) {
+ nfsm_chain_get_64(error, nmc, val64);
+ VATTR_SET(vap, va_data_size, val64);
+ }
+ nanotime(&now);
+ nfsm_chain_get_32(error, nmc, val);
+ switch (val) {
+ case NFS_TIME_SET_TO_CLIENT:
+ nfsm_chain_get_time(error, nmc, nd->nd_vers,
+ vap->va_access_time.tv_sec,
+ vap->va_access_time.tv_nsec);
+ VATTR_SET_ACTIVE(vap, va_access_time);
+ vap->va_vaflags &= ~VA_UTIMES_NULL;
+ break;
+ case NFS_TIME_SET_TO_SERVER:
+ VATTR_SET(vap, va_access_time, now);
+ vap->va_vaflags |= VA_UTIMES_NULL;
+ break;
+ }
+ nfsm_chain_get_32(error, nmc, val);
+ switch (val) {
+ case NFS_TIME_SET_TO_CLIENT:
+ nfsm_chain_get_time(error, nmc, nd->nd_vers,
+ vap->va_modify_time.tv_sec,
+ vap->va_modify_time.tv_nsec);
+ VATTR_SET_ACTIVE(vap, va_modify_time);
+ vap->va_vaflags &= ~VA_UTIMES_NULL;
+ break;
+ case NFS_TIME_SET_TO_SERVER:
+ VATTR_SET(vap, va_modify_time, now);
+ if (!VATTR_IS_ACTIVE(vap, va_access_time))
+ vap->va_vaflags |= VA_UTIMES_NULL;
+ break;