+static void
+filt_hfsdetach(struct knote *kn)
+{
+ struct vnode *vp;
+ int result;
+ struct proc *p = current_proc();
+
+ vp = (struct vnode *)kn->kn_hook;
+ if (1) { /* ! KNDETACH_VNLOCKED */
+ result = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
+ if (result) return;
+ };
+
+ result = KNOTE_DETACH(&VTOC(vp)->c_knotes, kn);
+
+ if (1) { /* ! KNDETACH_VNLOCKED */
+ VOP_UNLOCK(vp, 0, p);
+ };
+}
+
+/*ARGSUSED*/
+static int
+filt_hfsread(struct knote *kn, long hint)
+{
+ struct vnode *vp = (struct vnode *)kn->kn_fp->f_data;
+
+ if (hint == NOTE_REVOKE) {
+ /*
+ * filesystem is gone, so set the EOF flag and schedule
+ * the knote for deletion.
+ */
+ kn->kn_flags |= (EV_EOF | EV_ONESHOT);
+ return (1);
+ }
+
+ kn->kn_data = VTOF(vp)->ff_size - kn->kn_fp->f_offset;
+ return (kn->kn_data != 0);
+}
+
+/*ARGSUSED*/
+static int
+filt_hfswrite(struct knote *kn, long hint)
+{
+ if (hint == NOTE_REVOKE) {
+ /*
+ * filesystem is gone, so set the EOF flag and schedule
+ * the knote for deletion.
+ */
+ kn->kn_flags |= (EV_EOF | EV_ONESHOT);
+ }
+
+ kn->kn_data = 0;
+ return (1);
+}
+
+static int
+filt_hfsvnode(struct knote *kn, long hint)
+{
+
+ if (kn->kn_sfflags & hint)
+ kn->kn_fflags |= hint;
+ if (hint == NOTE_REVOKE) {
+ kn->kn_flags |= EV_EOF;
+ return (1);
+ }
+ return (kn->kn_fflags != 0);
+}
+
+static struct filterops hfsread_filtops =
+ { 1, NULL, filt_hfsdetach, filt_hfsread };
+static struct filterops hfswrite_filtops =
+ { 1, NULL, filt_hfsdetach, filt_hfswrite };
+static struct filterops hfsvnode_filtops =
+ { 1, NULL, filt_hfsdetach, filt_hfsvnode };
+
+/*
+ #
+ #% kqfilt_add vp L L L
+ #
+ vop_kqfilt_add
+ IN struct vnode *vp;
+ IN struct knote *kn;
+ IN struct proc *p;
+ */
+static int
+hfs_kqfilt_add(ap)
+ struct vop_kqfilt_add_args /* {
+ struct vnode *a_vp;
+ struct knote *a_kn;
+ struct proc *p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ struct knote *kn = ap->a_kn;
+
+ switch (kn->kn_filter) {
+ case EVFILT_READ:
+ if (vp->v_type == VREG) {
+ kn->kn_fop = &hfsread_filtops;
+ } else {
+ return EINVAL;
+ };
+ break;
+ case EVFILT_WRITE:
+ if (vp->v_type == VREG) {
+ kn->kn_fop = &hfswrite_filtops;
+ } else {
+ return EINVAL;
+ };
+ break;
+ case EVFILT_VNODE:
+ kn->kn_fop = &hfsvnode_filtops;
+ break;
+ default:
+ return (1);
+ }
+
+ kn->kn_hook = (caddr_t)vp;
+
+ /* simple_lock(&vp->v_pollinfo.vpi_lock); */
+ KNOTE_ATTACH(&VTOC(vp)->c_knotes, kn);
+ /* simple_unlock(&vp->v_pollinfo.vpi_lock); */
+
+ return (0);
+}
+
+/*
+ #
+ #% kqfilt_remove vp L L L
+ #
+ vop_kqfilt_remove
+ IN struct vnode *vp;
+ IN uintptr_t ident;
+ IN struct proc *p;
+ */
+static int
+hfs_kqfilt_remove(ap)
+ struct vop_kqfilt_remove_args /* {
+ struct vnode *a_vp;
+ uintptr_t ident;
+ struct proc *p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+ uintptr_t ident = ap->a_ident;
+ int result;
+
+ result = ENOTSUP; /* XXX */
+
+ return (result);
+}
+