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