be more paranoid about checking unallocated blocks in inodes
[unix-history] / usr / src / sys / ufs / lfs / lfs_vnops.c
CommitLineData
ca91bded 1/* lfs_vnops.c 4.25 82/06/07 */
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
18chdir()
19{
20
21 chdirec(&u.u_cdir);
22}
23
24chroot()
25{
26
27 if (suser())
28 chdirec(&u.u_rdir);
29}
30
31chdirec(ipp)
32register 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);
3e78e260
BJ
49 if (*ipp) {
50 ilock(*ipp);
51 iput(*ipp);
52 }
53 *ipp = ip;
54 return;
55
56bad:
57 iput(ip);
58}
59
60/*
61 * Open system call.
62 */
63open()
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 */
81creat()
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 */
107open1(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);
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--;
138out:
139 if (ip != NULL)
140 iput(ip);
141}
142
143/*
144 * Mknod system call
145 */
146mknod()
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
177out:
178 iput(ip);
179}
180
181/*
182 * link system call
183 */
184link()
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);
ca91bded 201 iunlock(ip);
3e78e260
BJ
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);
217out:
218 if (u.u_error) {
219 ip->i_nlink--;
220 ip->i_flag |= ICHG;
221 }
222out1:
223 iput(ip);
224}
225
226/*
227 * symlink -- make a symbolic link
228 */
229symlink()
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 */
275unlink()
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
345out:
346 iput(ip);
347out1:
348 iput(pp);
349}
350
351/*
352 * Seek system call
353 */
354seek()
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 */
382saccess()
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 */
413fstat()
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 */
434stat()
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 */
453lstat()
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 473stat1(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 */
502readlink()
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);
524out:
525 iput(ip);
526 u.u_r.r_val1 = uap->count - u.u_count;
527}
528
3e78e260 529chmod()
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 550chown()
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 574utime()
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 595sync()
d67a03eb 596{
d67a03eb 597
68503f9a 598 update(0);
d67a03eb 599}