xref: /netbsd-src/sys/lib/libsa/ufs.c (revision ae1bfcddc410612bc8c58b807e1830becb69a24c)
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.1 1994/01/26 02:04:01 brezak Exp $
65  */
66 
67 /*
68  *	Stand-alone file reading package.
69  */
70 
71 #include <sys/param.h>
72 #include <sys/time.h>
73 #if 0	/* BSD44 */
74 #include <ufs/ffs/fs.h>
75 #include <ufs/ufs/dinode.h>
76 #include <ufs/ufs/dir.h>
77 #else
78 #include <ufs/fs.h>
79 #include <ufs/dinode.h>
80 #include <ufs/dir.h>
81 #endif
82 #include "stand.h"
83 
84 /*
85  * In-core open file.
86  */
87 struct file {
88 	off_t		f_seekp;	/* seek pointer */
89 	struct fs	*f_fs;		/* pointer to super-block */
90 	struct dinode	f_di;		/* copy of on-disk inode */
91 	int		f_nindir[NIADDR];
92 					/* number of blocks mapped by
93 					   indirect block at level i */
94 	char		*f_blk[NIADDR];	/* buffer for indirect block at
95 					   level i */
96 	u_long		f_blksize[NIADDR];
97 					/* size of buffer */
98 	daddr_t		f_blkno[NIADDR];/* disk address of block in buffer */
99 	char		*f_buf;		/* buffer for data block */
100 	u_int		f_buf_size;	/* size of data block */
101 	daddr_t		f_buf_blkno;	/* block number of data block */
102 };
103 
104 /*
105  * Read a new inode into a file structure.
106  */
107 static int
108 read_inode(inumber, f)
109 	ino_t inumber;
110 	struct open_file *f;
111 {
112 	register struct file *fp = (struct file *)f->f_fsdata;
113 	register struct fs *fs = fp->f_fs;
114 	char *buf;
115 	u_int rsize;
116 	int rc;
117 
118 	/*
119 	 * Read inode and save it.
120 	 */
121 	buf = alloc(fs->fs_bsize);
122 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
123 		fsbtodb(fs, itod(fs, inumber)), fs->fs_bsize, buf, &rsize);
124 	if (rc)
125 		goto out;
126 	if (rsize != fs->fs_bsize) {
127 		rc = EIO;
128 		goto out;
129 	}
130 
131 	{
132 		register struct dinode *dp;
133 
134 		dp = (struct dinode *)buf;
135 		fp->f_di = dp[itoo(fs, inumber)];
136 	}
137 
138 	/*
139 	 * Clear out the old buffers
140 	 */
141 	{
142 		register int level;
143 
144 		for (level = 0; level < NIADDR; level++)
145 			fp->f_blkno[level] = -1;
146 		fp->f_buf_blkno = -1;
147 	}
148 out:
149 	free(buf, fs->fs_bsize);
150 	return (0);
151 }
152 
153 /*
154  * Given an offset in a file, find the disk block number that
155  * contains that block.
156  */
157 static int
158 block_map(f, file_block, disk_block_p)
159 	struct open_file *f;
160 	daddr_t file_block;
161 	daddr_t *disk_block_p;	/* out */
162 {
163 	register struct file *fp = (struct file *)f->f_fsdata;
164 	register struct fs *fs = fp->f_fs;
165 	int level;
166 	int idx;
167 	daddr_t ind_block_num;
168 	daddr_t *ind_p;
169 	int rc;
170 
171 	/*
172 	 * Index structure of an inode:
173 	 *
174 	 * di_db[0..NDADDR-1]	hold block numbers for blocks
175 	 *			0..NDADDR-1
176 	 *
177 	 * di_ib[0]		index block 0 is the single indirect block
178 	 *			holds block numbers for blocks
179 	 *			NDADDR .. NDADDR + NINDIR(fs)-1
180 	 *
181 	 * di_ib[1]		index block 1 is the double indirect block
182 	 *			holds block numbers for INDEX blocks for blocks
183 	 *			NDADDR + NINDIR(fs) ..
184 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
185 	 *
186 	 * di_ib[2]		index block 2 is the triple indirect block
187 	 *			holds block numbers for double-indirect
188 	 *			blocks for blocks
189 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
190 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2
191 	 *				+ NINDIR(fs)**3 - 1
192 	 */
193 
194 	if (file_block < NDADDR) {
195 		/* Direct block. */
196 		*disk_block_p = fp->f_di.di_db[file_block];
197 		return (0);
198 	}
199 
200 	file_block -= NDADDR;
201 
202 	/*
203 	 * nindir[0] = NINDIR
204 	 * nindir[1] = NINDIR**2
205 	 * nindir[2] = NINDIR**3
206 	 *	etc
207 	 */
208 	for (level = 0; level < NIADDR; level++) {
209 		if (file_block < fp->f_nindir[level])
210 			break;
211 		file_block -= fp->f_nindir[level];
212 	}
213 	if (level == NIADDR) {
214 		/* Block number too high */
215 		return (EFBIG);
216 	}
217 
218 	ind_block_num = fp->f_di.di_ib[level];
219 
220 	for (; level >= 0; level--) {
221 		if (ind_block_num == 0) {
222 			*disk_block_p = 0;	/* missing */
223 			return (0);
224 		}
225 
226 		if (fp->f_blkno[level] != ind_block_num) {
227 			if (fp->f_blk[level] == (char *)0)
228 				fp->f_blk[level] =
229 					alloc(fs->fs_bsize);
230 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
231 				fsbtodb(fp->f_fs, ind_block_num),
232 				fs->fs_bsize,
233 				fp->f_blk[level],
234 				(u_int *)&fp->f_blksize[level]);
235 			if (rc)
236 				return (rc);
237 			if (fp->f_blksize[level] != fs->fs_bsize)
238 				return (EIO);
239 			fp->f_blkno[level] = ind_block_num;
240 		}
241 
242 		ind_p = (daddr_t *)fp->f_blk[level];
243 
244 		if (level > 0) {
245 			idx = file_block / fp->f_nindir[level - 1];
246 			file_block %= fp->f_nindir[level - 1];
247 		} else
248 			idx = file_block;
249 
250 		ind_block_num = ind_p[idx];
251 	}
252 
253 	*disk_block_p = ind_block_num;
254 
255 	return (0);
256 }
257 
258 /*
259  * Read a portion of a file into an internal buffer.  Return
260  * the location in the buffer and the amount in the buffer.
261  */
262 static int
263 buf_read_file(f, buf_p, size_p)
264 	struct open_file *f;
265 	char **buf_p;		/* out */
266 	u_int *size_p;		/* out */
267 {
268 	register struct file *fp = (struct file *)f->f_fsdata;
269 	register struct fs *fs = fp->f_fs;
270 	long off;
271 	register daddr_t file_block;
272 	daddr_t	disk_block;
273 	long block_size;
274 	int rc;
275 
276 	off = blkoff(fs, fp->f_seekp);
277 	file_block = lblkno(fs, fp->f_seekp);
278 	block_size = dblksize(fs, &fp->f_di, file_block);
279 
280 	if (file_block != fp->f_buf_blkno) {
281 		rc = block_map(f, file_block, &disk_block);
282 		if (rc)
283 			return (rc);
284 
285 		if (fp->f_buf == (char *)0)
286 			fp->f_buf = alloc(fs->fs_bsize);
287 
288 		if (disk_block == 0) {
289 			bzero(fp->f_buf, block_size);
290 			fp->f_buf_size = block_size;
291 		} else {
292 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
293 				fsbtodb(fs, disk_block),
294 				block_size, fp->f_buf, &fp->f_buf_size);
295 			if (rc)
296 				return (rc);
297 		}
298 
299 		fp->f_buf_blkno = file_block;
300 	}
301 
302 	/*
303 	 * Return address of byte in buffer corresponding to
304 	 * offset, and size of remainder of buffer after that
305 	 * byte.
306 	 */
307 	*buf_p = fp->f_buf + off;
308 	*size_p = block_size - off;
309 
310 	/*
311 	 * But truncate buffer at end of file.
312 	 */
313 	if (*size_p > fp->f_di.di_size - fp->f_seekp)
314 		*size_p = fp->f_di.di_size - fp->f_seekp;
315 
316 	return (0);
317 }
318 
319 /*
320  * Search a directory for a name and return its
321  * i_number.
322  */
323 static int
324 search_directory(name, f, inumber_p)
325 	char *name;
326 	struct open_file *f;
327 	ino_t *inumber_p;		/* out */
328 {
329 	register struct file *fp = (struct file *)f->f_fsdata;
330 	register struct direct *dp;
331 	struct direct *edp;
332 	char *buf;
333 	u_int buf_size;
334 	int namlen, length;
335 	int rc;
336 
337 	length = strlen(name);
338 
339 	fp->f_seekp = 0;
340 	while (fp->f_seekp < fp->f_di.di_size) {
341 		rc = buf_read_file(f, &buf, &buf_size);
342 		if (rc)
343 			return (rc);
344 
345 		dp = (struct direct *)buf;
346 		edp = (struct direct *)(buf + buf_size);
347 		while (dp < edp) {
348 			if (dp->d_ino == (ino_t)0)
349 				goto next;
350 #if 0
351 #if BYTE_ORDER == LITTLE_ENDIAN
352 			if (fp->f_fs->fs_maxsymlinklen <= 0)
353 				namlen = dp->d_type;
354 			else
355 #endif
356 #endif
357 				namlen = dp->d_namlen;
358 			if (namlen == length &&
359 			    !strcmp(name, dp->d_name)) {
360 				/* found entry */
361 				*inumber_p = dp->d_ino;
362 				return (0);
363 			}
364 		next:
365 			dp = (struct direct *)((char *)dp + dp->d_reclen);
366 		}
367 		fp->f_seekp += buf_size;
368 	}
369 	return (ENOENT);
370 }
371 
372 /*
373  * Open a file.
374  */
375 int
376 ufs_open(path, f)
377 	char *path;
378 	struct open_file *f;
379 {
380 	register char *cp, *ncp;
381 	register int c;
382 	ino_t inumber, parent_inumber;
383 	int nlinks = 0;
384 	struct file *fp;
385 	struct fs *fs;
386 	int rc;
387 	u_int buf_size;
388 #if 0
389 	char namebuf[MAXPATHLEN+1];
390 #endif
391 
392 	/* allocate file system specific data structure */
393 	fp = alloc(sizeof(struct file));
394 	bzero(fp, sizeof(struct file));
395 	f->f_fsdata = (void *)fp;
396 
397 	/* allocate space and read super block */
398 	fs = alloc(SBSIZE);
399 	fp->f_fs = fs;
400 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
401 		SBLOCK, SBSIZE, (char *)fs, &buf_size);
402 	if (rc)
403 		goto out;
404 
405 	if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
406 	    fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
407 		rc = EINVAL;
408 		goto out;
409 	}
410 
411 	/*
412 	 * Calculate indirect block levels.
413 	 */
414 	{
415 		register int mult;
416 		register int level;
417 
418 		mult = 1;
419 		for (level = 0; level < NIADDR; level++) {
420 			mult *= NINDIR(fs);
421 			fp->f_nindir[level] = mult;
422 		}
423 	}
424 
425 	inumber = ROOTINO;
426 	if ((rc = read_inode(inumber, f)) != 0)
427 		goto out;
428 
429 	cp = path;
430 	while (*cp) {
431 
432 		/*
433 		 * Remove extra separators
434 		 */
435 		while (*cp == '/')
436 			cp++;
437 		if (*cp == '\0')
438 			break;
439 
440 		/*
441 		 * Check that current node is a directory.
442 		 */
443 		if ((fp->f_di.di_mode & IFMT) != IFDIR) {
444 			rc = ENOTDIR;
445 			goto out;
446 		}
447 
448 		/*
449 		 * Get next component of path name.
450 		 */
451 		{
452 			register int len = 0;
453 
454 			ncp = cp;
455 			while ((c = *cp) != '\0' && c != '/') {
456 				if (++len > MAXNAMLEN) {
457 					rc = ENOENT;
458 					goto out;
459 				}
460 				cp++;
461 			}
462 			*cp = '\0';
463 		}
464 
465 		/*
466 		 * Look up component in current directory.
467 		 * Save directory inumber in case we find a
468 		 * symbolic link.
469 		 */
470 		parent_inumber = inumber;
471 		rc = search_directory(ncp, f, &inumber);
472 		*cp = c;
473 		if (rc)
474 			goto out;
475 
476 		/*
477 		 * Open next component.
478 		 */
479 		if ((rc = read_inode(inumber, f)) != 0)
480 			goto out;
481 
482 #if 0
483 		/*
484 		 * Check for symbolic link.
485 		 */
486 		if ((fp->i_mode & IFMT) == IFLNK) {
487 			int link_len = fp->f_di.di_size;
488 			int len;
489 
490 			len = strlen(cp) + 1;
491 
492 			if (fp->f_di.di_size >= MAXPATHLEN - 1 ||
493 			    ++nlinks > MAXSYMLINKS) {
494 				rc = ENOENT;
495 				goto out;
496 			}
497 
498 			strcpy(&namebuf[link_len], cp);
499 
500 			if ((fp->i_flags & IC_FASTLINK) != 0) {
501 				bcopy(fp->i_symlink, namebuf, (unsigned) link_len);
502 			} else {
503 				/*
504 				 * Read file for symbolic link
505 				 */
506 				char *buf;
507 				u_int buf_size;
508 				daddr_t	disk_block;
509 				register struct fs *fs = fp->f_fs;
510 
511 				(void) block_map(f, (daddr_t)0, &disk_block);
512 				rc = device_read(&fp->f_dev,
513 						 fsbtodb(fs, disk_block),
514 						 blksize(fs, fp, 0),
515 						 &buf, &buf_size);
516 				if (rc)
517 					goto out;
518 
519 				bcopy((char *)buf, namebuf, (unsigned)link_len);
520 				free(buf, buf_size);
521 			}
522 
523 			/*
524 			 * If relative pathname, restart at parent directory.
525 			 * If absolute pathname, restart at root.
526 			 */
527 			cp = namebuf;
528 			if (*cp != '/')
529 				inumber = parent_inumber;
530 			else
531 				inumber = (ino_t)ROOTINO;
532 
533 			if ((rc = read_inode(inumber, fp)) != 0)
534 				goto out;
535 		}
536 #endif
537 	}
538 
539 	/*
540 	 * Found terminal component.
541 	 */
542 	rc = 0;
543 out:
544 	if (rc)
545 		free(fp, sizeof(struct file));
546 	return (rc);
547 }
548 
549 int
550 ufs_close(f)
551 	struct open_file *f;
552 {
553 	register struct file *fp = (struct file *)f->f_fsdata;
554 	int level;
555 
556 	f->f_fsdata = (void *)0;
557 	if (fp == (struct file *)0)
558 		return (0);
559 
560 	for (level = 0; level < NIADDR; level++) {
561 		if (fp->f_blk[level])
562 			free(fp->f_blk[level], fp->f_fs->fs_bsize);
563 	}
564 	if (fp->f_buf)
565 		free(fp->f_buf, fp->f_fs->fs_bsize);
566 	free(fp->f_fs, SBSIZE);
567 	free(fp, sizeof(struct file));
568 	return (0);
569 }
570 
571 /*
572  * Copy a portion of a file into kernel memory.
573  * Cross block boundaries when necessary.
574  */
575 int
576 ufs_read(f, start, size, resid)
577 	struct open_file *f;
578 	char *start;
579 	u_int size;
580 	u_int *resid;	/* out */
581 {
582 	register struct file *fp = (struct file *)f->f_fsdata;
583 	register u_int csize;
584 	char *buf;
585 	u_int buf_size;
586 	int rc = 0;
587 
588 	while (size != 0) {
589 		if (fp->f_seekp >= fp->f_di.di_size)
590 			break;
591 
592 		rc = buf_read_file(f, &buf, &buf_size);
593 		if (rc)
594 			break;
595 
596 		csize = size;
597 		if (csize > buf_size)
598 			csize = buf_size;
599 
600 		bcopy(buf, start, csize);
601 
602 		fp->f_seekp += csize;
603 		start += csize;
604 		size -= csize;
605 	}
606 	if (resid)
607 		*resid = size;
608 	return (rc);
609 }
610 
611 /*
612  * Not implemented.
613  */
614 int
615 ufs_write(f, start, size, resid)
616 	struct open_file *f;
617 	char *start;
618 	u_int size;
619 	u_int *resid;	/* out */
620 {
621 
622 	return (EROFS);
623 }
624 
625 off_t
626 ufs_seek(f, offset, where)
627 	struct open_file *f;
628 	off_t offset;
629 	int where;
630 {
631 	register struct file *fp = (struct file *)f->f_fsdata;
632 
633 	switch (where) {
634 	case SEEK_SET:
635 		fp->f_seekp = offset;
636 		break;
637 	case SEEK_CUR:
638 		fp->f_seekp += offset;
639 		break;
640 	case SEEK_END:
641 		fp->f_seekp = fp->f_di.di_size - offset;
642 		break;
643 	default:
644 		return (-1);
645 	}
646 	return (fp->f_seekp);
647 }
648 
649 int
650 ufs_stat(f, sb)
651 	struct open_file *f;
652 	struct stat *sb;
653 {
654 	register struct file *fp = (struct file *)f->f_fsdata;
655 
656 	/* only important stuff */
657 	sb->st_mode = fp->f_di.di_mode;
658 	sb->st_uid = fp->f_di.di_uid;
659 	sb->st_gid = fp->f_di.di_gid;
660 	sb->st_size = fp->f_di.di_size;
661 	return (0);
662 }
663