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