xref: /netbsd-src/sys/lib/libsa/ufs.c (revision dc43f412b020ec4f718c2c0d9551397b4171a6eb)
1 /*	$NetBSD: ufs.c,v 1.88 2022/12/01 18:06:09 christos 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 /* Do not (yet) support FFS_EI on LFS. */
104 #undef LIBSA_FFS_EI
105 /*
106  * In-core LFS superblock - just the on-disk one.
107  */
108 struct salfs {
109 	union {
110 		struct dlfs u_32;
111 		struct dlfs64 u_64;
112 	} lfs_dlfs_u;
113 	unsigned lfs_is64 : 1,
114 		lfs_dobyteswap : 1,
115 		lfs_hasolddirfmt : 1;
116 };
117 /* Get lfs accessors that use struct salfs. */
118 #define STRUCT_LFS struct salfs
119 #include <ufs/lfs/lfs_accessors.h>
120 
121 /* override this to avoid a mess with the dinode accessors */
122 #define lfs_dino_getsize(fs, dp) ((dp)->di_size)
123 
124 typedef struct salfs FS;
125 #define fs_magic	lfs_dlfs_u.u_32.dlfs_magic
126 #define fs_maxsymlinklen lfs_dlfs_u.u_32.dlfs_maxsymlinklen
127 #define lfs_version	lfs_dlfs_u.u_32.dlfs_version
128 
129 #define SBLOCKSIZE	LFS_SBPAD
130 #define SBLOCKOFFSET	LFS_LABELPAD
131 #else
132 /* NB ufs2 doesn't use the common superblock code... */
133 typedef struct fs FS;
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 #ifndef ufs_dinode_swap
169 #define ufs_dinode_swap ffs_dinode1_swap
170 #endif
171 #ifndef ufs_indp_swap
172 #define ufs_indp_swap bswap32
173 #endif
174 
175 /*
176  * To avoid having a lot of filesystem-block sized buffers lurking (which
177  * could be 32k) we only keep a few entries of the indirect block map.
178  * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block
179  * ~13 times pulling in a 6M kernel.
180  * The cache size must be smaller than the smallest filesystem block,
181  * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks).
182  */
183 #define LN2_IND_CACHE_SZ	6
184 #define IND_CACHE_SZ		(1 << LN2_IND_CACHE_SZ)
185 #define IND_CACHE_MASK		(IND_CACHE_SZ - 1)
186 
187 /*
188  * In-core open file.
189  */
190 struct file {
191 	off_t		f_seekp;	/* seek pointer */
192 	FS		*f_fs;		/* pointer to super-block */
193 	struct ufs_dinode	f_di;		/* copy of on-disk inode */
194 	uint		f_nishift;	/* for blocks in indirect block */
195 	indp_t		f_ind_cache_block;
196 	indp_t		f_ind_cache[IND_CACHE_SZ];
197 
198 	char		*f_buf;		/* buffer for data block */
199 	size_t		f_buf_size;	/* size of data block */
200 	daddr_t		f_buf_blkno;	/* block number of data block */
201 #if defined(LIBSA_FFS_EI)
202 	bool		f_swapped;	/* FFS is other endian */
203 #endif
204 };
205 
206 static int read_inode(ino32_t, struct open_file *);
207 static int block_map(struct open_file *, indp_t, indp_t *);
208 static int buf_read_file(struct open_file *, char **, size_t *);
209 static int search_directory(const char *, int, struct open_file *, ino32_t *);
210 #ifdef LIBSA_FFSv1
211 static void ffs_oldfscompat(FS *);
212 #endif
213 
214 #ifdef LIBSA_FFSv1
215 static __inline__ bool
ffs_is_magic(FS * fs)216 ffs_is_magic(FS *fs)
217 {
218 	return fs->fs_magic == FS_UFS1_MAGIC;
219 }
220 
221 #ifdef LIBSA_FFS_EI
222 static __inline__ bool
ffs_is_magic_swapped(FS * fs)223 ffs_is_magic_swapped(FS *fs)
224 {
225 	return fs->fs_magic == bswap32(FS_UFS1_MAGIC);
226 }
227 #endif
228 
229 #endif
230 
231 #ifdef LIBSA_FFSv2
232 static __inline__ bool
ffs_is_magic(FS * fs)233 ffs_is_magic(FS *fs)
234 {
235 	return fs->fs_magic == FS_UFS2_MAGIC || fs->fs_magic == FS_UFS2EA_MAGIC;
236 }
237 
238 #ifdef LIBSA_FFS_EI
239 static __inline__ bool
ffs_is_magic_swapped(FS * fs)240 ffs_is_magic_swapped(FS *fs)
241 {
242 	return fs->fs_magic == bswap32(FS_UFS2_MAGIC) ||
243 		fs->fs_magic == bswap32(FS_UFS2EA_MAGIC);
244 }
245 #endif
246 
247 #endif
248 
249 #ifdef LIBSA_LFS
250 static __inline__ bool
ffs_is_magic(FS * fs)251 ffs_is_magic(FS *fs)
252 {
253 	return fs->fs_magic == LFS_MAGIC;
254 }
255 
256 #ifdef LIBSA_FFS_EI
257 static __inline__ bool
ffs_is_magic_swapped(FS * fs)258 ffs_is_magic_swapped(FS *fs)
259 {
260 	return fs->fs_magic == bswap32(LFS_MAGIC);
261 }
262 #endif
263 
264 #endif
265 
266 static __inline__ void
ffs_fix_magic_swapped(struct file * fp,FS * fs)267 ffs_fix_magic_swapped(struct file *fp, FS *fs)
268 {
269 #ifdef LIBSA_FFS_EI
270 	fp->f_swapped = ffs_is_magic_swapped(fs);
271 	if (fp->f_swapped)
272 {
273 		ffs_sb_swap(fs, fs);
274 }
275 #endif
276 }
277 
278 #ifdef LIBSA_FFS_EI
279 static __inline__ bool
ffs_swapped(struct file * fp)280 ffs_swapped(struct file *fp)
281 {
282 	return fp->f_swapped;
283 }
284 #endif
285 
286 static __inline__ uint16_t
ffs_get_reclen(struct file * fp,struct direct * dp)287 ffs_get_reclen(struct file *fp, struct direct *dp)
288 {
289 #ifdef LIBSA_FFS_EI
290 	if (ffs_swapped(fp))
291 		return bswap16(dp->d_reclen);
292 #endif
293 	return dp->d_reclen;
294 }
295 
296 static __inline__ uint32_t
ffs_get_ino(struct file * fp,struct direct * dp)297 ffs_get_ino(struct file *fp, struct direct *dp)
298 {
299 #ifdef LIBSA_FFS_EI
300 	if (ffs_swapped(fp))
301 		return bswap32(dp->d_ino);
302 #endif
303 	return dp->d_ino;
304 }
305 
306 
307 #ifdef LIBSA_LFS
308 /*
309  * Find an inode's block.  Look it up in the ifile.  Whee!
310  */
311 static int
find_inode_sector(ino32_t inumber,struct open_file * f,daddr_t * isp)312 find_inode_sector(ino32_t inumber, struct open_file *f, daddr_t *isp)
313 {
314 	struct file *fp = (struct file *)f->f_fsdata;
315 	FS *fs = fp->f_fs;
316 	daddr_t ifileent_blkno;
317 	char *ent_in_buf;
318 	size_t buf_after_ent;
319 	size_t entsize;
320 	int rc;
321 
322 	rc = read_inode(LFS_IFILE_INUM, f);
323 	if (rc)
324 		return rc;
325 
326 	entsize = fs->lfs_is64 ? sizeof(IFILE64) :
327 		(lfs_sb_getversion(fs) > 1 ? sizeof(IFILE32) : sizeof(IFILE_V1));
328 	ifileent_blkno =
329 	    (inumber / lfs_sb_getifpb(fs)) + lfs_sb_getcleansz(fs) + lfs_sb_getsegtabsz(fs);
330 	fp->f_seekp = (off_t)ifileent_blkno * lfs_sb_getbsize(fs) +
331 	    (inumber % lfs_sb_getifpb(fs)) * entsize;
332 	rc = buf_read_file(f, &ent_in_buf, &buf_after_ent);
333 	if (rc)
334 		return rc;
335 	/* make sure something's not badly wrong, but don't panic. */
336 	if (buf_after_ent < entsize)
337 		return EINVAL;
338 
339 	*isp = FSBTODB(fs, lfs_if_getdaddr(fs, (IFILE *)ent_in_buf));
340 	if (*isp == LFS_UNUSED_DADDR)	/* again, something badly wrong */
341 		return EINVAL;
342 	return 0;
343 }
344 #endif
345 
346 /*
347  * Read a new inode into a file structure.
348  */
349 static int
read_inode(ino32_t inumber,struct open_file * f)350 read_inode(ino32_t inumber, struct open_file *f)
351 {
352 	struct file *fp = (struct file *)f->f_fsdata;
353 	FS *fs = fp->f_fs;
354 	char *buf;
355 	size_t rsize;
356 	int rc;
357 	daddr_t inode_sector = 0; /* XXX: gcc */
358 #ifdef LIBSA_LFS
359 	struct ufs_dinode *dip;
360 	int cnt;
361 #endif
362 
363 #ifdef LIBSA_LFS
364 	if (inumber == LFS_IFILE_INUM)
365 		inode_sector = FSBTODB(fs, lfs_sb_getidaddr(fs));
366 	else if ((rc = find_inode_sector(inumber, f, &inode_sector)) != 0)
367 		return rc;
368 #else
369 	inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
370 #endif
371 
372 	/*
373 	 * Read inode and save it.
374 	 */
375 	buf = fp->f_buf;
376 	twiddle();
377 	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
378 	    inode_sector, fs->fs_bsize, buf, &rsize);
379 	if (rc)
380 		return rc;
381 	if (rsize != (size_t)fs->fs_bsize)
382 		return EIO;
383 
384 #ifdef LIBSA_LFS
385 	cnt = INOPBx(fs);
386 	dip = (struct ufs_dinode *)buf + (cnt - 1);
387 	for (; dip->di_inumber != inumber; --dip) {
388 		/* kernel code panics, but boot blocks which panic are Bad. */
389 		if (--cnt == 0)
390 			return EINVAL;
391 	}
392 	fp->f_di = *dip;
393 #else
394 	fp->f_di = ((struct ufs_dinode *)buf)[ino_to_fsbo(fs, inumber)];
395 #ifdef LIBSA_FFS_EI
396 	if (ffs_swapped(fp))
397 		ufs_dinode_swap(&fp->f_di, &fp->f_di);
398 #endif
399 #endif
400 
401 	/*
402 	 * Clear out the old buffers
403 	 */
404 	fp->f_ind_cache_block = ~0;
405 	fp->f_buf_blkno = -1;
406 	return rc;
407 }
408 
409 /*
410  * Given an offset in a file, find the disk block number that
411  * contains that block.
412  */
413 static int
block_map(struct open_file * f,indp_t file_block,indp_t * disk_block_p)414 block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p)
415 {
416 	struct file *fp = (struct file *)f->f_fsdata;
417 	FS *fs = fp->f_fs;
418 	uint level;
419 	indp_t ind_cache;
420 	indp_t ind_block_num;
421 	size_t rsize;
422 	int rc;
423 	indp_t *buf = (void *)fp->f_buf;
424 
425 	/*
426 	 * Index structure of an inode:
427 	 *
428 	 * di_db[0..UFS_NDADDR-1]	hold block numbers for blocks
429 	 *			0..UFS_NDADDR-1
430 	 *
431 	 * di_ib[0]		index block 0 is the single indirect block
432 	 *			holds block numbers for blocks
433 	 *			UFS_NDADDR .. UFS_NDADDR + UFS_NINDIR(fs)-1
434 	 *
435 	 * di_ib[1]		index block 1 is the double indirect block
436 	 *			holds block numbers for INDEX blocks for blocks
437 	 *			UFS_NDADDR + UFS_NINDIR(fs) ..
438 	 *			UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 - 1
439 	 *
440 	 * di_ib[2]		index block 2 is the triple indirect block
441 	 *			holds block numbers for double-indirect
442 	 *			blocks for blocks
443 	 *			UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 ..
444 	 *			UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2
445 	 *				+ UFS_NINDIR(fs)**3 - 1
446 	 */
447 
448 	if (file_block < UFS_NDADDR) {
449 		/* Direct block. */
450 		*disk_block_p = fp->f_di.di_db[file_block];
451 		return 0;
452 	}
453 
454 	file_block -= UFS_NDADDR;
455 
456 	ind_cache = file_block >> LN2_IND_CACHE_SZ;
457 	if (ind_cache == fp->f_ind_cache_block) {
458 		*disk_block_p = fp->f_ind_cache[file_block & IND_CACHE_MASK];
459 		return 0;
460 	}
461 
462 	for (level = 0;;) {
463 		level += fp->f_nishift;
464 		if (file_block < (indp_t)1 << level)
465 			break;
466 		if (level > UFS_NIADDR * fp->f_nishift)
467 			/* Block number too high */
468 			return EFBIG;
469 		file_block -= (indp_t)1 << level;
470 	}
471 
472 	ind_block_num = fp->f_di.di_ib[level / fp->f_nishift - 1];
473 
474 	for (;;) {
475 		level -= fp->f_nishift;
476 		if (ind_block_num == 0) {
477 			*disk_block_p = 0;	/* missing */
478 			return 0;
479 		}
480 
481 		twiddle();
482 		/*
483 		 * If we were feeling brave, we could work out the number
484 		 * of the disk sector and read a single disk sector instead
485 		 * of a filesystem block.
486 		 * However we don't do this very often anyway...
487 		 */
488 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
489 			FSBTODB(fp->f_fs, ind_block_num), fs->fs_bsize,
490 			buf, &rsize);
491 		if (rc)
492 			return rc;
493 		if (rsize != (size_t)fs->fs_bsize)
494 			return EIO;
495 #ifdef LIBSA_FFS_EI
496 		if (ffs_swapped(fp))
497 			ind_block_num = ufs_indp_swap(buf[file_block >> level]);
498 		else
499 #endif
500 			ind_block_num = buf[file_block >> level];
501 		if (level == 0)
502 			break;
503 		file_block &= (1 << level) - 1;
504 	}
505 
506 	/* Save the part of the block that contains this sector */
507 #if defined(LIBSA_FFS_EI)
508 	if (ffs_swapped(fp)) {
509 		size_t i;
510 
511 		for (i = 0; i < IND_CACHE_SZ; i++) {
512 			fp->f_ind_cache[i] = ufs_indp_swap(
513 			    buf[(file_block & ~IND_CACHE_MASK) + i]);
514 		}
515 	} else
516 #endif
517 		memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK],
518 		    IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
519 	fp->f_ind_cache_block = ind_cache;
520 
521 	*disk_block_p = ind_block_num;
522 
523 	return 0;
524 }
525 
526 /*
527  * Read a portion of a file into an internal buffer.
528  * Return the location in the buffer and the amount in the buffer.
529  */
530 static int
buf_read_file(struct open_file * f,char ** buf_p,size_t * size_p)531 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
532 {
533 	struct file *fp = (struct file *)f->f_fsdata;
534 	FS *fs = fp->f_fs;
535 	long off;
536 	indp_t file_block;
537 	size_t block_size;
538 	int rc;
539 
540 	off = ufs_blkoff(fs, fp->f_seekp);
541 	file_block = ufs_lblkno(fs, fp->f_seekp);
542 #ifdef LIBSA_LFS
543 	block_size = (size_t)dblksize(fs, &fp->f_di, (uint64_t)file_block);
544 #else
545 	block_size = (size_t)ffs_sblksize(fs, (int64_t)fp->f_di.di_size, file_block);
546 #endif
547 
548 	if (file_block != fp->f_buf_blkno) {
549 		indp_t disk_block = 0; /* XXX: gcc */
550 		rc = block_map(f, file_block, &disk_block);
551 		if (rc)
552 			return rc;
553 
554 		if (disk_block == 0) {
555 			memset(fp->f_buf, 0, block_size);
556 			fp->f_buf_size = block_size;
557 		} else {
558 			twiddle();
559 			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
560 				FSBTODB(fs, disk_block),
561 				block_size, fp->f_buf, &fp->f_buf_size);
562 			if (rc)
563 				return rc;
564 		}
565 
566 		fp->f_buf_blkno = file_block;
567 	}
568 
569 	/*
570 	 * Return address of byte in buffer corresponding to
571 	 * offset, and size of remainder of buffer after that
572 	 * byte.
573 	 */
574 	*buf_p = fp->f_buf + off;
575 	*size_p = block_size - off;
576 
577 	/*
578 	 * But truncate buffer at end of file.
579 	 */
580 	if (*size_p > fp->f_di.di_size - fp->f_seekp)
581 		*size_p = fp->f_di.di_size - fp->f_seekp;
582 
583 	return 0;
584 }
585 
586 /*
587  * Search a directory for a name and return its
588  * inode number.
589  */
590 static int
search_directory(const char * name,int length,struct open_file * f,ino32_t * inumber_p)591 search_directory(const char *name, int length, struct open_file *f,
592 	ino32_t *inumber_p)
593 {
594 	struct file *fp = (struct file *)f->f_fsdata;
595 	struct direct *dp;
596 	struct direct *edp;
597 	char *buf;
598 	size_t buf_size;
599 	int namlen;
600 	int rc;
601 
602 	fp->f_seekp = 0;
603 	while (fp->f_seekp < (off_t)fp->f_di.di_size) {
604 		rc = buf_read_file(f, &buf, &buf_size);
605 		if (rc)
606 			return rc;
607 
608 		dp = (struct direct *)buf;
609 		edp = (struct direct *)(buf + buf_size);
610 		for (; dp < edp;
611 		     dp = (void *)((char *)dp + ffs_get_reclen(fp, dp))) {
612 			if (ffs_get_reclen(fp, dp) <= 0)
613 				break;
614 			if (ffs_get_ino(fp, dp) == (ino32_t)0)
615 				continue;
616 #if BYTE_ORDER == LITTLE_ENDIAN
617 			if (fp->f_fs->fs_maxsymlinklen <= 0)
618 				namlen = dp->d_type;
619 			else
620 #endif
621 				namlen = dp->d_namlen;
622 			if (namlen == length &&
623 			    !memcmp(name, dp->d_name, length)) {
624 				/* found entry */
625 				*inumber_p = ffs_get_ino(fp, dp);
626 				return 0;
627 			}
628 		}
629 		fp->f_seekp += buf_size;
630 	}
631 	return ENOENT;
632 }
633 
634 static __inline__ int
ffs_find_superblock(struct open_file * f,FS * fs)635 ffs_find_superblock(struct open_file *f, FS *fs)
636 {
637 	struct file *fp = (struct file *)f->f_fsdata;
638 	int rc;
639 	size_t buf_size;
640 #ifdef LIBSA_FFSv2
641 	static daddr_t sblock_try[] = SBLOCKSEARCH;
642 	int i;
643 #endif
644 
645 #ifdef LIBSA_FFSv2
646 	for (i = 0; sblock_try[i] != -1; i++) {
647 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
648 		    sblock_try[i] / GETSECSIZE(f), SBLOCKSIZE, fs, &buf_size);
649 		if (rc)
650 			return rc;
651 		if (buf_size != SBLOCKSIZE)
652 			return EINVAL;
653 		ffs_fix_magic_swapped(fp, fs);
654 		if (fs->fs_sblockloc != sblock_try[i])
655 			/* an alternate superblock - try again */
656 			continue;
657 		if (ffs_is_magic(fs))
658 			return 0;
659 	}
660 	return EINVAL;
661 #else /* LIBSA_FFSv2 */
662 	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
663 		SBLOCKOFFSET / GETSECSIZE(f), SBLOCKSIZE, fs, &buf_size);
664 	if (rc)
665 		return rc;
666 	if (buf_size != SBLOCKSIZE)
667 		return EINVAL;
668 	ffs_fix_magic_swapped(fp, fs);
669 
670 #ifdef LIBSA_LFS
671 	if (fs->lfs_version != REQUIRED_LFS_VERSION)
672 		return EINVAL;
673 #endif
674 	if (!ffs_is_magic(fs))
675 		return EINVAL;
676 
677 	return 0;
678 #endif /* !LIBSA_FFSv2 */
679 }
680 
681 /*
682  * Open a file.
683  */
684 __compactcall int
ufs_open(const char * path,struct open_file * f)685 ufs_open(const char *path, struct open_file *f)
686 {
687 #ifndef LIBSA_FS_SINGLECOMPONENT
688 	const char *cp, *ncp;
689 	int c;
690 #endif
691 	ino32_t inumber;
692 	struct file *fp;
693 	FS *fs;
694 	int rc;
695 #ifndef LIBSA_NO_FS_SYMLINK
696 	ino32_t parent_inumber;
697 	int nlinks = 0;
698 	char namebuf[MAXPATHLEN+1];
699 	char *buf;
700 #endif
701 
702 	/* allocate file system specific data structure */
703 	fp = alloc(sizeof(struct file));
704 	memset(fp, 0, sizeof(struct file));
705 	f->f_fsdata = (void *)fp;
706 
707 	/* allocate space and read super block */
708 	fs = alloc(SBLOCKSIZE);
709 	fp->f_fs = fs;
710 	twiddle();
711 
712 	rc = ffs_find_superblock(f, fs);
713 	if (rc)
714 		goto out;
715 
716 #if defined(LIBSA_LFS) && REQUIRED_LFS_VERSION == 2
717 	/*
718 	 * XXX	We should check the second superblock and use the eldest
719 	 *	of the two.  See comments near the top of lfs_mountfs()
720 	 *	in sys/ufs/lfs/lfs_vfsops.c.
721 	 *      This may need a LIBSA_LFS_SMALL check as well.
722 	 */
723 #endif
724 #if defined(LIBSA_LFS)
725 	fs->lfs_is64 = 0;
726 	fs->lfs_dobyteswap = 0;
727 	fs->lfs_hasolddirfmt = (fs->fs_maxsymlinklen <= 0);
728 #endif
729 #ifdef LIBSA_FFSv1
730 	ffs_oldfscompat(fs);
731 #endif
732 
733 	if (fs->fs_bsize > MAXBSIZE ||
734 	    (size_t)fs->fs_bsize < sizeof(FS)) {
735 		rc = EINVAL;
736 		goto out;
737 	}
738 
739 	/*
740 	 * Calculate indirect block levels.
741 	 */
742 	{
743 		indp_t mult;
744 		int ln2;
745 
746 		/*
747 		 * We note that the number of indirect blocks is always
748 		 * a power of 2.  This lets us use shifts and masks instead
749 		 * of divide and remainder and avoids pulling in the
750 		 * 64bit division routine into the boot code.
751 		 */
752 		mult = UFS_NINDIR(fs);
753 #ifdef DEBUG
754 		if (mult & (mult - 1)) {
755 			/* Hummm was't a power of 2 */
756 			rc = EINVAL;
757 			goto out;
758 		}
759 #endif
760 		for (ln2 = 0; mult != 1; ln2++)
761 			mult >>= 1;
762 
763 		fp->f_nishift = ln2;
764 	}
765 
766 	/* alloc a block sized buffer used for all fs transfers */
767 	fp->f_buf = alloc(fs->fs_bsize);
768 	inumber = UFS_ROOTINO;
769 	if ((rc = read_inode(inumber, f)) != 0)
770 		goto out;
771 
772 #ifndef LIBSA_FS_SINGLECOMPONENT
773 	cp = path;
774 	while (*cp) {
775 
776 		/*
777 		 * Remove extra separators
778 		 */
779 		while (*cp == '/')
780 			cp++;
781 		if (*cp == '\0')
782 			break;
783 
784 		/*
785 		 * Check that current node is a directory.
786 		 */
787 		if ((fp->f_di.di_mode & IFMT) != IFDIR) {
788 			rc = ENOTDIR;
789 			goto out;
790 		}
791 
792 		/*
793 		 * Get next component of path name.
794 		 */
795 		ncp = cp;
796 		while ((c = *cp) != '\0' && c != '/')
797 			cp++;
798 
799 		/*
800 		 * Look up component in current directory.
801 		 * Save directory inumber in case we find a
802 		 * symbolic link.
803 		 */
804 #ifndef LIBSA_NO_FS_SYMLINK
805 		parent_inumber = inumber;
806 #endif
807 		rc = search_directory(ncp, cp - ncp, f, &inumber);
808 		if (rc)
809 			goto out;
810 
811 		/*
812 		 * Open next component.
813 		 */
814 		if ((rc = read_inode(inumber, f)) != 0)
815 			goto out;
816 
817 #ifndef LIBSA_NO_FS_SYMLINK
818 		/*
819 		 * Check for symbolic link.
820 		 */
821 		if ((fp->f_di.di_mode & IFMT) == IFLNK) {
822 			int link_len = fp->f_di.di_size;
823 			int len;
824 
825 			len = strlen(cp);
826 
827 			if (link_len + len > MAXPATHLEN ||
828 			    ++nlinks > MAXSYMLINKS) {
829 				rc = ENOENT;
830 				goto out;
831 			}
832 
833 			memmove(&namebuf[link_len], cp, len + 1);
834 
835 			if (link_len < fs->fs_maxsymlinklen) {
836 				memcpy(namebuf, fp->f_di.di_db, link_len);
837 			} else {
838 				/*
839 				 * Read file for symbolic link
840 				 */
841 				size_t buf_size;
842 				indp_t	disk_block;
843 
844 				buf = fp->f_buf;
845 				rc = block_map(f, (indp_t)0, &disk_block);
846 				if (rc)
847 					goto out;
848 
849 				twiddle();
850 				rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
851 					F_READ, FSBTODB(fs, disk_block),
852 					fs->fs_bsize, buf, &buf_size);
853 				if (rc)
854 					goto out;
855 
856 				memcpy(namebuf, buf, link_len);
857 			}
858 
859 			/*
860 			 * If relative pathname, restart at parent directory.
861 			 * If absolute pathname, restart at root.
862 			 */
863 			cp = namebuf;
864 			if (*cp != '/')
865 				inumber = parent_inumber;
866 			else
867 				inumber = (ino32_t)UFS_ROOTINO;
868 
869 			if ((rc = read_inode(inumber, f)) != 0)
870 				goto out;
871 		}
872 #endif	/* !LIBSA_NO_FS_SYMLINK */
873 	}
874 
875 	/*
876 	 * Found terminal component.
877 	 */
878 	rc = 0;
879 
880 #else /* !LIBSA_FS_SINGLECOMPONENT */
881 
882 	/* look up component in the current (root) directory */
883 	rc = search_directory(path, strlen(path), f, &inumber);
884 	if (rc)
885 		goto out;
886 
887 	/* open it */
888 	rc = read_inode(inumber, f);
889 
890 #endif /* !LIBSA_FS_SINGLECOMPONENT */
891 
892 	fp->f_seekp = 0;		/* reset seek pointer */
893 
894 out:
895 	if (rc)
896 		ufs_close(f);
897 	else
898 #ifdef FSMOD
899 		fsmod = FSMOD;
900 #else
901 		fsmod = NULL;
902 #endif
903 	return rc;
904 }
905 
906 __compactcall int
ufs_close(struct open_file * f)907 ufs_close(struct open_file *f)
908 {
909 	struct file *fp = (struct file *)f->f_fsdata;
910 
911 	f->f_fsdata = NULL;
912 	if (fp == NULL)
913 		return 0;
914 
915 	if (fp->f_buf)
916 		dealloc(fp->f_buf, fp->f_fs->fs_bsize);
917 	dealloc(fp->f_fs, SBLOCKSIZE);
918 	dealloc(fp, sizeof(struct file));
919 	return 0;
920 }
921 
922 /*
923  * Copy a portion of a file into kernel memory.
924  * Cross block boundaries when necessary.
925  */
926 __compactcall int
ufs_read(struct open_file * f,void * start,size_t size,size_t * resid)927 ufs_read(struct open_file *f, void *start, size_t size, size_t *resid)
928 {
929 	struct file *fp = (struct file *)f->f_fsdata;
930 	size_t csize;
931 	char *buf;
932 	size_t buf_size;
933 	int rc = 0;
934 	char *addr = start;
935 
936 	while (size != 0) {
937 		if (fp->f_seekp >= (off_t)fp->f_di.di_size)
938 			break;
939 
940 		rc = buf_read_file(f, &buf, &buf_size);
941 		if (rc)
942 			break;
943 
944 		csize = size;
945 		if (csize > buf_size)
946 			csize = buf_size;
947 
948 		memcpy(addr, buf, csize);
949 
950 		fp->f_seekp += csize;
951 		addr += csize;
952 		size -= csize;
953 	}
954 	if (resid)
955 		*resid = size;
956 	return rc;
957 }
958 
959 /*
960  * Not implemented.
961  */
962 #ifndef LIBSA_NO_FS_WRITE
963 __compactcall int
ufs_write(struct open_file * f,void * start,size_t size,size_t * resid)964 ufs_write(struct open_file *f, void *start, size_t size, size_t *resid)
965 {
966 
967 	return EROFS;
968 }
969 #endif /* !LIBSA_NO_FS_WRITE */
970 
971 #ifndef LIBSA_NO_FS_SEEK
972 __compactcall off_t
ufs_seek(struct open_file * f,off_t offset,int where)973 ufs_seek(struct open_file *f, off_t offset, int where)
974 {
975 	struct file *fp = (struct file *)f->f_fsdata;
976 
977 	switch (where) {
978 	case SEEK_SET:
979 		fp->f_seekp = offset;
980 		break;
981 	case SEEK_CUR:
982 		fp->f_seekp += offset;
983 		break;
984 	case SEEK_END:
985 		fp->f_seekp = fp->f_di.di_size - offset;
986 		break;
987 	default:
988 		return -1;
989 	}
990 	return fp->f_seekp;
991 }
992 #endif /* !LIBSA_NO_FS_SEEK */
993 
994 __compactcall int
ufs_stat(struct open_file * f,struct stat * sb)995 ufs_stat(struct open_file *f, struct stat *sb)
996 {
997 	struct file *fp = (struct file *)f->f_fsdata;
998 
999 	/* only important stuff */
1000 	memset(sb, 0, sizeof *sb);
1001 	sb->st_mode = fp->f_di.di_mode;
1002 	sb->st_uid = fp->f_di.di_uid;
1003 	sb->st_gid = fp->f_di.di_gid;
1004 	sb->st_size = fp->f_di.di_size;
1005 	return 0;
1006 }
1007 
1008 #if defined(LIBSA_ENABLE_LS_OP)
1009 
1010 #include "ls.h"
1011 
1012 static const char    *const typestr[] = {
1013 	"unknown",
1014 	"FIFO",
1015 	"CHR",
1016 	0,
1017 	"DIR",
1018 	0,
1019 	"BLK",
1020 	0,
1021 	"REG",
1022 	0,
1023 	"LNK",
1024 	0,
1025 	"SOCK",
1026 	0,
1027 	"WHT"
1028 };
1029 
1030 __compactcall void
ufs_ls(struct open_file * f,const char * pattern)1031 ufs_ls(struct open_file *f, const char *pattern)
1032 {
1033 	struct file *fp = (struct file *)f->f_fsdata;
1034 	char *buf;
1035 	size_t buf_size;
1036 	lsentry_t *names = NULL;
1037 
1038 	fp->f_seekp = 0;
1039 	while (fp->f_seekp < (off_t)fp->f_di.di_size) {
1040 		struct direct  *dp, *edp;
1041 		int rc = buf_read_file(f, &buf, &buf_size);
1042 		if (rc)
1043 			goto out;
1044 		/* some firmware might use block size larger than DEV_BSIZE */
1045 		if (buf_size < UFS_DIRBLKSIZ)
1046 			goto out;
1047 
1048 		dp = (struct direct *)buf;
1049 		edp = (struct direct *)(buf + buf_size);
1050 
1051 		for (; dp < edp;
1052 		     dp = (void *)((char *)dp + ffs_get_reclen(fp, dp))) {
1053 			const char *t;
1054 			if (ffs_get_ino(fp, dp) == 0)
1055 				continue;
1056 
1057 			if (dp->d_type >= NELEM(typestr) ||
1058 			    !(t = typestr[dp->d_type])) {
1059 				/*
1060 				 * This does not handle "old"
1061 				 * filesystems properly. On little
1062 				 * endian machines, we get a bogus
1063 				 * type name if the namlen matches a
1064 				 * valid type identifier. We could
1065 				 * check if we read namlen "0" and
1066 				 * handle this case specially, if
1067 				 * there were a pressing need...
1068 				 */
1069 				printf("bad dir entry\n");
1070 				goto out;
1071 			}
1072 			lsadd(&names, pattern, dp->d_name, strlen(dp->d_name),
1073 			    ffs_get_ino(fp, dp), t);
1074 		}
1075 		fp->f_seekp += buf_size;
1076 	}
1077 	lsprint(names);
1078 out:	lsfree(names);
1079 }
1080 #endif /* LIBSA_ENABLE_LS_OP */
1081 
1082 #ifdef LIBSA_FFSv1
1083 /*
1084  * Sanity checks for old file systems.
1085  *
1086  * XXX - goes away some day.
1087  * Stripped of stuff libsa doesn't need.....
1088  */
1089 static void
ffs_oldfscompat(FS * fs)1090 ffs_oldfscompat(FS *fs)
1091 {
1092 
1093 #ifdef COMPAT_UFS
1094 	/*
1095 	 * Newer Solaris versions have a slightly incompatible
1096 	 * superblock - so always calculate this values on the fly, which
1097 	 * is good enough for libsa purposes
1098 	 */
1099 	if (fs->fs_magic == FS_UFS1_MAGIC
1100 #ifndef COMPAT_SOLARIS_UFS
1101 	    && fs->fs_old_inodefmt < FS_44INODEFMT
1102 #endif
1103 	    ) {
1104 		fs->fs_qbmask = ~fs->fs_bmask;
1105 		fs->fs_qfmask = ~fs->fs_fmask;
1106 	}
1107 #endif
1108 }
1109 #endif
1110