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