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