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