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