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