new location for specdev.h include
[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 *
ebe49688 7 * @(#)ufs_vnops.c 7.103 (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 }
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{
e6e1f8be
KM
280 register struct vattr *vap = ap->a_vap;
281 register struct vnode *vp = ap->a_vp;
282 register struct inode *ip = VTOI(vp);
283 register struct ucred *cred = ap->a_cred;
284 register struct proc *p = ap->a_p;
7e11a0c9 285 struct timeval atimeval, mtimeval;
031fd966 286 int error;
b4d1aee9 287
7188ac27 288 /*
031fd966 289 * Check for unsettable attributes.
7188ac27 290 */
e6e1f8be
KM
291 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
292 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
293 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
294 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
7188ac27 295 return (EINVAL);
b4d1aee9 296 }
7188ac27
KM
297 /*
298 * Go through the fields and update iff not VNOVAL.
299 */
e6e1f8be
KM
300 if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL)
301 if (error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, p))
7188ac27 302 return (error);
e6e1f8be
KM
303 if (vap->va_size != VNOVAL) {
304 if (vp->v_type == VDIR)
7188ac27 305 return (EISDIR);
69021bc5 306 if (error = VOP_TRUNCATE(vp, vap->va_size, 0, cred, p))
7188ac27 307 return (error);
3e78e260 308 }
e6e1f8be 309 ip = VTOI(vp);
7e11a0c9 310 if (vap->va_atime.ts_sec != VNOVAL || vap->va_mtime.ts_sec != VNOVAL) {
e6e1f8be
KM
311 if (cred->cr_uid != ip->i_uid &&
312 (error = suser(cred, &p->p_acflag)))
de412887 313 return (error);
7e11a0c9 314 if (vap->va_atime.ts_sec != VNOVAL)
7188ac27 315 ip->i_flag |= IACC;
7e11a0c9 316 if (vap->va_mtime.ts_sec != VNOVAL)
7188ac27
KM
317 ip->i_flag |= IUPD;
318 ip->i_flag |= ICHG;
7e11a0c9
KM
319 atimeval.tv_sec = vap->va_atime.ts_sec;
320 atimeval.tv_usec = vap->va_atime.ts_nsec / 1000;
321 mtimeval.tv_sec = vap->va_mtime.ts_sec;
322 mtimeval.tv_usec = vap->va_mtime.ts_nsec / 1000;
323 if (error = VOP_UPDATE(vp, &atimeval, &mtimeval, 1))
7188ac27 324 return (error);
5485e062 325 }
031fd966 326 error = 0;
e6e1f8be
KM
327 if (vap->va_mode != (mode_t)VNOVAL)
328 error = ufs_chmod(vp, (int)vap->va_mode, cred, p);
329 if (vap->va_flags != VNOVAL) {
330 if (cred->cr_uid != ip->i_uid &&
331 (error = suser(cred, &p->p_acflag)))
d07fc92a 332 return (error);
e6e1f8be
KM
333 if (cred->cr_uid == 0) {
334 ip->i_flags = vap->va_flags;
d07fc92a
KM
335 } else {
336 ip->i_flags &= 0xffff0000;
e6e1f8be 337 ip->i_flags |= (vap->va_flags & 0xffff);
d07fc92a
KM
338 }
339 ip->i_flag |= ICHG;
340 }
7188ac27 341 return (error);
528f664c
SL
342}
343
4f083fd7
SL
344/*
345 * Change the mode on a file.
346 * Inode must be locked before calling.
347 */
ca3e8b68 348static int
8e232de3 349ufs_chmod(vp, mode, cred, p)
7188ac27 350 register struct vnode *vp;
528f664c 351 register int mode;
8e232de3 352 register struct ucred *cred;
c6f5111d 353 struct proc *p;
528f664c 354{
7188ac27 355 register struct inode *ip = VTOI(vp);
de412887 356 int error;
197da11b 357
de412887 358 if (cred->cr_uid != ip->i_uid &&
c6f5111d 359 (error = suser(cred, &p->p_acflag)))
de412887 360 return (error);
7188ac27 361 if (cred->cr_uid) {
e57b6138 362 if (vp->v_type != VDIR && (mode & ISVTX))
39b5be4c 363 return (EFTYPE);
e57b6138 364 if (!groupmember(ip->i_gid, cred) && (mode & ISGID))
39b5be4c 365 return (EPERM);
f94ceb3b 366 }
39b5be4c 367 ip->i_mode &= ~07777;
7188ac27 368 ip->i_mode |= mode & 07777;
3e78e260 369 ip->i_flag |= ICHG;
7188ac27 370 if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0)
8986c97c 371 (void) vnode_pager_uncache(vp);
47af7174 372 return (0);
5485e062
BJ
373}
374
528f664c
SL
375/*
376 * Perform chown operation on inode ip;
377 * inode must be locked prior to call.
378 */
ca3e8b68 379static int
8e232de3 380ufs_chown(vp, uid, gid, cred, p)
7188ac27 381 register struct vnode *vp;
38285224
KM
382 uid_t uid;
383 gid_t gid;
8e232de3 384 struct ucred *cred;
c6f5111d 385 struct proc *p;
528f664c 386{
7188ac27 387 register struct inode *ip = VTOI(vp);
4b61628b
KM
388 uid_t ouid;
389 gid_t ogid;
390 int error = 0;
528f664c 391#ifdef QUOTA
4b61628b
KM
392 register int i;
393 long change;
bb1b75f4 394#endif
528f664c 395
38285224 396 if (uid == (uid_t)VNOVAL)
bb1b75f4 397 uid = ip->i_uid;
38285224 398 if (gid == (gid_t)VNOVAL)
bb1b75f4 399 gid = ip->i_gid;
18b0bce6
KB
400 /*
401 * If we don't own the file, are trying to change the owner
402 * of the file, or are not a member of the target group,
403 * the caller must be superuser or the call fails.
404 */
7188ac27
KM
405 if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid ||
406 !groupmember((gid_t)gid, cred)) &&
c6f5111d 407 (error = suser(cred, &p->p_acflag)))
7188ac27 408 return (error);
4b61628b
KM
409 ouid = ip->i_uid;
410 ogid = ip->i_gid;
bb1b75f4 411#ifdef QUOTA
4b61628b
KM
412 if (error = getinoquota(ip))
413 return (error);
414 if (ouid == uid) {
415 dqrele(vp, ip->i_dquot[USRQUOTA]);
416 ip->i_dquot[USRQUOTA] = NODQUOT;
417 }
418 if (ogid == gid) {
419 dqrele(vp, ip->i_dquot[GRPQUOTA]);
420 ip->i_dquot[GRPQUOTA] = NODQUOT;
421 }
422 change = ip->i_blocks;
423 (void) chkdq(ip, -change, cred, CHOWN);
424 (void) chkiq(ip, -1, cred, CHOWN);
425 for (i = 0; i < MAXQUOTAS; i++) {
426 dqrele(vp, ip->i_dquot[i]);
427 ip->i_dquot[i] = NODQUOT;
428 }
f94ceb3b 429#endif
bb1b75f4
SL
430 ip->i_uid = uid;
431 ip->i_gid = gid;
528f664c 432#ifdef QUOTA
4b61628b
KM
433 if ((error = getinoquota(ip)) == 0) {
434 if (ouid == uid) {
435 dqrele(vp, ip->i_dquot[USRQUOTA]);
436 ip->i_dquot[USRQUOTA] = NODQUOT;
437 }
438 if (ogid == gid) {
439 dqrele(vp, ip->i_dquot[GRPQUOTA]);
440 ip->i_dquot[GRPQUOTA] = NODQUOT;
441 }
442 if ((error = chkdq(ip, change, cred, CHOWN)) == 0) {
443 if ((error = chkiq(ip, 1, cred, CHOWN)) == 0)
722a9b31 444 goto good;
4b61628b
KM
445 else
446 (void) chkdq(ip, -change, cred, CHOWN|FORCE);
447 }
448 for (i = 0; i < MAXQUOTAS; i++) {
449 dqrele(vp, ip->i_dquot[i]);
450 ip->i_dquot[i] = NODQUOT;
451 }
452 }
453 ip->i_uid = ouid;
454 ip->i_gid = ogid;
455 if (getinoquota(ip) == 0) {
456 if (ouid == uid) {
457 dqrele(vp, ip->i_dquot[USRQUOTA]);
458 ip->i_dquot[USRQUOTA] = NODQUOT;
459 }
460 if (ogid == gid) {
461 dqrele(vp, ip->i_dquot[GRPQUOTA]);
462 ip->i_dquot[GRPQUOTA] = NODQUOT;
463 }
722a9b31
KM
464 (void) chkdq(ip, change, cred, FORCE|CHOWN);
465 (void) chkiq(ip, 1, cred, FORCE|CHOWN);
6cb69bbe 466 (void) getinoquota(ip);
4b61628b 467 }
6cb69bbe 468 return (error);
722a9b31 469good:
6cb69bbe
KM
470 if (getinoquota(ip))
471 panic("chown: lost quota");
472#endif /* QUOTA */
4b61628b
KM
473 if (ouid != uid || ogid != gid)
474 ip->i_flag |= ICHG;
475 if (ouid != uid && cred->cr_uid != 0)
476 ip->i_mode &= ~ISUID;
477 if (ogid != gid && cred->cr_uid != 0)
478 ip->i_mode &= ~ISGID;
479 return (0);
d67a03eb
BJ
480}
481
7188ac27 482/* ARGSUSED */
031fd966 483int
e6e1f8be 484ufs_ioctl(ap)
69021bc5
KM
485 struct vop_ioctl_args /* {
486 struct vnode *a_vp;
487 int a_command;
488 caddr_t a_data;
489 int a_fflag;
490 struct ucred *a_cred;
491 struct proc *a_p;
492 } */ *ap;
bb1b75f4 493{
bb1b75f4 494
7188ac27
KM
495 return (ENOTTY);
496}
497
498/* ARGSUSED */
031fd966 499int
e6e1f8be 500ufs_select(ap)
69021bc5
KM
501 struct vop_select_args /* {
502 struct vnode *a_vp;
503 int a_which;
504 int a_fflags;
505 struct ucred *a_cred;
506 struct proc *a_p;
507 } */ *ap;
7188ac27
KM
508{
509
5b169cb7
KM
510 /*
511 * We should really check to see if I/O is possible.
512 */
513 return (1);
bb1b75f4 514}
d67a03eb 515
4f083fd7 516/*
7188ac27
KM
517 * Mmap a file
518 *
519 * NB Currently unsupported.
4f083fd7 520 */
7188ac27 521/* ARGSUSED */
031fd966 522int
e6e1f8be 523ufs_mmap(ap)
69021bc5
KM
524 struct vop_mmap_args /* {
525 struct vnode *a_vp;
526 int a_fflags;
527 struct ucred *a_cred;
528 struct proc *a_p;
529 } */ *ap;
d67a03eb 530{
d67a03eb 531
7188ac27 532 return (EINVAL);
d67a03eb 533}
64d3a787 534
4f083fd7 535/*
7188ac27
KM
536 * Seek on a file
537 *
538 * Nothing to do, so just return.
4f083fd7 539 */
7188ac27 540/* ARGSUSED */
031fd966 541int
e6e1f8be 542ufs_seek(ap)
69021bc5
KM
543 struct vop_seek_args /* {
544 struct vnode *a_vp;
545 off_t a_oldoff;
546 off_t a_newoff;
547 struct ucred *a_cred;
548 } */ *ap;
528f664c 549{
7188ac27
KM
550
551 return (0);
552}
553
554/*
555 * ufs remove
556 * Hard to avoid races here, especially
557 * in unlinking directories.
558 */
031fd966 559int
e6e1f8be 560ufs_remove(ap)
69021bc5
KM
561 struct vop_remove_args /* {
562 struct vnode *a_dvp;
563 struct vnode *a_vp;
564 struct componentname *a_cnp;
565 } */ *ap;
7188ac27
KM
566{
567 register struct inode *ip, *dp;
568 int error;
569
e1b76915
JH
570 ip = VTOI(ap->a_vp);
571 dp = VTOI(ap->a_dvp);
572 error = ufs_dirremove(ap->a_dvp, ap->a_cnp);
7188ac27
KM
573 if (!error) {
574 ip->i_nlink--;
575 ip->i_flag |= ICHG;
528f664c 576 }
7188ac27
KM
577 if (dp == ip)
578 vrele(ITOV(ip));
579 else
031fd966
KB
580 ufs_iput(ip);
581 ufs_iput(dp);
7188ac27 582 return (error);
4f083fd7
SL
583}
584
585/*
7188ac27 586 * link vnode call
4f083fd7 587 */
031fd966 588int
e6e1f8be 589ufs_link(ap)
69021bc5
KM
590 struct vop_link_args /* {
591 struct vnode *a_vp;
592 struct vnode *a_tdvp;
593 struct componentname *a_cnp;
594 } */ *ap;
4f083fd7 595{
e6e1f8be
KM
596 register struct vnode *vp = ap->a_vp;
597 register struct vnode *tdvp = ap->a_tdvp;
598 register struct componentname *cnp = ap->a_cnp;
031fd966 599 register struct inode *ip;
fa4f99ac 600 struct timeval tv;
7188ac27 601 int error;
4f083fd7 602
e6e1f8be
KM
603 if (vp->v_mount != tdvp->v_mount) {
604 VOP_ABORTOP(vp, cnp);
605 if (tdvp == vp)
606 vrele(vp);
3330c9fe 607 else
e6e1f8be 608 vput(vp);
3330c9fe
JSP
609 return (EXDEV);
610 }
611
38285224 612#ifdef DIAGNOSTIC
e6e1f8be 613 if ((cnp->cn_flags & HASBUF) == 0)
655da945
KM
614 panic("ufs_link: no name");
615#endif
e6e1f8be 616 ip = VTOI(tdvp);
38285224 617 if ((nlink_t)ip->i_nlink >= LINK_MAX) {
e6e1f8be 618 free(cnp->cn_pnbuf, M_NAMEI);
986aedaa 619 return (EMLINK);
655da945 620 }
e6e1f8be 621 if (vp != tdvp)
7188ac27 622 ILOCK(ip);
7188ac27
KM
623 ip->i_nlink++;
624 ip->i_flag |= ICHG;
fa4f99ac
CT
625 tv = time;
626 error = VOP_UPDATE(tdvp, &tv, &tv, 1);
7188ac27 627 if (!error)
e6e1f8be
KM
628 error = ufs_direnter(ip, vp, cnp);
629 if (vp != tdvp)
7188ac27 630 IUNLOCK(ip);
e6e1f8be
KM
631 FREE(cnp->cn_pnbuf, M_NAMEI);
632 vput(vp);
7188ac27
KM
633 if (error) {
634 ip->i_nlink--;
82252d2b 635 ip->i_flag |= ICHG;
7188ac27
KM
636 }
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
3330c9fe 845 /* Check for cross-device rename */
e6e1f8be
KM
846 if ((fvp->v_mount != tdvp->v_mount) ||
847 (tvp && (fvp->v_mount != tvp->v_mount))) {
848 VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
849 if (tdvp == tvp)
850 vrele(tdvp);
3330c9fe 851 else
e6e1f8be
KM
852 vput(tdvp);
853 if (tvp)
854 vput(tvp);
855 VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
856 vrele(fdvp);
857 vrele(fvp);
3330c9fe
JSP
858 return (EXDEV);
859 }
860
38285224 861#ifdef DIAGNOSTIC
e6e1f8be
KM
862 if ((tcnp->cn_flags & HASBUF) == 0 ||
863 (fcnp->cn_flags & HASBUF) == 0)
655da945
KM
864 panic("ufs_rename: no name");
865#endif
e6e1f8be
KM
866 dp = VTOI(fdvp);
867 ip = VTOI(fvp);
655da945
KM
868 /*
869 * Check if just deleting a link name.
870 */
e6e1f8be
KM
871 if (fvp == tvp) {
872 VOP_ABORTOP(tdvp, tcnp);
873 vput(tdvp);
874 vput(tvp);
875 vrele(fdvp);
655da945 876 if ((ip->i_mode&IFMT) == IFDIR) {
e6e1f8be
KM
877 VOP_ABORTOP(fdvp, fcnp);
878 vrele(fvp);
655da945
KM
879 return (EINVAL);
880 }
881 doingdirectory = 0;
882 goto unlinkit;
883 }
7188ac27 884 ILOCK(ip);
4f083fd7 885 if ((ip->i_mode&IFMT) == IFDIR) {
4f083fd7 886 /*
046f18d1 887 * Avoid ".", "..", and aliases of "." for obvious reasons.
4f083fd7 888 */
e6e1f8be
KM
889 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
890 dp == ip || (fcnp->cn_flags&ISDOTDOT) ||
891 (ip->i_flag & IRENAME)) {
892 VOP_ABORTOP(tdvp, tcnp);
893 vput(tdvp);
894 if (tvp)
895 vput(tvp);
896 VOP_ABORTOP(fdvp, fcnp);
897 vrele(fdvp);
898 vput(fvp);
7188ac27 899 return (EINVAL);
4f083fd7 900 }
68f21562 901 ip->i_flag |= IRENAME;
4f083fd7
SL
902 oldparent = dp->i_number;
903 doingdirectory++;
904 }
e6e1f8be 905 vrele(fdvp);
4f083fd7
SL
906
907 /*
908 * 1) Bump link count while we're moving stuff
909 * around. If we crash somewhere before
910 * completing our work, the link count
911 * may be wrong, but correctable.
912 */
913 ip->i_nlink++;
914 ip->i_flag |= ICHG;
fa4f99ac
CT
915 tv = time;
916 error = VOP_UPDATE(fvp, &tv, &tv, 1);
a388503d 917 IUNLOCK(ip);
4f083fd7
SL
918
919 /*
920 * When the target exists, both the directory
7188ac27 921 * and target vnodes are returned locked.
4f083fd7 922 */
e6e1f8be 923 dp = VTOI(tdvp);
7188ac27 924 xp = NULL;
e6e1f8be
KM
925 if (tvp)
926 xp = VTOI(tvp);
046f18d1
SL
927 /*
928 * If ".." must be changed (ie the directory gets a new
81552f0f
KM
929 * parent) then the source directory must not be in the
930 * directory heirarchy above the target, as this would
931 * orphan everything below the source directory. Also
932 * the user must have write permission in the source so
933 * as to be able to change "..". We must repeat the call
934 * to namei, as the parent directory is unlocked by the
935 * call to checkpath().
046f18d1 936 */
68f21562
KM
937 if (oldparent != dp->i_number)
938 newparent = dp->i_number;
939 if (doingdirectory && newparent) {
e6e1f8be
KM
940 VOP_LOCK(fvp);
941 error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
942 VOP_UNLOCK(fvp);
48c3b6e8 943 if (error)
81552f0f 944 goto bad;
655da945 945 if (xp != NULL)
031fd966 946 ufs_iput(xp);
e6e1f8be 947 if (error = ufs_checkpath(ip, dp, tcnp->cn_cred))
655da945 948 goto out;
e6e1f8be 949 if ((tcnp->cn_flags & SAVESTART) == 0)
655da945 950 panic("ufs_rename: lost to startdir");
5e03b55d 951 p->p_spare[1]--;
e6e1f8be 952 if (error = relookup(tdvp, &tvp, tcnp))
655da945 953 goto out;
e6e1f8be 954 dp = VTOI(tdvp);
655da945 955 xp = NULL;
e6e1f8be
KM
956 if (tvp)
957 xp = VTOI(tvp);
81552f0f 958 }
4f083fd7
SL
959 /*
960 * 2) If target doesn't exist, link the target
961 * to the source and unlink the source.
962 * Otherwise, rewrite the target directory
963 * entry to reference the source inode and
964 * expunge the original entry's existence.
965 */
4f083fd7 966 if (xp == NULL) {
7188ac27
KM
967 if (dp->i_dev != ip->i_dev)
968 panic("rename: EXDEV");
4f083fd7 969 /*
68f21562
KM
970 * Account for ".." in new directory.
971 * When source and destination have the same
972 * parent we don't fool with the link count.
4f083fd7 973 */
68f21562 974 if (doingdirectory && newparent) {
38285224 975 if ((nlink_t)dp->i_nlink >= LINK_MAX) {
986aedaa
KM
976 error = EMLINK;
977 goto bad;
978 }
4f083fd7
SL
979 dp->i_nlink++;
980 dp->i_flag |= ICHG;
fa4f99ac 981 if (error = VOP_UPDATE(ITOV(dp), &tv, &tv, 1))
986aedaa 982 goto bad;
4f083fd7 983 }
e6e1f8be 984 if (error = ufs_direnter(ip, tdvp, tcnp)) {
394d67a8
KM
985 if (doingdirectory && newparent) {
986 dp->i_nlink--;
987 dp->i_flag |= ICHG;
fa4f99ac 988 (void)VOP_UPDATE(ITOV(dp), &tv, &tv, 1);
394d67a8
KM
989 }
990 goto bad;
991 }
031fd966 992 ufs_iput(dp);
4f083fd7 993 } else {
7188ac27
KM
994 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
995 panic("rename: EXDEV");
e69c3c9c
SL
996 /*
997 * Short circuit rename(foo, foo).
998 */
999 if (xp->i_number == ip->i_number)
7188ac27 1000 panic("rename: same file");
80cee150
JB
1001 /*
1002 * If the parent directory is "sticky", then the user must
1003 * own the parent directory, or the destination of the rename,
1004 * otherwise the destination may not be changed (except by
1005 * root). This implements append-only directories.
1006 */
e6e1f8be
KM
1007 if ((dp->i_mode & ISVTX) && tcnp->cn_cred->cr_uid != 0 &&
1008 tcnp->cn_cred->cr_uid != dp->i_uid &&
1009 xp->i_uid != tcnp->cn_cred->cr_uid) {
80cee150
JB
1010 error = EPERM;
1011 goto bad;
1012 }
4f083fd7 1013 /*
655da945
KM
1014 * Target must be empty if a directory and have no links
1015 * to it. Also, ensure source and target are compatible
1016 * (both directories, or both not directories).
4f083fd7
SL
1017 */
1018 if ((xp->i_mode&IFMT) == IFDIR) {
e6e1f8be 1019 if (!ufs_dirempty(xp, dp->i_number, tcnp->cn_cred) ||
7188ac27 1020 xp->i_nlink > 2) {
a5390dce 1021 error = ENOTEMPTY;
4f083fd7
SL
1022 goto bad;
1023 }
1024 if (!doingdirectory) {
a5390dce 1025 error = ENOTDIR;
4f083fd7
SL
1026 goto bad;
1027 }
7188ac27 1028 cache_purge(ITOV(dp));
4f083fd7 1029 } else if (doingdirectory) {
a5390dce 1030 error = EISDIR;
4f083fd7
SL
1031 goto bad;
1032 }
e6e1f8be 1033 if (error = ufs_dirrewrite(dp, ip, tcnp))
7188ac27 1034 goto bad;
a62786b9
KM
1035 /*
1036 * If the target directory is in the same
1037 * directory as the source directory,
1038 * decrement the link count on the parent
1039 * of the target directory.
1040 */
1041 if (doingdirectory && !newparent) {
1042 dp->i_nlink--;
1043 dp->i_flag |= ICHG;
1044 }
c59af027 1045 ufs_iput(dp);
4f083fd7 1046 /*
a5390dce
SL
1047 * Adjust the link count of the target to
1048 * reflect the dirrewrite above. If this is
1049 * a directory it is empty and there are
1050 * no links to it, so we can squash the inode and
1051 * any space associated with it. We disallowed
1052 * renaming over top of a directory with links to
68f21562
KM
1053 * it above, as the remaining link would point to
1054 * a directory without "." or ".." entries.
4f083fd7 1055 */
a5390dce 1056 xp->i_nlink--;
4f083fd7 1057 if (doingdirectory) {
a5390dce
SL
1058 if (--xp->i_nlink != 0)
1059 panic("rename: linked directory");
422c9c21 1060 error = VOP_TRUNCATE(ITOV(xp), (off_t)0, IO_SYNC,
69021bc5 1061 tcnp->cn_cred, tcnp->cn_proc);
a5390dce 1062 }
4f083fd7 1063 xp->i_flag |= ICHG;
031fd966 1064 ufs_iput(xp);
31db12cb 1065 xp = NULL;
4f083fd7
SL
1066 }
1067
1068 /*
1069 * 3) Unlink the source.
1070 */
655da945 1071unlinkit:
e6e1f8be
KM
1072 fcnp->cn_flags &= ~MODMASK;
1073 fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
1074 if ((fcnp->cn_flags & SAVESTART) == 0)
655da945 1075 panic("ufs_rename: lost from startdir");
5e03b55d 1076 p->p_spare[1]--;
e6e1f8be
KM
1077 (void) relookup(fdvp, &fvp, fcnp);
1078 if (fvp != NULL) {
1079 xp = VTOI(fvp);
1080 dp = VTOI(fdvp);
7188ac27 1081 } else {
d9d75b8f
KM
1082 /*
1083 * From name has disappeared.
1084 */
1085 if (doingdirectory)
1086 panic("rename: lost dir entry");
1087 vrele(ITOV(ip));
1088 return (0);
7188ac27 1089 }
4f083fd7 1090 /*
7188ac27 1091 * Ensure that the directory entry still exists and has not
68f21562
KM
1092 * changed while the new name has been entered. If the source is
1093 * a file then the entry may have been unlinked or renamed. In
1094 * either case there is no further work to be done. If the source
1095 * is a directory then it cannot have been rmdir'ed; its link
1096 * count of three would cause a rmdir to fail with ENOTEMPTY.
7188ac27 1097 * The IRENAME flag ensures that it cannot be moved by another
68f21562 1098 * rename.
4f083fd7 1099 */
4f1a9037 1100 if (xp != ip) {
68f21562 1101 if (doingdirectory)
4f1a9037 1102 panic("rename: lost dir entry");
68f21562 1103 } else {
4f083fd7 1104 /*
68f21562
KM
1105 * If the source is a directory with a
1106 * new parent, the link count of the old
1107 * parent directory must be decremented
1108 * and ".." set to point to the new parent.
4f083fd7 1109 */
68f21562 1110 if (doingdirectory && newparent) {
4f083fd7
SL
1111 dp->i_nlink--;
1112 dp->i_flag |= ICHG;
86cdabf6 1113 error = vn_rdwr(UIO_READ, ITOV(xp), (caddr_t)&dirbuf,
7188ac27 1114 sizeof (struct dirtemplate), (off_t)0,
86cdabf6 1115 UIO_SYSSPACE, IO_NODELOCKED,
e6e1f8be 1116 tcnp->cn_cred, (int *)0, (struct proc *)0);
68f21562 1117 if (error == 0) {
86fb5449
KM
1118# if (BYTE_ORDER == LITTLE_ENDIAN)
1119 if (fvp->v_mount->mnt_maxsymlinklen <= 0)
1120 namlen = dirbuf.dotdot_type;
1121 else
1122 namlen = dirbuf.dotdot_namlen;
1123# else
1124 namlen = dirbuf.dotdot_namlen;
1125# endif
1126 if (namlen != 2 ||
68f21562
KM
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 = {
86fb5449
KM
1173 0, 12, DT_DIR, 1, ".",
1174 0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
1175};
1176static struct odirtemplate omastertemplate = {
88a7a62a
SL
1177 0, 12, 1, ".",
1178 0, DIRBLKSIZ - 12, 2, ".."
1179};
1180
1181/*
1182 * Mkdir system call
1183 */
031fd966 1184int
e6e1f8be 1185ufs_mkdir(ap)
69021bc5
KM
1186 struct vop_mkdir_args /* {
1187 struct vnode *a_dvp;
1188 struct vnode **a_vpp;
1189 struct componentname *a_cnp;
1190 struct vattr *a_vap;
1191 } */ *ap;
88a7a62a 1192{
e6e1f8be
KM
1193 register struct vnode *dvp = ap->a_dvp;
1194 register struct vattr *vap = ap->a_vap;
1195 register struct componentname *cnp = ap->a_cnp;
88a7a62a 1196 register struct inode *ip, *dp;
c59af027 1197 struct vnode *tvp;
86fb5449 1198 struct dirtemplate dirtemplate, *dtp;
fa4f99ac
CT
1199 struct timeval tv;
1200 int error, dmode;
7188ac27 1201
38285224 1202#ifdef DIAGNOSTIC
e6e1f8be 1203 if ((cnp->cn_flags & HASBUF) == 0)
655da945
KM
1204 panic("ufs_mkdir: no name");
1205#endif
e6e1f8be 1206 dp = VTOI(dvp);
38285224 1207 if ((nlink_t)dp->i_nlink >= LINK_MAX) {
e6e1f8be 1208 free(cnp->cn_pnbuf, M_NAMEI);
031fd966 1209 ufs_iput(dp);
986aedaa
KM
1210 return (EMLINK);
1211 }
e6e1f8be 1212 dmode = vap->va_mode&0777;
7188ac27 1213 dmode |= IFDIR;
88a7a62a 1214 /*
655da945
KM
1215 * Must simulate part of maknode here to acquire the inode, but
1216 * not have it entered in the parent directory. The entry is made
1217 * later after writing "." and ".." entries.
88a7a62a 1218 */
e6e1f8be
KM
1219 if (error = VOP_VALLOC(dvp, dmode, cnp->cn_cred, &tvp)) {
1220 free(cnp->cn_pnbuf, M_NAMEI);
031fd966 1221 ufs_iput(dp);
7188ac27 1222 return (error);
88a7a62a 1223 }
c59af027 1224 ip = VTOI(tvp);
e6e1f8be 1225 ip->i_uid = cnp->cn_cred->cr_uid;
4b61628b 1226 ip->i_gid = dp->i_gid;
88a7a62a 1227#ifdef QUOTA
4b61628b 1228 if ((error = getinoquota(ip)) ||
e6e1f8be
KM
1229 (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
1230 free(cnp->cn_pnbuf, M_NAMEI);
c59af027 1231 VOP_VFREE(tvp, ip->i_number, dmode);
031fd966
KB
1232 ufs_iput(ip);
1233 ufs_iput(dp);
4b61628b
KM
1234 return (error);
1235 }
88a7a62a
SL
1236#endif
1237 ip->i_flag |= IACC|IUPD|ICHG;
7188ac27
KM
1238 ip->i_mode = dmode;
1239 ITOV(ip)->v_type = VDIR; /* Rest init'd in iget() */
88a7a62a 1240 ip->i_nlink = 2;
fa4f99ac
CT
1241 tv = time;
1242 error = VOP_UPDATE(ITOV(ip), &tv, &tv, 1);
88a7a62a
SL
1243
1244 /*
1245 * Bump link count in parent directory
1246 * to reflect work done below. Should
1247 * be done before reference is created
1248 * so reparation is possible if we crash.
1249 */
1250 dp->i_nlink++;
1251 dp->i_flag |= ICHG;
fa4f99ac 1252 if (error = VOP_UPDATE(ITOV(dp), &tv, &tv, 1))
394d67a8 1253 goto bad;
88a7a62a 1254
031fd966 1255 /* Initialize directory with "." and ".." from static template. */
86fb5449
KM
1256 if (dvp->v_mount->mnt_maxsymlinklen > 0)
1257 dtp = &mastertemplate;
1258 else
1259 dtp = (struct dirtemplate *)&omastertemplate;
1260 dirtemplate = *dtp;
88a7a62a
SL
1261 dirtemplate.dot_ino = ip->i_number;
1262 dirtemplate.dotdot_ino = dp->i_number;
86cdabf6 1263 error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate,
5b169cb7 1264 sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
e6e1f8be 1265 IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (int *)0, (struct proc *)0);
7188ac27 1266 if (error) {
88a7a62a
SL
1267 dp->i_nlink--;
1268 dp->i_flag |= ICHG;
1269 goto bad;
1270 }
e6e1f8be 1271 if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
031fd966
KB
1272 panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */
1273 else {
23de9f20 1274 ip->i_size = DIRBLKSIZ;
15365e07
KM
1275 ip->i_flag |= ICHG;
1276 }
031fd966
KB
1277
1278 /* Directory set up, now install it's entry in the parent directory. */
e6e1f8be 1279 if (error = ufs_direnter(ip, dvp, cnp)) {
2a5d2f56
KM
1280 dp->i_nlink--;
1281 dp->i_flag |= ICHG;
88a7a62a
SL
1282 }
1283bad:
1284 /*
c59af027
KM
1285 * No need to do an explicit VOP_TRUNCATE here, vrele will do this
1286 * for us because we set the link count to 0.
88a7a62a 1287 */
7188ac27 1288 if (error) {
88a7a62a
SL
1289 ip->i_nlink = 0;
1290 ip->i_flag |= ICHG;
031fd966 1291 ufs_iput(ip);
cbcdacd6 1292 } else
e1b76915 1293 *ap->a_vpp = ITOV(ip);
e6e1f8be 1294 FREE(cnp->cn_pnbuf, M_NAMEI);
031fd966 1295 ufs_iput(dp);
7188ac27 1296 return (error);
88a7a62a
SL
1297}
1298
1299/*
1300 * Rmdir system call.
1301 */
031fd966 1302int
e6e1f8be 1303ufs_rmdir(ap)
69021bc5 1304 struct vop_rmdir_args /* {
69021bc5
KM
1305 struct vnode *a_dvp;
1306 struct vnode *a_vp;
1307 struct componentname *a_cnp;
1308 } */ *ap;
88a7a62a 1309{
e6e1f8be
KM
1310 register struct vnode *dvp = ap->a_dvp;
1311 register struct componentname *cnp = ap->a_cnp;
88a7a62a 1312 register struct inode *ip, *dp;
031fd966 1313 int error;
7188ac27 1314
e1b76915 1315 ip = VTOI(ap->a_vp);
e6e1f8be 1316 dp = VTOI(dvp);
88a7a62a
SL
1317 /*
1318 * No rmdir "." please.
1319 */
1320 if (dp == ip) {
e6e1f8be 1321 vrele(dvp);
031fd966 1322 ufs_iput(ip);
7188ac27 1323 return (EINVAL);
88a7a62a
SL
1324 }
1325 /*
1326 * Verify the directory is empty (and valid).
1327 * (Rmdir ".." won't be valid since
1328 * ".." will contain a reference to
1329 * the current directory and thus be
1330 * non-empty.)
1331 */
031fd966
KB
1332 error = 0;
1333 if (ip->i_nlink != 2 ||
e6e1f8be 1334 !ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
7188ac27 1335 error = ENOTEMPTY;
88a7a62a
SL
1336 goto out;
1337 }
1338 /*
1339 * Delete reference to directory before purging
1340 * inode. If we crash in between, the directory
1341 * will be reattached to lost+found,
1342 */
e6e1f8be 1343 if (error = ufs_dirremove(dvp, cnp))
88a7a62a
SL
1344 goto out;
1345 dp->i_nlink--;
1346 dp->i_flag |= ICHG;
e6e1f8be 1347 cache_purge(dvp);
031fd966 1348 ufs_iput(dp);
e6e1f8be 1349 dvp = NULL;
88a7a62a
SL
1350 /*
1351 * Truncate inode. The only stuff left
1352 * in the directory is "." and "..". The
1353 * "." reference is inconsequential since
1354 * we're quashing it. The ".." reference
1355 * has already been adjusted above. We've
1356 * removed the "." reference and the reference
1357 * in the parent directory, but there may be
1358 * other hard links so decrement by 2 and
1359 * worry about them later.
1360 */
1361 ip->i_nlink -= 2;
69021bc5
KM
1362 error = VOP_TRUNCATE(ap->a_vp, (off_t)0, IO_SYNC, cnp->cn_cred,
1363 cnp->cn_proc);
7188ac27 1364 cache_purge(ITOV(ip));
88a7a62a 1365out:
e6e1f8be 1366 if (dvp)
031fd966
KB
1367 ufs_iput(dp);
1368 ufs_iput(ip);
7188ac27 1369 return (error);
88a7a62a
SL
1370}
1371
7188ac27
KM
1372/*
1373 * symlink -- make a symbolic link
1374 */
031fd966 1375int
e6e1f8be 1376ufs_symlink(ap)
69021bc5
KM
1377 struct vop_symlink_args /* {
1378 struct vnode *a_dvp;
1379 struct vnode **a_vpp;
1380 struct componentname *a_cnp;
1381 struct vattr *a_vap;
1382 char *a_target;
1383 } */ *ap;
7188ac27 1384{
2a7acb0a
KM
1385 register struct vnode *vp, **vpp = ap->a_vpp;
1386 register struct inode *ip;
1387 int len, error;
7188ac27 1388
e6e1f8be
KM
1389 if (error = ufs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
1390 vpp, ap->a_cnp))
7188ac27 1391 return (error);
2a7acb0a
KM
1392 vp = *vpp;
1393 len = strlen(ap->a_target);
1394 if (len < vp->v_mount->mnt_maxsymlinklen) {
1395 ip = VTOI(vp);
1396 bcopy(ap->a_target, (char *)ip->i_shortlink, len);
1397 ip->i_size = len;
1398 ip->i_flag |= IUPD|ICHG;
1399 } else
1400 error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
1401 UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0,
1402 (struct proc *)0);
1403 vput(vp);
7188ac27
KM
1404 return (error);
1405}
1406
1407/*
d8ba9f9d
KM
1408 * Vnode op for reading directories.
1409 *
1410 * The routine below assumes that the on-disk format of a directory
1411 * is the same as that defined by <sys/dirent.h>. If the on-disk
1412 * format changes, then it will be necessary to do a conversion
1413 * from the on-disk format that read returns to the format defined
1414 * by <sys/dirent.h>.
7188ac27 1415 */
031fd966 1416int
e6e1f8be 1417ufs_readdir(ap)
69021bc5
KM
1418 struct vop_readdir_args /* {
1419 struct vnode *a_vp;
1420 struct uio *a_uio;
1421 struct ucred *a_cred;
1422 } */ *ap;
88a7a62a 1423{
e6e1f8be 1424 register struct uio *uio = ap->a_uio;
86cdabf6 1425 int count, lost, error;
88a7a62a 1426
e6e1f8be 1427 count = uio->uio_resid;
7188ac27 1428 count &= ~(DIRBLKSIZ - 1);
e6e1f8be
KM
1429 lost = uio->uio_resid - count;
1430 if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1)))
7188ac27 1431 return (EINVAL);
e6e1f8be
KM
1432 uio->uio_resid = count;
1433 uio->uio_iov->iov_len = count;
86fb5449
KM
1434# if (BYTE_ORDER == LITTLE_ENDIAN)
1435 if (ap->a_vp->v_mount->mnt_maxsymlinklen > 0) {
1436 error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred);
1437 } else {
1438 struct dirent *dp, *edp;
1439 struct uio auio;
1440 struct iovec aiov;
1441 caddr_t dirbuf;
1442 int readcnt;
1443 u_char tmp;
1444
1445 auio = *uio;
1446 auio.uio_iov = &aiov;
1447 auio.uio_iovcnt = 1;
1448 auio.uio_segflg = UIO_SYSSPACE;
1449 aiov.iov_len = count;
1450 MALLOC(dirbuf, caddr_t, count, M_TEMP, M_WAITOK);
1451 aiov.iov_base = dirbuf;
1452 error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred);
1453 if (error == 0) {
1454 readcnt = count - auio.uio_resid;
1455 edp = (struct dirent *)&dirbuf[readcnt];
1456 for (dp = (struct dirent *)dirbuf; dp < edp; ) {
1457 tmp = dp->d_namlen;
1458 dp->d_namlen = dp->d_type;
1459 dp->d_type = tmp;
1460 if (dp->d_reclen > 0) {
1461 dp = (struct dirent *)
1462 ((char *)dp + dp->d_reclen);
1463 } else {
1464 error = EIO;
1465 break;
1466 }
1467 }
1468 if (dp >= edp)
1469 error = uiomove(dirbuf, readcnt, uio);
1470 }
1471 FREE(dirbuf, M_TEMP);
1472 }
1473# else
1474 error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred);
1475# endif
e6e1f8be 1476 uio->uio_resid += lost;
7188ac27
KM
1477 return (error);
1478}
1479
1480/*
1481 * Return target name of a symbolic link
1482 */
031fd966 1483int
e6e1f8be 1484ufs_readlink(ap)
69021bc5
KM
1485 struct vop_readlink_args /* {
1486 struct vnode *a_vp;
1487 struct uio *a_uio;
1488 struct ucred *a_cred;
1489 } */ *ap;
7188ac27 1490{
2a7acb0a
KM
1491 register struct vnode *vp = ap->a_vp;
1492 register struct inode *ip = VTOI(vp);
7188ac27 1493
2a7acb0a
KM
1494 if (ip->i_size < vp->v_mount->mnt_maxsymlinklen) {
1495 uiomove((char *)ip->i_shortlink, (int)ip->i_size, ap->a_uio);
1496 return (0);
1497 }
1498 return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
7188ac27
KM
1499}
1500
1501/*
1502 * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
655da945 1503 * done. If a buffer has been saved in anticipation of a CREATE, delete it.
7188ac27 1504 */
66955caf 1505/* ARGSUSED */
031fd966 1506int
e6e1f8be 1507ufs_abortop(ap)
69021bc5
KM
1508 struct vop_abortop_args /* {
1509 struct vnode *a_dvp;
1510 struct componentname *a_cnp;
1511 } */ *ap;
7188ac27 1512{
e1b76915
JH
1513 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
1514 FREE(ap->a_cnp->cn_pnbuf, M_NAMEI);
66955caf 1515 return (0);
7188ac27
KM
1516}
1517
1c3ebc10
KM
1518/*
1519 * Lock an inode.
1520 */
031fd966 1521int
e6e1f8be 1522ufs_lock(ap)
69021bc5
KM
1523 struct vop_lock_args /* {
1524 struct vnode *a_vp;
1525 } */ *ap;
7188ac27 1526{
e1b76915 1527 register struct inode *ip = VTOI(ap->a_vp);
7188ac27
KM
1528
1529 ILOCK(ip);
1530 return (0);
1531}
1532
1c3ebc10
KM
1533/*
1534 * Unlock an inode.
1535 */
031fd966 1536int
e6e1f8be 1537ufs_unlock(ap)
69021bc5
KM
1538 struct vop_unlock_args /* {
1539 struct vnode *a_vp;
1540 } */ *ap;
7188ac27 1541{
e1b76915 1542 register struct inode *ip = VTOI(ap->a_vp);
7188ac27
KM
1543
1544 if (!(ip->i_flag & ILOCKED))
1545 panic("ufs_unlock NOT LOCKED");
1546 IUNLOCK(ip);
1547 return (0);
1548}
1549
1c3ebc10
KM
1550/*
1551 * Check for a locked inode.
1552 */
031fd966 1553int
e6e1f8be 1554ufs_islocked(ap)
69021bc5
KM
1555 struct vop_islocked_args /* {
1556 struct vnode *a_vp;
1557 } */ *ap;
1c3ebc10
KM
1558{
1559
e1b76915 1560 if (VTOI(ap->a_vp)->i_flag & ILOCKED)
1c3ebc10
KM
1561 return (1);
1562 return (0);
1563}
1564
88a7a62a 1565/*
4f1ff475
KM
1566 * Calculate the logical to physical mapping if not done already,
1567 * then call the device strategy routine.
88a7a62a 1568 */
031fd966 1569int
e6e1f8be 1570ufs_strategy(ap)
69021bc5
KM
1571 struct vop_strategy_args /* {
1572 struct buf *a_bp;
1573 } */ *ap;
88a7a62a 1574{
e6e1f8be
KM
1575 register struct buf *bp = ap->a_bp;
1576 register struct vnode *vp = bp->b_vp;
031fd966 1577 register struct inode *ip;
e16fa59e
KM
1578 int error;
1579
e6e1f8be
KM
1580 ip = VTOI(vp);
1581 if (vp->v_type == VBLK || vp->v_type == VCHR)
e16fa59e 1582 panic("ufs_strategy: spec");
e6e1f8be 1583 if (bp->b_blkno == bp->b_lblkno) {
c59af027 1584 if (error =
e6e1f8be
KM
1585 VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno)) {
1586 bp->b_error = error;
1587 bp->b_flags |= B_ERROR;
1588 biodone(bp);
e16fa59e 1589 return (error);
dd1d1daf 1590 }
e6e1f8be
KM
1591 if ((long)bp->b_blkno == -1)
1592 clrbuf(bp);
e16fa59e 1593 }
e6e1f8be
KM
1594 if ((long)bp->b_blkno == -1) {
1595 biodone(bp);
e16fa59e 1596 return (0);
20aa076b 1597 }
e16fa59e 1598 vp = ip->i_devvp;
e6e1f8be 1599 bp->b_dev = vp->v_rdev;
ea460dfe 1600 VOCALL (vp->v_op, VOFFSET(vop_strategy), ap);
7188ac27
KM
1601 return (0);
1602}
88a7a62a 1603
e16fa59e
KM
1604/*
1605 * Print out the contents of an inode.
1606 */
031fd966 1607int
e6e1f8be 1608ufs_print(ap)
69021bc5
KM
1609 struct vop_print_args /* {
1610 struct vnode *a_vp;
1611 } */ *ap;
e16fa59e 1612{
e6e1f8be
KM
1613 register struct vnode *vp = ap->a_vp;
1614 register struct inode *ip = VTOI(vp);
e16fa59e 1615
a8f829ed
KM
1616 printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number,
1617 major(ip->i_dev), minor(ip->i_dev));
1618#ifdef FIFO
e6e1f8be
KM
1619 if (vp->v_type == VFIFO)
1620 fifo_printinfo(vp);
a8f829ed
KM
1621#endif /* FIFO */
1622 printf("%s\n", (ip->i_flag & ILOCKED) ? " (LOCKED)" : "");
4a8fb1bb 1623 if (ip->i_lockholder == 0)
031fd966 1624 return (0);
4a8fb1bb
KM
1625 printf("\towner pid %d", ip->i_lockholder);
1626 if (ip->i_lockwaiter)
1627 printf(" waiting pid %d", ip->i_lockwaiter);
96bae3e0 1628 printf("\n");
031fd966 1629 return (0);
e16fa59e
KM
1630}
1631
24a31b70
KM
1632/*
1633 * Read wrapper for special devices.
1634 */
031fd966 1635int
e6e1f8be 1636ufsspec_read(ap)
69021bc5
KM
1637 struct vop_read_args /* {
1638 struct vnode *a_vp;
1639 struct uio *a_uio;
1640 int a_ioflag;
1641 struct ucred *a_cred;
1642 } */ *ap;
24a31b70 1643{
ea460dfe 1644 extern int (**spec_vnodeop_p)();
24a31b70
KM
1645
1646 /*
1647 * Set access flag.
1648 */
e1b76915 1649 VTOI(ap->a_vp)->i_flag |= IACC;
ea460dfe 1650 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap));
24a31b70
KM
1651}
1652
1653/*
1654 * Write wrapper for special devices.
1655 */
031fd966 1656int
e6e1f8be 1657ufsspec_write(ap)
69021bc5
KM
1658 struct vop_write_args /* {
1659 struct vnode *a_vp;
1660 struct uio *a_uio;
1661 int a_ioflag;
1662 struct ucred *a_cred;
1663 } */ *ap;
24a31b70 1664{
ea460dfe 1665 extern int (**spec_vnodeop_p)();
24a31b70
KM
1666
1667 /*
1668 * Set update and change flags.
1669 */
e1b76915 1670 VTOI(ap->a_vp)->i_flag |= IUPD|ICHG;
ea460dfe 1671 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap));
24a31b70
KM
1672}
1673
1674/*
1675 * Close wrapper for special devices.
1676 *
1677 * Update the times on the inode then do device close.
1678 */
031fd966 1679int
e6e1f8be 1680ufsspec_close(ap)
69021bc5
KM
1681 struct vop_close_args /* {
1682 struct vnode *a_vp;
1683 int a_fflag;
1684 struct ucred *a_cred;
1685 struct proc *a_p;
1686 } */ *ap;
24a31b70 1687{
ea460dfe 1688 extern int (**spec_vnodeop_p)();
e1b76915 1689 register struct inode *ip = VTOI(ap->a_vp);
24a31b70 1690
e1b76915 1691 if (ap->a_vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
24a31b70 1692 ITIMES(ip, &time, &time);
ea460dfe 1693 return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap));
24a31b70
KM
1694}
1695
d1c43d7f
KM
1696#ifdef FIFO
1697/*
1698 * Read wrapper for fifo's
1699 */
031fd966 1700int
e6e1f8be 1701ufsfifo_read(ap)
69021bc5
KM
1702 struct vop_read_args /* {
1703 struct vnode *a_vp;
1704 struct uio *a_uio;
1705 int a_ioflag;
1706 struct ucred *a_cred;
1707 } */ *ap;
d1c43d7f 1708{
ea460dfe 1709 extern int (**fifo_vnodeop_p)();
d1c43d7f
KM
1710
1711 /*
1712 * Set access flag.
1713 */
e1b76915 1714 VTOI(ap->a_vp)->i_flag |= IACC;
ea460dfe 1715 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap));
d1c43d7f
KM
1716}
1717
1718/*
1719 * Write wrapper for fifo's.
1720 */
031fd966 1721int
e6e1f8be 1722ufsfifo_write(ap)
69021bc5
KM
1723 struct vop_write_args /* {
1724 struct vnode *a_vp;
1725 struct uio *a_uio;
1726 int a_ioflag;
1727 struct ucred *a_cred;
1728 } */ *ap;
d1c43d7f 1729{
ea460dfe 1730 extern int (**fifo_vnodeop_p)();
d1c43d7f
KM
1731
1732 /*
1733 * Set update and change flags.
1734 */
e1b76915 1735 VTOI(ap->a_vp)->i_flag |= IUPD|ICHG;
ea460dfe 1736 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap));
d1c43d7f
KM
1737}
1738
1739/*
1740 * Close wrapper for fifo's.
1741 *
1742 * Update the times on the inode then do device close.
1743 */
e6e1f8be 1744ufsfifo_close(ap)
69021bc5
KM
1745 struct vop_close_args /* {
1746 struct vnode *a_vp;
1747 int a_fflag;
1748 struct ucred *a_cred;
1749 struct proc *a_p;
1750 } */ *ap;
d1c43d7f 1751{
ea460dfe 1752 extern int (**fifo_vnodeop_p)();
e1b76915 1753 register struct inode *ip = VTOI(ap->a_vp);
d1c43d7f 1754
e1b76915 1755 if (ap->a_vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
d1c43d7f 1756 ITIMES(ip, &time, &time);
ea460dfe 1757 return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap));
d1c43d7f
KM
1758}
1759#endif /* FIFO */
1760
0b0bf936
KM
1761/*
1762 * Advisory record locking support
1763 */
031fd966 1764int
e6e1f8be 1765ufs_advlock(ap)
69021bc5
KM
1766 struct vop_advlock_args /* {
1767 struct vnode *a_vp;
1768 caddr_t a_id;
1769 int a_op;
1770 struct flock *a_fl;
1771 int a_flags;
1772 } */ *ap;
0b0bf936 1773{
e1b76915 1774 register struct inode *ip = VTOI(ap->a_vp);
e6e1f8be 1775 register struct flock *fl = ap->a_fl;
0b0bf936
KM
1776 register struct lockf *lock;
1777 off_t start, end;
1778 int error;
1779
1780 /*
1781 * Avoid the common case of unlocking when inode has no locks.
1782 */
1783 if (ip->i_lockf == (struct lockf *)0) {
e1b76915 1784 if (ap->a_op != F_SETLK) {
e6e1f8be 1785 fl->l_type = F_UNLCK;
0b0bf936
KM
1786 return (0);
1787 }
1788 }
1789 /*
1790 * Convert the flock structure into a start and end.
1791 */
e6e1f8be 1792 switch (fl->l_whence) {
0b0bf936
KM
1793
1794 case SEEK_SET:
1795 case SEEK_CUR:
1796 /*
1797 * Caller is responsible for adding any necessary offset
1798 * when SEEK_CUR is used.
1799 */
e6e1f8be 1800 start = fl->l_start;
0b0bf936
KM
1801 break;
1802
1803 case SEEK_END:
e6e1f8be 1804 start = ip->i_size + fl->l_start;
0b0bf936
KM
1805 break;
1806
1807 default:
1808 return (EINVAL);
1809 }
1810 if (start < 0)
1811 return (EINVAL);
e6e1f8be 1812 if (fl->l_len == 0)
0b0bf936
KM
1813 end = -1;
1814 else
e6e1f8be 1815 end = start + fl->l_len - 1;
0b0bf936
KM
1816 /*
1817 * Create the lockf structure
1818 */
1819 MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK);
1820 lock->lf_start = start;
1821 lock->lf_end = end;
e1b76915 1822 lock->lf_id = ap->a_id;
0b0bf936 1823 lock->lf_inode = ip;
e6e1f8be 1824 lock->lf_type = fl->l_type;
0b0bf936
KM
1825 lock->lf_next = (struct lockf *)0;
1826 lock->lf_block = (struct lockf *)0;
e1b76915 1827 lock->lf_flags = ap->a_flags;
0b0bf936
KM
1828 /*
1829 * Do the requested operation.
1830 */
e1b76915 1831 switch(ap->a_op) {
0b0bf936 1832 case F_SETLK:
b9fc1077 1833 return (lf_setlock(lock));
0b0bf936
KM
1834
1835 case F_UNLCK:
b9fc1077
KM
1836 error = lf_clearlock(lock);
1837 FREE(lock, M_LOCKF);
1838 return (error);
0b0bf936
KM
1839
1840 case F_GETLK:
e6e1f8be 1841 error = lf_getlock(lock, fl);
b9fc1077
KM
1842 FREE(lock, M_LOCKF);
1843 return (error);
0b0bf936
KM
1844
1845 default:
1846 free(lock, M_LOCKF);
1847 return (EINVAL);
1848 }
1849 /* NOTREACHED */
1850}
5b169cb7
KM
1851
1852/*
031fd966
KB
1853 * Initialize the vnode associated with a new inode, handle aliased
1854 * vnodes.
5b169cb7 1855 */
031fd966 1856int
c59af027 1857ufs_vinit(mntp, specops, fifoops, vpp)
031fd966 1858 struct mount *mntp;
1d52469b
JH
1859 int (**specops)();
1860 int (**fifoops)();
031fd966
KB
1861 struct vnode **vpp;
1862{
1863 struct inode *ip, *nip;
1864 struct vnode *vp, *nvp;
9342689a 1865 extern int (**spec_vnodeop_p)();
031fd966
KB
1866
1867 vp = *vpp;
1868 ip = VTOI(vp);
1869 switch(vp->v_type = IFTOVT(ip->i_mode)) {
1870 case VCHR:
1871 case VBLK:
c59af027 1872 vp->v_op = specops;
031fd966 1873 if (nvp = checkalias(vp, ip->i_rdev, mntp)) {
c59af027 1874 /*
4a8fb1bb 1875 * Discard unneeded vnode, but save its inode.
c59af027 1876 */
4a8fb1bb
KM
1877 remque(ip);
1878 IUNLOCK(ip);
1879 nvp->v_data = vp->v_data;
1880 vp->v_data = NULL;
9342689a 1881 vp->v_op = spec_vnodeop_p;
4a8fb1bb
KM
1882 vrele(vp);
1883 vgone(vp);
c59af027 1884 /*
4a8fb1bb 1885 * Reinitialize aliased inode.
c59af027 1886 */
4a8fb1bb
KM
1887 vp = nvp;
1888 ip->i_vnode = vp;
1889 ufs_ihashins(ip);
031fd966
KB
1890 }
1891 break;
1892 case VFIFO:
1893#ifdef FIFO
c59af027 1894 vp->v_op = fifoops;
031fd966
KB
1895 break;
1896#else
1897 return (EOPNOTSUPP);
1898#endif
1899 }
031fd966
KB
1900 if (ip->i_number == ROOTINO)
1901 vp->v_flag |= VROOT;
1a3cb193
KM
1902 /*
1903 * Initialize modrev times
1904 */
1905 SETHIGH(ip->i_modrev, mono_time.tv_sec);
1906 SETLOW(ip->i_modrev, mono_time.tv_usec * 4294);
031fd966
KB
1907 *vpp = vp;
1908 return (0);
1909}
5b169cb7 1910
031fd966
KB
1911/*
1912 * Allocate a new inode.
1913 */
1914int
6e57e9ff 1915ufs_makeinode(mode, dvp, vpp, cnp)
031fd966 1916 int mode;
cfef4373 1917 struct vnode *dvp;
c59af027 1918 struct vnode **vpp;
cfef4373 1919 struct componentname *cnp;
031fd966
KB
1920{
1921 register struct inode *ip, *pdir;
fa4f99ac 1922 struct timeval tv;
c59af027 1923 struct vnode *tvp;
031fd966
KB
1924 int error;
1925
cfef4373 1926 pdir = VTOI(dvp);
38285224 1927#ifdef DIAGNOSTIC
cfef4373 1928 if ((cnp->cn_flags & HASBUF) == 0)
031fd966
KB
1929 panic("ufs_makeinode: no name");
1930#endif
c59af027 1931 *vpp = NULL;
031fd966
KB
1932 if ((mode & IFMT) == 0)
1933 mode |= IFREG;
1934
cfef4373
JH
1935 if (error = VOP_VALLOC(dvp, mode, cnp->cn_cred, &tvp)) {
1936 free(cnp->cn_pnbuf, M_NAMEI);
031fd966
KB
1937 ufs_iput(pdir);
1938 return (error);
1939 }
c59af027 1940 ip = VTOI(tvp);
cfef4373 1941 ip->i_uid = cnp->cn_cred->cr_uid;
031fd966
KB
1942 ip->i_gid = pdir->i_gid;
1943#ifdef QUOTA
1944 if ((error = getinoquota(ip)) ||
cfef4373
JH
1945 (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
1946 free(cnp->cn_pnbuf, M_NAMEI);
c59af027 1947 VOP_VFREE(tvp, ip->i_number, mode);
031fd966
KB
1948 ufs_iput(ip);
1949 ufs_iput(pdir);
1950 return (error);
1951 }
1952#endif
1953 ip->i_flag |= IACC|IUPD|ICHG;
1954 ip->i_mode = mode;
c59af027 1955 tvp->v_type = IFTOVT(mode); /* Rest init'd in iget() */
031fd966 1956 ip->i_nlink = 1;
cfef4373
JH
1957 if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) &&
1958 suser(cnp->cn_cred, NULL))
031fd966
KB
1959 ip->i_mode &= ~ISGID;
1960
1961 /*
1962 * Make sure inode goes to disk before directory entry.
1963 */
fa4f99ac
CT
1964 tv = time;
1965 if (error = VOP_UPDATE(tvp, &tv, &tv, 1))
031fd966 1966 goto bad;
cfef4373 1967 if (error = ufs_direnter(ip, dvp, cnp))
031fd966 1968 goto bad;
cfef4373
JH
1969 if ((cnp->cn_flags & SAVESTART) == 0)
1970 FREE(cnp->cn_pnbuf, M_NAMEI);
031fd966 1971 ufs_iput(pdir);
c59af027 1972 *vpp = tvp;
031fd966
KB
1973 return (0);
1974
1975bad:
1976 /*
1977 * Write error occurred trying to update the inode
1978 * or the directory so must deallocate the inode.
1979 */
cfef4373 1980 free(cnp->cn_pnbuf, M_NAMEI);
031fd966
KB
1981 ufs_iput(pdir);
1982 ip->i_nlink = 0;
1983 ip->i_flag |= ICHG;
1984 ufs_iput(ip);
1985 return (error);
1986}