replace ufs_iput with vput; replace ILOCK and IUNLOCK with VOP_LOCK
[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 *
8484f537 7 * @(#)ufs_vnops.c 7.111 (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;
1558 }
1559#endif
1560 (void) sleep((caddr_t)ip, PINOD);
1561 goto start;
1562 }
1563#ifdef DIAGNOSTIC
1564 ip->i_lockwaiter = 0;
1565 if (p)
1566 ip->i_lockholder = p->p_pid;
1567#endif
1568 ip->i_flag |= ILOCKED;
7188ac27
KM
1569 return (0);
1570}
1571
1c3ebc10 1572/*
8484f537 1573 * Unlock an inode. If WANT bit is on, wakeup.
1c3ebc10 1574 */
031fd966 1575int
e6e1f8be 1576ufs_unlock(ap)
69021bc5
KM
1577 struct vop_unlock_args /* {
1578 struct vnode *a_vp;
1579 } */ *ap;
7188ac27 1580{
e1b76915 1581 register struct inode *ip = VTOI(ap->a_vp);
7188ac27 1582
8484f537
KM
1583 if ((ip->i_flag & ILOCKED) == 0) {
1584 vprint("ufs_unlock: unlocked inode", ap->a_vp);
7188ac27 1585 panic("ufs_unlock NOT LOCKED");
8484f537
KM
1586 }
1587#ifdef DIAGNOSTIC
1588 ip->i_lockholder = 0;
1589#endif
1590 ip->i_flag &= ~ILOCKED;
1591 if (ip->i_flag & IWANT) {
1592 ip->i_flag &= ~IWANT;
1593 wakeup((caddr_t)ip);
1594 }
7188ac27
KM
1595 return (0);
1596}
1597
1c3ebc10
KM
1598/*
1599 * Check for a locked inode.
1600 */
031fd966 1601int
e6e1f8be 1602ufs_islocked(ap)
69021bc5
KM
1603 struct vop_islocked_args /* {
1604 struct vnode *a_vp;
1605 } */ *ap;
1c3ebc10
KM
1606{
1607
e1b76915 1608 if (VTOI(ap->a_vp)->i_flag & ILOCKED)
1c3ebc10
KM
1609 return (1);
1610 return (0);
1611}
1612
88a7a62a 1613/*
4f1ff475
KM
1614 * Calculate the logical to physical mapping if not done already,
1615 * then call the device strategy routine.
88a7a62a 1616 */
031fd966 1617int
e6e1f8be 1618ufs_strategy(ap)
69021bc5
KM
1619 struct vop_strategy_args /* {
1620 struct buf *a_bp;
1621 } */ *ap;
88a7a62a 1622{
e6e1f8be
KM
1623 register struct buf *bp = ap->a_bp;
1624 register struct vnode *vp = bp->b_vp;
031fd966 1625 register struct inode *ip;
e16fa59e
KM
1626 int error;
1627
e6e1f8be
KM
1628 ip = VTOI(vp);
1629 if (vp->v_type == VBLK || vp->v_type == VCHR)
e16fa59e 1630 panic("ufs_strategy: spec");
e6e1f8be 1631 if (bp->b_blkno == bp->b_lblkno) {
c59af027 1632 if (error =
c43604c7 1633 VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL)) {
e6e1f8be
KM
1634 bp->b_error = error;
1635 bp->b_flags |= B_ERROR;
1636 biodone(bp);
e16fa59e 1637 return (error);
dd1d1daf 1638 }
e6e1f8be
KM
1639 if ((long)bp->b_blkno == -1)
1640 clrbuf(bp);
e16fa59e 1641 }
e6e1f8be
KM
1642 if ((long)bp->b_blkno == -1) {
1643 biodone(bp);
e16fa59e 1644 return (0);
20aa076b 1645 }
e16fa59e 1646 vp = ip->i_devvp;
e6e1f8be 1647 bp->b_dev = vp->v_rdev;
ea460dfe 1648 VOCALL (vp->v_op, VOFFSET(vop_strategy), ap);
7188ac27
KM
1649 return (0);
1650}
88a7a62a 1651
e16fa59e
KM
1652/*
1653 * Print out the contents of an inode.
1654 */
031fd966 1655int
e6e1f8be 1656ufs_print(ap)
69021bc5
KM
1657 struct vop_print_args /* {
1658 struct vnode *a_vp;
1659 } */ *ap;
e16fa59e 1660{
e6e1f8be
KM
1661 register struct vnode *vp = ap->a_vp;
1662 register struct inode *ip = VTOI(vp);
e16fa59e 1663
a8f829ed
KM
1664 printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number,
1665 major(ip->i_dev), minor(ip->i_dev));
1666#ifdef FIFO
e6e1f8be
KM
1667 if (vp->v_type == VFIFO)
1668 fifo_printinfo(vp);
a8f829ed
KM
1669#endif /* FIFO */
1670 printf("%s\n", (ip->i_flag & ILOCKED) ? " (LOCKED)" : "");
4a8fb1bb 1671 if (ip->i_lockholder == 0)
031fd966 1672 return (0);
4a8fb1bb
KM
1673 printf("\towner pid %d", ip->i_lockholder);
1674 if (ip->i_lockwaiter)
1675 printf(" waiting pid %d", ip->i_lockwaiter);
96bae3e0 1676 printf("\n");
031fd966 1677 return (0);
e16fa59e
KM
1678}
1679
24a31b70
KM
1680/*
1681 * Read wrapper for special devices.
1682 */
031fd966 1683int
e6e1f8be 1684ufsspec_read(ap)
69021bc5
KM
1685 struct vop_read_args /* {
1686 struct vnode *a_vp;
1687 struct uio *a_uio;
1688 int a_ioflag;
1689 struct ucred *a_cred;
1690 } */ *ap;
24a31b70
KM
1691{
1692
1693 /*
1694 * Set access flag.
1695 */
e1b76915 1696 VTOI(ap->a_vp)->i_flag |= IACC;
ea460dfe 1697 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap));
24a31b70
KM
1698}
1699
1700/*
1701 * Write wrapper for special devices.
1702 */
031fd966 1703int
e6e1f8be 1704ufsspec_write(ap)
69021bc5
KM
1705 struct vop_write_args /* {
1706 struct vnode *a_vp;
1707 struct uio *a_uio;
1708 int a_ioflag;
1709 struct ucred *a_cred;
1710 } */ *ap;
24a31b70
KM
1711{
1712
1713 /*
1714 * Set update and change flags.
1715 */
e1b76915 1716 VTOI(ap->a_vp)->i_flag |= IUPD|ICHG;
ea460dfe 1717 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap));
24a31b70
KM
1718}
1719
1720/*
1721 * Close wrapper for special devices.
1722 *
1723 * Update the times on the inode then do device close.
1724 */
031fd966 1725int
e6e1f8be 1726ufsspec_close(ap)
69021bc5
KM
1727 struct vop_close_args /* {
1728 struct vnode *a_vp;
1729 int a_fflag;
1730 struct ucred *a_cred;
1731 struct proc *a_p;
1732 } */ *ap;
24a31b70 1733{
e1b76915 1734 register struct inode *ip = VTOI(ap->a_vp);
24a31b70 1735
e1b76915 1736 if (ap->a_vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
24a31b70 1737 ITIMES(ip, &time, &time);
ea460dfe 1738 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap));
24a31b70
KM
1739}
1740
d1c43d7f
KM
1741#ifdef FIFO
1742/*
1743 * Read wrapper for fifo's
1744 */
031fd966 1745int
e6e1f8be 1746ufsfifo_read(ap)
69021bc5
KM
1747 struct vop_read_args /* {
1748 struct vnode *a_vp;
1749 struct uio *a_uio;
1750 int a_ioflag;
1751 struct ucred *a_cred;
1752 } */ *ap;
d1c43d7f 1753{
ea460dfe 1754 extern int (**fifo_vnodeop_p)();
d1c43d7f
KM
1755
1756 /*
1757 * Set access flag.
1758 */
e1b76915 1759 VTOI(ap->a_vp)->i_flag |= IACC;
ea460dfe 1760 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap));
d1c43d7f
KM
1761}
1762
1763/*
1764 * Write wrapper for fifo's.
1765 */
031fd966 1766int
e6e1f8be 1767ufsfifo_write(ap)
69021bc5
KM
1768 struct vop_write_args /* {
1769 struct vnode *a_vp;
1770 struct uio *a_uio;
1771 int a_ioflag;
1772 struct ucred *a_cred;
1773 } */ *ap;
d1c43d7f 1774{
ea460dfe 1775 extern int (**fifo_vnodeop_p)();
d1c43d7f
KM
1776
1777 /*
1778 * Set update and change flags.
1779 */
e1b76915 1780 VTOI(ap->a_vp)->i_flag |= IUPD|ICHG;
ea460dfe 1781 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap));
d1c43d7f
KM
1782}
1783
1784/*
1785 * Close wrapper for fifo's.
1786 *
1787 * Update the times on the inode then do device close.
1788 */
e6e1f8be 1789ufsfifo_close(ap)
69021bc5
KM
1790 struct vop_close_args /* {
1791 struct vnode *a_vp;
1792 int a_fflag;
1793 struct ucred *a_cred;
1794 struct proc *a_p;
1795 } */ *ap;
d1c43d7f 1796{
ea460dfe 1797 extern int (**fifo_vnodeop_p)();
e1b76915 1798 register struct inode *ip = VTOI(ap->a_vp);
d1c43d7f 1799
e1b76915 1800 if (ap->a_vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
d1c43d7f 1801 ITIMES(ip, &time, &time);
ea460dfe 1802 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap));
d1c43d7f
KM
1803}
1804#endif /* FIFO */
1805
0b0bf936
KM
1806/*
1807 * Advisory record locking support
1808 */
031fd966 1809int
e6e1f8be 1810ufs_advlock(ap)
69021bc5
KM
1811 struct vop_advlock_args /* {
1812 struct vnode *a_vp;
1813 caddr_t a_id;
1814 int a_op;
1815 struct flock *a_fl;
1816 int a_flags;
1817 } */ *ap;
0b0bf936 1818{
e1b76915 1819 register struct inode *ip = VTOI(ap->a_vp);
e6e1f8be 1820 register struct flock *fl = ap->a_fl;
0b0bf936
KM
1821 register struct lockf *lock;
1822 off_t start, end;
1823 int error;
1824
1825 /*
1826 * Avoid the common case of unlocking when inode has no locks.
1827 */
1828 if (ip->i_lockf == (struct lockf *)0) {
e1b76915 1829 if (ap->a_op != F_SETLK) {
e6e1f8be 1830 fl->l_type = F_UNLCK;
0b0bf936
KM
1831 return (0);
1832 }
1833 }
1834 /*
1835 * Convert the flock structure into a start and end.
1836 */
e6e1f8be 1837 switch (fl->l_whence) {
0b0bf936
KM
1838
1839 case SEEK_SET:
1840 case SEEK_CUR:
1841 /*
1842 * Caller is responsible for adding any necessary offset
1843 * when SEEK_CUR is used.
1844 */
e6e1f8be 1845 start = fl->l_start;
0b0bf936
KM
1846 break;
1847
1848 case SEEK_END:
e6e1f8be 1849 start = ip->i_size + fl->l_start;
0b0bf936
KM
1850 break;
1851
1852 default:
1853 return (EINVAL);
1854 }
1855 if (start < 0)
1856 return (EINVAL);
e6e1f8be 1857 if (fl->l_len == 0)
0b0bf936
KM
1858 end = -1;
1859 else
e6e1f8be 1860 end = start + fl->l_len - 1;
0b0bf936
KM
1861 /*
1862 * Create the lockf structure
1863 */
1864 MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK);
1865 lock->lf_start = start;
1866 lock->lf_end = end;
e1b76915 1867 lock->lf_id = ap->a_id;
0b0bf936 1868 lock->lf_inode = ip;
e6e1f8be 1869 lock->lf_type = fl->l_type;
0b0bf936
KM
1870 lock->lf_next = (struct lockf *)0;
1871 lock->lf_block = (struct lockf *)0;
e1b76915 1872 lock->lf_flags = ap->a_flags;
0b0bf936
KM
1873 /*
1874 * Do the requested operation.
1875 */
e1b76915 1876 switch(ap->a_op) {
0b0bf936 1877 case F_SETLK:
b9fc1077 1878 return (lf_setlock(lock));
0b0bf936
KM
1879
1880 case F_UNLCK:
b9fc1077
KM
1881 error = lf_clearlock(lock);
1882 FREE(lock, M_LOCKF);
1883 return (error);
0b0bf936
KM
1884
1885 case F_GETLK:
e6e1f8be 1886 error = lf_getlock(lock, fl);
b9fc1077
KM
1887 FREE(lock, M_LOCKF);
1888 return (error);
0b0bf936
KM
1889
1890 default:
1891 free(lock, M_LOCKF);
1892 return (EINVAL);
1893 }
1894 /* NOTREACHED */
1895}
5b169cb7
KM
1896
1897/*
031fd966
KB
1898 * Initialize the vnode associated with a new inode, handle aliased
1899 * vnodes.
5b169cb7 1900 */
031fd966 1901int
c59af027 1902ufs_vinit(mntp, specops, fifoops, vpp)
031fd966 1903 struct mount *mntp;
1d52469b
JH
1904 int (**specops)();
1905 int (**fifoops)();
031fd966
KB
1906 struct vnode **vpp;
1907{
cda1e3e8 1908 struct inode *ip;
031fd966
KB
1909 struct vnode *vp, *nvp;
1910
1911 vp = *vpp;
1912 ip = VTOI(vp);
1913 switch(vp->v_type = IFTOVT(ip->i_mode)) {
1914 case VCHR:
1915 case VBLK:
c59af027 1916 vp->v_op = specops;
031fd966 1917 if (nvp = checkalias(vp, ip->i_rdev, mntp)) {
c59af027 1918 /*
4a8fb1bb 1919 * Discard unneeded vnode, but save its inode.
c59af027 1920 */
cda1e3e8 1921 ufs_ihashrem(ip);
8484f537 1922 VOP_UNLOCK(vp);
4a8fb1bb
KM
1923 nvp->v_data = vp->v_data;
1924 vp->v_data = NULL;
9342689a 1925 vp->v_op = spec_vnodeop_p;
4a8fb1bb
KM
1926 vrele(vp);
1927 vgone(vp);
c59af027 1928 /*
4a8fb1bb 1929 * Reinitialize aliased inode.
c59af027 1930 */
4a8fb1bb
KM
1931 vp = nvp;
1932 ip->i_vnode = vp;
1933 ufs_ihashins(ip);
031fd966
KB
1934 }
1935 break;
1936 case VFIFO:
1937#ifdef FIFO
c59af027 1938 vp->v_op = fifoops;
031fd966
KB
1939 break;
1940#else
1941 return (EOPNOTSUPP);
1942#endif
1943 }
031fd966
KB
1944 if (ip->i_number == ROOTINO)
1945 vp->v_flag |= VROOT;
1a3cb193
KM
1946 /*
1947 * Initialize modrev times
1948 */
1949 SETHIGH(ip->i_modrev, mono_time.tv_sec);
1950 SETLOW(ip->i_modrev, mono_time.tv_usec * 4294);
031fd966
KB
1951 *vpp = vp;
1952 return (0);
1953}
5b169cb7 1954
031fd966
KB
1955/*
1956 * Allocate a new inode.
1957 */
1958int
6e57e9ff 1959ufs_makeinode(mode, dvp, vpp, cnp)
031fd966 1960 int mode;
cfef4373 1961 struct vnode *dvp;
c59af027 1962 struct vnode **vpp;
cfef4373 1963 struct componentname *cnp;
031fd966
KB
1964{
1965 register struct inode *ip, *pdir;
fa4f99ac 1966 struct timeval tv;
c59af027 1967 struct vnode *tvp;
031fd966
KB
1968 int error;
1969
cfef4373 1970 pdir = VTOI(dvp);
38285224 1971#ifdef DIAGNOSTIC
cfef4373 1972 if ((cnp->cn_flags & HASBUF) == 0)
031fd966
KB
1973 panic("ufs_makeinode: no name");
1974#endif
c59af027 1975 *vpp = NULL;
031fd966
KB
1976 if ((mode & IFMT) == 0)
1977 mode |= IFREG;
1978
cfef4373
JH
1979 if (error = VOP_VALLOC(dvp, mode, cnp->cn_cred, &tvp)) {
1980 free(cnp->cn_pnbuf, M_NAMEI);
8484f537 1981 vput(dvp);
031fd966
KB
1982 return (error);
1983 }
c59af027 1984 ip = VTOI(tvp);
cfef4373 1985 ip->i_uid = cnp->cn_cred->cr_uid;
031fd966
KB
1986 ip->i_gid = pdir->i_gid;
1987#ifdef QUOTA
1988 if ((error = getinoquota(ip)) ||
cfef4373
JH
1989 (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
1990 free(cnp->cn_pnbuf, M_NAMEI);
c59af027 1991 VOP_VFREE(tvp, ip->i_number, mode);
8484f537
KM
1992 vput(tvp);
1993 vput(dvp);
031fd966
KB
1994 return (error);
1995 }
1996#endif
1997 ip->i_flag |= IACC|IUPD|ICHG;
1998 ip->i_mode = mode;
c59af027 1999 tvp->v_type = IFTOVT(mode); /* Rest init'd in iget() */
031fd966 2000 ip->i_nlink = 1;
cfef4373
JH
2001 if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) &&
2002 suser(cnp->cn_cred, NULL))
031fd966
KB
2003 ip->i_mode &= ~ISGID;
2004
2005 /*
2006 * Make sure inode goes to disk before directory entry.
2007 */
fa4f99ac
CT
2008 tv = time;
2009 if (error = VOP_UPDATE(tvp, &tv, &tv, 1))
031fd966 2010 goto bad;
cfef4373 2011 if (error = ufs_direnter(ip, dvp, cnp))
031fd966 2012 goto bad;
cfef4373
JH
2013 if ((cnp->cn_flags & SAVESTART) == 0)
2014 FREE(cnp->cn_pnbuf, M_NAMEI);
8484f537 2015 vput(dvp);
c59af027 2016 *vpp = tvp;
031fd966
KB
2017 return (0);
2018
2019bad:
2020 /*
2021 * Write error occurred trying to update the inode
2022 * or the directory so must deallocate the inode.
2023 */
cfef4373 2024 free(cnp->cn_pnbuf, M_NAMEI);
8484f537 2025 vput(dvp);
031fd966
KB
2026 ip->i_nlink = 0;
2027 ip->i_flag |= ICHG;
8484f537 2028 vput(tvp);
031fd966
KB
2029 return (error);
2030}