add macro `cacheinval' to purge stale entries in the inode table
[unix-history] / usr / src / sys / ufs / lfs / lfs_vnops.c
CommitLineData
715baff1 1/* lfs_vnops.c 6.11 84/07/08 */
6459ebe0 2
d67a03eb
BJ
3#include "../h/param.h"
4#include "../h/systm.h"
d67a03eb
BJ
5#include "../h/dir.h"
6#include "../h/user.h"
35e7c31a 7#include "../h/kernel.h"
d67a03eb 8#include "../h/file.h"
6459ebe0 9#include "../h/stat.h"
3e78e260 10#include "../h/inode.h"
6459ebe0 11#include "../h/fs.h"
3e78e260 12#include "../h/buf.h"
3e78e260 13#include "../h/proc.h"
0a77f278 14#include "../h/quota.h"
31949305
BJ
15#include "../h/uio.h"
16#include "../h/socket.h"
b32450f4 17#include "../h/socketvar.h"
88a7a62a
SL
18#include "../h/mount.h"
19
20extern struct fileops inodeops;
21struct file *getinode();
3e78e260 22
4f083fd7
SL
23/*
24 * Change current working directory (``.'').
25 */
3e78e260
BJ
26chdir()
27{
28
29 chdirec(&u.u_cdir);
30}
31
4f083fd7
SL
32/*
33 * Change notion of root (``/'') directory.
34 */
3e78e260
BJ
35chroot()
36{
37
38 if (suser())
39 chdirec(&u.u_rdir);
40}
41
4f083fd7
SL
42/*
43 * Common routine for chroot and chdir.
44 */
3e78e260 45chdirec(ipp)
528f664c 46 register struct inode **ipp;
3e78e260
BJ
47{
48 register struct inode *ip;
49 struct a {
50 char *fname;
715baff1
KM
51 } *uap = (struct a *)u.u_ap;
52 register struct nameidata *ndp = &u.u_nd;
3e78e260 53
715baff1
KM
54 ndp->ni_nameiop = LOOKUP | FOLLOW;
55 ndp->ni_segflg = UIO_USERSPACE;
56 ndp->ni_dirp = uap->fname;
57 ip = namei(ndp);
4f083fd7 58 if (ip == NULL)
3e78e260 59 return;
4f083fd7 60 if ((ip->i_mode&IFMT) != IFDIR) {
3e78e260
BJ
61 u.u_error = ENOTDIR;
62 goto bad;
63 }
4f083fd7 64 if (access(ip, IEXEC))
3e78e260 65 goto bad;
a388503d 66 IUNLOCK(ip);
8eee8525
KM
67 if (*ipp)
68 irele(*ipp);
3e78e260
BJ
69 *ipp = ip;
70 return;
71
72bad:
73 iput(ip);
74}
75
76/*
77 * Open system call.
78 */
79open()
80{
88a7a62a 81 struct a {
3e78e260 82 char *fname;
528f664c 83 int mode;
88a7a62a
SL
84 int crtmode;
85 } *uap = (struct a *) u.u_ap;
3e78e260 86
715baff1 87 copen(uap->mode-FOPEN, uap->crtmode, uap->fname);
3e78e260
BJ
88}
89
90/*
91 * Creat system call.
92 */
88a7a62a 93creat()
3e78e260 94{
88a7a62a 95 struct a {
3e78e260
BJ
96 char *fname;
97 int fmode;
88a7a62a 98 } *uap = (struct a *)u.u_ap;
3e78e260 99
715baff1 100 copen(FWRITE|FCREAT|FTRUNC, uap->fmode, uap->fname);
3e78e260
BJ
101}
102
103/*
104 * Common code for open and creat.
88a7a62a
SL
105 * Check permissions, allocate an open file structure,
106 * and call the device open routine if any.
3e78e260 107 */
715baff1 108copen(mode, arg, fname)
88a7a62a
SL
109 register int mode;
110 int arg;
715baff1 111 caddr_t fname;
3e78e260 112{
88a7a62a 113 register struct inode *ip;
3e78e260 114 register struct file *fp;
715baff1 115 register struct nameidata *ndp = &u.u_nd;
88a7a62a 116 int i;
3e78e260 117
88a7a62a
SL
118#ifdef notdef
119 if ((mode&(FREAD|FWRITE)) == 0) {
120 u.u_error = EINVAL;
121 return;
122 }
123#endif
715baff1
KM
124 ndp->ni_segflg = UIO_USERSPACE;
125 ndp->ni_dirp = fname;
88a7a62a 126 if (mode&FCREAT) {
715baff1
KM
127 ndp->ni_nameiop = CREATE | FOLLOW;
128 ip = namei(ndp);
88a7a62a
SL
129 if (ip == NULL) {
130 if (u.u_error)
131 return;
715baff1 132 ip = maknode(arg&07777&(~ISVTX), ndp);
88a7a62a
SL
133 if (ip == NULL)
134 return;
135 mode &= ~FTRUNC;
136 } else {
137 if (mode&FEXCL) {
138 u.u_error = EEXIST;
139 iput(ip);
140 return;
141 }
142 mode &= ~FCREAT;
143 }
144 } else {
715baff1
KM
145 ndp->ni_nameiop = LOOKUP | FOLLOW;
146 ip = namei(ndp);
88a7a62a
SL
147 if (ip == NULL)
148 return;
149 }
150 if ((ip->i_mode & IFMT) == IFSOCK) {
151 u.u_error = EOPNOTSUPP;
152 goto bad;
153 }
154 if ((mode&FCREAT) == 0) {
3e78e260 155 if (mode&FREAD)
528f664c
SL
156 if (access(ip, IREAD))
157 goto bad;
09bf91df 158 if (mode&(FWRITE|FTRUNC)) {
528f664c
SL
159 if (access(ip, IWRITE))
160 goto bad;
161 if ((ip->i_mode&IFMT) == IFDIR) {
3e78e260 162 u.u_error = EISDIR;
528f664c
SL
163 goto bad;
164 }
3e78e260
BJ
165 }
166 }
88a7a62a
SL
167 fp = falloc();
168 if (fp == NULL)
169 goto bad;
170 if (mode&FTRUNC)
4f083fd7 171 itrunc(ip, (u_long)0);
a388503d 172 IUNLOCK(ip);
88a7a62a
SL
173 fp->f_flag = mode&FMASK;
174 fp->f_type = DTYPE_INODE;
175 fp->f_ops = &inodeops;
176 fp->f_data = (caddr_t)ip;
3e78e260 177 i = u.u_r.r_val1;
88a7a62a
SL
178 if (setjmp(&u.u_qsave)) {
179 if (u.u_error == 0)
180 u.u_error = EINTR;
181 u.u_ofile[i] = NULL;
182 closef(fp);
3e78e260 183 return;
528f664c 184 }
88a7a62a
SL
185 u.u_error = openi(ip, mode);
186 if (u.u_error == 0)
187 return;
3e78e260
BJ
188 u.u_ofile[i] = NULL;
189 fp->f_count--;
8eee8525 190 irele(ip);
528f664c
SL
191 return;
192bad:
193 iput(ip);
3e78e260
BJ
194}
195
196/*
197 * Mknod system call
198 */
199mknod()
200{
201 register struct inode *ip;
202 register struct a {
203 char *fname;
204 int fmode;
205 int dev;
715baff1
KM
206 } *uap = (struct a *)u.u_ap;
207 register struct nameidata *ndp = &u.u_nd;
3e78e260 208
88a7a62a
SL
209 if (!suser())
210 return;
715baff1
KM
211 ndp->ni_nameiop = CREATE;
212 ndp->ni_segflg = UIO_USERSPACE;
213 ndp->ni_dirp = uap->fname;
214 ip = namei(ndp);
88a7a62a
SL
215 if (ip != NULL) {
216 u.u_error = EEXIST;
217 goto out;
3e78e260
BJ
218 }
219 if (u.u_error)
220 return;
715baff1 221 ip = maknode(uap->fmode, ndp);
3e78e260
BJ
222 if (ip == NULL)
223 return;
88a7a62a
SL
224 switch (ip->i_mode & IFMT) {
225
7bfaea72 226 case IFMT: /* used by badsect to flag bad sectors */
88a7a62a
SL
227 case IFCHR:
228 case IFBLK:
229 if (uap->dev) {
230 /*
231 * Want to be able to use this to make badblock
232 * inodes, so don't truncate the dev number.
233 */
234 ip->i_rdev = uap->dev;
235 ip->i_flag |= IACC|IUPD|ICHG;
236 }
3e78e260
BJ
237 }
238
239out:
240 iput(ip);
241}
242
243/*
244 * link system call
245 */
246link()
247{
248 register struct inode *ip, *xp;
249 register struct a {
250 char *target;
251 char *linkname;
715baff1
KM
252 } *uap = (struct a *)u.u_ap;
253 register struct nameidata *ndp = &u.u_nd;
3e78e260 254
715baff1
KM
255 ndp->ni_nameiop = LOOKUP | FOLLOW;
256 ndp->ni_segflg = UIO_USERSPACE;
257 ndp->ni_dirp = uap->target;
258 ip = namei(ndp); /* well, this routine is doomed anyhow */
3e78e260
BJ
259 if (ip == NULL)
260 return;
4f083fd7 261 if ((ip->i_mode&IFMT) == IFDIR && !suser()) {
f94ceb3b
BJ
262 iput(ip);
263 return;
264 }
3e78e260
BJ
265 ip->i_nlink++;
266 ip->i_flag |= ICHG;
3fd23f5c 267 iupdat(ip, &time, &time, 1);
a388503d 268 IUNLOCK(ip);
715baff1
KM
269 ndp->ni_nameiop = CREATE;
270 ndp->ni_segflg = UIO_USERSPACE;
271 ndp->ni_dirp = (caddr_t)uap->linkname;
272 xp = namei(ndp);
3e78e260
BJ
273 if (xp != NULL) {
274 u.u_error = EEXIST;
275 iput(xp);
276 goto out;
277 }
278 if (u.u_error)
279 goto out;
715baff1
KM
280 if (ndp->ni_pdir->i_dev != ip->i_dev) {
281 iput(ndp->ni_pdir);
3e78e260
BJ
282 u.u_error = EXDEV;
283 goto out;
284 }
715baff1 285 u.u_error = direnter(ip, ndp);
3e78e260
BJ
286out:
287 if (u.u_error) {
288 ip->i_nlink--;
289 ip->i_flag |= ICHG;
290 }
8eee8525 291 irele(ip);
3e78e260
BJ
292}
293
294/*
295 * symlink -- make a symbolic link
296 */
297symlink()
298{
299 register struct a {
300 char *target;
301 char *linkname;
715baff1 302 } *uap = (struct a *)u.u_ap;
3e78e260
BJ
303 register struct inode *ip;
304 register char *tp;
305 register c, nc;
715baff1 306 register struct nameidata *ndp = &u.u_nd;
3e78e260 307
3e78e260
BJ
308 tp = uap->target;
309 nc = 0;
310 while (c = fubyte(tp)) {
311 if (c < 0) {
312 u.u_error = EFAULT;
313 return;
314 }
315 tp++;
316 nc++;
317 }
715baff1
KM
318 ndp->ni_nameiop = CREATE;
319 ndp->ni_segflg = UIO_USERSPACE;
320 ndp->ni_dirp = uap->linkname;
321 ip = namei(ndp);
3e78e260
BJ
322 if (ip) {
323 iput(ip);
324 u.u_error = EEXIST;
325 return;
326 }
327 if (u.u_error)
328 return;
715baff1 329 ip = maknode(IFLNK | 0777, ndp);
3e78e260
BJ
330 if (ip == NULL)
331 return;
31949305 332 u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0);
4f083fd7 333 /* handle u.u_error != 0 */
3e78e260
BJ
334 iput(ip);
335}
336
337/*
338 * Unlink system call.
339 * Hard to avoid races here, especially
340 * in unlinking directories.
341 */
342unlink()
343{
3e78e260
BJ
344 struct a {
345 char *fname;
715baff1 346 } *uap = (struct a *)u.u_ap;
4f083fd7 347 register struct inode *ip, *dp;
715baff1 348 register struct nameidata *ndp = &u.u_nd;
3e78e260 349
715baff1
KM
350 ndp->ni_nameiop = DELETE | LOCKPARENT;
351 ndp->ni_segflg = UIO_USERSPACE;
352 ndp->ni_dirp = uap->fname;
353 ip = namei(ndp);
4f083fd7 354 if (ip == NULL)
3e78e260 355 return;
715baff1 356 dp = ndp->ni_pdir;
4f083fd7 357 if ((ip->i_mode&IFMT) == IFDIR && !suser())
3e78e260
BJ
358 goto out;
359 /*
360 * Don't unlink a mounted file.
361 */
4f083fd7 362 if (ip->i_dev != dp->i_dev) {
3e78e260
BJ
363 u.u_error = EBUSY;
364 goto out;
365 }
366 if (ip->i_flag&ITEXT)
367 xrele(ip); /* try once to free text */
715baff1 368 if (dirremove(ndp)) {
64d3a787
BJ
369 ip->i_nlink--;
370 ip->i_flag |= ICHG;
6459ebe0 371 }
3e78e260 372out:
4f083fd7 373 if (dp == ip)
8eee8525
KM
374 irele(ip);
375 else
376 iput(ip);
4f083fd7 377 iput(dp);
3e78e260
BJ
378}
379
380/*
381 * Seek system call
382 */
35e7c31a 383lseek()
3e78e260
BJ
384{
385 register struct file *fp;
386 register struct a {
528f664c 387 int fd;
3e78e260
BJ
388 off_t off;
389 int sbase;
715baff1 390 } *uap = (struct a *)u.u_ap;
3e78e260 391
8462a185
SL
392 GETF(fp, uap->fd);
393 if (fp->f_type != DTYPE_INODE) {
394 u.u_error = ESPIPE;
3e78e260 395 return;
8462a185 396 }
b4d1aee9
SL
397 switch (uap->sbase) {
398
399 case L_INCR:
400 fp->f_offset += uap->off;
401 break;
402
403 case L_XTND:
404 fp->f_offset = uap->off + ((struct inode *)fp->f_data)->i_size;
405 break;
406
407 case L_SET:
408 fp->f_offset = uap->off;
409 break;
410
411 default:
412 u.u_error = EINVAL;
413 return;
414 }
415 u.u_r.r_off = fp->f_offset;
3e78e260
BJ
416}
417
418/*
419 * Access system call
420 */
421saccess()
422{
423 register svuid, svgid;
424 register struct inode *ip;
425 register struct a {
426 char *fname;
427 int fmode;
715baff1
KM
428 } *uap = (struct a *)u.u_ap;
429 register struct nameidata *ndp = &u.u_nd;
3e78e260 430
3e78e260
BJ
431 svuid = u.u_uid;
432 svgid = u.u_gid;
433 u.u_uid = u.u_ruid;
434 u.u_gid = u.u_rgid;
715baff1
KM
435 ndp->ni_nameiop = LOOKUP | FOLLOW;
436 ndp->ni_segflg = UIO_USERSPACE;
437 ndp->ni_dirp = uap->fname;
438 ip = namei(ndp);
3e78e260 439 if (ip != NULL) {
88a7a62a 440 if ((uap->fmode&R_OK) && access(ip, IREAD))
528f664c 441 goto done;
88a7a62a 442 if ((uap->fmode&W_OK) && access(ip, IWRITE))
528f664c 443 goto done;
88a7a62a 444 if ((uap->fmode&X_OK) && access(ip, IEXEC))
528f664c
SL
445 goto done;
446done:
3e78e260
BJ
447 iput(ip);
448 }
449 u.u_uid = svuid;
450 u.u_gid = svgid;
451}
d67a03eb 452
d67a03eb 453/*
6459ebe0 454 * Stat system call. This version follows links.
d67a03eb
BJ
455 */
456stat()
457{
d67a03eb 458
715baff1 459 stat1(FOLLOW);
d67a03eb
BJ
460}
461
5485e062 462/*
6459ebe0 463 * Lstat system call. This version does not follow links.
5485e062
BJ
464 */
465lstat()
88a7a62a
SL
466{
467
715baff1 468 stat1(NOFOLLOW);
88a7a62a
SL
469}
470
471stat1(follow)
472 int follow;
5485e062
BJ
473{
474 register struct inode *ip;
475 register struct a {
476 char *fname;
88a7a62a 477 struct stat *ub;
715baff1 478 } *uap = (struct a *)u.u_ap;
88a7a62a 479 struct stat sb;
715baff1 480 register struct nameidata *ndp = &u.u_nd;
5485e062 481
715baff1
KM
482 ndp->ni_nameiop = LOOKUP | follow;
483 ndp->ni_segflg = UIO_USERSPACE;
484 ndp->ni_dirp = uap->fname;
485 ip = namei(ndp);
5485e062
BJ
486 if (ip == NULL)
487 return;
0eaf24e3 488 (void) ino_stat(ip, &sb);
5485e062 489 iput(ip);
88a7a62a 490 u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
d67a03eb
BJ
491}
492
493/*
5485e062
BJ
494 * Return target name of a symbolic link
495 */
496readlink()
497{
498 register struct inode *ip;
499 register struct a {
500 char *name;
501 char *buf;
502 int count;
31949305 503 } *uap = (struct a *)u.u_ap;
715baff1 504 register struct nameidata *ndp = &u.u_nd;
31949305 505 int resid;
5485e062 506
715baff1
KM
507 ndp->ni_nameiop = LOOKUP;
508 ndp->ni_segflg = UIO_USERSPACE;
509 ndp->ni_dirp = uap->name;
510 ip = namei(ndp);
5485e062
BJ
511 if (ip == NULL)
512 return;
513 if ((ip->i_mode&IFMT) != IFLNK) {
514 u.u_error = ENXIO;
515 goto out;
516 }
31949305 517 u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid);
5485e062
BJ
518out:
519 iput(ip);
31949305 520 u.u_r.r_val1 = uap->count - resid;
5485e062
BJ
521}
522
4f083fd7
SL
523/*
524 * Change mode of a file given path name.
525 */
3e78e260 526chmod()
5485e062 527{
528f664c
SL
528 struct inode *ip;
529 struct a {
3e78e260
BJ
530 char *fname;
531 int fmode;
715baff1 532 } *uap = (struct a *)u.u_ap;
5485e062 533
715baff1 534 if ((ip = owner(uap->fname, FOLLOW)) == NULL)
5485e062 535 return;
528f664c 536 chmod1(ip, uap->fmode);
4f083fd7 537 iput(ip);
528f664c 538}
f94ceb3b 539
4f083fd7
SL
540/*
541 * Change mode of a file given a file descriptor.
542 */
528f664c
SL
543fchmod()
544{
545 struct a {
546 int fd;
547 int fmode;
715baff1 548 } *uap = (struct a *)u.u_ap;
528f664c
SL
549 register struct inode *ip;
550 register struct file *fp;
551
88a7a62a 552 fp = getinode(uap->fd);
528f664c
SL
553 if (fp == NULL)
554 return;
88a7a62a 555 ip = (struct inode *)fp->f_data;
4f083fd7 556 if (u.u_uid != ip->i_uid && !suser())
528f664c 557 return;
a388503d 558 ILOCK(ip);
528f664c 559 chmod1(ip, uap->fmode);
a388503d 560 IUNLOCK(ip);
528f664c
SL
561}
562
4f083fd7
SL
563/*
564 * Change the mode on a file.
565 * Inode must be locked before calling.
566 */
528f664c
SL
567chmod1(ip, mode)
568 register struct inode *ip;
569 register int mode;
570{
197da11b 571
3e78e260 572 ip->i_mode &= ~07777;
f94ceb3b 573 if (u.u_uid) {
528f664c 574 mode &= ~ISVTX;
bb1b75f4
SL
575 if (!groupmember(ip->i_gid))
576 mode &= ~ISGID;
f94ceb3b 577 }
528f664c 578 ip->i_mode |= mode&07777;
3e78e260
BJ
579 ip->i_flag |= ICHG;
580 if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
581 xrele(ip);
5485e062
BJ
582}
583
4f083fd7
SL
584/*
585 * Set ownership given a path name.
586 */
3e78e260 587chown()
d67a03eb 588{
528f664c
SL
589 struct inode *ip;
590 struct a {
3e78e260
BJ
591 char *fname;
592 int uid;
593 int gid;
715baff1 594 } *uap = (struct a *)u.u_ap;
d67a03eb 595
715baff1 596 if (!suser() || (ip = owner(uap->fname, NOFOLLOW)) == NULL)
d67a03eb 597 return;
bb1b75f4 598 u.u_error = chown1(ip, uap->uid, uap->gid);
4f083fd7 599 iput(ip);
528f664c 600}
f94ceb3b 601
4f083fd7
SL
602/*
603 * Set ownership given a file descriptor.
604 */
528f664c
SL
605fchown()
606{
607 struct a {
608 int fd;
609 int uid;
610 int gid;
715baff1 611 } *uap = (struct a *)u.u_ap;
528f664c
SL
612 register struct inode *ip;
613 register struct file *fp;
614
88a7a62a 615 fp = getinode(uap->fd);
528f664c
SL
616 if (fp == NULL)
617 return;
88a7a62a 618 ip = (struct inode *)fp->f_data;
aad8ef38 619 if (!suser())
528f664c 620 return;
a388503d 621 ILOCK(ip);
bb1b75f4 622 u.u_error = chown1(ip, uap->uid, uap->gid);
a388503d 623 IUNLOCK(ip);
528f664c
SL
624}
625
626/*
627 * Perform chown operation on inode ip;
628 * inode must be locked prior to call.
629 */
630chown1(ip, uid, gid)
631 register struct inode *ip;
632 int uid, gid;
633{
634#ifdef QUOTA
635 register long change;
bb1b75f4 636#endif
528f664c 637
bb1b75f4
SL
638 if (uid == -1)
639 uid = ip->i_uid;
640 if (gid == -1)
641 gid = ip->i_gid;
bb1b75f4 642#ifdef QUOTA
3809bf69 643 if (ip->i_uid == uid) /* this just speeds things a little */
0a77f278 644 change = 0;
2e073567
SL
645 else
646 change = ip->i_blocks;
647 (void) chkdq(ip, -change, 1);
648 (void) chkiq(ip->i_dev, ip, ip->i_uid, 1);
0a77f278 649 dqrele(ip->i_dquot);
f94ceb3b 650#endif
bb1b75f4
SL
651 ip->i_uid = uid;
652 ip->i_gid = gid;
3e78e260
BJ
653 ip->i_flag |= ICHG;
654 if (u.u_ruid != 0)
655 ip->i_mode &= ~(ISUID|ISGID);
528f664c 656#ifdef QUOTA
0a77f278 657 ip->i_dquot = inoquota(ip);
2e073567
SL
658 (void) chkdq(ip, change, 1);
659 (void) chkiq(ip->i_dev, (struct inode *)NULL, uid, 1);
660 return (u.u_error); /* should == 0 ALWAYS !! */
661#else
bb1b75f4 662 return (0);
2e073567 663#endif
d67a03eb
BJ
664}
665
bb1b75f4
SL
666utimes()
667{
668 register struct a {
669 char *fname;
670 struct timeval *tptr;
671 } *uap = (struct a *)u.u_ap;
672 register struct inode *ip;
673 struct timeval tv[2];
674
715baff1 675 if ((ip = owner(uap->fname, FOLLOW)) == NULL)
bb1b75f4
SL
676 return;
677 u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
678 if (u.u_error == 0) {
679 ip->i_flag |= IACC|IUPD|ICHG;
680 iupdat(ip, &tv[0], &tv[1], 0);
681 }
682 iput(ip);
683}
d67a03eb 684
4f083fd7
SL
685/*
686 * Flush any pending I/O.
687 */
3e78e260 688sync()
d67a03eb 689{
d67a03eb 690
3fd23f5c 691 update();
d67a03eb 692}
64d3a787 693
4f083fd7
SL
694/*
695 * Truncate a file given its path name.
696 */
528f664c
SL
697truncate()
698{
699 struct a {
700 char *fname;
4f083fd7 701 u_long length;
31949305 702 } *uap = (struct a *)u.u_ap;
528f664c 703 struct inode *ip;
715baff1 704 register struct nameidata *ndp = &u.u_nd;
528f664c 705
715baff1
KM
706 ndp->ni_nameiop = LOOKUP | FOLLOW;
707 ndp->ni_segflg = UIO_USERSPACE;
708 ndp->ni_dirp = uap->fname;
709 ip = namei(ndp);
528f664c
SL
710 if (ip == NULL)
711 return;
712 if (access(ip, IWRITE))
713 goto bad;
714 if ((ip->i_mode&IFMT) == IFDIR) {
715 u.u_error = EISDIR;
716 goto bad;
717 }
718 itrunc(ip, uap->length);
528f664c
SL
719bad:
720 iput(ip);
721}
722
4f083fd7
SL
723/*
724 * Truncate a file given a file descriptor.
725 */
528f664c
SL
726ftruncate()
727{
728 struct a {
729 int fd;
4f083fd7 730 u_long length;
31949305 731 } *uap = (struct a *)u.u_ap;
528f664c
SL
732 struct inode *ip;
733 struct file *fp;
734
88a7a62a 735 fp = getinode(uap->fd);
528f664c
SL
736 if (fp == NULL)
737 return;
528f664c
SL
738 if ((fp->f_flag&FWRITE) == 0) {
739 u.u_error = EINVAL;
740 return;
741 }
88a7a62a 742 ip = (struct inode *)fp->f_data;
a388503d 743 ILOCK(ip);
528f664c 744 itrunc(ip, uap->length);
a388503d 745 IUNLOCK(ip);
4f083fd7
SL
746}
747
748/*
749 * Synch an open file.
750 */
751fsync()
752{
753 struct a {
754 int fd;
755 } *uap = (struct a *)u.u_ap;
756 struct inode *ip;
757 struct file *fp;
758
88a7a62a 759 fp = getinode(uap->fd);
4f083fd7
SL
760 if (fp == NULL)
761 return;
88a7a62a 762 ip = (struct inode *)fp->f_data;
a388503d 763 ILOCK(ip);
4f083fd7 764 syncip(ip);
a388503d 765 IUNLOCK(ip);
528f664c
SL
766}
767
4f083fd7
SL
768/*
769 * Rename system call.
770 * rename("foo", "bar");
771 * is essentially
772 * unlink("bar");
773 * link("foo", "bar");
774 * unlink("foo");
775 * but ``atomically''. Can't do full commit without saving state in the
776 * inode on disk which isn't feasible at this time. Best we can do is
777 * always guarantee the target exists.
778 *
779 * Basic algorithm is:
780 *
781 * 1) Bump link count on source while we're linking it to the
782 * target. This also insure the inode won't be deleted out
783 * from underneath us while we work.
784 * 2) Link source to destination. If destination already exists,
785 * delete it first.
786 * 3) Unlink source reference to inode if still around.
787 * 4) If a directory was moved and the parent of the destination
788 * is different from the source, patch the ".." entry in the
789 * directory.
790 *
791 * Source and destination must either both be directories, or both
792 * not be directories. If target is a directory, it must be empty.
793 */
528f664c
SL
794rename()
795{
796 struct a {
797 char *from;
798 char *to;
715baff1 799 } *uap = (struct a *)u.u_ap;
4f083fd7 800 register struct inode *ip, *xp, *dp;
963fd9f8 801 struct inode *zp;
4f083fd7 802 int oldparent, parentdifferent, doingdirectory;
715baff1 803 register struct nameidata *ndp = &u.u_nd;
a5390dce 804 int error = 0;
4f083fd7 805
715baff1
KM
806 ndp->ni_nameiop = DELETE | LOCKPARENT;
807 ndp->ni_segflg = UIO_USERSPACE;
808 ndp->ni_dirp = uap->from;
809 ip = namei(ndp);
4f083fd7
SL
810 if (ip == NULL)
811 return;
715baff1 812 dp = ndp->ni_pdir;
4f083fd7
SL
813 oldparent = 0, doingdirectory = 0;
814 if ((ip->i_mode&IFMT) == IFDIR) {
815 register struct direct *d;
816
715baff1 817 d = &ndp->ni_dent;
4f083fd7 818 /*
046f18d1 819 * Avoid ".", "..", and aliases of "." for obvious reasons.
4f083fd7 820 */
046f18d1
SL
821 if ((d->d_namlen == 1 && d->d_name[0] == '.') ||
822 (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) ||
823 (dp == ip)) {
824 iput(dp);
825 if (dp == ip)
826 irele(ip);
827 else
4f083fd7 828 iput(ip);
046f18d1
SL
829 u.u_error = EINVAL;
830 return;
4f083fd7
SL
831 }
832 oldparent = dp->i_number;
833 doingdirectory++;
834 }
046f18d1 835 iput(dp);
4f083fd7
SL
836
837 /*
838 * 1) Bump link count while we're moving stuff
839 * around. If we crash somewhere before
840 * completing our work, the link count
841 * may be wrong, but correctable.
842 */
843 ip->i_nlink++;
844 ip->i_flag |= ICHG;
845 iupdat(ip, &time, &time, 1);
a388503d 846 IUNLOCK(ip);
4f083fd7
SL
847
848 /*
849 * When the target exists, both the directory
850 * and target inodes are returned locked.
851 */
715baff1
KM
852 ndp->ni_nameiop = CREATE | LOCKPARENT | NOCACHE;
853 ndp->ni_dirp = (caddr_t)uap->to;
854 xp = namei(ndp);
a5390dce
SL
855 if (u.u_error) {
856 error = u.u_error;
4f083fd7 857 goto out;
a5390dce 858 }
715baff1 859 dp = ndp->ni_pdir;
046f18d1
SL
860 /*
861 * If ".." must be changed (ie the directory gets a new
81552f0f
KM
862 * parent) then the source directory must not be in the
863 * directory heirarchy above the target, as this would
864 * orphan everything below the source directory. Also
865 * the user must have write permission in the source so
866 * as to be able to change "..". We must repeat the call
867 * to namei, as the parent directory is unlocked by the
868 * call to checkpath().
046f18d1
SL
869 */
870 parentdifferent = oldparent != dp->i_number;
81552f0f
KM
871 if (doingdirectory && parentdifferent) {
872 if (access(ip, IWRITE))
873 goto bad;
874 do {
715baff1 875 dp = ndp->ni_pdir;
81552f0f
KM
876 if (xp != NULL)
877 iput(xp);
878 u.u_error = checkpath(ip, dp);
879 if (u.u_error)
880 goto out;
715baff1 881 xp = namei(ndp);
81552f0f
KM
882 if (u.u_error) {
883 error = u.u_error;
884 goto out;
885 }
715baff1 886 } while (dp != ndp->ni_pdir);
81552f0f 887 }
4f083fd7
SL
888 /*
889 * 2) If target doesn't exist, link the target
890 * to the source and unlink the source.
891 * Otherwise, rewrite the target directory
892 * entry to reference the source inode and
893 * expunge the original entry's existence.
894 */
4f083fd7
SL
895 if (xp == NULL) {
896 if (dp->i_dev != ip->i_dev) {
a5390dce 897 error = EXDEV;
4f083fd7
SL
898 goto bad;
899 }
900 /*
901 * Account for ".." in directory.
902 * When source and destination have the
903 * same parent we don't fool with the
904 * link count -- this isn't required
905 * because we do a similar check below.
906 */
907 if (doingdirectory && parentdifferent) {
908 dp->i_nlink++;
909 dp->i_flag |= ICHG;
910 iupdat(dp, &time, &time, 1);
911 }
715baff1 912 error = direnter(ip, ndp);
f2a5ad78 913 if (error)
4f083fd7
SL
914 goto out;
915 } else {
916 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) {
a5390dce 917 error = EXDEV;
4f083fd7
SL
918 goto bad;
919 }
e69c3c9c
SL
920 /*
921 * Short circuit rename(foo, foo).
922 */
923 if (xp->i_number == ip->i_number)
924 goto bad;
4f083fd7 925 /*
a5390dce
SL
926 * Target must be empty if a directory
927 * and have no links to it.
4f083fd7
SL
928 * Also, insure source and target are
929 * compatible (both directories, or both
930 * not directories).
931 */
932 if ((xp->i_mode&IFMT) == IFDIR) {
a5390dce
SL
933 if (!dirempty(xp) || xp->i_nlink > 2) {
934 error = ENOTEMPTY;
4f083fd7
SL
935 goto bad;
936 }
937 if (!doingdirectory) {
a5390dce 938 error = ENOTDIR;
4f083fd7
SL
939 goto bad;
940 }
941 } else if (doingdirectory) {
a5390dce 942 error = EISDIR;
4f083fd7
SL
943 goto bad;
944 }
715baff1 945 dirrewrite(dp, ip, ndp);
a5390dce
SL
946 if (u.u_error) {
947 error = u.u_error;
4f083fd7 948 goto bad1;
a5390dce 949 }
4f083fd7 950 /*
a5390dce
SL
951 * Adjust the link count of the target to
952 * reflect the dirrewrite above. If this is
953 * a directory it is empty and there are
954 * no links to it, so we can squash the inode and
955 * any space associated with it. We disallowed
956 * renaming over top of a directory with links to
957 * it above, as we've no way to determine if
958 * we've got a link or the directory itself, and
959 * if we get a link, then ".." will be screwed up.
4f083fd7 960 */
a5390dce 961 xp->i_nlink--;
4f083fd7 962 if (doingdirectory) {
a5390dce
SL
963 if (--xp->i_nlink != 0)
964 panic("rename: linked directory");
4f083fd7 965 itrunc(xp, (u_long)0);
a5390dce 966 }
4f083fd7
SL
967 xp->i_flag |= ICHG;
968 iput(xp);
31db12cb 969 xp = NULL;
4f083fd7
SL
970 }
971
972 /*
973 * 3) Unlink the source.
974 */
715baff1
KM
975 ndp->ni_nameiop = DELETE | LOCKPARENT;
976 ndp->ni_segflg = UIO_USERSPACE;
977 ndp->ni_dirp = uap->from;
978 zp = namei(ndp);
979 dp = ndp->ni_pdir;
4f083fd7
SL
980 /*
981 * Insure directory entry still exists and
982 * has not changed since the start of all
983 * this. If either has occured, forget about
85792f12 984 * about deleting the original entry.
4f083fd7 985 */
963fd9f8 986 if (dp != NULL && zp == ip) {
4f083fd7
SL
987 /*
988 * If source is a directory, must adjust
989 * link count of parent directory also.
990 * If target didn't exist and source and
991 * target have the same parent, then we
992 * needn't touch the link count, it all
993 * balances out in the end. Otherwise, we
994 * must do so to reflect deletion of ".."
995 * done above.
996 */
997 if (doingdirectory && (xp != NULL || parentdifferent)) {
998 dp->i_nlink--;
999 dp->i_flag |= ICHG;
1000 }
715baff1 1001 if (dirremove(ndp)) {
963fd9f8
KM
1002 zp->i_nlink--;
1003 zp->i_flag |= ICHG;
4f083fd7 1004 }
a5390dce
SL
1005 if (error == 0) /* conservative */
1006 error = u.u_error;
4f083fd7 1007 }
963fd9f8
KM
1008 if (zp != NULL)
1009 iput(zp);
4f083fd7
SL
1010 irele(ip);
1011 if (dp)
1012 iput(dp);
1013
1014 /*
1015 * 4) Renaming a directory with the parent
1016 * different requires ".." to be rewritten.
1017 * The window is still there for ".." to
1018 * be inconsistent, but this is unavoidable,
1019 * and a lot shorter than when it was done
1020 * in a user process.
1021 */
a5390dce 1022 if (doingdirectory && parentdifferent && error == 0) {
4f083fd7 1023 struct dirtemplate dirbuf;
528f664c 1024
715baff1
KM
1025 ndp->ni_nameiop = LOOKUP | LOCKPARENT;
1026 ndp->ni_segflg = UIO_USERSPACE;
1027 ndp->ni_dirp = uap->to;
1028 ip = namei(ndp);
4f083fd7
SL
1029 if (ip == NULL) {
1030 printf("rename: .. went away\n");
1031 return;
1032 }
715baff1 1033 dp = ndp->ni_pdir;
4f083fd7
SL
1034 if ((ip->i_mode&IFMT) != IFDIR) {
1035 printf("rename: .. not a directory\n");
1036 goto stuck;
1037 }
a5390dce 1038 error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf,
4f083fd7 1039 sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
a5390dce 1040 if (error == 0) {
4f083fd7 1041 dirbuf.dotdot_ino = dp->i_number;
8ac1234a 1042 dp->i_id = ++nextinodeid;
4f083fd7
SL
1043 (void) rdwri(UIO_WRITE, ip, (caddr_t)&dirbuf,
1044 sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
1045 }
1046stuck:
1047 irele(dp);
1048 iput(ip);
1049 }
a5390dce
SL
1050 goto done;
1051
4f083fd7 1052bad:
31db12cb 1053 iput(dp);
4f083fd7
SL
1054bad1:
1055 if (xp)
31db12cb 1056 iput(xp);
4f083fd7
SL
1057out:
1058 ip->i_nlink--;
1059 ip->i_flag |= ICHG;
1060 irele(ip);
a5390dce
SL
1061done:
1062 if (error)
1063 u.u_error = error;
528f664c
SL
1064}
1065
64d3a787
BJ
1066/*
1067 * Make a new file.
1068 */
1069struct inode *
715baff1 1070maknode(mode, ndp)
64d3a787 1071 int mode;
715baff1 1072 register struct nameidata *ndp;
64d3a787
BJ
1073{
1074 register struct inode *ip;
715baff1 1075 register struct inode *pdir = ndp->ni_pdir;
64d3a787
BJ
1076 ino_t ipref;
1077
1078 if ((mode & IFMT) == IFDIR)
715baff1 1079 ipref = dirpref(pdir->i_fs);
64d3a787 1080 else
715baff1
KM
1081 ipref = pdir->i_number;
1082 ip = ialloc(pdir, ipref, mode);
64d3a787 1083 if (ip == NULL) {
715baff1 1084 iput(pdir);
528f664c 1085 return (NULL);
64d3a787 1086 }
528f664c 1087#ifdef QUOTA
64d3a787
BJ
1088 if (ip->i_dquot != NODQUOT)
1089 panic("maknode: dquot");
1090#endif
1091 ip->i_flag |= IACC|IUPD|ICHG;
1092 if ((mode & IFMT) == 0)
1093 mode |= IFREG;
1094 ip->i_mode = mode & ~u.u_cmask;
1095 ip->i_nlink = 1;
1096 ip->i_uid = u.u_uid;
715baff1 1097 ip->i_gid = pdir->i_gid;
bb1b75f4
SL
1098 if (ip->i_mode & ISGID && !groupmember(ip->i_gid))
1099 ip->i_mode &= ~ISGID;
528f664c 1100#ifdef QUOTA
64d3a787
BJ
1101 ip->i_dquot = inoquota(ip);
1102#endif
1103
1104 /*
1105 * Make sure inode goes to disk before directory entry.
1106 */
3fd23f5c 1107 iupdat(ip, &time, &time, 1);
715baff1 1108 u.u_error = direnter(ip, ndp);
64d3a787
BJ
1109 if (u.u_error) {
1110 /*
f2a5ad78
SL
1111 * Write error occurred trying to update directory
1112 * so must deallocate the inode.
64d3a787
BJ
1113 */
1114 ip->i_nlink = 0;
1115 ip->i_flag |= ICHG;
1116 iput(ip);
528f664c 1117 return (NULL);
64d3a787 1118 }
528f664c 1119 return (ip);
64d3a787 1120}
88a7a62a
SL
1121
1122/*
1123 * A virgin directory (no blushing please).
1124 */
1125struct dirtemplate mastertemplate = {
1126 0, 12, 1, ".",
1127 0, DIRBLKSIZ - 12, 2, ".."
1128};
1129
1130/*
1131 * Mkdir system call
1132 */
1133mkdir()
1134{
1135 struct a {
1136 char *name;
1137 int dmode;
715baff1 1138 } *uap = (struct a *)u.u_ap;
88a7a62a
SL
1139 register struct inode *ip, *dp;
1140 struct dirtemplate dirtemplate;
715baff1 1141 register struct nameidata *ndp = &u.u_nd;
88a7a62a 1142
715baff1
KM
1143 ndp->ni_nameiop = CREATE;
1144 ndp->ni_segflg = UIO_USERSPACE;
1145 ndp->ni_dirp = uap->name;
1146 ip = namei(ndp);
88a7a62a
SL
1147 if (u.u_error)
1148 return;
1149 if (ip != NULL) {
1150 iput(ip);
1151 u.u_error = EEXIST;
1152 return;
1153 }
715baff1 1154 dp = ndp->ni_pdir;
88a7a62a
SL
1155 uap->dmode &= 0777;
1156 uap->dmode |= IFDIR;
1157 /*
1158 * Must simulate part of maknode here
1159 * in order to acquire the inode, but
1160 * not have it entered in the parent
1161 * directory. The entry is made later
1162 * after writing "." and ".." entries out.
1163 */
1164 ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode);
1165 if (ip == NULL) {
1166 iput(dp);
1167 return;
1168 }
1169#ifdef QUOTA
1170 if (ip->i_dquot != NODQUOT)
1171 panic("mkdir: dquot");
1172#endif
1173 ip->i_flag |= IACC|IUPD|ICHG;
1174 ip->i_mode = uap->dmode & ~u.u_cmask;
1175 ip->i_nlink = 2;
1176 ip->i_uid = u.u_uid;
1177 ip->i_gid = dp->i_gid;
1178#ifdef QUOTA
1179 ip->i_dquot = inoquota(ip);
1180#endif
1181 iupdat(ip, &time, &time, 1);
1182
1183 /*
1184 * Bump link count in parent directory
1185 * to reflect work done below. Should
1186 * be done before reference is created
1187 * so reparation is possible if we crash.
1188 */
1189 dp->i_nlink++;
1190 dp->i_flag |= ICHG;
1191 iupdat(dp, &time, &time, 1);
1192
1193 /*
1194 * Initialize directory with "."
1195 * and ".." from static template.
1196 */
1197 dirtemplate = mastertemplate;
1198 dirtemplate.dot_ino = ip->i_number;
1199 dirtemplate.dotdot_ino = dp->i_number;
1200 u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate,
1201 sizeof (dirtemplate), (off_t)0, 1, (int *)0);
1202 if (u.u_error) {
1203 dp->i_nlink--;
1204 dp->i_flag |= ICHG;
1205 goto bad;
1206 }
1207 /*
1208 * Directory all set up, now
1209 * install the entry for it in
1210 * the parent directory.
1211 */
715baff1 1212 u.u_error = direnter(ip, ndp);
88a7a62a
SL
1213 dp = NULL;
1214 if (u.u_error) {
715baff1
KM
1215 ndp->ni_nameiop = LOOKUP | NOCACHE;
1216 ndp->ni_segflg = UIO_USERSPACE;
1217 ndp->ni_dirp = uap->name;
1218 dp = namei(ndp);
88a7a62a
SL
1219 if (dp) {
1220 dp->i_nlink--;
1221 dp->i_flag |= ICHG;
1222 }
1223 }
1224bad:
1225 /*
1226 * No need to do an explicit itrunc here,
1227 * irele will do this for us because we set
1228 * the link count to 0.
1229 */
1230 if (u.u_error) {
1231 ip->i_nlink = 0;
1232 ip->i_flag |= ICHG;
1233 }
1234 if (dp)
1235 iput(dp);
1236 iput(ip);
1237}
1238
1239/*
1240 * Rmdir system call.
1241 */
1242rmdir()
1243{
1244 struct a {
1245 char *name;
715baff1 1246 } *uap = (struct a *)u.u_ap;
88a7a62a 1247 register struct inode *ip, *dp;
715baff1 1248 register struct nameidata *ndp = &u.u_nd;
88a7a62a 1249
715baff1
KM
1250 ndp->ni_nameiop = DELETE | LOCKPARENT;
1251 ndp->ni_segflg = UIO_USERSPACE;
1252 ndp->ni_dirp = uap->name;
1253 ip = namei(ndp);
88a7a62a
SL
1254 if (ip == NULL)
1255 return;
715baff1 1256 dp = ndp->ni_pdir;
88a7a62a
SL
1257 /*
1258 * No rmdir "." please.
1259 */
1260 if (dp == ip) {
1261 irele(dp);
1262 iput(ip);
1263 u.u_error = EINVAL;
1264 return;
1265 }
1266 if ((ip->i_mode&IFMT) != IFDIR) {
1267 u.u_error = ENOTDIR;
1268 goto out;
1269 }
1270 /*
1271 * Don't remove a mounted on directory.
1272 */
1273 if (ip->i_dev != dp->i_dev) {
1274 u.u_error = EBUSY;
1275 goto out;
1276 }
1277 /*
1278 * Verify the directory is empty (and valid).
1279 * (Rmdir ".." won't be valid since
1280 * ".." will contain a reference to
1281 * the current directory and thus be
1282 * non-empty.)
1283 */
1284 if (ip->i_nlink != 2 || !dirempty(ip)) {
1285 u.u_error = ENOTEMPTY;
1286 goto out;
1287 }
1288 /*
1289 * Delete reference to directory before purging
1290 * inode. If we crash in between, the directory
1291 * will be reattached to lost+found,
1292 */
715baff1 1293 if (dirremove(ndp) == 0)
88a7a62a
SL
1294 goto out;
1295 dp->i_nlink--;
1296 dp->i_flag |= ICHG;
1297 iput(dp);
1298 dp = NULL;
1299 /*
1300 * Truncate inode. The only stuff left
1301 * in the directory is "." and "..". The
1302 * "." reference is inconsequential since
1303 * we're quashing it. The ".." reference
1304 * has already been adjusted above. We've
1305 * removed the "." reference and the reference
1306 * in the parent directory, but there may be
1307 * other hard links so decrement by 2 and
1308 * worry about them later.
1309 */
1310 ip->i_nlink -= 2;
1311 itrunc(ip, (u_long)0);
1312out:
1313 if (dp)
1314 iput(dp);
1315 iput(ip);
1316}
1317
1318struct file *
1319getinode(fdes)
1320 int fdes;
1321{
8462a185 1322 struct file *fp;
88a7a62a 1323
8462a185
SL
1324 if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) {
1325 u.u_error = EBADF;
1326 return ((struct file *)0);
1327 }
88a7a62a
SL
1328 if (fp->f_type != DTYPE_INODE) {
1329 u.u_error = EINVAL;
8462a185 1330 return ((struct file *)0);
88a7a62a
SL
1331 }
1332 return (fp);
1333}
1334
1335/*
1336 * mode mask for creation of files
1337 */
1338umask()
1339{
1340 register struct a {
1341 int mask;
715baff1 1342 } *uap = (struct a *)u.u_ap;
88a7a62a 1343
88a7a62a
SL
1344 u.u_r.r_val1 = u.u_cmask;
1345 u.u_cmask = uap->mask & 07777;
1346}