move vax header files to their own directory
[unix-history] / usr / src / sys / ufs / ffs / ufs_vnops.c
... / ...
CommitLineData
1/* ufs_vnops.c 4.38 82/10/10 */
2
3#include "../h/param.h"
4#include "../h/systm.h"
5#include "../h/dir.h"
6#include "../h/user.h"
7#include "../h/kernel.h"
8#include "../h/file.h"
9#include "../h/stat.h"
10#include "../h/inode.h"
11#include "../h/fs.h"
12#include "../h/buf.h"
13#include "../h/proc.h"
14#include "../h/quota.h"
15#include "../h/descrip.h"
16#include "../h/uio.h"
17#include "../h/socket.h"
18
19chdir()
20{
21
22 chdirec(&u.u_cdir);
23}
24
25chroot()
26{
27
28 if (suser())
29 chdirec(&u.u_rdir);
30}
31
32chdirec(ipp)
33 register struct inode **ipp;
34{
35 register struct inode *ip;
36 struct a {
37 char *fname;
38 };
39
40 ip = namei(uchar, 0, 1);
41 if(ip == NULL)
42 return;
43 if((ip->i_mode&IFMT) != IFDIR) {
44 u.u_error = ENOTDIR;
45 goto bad;
46 }
47 if(access(ip, IEXEC))
48 goto bad;
49 iunlock(ip);
50 if (*ipp)
51 irele(*ipp);
52 *ipp = ip;
53 return;
54
55bad:
56 iput(ip);
57}
58
59/*
60 * Open system call.
61 */
62open()
63{
64 register struct inode *ip;
65 register struct a {
66 char *fname;
67 int flags;
68 int mode;
69 } *uap;
70 int checkpermissions = 1;
71
72 uap = (struct a *)u.u_ap;
73 if (uap->flags&FCREATE) {
74 ip = namei(uchar, 1, 1);
75 if (ip == NULL) {
76 if (u.u_error)
77 return;
78 ip = maknode(uap->mode&07777&(~ISVTX));
79 checkpermissions = 0;
80 uap->flags &= ~FTRUNCATE;
81 }
82 } else
83 ip = namei(uchar, 0, 1);
84 if (ip == NULL)
85 return;
86 open1(ip, ++uap->flags, checkpermissions);
87}
88
89#ifndef NOCOMPAT
90/*
91 * Creat system call.
92 */
93ocreat()
94{
95 register struct inode *ip;
96 register struct a {
97 char *fname;
98 int fmode;
99 } *uap;
100
101 uap = (struct a *)u.u_ap;
102 ip = namei(uchar, 1, 1);
103 if (ip == NULL) {
104 if (u.u_error)
105 return;
106 ip = maknode(uap->fmode&07777&(~ISVTX));
107 if (ip == NULL)
108 return;
109 open1(ip, FWRITE, 0);
110 } else
111 open1(ip, FWRITE|FTRUNCATE, 0);
112}
113#endif
114
115/*
116 * Common code for open and creat.
117 * Check permissions (if we haven't done so already),
118 * allocate an open file structure, and call
119 * the device open routine, if any.
120 */
121open1(ip, mode, checkpermissions)
122 register struct inode *ip;
123 register mode;
124{
125 register struct file *fp;
126 int i, flags;
127
128 if (checkpermissions) {
129 if (mode&FREAD)
130 if (access(ip, IREAD))
131 goto bad;
132 if (mode&FWRITE) {
133 if (access(ip, IWRITE))
134 goto bad;
135 if ((ip->i_mode&IFMT) == IFDIR) {
136 u.u_error = EISDIR;
137 goto bad;
138 }
139 }
140 }
141
142 /*
143 * Check locking on inode. Release "inode lock"
144 * while doing so in case we block inside flocki.
145 */
146 flags = 0;
147 if (mode&(FRDLOCK|FWRLOCK)) {
148 iunlock(ip);
149 flags = flocki(ip, 0, mode);
150 ilock(ip);
151 if (u.u_error)
152 goto bad;
153 }
154 if (mode&FTRUNCATE)
155 itrunc(ip, 0);
156 iunlock(ip);
157 if ((fp = falloc()) == NULL)
158 goto out;
159 fp->f_flag = mode & FMODES;
160 fp->f_type = DTYPE_FILE;
161 i = u.u_r.r_val1;
162 fp->f_inode = ip;
163 openi(ip, mode);
164 if (u.u_error == 0) {
165 u.u_pofile[i] = flags;
166 return;
167 }
168 u.u_ofile[i] = NULL;
169 fp->f_count--;
170out:
171 irele(ip);
172 return;
173bad:
174 iput(ip);
175}
176
177/*
178 * Mknod system call
179 */
180mknod()
181{
182 register struct inode *ip;
183 register struct a {
184 char *fname;
185 int fmode;
186 int dev;
187 } *uap;
188
189 uap = (struct a *)u.u_ap;
190 if (suser()) {
191 ip = namei(uchar, 1, 0);
192 if (ip != NULL) {
193 u.u_error = EEXIST;
194 goto out;
195 }
196 }
197 if (u.u_error)
198 return;
199 ip = maknode(uap->fmode);
200 if (ip == NULL)
201 return;
202 if (uap->dev) {
203 /*
204 * Want to be able to use this to make badblock
205 * inodes, so don't truncate the dev number.
206 */
207 ip->i_rdev = uap->dev;
208 ip->i_flag |= IACC|IUPD|ICHG;
209 }
210
211out:
212 iput(ip);
213}
214
215/*
216 * link system call
217 */
218link()
219{
220 register struct inode *ip, *xp;
221 register struct a {
222 char *target;
223 char *linkname;
224 } *uap;
225
226 uap = (struct a *)u.u_ap;
227 ip = namei(uchar, 0, 1); /* well, this routine is doomed anyhow */
228 if (ip == NULL)
229 return;
230 if ((ip->i_mode&IFMT)==IFDIR && !suser()) {
231 iput(ip);
232 return;
233 }
234 ip->i_nlink++;
235 ip->i_flag |= ICHG;
236 iupdat(ip, &time.tv_sec, &time.tv_sec, 1);
237 iunlock(ip);
238 u.u_dirp = (caddr_t)uap->linkname;
239 xp = namei(uchar, 1, 0);
240 if (xp != NULL) {
241 u.u_error = EEXIST;
242 iput(xp);
243 goto out;
244 }
245 if (u.u_error)
246 goto out;
247 if (u.u_pdir->i_dev != ip->i_dev) {
248 iput(u.u_pdir);
249 u.u_error = EXDEV;
250 goto out;
251 }
252 direnter(ip);
253out:
254 if (u.u_error) {
255 ip->i_nlink--;
256 ip->i_flag |= ICHG;
257 }
258 irele(ip);
259}
260
261/*
262 * symlink -- make a symbolic link
263 */
264symlink()
265{
266 register struct a {
267 char *target;
268 char *linkname;
269 } *uap;
270 register struct inode *ip;
271 register char *tp;
272 register c, nc;
273
274 uap = (struct a *)u.u_ap;
275 tp = uap->target;
276 nc = 0;
277 while (c = fubyte(tp)) {
278 if (c < 0) {
279 u.u_error = EFAULT;
280 return;
281 }
282 tp++;
283 nc++;
284 }
285 u.u_dirp = uap->linkname;
286 ip = namei(uchar, 1, 0);
287 if (ip) {
288 iput(ip);
289 u.u_error = EEXIST;
290 return;
291 }
292 if (u.u_error)
293 return;
294 ip = maknode(IFLNK | 0777);
295 if (ip == NULL)
296 return;
297 u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0);
298 iput(ip);
299}
300
301/*
302 * Unlink system call.
303 * Hard to avoid races here, especially
304 * in unlinking directories.
305 */
306unlink()
307{
308 register struct inode *ip, *pp;
309 struct a {
310 char *fname;
311 };
312 int unlinkingdot = 0;
313
314 pp = namei(uchar, 2, 0);
315 if (pp == NULL)
316 return;
317
318 /*
319 * Check for unlink(".")
320 * to avoid hanging on the iget
321 */
322 if (pp->i_number == u.u_dent.d_ino) {
323 ip = pp;
324 ip->i_count++;
325 unlinkingdot++;
326 } else
327 ip = iget(pp->i_dev, pp->i_fs, u.u_dent.d_ino);
328 if(ip == NULL)
329 goto out1;
330 if((ip->i_mode&IFMT)==IFDIR && !suser())
331 goto out;
332 /*
333 * Don't unlink a mounted file.
334 */
335 if (ip->i_dev != pp->i_dev) {
336 u.u_error = EBUSY;
337 goto out;
338 }
339 if (ip->i_flag&ITEXT)
340 xrele(ip); /* try once to free text */
341 if (dirremove()) {
342 ip->i_nlink--;
343 ip->i_flag |= ICHG;
344 }
345out:
346 if (unlinkingdot)
347 irele(ip);
348 else
349 iput(ip);
350out1:
351 iput(pp);
352}
353
354/*
355 * Seek system call
356 */
357lseek()
358{
359 register struct file *fp;
360 register struct a {
361 int fd;
362 off_t off;
363 int sbase;
364 } *uap;
365
366 uap = (struct a *)u.u_ap;
367 fp = getf(uap->fd);
368 if (fp == NULL)
369 return;
370 if (fp->f_type == DTYPE_SOCKET) {
371 u.u_error = ESPIPE;
372 return;
373 }
374 if (uap->sbase == FSEEK_RELATIVE)
375 uap->off += fp->f_offset;
376 else if (uap->sbase == FSEEK_EOF)
377 uap->off += fp->f_inode->i_size;
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;
399 ip = namei(uchar, 0, 1);
400 if (ip != NULL) {
401 if (uap->fmode&FACCESS_READ && access(ip, IREAD))
402 goto done;
403 if (uap->fmode&FACCESS_WRITE && access(ip, IWRITE))
404 goto done;
405 if (uap->fmode&FACCESS_EXECUTE && access(ip, IEXEC))
406 goto done;
407done:
408 iput(ip);
409 }
410 u.u_uid = svuid;
411 u.u_gid = svgid;
412}
413
414/*
415 * the fstat system call.
416 */
417fstat()
418{
419 register struct file *fp;
420 register struct a {
421 int fd;
422 struct stat *sb;
423 } *uap;
424
425 uap = (struct a *)u.u_ap;
426 fp = getf(uap->fd);
427 if (fp == NULL)
428 return;
429 if (fp->f_type == DTYPE_SOCKET)
430 u.u_error = sostat(fp->f_socket, uap->sb);
431 else
432 stat1(fp->f_inode, uap->sb);
433}
434
435/*
436 * Stat system call. This version follows links.
437 */
438stat()
439{
440 register struct inode *ip;
441 register struct a {
442 char *fname;
443 struct stat *sb;
444 } *uap;
445
446 uap = (struct a *)u.u_ap;
447 ip = namei(uchar, 0, 1);
448 if (ip == NULL)
449 return;
450 stat1(ip, uap->sb);
451 iput(ip);
452}
453
454/*
455 * Lstat system call. This version does not follow links.
456 */
457lstat()
458{
459 register struct inode *ip;
460 register struct a {
461 char *fname;
462 struct stat *sb;
463 } *uap;
464
465 uap = (struct a *)u.u_ap;
466 ip = namei(uchar, 0, 0);
467 if (ip == NULL)
468 return;
469 stat1(ip, uap->sb);
470 iput(ip);
471}
472
473/*
474 * The basic routine for fstat and stat:
475 * get the inode and pass appropriate parts back.
476 */
477stat1(ip, ub)
478 register struct inode *ip;
479 struct stat *ub;
480{
481 struct stat ds;
482
483 IUPDAT(ip, &time.tv_sec, &time.tv_sec, 0);
484 /*
485 * Copy from inode table
486 */
487 ds.st_dev = ip->i_dev;
488 ds.st_ino = ip->i_number;
489 ds.st_mode = ip->i_mode;
490 ds.st_nlink = ip->i_nlink;
491 ds.st_uid = ip->i_uid;
492 ds.st_gid = ip->i_gid;
493 ds.st_rdev = (dev_t)ip->i_rdev;
494 ds.st_size = ip->i_size;
495 ds.st_atime = ip->i_atime;
496 ds.st_mtime = ip->i_mtime;
497 ds.st_ctime = ip->i_ctime;
498 /* this doesn't belong here */
499 if ((ip->i_mode&IFMT) == IFBLK)
500 ds.st_blksize = BLKDEV_IOSIZE;
501 else if ((ip->i_mode&IFMT) == IFCHR)
502 ds.st_blksize = MAXBSIZE;
503 else
504 ds.st_blksize = ip->i_fs->fs_bsize;
505 if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
506 u.u_error = EFAULT;
507}
508
509/*
510 * Return target name of a symbolic link
511 */
512readlink()
513{
514 register struct inode *ip;
515 register struct a {
516 char *name;
517 char *buf;
518 int count;
519 } *uap = (struct a *)u.u_ap;
520 int resid;
521
522 ip = namei(uchar, 0, 0);
523 if (ip == NULL)
524 return;
525 if ((ip->i_mode&IFMT) != IFLNK) {
526 u.u_error = ENXIO;
527 goto out;
528 }
529 u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid);
530out:
531 iput(ip);
532 u.u_r.r_val1 = uap->count - resid;
533}
534
535chmod()
536{
537 struct inode *ip;
538 struct a {
539 char *fname;
540 int fmode;
541 } *uap;
542
543 uap = (struct a *)u.u_ap;
544 if ((ip = owner(1)) == NULL)
545 return;
546 chmod1(ip, uap->fmode);
547}
548
549fchmod()
550{
551 struct a {
552 int fd;
553 int fmode;
554 } *uap;
555 register struct inode *ip;
556 register struct file *fp;
557
558 uap = (struct a *)u.u_ap;
559 fp = getf(uap->fd);
560 if (fp == NULL)
561 return;
562 if (fp->f_type == DTYPE_SOCKET) {
563 u.u_error = EINVAL;
564 return;
565 }
566 ip = fp->f_inode;
567 ilock(ip);
568 if (u.u_uid != ip->i_uid && !suser()) {
569 iunlock(ip);
570 return;
571 }
572 chmod1(ip, uap->fmode);
573}
574
575chmod1(ip, mode)
576 register struct inode *ip;
577 register int mode;
578{
579 register int *gp;
580
581 ip->i_mode &= ~07777;
582 if (u.u_uid) {
583 mode &= ~ISVTX;
584 for (gp = u.u_groups; gp < &u.u_groups[NGROUPS]; gp++)
585 if (*gp == ip->i_gid)
586 goto ok;
587 mode &= ~ISGID;
588ok:
589 ;
590#ifdef MUSH
591 if (u.u_quota->q_syflags & QF_UMASK && u.u_uid != 0 &&
592 (ip->i_mode & IFMT) != IFCHR)
593 mode &= ~u.u_cmask;
594#endif
595 }
596 ip->i_mode |= mode&07777;
597 ip->i_flag |= ICHG;
598 if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
599 xrele(ip);
600 iput(ip);
601}
602
603chown()
604{
605 struct inode *ip;
606 struct a {
607 char *fname;
608 int uid;
609 int gid;
610 } *uap;
611
612 uap = (struct a *)u.u_ap;
613 if (!suser() || (ip = owner(0)) == NULL)
614 return;
615 chown1(ip, uap->uid, uap->gid);
616}
617
618fchown()
619{
620 struct a {
621 int fd;
622 int uid;
623 int gid;
624 } *uap;
625 register struct inode *ip;
626 register struct file *fp;
627
628 uap = (struct a *)u.u_ap;
629 fp = getf(uap->fd);
630 if (fp == NULL)
631 return;
632 if (fp->f_type == DTYPE_SOCKET) {
633 u.u_error = EINVAL;
634 return;
635 }
636 ip = fp->f_inode;
637 ilock(ip);
638 if (!suser()) {
639 iunlock(ip);
640 return;
641 }
642 chown1(ip, uap->uid, uap->gid);
643}
644
645/*
646 * Perform chown operation on inode ip;
647 * inode must be locked prior to call.
648 */
649chown1(ip, uid, gid)
650 register struct inode *ip;
651 int uid, gid;
652{
653#ifdef QUOTA
654 register long change;
655
656 /*
657 * This doesn't allow for holes in files (which hopefully don't
658 * happen often in files that we chown), and is not accurate anyway
659 * (eg: it totally ignores 3 level indir blk files - but hopefully
660 * noone who can make a file that big will have a quota)
661 */
662 if (ip->i_uid == uid)
663 change = 0;
664 else {
665 register struct fs *fs = ip->i_fs;
666
667 if (ip->i_size > (change = NDADDR * fs->fs_bsize)) {
668 register off_t size;
669
670 size = blkroundup(fs, ip->i_size) - change;
671 change += size;
672 change += fs->fs_bsize;
673 /* this assumes NIADDR <= 2 */
674 if (size > NINDIR(fs) * fs->fs_bsize)
675 change += fs->fs_bsize;
676 } else
677 change = fragroundup(fs, ip->i_size);
678 change /= DEV_BSIZE;
679 }
680 chkdq(ip, -change, 1);
681 chkiq(ip->i_dev, ip, ip->i_uid, 1);
682 dqrele(ip->i_dquot);
683#endif
684 /*
685 * keep uid/gid's in sane range -- no err,
686 * so chown(file, uid, -1) will do something useful
687 */
688 if (uid >= 0 && uid <= 32767) /* should have a constant */
689 ip->i_uid = uid;
690 if (gid >= 0 && gid <= 32767) /* same here */
691 ip->i_gid = gid;
692 ip->i_flag |= ICHG;
693 if (u.u_ruid != 0)
694 ip->i_mode &= ~(ISUID|ISGID);
695#ifdef QUOTA
696 ip->i_dquot = inoquota(ip);
697 chkdq(ip, change, 1);
698 chkiq(ip->i_dev, NULL, uid, 1);
699#endif
700 iput(ip);
701}
702
703/*
704 * Set IUPD and IACC times on file.
705 * Can't set ICHG.
706 */
707outime()
708{
709 register struct a {
710 char *fname;
711 time_t *tptr;
712 } *uap;
713 register struct inode *ip;
714 time_t tv[2];
715
716 uap = (struct a *)u.u_ap;
717 if ((ip = owner(1)) == NULL)
718 return;
719 if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) {
720 u.u_error = EFAULT;
721 } else {
722 ip->i_flag |= IACC|IUPD|ICHG;
723 iupdat(ip, &tv[0], &tv[1], 0);
724 }
725 iput(ip);
726}
727
728sync()
729{
730
731 update(0);
732}
733
734flock()
735{
736 struct a {
737 int fd;
738 int how;
739 } *uap;
740 register struct file *fp;
741 register int cmd, flags;
742
743 uap = (struct a *)u.u_ap;
744 fp = getf(uap->fd);
745 if (fp == NULL)
746 return;
747 if (fp->f_type == DTYPE_SOCKET) { /* XXX */
748 u.u_error = EINVAL;
749 return;
750 }
751 cmd = uap->how;
752 flags = u.u_pofile[uap->fd] & (RDLOCK|WRLOCK);
753 if (cmd&FUNLOCK) {
754 if (flags == 0) {
755 u.u_error = EINVAL;
756 return;
757 }
758 funlocki(fp->f_inode, flags);
759 u.u_pofile[uap->fd] &= ~(RDLOCK|WRLOCK);
760 return;
761 }
762 /*
763 * No reason to write lock a file we've already
764 * write locked, similarly with a read lock.
765 */
766 if ((flags&WRLOCK) && (cmd&FWRLOCK) ||
767 (flags&RDLOCK) && (cmd&FRDLOCK))
768 return;
769 u.u_pofile[uap->fd] = flocki(fp->f_inode, u.u_pofile[uap->fd], cmd);
770}
771
772truncate()
773{
774 struct a {
775 char *fname;
776 int length;
777 } *uap = (struct a *)u.u_ap;
778 struct inode *ip;
779
780 ip = namei(uchar, 0, 1);
781 if (ip == NULL)
782 return;
783 if (access(ip, IWRITE))
784 goto bad;
785 if ((ip->i_mode&IFMT) == IFDIR) {
786 u.u_error = EISDIR;
787 goto bad;
788 }
789 itrunc(ip, uap->length);
790 return;
791bad:
792 iput(ip);
793}
794
795ftruncate()
796{
797 struct a {
798 int fd;
799 int length;
800 } *uap = (struct a *)u.u_ap;
801 struct inode *ip;
802 struct file *fp;
803
804 fp = getf(uap->fd);
805 if (fp == NULL)
806 return;
807 if (fp->f_type == DTYPE_SOCKET) {
808 u.u_error = EINVAL;
809 return;
810 }
811 if ((fp->f_flag&FWRITE) == 0) {
812 u.u_error = EINVAL;
813 return;
814 }
815 ip = fp->f_inode;
816 ilock(ip);
817 itrunc(ip, uap->length);
818}
819
820rename()
821{
822#ifdef notdef
823 struct a {
824 char *from;
825 char *to;
826 } *uap;
827#endif
828
829}
830
831/*
832 * Make a new file.
833 */
834struct inode *
835maknode(mode)
836 int mode;
837{
838 register struct inode *ip;
839 ino_t ipref;
840
841 if ((mode & IFMT) == IFDIR)
842 ipref = dirpref(u.u_pdir->i_fs);
843 else
844 ipref = u.u_pdir->i_number;
845 ip = ialloc(u.u_pdir, ipref, mode);
846 if (ip == NULL) {
847 iput(u.u_pdir);
848 return (NULL);
849 }
850#ifdef QUOTA
851 if (ip->i_dquot != NODQUOT)
852 panic("maknode: dquot");
853#endif
854 ip->i_flag |= IACC|IUPD|ICHG;
855 if ((mode & IFMT) == 0)
856 mode |= IFREG;
857 ip->i_mode = mode & ~u.u_cmask;
858 ip->i_nlink = 1;
859 ip->i_uid = u.u_uid;
860 ip->i_gid = u.u_pdir->i_gid;
861#ifdef QUOTA
862 ip->i_dquot = inoquota(ip);
863#endif
864
865 /*
866 * Make sure inode goes to disk before directory entry.
867 */
868 iupdat(ip, &time.tv_sec, &time.tv_sec, 1);
869 direnter(ip);
870 if (u.u_error) {
871 /*
872 * write error occurred trying to update directory
873 * so must deallocate the inode
874 */
875 ip->i_nlink = 0;
876 ip->i_flag |= ICHG;
877 iput(ip);
878 return (NULL);
879 }
880 return (ip);
881}