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