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