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