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