/* * Copyright (c) 2006-2007 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * miscellaneous support functions for NFSv4 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * NFSv4 SETCLIENTID */ int nfs4_setclientid(struct nfsmount *nmp) { struct sockaddr *saddr; uint64_t verifier; char id[128]; int idlen, len, error = 0, status, numops; u_int64_t xid; vfs_context_t ctx; thread_t thd; kauth_cred_t cred; struct nfsm_chain nmreq, nmrep; static uint8_t en0addr[6]; static uint8_t en0addr_set = 0; lck_mtx_lock(nfs_request_mutex); if (!en0addr_set) { ifnet_t interface = NULL; error = ifnet_find_by_name("en0", &interface); if (!error) error = ifnet_lladdr_copy_bytes(interface, en0addr, sizeof(en0addr)); if (error) printf("nfs4_setclientid: error getting en0 address, %d\n", error); if (!error) en0addr_set = 1; error = 0; if (interface) ifnet_release(interface); } lck_mtx_unlock(nfs_request_mutex); ctx = vfs_context_kernel(); /* XXX */ thd = vfs_context_thread(ctx); cred = vfs_context_ucred(ctx); nfsm_chain_null(&nmreq); nfsm_chain_null(&nmrep); /* ID: en0_address + server_address */ idlen = len = sizeof(en0addr); bcopy(en0addr, &id[0], len); saddr = mbuf_data(nmp->nm_nam); len = min(saddr->sa_len, sizeof(id)-idlen); bcopy(saddr, &id[idlen], len); idlen += len; // SETCLIENTID numops = 1; nfsm_chain_build_alloc_init(error, &nmreq, 14 * NFSX_UNSIGNED + idlen); nfsm_chain_add_compound_header(error, &nmreq, "setclientid", numops); numops--; nfsm_chain_add_32(error, &nmreq, NFS_OP_SETCLIENTID); /* nfs_client_id4 client; */ nfsm_chain_add_64(error, &nmreq, nmp->nm_mounttime); nfsm_chain_add_32(error, &nmreq, idlen); nfsm_chain_add_opaque(error, &nmreq, id, idlen); /* cb_client4 callback; */ /* We don't provide callback info yet */ nfsm_chain_add_32(error, &nmreq, 0); /* callback program */ nfsm_chain_add_string(error, &nmreq, "", 0); /* callback r_netid */ nfsm_chain_add_string(error, &nmreq, "", 0); /* callback r_addr */ nfsm_chain_add_32(error, &nmreq, 0); /* callback_ident */ nfsm_chain_build_done(error, &nmreq); nfsm_assert(error, (numops == 0), EPROTO); nfsmout_if(error); error = nfs_request2(NULL, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND, thd, cred, R_SETUP, &nmrep, &xid, &status); nfsm_chain_skip_tag(error, &nmrep); nfsm_chain_get_32(error, &nmrep, numops); nfsm_chain_op_check(error, &nmrep, NFS_OP_SETCLIENTID); if (error == NFSERR_CLID_INUSE) printf("nfs4_setclientid: client ID in use?\n"); nfsmout_if(error); nfsm_chain_get_64(error, &nmrep, nmp->nm_clientid); nfsm_chain_get_64(error, &nmrep, verifier); nfsm_chain_cleanup(&nmreq); nfsm_chain_cleanup(&nmrep); // SETCLIENTID_CONFIRM numops = 1; nfsm_chain_build_alloc_init(error, &nmreq, 13 * NFSX_UNSIGNED); nfsm_chain_add_compound_header(error, &nmreq, "setclientid_confirm", numops); numops--; nfsm_chain_add_32(error, &nmreq, NFS_OP_SETCLIENTID_CONFIRM); nfsm_chain_add_64(error, &nmreq, nmp->nm_clientid); nfsm_chain_add_64(error, &nmreq, verifier); nfsm_chain_build_done(error, &nmreq); nfsm_assert(error, (numops == 0), EPROTO); nfsmout_if(error); error = nfs_request2(NULL, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND, thd, cred, R_SETUP, &nmrep, &xid, &status); nfsm_chain_skip_tag(error, &nmrep); nfsm_chain_get_32(error, &nmrep, numops); nfsm_chain_op_check(error, &nmrep, NFS_OP_SETCLIENTID_CONFIRM); if (error) printf("nfs4_setclientid: confirm error %d\n", error); nfsmout: nfsm_chain_cleanup(&nmreq); nfsm_chain_cleanup(&nmrep); if (error) printf("nfs4_setclientid failed, %d\n", error); return (error); } /* * periodic timer to renew lease state on server */ void nfs4_renew_timer(void *param0, __unused void *param1) { struct nfsmount *nmp = param0; int error = 0, status, numops, interval; u_int64_t xid; vfs_context_t ctx; struct nfsm_chain nmreq, nmrep; ctx = vfs_context_kernel(); /* XXX */ nfsm_chain_null(&nmreq); nfsm_chain_null(&nmrep); // RENEW numops = 1; nfsm_chain_build_alloc_init(error, &nmreq, 8 * NFSX_UNSIGNED); nfsm_chain_add_compound_header(error, &nmreq, "renew", numops); numops--; nfsm_chain_add_32(error, &nmreq, NFS_OP_RENEW); nfsm_chain_add_64(error, &nmreq, nmp->nm_clientid); nfsm_chain_build_done(error, &nmreq); nfsm_assert(error, (numops == 0), EPROTO); nfsmout_if(error); error = nfs_request(NULL, nmp->nm_mountp, &nmreq, NFSPROC4_COMPOUND, ctx, &nmrep, &xid, &status); nfsm_chain_skip_tag(error, &nmrep); nfsm_chain_get_32(error, &nmrep, numops); nfsm_chain_op_check(error, &nmrep, NFS_OP_RENEW); nfsmout: if (error) printf("nfs4_renew_timer: error %d\n", error); nfsm_chain_cleanup(&nmreq); nfsm_chain_cleanup(&nmrep); interval = nmp->nm_fsattr.nfsa_lease / (error ? 4 : 2); if (interval < 1) interval = 1; nfs_interval_timer_start(nmp->nm_renew_timer, interval * 1000); } /* * Set a vnode attr's supported bits according to the given bitmap */ void nfs_vattr_set_supported(uint32_t *bitmap, struct vnode_attr *vap) { if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TYPE)) VATTR_SET_SUPPORTED(vap, va_type); // if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CHANGE)) if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SIZE)) VATTR_SET_SUPPORTED(vap, va_data_size); // if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_NAMED_ATTR)) if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FSID)) VATTR_SET_SUPPORTED(vap, va_fsid); // if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ACL)) // VATTR_SET_SUPPORTED(vap, va_acl); if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ARCHIVE)) VATTR_SET_SUPPORTED(vap, va_flags); if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FILEID)) VATTR_SET_SUPPORTED(vap, va_fileid); if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_HIDDEN)) VATTR_SET_SUPPORTED(vap, va_flags); // if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MIMETYPE)) if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MODE)) VATTR_SET_SUPPORTED(vap, va_mode); if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_NUMLINKS)) VATTR_SET_SUPPORTED(vap, va_nlink); if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_OWNER)) VATTR_SET_SUPPORTED(vap, va_uid); if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_OWNER_GROUP)) VATTR_SET_SUPPORTED(vap, va_gid); if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_RAWDEV)) VATTR_SET_SUPPORTED(vap, va_rdev); if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SPACE_USED)) VATTR_SET_SUPPORTED(vap, va_total_alloc); // if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SYSTEM)) if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_ACCESS)) VATTR_SET_SUPPORTED(vap, va_access_time); if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_BACKUP)) VATTR_SET_SUPPORTED(vap, va_backup_time); if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_CREATE)) VATTR_SET_SUPPORTED(vap, va_create_time); if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_METADATA)) VATTR_SET_SUPPORTED(vap, va_change_time); if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_MODIFY)) VATTR_SET_SUPPORTED(vap, va_modify_time); } /* * Parse the attributes that are in the mbuf list and store them in * the given structures. */ int nfs4_parsefattr( struct nfsm_chain *nmc, struct nfs_fsattr *nfsap, struct nfs_vattr *nvap, fhandle_t *fhp, struct dqblk *dqbp) { int error = 0, attrbytes; uint32_t val, val2, val3, i, j; uint32_t bitmap[NFS_ATTR_BITMAP_LEN], len; char *s; struct nfs_fsattr nfsa_dummy; struct nfs_vattr nva_dummy; struct dqblk dqb_dummy; /* if not interested in some values... throw 'em into a local dummy variable */ if (!nfsap) nfsap = &nfsa_dummy; if (!nvap) nvap = &nva_dummy; if (!dqbp) dqbp = &dqb_dummy; attrbytes = val = val2 = val3 = 0; len = NFS_ATTR_BITMAP_LEN; nfsm_chain_get_bitmap(error, nmc, bitmap, len); /* add bits to object/fs attr bitmaps */ for (i=0; i < NFS_ATTR_BITMAP_LEN; i++) { nvap->nva_bitmap[i] |= bitmap[i] & nfs_object_attr_bitmap[i]; nfsap->nfsa_bitmap[i] |= bitmap[i] & nfs_fs_attr_bitmap[i]; } nfsm_chain_get_32(error, nmc, attrbytes); nfsmout_if(error); if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SUPPORTED_ATTRS)) { len = NFS_ATTR_BITMAP_LEN; nfsm_chain_get_bitmap(error, nmc, nfsap->nfsa_supp_attr, len); attrbytes -= (len + 1) * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TYPE)) { nfsm_chain_get_32(error, nmc, val); nvap->nva_type = nfstov_type(val, NFS_VER4); attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FH_EXPIRE_TYPE)) { nfsm_chain_get_32(error, nmc, val); nfsmout_if(error); if (val != NFS_FH_PERSISTENT) printf("nfs: warning: non-persistent file handles!\n"); if (val & ~0xff) printf("nfs: warning unknown fh type: 0x%x\n", val); nfsap->nfsa_flags &= ~NFS_FSFLAG_FHTYPE_MASK; nfsap->nfsa_flags |= val << 24; attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CHANGE)) { nfsm_chain_get_64(error, nmc, nvap->nva_change); attrbytes -= 2 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SIZE)) { nfsm_chain_get_64(error, nmc, nvap->nva_size); attrbytes -= 2 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_LINK_SUPPORT)) { nfsm_chain_get_32(error, nmc, val); if (val) nfsap->nfsa_flags |= NFS_FSFLAG_LINK; else nfsap->nfsa_flags &= ~NFS_FSFLAG_LINK; attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SYMLINK_SUPPORT)) { nfsm_chain_get_32(error, nmc, val); if (val) nfsap->nfsa_flags |= NFS_FSFLAG_SYMLINK; else nfsap->nfsa_flags &= ~NFS_FSFLAG_SYMLINK; attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_NAMED_ATTR)) { nfsm_chain_get_32(error, nmc, val); if (val) nvap->nva_flags |= NFS_FFLAG_NAMED_ATTR; else nvap->nva_flags &= ~NFS_FFLAG_NAMED_ATTR; attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FSID)) { nfsm_chain_get_64(error, nmc, nvap->nva_fsid.major); nfsm_chain_get_64(error, nmc, nvap->nva_fsid.minor); attrbytes -= 4 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_UNIQUE_HANDLES)) { nfsm_chain_get_32(error, nmc, val); if (val) nfsap->nfsa_flags |= NFS_FSFLAG_UNIQUE_FH; else nfsap->nfsa_flags &= ~NFS_FSFLAG_UNIQUE_FH; attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_LEASE_TIME)) { nfsm_chain_get_32(error, nmc, nfsap->nfsa_lease); attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_RDATTR_ERROR)) { nfsm_chain_get_32(error, nmc, error); attrbytes -= NFSX_UNSIGNED; nfsmout_if(error); } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ACL)) { /* skip for now */ nfsm_chain_get_32(error, nmc, val); /* ACE count */ for (i=0; !error && (i < val); i++) { nfsm_chain_adv(error, nmc, 3 * NFSX_UNSIGNED); nfsm_chain_get_32(error, nmc, val2); /* string length */ nfsm_chain_adv(error, nmc, nfsm_rndup(val2)); attrbytes -= 4*NFSX_UNSIGNED + nfsm_rndup(val2); nfsm_assert(error, (attrbytes >= 0), EBADRPC); } } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ACLSUPPORT)) { nfsm_chain_get_32(error, nmc, val); if (val) nfsap->nfsa_flags |= NFS_FSFLAG_ACL; else nfsap->nfsa_flags &= ~NFS_FSFLAG_ACL; attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ARCHIVE)) { /* SF_ARCHIVED */ nfsm_chain_get_32(error, nmc, val); if (val) nvap->nva_flags |= NFS_FFLAG_ARCHIVED; else nvap->nva_flags &= ~NFS_FFLAG_ARCHIVED; attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CANSETTIME)) { nfsm_chain_get_32(error, nmc, val); if (val) nfsap->nfsa_flags |= NFS_FSFLAG_SET_TIME; else nfsap->nfsa_flags &= ~NFS_FSFLAG_SET_TIME; attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CASE_INSENSITIVE)) { nfsm_chain_get_32(error, nmc, val); if (val) nfsap->nfsa_flags |= NFS_FSFLAG_CASE_INSENSITIVE; else nfsap->nfsa_flags &= ~NFS_FSFLAG_CASE_INSENSITIVE; attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CASE_PRESERVING)) { nfsm_chain_get_32(error, nmc, val); if (val) nfsap->nfsa_flags |= NFS_FSFLAG_CASE_PRESERVING; else nfsap->nfsa_flags &= ~NFS_FSFLAG_CASE_PRESERVING; attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_CHOWN_RESTRICTED)) { nfsm_chain_get_32(error, nmc, val); if (val) nfsap->nfsa_flags |= NFS_FSFLAG_CHOWN_RESTRICTED; else nfsap->nfsa_flags &= ~NFS_FSFLAG_CHOWN_RESTRICTED; attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FILEHANDLE)) { nfsm_chain_get_32(error, nmc, val); if (fhp) { fhp->fh_len = val; nfsm_chain_get_opaque(error, nmc, nfsm_rndup(val), fhp->fh_data); } else { nfsm_chain_adv(error, nmc, nfsm_rndup(val)); } attrbytes -= NFSX_UNSIGNED + nfsm_rndup(val); } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FILEID)) { nfsm_chain_get_64(error, nmc, nvap->nva_fileid); attrbytes -= 2 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FILES_AVAIL)) { nfsm_chain_get_64(error, nmc, nfsap->nfsa_files_avail); attrbytes -= 2 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FILES_FREE)) { nfsm_chain_get_64(error, nmc, nfsap->nfsa_files_free); attrbytes -= 2 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FILES_TOTAL)) { nfsm_chain_get_64(error, nmc, nfsap->nfsa_files_total); attrbytes -= 2 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_FS_LOCATIONS)) { /* skip for now */ nfsm_chain_get_32(error, nmc, val); /* root path length */ nfsm_chain_adv(error, nmc, nfsm_rndup(val)); /* root path */ attrbytes -= (2 * NFSX_UNSIGNED) + nfsm_rndup(val); nfsm_chain_get_32(error, nmc, val); /* location count */ for (i=0; !error && (i < val); i++) { nfsm_chain_get_32(error, nmc, val2); /* server string length */ nfsm_chain_adv(error, nmc, nfsm_rndup(val2)); /* server string */ attrbytes -= (2 * NFSX_UNSIGNED) + nfsm_rndup(val2); nfsm_chain_get_32(error, nmc, val2); /* pathname component count */ for (j=0; !error && (j < val2); j++) { nfsm_chain_get_32(error, nmc, val3); /* component length */ nfsm_chain_adv(error, nmc, nfsm_rndup(val3)); /* component */ attrbytes -= NFSX_UNSIGNED + nfsm_rndup(val3); nfsm_assert(error, (attrbytes >= 0), EBADRPC); } nfsm_assert(error, (attrbytes >= 0), EBADRPC); } nfsm_assert(error, (attrbytes >= 0), EBADRPC); } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_HIDDEN)) { /* UF_HIDDEN */ nfsm_chain_get_32(error, nmc, val); if (val) nvap->nva_flags |= NFS_FFLAG_HIDDEN; else nvap->nva_flags &= ~NFS_FFLAG_HIDDEN; attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_HOMOGENEOUS)) { /* XXX If NOT homogeneous, we may need to clear flags on the mount */ nfsm_chain_get_32(error, nmc, val); if (val) nfsap->nfsa_flags |= NFS_FSFLAG_HOMOGENEOUS; else nfsap->nfsa_flags &= ~NFS_FSFLAG_HOMOGENEOUS; attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MAXFILESIZE)) { nfsm_chain_get_64(error, nmc, nfsap->nfsa_maxfilesize); attrbytes -= 2 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MAXLINK)) { nfsm_chain_get_32(error, nmc, nvap->nva_maxlink); if (!error && (nfsap->nfsa_maxlink > INT32_MAX)) nfsap->nfsa_maxlink = INT32_MAX; attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MAXNAME)) { nfsm_chain_get_32(error, nmc, nfsap->nfsa_maxname); if (!error && (nfsap->nfsa_maxname > INT32_MAX)) nfsap->nfsa_maxname = INT32_MAX; attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MAXREAD)) { nfsm_chain_get_64(error, nmc, nfsap->nfsa_maxread); attrbytes -= 2 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MAXWRITE)) { nfsm_chain_get_64(error, nmc, nfsap->nfsa_maxwrite); attrbytes -= 2 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MIMETYPE)) { nfsm_chain_get_32(error, nmc, val); nfsm_chain_adv(error, nmc, nfsm_rndup(val)); attrbytes -= NFSX_UNSIGNED + nfsm_rndup(val); } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MODE)) { nfsm_chain_get_32(error, nmc, nvap->nva_mode); attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_NO_TRUNC)) { nfsm_chain_get_32(error, nmc, val); if (val) nfsap->nfsa_flags |= NFS_FSFLAG_NO_TRUNC; else nfsap->nfsa_flags &= ~NFS_FSFLAG_NO_TRUNC; attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_NUMLINKS)) { nfsm_chain_get_32(error, nmc, val); nvap->nva_nlink = val; attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_OWNER)) { /* XXX ugly hack for now */ nfsm_chain_get_32(error, nmc, len); nfsm_chain_get_opaque_pointer(error, nmc, len, s); attrbytes -= NFSX_UNSIGNED + nfsm_rndup(len); nfsmout_if(error); if ((*s >= '0') && (*s <= '9')) nvap->nva_uid = strtol(s, NULL, 10); else if (!strncmp(s, "nobody@", 7)) nvap->nva_uid = -2; else if (!strncmp(s, "root@", 5)) nvap->nva_uid = 0; else nvap->nva_uid = 99; /* unknown */ } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_OWNER_GROUP)) { /* XXX ugly hack for now */ nfsm_chain_get_32(error, nmc, len); nfsm_chain_get_opaque_pointer(error, nmc, len, s); attrbytes -= NFSX_UNSIGNED + nfsm_rndup(len); nfsmout_if(error); if ((*s >= '0') && (*s <= '9')) nvap->nva_gid = strtol(s, NULL, 10); else if (!strncmp(s, "nobody@", 7)) nvap->nva_gid = -2; else if (!strncmp(s, "root@", 5)) nvap->nva_uid = 0; else nvap->nva_gid = 99; /* unknown */ } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_QUOTA_AVAIL_HARD)) { nfsm_chain_get_64(error, nmc, dqbp->dqb_bhardlimit); attrbytes -= 2 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_QUOTA_AVAIL_SOFT)) { nfsm_chain_get_64(error, nmc, dqbp->dqb_bsoftlimit); attrbytes -= 2 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_QUOTA_USED)) { nfsm_chain_get_64(error, nmc, dqbp->dqb_curbytes); attrbytes -= 2 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_RAWDEV)) { nfsm_chain_get_32(error, nmc, nvap->nva_rawdev.specdata1); nfsm_chain_get_32(error, nmc, nvap->nva_rawdev.specdata2); attrbytes -= 2 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SPACE_AVAIL)) { nfsm_chain_get_64(error, nmc, nfsap->nfsa_space_avail); attrbytes -= 2 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SPACE_FREE)) { nfsm_chain_get_64(error, nmc, nfsap->nfsa_space_free); attrbytes -= 2 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SPACE_TOTAL)) { nfsm_chain_get_64(error, nmc, nfsap->nfsa_space_total); attrbytes -= 2 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SPACE_USED)) { nfsm_chain_get_64(error, nmc, nvap->nva_bytes); attrbytes -= 2 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SYSTEM)) { /* we'd support this if we had a flag to map it to... */ nfsm_chain_adv(error, nmc, NFSX_UNSIGNED); attrbytes -= NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_ACCESS)) { nfsm_chain_get_64(error, nmc, nvap->nva_timesec[NFSTIME_ACCESS]); nfsm_chain_get_32(error, nmc, nvap->nva_timensec[NFSTIME_ACCESS]); attrbytes -= 3 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_ACCESS_SET)) { nfsm_chain_adv(error, nmc, 4*NFSX_UNSIGNED); /* just skip it */ attrbytes -= 4 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_BACKUP)) { nfsm_chain_get_64(error, nmc, nvap->nva_timesec[NFSTIME_BACKUP]); nfsm_chain_get_32(error, nmc, nvap->nva_timensec[NFSTIME_BACKUP]); attrbytes -= 3 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_CREATE)) { nfsm_chain_get_64(error, nmc, nvap->nva_timesec[NFSTIME_CREATE]); nfsm_chain_get_32(error, nmc, nvap->nva_timensec[NFSTIME_CREATE]); attrbytes -= 3 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_DELTA)) { /* skip for now */ nfsm_chain_adv(error, nmc, 3*NFSX_UNSIGNED); attrbytes -= 3 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_METADATA)) { nfsm_chain_get_64(error, nmc, nvap->nva_timesec[NFSTIME_CHANGE]); nfsm_chain_get_32(error, nmc, nvap->nva_timensec[NFSTIME_CHANGE]); attrbytes -= 3 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_MODIFY)) { nfsm_chain_get_64(error, nmc, nvap->nva_timesec[NFSTIME_MODIFY]); nfsm_chain_get_32(error, nmc, nvap->nva_timensec[NFSTIME_MODIFY]); attrbytes -= 3 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_MODIFY_SET)) { nfsm_chain_adv(error, nmc, 4*NFSX_UNSIGNED); /* just skip it */ attrbytes -= 4 * NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MOUNTED_ON_FILEID)) { /* skip for now */ nfsm_chain_adv(error, nmc, 2*NFSX_UNSIGNED); attrbytes -= 2 * NFSX_UNSIGNED; } /* advance over any leftover attrbytes */ nfsm_assert(error, (attrbytes >= 0), EBADRPC); nfsm_chain_adv(error, nmc, nfsm_rndup(attrbytes)); nfsmout: return (error); } /* * Add an NFSv4 "sattr" structure to an mbuf chain */ int nfsm_chain_add_fattr4_f(struct nfsm_chain *nmc, struct vnode_attr *vap, struct nfsmount *nmp) { int error = 0, attrbytes, slen, i; uint32_t *pattrbytes; uint32_t bitmap[NFS_ATTR_BITMAP_LEN]; char s[32]; /* * Do this in two passes. * First calculate the bitmap, then pack * everything together and set the size. */ NFS_CLEAR_ATTRIBUTES(bitmap); if (VATTR_IS_ACTIVE(vap, va_data_size)) NFS_BITMAP_SET(bitmap, NFS_FATTR_SIZE); if (VATTR_IS_ACTIVE(vap, va_acl)) { // NFS_BITMAP_SET(bitmap, NFS_FATTR_ACL) } if (VATTR_IS_ACTIVE(vap, va_flags)) { NFS_BITMAP_SET(bitmap, NFS_FATTR_ARCHIVE); NFS_BITMAP_SET(bitmap, NFS_FATTR_HIDDEN); } // NFS_BITMAP_SET(bitmap, NFS_FATTR_MIMETYPE) if (VATTR_IS_ACTIVE(vap, va_mode)) NFS_BITMAP_SET(bitmap, NFS_FATTR_MODE); if (VATTR_IS_ACTIVE(vap, va_uid)) NFS_BITMAP_SET(bitmap, NFS_FATTR_OWNER); if (VATTR_IS_ACTIVE(vap, va_gid)) NFS_BITMAP_SET(bitmap, NFS_FATTR_OWNER_GROUP); // NFS_BITMAP_SET(bitmap, NFS_FATTR_SYSTEM) if (vap->va_vaflags & VA_UTIMES_NULL) { NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_ACCESS_SET); NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_MODIFY_SET); } else { if (VATTR_IS_ACTIVE(vap, va_access_time)) NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_ACCESS_SET); if (VATTR_IS_ACTIVE(vap, va_modify_time)) NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_MODIFY_SET); } if (VATTR_IS_ACTIVE(vap, va_backup_time)) NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_BACKUP); if (VATTR_IS_ACTIVE(vap, va_create_time)) NFS_BITMAP_SET(bitmap, NFS_FATTR_TIME_CREATE); /* and limit to what is supported by server */ for (i=0; i < NFS_ATTR_BITMAP_LEN; i++) bitmap[i] &= nmp->nm_fsattr.nfsa_supp_attr[i]; /* * Now pack it all together: * BITMAP, #BYTES, ATTRS * Keep a pointer to the length so we can set it later. */ nfsm_chain_add_bitmap(error, nmc, bitmap, NFS_ATTR_BITMAP_LEN); attrbytes = 0; nfsm_chain_add_32(error, nmc, attrbytes); pattrbytes = (uint32_t*)(nmc->nmc_ptr - NFSX_UNSIGNED); if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_SIZE)) { nfsm_chain_add_64(error, nmc, vap->va_data_size); attrbytes += 2*NFSX_UNSIGNED; } // NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ACL) if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_ARCHIVE)) { nfsm_chain_add_32(error, nmc, (vap->va_flags & SF_ARCHIVED) ? 1 : 0); attrbytes += NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_HIDDEN)) { nfsm_chain_add_32(error, nmc, (vap->va_flags & UF_HIDDEN) ? 1 : 0); attrbytes += NFSX_UNSIGNED; } // NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MIMETYPE) if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_MODE)) { nfsm_chain_add_32(error, nmc, vap->va_mode); attrbytes += NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_OWNER)) { slen = snprintf(s, sizeof(s), "%d", vap->va_uid); nfsm_chain_add_string(error, nmc, s, slen); attrbytes += NFSX_UNSIGNED + nfsm_rndup(slen); } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_OWNER_GROUP)) { slen = snprintf(s, sizeof(s), "%d", vap->va_gid); nfsm_chain_add_string(error, nmc, s, slen); attrbytes += NFSX_UNSIGNED + nfsm_rndup(slen); } // NFS_BITMAP_SET(bitmap, NFS_FATTR_SYSTEM) if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_ACCESS_SET)) { if (vap->va_vaflags & VA_UTIMES_NULL) { nfsm_chain_add_32(error, nmc, NFS_TIME_SET_TO_SERVER); attrbytes += NFSX_UNSIGNED; } else { nfsm_chain_add_32(error, nmc, NFS_TIME_SET_TO_CLIENT); nfsm_chain_add_64(error, nmc, vap->va_access_time.tv_sec); nfsm_chain_add_32(error, nmc, vap->va_access_time.tv_nsec); attrbytes += 4*NFSX_UNSIGNED; } } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_BACKUP)) { nfsm_chain_add_64(error, nmc, vap->va_backup_time.tv_sec); nfsm_chain_add_32(error, nmc, vap->va_backup_time.tv_nsec); attrbytes += 3*NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_CREATE)) { nfsm_chain_add_64(error, nmc, vap->va_create_time.tv_sec); nfsm_chain_add_32(error, nmc, vap->va_create_time.tv_nsec); attrbytes += 3*NFSX_UNSIGNED; } if (NFS_BITMAP_ISSET(bitmap, NFS_FATTR_TIME_MODIFY_SET)) { if (vap->va_vaflags & VA_UTIMES_NULL) { nfsm_chain_add_32(error, nmc, NFS_TIME_SET_TO_SERVER); attrbytes += NFSX_UNSIGNED; } else { nfsm_chain_add_32(error, nmc, NFS_TIME_SET_TO_CLIENT); nfsm_chain_add_64(error, nmc, vap->va_modify_time.tv_sec); nfsm_chain_add_32(error, nmc, vap->va_modify_time.tv_nsec); attrbytes += 4*NFSX_UNSIGNED; } } nfsmout_if(error); /* Now, set the attribute data length */ *pattrbytes = txdr_unsigned(attrbytes); nfsmout: return (error); }