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