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