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