update rename to use new namei / lookup scheme
[unix-history] / usr / src / sys / ufs / ufs / ufs_vnops.c
CommitLineData
da7c5cc6 1/*
7188ac27
KM
2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
3 * All rights reserved.
da7c5cc6 4 *
b702c21d 5 * %sccs.include.redist.c%
7188ac27 6 *
655da945 7 * @(#)ufs_vnops.c 7.63 (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");
841 if (error = lookup(tndp, p))
842 goto out;
843 dp = VTOI(tndp->ni_dvp);
844 xp = NULL;
845 if (tndp->ni_vp)
846 xp = VTOI(tndp->ni_vp);
81552f0f 847 }
4f083fd7
SL
848 /*
849 * 2) If target doesn't exist, link the target
850 * to the source and unlink the source.
851 * Otherwise, rewrite the target directory
852 * entry to reference the source inode and
853 * expunge the original entry's existence.
854 */
4f083fd7 855 if (xp == NULL) {
7188ac27
KM
856 if (dp->i_dev != ip->i_dev)
857 panic("rename: EXDEV");
4f083fd7 858 /*
68f21562
KM
859 * Account for ".." in new directory.
860 * When source and destination have the same
861 * parent we don't fool with the link count.
4f083fd7 862 */
68f21562 863 if (doingdirectory && newparent) {
986aedaa
KM
864 if ((unsigned short)dp->i_nlink >= LINK_MAX) {
865 error = EMLINK;
866 goto bad;
867 }
4f083fd7
SL
868 dp->i_nlink++;
869 dp->i_flag |= ICHG;
986aedaa
KM
870 if (error = iupdat(dp, &time, &time, 1))
871 goto bad;
4f083fd7 872 }
394d67a8
KM
873 if (error = direnter(ip, tndp)) {
874 if (doingdirectory && newparent) {
875 dp->i_nlink--;
876 dp->i_flag |= ICHG;
877 (void) iupdat(dp, &time, &time, 1);
878 }
879 goto bad;
880 }
4093ba31 881 iput(dp);
4f083fd7 882 } else {
7188ac27
KM
883 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
884 panic("rename: EXDEV");
e69c3c9c
SL
885 /*
886 * Short circuit rename(foo, foo).
887 */
888 if (xp->i_number == ip->i_number)
7188ac27 889 panic("rename: same file");
80cee150
JB
890 /*
891 * If the parent directory is "sticky", then the user must
892 * own the parent directory, or the destination of the rename,
893 * otherwise the destination may not be changed (except by
894 * root). This implements append-only directories.
895 */
7188ac27
KM
896 if ((dp->i_mode & ISVTX) && tndp->ni_cred->cr_uid != 0 &&
897 tndp->ni_cred->cr_uid != dp->i_uid &&
898 xp->i_uid != tndp->ni_cred->cr_uid) {
80cee150
JB
899 error = EPERM;
900 goto bad;
901 }
4f083fd7 902 /*
655da945
KM
903 * Target must be empty if a directory and have no links
904 * to it. Also, ensure source and target are compatible
905 * (both directories, or both not directories).
4f083fd7
SL
906 */
907 if ((xp->i_mode&IFMT) == IFDIR) {
7188ac27
KM
908 if (!dirempty(xp, dp->i_number, tndp->ni_cred) ||
909 xp->i_nlink > 2) {
a5390dce 910 error = ENOTEMPTY;
4f083fd7
SL
911 goto bad;
912 }
913 if (!doingdirectory) {
a5390dce 914 error = ENOTDIR;
4f083fd7
SL
915 goto bad;
916 }
7188ac27 917 cache_purge(ITOV(dp));
4f083fd7 918 } else if (doingdirectory) {
a5390dce 919 error = EISDIR;
4f083fd7
SL
920 goto bad;
921 }
7188ac27
KM
922 if (error = dirrewrite(dp, ip, tndp))
923 goto bad;
a62786b9
KM
924 /*
925 * If the target directory is in the same
926 * directory as the source directory,
927 * decrement the link count on the parent
928 * of the target directory.
929 */
930 if (doingdirectory && !newparent) {
931 dp->i_nlink--;
932 dp->i_flag |= ICHG;
933 }
7188ac27 934 vput(ITOV(dp));
4f083fd7 935 /*
a5390dce
SL
936 * Adjust the link count of the target to
937 * reflect the dirrewrite above. If this is
938 * a directory it is empty and there are
939 * no links to it, so we can squash the inode and
940 * any space associated with it. We disallowed
941 * renaming over top of a directory with links to
68f21562
KM
942 * it above, as the remaining link would point to
943 * a directory without "." or ".." entries.
4f083fd7 944 */
a5390dce 945 xp->i_nlink--;
4f083fd7 946 if (doingdirectory) {
a5390dce
SL
947 if (--xp->i_nlink != 0)
948 panic("rename: linked directory");
e16fa59e 949 error = itrunc(xp, (u_long)0, IO_SYNC);
a5390dce 950 }
4f083fd7 951 xp->i_flag |= ICHG;
88d931ba 952 iput(xp);
31db12cb 953 xp = NULL;
4f083fd7
SL
954 }
955
956 /*
957 * 3) Unlink the source.
958 */
655da945
KM
959unlinkit:
960 fndp->ni_nameiop &= ~MODMASK;
961 fndp->ni_nameiop |= LOCKPARENT | LOCKLEAF;
962 if ((fndp->ni_nameiop & SAVESTART) == 0)
963 panic("ufs_rename: lost from startdir");
964 (void) lookup(fndp, p);
7188ac27
KM
965 if (fndp->ni_vp != NULL) {
966 xp = VTOI(fndp->ni_vp);
967 dp = VTOI(fndp->ni_dvp);
968 } else {
d9d75b8f
KM
969 /*
970 * From name has disappeared.
971 */
972 if (doingdirectory)
973 panic("rename: lost dir entry");
974 vrele(ITOV(ip));
975 return (0);
7188ac27 976 }
4f083fd7 977 /*
7188ac27 978 * Ensure that the directory entry still exists and has not
68f21562
KM
979 * changed while the new name has been entered. If the source is
980 * a file then the entry may have been unlinked or renamed. In
981 * either case there is no further work to be done. If the source
982 * is a directory then it cannot have been rmdir'ed; its link
983 * count of three would cause a rmdir to fail with ENOTEMPTY.
7188ac27 984 * The IRENAME flag ensures that it cannot be moved by another
68f21562 985 * rename.
4f083fd7 986 */
4f1a9037 987 if (xp != ip) {
68f21562 988 if (doingdirectory)
4f1a9037 989 panic("rename: lost dir entry");
68f21562 990 } else {
4f083fd7 991 /*
68f21562
KM
992 * If the source is a directory with a
993 * new parent, the link count of the old
994 * parent directory must be decremented
995 * and ".." set to point to the new parent.
4f083fd7 996 */
68f21562 997 if (doingdirectory && newparent) {
4f083fd7
SL
998 dp->i_nlink--;
999 dp->i_flag |= ICHG;
86cdabf6 1000 error = vn_rdwr(UIO_READ, ITOV(xp), (caddr_t)&dirbuf,
7188ac27 1001 sizeof (struct dirtemplate), (off_t)0,
86cdabf6 1002 UIO_SYSSPACE, IO_NODELOCKED,
5b169cb7 1003 tndp->ni_cred, (int *)0, (struct proc *)0);
68f21562
KM
1004 if (error == 0) {
1005 if (dirbuf.dotdot_namlen != 2 ||
1006 dirbuf.dotdot_name[0] != '.' ||
1007 dirbuf.dotdot_name[1] != '.') {
8ad54d9e 1008 dirbad(xp, 12, "rename: mangled dir");
68f21562
KM
1009 } else {
1010 dirbuf.dotdot_ino = newparent;
86cdabf6 1011 (void) vn_rdwr(UIO_WRITE, ITOV(xp),
68f21562
KM
1012 (caddr_t)&dirbuf,
1013 sizeof (struct dirtemplate),
93e273b9 1014 (off_t)0, UIO_SYSSPACE,
86cdabf6 1015 IO_NODELOCKED|IO_SYNC,
5b169cb7
KM
1016 tndp->ni_cred, (int *)0,
1017 (struct proc *)0);
7188ac27 1018 cache_purge(ITOV(dp));
68f21562
KM
1019 }
1020 }
4f083fd7 1021 }
7188ac27
KM
1022 error = dirremove(fndp);
1023 if (!error) {
68f21562
KM
1024 xp->i_nlink--;
1025 xp->i_flag |= ICHG;
4f083fd7 1026 }
68f21562 1027 xp->i_flag &= ~IRENAME;
4f083fd7 1028 }
4f083fd7 1029 if (dp)
7188ac27 1030 vput(ITOV(dp));
68f21562 1031 if (xp)
7188ac27
KM
1032 vput(ITOV(xp));
1033 vrele(ITOV(ip));
1034 return (error);
a5390dce 1035
4f083fd7 1036bad:
4f083fd7 1037 if (xp)
7188ac27
KM
1038 vput(ITOV(xp));
1039 vput(ITOV(dp));
4f083fd7
SL
1040out:
1041 ip->i_nlink--;
1042 ip->i_flag |= ICHG;
7188ac27
KM
1043 vrele(ITOV(ip));
1044 return (error);
64d3a787 1045}
88a7a62a
SL
1046
1047/*
1048 * A virgin directory (no blushing please).
1049 */
1050struct dirtemplate mastertemplate = {
1051 0, 12, 1, ".",
1052 0, DIRBLKSIZ - 12, 2, ".."
1053};
1054
1055/*
1056 * Mkdir system call
1057 */
5b169cb7 1058ufs_mkdir(ndp, vap, p)
7188ac27
KM
1059 struct nameidata *ndp;
1060 struct vattr *vap;
5b169cb7 1061 struct proc *p;
88a7a62a 1062{
88a7a62a 1063 register struct inode *ip, *dp;
7188ac27
KM
1064 struct inode *tip;
1065 struct vnode *dvp;
88a7a62a 1066 struct dirtemplate dirtemplate;
7188ac27
KM
1067 int error;
1068 int dmode;
1069
655da945
KM
1070#ifdef DIANOSTIC
1071 if ((ndp->ni_nameiop & HASBUF) == 0)
1072 panic("ufs_mkdir: no name");
1073#endif
7188ac27
KM
1074 dvp = ndp->ni_dvp;
1075 dp = VTOI(dvp);
986aedaa 1076 if ((unsigned short)dp->i_nlink >= LINK_MAX) {
655da945 1077 free(ndp->ni_pnbuf, M_NAMEI);
986aedaa
KM
1078 iput(dp);
1079 return (EMLINK);
1080 }
7188ac27
KM
1081 dmode = vap->va_mode&0777;
1082 dmode |= IFDIR;
88a7a62a 1083 /*
655da945
KM
1084 * Must simulate part of maknode here to acquire the inode, but
1085 * not have it entered in the parent directory. The entry is made
1086 * later after writing "." and ".." entries.
88a7a62a 1087 */
4b61628b 1088 if (error = ialloc(dp, dirpref(dp->i_fs), dmode, ndp->ni_cred, &tip)) {
655da945 1089 free(ndp->ni_pnbuf, M_NAMEI);
88a7a62a 1090 iput(dp);
7188ac27 1091 return (error);
88a7a62a 1092 }
7188ac27 1093 ip = tip;
4b61628b
KM
1094 ip->i_uid = ndp->ni_cred->cr_uid;
1095 ip->i_gid = dp->i_gid;
88a7a62a 1096#ifdef QUOTA
4b61628b
KM
1097 if ((error = getinoquota(ip)) ||
1098 (error = chkiq(ip, 1, ndp->ni_cred, 0))) {
655da945 1099 free(ndp->ni_pnbuf, M_NAMEI);
4b61628b
KM
1100 ifree(ip, ip->i_number, dmode);
1101 iput(ip);
1102 iput(dp);
1103 return (error);
1104 }
88a7a62a
SL
1105#endif
1106 ip->i_flag |= IACC|IUPD|ICHG;
7188ac27
KM
1107 ip->i_mode = dmode;
1108 ITOV(ip)->v_type = VDIR; /* Rest init'd in iget() */
88a7a62a 1109 ip->i_nlink = 2;
7188ac27 1110 error = iupdat(ip, &time, &time, 1);
88a7a62a
SL
1111
1112 /*
1113 * Bump link count in parent directory
1114 * to reflect work done below. Should
1115 * be done before reference is created
1116 * so reparation is possible if we crash.
1117 */
1118 dp->i_nlink++;
1119 dp->i_flag |= ICHG;
394d67a8
KM
1120 if (error = iupdat(dp, &time, &time, 1))
1121 goto bad;
88a7a62a
SL
1122
1123 /*
1124 * Initialize directory with "."
1125 * and ".." from static template.
1126 */
1127 dirtemplate = mastertemplate;
1128 dirtemplate.dot_ino = ip->i_number;
1129 dirtemplate.dotdot_ino = dp->i_number;
86cdabf6 1130 error = vn_rdwr(UIO_WRITE, ITOV(ip), (caddr_t)&dirtemplate,
5b169cb7
KM
1131 sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
1132 IO_NODELOCKED|IO_SYNC, ndp->ni_cred, (int *)0, (struct proc *)0);
7188ac27 1133 if (error) {
88a7a62a
SL
1134 dp->i_nlink--;
1135 dp->i_flag |= ICHG;
1136 goto bad;
1137 }
15365e07 1138 if (DIRBLKSIZ > dp->i_fs->fs_fsize) {
7188ac27 1139 panic("mkdir: blksize"); /* XXX - should grow w/balloc() */
15365e07 1140 } else {
23de9f20 1141 ip->i_size = DIRBLKSIZ;
15365e07
KM
1142 ip->i_flag |= ICHG;
1143 }
88a7a62a
SL
1144 /*
1145 * Directory all set up, now
1146 * install the entry for it in
1147 * the parent directory.
1148 */
394d67a8 1149 if (error = direnter(ip, ndp)) {
2a5d2f56
KM
1150 dp->i_nlink--;
1151 dp->i_flag |= ICHG;
88a7a62a
SL
1152 }
1153bad:
1154 /*
1155 * No need to do an explicit itrunc here,
7188ac27 1156 * vrele will do this for us because we set
88a7a62a
SL
1157 * the link count to 0.
1158 */
7188ac27 1159 if (error) {
88a7a62a
SL
1160 ip->i_nlink = 0;
1161 ip->i_flag |= ICHG;
cbcdacd6
KM
1162 iput(ip);
1163 } else
1164 ndp->ni_vp = ITOV(ip);
655da945 1165 FREE(ndp->ni_pnbuf, M_NAMEI);
394d67a8 1166 iput(dp);
7188ac27 1167 return (error);
88a7a62a
SL
1168}
1169
1170/*
1171 * Rmdir system call.
1172 */
5b169cb7 1173ufs_rmdir(ndp, p)
7188ac27 1174 register struct nameidata *ndp;
5b169cb7 1175 struct proc *p;
88a7a62a 1176{
88a7a62a 1177 register struct inode *ip, *dp;
7188ac27
KM
1178 int error = 0;
1179
1180 ip = VTOI(ndp->ni_vp);
1181 dp = VTOI(ndp->ni_dvp);
88a7a62a
SL
1182 /*
1183 * No rmdir "." please.
1184 */
1185 if (dp == ip) {
7188ac27 1186 vrele(ITOV(dp));
88a7a62a 1187 iput(ip);
7188ac27 1188 return (EINVAL);
88a7a62a
SL
1189 }
1190 /*
1191 * Verify the directory is empty (and valid).
1192 * (Rmdir ".." won't be valid since
1193 * ".." will contain a reference to
1194 * the current directory and thus be
1195 * non-empty.)
1196 */
7188ac27
KM
1197 if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number, ndp->ni_cred)) {
1198 error = ENOTEMPTY;
88a7a62a
SL
1199 goto out;
1200 }
1201 /*
1202 * Delete reference to directory before purging
1203 * inode. If we crash in between, the directory
1204 * will be reattached to lost+found,
1205 */
7188ac27 1206 if (error = dirremove(ndp))
88a7a62a
SL
1207 goto out;
1208 dp->i_nlink--;
1209 dp->i_flag |= ICHG;
7188ac27 1210 cache_purge(ITOV(dp));
88a7a62a 1211 iput(dp);
7188ac27 1212 ndp->ni_dvp = NULL;
88a7a62a
SL
1213 /*
1214 * Truncate inode. The only stuff left
1215 * in the directory is "." and "..". The
1216 * "." reference is inconsequential since
1217 * we're quashing it. The ".." reference
1218 * has already been adjusted above. We've
1219 * removed the "." reference and the reference
1220 * in the parent directory, but there may be
1221 * other hard links so decrement by 2 and
1222 * worry about them later.
1223 */
1224 ip->i_nlink -= 2;
e16fa59e 1225 error = itrunc(ip, (u_long)0, IO_SYNC);
7188ac27 1226 cache_purge(ITOV(ip));
88a7a62a 1227out:
7188ac27 1228 if (ndp->ni_dvp)
88a7a62a
SL
1229 iput(dp);
1230 iput(ip);
7188ac27 1231 return (error);
88a7a62a
SL
1232}
1233
7188ac27
KM
1234/*
1235 * symlink -- make a symbolic link
1236 */
5b169cb7 1237ufs_symlink(ndp, vap, target, p)
7188ac27
KM
1238 struct nameidata *ndp;
1239 struct vattr *vap;
1240 char *target;
5b169cb7 1241 struct proc *p;
7188ac27
KM
1242{
1243 struct inode *ip;
1244 int error;
1245
1246 error = maknode(IFLNK | vap->va_mode, ndp, &ip);
1247 if (error)
1248 return (error);
86cdabf6 1249 error = vn_rdwr(UIO_WRITE, ITOV(ip), target, strlen(target), (off_t)0,
5b169cb7
KM
1250 UIO_SYSSPACE, IO_NODELOCKED, ndp->ni_cred, (int *)0,
1251 (struct proc *)0);
7188ac27
KM
1252 iput(ip);
1253 return (error);
1254}
1255
1256/*
1257 * Vnode op for read and write
1258 */
930730fd 1259ufs_readdir(vp, uio, cred, eofflagp)
7188ac27
KM
1260 struct vnode *vp;
1261 register struct uio *uio;
7188ac27 1262 struct ucred *cred;
930730fd 1263 int *eofflagp;
88a7a62a 1264{
86cdabf6 1265 int count, lost, error;
88a7a62a 1266
7188ac27
KM
1267 count = uio->uio_resid;
1268 count &= ~(DIRBLKSIZ - 1);
86cdabf6
KM
1269 lost = uio->uio_resid - count;
1270 if (count < DIRBLKSIZ || (uio->uio_offset & (DIRBLKSIZ -1)))
7188ac27 1271 return (EINVAL);
7188ac27
KM
1272 uio->uio_resid = count;
1273 uio->uio_iov->iov_len = count;
86cdabf6
KM
1274 error = ufs_read(vp, uio, 0, cred);
1275 uio->uio_resid += lost;
930730fd
KM
1276 if ((VTOI(vp)->i_size - uio->uio_offset) <= 0)
1277 *eofflagp = 1;
1278 else
1279 *eofflagp = 0;
7188ac27
KM
1280 return (error);
1281}
1282
1283/*
1284 * Return target name of a symbolic link
1285 */
1286ufs_readlink(vp, uiop, cred)
1287 struct vnode *vp;
1288 struct uio *uiop;
1289 struct ucred *cred;
1290{
1291
86cdabf6 1292 return (ufs_read(vp, uiop, 0, cred));
7188ac27
KM
1293}
1294
1295/*
1296 * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
655da945 1297 * done. If a buffer has been saved in anticipation of a CREATE, delete it.
7188ac27 1298 */
66955caf 1299/* ARGSUSED */
7188ac27 1300ufs_abortop(ndp)
66955caf 1301 struct nameidata *ndp;
7188ac27 1302{
7188ac27 1303
655da945
KM
1304 if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF)
1305 FREE(ndp->ni_pnbuf, M_NAMEI);
66955caf 1306 return (0);
7188ac27
KM
1307}
1308
1c3ebc10
KM
1309/*
1310 * Lock an inode.
1311 */
7188ac27
KM
1312ufs_lock(vp)
1313 struct vnode *vp;
1314{
1315 register struct inode *ip = VTOI(vp);
1316
1317 ILOCK(ip);
1318 return (0);
1319}
1320
1c3ebc10
KM
1321/*
1322 * Unlock an inode.
1323 */
7188ac27
KM
1324ufs_unlock(vp)
1325 struct vnode *vp;
1326{
1327 register struct inode *ip = VTOI(vp);
1328
1329 if (!(ip->i_flag & ILOCKED))
1330 panic("ufs_unlock NOT LOCKED");
1331 IUNLOCK(ip);
1332 return (0);
1333}
1334
1c3ebc10
KM
1335/*
1336 * Check for a locked inode.
1337 */
1338ufs_islocked(vp)
1339 struct vnode *vp;
1340{
1341
1342 if (VTOI(vp)->i_flag & ILOCKED)
1343 return (1);
1344 return (0);
1345}
1346
7188ac27
KM
1347/*
1348 * Get access to bmap
1349 */
1350ufs_bmap(vp, bn, vpp, bnp)
1351 struct vnode *vp;
1352 daddr_t bn;
1353 struct vnode **vpp;
1354 daddr_t *bnp;
1355{
1356 struct inode *ip = VTOI(vp);
1357
1358 if (vpp != NULL)
1359 *vpp = ip->i_devvp;
1360 if (bnp == NULL)
1361 return (0);
4f1ff475 1362 return (bmap(ip, bn, bnp));
88a7a62a
SL
1363}
1364
1365/*
4f1ff475
KM
1366 * Calculate the logical to physical mapping if not done already,
1367 * then call the device strategy routine.
88a7a62a 1368 */
4f1ff475 1369int checkoverlap = 0;
e16fa59e 1370
7188ac27
KM
1371ufs_strategy(bp)
1372 register struct buf *bp;
88a7a62a 1373{
e16fa59e 1374 register struct inode *ip = VTOI(bp->b_vp);
e16fa59e 1375 struct vnode *vp;
e16fa59e
KM
1376 int error;
1377
1378 if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR)
1379 panic("ufs_strategy: spec");
1380 if (bp->b_blkno == bp->b_lblkno) {
1381 if (error = bmap(ip, bp->b_lblkno, &bp->b_blkno))
1382 return (error);
20aa076b 1383 if ((long)bp->b_blkno == -1)
e16fa59e 1384 clrbuf(bp);
e16fa59e 1385 }
20aa076b
KM
1386 if ((long)bp->b_blkno == -1) {
1387 biodone(bp);
e16fa59e 1388 return (0);
20aa076b 1389 }
4f1ff475 1390#ifdef DIAGNOSTIC
e16fa59e 1391 if (checkoverlap) {
4f1ff475
KM
1392 register struct buf *ep;
1393 struct buf *ebp;
1394 daddr_t start, last;
1395
e16fa59e
KM
1396 ebp = &buf[nbuf];
1397 start = bp->b_blkno;
1398 last = start + btodb(bp->b_bcount) - 1;
1399 for (ep = buf; ep < ebp; ep++) {
1400 if (ep == bp || (ep->b_flags & B_INVAL) ||
fcd4f15a 1401 ep->b_vp == NULLVP)
e16fa59e
KM
1402 continue;
1403 if (VOP_BMAP(ep->b_vp, (daddr_t)0, &vp, (daddr_t)0))
1404 continue;
1405 if (vp != ip->i_devvp)
1406 continue;
1407 /* look for overlap */
1408 if (ep->b_bcount == 0 || ep->b_blkno > last ||
1409 ep->b_blkno + btodb(ep->b_bcount) <= start)
1410 continue;
20aa076b
KM
1411 vprint("Disk overlap", vp);
1412 printf("\tstart %d, end %d overlap start %d, end %d\n",
1413 start, last, ep->b_blkno,
1414 ep->b_blkno + btodb(ep->b_bcount) - 1);
4f1ff475 1415 panic("Disk buffer overlap");
e16fa59e
KM
1416 }
1417 }
4f1ff475 1418#endif /* DIAGNOSTIC */
e16fa59e
KM
1419 vp = ip->i_devvp;
1420 bp->b_dev = vp->v_rdev;
1421 (*(vp->v_op->vn_strategy))(bp);
7188ac27
KM
1422 return (0);
1423}
88a7a62a 1424
e16fa59e
KM
1425/*
1426 * Print out the contents of an inode.
1427 */
1428ufs_print(vp)
1429 struct vnode *vp;
1430{
1431 register struct inode *ip = VTOI(vp);
1432
a8f829ed
KM
1433 printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number,
1434 major(ip->i_dev), minor(ip->i_dev));
1435#ifdef FIFO
1436 if (vp->v_type == VFIFO)
1437 fifo_printinfo(vp);
1438#endif /* FIFO */
1439 printf("%s\n", (ip->i_flag & ILOCKED) ? " (LOCKED)" : "");
96bae3e0
KM
1440 if (ip->i_spare0 == 0)
1441 return;
1442 printf("\towner pid %d", ip->i_spare0);
1443 if (ip->i_spare1)
1444 printf(" waiting pid %d", ip->i_spare1);
1445 printf("\n");
e16fa59e
KM
1446}
1447
24a31b70
KM
1448/*
1449 * Read wrapper for special devices.
1450 */
1451ufsspec_read(vp, uio, ioflag, cred)
1452 struct vnode *vp;
1453 struct uio *uio;
1454 int ioflag;
1455 struct ucred *cred;
1456{
1457
1458 /*
1459 * Set access flag.
1460 */
1461 VTOI(vp)->i_flag |= IACC;
1462 return (spec_read(vp, uio, ioflag, cred));
1463}
1464
1465/*
1466 * Write wrapper for special devices.
1467 */
1468ufsspec_write(vp, uio, ioflag, cred)
1469 struct vnode *vp;
1470 struct uio *uio;
1471 int ioflag;
1472 struct ucred *cred;
1473{
1474
1475 /*
1476 * Set update and change flags.
1477 */
1478 VTOI(vp)->i_flag |= IUPD|ICHG;
1479 return (spec_write(vp, uio, ioflag, cred));
1480}
1481
1482/*
1483 * Close wrapper for special devices.
1484 *
1485 * Update the times on the inode then do device close.
1486 */
5b169cb7 1487ufsspec_close(vp, fflag, cred, p)
24a31b70
KM
1488 struct vnode *vp;
1489 int fflag;
1490 struct ucred *cred;
5b169cb7 1491 struct proc *p;
24a31b70
KM
1492{
1493 register struct inode *ip = VTOI(vp);
1494
de67eefc 1495 if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
24a31b70 1496 ITIMES(ip, &time, &time);
5b169cb7 1497 return (spec_close(vp, fflag, cred, p));
24a31b70
KM
1498}
1499
d1c43d7f
KM
1500#ifdef FIFO
1501/*
1502 * Read wrapper for fifo's
1503 */
1504ufsfifo_read(vp, uio, ioflag, cred)
1505 struct vnode *vp;
1506 struct uio *uio;
1507 int ioflag;
1508 struct ucred *cred;
1509{
1510
1511 /*
1512 * Set access flag.
1513 */
1514 VTOI(vp)->i_flag |= IACC;
1515 return (fifo_read(vp, uio, ioflag, cred));
1516}
1517
1518/*
1519 * Write wrapper for fifo's.
1520 */
1521ufsfifo_write(vp, uio, ioflag, cred)
1522 struct vnode *vp;
1523 struct uio *uio;
1524 int ioflag;
1525 struct ucred *cred;
1526{
1527
1528 /*
1529 * Set update and change flags.
1530 */
1531 VTOI(vp)->i_flag |= IUPD|ICHG;
1532 return (fifo_write(vp, uio, ioflag, cred));
1533}
1534
1535/*
1536 * Close wrapper for fifo's.
1537 *
1538 * Update the times on the inode then do device close.
1539 */
5b169cb7 1540ufsfifo_close(vp, fflag, cred, p)
d1c43d7f
KM
1541 struct vnode *vp;
1542 int fflag;
1543 struct ucred *cred;
5b169cb7 1544 struct proc *p;
d1c43d7f
KM
1545{
1546 register struct inode *ip = VTOI(vp);
1547
1548 if (vp->v_usecount > 1 && !(ip->i_flag & ILOCKED))
1549 ITIMES(ip, &time, &time);
5b169cb7 1550 return (fifo_close(vp, fflag, cred, p));
d1c43d7f
KM
1551}
1552#endif /* FIFO */
1553
7188ac27 1554/*
36979c87 1555 * Allocate a new inode.
7188ac27
KM
1556 */
1557maknode(mode, ndp, ipp)
1558 int mode;
1559 register struct nameidata *ndp;
1560 struct inode **ipp;
1561{
1562 register struct inode *ip;
1563 struct inode *tip;
1564 register struct inode *pdir = VTOI(ndp->ni_dvp);
1565 ino_t ipref;
1566 int error;
1567
655da945
KM
1568#ifdef DIANOSTIC
1569 if ((ndp->ni_nameiop & HASBUF) == 0)
1570 panic("maknode: no name");
1571#endif
7188ac27 1572 *ipp = 0;
4b61628b
KM
1573 if ((mode & IFMT) == 0)
1574 mode |= IFREG;
7188ac27
KM
1575 if ((mode & IFMT) == IFDIR)
1576 ipref = dirpref(pdir->i_fs);
1577 else
1578 ipref = pdir->i_number;
4b61628b 1579 if (error = ialloc(pdir, ipref, mode, ndp->ni_cred, &tip)) {
655da945 1580 free(ndp->ni_pnbuf, M_NAMEI);
7188ac27
KM
1581 iput(pdir);
1582 return (error);
1583 }
1584 ip = tip;
4b61628b
KM
1585 ip->i_uid = ndp->ni_cred->cr_uid;
1586 ip->i_gid = pdir->i_gid;
7188ac27 1587#ifdef QUOTA
4b61628b
KM
1588 if ((error = getinoquota(ip)) ||
1589 (error = chkiq(ip, 1, ndp->ni_cred, 0))) {
655da945 1590 free(ndp->ni_pnbuf, M_NAMEI);
4b61628b
KM
1591 ifree(ip, ip->i_number, mode);
1592 iput(ip);
1593 iput(pdir);
1594 return (error);
1595 }
7188ac27
KM
1596#endif
1597 ip->i_flag |= IACC|IUPD|ICHG;
7188ac27
KM
1598 ip->i_mode = mode;
1599 ITOV(ip)->v_type = IFTOVT(mode); /* Rest init'd in iget() */
1600 ip->i_nlink = 1;
7188ac27
KM
1601 if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, ndp->ni_cred) &&
1602 suser(ndp->ni_cred, NULL))
1603 ip->i_mode &= ~ISGID;
7188ac27
KM
1604
1605 /*
1606 * Make sure inode goes to disk before directory entry.
1607 */
4b61628b
KM
1608 if (error = iupdat(ip, &time, &time, 1))
1609 goto bad;
394d67a8 1610 if (error = direnter(ip, ndp))
4b61628b 1611 goto bad;
655da945
KM
1612 if ((ndp->ni_nameiop & SAVESTART) == 0)
1613 FREE(ndp->ni_pnbuf, M_NAMEI);
394d67a8 1614 iput(pdir);
7188ac27
KM
1615 *ipp = ip;
1616 return (0);
4b61628b
KM
1617
1618bad:
1619 /*
1620 * Write error occurred trying to update the inode
1621 * or the directory so must deallocate the inode.
1622 */
655da945 1623 free(ndp->ni_pnbuf, M_NAMEI);
394d67a8 1624 iput(pdir);
4b61628b
KM
1625 ip->i_nlink = 0;
1626 ip->i_flag |= ICHG;
1627 iput(ip);
1628 return (error);
88a7a62a 1629}
0b0bf936
KM
1630
1631/*
1632 * Advisory record locking support
1633 */
1634ufs_advlock(vp, id, op, fl, flags)
1635 struct vnode *vp;
1636 caddr_t id;
1637 int op;
1638 register struct flock *fl;
1639 int flags;
1640{
1641 register struct inode *ip = VTOI(vp);
1642 register struct lockf *lock;
1643 off_t start, end;
1644 int error;
1645
1646 /*
1647 * Avoid the common case of unlocking when inode has no locks.
1648 */
1649 if (ip->i_lockf == (struct lockf *)0) {
1650 if (op != F_SETLK) {
1651 fl->l_type = F_UNLCK;
1652 return (0);
1653 }
1654 }
1655 /*
1656 * Convert the flock structure into a start and end.
1657 */
1658 switch (fl->l_whence) {
1659
1660 case SEEK_SET:
1661 case SEEK_CUR:
1662 /*
1663 * Caller is responsible for adding any necessary offset
1664 * when SEEK_CUR is used.
1665 */
1666 start = fl->l_start;
1667 break;
1668
1669 case SEEK_END:
1670 start = ip->i_size + fl->l_start;
1671 break;
1672
1673 default:
1674 return (EINVAL);
1675 }
1676 if (start < 0)
1677 return (EINVAL);
1678 if (fl->l_len == 0)
1679 end = -1;
1680 else
c412cb68 1681 end = start + fl->l_len - 1;
0b0bf936
KM
1682 /*
1683 * Create the lockf structure
1684 */
1685 MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK);
1686 lock->lf_start = start;
1687 lock->lf_end = end;
1688 lock->lf_id = id;
1689 lock->lf_inode = ip;
1690 lock->lf_type = fl->l_type;
1691 lock->lf_next = (struct lockf *)0;
1692 lock->lf_block = (struct lockf *)0;
1693 lock->lf_flags = flags;
1694 /*
1695 * Do the requested operation.
1696 */
1697 switch(op) {
1698 case F_SETLK:
b9fc1077 1699 return (lf_setlock(lock));
0b0bf936
KM
1700
1701 case F_UNLCK:
b9fc1077
KM
1702 error = lf_clearlock(lock);
1703 FREE(lock, M_LOCKF);
1704 return (error);
0b0bf936
KM
1705
1706 case F_GETLK:
b9fc1077
KM
1707 error = lf_getlock(lock, fl);
1708 FREE(lock, M_LOCKF);
1709 return (error);
0b0bf936
KM
1710
1711 default:
1712 free(lock, M_LOCKF);
1713 return (EINVAL);
1714 }
1715 /* NOTREACHED */
1716}
5b169cb7
KM
1717
1718/*
1719 * Global vfs data structures for ufs
1720 */
1721struct vnodeops ufs_vnodeops = {
1722 ufs_lookup, /* lookup */
1723 ufs_create, /* create */
1724 ufs_mknod, /* mknod */
1725 ufs_open, /* open */
1726 ufs_close, /* close */
1727 ufs_access, /* access */
1728 ufs_getattr, /* getattr */
1729 ufs_setattr, /* setattr */
1730 ufs_read, /* read */
1731 ufs_write, /* write */
1732 ufs_ioctl, /* ioctl */
1733 ufs_select, /* select */
1734 ufs_mmap, /* mmap */
1735 ufs_fsync, /* fsync */
1736 ufs_seek, /* seek */
1737 ufs_remove, /* remove */
1738 ufs_link, /* link */
1739 ufs_rename, /* rename */
1740 ufs_mkdir, /* mkdir */
1741 ufs_rmdir, /* rmdir */
1742 ufs_symlink, /* symlink */
1743 ufs_readdir, /* readdir */
1744 ufs_readlink, /* readlink */
1745 ufs_abortop, /* abortop */
1746 ufs_inactive, /* inactive */
1747 ufs_reclaim, /* reclaim */
1748 ufs_lock, /* lock */
1749 ufs_unlock, /* unlock */
1750 ufs_bmap, /* bmap */
1751 ufs_strategy, /* strategy */
1752 ufs_print, /* print */
1753 ufs_islocked, /* islocked */
1754 ufs_advlock, /* advlock */
1755};
1756
1757struct vnodeops spec_inodeops = {
1758 spec_lookup, /* lookup */
1759 spec_create, /* create */
1760 spec_mknod, /* mknod */
1761 spec_open, /* open */
1762 ufsspec_close, /* close */
1763 ufs_access, /* access */
1764 ufs_getattr, /* getattr */
1765 ufs_setattr, /* setattr */
1766 ufsspec_read, /* read */
1767 ufsspec_write, /* write */
1768 spec_ioctl, /* ioctl */
1769 spec_select, /* select */
1770 spec_mmap, /* mmap */
1771 spec_fsync, /* fsync */
1772 spec_seek, /* seek */
1773 spec_remove, /* remove */
1774 spec_link, /* link */
1775 spec_rename, /* rename */
1776 spec_mkdir, /* mkdir */
1777 spec_rmdir, /* rmdir */
1778 spec_symlink, /* symlink */
1779 spec_readdir, /* readdir */
1780 spec_readlink, /* readlink */
1781 spec_abortop, /* abortop */
1782 ufs_inactive, /* inactive */
1783 ufs_reclaim, /* reclaim */
1784 ufs_lock, /* lock */
1785 ufs_unlock, /* unlock */
1786 spec_bmap, /* bmap */
1787 spec_strategy, /* strategy */
1788 ufs_print, /* print */
1789 ufs_islocked, /* islocked */
1790 spec_advlock, /* advlock */
1791};
1792
1793#ifdef FIFO
1794struct vnodeops fifo_inodeops = {
1795 fifo_lookup, /* lookup */
1796 fifo_create, /* create */
1797 fifo_mknod, /* mknod */
1798 fifo_open, /* open */
1799 ufsfifo_close, /* close */
1800 ufs_access, /* access */
1801 ufs_getattr, /* getattr */
1802 ufs_setattr, /* setattr */
1803 ufsfifo_read, /* read */
1804 ufsfifo_write, /* write */
1805 fifo_ioctl, /* ioctl */
1806 fifo_select, /* select */
1807 fifo_mmap, /* mmap */
1808 fifo_fsync, /* fsync */
1809 fifo_seek, /* seek */
1810 fifo_remove, /* remove */
1811 fifo_link, /* link */
1812 fifo_rename, /* rename */
1813 fifo_mkdir, /* mkdir */
1814 fifo_rmdir, /* rmdir */
1815 fifo_symlink, /* symlink */
1816 fifo_readdir, /* readdir */
1817 fifo_readlink, /* readlink */
1818 fifo_abortop, /* abortop */
1819 ufs_inactive, /* inactive */
1820 ufs_reclaim, /* reclaim */
1821 ufs_lock, /* lock */
1822 ufs_unlock, /* unlock */
1823 fifo_bmap, /* bmap */
1824 fifo_strategy, /* strategy */
1825 ufs_print, /* print */
1826 ufs_islocked, /* islocked */
1827 fifo_advlock, /* advlock */
1828};
1829#endif /* FIFO */
1830
1831enum vtype iftovt_tab[16] = {
1832 VNON, VFIFO, VCHR, VNON, VDIR, VNON, VBLK, VNON,
1833 VREG, VNON, VLNK, VNON, VSOCK, VNON, VNON, VBAD,
1834};
1835int vttoif_tab[9] = {
1836 0, IFREG, IFDIR, IFBLK, IFCHR, IFLNK, IFSOCK, IFIFO, IFMT,
1837};