+/*
+ * Verify that the vnode 'vp' is a vnode that lives in the shadow
+ * directory. We can't just query the parent pointer directly since
+ * the shadowfile is hooked up to the actual file it's a stream for.
+ */
+errno_t vnode_verifynamedstream(vnode_t vp) {
+ int error;
+ struct vnode *shadow_dvp = NULL;
+ struct vnode *shadowfile = NULL;
+ struct componentname cn;
+
+ /*
+ * We need to use the kernel context here. If we used the supplied
+ * VFS context we have no clue whether or not it originated from userland
+ * where it could be subject to a chroot jail. We need to ensure that all
+ * filesystem access to shadow files is done on the same FS regardless of
+ * userland process restrictions.
+ */
+ vfs_context_t kernelctx = vfs_context_kernel();
+ char tmpname[80];
+
+
+ /* Get the shadow directory vnode */
+ error = get_shadow_dir(&shadow_dvp);
+ if (error) {
+ return error;
+ }
+
+ /* Re-generate the shadow name in the buffer */
+ MAKE_SHADOW_NAME (vp, tmpname);
+
+ /* Look up item in shadow dir */
+ bzero(&cn, sizeof(cn));
+ cn.cn_nameiop = LOOKUP;
+ cn.cn_flags = ISLASTCN | CN_ALLOWRSRCFORK;
+ cn.cn_context = kernelctx;
+ cn.cn_pnbuf = tmpname;
+ cn.cn_pnlen = sizeof(tmpname);
+ cn.cn_nameptr = cn.cn_pnbuf;
+ cn.cn_namelen = strlen(tmpname);
+
+ if (VNOP_LOOKUP (shadow_dvp, &shadowfile, &cn, kernelctx) == 0) {
+ /* is the pointer the same? */
+ if (shadowfile == vp) {
+ error = 0;
+ }
+ else {
+ error = EPERM;
+ }
+ /* drop the iocount acquired */
+ vnode_put (shadowfile);
+ }
+
+ /* Drop iocount on shadow dir */
+ vnode_put (shadow_dvp);
+ return error;
+}
+
+/*
+ * Access or create the shadow file as needed.
+ *
+ * 'makestream' with non-zero value means that we need to guarantee we were the
+ * creator of the shadow file.
+ *
+ * 'context' is the user supplied context for the original VFS operation that
+ * caused us to need a shadow file.
+ *
+ * int pointed to by 'creator' is nonzero if we created the shadowfile.
+ */