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