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