+
+/*
+ * Retrieve the data of an extended attribute.
+ */
+int
+getxattr(struct proc *p, struct getxattr_args *uap, user_ssize_t *retval)
+{
+ struct vnode *vp;
+ struct nameidata nd;
+ char attrname[XATTR_MAXNAMELEN+1];
+ struct vfs_context context;
+ uio_t auio = NULL;
+ int spacetype = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
+ size_t attrsize = 0;
+ size_t namelen;
+ u_long nameiflags;
+ int error;
+ char uio_buf[ UIO_SIZEOF(1) ];
+
+ context.vc_proc = p;
+ context.vc_ucred = kauth_cred_get();
+
+ if (uap->options & XATTR_NOSECURITY)
+ return (EINVAL);
+
+ nameiflags = (uap->options & XATTR_NOFOLLOW) ? 0 : FOLLOW;
+ NDINIT(&nd, LOOKUP, nameiflags, spacetype, uap->path, &context);
+ if ((error = namei(&nd))) {
+ return (error);
+ }
+ vp = nd.ni_vp;
+ nameidone(&nd);
+
+ if ((error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen) != 0)) {
+ goto out;
+ }
+ if (xattr_protected(attrname)) {
+ error = EPERM;
+ goto out;
+ }
+ if (uap->value && uap->size > 0) {
+ auio = uio_createwithbuffer(1, uap->position, spacetype, UIO_READ,
+ &uio_buf[0], sizeof(uio_buf));
+ uio_addiov(auio, uap->value, uap->size);
+ }
+
+ error = vn_getxattr(vp, attrname, auio, &attrsize, uap->options, &context);
+out:
+ vnode_put(vp);
+
+ if (auio) {
+ *retval = uap->size - uio_resid(auio);
+ } else {
+ *retval = (user_ssize_t)attrsize;
+ }
+
+ return (error);
+}
+
+/*
+ * Retrieve the data of an extended attribute.
+ */
+int
+fgetxattr(struct proc *p, struct fgetxattr_args *uap, user_ssize_t *retval)
+{
+ struct vnode *vp;
+ char attrname[XATTR_MAXNAMELEN+1];
+ struct vfs_context context;
+ uio_t auio = NULL;
+ int spacetype = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
+ size_t attrsize = 0;
+ size_t namelen;
+ int error;
+ char uio_buf[ UIO_SIZEOF(1) ];
+
+ if (uap->options & (XATTR_NOFOLLOW | XATTR_NOSECURITY))
+ return (EINVAL);
+
+ if ( (error = file_vnode(uap->fd, &vp)) ) {
+ return (error);
+ }
+ if ( (error = vnode_getwithref(vp)) ) {
+ file_drop(uap->fd);
+ return(error);
+ }
+ if ((error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen) != 0)) {
+ goto out;
+ }
+ if (xattr_protected(attrname)) {
+ error = EPERM;
+ goto out;
+ }
+ if (uap->value && uap->size > 0) {
+ auio = uio_createwithbuffer(1, uap->position, spacetype, UIO_READ,
+ &uio_buf[0], sizeof(uio_buf));
+ uio_addiov(auio, uap->value, uap->size);
+ }
+ context.vc_proc = p;
+ context.vc_ucred = kauth_cred_get();
+
+ error = vn_getxattr(vp, attrname, auio, &attrsize, uap->options, &context);
+out:
+ (void)vnode_put(vp);
+ file_drop(uap->fd);
+
+ if (auio) {
+ *retval = uap->size - uio_resid(auio);
+ } else {
+ *retval = (user_ssize_t)attrsize;
+ }
+ return (error);
+}
+
+/*
+ * Set the data of an extended attribute.
+ */
+int
+setxattr(struct proc *p, struct setxattr_args *uap, int *retval)
+{
+ struct vnode *vp;
+ struct nameidata nd;
+ char attrname[XATTR_MAXNAMELEN+1];
+ struct vfs_context context;
+ uio_t auio = NULL;
+ int spacetype = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
+ size_t namelen;
+ u_long nameiflags;
+ int error;
+ char uio_buf[ UIO_SIZEOF(1) ];
+
+ context.vc_proc = p;
+ context.vc_ucred = kauth_cred_get();
+
+ if (uap->options & XATTR_NOSECURITY)
+ return (EINVAL);
+
+ if ((error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen) != 0)) {
+ return (error);
+ }
+ if (xattr_protected(attrname))
+ return(EPERM);
+ if (uap->value == 0 || uap->size == 0) {
+ return (EINVAL);
+ }
+
+ nameiflags = (uap->options & XATTR_NOFOLLOW) ? 0 : FOLLOW;
+ NDINIT(&nd, LOOKUP, nameiflags, spacetype, uap->path, &context);
+ if ((error = namei(&nd))) {
+ return (error);
+ }
+ vp = nd.ni_vp;
+ nameidone(&nd);
+
+ auio = uio_createwithbuffer(1, uap->position, spacetype, UIO_WRITE,
+ &uio_buf[0], sizeof(uio_buf));
+ uio_addiov(auio, uap->value, uap->size);
+
+ error = vn_setxattr(vp, attrname, auio, uap->options, &context);
+ vnode_put(vp);
+ *retval = 0;
+ return (error);
+}
+
+/*
+ * Set the data of an extended attribute.
+ */
+int
+fsetxattr(struct proc *p, struct fsetxattr_args *uap, int *retval)
+{
+ struct vnode *vp;
+ char attrname[XATTR_MAXNAMELEN+1];
+ struct vfs_context context;
+ uio_t auio = NULL;
+ int spacetype = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
+ size_t namelen;
+ int error;
+ char uio_buf[ UIO_SIZEOF(1) ];
+
+ if (uap->options & (XATTR_NOFOLLOW | XATTR_NOSECURITY))
+ return (EINVAL);
+
+ if ((error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen) != 0)) {
+ return (error);
+ }
+ if (xattr_protected(attrname))
+ return(EPERM);
+ if (uap->value == 0 || uap->size == 0) {
+ return (EINVAL);
+ }
+ if ( (error = file_vnode(uap->fd, &vp)) ) {
+ return (error);
+ }
+ if ( (error = vnode_getwithref(vp)) ) {
+ file_drop(uap->fd);
+ return(error);
+ }
+ auio = uio_createwithbuffer(1, uap->position, spacetype, UIO_WRITE,
+ &uio_buf[0], sizeof(uio_buf));
+ uio_addiov(auio, uap->value, uap->size);
+ context.vc_proc = p;
+ context.vc_ucred = kauth_cred_get();
+
+ error = vn_setxattr(vp, attrname, auio, uap->options, &context);
+ vnode_put(vp);
+ file_drop(uap->fd);
+ *retval = 0;
+ return (error);
+}
+
+/*
+ * Remove an extended attribute.
+ */
+#warning "code duplication"
+int
+removexattr(struct proc *p, struct removexattr_args *uap, int *retval)
+{
+ struct vnode *vp;
+ struct nameidata nd;
+ char attrname[XATTR_MAXNAMELEN+1];
+ int spacetype = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
+ struct vfs_context context;
+ size_t namelen;
+ u_long nameiflags;
+ int error;
+
+ context.vc_proc = p;
+ context.vc_ucred = kauth_cred_get();
+
+ if (uap->options & XATTR_NOSECURITY)
+ return (EINVAL);
+
+ error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen);
+ if (error != 0) {
+ return (error);
+ }
+ if (xattr_protected(attrname))
+ return(EPERM);
+ nameiflags = (uap->options & XATTR_NOFOLLOW) ? 0 : FOLLOW;
+ NDINIT(&nd, LOOKUP, nameiflags, spacetype, uap->path, &context);
+ if ((error = namei(&nd))) {
+ return (error);
+ }
+ vp = nd.ni_vp;
+ nameidone(&nd);
+
+ error = vn_removexattr(vp, attrname, uap->options, &context);
+ vnode_put(vp);
+ *retval = 0;
+ return (error);
+}
+
+/*
+ * Remove an extended attribute.
+ */
+#warning "code duplication"
+int
+fremovexattr(struct proc *p, struct fremovexattr_args *uap, int *retval)
+{
+ struct vnode *vp;
+ char attrname[XATTR_MAXNAMELEN+1];
+ struct vfs_context context;
+ size_t namelen;
+ int error;
+
+ if (uap->options & (XATTR_NOFOLLOW | XATTR_NOSECURITY))
+ return (EINVAL);
+
+ error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen);
+ if (error != 0) {
+ return (error);
+ }
+ if (xattr_protected(attrname))
+ return(EPERM);
+ if ( (error = file_vnode(uap->fd, &vp)) ) {
+ return (error);
+ }
+ if ( (error = vnode_getwithref(vp)) ) {
+ file_drop(uap->fd);
+ return(error);
+ }
+ context.vc_proc = p;
+ context.vc_ucred = kauth_cred_get();
+
+ error = vn_removexattr(vp, attrname, uap->options, &context);
+ vnode_put(vp);
+ file_drop(uap->fd);
+ *retval = 0;
+ return (error);
+}
+
+/*
+ * Retrieve the list of extended attribute names.
+ */
+#warning "code duplication"
+int
+listxattr(struct proc *p, struct listxattr_args *uap, user_ssize_t *retval)
+{
+ struct vnode *vp;
+ struct nameidata nd;
+ struct vfs_context context;
+ uio_t auio = NULL;
+ int spacetype = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
+ size_t attrsize = 0;
+ u_long nameiflags;
+ int error;
+ char uio_buf[ UIO_SIZEOF(1) ];
+
+ context.vc_proc = p;
+ context.vc_ucred = kauth_cred_get();
+
+ if (uap->options & XATTR_NOSECURITY)
+ return (EINVAL);
+
+ nameiflags = (uap->options & XATTR_NOFOLLOW) ? 0 : FOLLOW;
+ NDINIT(&nd, LOOKUP, nameiflags, spacetype, uap->path, &context);
+ if ((error = namei(&nd))) {
+ return (error);
+ }
+ vp = nd.ni_vp;
+ nameidone(&nd);
+ if (uap->namebuf != 0 && uap->bufsize > 0) {
+ // LP64todo - fix this!
+ auio = uio_createwithbuffer(1, 0, spacetype,
+ UIO_READ, &uio_buf[0], sizeof(uio_buf));
+ uio_addiov(auio, uap->namebuf, uap->bufsize);
+ }
+
+ error = vn_listxattr(vp, auio, &attrsize, uap->options, &context);
+
+ vnode_put(vp);
+ if (auio) {
+ *retval = (user_ssize_t)uap->bufsize - uio_resid(auio);
+ } else {
+ *retval = (user_ssize_t)attrsize;
+ }
+ return (error);
+}
+
+/*
+ * Retrieve the list of extended attribute names.
+ */
+#warning "code duplication"
+int
+flistxattr(struct proc *p, struct flistxattr_args *uap, user_ssize_t *retval)
+{
+ struct vnode *vp;
+ struct vfs_context context;
+ uio_t auio = NULL;
+ int spacetype = proc_is64bit(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
+ size_t attrsize = 0;
+ int error;
+ char uio_buf[ UIO_SIZEOF(1) ];
+
+ if (uap->options & (XATTR_NOFOLLOW | XATTR_NOSECURITY))
+ return (EINVAL);
+
+ if ( (error = file_vnode(uap->fd, &vp)) ) {
+ return (error);
+ }
+ if ( (error = vnode_getwithref(vp)) ) {
+ file_drop(uap->fd);
+ return(error);
+ }
+ if (uap->namebuf != 0 && uap->bufsize > 0) {
+ // LP64todo - fix this!
+ auio = uio_createwithbuffer(1, 0, spacetype,
+ UIO_READ, &uio_buf[0], sizeof(uio_buf));
+ uio_addiov(auio, uap->namebuf, uap->bufsize);
+ }
+ context.vc_proc = p;
+ context.vc_ucred = kauth_cred_get();
+
+ error = vn_listxattr(vp, auio, &attrsize, uap->options, &context);
+
+ vnode_put(vp);
+ file_drop(uap->fd);
+ if (auio) {
+ *retval = (user_ssize_t)uap->bufsize - uio_resid(auio);
+ } else {
+ *retval = (user_ssize_t)attrsize;
+ }
+ return (error);
+}
+
+/*
+ * Common routine to handle various flavors of statfs data heading out
+ * to user space.
+ */
+static int
+munge_statfs(struct mount *mp, struct vfsstatfs *sfsp,
+ user_addr_t bufp, int *sizep, boolean_t is_64_bit,
+ boolean_t partial_copy)
+{
+ int error;
+ int my_size, copy_size;
+
+ if (is_64_bit) {
+ struct user_statfs sfs;
+ my_size = copy_size = sizeof(sfs);
+ bzero(&sfs, my_size);
+ sfs.f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
+ sfs.f_type = mp->mnt_vtable->vfc_typenum;
+ sfs.f_reserved1 = (short)sfsp->f_fssubtype;
+ sfs.f_bsize = (user_long_t)sfsp->f_bsize;
+ sfs.f_iosize = (user_long_t)sfsp->f_iosize;
+ sfs.f_blocks = (user_long_t)sfsp->f_blocks;
+ sfs.f_bfree = (user_long_t)sfsp->f_bfree;
+ sfs.f_bavail = (user_long_t)sfsp->f_bavail;
+ sfs.f_files = (user_long_t)sfsp->f_files;
+ sfs.f_ffree = (user_long_t)sfsp->f_ffree;
+ sfs.f_fsid = sfsp->f_fsid;
+ sfs.f_owner = sfsp->f_owner;
+ strncpy(&sfs.f_fstypename[0], &sfsp->f_fstypename[0], MFSNAMELEN-1);
+ strncpy(&sfs.f_mntonname[0], &sfsp->f_mntonname[0], MNAMELEN-1);
+ strncpy(&sfs.f_mntfromname[0], &sfsp->f_mntfromname[0], MNAMELEN-1);
+
+ if (partial_copy) {
+ copy_size -= (sizeof(sfs.f_reserved3) + sizeof(sfs.f_reserved4));
+ }
+ error = copyout((caddr_t)&sfs, bufp, copy_size);
+ }
+ else {
+ struct statfs sfs;
+ my_size = copy_size = sizeof(sfs);
+ bzero(&sfs, my_size);
+
+ sfs.f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
+ sfs.f_type = mp->mnt_vtable->vfc_typenum;
+ sfs.f_reserved1 = (short)sfsp->f_fssubtype;
+
+ /*
+ * It's possible for there to be more than 2^^31 blocks in the filesystem, so we
+ * have to fudge the numbers here in that case. We inflate the blocksize in order
+ * to reflect the filesystem size as best we can.
+ */
+ if ((sfsp->f_blocks > LONG_MAX)
+ /* Hack for 4061702 . I think the real fix is for Carbon to
+ * look for some volume capability and not depend on hidden
+ * semantics agreed between a FS and carbon.
+ * f_blocks, f_bfree, and f_bavail set to -1 is the trigger
+ * for Carbon to set bNoVolumeSizes volume attribute.
+ * Without this the webdavfs files cannot be copied onto
+ * disk as they look huge. This change should not affect
+ * XSAN as they should not setting these to -1..
+ */
+ && (sfsp->f_blocks != 0xffffffffffffffff)
+ && (sfsp->f_bfree != 0xffffffffffffffff)
+ && (sfsp->f_bavail != 0xffffffffffffffff)) {
+ int shift;
+
+ /*
+ * Work out how far we have to shift the block count down to make it fit.
+ * Note that it's possible to have to shift so far that the resulting
+ * blocksize would be unreportably large. At that point, we will clip
+ * any values that don't fit.
+ *
+ * For safety's sake, we also ensure that f_iosize is never reported as
+ * being smaller than f_bsize.
+ */
+ for (shift = 0; shift < 32; shift++) {
+ if ((sfsp->f_blocks >> shift) <= LONG_MAX)
+ break;
+ if ((sfsp->f_bsize << (shift + 1)) > LONG_MAX)
+ break;
+ }
+#define __SHIFT_OR_CLIP(x, s) ((((x) >> (s)) > LONG_MAX) ? LONG_MAX : ((x) >> (s)))
+ sfs.f_blocks = (long)__SHIFT_OR_CLIP(sfsp->f_blocks, shift);
+ sfs.f_bfree = (long)__SHIFT_OR_CLIP(sfsp->f_bfree, shift);
+ sfs.f_bavail = (long)__SHIFT_OR_CLIP(sfsp->f_bavail, shift);
+#undef __SHIFT_OR_CLIP
+ sfs.f_bsize = (long)(sfsp->f_bsize << shift);
+ sfs.f_iosize = lmax(sfsp->f_iosize, sfsp->f_bsize);
+ } else {
+ /* filesystem is small enough to be reported honestly */
+ sfs.f_bsize = (long)sfsp->f_bsize;
+ sfs.f_iosize = (long)sfsp->f_iosize;
+ sfs.f_blocks = (long)sfsp->f_blocks;
+ sfs.f_bfree = (long)sfsp->f_bfree;
+ sfs.f_bavail = (long)sfsp->f_bavail;
+ }
+ sfs.f_files = (long)sfsp->f_files;
+ sfs.f_ffree = (long)sfsp->f_ffree;
+ sfs.f_fsid = sfsp->f_fsid;
+ sfs.f_owner = sfsp->f_owner;
+ strncpy(&sfs.f_fstypename[0], &sfsp->f_fstypename[0], MFSNAMELEN-1);
+ strncpy(&sfs.f_mntonname[0], &sfsp->f_mntonname[0], MNAMELEN-1);
+ strncpy(&sfs.f_mntfromname[0], &sfsp->f_mntfromname[0], MNAMELEN-1);
+
+ if (partial_copy) {
+ copy_size -= (sizeof(sfs.f_reserved3) + sizeof(sfs.f_reserved4));
+ }
+ error = copyout((caddr_t)&sfs, bufp, copy_size);
+ }
+
+ if (sizep != NULL) {
+ *sizep = my_size;
+ }
+ return(error);
+}
+
+/*
+ * copy stat structure into user_stat structure.
+ */
+void munge_stat(struct stat *sbp, struct user_stat *usbp)
+{
+ usbp->st_dev = sbp->st_dev;
+ usbp->st_ino = sbp->st_ino;
+ usbp->st_mode = sbp->st_mode;
+ usbp->st_nlink = sbp->st_nlink;
+ usbp->st_uid = sbp->st_uid;
+ usbp->st_gid = sbp->st_gid;
+ usbp->st_rdev = sbp->st_rdev;
+#ifndef _POSIX_SOURCE
+ usbp->st_atimespec.tv_sec = sbp->st_atimespec.tv_sec;
+ usbp->st_atimespec.tv_nsec = sbp->st_atimespec.tv_nsec;
+ usbp->st_mtimespec.tv_sec = sbp->st_mtimespec.tv_sec;
+ usbp->st_mtimespec.tv_nsec = sbp->st_mtimespec.tv_nsec;
+ usbp->st_ctimespec.tv_sec = sbp->st_ctimespec.tv_sec;
+ usbp->st_ctimespec.tv_nsec = sbp->st_ctimespec.tv_nsec;
+#else
+ usbp->st_atime = sbp->st_atime;
+ usbp->st_atimensec = sbp->st_atimensec;
+ usbp->st_mtime = sbp->st_mtime;
+ usbp->st_mtimensec = sbp->st_mtimensec;
+ usbp->st_ctime = sbp->st_ctime;
+ usbp->st_ctimensec = sbp->st_ctimensec;
+#endif
+ usbp->st_size = sbp->st_size;
+ usbp->st_blocks = sbp->st_blocks;
+ usbp->st_blksize = sbp->st_blksize;
+ usbp->st_flags = sbp->st_flags;
+ usbp->st_gen = sbp->st_gen;
+ usbp->st_lspare = sbp->st_lspare;
+ usbp->st_qspare[0] = sbp->st_qspare[0];
+ usbp->st_qspare[1] = sbp->st_qspare[1];
+}