2 * modified for EXT2FS support in Lites 1.1
4 * Aug 1995, Godmar Back (gback@cs.utah.edu)
5 * University of Utah, Department of Computer Science
8 * Copyright (c) 1982, 1986, 1989, 1993
9 * The Regents of the University of California. All rights reserved.
10 * (c) UNIX System Laboratories, Inc.
11 * All or some portions of this file are derived from material licensed
12 * to the University of California by American Telephone and Telegraph
13 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
14 * the permission of UNIX System Laboratories, Inc.
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. All advertising materials mentioning features or use of this software
25 * must display the following acknowledgement:
26 * This product includes software developed by the University of
27 * California, Berkeley and its contributors.
28 * 4. Neither the name of the University nor the names of its contributors
29 * may be used to endorse or promote products derived from this software
30 * without specific prior written permission.
32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 * @(#)ufs_vnops.c 8.27 (Berkeley) 5/27/95
45 * @(#)ext2_vnops.c 8.7 (Berkeley) 2/3/94
49 #include "opt_quota.h"
50 #include "opt_suiddir.h"
52 #include <sys/param.h>
53 #include <sys/systm.h>
54 #include <sys/resourcevar.h>
55 #include <sys/kernel.h>
59 #include <sys/mount.h>
61 #include <sys/vnode.h>
62 #include <sys/namei.h>
65 #include <vm/vm_extern.h>
66 #include <vm/vm_zone.h>
67 #include <vm/vnode_pager.h>
69 #include <sys/signalvar.h>
70 #include <ufs/ufs/dir.h>
71 #include <ufs/ufs/quota.h>
72 #include <ufs/ufs/inode.h>
73 #include <ufs/ufs/ufsmount.h>
74 #include <ufs/ufs/ufs_extern.h>
76 #include <gnu/ext2fs/ext2_fs_sb.h>
77 #include <gnu/ext2fs/fs.h>
78 #include <gnu/ext2fs/ext2_extern.h>
80 static int ext2_makeinode __P((int mode, struct vnode *, struct vnode **, struct componentname *));
82 static int ext2_fsync __P((struct vop_fsync_args *));
83 static int ext2_read __P((struct vop_read_args *));
84 static int ext2_write __P((struct vop_write_args *));
85 static int ext2_remove __P((struct vop_remove_args *));
86 static int ext2_link __P((struct vop_link_args *));
87 static int ext2_rename __P((struct vop_rename_args *));
88 static int ext2_mkdir __P((struct vop_mkdir_args *));
89 static int ext2_rmdir __P((struct vop_rmdir_args *));
90 static int ext2_create __P((struct vop_create_args *));
91 static int ext2_mknod __P((struct vop_mknod_args *));
92 static int ext2_symlink __P((struct vop_symlink_args *));
93 static int ext2_getpages __P((struct vop_getpages_args *));
94 static int ext2_putpages __P((struct vop_putpages_args *));
96 /* Global vfs data structures for ufs. */
97 vop_t **ext2_vnodeop_p;
98 static struct vnodeopv_entry_desc ext2_vnodeop_entries[] = {
99 { &vop_default_desc, (vop_t *) ufs_vnoperate },
100 { &vop_cachedlookup_desc, (vop_t *) ext2_lookup },
101 { &vop_fsync_desc, (vop_t *) ext2_fsync },
102 { &vop_inactive_desc, (vop_t *) ext2_inactive },
103 { &vop_lookup_desc, (vop_t *) vfs_cache_lookup },
104 { &vop_read_desc, (vop_t *) ext2_read },
105 { &vop_readdir_desc, (vop_t *) ext2_readdir },
106 { &vop_reallocblks_desc, (vop_t *) ext2_reallocblks },
107 { &vop_write_desc, (vop_t *) ext2_write },
108 { &vop_remove_desc, (vop_t *) ext2_remove },
109 { &vop_link_desc, (vop_t *) ext2_link },
110 { &vop_rename_desc, (vop_t *) ext2_rename },
111 { &vop_mkdir_desc, (vop_t *) ext2_mkdir },
112 { &vop_rmdir_desc, (vop_t *) ext2_rmdir },
113 { &vop_create_desc, (vop_t *) ext2_create },
114 { &vop_mknod_desc, (vop_t *) ext2_mknod },
115 { &vop_symlink_desc, (vop_t *) ext2_symlink },
116 { &vop_getpages_desc, (vop_t *) ext2_getpages },
117 { &vop_putpages_desc, (vop_t *) ext2_putpages },
120 static struct vnodeopv_desc ext2fs_vnodeop_opv_desc =
121 { &ext2_vnodeop_p, ext2_vnodeop_entries };
123 vop_t **ext2_specop_p;
124 static struct vnodeopv_entry_desc ext2_specop_entries[] = {
125 { &vop_default_desc, (vop_t *) ufs_vnoperatespec },
126 { &vop_fsync_desc, (vop_t *) ext2_fsync },
127 { &vop_inactive_desc, (vop_t *) ext2_inactive },
130 static struct vnodeopv_desc ext2fs_specop_opv_desc =
131 { &ext2_specop_p, ext2_specop_entries };
133 vop_t **ext2_fifoop_p;
134 static struct vnodeopv_entry_desc ext2_fifoop_entries[] = {
135 { &vop_default_desc, (vop_t *) ufs_vnoperatefifo },
136 { &vop_fsync_desc, (vop_t *) ext2_fsync },
137 { &vop_inactive_desc, (vop_t *) ext2_inactive },
140 static struct vnodeopv_desc ext2fs_fifoop_opv_desc =
141 { &ext2_fifoop_p, ext2_fifoop_entries };
143 VNODEOP_SET(ext2fs_vnodeop_opv_desc);
144 VNODEOP_SET(ext2fs_specop_opv_desc);
145 VNODEOP_SET(ext2fs_fifoop_opv_desc);
147 #include <gnu/ext2fs/ext2_readwrite.c>
150 * Create a regular file
154 struct vop_create_args /* {
156 struct vnode **a_vpp;
157 struct componentname *a_cnp;
164 ext2_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
165 ap->a_dvp, ap->a_vpp, ap->a_cnp);
172 * Synch an open file.
177 struct vop_fsync_args /* {
179 struct ucred *a_cred;
184 register struct vnode *vp = ap->a_vp;
185 register struct buf *bp;
190 * XXX why is all this fs specific?
194 * Flush all dirty buffers associated with a vnode.
196 ext2_discard_prealloc(VTOI(vp));
200 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
201 nbp = TAILQ_NEXT(bp, b_vnbufs);
202 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT))
204 if ((bp->b_flags & B_DELWRI) == 0)
205 panic("ext2_fsync: not dirty");
209 * Wait for I/O associated with indirect blocks to complete,
210 * since there is no way to quickly wait for them below.
212 if (bp->b_vp == vp || ap->a_waitfor == MNT_NOWAIT)
218 if (ap->a_waitfor == MNT_WAIT) {
219 while (vp->v_numoutput) {
220 vp->v_flag |= VBWAIT;
221 tsleep(&vp->v_numoutput, PRIBIO + 1, "e2fsyn", 0);
224 if (!TAILQ_EMPTY(&vp->v_dirtyblkhd)) {
225 vprint("ext2_fsync: dirty", vp);
231 return (UFS_UPDATE(ap->a_vp, ap->a_waitfor == MNT_WAIT));
240 struct vop_mknod_args /* {
242 struct vnode **a_vpp;
243 struct componentname *a_cnp;
247 struct vattr *vap = ap->a_vap;
248 struct vnode **vpp = ap->a_vpp;
252 error = ext2_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
253 ap->a_dvp, vpp, ap->a_cnp);
257 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
258 if (vap->va_rdev != VNOVAL) {
260 * Want to be able to use this to make badblock
261 * inodes, so don't truncate the dev number.
263 ip->i_rdev = vap->va_rdev;
266 * Remove inode, then reload it through VFS_VGET so it is
267 * checked to see if it is an alias of an existing entry in
271 (*vpp)->v_type = VNON;
273 error = VFS_VGET(ap->a_dvp->v_mount, ip->i_ino, vpp);
283 struct vop_remove_args /* {
286 struct componentname *a_cnp;
290 struct vnode *vp = ap->a_vp;
291 struct vnode *dvp = ap->a_dvp;
295 if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
296 (VTOI(dvp)->i_flags & APPEND)) {
300 error = ext2_dirremove(dvp, ap->a_cnp);
303 ip->i_flag |= IN_CHANGE;
314 struct vop_link_args /* {
315 struct vnode *a_tdvp;
317 struct componentname *a_cnp;
320 struct vnode *vp = ap->a_vp;
321 struct vnode *tdvp = ap->a_tdvp;
322 struct componentname *cnp = ap->a_cnp;
323 struct proc *p = cnp->cn_proc;
328 if ((cnp->cn_flags & HASBUF) == 0)
329 panic("ufs_link: no name");
331 if (tdvp->v_mount != vp->v_mount) {
335 if (tdvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) {
339 if ((nlink_t)ip->i_nlink >= LINK_MAX) {
343 if (ip->i_flags & (IMMUTABLE | APPEND)) {
348 ip->i_flag |= IN_CHANGE;
349 error = UFS_UPDATE(vp, 1);
351 error = ext2_direnter(ip, tdvp, cnp);
354 ip->i_flag |= IN_CHANGE;
358 VOP_UNLOCK(vp, 0, p);
364 * Rename system call.
365 * See comments in sys/ufs/ufs/ufs_vnops.c
369 struct vop_rename_args /* {
370 struct vnode *a_fdvp;
372 struct componentname *a_fcnp;
373 struct vnode *a_tdvp;
375 struct componentname *a_tcnp;
378 struct vnode *tvp = ap->a_tvp;
379 register struct vnode *tdvp = ap->a_tdvp;
380 struct vnode *fvp = ap->a_fvp;
381 struct vnode *fdvp = ap->a_fdvp;
382 struct componentname *tcnp = ap->a_tcnp;
383 struct componentname *fcnp = ap->a_fcnp;
384 struct proc *p = fcnp->cn_proc;
385 struct inode *ip, *xp, *dp;
386 struct dirtemplate dirbuf;
387 int doingdirectory = 0, oldparent = 0, newparent = 0;
392 if ((tcnp->cn_flags & HASBUF) == 0 ||
393 (fcnp->cn_flags & HASBUF) == 0)
394 panic("ufs_rename: no name");
397 * Check for cross-device rename.
399 if ((fvp->v_mount != tdvp->v_mount) ||
400 (tvp && (fvp->v_mount != tvp->v_mount))) {
414 if (tvp && ((VTOI(tvp)->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
415 (VTOI(tdvp)->i_flags & APPEND))) {
421 * Check if just deleting a link name or if we've lost a race.
422 * If another process completes the same rename after we've looked
423 * up the source and have blocked looking up the target, then the
424 * source and target inodes may be identical now although the
425 * names were never linked.
428 if (fvp->v_type == VDIR) {
430 * Linked directories are impossible, so we must
431 * have lost the race. Pretend that the rename
432 * completed before the lookup.
434 #ifdef UFS_RENAME_DEBUG
435 printf("ufs_rename: fvp == tvp for directories\n");
441 /* Release destination completely. */
446 * Delete source. There is another race now that everything
447 * is unlocked, but this doesn't cause any new complications.
448 * Relookup() may find a file that is unrelated to the
449 * original one, or it may fail. Too bad.
453 fcnp->cn_flags &= ~MODMASK;
454 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
455 fcnp->cn_nameiop = DELETE;
457 error = relookup(fdvp, &fvp, fcnp);
461 #ifdef UFS_RENAME_DEBUG
462 printf("ufs_rename: from name disappeared\n");
466 error = VOP_REMOVE(fdvp, fvp, fcnp);
475 if ((error = vn_lock(fvp, LK_EXCLUSIVE, p)) != 0)
479 if (ip->i_nlink >= LINK_MAX) {
480 VOP_UNLOCK(fvp, 0, p);
484 if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))
485 || (dp->i_flags & APPEND)) {
486 VOP_UNLOCK(fvp, 0, p);
490 if ((ip->i_mode & IFMT) == IFDIR) {
492 * Avoid ".", "..", and aliases of "." for obvious reasons.
494 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
495 dp == ip || (fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT ||
496 (ip->i_flag & IN_RENAME)) {
497 VOP_UNLOCK(fvp, 0, p);
501 ip->i_flag |= IN_RENAME;
502 oldparent = dp->i_number;
508 * When the target exists, both the directory
509 * and target vnodes are returned locked.
517 * 1) Bump link count while we're moving stuff
518 * around. If we crash somewhere before
519 * completing our work, the link count
520 * may be wrong, but correctable.
523 ip->i_flag |= IN_CHANGE;
524 if ((error = UFS_UPDATE(fvp, 1)) != 0) {
525 VOP_UNLOCK(fvp, 0, p);
530 * If ".." must be changed (ie the directory gets a new
531 * parent) then the source directory must not be in the
532 * directory heirarchy above the target, as this would
533 * orphan everything below the source directory. Also
534 * the user must have write permission in the source so
535 * as to be able to change "..". We must repeat the call
536 * to namei, as the parent directory is unlocked by the
537 * call to checkpath().
539 error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
540 VOP_UNLOCK(fvp, 0, p);
541 if (oldparent != dp->i_number)
542 newparent = dp->i_number;
543 if (doingdirectory && newparent) {
544 if (error) /* write access check above */
548 error = ext2_checkpath(ip, dp, tcnp->cn_cred);
552 error = relookup(tdvp, &tvp, tcnp);
562 * 2) If target doesn't exist, link the target
563 * to the source and unlink the source.
564 * Otherwise, rewrite the target directory
565 * entry to reference the source inode and
566 * expunge the original entry's existence.
569 if (dp->i_dev != ip->i_dev)
570 panic("ufs_rename: EXDEV");
572 * Account for ".." in new directory.
573 * When source and destination have the same
574 * parent we don't fool with the link count.
576 if (doingdirectory && newparent) {
577 if ((nlink_t)dp->i_nlink >= LINK_MAX) {
582 dp->i_flag |= IN_CHANGE;
583 error = UFS_UPDATE(tdvp, 1);
587 error = ext2_direnter(ip, tdvp, tcnp);
589 if (doingdirectory && newparent) {
591 dp->i_flag |= IN_CHANGE;
592 (void)UFS_UPDATE(tdvp, 1);
598 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
599 panic("ufs_rename: EXDEV");
601 * Short circuit rename(foo, foo).
603 if (xp->i_number == ip->i_number)
604 panic("ufs_rename: same file");
606 * If the parent directory is "sticky", then the user must
607 * own the parent directory, or the destination of the rename,
608 * otherwise the destination may not be changed (except by
609 * root). This implements append-only directories.
611 if ((dp->i_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 &&
612 tcnp->cn_cred->cr_uid != dp->i_uid &&
613 xp->i_uid != tcnp->cn_cred->cr_uid) {
618 * Target must be empty if a directory and have no links
619 * to it. Also, ensure source and target are compatible
620 * (both directories, or both not directories).
622 if ((xp->i_mode&IFMT) == IFDIR) {
623 if (! ext2_dirempty(xp, dp->i_number, tcnp->cn_cred) ||
628 if (!doingdirectory) {
633 } else if (doingdirectory) {
637 error = ext2_dirrewrite(dp, ip, tcnp);
641 * If the target directory is in the same
642 * directory as the source directory,
643 * decrement the link count on the parent
644 * of the target directory.
646 if (doingdirectory && !newparent) {
648 dp->i_flag |= IN_CHANGE;
652 * Adjust the link count of the target to
653 * reflect the dirrewrite above. If this is
654 * a directory it is empty and there are
655 * no links to it, so we can squash the inode and
656 * any space associated with it. We disallowed
657 * renaming over top of a directory with links to
658 * it above, as the remaining link would point to
659 * a directory without "." or ".." entries.
662 if (doingdirectory) {
663 if (--xp->i_nlink != 0)
664 panic("ufs_rename: linked directory");
665 error = UFS_TRUNCATE(tvp, (off_t)0, IO_SYNC,
666 tcnp->cn_cred, tcnp->cn_proc);
668 xp->i_flag |= IN_CHANGE;
674 * 3) Unlink the source.
676 fcnp->cn_flags &= ~MODMASK;
677 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
679 error = relookup(fdvp, &fvp, fcnp);
687 * From name has disappeared.
690 panic("ufs_rename: lost dir entry");
695 * Ensure that the directory entry still exists and has not
696 * changed while the new name has been entered. If the source is
697 * a file then the entry may have been unlinked or renamed. In
698 * either case there is no further work to be done. If the source
699 * is a directory then it cannot have been rmdir'ed; its link
700 * count of three would cause a rmdir to fail with ENOTEMPTY.
701 * The IN_RENAME flag ensures that it cannot be moved by another
706 panic("ufs_rename: lost dir entry");
709 * If the source is a directory with a
710 * new parent, the link count of the old
711 * parent directory must be decremented
712 * and ".." set to point to the new parent.
714 if (doingdirectory && newparent) {
716 dp->i_flag |= IN_CHANGE;
717 error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf,
718 sizeof (struct dirtemplate), (off_t)0,
719 UIO_SYSSPACE, IO_NODELOCKED,
720 tcnp->cn_cred, (int *)0, (struct proc *)0);
722 namlen = ((struct odirtemplate *)
723 &dirbuf)->dotdot_namlen;
725 dirbuf.dotdot_name[0] != '.' ||
726 dirbuf.dotdot_name[1] != '.') {
727 ufs_dirbad(xp, (doff_t)12,
728 "rename: mangled dir");
730 dirbuf.dotdot_ino = newparent;
731 (void) vn_rdwr(UIO_WRITE, fvp,
733 sizeof (struct dirtemplate),
734 (off_t)0, UIO_SYSSPACE,
735 IO_NODELOCKED|IO_SYNC,
736 tcnp->cn_cred, (int *)0,
742 error = ext2_dirremove(fdvp, fcnp);
745 xp->i_flag |= IN_CHANGE;
747 xp->i_flag &= ~IN_RENAME;
762 ip->i_flag &= ~IN_RENAME;
763 if (vn_lock(fvp, LK_EXCLUSIVE, p) == 0) {
765 ip->i_flag |= IN_CHANGE;
766 ip->i_flag &= ~IN_RENAME;
774 * A virgin directory (no blushing please).
776 static struct odirtemplate omastertemplate = {
777 0, 12, 1, { '.', 0 },
778 0, DIRBLKSIZ - 12, 2, { '.', '.', 0 }
786 struct vop_mkdir_args /* {
788 struct vnode **a_vpp;
789 struct componentname *a_cnp;
793 register struct vnode *dvp = ap->a_dvp;
794 register struct vattr *vap = ap->a_vap;
795 register struct componentname *cnp = ap->a_cnp;
796 register struct inode *ip, *dp;
798 struct dirtemplate dirtemplate, *dtp;
802 if ((cnp->cn_flags & HASBUF) == 0)
803 panic("ufs_mkdir: no name");
806 if ((nlink_t)dp->i_nlink >= LINK_MAX) {
810 dmode = vap->va_mode & 0777;
813 * Must simulate part of ext2_makeinode here to acquire the inode,
814 * but not have it entered in the parent directory. The entry is
815 * made later after writing "." and ".." entries.
817 error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, &tvp);
821 ip->i_gid = dp->i_gid;
825 struct ucred ucred, *ucp;
829 * if we are hacking owners here, (only do this where told to)
830 * and we are not giving it TOO root, (would subvert quotas)
831 * then go ahead and give it to the other user.
832 * The new directory also inherits the SUID bit.
833 * If user's UID and dir UID are the same,
834 * 'give it away' so that the SUID is still forced on.
836 if ( (dvp->v_mount->mnt_flag & MNT_SUIDDIR) &&
837 (dp->i_mode & ISUID) && dp->i_uid) {
839 ip->i_uid = dp->i_uid;
841 if (dp->i_uid != cnp->cn_cred->cr_uid) {
843 * make sure the correct user gets charged
845 * Make a dummy credential for the victim.
846 * XXX This seems to never be accessed out of
847 * our context so a stack variable is ok.
850 ucred.cr_uid = ip->i_uid;
851 ucred.cr_ngroups = 1;
852 ucred.cr_groups[0] = dp->i_gid;
857 ip->i_uid = cnp->cn_cred->cr_uid;
860 if ((error = getinoquota(ip)) ||
861 (error = chkiq(ip, 1, ucp, 0))) {
862 UFS_VFREE(tvp, ip->i_number, dmode);
869 ip->i_uid = cnp->cn_cred->cr_uid;
871 if ((error = getinoquota(ip)) ||
872 (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
873 UFS_VFREE(tvp, ip->i_number, dmode);
879 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
881 tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */
883 if (cnp->cn_flags & ISWHITEOUT)
884 ip->i_flags |= UF_OPAQUE;
885 error = UFS_UPDATE(tvp, 1);
888 * Bump link count in parent directory
889 * to reflect work done below. Should
890 * be done before reference is created
891 * so reparation is possible if we crash.
894 dp->i_flag |= IN_CHANGE;
895 error = UFS_UPDATE(dvp, 1);
899 /* Initialize directory with "." and ".." from static template. */
900 dtp = (struct dirtemplate *)&omastertemplate;
902 dirtemplate.dot_ino = ip->i_number;
903 dirtemplate.dotdot_ino = dp->i_number;
904 /* note that in ext2 DIRBLKSIZ == blocksize, not DEV_BSIZE
905 * so let's just redefine it - for this function only
908 #define DIRBLKSIZ VTOI(dvp)->i_e2fs->s_blocksize
909 dirtemplate.dotdot_reclen = DIRBLKSIZ - 12;
910 error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate,
911 sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
912 IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (int *)0, (struct proc *)0);
915 dp->i_flag |= IN_CHANGE;
918 if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
919 panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */
921 ip->i_size = DIRBLKSIZ;
922 ip->i_flag |= IN_CHANGE;
925 /* Directory set up, now install its entry in the parent directory. */
926 error = ext2_direnter(ip, dvp, cnp);
929 dp->i_flag |= IN_CHANGE;
933 * No need to do an explicit VOP_TRUNCATE here, vrele will do this
934 * for us because we set the link count to 0.
938 ip->i_flag |= IN_CHANGE;
945 #define DIRBLKSIZ DEV_BSIZE
953 struct vop_rmdir_args /* {
956 struct componentname *a_cnp;
959 struct vnode *vp = ap->a_vp;
960 struct vnode *dvp = ap->a_dvp;
961 struct componentname *cnp = ap->a_cnp;
962 struct proc *p = cnp->cn_proc;
963 struct inode *ip, *dp;
970 * Verify the directory is empty (and valid).
971 * (Rmdir ".." won't be valid since
972 * ".." will contain a reference to
973 * the current directory and thus be
977 if (ip->i_nlink != 2 || !ext2_dirempty(ip, dp->i_number, cnp->cn_cred)) {
981 if ((dp->i_flags & APPEND)
982 || (ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))) {
987 * Delete reference to directory before purging
988 * inode. If we crash in between, the directory
989 * will be reattached to lost+found,
991 error = ext2_dirremove(dvp, cnp);
995 dp->i_flag |= IN_CHANGE;
997 VOP_UNLOCK(dvp, 0, p);
999 * Truncate inode. The only stuff left
1000 * in the directory is "." and "..". The
1001 * "." reference is inconsequential since
1002 * we're quashing it. The ".." reference
1003 * has already been adjusted above. We've
1004 * removed the "." reference and the reference
1005 * in the parent directory, but there may be
1006 * other hard links so decrement by 2 and
1007 * worry about them later.
1010 error = UFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred, p);
1011 cache_purge(ITOV(ip));
1012 vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
1018 * symlink -- make a symbolic link
1022 struct vop_symlink_args /* {
1023 struct vnode *a_dvp;
1024 struct vnode **a_vpp;
1025 struct componentname *a_cnp;
1026 struct vattr *a_vap;
1030 register struct vnode *vp, **vpp = ap->a_vpp;
1031 register struct inode *ip;
1034 error = ext2_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
1039 len = strlen(ap->a_target);
1040 if (len < vp->v_mount->mnt_maxsymlinklen) {
1042 bcopy(ap->a_target, (char *)ip->i_shortlink, len);
1044 ip->i_flag |= IN_CHANGE | IN_UPDATE;
1046 error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
1047 UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0,
1055 * Allocate a new inode.
1058 ext2_makeinode(mode, dvp, vpp, cnp)
1062 struct componentname *cnp;
1064 register struct inode *ip, *pdir;
1070 if ((cnp->cn_flags & HASBUF) == 0)
1071 panic("ext2_makeinode: no name");
1074 if ((mode & IFMT) == 0)
1077 error = UFS_VALLOC(dvp, mode, cnp->cn_cred, &tvp);
1082 ip->i_gid = pdir->i_gid;
1086 struct ucred ucred, *ucp;
1091 * not the owner of the directory,
1092 * and we are hacking owners here, (only do this where told to)
1093 * and we are not giving it TOO root, (would subvert quotas)
1094 * then go ahead and give it to the other user.
1095 * Note that this drops off the execute bits for security.
1097 if ( (dvp->v_mount->mnt_flag & MNT_SUIDDIR) &&
1098 (pdir->i_mode & ISUID) &&
1099 (pdir->i_uid != cnp->cn_cred->cr_uid) && pdir->i_uid) {
1100 ip->i_uid = pdir->i_uid;
1104 * make sure the correct user gets charged
1106 * Quickly knock up a dummy credential for the victim.
1107 * XXX This seems to never be accessed out of our
1108 * context so a stack variable is ok.
1111 ucred.cr_uid = ip->i_uid;
1112 ucred.cr_ngroups = 1;
1113 ucred.cr_groups[0] = pdir->i_gid;
1117 ip->i_uid = cnp->cn_cred->cr_uid;
1121 if ((error = getinoquota(ip)) ||
1122 (error = chkiq(ip, 1, ucp, 0))) {
1123 UFS_VFREE(tvp, ip->i_number, mode);
1130 ip->i_uid = cnp->cn_cred->cr_uid;
1132 if ((error = getinoquota(ip)) ||
1133 (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
1134 UFS_VFREE(tvp, ip->i_number, mode);
1140 ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1142 tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */
1144 if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) &&
1145 suser_xxx(cnp->cn_cred, 0, PRISON_ROOT))
1146 ip->i_mode &= ~ISGID;
1148 if (cnp->cn_flags & ISWHITEOUT)
1149 ip->i_flags |= UF_OPAQUE;
1152 * Make sure inode goes to disk before directory entry.
1154 error = UFS_UPDATE(tvp, 1);
1157 error = ext2_direnter(ip, dvp, cnp);
1166 * Write error occurred trying to update the inode
1167 * or the directory so must deallocate the inode.
1170 ip->i_flag |= IN_CHANGE;
1178 * XXX By default, wimp out... note that a_offset is ignored (and always
1183 struct vop_getpages_args *ap;
1185 return (vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count,
1192 * XXX By default, wimp out... note that a_offset is ignored (and always
1197 struct vop_putpages_args *ap;
1199 return (vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count,
1200 ap->a_sync, ap->a_rtvals));