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