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