- struct nameidata nd;
- struct filedesc *fdp = p->p_fd;
- int fmode;
- int cmode;
-
- /*
- * Open the named file in the upper layer. Note that
- * the file may have come into existence *since* the
- * lookup was done, since the upper layer may really
- * be a loopback mount of some other filesystem...
- * so open the file with exclusive create and barf if
- * it already exists.
- * XXX - perhaps shoudl re-lookup the node (once more
- * with feeling) and simply open that. Who knows.
- */
- NDINIT(&nd, CREATE, 0, UIO_SYSSPACE, un->un_path, p);
- fmode = (O_CREAT|O_TRUNC|O_EXCL);
- cmode = UN_FILEMODE & ~fdp->fd_cmask;
- error = vn_open(&nd, fmode, cmode);
- if (error)
- return (error);
- un->un_uppervp = nd.ni_vp; /* XXX */
- /* at this point, uppervp is locked */
-
- /*
- * Now, if the file is being opened with truncation,
- * then the (new) upper vnode is ready to fly,
- * otherwise the data from the lower vnode must be
- * copied to the upper layer first. This only works
- * for regular files (check is made above).
- */
- if ((mode & O_TRUNC) == 0) {
- /*
- * XXX - should not ignore errors
- * from VOP_CLOSE
- */
- VOP_LOCK(un->un_lowervp);
- error = VOP_OPEN(tvp, FREAD, cred, p);
- if (error == 0) {
- error = union_copyfile(p, cred,
- tvp, un->un_uppervp);
- VOP_UNLOCK(tvp);
- (void) VOP_CLOSE(tvp, FREAD);
- } else {
- VOP_UNLOCK(tvp);
- }
- VOP_UNLOCK(un->un_uppervp);
- (void) VOP_CLOSE(un->un_uppervp, FWRITE);
- VOP_LOCK(un->un_uppervp);
- }