Annotation of src/sys/ufs/ufs/ufs_vnops.c, Revision 1.156.4.1
1.156.4.1! yamt 1: /* $NetBSD: ufs_vnops.c,v 1.156 2007/08/09 09:22:34 hannken Exp $ */
1.3 cgd 2:
1.1 mycroft 3: /*
1.35 fvdl 4: * Copyright (c) 1982, 1986, 1989, 1993, 1995
1.1 mycroft 5: * The Regents of the University of California. All rights reserved.
6: * (c) UNIX System Laboratories, Inc.
7: * All or some portions of this file are derived from material licensed
8: * to the University of California by American Telephone and Telegraph
9: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10: * the permission of UNIX System Laboratories, Inc.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
1.104 agc 20: * 3. Neither the name of the University nor the names of its contributors
1.1 mycroft 21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: *
1.35 fvdl 36: * @(#)ufs_vnops.c 8.28 (Berkeley) 7/31/95
1.1 mycroft 37: */
1.83 lukem 38:
39: #include <sys/cdefs.h>
1.156.4.1! yamt 40: __KERNEL_RCSID(0, "$NetBSD: ufs_vnops.c,v 1.156 2007/08/09 09:22:34 hannken Exp $");
1.33 mrg 41:
1.125 dbj 42: #if defined(_KERNEL_OPT)
1.128 thorpej 43: #include "opt_ffs.h"
1.40 scottr 44: #include "opt_quota.h"
1.69 perseant 45: #include "fs_lfs.h"
1.125 dbj 46: #endif
1.1 mycroft 47:
48: #include <sys/param.h>
49: #include <sys/systm.h>
50: #include <sys/namei.h>
51: #include <sys/resourcevar.h>
52: #include <sys/kernel.h>
53: #include <sys/file.h>
54: #include <sys/stat.h>
55: #include <sys/buf.h>
56: #include <sys/proc.h>
57: #include <sys/mount.h>
58: #include <sys/vnode.h>
59: #include <sys/malloc.h>
60: #include <sys/dirent.h>
61: #include <sys/lockf.h>
1.140 elad 62: #include <sys/kauth.h>
1.148 hannken 63: #include <sys/fstrans.h>
1.32 mrg 64:
1.1 mycroft 65: #include <miscfs/specfs/specdev.h>
1.15 christos 66: #include <miscfs/fifofs/fifo.h>
1.1 mycroft 67:
68: #include <ufs/ufs/inode.h>
69: #include <ufs/ufs/dir.h>
70: #include <ufs/ufs/ufsmount.h>
1.38 bouyer 71: #include <ufs/ufs/ufs_bswap.h>
1.1 mycroft 72: #include <ufs/ufs/ufs_extern.h>
1.124 rumble 73: #ifdef UFS_DIRHASH
74: #include <ufs/ufs/dirhash.h>
75: #endif
1.26 bouyer 76: #include <ufs/ext2fs/ext2fs_extern.h>
1.133 christos 77: #include <ufs/ffs/ffs_extern.h>
1.69 perseant 78: #include <ufs/lfs/lfs_extern.h>
1.1 mycroft 79:
1.90 perseant 80: #include <uvm/uvm.h>
81:
1.142 ad 82: static int ufs_chmod(struct vnode *, int, kauth_cred_t, struct lwp *);
1.140 elad 83: static int ufs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t,
1.142 ad 84: struct lwp *);
1.1 mycroft 85:
86: /*
1.59 fvdl 87: * A virgin directory (no blushing please).
88: */
1.98 yamt 89: static const struct dirtemplate mastertemplate = {
1.76 lukem 90: 0, 12, DT_DIR, 1, ".",
91: 0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
1.59 fvdl 92: };
93:
94: /*
1.1 mycroft 95: * Create a regular file
96: */
97: int
1.76 lukem 98: ufs_create(void *v)
1.15 christos 99: {
1.1 mycroft 100: struct vop_create_args /* {
1.76 lukem 101: struct vnode *a_dvp;
102: struct vnode **a_vpp;
103: struct componentname *a_cnp;
104: struct vattr *a_vap;
1.15 christos 105: } */ *ap = v;
1.88 jdolecek 106: int error;
1.76 lukem 107:
1.153 hannken 108: fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED);
1.88 jdolecek 109: error =
1.1 mycroft 110: ufs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
1.15 christos 111: ap->a_dvp, ap->a_vpp, ap->a_cnp);
1.148 hannken 112: fstrans_done(ap->a_dvp->v_mount);
1.88 jdolecek 113: if (error)
114: return (error);
115: VN_KNOTE(ap->a_dvp, NOTE_WRITE);
116: return (0);
1.1 mycroft 117: }
118:
119: /*
120: * Mknod vnode call
121: */
122: /* ARGSUSED */
123: int
1.76 lukem 124: ufs_mknod(void *v)
1.15 christos 125: {
1.1 mycroft 126: struct vop_mknod_args /* {
1.76 lukem 127: struct vnode *a_dvp;
128: struct vnode **a_vpp;
129: struct componentname *a_cnp;
130: struct vattr *a_vap;
131: } */ *ap = v;
132: struct vattr *vap;
133: struct vnode **vpp;
134: struct inode *ip;
135: int error;
1.126 perry 136: struct mount *mp;
1.79 assar 137: ino_t ino;
1.1 mycroft 138:
1.76 lukem 139: vap = ap->a_vap;
140: vpp = ap->a_vpp;
1.153 hannken 141: fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED);
1.15 christos 142: if ((error =
1.1 mycroft 143: ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
1.15 christos 144: ap->a_dvp, vpp, ap->a_cnp)) != 0)
1.148 hannken 145: goto out;
1.88 jdolecek 146: VN_KNOTE(ap->a_dvp, NOTE_WRITE);
1.1 mycroft 147: ip = VTOI(*vpp);
1.79 assar 148: mp = (*vpp)->v_mount;
149: ino = ip->i_number;
1.1 mycroft 150: ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
151: if (vap->va_rdev != VNOVAL) {
1.120 mycroft 152: struct ufsmount *ump = ip->i_ump;
1.1 mycroft 153: /*
154: * Want to be able to use this to make badblock
155: * inodes, so don't truncate the dev number.
156: */
1.120 mycroft 157: if (ump->um_fstype == UFS1)
1.92 fvdl 158: ip->i_ffs1_rdev = ufs_rw32(vap->va_rdev,
1.120 mycroft 159: UFS_MPNEEDSWAP(ump));
1.92 fvdl 160: else
161: ip->i_ffs2_rdev = ufs_rw64(vap->va_rdev,
1.120 mycroft 162: UFS_MPNEEDSWAP(ump));
1.1 mycroft 163: }
164: /*
165: * Remove inode so that it will be reloaded by VFS_VGET and
166: * checked to see if it is an alias of an existing entry in
167: * the inode cache.
168: */
169: vput(*vpp);
170: (*vpp)->v_type = VNON;
171: vgone(*vpp);
1.101 thorpej 172: error = VFS_VGET(mp, ino, vpp);
1.148 hannken 173: out:
174: fstrans_done(ap->a_dvp->v_mount);
1.79 assar 175: if (error != 0) {
176: *vpp = NULL;
177: return (error);
178: }
1.1 mycroft 179: return (0);
180: }
181:
182: /*
183: * Open called.
184: *
185: * Nothing to do.
186: */
187: /* ARGSUSED */
188: int
1.76 lukem 189: ufs_open(void *v)
1.15 christos 190: {
1.1 mycroft 191: struct vop_open_args /* {
1.76 lukem 192: struct vnode *a_vp;
193: int a_mode;
1.140 elad 194: kauth_cred_t a_cred;
1.138 christos 195: struct lwp *a_l;
1.15 christos 196: } */ *ap = v;
1.1 mycroft 197:
198: /*
199: * Files marked append-only must be opened for appending.
200: */
1.92 fvdl 201: if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
1.1 mycroft 202: (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
203: return (EPERM);
204: return (0);
205: }
206:
207: /*
208: * Close called.
209: *
210: * Update the times on the inode.
211: */
212: /* ARGSUSED */
213: int
1.76 lukem 214: ufs_close(void *v)
1.15 christos 215: {
1.1 mycroft 216: struct vop_close_args /* {
1.76 lukem 217: struct vnode *a_vp;
218: int a_fflag;
1.140 elad 219: kauth_cred_t a_cred;
1.138 christos 220: struct lwp *a_l;
1.76 lukem 221: } */ *ap = v;
222: struct vnode *vp;
223: struct inode *ip;
1.1 mycroft 224:
1.76 lukem 225: vp = ap->a_vp;
226: ip = VTOI(vp);
1.35 fvdl 227: simple_lock(&vp->v_interlock);
1.133 christos 228: if (vp->v_usecount > 1)
1.135 yamt 229: UFS_ITIMES(vp, NULL, NULL, NULL);
1.35 fvdl 230: simple_unlock(&vp->v_interlock);
1.1 mycroft 231: return (0);
232: }
233:
234: int
1.76 lukem 235: ufs_access(void *v)
1.15 christos 236: {
1.1 mycroft 237: struct vop_access_args /* {
1.76 lukem 238: struct vnode *a_vp;
239: int a_mode;
1.140 elad 240: kauth_cred_t a_cred;
1.138 christos 241: struct lwp *a_l;
1.76 lukem 242: } */ *ap = v;
243: struct vnode *vp;
1.126 perry 244: struct inode *ip;
1.76 lukem 245: mode_t mode;
1.35 fvdl 246: #ifdef QUOTA
1.76 lukem 247: int error;
1.35 fvdl 248: #endif
1.1 mycroft 249:
1.76 lukem 250: vp = ap->a_vp;
251: ip = VTOI(vp);
252: mode = ap->a_mode;
1.35 fvdl 253: /*
254: * Disallow write attempts on read-only file systems;
255: * unless the file is a socket, fifo, or a block or
256: * character device resident on the file system.
257: */
258: if (mode & VWRITE) {
1.1 mycroft 259: switch (vp->v_type) {
260: case VDIR:
261: case VLNK:
262: case VREG:
1.35 fvdl 263: if (vp->v_mount->mnt_flag & MNT_RDONLY)
264: return (EROFS);
265: #ifdef QUOTA
1.153 hannken 266: fstrans_start(vp->v_mount, FSTRANS_SHARED);
1.148 hannken 267: error = getinoquota(ip);
268: fstrans_done(vp->v_mount);
269: if (error != 0)
270: return error;
1.35 fvdl 271: #endif
1.1 mycroft 272: break;
1.15 christos 273: case VBAD:
274: case VBLK:
275: case VCHR:
276: case VSOCK:
277: case VFIFO:
278: case VNON:
1.35 fvdl 279: default:
1.15 christos 280: break;
1.1 mycroft 281: }
1.35 fvdl 282: }
1.1 mycroft 283:
284: /* If immutable bit set, nobody gets to write it. */
1.115 hannken 285: if ((mode & VWRITE) && (ip->i_flags & (IMMUTABLE | SF_SNAPSHOT)))
1.1 mycroft 286: return (EPERM);
287:
1.92 fvdl 288: return (vaccess(vp->v_type, ip->i_mode & ALLPERMS,
289: ip->i_uid, ip->i_gid, mode, ap->a_cred));
1.1 mycroft 290: }
291:
292: /* ARGSUSED */
293: int
1.76 lukem 294: ufs_getattr(void *v)
1.15 christos 295: {
1.1 mycroft 296: struct vop_getattr_args /* {
1.76 lukem 297: struct vnode *a_vp;
298: struct vattr *a_vap;
1.140 elad 299: kauth_cred_t a_cred;
1.138 christos 300: struct lwp *a_l;
1.76 lukem 301: } */ *ap = v;
302: struct vnode *vp;
303: struct inode *ip;
304: struct vattr *vap;
1.1 mycroft 305:
1.76 lukem 306: vp = ap->a_vp;
307: ip = VTOI(vp);
308: vap = ap->a_vap;
1.135 yamt 309: UFS_ITIMES(vp, NULL, NULL, NULL);
1.92 fvdl 310:
1.1 mycroft 311: /*
312: * Copy from inode table
313: */
314: vap->va_fsid = ip->i_dev;
315: vap->va_fileid = ip->i_number;
1.92 fvdl 316: vap->va_mode = ip->i_mode & ALLPERMS;
1.59 fvdl 317: vap->va_nlink = ip->i_ffs_effnlink;
1.92 fvdl 318: vap->va_uid = ip->i_uid;
319: vap->va_gid = ip->i_gid;
1.81 chs 320: vap->va_size = vp->v_size;
1.92 fvdl 321: if (ip->i_ump->um_fstype == UFS1) {
322: vap->va_rdev = (dev_t)ufs_rw32(ip->i_ffs1_rdev,
1.121 mycroft 323: UFS_MPNEEDSWAP(ip->i_ump));
1.92 fvdl 324: vap->va_atime.tv_sec = ip->i_ffs1_atime;
325: vap->va_atime.tv_nsec = ip->i_ffs1_atimensec;
326: vap->va_mtime.tv_sec = ip->i_ffs1_mtime;
327: vap->va_mtime.tv_nsec = ip->i_ffs1_mtimensec;
328: vap->va_ctime.tv_sec = ip->i_ffs1_ctime;
329: vap->va_ctime.tv_nsec = ip->i_ffs1_ctimensec;
330: vap->va_birthtime.tv_sec = 0;
331: vap->va_birthtime.tv_nsec = 0;
332: vap->va_bytes = dbtob((u_quad_t)ip->i_ffs1_blocks);
333: } else {
334: vap->va_rdev = (dev_t)ufs_rw64(ip->i_ffs2_rdev,
1.121 mycroft 335: UFS_MPNEEDSWAP(ip->i_ump));
1.92 fvdl 336: vap->va_atime.tv_sec = ip->i_ffs2_atime;
337: vap->va_atime.tv_nsec = ip->i_ffs2_atimensec;
338: vap->va_mtime.tv_sec = ip->i_ffs2_mtime;
339: vap->va_mtime.tv_nsec = ip->i_ffs2_mtimensec;
340: vap->va_ctime.tv_sec = ip->i_ffs2_ctime;
341: vap->va_ctime.tv_nsec = ip->i_ffs2_ctimensec;
342: vap->va_birthtime.tv_sec = ip->i_ffs2_birthtime;
343: vap->va_birthtime.tv_nsec = ip->i_ffs2_birthnsec;
344: vap->va_bytes = dbtob(ip->i_ffs2_blocks);
345: }
346: vap->va_gen = ip->i_gen;
347: vap->va_flags = ip->i_flags;
348:
1.1 mycroft 349: /* this doesn't belong here */
350: if (vp->v_type == VBLK)
351: vap->va_blocksize = BLKDEV_IOSIZE;
352: else if (vp->v_type == VCHR)
353: vap->va_blocksize = MAXBSIZE;
354: else
355: vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
356: vap->va_type = vp->v_type;
357: vap->va_filerev = ip->i_modrev;
358: return (0);
359: }
360:
361: /*
362: * Set attribute vnode op. called from several syscalls
363: */
364: int
1.76 lukem 365: ufs_setattr(void *v)
1.15 christos 366: {
1.1 mycroft 367: struct vop_setattr_args /* {
1.76 lukem 368: struct vnode *a_vp;
369: struct vattr *a_vap;
1.140 elad 370: kauth_cred_t a_cred;
1.138 christos 371: struct lwp *a_l;
1.76 lukem 372: } */ *ap = v;
373: struct vattr *vap;
374: struct vnode *vp;
375: struct inode *ip;
1.140 elad 376: kauth_cred_t cred;
1.138 christos 377: struct lwp *l;
1.76 lukem 378: int error;
379:
380: vap = ap->a_vap;
381: vp = ap->a_vp;
382: ip = VTOI(vp);
383: cred = ap->a_cred;
1.138 christos 384: l = ap->a_l;
1.1 mycroft 385:
386: /*
387: * Check for unsettable attributes.
388: */
389: if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
390: (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
391: (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
392: ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
393: return (EINVAL);
394: }
1.148 hannken 395:
1.153 hannken 396: fstrans_start(vp->v_mount, FSTRANS_SHARED);
1.148 hannken 397:
1.1 mycroft 398: if (vap->va_flags != VNOVAL) {
1.148 hannken 399: if (vp->v_mount->mnt_flag & MNT_RDONLY) {
400: error = EROFS;
401: goto out;
402: }
1.140 elad 403: if (kauth_cred_geteuid(cred) != ip->i_uid &&
404: (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
1.147 elad 405: NULL)))
1.148 hannken 406: goto out;
1.147 elad 407: if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
408: NULL) == 0) {
1.92 fvdl 409: if ((ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) &&
1.146 elad 410: kauth_authorize_system(l->l_cred,
1.148 hannken 411: KAUTH_SYSTEM_CHSYSFLAGS, 0, NULL, NULL, NULL)) {
412: error = EPERM;
413: goto out;
414: }
1.115 hannken 415: /* Snapshot flag cannot be set or cleared */
1.126 perry 416: if ((vap->va_flags & SF_SNAPSHOT) !=
1.148 hannken 417: (ip->i_flags & SF_SNAPSHOT)) {
418: error = EPERM;
419: goto out;
420: }
1.92 fvdl 421: ip->i_flags = vap->va_flags;
1.99 kristerw 422: DIP_ASSIGN(ip, flags, ip->i_flags);
1.1 mycroft 423: } else {
1.92 fvdl 424: if ((ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) ||
1.148 hannken 425: (vap->va_flags & UF_SETTABLE) != vap->va_flags) {
426: error = EPERM;
427: goto out;
428: }
1.92 fvdl 429: if ((ip->i_flags & SF_SETTABLE) !=
1.148 hannken 430: (vap->va_flags & SF_SETTABLE)) {
431: error = EPERM;
432: goto out;
433: }
1.92 fvdl 434: ip->i_flags &= SF_SETTABLE;
435: ip->i_flags |= (vap->va_flags & UF_SETTABLE);
1.99 kristerw 436: DIP_ASSIGN(ip, flags, ip->i_flags);
1.1 mycroft 437: }
438: ip->i_flag |= IN_CHANGE;
1.148 hannken 439: if (vap->va_flags & (IMMUTABLE | APPEND)) {
440: error = 0;
441: goto out;
442: }
443: }
444: if (ip->i_flags & (IMMUTABLE | APPEND)) {
445: error = EPERM;
446: goto out;
1.1 mycroft 447: }
448: /*
449: * Go through the fields and update iff not VNOVAL.
450: */
1.15 christos 451: if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
1.148 hannken 452: if (vp->v_mount->mnt_flag & MNT_RDONLY) {
453: error = EROFS;
454: goto out;
455: }
1.142 ad 456: error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
1.15 christos 457: if (error)
1.148 hannken 458: goto out;
1.15 christos 459: }
1.1 mycroft 460: if (vap->va_size != VNOVAL) {
1.35 fvdl 461: /*
462: * Disallow write attempts on read-only file systems;
463: * unless the file is a socket, fifo, or a block or
464: * character device resident on the file system.
465: */
466: switch (vp->v_type) {
467: case VDIR:
1.148 hannken 468: error = EISDIR;
469: goto out;
1.137 yamt 470: case VCHR:
471: case VBLK:
472: case VFIFO:
473: break;
1.35 fvdl 474: case VREG:
1.148 hannken 475: if (vp->v_mount->mnt_flag & MNT_RDONLY) {
476: error = EROFS;
477: goto out;
478: }
479: if ((ip->i_flags & SF_SNAPSHOT) != 0) {
480: error = EPERM;
481: goto out;
482: }
1.138 christos 483: error = UFS_TRUNCATE(vp, vap->va_size, 0, cred, l);
1.137 yamt 484: if (error)
1.148 hannken 485: goto out;
1.35 fvdl 486: break;
487: default:
1.148 hannken 488: error = EOPNOTSUPP;
489: goto out;
1.35 fvdl 490: }
1.1 mycroft 491: }
492: ip = VTOI(vp);
1.92 fvdl 493: if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
494: vap->va_birthtime.tv_sec != VNOVAL) {
1.148 hannken 495: if (vp->v_mount->mnt_flag & MNT_RDONLY) {
496: error = EROFS;
497: goto out;
498: }
499: if ((ip->i_flags & SF_SNAPSHOT) != 0) {
500: error = EPERM;
501: goto out;
502: }
1.140 elad 503: if (kauth_cred_geteuid(cred) != ip->i_uid &&
504: (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
1.147 elad 505: NULL)) &&
1.126 perry 506: ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
1.138 christos 507: (error = VOP_ACCESS(vp, VWRITE, cred, l))))
1.148 hannken 508: goto out;
1.12 jtc 509: if (vap->va_atime.tv_sec != VNOVAL)
1.22 tls 510: if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
511: ip->i_flag |= IN_ACCESS;
1.12 jtc 512: if (vap->va_mtime.tv_sec != VNOVAL)
1.1 mycroft 513: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1.92 fvdl 514: if (vap->va_birthtime.tv_sec != VNOVAL &&
515: ip->i_ump->um_fstype == UFS2) {
516: ip->i_ffs2_birthtime = vap->va_birthtime.tv_sec;
517: ip->i_ffs2_birthnsec = vap->va_birthtime.tv_nsec;
518: }
1.136 yamt 519: error = UFS_UPDATE(vp, &vap->va_atime, &vap->va_mtime, 0);
1.15 christos 520: if (error)
1.148 hannken 521: goto out;
1.1 mycroft 522: }
523: error = 0;
1.35 fvdl 524: if (vap->va_mode != (mode_t)VNOVAL) {
1.148 hannken 525: if (vp->v_mount->mnt_flag & MNT_RDONLY) {
526: error = EROFS;
527: goto out;
528: }
1.115 hannken 529: if ((ip->i_flags & SF_SNAPSHOT) != 0 &&
530: (vap->va_mode & (S_IXUSR | S_IWUSR | S_IXGRP | S_IWGRP |
1.148 hannken 531: S_IXOTH | S_IWOTH))) {
532: error = EPERM;
533: goto out;
534: }
1.142 ad 535: error = ufs_chmod(vp, (int)vap->va_mode, cred, l);
1.35 fvdl 536: }
1.88 jdolecek 537: VN_KNOTE(vp, NOTE_ATTRIB);
1.148 hannken 538: out:
539: fstrans_done(vp->v_mount);
1.1 mycroft 540: return (error);
541: }
542:
543: /*
544: * Change the mode on a file.
545: * Inode must be locked before calling.
546: */
547: static int
1.142 ad 548: ufs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l)
1.1 mycroft 549: {
1.76 lukem 550: struct inode *ip;
1.140 elad 551: int error, ismember = 0;
1.1 mycroft 552:
1.76 lukem 553: ip = VTOI(vp);
1.140 elad 554: if (kauth_cred_geteuid(cred) != ip->i_uid &&
1.147 elad 555: (error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL)))
1.1 mycroft 556: return (error);
1.147 elad 557: if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL)) {
1.1 mycroft 558: if (vp->v_type != VDIR && (mode & S_ISTXT))
559: return (EFTYPE);
1.140 elad 560: if ((kauth_cred_ismember_gid(cred, ip->i_gid, &ismember) != 0 ||
561: !ismember) && (mode & ISGID))
1.1 mycroft 562: return (EPERM);
563: }
1.92 fvdl 564: ip->i_mode &= ~ALLPERMS;
565: ip->i_mode |= (mode & ALLPERMS);
1.1 mycroft 566: ip->i_flag |= IN_CHANGE;
1.99 kristerw 567: DIP_ASSIGN(ip, mode, ip->i_mode);
1.1 mycroft 568: return (0);
569: }
570:
571: /*
572: * Perform chown operation on inode ip;
573: * inode must be locked prior to call.
574: */
575: static int
1.140 elad 576: ufs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
1.142 ad 577: struct lwp *l)
1.1 mycroft 578: {
1.76 lukem 579: struct inode *ip;
1.140 elad 580: int error, ismember = 0;
1.34 kleink 581: #ifdef QUOTA
1.76 lukem 582: uid_t ouid;
583: gid_t ogid;
1.92 fvdl 584: int64_t change;
1.1 mycroft 585: #endif
1.76 lukem 586: ip = VTOI(vp);
587: error = 0;
1.1 mycroft 588:
589: if (uid == (uid_t)VNOVAL)
1.92 fvdl 590: uid = ip->i_uid;
1.1 mycroft 591: if (gid == (gid_t)VNOVAL)
1.92 fvdl 592: gid = ip->i_gid;
1.37 kleink 593: /*
594: * If we don't own the file, are trying to change the owner
595: * of the file, or are not a member of the target group,
596: * the caller's credentials must imply super-user privilege
597: * or the call fails.
598: */
1.140 elad 599: if ((kauth_cred_geteuid(cred) != ip->i_uid || uid != ip->i_uid ||
1.114 kleink 600: (gid != ip->i_gid &&
1.142 ad 601: !(kauth_cred_getegid(cred) == gid ||
602: (kauth_cred_ismember_gid(cred, gid, &ismember) == 0 &&
603: ismember)))) &&
1.140 elad 604: ((error = kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
1.147 elad 605: NULL)) != 0))
1.37 kleink 606: return (error);
607:
1.34 kleink 608: #ifdef QUOTA
1.92 fvdl 609: ogid = ip->i_gid;
610: ouid = ip->i_uid;
611: change = DIP(ip, blocks);
1.154 hannken 612: (void) chkdq(ip, -change, cred, 0);
613: (void) chkiq(ip, -1, cred, 0);
1.1 mycroft 614: #endif
1.92 fvdl 615: ip->i_gid = gid;
1.99 kristerw 616: DIP_ASSIGN(ip, gid, gid);
1.92 fvdl 617: ip->i_uid = uid;
1.99 kristerw 618: DIP_ASSIGN(ip, uid, uid);
1.1 mycroft 619: #ifdef QUOTA
1.154 hannken 620: if ((error = chkdq(ip, change, cred, 0)) == 0) {
621: if ((error = chkiq(ip, 1, cred, 0)) == 0)
622: goto good;
623: else
624: (void) chkdq(ip, -change, cred, FORCE);
1.1 mycroft 625: }
1.92 fvdl 626: ip->i_gid = ogid;
1.99 kristerw 627: DIP_ASSIGN(ip, gid, ogid);
1.92 fvdl 628: ip->i_uid = ouid;
1.99 kristerw 629: DIP_ASSIGN(ip, uid, ouid);
1.154 hannken 630: (void) chkdq(ip, change, cred, FORCE);
631: (void) chkiq(ip, 1, cred, FORCE);
1.1 mycroft 632: return (error);
1.76 lukem 633: good:
1.1 mycroft 634: #endif /* QUOTA */
1.34 kleink 635: ip->i_flag |= IN_CHANGE;
1.1 mycroft 636: return (0);
637: }
638:
639: int
1.76 lukem 640: ufs_remove(void *v)
1.15 christos 641: {
1.1 mycroft 642: struct vop_remove_args /* {
1.76 lukem 643: struct vnode *a_dvp;
644: struct vnode *a_vp;
645: struct componentname *a_cnp;
646: } */ *ap = v;
647: struct vnode *vp, *dvp;
648: struct inode *ip;
649: int error;
1.1 mycroft 650:
1.76 lukem 651: vp = ap->a_vp;
652: dvp = ap->a_dvp;
1.1 mycroft 653: ip = VTOI(vp);
1.153 hannken 654: fstrans_start(dvp->v_mount, FSTRANS_SHARED);
1.92 fvdl 655: if (vp->v_type == VDIR || (ip->i_flags & (IMMUTABLE | APPEND)) ||
656: (VTOI(dvp)->i_flags & APPEND))
1.1 mycroft 657: error = EPERM;
1.59 fvdl 658: else
659: error = ufs_dirremove(dvp, ip, ap->a_cnp->cn_flags, 0);
1.88 jdolecek 660: VN_KNOTE(vp, NOTE_DELETE);
661: VN_KNOTE(dvp, NOTE_WRITE);
1.1 mycroft 662: if (dvp == vp)
663: vrele(vp);
664: else
665: vput(vp);
666: vput(dvp);
1.148 hannken 667: fstrans_done(dvp->v_mount);
1.1 mycroft 668: return (error);
669: }
670:
671: /*
672: * link vnode call
673: */
674: int
1.76 lukem 675: ufs_link(void *v)
1.15 christos 676: {
1.1 mycroft 677: struct vop_link_args /* {
1.14 mycroft 678: struct vnode *a_dvp;
1.1 mycroft 679: struct vnode *a_vp;
680: struct componentname *a_cnp;
1.15 christos 681: } */ *ap = v;
1.76 lukem 682: struct vnode *vp, *dvp;
683: struct componentname *cnp;
684: struct inode *ip;
1.116 hannken 685: struct direct *newdir;
1.76 lukem 686: int error;
687:
688: dvp = ap->a_dvp;
689: vp = ap->a_vp;
690: cnp = ap->a_cnp;
1.1 mycroft 691: #ifdef DIAGNOSTIC
692: if ((cnp->cn_flags & HASBUF) == 0)
693: panic("ufs_link: no name");
694: #endif
1.153 hannken 695: fstrans_start(dvp->v_mount, FSTRANS_SHARED);
1.14 mycroft 696: if (vp->v_type == VDIR) {
697: VOP_ABORTOP(dvp, cnp);
1.23 mikel 698: error = EPERM;
1.14 mycroft 699: goto out2;
700: }
701: if (dvp->v_mount != vp->v_mount) {
702: VOP_ABORTOP(dvp, cnp);
1.1 mycroft 703: error = EXDEV;
704: goto out2;
705: }
1.35 fvdl 706: if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE))) {
1.14 mycroft 707: VOP_ABORTOP(dvp, cnp);
1.1 mycroft 708: goto out2;
709: }
1.14 mycroft 710: ip = VTOI(vp);
1.92 fvdl 711: if ((nlink_t)ip->i_nlink >= LINK_MAX) {
1.14 mycroft 712: VOP_ABORTOP(dvp, cnp);
1.1 mycroft 713: error = EMLINK;
714: goto out1;
715: }
1.92 fvdl 716: if (ip->i_flags & (IMMUTABLE | APPEND)) {
1.14 mycroft 717: VOP_ABORTOP(dvp, cnp);
1.1 mycroft 718: error = EPERM;
719: goto out1;
720: }
1.59 fvdl 721: ip->i_ffs_effnlink++;
1.92 fvdl 722: ip->i_nlink++;
1.99 kristerw 723: DIP_ASSIGN(ip, nlink, ip->i_nlink);
1.1 mycroft 724: ip->i_flag |= IN_CHANGE;
1.59 fvdl 725: if (DOINGSOFTDEP(vp))
1.62 fvdl 726: softdep_change_linkcnt(ip);
1.136 yamt 727: error = UFS_UPDATE(vp, NULL, NULL, UPDATE_DIROP);
1.59 fvdl 728: if (!error) {
1.116 hannken 729: newdir = pool_get(&ufs_direct_pool, PR_WAITOK);
730: ufs_makedirentry(ip, cnp, newdir);
731: error = ufs_direnter(dvp, vp, newdir, cnp, NULL);
732: pool_put(&ufs_direct_pool, newdir);
1.59 fvdl 733: }
1.1 mycroft 734: if (error) {
1.59 fvdl 735: ip->i_ffs_effnlink--;
1.92 fvdl 736: ip->i_nlink--;
1.99 kristerw 737: DIP_ASSIGN(ip, nlink, ip->i_nlink);
1.1 mycroft 738: ip->i_flag |= IN_CHANGE;
1.62 fvdl 739: if (DOINGSOFTDEP(vp))
740: softdep_change_linkcnt(ip);
1.1 mycroft 741: }
1.73 thorpej 742: PNBUF_PUT(cnp->cn_pnbuf);
1.76 lukem 743: out1:
1.14 mycroft 744: if (dvp != vp)
1.35 fvdl 745: VOP_UNLOCK(vp, 0);
1.76 lukem 746: out2:
1.88 jdolecek 747: VN_KNOTE(vp, NOTE_LINK);
748: VN_KNOTE(dvp, NOTE_WRITE);
1.14 mycroft 749: vput(dvp);
1.148 hannken 750: fstrans_done(dvp->v_mount);
1.1 mycroft 751: return (error);
752: }
753:
754: /*
1.6 mycroft 755: * whiteout vnode call
756: */
757: int
1.76 lukem 758: ufs_whiteout(void *v)
1.15 christos 759: {
1.6 mycroft 760: struct vop_whiteout_args /* {
1.76 lukem 761: struct vnode *a_dvp;
762: struct componentname *a_cnp;
763: int a_flags;
764: } */ *ap = v;
1.119 mycroft 765: struct vnode *dvp = ap->a_dvp;
766: struct componentname *cnp = ap->a_cnp;
1.116 hannken 767: struct direct *newdir;
1.76 lukem 768: int error;
1.119 mycroft 769: struct ufsmount *ump = VFSTOUFS(dvp->v_mount);
1.6 mycroft 770:
1.76 lukem 771: error = 0;
1.6 mycroft 772: switch (ap->a_flags) {
773: case LOOKUP:
774: /* 4.4 format directories support whiteout operations */
1.119 mycroft 775: if (ump->um_maxsymlinklen > 0)
1.6 mycroft 776: return (0);
777: return (EOPNOTSUPP);
778:
779: case CREATE:
780: /* create a new directory whiteout */
1.153 hannken 781: fstrans_start(dvp->v_mount, FSTRANS_SHARED);
1.6 mycroft 782: #ifdef DIAGNOSTIC
783: if ((cnp->cn_flags & SAVENAME) == 0)
784: panic("ufs_whiteout: missing name");
1.119 mycroft 785: if (ump->um_maxsymlinklen <= 0)
1.6 mycroft 786: panic("ufs_whiteout: old format filesystem");
787: #endif
788:
1.116 hannken 789: newdir = pool_get(&ufs_direct_pool, PR_WAITOK);
790: newdir->d_ino = WINO;
791: newdir->d_namlen = cnp->cn_namelen;
792: memcpy(newdir->d_name, cnp->cn_nameptr,
1.108 christos 793: (size_t)cnp->cn_namelen);
1.116 hannken 794: newdir->d_name[cnp->cn_namelen] = '\0';
795: newdir->d_type = DT_WHT;
796: error = ufs_direnter(dvp, NULL, newdir, cnp, NULL);
797: pool_put(&ufs_direct_pool, newdir);
1.6 mycroft 798: break;
799:
800: case DELETE:
801: /* remove an existing directory whiteout */
1.153 hannken 802: fstrans_start(dvp->v_mount, FSTRANS_SHARED);
1.6 mycroft 803: #ifdef DIAGNOSTIC
1.119 mycroft 804: if (ump->um_maxsymlinklen <= 0)
1.6 mycroft 805: panic("ufs_whiteout: old format filesystem");
806: #endif
807:
808: cnp->cn_flags &= ~DOWHITEOUT;
1.59 fvdl 809: error = ufs_dirremove(dvp, NULL, cnp->cn_flags, 0);
1.6 mycroft 810: break;
1.59 fvdl 811: default:
812: panic("ufs_whiteout: unknown op");
813: /* NOTREACHED */
1.6 mycroft 814: }
815: if (cnp->cn_flags & HASBUF) {
1.73 thorpej 816: PNBUF_PUT(cnp->cn_pnbuf);
1.6 mycroft 817: cnp->cn_flags &= ~HASBUF;
818: }
1.148 hannken 819: fstrans_done(dvp->v_mount);
1.6 mycroft 820: return (error);
821: }
822:
823:
824: /*
1.1 mycroft 825: * Rename system call.
826: * rename("foo", "bar");
827: * is essentially
828: * unlink("bar");
829: * link("foo", "bar");
830: * unlink("foo");
831: * but ``atomically''. Can't do full commit without saving state in the
832: * inode on disk which isn't feasible at this time. Best we can do is
833: * always guarantee the target exists.
834: *
835: * Basic algorithm is:
836: *
837: * 1) Bump link count on source while we're linking it to the
838: * target. This also ensure the inode won't be deleted out
839: * from underneath us while we work (it may be truncated by
840: * a concurrent `trunc' or `open' for creation).
841: * 2) Link source to destination. If destination already exists,
842: * delete it first.
843: * 3) Unlink source reference to inode if still around. If a
844: * directory was moved and the parent of the destination
845: * is different from the source, patch the ".." entry in the
846: * directory.
847: */
848: int
1.76 lukem 849: ufs_rename(void *v)
1.15 christos 850: {
1.1 mycroft 851: struct vop_rename_args /* {
1.76 lukem 852: struct vnode *a_fdvp;
853: struct vnode *a_fvp;
854: struct componentname *a_fcnp;
855: struct vnode *a_tdvp;
856: struct vnode *a_tvp;
857: struct componentname *a_tcnp;
858: } */ *ap = v;
859: struct vnode *tvp, *tdvp, *fvp, *fdvp;
860: struct componentname *tcnp, *fcnp;
861: struct inode *ip, *xp, *dp;
1.148 hannken 862: struct mount *mp;
1.116 hannken 863: struct direct *newdir;
1.76 lukem 864: int doingdirectory, oldparent, newparent, error;
865:
866: tvp = ap->a_tvp;
867: tdvp = ap->a_tdvp;
868: fvp = ap->a_fvp;
869: fdvp = ap->a_fdvp;
870: tcnp = ap->a_tcnp;
871: fcnp = ap->a_fcnp;
872: doingdirectory = oldparent = newparent = error = 0;
1.1 mycroft 873:
874: #ifdef DIAGNOSTIC
875: if ((tcnp->cn_flags & HASBUF) == 0 ||
876: (fcnp->cn_flags & HASBUF) == 0)
877: panic("ufs_rename: no name");
878: #endif
879: /*
880: * Check for cross-device rename.
881: */
882: if ((fvp->v_mount != tdvp->v_mount) ||
883: (tvp && (fvp->v_mount != tvp->v_mount))) {
884: error = EXDEV;
1.76 lukem 885: abortit:
1.1 mycroft 886: VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
887: if (tdvp == tvp)
888: vrele(tdvp);
889: else
890: vput(tdvp);
891: if (tvp)
892: vput(tvp);
893: VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
894: vrele(fdvp);
895: vrele(fvp);
896: return (error);
897: }
898:
899: /*
900: * Check if just deleting a link name.
901: */
1.92 fvdl 902: if (tvp && ((VTOI(tvp)->i_flags & (IMMUTABLE | APPEND)) ||
903: (VTOI(tdvp)->i_flags & APPEND))) {
1.1 mycroft 904: error = EPERM;
905: goto abortit;
906: }
907: if (fvp == tvp) {
908: if (fvp->v_type == VDIR) {
909: error = EINVAL;
910: goto abortit;
911: }
1.9 cgd 912:
913: /* Release destination completely. */
914: VOP_ABORTOP(tdvp, tcnp);
915: vput(tdvp);
916: vput(tvp);
917:
918: /* Delete source. */
1.1 mycroft 919: vrele(fvp);
1.61 wrstuden 920: fcnp->cn_flags &= ~(MODMASK | SAVESTART);
1.9 cgd 921: fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
922: fcnp->cn_nameiop = DELETE;
1.144 chs 923: vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
924: if ((error = relookup(fdvp, &fvp, fcnp))) {
925: vput(fdvp);
1.61 wrstuden 926: return (error);
927: }
1.9 cgd 928: return (VOP_REMOVE(fdvp, fvp, fcnp));
1.1 mycroft 929: }
1.35 fvdl 930: if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
1.1 mycroft 931: goto abortit;
932: dp = VTOI(fdvp);
933: ip = VTOI(fvp);
1.92 fvdl 934: if ((nlink_t) ip->i_nlink >= LINK_MAX) {
1.54 mrg 935: VOP_UNLOCK(fvp, 0);
936: error = EMLINK;
937: goto abortit;
938: }
1.92 fvdl 939: if ((ip->i_flags & (IMMUTABLE | APPEND)) ||
940: (dp->i_flags & APPEND)) {
1.35 fvdl 941: VOP_UNLOCK(fvp, 0);
1.1 mycroft 942: error = EPERM;
943: goto abortit;
944: }
1.92 fvdl 945: if ((ip->i_mode & IFMT) == IFDIR) {
1.1 mycroft 946: /*
947: * Avoid ".", "..", and aliases of "." for obvious reasons.
948: */
949: if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
1.27 christos 950: dp == ip ||
951: (fcnp->cn_flags & ISDOTDOT) ||
952: (tcnp->cn_flags & ISDOTDOT) ||
1.1 mycroft 953: (ip->i_flag & IN_RENAME)) {
1.35 fvdl 954: VOP_UNLOCK(fvp, 0);
1.1 mycroft 955: error = EINVAL;
956: goto abortit;
957: }
958: ip->i_flag |= IN_RENAME;
959: oldparent = dp->i_number;
1.59 fvdl 960: doingdirectory = 1;
1.1 mycroft 961: }
1.88 jdolecek 962: VN_KNOTE(fdvp, NOTE_WRITE); /* XXXLUKEM/XXX: right place? */
1.1 mycroft 963:
964: /*
965: * When the target exists, both the directory
966: * and target vnodes are returned locked.
967: */
968: dp = VTOI(tdvp);
969: xp = NULL;
970: if (tvp)
971: xp = VTOI(tvp);
972:
1.148 hannken 973: mp = fdvp->v_mount;
1.153 hannken 974: fstrans_start(mp, FSTRANS_SHARED);
1.148 hannken 975:
1.1 mycroft 976: /*
977: * 1) Bump link count while we're moving stuff
978: * around. If we crash somewhere before
979: * completing our work, the link count
980: * may be wrong, but correctable.
981: */
1.59 fvdl 982: ip->i_ffs_effnlink++;
1.92 fvdl 983: ip->i_nlink++;
1.99 kristerw 984: DIP_ASSIGN(ip, nlink, ip->i_nlink);
1.68 mycroft 985: ip->i_flag |= IN_CHANGE;
1.59 fvdl 986: if (DOINGSOFTDEP(fvp))
1.62 fvdl 987: softdep_change_linkcnt(ip);
1.136 yamt 988: if ((error = UFS_UPDATE(fvp, NULL, NULL, UPDATE_DIROP)) != 0) {
1.35 fvdl 989: VOP_UNLOCK(fvp, 0);
1.1 mycroft 990: goto bad;
991: }
992:
993: /*
994: * If ".." must be changed (ie the directory gets a new
995: * parent) then the source directory must not be in the
1.80 wiz 996: * directory hierarchy above the target, as this would
1.1 mycroft 997: * orphan everything below the source directory. Also
998: * the user must have write permission in the source so
1.126 perry 999: * as to be able to change "..". We must repeat the call
1.1 mycroft 1000: * to namei, as the parent directory is unlocked by the
1001: * call to checkpath().
1002: */
1.138 christos 1003: error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_lwp);
1.35 fvdl 1004: VOP_UNLOCK(fvp, 0);
1.1 mycroft 1005: if (oldparent != dp->i_number)
1006: newparent = dp->i_number;
1007: if (doingdirectory && newparent) {
1008: if (error) /* write access check above */
1009: goto bad;
1010: if (xp != NULL)
1011: vput(tvp);
1.144 chs 1012: vref(tdvp); /* compensate for the ref checkpath loses */
1.102 fvdl 1013: if ((error = ufs_checkpath(ip, dp, tcnp->cn_cred)) != 0) {
1.61 wrstuden 1014: vrele(tdvp);
1.1 mycroft 1015: goto out;
1.61 wrstuden 1016: }
1017: tcnp->cn_flags &= ~SAVESTART;
1.144 chs 1018: vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY);
1019: error = relookup(tdvp, &tvp, tcnp);
1020: if (error != 0) {
1021: vput(tdvp);
1.1 mycroft 1022: goto out;
1.144 chs 1023: }
1.1 mycroft 1024: dp = VTOI(tdvp);
1025: xp = NULL;
1026: if (tvp)
1027: xp = VTOI(tvp);
1028: }
1029: /*
1030: * 2) If target doesn't exist, link the target
1.126 perry 1031: * to the source and unlink the source.
1.1 mycroft 1032: * Otherwise, rewrite the target directory
1033: * entry to reference the source inode and
1034: * expunge the original entry's existence.
1035: */
1036: if (xp == NULL) {
1037: if (dp->i_dev != ip->i_dev)
1038: panic("rename: EXDEV");
1039: /*
1040: * Account for ".." in new directory.
1041: * When source and destination have the same
1042: * parent we don't fool with the link count.
1043: */
1044: if (doingdirectory && newparent) {
1.92 fvdl 1045: if ((nlink_t)dp->i_nlink >= LINK_MAX) {
1.1 mycroft 1046: error = EMLINK;
1047: goto bad;
1048: }
1.59 fvdl 1049: dp->i_ffs_effnlink++;
1.92 fvdl 1050: dp->i_nlink++;
1.99 kristerw 1051: DIP_ASSIGN(dp, nlink, dp->i_nlink);
1.1 mycroft 1052: dp->i_flag |= IN_CHANGE;
1.59 fvdl 1053: if (DOINGSOFTDEP(tdvp))
1.62 fvdl 1054: softdep_change_linkcnt(dp);
1.136 yamt 1055: if ((error = UFS_UPDATE(tdvp, NULL, NULL,
1.66 perseant 1056: UPDATE_DIROP)) != 0) {
1.59 fvdl 1057: dp->i_ffs_effnlink--;
1.92 fvdl 1058: dp->i_nlink--;
1.99 kristerw 1059: DIP_ASSIGN(dp, nlink, dp->i_nlink);
1.59 fvdl 1060: dp->i_flag |= IN_CHANGE;
1.62 fvdl 1061: if (DOINGSOFTDEP(tdvp))
1062: softdep_change_linkcnt(dp);
1.1 mycroft 1063: goto bad;
1.59 fvdl 1064: }
1.1 mycroft 1065: }
1.116 hannken 1066: newdir = pool_get(&ufs_direct_pool, PR_WAITOK);
1067: ufs_makedirentry(ip, tcnp, newdir);
1068: error = ufs_direnter(tdvp, NULL, newdir, tcnp, NULL);
1069: pool_put(&ufs_direct_pool, newdir);
1.59 fvdl 1070: if (error != 0) {
1.1 mycroft 1071: if (doingdirectory && newparent) {
1.59 fvdl 1072: dp->i_ffs_effnlink--;
1.92 fvdl 1073: dp->i_nlink--;
1.99 kristerw 1074: DIP_ASSIGN(dp, nlink, dp->i_nlink);
1.1 mycroft 1075: dp->i_flag |= IN_CHANGE;
1.62 fvdl 1076: if (DOINGSOFTDEP(tdvp))
1077: softdep_change_linkcnt(dp);
1.136 yamt 1078: (void)UFS_UPDATE(tdvp, NULL, NULL,
1.66 perseant 1079: UPDATE_WAIT|UPDATE_DIROP);
1.1 mycroft 1080: }
1081: goto bad;
1082: }
1.88 jdolecek 1083: VN_KNOTE(tdvp, NOTE_WRITE);
1.1 mycroft 1084: vput(tdvp);
1085: } else {
1086: if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
1087: panic("rename: EXDEV");
1088: /*
1089: * Short circuit rename(foo, foo).
1090: */
1091: if (xp->i_number == ip->i_number)
1092: panic("rename: same file");
1093: /*
1094: * If the parent directory is "sticky", then the user must
1095: * own the parent directory, or the destination of the rename,
1096: * otherwise the destination may not be changed (except by
1097: * root). This implements append-only directories.
1098: */
1.147 elad 1099: if ((dp->i_mode & S_ISTXT) &&
1100: kauth_authorize_generic(tcnp->cn_cred,
1101: KAUTH_GENERIC_ISSUSER, NULL) != 0 &&
1.140 elad 1102: kauth_cred_geteuid(tcnp->cn_cred) != dp->i_uid &&
1103: xp->i_uid != kauth_cred_geteuid(tcnp->cn_cred)) {
1.1 mycroft 1104: error = EPERM;
1105: goto bad;
1106: }
1107: /*
1108: * Target must be empty if a directory and have no links
1109: * to it. Also, ensure source and target are compatible
1110: * (both directories, or both not directories).
1111: */
1.92 fvdl 1112: if ((xp->i_mode & IFMT) == IFDIR) {
1.59 fvdl 1113: if (xp->i_ffs_effnlink > 2 ||
1114: !ufs_dirempty(xp, dp->i_number, tcnp->cn_cred)) {
1.1 mycroft 1115: error = ENOTEMPTY;
1116: goto bad;
1117: }
1118: if (!doingdirectory) {
1119: error = ENOTDIR;
1120: goto bad;
1121: }
1122: cache_purge(tdvp);
1123: } else if (doingdirectory) {
1124: error = EISDIR;
1125: goto bad;
1126: }
1.126 perry 1127: if ((error = ufs_dirrewrite(dp, xp, ip->i_number,
1.92 fvdl 1128: IFTODT(ip->i_mode), doingdirectory && newparent ?
1.118 mycroft 1129: newparent : doingdirectory, IN_CHANGE | IN_UPDATE)) != 0)
1.1 mycroft 1130: goto bad;
1.59 fvdl 1131: if (doingdirectory) {
1132: if (!newparent) {
1133: dp->i_ffs_effnlink--;
1.62 fvdl 1134: if (DOINGSOFTDEP(tdvp))
1135: softdep_change_linkcnt(dp);
1.59 fvdl 1136: }
1137: xp->i_ffs_effnlink--;
1.62 fvdl 1138: if (DOINGSOFTDEP(tvp))
1139: softdep_change_linkcnt(xp);
1.59 fvdl 1140: }
1141: if (doingdirectory && !DOINGSOFTDEP(tvp)) {
1142: /*
1143: * Truncate inode. The only stuff left in the directory
1144: * is "." and "..". The "." reference is inconsequential
1145: * since we are quashing it. We have removed the "."
1146: * reference and the reference in the parent directory,
1147: * but there may be other hard links. The soft
1148: * dependency code will arrange to do these operations
1149: * after the parent directory entry has been deleted on
1150: * disk, so when running with that code we avoid doing
1151: * them now.
1152: */
1.62 fvdl 1153: if (!newparent) {
1.92 fvdl 1154: dp->i_nlink--;
1.99 kristerw 1155: DIP_ASSIGN(dp, nlink, dp->i_nlink);
1.62 fvdl 1156: dp->i_flag |= IN_CHANGE;
1157: }
1.92 fvdl 1158: xp->i_nlink--;
1.99 kristerw 1159: DIP_ASSIGN(xp, nlink, xp->i_nlink);
1.62 fvdl 1160: xp->i_flag |= IN_CHANGE;
1.136 yamt 1161: if ((error = UFS_TRUNCATE(tvp, (off_t)0, IO_SYNC,
1.138 christos 1162: tcnp->cn_cred, tcnp->cn_lwp)))
1.59 fvdl 1163: goto bad;
1.1 mycroft 1164: }
1.88 jdolecek 1165: VN_KNOTE(tdvp, NOTE_WRITE);
1.1 mycroft 1166: vput(tdvp);
1.88 jdolecek 1167: VN_KNOTE(tvp, NOTE_DELETE);
1.1 mycroft 1168: vput(tvp);
1169: xp = NULL;
1170: }
1171:
1172: /*
1173: * 3) Unlink the source.
1174: */
1.61 wrstuden 1175: fcnp->cn_flags &= ~(MODMASK | SAVESTART);
1.1 mycroft 1176: fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
1.144 chs 1177: vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
1.61 wrstuden 1178: if ((error = relookup(fdvp, &fvp, fcnp))) {
1.144 chs 1179: vput(fdvp);
1.61 wrstuden 1180: vrele(ap->a_fvp);
1.148 hannken 1181: goto out2;
1.61 wrstuden 1182: }
1.1 mycroft 1183: if (fvp != NULL) {
1184: xp = VTOI(fvp);
1185: dp = VTOI(fdvp);
1186: } else {
1187: /*
1188: * From name has disappeared.
1189: */
1190: if (doingdirectory)
1191: panic("rename: lost dir entry");
1192: vrele(ap->a_fvp);
1.148 hannken 1193: error = 0;
1194: goto out2;
1.1 mycroft 1195: }
1196: /*
1197: * Ensure that the directory entry still exists and has not
1198: * changed while the new name has been entered. If the source is
1199: * a file then the entry may have been unlinked or renamed. In
1200: * either case there is no further work to be done. If the source
1.59 fvdl 1201: * is a directory then it cannot have been rmdir'ed; The IRENAME
1202: * flag ensures that it cannot be moved by another rename or removed
1203: * by a rmdir.
1.1 mycroft 1204: */
1205: if (xp != ip) {
1206: if (doingdirectory)
1207: panic("rename: lost dir entry");
1208: } else {
1209: /*
1210: * If the source is a directory with a
1211: * new parent, the link count of the old
1212: * parent directory must be decremented
1213: * and ".." set to point to the new parent.
1214: */
1215: if (doingdirectory && newparent) {
1.143 christos 1216: KASSERT(dp != NULL);
1.59 fvdl 1217: xp->i_offset = mastertemplate.dot_reclen;
1.103 pk 1218: ufs_dirrewrite(xp, dp, newparent, DT_DIR, 0, IN_CHANGE);
1.59 fvdl 1219: cache_purge(fdvp);
1.1 mycroft 1220: }
1.59 fvdl 1221: error = ufs_dirremove(fdvp, xp, fcnp->cn_flags, 0);
1.1 mycroft 1222: xp->i_flag &= ~IN_RENAME;
1223: }
1.88 jdolecek 1224: VN_KNOTE(fvp, NOTE_RENAME);
1.1 mycroft 1225: if (dp)
1226: vput(fdvp);
1227: if (xp)
1228: vput(fvp);
1229: vrele(ap->a_fvp);
1.148 hannken 1230: goto out2;
1.1 mycroft 1231:
1.61 wrstuden 1232: /* exit routines from steps 1 & 2 */
1.76 lukem 1233: bad:
1.1 mycroft 1234: if (xp)
1235: vput(ITOV(xp));
1236: vput(ITOV(dp));
1.76 lukem 1237: out:
1.8 mycroft 1238: if (doingdirectory)
1239: ip->i_flag &= ~IN_RENAME;
1.35 fvdl 1240: if (vn_lock(fvp, LK_EXCLUSIVE) == 0) {
1.62 fvdl 1241: ip->i_ffs_effnlink--;
1.92 fvdl 1242: ip->i_nlink--;
1.99 kristerw 1243: DIP_ASSIGN(ip, nlink, ip->i_nlink);
1.1 mycroft 1244: ip->i_flag |= IN_CHANGE;
1.92 fvdl 1245: ip->i_flag &= ~IN_RENAME;
1.62 fvdl 1246: if (DOINGSOFTDEP(fvp))
1247: softdep_change_linkcnt(ip);
1.1 mycroft 1248: vput(fvp);
1249: } else
1250: vrele(fvp);
1.61 wrstuden 1251: vrele(fdvp);
1.148 hannken 1252:
1253: /* exit routines from step 3 */
1254: out2:
1255: fstrans_done(mp);
1.1 mycroft 1256: return (error);
1257: }
1258:
1259: /*
1260: * Mkdir system call
1261: */
1262: int
1.76 lukem 1263: ufs_mkdir(void *v)
1.15 christos 1264: {
1.1 mycroft 1265: struct vop_mkdir_args /* {
1.76 lukem 1266: struct vnode *a_dvp;
1267: struct vnode **a_vpp;
1268: struct componentname *a_cnp;
1269: struct vattr *a_vap;
1.15 christos 1270: } */ *ap = v;
1.119 mycroft 1271: struct vnode *dvp = ap->a_dvp, *tvp;
1272: struct vattr *vap = ap->a_vap;
1273: struct componentname *cnp = ap->a_cnp;
1274: struct inode *ip, *dp = VTOI(dvp);
1.76 lukem 1275: struct buf *bp;
1276: struct dirtemplate dirtemplate;
1.116 hannken 1277: struct direct *newdir;
1.76 lukem 1278: int error, dmode, blkoff;
1.119 mycroft 1279: struct ufsmount *ump = dp->i_ump;
1280: int dirblksiz = ump->um_dirblksiz;
1.76 lukem 1281:
1.153 hannken 1282: fstrans_start(dvp->v_mount, FSTRANS_SHARED);
1.148 hannken 1283:
1.1 mycroft 1284: #ifdef DIAGNOSTIC
1285: if ((cnp->cn_flags & HASBUF) == 0)
1286: panic("ufs_mkdir: no name");
1287: #endif
1.92 fvdl 1288: if ((nlink_t)dp->i_nlink >= LINK_MAX) {
1.1 mycroft 1289: error = EMLINK;
1290: goto out;
1291: }
1.25 mycroft 1292: dmode = vap->va_mode & ACCESSPERMS;
1.1 mycroft 1293: dmode |= IFDIR;
1294: /*
1295: * Must simulate part of ufs_makeinode here to acquire the inode,
1296: * but not have it entered in the parent directory. The entry is
1297: * made later after writing "." and ".." entries.
1298: */
1.136 yamt 1299: if ((error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, ap->a_vpp)) != 0)
1.1 mycroft 1300: goto out;
1.127 perseant 1301: tvp = *ap->a_vpp;
1.1 mycroft 1302: ip = VTOI(tvp);
1.140 elad 1303: ip->i_uid = kauth_cred_geteuid(cnp->cn_cred);
1.99 kristerw 1304: DIP_ASSIGN(ip, uid, ip->i_uid);
1.92 fvdl 1305: ip->i_gid = dp->i_gid;
1.99 kristerw 1306: DIP_ASSIGN(ip, gid, ip->i_gid);
1.1 mycroft 1307: #ifdef QUOTA
1.154 hannken 1308: if ((error = chkiq(ip, 1, cnp->cn_cred, 0))) {
1.73 thorpej 1309: PNBUF_PUT(cnp->cn_pnbuf);
1.136 yamt 1310: UFS_VFREE(tvp, ip->i_number, dmode);
1.148 hannken 1311: fstrans_done(dvp->v_mount);
1.1 mycroft 1312: vput(tvp);
1313: vput(dvp);
1314: return (error);
1315: }
1316: #endif
1317: ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1.92 fvdl 1318: ip->i_mode = dmode;
1.99 kristerw 1319: DIP_ASSIGN(ip, mode, dmode);
1.1 mycroft 1320: tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */
1.59 fvdl 1321: ip->i_ffs_effnlink = 2;
1.92 fvdl 1322: ip->i_nlink = 2;
1.99 kristerw 1323: DIP_ASSIGN(ip, nlink, 2);
1.59 fvdl 1324: if (DOINGSOFTDEP(tvp))
1.62 fvdl 1325: softdep_change_linkcnt(ip);
1.92 fvdl 1326: if (cnp->cn_flags & ISWHITEOUT) {
1327: ip->i_flags |= UF_OPAQUE;
1.99 kristerw 1328: DIP_ASSIGN(ip, flags, ip->i_flags);
1.92 fvdl 1329: }
1.1 mycroft 1330:
1331: /*
1.59 fvdl 1332: * Bump link count in parent directory to reflect work done below.
1333: * Should be done before reference is created so cleanup is
1334: * possible if we crash.
1.1 mycroft 1335: */
1.59 fvdl 1336: dp->i_ffs_effnlink++;
1.92 fvdl 1337: dp->i_nlink++;
1.99 kristerw 1338: DIP_ASSIGN(dp, nlink, dp->i_nlink);
1.1 mycroft 1339: dp->i_flag |= IN_CHANGE;
1.59 fvdl 1340: if (DOINGSOFTDEP(dvp))
1.62 fvdl 1341: softdep_change_linkcnt(dp);
1.136 yamt 1342: if ((error = UFS_UPDATE(dvp, NULL, NULL, UPDATE_DIROP)) != 0)
1.1 mycroft 1343: goto bad;
1344:
1.59 fvdl 1345: /*
1346: * Initialize directory with "." and ".." from static template.
1347: */
1.38 bouyer 1348: dirtemplate = mastertemplate;
1.87 dbj 1349: dirtemplate.dotdot_reclen = dirblksiz - dirtemplate.dot_reclen;
1.119 mycroft 1350: dirtemplate.dot_ino = ufs_rw32(ip->i_number, UFS_MPNEEDSWAP(ump));
1351: dirtemplate.dotdot_ino = ufs_rw32(dp->i_number, UFS_MPNEEDSWAP(ump));
1.38 bouyer 1352: dirtemplate.dot_reclen = ufs_rw16(dirtemplate.dot_reclen,
1.119 mycroft 1353: UFS_MPNEEDSWAP(ump));
1.38 bouyer 1354: dirtemplate.dotdot_reclen = ufs_rw16(dirtemplate.dotdot_reclen,
1.119 mycroft 1355: UFS_MPNEEDSWAP(ump));
1356: if (ump->um_maxsymlinklen <= 0) {
1.38 bouyer 1357: #if BYTE_ORDER == LITTLE_ENDIAN
1.119 mycroft 1358: if (UFS_MPNEEDSWAP(ump) == 0)
1.38 bouyer 1359: #else
1.119 mycroft 1360: if (UFS_MPNEEDSWAP(ump) != 0)
1.38 bouyer 1361: #endif
1.76 lukem 1362: {
1.38 bouyer 1363: dirtemplate.dot_type = dirtemplate.dot_namlen;
1364: dirtemplate.dotdot_type = dirtemplate.dotdot_namlen;
1365: dirtemplate.dot_namlen = dirtemplate.dotdot_namlen = 0;
1366: } else
1367: dirtemplate.dot_type = dirtemplate.dotdot_type = 0;
1368: }
1.136 yamt 1369: if ((error = UFS_BALLOC(tvp, (off_t)0, dirblksiz, cnp->cn_cred,
1.59 fvdl 1370: B_CLRBUF, &bp)) != 0)
1.1 mycroft 1371: goto bad;
1.92 fvdl 1372: ip->i_size = dirblksiz;
1.99 kristerw 1373: DIP_ASSIGN(ip, size, dirblksiz);
1.59 fvdl 1374: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1.92 fvdl 1375: uvm_vnp_setsize(tvp, ip->i_size);
1.152 christos 1376: memcpy((void *)bp->b_data, (void *)&dirtemplate, sizeof dirtemplate);
1.59 fvdl 1377: if (DOINGSOFTDEP(tvp)) {
1378: /*
1379: * Ensure that the entire newly allocated block is a
1380: * valid directory so that future growth within the
1381: * block does not have to ensure that the block is
1382: * written before the inode.
1383: */
1.87 dbj 1384: blkoff = dirblksiz;
1.59 fvdl 1385: while (blkoff < bp->b_bcount) {
1386: ((struct direct *)
1.152 christos 1387: ((char *)bp->b_data + blkoff))->d_reclen = dirblksiz;
1.87 dbj 1388: blkoff += dirblksiz;
1.59 fvdl 1389: }
1.1 mycroft 1390: }
1.59 fvdl 1391: /*
1392: * Directory set up, now install it's entry in the parent directory.
1393: *
1394: * If we are not doing soft dependencies, then we must write out the
1395: * buffer containing the new directory body before entering the new
1396: * name in the parent. If we are doing soft dependencies, then the
1397: * buffer containing the new directory body will be passed to and
1398: * released in the soft dependency code after the code has attached
1399: * an appropriate ordering dependency to the buffer which ensures that
1400: * the buffer is written before the new name is written in the parent.
1401: */
1.86 mycroft 1402: if (!DOINGSOFTDEP(tvp) && ((error = VOP_BWRITE(bp)) != 0))
1.59 fvdl 1403: goto bad;
1.136 yamt 1404: if ((error = UFS_UPDATE(tvp, NULL, NULL, UPDATE_DIROP)) != 0) {
1.86 mycroft 1405: if (DOINGSOFTDEP(tvp))
1406: (void)VOP_BWRITE(bp);
1407: goto bad;
1408: }
1.116 hannken 1409: newdir = pool_get(&ufs_direct_pool, PR_WAITOK);
1410: ufs_makedirentry(ip, cnp, newdir);
1411: error = ufs_direnter(dvp, tvp, newdir, cnp, bp);
1412: pool_put(&ufs_direct_pool, newdir);
1.76 lukem 1413: bad:
1.59 fvdl 1414: if (error == 0) {
1.88 jdolecek 1415: VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1.59 fvdl 1416: } else {
1417: dp->i_ffs_effnlink--;
1.92 fvdl 1418: dp->i_nlink--;
1.99 kristerw 1419: DIP_ASSIGN(dp, nlink, dp->i_nlink);
1.1 mycroft 1420: dp->i_flag |= IN_CHANGE;
1.62 fvdl 1421: if (DOINGSOFTDEP(dvp))
1422: softdep_change_linkcnt(dp);
1.59 fvdl 1423: /*
1.136 yamt 1424: * No need to do an explicit UFS_TRUNCATE here, vrele will
1.59 fvdl 1425: * do this for us because we set the link count to 0.
1426: */
1427: ip->i_ffs_effnlink = 0;
1.92 fvdl 1428: ip->i_nlink = 0;
1.99 kristerw 1429: DIP_ASSIGN(ip, nlink, 0);
1.1 mycroft 1430: ip->i_flag |= IN_CHANGE;
1.69 perseant 1431: #ifdef LFS
1432: /* If IN_ADIROP, account for it */
1433: lfs_unmark_vnode(tvp);
1434: #endif
1.62 fvdl 1435: if (DOINGSOFTDEP(tvp))
1436: softdep_change_linkcnt(ip);
1.1 mycroft 1437: vput(tvp);
1.59 fvdl 1438: }
1.76 lukem 1439: out:
1.73 thorpej 1440: PNBUF_PUT(cnp->cn_pnbuf);
1.148 hannken 1441: fstrans_done(dvp->v_mount);
1.1 mycroft 1442: vput(dvp);
1443: return (error);
1444: }
1445:
1446: /*
1447: * Rmdir system call.
1448: */
1449: int
1.76 lukem 1450: ufs_rmdir(void *v)
1.15 christos 1451: {
1.1 mycroft 1452: struct vop_rmdir_args /* {
1.76 lukem 1453: struct vnode *a_dvp;
1454: struct vnode *a_vp;
1455: struct componentname *a_cnp;
1456: } */ *ap = v;
1457: struct vnode *vp, *dvp;
1458: struct componentname *cnp;
1459: struct inode *ip, *dp;
1460: int error;
1461:
1462: vp = ap->a_vp;
1463: dvp = ap->a_dvp;
1464: cnp = ap->a_cnp;
1.1 mycroft 1465: ip = VTOI(vp);
1466: dp = VTOI(dvp);
1467: /*
1.59 fvdl 1468: * No rmdir "." or of mounted directories please.
1.1 mycroft 1469: */
1.59 fvdl 1470: if (dp == ip || vp->v_mountedhere != NULL) {
1.144 chs 1471: if (dp == ip)
1472: vrele(vp);
1473: else
1474: vput(vp);
1.1 mycroft 1475: vput(vp);
1476: return (EINVAL);
1477: }
1.148 hannken 1478:
1.153 hannken 1479: fstrans_start(dvp->v_mount, FSTRANS_SHARED);
1.148 hannken 1480:
1.1 mycroft 1481: /*
1.59 fvdl 1482: * Do not remove a directory that is in the process of being renamed.
1483: * Verify that the directory is empty (and valid). (Rmdir ".." won't
1484: * be valid since ".." will contain a reference to the current
1485: * directory and thus be non-empty.)
1.1 mycroft 1486: */
1487: error = 0;
1.59 fvdl 1488: if (ip->i_flag & IN_RENAME) {
1489: error = EINVAL;
1490: goto out;
1491: }
1492: if (ip->i_ffs_effnlink != 2 ||
1.1 mycroft 1493: !ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
1494: error = ENOTEMPTY;
1495: goto out;
1496: }
1.92 fvdl 1497: if ((dp->i_flags & APPEND) ||
1498: (ip->i_flags & (IMMUTABLE | APPEND))) {
1.1 mycroft 1499: error = EPERM;
1500: goto out;
1501: }
1502: /*
1503: * Delete reference to directory before purging
1504: * inode. If we crash in between, the directory
1505: * will be reattached to lost+found,
1506: */
1.62 fvdl 1507: if (DOINGSOFTDEP(vp)) {
1.109 dbj 1508: dp->i_ffs_effnlink--;
1509: ip->i_ffs_effnlink--;
1.62 fvdl 1510: softdep_change_linkcnt(dp);
1511: softdep_change_linkcnt(ip);
1512: }
1513: error = ufs_dirremove(dvp, ip, cnp->cn_flags, 1);
1514: if (error) {
1515: if (DOINGSOFTDEP(vp)) {
1.109 dbj 1516: dp->i_ffs_effnlink++;
1517: ip->i_ffs_effnlink++;
1.62 fvdl 1518: softdep_change_linkcnt(dp);
1519: softdep_change_linkcnt(ip);
1520: }
1.1 mycroft 1521: goto out;
1.62 fvdl 1522: }
1.88 jdolecek 1523: VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
1.1 mycroft 1524: cache_purge(dvp);
1525: /*
1.59 fvdl 1526: * Truncate inode. The only stuff left in the directory is "." and
1527: * "..". The "." reference is inconsequential since we're quashing
1.62 fvdl 1528: * it. The soft dependency code will arrange to do these operations
1529: * after the parent directory entry has been deleted on disk, so
1530: * when running with that code we avoid doing them now.
1.59 fvdl 1531: */
1532: if (!DOINGSOFTDEP(vp)) {
1.92 fvdl 1533: dp->i_nlink--;
1.109 dbj 1534: dp->i_ffs_effnlink--;
1.99 kristerw 1535: DIP_ASSIGN(dp, nlink, dp->i_nlink);
1.62 fvdl 1536: dp->i_flag |= IN_CHANGE;
1.92 fvdl 1537: ip->i_nlink--;
1.109 dbj 1538: ip->i_ffs_effnlink--;
1.99 kristerw 1539: DIP_ASSIGN(ip, nlink, ip->i_nlink);
1.62 fvdl 1540: ip->i_flag |= IN_CHANGE;
1.136 yamt 1541: error = UFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred,
1.138 christos 1542: cnp->cn_lwp);
1.59 fvdl 1543: }
1544: cache_purge(vp);
1.124 rumble 1545: #ifdef UFS_DIRHASH
1546: if (ip->i_dirhash != NULL)
1547: ufsdirhash_free(ip);
1548: #endif
1.76 lukem 1549: out:
1.88 jdolecek 1550: VN_KNOTE(vp, NOTE_DELETE);
1.148 hannken 1551: fstrans_done(dvp->v_mount);
1.59 fvdl 1552: vput(dvp);
1.1 mycroft 1553: vput(vp);
1554: return (error);
1555: }
1556:
1557: /*
1558: * symlink -- make a symbolic link
1559: */
1560: int
1.76 lukem 1561: ufs_symlink(void *v)
1.15 christos 1562: {
1.1 mycroft 1563: struct vop_symlink_args /* {
1.76 lukem 1564: struct vnode *a_dvp;
1565: struct vnode **a_vpp;
1566: struct componentname *a_cnp;
1567: struct vattr *a_vap;
1568: char *a_target;
1569: } */ *ap = v;
1570: struct vnode *vp, **vpp;
1571: struct inode *ip;
1572: int len, error;
1.1 mycroft 1573:
1.76 lukem 1574: vpp = ap->a_vpp;
1.153 hannken 1575: fstrans_start(ap->a_dvp->v_mount, FSTRANS_SHARED);
1.15 christos 1576: error = ufs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
1577: vpp, ap->a_cnp);
1578: if (error)
1.148 hannken 1579: goto out;
1.88 jdolecek 1580: VN_KNOTE(ap->a_dvp, NOTE_WRITE);
1.1 mycroft 1581: vp = *vpp;
1582: len = strlen(ap->a_target);
1.119 mycroft 1583: ip = VTOI(vp);
1584: if (len < ip->i_ump->um_maxsymlinklen) {
1.92 fvdl 1585: memcpy((char *)SHORTLINK(ip), ap->a_target, len);
1586: ip->i_size = len;
1.99 kristerw 1587: DIP_ASSIGN(ip, size, len);
1.92 fvdl 1588: uvm_vnp_setsize(vp, ip->i_size);
1.1 mycroft 1589: ip->i_flag |= IN_CHANGE | IN_UPDATE;
1590: } else
1591: error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
1.44 thorpej 1592: UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, NULL,
1.122 skrll 1593: NULL);
1.79 assar 1594: if (error)
1595: vput(vp);
1.148 hannken 1596: out:
1597: fstrans_done(ap->a_dvp->v_mount);
1.1 mycroft 1598: return (error);
1599: }
1600:
1601: /*
1602: * Vnode op for reading directories.
1.126 perry 1603: *
1.130 christos 1604: * This routine handles converting from the on-disk directory format
1605: * "struct direct" to the in-memory format "struct dirent" as well as
1606: * byte swapping the entries if necessary.
1.1 mycroft 1607: */
1608: int
1.76 lukem 1609: ufs_readdir(void *v)
1.15 christos 1610: {
1.1 mycroft 1611: struct vop_readdir_args /* {
1.76 lukem 1612: struct vnode *a_vp;
1613: struct uio *a_uio;
1.140 elad 1614: kauth_cred_t a_cred;
1.76 lukem 1615: int *a_eofflag;
1616: off_t **a_cookies;
1617: int *ncookies;
1618: } */ *ap = v;
1.119 mycroft 1619: struct vnode *vp = ap->a_vp;
1.130 christos 1620: struct direct *cdp, *ecdp;
1621: struct dirent *ndp;
1622: char *cdbuf, *ndbuf, *endp;
1623: struct uio auio, *uio;
1624: struct iovec aiov;
1.76 lukem 1625: int error;
1.130 christos 1626: size_t count, ccount, rcount;
1627: off_t off, *ccp;
1.145 yamt 1628: off_t startoff;
1629: size_t skipbytes;
1.119 mycroft 1630: struct ufsmount *ump = VFSTOUFS(vp->v_mount);
1.130 christos 1631: int nswap = UFS_MPNEEDSWAP(ump);
1.38 bouyer 1632: #if BYTE_ORDER == LITTLE_ENDIAN
1.130 christos 1633: int needswap = ump->um_maxsymlinklen <= 0 && nswap == 0;
1.38 bouyer 1634: #else
1.130 christos 1635: int needswap = ump->um_maxsymlinklen <= 0 && nswap != 0;
1.38 bouyer 1636: #endif
1.130 christos 1637: uio = ap->a_uio;
1638: count = uio->uio_resid;
1639: rcount = count - ((uio->uio_offset + count) & (ump->um_dirblksiz - 1));
1640:
1641: if (rcount < _DIRENT_MINSIZE(cdp) || count < _DIRENT_MINSIZE(ndp))
1642: return EINVAL;
1643:
1.145 yamt 1644: startoff = uio->uio_offset & ~(ump->um_dirblksiz - 1);
1645: skipbytes = uio->uio_offset - startoff;
1646: rcount += skipbytes;
1647:
1.130 christos 1648: auio.uio_iov = &aiov;
1649: auio.uio_iovcnt = 1;
1.145 yamt 1650: auio.uio_offset = startoff;
1.130 christos 1651: auio.uio_resid = rcount;
1.139 yamt 1652: UIO_SETUP_SYSSPACE(&auio);
1.130 christos 1653: auio.uio_rw = UIO_READ;
1654: cdbuf = malloc(rcount, M_TEMP, M_WAITOK);
1655: aiov.iov_base = cdbuf;
1656: aiov.iov_len = rcount;
1657: error = VOP_READ(vp, &auio, 0, ap->a_cred);
1658: if (error != 0) {
1659: free(cdbuf, M_TEMP);
1660: return error;
1661: }
1662:
1.145 yamt 1663: rcount -= auio.uio_resid;
1.130 christos 1664:
1665: cdp = (struct direct *)(void *)cdbuf;
1666: ecdp = (struct direct *)(void *)&cdbuf[rcount];
1667:
1668: ndbuf = malloc(count, M_TEMP, M_WAITOK);
1669: ndp = (struct dirent *)(void *)ndbuf;
1670: endp = &ndbuf[count];
1671:
1672: off = uio->uio_offset;
1673: if (ap->a_cookies) {
1.131 yamt 1674: ccount = rcount / _DIRENT_RECLEN(cdp, 1);
1.130 christos 1675: ccp = *(ap->a_cookies) = malloc(ccount * sizeof(*ccp),
1676: M_TEMP, M_WAITOK);
1.38 bouyer 1677: } else {
1.130 christos 1678: /* XXX: GCC */
1679: ccount = 0;
1680: ccp = NULL;
1681: }
1682:
1683: while (cdp < ecdp) {
1684: cdp->d_reclen = ufs_rw16(cdp->d_reclen, nswap);
1.145 yamt 1685: if (skipbytes > 0) {
1686: if (cdp->d_reclen <= skipbytes) {
1687: skipbytes -= cdp->d_reclen;
1688: cdp = _DIRENT_NEXT(cdp);
1689: continue;
1690: }
1691: /*
1.151 pooka 1692: * invalid cookie.
1.145 yamt 1693: */
1694: error = EINVAL;
1695: goto out;
1696: }
1.130 christos 1697: if (cdp->d_reclen == 0) {
1698: struct dirent *ondp = ndp;
1699: ndp->d_reclen = _DIRENT_MINSIZE(ndp);
1700: ndp = _DIRENT_NEXT(ndp);
1701: ondp->d_reclen = 0;
1702: cdp = ecdp;
1703: break;
1704: }
1705: if (needswap) {
1706: ndp->d_type = cdp->d_namlen;
1707: ndp->d_namlen = cdp->d_type;
1708: } else {
1709: ndp->d_type = cdp->d_type;
1710: ndp->d_namlen = cdp->d_namlen;
1711: }
1712: ndp->d_reclen = _DIRENT_RECLEN(ndp, ndp->d_namlen);
1713: if ((char *)(void *)ndp + ndp->d_reclen +
1714: _DIRENT_MINSIZE(ndp) > endp)
1715: break;
1716: ndp->d_fileno = ufs_rw32(cdp->d_ino, nswap);
1717: (void)memcpy(ndp->d_name, cdp->d_name, ndp->d_namlen);
1.132 yamt 1718: memset(&ndp->d_name[ndp->d_namlen], 0,
1719: ndp->d_reclen - _DIRENT_NAMEOFF(ndp) - ndp->d_namlen);
1.130 christos 1720: off += cdp->d_reclen;
1721: if (ap->a_cookies) {
1722: KASSERT(ccp - *(ap->a_cookies) < ccount);
1723: *(ccp++) = off;
1.1 mycroft 1724: }
1.130 christos 1725: ndp = _DIRENT_NEXT(ndp);
1726: cdp = _DIRENT_NEXT(cdp);
1.38 bouyer 1727: }
1.1 mycroft 1728:
1.130 christos 1729: count = ((char *)(void *)ndp - ndbuf);
1730: error = uiomove(ndbuf, count, uio);
1.145 yamt 1731: out:
1.130 christos 1732: if (ap->a_cookies) {
1.150 pooka 1733: if (error) {
1.130 christos 1734: free(*(ap->a_cookies), M_TEMP);
1.150 pooka 1735: *(ap->a_cookies) = NULL;
1736: *(ap->a_ncookies) = 0;
1737: } else {
1.130 christos 1738: *ap->a_ncookies = ccp - *(ap->a_cookies);
1.150 pooka 1739: }
1.1 mycroft 1740: }
1.130 christos 1741: uio->uio_offset = off;
1742: free(ndbuf, M_TEMP);
1743: free(cdbuf, M_TEMP);
1.119 mycroft 1744: *ap->a_eofflag = VTOI(vp)->i_size <= uio->uio_offset;
1.130 christos 1745: return error;
1.1 mycroft 1746: }
1747:
1748: /*
1749: * Return target name of a symbolic link
1750: */
1751: int
1.76 lukem 1752: ufs_readlink(void *v)
1.15 christos 1753: {
1.1 mycroft 1754: struct vop_readlink_args /* {
1.76 lukem 1755: struct vnode *a_vp;
1756: struct uio *a_uio;
1.140 elad 1757: kauth_cred_t a_cred;
1.76 lukem 1758: } */ *ap = v;
1.119 mycroft 1759: struct vnode *vp = ap->a_vp;
1760: struct inode *ip = VTOI(vp);
1761: struct ufsmount *ump = VFSTOUFS(vp->v_mount);
1.76 lukem 1762: int isize;
1.1 mycroft 1763:
1.92 fvdl 1764: isize = ip->i_size;
1.119 mycroft 1765: if (isize < ump->um_maxsymlinklen ||
1766: (ump->um_maxsymlinklen == 0 && DIP(ip, blocks) == 0)) {
1.92 fvdl 1767: uiomove((char *)SHORTLINK(ip), isize, ap->a_uio);
1.1 mycroft 1768: return (0);
1769: }
1770: return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
1771: }
1772:
1773: /*
1774: * Calculate the logical to physical mapping if not done already,
1775: * then call the device strategy routine.
1776: */
1777: int
1.76 lukem 1778: ufs_strategy(void *v)
1.15 christos 1779: {
1.1 mycroft 1780: struct vop_strategy_args /* {
1.113 hannken 1781: struct vnode *a_vp;
1.1 mycroft 1782: struct buf *a_bp;
1.15 christos 1783: } */ *ap = v;
1.76 lukem 1784: struct buf *bp;
1785: struct vnode *vp;
1786: struct inode *ip;
1787: int error;
1.1 mycroft 1788:
1.76 lukem 1789: bp = ap->a_bp;
1.113 hannken 1790: vp = ap->a_vp;
1.1 mycroft 1791: ip = VTOI(vp);
1792: if (vp->v_type == VBLK || vp->v_type == VCHR)
1793: panic("ufs_strategy: spec");
1.75 chs 1794: KASSERT(bp->b_bcount != 0);
1.1 mycroft 1795: if (bp->b_blkno == bp->b_lblkno) {
1.15 christos 1796: error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno,
1797: NULL);
1798: if (error) {
1.1 mycroft 1799: bp->b_error = error;
1800: biodone(bp);
1801: return (error);
1802: }
1.117 dbj 1803: if (bp->b_blkno == -1) /* no valid data */
1.1 mycroft 1804: clrbuf(bp);
1805: }
1.117 dbj 1806: if (bp->b_blkno < 0) { /* block is not on disk */
1.1 mycroft 1807: biodone(bp);
1808: return (0);
1809: }
1810: vp = ip->i_devvp;
1.110 hannken 1811: return (VOP_STRATEGY(vp, bp));
1.1 mycroft 1812: }
1813:
1814: /*
1815: * Print out the contents of an inode.
1816: */
1817: int
1.76 lukem 1818: ufs_print(void *v)
1.15 christos 1819: {
1.1 mycroft 1820: struct vop_print_args /* {
1.76 lukem 1821: struct vnode *a_vp;
1.15 christos 1822: } */ *ap = v;
1.76 lukem 1823: struct vnode *vp;
1824: struct inode *ip;
1.1 mycroft 1825:
1.76 lukem 1826: vp = ap->a_vp;
1827: ip = VTOI(vp);
1.130 christos 1828: printf("tag VT_UFS, ino %llu, on dev %d, %d",
1829: (unsigned long long)ip->i_number,
1.20 christos 1830: major(ip->i_dev), minor(ip->i_dev));
1.59 fvdl 1831: printf(" flags 0x%x, effnlink %d, nlink %d\n",
1.92 fvdl 1832: ip->i_flag, ip->i_ffs_effnlink, ip->i_nlink);
1.59 fvdl 1833: printf("\tmode 0%o, owner %d, group %d, size %qd",
1.92 fvdl 1834: ip->i_mode, ip->i_uid, ip->i_gid,
1835: (long long)ip->i_size);
1.1 mycroft 1836: if (vp->v_type == VFIFO)
1837: fifo_printinfo(vp);
1.58 wrstuden 1838: lockmgr_printinfo(&vp->v_lock);
1.21 christos 1839: printf("\n");
1.1 mycroft 1840: return (0);
1841: }
1842:
1843: /*
1844: * Read wrapper for special devices.
1845: */
1846: int
1.76 lukem 1847: ufsspec_read(void *v)
1.15 christos 1848: {
1.1 mycroft 1849: struct vop_read_args /* {
1.76 lukem 1850: struct vnode *a_vp;
1851: struct uio *a_uio;
1852: int a_ioflag;
1.140 elad 1853: kauth_cred_t a_cred;
1.15 christos 1854: } */ *ap = v;
1.1 mycroft 1855:
1856: /*
1857: * Set access flag.
1858: */
1.53 kenh 1859: if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0)
1860: VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
1.1 mycroft 1861: return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap));
1862: }
1863:
1864: /*
1865: * Write wrapper for special devices.
1866: */
1867: int
1.76 lukem 1868: ufsspec_write(void *v)
1.15 christos 1869: {
1.1 mycroft 1870: struct vop_write_args /* {
1.76 lukem 1871: struct vnode *a_vp;
1872: struct uio *a_uio;
1873: int a_ioflag;
1.140 elad 1874: kauth_cred_t a_cred;
1.15 christos 1875: } */ *ap = v;
1.1 mycroft 1876:
1877: /*
1878: * Set update and change flags.
1879: */
1.53 kenh 1880: if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0)
1.118 mycroft 1881: VTOI(ap->a_vp)->i_flag |= IN_MODIFY;
1.1 mycroft 1882: return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap));
1883: }
1884:
1885: /*
1886: * Close wrapper for special devices.
1887: *
1888: * Update the times on the inode then do device close.
1889: */
1890: int
1.76 lukem 1891: ufsspec_close(void *v)
1.15 christos 1892: {
1.1 mycroft 1893: struct vop_close_args /* {
1.76 lukem 1894: struct vnode *a_vp;
1895: int a_fflag;
1.140 elad 1896: kauth_cred_t a_cred;
1.138 christos 1897: struct lwp *a_l;
1.76 lukem 1898: } */ *ap = v;
1899: struct vnode *vp;
1900: struct inode *ip;
1.1 mycroft 1901:
1.76 lukem 1902: vp = ap->a_vp;
1903: ip = VTOI(vp);
1.35 fvdl 1904: simple_lock(&vp->v_interlock);
1.133 christos 1905: if (vp->v_usecount > 1)
1.135 yamt 1906: UFS_ITIMES(vp, NULL, NULL, NULL);
1.35 fvdl 1907: simple_unlock(&vp->v_interlock);
1.1 mycroft 1908: return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap));
1909: }
1910:
1911: /*
1912: * Read wrapper for fifo's
1913: */
1914: int
1.76 lukem 1915: ufsfifo_read(void *v)
1.15 christos 1916: {
1.1 mycroft 1917: struct vop_read_args /* {
1.76 lukem 1918: struct vnode *a_vp;
1919: struct uio *a_uio;
1920: int a_ioflag;
1.140 elad 1921: kauth_cred_t a_cred;
1.15 christos 1922: } */ *ap = v;
1.1 mycroft 1923:
1924: /*
1925: * Set access flag.
1926: */
1927: VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
1928: return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap));
1929: }
1930:
1931: /*
1932: * Write wrapper for fifo's.
1933: */
1934: int
1.76 lukem 1935: ufsfifo_write(void *v)
1.15 christos 1936: {
1.1 mycroft 1937: struct vop_write_args /* {
1.76 lukem 1938: struct vnode *a_vp;
1939: struct uio *a_uio;
1940: int a_ioflag;
1.140 elad 1941: kauth_cred_t a_cred;
1.15 christos 1942: } */ *ap = v;
1.1 mycroft 1943:
1944: /*
1945: * Set update and change flags.
1946: */
1.118 mycroft 1947: VTOI(ap->a_vp)->i_flag |= IN_MODIFY;
1.1 mycroft 1948: return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap));
1949: }
1950:
1951: /*
1952: * Close wrapper for fifo's.
1953: *
1954: * Update the times on the inode then do device close.
1955: */
1.15 christos 1956: int
1.76 lukem 1957: ufsfifo_close(void *v)
1.15 christos 1958: {
1.1 mycroft 1959: struct vop_close_args /* {
1.76 lukem 1960: struct vnode *a_vp;
1961: int a_fflag;
1.140 elad 1962: kauth_cred_t a_cred;
1.138 christos 1963: struct lwp *a_l;
1.76 lukem 1964: } */ *ap = v;
1965: struct vnode *vp;
1966: struct inode *ip;
1.1 mycroft 1967:
1.76 lukem 1968: vp = ap->a_vp;
1969: ip = VTOI(vp);
1.35 fvdl 1970: simple_lock(&vp->v_interlock);
1.133 christos 1971: if (ap->a_vp->v_usecount > 1)
1.135 yamt 1972: UFS_ITIMES(vp, NULL, NULL, NULL);
1.35 fvdl 1973: simple_unlock(&vp->v_interlock);
1.1 mycroft 1974: return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap));
1975: }
1976:
1977: /*
1978: * Return POSIX pathconf information applicable to ufs filesystems.
1979: */
1.15 christos 1980: int
1.76 lukem 1981: ufs_pathconf(void *v)
1.15 christos 1982: {
1.1 mycroft 1983: struct vop_pathconf_args /* {
1.76 lukem 1984: struct vnode *a_vp;
1985: int a_name;
1986: register_t *a_retval;
1.15 christos 1987: } */ *ap = v;
1.1 mycroft 1988:
1989: switch (ap->a_name) {
1990: case _PC_LINK_MAX:
1991: *ap->a_retval = LINK_MAX;
1992: return (0);
1993: case _PC_NAME_MAX:
1994: *ap->a_retval = NAME_MAX;
1995: return (0);
1996: case _PC_PATH_MAX:
1997: *ap->a_retval = PATH_MAX;
1998: return (0);
1999: case _PC_PIPE_BUF:
2000: *ap->a_retval = PIPE_BUF;
2001: return (0);
2002: case _PC_CHOWN_RESTRICTED:
2003: *ap->a_retval = 1;
2004: return (0);
2005: case _PC_NO_TRUNC:
1.45 kleink 2006: *ap->a_retval = 1;
2007: return (0);
2008: case _PC_SYNC_IO:
1.1 mycroft 2009: *ap->a_retval = 1;
1.56 kleink 2010: return (0);
2011: case _PC_FILESIZEBITS:
2012: *ap->a_retval = 42;
1.1 mycroft 2013: return (0);
2014: default:
2015: return (EINVAL);
2016: }
2017: /* NOTREACHED */
2018: }
2019:
2020: /*
2021: * Advisory record locking support
2022: */
2023: int
1.76 lukem 2024: ufs_advlock(void *v)
1.15 christos 2025: {
1.1 mycroft 2026: struct vop_advlock_args /* {
1.76 lukem 2027: struct vnode *a_vp;
1.152 christos 2028: void * a_id;
1.76 lukem 2029: int a_op;
2030: struct flock *a_fl;
2031: int a_flags;
1.15 christos 2032: } */ *ap = v;
1.76 lukem 2033: struct inode *ip;
1.1 mycroft 2034:
1.76 lukem 2035: ip = VTOI(ap->a_vp);
1.92 fvdl 2036: return lf_advlock(ap, &ip->i_lockf, ip->i_size);
1.1 mycroft 2037: }
2038:
2039: /*
2040: * Initialize the vnode associated with a new inode, handle aliased
2041: * vnodes.
2042: */
1.81 chs 2043: void
1.76 lukem 2044: ufs_vinit(struct mount *mntp, int (**specops)(void *), int (**fifoops)(void *),
2045: struct vnode **vpp)
1.1 mycroft 2046: {
1.141 kardel 2047: struct timeval tv;
1.76 lukem 2048: struct inode *ip;
2049: struct vnode *vp, *nvp;
1.92 fvdl 2050: dev_t rdev;
1.119 mycroft 2051: struct ufsmount *ump;
1.1 mycroft 2052:
2053: vp = *vpp;
2054: ip = VTOI(vp);
1.92 fvdl 2055: switch(vp->v_type = IFTOVT(ip->i_mode)) {
1.1 mycroft 2056: case VCHR:
2057: case VBLK:
2058: vp->v_op = specops;
1.119 mycroft 2059: ump = ip->i_ump;
2060: if (ump->um_fstype == UFS1)
1.92 fvdl 2061: rdev = (dev_t)ufs_rw32(ip->i_ffs1_rdev,
1.119 mycroft 2062: UFS_MPNEEDSWAP(ump));
1.92 fvdl 2063: else
2064: rdev = (dev_t)ufs_rw64(ip->i_ffs2_rdev,
1.119 mycroft 2065: UFS_MPNEEDSWAP(ump));
1.92 fvdl 2066: if ((nvp = checkalias(vp, rdev, mntp)) != NULL) {
1.1 mycroft 2067: /*
2068: * Discard unneeded vnode, but save its inode.
2069: */
2070: nvp->v_data = vp->v_data;
2071: vp->v_data = NULL;
1.77 fvdl 2072: /* XXX spec_vnodeops has no locking, do it explicitly */
1.156.4.1! yamt 2073: vp->v_vflag &= ~VV_LOCKSWORK;
1.77 fvdl 2074: VOP_UNLOCK(vp, 0);
1.1 mycroft 2075: vp->v_op = spec_vnodeop_p;
1.77 fvdl 2076: vrele(vp);
1.1 mycroft 2077: vgone(vp);
1.58 wrstuden 2078: lockmgr(&nvp->v_lock, LK_EXCLUSIVE, &nvp->v_interlock);
1.1 mycroft 2079: /*
2080: * Reinitialize aliased inode.
2081: */
2082: vp = nvp;
2083: ip->i_vnode = vp;
2084: }
2085: break;
2086: case VFIFO:
2087: vp->v_op = fifoops;
2088: break;
1.96 fvdl 2089: case VNON:
1.15 christos 2090: case VBAD:
2091: case VSOCK:
2092: case VLNK:
2093: case VDIR:
2094: case VREG:
2095: break;
1.1 mycroft 2096: }
2097: if (ip->i_number == ROOTINO)
1.156.4.1! yamt 2098: vp->v_vflag |= VV_ROOT;
1.1 mycroft 2099: /*
2100: * Initialize modrev times
2101: */
1.141 kardel 2102: getmicrouptime(&tv);
2103: ip->i_modrev = (uint64_t)(uint)tv.tv_sec << 32
2104: | tv.tv_usec * 4294u;
1.1 mycroft 2105: *vpp = vp;
2106: }
2107:
2108: /*
2109: * Allocate a new inode.
2110: */
2111: int
1.76 lukem 2112: ufs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
2113: struct componentname *cnp)
1.1 mycroft 2114: {
1.76 lukem 2115: struct inode *ip, *pdir;
1.116 hannken 2116: struct direct *newdir;
1.76 lukem 2117: struct vnode *tvp;
1.140 elad 2118: int error, ismember = 0;
1.1 mycroft 2119:
2120: pdir = VTOI(dvp);
2121: #ifdef DIAGNOSTIC
2122: if ((cnp->cn_flags & HASBUF) == 0)
2123: panic("ufs_makeinode: no name");
2124: #endif
2125: if ((mode & IFMT) == 0)
2126: mode |= IFREG;
2127:
1.136 yamt 2128: if ((error = UFS_VALLOC(dvp, mode, cnp->cn_cred, vpp)) != 0) {
1.73 thorpej 2129: PNBUF_PUT(cnp->cn_pnbuf);
1.1 mycroft 2130: vput(dvp);
2131: return (error);
2132: }
1.127 perseant 2133: tvp = *vpp;
1.1 mycroft 2134: ip = VTOI(tvp);
1.92 fvdl 2135: ip->i_gid = pdir->i_gid;
1.99 kristerw 2136: DIP_ASSIGN(ip, gid, ip->i_gid);
1.140 elad 2137: ip->i_uid = kauth_cred_geteuid(cnp->cn_cred);
1.99 kristerw 2138: DIP_ASSIGN(ip, uid, ip->i_uid);
1.1 mycroft 2139: #ifdef QUOTA
1.154 hannken 2140: if ((error = chkiq(ip, 1, cnp->cn_cred, 0))) {
1.136 yamt 2141: UFS_VFREE(tvp, ip->i_number, mode);
1.1 mycroft 2142: vput(tvp);
1.105 dsl 2143: PNBUF_PUT(cnp->cn_pnbuf);
1.1 mycroft 2144: vput(dvp);
2145: return (error);
2146: }
2147: #endif
2148: ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1.92 fvdl 2149: ip->i_mode = mode;
1.99 kristerw 2150: DIP_ASSIGN(ip, mode, mode);
1.1 mycroft 2151: tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */
1.59 fvdl 2152: ip->i_ffs_effnlink = 1;
1.92 fvdl 2153: ip->i_nlink = 1;
1.99 kristerw 2154: DIP_ASSIGN(ip, nlink, 1);
1.59 fvdl 2155: if (DOINGSOFTDEP(tvp))
1.62 fvdl 2156: softdep_change_linkcnt(ip);
1.140 elad 2157: if ((ip->i_mode & ISGID) && (kauth_cred_ismember_gid(cnp->cn_cred,
2158: ip->i_gid, &ismember) != 0 || !ismember) &&
2159: kauth_authorize_generic(cnp->cn_cred, KAUTH_GENERIC_ISSUSER, NULL)) {
1.92 fvdl 2160: ip->i_mode &= ~ISGID;
1.99 kristerw 2161: DIP_ASSIGN(ip, mode, ip->i_mode);
1.92 fvdl 2162: }
1.6 mycroft 2163:
1.92 fvdl 2164: if (cnp->cn_flags & ISWHITEOUT) {
2165: ip->i_flags |= UF_OPAQUE;
1.99 kristerw 2166: DIP_ASSIGN(ip, flags, ip->i_flags);
1.92 fvdl 2167: }
1.1 mycroft 2168:
2169: /*
2170: * Make sure inode goes to disk before directory entry.
2171: */
1.136 yamt 2172: if ((error = UFS_UPDATE(tvp, NULL, NULL, UPDATE_DIROP)) != 0)
1.1 mycroft 2173: goto bad;
1.116 hannken 2174: newdir = pool_get(&ufs_direct_pool, PR_WAITOK);
2175: ufs_makedirentry(ip, cnp, newdir);
2176: error = ufs_direnter(dvp, tvp, newdir, cnp, NULL);
2177: pool_put(&ufs_direct_pool, newdir);
2178: if (error)
1.1 mycroft 2179: goto bad;
2180: if ((cnp->cn_flags & SAVESTART) == 0)
1.73 thorpej 2181: PNBUF_PUT(cnp->cn_pnbuf);
1.1 mycroft 2182: vput(dvp);
2183: *vpp = tvp;
2184: return (0);
2185:
1.76 lukem 2186: bad:
1.1 mycroft 2187: /*
2188: * Write error occurred trying to update the inode
2189: * or the directory so must deallocate the inode.
2190: */
1.59 fvdl 2191: ip->i_ffs_effnlink = 0;
1.92 fvdl 2192: ip->i_nlink = 0;
1.99 kristerw 2193: DIP_ASSIGN(ip, nlink, 0);
1.1 mycroft 2194: ip->i_flag |= IN_CHANGE;
1.69 perseant 2195: #ifdef LFS
2196: /* If IN_ADIROP, account for it */
2197: lfs_unmark_vnode(tvp);
2198: #endif
1.62 fvdl 2199: if (DOINGSOFTDEP(tvp))
2200: softdep_change_linkcnt(ip);
1.105 dsl 2201: tvp->v_type = VNON; /* explodes later if VBLK */
1.1 mycroft 2202: vput(tvp);
1.105 dsl 2203: PNBUF_PUT(cnp->cn_pnbuf);
2204: vput(dvp);
1.1 mycroft 2205: return (error);
1.90 perseant 2206: }
2207:
2208: /*
2209: * Allocate len bytes at offset off.
2210: */
2211: int
2212: ufs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags,
1.140 elad 2213: kauth_cred_t cred)
1.90 perseant 2214: {
2215: struct inode *ip = VTOI(vp);
2216: int error, delta, bshift, bsize;
2217: UVMHIST_FUNC("ufs_gop_alloc"); UVMHIST_CALLED(ubchist);
2218:
2219: error = 0;
1.126 perry 2220: bshift = vp->v_mount->mnt_fs_bshift;
1.90 perseant 2221: bsize = 1 << bshift;
2222:
2223: delta = off & (bsize - 1);
2224: off -= delta;
2225: len += delta;
2226:
2227: while (len > 0) {
2228: bsize = MIN(bsize, len);
2229:
1.136 yamt 2230: error = UFS_BALLOC(vp, off, bsize, cred, flags, NULL);
1.90 perseant 2231: if (error) {
2232: goto out;
2233: }
2234:
2235: /*
1.136 yamt 2236: * increase file size now, UFS_BALLOC() requires that
1.90 perseant 2237: * EOF be up-to-date before each call.
2238: */
2239:
1.92 fvdl 2240: if (ip->i_size < off + bsize) {
1.90 perseant 2241: UVMHIST_LOG(ubchist, "vp %p old 0x%x new 0x%x",
1.93 drochner 2242: vp, ip->i_size, off + bsize, 0);
1.92 fvdl 2243: ip->i_size = off + bsize;
1.99 kristerw 2244: DIP_ASSIGN(ip, size, ip->i_size);
1.90 perseant 2245: }
2246:
2247: off += bsize;
2248: len -= bsize;
2249: }
2250:
2251: out:
2252: return error;
1.1 mycroft 2253: }
1.129 yamt 2254:
2255: void
2256: ufs_gop_markupdate(struct vnode *vp, int flags)
2257: {
2258: u_int32_t mask = 0;
2259:
2260: if ((flags & GOP_UPDATE_ACCESSED) != 0) {
2261: mask = IN_ACCESS;
2262: }
2263: if ((flags & GOP_UPDATE_MODIFIED) != 0) {
2264: if (vp->v_type == VREG) {
2265: mask |= IN_CHANGE | IN_UPDATE;
2266: } else {
2267: mask |= IN_MODIFY;
2268: }
2269: }
2270: if (mask) {
2271: struct inode *ip = VTOI(vp);
2272:
2273: ip->i_flag |= mask;
2274: }
2275: }
CVSweb <webmaster@jp.NetBSD.org>