xref: /netbsd-src/sys/lib/libsa/ufs.c (revision 9fb66d812c00ebfb445c0b47dea128f32aa6fe96)
1 /*	$NetBSD: ufs.c,v 1.78 2020/12/19 08:51:03 rin Exp $	*/
2 
3 /*-
4  * Copyright (c) 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * The Mach Operating System project at Carnegie-Mellon University.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *
35  * Copyright (c) 1990, 1991 Carnegie Mellon University
36  * All Rights Reserved.
37  *
38  * Author: David Golub
39  *
40  * Permission to use, copy, modify and distribute this software and its
41  * documentation is hereby granted, provided that both the copyright
42  * notice and this permission notice appear in all copies of the
43  * software, derivative works or modified versions, and any portions
44  * thereof, and that both notices appear in supporting documentation.
45  *
46  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
47  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
48  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
49  *
50  * Carnegie Mellon requests users of this software to return to
51  *
52  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
53  *  School of Computer Science
54  *  Carnegie Mellon University
55  *  Pittsburgh PA 15213-3890
56  *
57  * any improvements or extensions that they make and grant Carnegie the
58  * rights to redistribute these changes.
59  */
60 
61 /*
62  *	Stand-alone file reading package for UFS and LFS filesystems.
63  */
64 
65 #include <sys/param.h>
66 #include <sys/time.h>
67 #include <ufs/ufs/dinode.h>
68 #include <ufs/ufs/dir.h>
69 #ifdef LIBSA_LFS
70 #include <sys/queue.h>
71 #include <sys/condvar.h>
72 #include <sys/mount.h>			/* XXX for MNAMELEN */
73 #include <ufs/lfs/lfs.h>
74 #else
75 #include <ufs/ffs/fs.h>
76 #endif
77 #ifdef _STANDALONE
78 #include <lib/libkern/libkern.h>
79 #else
80 #include <string.h>
81 #endif
82 
83 #include "stand.h"
84 #ifdef LIBSA_LFS
85 #include "lfs.h"
86 #else
87 #include "ufs.h"
88 #endif
89 
90 /* If this file is compiled by itself, build ufs (aka ffsv1) support */
91 #if !defined(LIBSA_FFSv2) && !defined(LIBSA_LFS)
92 #define LIBSA_FFSv1
93 #endif
94 
95 #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK)
96 #define LIBSA_NO_FS_SYMLINK
97 #endif
98 #if defined(COMPAT_UFS) && defined(LIBSA_NO_COMPAT_UFS)
99 #undef COMPAT_UFS
100 #endif
101 
102 #ifdef LIBSA_LFS
103 /*
104  * In-core LFS superblock - just the on-disk one.
105  */
106 struct salfs {
107 	union {
108 		struct dlfs u_32;
109 		struct dlfs64 u_64;
110 	} lfs_dlfs_u;
111 	unsigned lfs_is64 : 1,
112 		lfs_dobyteswap : 1,
113 		lfs_hasolddirfmt : 1;
114 };
115 /* Get lfs accessors that use struct salfs. */
116 #define STRUCT_LFS struct salfs
117 #include <ufs/lfs/lfs_accessors.h>
118 
119 /* override this to avoid a mess with the dinode accessors */
120 #define lfs_dino_getsize(fs, dp) ((dp)->di_size)
121 
122 typedef struct salfs FS;
123 #define fs_magic	lfs_dlfs_u.u_32.dlfs_magic
124 #define fs_maxsymlinklen lfs_dlfs_u.u_32.dlfs_maxsymlinklen
125 #define lfs_version	lfs_dlfs_u.u_32.dlfs_version
126 
127 #define FS_MAGIC	LFS_MAGIC
128 #define SBLOCKSIZE	LFS_SBPAD
129 #define SBLOCKOFFSET	LFS_LABELPAD
130 #else
131 /* NB ufs2 doesn't use the common superblock code... */
132 typedef struct fs FS;
133 #define FS_MAGIC	FS_UFS1_MAGIC
134 #define SBLOCKOFFSET	SBLOCK_UFS1
135 #endif
136 
137 #if defined(LIBSA_NO_TWIDDLE)
138 #define twiddle()
139 #endif
140 
141 #undef cgstart
142 #if defined(LIBSA_FFSv2)
143 #define cgstart(fc, c) cgstart_ufs2((fs), (c))
144 #else
145 #define cgstart(fc, c) cgstart_ufs1((fs), (c))
146 #endif
147 
148 #ifndef ufs_dinode
149 #define ufs_dinode	ufs1_dinode
150 #endif
151 #ifndef indp_t
152 #define indp_t		int32_t
153 #endif
154 typedef uint32_t	ino32_t;
155 
156 #ifndef FSBTODB
157 #define FSBTODB(fs, indp) FFS_FSBTODB(fs, indp)
158 #endif
159 #ifndef UFS_NINDIR
160 #define UFS_NINDIR FFS_NINDIR
161 #endif
162 #ifndef ufs_blkoff
163 #define ufs_blkoff ffs_blkoff
164 #endif
165 #ifndef ufs_lblkno
166 #define ufs_lblkno ffs_lblkno
167 #endif
168 
169 /*
170  * To avoid having a lot of filesystem-block sized buffers lurking (which
171  * could be 32k) we only keep a few entries of the indirect block map.
172  * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block
173  * ~13 times pulling in a 6M kernel.
174  * The cache size must be smaller than the smallest filesystem block,
175  * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks).
176  */
177 #define LN2_IND_CACHE_SZ	6
178 #define IND_CACHE_SZ		(1 << LN2_IND_CACHE_SZ)
179 #define IND_CACHE_MASK		(IND_CACHE_SZ - 1)
180 
181 /*
182  * In-core open file.
183  */
184 struct file {
185 	off_t		f_seekp;	/* seek pointer */
186 	FS		*f_fs;		/* pointer to super-block */
187 	struct ufs_dinode	f_di;		/* copy of on-disk inode */
188 	uint		f_nishift;	/* for blocks in indirect block */
189 	indp_t		f_ind_cache_block;
190 	indp_t		f_ind_cache[IND_CACHE_SZ];
191 
192 	char		*f_buf;		/* buffer for data block */
193 	size_t		f_buf_size;	/* size of data block */
194 	daddr_t		f_buf_blkno;	/* block number of data block */
195 };
196 
197 static int read_inode(ino32_t, struct open_file *);
198 static int block_map(struct open_file *, indp_t, indp_t *);
199 static int buf_read_file(struct open_file *, char **, size_t *);
200 static int search_directory(const char *, int, struct open_file *, ino32_t *);
201 #ifdef LIBSA_FFSv1
202 static void ffs_oldfscompat(FS *);
203 #endif
204 #ifdef LIBSA_FFSv2
205 static int ffs_find_superblock(struct open_file *, FS *);
206 #endif
207 
208 
209 #ifdef LIBSA_LFS
210 /*
211  * Find an inode's block.  Look it up in the ifile.  Whee!
212  */
213 static int
214 find_inode_sector(ino32_t inumber, struct open_file *f, daddr_t *isp)
215 {
216 	struct file *fp = (struct file *)f->f_fsdata;
217 	FS *fs = fp->f_fs;
218 	daddr_t ifileent_blkno;
219 	char *ent_in_buf;
220 	size_t buf_after_ent;
221 	size_t entsize;
222 	int rc;
223 
224 	rc = read_inode(LFS_IFILE_INUM, f);
225 	if (rc)
226 		return rc;
227 
228 	entsize = fs->lfs_is64 ? sizeof(IFILE64) :
229 		(lfs_sb_getversion(fs) > 1 ? sizeof(IFILE32) : sizeof(IFILE_V1));
230 	ifileent_blkno =
231 	    (inumber / lfs_sb_getifpb(fs)) + lfs_sb_getcleansz(fs) + lfs_sb_getsegtabsz(fs);
232 	fp->f_seekp = (off_t)ifileent_blkno * lfs_sb_getbsize(fs) +
233 	    (inumber % lfs_sb_getifpb(fs)) * entsize;
234 	rc = buf_read_file(f, &ent_in_buf, &buf_after_ent);
235 	if (rc)
236 		return rc;
237 	/* make sure something's not badly wrong, but don't panic. */
238 	if (buf_after_ent < entsize)
239 		return EINVAL;
240 
241 	*isp = FSBTODB(fs, lfs_if_getdaddr(fs, (IFILE *)ent_in_buf));
242 	if (*isp == LFS_UNUSED_DADDR)	/* again, something badly wrong */
243 		return EINVAL;
244 	return 0;
245 }
246 #endif
247 
248 /*
249  * Read a new inode into a file structure.
250  */
251 static int
252 read_inode(ino32_t inumber, struct open_file *f)
253 {
254 	struct file *fp = (struct file *)f->f_fsdata;
255 	FS *fs = fp->f_fs;
256 	char *buf;
257 	size_t rsize;
258 	int rc;
259 	daddr_t inode_sector = 0; /* XXX: gcc */
260 #ifdef LIBSA_LFS
261 	struct ufs_dinode *dip;
262 	int cnt;
263 #endif
264 
265 #ifdef LIBSA_LFS
266 	if (inumber == LFS_IFILE_INUM)
267 		inode_sector = FSBTODB(fs, lfs_sb_getidaddr(fs));
268 	else if ((rc = find_inode_sector(inumber, f, &inode_sector)) != 0)
269 		return rc;
270 #else
271 	inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
272 #endif
273 
274 	/*
275 	 * Read inode and save it.
276 	 */
277 	buf = fp->f_buf;
278 	twiddle();
279 	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
280 	    inode_sector, fs->fs_bsize, buf, &rsize);
281 	if (rc)
282 		return rc;
283 	if (rsize != (size_t)fs->fs_bsize)
284 		return EIO;
285 
286 #ifdef LIBSA_LFS
287 	cnt = INOPBx(fs);
288 	dip = (struct ufs_dinode *)buf + (cnt - 1);
289 	for (; dip->di_inumber != inumber; --dip) {
290 		/* kernel code panics, but boot blocks which panic are Bad. */
291 		if (--cnt == 0)
292 			return EINVAL;
293 	}
294 	fp->f_di = *dip;
295 #else
296 	fp->f_di = ((struct ufs_dinode *)buf)[ino_to_fsbo(fs, inumber)];
297 #endif
298 
299 	/*
300 	 * Clear out the old buffers
301 	 */
302 	fp->f_ind_cache_block = ~0;
303 	fp->f_buf_blkno = -1;
304 	return rc;
305 }
306 
307 /*
308  * Given an offset in a file, find the disk block number that
309  * contains that block.
310  */
311 static int
312 block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p)
313 {
314 	struct file *fp = (struct file *)f->f_fsdata;
315 	FS *fs = fp->f_fs;
316 	uint level;
317 	indp_t ind_cache;
318 	indp_t ind_block_num;
319 	size_t rsize;
320 	int rc;
321 	indp_t *buf = (void *)fp->f_buf;
322 
323 	/*
324 	 * Index structure of an inode:
325 	 *
326 	 * di_db[0..UFS_NDADDR-1]	hold block numbers for blocks
327 	 *			0..UFS_NDADDR-1
328 	 *
329 	 * di_ib[0]		index block 0 is the single indirect block
330 	 *			holds block numbers for blocks
331 	 *			UFS_NDADDR .. UFS_NDADDR + UFS_NINDIR(fs)-1
332 	 *
333 	 * di_ib[1]		index block 1 is the double indirect block
334 	 *			holds block numbers for INDEX blocks for blocks
335 	 *			UFS_NDADDR + UFS_NINDIR(fs) ..
336 	 *			UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 - 1
337 	 *
338 	 * di_ib[2]		index block 2 is the triple indirect block
339 	 *			holds block numbers for double-indirect
340 	 *			blocks for blocks
341 	 *			UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 ..
342 	 *			UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2
343 	 *				+ UFS_NINDIR(fs)**3 - 1
344 	 */
345 
346 	if (file_block < UFS_NDADDR) {
347 		/* Direct block. */
348 		*disk_block_p = fp->f_di.di_db[file_block];
349 		return 0;
350 	}
351 
352 	file_block -= UFS_NDADDR;
353 
354 	ind_cache = file_block >> LN2_IND_CACHE_SZ;
355 	if (ind_cache == fp->f_ind_cache_block) {
356 		*disk_block_p = fp->f_ind_cache[file_block & IND_CACHE_MASK];
357 		return 0;
358 	}
359 
360 	for (level = 0;;) {
361 		level += fp->f_nishift;
362 		if (file_block < (indp_t)1 << level)
363 			break;
364 		if (level > UFS_NIADDR * fp->f_nishift)
365 			/* Block number too high */
366 			return EFBIG;
367 		file_block -= (indp_t)1 << level;
368 	}
369 
370 	ind_block_num = fp->f_di.di_ib[level / fp->f_nishift - 1];
371 
372 	for (;;) {
373 		level -= fp->f_nishift;
374 		if (ind_block_num == 0) {
375 			*disk_block_p = 0;	/* missing */
376 			return 0;
377 		}
378 
379 		twiddle();
380 		/*
381 		 * If we were feeling brave, we could work out the number
382 		 * of the disk sector and read a single disk sector instead
383 		 * of a filesystem block.
384 		 * However we don't do this very often anyway...
385 		 */
386 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
387 			FSBTODB(fp->f_fs, ind_block_num), fs->fs_bsize,
388 			buf, &rsize);
389 		if (rc)
390 			return rc;
391 		if (rsize != (size_t)fs->fs_bsize)
392 			return EIO;
393 		ind_block_num = buf[file_block >> level];
394 		if (level == 0)
395 			break;
396 		file_block &= (1 << level) - 1;
397 	}
398 
399 	/* Save the part of the block that contains this sector */
400 	memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK],
401 	    IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
402 	fp->f_ind_cache_block = ind_cache;
403 
404 	*disk_block_p = ind_block_num;
405 
406 	return 0;
407 }
408 
409 /*
410  * Read a portion of a file into an internal buffer.
411  * Return the location in the buffer and the amount in the buffer.
412  */
413 static int
414 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
415 {
416 	struct file *fp = (struct file *)f->f_fsdata;
417 	FS *fs = fp->f_fs;
418 	long off;
419 	indp_t file_block;
420 	size_t block_size;
421 	int rc;
422 
423 	off = ufs_blkoff(fs, fp->f_seekp);
424 	file_block = ufs_lblkno(fs, fp->f_seekp);
425 #ifdef LIBSA_LFS
426 	block_size = (size_t)dblksize(fs, &fp->f_di, (uint64_t)file_block);
427 #else
428 	block_size = (size_t)ffs_sblksize(fs, (int64_t)fp->f_di.di_size, file_block);
429 #endif
430 
431 	if (file_block != fp->f_buf_blkno) {
432 		indp_t disk_block = 0; /* XXX: gcc */
433 		rc = block_map(f, file_block, &disk_block);
434 		if (rc)
435 			return rc;
436 
437 		if (disk_block == 0) {
438 			memset(fp->f_buf, 0, block_size);
439 			fp->f_buf_size = block_size;
440 		} else {
441 			twiddle();
442 			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
443 				FSBTODB(fs, disk_block),
444 				block_size, fp->f_buf, &fp->f_buf_size);
445 			if (rc)
446 				return rc;
447 		}
448 
449 		fp->f_buf_blkno = file_block;
450 	}
451 
452 	/*
453 	 * Return address of byte in buffer corresponding to
454 	 * offset, and size of remainder of buffer after that
455 	 * byte.
456 	 */
457 	*buf_p = fp->f_buf + off;
458 	*size_p = block_size - off;
459 
460 	/*
461 	 * But truncate buffer at end of file.
462 	 */
463 	if (*size_p > fp->f_di.di_size - fp->f_seekp)
464 		*size_p = fp->f_di.di_size - fp->f_seekp;
465 
466 	return 0;
467 }
468 
469 /*
470  * Search a directory for a name and return its
471  * inode number.
472  */
473 static int
474 search_directory(const char *name, int length, struct open_file *f,
475 	ino32_t *inumber_p)
476 {
477 	struct file *fp = (struct file *)f->f_fsdata;
478 	struct direct *dp;
479 	struct direct *edp;
480 	char *buf;
481 	size_t buf_size;
482 	int namlen;
483 	int rc;
484 
485 	fp->f_seekp = 0;
486 	while (fp->f_seekp < (off_t)fp->f_di.di_size) {
487 		rc = buf_read_file(f, &buf, &buf_size);
488 		if (rc)
489 			return rc;
490 
491 		dp = (struct direct *)buf;
492 		edp = (struct direct *)(buf + buf_size);
493 		for (;dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) {
494 			if (dp->d_reclen <= 0)
495 				break;
496 			if (dp->d_ino == (ino32_t)0)
497 				continue;
498 #if BYTE_ORDER == LITTLE_ENDIAN
499 			if (fp->f_fs->fs_maxsymlinklen <= 0)
500 				namlen = dp->d_type;
501 			else
502 #endif
503 				namlen = dp->d_namlen;
504 			if (namlen == length &&
505 			    !memcmp(name, dp->d_name, length)) {
506 				/* found entry */
507 				*inumber_p = dp->d_ino;
508 				return 0;
509 			}
510 		}
511 		fp->f_seekp += buf_size;
512 	}
513 	return ENOENT;
514 }
515 
516 #ifdef LIBSA_FFSv2
517 
518 daddr_t sblock_try[] = SBLOCKSEARCH;
519 
520 static int
521 ffs_find_superblock(struct open_file *f, FS *fs)
522 {
523 	int i, rc;
524 	size_t buf_size;
525 
526 	for (i = 0; sblock_try[i] != -1; i++) {
527 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
528 		    sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size);
529 		if (rc != 0 || buf_size != SBLOCKSIZE)
530 			return rc;
531 		if (fs->fs_sblockloc != sblock_try[i])
532 			/* an alternate superblock - try again */
533 			continue;
534 		if (fs->fs_magic == FS_UFS2_MAGIC) {
535 			return 0;
536 		}
537 	}
538 	return EINVAL;
539 }
540 
541 #endif
542 
543 /*
544  * Open a file.
545  */
546 __compactcall int
547 ufs_open(const char *path, struct open_file *f)
548 {
549 #ifndef LIBSA_FS_SINGLECOMPONENT
550 	const char *cp, *ncp;
551 	int c;
552 #endif
553 	ino32_t inumber;
554 	struct file *fp;
555 	FS *fs;
556 	int rc;
557 #ifndef LIBSA_NO_FS_SYMLINK
558 	ino32_t parent_inumber;
559 	int nlinks = 0;
560 	char namebuf[MAXPATHLEN+1];
561 	char *buf;
562 #endif
563 
564 	/* allocate file system specific data structure */
565 	fp = alloc(sizeof(struct file));
566 	memset(fp, 0, sizeof(struct file));
567 	f->f_fsdata = (void *)fp;
568 
569 	/* allocate space and read super block */
570 	fs = alloc(SBLOCKSIZE);
571 	fp->f_fs = fs;
572 	twiddle();
573 
574 #ifdef LIBSA_FFSv2
575 	rc = ffs_find_superblock(f, fs);
576 	if (rc)
577 		goto out;
578 #else
579 	{
580 		size_t buf_size;
581 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
582 			SBLOCKOFFSET / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size);
583 		if (rc)
584 			goto out;
585 		if (buf_size != SBLOCKSIZE ||
586 #ifdef LIBSA_LFS
587 		    fs->lfs_version != REQUIRED_LFS_VERSION ||
588 #endif
589 		    fs->fs_magic != FS_MAGIC) {
590 			rc = EINVAL;
591 			goto out;
592 		}
593 	}
594 #if defined(LIBSA_LFS) && REQUIRED_LFS_VERSION == 2
595 	/*
596 	 * XXX	We should check the second superblock and use the eldest
597 	 *	of the two.  See comments near the top of lfs_mountfs()
598 	 *	in sys/ufs/lfs/lfs_vfsops.c.
599 	 *      This may need a LIBSA_LFS_SMALL check as well.
600 	 */
601 #endif
602 #if defined(LIBSA_LFS)
603 	fs->lfs_is64 = 0;
604 	fs->lfs_dobyteswap = 0;
605 	fs->lfs_hasolddirfmt = (fs->fs_maxsymlinklen <= 0);
606 #endif
607 #endif
608 
609 #ifdef LIBSA_FFSv1
610 	ffs_oldfscompat(fs);
611 #endif
612 
613 	if (fs->fs_bsize > MAXBSIZE ||
614 	    (size_t)fs->fs_bsize < sizeof(FS)) {
615 		rc = EINVAL;
616 		goto out;
617 	}
618 
619 	/*
620 	 * Calculate indirect block levels.
621 	 */
622 	{
623 		indp_t mult;
624 		int ln2;
625 
626 		/*
627 		 * We note that the number of indirect blocks is always
628 		 * a power of 2.  This lets us use shifts and masks instead
629 		 * of divide and remainder and avoinds pulling in the
630 		 * 64bit division routine into the boot code.
631 		 */
632 		mult = UFS_NINDIR(fs);
633 #ifdef DEBUG
634 		if (mult & (mult - 1)) {
635 			/* Hummm was't a power of 2 */
636 			rc = EINVAL;
637 			goto out;
638 		}
639 #endif
640 		for (ln2 = 0; mult != 1; ln2++)
641 			mult >>= 1;
642 
643 		fp->f_nishift = ln2;
644 	}
645 
646 	/* alloc a block sized buffer used for all fs transfers */
647 	fp->f_buf = alloc(fs->fs_bsize);
648 	inumber = UFS_ROOTINO;
649 	if ((rc = read_inode(inumber, f)) != 0)
650 		goto out;
651 
652 #ifndef LIBSA_FS_SINGLECOMPONENT
653 	cp = path;
654 	while (*cp) {
655 
656 		/*
657 		 * Remove extra separators
658 		 */
659 		while (*cp == '/')
660 			cp++;
661 		if (*cp == '\0')
662 			break;
663 
664 		/*
665 		 * Check that current node is a directory.
666 		 */
667 		if ((fp->f_di.di_mode & IFMT) != IFDIR) {
668 			rc = ENOTDIR;
669 			goto out;
670 		}
671 
672 		/*
673 		 * Get next component of path name.
674 		 */
675 		ncp = cp;
676 		while ((c = *cp) != '\0' && c != '/')
677 			cp++;
678 
679 		/*
680 		 * Look up component in current directory.
681 		 * Save directory inumber in case we find a
682 		 * symbolic link.
683 		 */
684 #ifndef LIBSA_NO_FS_SYMLINK
685 		parent_inumber = inumber;
686 #endif
687 		rc = search_directory(ncp, cp - ncp, f, &inumber);
688 		if (rc)
689 			goto out;
690 
691 		/*
692 		 * Open next component.
693 		 */
694 		if ((rc = read_inode(inumber, f)) != 0)
695 			goto out;
696 
697 #ifndef LIBSA_NO_FS_SYMLINK
698 		/*
699 		 * Check for symbolic link.
700 		 */
701 		if ((fp->f_di.di_mode & IFMT) == IFLNK) {
702 			int link_len = fp->f_di.di_size;
703 			int len;
704 
705 			len = strlen(cp);
706 
707 			if (link_len + len > MAXPATHLEN ||
708 			    ++nlinks > MAXSYMLINKS) {
709 				rc = ENOENT;
710 				goto out;
711 			}
712 
713 			memmove(&namebuf[link_len], cp, len + 1);
714 
715 			if (link_len < fs->fs_maxsymlinklen) {
716 				memcpy(namebuf, fp->f_di.di_db, link_len);
717 			} else {
718 				/*
719 				 * Read file for symbolic link
720 				 */
721 				size_t buf_size;
722 				indp_t	disk_block;
723 
724 				buf = fp->f_buf;
725 				rc = block_map(f, (indp_t)0, &disk_block);
726 				if (rc)
727 					goto out;
728 
729 				twiddle();
730 				rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
731 					F_READ, FSBTODB(fs, disk_block),
732 					fs->fs_bsize, buf, &buf_size);
733 				if (rc)
734 					goto out;
735 
736 				memcpy(namebuf, buf, link_len);
737 			}
738 
739 			/*
740 			 * If relative pathname, restart at parent directory.
741 			 * If absolute pathname, restart at root.
742 			 */
743 			cp = namebuf;
744 			if (*cp != '/')
745 				inumber = parent_inumber;
746 			else
747 				inumber = (ino32_t)UFS_ROOTINO;
748 
749 			if ((rc = read_inode(inumber, f)) != 0)
750 				goto out;
751 		}
752 #endif	/* !LIBSA_NO_FS_SYMLINK */
753 	}
754 
755 	/*
756 	 * Found terminal component.
757 	 */
758 	rc = 0;
759 
760 #else /* !LIBSA_FS_SINGLECOMPONENT */
761 
762 	/* look up component in the current (root) directory */
763 	rc = search_directory(path, strlen(path), f, &inumber);
764 	if (rc)
765 		goto out;
766 
767 	/* open it */
768 	rc = read_inode(inumber, f);
769 
770 #endif /* !LIBSA_FS_SINGLECOMPONENT */
771 
772 	fp->f_seekp = 0;		/* reset seek pointer */
773 
774 out:
775 	if (rc)
776 		ufs_close(f);
777 #ifdef FSMOD		/* Only defined for lfs */
778 	else
779 		fsmod = FSMOD;
780 #endif
781 	return rc;
782 }
783 
784 __compactcall int
785 ufs_close(struct open_file *f)
786 {
787 	struct file *fp = (struct file *)f->f_fsdata;
788 
789 	f->f_fsdata = NULL;
790 	if (fp == NULL)
791 		return 0;
792 
793 	if (fp->f_buf)
794 		dealloc(fp->f_buf, fp->f_fs->fs_bsize);
795 	dealloc(fp->f_fs, SBLOCKSIZE);
796 	dealloc(fp, sizeof(struct file));
797 	return 0;
798 }
799 
800 /*
801  * Copy a portion of a file into kernel memory.
802  * Cross block boundaries when necessary.
803  */
804 __compactcall int
805 ufs_read(struct open_file *f, void *start, size_t size, size_t *resid)
806 {
807 	struct file *fp = (struct file *)f->f_fsdata;
808 	size_t csize;
809 	char *buf;
810 	size_t buf_size;
811 	int rc = 0;
812 	char *addr = start;
813 
814 	while (size != 0) {
815 		if (fp->f_seekp >= (off_t)fp->f_di.di_size)
816 			break;
817 
818 		rc = buf_read_file(f, &buf, &buf_size);
819 		if (rc)
820 			break;
821 
822 		csize = size;
823 		if (csize > buf_size)
824 			csize = buf_size;
825 
826 		memcpy(addr, buf, csize);
827 
828 		fp->f_seekp += csize;
829 		addr += csize;
830 		size -= csize;
831 	}
832 	if (resid)
833 		*resid = size;
834 	return rc;
835 }
836 
837 /*
838  * Not implemented.
839  */
840 #ifndef LIBSA_NO_FS_WRITE
841 __compactcall int
842 ufs_write(struct open_file *f, void *start, size_t size, size_t *resid)
843 {
844 
845 	return EROFS;
846 }
847 #endif /* !LIBSA_NO_FS_WRITE */
848 
849 #ifndef LIBSA_NO_FS_SEEK
850 __compactcall off_t
851 ufs_seek(struct open_file *f, off_t offset, int where)
852 {
853 	struct file *fp = (struct file *)f->f_fsdata;
854 
855 	switch (where) {
856 	case SEEK_SET:
857 		fp->f_seekp = offset;
858 		break;
859 	case SEEK_CUR:
860 		fp->f_seekp += offset;
861 		break;
862 	case SEEK_END:
863 		fp->f_seekp = fp->f_di.di_size - offset;
864 		break;
865 	default:
866 		return -1;
867 	}
868 	return fp->f_seekp;
869 }
870 #endif /* !LIBSA_NO_FS_SEEK */
871 
872 __compactcall int
873 ufs_stat(struct open_file *f, struct stat *sb)
874 {
875 	struct file *fp = (struct file *)f->f_fsdata;
876 
877 	/* only important stuff */
878 	memset(sb, 0, sizeof *sb);
879 	sb->st_mode = fp->f_di.di_mode;
880 	sb->st_uid = fp->f_di.di_uid;
881 	sb->st_gid = fp->f_di.di_gid;
882 	sb->st_size = fp->f_di.di_size;
883 	return 0;
884 }
885 
886 #if defined(LIBSA_ENABLE_LS_OP)
887 
888 #include "ls.h"
889 
890 static const char    *const typestr[] = {
891 	"unknown",
892 	"FIFO",
893 	"CHR",
894 	0,
895 	"DIR",
896 	0,
897 	"BLK",
898 	0,
899 	"REG",
900 	0,
901 	"LNK",
902 	0,
903 	"SOCK",
904 	0,
905 	"WHT"
906 };
907 
908 __compactcall void
909 ufs_ls(struct open_file *f, const char *pattern)
910 {
911 	struct file *fp = (struct file *)f->f_fsdata;
912 	char *buf;
913 	size_t buf_size;
914 	lsentry_t *names = NULL;
915 
916 	fp->f_seekp = 0;
917 	while (fp->f_seekp < (off_t)fp->f_di.di_size) {
918 		struct direct  *dp, *edp;
919 		int rc = buf_read_file(f, &buf, &buf_size);
920 		if (rc)
921 			goto out;
922 		/* some firmware might use block size larger than DEV_BSIZE */
923 		if (buf_size < UFS_DIRBLKSIZ)
924 			goto out;
925 
926 		dp = (struct direct *)buf;
927 		edp = (struct direct *)(buf + buf_size);
928 
929 		for (; dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) {
930 			const char *t;
931 			if (dp->d_ino ==  0)
932 				continue;
933 
934 			if (dp->d_type >= NELEM(typestr) ||
935 			    !(t = typestr[dp->d_type])) {
936 				/*
937 				 * This does not handle "old"
938 				 * filesystems properly. On little
939 				 * endian machines, we get a bogus
940 				 * type name if the namlen matches a
941 				 * valid type identifier. We could
942 				 * check if we read namlen "0" and
943 				 * handle this case specially, if
944 				 * there were a pressing need...
945 				 */
946 				printf("bad dir entry\n");
947 				goto out;
948 			}
949 			lsadd(&names, pattern, dp->d_name, strlen(dp->d_name),
950 			    dp->d_ino, t);
951 		}
952 		fp->f_seekp += buf_size;
953 	}
954 	lsprint(names);
955 out:	lsfree(names);
956 }
957 #endif /* LIBSA_ENABLE_LS_OP */
958 
959 #ifdef LIBSA_FFSv1
960 /*
961  * Sanity checks for old file systems.
962  *
963  * XXX - goes away some day.
964  * Stripped of stuff libsa doesn't need.....
965  */
966 static void
967 ffs_oldfscompat(FS *fs)
968 {
969 
970 #ifdef COMPAT_UFS
971 	/*
972 	 * Newer Solaris versions have a slightly incompatible
973 	 * superblock - so always calculate this values on the fly, which
974 	 * is good enough for libsa purposes
975 	 */
976 	if (fs->fs_magic == FS_UFS1_MAGIC
977 #ifndef COMPAT_SOLARIS_UFS
978 	    && fs->fs_old_inodefmt < FS_44INODEFMT
979 #endif
980 	    ) {
981 		fs->fs_qbmask = ~fs->fs_bmask;
982 		fs->fs_qfmask = ~fs->fs_fmask;
983 	}
984 #endif
985 }
986 #endif
987