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