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