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