xref: /netbsd-src/sys/lib/libsa/ufs.c (revision 6ea46cb5e46c49111a6ecf3bcbe3c7e2730fe9f6)
1 /*-
2  * Copyright (c) 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * The Mach Operating System project at Carnegie-Mellon University.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	from: @(#)ufs.c	8.1 (Berkeley) 6/11/93
37  *
38  *
39  * Copyright (c) 1990, 1991 Carnegie Mellon University
40  * All Rights Reserved.
41  *
42  * Author: David Golub
43  *
44  * Permission to use, copy, modify and distribute this software and its
45  * documentation is hereby granted, provided that both the copyright
46  * notice and this permission notice appear in all copies of the
47  * software, derivative works or modified versions, and any portions
48  * thereof, and that both notices appear in supporting documentation.
49  *
50  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
51  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
52  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
53  *
54  * Carnegie Mellon requests users of this software to return to
55  *
56  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
57  *  School of Computer Science
58  *  Carnegie Mellon University
59  *  Pittsburgh PA 15213-3890
60  *
61  * any improvements or extensions that they make and grant Carnegie the
62  * rights to redistribute these changes.
63  *
64  *	$Id: ufs.c,v 1.7 1994/08/22 21:56:15 brezak Exp $
65  */
66 
67 /*
68  *	Stand-alone file reading package.
69  */
70 
71 #include <string.h>
72 #include <sys/param.h>
73 #include <sys/time.h>
74 #include <ufs/ffs/fs.h>
75 #include <ufs/ufs/dinode.h>
76 #include <ufs/ufs/dir.h>
77 #include <lib/libkern/libkern.h>
78 
79 #include "stand.h"
80 
81 /*
82  * In-core open file.
83  */
84 struct file {
85 	off_t		f_seekp;	/* seek pointer */
86 	struct fs	*f_fs;		/* pointer to super-block */
87 	struct dinode	f_di;		/* copy of on-disk inode */
88 	int		f_nindir[NIADDR];
89 					/* number of blocks mapped by
90 					   indirect block at level i */
91 	char		*f_blk[NIADDR];	/* buffer for indirect block at
92 					   level i */
93 	u_long		f_blksize[NIADDR];
94 					/* size of buffer */
95 	daddr_t		f_blkno[NIADDR];/* disk address of block in buffer */
96 	char		*f_buf;		/* buffer for data block */
97 	u_int		f_buf_size;	/* size of data block */
98 	daddr_t		f_buf_blkno;	/* block number of data block */
99 };
100 
101 #ifdef COMPAT_UFS
102 void ffs_oldfscompat __P((struct fs *));
103 #endif
104 
105 /*
106  * Read a new inode into a file structure.
107  */
108 static int
109 read_inode(inumber, f)
110 	ino_t inumber;
111 	struct open_file *f;
112 {
113 	register struct file *fp = (struct file *)f->f_fsdata;
114 	register struct fs *fs = fp->f_fs;
115 	char *buf;
116 	u_int rsize;
117 	int rc;
118 
119 	/*
120 	 * Read inode and save it.
121 	 */
122 	buf = alloc(fs->fs_bsize);
123 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
124 		fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize, buf, &rsize);
125 	if (rc)
126 		goto out;
127 	if (rsize != fs->fs_bsize) {
128 		rc = EIO;
129 		goto out;
130 	}
131 
132 	{
133 		register struct dinode *dp;
134 
135 		dp = (struct dinode *)buf;
136 		fp->f_di = dp[ino_to_fsbo(fs, inumber)];
137 	}
138 
139 	/*
140 	 * Clear out the old buffers
141 	 */
142 	{
143 		register int level;
144 
145 		for (level = 0; level < NIADDR; level++)
146 			fp->f_blkno[level] = -1;
147 		fp->f_buf_blkno = -1;
148 	}
149 out:
150 	free(buf, fs->fs_bsize);
151 	return (0);
152 }
153 
154 /*
155  * Given an offset in a file, find the disk block number that
156  * contains that block.
157  */
158 static int
159 block_map(f, file_block, disk_block_p)
160 	struct open_file *f;
161 	daddr_t file_block;
162 	daddr_t *disk_block_p;	/* out */
163 {
164 	register struct file *fp = (struct file *)f->f_fsdata;
165 	register struct fs *fs = fp->f_fs;
166 	int level;
167 	int idx;
168 	daddr_t ind_block_num;
169 	daddr_t *ind_p;
170 	int rc;
171 
172 	/*
173 	 * Index structure of an inode:
174 	 *
175 	 * di_db[0..NDADDR-1]	hold block numbers for blocks
176 	 *			0..NDADDR-1
177 	 *
178 	 * di_ib[0]		index block 0 is the single indirect block
179 	 *			holds block numbers for blocks
180 	 *			NDADDR .. NDADDR + NINDIR(fs)-1
181 	 *
182 	 * di_ib[1]		index block 1 is the double indirect block
183 	 *			holds block numbers for INDEX blocks for blocks
184 	 *			NDADDR + NINDIR(fs) ..
185 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
186 	 *
187 	 * di_ib[2]		index block 2 is the triple indirect block
188 	 *			holds block numbers for double-indirect
189 	 *			blocks for blocks
190 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
191 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2
192 	 *				+ NINDIR(fs)**3 - 1
193 	 */
194 
195 	if (file_block < NDADDR) {
196 		/* Direct block. */
197 		*disk_block_p = fp->f_di.di_db[file_block];
198 		return (0);
199 	}
200 
201 	file_block -= NDADDR;
202 
203 	/*
204 	 * nindir[0] = NINDIR
205 	 * nindir[1] = NINDIR**2
206 	 * nindir[2] = NINDIR**3
207 	 *	etc
208 	 */
209 	for (level = 0; level < NIADDR; level++) {
210 		if (file_block < fp->f_nindir[level])
211 			break;
212 		file_block -= fp->f_nindir[level];
213 	}
214 	if (level == NIADDR) {
215 		/* Block number too high */
216 		return (EFBIG);
217 	}
218 
219 	ind_block_num = fp->f_di.di_ib[level];
220 
221 	for (; level >= 0; level--) {
222 		if (ind_block_num == 0) {
223 			*disk_block_p = 0;	/* missing */
224 			return (0);
225 		}
226 
227 		if (fp->f_blkno[level] != ind_block_num) {
228 			if (fp->f_blk[level] == (char *)0)
229 				fp->f_blk[level] =
230 					alloc(fs->fs_bsize);
231 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
232 				fsbtodb(fp->f_fs, ind_block_num),
233 				fs->fs_bsize,
234 				fp->f_blk[level],
235 				(u_int *)&fp->f_blksize[level]);
236 			if (rc)
237 				return (rc);
238 			if (fp->f_blksize[level] != fs->fs_bsize)
239 				return (EIO);
240 			fp->f_blkno[level] = ind_block_num;
241 		}
242 
243 		ind_p = (daddr_t *)fp->f_blk[level];
244 
245 		if (level > 0) {
246 			idx = file_block / fp->f_nindir[level - 1];
247 			file_block %= fp->f_nindir[level - 1];
248 		} else
249 			idx = file_block;
250 
251 		ind_block_num = ind_p[idx];
252 	}
253 
254 	*disk_block_p = ind_block_num;
255 
256 	return (0);
257 }
258 
259 /*
260  * Read a portion of a file into an internal buffer.  Return
261  * the location in the buffer and the amount in the buffer.
262  */
263 static int
264 buf_read_file(f, buf_p, size_p)
265 	struct open_file *f;
266 	char **buf_p;		/* out */
267 	u_int *size_p;		/* out */
268 {
269 	register struct file *fp = (struct file *)f->f_fsdata;
270 	register struct fs *fs = fp->f_fs;
271 	long off;
272 	register daddr_t file_block;
273 	daddr_t	disk_block;
274 	long block_size;
275 	int rc;
276 
277 	off = blkoff(fs, fp->f_seekp);
278 	file_block = lblkno(fs, fp->f_seekp);
279 	block_size = dblksize(fs, &fp->f_di, file_block);
280 
281 	if (file_block != fp->f_buf_blkno) {
282 		rc = block_map(f, file_block, &disk_block);
283 		if (rc)
284 			return (rc);
285 
286 		if (fp->f_buf == (char *)0)
287 			fp->f_buf = alloc(fs->fs_bsize);
288 
289 		if (disk_block == 0) {
290 			bzero(fp->f_buf, block_size);
291 			fp->f_buf_size = block_size;
292 		} else {
293 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
294 				fsbtodb(fs, disk_block),
295 				block_size, fp->f_buf, &fp->f_buf_size);
296 			if (rc)
297 				return (rc);
298 		}
299 
300 		fp->f_buf_blkno = file_block;
301 	}
302 
303 	/*
304 	 * Return address of byte in buffer corresponding to
305 	 * offset, and size of remainder of buffer after that
306 	 * byte.
307 	 */
308 	*buf_p = fp->f_buf + off;
309 	*size_p = block_size - off;
310 
311 	/*
312 	 * But truncate buffer at end of file.
313 	 */
314 	if (*size_p > fp->f_di.di_size - fp->f_seekp)
315 		*size_p = fp->f_di.di_size - fp->f_seekp;
316 
317 	return (0);
318 }
319 
320 /*
321  * Search a directory for a name and return its
322  * i_number.
323  */
324 static int
325 search_directory(name, f, inumber_p)
326 	char *name;
327 	struct open_file *f;
328 	ino_t *inumber_p;		/* out */
329 {
330 	register struct file *fp = (struct file *)f->f_fsdata;
331 	register struct direct *dp;
332 	struct direct *edp;
333 	char *buf;
334 	u_int buf_size;
335 	int namlen, length;
336 	int rc;
337 
338 	length = strlen(name);
339 
340 	fp->f_seekp = 0;
341 	while (fp->f_seekp < fp->f_di.di_size) {
342 		rc = buf_read_file(f, &buf, &buf_size);
343 		if (rc)
344 			return (rc);
345 
346 		dp = (struct direct *)buf;
347 		edp = (struct direct *)(buf + buf_size);
348 		while (dp < edp) {
349 			if (dp->d_ino == (ino_t)0)
350 				goto next;
351 #if BYTE_ORDER == LITTLE_ENDIAN
352 			if (fp->f_fs->fs_maxsymlinklen <= 0)
353 				namlen = dp->d_type;
354 			else
355 #endif
356 				namlen = dp->d_namlen;
357 			if (namlen == length &&
358 			    !strcmp(name, dp->d_name)) {
359 				/* found entry */
360 				*inumber_p = dp->d_ino;
361 				return (0);
362 			}
363 		next:
364 			dp = (struct direct *)((char *)dp + dp->d_reclen);
365 		}
366 		fp->f_seekp += buf_size;
367 	}
368 	return (ENOENT);
369 }
370 
371 /*
372  * Open a file.
373  */
374 int
375 ufs_open(path, f)
376 	char *path;
377 	struct open_file *f;
378 {
379 	register char *cp, *ncp;
380 	register int c;
381 	ino_t inumber, parent_inumber;
382 	struct file *fp;
383 	struct fs *fs;
384 	int rc;
385 	u_int buf_size;
386 #if 0
387 	int nlinks = 0;
388 	char namebuf[MAXPATHLEN+1];
389 #endif
390 
391 	/* allocate file system specific data structure */
392 	fp = alloc(sizeof(struct file));
393 	bzero(fp, sizeof(struct file));
394 	f->f_fsdata = (void *)fp;
395 
396 	/* allocate space and read super block */
397 	fs = alloc(SBSIZE);
398 	fp->f_fs = fs;
399 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
400 		SBLOCK, SBSIZE, (char *)fs, &buf_size);
401 	if (rc)
402 		goto out;
403 
404 	if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
405 	    fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
406 		rc = EINVAL;
407 		goto out;
408 	}
409 #ifdef COMPAT_UFS
410 	ffs_oldfscompat(fs);
411 #endif
412 
413 	/*
414 	 * Calculate indirect block levels.
415 	 */
416 	{
417 		register int mult;
418 		register int level;
419 
420 		mult = 1;
421 		for (level = 0; level < NIADDR; level++) {
422 			mult *= NINDIR(fs);
423 			fp->f_nindir[level] = mult;
424 		}
425 	}
426 
427 	inumber = ROOTINO;
428 	if ((rc = read_inode(inumber, f)) != 0)
429 		goto out;
430 
431 	cp = path;
432 	while (*cp) {
433 
434 		/*
435 		 * Remove extra separators
436 		 */
437 		while (*cp == '/')
438 			cp++;
439 		if (*cp == '\0')
440 			break;
441 
442 		/*
443 		 * Check that current node is a directory.
444 		 */
445 		if ((fp->f_di.di_mode & IFMT) != IFDIR) {
446 			rc = ENOTDIR;
447 			goto out;
448 		}
449 
450 		/*
451 		 * Get next component of path name.
452 		 */
453 		{
454 			register int len = 0;
455 
456 			ncp = cp;
457 			while ((c = *cp) != '\0' && c != '/') {
458 				if (++len > MAXNAMLEN) {
459 					rc = ENOENT;
460 					goto out;
461 				}
462 				cp++;
463 			}
464 			*cp = '\0';
465 		}
466 
467 		/*
468 		 * Look up component in current directory.
469 		 * Save directory inumber in case we find a
470 		 * symbolic link.
471 		 */
472 		parent_inumber = inumber;
473 		rc = search_directory(ncp, f, &inumber);
474 		*cp = c;
475 		if (rc)
476 			goto out;
477 
478 		/*
479 		 * Open next component.
480 		 */
481 		if ((rc = read_inode(inumber, f)) != 0)
482 			goto out;
483 
484 #if 0
485 		/*
486 		 * Check for symbolic link.
487 		 */
488 		if ((fp->i_mode & IFMT) == IFLNK) {
489 			int link_len = fp->f_di.di_size;
490 			int len;
491 
492 			len = strlen(cp) + 1;
493 
494 			if (fp->f_di.di_size >= MAXPATHLEN - 1 ||
495 			    ++nlinks > MAXSYMLINKS) {
496 				rc = ENOENT;
497 				goto out;
498 			}
499 
500 			strcpy(&namebuf[link_len], cp);
501 
502 			if ((fp->i_flags & IC_FASTLINK) != 0) {
503 				bcopy(fp->i_symlink, namebuf, (unsigned) link_len);
504 			} else {
505 				/*
506 				 * Read file for symbolic link
507 				 */
508 				char *buf;
509 				u_int buf_size;
510 				daddr_t	disk_block;
511 				register struct fs *fs = fp->f_fs;
512 
513 				(void) block_map(f, (daddr_t)0, &disk_block);
514 				rc = device_read(&fp->f_dev,
515 						 fsbtodb(fs, disk_block),
516 						 blksize(fs, fp, 0),
517 						 &buf, &buf_size);
518 				if (rc)
519 					goto out;
520 
521 				bcopy((char *)buf, namebuf, (unsigned)link_len);
522 				free(buf, buf_size);
523 			}
524 
525 			/*
526 			 * If relative pathname, restart at parent directory.
527 			 * If absolute pathname, restart at root.
528 			 */
529 			cp = namebuf;
530 			if (*cp != '/')
531 				inumber = parent_inumber;
532 			else
533 				inumber = (ino_t)ROOTINO;
534 
535 			if ((rc = read_inode(inumber, fp)) != 0)
536 				goto out;
537 		}
538 #endif
539 	}
540 
541 	/*
542 	 * Found terminal component.
543 	 */
544 	rc = 0;
545 out:
546 	if (rc)
547 		free(fp, sizeof(struct file));
548 	return (rc);
549 }
550 
551 int
552 ufs_close(f)
553 	struct open_file *f;
554 {
555 	register struct file *fp = (struct file *)f->f_fsdata;
556 	int level;
557 
558 	f->f_fsdata = (void *)0;
559 	if (fp == (struct file *)0)
560 		return (0);
561 
562 	for (level = 0; level < NIADDR; level++) {
563 		if (fp->f_blk[level])
564 			free(fp->f_blk[level], fp->f_fs->fs_bsize);
565 	}
566 	if (fp->f_buf)
567 		free(fp->f_buf, fp->f_fs->fs_bsize);
568 	free(fp->f_fs, SBSIZE);
569 	free(fp, sizeof(struct file));
570 	return (0);
571 }
572 
573 /*
574  * Copy a portion of a file into kernel memory.
575  * Cross block boundaries when necessary.
576  */
577 int
578 ufs_read(f, start, size, resid)
579 	struct open_file *f;
580 	char *start;
581 	u_int size;
582 	u_int *resid;	/* out */
583 {
584 	register struct file *fp = (struct file *)f->f_fsdata;
585 	register u_int csize;
586 	char *buf;
587 	u_int buf_size;
588 	int rc = 0;
589 
590 	while (size != 0) {
591 		if (fp->f_seekp >= fp->f_di.di_size)
592 			break;
593 
594 		rc = buf_read_file(f, &buf, &buf_size);
595 		if (rc)
596 			break;
597 
598 		csize = size;
599 		if (csize > buf_size)
600 			csize = buf_size;
601 
602 		bcopy(buf, start, csize);
603 
604 		fp->f_seekp += csize;
605 		start += csize;
606 		size -= csize;
607 	}
608 	if (resid)
609 		*resid = size;
610 	return (rc);
611 }
612 
613 /*
614  * Not implemented.
615  */
616 int
617 ufs_write(f, start, size, resid)
618 	struct open_file *f;
619 	char *start;
620 	u_int size;
621 	u_int *resid;	/* out */
622 {
623 
624 	return (EROFS);
625 }
626 
627 off_t
628 ufs_seek(f, offset, where)
629 	struct open_file *f;
630 	off_t offset;
631 	int where;
632 {
633 	register struct file *fp = (struct file *)f->f_fsdata;
634 
635 	switch (where) {
636 	case SEEK_SET:
637 		fp->f_seekp = offset;
638 		break;
639 	case SEEK_CUR:
640 		fp->f_seekp += offset;
641 		break;
642 	case SEEK_END:
643 		fp->f_seekp = fp->f_di.di_size - offset;
644 		break;
645 	default:
646 		return (-1);
647 	}
648 	return (fp->f_seekp);
649 }
650 
651 int
652 ufs_stat(f, sb)
653 	struct open_file *f;
654 	struct stat *sb;
655 {
656 	register struct file *fp = (struct file *)f->f_fsdata;
657 
658 	/* only important stuff */
659 	sb->st_mode = fp->f_di.di_mode;
660 	sb->st_uid = fp->f_di.di_uid;
661 	sb->st_gid = fp->f_di.di_gid;
662 	sb->st_size = fp->f_di.di_size;
663 	return (0);
664 }
665 
666 #ifdef COMPAT_UFS
667 /*
668  * Sanity checks for old file systems.
669  *
670  * XXX - goes away some day.
671  */
672 void
673 ffs_oldfscompat(fs)
674 	struct fs *fs;
675 {
676 	int i;
677 
678 	fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);	/* XXX */
679 	fs->fs_interleave = max(fs->fs_interleave, 1);		/* XXX */
680 	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
681 		fs->fs_nrpos = 8;				/* XXX */
682 	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
683 		quad_t sizepb = fs->fs_bsize;			/* XXX */
684 								/* XXX */
685 		fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;	/* XXX */
686 		for (i = 0; i < NIADDR; i++) {			/* XXX */
687 			sizepb *= NINDIR(fs);			/* XXX */
688 			fs->fs_maxfilesize += sizepb;		/* XXX */
689 		}						/* XXX */
690 		fs->fs_qbmask = ~fs->fs_bmask;			/* XXX */
691 		fs->fs_qfmask = ~fs->fs_fmask;			/* XXX */
692 	}							/* XXX */
693 }
694 #endif
695