european timezone rules
[unix-history] / usr / src / sys / ufs / ffs / ffs_vnops.c
CommitLineData
b8883494 1/* ffs_vnops.c 4.61 83/07/09 */
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;
0eaf24e3 446 (void) ino_stat(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 * Truncate a file given its path name.
654 */
528f664c
SL
655truncate()
656{
657 struct a {
658 char *fname;
4f083fd7 659 u_long length;
31949305 660 } *uap = (struct a *)u.u_ap;
528f664c
SL
661 struct inode *ip;
662
4f083fd7 663 ip = namei(uchar, LOOKUP, 1);
528f664c
SL
664 if (ip == NULL)
665 return;
666 if (access(ip, IWRITE))
667 goto bad;
668 if ((ip->i_mode&IFMT) == IFDIR) {
669 u.u_error = EISDIR;
670 goto bad;
671 }
672 itrunc(ip, uap->length);
528f664c
SL
673bad:
674 iput(ip);
675}
676
4f083fd7
SL
677/*
678 * Truncate a file given a file descriptor.
679 */
528f664c
SL
680ftruncate()
681{
682 struct a {
683 int fd;
4f083fd7 684 u_long length;
31949305 685 } *uap = (struct a *)u.u_ap;
528f664c
SL
686 struct inode *ip;
687 struct file *fp;
688
88a7a62a 689 fp = getinode(uap->fd);
528f664c
SL
690 if (fp == NULL)
691 return;
528f664c
SL
692 if ((fp->f_flag&FWRITE) == 0) {
693 u.u_error = EINVAL;
694 return;
695 }
88a7a62a 696 ip = (struct inode *)fp->f_data;
528f664c
SL
697 ilock(ip);
698 itrunc(ip, uap->length);
4f083fd7
SL
699 iunlock(ip);
700}
701
702/*
703 * Synch an open file.
704 */
705fsync()
706{
707 struct a {
708 int fd;
709 } *uap = (struct a *)u.u_ap;
710 struct inode *ip;
711 struct file *fp;
712
88a7a62a 713 fp = getinode(uap->fd);
4f083fd7
SL
714 if (fp == NULL)
715 return;
88a7a62a 716 ip = (struct inode *)fp->f_data;
4f083fd7
SL
717 ilock(ip);
718 syncip(ip);
719 iunlock(ip);
528f664c
SL
720}
721
4f083fd7
SL
722/*
723 * Rename system call.
724 * rename("foo", "bar");
725 * is essentially
726 * unlink("bar");
727 * link("foo", "bar");
728 * unlink("foo");
729 * but ``atomically''. Can't do full commit without saving state in the
730 * inode on disk which isn't feasible at this time. Best we can do is
731 * always guarantee the target exists.
732 *
733 * Basic algorithm is:
734 *
735 * 1) Bump link count on source while we're linking it to the
736 * target. This also insure the inode won't be deleted out
737 * from underneath us while we work.
738 * 2) Link source to destination. If destination already exists,
739 * delete it first.
740 * 3) Unlink source reference to inode if still around.
741 * 4) If a directory was moved and the parent of the destination
742 * is different from the source, patch the ".." entry in the
743 * directory.
744 *
745 * Source and destination must either both be directories, or both
746 * not be directories. If target is a directory, it must be empty.
747 */
528f664c
SL
748rename()
749{
750 struct a {
751 char *from;
752 char *to;
753 } *uap;
4f083fd7
SL
754 register struct inode *ip, *xp, *dp;
755 int oldparent, parentdifferent, doingdirectory;
a5390dce 756 int error = 0;
4f083fd7
SL
757
758 uap = (struct a *)u.u_ap;
046f18d1 759 ip = namei(uchar, DELETE | LOCKPARENT, 0);
4f083fd7
SL
760 if (ip == NULL)
761 return;
762 dp = u.u_pdir;
763 oldparent = 0, doingdirectory = 0;
764 if ((ip->i_mode&IFMT) == IFDIR) {
765 register struct direct *d;
766
767 d = &u.u_dent;
768 /*
046f18d1 769 * Avoid ".", "..", and aliases of "." for obvious reasons.
4f083fd7 770 */
046f18d1
SL
771 if ((d->d_namlen == 1 && d->d_name[0] == '.') ||
772 (d->d_namlen == 2 && bcmp(d->d_name, "..", 2) == 0) ||
773 (dp == ip)) {
774 iput(dp);
775 if (dp == ip)
776 irele(ip);
777 else
4f083fd7 778 iput(ip);
046f18d1
SL
779 u.u_error = EINVAL;
780 return;
4f083fd7
SL
781 }
782 oldparent = dp->i_number;
783 doingdirectory++;
784 }
046f18d1 785 iput(dp);
4f083fd7
SL
786
787 /*
788 * 1) Bump link count while we're moving stuff
789 * around. If we crash somewhere before
790 * completing our work, the link count
791 * may be wrong, but correctable.
792 */
793 ip->i_nlink++;
794 ip->i_flag |= ICHG;
795 iupdat(ip, &time, &time, 1);
796 iunlock(ip);
797
798 /*
799 * When the target exists, both the directory
800 * and target inodes are returned locked.
801 */
802 u.u_dirp = (caddr_t)uap->to;
803 xp = namei(uchar, CREATE | LOCKPARENT, 0);
a5390dce
SL
804 if (u.u_error) {
805 error = u.u_error;
4f083fd7 806 goto out;
a5390dce 807 }
4f083fd7 808 dp = u.u_pdir;
046f18d1
SL
809 /*
810 * If ".." must be changed (ie the directory gets a new
81552f0f
KM
811 * parent) then the source directory must not be in the
812 * directory heirarchy above the target, as this would
813 * orphan everything below the source directory. Also
814 * the user must have write permission in the source so
815 * as to be able to change "..". We must repeat the call
816 * to namei, as the parent directory is unlocked by the
817 * call to checkpath().
046f18d1
SL
818 */
819 parentdifferent = oldparent != dp->i_number;
81552f0f
KM
820 if (doingdirectory && parentdifferent) {
821 if (access(ip, IWRITE))
822 goto bad;
823 do {
824 dp = u.u_pdir;
825 if (xp != NULL)
826 iput(xp);
827 u.u_error = checkpath(ip, dp);
828 if (u.u_error)
829 goto out;
830 u.u_dirp = (caddr_t)uap->to;
831 xp = namei(uchar, CREATE | LOCKPARENT, 0);
832 if (u.u_error) {
833 error = u.u_error;
834 goto out;
835 }
836 } while (dp != u.u_pdir);
837 }
4f083fd7
SL
838 /*
839 * 2) If target doesn't exist, link the target
840 * to the source and unlink the source.
841 * Otherwise, rewrite the target directory
842 * entry to reference the source inode and
843 * expunge the original entry's existence.
844 */
4f083fd7
SL
845 if (xp == NULL) {
846 if (dp->i_dev != ip->i_dev) {
a5390dce 847 error = EXDEV;
4f083fd7
SL
848 goto bad;
849 }
850 /*
851 * Account for ".." in directory.
852 * When source and destination have the
853 * same parent we don't fool with the
854 * link count -- this isn't required
855 * because we do a similar check below.
856 */
857 if (doingdirectory && parentdifferent) {
858 dp->i_nlink++;
859 dp->i_flag |= ICHG;
860 iupdat(dp, &time, &time, 1);
861 }
f2a5ad78
SL
862 error = direnter(ip);
863 if (error)
4f083fd7
SL
864 goto out;
865 } else {
866 if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) {
a5390dce 867 error = EXDEV;
4f083fd7
SL
868 goto bad;
869 }
e69c3c9c
SL
870 /*
871 * Short circuit rename(foo, foo).
872 */
873 if (xp->i_number == ip->i_number)
874 goto bad;
4f083fd7 875 /*
a5390dce
SL
876 * Target must be empty if a directory
877 * and have no links to it.
4f083fd7
SL
878 * Also, insure source and target are
879 * compatible (both directories, or both
880 * not directories).
881 */
882 if ((xp->i_mode&IFMT) == IFDIR) {
a5390dce
SL
883 if (!dirempty(xp) || xp->i_nlink > 2) {
884 error = ENOTEMPTY;
4f083fd7
SL
885 goto bad;
886 }
887 if (!doingdirectory) {
a5390dce 888 error = ENOTDIR;
4f083fd7
SL
889 goto bad;
890 }
891 } else if (doingdirectory) {
a5390dce 892 error = EISDIR;
4f083fd7
SL
893 goto bad;
894 }
895 dirrewrite(dp, ip);
a5390dce
SL
896 if (u.u_error) {
897 error = u.u_error;
4f083fd7 898 goto bad1;
a5390dce 899 }
4f083fd7 900 /*
a5390dce
SL
901 * Adjust the link count of the target to
902 * reflect the dirrewrite above. If this is
903 * a directory it is empty and there are
904 * no links to it, so we can squash the inode and
905 * any space associated with it. We disallowed
906 * renaming over top of a directory with links to
907 * it above, as we've no way to determine if
908 * we've got a link or the directory itself, and
909 * if we get a link, then ".." will be screwed up.
4f083fd7 910 */
a5390dce 911 xp->i_nlink--;
4f083fd7 912 if (doingdirectory) {
a5390dce
SL
913 if (--xp->i_nlink != 0)
914 panic("rename: linked directory");
4f083fd7 915 itrunc(xp, (u_long)0);
a5390dce 916 }
4f083fd7
SL
917 xp->i_flag |= ICHG;
918 iput(xp);
31db12cb 919 xp = NULL;
4f083fd7
SL
920 }
921
922 /*
923 * 3) Unlink the source.
924 */
925 u.u_dirp = uap->from;
926 dp = namei(uchar, DELETE, 0);
927 /*
928 * Insure directory entry still exists and
929 * has not changed since the start of all
930 * this. If either has occured, forget about
931 * about deleting the original entry and just
932 * adjust the link count in the inode.
933 */
934 if (dp == NULL || u.u_dent.d_ino != ip->i_number) {
935 ip->i_nlink--;
936 ip->i_flag |= ICHG;
937 } else {
938 /*
939 * If source is a directory, must adjust
940 * link count of parent directory also.
941 * If target didn't exist and source and
942 * target have the same parent, then we
943 * needn't touch the link count, it all
944 * balances out in the end. Otherwise, we
945 * must do so to reflect deletion of ".."
946 * done above.
947 */
948 if (doingdirectory && (xp != NULL || parentdifferent)) {
949 dp->i_nlink--;
950 dp->i_flag |= ICHG;
951 }
952 if (dirremove()) {
953 ip->i_nlink--;
954 ip->i_flag |= ICHG;
955 }
a5390dce
SL
956 if (error == 0) /* conservative */
957 error = u.u_error;
4f083fd7
SL
958 }
959 irele(ip);
960 if (dp)
961 iput(dp);
962
963 /*
964 * 4) Renaming a directory with the parent
965 * different requires ".." to be rewritten.
966 * The window is still there for ".." to
967 * be inconsistent, but this is unavoidable,
968 * and a lot shorter than when it was done
969 * in a user process.
970 */
a5390dce 971 if (doingdirectory && parentdifferent && error == 0) {
4f083fd7 972 struct dirtemplate dirbuf;
528f664c 973
4f083fd7
SL
974 u.u_dirp = uap->to;
975 ip = namei(uchar, LOOKUP | LOCKPARENT, 0);
976 if (ip == NULL) {
977 printf("rename: .. went away\n");
978 return;
979 }
980 dp = u.u_pdir;
981 if ((ip->i_mode&IFMT) != IFDIR) {
982 printf("rename: .. not a directory\n");
983 goto stuck;
984 }
a5390dce 985 error = rdwri(UIO_READ, ip, (caddr_t)&dirbuf,
4f083fd7 986 sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
a5390dce 987 if (error == 0) {
4f083fd7
SL
988 dirbuf.dotdot_ino = dp->i_number;
989 (void) rdwri(UIO_WRITE, ip, (caddr_t)&dirbuf,
990 sizeof (struct dirtemplate), (off_t)0, 1, (int *)0);
991 }
992stuck:
993 irele(dp);
994 iput(ip);
995 }
a5390dce
SL
996 goto done;
997
4f083fd7 998bad:
31db12cb 999 iput(dp);
4f083fd7
SL
1000bad1:
1001 if (xp)
31db12cb 1002 iput(xp);
4f083fd7
SL
1003out:
1004 ip->i_nlink--;
1005 ip->i_flag |= ICHG;
1006 irele(ip);
a5390dce
SL
1007done:
1008 if (error)
1009 u.u_error = error;
528f664c
SL
1010}
1011
64d3a787
BJ
1012/*
1013 * Make a new file.
1014 */
1015struct inode *
1016maknode(mode)
1017 int mode;
1018{
1019 register struct inode *ip;
1020 ino_t ipref;
1021
1022 if ((mode & IFMT) == IFDIR)
1023 ipref = dirpref(u.u_pdir->i_fs);
1024 else
1025 ipref = u.u_pdir->i_number;
1026 ip = ialloc(u.u_pdir, ipref, mode);
1027 if (ip == NULL) {
1028 iput(u.u_pdir);
528f664c 1029 return (NULL);
64d3a787 1030 }
528f664c 1031#ifdef QUOTA
64d3a787
BJ
1032 if (ip->i_dquot != NODQUOT)
1033 panic("maknode: dquot");
1034#endif
1035 ip->i_flag |= IACC|IUPD|ICHG;
1036 if ((mode & IFMT) == 0)
1037 mode |= IFREG;
1038 ip->i_mode = mode & ~u.u_cmask;
1039 ip->i_nlink = 1;
1040 ip->i_uid = u.u_uid;
1041 ip->i_gid = u.u_pdir->i_gid;
bb1b75f4
SL
1042 if (ip->i_mode & ISGID && !groupmember(ip->i_gid))
1043 ip->i_mode &= ~ISGID;
528f664c 1044#ifdef QUOTA
64d3a787
BJ
1045 ip->i_dquot = inoquota(ip);
1046#endif
1047
1048 /*
1049 * Make sure inode goes to disk before directory entry.
1050 */
3fd23f5c 1051 iupdat(ip, &time, &time, 1);
f2a5ad78 1052 u.u_error = direnter(ip);
64d3a787
BJ
1053 if (u.u_error) {
1054 /*
f2a5ad78
SL
1055 * Write error occurred trying to update directory
1056 * so must deallocate the inode.
64d3a787
BJ
1057 */
1058 ip->i_nlink = 0;
1059 ip->i_flag |= ICHG;
1060 iput(ip);
528f664c 1061 return (NULL);
64d3a787 1062 }
528f664c 1063 return (ip);
64d3a787 1064}
88a7a62a
SL
1065
1066/*
1067 * A virgin directory (no blushing please).
1068 */
1069struct dirtemplate mastertemplate = {
1070 0, 12, 1, ".",
1071 0, DIRBLKSIZ - 12, 2, ".."
1072};
1073
1074/*
1075 * Mkdir system call
1076 */
1077mkdir()
1078{
1079 struct a {
1080 char *name;
1081 int dmode;
1082 } *uap;
1083 register struct inode *ip, *dp;
1084 struct dirtemplate dirtemplate;
1085
1086 uap = (struct a *)u.u_ap;
1087 ip = namei(uchar, CREATE, 0);
1088 if (u.u_error)
1089 return;
1090 if (ip != NULL) {
1091 iput(ip);
1092 u.u_error = EEXIST;
1093 return;
1094 }
1095 dp = u.u_pdir;
1096 uap->dmode &= 0777;
1097 uap->dmode |= IFDIR;
1098 /*
1099 * Must simulate part of maknode here
1100 * in order to acquire the inode, but
1101 * not have it entered in the parent
1102 * directory. The entry is made later
1103 * after writing "." and ".." entries out.
1104 */
1105 ip = ialloc(dp, dirpref(dp->i_fs), uap->dmode);
1106 if (ip == NULL) {
1107 iput(dp);
1108 return;
1109 }
1110#ifdef QUOTA
1111 if (ip->i_dquot != NODQUOT)
1112 panic("mkdir: dquot");
1113#endif
1114 ip->i_flag |= IACC|IUPD|ICHG;
1115 ip->i_mode = uap->dmode & ~u.u_cmask;
1116 ip->i_nlink = 2;
1117 ip->i_uid = u.u_uid;
1118 ip->i_gid = dp->i_gid;
1119#ifdef QUOTA
1120 ip->i_dquot = inoquota(ip);
1121#endif
1122 iupdat(ip, &time, &time, 1);
1123
1124 /*
1125 * Bump link count in parent directory
1126 * to reflect work done below. Should
1127 * be done before reference is created
1128 * so reparation is possible if we crash.
1129 */
1130 dp->i_nlink++;
1131 dp->i_flag |= ICHG;
1132 iupdat(dp, &time, &time, 1);
1133
1134 /*
1135 * Initialize directory with "."
1136 * and ".." from static template.
1137 */
1138 dirtemplate = mastertemplate;
1139 dirtemplate.dot_ino = ip->i_number;
1140 dirtemplate.dotdot_ino = dp->i_number;
1141 u.u_error = rdwri(UIO_WRITE, ip, (caddr_t)&dirtemplate,
1142 sizeof (dirtemplate), (off_t)0, 1, (int *)0);
1143 if (u.u_error) {
1144 dp->i_nlink--;
1145 dp->i_flag |= ICHG;
1146 goto bad;
1147 }
1148 /*
1149 * Directory all set up, now
1150 * install the entry for it in
1151 * the parent directory.
1152 */
1153 u.u_error = direnter(ip);
1154 dp = NULL;
1155 if (u.u_error) {
1156 u.u_dirp = uap->name;
1157 dp = namei(uchar, LOOKUP, 0);
1158 if (dp) {
1159 dp->i_nlink--;
1160 dp->i_flag |= ICHG;
1161 }
1162 }
1163bad:
1164 /*
1165 * No need to do an explicit itrunc here,
1166 * irele will do this for us because we set
1167 * the link count to 0.
1168 */
1169 if (u.u_error) {
1170 ip->i_nlink = 0;
1171 ip->i_flag |= ICHG;
1172 }
1173 if (dp)
1174 iput(dp);
1175 iput(ip);
1176}
1177
1178/*
1179 * Rmdir system call.
1180 */
1181rmdir()
1182{
1183 struct a {
1184 char *name;
1185 };
1186 register struct inode *ip, *dp;
1187
1188 ip = namei(uchar, DELETE | LOCKPARENT, 0);
1189 if (ip == NULL)
1190 return;
1191 dp = u.u_pdir;
1192 /*
1193 * No rmdir "." please.
1194 */
1195 if (dp == ip) {
1196 irele(dp);
1197 iput(ip);
1198 u.u_error = EINVAL;
1199 return;
1200 }
1201 if ((ip->i_mode&IFMT) != IFDIR) {
1202 u.u_error = ENOTDIR;
1203 goto out;
1204 }
1205 /*
1206 * Don't remove a mounted on directory.
1207 */
1208 if (ip->i_dev != dp->i_dev) {
1209 u.u_error = EBUSY;
1210 goto out;
1211 }
1212 /*
1213 * Verify the directory is empty (and valid).
1214 * (Rmdir ".." won't be valid since
1215 * ".." will contain a reference to
1216 * the current directory and thus be
1217 * non-empty.)
1218 */
1219 if (ip->i_nlink != 2 || !dirempty(ip)) {
1220 u.u_error = ENOTEMPTY;
1221 goto out;
1222 }
1223 /*
1224 * Delete reference to directory before purging
1225 * inode. If we crash in between, the directory
1226 * will be reattached to lost+found,
1227 */
1228 if (dirremove() == 0)
1229 goto out;
1230 dp->i_nlink--;
1231 dp->i_flag |= ICHG;
1232 iput(dp);
1233 dp = NULL;
1234 /*
1235 * Truncate inode. The only stuff left
1236 * in the directory is "." and "..". The
1237 * "." reference is inconsequential since
1238 * we're quashing it. The ".." reference
1239 * has already been adjusted above. We've
1240 * removed the "." reference and the reference
1241 * in the parent directory, but there may be
1242 * other hard links so decrement by 2 and
1243 * worry about them later.
1244 */
1245 ip->i_nlink -= 2;
1246 itrunc(ip, (u_long)0);
1247out:
1248 if (dp)
1249 iput(dp);
1250 iput(ip);
1251}
1252
1253struct file *
1254getinode(fdes)
1255 int fdes;
1256{
1257 register struct file *fp;
1258
1259 fp = getf(fdes);
1260 if (fp == 0)
1261 return (0);
1262 if (fp->f_type != DTYPE_INODE) {
1263 u.u_error = EINVAL;
1264 return (0);
1265 }
1266 return (fp);
1267}
1268
1269/*
1270 * mode mask for creation of files
1271 */
1272umask()
1273{
1274 register struct a {
1275 int mask;
1276 } *uap;
1277
1278 uap = (struct a *)u.u_ap;
1279 u.u_r.r_val1 = u.u_cmask;
1280 u.u_cmask = uap->mask & 07777;
1281}