PERFORCE change 42266 for review
Chris Vance
cvance at FreeBSD.org
Thu Nov 13 20:11:27 GMT 2003
http://perforce.freebsd.org/chv.cgi?CH=42266
Change 42266 by cvance at cvance_osx_laptop on 2003/11/13 12:10:46
With this submission, HFS supports basic extattr use. Only the
autostart mechanism is supported, along with get & set operations.
- Added shutdown routines
- Added ENOATTR error code
- Added support for the hfs_sextattr_set operation
- Removed extaneous debugging
Affected files ...
.. //depot/projects/trustedbsd/sedarwin/apsl/xnu/bsd/hfs/hfs_extattr.c#4 edit
.. //depot/projects/trustedbsd/sedarwin/apsl/xnu/bsd/hfs/hfs_vfsops.c#4 edit
.. //depot/projects/trustedbsd/sedarwin/apsl/xnu/bsd/sys/errno.h#2 edit
Differences ...
==== //depot/projects/trustedbsd/sedarwin/apsl/xnu/bsd/hfs/hfs_extattr.c#4 (text+ko) ====
@@ -59,6 +59,12 @@
#ifdef HFS_EXTATTR
+/* XXX/TBD: This should be available via a sysctl */
+static hfs_extattr_sync = 0;
+
+static int hfs_extattr_disable(struct hfsmount *hfsmp, int attrnamespace,
+ const char *attrname, struct proc *p);
+
/*
* Lock functions copied/ported From FreeBSD 5.1, including comments...
*
@@ -154,7 +160,7 @@
panic("hfs_extattr_uepm_destroy: not initialized");
if ((uepm->uepm_flags & HFS_EXTATTR_UEPM_STARTED))
- panic("Hfs_extattr_uepm_destroy: called while still started");
+ panic("hfs_extattr_uepm_destroy: called while still started");
simple_lock(&mountlist_slock);
uepm->uepm_flags &= ~HFS_EXTATTR_UEPM_INITIALIZED;
@@ -211,7 +217,6 @@
struct vnode *target_vp;
int error;
- printf("hfs_extattr_lookup: called with dirname=%s\n", dirname);
bzero(&cnp, sizeof(cnp));
cnp.cn_nameiop = LOOKUP;
cnp.cn_flags = ISLASTCN;
@@ -229,7 +234,6 @@
VOP_UNLOCK(start_dvp, 0, p);
}
_FREE_ZONE(cnp.cn_pnbuf, cnp.cn_pnlen, M_NAMEI);
- printf("hfs_extattr_lookup: copystr failed\n");
return (error);
}
cnp.cn_namelen--; /* trim nul termination */
@@ -255,7 +259,6 @@
if (lockparent == UE_GETDIR_LOCKPARENT)
panic("hfs_extattr_lookup: lockparent but PDIRUNLOCK");
*/
- printf("hfs_extattr_lookup: hfs_lookup failed with error %d\n", error);
return (error);
}
/*
@@ -272,7 +275,6 @@
panic("hfs_extattr_lookup: lockparent but PDIRUNLOCK");
*/
- printf("hfs_extattr_lookup: success, vp=%x\n", vp);
*vp = target_vp;
return (0);
}
@@ -337,20 +339,16 @@
goto unlock_free_exit;
if (auio.uio_resid != 0) {
- printf("hfs_extattr_enable: malformed attribute header\n");
error = EINVAL;
goto unlock_free_exit;
}
if (attribute->uele_fileheader.uef_magic != HFS_EXTATTR_MAGIC) {
- printf("hfs_extattr_enable: invalid attribute header magic\n");
error = EINVAL;
goto unlock_free_exit;
}
if (attribute->uele_fileheader.uef_version != HFS_EXTATTR_VERSION) {
- printf("hfs_extattr_enable: incorrect attribute header "
- "version\n");
error = EINVAL;
goto unlock_free_exit;
}
@@ -392,8 +390,6 @@
error = VOP_OPEN(vp, FREAD|FWRITE, p->p_ucred, p);
if (error) {
ubc_rele(vp);
- printf("hfs_extattr_enable_with_open.VOP_OPEN(): failed "
- "with %d\n", error);
VOP_UNLOCK(vp, 0, p);
return (error);
}
@@ -408,6 +404,8 @@
error = hfs_extattr_enable(hfsmp, attrnamespace, attrname, vp, p);
if (error != 0)
vn_close(vp, FREAD|FWRITE, p->p_ucred, p);
+
+
return (error);
}
@@ -462,8 +460,6 @@
aiov.iov_len = DIRBLKSIZ;
error = hfs_readdir(&vargs);
if (error) {
- printf("hfs_extattr_iterate_directory: hfs_readdir "
- "%d\n", error);
return (error);
}
@@ -490,11 +486,7 @@
error = hfs_extattr_enable_with_open(hfsmp,
attr_vp, attrnamespace, dp->d_name, p);
vrele(attr_vp);
- if (error) {
- printf("hfs_extattr_iterate_directory: "
- "enable %s %d\n", dp->d_name,
- error);
- } else {
+ if (!error) {
printf("HFS autostarted EA %s\n",
dp->d_name);
}
@@ -518,7 +510,6 @@
hfs_extattr_autostart(struct mount *mp, struct proc *p)
{
- printf("hfs_extattr_autostart called\n");
struct vnode *rvp, *attr_dvp, *attr_system_dvp, *attr_user_dvp;
int error;
@@ -528,8 +519,6 @@
*/
error = VFS_ROOT(mp, &rvp);
if (error) {
- printf("hfs_extattr_autostart.VFS_ROOT() returned %d\n",
- error);
return (error);
}
@@ -556,8 +545,6 @@
error = hfs_extattr_start(mp, p);
if (error) {
- printf("hfs_extattr_autostart: hfs_extattr_start failed (%d)\n",
- error);
goto return_vput_attr_dvp;
}
@@ -573,9 +560,6 @@
if (!error) {
error = hfs_extattr_iterate_directory(VFSTOHFS(mp),
attr_system_dvp, EXTATTR_NAMESPACE_SYSTEM, p);
- if (error)
- printf("hfs_extattr_iterate_directory returned %d\n",
- error);
vput(attr_system_dvp);
}
@@ -584,9 +568,6 @@
if (!error) {
error = hfs_extattr_iterate_directory(VFSTOHFS(mp),
attr_user_dvp, EXTATTR_NAMESPACE_USER, p);
- if (error)
- printf("hfs_extattr_iterate_directory returned %d\n",
- error);
vput(attr_user_dvp);
}
@@ -606,8 +587,32 @@
hfs_extattr_stop(struct mount *mp, struct proc *p)
{
- printf("hfs_extattr_stop called\n");
- return (0);
+ struct hfs_extattr_list_entry *uele;
+ struct hfsmount *hfsmp = VFSTOHFS(mp);
+ int error = 0;
+
+ hfs_extattr_uepm_lock(hfsmp, p);
+
+ if (!(hfsmp->hfs_extattr.uepm_flags & HFS_EXTATTR_UEPM_STARTED)) {
+ error = EOPNOTSUPP;
+ goto unlock;
+ }
+
+ while (LIST_FIRST(&hfsmp->hfs_extattr.uepm_list) != NULL) {
+ uele = LIST_FIRST(&hfsmp->hfs_extattr.uepm_list);
+ hfs_extattr_disable(hfsmp, uele->uele_attrnamespace,
+ uele->uele_attrname, p);
+ }
+
+ hfsmp->hfs_extattr.uepm_flags &= ~HFS_EXTATTR_UEPM_STARTED;
+
+ crfree(hfsmp->hfs_extattr.uepm_ucred);
+ hfsmp->hfs_extattr.uepm_ucred = NULL;
+
+unlock:
+ hfs_extattr_uepm_unlock(hfsmp, p);
+
+ return (error);
}
/*
@@ -619,7 +624,149 @@
struct uio *uio, size_t *size, struct ucred *cred, struct proc *p)
{
- return (ENOTSUP);
+ struct hfs_extattr_list_entry *attribute;
+ struct hfs_extattr_header ueh;
+ struct iovec local_aiov;
+ struct uio local_aio;
+ struct mount *mp = vp->v_mount;
+ struct hfsmount *hfsmp = VFSTOHFS(mp);
+ struct cnode *cp = VTOC(vp);
+ off_t base_offset;
+ size_t len, old_len;
+ int error = 0;
+
+ if (!(hfsmp->hfs_extattr.uepm_flags & HFS_EXTATTR_UEPM_STARTED))
+ return (EOPNOTSUPP);
+
+ if (strlen(name) == 0)
+ return (EINVAL);
+
+/*
+ * XXX/TBD:
+ */
+/*
+ error = extattr_check_cred(vp, attrnamespace, cred, p, IREAD);
+ if (error)
+ return (error);
+*/
+
+ attribute = hfs_extattr_find_attr(hfsmp, attrnamespace, name);
+ if (!attribute)
+ return (ENOATTR);
+
+ /*
+ * Allow only offsets of zero to encourage the read/replace
+ * extended attribute semantic. Otherwise we can't guarantee
+ * atomicity, as we don't provide locks for extended attributes.
+ */
+ if (uio != NULL && uio->uio_offset != 0)
+ return (ENXIO);
+
+ /*
+ * Find base offset of header in file based on file header size, and
+ * data header size + maximum data size, indexed by inode number.
+ */
+ base_offset = sizeof(struct hfs_extattr_fileheader) +
+ cp->c_fileid * (sizeof(struct hfs_extattr_header) +
+ attribute->uele_fileheader.uef_size);
+
+ /*
+ * Read in the data header to see if the data is defined, and if so
+ * how much.
+ */
+ bzero(&ueh, sizeof(struct hfs_extattr_header));
+ local_aiov.iov_base = (caddr_t) &ueh;
+ local_aiov.iov_len = sizeof(struct hfs_extattr_header);
+ local_aio.uio_iov = &local_aiov;
+ local_aio.uio_iovcnt = 1;
+ local_aio.uio_rw = UIO_READ;
+ local_aio.uio_segflg = UIO_SYSSPACE;
+ local_aio.uio_procp = p;
+ local_aio.uio_offset = base_offset;
+ local_aio.uio_resid = sizeof(struct hfs_extattr_header);
+
+ /*
+ * Acquire locks.
+ */
+ VOP_LEASE(attribute->uele_backing_vnode, p, cred, LEASE_READ);
+ /*
+ * Don't need to get a lock on the backing file if the getattr is
+ * being applied to the backing file, as the lock is already held.
+ */
+ if (attribute->uele_backing_vnode != vp)
+ vn_lock(attribute->uele_backing_vnode, LK_SHARED |
+ LK_RETRY, p);
+
+ error = VOP_READ(attribute->uele_backing_vnode, &local_aio,
+ IO_NODELOCKED, hfsmp->hfs_extattr.uepm_ucred);
+ if (error)
+ goto vopunlock_exit;
+
+ /* Defined? */
+ if ((ueh.ueh_flags & HFS_EXTATTR_ATTR_FLAG_INUSE) == 0) {
+ error = ENOATTR;
+ goto vopunlock_exit;
+ }
+
+#ifdef HFS_GENERATIONS
+ /* XXX/TBD: is there something similiar in hfs? */
+
+ /* Valid for the current inode generation? */
+ if (ueh.ueh_i_gen != ip->i_gen) {
+ /*
+ * The inode itself has a different generation number
+ * than the attribute data. For now, the best solution
+ * is to coerce this to undefined, and let it get cleaned
+ * up by the next write or extattrctl clean.
+ */
+ printf("hfs_extattr_get (%s): inode number inconsistency (%d, %jd)\n",
+ mp->mnt_stat.f_mntonname, ueh.ueh_i_gen, (intmax_t)ip->i_gen);
+ error = ENOATTR;
+ goto vopunlock_exit;
+ }
+#endif
+
+ /* Local size consistency check. */
+ if (ueh.ueh_len > attribute->uele_fileheader.uef_size) {
+ error = ENXIO;
+ goto vopunlock_exit;
+ }
+
+ /* Return full data size if caller requested it. */
+ if (size != NULL)
+ *size = ueh.ueh_len;
+
+ /* Return data if the caller requested it. */
+ if (uio != NULL) {
+ /* Allow for offset into the attribute data. */
+ uio->uio_offset = base_offset + sizeof(struct
+ hfs_extattr_header);
+
+ /*
+ * Figure out maximum to transfer -- use buffer size and
+ * local data limit.
+ */
+ len = MIN(uio->uio_resid, ueh.ueh_len);
+ old_len = uio->uio_resid;
+ uio->uio_resid = len;
+
+ error = VOP_READ(attribute->uele_backing_vnode, uio,
+ IO_NODELOCKED, hfsmp->hfs_extattr.uepm_ucred);
+ if (error)
+ goto vopunlock_exit;
+
+ uio->uio_resid = old_len - (len - uio->uio_resid);
+ }
+
+vopunlock_exit:
+
+ if (uio != NULL)
+ uio->uio_offset = 0;
+
+ if (attribute->uele_backing_vnode != vp)
+ VOP_UNLOCK(attribute->uele_backing_vnode, 0, p);
+
+ return (error);
}
/*
@@ -630,8 +777,119 @@
hfs_extattr_set(struct vnode *vp, int attrnamespace, const char *name,
struct uio *uio, struct ucred *cred, struct proc *p)
{
+ struct hfs_extattr_list_entry *attribute;
+ struct hfs_extattr_header ueh;
+ struct iovec local_aiov;
+ struct uio local_aio;
+ struct mount *mp = vp->v_mount;
+ struct hfsmount *hfsmp = VFSTOHFS(mp);
+ struct cnode *cp = VTOC(vp);
+ off_t base_offset;
+ int error = 0, ioflag;
+
+ if (vp->v_mount->mnt_flag & MNT_RDONLY)
+ return (EROFS);
+ if (!(hfsmp->hfs_extattr.uepm_flags & HFS_EXTATTR_UEPM_STARTED))
+ return (EOPNOTSUPP);
+ if (!hfs_extattr_valid_attrname(attrnamespace, name))
+ return (EINVAL);
+
+/*
+ * XXX/TBD:
+ */
+/*
+ error = extattr_check_cred(vp, attrnamespace, cred, td, IWRITE);
+ if (error)
+ return (error);
+*/
+ attribute = hfs_extattr_find_attr(hfsmp, attrnamespace, name);
- return (ENOTSUP);
+ if (!attribute) {
+ return (ENOATTR);
+ }
+
+ /*
+ * Early rejection of invalid offsets/length.
+ * Reject: any offset but 0 (replace)
+ * Any size greater than attribute size limit
+ */
+ if (uio->uio_offset != 0 ||
+ uio->uio_resid > attribute->uele_fileheader.uef_size) {
+ return (ENXIO);
+ }
+
+ /*
+ * Find base offset of header in file based on file header size, and
+ * data header size + maximum data size, indexed by inode number.
+ */
+ base_offset = sizeof(struct hfs_extattr_fileheader) +
+ cp->c_fileid * (sizeof(struct hfs_extattr_header) +
+ attribute->uele_fileheader.uef_size);
+
+ /*
+ * Write out a data header for the data.
+ */
+ ueh.ueh_len = uio->uio_resid;
+ ueh.ueh_flags = HFS_EXTATTR_ATTR_FLAG_INUSE;
+#ifdef HFS_GENERATIONS
+ /* XXX/TBD: is there something similiar in hfs? */
+ ueh.ueh_i_gen = ip->i_gen;
+#endif
+ local_aiov.iov_base = (caddr_t) &ueh;
+ local_aiov.iov_len = sizeof(struct hfs_extattr_header);
+ local_aio.uio_iov = &local_aiov;
+ local_aio.uio_iovcnt = 1;
+ local_aio.uio_rw = UIO_WRITE;
+ local_aio.uio_segflg = UIO_SYSSPACE;
+ local_aio.uio_procp = p;
+ local_aio.uio_offset = base_offset;
+ local_aio.uio_resid = sizeof(struct hfs_extattr_header);
+
+ /*
+ * Acquire locks.
+ */
+ VOP_LEASE(attribute->uele_backing_vnode, p, cred, LEASE_WRITE);
+
+ /*
+ * Don't need to get a lock on the backing file if the setattr is
+ * being applied to the backing file, as the lock is already held.
+ */
+ if (attribute->uele_backing_vnode != vp)
+ vn_lock(attribute->uele_backing_vnode,
+ LK_EXCLUSIVE | LK_RETRY, p);
+
+ ioflag = IO_NODELOCKED;
+ if (hfs_extattr_sync)
+ ioflag |= IO_SYNC;
+ error = VOP_WRITE(attribute->uele_backing_vnode, &local_aio, ioflag,
+ hfsmp->hfs_extattr.uepm_ucred);
+ if (error) {
+ goto vopunlock_exit;
+ }
+
+ if (local_aio.uio_resid != 0) {
+ error = ENXIO;
+ goto vopunlock_exit;
+ }
+
+ /*
+ * Write out user data.
+ */
+ uio->uio_offset = base_offset + sizeof(struct hfs_extattr_header);
+
+ ioflag = IO_NODELOCKED;
+ if (hfs_extattr_sync)
+ ioflag |= IO_SYNC;
+ error = VOP_WRITE(attribute->uele_backing_vnode, uio, ioflag,
+ hfsmp->hfs_extattr.uepm_ucred);
+
+vopunlock_exit:
+ uio->uio_offset = 0;
+
+ if (attribute->uele_backing_vnode != vp)
+ VOP_UNLOCK(attribute->uele_backing_vnode, 0, p);
+
+ return (error);
}
/*
@@ -667,7 +925,6 @@
struct hfsmount *hfsmp = VTOHFS(ap->a_vp);
int error;
- printf("hfs_getextattr called\n");
hfs_extattr_uepm_lock(hfsmp, ap->a_p);
@@ -700,7 +957,6 @@
int error;
- printf("hfs_setextattr called\n");
hfs_extattr_uepm_lock(hfsmp, ap->a_p);
/*
@@ -749,5 +1005,38 @@
return (error);
}
+/*
+ * Disable extended attribute support on an FS.
+ */
+static int
+hfs_extattr_disable(struct hfsmount *hfsmp, int attrnamespace,
+ const char *attrname, struct proc *p)
+{
+ struct hfs_extattr_list_entry *uele;
+ int error = 0;
+
+ if (!hfs_extattr_valid_attrname(attrnamespace, attrname)) {
+ return (EINVAL);
+ }
+
+ uele = hfs_extattr_find_attr(hfsmp, attrnamespace, attrname);
+ if (!uele) {
+ return (ENOATTR);
+ }
+
+ LIST_REMOVE(uele, uele_entries);
+
+ vn_lock(uele->uele_backing_vnode, LK_SHARED | LK_RETRY, p);
+/* XXX/TBD */
+/* ASSERT_VOP_LOCKED(uele->uele_backing_vnode, "hfs_extattr_disable"); */
+ uele->uele_backing_vnode->v_flag &= ~VSYSTEM;
+ VOP_UNLOCK(uele->uele_backing_vnode, 0, p);
+ error = vn_close(uele->uele_backing_vnode, FREAD|FWRITE,
+ p->p_ucred, p);
+
+ FREE(uele, M_EXTATTR);
+
+ return (error);
+}
#endif /* !HFS_EXTATTR */
==== //depot/projects/trustedbsd/sedarwin/apsl/xnu/bsd/hfs/hfs_vfsops.c#4 (text+ko) ====
@@ -1225,11 +1225,11 @@
force = 1;
}
-#ifdef UFS_EXTATTR
- if ((error = hfs_extattr_stop(mp, p))) {
- if (error != ENOTSUP)
+#ifdef HFS_EXTATTR
+ if ((retval = hfs_extattr_stop(mp, p))) {
+ if (retval != ENOTSUP)
printf("hfs_unmount: hfs_extattr_stop returned %d\n",
- error);
+ retval);
} else {
hfs_extattr_uepm_destroy(&hfsmp->hfs_extattr, p);
}
==== //depot/projects/trustedbsd/sedarwin/apsl/xnu/bsd/sys/errno.h#2 (text+ko) ====
@@ -205,7 +205,8 @@
#define EBADMACHO 88 /* Malformed Macho file */
#define ECANCELED 89 /* Operation canceled */
-#define ELAST 89 /* Must be equal largest errno */
+#define ENOATTR 90 /* Attribute not found */
+#define ELAST 90 /* Must be equal largest errno */
#endif /* _POSIX_SOURCE */
#ifdef KERNEL
To Unsubscribe: send mail to majordomo at trustedbsd.org
with "unsubscribe trustedbsd-cvs" in the body of the message
More information about the trustedbsd-cvs
mailing list