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