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