add utimes call; protection fixes galore
[unix-history] / usr / src / sys / ufs / ffs / ffs_vnops.c
CommitLineData
bb1b75f4 1/* ffs_vnops.c 4.54 83/03/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"
4147b3f6 15#include "../h/descrip.h"
31949305
BJ
16#include "../h/uio.h"
17#include "../h/socket.h"
b32450f4 18#include "../h/socketvar.h"
4f083fd7 19#include "../h/nami.h"
3e78e260 20
4f083fd7
SL
21/*
22 * Change current working directory (``.'').
23 */
3e78e260
BJ
24chdir()
25{
26
27 chdirec(&u.u_cdir);
28}
29
4f083fd7
SL
30/*
31 * Change notion of root (``/'') directory.
32 */
3e78e260
BJ
33chroot()
34{
35
36 if (suser())
37 chdirec(&u.u_rdir);
38}
39
4f083fd7
SL
40/*
41 * Common routine for chroot and chdir.
42 */
3e78e260 43chdirec(ipp)
528f664c 44 register struct inode **ipp;
3e78e260
BJ
45{
46 register struct inode *ip;
47 struct a {
48 char *fname;
49 };
50
4f083fd7
SL
51 ip = namei(uchar, LOOKUP, 1);
52 if (ip == NULL)
3e78e260 53 return;
4f083fd7 54 if ((ip->i_mode&IFMT) != IFDIR) {
3e78e260
BJ
55 u.u_error = ENOTDIR;
56 goto bad;
57 }
4f083fd7 58 if (access(ip, IEXEC))
3e78e260 59 goto bad;
ca91bded 60 iunlock(ip);
8eee8525
KM
61 if (*ipp)
62 irele(*ipp);
3e78e260
BJ
63 *ipp = ip;
64 return;
65
66bad:
67 iput(ip);
68}
69
70/*
71 * Open system call.
72 */
73open()
74{
75 register struct inode *ip;
76 register struct a {
77 char *fname;
528f664c
SL
78 int flags;
79 int mode;
3e78e260 80 } *uap;
4f083fd7 81 int checkpermissions = 1, flags;
3e78e260
BJ
82
83 uap = (struct a *)u.u_ap;
4f083fd7
SL
84 flags = uap->flags + 1;
85 if ((flags&FTRUNCATE) && (flags&FWRITE) == 0) {
86 u.u_error = EINVAL;
87 return;
88 }
89 if (flags&FCREATE) {
90 ip = namei(uchar, CREATE, 1);
528f664c
SL
91 if (ip == NULL) {
92 if (u.u_error)
93 return;
94 ip = maknode(uap->mode&07777&(~ISVTX));
95 checkpermissions = 0;
4f083fd7 96 flags &= ~FTRUNCATE;
528f664c
SL
97 }
98 } else
4f083fd7 99 ip = namei(uchar, LOOKUP, 1);
3e78e260
BJ
100 if (ip == NULL)
101 return;
4f083fd7 102 open1(ip, flags, checkpermissions);
3e78e260
BJ
103}
104
528f664c 105#ifndef NOCOMPAT
3e78e260
BJ
106/*
107 * Creat system call.
108 */
4147b3f6 109ocreat()
3e78e260
BJ
110{
111 register struct inode *ip;
112 register struct a {
113 char *fname;
114 int fmode;
115 } *uap;
116
117 uap = (struct a *)u.u_ap;
4f083fd7 118 ip = namei(uchar, CREATE, 1);
3e78e260
BJ
119 if (ip == NULL) {
120 if (u.u_error)
121 return;
122 ip = maknode(uap->fmode&07777&(~ISVTX));
528f664c 123 if (ip == NULL)
3e78e260 124 return;
528f664c 125 open1(ip, FWRITE, 0);
3e78e260 126 } else
4f083fd7 127 open1(ip, FWRITE|FTRUNCATE, 1);
3e78e260 128}
528f664c 129#endif
3e78e260
BJ
130
131/*
132 * Common code for open and creat.
528f664c
SL
133 * Check permissions (if we haven't done so already),
134 * allocate an open file structure, and call
135 * the device open routine, if any.
3e78e260 136 */
528f664c 137open1(ip, mode, checkpermissions)
3e78e260
BJ
138 register struct inode *ip;
139 register mode;
140{
141 register struct file *fp;
528f664c 142 int i, flags;
3e78e260 143
528f664c 144 if (checkpermissions) {
3e78e260 145 if (mode&FREAD)
528f664c
SL
146 if (access(ip, IREAD))
147 goto bad;
3e78e260 148 if (mode&FWRITE) {
528f664c
SL
149 if (access(ip, IWRITE))
150 goto bad;
151 if ((ip->i_mode&IFMT) == IFDIR) {
3e78e260 152 u.u_error = EISDIR;
528f664c
SL
153 goto bad;
154 }
3e78e260
BJ
155 }
156 }
528f664c
SL
157
158 /*
159 * Check locking on inode. Release "inode lock"
160 * while doing so in case we block inside flocki.
161 */
162 flags = 0;
4f083fd7 163 if (mode&(FSHLOCK|FEXLOCK)) {
528f664c
SL
164 iunlock(ip);
165 flags = flocki(ip, 0, mode);
166 ilock(ip);
167 if (u.u_error)
168 goto bad;
8eee8525 169 }
528f664c 170 if (mode&FTRUNCATE)
4f083fd7 171 itrunc(ip, (u_long)0);
ca91bded 172 iunlock(ip);
3e78e260
BJ
173 if ((fp = falloc()) == NULL)
174 goto out;
528f664c 175 fp->f_flag = mode & FMODES;
4147b3f6 176 fp->f_type = DTYPE_FILE;
3e78e260
BJ
177 i = u.u_r.r_val1;
178 fp->f_inode = ip;
f45396c3 179 u.u_error = openi(ip, mode);
528f664c
SL
180 if (u.u_error == 0) {
181 u.u_pofile[i] = flags;
3e78e260 182 return;
528f664c 183 }
3e78e260
BJ
184 u.u_ofile[i] = NULL;
185 fp->f_count--;
186out:
8eee8525 187 irele(ip);
528f664c
SL
188 return;
189bad:
190 iput(ip);
3e78e260
BJ
191}
192
193/*
194 * Mknod system call
195 */
196mknod()
197{
198 register struct inode *ip;
199 register struct a {
200 char *fname;
201 int fmode;
202 int dev;
203 } *uap;
204
205 uap = (struct a *)u.u_ap;
206 if (suser()) {
4f083fd7 207 ip = namei(uchar, CREATE, 0);
3e78e260
BJ
208 if (ip != NULL) {
209 u.u_error = EEXIST;
210 goto out;
211 }
212 }
213 if (u.u_error)
214 return;
215 ip = maknode(uap->fmode);
216 if (ip == NULL)
217 return;
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 */
6459ebe0 223 ip->i_rdev = uap->dev;
3e78e260
BJ
224 ip->i_flag |= IACC|IUPD|ICHG;
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;
528f664c 370 fp = getf(uap->fd);
3e78e260
BJ
371 if (fp == NULL)
372 return;
4147b3f6 373 if (fp->f_type == DTYPE_SOCKET) {
3e78e260
BJ
374 u.u_error = ESPIPE;
375 return;
376 }
528f664c 377 if (uap->sbase == FSEEK_RELATIVE)
3e78e260 378 uap->off += fp->f_offset;
528f664c 379 else if (uap->sbase == FSEEK_EOF)
3e78e260
BJ
380 uap->off += fp->f_inode->i_size;
381 fp->f_offset = uap->off;
382 u.u_r.r_off = uap->off;
383}
384
385/*
386 * Access system call
387 */
388saccess()
389{
390 register svuid, svgid;
391 register struct inode *ip;
392 register struct a {
393 char *fname;
394 int fmode;
395 } *uap;
396
397 uap = (struct a *)u.u_ap;
398 svuid = u.u_uid;
399 svgid = u.u_gid;
400 u.u_uid = u.u_ruid;
401 u.u_gid = u.u_rgid;
4f083fd7 402 ip = namei(uchar, LOOKUP, 1);
3e78e260 403 if (ip != NULL) {
4f083fd7 404 if ((uap->fmode&FACCESS_READ) && access(ip, IREAD))
528f664c 405 goto done;
4f083fd7 406 if ((uap->fmode&FACCESS_WRITE) && access(ip, IWRITE))
528f664c 407 goto done;
4f083fd7 408 if ((uap->fmode&FACCESS_EXECUTE) && access(ip, IEXEC))
528f664c
SL
409 goto done;
410done:
3e78e260
BJ
411 iput(ip);
412 }
413 u.u_uid = svuid;
414 u.u_gid = svgid;
415}
d67a03eb
BJ
416
417/*
418 * the fstat system call.
419 */
420fstat()
421{
422 register struct file *fp;
423 register struct a {
528f664c 424 int fd;
d67a03eb
BJ
425 struct stat *sb;
426 } *uap;
427
428 uap = (struct a *)u.u_ap;
528f664c 429 fp = getf(uap->fd);
e92a04af 430 if (fp == NULL)
d67a03eb 431 return;
4147b3f6 432 if (fp->f_type == DTYPE_SOCKET)
cc15ab5d 433 u.u_error = sostat(fp->f_socket, uap->sb);
e92a04af
BJ
434 else
435 stat1(fp->f_inode, uap->sb);
d67a03eb
BJ
436}
437
438/*
6459ebe0 439 * Stat system call. This version follows links.
d67a03eb
BJ
440 */
441stat()
442{
443 register struct inode *ip;
444 register struct a {
445 char *fname;
446 struct stat *sb;
447 } *uap;
448
449 uap = (struct a *)u.u_ap;
4f083fd7 450 ip = namei(uchar, LOOKUP, 1);
e92a04af 451 if (ip == NULL)
d67a03eb 452 return;
a3aa7f92 453 stat1(ip, uap->sb);
d67a03eb
BJ
454 iput(ip);
455}
456
5485e062 457/*
6459ebe0 458 * Lstat system call. This version does not follow links.
5485e062
BJ
459 */
460lstat()
461{
462 register struct inode *ip;
463 register struct a {
464 char *fname;
465 struct stat *sb;
466 } *uap;
467
468 uap = (struct a *)u.u_ap;
4f083fd7 469 ip = namei(uchar, LOOKUP, 0);
5485e062
BJ
470 if (ip == NULL)
471 return;
019b08c9 472 stat1(ip, uap->sb);
5485e062
BJ
473 iput(ip);
474}
475
d67a03eb
BJ
476/*
477 * The basic routine for fstat and stat:
478 * get the inode and pass appropriate parts back.
479 */
a3aa7f92 480stat1(ip, ub)
e92a04af
BJ
481 register struct inode *ip;
482 struct stat *ub;
d67a03eb 483{
d67a03eb
BJ
484 struct stat ds;
485
3fd23f5c 486 IUPDAT(ip, &time, &time, 0);
d67a03eb 487 /*
09c42945 488 * Copy from inode table
d67a03eb
BJ
489 */
490 ds.st_dev = ip->i_dev;
491 ds.st_ino = ip->i_number;
492 ds.st_mode = ip->i_mode;
493 ds.st_nlink = ip->i_nlink;
494 ds.st_uid = ip->i_uid;
495 ds.st_gid = ip->i_gid;
6459ebe0 496 ds.st_rdev = (dev_t)ip->i_rdev;
a3aa7f92 497 ds.st_size = ip->i_size;
6459ebe0 498 ds.st_atime = ip->i_atime;
f9559304 499 ds.st_spare1 = 0;
6459ebe0 500 ds.st_mtime = ip->i_mtime;
f9559304 501 ds.st_spare2 = 0;
6459ebe0 502 ds.st_ctime = ip->i_ctime;
f9559304 503 ds.st_spare3 = 0;
528f664c
SL
504 /* this doesn't belong here */
505 if ((ip->i_mode&IFMT) == IFBLK)
506 ds.st_blksize = BLKDEV_IOSIZE;
507 else if ((ip->i_mode&IFMT) == IFCHR)
508 ds.st_blksize = MAXBSIZE;
509 else
510 ds.st_blksize = ip->i_fs->fs_bsize;
f9559304 511 ds.st_spare4[0] = ds.st_spare4[1] = ds.st_spare4[2] = 0;
127f7d76 512 u.u_error = copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds));
d67a03eb
BJ
513}
514
515/*
5485e062
BJ
516 * Return target name of a symbolic link
517 */
518readlink()
519{
520 register struct inode *ip;
521 register struct a {
522 char *name;
523 char *buf;
524 int count;
31949305
BJ
525 } *uap = (struct a *)u.u_ap;
526 int resid;
5485e062 527
4f083fd7 528 ip = namei(uchar, LOOKUP, 0);
5485e062
BJ
529 if (ip == NULL)
530 return;
531 if ((ip->i_mode&IFMT) != IFLNK) {
532 u.u_error = ENXIO;
533 goto out;
534 }
31949305 535 u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid);
5485e062
BJ
536out:
537 iput(ip);
31949305 538 u.u_r.r_val1 = uap->count - resid;
5485e062
BJ
539}
540
4f083fd7
SL
541/*
542 * Change mode of a file given path name.
543 */
3e78e260 544chmod()
5485e062 545{
528f664c
SL
546 struct inode *ip;
547 struct a {
3e78e260
BJ
548 char *fname;
549 int fmode;
5485e062 550 } *uap;
5485e062
BJ
551
552 uap = (struct a *)u.u_ap;
3e78e260 553 if ((ip = owner(1)) == NULL)
5485e062 554 return;
528f664c 555 chmod1(ip, uap->fmode);
4f083fd7 556 iput(ip);
528f664c 557}
f94ceb3b 558
4f083fd7
SL
559/*
560 * Change mode of a file given a file descriptor.
561 */
528f664c
SL
562fchmod()
563{
564 struct a {
565 int fd;
566 int fmode;
567 } *uap;
568 register struct inode *ip;
569 register struct file *fp;
570
571 uap = (struct a *)u.u_ap;
572 fp = getf(uap->fd);
573 if (fp == NULL)
574 return;
575 if (fp->f_type == DTYPE_SOCKET) {
576 u.u_error = EINVAL;
577 return;
f94ceb3b 578 }
528f664c 579 ip = fp->f_inode;
4f083fd7 580 if (u.u_uid != ip->i_uid && !suser())
528f664c 581 return;
4f083fd7 582 ilock(ip);
528f664c 583 chmod1(ip, uap->fmode);
4f083fd7 584 iunlock(ip);
528f664c
SL
585}
586
4f083fd7
SL
587/*
588 * Change the mode on a file.
589 * Inode must be locked before calling.
590 */
528f664c
SL
591chmod1(ip, mode)
592 register struct inode *ip;
593 register int mode;
594{
197da11b
BJ
595 register int *gp;
596
3e78e260 597 ip->i_mode &= ~07777;
f94ceb3b 598 if (u.u_uid) {
528f664c 599 mode &= ~ISVTX;
bb1b75f4
SL
600 if (!groupmember(ip->i_gid))
601 mode &= ~ISGID;
528f664c 602#ifdef MUSH
bb1b75f4 603 if (u.u_quota->q_syflags & QF_UMASK &&
0a77f278 604 (ip->i_mode & IFMT) != IFCHR)
528f664c 605 mode &= ~u.u_cmask;
0a77f278 606#endif
f94ceb3b 607 }
528f664c 608 ip->i_mode |= mode&07777;
3e78e260
BJ
609 ip->i_flag |= ICHG;
610 if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
611 xrele(ip);
5485e062
BJ
612}
613
4f083fd7
SL
614/*
615 * Set ownership given a path name.
616 */
3e78e260 617chown()
d67a03eb 618{
528f664c
SL
619 struct inode *ip;
620 struct a {
3e78e260
BJ
621 char *fname;
622 int uid;
623 int gid;
d67a03eb 624 } *uap;
d67a03eb
BJ
625
626 uap = (struct a *)u.u_ap;
bb1b75f4 627 if ((ip = owner(0)) == NULL)
d67a03eb 628 return;
bb1b75f4 629 u.u_error = chown1(ip, uap->uid, uap->gid);
4f083fd7 630 iput(ip);
528f664c 631}
f94ceb3b 632
4f083fd7
SL
633/*
634 * Set ownership given a file descriptor.
635 */
528f664c
SL
636fchown()
637{
638 struct a {
639 int fd;
640 int uid;
641 int gid;
642 } *uap;
643 register struct inode *ip;
644 register struct file *fp;
645
646 uap = (struct a *)u.u_ap;
647 fp = getf(uap->fd);
648 if (fp == NULL)
649 return;
650 if (fp->f_type == DTYPE_SOCKET) {
651 u.u_error = EINVAL;
652 return;
f94ceb3b 653 }
528f664c 654 ip = fp->f_inode;
bb1b75f4 655 if (ip->i_uid != u.u_uid && !suser())
528f664c 656 return;
4f083fd7 657 ilock(ip);
bb1b75f4 658 u.u_error = chown1(ip, uap->uid, uap->gid);
4f083fd7 659 iunlock(ip);
528f664c
SL
660}
661
662/*
663 * Perform chown operation on inode ip;
664 * inode must be locked prior to call.
665 */
666chown1(ip, uid, gid)
667 register struct inode *ip;
668 int uid, gid;
669{
670#ifdef QUOTA
671 register long change;
bb1b75f4 672#endif
528f664c 673
bb1b75f4
SL
674 if (uid == -1)
675 uid = ip->i_uid;
676 if (gid == -1)
677 gid = ip->i_gid;
678 if (u.u_uid && ip->i_gid != gid && !groupmember(gid))
679 return (EPERM);
680#ifdef QUOTA
0a77f278
RE
681 /*
682 * This doesn't allow for holes in files (which hopefully don't
683 * happen often in files that we chown), and is not accurate anyway
684 * (eg: it totally ignores 3 level indir blk files - but hopefully
685 * noone who can make a file that big will have a quota)
686 */
528f664c 687 if (ip->i_uid == uid)
0a77f278
RE
688 change = 0;
689 else {
690 register struct fs *fs = ip->i_fs;
691
692 if (ip->i_size > (change = NDADDR * fs->fs_bsize)) {
693 register off_t size;
694
695 size = blkroundup(fs, ip->i_size) - change;
696 change += size;
697 change += fs->fs_bsize;
528f664c 698 /* this assumes NIADDR <= 2 */
0a77f278
RE
699 if (size > NINDIR(fs) * fs->fs_bsize)
700 change += fs->fs_bsize;
701 } else
702 change = fragroundup(fs, ip->i_size);
703 change /= DEV_BSIZE;
704 }
4f083fd7
SL
705 (void)chkdq(ip, -change, 1);
706 (void)chkiq(ip->i_dev, ip, ip->i_uid, 1);
0a77f278 707 dqrele(ip->i_dquot);
f94ceb3b 708#endif
bb1b75f4
SL
709 ip->i_uid = uid;
710 ip->i_gid = gid;
3e78e260
BJ
711 ip->i_flag |= ICHG;
712 if (u.u_ruid != 0)
713 ip->i_mode &= ~(ISUID|ISGID);
528f664c 714#ifdef QUOTA
0a77f278 715 ip->i_dquot = inoquota(ip);
4f083fd7
SL
716 (void)chkdq(ip, change, 1);
717 (void)chkiq(ip->i_dev, (struct inode *)NULL, uid, 1);
bb1b75f4 718 return (u.u_error);
0a77f278 719#endif
bb1b75f4 720 return (0);
d67a03eb
BJ
721}
722
bb1b75f4 723#ifndef NOCOMPAT
d67a03eb 724/*
3e78e260
BJ
725 * Set IUPD and IACC times on file.
726 * Can't set ICHG.
d67a03eb 727 */
68da6a91 728outime()
e92a04af 729{
d67a03eb 730 register struct a {
3e78e260
BJ
731 char *fname;
732 time_t *tptr;
bb1b75f4 733 } *uap = (struct a *)u.u_ap;
3e78e260
BJ
734 register struct inode *ip;
735 time_t tv[2];
b32450f4 736 struct timeval tv0, tv1;
d67a03eb 737
3e78e260 738 if ((ip = owner(1)) == NULL)
d67a03eb 739 return;
bb1b75f4 740 u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
127f7d76 741 if (u.u_error == 0) {
3e78e260 742 ip->i_flag |= IACC|IUPD|ICHG;
b32450f4
BJ
743 tv0.tv_sec = tv[0]; tv0.tv_usec = 0;
744 tv1.tv_sec = tv[1]; tv1.tv_usec = 0;
745 iupdat(ip, &tv0, &tv1, 0);
d67a03eb 746 }
d67a03eb
BJ
747 iput(ip);
748}
bb1b75f4
SL
749#endif
750
751utimes()
752{
753 register struct a {
754 char *fname;
755 struct timeval *tptr;
756 } *uap = (struct a *)u.u_ap;
757 register struct inode *ip;
758 struct timeval tv[2];
759
760 if ((ip = owner(1)) == NULL)
761 return;
762 u.u_error = copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof (tv));
763 if (u.u_error == 0) {
764 ip->i_flag |= IACC|IUPD|ICHG;
765 iupdat(ip, &tv[0], &tv[1], 0);
766 }
767 iput(ip);
768}
d67a03eb 769
4f083fd7
SL
770/*
771 * Flush any pending I/O.
772 */
3e78e260 773sync()
d67a03eb 774{
d67a03eb 775
3fd23f5c 776 update();
d67a03eb 777}
64d3a787 778
4f083fd7
SL
779/*
780 * Apply an advisory lock on a file descriptor.
781 */
528f664c
SL
782flock()
783{
784 struct a {
785 int fd;
786 int how;
787 } *uap;
788 register struct file *fp;
789 register int cmd, flags;
790
791 uap = (struct a *)u.u_ap;
792 fp = getf(uap->fd);
793 if (fp == NULL)
794 return;
795 if (fp->f_type == DTYPE_SOCKET) { /* XXX */
796 u.u_error = EINVAL;
797 return;
798 }
799 cmd = uap->how;
3650c37d 800 flags = u.u_pofile[uap->fd] & (UF_SHLOCK|UF_EXLOCK);
528f664c
SL
801 if (cmd&FUNLOCK) {
802 if (flags == 0) {
803 u.u_error = EINVAL;
804 return;
805 }
806 funlocki(fp->f_inode, flags);
3650c37d 807 u.u_pofile[uap->fd] &= ~(UF_SHLOCK|UF_EXLOCK);
528f664c
SL
808 return;
809 }
810 /*
811 * No reason to write lock a file we've already
812 * write locked, similarly with a read lock.
813 */
3650c37d
SL
814 if ((flags&UF_EXLOCK) && (cmd&FEXLOCK) ||
815 (flags&UF_SHLOCK) && (cmd&FSHLOCK))
528f664c
SL
816 return;
817 u.u_pofile[uap->fd] = flocki(fp->f_inode, u.u_pofile[uap->fd], cmd);
818}
819
4f083fd7
SL
820/*
821 * Truncate a file given its path name.
822 */
528f664c
SL
823truncate()
824{
825 struct a {
826 char *fname;
4f083fd7 827 u_long length;
31949305 828 } *uap = (struct a *)u.u_ap;
528f664c
SL
829 struct inode *ip;
830
4f083fd7 831 ip = namei(uchar, LOOKUP, 1);
528f664c
SL
832 if (ip == NULL)
833 return;
834 if (access(ip, IWRITE))
835 goto bad;
836 if ((ip->i_mode&IFMT) == IFDIR) {
837 u.u_error = EISDIR;
838 goto bad;
839 }
840 itrunc(ip, uap->length);
528f664c
SL
841bad:
842 iput(ip);
843}
844
4f083fd7
SL
845/*
846 * Truncate a file given a file descriptor.
847 */
528f664c
SL
848ftruncate()
849{
850 struct a {
851 int fd;
4f083fd7 852 u_long length;
31949305 853 } *uap = (struct a *)u.u_ap;
528f664c
SL
854 struct inode *ip;
855 struct file *fp;
856
857 fp = getf(uap->fd);
858 if (fp == NULL)
859 return;
860 if (fp->f_type == DTYPE_SOCKET) {
861 u.u_error = EINVAL;
862 return;
863 }
864 if ((fp->f_flag&FWRITE) == 0) {
865 u.u_error = EINVAL;
866 return;
867 }
868 ip = fp->f_inode;
869 ilock(ip);
870 itrunc(ip, uap->length);
4f083fd7
SL
871 iunlock(ip);
872}
873
874/*
875 * Synch an open file.
876 */
877fsync()
878{
879 struct a {
880 int fd;
881 } *uap = (struct a *)u.u_ap;
882 struct inode *ip;
883 struct file *fp;
884
885 fp = getf(uap->fd);
886 if (fp == NULL)
887 return;
888 if (fp->f_type == DTYPE_SOCKET) {
889 u.u_error = EINVAL;
890 return;
891 }
892 ip = fp->f_inode;
893 ilock(ip);
894 syncip(ip);
895 iunlock(ip);
528f664c
SL
896}
897
4f083fd7
SL
898/*
899 * Rename system call.
900 * rename("foo", "bar");
901 * is essentially
902 * unlink("bar");
903 * link("foo", "bar");
904 * unlink("foo");
905 * but ``atomically''. Can't do full commit without saving state in the
906 * inode on disk which isn't feasible at this time. Best we can do is
907 * always guarantee the target exists.
908 *
909 * Basic algorithm is:
910 *
911 * 1) Bump link count on source while we're linking it to the
912 * target. This also insure the inode won't be deleted out
913 * from underneath us while we work.
914 * 2) Link source to destination. If destination already exists,
915 * delete it first.
916 * 3) Unlink source reference to inode if still around.
917 * 4) If a directory was moved and the parent of the destination
918 * is different from the source, patch the ".." entry in the
919 * directory.
920 *
921 * Source and destination must either both be directories, or both
922 * not be directories. If target is a directory, it must be empty.
923 */
528f664c
SL
924rename()
925{
926 struct a {
927 char *from;
928 char *to;
929 } *uap;
4f083fd7
SL
930 register struct inode *ip, *xp, *dp;
931 int oldparent, parentdifferent, doingdirectory;
a5390dce 932 int error = 0;
4f083fd7
SL
933
934 uap = (struct a *)u.u_ap;
046f18d1 935 ip = namei(uchar, DELETE | LOCKPARENT, 0);
4f083fd7
SL
936 if (ip == NULL)
937 return;
938 dp = u.u_pdir;
939 oldparent = 0, doingdirectory = 0;
940 if ((ip->i_mode&IFMT) == IFDIR) {
941 register struct direct *d;
942
943 d = &u.u_dent;
944 /*
046f18d1 945 * Avoid ".", "..", and aliases of "." for obvious reasons.
4f083fd7 946 */
046f18d1
SL
947 if ((d->d_namlen == 1 && d->d_name[0] == '.') ||
948 (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) ||
949 (dp == ip)) {
950 iput(dp);
951 if (dp == ip)
952 irele(ip);
953 else
4f083fd7 954 iput(ip);
046f18d1
SL
955 u.u_error = EINVAL;
956 return;
4f083fd7
SL
957 }
958 oldparent = dp->i_number;
959 doingdirectory++;
960 }
046f18d1 961 iput(dp);
4f083fd7
SL
962
963 /*
964 * 1) Bump link count while we're moving stuff
965 * around. If we crash somewhere before
966 * completing our work, the link count
967 * may be wrong, but correctable.
968 */
969 ip->i_nlink++;
970 ip->i_flag |= ICHG;
971 iupdat(ip, &time, &time, 1);
972 iunlock(ip);
973
974 /*
975 * When the target exists, both the directory
976 * and target inodes are returned locked.
977 */
978 u.u_dirp = (caddr_t)uap->to;
979 xp = namei(uchar, CREATE | LOCKPARENT, 0);
a5390dce
SL
980 if (u.u_error) {
981 error = u.u_error;
4f083fd7 982 goto out;
a5390dce 983 }
4f083fd7 984 dp = u.u_pdir;
046f18d1
SL
985 /*
986 * If ".." must be changed (ie the directory gets a new
987 * parent) then the user must have write permission.
988 */
989 parentdifferent = oldparent != dp->i_number;
5463e92b 990 if (doingdirectory && parentdifferent && access(ip, IWRITE))
046f18d1 991 goto bad;
4f083fd7
SL
992 /*
993 * 2) If target doesn't exist, link the target
994 * to the source and unlink the source.
995 * Otherwise, rewrite the target directory
996 * entry to reference the source inode and
997 * expunge the original entry's existence.
998 */
4f083fd7
SL
999 if (xp == NULL) {
1000 if (dp->i_dev != ip->i_dev) {
a5390dce 1001 error = EXDEV;
4f083fd7
SL
1002 goto bad;
1003 }
e69c3c9c
SL
1004 /*
1005 * Disallow rename(foo, foo/bar).
1006 */
1007 if (dp->i_number == ip->i_number) {
1008 error = EEXIST;
1009 goto bad;
1010 }
4f083fd7
SL
1011 /*
1012 * Account for ".." in directory.
1013 * When source and destination have the
1014 * same parent we don't fool with the
1015 * link count -- this isn't required
1016 * because we do a similar check below.
1017 */
1018 if (doingdirectory && parentdifferent) {
1019 dp->i_nlink++;
1020 dp->i_flag |= ICHG;
1021 iupdat(dp, &time, &time, 1);
1022 }
f2a5ad78
SL
1023 error = direnter(ip);
1024 if (error)
4f083fd7
SL
1025 goto out;
1026 } else {
1027 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) {
a5390dce 1028 error = EXDEV;
4f083fd7
SL
1029 goto bad;
1030 }
e69c3c9c
SL
1031 /*
1032 * Short circuit rename(foo, foo).
1033 */
1034 if (xp->i_number == ip->i_number)
1035 goto bad;
4f083fd7 1036 /*
a5390dce
SL
1037 * Target must be empty if a directory
1038 * and have no links to it.
4f083fd7
SL
1039 * Also, insure source and target are
1040 * compatible (both directories, or both
1041 * not directories).
1042 */
1043 if ((xp->i_mode&IFMT) == IFDIR) {
a5390dce
SL
1044 if (!dirempty(xp) || xp->i_nlink > 2) {
1045 error = ENOTEMPTY;
4f083fd7
SL
1046 goto bad;
1047 }
1048 if (!doingdirectory) {
a5390dce 1049 error = ENOTDIR;
4f083fd7
SL
1050 goto bad;
1051 }
1052 } else if (doingdirectory) {
a5390dce 1053 error = EISDIR;
4f083fd7
SL
1054 goto bad;
1055 }
1056 dirrewrite(dp, ip);
a5390dce
SL
1057 if (u.u_error) {
1058 error = u.u_error;
4f083fd7 1059 goto bad1;
a5390dce 1060 }
4f083fd7 1061 /*
a5390dce
SL
1062 * Adjust the link count of the target to
1063 * reflect the dirrewrite above. If this is
1064 * a directory it is empty and there are
1065 * no links to it, so we can squash the inode and
1066 * any space associated with it. We disallowed
1067 * renaming over top of a directory with links to
1068 * it above, as we've no way to determine if
1069 * we've got a link or the directory itself, and
1070 * if we get a link, then ".." will be screwed up.
4f083fd7 1071 */
a5390dce 1072 xp->i_nlink--;
4f083fd7 1073 if (doingdirectory) {
a5390dce
SL
1074 if (--xp->i_nlink != 0)
1075 panic("rename: linked directory");
4f083fd7 1076 itrunc(xp, (u_long)0);
a5390dce 1077 }
4f083fd7
SL
1078 xp->i_flag |= ICHG;
1079 iput(xp);
31db12cb 1080 xp = NULL;
4f083fd7
SL
1081 }
1082
1083 /*
1084 * 3) Unlink the source.
1085 */
1086 u.u_dirp = uap->from;
1087 dp = namei(uchar, DELETE, 0);
1088 /*
1089 * Insure directory entry still exists and
1090 * has not changed since the start of all
1091 * this. If either has occured, forget about
1092 * about deleting the original entry and just
1093 * adjust the link count in the inode.
1094 */
1095 if (dp == NULL || u.u_dent.d_ino != ip->i_number) {
1096 ip->i_nlink--;
1097 ip->i_flag |= ICHG;
1098 } else {
1099 /*
1100 * If source is a directory, must adjust
1101 * link count of parent directory also.
1102 * If target didn't exist and source and
1103 * target have the same parent, then we
1104 * needn't touch the link count, it all
1105 * balances out in the end. Otherwise, we
1106 * must do so to reflect deletion of ".."
1107 * done above.
1108 */
1109 if (doingdirectory && (xp != NULL || parentdifferent)) {
1110 dp->i_nlink--;
1111 dp->i_flag |= ICHG;
1112 }
1113 if (dirremove()) {
1114 ip->i_nlink--;
1115 ip->i_flag |= ICHG;
1116 }
a5390dce
SL
1117 if (error == 0) /* conservative */
1118 error = u.u_error;
4f083fd7
SL
1119 }
1120 irele(ip);
1121 if (dp)
1122 iput(dp);
1123
1124 /*
1125 * 4) Renaming a directory with the parent
1126 * different requires ".." to be rewritten.
1127 * The window is still there for ".." to
1128 * be inconsistent, but this is unavoidable,
1129 * and a lot shorter than when it was done
1130 * in a user process.
1131 */
a5390dce 1132 if (doingdirectory && parentdifferent && error == 0) {
4f083fd7 1133 struct dirtemplate dirbuf;
528f664c 1134
4f083fd7
SL
1135 u.u_dirp = uap->to;
1136 ip = namei(uchar, LOOKUP | LOCKPARENT, 0);
1137 if (ip == NULL) {
1138 printf("rename: .. went away\n");
1139 return;
1140 }
1141 dp = u.u_pdir;
1142 if ((ip->i_mode&IFMT) != IFDIR) {
1143 printf("rename: .. not a directory\n");
1144 goto stuck;
1145 }
a5390dce 1146 error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf,
4f083fd7 1147 sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
a5390dce 1148 if (error == 0) {
4f083fd7
SL
1149 dirbuf.dotdot_ino = dp->i_number;
1150 (void) rdwri(UIO_WRITE, ip, (caddr_t)&dirbuf,
1151 sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
1152 }
1153stuck:
1154 irele(dp);
1155 iput(ip);
1156 }
a5390dce
SL
1157 goto done;
1158
4f083fd7 1159bad:
31db12cb 1160 iput(dp);
4f083fd7
SL
1161bad1:
1162 if (xp)
31db12cb 1163 iput(xp);
4f083fd7
SL
1164out:
1165 ip->i_nlink--;
1166 ip->i_flag |= ICHG;
1167 irele(ip);
a5390dce
SL
1168done:
1169 if (error)
1170 u.u_error = error;
528f664c
SL
1171}
1172
64d3a787
BJ
1173/*
1174 * Make a new file.
1175 */
1176struct inode *
1177maknode(mode)
1178 int mode;
1179{
1180 register struct inode *ip;
1181 ino_t ipref;
1182
1183 if ((mode & IFMT) == IFDIR)
1184 ipref = dirpref(u.u_pdir->i_fs);
1185 else
1186 ipref = u.u_pdir->i_number;
1187 ip = ialloc(u.u_pdir, ipref, mode);
1188 if (ip == NULL) {
1189 iput(u.u_pdir);
528f664c 1190 return (NULL);
64d3a787 1191 }
528f664c 1192#ifdef QUOTA
64d3a787
BJ
1193 if (ip->i_dquot != NODQUOT)
1194 panic("maknode: dquot");
1195#endif
1196 ip->i_flag |= IACC|IUPD|ICHG;
1197 if ((mode & IFMT) == 0)
1198 mode |= IFREG;
1199 ip->i_mode = mode & ~u.u_cmask;
1200 ip->i_nlink = 1;
1201 ip->i_uid = u.u_uid;
1202 ip->i_gid = u.u_pdir->i_gid;
bb1b75f4
SL
1203 if (ip->i_mode & ISGID && !groupmember(ip->i_gid))
1204 ip->i_mode &= ~ISGID;
528f664c 1205#ifdef QUOTA
64d3a787
BJ
1206 ip->i_dquot = inoquota(ip);
1207#endif
1208
1209 /*
1210 * Make sure inode goes to disk before directory entry.
1211 */
3fd23f5c 1212 iupdat(ip, &time, &time, 1);
f2a5ad78 1213 u.u_error = direnter(ip);
64d3a787
BJ
1214 if (u.u_error) {
1215 /*
f2a5ad78
SL
1216 * Write error occurred trying to update directory
1217 * so must deallocate the inode.
64d3a787
BJ
1218 */
1219 ip->i_nlink = 0;
1220 ip->i_flag |= ICHG;
1221 iput(ip);
528f664c 1222 return (NULL);
64d3a787 1223 }
528f664c 1224 return (ip);
64d3a787 1225}