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