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