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