minor lint; initialize modrev time for NFS leases
[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 *
1a3cb193 7 * @(#)ufs_vnops.c 7.71 (Berkeley) %G%
da7c5cc6 8 */
6459ebe0 9
031fd966
KB
10#include <sys/param.h>
11#include <sys/systm.h>
12#include <sys/namei.h>
13#include <sys/resourcevar.h>
14#include <sys/kernel.h>
15#include <sys/file.h>
16#include <sys/stat.h>
17#include <sys/buf.h>
18#include <sys/proc.h>
19#include <sys/conf.h>
20#include <sys/mount.h>
21#include <sys/vnode.h>
22#include <sys/specdev.h>
23#include <sys/fifo.h>
24#include <sys/malloc.h>
25
26#include <ufs/ufs/lockf.h>
27#include <ufs/ufs/quota.h>
28#include <ufs/ufs/inode.h>
29#include <ufs/ufs/dir.h>
30#include <ufs/ufs/ufsmount.h>
31#include <ufs/ufs/ufs_extern.h>
32
1a3cb193
KM
33int ufs_chmod __P((struct vnode *, int, struct proc *));
34int ufs_chown __P((struct vnode *, u_int, u_int, struct proc *));
031fd966 35
031fd966
KB
36enum vtype iftovt_tab[16] = {
37 VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
38 VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD,
39};
40int vttoif_tab[9] = {
41 0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFIFO, IFMT,
42};
3e78e260 43
1a3cb193
KM
44#ifdef _NOQUAD
45#define SETHIGH(q, h) (q).val[_QUAD_HIGHWORD] = (h)
46#define SETLOW(q, l) (q).val[_QUAD_LOWWORD] = (l)
47#else /* QUAD */
48union _qcvt {
49 quad_t qcvt;
50 long val[2];
51};
52#define SETHIGH(q, h) { \
53 union _qcvt tmp; \
54 tmp.qcvt = (q); \
55 tmp.val[_QUAD_HIGHWORD] = (h); \
56 (q) = tmp.qcvt; \
57}
58#define SETLOW(q, l) { \
59 union _qcvt tmp; \
60 tmp.qcvt = (q); \
61 tmp.val[_QUAD_LOWWORD] = (l); \
62 (q) = tmp.qcvt; \
63}
64#endif /* QUAD */
65
4f083fd7 66/*
7188ac27 67 * Create a regular file
4f083fd7 68 */
031fd966 69int
5b169cb7 70ufs_create(ndp, vap, p)
7188ac27
KM
71 struct nameidata *ndp;
72 struct vattr *vap;
5b169cb7 73 struct proc *p;
3e78e260 74{
c59af027 75 struct vnode *vp;
7188ac27 76 int error;
3e78e260 77
031fd966 78 if (error =
c59af027 79 ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &vp))
7188ac27 80 return (error);
c59af027 81 ndp->ni_vp = vp;
7188ac27 82 return (0);
3e78e260
BJ
83}
84
4f083fd7 85/*
7188ac27 86 * Mknod vnode call
4f083fd7 87 */
7188ac27 88/* ARGSUSED */
031fd966 89int
5b169cb7 90ufs_mknod(ndp, vap, cred, p)
7188ac27 91 struct nameidata *ndp;
7188ac27 92 struct vattr *vap;
031fd966 93 struct ucred *cred;
5b169cb7 94 struct proc *p;
3e78e260 95{
c59af027
KM
96 register struct inode *ip;
97 struct vnode *vp;
7188ac27 98 int error;
3e78e260 99
031fd966 100 if (error =
c59af027 101 ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode), ndp, &vp))
7188ac27 102 return (error);
c59af027 103 ip = VTOI(vp);
d1c43d7f
KM
104 ip->i_flag |= IACC|IUPD|ICHG;
105 if (vap->va_rdev != VNOVAL) {
7188ac27
KM
106 /*
107 * Want to be able to use this to make badblock
108 * inodes, so don't truncate the dev number.
109 */
b373e060 110 ip->i_rdev = vap->va_rdev;
7188ac27 111 }
7188ac27
KM
112 /*
113 * Remove inode so that it will be reloaded by iget and
114 * checked to see if it is an alias of an existing entry
115 * in the inode cache.
116 */
d1c43d7f 117 vput(vp);
f09fe6d3
KM
118 vp->v_type = VNON;
119 vgone(vp);
7188ac27 120 return (0);
3e78e260
BJ
121}
122
123/*
7188ac27
KM
124 * Open called.
125 *
126 * Nothing to do.
3e78e260 127 */
7188ac27 128/* ARGSUSED */
031fd966 129int
5b169cb7 130ufs_open(vp, mode, cred, p)
7188ac27
KM
131 struct vnode *vp;
132 int mode;
133 struct ucred *cred;
5b169cb7 134 struct proc *p;
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
5b169cb7 147ufs_close(vp, fflag, cred, p)
7188ac27
KM
148 struct vnode *vp;
149 int fflag;
150 struct ucred *cred;
5b169cb7 151 struct proc *p;
3e78e260 152{
031fd966 153 register struct inode *ip;
3e78e260 154
031fd966 155 ip = VTOI(vp);
de67eefc 156 if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
7188ac27
KM
157 ITIMES(ip, &time, &time);
158 return (0);
3e78e260
BJ
159}
160
4b61628b
KM
161/*
162 * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
163 * The mode is shifted to select the owner/group/other fields. The
164 * super user is granted all permissions.
165 */
031fd966 166int
5b169cb7 167ufs_access(vp, mode, cred, p)
7188ac27 168 struct vnode *vp;
4b61628b 169 register int mode;
7188ac27 170 struct ucred *cred;
5b169cb7 171 struct proc *p;
3e78e260 172{
4b61628b
KM
173 register struct inode *ip = VTOI(vp);
174 register gid_t *gp;
175 int i, error;
3e78e260 176
4b61628b
KM
177#ifdef DIAGNOSTIC
178 if (!VOP_ISLOCKED(vp)) {
179 vprint("ufs_access: not locked", vp);
180 panic("ufs_access: not locked");
181 }
182#endif
183#ifdef QUOTA
184 if (mode & VWRITE) {
185 switch (vp->v_type) {
186 case VREG: case VDIR: case VLNK:
187 if (error = getinoquota(ip))
188 return (error);
189 }
190 }
191#endif /* QUOTA */
192 /*
193 * If you're the super-user, you always get access.
194 */
195 if (cred->cr_uid == 0)
196 return (0);
197 /*
198 * Access check is based on only one of owner, group, public.
199 * If not owner, then check group. If not a member of the
200 * group, then check public access.
201 */
202 if (cred->cr_uid != ip->i_uid) {
203 mode >>= 3;
204 gp = cred->cr_groups;
205 for (i = 0; i < cred->cr_ngroups; i++, gp++)
206 if (ip->i_gid == *gp)
207 goto found;
208 mode >>= 3;
209found:
210 ;
211 }
212 if ((ip->i_mode & mode) != 0)
213 return (0);
214 return (EACCES);
3e78e260
BJ
215}
216
7188ac27 217/* ARGSUSED */
031fd966 218int
5b169cb7 219ufs_getattr(vp, vap, cred, p)
7188ac27
KM
220 struct vnode *vp;
221 register struct vattr *vap;
222 struct ucred *cred;
5b169cb7 223 struct proc *p;
3e78e260 224{
031fd966 225 register struct inode *ip;
3e78e260 226
031fd966 227 ip = VTOI(vp);
7188ac27 228 ITIMES(ip, &time, &time);
3e78e260 229 /*
7188ac27 230 * Copy from inode table
3e78e260 231 */
7188ac27
KM
232 vap->va_fsid = ip->i_dev;
233 vap->va_fileid = ip->i_number;
234 vap->va_mode = ip->i_mode & ~IFMT;
235 vap->va_nlink = ip->i_nlink;
236 vap->va_uid = ip->i_uid;
237 vap->va_gid = ip->i_gid;
238 vap->va_rdev = (dev_t)ip->i_rdev;
4b61628b
KM
239#ifdef tahoe
240 vap->va_size = ip->i_size;
241 vap->va_size_rsv = 0;
242#else
8fae943a 243 vap->va_qsize = ip->i_din.di_qsize;
4b61628b 244#endif
7188ac27 245 vap->va_atime.tv_sec = ip->i_atime;
6ef53d70 246 vap->va_atime.tv_usec = 0;
7188ac27 247 vap->va_mtime.tv_sec = ip->i_mtime;
6ef53d70 248 vap->va_mtime.tv_usec = 0;
7188ac27 249 vap->va_ctime.tv_sec = ip->i_ctime;
6ef53d70 250 vap->va_ctime.tv_usec = 0;
d07fc92a
KM
251 vap->va_flags = ip->i_flags;
252 vap->va_gen = ip->i_gen;
7188ac27
KM
253 /* this doesn't belong here */
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
cc173077 259 vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
a61a68d6 260 vap->va_bytes = dbtob(ip->i_blocks);
1a3cb193 261#ifdef _NOQUAD
8fae943a 262 vap->va_bytes_rsv = 0;
1a3cb193 263#endif
7188ac27 264 vap->va_type = vp->v_type;
1a3cb193 265 vap->va_filerev = ip->i_modrev;
7188ac27 266 return (0);
3e78e260
BJ
267}
268
269/*
7188ac27 270 * Set attribute vnode op. called from several syscalls
3e78e260 271 */
031fd966 272int
5b169cb7 273ufs_setattr(vp, vap, cred, p)
7188ac27
KM
274 register struct vnode *vp;
275 register struct vattr *vap;
276 register struct ucred *cred;
5b169cb7 277 struct proc *p;
3e78e260 278{
031fd966 279 register struct inode *ip;
031fd966 280 int error;
b4d1aee9 281
7188ac27 282 /*
031fd966 283 * Check for unsettable attributes.
7188ac27
KM
284 */
285 if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
286 (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
287 (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
d07fc92a 288 ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
7188ac27 289 return (EINVAL);
b4d1aee9 290 }
7188ac27
KM
291 /*
292 * Go through the fields and update iff not VNOVAL.
293 */
294 if (vap->va_uid != (u_short)VNOVAL || vap->va_gid != (u_short)VNOVAL)
031fd966 295 if (error = ufs_chown(vp, vap->va_uid, vap->va_gid, p))
7188ac27
KM
296 return (error);
297 if (vap->va_size != VNOVAL) {
298 if (vp->v_type == VDIR)
299 return (EISDIR);
c59af027 300 if (error = VOP_TRUNCATE(vp, vap->va_size, 0)) /* IO_SYNC? */
7188ac27 301 return (error);
3e78e260 302 }
c59af027 303 ip = VTOI(vp);
7188ac27 304 if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
de412887 305 if (cred->cr_uid != ip->i_uid &&
c6f5111d 306 (error = suser(cred, &p->p_acflag)))
de412887 307 return (error);
7188ac27
KM
308 if (vap->va_atime.tv_sec != VNOVAL)
309 ip->i_flag |= IACC;
310 if (vap->va_mtime.tv_sec != VNOVAL)
311 ip->i_flag |= IUPD;
312 ip->i_flag |= ICHG;
c59af027 313 if (error = VOP_UPDATE(vp, &vap->va_atime, &vap->va_mtime, 1))
7188ac27 314 return (error);
5485e062 315 }
031fd966 316 error = 0;
7188ac27 317 if (vap->va_mode != (u_short)VNOVAL)
031fd966 318 error = ufs_chmod(vp, (int)vap->va_mode, p);
d07fc92a
KM
319 if (vap->va_flags != VNOVAL) {
320 if (cred->cr_uid != ip->i_uid &&
c6f5111d 321 (error = suser(cred, &p->p_acflag)))
d07fc92a
KM
322 return (error);
323 if (cred->cr_uid == 0) {
324 ip->i_flags = vap->va_flags;
325 } else {
326 ip->i_flags &= 0xffff0000;
327 ip->i_flags |= (vap->va_flags & 0xffff);
328 }
329 ip->i_flag |= ICHG;
330 }
7188ac27 331 return (error);
528f664c
SL
332}
333
4f083fd7
SL
334/*
335 * Change the mode on a file.
336 * Inode must be locked before calling.
337 */
ca3e8b68 338static int
031fd966 339ufs_chmod(vp, mode, p)
7188ac27 340 register struct vnode *vp;
528f664c 341 register int mode;
c6f5111d 342 struct proc *p;
528f664c 343{
c6f5111d 344 register struct ucred *cred = p->p_ucred;
7188ac27 345 register struct inode *ip = VTOI(vp);
de412887 346 int error;
197da11b 347
de412887 348 if (cred->cr_uid != ip->i_uid &&
c6f5111d 349 (error = suser(cred, &p->p_acflag)))
de412887 350 return (error);
7188ac27 351 if (cred->cr_uid) {
e57b6138 352 if (vp->v_type != VDIR && (mode & ISVTX))
39b5be4c 353 return (EFTYPE);
e57b6138 354 if (!groupmember(ip->i_gid, cred) && (mode & ISGID))
39b5be4c 355 return (EPERM);
f94ceb3b 356 }
39b5be4c 357 ip->i_mode &= ~07777;
7188ac27 358 ip->i_mode |= mode & 07777;
3e78e260 359 ip->i_flag |= ICHG;
7188ac27 360 if ((vp->v_flag & VTEXT) && (ip->i_mode & ISVTX) == 0)
8986c97c 361 (void) vnode_pager_uncache(vp);
47af7174 362 return (0);
5485e062
BJ
363}
364
528f664c
SL
365/*
366 * Perform chown operation on inode ip;
367 * inode must be locked prior to call.
368 */
ca3e8b68 369static int
031fd966 370ufs_chown(vp, uid, gid, p)
7188ac27 371 register struct vnode *vp;
031fd966
KB
372 u_int uid;
373 u_int gid;
c6f5111d 374 struct proc *p;
528f664c 375{
7188ac27 376 register struct inode *ip = VTOI(vp);
c6f5111d 377 register struct ucred *cred = p->p_ucred;
4b61628b
KM
378 uid_t ouid;
379 gid_t ogid;
380 int error = 0;
528f664c 381#ifdef QUOTA
4b61628b
KM
382 register int i;
383 long change;
bb1b75f4 384#endif
528f664c 385
7188ac27 386 if (uid == (u_short)VNOVAL)
bb1b75f4 387 uid = ip->i_uid;
7188ac27 388 if (gid == (u_short)VNOVAL)
bb1b75f4 389 gid = ip->i_gid;
18b0bce6
KB
390 /*
391 * If we don't own the file, are trying to change the owner
392 * of the file, or are not a member of the target group,
393 * the caller must be superuser or the call fails.
394 */
7188ac27
KM
395 if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid ||
396 !groupmember((gid_t)gid, cred)) &&
c6f5111d 397 (error = suser(cred, &p->p_acflag)))
7188ac27 398 return (error);
4b61628b
KM
399 ouid = ip->i_uid;
400 ogid = ip->i_gid;
bb1b75f4 401#ifdef QUOTA
4b61628b
KM
402 if (error = getinoquota(ip))
403 return (error);
404 if (ouid == uid) {
405 dqrele(vp, ip->i_dquot[USRQUOTA]);
406 ip->i_dquot[USRQUOTA] = NODQUOT;
407 }
408 if (ogid == gid) {
409 dqrele(vp, ip->i_dquot[GRPQUOTA]);
410 ip->i_dquot[GRPQUOTA] = NODQUOT;
411 }
412 change = ip->i_blocks;
413 (void) chkdq(ip, -change, cred, CHOWN);
414 (void) chkiq(ip, -1, cred, CHOWN);
415 for (i = 0; i < MAXQUOTAS; i++) {
416 dqrele(vp, ip->i_dquot[i]);
417 ip->i_dquot[i] = NODQUOT;
418 }
f94ceb3b 419#endif
bb1b75f4
SL
420 ip->i_uid = uid;
421 ip->i_gid = gid;
528f664c 422#ifdef QUOTA
4b61628b
KM
423 if ((error = getinoquota(ip)) == 0) {
424 if (ouid == uid) {
425 dqrele(vp, ip->i_dquot[USRQUOTA]);
426 ip->i_dquot[USRQUOTA] = NODQUOT;
427 }
428 if (ogid == gid) {
429 dqrele(vp, ip->i_dquot[GRPQUOTA]);
430 ip->i_dquot[GRPQUOTA] = NODQUOT;
431 }
432 if ((error = chkdq(ip, change, cred, CHOWN)) == 0) {
433 if ((error = chkiq(ip, 1, cred, CHOWN)) == 0)
722a9b31 434 goto good;
4b61628b
KM
435 else
436 (void) chkdq(ip, -change, cred, CHOWN|FORCE);
437 }
438 for (i = 0; i < MAXQUOTAS; i++) {
439 dqrele(vp, ip->i_dquot[i]);
440 ip->i_dquot[i] = NODQUOT;
441 }
442 }
443 ip->i_uid = ouid;
444 ip->i_gid = ogid;
445 if (getinoquota(ip) == 0) {
446 if (ouid == uid) {
447 dqrele(vp, ip->i_dquot[USRQUOTA]);
448 ip->i_dquot[USRQUOTA] = NODQUOT;
449 }
450 if (ogid == gid) {
451 dqrele(vp, ip->i_dquot[GRPQUOTA]);
452 ip->i_dquot[GRPQUOTA] = NODQUOT;
453 }
722a9b31
KM
454 (void) chkdq(ip, change, cred, FORCE|CHOWN);
455 (void) chkiq(ip, 1, cred, FORCE|CHOWN);
6cb69bbe 456 (void) getinoquota(ip);
4b61628b 457 }
6cb69bbe 458 return (error);
722a9b31 459good:
6cb69bbe
KM
460 if (getinoquota(ip))
461 panic("chown: lost quota");
462#endif /* QUOTA */
4b61628b
KM
463 if (ouid != uid || ogid != gid)
464 ip->i_flag |= ICHG;
465 if (ouid != uid && cred->cr_uid != 0)
466 ip->i_mode &= ~ISUID;
467 if (ogid != gid && cred->cr_uid != 0)
468 ip->i_mode &= ~ISGID;
469 return (0);
d67a03eb
BJ
470}
471
7188ac27 472/* ARGSUSED */
031fd966 473int
5b169cb7 474ufs_ioctl(vp, com, data, fflag, cred, p)
7188ac27
KM
475 struct vnode *vp;
476 int com;
477 caddr_t data;
478 int fflag;
479 struct ucred *cred;
5b169cb7 480 struct proc *p;
bb1b75f4 481{
bb1b75f4 482
7188ac27
KM
483 return (ENOTTY);
484}
485
486/* ARGSUSED */
031fd966 487int
5b169cb7 488ufs_select(vp, which, fflags, cred, p)
7188ac27 489 struct vnode *vp;
d1c43d7f 490 int which, fflags;
7188ac27 491 struct ucred *cred;
5b169cb7 492 struct proc *p;
7188ac27
KM
493{
494
5b169cb7
KM
495 /*
496 * We should really check to see if I/O is possible.
497 */
498 return (1);
bb1b75f4 499}
d67a03eb 500
4f083fd7 501/*
7188ac27
KM
502 * Mmap a file
503 *
504 * NB Currently unsupported.
4f083fd7 505 */
7188ac27 506/* ARGSUSED */
031fd966 507int
5b169cb7 508ufs_mmap(vp, fflags, cred, p)
7188ac27
KM
509 struct vnode *vp;
510 int fflags;
511 struct ucred *cred;
5b169cb7 512 struct proc *p;
d67a03eb 513{
d67a03eb 514
7188ac27 515 return (EINVAL);
d67a03eb 516}
64d3a787 517
4f083fd7 518/*
7188ac27
KM
519 * Seek on a file
520 *
521 * Nothing to do, so just return.
4f083fd7 522 */
7188ac27 523/* ARGSUSED */
031fd966 524int
7188ac27
KM
525ufs_seek(vp, oldoff, newoff, cred)
526 struct vnode *vp;
527 off_t oldoff, newoff;
528 struct ucred *cred;
528f664c 529{
7188ac27
KM
530
531 return (0);
532}
533
534/*
535 * ufs remove
536 * Hard to avoid races here, especially
537 * in unlinking directories.
538 */
031fd966 539int
5b169cb7 540ufs_remove(ndp, p)
7188ac27 541 struct nameidata *ndp;
5b169cb7 542 struct proc *p;
7188ac27
KM
543{
544 register struct inode *ip, *dp;
545 int error;
546
547 ip = VTOI(ndp->ni_vp);
548 dp = VTOI(ndp->ni_dvp);
031fd966 549 error = ufs_dirremove(ndp);
7188ac27
KM
550 if (!error) {
551 ip->i_nlink--;
552 ip->i_flag |= ICHG;
528f664c 553 }
7188ac27
KM
554 if (dp == ip)
555 vrele(ITOV(ip));
556 else
031fd966
KB
557 ufs_iput(ip);
558 ufs_iput(dp);
7188ac27 559 return (error);
4f083fd7
SL
560}
561
562/*
7188ac27 563 * link vnode call
4f083fd7 564 */
031fd966 565int
5b169cb7 566ufs_link(vp, ndp, p)
7188ac27
KM
567 register struct vnode *vp;
568 register struct nameidata *ndp;
5b169cb7 569 struct proc *p;
4f083fd7 570{
031fd966 571 register struct inode *ip;
7188ac27 572 int error;
4f083fd7 573
655da945
KM
574#ifdef DIANOSTIC
575 if ((ndp->ni_nameiop & HASBUF) == 0)
576 panic("ufs_link: no name");
577#endif
031fd966 578 ip = VTOI(vp);
655da945
KM
579 if ((unsigned short)ip->i_nlink >= LINK_MAX) {
580 free(ndp->ni_pnbuf, M_NAMEI);
986aedaa 581 return (EMLINK);
655da945 582 }
7188ac27
KM
583 if (ndp->ni_dvp != vp)
584 ILOCK(ip);
7188ac27
KM
585 ip->i_nlink++;
586 ip->i_flag |= ICHG;
c59af027 587 error = VOP_UPDATE(vp, &time, &time, 1);
7188ac27 588 if (!error)
031fd966 589 error = ufs_direnter(ip, ndp);
7188ac27
KM
590 if (ndp->ni_dvp != vp)
591 IUNLOCK(ip);
655da945 592 FREE(ndp->ni_pnbuf, M_NAMEI);
394d67a8 593 vput(ndp->ni_dvp);
7188ac27
KM
594 if (error) {
595 ip->i_nlink--;
82252d2b 596 ip->i_flag |= ICHG;
7188ac27
KM
597 }
598 return (error);
528f664c
SL
599}
600
4f083fd7
SL
601/*
602 * Rename system call.
603 * rename("foo", "bar");
604 * is essentially
605 * unlink("bar");
606 * link("foo", "bar");
607 * unlink("foo");
608 * but ``atomically''. Can't do full commit without saving state in the
609 * inode on disk which isn't feasible at this time. Best we can do is
610 * always guarantee the target exists.
611 *
612 * Basic algorithm is:
613 *
614 * 1) Bump link count on source while we're linking it to the
7188ac27 615 * target. This also ensure the inode won't be deleted out
68f21562
KM
616 * from underneath us while we work (it may be truncated by
617 * a concurrent `trunc' or `open' for creation).
4f083fd7
SL
618 * 2) Link source to destination. If destination already exists,
619 * delete it first.
68f21562
KM
620 * 3) Unlink source reference to inode if still around. If a
621 * directory was moved and the parent of the destination
4f083fd7
SL
622 * is different from the source, patch the ".." entry in the
623 * directory.
4f083fd7 624 */
031fd966 625int
5b169cb7 626ufs_rename(fndp, tndp, p)
7188ac27 627 register struct nameidata *fndp, *tndp;
5b169cb7 628 struct proc *p;
528f664c 629{
4f083fd7 630 register struct inode *ip, *xp, *dp;
68f21562
KM
631 struct dirtemplate dirbuf;
632 int doingdirectory = 0, oldparent = 0, newparent = 0;
a5390dce 633 int error = 0;
4f083fd7 634
655da945
KM
635#ifdef DIANOSTIC
636 if ((tndp->ni_nameiop & HASBUF) == 0 ||
637 (fndp->ni_nameiop & HASBUF) == 0)
638 panic("ufs_rename: no name");
639#endif
7188ac27
KM
640 dp = VTOI(fndp->ni_dvp);
641 ip = VTOI(fndp->ni_vp);
655da945
KM
642 /*
643 * Check if just deleting a link name.
644 */
645 if (fndp->ni_vp == tndp->ni_vp) {
646 VOP_ABORTOP(tndp);
647 vput(tndp->ni_dvp);
648 vput(tndp->ni_vp);
649 vrele(fndp->ni_dvp);
650 if ((ip->i_mode&IFMT) == IFDIR) {
651 VOP_ABORTOP(fndp);
652 vrele(fndp->ni_vp);
653 return (EINVAL);
654 }
655 doingdirectory = 0;
656 goto unlinkit;
657 }
7188ac27 658 ILOCK(ip);
4f083fd7 659 if ((ip->i_mode&IFMT) == IFDIR) {
4f083fd7 660 /*
046f18d1 661 * Avoid ".", "..", and aliases of "." for obvious reasons.
4f083fd7 662 */
655da945
KM
663 if ((fndp->ni_namelen == 1 && fndp->ni_ptr[0] == '.') ||
664 dp == ip || fndp->ni_isdotdot || (ip->i_flag & IRENAME)) {
66955caf
KM
665 VOP_ABORTOP(tndp);
666 vput(tndp->ni_dvp);
667 if (tndp->ni_vp)
668 vput(tndp->ni_vp);
669 VOP_ABORTOP(fndp);
670 vrele(fndp->ni_dvp);
671 vput(fndp->ni_vp);
7188ac27 672 return (EINVAL);
4f083fd7 673 }
68f21562 674 ip->i_flag |= IRENAME;
4f083fd7
SL
675 oldparent = dp->i_number;
676 doingdirectory++;
677 }
7188ac27 678 vrele(fndp->ni_dvp);
4f083fd7
SL
679
680 /*
681 * 1) Bump link count while we're moving stuff
682 * around. If we crash somewhere before
683 * completing our work, the link count
684 * may be wrong, but correctable.
685 */
686 ip->i_nlink++;
687 ip->i_flag |= ICHG;
c59af027 688 error = VOP_UPDATE(fndp->ni_vp, &time, &time, 1);
a388503d 689 IUNLOCK(ip);
4f083fd7
SL
690
691 /*
692 * When the target exists, both the directory
7188ac27 693 * and target vnodes are returned locked.
4f083fd7 694 */
7188ac27
KM
695 dp = VTOI(tndp->ni_dvp);
696 xp = NULL;
697 if (tndp->ni_vp)
698 xp = VTOI(tndp->ni_vp);
046f18d1
SL
699 /*
700 * If ".." must be changed (ie the directory gets a new
81552f0f
KM
701 * parent) then the source directory must not be in the
702 * directory heirarchy above the target, as this would
703 * orphan everything below the source directory. Also
704 * the user must have write permission in the source so
705 * as to be able to change "..". We must repeat the call
706 * to namei, as the parent directory is unlocked by the
707 * call to checkpath().
046f18d1 708 */
68f21562
KM
709 if (oldparent != dp->i_number)
710 newparent = dp->i_number;
711 if (doingdirectory && newparent) {
48c3b6e8 712 VOP_LOCK(fndp->ni_vp);
5b169cb7 713 error = ufs_access(fndp->ni_vp, VWRITE, tndp->ni_cred, p);
48c3b6e8
KM
714 VOP_UNLOCK(fndp->ni_vp);
715 if (error)
81552f0f 716 goto bad;
655da945 717 if (xp != NULL)
031fd966
KB
718 ufs_iput(xp);
719 if (error = ufs_checkpath(ip, dp, tndp->ni_cred))
655da945
KM
720 goto out;
721 if ((tndp->ni_nameiop & SAVESTART) == 0)
722 panic("ufs_rename: lost to startdir");
5e03b55d 723 p->p_spare[1]--;
655da945
KM
724 if (error = lookup(tndp, p))
725 goto out;
726 dp = VTOI(tndp->ni_dvp);
727 xp = NULL;
728 if (tndp->ni_vp)
729 xp = VTOI(tndp->ni_vp);
81552f0f 730 }
4f083fd7
SL
731 /*
732 * 2) If target doesn't exist, link the target
733 * to the source and unlink the source.
734 * Otherwise, rewrite the target directory
735 * entry to reference the source inode and
736 * expunge the original entry's existence.
737 */
4f083fd7 738 if (xp == NULL) {
7188ac27
KM
739 if (dp->i_dev != ip->i_dev)
740 panic("rename: EXDEV");
4f083fd7 741 /*
68f21562
KM
742 * Account for ".." in new directory.
743 * When source and destination have the same
744 * parent we don't fool with the link count.
4f083fd7 745 */
68f21562 746 if (doingdirectory && newparent) {
986aedaa
KM
747 if ((unsigned short)dp->i_nlink >= LINK_MAX) {
748 error = EMLINK;
749 goto bad;
750 }
4f083fd7
SL
751 dp->i_nlink++;
752 dp->i_flag |= ICHG;
c59af027 753 if (error = VOP_UPDATE(ITOV(dp), &time, &time, 1))
986aedaa 754 goto bad;
4f083fd7 755 }
031fd966 756 if (error = ufs_direnter(ip, tndp)) {
394d67a8
KM
757 if (doingdirectory && newparent) {
758 dp->i_nlink--;
759 dp->i_flag |= ICHG;
c59af027 760 (void)VOP_UPDATE(ITOV(dp), &time, &time, 1);
394d67a8
KM
761 }
762 goto bad;
763 }
031fd966 764 ufs_iput(dp);
4f083fd7 765 } else {
7188ac27
KM
766 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
767 panic("rename: EXDEV");
e69c3c9c
SL
768 /*
769 * Short circuit rename(foo, foo).
770 */
771 if (xp->i_number == ip->i_number)
7188ac27 772 panic("rename: same file");
80cee150
JB
773 /*
774 * If the parent directory is "sticky", then the user must
775 * own the parent directory, or the destination of the rename,
776 * otherwise the destination may not be changed (except by
777 * root). This implements append-only directories.
778 */
7188ac27
KM
779 if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 &&
780 tndp->ni_cred->cr_uid != dp->i_uid &&
781 xp->i_uid != tndp->ni_cred->cr_uid) {
80cee150
JB
782 error = EPERM;
783 goto bad;
784 }
4f083fd7 785 /*
655da945
KM
786 * Target must be empty if a directory and have no links
787 * to it. Also, ensure source and target are compatible
788 * (both directories, or both not directories).
4f083fd7
SL
789 */
790 if ((xp->i_mode&IFMT) == IFDIR) {
031fd966 791 if (!ufs_dirempty(xp, dp->i_number, tndp->ni_cred) ||
7188ac27 792 xp->i_nlink > 2) {
a5390dce 793 error = ENOTEMPTY;
4f083fd7
SL
794 goto bad;
795 }
796 if (!doingdirectory) {
a5390dce 797 error = ENOTDIR;
4f083fd7
SL
798 goto bad;
799 }
7188ac27 800 cache_purge(ITOV(dp));
4f083fd7 801 } else if (doingdirectory) {
a5390dce 802 error = EISDIR;
4f083fd7
SL
803 goto bad;
804 }
031fd966 805 if (error = ufs_dirrewrite(dp, ip, tndp))
7188ac27 806 goto bad;
a62786b9
KM
807 /*
808 * If the target directory is in the same
809 * directory as the source directory,
810 * decrement the link count on the parent
811 * of the target directory.
812 */
813 if (doingdirectory && !newparent) {
814 dp->i_nlink--;
815 dp->i_flag |= ICHG;
816 }
c59af027 817 ufs_iput(dp);
4f083fd7 818 /*
a5390dce
SL
819 * Adjust the link count of the target to
820 * reflect the dirrewrite above. If this is
821 * a directory it is empty and there are
822 * no links to it, so we can squash the inode and
823 * any space associated with it. We disallowed
824 * renaming over top of a directory with links to
68f21562
KM
825 * it above, as the remaining link would point to
826 * a directory without "." or ".." entries.
4f083fd7 827 */
a5390dce 828 xp->i_nlink--;
4f083fd7 829 if (doingdirectory) {
a5390dce
SL
830 if (--xp->i_nlink != 0)
831 panic("rename: linked directory");
c59af027 832 error = VOP_TRUNCATE(ITOV(xp), (u_long)0, IO_SYNC);
a5390dce 833 }
4f083fd7 834 xp->i_flag |= ICHG;
031fd966 835 ufs_iput(xp);
31db12cb 836 xp = NULL;
4f083fd7
SL
837 }
838
839 /*
840 * 3) Unlink the source.
841 */
655da945
KM
842unlinkit:
843 fndp->ni_nameiop &= ~MODMASK;
844 fndp->ni_nameiop |= LOCKPARENT | LOCKLEAF;
845 if ((fndp->ni_nameiop & SAVESTART) == 0)
846 panic("ufs_rename: lost from startdir");
5e03b55d 847 p->p_spare[1]--;
655da945 848 (void) lookup(fndp, p);
7188ac27
KM
849 if (fndp->ni_vp != NULL) {
850 xp = VTOI(fndp->ni_vp);
851 dp = VTOI(fndp->ni_dvp);
852 } else {
d9d75b8f
KM
853 /*
854 * From name has disappeared.
855 */
856 if (doingdirectory)
857 panic("rename: lost dir entry");
858 vrele(ITOV(ip));
859 return (0);
7188ac27 860 }
4f083fd7 861 /*
7188ac27 862 * Ensure that the directory entry still exists and has not
68f21562
KM
863 * changed while the new name has been entered. If the source is
864 * a file then the entry may have been unlinked or renamed. In
865 * either case there is no further work to be done. If the source
866 * is a directory then it cannot have been rmdir'ed; its link
867 * count of three would cause a rmdir to fail with ENOTEMPTY.
7188ac27 868 * The IRENAME flag ensures that it cannot be moved by another
68f21562 869 * rename.
4f083fd7 870 */
4f1a9037 871 if (xp != ip) {
68f21562 872 if (doingdirectory)
4f1a9037 873 panic("rename: lost dir entry");
68f21562 874 } else {
4f083fd7 875 /*
68f21562
KM
876 * If the source is a directory with a
877 * new parent, the link count of the old
878 * parent directory must be decremented
879 * and ".." set to point to the new parent.
4f083fd7 880 */
68f21562 881 if (doingdirectory && newparent) {
4f083fd7
SL
882 dp->i_nlink--;
883 dp->i_flag |= ICHG;
86cdabf6 884 error = vn_rdwr(UIO_READ, ITOV(xp), (caddr_t)&dirbuf,
7188ac27 885 sizeof (struct dirtemplate), (off_t)0,
86cdabf6 886 UIO_SYSSPACE, IO_NODELOCKED,
5b169cb7 887 tndp->ni_cred, (int *)0, (struct proc *)0);
68f21562
KM
888 if (error == 0) {
889 if (dirbuf.dotdot_namlen != 2 ||
890 dirbuf.dotdot_name[0] != '.' ||
891 dirbuf.dotdot_name[1] != '.') {
031fd966
KB
892 ufs_dirbad(xp, 12,
893 "rename: mangled dir");
68f21562
KM
894 } else {
895 dirbuf.dotdot_ino = newparent;
86cdabf6 896 (void) vn_rdwr(UIO_WRITE, ITOV(xp),
68f21562
KM
897 (caddr_t)&dirbuf,
898 sizeof (struct dirtemplate),
93e273b9 899 (off_t)0, UIO_SYSSPACE,
86cdabf6 900 IO_NODELOCKED|IO_SYNC,
5b169cb7
KM
901 tndp->ni_cred, (int *)0,
902 (struct proc *)0);
7188ac27 903 cache_purge(ITOV(dp));
68f21562
KM
904 }
905 }
4f083fd7 906 }
031fd966 907 error = ufs_dirremove(fndp);
7188ac27 908 if (!error) {
68f21562
KM
909 xp->i_nlink--;
910 xp->i_flag |= ICHG;
4f083fd7 911 }
68f21562 912 xp->i_flag &= ~IRENAME;
4f083fd7 913 }
4f083fd7 914 if (dp)
7188ac27 915 vput(ITOV(dp));
68f21562 916 if (xp)
7188ac27
KM
917 vput(ITOV(xp));
918 vrele(ITOV(ip));
919 return (error);
a5390dce 920
4f083fd7 921bad:
4f083fd7 922 if (xp)
7188ac27
KM
923 vput(ITOV(xp));
924 vput(ITOV(dp));
4f083fd7
SL
925out:
926 ip->i_nlink--;
927 ip->i_flag |= ICHG;
7188ac27
KM
928 vrele(ITOV(ip));
929 return (error);
64d3a787 930}
88a7a62a
SL
931
932/*
933 * A virgin directory (no blushing please).
934 */
031fd966 935static struct dirtemplate mastertemplate = {
88a7a62a
SL
936 0, 12, 1, ".",
937 0, DIRBLKSIZ - 12, 2, ".."
938};
939
940/*
941 * Mkdir system call
942 */
031fd966 943int
5b169cb7 944ufs_mkdir(ndp, vap, p)
7188ac27
KM
945 struct nameidata *ndp;
946 struct vattr *vap;
5b169cb7 947 struct proc *p;
88a7a62a 948{
88a7a62a 949 register struct inode *ip, *dp;
c59af027 950 struct vnode *tvp;
7188ac27 951 struct vnode *dvp;
88a7a62a 952 struct dirtemplate dirtemplate;
7188ac27
KM
953 int error;
954 int dmode;
955
655da945
KM
956#ifdef DIANOSTIC
957 if ((ndp->ni_nameiop & HASBUF) == 0)
958 panic("ufs_mkdir: no name");
959#endif
7188ac27
KM
960 dvp = ndp->ni_dvp;
961 dp = VTOI(dvp);
986aedaa 962 if ((unsigned short)dp->i_nlink >= LINK_MAX) {
655da945 963 free(ndp->ni_pnbuf, M_NAMEI);
031fd966 964 ufs_iput(dp);
986aedaa
KM
965 return (EMLINK);
966 }
7188ac27
KM
967 dmode = vap->va_mode&0777;
968 dmode |= IFDIR;
88a7a62a 969 /*
655da945
KM
970 * Must simulate part of maknode here to acquire the inode, but
971 * not have it entered in the parent directory. The entry is made
972 * later after writing "." and ".." entries.
88a7a62a 973 */
c59af027 974 if (error = VOP_VALLOC(dvp, dmode, ndp->ni_cred, &tvp)) {
655da945 975 free(ndp->ni_pnbuf, M_NAMEI);
031fd966 976 ufs_iput(dp);
7188ac27 977 return (error);
88a7a62a 978 }
c59af027 979 ip = VTOI(tvp);
4b61628b
KM
980 ip->i_uid = ndp->ni_cred->cr_uid;
981 ip->i_gid = dp->i_gid;
88a7a62a 982#ifdef QUOTA
4b61628b
KM
983 if ((error = getinoquota(ip)) ||
984 (error = chkiq(ip, 1, ndp->ni_cred, 0))) {
655da945 985 free(ndp->ni_pnbuf, M_NAMEI);
c59af027 986 VOP_VFREE(tvp, ip->i_number, dmode);
031fd966
KB
987 ufs_iput(ip);
988 ufs_iput(dp);
4b61628b
KM
989 return (error);
990 }
88a7a62a
SL
991#endif
992 ip->i_flag |= IACC|IUPD|ICHG;
7188ac27
KM
993 ip->i_mode = dmode;
994 ITOV(ip)->v_type = VDIR; /* Rest init'd in iget() */
88a7a62a 995 ip->i_nlink = 2;
c59af027 996 error = VOP_UPDATE(ITOV(ip), &time, &time, 1);
88a7a62a
SL
997
998 /*
999 * Bump link count in parent directory
1000 * to reflect work done below. Should
1001 * be done before reference is created
1002 * so reparation is possible if we crash.
1003 */
1004 dp->i_nlink++;
1005 dp->i_flag |= ICHG;
c59af027 1006 if (error = VOP_UPDATE(ITOV(dp), &time, &time, 1))
394d67a8 1007 goto bad;
88a7a62a 1008
031fd966 1009 /* Initialize directory with "." and ".." from static template. */
88a7a62a
SL
1010 dirtemplate = mastertemplate;
1011 dirtemplate.dot_ino = ip->i_number;
1012 dirtemplate.dotdot_ino = dp->i_number;
86cdabf6 1013 error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate,
5b169cb7
KM
1014 sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
1015 IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0, (struct proc *)0);
7188ac27 1016 if (error) {
88a7a62a
SL
1017 dp->i_nlink--;
1018 dp->i_flag |= ICHG;
1019 goto bad;
1020 }
cc173077 1021 if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
031fd966
KB
1022 panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */
1023 else {
23de9f20 1024 ip->i_size = DIRBLKSIZ;
15365e07
KM
1025 ip->i_flag |= ICHG;
1026 }
031fd966
KB
1027
1028 /* Directory set up, now install it's entry in the parent directory. */
1029 if (error = ufs_direnter(ip, ndp)) {
2a5d2f56
KM
1030 dp->i_nlink--;
1031 dp->i_flag |= ICHG;
88a7a62a
SL
1032 }
1033bad:
1034 /*
c59af027
KM
1035 * No need to do an explicit VOP_TRUNCATE here, vrele will do this
1036 * for us because we set the link count to 0.
88a7a62a 1037 */
7188ac27 1038 if (error) {
88a7a62a
SL
1039 ip->i_nlink = 0;
1040 ip->i_flag |= ICHG;
031fd966 1041 ufs_iput(ip);
cbcdacd6
KM
1042 } else
1043 ndp->ni_vp = ITOV(ip);
655da945 1044 FREE(ndp->ni_pnbuf, M_NAMEI);
031fd966 1045 ufs_iput(dp);
7188ac27 1046 return (error);
88a7a62a
SL
1047}
1048
1049/*
1050 * Rmdir system call.
1051 */
031fd966 1052int
5b169cb7 1053ufs_rmdir(ndp, p)
7188ac27 1054 register struct nameidata *ndp;
5b169cb7 1055 struct proc *p;
88a7a62a 1056{
88a7a62a 1057 register struct inode *ip, *dp;
031fd966 1058 int error;
7188ac27
KM
1059
1060 ip = VTOI(ndp->ni_vp);
1061 dp = VTOI(ndp->ni_dvp);
88a7a62a
SL
1062 /*
1063 * No rmdir "." please.
1064 */
1065 if (dp == ip) {
c59af027 1066 vrele(ndp->ni_dvp);
031fd966 1067 ufs_iput(ip);
7188ac27 1068 return (EINVAL);
88a7a62a
SL
1069 }
1070 /*
1071 * Verify the directory is empty (and valid).
1072 * (Rmdir ".." won't be valid since
1073 * ".." will contain a reference to
1074 * the current directory and thus be
1075 * non-empty.)
1076 */
031fd966
KB
1077 error = 0;
1078 if (ip->i_nlink != 2 ||
1079 !ufs_dirempty(ip, dp->i_number, ndp->ni_cred)) {
7188ac27 1080 error = ENOTEMPTY;
88a7a62a
SL
1081 goto out;
1082 }
1083 /*
1084 * Delete reference to directory before purging
1085 * inode. If we crash in between, the directory
1086 * will be reattached to lost+found,
1087 */
031fd966 1088 if (error = ufs_dirremove(ndp))
88a7a62a
SL
1089 goto out;
1090 dp->i_nlink--;
1091 dp->i_flag |= ICHG;
c59af027 1092 cache_purge(ndp->ni_dvp);
031fd966 1093 ufs_iput(dp);
7188ac27 1094 ndp->ni_dvp = NULL;
88a7a62a
SL
1095 /*
1096 * Truncate inode. The only stuff left
1097 * in the directory is "." and "..". The
1098 * "." reference is inconsequential since
1099 * we're quashing it. The ".." reference
1100 * has already been adjusted above. We've
1101 * removed the "." reference and the reference
1102 * in the parent directory, but there may be
1103 * other hard links so decrement by 2 and
1104 * worry about them later.
1105 */
1106 ip->i_nlink -= 2;
c59af027 1107 error = VOP_TRUNCATE(ndp->ni_vp, (u_long)0, IO_SYNC);
7188ac27 1108 cache_purge(ITOV(ip));
88a7a62a 1109out:
7188ac27 1110 if (ndp->ni_dvp)
031fd966
KB
1111 ufs_iput(dp);
1112 ufs_iput(ip);
7188ac27 1113 return (error);
88a7a62a
SL
1114}
1115
7188ac27
KM
1116/*
1117 * symlink -- make a symbolic link
1118 */
031fd966 1119int
5b169cb7 1120ufs_symlink(ndp, vap, target, p)
7188ac27
KM
1121 struct nameidata *ndp;
1122 struct vattr *vap;
1123 char *target;
5b169cb7 1124 struct proc *p;
7188ac27 1125{
c59af027 1126 struct vnode *vp;
7188ac27
KM
1127 int error;
1128
c59af027 1129 if (error = ufs_makeinode(IFLNK | vap->va_mode, ndp, &vp))
7188ac27 1130 return (error);
c59af027 1131 error = vn_rdwr(UIO_WRITE, vp, target, strlen(target), (off_t)0,
5b169cb7
KM
1132 UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0,
1133 (struct proc *)0);
c59af027 1134 vput(vp);
7188ac27
KM
1135 return (error);
1136}
1137
1138/*
1139 * Vnode op for read and write
1140 */
031fd966 1141int
930730fd 1142ufs_readdir(vp, uio, cred, eofflagp)
7188ac27
KM
1143 struct vnode *vp;
1144 register struct uio *uio;
7188ac27 1145 struct ucred *cred;
930730fd 1146 int *eofflagp;
88a7a62a 1147{
86cdabf6 1148 int count, lost, error;
88a7a62a 1149
7188ac27
KM
1150 count = uio->uio_resid;
1151 count &= ~(DIRBLKSIZ - 1);
86cdabf6
KM
1152 lost = uio->uio_resid - count;
1153 if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1)))
7188ac27 1154 return (EINVAL);
7188ac27
KM
1155 uio->uio_resid = count;
1156 uio->uio_iov->iov_len = count;
031fd966 1157 error = VOP_READ(vp, uio, 0, cred);
86cdabf6 1158 uio->uio_resid += lost;
930730fd
KM
1159 if ((VTOI(vp)->i_size - uio->uio_offset) <= 0)
1160 *eofflagp = 1;
1161 else
1162 *eofflagp = 0;
7188ac27
KM
1163 return (error);
1164}
1165
1166/*
1167 * Return target name of a symbolic link
1168 */
031fd966 1169int
7188ac27
KM
1170ufs_readlink(vp, uiop, cred)
1171 struct vnode *vp;
1172 struct uio *uiop;
1173 struct ucred *cred;
1174{
1175
031fd966 1176 return (VOP_READ(vp, uiop, 0, cred));
7188ac27
KM
1177}
1178
1179/*
1180 * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
655da945 1181 * done. If a buffer has been saved in anticipation of a CREATE, delete it.
7188ac27 1182 */
66955caf 1183/* ARGSUSED */
031fd966 1184int
7188ac27 1185ufs_abortop(ndp)
66955caf 1186 struct nameidata *ndp;
7188ac27 1187{
7188ac27 1188
655da945
KM
1189 if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF)
1190 FREE(ndp->ni_pnbuf, M_NAMEI);
66955caf 1191 return (0);
7188ac27
KM
1192}
1193
1c3ebc10
KM
1194/*
1195 * Lock an inode.
1196 */
031fd966 1197int
7188ac27
KM
1198ufs_lock(vp)
1199 struct vnode *vp;
1200{
1201 register struct inode *ip = VTOI(vp);
1202
1203 ILOCK(ip);
1204 return (0);
1205}
1206
1c3ebc10
KM
1207/*
1208 * Unlock an inode.
1209 */
031fd966 1210int
7188ac27
KM
1211ufs_unlock(vp)
1212 struct vnode *vp;
1213{
1214 register struct inode *ip = VTOI(vp);
1215
1216 if (!(ip->i_flag & ILOCKED))
1217 panic("ufs_unlock NOT LOCKED");
1218 IUNLOCK(ip);
1219 return (0);
1220}
1221
1c3ebc10
KM
1222/*
1223 * Check for a locked inode.
1224 */
031fd966 1225int
1c3ebc10
KM
1226ufs_islocked(vp)
1227 struct vnode *vp;
1228{
1229
1230 if (VTOI(vp)->i_flag & ILOCKED)
1231 return (1);
1232 return (0);
1233}
1234
88a7a62a 1235/*
4f1ff475
KM
1236 * Calculate the logical to physical mapping if not done already,
1237 * then call the device strategy routine.
88a7a62a 1238 */
4f1ff475 1239int checkoverlap = 0;
e16fa59e 1240
031fd966 1241int
7188ac27
KM
1242ufs_strategy(bp)
1243 register struct buf *bp;
88a7a62a 1244{
031fd966 1245 register struct inode *ip;
e16fa59e 1246 struct vnode *vp;
e16fa59e
KM
1247 int error;
1248
031fd966 1249 ip = VTOI(bp->b_vp);
e16fa59e
KM
1250 if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR)
1251 panic("ufs_strategy: spec");
1252 if (bp->b_blkno == bp->b_lblkno) {
c59af027
KM
1253 if (error =
1254 VOP_BMAP(bp->b_vp, bp->b_lblkno, NULL, &bp->b_blkno))
e16fa59e 1255 return (error);
20aa076b 1256 if ((long)bp->b_blkno == -1)
e16fa59e 1257 clrbuf(bp);
e16fa59e 1258 }
20aa076b
KM
1259 if ((long)bp->b_blkno == -1) {
1260 biodone(bp);
e16fa59e 1261 return (0);
20aa076b 1262 }
4f1ff475 1263#ifdef DIAGNOSTIC
031fd966
KB
1264 if (checkoverlap && bp->b_vp->v_mount->mnt_stat.f_type == MOUNT_UFS)
1265 ffs_checkoverlap(bp, ip);
1266#endif
1267
e16fa59e
KM
1268 vp = ip->i_devvp;
1269 bp->b_dev = vp->v_rdev;
031fd966 1270 (vp->v_op->vop_strategy)(bp);
7188ac27
KM
1271 return (0);
1272}
88a7a62a 1273
e16fa59e
KM
1274/*
1275 * Print out the contents of an inode.
1276 */
031fd966 1277int
e16fa59e
KM
1278ufs_print(vp)
1279 struct vnode *vp;
1280{
1281 register struct inode *ip = VTOI(vp);
1282
a8f829ed
KM
1283 printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number,
1284 major(ip->i_dev), minor(ip->i_dev));
1285#ifdef FIFO
1286 if (vp->v_type == VFIFO)
1287 fifo_printinfo(vp);
1288#endif /* FIFO */
1289 printf("%s\n", (ip->i_flag & ILOCKED) ? " (LOCKED)" : "");
4a8fb1bb 1290 if (ip->i_lockholder == 0)
031fd966 1291 return (0);
4a8fb1bb
KM
1292 printf("\towner pid %d", ip->i_lockholder);
1293 if (ip->i_lockwaiter)
1294 printf(" waiting pid %d", ip->i_lockwaiter);
96bae3e0 1295 printf("\n");
031fd966 1296 return (0);
e16fa59e
KM
1297}
1298
24a31b70
KM
1299/*
1300 * Read wrapper for special devices.
1301 */
031fd966 1302int
24a31b70
KM
1303ufsspec_read(vp, uio, ioflag, cred)
1304 struct vnode *vp;
1305 struct uio *uio;
1306 int ioflag;
1307 struct ucred *cred;
1308{
1309
1310 /*
1311 * Set access flag.
1312 */
1313 VTOI(vp)->i_flag |= IACC;
1314 return (spec_read(vp, uio, ioflag, cred));
1315}
1316
1317/*
1318 * Write wrapper for special devices.
1319 */
031fd966 1320int
24a31b70
KM
1321ufsspec_write(vp, uio, ioflag, cred)
1322 struct vnode *vp;
1323 struct uio *uio;
1324 int ioflag;
1325 struct ucred *cred;
1326{
1327
1328 /*
1329 * Set update and change flags.
1330 */
1331 VTOI(vp)->i_flag |= IUPD|ICHG;
1332 return (spec_write(vp, uio, ioflag, cred));
1333}
1334
1335/*
1336 * Close wrapper for special devices.
1337 *
1338 * Update the times on the inode then do device close.
1339 */
031fd966 1340int
5b169cb7 1341ufsspec_close(vp, fflag, cred, p)
24a31b70
KM
1342 struct vnode *vp;
1343 int fflag;
1344 struct ucred *cred;
5b169cb7 1345 struct proc *p;
24a31b70
KM
1346{
1347 register struct inode *ip = VTOI(vp);
1348
de67eefc 1349 if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
24a31b70 1350 ITIMES(ip, &time, &time);
5b169cb7 1351 return (spec_close(vp, fflag, cred, p));
24a31b70
KM
1352}
1353
d1c43d7f
KM
1354#ifdef FIFO
1355/*
1356 * Read wrapper for fifo's
1357 */
031fd966 1358int
d1c43d7f
KM
1359ufsfifo_read(vp, uio, ioflag, cred)
1360 struct vnode *vp;
1361 struct uio *uio;
1362 int ioflag;
1363 struct ucred *cred;
1364{
1365
1366 /*
1367 * Set access flag.
1368 */
1369 VTOI(vp)->i_flag |= IACC;
1370 return (fifo_read(vp, uio, ioflag, cred));
1371}
1372
1373/*
1374 * Write wrapper for fifo's.
1375 */
031fd966 1376int
d1c43d7f
KM
1377ufsfifo_write(vp, uio, ioflag, cred)
1378 struct vnode *vp;
1379 struct uio *uio;
1380 int ioflag;
1381 struct ucred *cred;
1382{
1383
1384 /*
1385 * Set update and change flags.
1386 */
1387 VTOI(vp)->i_flag |= IUPD|ICHG;
1388 return (fifo_write(vp, uio, ioflag, cred));
1389}
1390
1391/*
1392 * Close wrapper for fifo's.
1393 *
1394 * Update the times on the inode then do device close.
1395 */
5b169cb7 1396ufsfifo_close(vp, fflag, cred, p)
d1c43d7f
KM
1397 struct vnode *vp;
1398 int fflag;
1399 struct ucred *cred;
5b169cb7 1400 struct proc *p;
d1c43d7f
KM
1401{
1402 register struct inode *ip = VTOI(vp);
1403
1404 if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
1405 ITIMES(ip, &time, &time);
5b169cb7 1406 return (fifo_close(vp, fflag, cred, p));
d1c43d7f
KM
1407}
1408#endif /* FIFO */
1409
0b0bf936
KM
1410/*
1411 * Advisory record locking support
1412 */
031fd966 1413int
0b0bf936
KM
1414ufs_advlock(vp, id, op, fl, flags)
1415 struct vnode *vp;
1416 caddr_t id;
1417 int op;
1418 register struct flock *fl;
1419 int flags;
1420{
1421 register struct inode *ip = VTOI(vp);
1422 register struct lockf *lock;
1423 off_t start, end;
1424 int error;
1425
1426 /*
1427 * Avoid the common case of unlocking when inode has no locks.
1428 */
1429 if (ip->i_lockf == (struct lockf *)0) {
1430 if (op != F_SETLK) {
1431 fl->l_type = F_UNLCK;
1432 return (0);
1433 }
1434 }
1435 /*
1436 * Convert the flock structure into a start and end.
1437 */
1438 switch (fl->l_whence) {
1439
1440 case SEEK_SET:
1441 case SEEK_CUR:
1442 /*
1443 * Caller is responsible for adding any necessary offset
1444 * when SEEK_CUR is used.
1445 */
1446 start = fl->l_start;
1447 break;
1448
1449 case SEEK_END:
1450 start = ip->i_size + fl->l_start;
1451 break;
1452
1453 default:
1454 return (EINVAL);
1455 }
1456 if (start < 0)
1457 return (EINVAL);
1458 if (fl->l_len == 0)
1459 end = -1;
1460 else
c412cb68 1461 end = start + fl->l_len - 1;
0b0bf936
KM
1462 /*
1463 * Create the lockf structure
1464 */
1465 MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK);
1466 lock->lf_start = start;
1467 lock->lf_end = end;
1468 lock->lf_id = id;
1469 lock->lf_inode = ip;
1470 lock->lf_type = fl->l_type;
1471 lock->lf_next = (struct lockf *)0;
1472 lock->lf_block = (struct lockf *)0;
1473 lock->lf_flags = flags;
1474 /*
1475 * Do the requested operation.
1476 */
1477 switch(op) {
1478 case F_SETLK:
b9fc1077 1479 return (lf_setlock(lock));
0b0bf936
KM
1480
1481 case F_UNLCK:
b9fc1077
KM
1482 error = lf_clearlock(lock);
1483 FREE(lock, M_LOCKF);
1484 return (error);
0b0bf936
KM
1485
1486 case F_GETLK:
b9fc1077
KM
1487 error = lf_getlock(lock, fl);
1488 FREE(lock, M_LOCKF);
1489 return (error);
0b0bf936
KM
1490
1491 default:
1492 free(lock, M_LOCKF);
1493 return (EINVAL);
1494 }
1495 /* NOTREACHED */
1496}
5b169cb7
KM
1497
1498/*
031fd966
KB
1499 * Initialize the vnode associated with a new inode, handle aliased
1500 * vnodes.
5b169cb7 1501 */
031fd966 1502int
c59af027 1503ufs_vinit(mntp, specops, fifoops, vpp)
031fd966 1504 struct mount *mntp;
c59af027 1505 struct vnodeops *specops, *fifoops;
031fd966
KB
1506 struct vnode **vpp;
1507{
1508 struct inode *ip, *nip;
1509 struct vnode *vp, *nvp;
4a8fb1bb 1510 extern struct vnodeops spec_vnodeops;
031fd966
KB
1511
1512 vp = *vpp;
1513 ip = VTOI(vp);
1514 switch(vp->v_type = IFTOVT(ip->i_mode)) {
1515 case VCHR:
1516 case VBLK:
c59af027 1517 vp->v_op = specops;
031fd966 1518 if (nvp = checkalias(vp, ip->i_rdev, mntp)) {
c59af027 1519 /*
4a8fb1bb 1520 * Discard unneeded vnode, but save its inode.
c59af027 1521 */
4a8fb1bb
KM
1522 remque(ip);
1523 IUNLOCK(ip);
1524 nvp->v_data = vp->v_data;
1525 vp->v_data = NULL;
1526 vp->v_op = &spec_vnodeops;
1527 vrele(vp);
1528 vgone(vp);
c59af027 1529 /*
4a8fb1bb 1530 * Reinitialize aliased inode.
c59af027 1531 */
4a8fb1bb
KM
1532 vp = nvp;
1533 ip->i_vnode = vp;
1534 ufs_ihashins(ip);
031fd966
KB
1535 }
1536 break;
1537 case VFIFO:
1538#ifdef FIFO
c59af027 1539 vp->v_op = fifoops;
031fd966
KB
1540 break;
1541#else
1542 return (EOPNOTSUPP);
1543#endif
1544 }
031fd966
KB
1545 if (ip->i_number == ROOTINO)
1546 vp->v_flag |= VROOT;
1a3cb193
KM
1547 /*
1548 * Initialize modrev times
1549 */
1550 SETHIGH(ip->i_modrev, mono_time.tv_sec);
1551 SETLOW(ip->i_modrev, mono_time.tv_usec * 4294);
031fd966
KB
1552 *vpp = vp;
1553 return (0);
1554}
5b169cb7 1555
031fd966
KB
1556/*
1557 * Allocate a new inode.
1558 */
1559int
c59af027 1560ufs_makeinode(mode, ndp, vpp)
031fd966
KB
1561 int mode;
1562 register struct nameidata *ndp;
c59af027 1563 struct vnode **vpp;
031fd966
KB
1564{
1565 register struct inode *ip, *pdir;
c59af027 1566 struct vnode *tvp;
031fd966
KB
1567 int error;
1568
1569 pdir = VTOI(ndp->ni_dvp);
1570#ifdef DIANOSTIC
1571 if ((ndp->ni_nameiop & HASBUF) == 0)
1572 panic("ufs_makeinode: no name");
1573#endif
c59af027 1574 *vpp = NULL;
031fd966
KB
1575 if ((mode & IFMT) == 0)
1576 mode |= IFREG;
1577
c59af027 1578 if (error = VOP_VALLOC(ndp->ni_dvp, mode, ndp->ni_cred, &tvp)) {
031fd966
KB
1579 free(ndp->ni_pnbuf, M_NAMEI);
1580 ufs_iput(pdir);
1581 return (error);
1582 }
c59af027 1583 ip = VTOI(tvp);
031fd966
KB
1584 ip->i_uid = ndp->ni_cred->cr_uid;
1585 ip->i_gid = pdir->i_gid;
1586#ifdef QUOTA
1587 if ((error = getinoquota(ip)) ||
1588 (error = chkiq(ip, 1, ndp->ni_cred, 0))) {
1589 free(ndp->ni_pnbuf, M_NAMEI);
c59af027 1590 VOP_VFREE(tvp, ip->i_number, mode);
031fd966
KB
1591 ufs_iput(ip);
1592 ufs_iput(pdir);
1593 return (error);
1594 }
1595#endif
1596 ip->i_flag |= IACC|IUPD|ICHG;
1597 ip->i_mode = mode;
c59af027 1598 tvp->v_type = IFTOVT(mode); /* Rest init'd in iget() */
031fd966
KB
1599 ip->i_nlink = 1;
1600 if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) &&
1601 suser(ndp->ni_cred, NULL))
1602 ip->i_mode &= ~ISGID;
1603
1604 /*
1605 * Make sure inode goes to disk before directory entry.
1606 */
c59af027 1607 if (error = VOP_UPDATE(tvp, &time, &time, 1))
031fd966
KB
1608 goto bad;
1609 if (error = ufs_direnter(ip, ndp))
1610 goto bad;
1611 if ((ndp->ni_nameiop & SAVESTART) == 0)
1612 FREE(ndp->ni_pnbuf, M_NAMEI);
1613 ufs_iput(pdir);
c59af027 1614 *vpp = tvp;
031fd966
KB
1615 return (0);
1616
1617bad:
1618 /*
1619 * Write error occurred trying to update the inode
1620 * or the directory so must deallocate the inode.
1621 */
1622 free(ndp->ni_pnbuf, M_NAMEI);
1623 ufs_iput(pdir);
1624 ip->i_nlink = 0;
1625 ip->i_flag |= ICHG;
1626 ufs_iput(ip);
1627 return (error);
1628}