don't close, binval on failed mount because already mounted.
[unix-history] / usr / src / sys / ufs / ffs / ufs_vnops.c
CommitLineData
da7c5cc6
KM
1/*
2 * Copyright (c) 1982 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
51c4d8fa 6 * @(#)ufs_vnops.c 6.21 (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;
31949305 334 u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0);
4f083fd7 335 /* handle u.u_error != 0 */
3e78e260
BJ
336 iput(ip);
337}
338
339/*
340 * Unlink system call.
341 * Hard to avoid races here, especially
342 * in unlinking directories.
343 */
344unlink()
345{
3e78e260
BJ
346 struct a {
347 char *fname;
715baff1 348 } *uap = (struct a *)u.u_ap;
4f083fd7 349 register struct inode *ip, *dp;
715baff1 350 register struct nameidata *ndp = &u.u_nd;
3e78e260 351
715baff1
KM
352 ndp->ni_nameiop = DELETE | LOCKPARENT;
353 ndp->ni_segflg = UIO_USERSPACE;
354 ndp->ni_dirp = uap->fname;
355 ip = namei(ndp);
4f083fd7 356 if (ip == NULL)
3e78e260 357 return;
715baff1 358 dp = ndp->ni_pdir;
4f083fd7 359 if ((ip->i_mode&IFMT) == IFDIR && !suser())
3e78e260
BJ
360 goto out;
361 /*
362 * Don't unlink a mounted file.
363 */
4f083fd7 364 if (ip->i_dev != dp->i_dev) {
3e78e260
BJ
365 u.u_error = EBUSY;
366 goto out;
367 }
368 if (ip->i_flag&ITEXT)
369 xrele(ip); /* try once to free text */
715baff1 370 if (dirremove(ndp)) {
64d3a787
BJ
371 ip->i_nlink--;
372 ip->i_flag |= ICHG;
6459ebe0 373 }
3e78e260 374out:
4f083fd7 375 if (dp == ip)
8eee8525
KM
376 irele(ip);
377 else
378 iput(ip);
4f083fd7 379 iput(dp);
3e78e260
BJ
380}
381
382/*
383 * Seek system call
384 */
35e7c31a 385lseek()
3e78e260
BJ
386{
387 register struct file *fp;
388 register struct a {
528f664c 389 int fd;
3e78e260
BJ
390 off_t off;
391 int sbase;
715baff1 392 } *uap = (struct a *)u.u_ap;
3e78e260 393
8462a185
SL
394 GETF(fp, uap->fd);
395 if (fp->f_type != DTYPE_INODE) {
396 u.u_error = ESPIPE;
3e78e260 397 return;
8462a185 398 }
b4d1aee9
SL
399 switch (uap->sbase) {
400
401 case L_INCR:
402 fp->f_offset += uap->off;
403 break;
404
405 case L_XTND:
406 fp->f_offset = uap->off + ((struct inode *)fp->f_data)->i_size;
407 break;
408
409 case L_SET:
410 fp->f_offset = uap->off;
411 break;
412
413 default:
414 u.u_error = EINVAL;
415 return;
416 }
417 u.u_r.r_off = fp->f_offset;
3e78e260
BJ
418}
419
420/*
421 * Access system call
422 */
423saccess()
424{
425 register svuid, svgid;
426 register struct inode *ip;
427 register struct a {
428 char *fname;
429 int fmode;
715baff1
KM
430 } *uap = (struct a *)u.u_ap;
431 register struct nameidata *ndp = &u.u_nd;
3e78e260 432
3e78e260
BJ
433 svuid = u.u_uid;
434 svgid = u.u_gid;
435 u.u_uid = u.u_ruid;
436 u.u_gid = u.u_rgid;
715baff1
KM
437 ndp->ni_nameiop = LOOKUP | FOLLOW;
438 ndp->ni_segflg = UIO_USERSPACE;
439 ndp->ni_dirp = uap->fname;
440 ip = namei(ndp);
3e78e260 441 if (ip != NULL) {
88a7a62a 442 if ((uap->fmode&R_OK) && access(ip, IREAD))
528f664c 443 goto done;
88a7a62a 444 if ((uap->fmode&W_OK) && access(ip, IWRITE))
528f664c 445 goto done;
88a7a62a 446 if ((uap->fmode&X_OK) && access(ip, IEXEC))
528f664c
SL
447 goto done;
448done:
3e78e260
BJ
449 iput(ip);
450 }
451 u.u_uid = svuid;
452 u.u_gid = svgid;
453}
d67a03eb 454
d67a03eb 455/*
6459ebe0 456 * Stat system call. This version follows links.
d67a03eb
BJ
457 */
458stat()
459{
d67a03eb 460
715baff1 461 stat1(FOLLOW);
d67a03eb
BJ
462}
463
5485e062 464/*
6459ebe0 465 * Lstat system call. This version does not follow links.
5485e062
BJ
466 */
467lstat()
88a7a62a
SL
468{
469
715baff1 470 stat1(NOFOLLOW);
88a7a62a
SL
471}
472
473stat1(follow)
474 int follow;
5485e062
BJ
475{
476 register struct inode *ip;
477 register struct a {
478 char *fname;
88a7a62a 479 struct stat *ub;
715baff1 480 } *uap = (struct a *)u.u_ap;
88a7a62a 481 struct stat sb;
715baff1 482 register struct nameidata *ndp = &u.u_nd;
5485e062 483
715baff1
KM
484 ndp->ni_nameiop = LOOKUP | follow;
485 ndp->ni_segflg = UIO_USERSPACE;
486 ndp->ni_dirp = uap->fname;
487 ip = namei(ndp);
5485e062
BJ
488 if (ip == NULL)
489 return;
0eaf24e3 490 (void) ino_stat(ip, &sb);
5485e062 491 iput(ip);
88a7a62a 492 u.u_error = copyout((caddr_t)&sb, (caddr_t)uap->ub, sizeof (sb));
d67a03eb
BJ
493}
494
495/*
5485e062
BJ
496 * Return target name of a symbolic link
497 */
498readlink()
499{
500 register struct inode *ip;
501 register struct a {
502 char *name;
503 char *buf;
504 int count;
31949305 505 } *uap = (struct a *)u.u_ap;
715baff1 506 register struct nameidata *ndp = &u.u_nd;
31949305 507 int resid;
5485e062 508
715baff1
KM
509 ndp->ni_nameiop = LOOKUP;
510 ndp->ni_segflg = UIO_USERSPACE;
511 ndp->ni_dirp = uap->name;
512 ip = namei(ndp);
5485e062
BJ
513 if (ip == NULL)
514 return;
515 if ((ip->i_mode&IFMT) != IFLNK) {
47af7174 516 u.u_error = EINVAL;
5485e062
BJ
517 goto out;
518 }
31949305 519 u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid);
5485e062
BJ
520out:
521 iput(ip);
31949305 522 u.u_r.r_val1 = uap->count - resid;
5485e062
BJ
523}
524
4f083fd7
SL
525/*
526 * Change mode of a file given path name.
527 */
3e78e260 528chmod()
5485e062 529{
528f664c
SL
530 struct inode *ip;
531 struct a {
3e78e260
BJ
532 char *fname;
533 int fmode;
715baff1 534 } *uap = (struct a *)u.u_ap;
5485e062 535
715baff1 536 if ((ip = owner(uap->fname, FOLLOW)) == NULL)
5485e062 537 return;
47af7174 538 u.u_error = chmod1(ip, uap->fmode);
4f083fd7 539 iput(ip);
528f664c 540}
f94ceb3b 541
4f083fd7
SL
542/*
543 * Change mode of a file given a file descriptor.
544 */
528f664c
SL
545fchmod()
546{
547 struct a {
548 int fd;
549 int fmode;
715baff1 550 } *uap = (struct a *)u.u_ap;
528f664c
SL
551 register struct inode *ip;
552 register struct file *fp;
553
88a7a62a 554 fp = getinode(uap->fd);
528f664c
SL
555 if (fp == NULL)
556 return;
88a7a62a 557 ip = (struct inode *)fp->f_data;
4f083fd7 558 if (u.u_uid != ip->i_uid && !suser())
528f664c 559 return;
a388503d 560 ILOCK(ip);
47af7174 561 u.u_error = chmod1(ip, uap->fmode);
a388503d 562 IUNLOCK(ip);
528f664c
SL
563}
564
4f083fd7
SL
565/*
566 * Change the mode on a file.
567 * Inode must be locked before calling.
568 */
528f664c
SL
569chmod1(ip, mode)
570 register struct inode *ip;
571 register int mode;
572{
197da11b 573
47af7174
KM
574 if (ip->i_fs->fs_ronly)
575 return (EROFS);
3e78e260 576 ip->i_mode &= ~07777;
f94ceb3b 577 if (u.u_uid) {
47af7174
KM
578 if ((ip->i_mode & IFMT) != IFDIR)
579 mode &= ~ISVTX;
bb1b75f4
SL
580 if (!groupmember(ip->i_gid))
581 mode &= ~ISGID;
f94ceb3b 582 }
528f664c 583 ip->i_mode |= mode&07777;
3e78e260
BJ
584 ip->i_flag |= ICHG;
585 if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
586 xrele(ip);
47af7174 587 return (0);
5485e062
BJ
588}
589
4f083fd7
SL
590/*
591 * Set ownership given a path name.
592 */
3e78e260 593chown()
d67a03eb 594{
528f664c
SL
595 struct inode *ip;
596 struct a {
3e78e260
BJ
597 char *fname;
598 int uid;
599 int gid;
715baff1 600 } *uap = (struct a *)u.u_ap;
d67a03eb 601
715baff1 602 if (!suser() || (ip = owner(uap->fname, NOFOLLOW)) == NULL)
d67a03eb 603 return;
bb1b75f4 604 u.u_error = chown1(ip, uap->uid, uap->gid);
4f083fd7 605 iput(ip);
528f664c 606}
f94ceb3b 607
4f083fd7
SL
608/*
609 * Set ownership given a file descriptor.
610 */
528f664c
SL
611fchown()
612{
613 struct a {
614 int fd;
615 int uid;
616 int gid;
715baff1 617 } *uap = (struct a *)u.u_ap;
528f664c
SL
618 register struct inode *ip;
619 register struct file *fp;
620
88a7a62a 621 fp = getinode(uap->fd);
528f664c
SL
622 if (fp == NULL)
623 return;
88a7a62a 624 ip = (struct inode *)fp->f_data;
aad8ef38 625 if (!suser())
528f664c 626 return;
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;
bb1b75f4 650#ifdef QUOTA
3809bf69 651 if (ip->i_uid == uid) /* this just speeds things a little */
0a77f278 652 change = 0;
2e073567
SL
653 else
654 change = ip->i_blocks;
655 (void) chkdq(ip, -change, 1);
656 (void) chkiq(ip->i_dev, ip, ip->i_uid, 1);
0a77f278 657 dqrele(ip->i_dquot);
f94ceb3b 658#endif
bb1b75f4
SL
659 ip->i_uid = uid;
660 ip->i_gid = gid;
3e78e260
BJ
661 ip->i_flag |= ICHG;
662 if (u.u_ruid != 0)
663 ip->i_mode &= ~(ISUID|ISGID);
528f664c 664#ifdef QUOTA
0a77f278 665 ip->i_dquot = inoquota(ip);
2e073567
SL
666 (void) chkdq(ip, change, 1);
667 (void) chkiq(ip->i_dev, (struct inode *)NULL, uid, 1);
668 return (u.u_error); /* should == 0 ALWAYS !! */
669#else
bb1b75f4 670 return (0);
2e073567 671#endif
d67a03eb
BJ
672}
673
bb1b75f4
SL
674utimes()
675{
676 register struct a {
677 char *fname;
678 struct timeval *tptr;
679 } *uap = (struct a *)u.u_ap;
680 register struct inode *ip;
681 struct timeval tv[2];
682
715baff1 683 if ((ip = owner(uap->fname, FOLLOW)) == NULL)
bb1b75f4 684 return;
47af7174
KM
685 if (ip->i_fs->fs_ronly) {
686 u.u_error = EROFS;
687 iput(ip);
688 return;
689 }
bb1b75f4
SL
690 u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
691 if (u.u_error == 0) {
692 ip->i_flag |= IACC|IUPD|ICHG;
693 iupdat(ip, &tv[0], &tv[1], 0);
694 }
695 iput(ip);
696}
d67a03eb 697
4f083fd7
SL
698/*
699 * Flush any pending I/O.
700 */
3e78e260 701sync()
d67a03eb 702{
d67a03eb 703
3fd23f5c 704 update();
d67a03eb 705}
64d3a787 706
4f083fd7
SL
707/*
708 * Truncate a file given its path name.
709 */
528f664c
SL
710truncate()
711{
712 struct a {
713 char *fname;
4f083fd7 714 u_long length;
31949305 715 } *uap = (struct a *)u.u_ap;
528f664c 716 struct inode *ip;
715baff1 717 register struct nameidata *ndp = &u.u_nd;
528f664c 718
715baff1
KM
719 ndp->ni_nameiop = LOOKUP | FOLLOW;
720 ndp->ni_segflg = UIO_USERSPACE;
721 ndp->ni_dirp = uap->fname;
722 ip = namei(ndp);
528f664c
SL
723 if (ip == NULL)
724 return;
725 if (access(ip, IWRITE))
726 goto bad;
727 if ((ip->i_mode&IFMT) == IFDIR) {
728 u.u_error = EISDIR;
729 goto bad;
730 }
731 itrunc(ip, uap->length);
528f664c
SL
732bad:
733 iput(ip);
734}
735
4f083fd7
SL
736/*
737 * Truncate a file given a file descriptor.
738 */
528f664c
SL
739ftruncate()
740{
741 struct a {
742 int fd;
4f083fd7 743 u_long length;
31949305 744 } *uap = (struct a *)u.u_ap;
528f664c
SL
745 struct inode *ip;
746 struct file *fp;
747
88a7a62a 748 fp = getinode(uap->fd);
528f664c
SL
749 if (fp == NULL)
750 return;
528f664c
SL
751 if ((fp->f_flag&FWRITE) == 0) {
752 u.u_error = EINVAL;
753 return;
754 }
88a7a62a 755 ip = (struct inode *)fp->f_data;
a388503d 756 ILOCK(ip);
528f664c 757 itrunc(ip, uap->length);
a388503d 758 IUNLOCK(ip);
4f083fd7
SL
759}
760
761/*
762 * Synch an open file.
763 */
764fsync()
765{
766 struct a {
767 int fd;
768 } *uap = (struct a *)u.u_ap;
769 struct inode *ip;
770 struct file *fp;
771
88a7a62a 772 fp = getinode(uap->fd);
4f083fd7
SL
773 if (fp == NULL)
774 return;
88a7a62a 775 ip = (struct inode *)fp->f_data;
a388503d 776 ILOCK(ip);
4f083fd7 777 syncip(ip);
a388503d 778 IUNLOCK(ip);
528f664c
SL
779}
780
4f083fd7
SL
781/*
782 * Rename system call.
783 * rename("foo", "bar");
784 * is essentially
785 * unlink("bar");
786 * link("foo", "bar");
787 * unlink("foo");
788 * but ``atomically''. Can't do full commit without saving state in the
789 * inode on disk which isn't feasible at this time. Best we can do is
790 * always guarantee the target exists.
791 *
792 * Basic algorithm is:
793 *
794 * 1) Bump link count on source while we're linking it to the
795 * target. This also insure the inode won't be deleted out
68f21562
KM
796 * from underneath us while we work (it may be truncated by
797 * a concurrent `trunc' or `open' for creation).
4f083fd7
SL
798 * 2) Link source to destination. If destination already exists,
799 * delete it first.
68f21562
KM
800 * 3) Unlink source reference to inode if still around. If a
801 * directory was moved and the parent of the destination
4f083fd7
SL
802 * is different from the source, patch the ".." entry in the
803 * directory.
804 *
805 * Source and destination must either both be directories, or both
806 * not be directories. If target is a directory, it must be empty.
807 */
528f664c
SL
808rename()
809{
810 struct a {
811 char *from;
812 char *to;
715baff1 813 } *uap = (struct a *)u.u_ap;
4f083fd7 814 register struct inode *ip, *xp, *dp;
68f21562
KM
815 struct dirtemplate dirbuf;
816 int doingdirectory = 0, oldparent = 0, newparent = 0;
715baff1 817 register struct nameidata *ndp = &u.u_nd;
a5390dce 818 int error = 0;
4f083fd7 819
715baff1
KM
820 ndp->ni_nameiop = DELETE | LOCKPARENT;
821 ndp->ni_segflg = UIO_USERSPACE;
822 ndp->ni_dirp = uap->from;
823 ip = namei(ndp);
4f083fd7
SL
824 if (ip == NULL)
825 return;
715baff1 826 dp = ndp->ni_pdir;
4f083fd7
SL
827 if ((ip->i_mode&IFMT) == IFDIR) {
828 register struct direct *d;
829
715baff1 830 d = &ndp->ni_dent;
4f083fd7 831 /*
046f18d1 832 * Avoid ".", "..", and aliases of "." for obvious reasons.
4f083fd7 833 */
046f18d1
SL
834 if ((d->d_namlen == 1 && d->d_name[0] == '.') ||
835 (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) ||
68f21562 836 (dp == ip) || (ip->i_flag & IRENAME)) {
046f18d1
SL
837 iput(dp);
838 if (dp == ip)
839 irele(ip);
840 else
4f083fd7 841 iput(ip);
046f18d1
SL
842 u.u_error = EINVAL;
843 return;
4f083fd7 844 }
68f21562 845 ip->i_flag |= IRENAME;
4f083fd7
SL
846 oldparent = dp->i_number;
847 doingdirectory++;
848 }
046f18d1 849 iput(dp);
4f083fd7
SL
850
851 /*
852 * 1) Bump link count while we're moving stuff
853 * around. If we crash somewhere before
854 * completing our work, the link count
855 * may be wrong, but correctable.
856 */
857 ip->i_nlink++;
858 ip->i_flag |= ICHG;
859 iupdat(ip, &time, &time, 1);
a388503d 860 IUNLOCK(ip);
4f083fd7
SL
861
862 /*
863 * When the target exists, both the directory
864 * and target inodes are returned locked.
865 */
715baff1
KM
866 ndp->ni_nameiop = CREATE | LOCKPARENT | NOCACHE;
867 ndp->ni_dirp = (caddr_t)uap->to;
868 xp = namei(ndp);
a5390dce
SL
869 if (u.u_error) {
870 error = u.u_error;
4f083fd7 871 goto out;
a5390dce 872 }
715baff1 873 dp = ndp->ni_pdir;
046f18d1
SL
874 /*
875 * If ".." must be changed (ie the directory gets a new
81552f0f
KM
876 * parent) then the source directory must not be in the
877 * directory heirarchy above the target, as this would
878 * orphan everything below the source directory. Also
879 * the user must have write permission in the source so
880 * as to be able to change "..". We must repeat the call
881 * to namei, as the parent directory is unlocked by the
882 * call to checkpath().
046f18d1 883 */
68f21562
KM
884 if (oldparent != dp->i_number)
885 newparent = dp->i_number;
886 if (doingdirectory && newparent) {
81552f0f
KM
887 if (access(ip, IWRITE))
888 goto bad;
889 do {
715baff1 890 dp = ndp->ni_pdir;
81552f0f
KM
891 if (xp != NULL)
892 iput(xp);
893 u.u_error = checkpath(ip, dp);
894 if (u.u_error)
895 goto out;
715baff1 896 xp = namei(ndp);
81552f0f
KM
897 if (u.u_error) {
898 error = u.u_error;
899 goto out;
900 }
715baff1 901 } while (dp != ndp->ni_pdir);
81552f0f 902 }
4f083fd7
SL
903 /*
904 * 2) If target doesn't exist, link the target
905 * to the source and unlink the source.
906 * Otherwise, rewrite the target directory
907 * entry to reference the source inode and
908 * expunge the original entry's existence.
909 */
4f083fd7
SL
910 if (xp == NULL) {
911 if (dp->i_dev != ip->i_dev) {
a5390dce 912 error = EXDEV;
4f083fd7
SL
913 goto bad;
914 }
915 /*
68f21562
KM
916 * Account for ".." in new directory.
917 * When source and destination have the same
918 * parent we don't fool with the link count.
4f083fd7 919 */
68f21562 920 if (doingdirectory && newparent) {
4f083fd7
SL
921 dp->i_nlink++;
922 dp->i_flag |= ICHG;
923 iupdat(dp, &time, &time, 1);
924 }
715baff1 925 error = direnter(ip, ndp);
f2a5ad78 926 if (error)
4f083fd7
SL
927 goto out;
928 } else {
929 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) {
a5390dce 930 error = EXDEV;
4f083fd7
SL
931 goto bad;
932 }
e69c3c9c
SL
933 /*
934 * Short circuit rename(foo, foo).
935 */
936 if (xp->i_number == ip->i_number)
937 goto bad;
80cee150
JB
938 /*
939 * If the parent directory is "sticky", then the user must
940 * own the parent directory, or the destination of the rename,
941 * otherwise the destination may not be changed (except by
942 * root). This implements append-only directories.
943 */
944 if ((dp->i_mode & ISVTX) && u.u_uid != 0 &&
945 u.u_uid != dp->i_uid && xp->i_uid != u.u_uid) {
946 error = EPERM;
947 goto bad;
948 }
4f083fd7 949 /*
a5390dce
SL
950 * Target must be empty if a directory
951 * and have no links to it.
4f083fd7
SL
952 * Also, insure source and target are
953 * compatible (both directories, or both
954 * not directories).
955 */
956 if ((xp->i_mode&IFMT) == IFDIR) {
68f21562 957 if (!dirempty(xp, dp->i_number) || xp->i_nlink > 2) {
a5390dce 958 error = ENOTEMPTY;
4f083fd7
SL
959 goto bad;
960 }
961 if (!doingdirectory) {
a5390dce 962 error = ENOTDIR;
4f083fd7
SL
963 goto bad;
964 }
68f21562 965 cacheinval(dp);
4f083fd7 966 } else if (doingdirectory) {
a5390dce 967 error = EISDIR;
4f083fd7
SL
968 goto bad;
969 }
715baff1 970 dirrewrite(dp, ip, ndp);
a5390dce
SL
971 if (u.u_error) {
972 error = u.u_error;
4f083fd7 973 goto bad1;
a5390dce 974 }
4f083fd7 975 /*
a5390dce
SL
976 * Adjust the link count of the target to
977 * reflect the dirrewrite above. If this is
978 * a directory it is empty and there are
979 * no links to it, so we can squash the inode and
980 * any space associated with it. We disallowed
981 * renaming over top of a directory with links to
68f21562
KM
982 * it above, as the remaining link would point to
983 * a directory without "." or ".." entries.
4f083fd7 984 */
a5390dce 985 xp->i_nlink--;
4f083fd7 986 if (doingdirectory) {
a5390dce
SL
987 if (--xp->i_nlink != 0)
988 panic("rename: linked directory");
4f083fd7 989 itrunc(xp, (u_long)0);
a5390dce 990 }
4f083fd7
SL
991 xp->i_flag |= ICHG;
992 iput(xp);
31db12cb 993 xp = NULL;
4f083fd7
SL
994 }
995
996 /*
997 * 3) Unlink the source.
998 */
715baff1
KM
999 ndp->ni_nameiop = DELETE | LOCKPARENT;
1000 ndp->ni_segflg = UIO_USERSPACE;
1001 ndp->ni_dirp = uap->from;
68f21562 1002 xp = namei(ndp);
4f1a9037
KM
1003 if (xp != NULL)
1004 dp = ndp->ni_pdir;
1005 else
1006 dp = NULL;
4f083fd7 1007 /*
68f21562
KM
1008 * Insure that the directory entry still exists and has not
1009 * changed while the new name has been entered. If the source is
1010 * a file then the entry may have been unlinked or renamed. In
1011 * either case there is no further work to be done. If the source
1012 * is a directory then it cannot have been rmdir'ed; its link
1013 * count of three would cause a rmdir to fail with ENOTEMPTY.
1014 * The IRENAME flag insures that it cannot be moved by another
1015 * rename.
4f083fd7 1016 */
4f1a9037 1017 if (xp != ip) {
68f21562 1018 if (doingdirectory)
4f1a9037 1019 panic("rename: lost dir entry");
68f21562 1020 } else {
4f083fd7 1021 /*
68f21562
KM
1022 * If the source is a directory with a
1023 * new parent, the link count of the old
1024 * parent directory must be decremented
1025 * and ".." set to point to the new parent.
4f083fd7 1026 */
68f21562 1027 if (doingdirectory && newparent) {
4f083fd7
SL
1028 dp->i_nlink--;
1029 dp->i_flag |= ICHG;
68f21562
KM
1030 error = rdwri(UIO_READ, xp, (caddr_t)&dirbuf,
1031 sizeof (struct dirtemplate), (off_t)0, 1,
1032 (int *)0);
1033 if (error == 0) {
1034 if (dirbuf.dotdot_namlen != 2 ||
1035 dirbuf.dotdot_name[0] != '.' ||
1036 dirbuf.dotdot_name[1] != '.') {
1037 printf("rename: mangled dir\n");
1038 } else {
1039 dirbuf.dotdot_ino = newparent;
1040 (void) rdwri(UIO_WRITE, xp,
1041 (caddr_t)&dirbuf,
1042 sizeof (struct dirtemplate),
1043 (off_t)0, 1, (int *)0);
1044 cacheinval(dp);
1045 }
1046 }
4f083fd7 1047 }
715baff1 1048 if (dirremove(ndp)) {
68f21562
KM
1049 xp->i_nlink--;
1050 xp->i_flag |= ICHG;
4f083fd7 1051 }
68f21562
KM
1052 xp->i_flag &= ~IRENAME;
1053 if (error == 0) /* XXX conservative */
a5390dce 1054 error = u.u_error;
4f083fd7 1055 }
4f083fd7
SL
1056 if (dp)
1057 iput(dp);
68f21562
KM
1058 if (xp)
1059 iput(xp);
1060 irele(ip);
1061 if (error)
1062 u.u_error = error;
1063 return;
a5390dce 1064
4f083fd7 1065bad:
31db12cb 1066 iput(dp);
4f083fd7
SL
1067bad1:
1068 if (xp)
31db12cb 1069 iput(xp);
4f083fd7
SL
1070out:
1071 ip->i_nlink--;
1072 ip->i_flag |= ICHG;
1073 irele(ip);
a5390dce
SL
1074 if (error)
1075 u.u_error = error;
528f664c
SL
1076}
1077
64d3a787
BJ
1078/*
1079 * Make a new file.
1080 */
1081struct inode *
715baff1 1082maknode(mode, ndp)
64d3a787 1083 int mode;
715baff1 1084 register struct nameidata *ndp;
64d3a787
BJ
1085{
1086 register struct inode *ip;
715baff1 1087 register struct inode *pdir = ndp->ni_pdir;
64d3a787
BJ
1088 ino_t ipref;
1089
1090 if ((mode & IFMT) == IFDIR)
715baff1 1091 ipref = dirpref(pdir->i_fs);
64d3a787 1092 else
715baff1
KM
1093 ipref = pdir->i_number;
1094 ip = ialloc(pdir, ipref, mode);
64d3a787 1095 if (ip == NULL) {
715baff1 1096 iput(pdir);
528f664c 1097 return (NULL);
64d3a787 1098 }
528f664c 1099#ifdef QUOTA
64d3a787
BJ
1100 if (ip->i_dquot != NODQUOT)
1101 panic("maknode: dquot");
1102#endif
1103 ip->i_flag |= IACC|IUPD|ICHG;
1104 if ((mode & IFMT) == 0)
1105 mode |= IFREG;
1106 ip->i_mode = mode & ~u.u_cmask;
1107 ip->i_nlink = 1;
1108 ip->i_uid = u.u_uid;
715baff1 1109 ip->i_gid = pdir->i_gid;
bb1b75f4
SL
1110 if (ip->i_mode & ISGID && !groupmember(ip->i_gid))
1111 ip->i_mode &= ~ISGID;
528f664c 1112#ifdef QUOTA
64d3a787
BJ
1113 ip->i_dquot = inoquota(ip);
1114#endif
1115
1116 /*
1117 * Make sure inode goes to disk before directory entry.
1118 */
3fd23f5c 1119 iupdat(ip, &time, &time, 1);
715baff1 1120 u.u_error = direnter(ip, ndp);
64d3a787
BJ
1121 if (u.u_error) {
1122 /*
f2a5ad78
SL
1123 * Write error occurred trying to update directory
1124 * so must deallocate the inode.
64d3a787
BJ
1125 */
1126 ip->i_nlink = 0;
1127 ip->i_flag |= ICHG;
1128 iput(ip);
528f664c 1129 return (NULL);
64d3a787 1130 }
528f664c 1131 return (ip);
64d3a787 1132}
88a7a62a
SL
1133
1134/*
1135 * A virgin directory (no blushing please).
1136 */
1137struct dirtemplate mastertemplate = {
1138 0, 12, 1, ".",
1139 0, DIRBLKSIZ - 12, 2, ".."
1140};
1141
1142/*
1143 * Mkdir system call
1144 */
1145mkdir()
1146{
1147 struct a {
1148 char *name;
1149 int dmode;
715baff1 1150 } *uap = (struct a *)u.u_ap;
88a7a62a
SL
1151 register struct inode *ip, *dp;
1152 struct dirtemplate dirtemplate;
715baff1 1153 register struct nameidata *ndp = &u.u_nd;
88a7a62a 1154
715baff1
KM
1155 ndp->ni_nameiop = CREATE;
1156 ndp->ni_segflg = UIO_USERSPACE;
1157 ndp->ni_dirp = uap->name;
1158 ip = namei(ndp);
88a7a62a
SL
1159 if (u.u_error)
1160 return;
1161 if (ip != NULL) {
1162 iput(ip);
1163 u.u_error = EEXIST;
1164 return;
1165 }
715baff1 1166 dp = ndp->ni_pdir;
88a7a62a
SL
1167 uap->dmode &= 0777;
1168 uap->dmode |= IFDIR;
1169 /*
1170 * Must simulate part of maknode here
1171 * in order to acquire the inode, but
1172 * not have it entered in the parent
1173 * directory. The entry is made later
1174 * after writing "." and ".." entries out.
1175 */
1176 ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode);
1177 if (ip == NULL) {
1178 iput(dp);
1179 return;
1180 }
1181#ifdef QUOTA
1182 if (ip->i_dquot != NODQUOT)
1183 panic("mkdir: dquot");
1184#endif
1185 ip->i_flag |= IACC|IUPD|ICHG;
1186 ip->i_mode = uap->dmode & ~u.u_cmask;
1187 ip->i_nlink = 2;
1188 ip->i_uid = u.u_uid;
1189 ip->i_gid = dp->i_gid;
1190#ifdef QUOTA
1191 ip->i_dquot = inoquota(ip);
1192#endif
1193 iupdat(ip, &time, &time, 1);
1194
1195 /*
1196 * Bump link count in parent directory
1197 * to reflect work done below. Should
1198 * be done before reference is created
1199 * so reparation is possible if we crash.
1200 */
1201 dp->i_nlink++;
1202 dp->i_flag |= ICHG;
1203 iupdat(dp, &time, &time, 1);
1204
1205 /*
1206 * Initialize directory with "."
1207 * and ".." from static template.
1208 */
1209 dirtemplate = mastertemplate;
1210 dirtemplate.dot_ino = ip->i_number;
1211 dirtemplate.dotdot_ino = dp->i_number;
1212 u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate,
1213 sizeof (dirtemplate), (off_t)0, 1, (int *)0);
1214 if (u.u_error) {
1215 dp->i_nlink--;
1216 dp->i_flag |= ICHG;
1217 goto bad;
1218 }
23de9f20
KM
1219 if (DIRBLKSIZ > ip->i_fs->fs_fsize)
1220 panic("mkdir: blksize"); /* XXX - should grow with bmap() */
1221 else
1222 ip->i_size = DIRBLKSIZ;
88a7a62a
SL
1223 /*
1224 * Directory all set up, now
1225 * install the entry for it in
1226 * the parent directory.
1227 */
715baff1 1228 u.u_error = direnter(ip, ndp);
88a7a62a
SL
1229 dp = NULL;
1230 if (u.u_error) {
715baff1
KM
1231 ndp->ni_nameiop = LOOKUP | NOCACHE;
1232 ndp->ni_segflg = UIO_USERSPACE;
1233 ndp->ni_dirp = uap->name;
1234 dp = namei(ndp);
88a7a62a
SL
1235 if (dp) {
1236 dp->i_nlink--;
1237 dp->i_flag |= ICHG;
1238 }
1239 }
1240bad:
1241 /*
1242 * No need to do an explicit itrunc here,
1243 * irele will do this for us because we set
1244 * the link count to 0.
1245 */
1246 if (u.u_error) {
1247 ip->i_nlink = 0;
1248 ip->i_flag |= ICHG;
1249 }
1250 if (dp)
1251 iput(dp);
1252 iput(ip);
1253}
1254
1255/*
1256 * Rmdir system call.
1257 */
1258rmdir()
1259{
1260 struct a {
1261 char *name;
715baff1 1262 } *uap = (struct a *)u.u_ap;
88a7a62a 1263 register struct inode *ip, *dp;
715baff1 1264 register struct nameidata *ndp = &u.u_nd;
88a7a62a 1265
715baff1
KM
1266 ndp->ni_nameiop = DELETE | LOCKPARENT;
1267 ndp->ni_segflg = UIO_USERSPACE;
1268 ndp->ni_dirp = uap->name;
1269 ip = namei(ndp);
88a7a62a
SL
1270 if (ip == NULL)
1271 return;
715baff1 1272 dp = ndp->ni_pdir;
88a7a62a
SL
1273 /*
1274 * No rmdir "." please.
1275 */
1276 if (dp == ip) {
1277 irele(dp);
1278 iput(ip);
1279 u.u_error = EINVAL;
1280 return;
1281 }
1282 if ((ip->i_mode&IFMT) != IFDIR) {
1283 u.u_error = ENOTDIR;
1284 goto out;
1285 }
1286 /*
1287 * Don't remove a mounted on directory.
1288 */
1289 if (ip->i_dev != dp->i_dev) {
1290 u.u_error = EBUSY;
1291 goto out;
1292 }
1293 /*
1294 * Verify the directory is empty (and valid).
1295 * (Rmdir ".." won't be valid since
1296 * ".." will contain a reference to
1297 * the current directory and thus be
1298 * non-empty.)
1299 */
68f21562 1300 if (ip->i_nlink != 2 || !dirempty(ip, dp->i_number)) {
88a7a62a
SL
1301 u.u_error = ENOTEMPTY;
1302 goto out;
1303 }
1304 /*
1305 * Delete reference to directory before purging
1306 * inode. If we crash in between, the directory
1307 * will be reattached to lost+found,
1308 */
715baff1 1309 if (dirremove(ndp) == 0)
88a7a62a
SL
1310 goto out;
1311 dp->i_nlink--;
1312 dp->i_flag |= ICHG;
68f21562 1313 cacheinval(dp);
88a7a62a
SL
1314 iput(dp);
1315 dp = NULL;
1316 /*
1317 * Truncate inode. The only stuff left
1318 * in the directory is "." and "..". The
1319 * "." reference is inconsequential since
1320 * we're quashing it. The ".." reference
1321 * has already been adjusted above. We've
1322 * removed the "." reference and the reference
1323 * in the parent directory, but there may be
1324 * other hard links so decrement by 2 and
1325 * worry about them later.
1326 */
1327 ip->i_nlink -= 2;
1328 itrunc(ip, (u_long)0);
1d00c1cf 1329 cacheinval(ip);
88a7a62a
SL
1330out:
1331 if (dp)
1332 iput(dp);
1333 iput(ip);
1334}
1335
1336struct file *
1337getinode(fdes)
1338 int fdes;
1339{
8462a185 1340 struct file *fp;
88a7a62a 1341
8462a185
SL
1342 if ((unsigned)fdes >= NOFILE || (fp = u.u_ofile[fdes]) == NULL) {
1343 u.u_error = EBADF;
1344 return ((struct file *)0);
1345 }
88a7a62a
SL
1346 if (fp->f_type != DTYPE_INODE) {
1347 u.u_error = EINVAL;
8462a185 1348 return ((struct file *)0);
88a7a62a
SL
1349 }
1350 return (fp);
1351}
1352
1353/*
1354 * mode mask for creation of files
1355 */
1356umask()
1357{
1358 register struct a {
1359 int mask;
715baff1 1360 } *uap = (struct a *)u.u_ap;
88a7a62a 1361
88a7a62a
SL
1362 u.u_r.r_val1 = u.u_cmask;
1363 u.u_cmask = uap->mask & 07777;
1364}