xref: /csrg-svn/sys/ufs/lfs/lfs_vnops.c (revision 7142)
1 /*	lfs_vnops.c	4.26	82/06/10	*/
2 
3 #ifdef SIMFS
4 #include "../h/sysrenam.h"
5 #endif
6 #include "../h/param.h"
7 #include "../h/systm.h"
8 #include "../h/dir.h"
9 #include "../h/user.h"
10 #include "../h/file.h"
11 #include "../h/stat.h"
12 #include "../h/inode.h"
13 #include "../h/fs.h"
14 #include "../h/buf.h"
15 #include "../h/proc.h"
16 #include "../h/inline.h"
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 	iunlock(ip);
49 	if (*ipp)
50 		irele(*ipp);
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 	}
121 	if (u.u_error) {
122 		iput(ip);
123 		return;
124 	}
125 	if (trf == 1)
126 		itrunc(ip);
127 	iunlock(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 	irele(ip);
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 		 */
172 		ip->i_rdev = uap->dev;
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);
200 	iunlock(ip);
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:
222 	irele(ip);
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 	};
280 	struct fs *fs;
281 	struct buf *bp;
282 	int lbn, bn, base;
283 	int unlinkingdot = 0;
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 		unlinkingdot++;
296 	} else
297 		ip = iget(pp->i_dev, pp->i_fs, u.u_dent.d_ino);
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 */
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 	}
343 	ip->i_nlink--;
344 	ip->i_flag |= ICHG;
345 
346 out:
347 	if (unlinkingdot)
348 		irele(ip);
349 	else
350 		iput(ip);
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 }
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);
427 	if (fp == NULL)
428 		return;
429 	if (fp->f_flag & FSOCKET)
430 		u.u_error = sostat(fp->f_socket, uap->sb);
431 	else
432 		stat1(fp->f_inode, uap->sb);
433 }
434 
435 /*
436  * Stat system call.  This version follows links.
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;
447 	ip = namei(uchar, 0, 1);
448 	if (ip == NULL)
449 		return;
450 	stat1(ip, uap->sb);
451 	iput(ip);
452 }
453 
454 /*
455  * Lstat system call.  This version does not follow links.
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;
466 	ip = namei(uchar, 0, 0);
467 	if (ip == NULL)
468 		return;
469 	stat1(ip, uap->sb);
470 	iput(ip);
471 }
472 
473 /*
474  * The basic routine for fstat and stat:
475  * get the inode and pass appropriate parts back.
476  */
477 stat1(ip, ub)
478 	register struct inode *ip;
479 	struct stat *ub;
480 {
481 	struct stat ds;
482 
483 	IUPDAT(ip, &time, &time, 0);
484 	/*
485 	 * Copy from inode table
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;
493 	ds.st_rdev = (dev_t)ip->i_rdev;
494 	ds.st_size = ip->i_size;
495 	ds.st_atime = ip->i_atime;
496 	ds.st_mtime = ip->i_mtime;
497 	ds.st_ctime = ip->i_ctime;
498 	ds.st_blksize = ip->i_fs->fs_bsize;
499 	if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
500 		u.u_error = EFAULT;
501 }
502 
503 /*
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 
533 chmod()
534 {
535 	register struct inode *ip;
536 	register struct a {
537 		char	*fname;
538 		int	fmode;
539 	} *uap;
540 
541 	uap = (struct a *)u.u_ap;
542 	if ((ip = owner(1)) == NULL)
543 		return;
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);
551 	iput(ip);
552 }
553 
554 chown()
555 {
556 	register struct inode *ip;
557 	register struct a {
558 		char	*fname;
559 		int	uid;
560 		int	gid;
561 	} *uap;
562 
563 	uap = (struct a *)u.u_ap;
564 	if (!suser() || (ip = owner(0)) == NULL)
565 		return;
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);
572 }
573 
574 /*
575  * Set IUPD and IACC times on file.
576  * Can't set ICHG.
577  */
578 utime()
579 {
580 	register struct a {
581 		char	*fname;
582 		time_t	*tptr;
583 	} *uap;
584 	register struct inode *ip;
585 	time_t tv[2];
586 
587 	uap = (struct a *)u.u_ap;
588 	if ((ip = owner(1)) == NULL)
589 		return;
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);
595 	}
596 	iput(ip);
597 }
598 
599 sync()
600 {
601 
602 	update(0);
603 }
604