drop #ifdef SIMFS for /etc/config's sake
[unix-history] / usr / src / sys / ufs / ffs / ufs_vnops.c
CommitLineData
f3e6400f 1/* ufs_vnops.c 4.27 82/06/25 */
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"
d67a03eb 7#include "../h/file.h"
6459ebe0 8#include "../h/stat.h"
3e78e260 9#include "../h/inode.h"
6459ebe0 10#include "../h/fs.h"
3e78e260 11#include "../h/buf.h"
3e78e260 12#include "../h/proc.h"
0737b714 13#include "../h/inline.h"
3e78e260
BJ
14
15chdir()
16{
17
18 chdirec(&u.u_cdir);
19}
20
21chroot()
22{
23
24 if (suser())
25 chdirec(&u.u_rdir);
26}
27
28chdirec(ipp)
29register struct inode **ipp;
30{
31 register struct inode *ip;
32 struct a {
33 char *fname;
34 };
35
36 ip = namei(uchar, 0, 1);
37 if(ip == NULL)
38 return;
39 if((ip->i_mode&IFMT) != IFDIR) {
40 u.u_error = ENOTDIR;
41 goto bad;
42 }
43 if(access(ip, IEXEC))
44 goto bad;
ca91bded 45 iunlock(ip);
8eee8525
KM
46 if (*ipp)
47 irele(*ipp);
3e78e260
BJ
48 *ipp = ip;
49 return;
50
51bad:
52 iput(ip);
53}
54
55/*
56 * Open system call.
57 */
58open()
59{
60 register struct inode *ip;
61 register struct a {
62 char *fname;
63 int rwmode;
64 } *uap;
65
66 uap = (struct a *)u.u_ap;
67 ip = namei(uchar, 0, 1);
68 if (ip == NULL)
69 return;
70 open1(ip, ++uap->rwmode, 0);
71}
72
73/*
74 * Creat system call.
75 */
76creat()
77{
78 register struct inode *ip;
79 register struct a {
80 char *fname;
81 int fmode;
82 } *uap;
83
84 uap = (struct a *)u.u_ap;
85 ip = namei(uchar, 1, 1);
86 if (ip == NULL) {
87 if (u.u_error)
88 return;
89 ip = maknode(uap->fmode&07777&(~ISVTX));
90 if (ip==NULL)
91 return;
92 open1(ip, FWRITE, 2);
93 } else
94 open1(ip, FWRITE, 1);
95}
96
97/*
98 * Common code for open and creat.
99 * Check permissions, allocate an open file structure,
100 * and call the device open routine if any.
101 */
102open1(ip, mode, trf)
103 register struct inode *ip;
104 register mode;
105{
106 register struct file *fp;
107 int i;
108
109 if (trf != 2) {
110 if (mode&FREAD)
111 (void) access(ip, IREAD);
112 if (mode&FWRITE) {
113 (void) access(ip, IWRITE);
114 if ((ip->i_mode&IFMT) == IFDIR)
115 u.u_error = EISDIR;
116 }
117 }
8eee8525
KM
118 if (u.u_error) {
119 iput(ip);
120 return;
121 }
3e78e260
BJ
122 if (trf == 1)
123 itrunc(ip);
ca91bded 124 iunlock(ip);
3e78e260
BJ
125 if ((fp = falloc()) == NULL)
126 goto out;
127 fp->f_flag = mode&(FREAD|FWRITE);
128 i = u.u_r.r_val1;
129 fp->f_inode = ip;
130 openi(ip, mode&(FREAD|FWRITE));
131 if (u.u_error == 0)
132 return;
133 u.u_ofile[i] = NULL;
134 fp->f_count--;
135out:
8eee8525 136 irele(ip);
3e78e260
BJ
137}
138
139/*
140 * Mknod system call
141 */
142mknod()
143{
144 register struct inode *ip;
145 register struct a {
146 char *fname;
147 int fmode;
148 int dev;
149 } *uap;
150
151 uap = (struct a *)u.u_ap;
152 if (suser()) {
153 ip = namei(uchar, 1, 0);
154 if (ip != NULL) {
155 u.u_error = EEXIST;
156 goto out;
157 }
158 }
159 if (u.u_error)
160 return;
161 ip = maknode(uap->fmode);
162 if (ip == NULL)
163 return;
164 if (uap->dev) {
165 /*
166 * Want to be able to use this to make badblock
167 * inodes, so don't truncate the dev number.
168 */
6459ebe0 169 ip->i_rdev = uap->dev;
3e78e260
BJ
170 ip->i_flag |= IACC|IUPD|ICHG;
171 }
172
173out:
174 iput(ip);
175}
176
177/*
178 * link system call
179 */
180link()
181{
182 register struct inode *ip, *xp;
183 register struct a {
184 char *target;
185 char *linkname;
186 } *uap;
187
188 uap = (struct a *)u.u_ap;
189 ip = namei(uchar, 0, 1); /* well, this routine is doomed anyhow */
190 if (ip == NULL)
191 return;
192 if ((ip->i_mode&IFMT)==IFDIR && !suser())
193 goto out1;
194 ip->i_nlink++;
195 ip->i_flag |= ICHG;
196 iupdat(ip, &time, &time, 1);
ca91bded 197 iunlock(ip);
3e78e260
BJ
198 u.u_dirp = (caddr_t)uap->linkname;
199 xp = namei(uchar, 1, 0);
200 if (xp != NULL) {
201 u.u_error = EEXIST;
202 iput(xp);
203 goto out;
204 }
205 if (u.u_error)
206 goto out;
207 if (u.u_pdir->i_dev != ip->i_dev) {
208 iput(u.u_pdir);
209 u.u_error = EXDEV;
210 goto out;
211 }
212 wdir(ip);
213out:
214 if (u.u_error) {
215 ip->i_nlink--;
216 ip->i_flag |= ICHG;
217 }
218out1:
8eee8525 219 irele(ip);
3e78e260
BJ
220}
221
222/*
223 * symlink -- make a symbolic link
224 */
225symlink()
226{
227 register struct a {
228 char *target;
229 char *linkname;
230 } *uap;
231 register struct inode *ip;
232 register char *tp;
233 register c, nc;
234
235 uap = (struct a *)u.u_ap;
236 tp = uap->target;
237 nc = 0;
238 while (c = fubyte(tp)) {
239 if (c < 0) {
240 u.u_error = EFAULT;
241 return;
242 }
243 tp++;
244 nc++;
245 }
246 u.u_dirp = uap->linkname;
247 ip = namei(uchar, 1, 0);
248 if (ip) {
249 iput(ip);
250 u.u_error = EEXIST;
251 return;
252 }
253 if (u.u_error)
254 return;
255 ip = maknode(IFLNK | 0777);
256 if (ip == NULL)
257 return;
258 u.u_base = uap->target;
259 u.u_count = nc;
260 u.u_offset = 0;
261 u.u_segflg = 0;
262 writei(ip);
263 iput(ip);
264}
265
266/*
267 * Unlink system call.
268 * Hard to avoid races here, especially
269 * in unlinking directories.
270 */
271unlink()
272{
273 register struct inode *ip, *pp;
274 struct a {
275 char *fname;
276 };
6459ebe0
KM
277 struct fs *fs;
278 struct buf *bp;
279 int lbn, bn, base;
8eee8525 280 int unlinkingdot = 0;
3e78e260
BJ
281
282 pp = namei(uchar, 2, 0);
283 if(pp == NULL)
284 return;
285 /*
286 * Check for unlink(".")
287 * to avoid hanging on the iget
288 */
289 if (pp->i_number == u.u_dent.d_ino) {
290 ip = pp;
291 ip->i_count++;
8eee8525 292 unlinkingdot++;
3e78e260 293 } else
6459ebe0 294 ip = iget(pp->i_dev, pp->i_fs, u.u_dent.d_ino);
3e78e260
BJ
295 if(ip == NULL)
296 goto out1;
297 if((ip->i_mode&IFMT)==IFDIR && !suser())
298 goto out;
299 /*
300 * Don't unlink a mounted file.
301 */
302 if (ip->i_dev != pp->i_dev) {
303 u.u_error = EBUSY;
304 goto out;
305 }
306 if (ip->i_flag&ITEXT)
307 xrele(ip); /* try once to free text */
308/*
309 if ((ip->i_flag&ITEXT) && ip->i_nlink==1) {
310 u.u_error = ETXTBSY;
311 goto out;
312 }
313*/
6459ebe0
KM
314 if (u.u_count == 0) {
315 /*
316 * first entry in block, so set d_ino to zero.
317 */
318 u.u_base = (caddr_t)&u.u_dent;
319 u.u_count = DIRSIZ(&u.u_dent);
320 u.u_dent.d_ino = 0;
321 writei(pp);
322 } else {
323 /*
324 * updating preceeding entry to skip over current entry.
325 */
326 fs = pp->i_fs;
327 lbn = lblkno(fs, u.u_offset);
328 base = blkoff(fs, u.u_offset);
329 bn = fsbtodb(fs, bmap(pp, lbn, B_WRITE, base + u.u_count));
330 bp = bread(pp->i_dev, bn, blksize(fs, pp, lbn));
331 if (bp->b_flags & B_ERROR) {
332 brelse(bp);
333 goto out;
334 }
335 ((struct direct *)(bp->b_un.b_addr + base))->d_reclen +=
336 u.u_dent.d_reclen;
337 bwrite(bp);
338 pp->i_flag |= IUPD|ICHG;
339 }
3e78e260
BJ
340 ip->i_nlink--;
341 ip->i_flag |= ICHG;
342
343out:
8eee8525
KM
344 if (unlinkingdot)
345 irele(ip);
346 else
347 iput(ip);
3e78e260
BJ
348out1:
349 iput(pp);
350}
351
352/*
353 * Seek system call
354 */
355seek()
356{
357 register struct file *fp;
358 register struct a {
359 int fdes;
360 off_t off;
361 int sbase;
362 } *uap;
363
364 uap = (struct a *)u.u_ap;
365 fp = getf(uap->fdes);
366 if (fp == NULL)
367 return;
368 if (fp->f_flag&FSOCKET) {
369 u.u_error = ESPIPE;
370 return;
371 }
372 if (uap->sbase == 1)
373 uap->off += fp->f_offset;
374 else if (uap->sbase == 2)
375 uap->off += fp->f_inode->i_size;
376 fp->f_offset = uap->off;
377 u.u_r.r_off = uap->off;
378}
379
380/*
381 * Access system call
382 */
383saccess()
384{
385 register svuid, svgid;
386 register struct inode *ip;
387 register struct a {
388 char *fname;
389 int fmode;
390 } *uap;
391
392 uap = (struct a *)u.u_ap;
393 svuid = u.u_uid;
394 svgid = u.u_gid;
395 u.u_uid = u.u_ruid;
396 u.u_gid = u.u_rgid;
397 ip = namei(uchar, 0, 1);
398 if (ip != NULL) {
399 if (uap->fmode&(IREAD>>6))
400 (void) access(ip, IREAD);
401 if (uap->fmode&(IWRITE>>6))
402 (void) access(ip, IWRITE);
403 if (uap->fmode&(IEXEC>>6))
404 (void) access(ip, IEXEC);
405 iput(ip);
406 }
407 u.u_uid = svuid;
408 u.u_gid = svgid;
409}
d67a03eb
BJ
410
411/*
412 * the fstat system call.
413 */
414fstat()
415{
416 register struct file *fp;
417 register struct a {
418 int fdes;
419 struct stat *sb;
420 } *uap;
421
422 uap = (struct a *)u.u_ap;
423 fp = getf(uap->fdes);
e92a04af 424 if (fp == NULL)
d67a03eb 425 return;
e92a04af 426 if (fp->f_flag & FSOCKET)
cc15ab5d 427 u.u_error = sostat(fp->f_socket, uap->sb);
e92a04af
BJ
428 else
429 stat1(fp->f_inode, uap->sb);
d67a03eb
BJ
430}
431
432/*
6459ebe0 433 * Stat system call. This version follows links.
d67a03eb
BJ
434 */
435stat()
436{
437 register struct inode *ip;
438 register struct a {
439 char *fname;
440 struct stat *sb;
441 } *uap;
442
443 uap = (struct a *)u.u_ap;
66d4ba1b 444 ip = namei(uchar, 0, 1);
e92a04af 445 if (ip == NULL)
d67a03eb 446 return;
a3aa7f92 447 stat1(ip, uap->sb);
d67a03eb
BJ
448 iput(ip);
449}
450
5485e062 451/*
6459ebe0 452 * Lstat system call. This version does not follow links.
5485e062
BJ
453 */
454lstat()
455{
456 register struct inode *ip;
457 register struct a {
458 char *fname;
459 struct stat *sb;
460 } *uap;
461
462 uap = (struct a *)u.u_ap;
66d4ba1b 463 ip = namei(uchar, 0, 0);
5485e062
BJ
464 if (ip == NULL)
465 return;
019b08c9 466 stat1(ip, uap->sb);
5485e062
BJ
467 iput(ip);
468}
469
d67a03eb
BJ
470/*
471 * The basic routine for fstat and stat:
472 * get the inode and pass appropriate parts back.
473 */
a3aa7f92 474stat1(ip, ub)
e92a04af
BJ
475 register struct inode *ip;
476 struct stat *ub;
d67a03eb 477{
d67a03eb
BJ
478 struct stat ds;
479
c0bb1685 480 IUPDAT(ip, &time, &time, 0);
d67a03eb 481 /*
09c42945 482 * Copy from inode table
d67a03eb
BJ
483 */
484 ds.st_dev = ip->i_dev;
485 ds.st_ino = ip->i_number;
486 ds.st_mode = ip->i_mode;
487 ds.st_nlink = ip->i_nlink;
488 ds.st_uid = ip->i_uid;
489 ds.st_gid = ip->i_gid;
6459ebe0 490 ds.st_rdev = (dev_t)ip->i_rdev;
a3aa7f92 491 ds.st_size = ip->i_size;
6459ebe0
KM
492 ds.st_atime = ip->i_atime;
493 ds.st_mtime = ip->i_mtime;
494 ds.st_ctime = ip->i_ctime;
09c42945 495 ds.st_blksize = ip->i_fs->fs_bsize;
d67a03eb
BJ
496 if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
497 u.u_error = EFAULT;
498}
499
500/*
5485e062
BJ
501 * Return target name of a symbolic link
502 */
503readlink()
504{
505 register struct inode *ip;
506 register struct a {
507 char *name;
508 char *buf;
509 int count;
510 } *uap;
511
512 ip = namei(uchar, 0, 0);
513 if (ip == NULL)
514 return;
515 if ((ip->i_mode&IFMT) != IFLNK) {
516 u.u_error = ENXIO;
517 goto out;
518 }
519 uap = (struct a *)u.u_ap;
520 u.u_offset = 0;
521 u.u_base = uap->buf;
522 u.u_count = uap->count;
523 u.u_segflg = 0;
524 readi(ip);
525out:
526 iput(ip);
527 u.u_r.r_val1 = uap->count - u.u_count;
528}
529
3e78e260 530chmod()
5485e062 531{
3e78e260 532 register struct inode *ip;
5485e062 533 register struct a {
3e78e260
BJ
534 char *fname;
535 int fmode;
5485e062 536 } *uap;
5485e062
BJ
537
538 uap = (struct a *)u.u_ap;
3e78e260 539 if ((ip = owner(1)) == NULL)
5485e062 540 return;
3e78e260
BJ
541 ip->i_mode &= ~07777;
542 if (u.u_uid)
543 uap->fmode &= ~ISVTX;
544 ip->i_mode |= uap->fmode&07777;
545 ip->i_flag |= ICHG;
546 if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
547 xrele(ip);
5485e062
BJ
548 iput(ip);
549}
550
3e78e260 551chown()
d67a03eb 552{
3e78e260 553 register struct inode *ip;
d67a03eb 554 register struct a {
3e78e260
BJ
555 char *fname;
556 int uid;
557 int gid;
d67a03eb 558 } *uap;
d67a03eb
BJ
559
560 uap = (struct a *)u.u_ap;
3e78e260 561 if (!suser() || (ip = owner(0)) == NULL)
d67a03eb 562 return;
3e78e260
BJ
563 ip->i_uid = uap->uid;
564 ip->i_gid = uap->gid;
565 ip->i_flag |= ICHG;
566 if (u.u_ruid != 0)
567 ip->i_mode &= ~(ISUID|ISGID);
568 iput(ip);
d67a03eb
BJ
569}
570
571/*
3e78e260
BJ
572 * Set IUPD and IACC times on file.
573 * Can't set ICHG.
d67a03eb 574 */
3e78e260 575utime()
e92a04af 576{
d67a03eb 577 register struct a {
3e78e260
BJ
578 char *fname;
579 time_t *tptr;
d67a03eb 580 } *uap;
3e78e260
BJ
581 register struct inode *ip;
582 time_t tv[2];
d67a03eb
BJ
583
584 uap = (struct a *)u.u_ap;
3e78e260 585 if ((ip = owner(1)) == NULL)
d67a03eb 586 return;
3e78e260
BJ
587 if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) {
588 u.u_error = EFAULT;
589 } else {
590 ip->i_flag |= IACC|IUPD|ICHG;
591 iupdat(ip, &tv[0], &tv[1], 0);
d67a03eb 592 }
d67a03eb
BJ
593 iput(ip);
594}
595
3e78e260 596sync()
d67a03eb 597{
d67a03eb 598
68503f9a 599 update(0);
d67a03eb 600}