1*0a6a1f1dSLionel Sambuc /* $NetBSD: ufs.c,v 1.74 2015/09/01 06:16:58 dholland Exp $ */
258a2b000SEvgeniy Ivanov
358a2b000SEvgeniy Ivanov /*-
458a2b000SEvgeniy Ivanov * Copyright (c) 1993
558a2b000SEvgeniy Ivanov * The Regents of the University of California. All rights reserved.
658a2b000SEvgeniy Ivanov *
758a2b000SEvgeniy Ivanov * This code is derived from software contributed to Berkeley by
858a2b000SEvgeniy Ivanov * The Mach Operating System project at Carnegie-Mellon University.
958a2b000SEvgeniy Ivanov *
1058a2b000SEvgeniy Ivanov * Redistribution and use in source and binary forms, with or without
1158a2b000SEvgeniy Ivanov * modification, are permitted provided that the following conditions
1258a2b000SEvgeniy Ivanov * are met:
1358a2b000SEvgeniy Ivanov * 1. Redistributions of source code must retain the above copyright
1458a2b000SEvgeniy Ivanov * notice, this list of conditions and the following disclaimer.
1558a2b000SEvgeniy Ivanov * 2. Redistributions in binary form must reproduce the above copyright
1658a2b000SEvgeniy Ivanov * notice, this list of conditions and the following disclaimer in the
1758a2b000SEvgeniy Ivanov * documentation and/or other materials provided with the distribution.
1858a2b000SEvgeniy Ivanov * 3. Neither the name of the University nor the names of its contributors
1958a2b000SEvgeniy Ivanov * may be used to endorse or promote products derived from this software
2058a2b000SEvgeniy Ivanov * without specific prior written permission.
2158a2b000SEvgeniy Ivanov *
2258a2b000SEvgeniy Ivanov * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2358a2b000SEvgeniy Ivanov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2458a2b000SEvgeniy Ivanov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2558a2b000SEvgeniy Ivanov * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2658a2b000SEvgeniy Ivanov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2758a2b000SEvgeniy Ivanov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2858a2b000SEvgeniy Ivanov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2958a2b000SEvgeniy Ivanov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3058a2b000SEvgeniy Ivanov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3158a2b000SEvgeniy Ivanov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3258a2b000SEvgeniy Ivanov * SUCH DAMAGE.
3358a2b000SEvgeniy Ivanov *
3458a2b000SEvgeniy Ivanov *
3558a2b000SEvgeniy Ivanov * Copyright (c) 1990, 1991 Carnegie Mellon University
3658a2b000SEvgeniy Ivanov * All Rights Reserved.
3758a2b000SEvgeniy Ivanov *
3858a2b000SEvgeniy Ivanov * Author: David Golub
3958a2b000SEvgeniy Ivanov *
4058a2b000SEvgeniy Ivanov * Permission to use, copy, modify and distribute this software and its
4158a2b000SEvgeniy Ivanov * documentation is hereby granted, provided that both the copyright
4258a2b000SEvgeniy Ivanov * notice and this permission notice appear in all copies of the
4358a2b000SEvgeniy Ivanov * software, derivative works or modified versions, and any portions
4458a2b000SEvgeniy Ivanov * thereof, and that both notices appear in supporting documentation.
4558a2b000SEvgeniy Ivanov *
4658a2b000SEvgeniy Ivanov * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
4758a2b000SEvgeniy Ivanov * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
4858a2b000SEvgeniy Ivanov * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
4958a2b000SEvgeniy Ivanov *
5058a2b000SEvgeniy Ivanov * Carnegie Mellon requests users of this software to return to
5158a2b000SEvgeniy Ivanov *
5258a2b000SEvgeniy Ivanov * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
5358a2b000SEvgeniy Ivanov * School of Computer Science
5458a2b000SEvgeniy Ivanov * Carnegie Mellon University
5558a2b000SEvgeniy Ivanov * Pittsburgh PA 15213-3890
5658a2b000SEvgeniy Ivanov *
5758a2b000SEvgeniy Ivanov * any improvements or extensions that they make and grant Carnegie the
5858a2b000SEvgeniy Ivanov * rights to redistribute these changes.
5958a2b000SEvgeniy Ivanov */
6058a2b000SEvgeniy Ivanov
6158a2b000SEvgeniy Ivanov /*
6258a2b000SEvgeniy Ivanov * Stand-alone file reading package for UFS and LFS filesystems.
6358a2b000SEvgeniy Ivanov */
6458a2b000SEvgeniy Ivanov
6558a2b000SEvgeniy Ivanov #include <sys/param.h>
6658a2b000SEvgeniy Ivanov #include <sys/time.h>
6758a2b000SEvgeniy Ivanov #include <ufs/ufs/dinode.h>
6858a2b000SEvgeniy Ivanov #include <ufs/ufs/dir.h>
6958a2b000SEvgeniy Ivanov #ifdef LIBSA_LFS
7058a2b000SEvgeniy Ivanov #include <sys/queue.h>
7158a2b000SEvgeniy Ivanov #include <sys/condvar.h>
7258a2b000SEvgeniy Ivanov #include <sys/mount.h> /* XXX for MNAMELEN */
7358a2b000SEvgeniy Ivanov #include <ufs/lfs/lfs.h>
7458a2b000SEvgeniy Ivanov #else
7558a2b000SEvgeniy Ivanov #include <ufs/ffs/fs.h>
7658a2b000SEvgeniy Ivanov #endif
7758a2b000SEvgeniy Ivanov #ifdef _STANDALONE
7858a2b000SEvgeniy Ivanov #include <lib/libkern/libkern.h>
7958a2b000SEvgeniy Ivanov #else
8058a2b000SEvgeniy Ivanov #include <string.h>
8158a2b000SEvgeniy Ivanov #endif
8258a2b000SEvgeniy Ivanov
8358a2b000SEvgeniy Ivanov #include "stand.h"
8458a2b000SEvgeniy Ivanov #ifdef LIBSA_LFS
8558a2b000SEvgeniy Ivanov #include "lfs.h"
8658a2b000SEvgeniy Ivanov #else
8758a2b000SEvgeniy Ivanov #include "ufs.h"
8858a2b000SEvgeniy Ivanov #endif
8958a2b000SEvgeniy Ivanov
9058a2b000SEvgeniy Ivanov /* If this file is compiled by itself, build ufs (aka ffsv1) support */
9158a2b000SEvgeniy Ivanov #if !defined(LIBSA_FFSv2) && !defined(LIBSA_LFS)
9258a2b000SEvgeniy Ivanov #define LIBSA_FFSv1
9358a2b000SEvgeniy Ivanov #endif
9458a2b000SEvgeniy Ivanov
9558a2b000SEvgeniy Ivanov #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK)
9658a2b000SEvgeniy Ivanov #define LIBSA_NO_FS_SYMLINK
9758a2b000SEvgeniy Ivanov #endif
9858a2b000SEvgeniy Ivanov #if defined(COMPAT_UFS) && defined(LIBSA_NO_COMPAT_UFS)
9958a2b000SEvgeniy Ivanov #undef COMPAT_UFS
10058a2b000SEvgeniy Ivanov #endif
10158a2b000SEvgeniy Ivanov
10258a2b000SEvgeniy Ivanov #ifdef LIBSA_LFS
10358a2b000SEvgeniy Ivanov /*
104*0a6a1f1dSLionel Sambuc * In-core LFS superblock - just the on-disk one.
10558a2b000SEvgeniy Ivanov */
106*0a6a1f1dSLionel Sambuc struct salfs {
107*0a6a1f1dSLionel Sambuc union {
108*0a6a1f1dSLionel Sambuc struct dlfs u_32;
109*0a6a1f1dSLionel Sambuc struct dlfs64 u_64;
110*0a6a1f1dSLionel Sambuc } lfs_dlfs_u;
111*0a6a1f1dSLionel Sambuc unsigned lfs_is64 : 1,
112*0a6a1f1dSLionel Sambuc lfs_dobyteswap : 1,
113*0a6a1f1dSLionel Sambuc lfs_hasolddirfmt : 1;
11458a2b000SEvgeniy Ivanov };
115*0a6a1f1dSLionel Sambuc /* Get lfs accessors that use struct salfs. */
116*0a6a1f1dSLionel Sambuc #define STRUCT_LFS struct salfs
117*0a6a1f1dSLionel Sambuc #include <ufs/lfs/lfs_accessors.h>
118*0a6a1f1dSLionel Sambuc
119*0a6a1f1dSLionel Sambuc /* override this to avoid a mess with the dinode accessors */
120*0a6a1f1dSLionel Sambuc #define lfs_dino_getsize(fs, dp) ((dp)->di_size)
121*0a6a1f1dSLionel Sambuc
122*0a6a1f1dSLionel Sambuc typedef struct salfs FS;
123*0a6a1f1dSLionel Sambuc #define fs_magic lfs_dlfs_u.u_32.dlfs_magic
124*0a6a1f1dSLionel Sambuc #define fs_maxsymlinklen lfs_dlfs_u.u_32.dlfs_maxsymlinklen
12558a2b000SEvgeniy Ivanov
12658a2b000SEvgeniy Ivanov #define FS_MAGIC LFS_MAGIC
12758a2b000SEvgeniy Ivanov #define SBLOCKSIZE LFS_SBPAD
12858a2b000SEvgeniy Ivanov #define SBLOCKOFFSET LFS_LABELPAD
12958a2b000SEvgeniy Ivanov #else
130*0a6a1f1dSLionel Sambuc /* NB ufs2 doesn't use the common superblock code... */
131*0a6a1f1dSLionel Sambuc typedef struct fs FS;
13258a2b000SEvgeniy Ivanov #define FS_MAGIC FS_UFS1_MAGIC
13358a2b000SEvgeniy Ivanov #define SBLOCKOFFSET SBLOCK_UFS1
13458a2b000SEvgeniy Ivanov #endif
13558a2b000SEvgeniy Ivanov
13658a2b000SEvgeniy Ivanov #if defined(LIBSA_NO_TWIDDLE)
13758a2b000SEvgeniy Ivanov #define twiddle()
13858a2b000SEvgeniy Ivanov #endif
13958a2b000SEvgeniy Ivanov
14058a2b000SEvgeniy Ivanov #undef cgstart
14158a2b000SEvgeniy Ivanov #if defined(LIBSA_FFSv2)
14258a2b000SEvgeniy Ivanov #define cgstart(fc, c) cgstart_ufs2((fs), (c))
14358a2b000SEvgeniy Ivanov #else
14458a2b000SEvgeniy Ivanov #define cgstart(fc, c) cgstart_ufs1((fs), (c))
14558a2b000SEvgeniy Ivanov #endif
14658a2b000SEvgeniy Ivanov
14758a2b000SEvgeniy Ivanov #ifndef ufs_dinode
14858a2b000SEvgeniy Ivanov #define ufs_dinode ufs1_dinode
14958a2b000SEvgeniy Ivanov #endif
15058a2b000SEvgeniy Ivanov #ifndef indp_t
15158a2b000SEvgeniy Ivanov #define indp_t int32_t
15258a2b000SEvgeniy Ivanov #endif
15358a2b000SEvgeniy Ivanov typedef uint32_t ino32_t;
15484d9c625SLionel Sambuc
15558a2b000SEvgeniy Ivanov #ifndef FSBTODB
15684d9c625SLionel Sambuc #define FSBTODB(fs, indp) FFS_FSBTODB(fs, indp)
15784d9c625SLionel Sambuc #endif
15884d9c625SLionel Sambuc #ifndef UFS_NINDIR
15984d9c625SLionel Sambuc #define UFS_NINDIR FFS_NINDIR
16084d9c625SLionel Sambuc #endif
16184d9c625SLionel Sambuc #ifndef ufs_blkoff
16284d9c625SLionel Sambuc #define ufs_blkoff ffs_blkoff
16384d9c625SLionel Sambuc #endif
16484d9c625SLionel Sambuc #ifndef ufs_lblkno
16584d9c625SLionel Sambuc #define ufs_lblkno ffs_lblkno
16658a2b000SEvgeniy Ivanov #endif
16758a2b000SEvgeniy Ivanov
16858a2b000SEvgeniy Ivanov /*
16958a2b000SEvgeniy Ivanov * To avoid having a lot of filesystem-block sized buffers lurking (which
17058a2b000SEvgeniy Ivanov * could be 32k) we only keep a few entries of the indirect block map.
17158a2b000SEvgeniy Ivanov * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block
17258a2b000SEvgeniy Ivanov * ~13 times pulling in a 6M kernel.
17358a2b000SEvgeniy Ivanov * The cache size must be smaller than the smallest filesystem block,
17458a2b000SEvgeniy Ivanov * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks).
17558a2b000SEvgeniy Ivanov */
17658a2b000SEvgeniy Ivanov #define LN2_IND_CACHE_SZ 6
17758a2b000SEvgeniy Ivanov #define IND_CACHE_SZ (1 << LN2_IND_CACHE_SZ)
17858a2b000SEvgeniy Ivanov #define IND_CACHE_MASK (IND_CACHE_SZ - 1)
17958a2b000SEvgeniy Ivanov
18058a2b000SEvgeniy Ivanov /*
18158a2b000SEvgeniy Ivanov * In-core open file.
18258a2b000SEvgeniy Ivanov */
18358a2b000SEvgeniy Ivanov struct file {
18458a2b000SEvgeniy Ivanov off_t f_seekp; /* seek pointer */
185*0a6a1f1dSLionel Sambuc FS *f_fs; /* pointer to super-block */
18658a2b000SEvgeniy Ivanov struct ufs_dinode f_di; /* copy of on-disk inode */
18758a2b000SEvgeniy Ivanov uint f_nishift; /* for blocks in indirect block */
18858a2b000SEvgeniy Ivanov indp_t f_ind_cache_block;
18958a2b000SEvgeniy Ivanov indp_t f_ind_cache[IND_CACHE_SZ];
19058a2b000SEvgeniy Ivanov
19158a2b000SEvgeniy Ivanov char *f_buf; /* buffer for data block */
19258a2b000SEvgeniy Ivanov size_t f_buf_size; /* size of data block */
19358a2b000SEvgeniy Ivanov daddr_t f_buf_blkno; /* block number of data block */
19458a2b000SEvgeniy Ivanov };
19558a2b000SEvgeniy Ivanov
19658a2b000SEvgeniy Ivanov static int read_inode(ino32_t, struct open_file *);
19758a2b000SEvgeniy Ivanov static int block_map(struct open_file *, indp_t, indp_t *);
19858a2b000SEvgeniy Ivanov static int buf_read_file(struct open_file *, char **, size_t *);
19958a2b000SEvgeniy Ivanov static int search_directory(const char *, int, struct open_file *, ino32_t *);
20058a2b000SEvgeniy Ivanov #ifdef LIBSA_FFSv1
201*0a6a1f1dSLionel Sambuc static void ffs_oldfscompat(FS *);
20258a2b000SEvgeniy Ivanov #endif
20358a2b000SEvgeniy Ivanov #ifdef LIBSA_FFSv2
204*0a6a1f1dSLionel Sambuc static int ffs_find_superblock(struct open_file *, FS *);
20558a2b000SEvgeniy Ivanov #endif
20658a2b000SEvgeniy Ivanov
20758a2b000SEvgeniy Ivanov
20858a2b000SEvgeniy Ivanov #ifdef LIBSA_LFS
20958a2b000SEvgeniy Ivanov /*
21058a2b000SEvgeniy Ivanov * Find an inode's block. Look it up in the ifile. Whee!
21158a2b000SEvgeniy Ivanov */
21258a2b000SEvgeniy Ivanov static int
find_inode_sector(ino32_t inumber,struct open_file * f,daddr_t * isp)21358a2b000SEvgeniy Ivanov find_inode_sector(ino32_t inumber, struct open_file *f, daddr_t *isp)
21458a2b000SEvgeniy Ivanov {
21558a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
216*0a6a1f1dSLionel Sambuc FS *fs = fp->f_fs;
21758a2b000SEvgeniy Ivanov daddr_t ifileent_blkno;
21858a2b000SEvgeniy Ivanov char *ent_in_buf;
21958a2b000SEvgeniy Ivanov size_t buf_after_ent;
220*0a6a1f1dSLionel Sambuc size_t entsize;
22158a2b000SEvgeniy Ivanov int rc;
22258a2b000SEvgeniy Ivanov
223*0a6a1f1dSLionel Sambuc rc = read_inode(LFS_IFILE_INUM, f);
22458a2b000SEvgeniy Ivanov if (rc)
22558a2b000SEvgeniy Ivanov return rc;
22658a2b000SEvgeniy Ivanov
227*0a6a1f1dSLionel Sambuc entsize = fs->lfs_is64 ? sizeof(IFILE64) :
228*0a6a1f1dSLionel Sambuc (lfs_sb_getversion(fs) > 1 ? sizeof(IFILE32) : sizeof(IFILE_V1));
22958a2b000SEvgeniy Ivanov ifileent_blkno =
230*0a6a1f1dSLionel Sambuc (inumber / lfs_sb_getifpb(fs)) + lfs_sb_getcleansz(fs) + lfs_sb_getsegtabsz(fs);
231*0a6a1f1dSLionel Sambuc fp->f_seekp = (off_t)ifileent_blkno * lfs_sb_getbsize(fs) +
232*0a6a1f1dSLionel Sambuc (inumber % lfs_sb_getifpb(fs)) * entsize;
23358a2b000SEvgeniy Ivanov rc = buf_read_file(f, &ent_in_buf, &buf_after_ent);
23458a2b000SEvgeniy Ivanov if (rc)
23558a2b000SEvgeniy Ivanov return rc;
23658a2b000SEvgeniy Ivanov /* make sure something's not badly wrong, but don't panic. */
237*0a6a1f1dSLionel Sambuc if (buf_after_ent < entsize)
23858a2b000SEvgeniy Ivanov return EINVAL;
23958a2b000SEvgeniy Ivanov
240*0a6a1f1dSLionel Sambuc *isp = FSBTODB(fs, lfs_if_getdaddr(fs, (IFILE *)ent_in_buf));
24158a2b000SEvgeniy Ivanov if (*isp == LFS_UNUSED_DADDR) /* again, something badly wrong */
24258a2b000SEvgeniy Ivanov return EINVAL;
24358a2b000SEvgeniy Ivanov return 0;
24458a2b000SEvgeniy Ivanov }
24558a2b000SEvgeniy Ivanov #endif
24658a2b000SEvgeniy Ivanov
24758a2b000SEvgeniy Ivanov /*
24858a2b000SEvgeniy Ivanov * Read a new inode into a file structure.
24958a2b000SEvgeniy Ivanov */
25058a2b000SEvgeniy Ivanov static int
read_inode(ino32_t inumber,struct open_file * f)25158a2b000SEvgeniy Ivanov read_inode(ino32_t inumber, struct open_file *f)
25258a2b000SEvgeniy Ivanov {
25358a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
254*0a6a1f1dSLionel Sambuc FS *fs = fp->f_fs;
25558a2b000SEvgeniy Ivanov char *buf;
25658a2b000SEvgeniy Ivanov size_t rsize;
25758a2b000SEvgeniy Ivanov int rc;
25884d9c625SLionel Sambuc daddr_t inode_sector = 0; /* XXX: gcc */
25958a2b000SEvgeniy Ivanov #ifdef LIBSA_LFS
26058a2b000SEvgeniy Ivanov struct ufs_dinode *dip;
26158a2b000SEvgeniy Ivanov int cnt;
26258a2b000SEvgeniy Ivanov #endif
26358a2b000SEvgeniy Ivanov
26458a2b000SEvgeniy Ivanov #ifdef LIBSA_LFS
265*0a6a1f1dSLionel Sambuc if (inumber == LFS_IFILE_INUM)
266*0a6a1f1dSLionel Sambuc inode_sector = FSBTODB(fs, lfs_sb_getidaddr(fs));
26758a2b000SEvgeniy Ivanov else if ((rc = find_inode_sector(inumber, f, &inode_sector)) != 0)
26858a2b000SEvgeniy Ivanov return rc;
26958a2b000SEvgeniy Ivanov #else
27058a2b000SEvgeniy Ivanov inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
27158a2b000SEvgeniy Ivanov #endif
27258a2b000SEvgeniy Ivanov
27358a2b000SEvgeniy Ivanov /*
27458a2b000SEvgeniy Ivanov * Read inode and save it.
27558a2b000SEvgeniy Ivanov */
27658a2b000SEvgeniy Ivanov buf = fp->f_buf;
27758a2b000SEvgeniy Ivanov twiddle();
27858a2b000SEvgeniy Ivanov rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
27958a2b000SEvgeniy Ivanov inode_sector, fs->fs_bsize, buf, &rsize);
28058a2b000SEvgeniy Ivanov if (rc)
28158a2b000SEvgeniy Ivanov return rc;
28258a2b000SEvgeniy Ivanov if (rsize != fs->fs_bsize)
28358a2b000SEvgeniy Ivanov return EIO;
28458a2b000SEvgeniy Ivanov
28558a2b000SEvgeniy Ivanov #ifdef LIBSA_LFS
28658a2b000SEvgeniy Ivanov cnt = INOPBx(fs);
28758a2b000SEvgeniy Ivanov dip = (struct ufs_dinode *)buf + (cnt - 1);
28858a2b000SEvgeniy Ivanov for (; dip->di_inumber != inumber; --dip) {
28958a2b000SEvgeniy Ivanov /* kernel code panics, but boot blocks which panic are Bad. */
29058a2b000SEvgeniy Ivanov if (--cnt == 0)
29158a2b000SEvgeniy Ivanov return EINVAL;
29258a2b000SEvgeniy Ivanov }
29358a2b000SEvgeniy Ivanov fp->f_di = *dip;
29458a2b000SEvgeniy Ivanov #else
29558a2b000SEvgeniy Ivanov fp->f_di = ((struct ufs_dinode *)buf)[ino_to_fsbo(fs, inumber)];
29658a2b000SEvgeniy Ivanov #endif
29758a2b000SEvgeniy Ivanov
29858a2b000SEvgeniy Ivanov /*
29958a2b000SEvgeniy Ivanov * Clear out the old buffers
30058a2b000SEvgeniy Ivanov */
30158a2b000SEvgeniy Ivanov fp->f_ind_cache_block = ~0;
30258a2b000SEvgeniy Ivanov fp->f_buf_blkno = -1;
30358a2b000SEvgeniy Ivanov return rc;
30458a2b000SEvgeniy Ivanov }
30558a2b000SEvgeniy Ivanov
30658a2b000SEvgeniy Ivanov /*
30758a2b000SEvgeniy Ivanov * Given an offset in a file, find the disk block number that
30858a2b000SEvgeniy Ivanov * contains that block.
30958a2b000SEvgeniy Ivanov */
31058a2b000SEvgeniy Ivanov static int
block_map(struct open_file * f,indp_t file_block,indp_t * disk_block_p)31158a2b000SEvgeniy Ivanov block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p)
31258a2b000SEvgeniy Ivanov {
31358a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
314*0a6a1f1dSLionel Sambuc FS *fs = fp->f_fs;
31558a2b000SEvgeniy Ivanov uint level;
31658a2b000SEvgeniy Ivanov indp_t ind_cache;
31758a2b000SEvgeniy Ivanov indp_t ind_block_num;
31858a2b000SEvgeniy Ivanov size_t rsize;
31958a2b000SEvgeniy Ivanov int rc;
32058a2b000SEvgeniy Ivanov indp_t *buf = (void *)fp->f_buf;
32158a2b000SEvgeniy Ivanov
32258a2b000SEvgeniy Ivanov /*
32358a2b000SEvgeniy Ivanov * Index structure of an inode:
32458a2b000SEvgeniy Ivanov *
32584d9c625SLionel Sambuc * di_db[0..UFS_NDADDR-1] hold block numbers for blocks
32684d9c625SLionel Sambuc * 0..UFS_NDADDR-1
32758a2b000SEvgeniy Ivanov *
32858a2b000SEvgeniy Ivanov * di_ib[0] index block 0 is the single indirect block
32958a2b000SEvgeniy Ivanov * holds block numbers for blocks
33084d9c625SLionel Sambuc * UFS_NDADDR .. UFS_NDADDR + UFS_NINDIR(fs)-1
33158a2b000SEvgeniy Ivanov *
33258a2b000SEvgeniy Ivanov * di_ib[1] index block 1 is the double indirect block
33358a2b000SEvgeniy Ivanov * holds block numbers for INDEX blocks for blocks
33484d9c625SLionel Sambuc * UFS_NDADDR + UFS_NINDIR(fs) ..
33584d9c625SLionel Sambuc * UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 - 1
33658a2b000SEvgeniy Ivanov *
33758a2b000SEvgeniy Ivanov * di_ib[2] index block 2 is the triple indirect block
33858a2b000SEvgeniy Ivanov * holds block numbers for double-indirect
33958a2b000SEvgeniy Ivanov * blocks for blocks
34084d9c625SLionel Sambuc * UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2 ..
34184d9c625SLionel Sambuc * UFS_NDADDR + UFS_NINDIR(fs) + UFS_NINDIR(fs)**2
34284d9c625SLionel Sambuc * + UFS_NINDIR(fs)**3 - 1
34358a2b000SEvgeniy Ivanov */
34458a2b000SEvgeniy Ivanov
34584d9c625SLionel Sambuc if (file_block < UFS_NDADDR) {
34658a2b000SEvgeniy Ivanov /* Direct block. */
34758a2b000SEvgeniy Ivanov *disk_block_p = fp->f_di.di_db[file_block];
34858a2b000SEvgeniy Ivanov return 0;
34958a2b000SEvgeniy Ivanov }
35058a2b000SEvgeniy Ivanov
35184d9c625SLionel Sambuc file_block -= UFS_NDADDR;
35258a2b000SEvgeniy Ivanov
35358a2b000SEvgeniy Ivanov ind_cache = file_block >> LN2_IND_CACHE_SZ;
35458a2b000SEvgeniy Ivanov if (ind_cache == fp->f_ind_cache_block) {
35558a2b000SEvgeniy Ivanov *disk_block_p = fp->f_ind_cache[file_block & IND_CACHE_MASK];
35658a2b000SEvgeniy Ivanov return 0;
35758a2b000SEvgeniy Ivanov }
35858a2b000SEvgeniy Ivanov
35958a2b000SEvgeniy Ivanov for (level = 0;;) {
36058a2b000SEvgeniy Ivanov level += fp->f_nishift;
36158a2b000SEvgeniy Ivanov if (file_block < (indp_t)1 << level)
36258a2b000SEvgeniy Ivanov break;
36384d9c625SLionel Sambuc if (level > UFS_NIADDR * fp->f_nishift)
36458a2b000SEvgeniy Ivanov /* Block number too high */
36558a2b000SEvgeniy Ivanov return EFBIG;
36658a2b000SEvgeniy Ivanov file_block -= (indp_t)1 << level;
36758a2b000SEvgeniy Ivanov }
36858a2b000SEvgeniy Ivanov
36958a2b000SEvgeniy Ivanov ind_block_num = fp->f_di.di_ib[level / fp->f_nishift - 1];
37058a2b000SEvgeniy Ivanov
37158a2b000SEvgeniy Ivanov for (;;) {
37258a2b000SEvgeniy Ivanov level -= fp->f_nishift;
37358a2b000SEvgeniy Ivanov if (ind_block_num == 0) {
37458a2b000SEvgeniy Ivanov *disk_block_p = 0; /* missing */
37558a2b000SEvgeniy Ivanov return 0;
37658a2b000SEvgeniy Ivanov }
37758a2b000SEvgeniy Ivanov
37858a2b000SEvgeniy Ivanov twiddle();
37958a2b000SEvgeniy Ivanov /*
38058a2b000SEvgeniy Ivanov * If we were feeling brave, we could work out the number
38158a2b000SEvgeniy Ivanov * of the disk sector and read a single disk sector instead
38258a2b000SEvgeniy Ivanov * of a filesystem block.
38358a2b000SEvgeniy Ivanov * However we don't do this very often anyway...
38458a2b000SEvgeniy Ivanov */
38558a2b000SEvgeniy Ivanov rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
38658a2b000SEvgeniy Ivanov FSBTODB(fp->f_fs, ind_block_num), fs->fs_bsize,
38758a2b000SEvgeniy Ivanov buf, &rsize);
38858a2b000SEvgeniy Ivanov if (rc)
38958a2b000SEvgeniy Ivanov return rc;
39058a2b000SEvgeniy Ivanov if (rsize != fs->fs_bsize)
39158a2b000SEvgeniy Ivanov return EIO;
39258a2b000SEvgeniy Ivanov ind_block_num = buf[file_block >> level];
39358a2b000SEvgeniy Ivanov if (level == 0)
39458a2b000SEvgeniy Ivanov break;
39558a2b000SEvgeniy Ivanov file_block &= (1 << level) - 1;
39658a2b000SEvgeniy Ivanov }
39758a2b000SEvgeniy Ivanov
39858a2b000SEvgeniy Ivanov /* Save the part of the block that contains this sector */
39958a2b000SEvgeniy Ivanov memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK],
40058a2b000SEvgeniy Ivanov IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
40158a2b000SEvgeniy Ivanov fp->f_ind_cache_block = ind_cache;
40258a2b000SEvgeniy Ivanov
40358a2b000SEvgeniy Ivanov *disk_block_p = ind_block_num;
40458a2b000SEvgeniy Ivanov
40558a2b000SEvgeniy Ivanov return 0;
40658a2b000SEvgeniy Ivanov }
40758a2b000SEvgeniy Ivanov
40858a2b000SEvgeniy Ivanov /*
40958a2b000SEvgeniy Ivanov * Read a portion of a file into an internal buffer.
41058a2b000SEvgeniy Ivanov * Return the location in the buffer and the amount in the buffer.
41158a2b000SEvgeniy Ivanov */
41258a2b000SEvgeniy Ivanov static int
buf_read_file(struct open_file * f,char ** buf_p,size_t * size_p)41358a2b000SEvgeniy Ivanov buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
41458a2b000SEvgeniy Ivanov {
41558a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
416*0a6a1f1dSLionel Sambuc FS *fs = fp->f_fs;
41758a2b000SEvgeniy Ivanov long off;
41858a2b000SEvgeniy Ivanov indp_t file_block;
41958a2b000SEvgeniy Ivanov size_t block_size;
42058a2b000SEvgeniy Ivanov int rc;
42158a2b000SEvgeniy Ivanov
42284d9c625SLionel Sambuc off = ufs_blkoff(fs, fp->f_seekp);
42384d9c625SLionel Sambuc file_block = ufs_lblkno(fs, fp->f_seekp);
42458a2b000SEvgeniy Ivanov #ifdef LIBSA_LFS
42558a2b000SEvgeniy Ivanov block_size = dblksize(fs, &fp->f_di, file_block);
42658a2b000SEvgeniy Ivanov #else
42784d9c625SLionel Sambuc block_size = ffs_sblksize(fs, (int64_t)fp->f_di.di_size, file_block);
42858a2b000SEvgeniy Ivanov #endif
42958a2b000SEvgeniy Ivanov
43058a2b000SEvgeniy Ivanov if (file_block != fp->f_buf_blkno) {
43184d9c625SLionel Sambuc indp_t disk_block = 0; /* XXX: gcc */
43258a2b000SEvgeniy Ivanov rc = block_map(f, file_block, &disk_block);
43358a2b000SEvgeniy Ivanov if (rc)
43458a2b000SEvgeniy Ivanov return rc;
43558a2b000SEvgeniy Ivanov
43658a2b000SEvgeniy Ivanov if (disk_block == 0) {
43758a2b000SEvgeniy Ivanov memset(fp->f_buf, 0, block_size);
43858a2b000SEvgeniy Ivanov fp->f_buf_size = block_size;
43958a2b000SEvgeniy Ivanov } else {
44058a2b000SEvgeniy Ivanov twiddle();
44158a2b000SEvgeniy Ivanov rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
44258a2b000SEvgeniy Ivanov FSBTODB(fs, disk_block),
44358a2b000SEvgeniy Ivanov block_size, fp->f_buf, &fp->f_buf_size);
44458a2b000SEvgeniy Ivanov if (rc)
44558a2b000SEvgeniy Ivanov return rc;
44658a2b000SEvgeniy Ivanov }
44758a2b000SEvgeniy Ivanov
44858a2b000SEvgeniy Ivanov fp->f_buf_blkno = file_block;
44958a2b000SEvgeniy Ivanov }
45058a2b000SEvgeniy Ivanov
45158a2b000SEvgeniy Ivanov /*
45258a2b000SEvgeniy Ivanov * Return address of byte in buffer corresponding to
45358a2b000SEvgeniy Ivanov * offset, and size of remainder of buffer after that
45458a2b000SEvgeniy Ivanov * byte.
45558a2b000SEvgeniy Ivanov */
45658a2b000SEvgeniy Ivanov *buf_p = fp->f_buf + off;
45758a2b000SEvgeniy Ivanov *size_p = block_size - off;
45858a2b000SEvgeniy Ivanov
45958a2b000SEvgeniy Ivanov /*
46058a2b000SEvgeniy Ivanov * But truncate buffer at end of file.
46158a2b000SEvgeniy Ivanov */
46258a2b000SEvgeniy Ivanov if (*size_p > fp->f_di.di_size - fp->f_seekp)
46358a2b000SEvgeniy Ivanov *size_p = fp->f_di.di_size - fp->f_seekp;
46458a2b000SEvgeniy Ivanov
46558a2b000SEvgeniy Ivanov return 0;
46658a2b000SEvgeniy Ivanov }
46758a2b000SEvgeniy Ivanov
46858a2b000SEvgeniy Ivanov /*
46958a2b000SEvgeniy Ivanov * Search a directory for a name and return its
47058a2b000SEvgeniy Ivanov * inode number.
47158a2b000SEvgeniy Ivanov */
47258a2b000SEvgeniy Ivanov static int
search_directory(const char * name,int length,struct open_file * f,ino32_t * inumber_p)47358a2b000SEvgeniy Ivanov search_directory(const char *name, int length, struct open_file *f,
47458a2b000SEvgeniy Ivanov ino32_t *inumber_p)
47558a2b000SEvgeniy Ivanov {
47658a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
47758a2b000SEvgeniy Ivanov struct direct *dp;
47858a2b000SEvgeniy Ivanov struct direct *edp;
47958a2b000SEvgeniy Ivanov char *buf;
48058a2b000SEvgeniy Ivanov size_t buf_size;
48158a2b000SEvgeniy Ivanov int namlen;
48258a2b000SEvgeniy Ivanov int rc;
48358a2b000SEvgeniy Ivanov
48458a2b000SEvgeniy Ivanov fp->f_seekp = 0;
48558a2b000SEvgeniy Ivanov while (fp->f_seekp < (off_t)fp->f_di.di_size) {
48658a2b000SEvgeniy Ivanov rc = buf_read_file(f, &buf, &buf_size);
48758a2b000SEvgeniy Ivanov if (rc)
48858a2b000SEvgeniy Ivanov return rc;
48958a2b000SEvgeniy Ivanov
49058a2b000SEvgeniy Ivanov dp = (struct direct *)buf;
49158a2b000SEvgeniy Ivanov edp = (struct direct *)(buf + buf_size);
49258a2b000SEvgeniy Ivanov for (;dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) {
49358a2b000SEvgeniy Ivanov if (dp->d_reclen <= 0)
49458a2b000SEvgeniy Ivanov break;
49558a2b000SEvgeniy Ivanov if (dp->d_ino == (ino32_t)0)
49658a2b000SEvgeniy Ivanov continue;
49758a2b000SEvgeniy Ivanov #if BYTE_ORDER == LITTLE_ENDIAN
49858a2b000SEvgeniy Ivanov if (fp->f_fs->fs_maxsymlinklen <= 0)
49958a2b000SEvgeniy Ivanov namlen = dp->d_type;
50058a2b000SEvgeniy Ivanov else
50158a2b000SEvgeniy Ivanov #endif
50258a2b000SEvgeniy Ivanov namlen = dp->d_namlen;
50358a2b000SEvgeniy Ivanov if (namlen == length &&
50458a2b000SEvgeniy Ivanov !memcmp(name, dp->d_name, length)) {
50558a2b000SEvgeniy Ivanov /* found entry */
50658a2b000SEvgeniy Ivanov *inumber_p = dp->d_ino;
50758a2b000SEvgeniy Ivanov return 0;
50858a2b000SEvgeniy Ivanov }
50958a2b000SEvgeniy Ivanov }
51058a2b000SEvgeniy Ivanov fp->f_seekp += buf_size;
51158a2b000SEvgeniy Ivanov }
51258a2b000SEvgeniy Ivanov return ENOENT;
51358a2b000SEvgeniy Ivanov }
51458a2b000SEvgeniy Ivanov
51558a2b000SEvgeniy Ivanov #ifdef LIBSA_FFSv2
51658a2b000SEvgeniy Ivanov
51758a2b000SEvgeniy Ivanov daddr_t sblock_try[] = SBLOCKSEARCH;
51858a2b000SEvgeniy Ivanov
51958a2b000SEvgeniy Ivanov static int
ffs_find_superblock(struct open_file * f,FS * fs)520*0a6a1f1dSLionel Sambuc ffs_find_superblock(struct open_file *f, FS *fs)
52158a2b000SEvgeniy Ivanov {
52258a2b000SEvgeniy Ivanov int i, rc;
52358a2b000SEvgeniy Ivanov size_t buf_size;
52458a2b000SEvgeniy Ivanov
52558a2b000SEvgeniy Ivanov for (i = 0; sblock_try[i] != -1; i++) {
52658a2b000SEvgeniy Ivanov rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
52758a2b000SEvgeniy Ivanov sblock_try[i] / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size);
52858a2b000SEvgeniy Ivanov if (rc != 0 || buf_size != SBLOCKSIZE)
52958a2b000SEvgeniy Ivanov return rc;
53058a2b000SEvgeniy Ivanov if (fs->fs_sblockloc != sblock_try[i])
53158a2b000SEvgeniy Ivanov /* an alternate superblock - try again */
53258a2b000SEvgeniy Ivanov continue;
53358a2b000SEvgeniy Ivanov if (fs->fs_magic == FS_UFS2_MAGIC) {
53458a2b000SEvgeniy Ivanov return 0;
53558a2b000SEvgeniy Ivanov }
53658a2b000SEvgeniy Ivanov }
53758a2b000SEvgeniy Ivanov return EINVAL;
53858a2b000SEvgeniy Ivanov }
53958a2b000SEvgeniy Ivanov
54058a2b000SEvgeniy Ivanov #endif
54158a2b000SEvgeniy Ivanov
54258a2b000SEvgeniy Ivanov /*
54358a2b000SEvgeniy Ivanov * Open a file.
54458a2b000SEvgeniy Ivanov */
54558a2b000SEvgeniy Ivanov __compactcall int
ufs_open(const char * path,struct open_file * f)54658a2b000SEvgeniy Ivanov ufs_open(const char *path, struct open_file *f)
54758a2b000SEvgeniy Ivanov {
54858a2b000SEvgeniy Ivanov #ifndef LIBSA_FS_SINGLECOMPONENT
54958a2b000SEvgeniy Ivanov const char *cp, *ncp;
55058a2b000SEvgeniy Ivanov int c;
55158a2b000SEvgeniy Ivanov #endif
55258a2b000SEvgeniy Ivanov ino32_t inumber;
55358a2b000SEvgeniy Ivanov struct file *fp;
554*0a6a1f1dSLionel Sambuc FS *fs;
55558a2b000SEvgeniy Ivanov int rc;
55658a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_SYMLINK
55758a2b000SEvgeniy Ivanov ino32_t parent_inumber;
55858a2b000SEvgeniy Ivanov int nlinks = 0;
55958a2b000SEvgeniy Ivanov char namebuf[MAXPATHLEN+1];
56058a2b000SEvgeniy Ivanov char *buf;
56158a2b000SEvgeniy Ivanov #endif
56258a2b000SEvgeniy Ivanov
56358a2b000SEvgeniy Ivanov /* allocate file system specific data structure */
56458a2b000SEvgeniy Ivanov fp = alloc(sizeof(struct file));
56558a2b000SEvgeniy Ivanov memset(fp, 0, sizeof(struct file));
56658a2b000SEvgeniy Ivanov f->f_fsdata = (void *)fp;
56758a2b000SEvgeniy Ivanov
56858a2b000SEvgeniy Ivanov /* allocate space and read super block */
56958a2b000SEvgeniy Ivanov fs = alloc(SBLOCKSIZE);
57058a2b000SEvgeniy Ivanov fp->f_fs = fs;
57158a2b000SEvgeniy Ivanov twiddle();
57258a2b000SEvgeniy Ivanov
57358a2b000SEvgeniy Ivanov #ifdef LIBSA_FFSv2
57458a2b000SEvgeniy Ivanov rc = ffs_find_superblock(f, fs);
57558a2b000SEvgeniy Ivanov if (rc)
57658a2b000SEvgeniy Ivanov goto out;
57758a2b000SEvgeniy Ivanov #else
57858a2b000SEvgeniy Ivanov {
57958a2b000SEvgeniy Ivanov size_t buf_size;
58058a2b000SEvgeniy Ivanov rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
58158a2b000SEvgeniy Ivanov SBLOCKOFFSET / DEV_BSIZE, SBLOCKSIZE, fs, &buf_size);
58258a2b000SEvgeniy Ivanov if (rc)
58358a2b000SEvgeniy Ivanov goto out;
58458a2b000SEvgeniy Ivanov if (buf_size != SBLOCKSIZE ||
58558a2b000SEvgeniy Ivanov #ifdef LIBSA_FFS
58658a2b000SEvgeniy Ivanov fs->lfs_version != REQUIRED_LFS_VERSION ||
58758a2b000SEvgeniy Ivanov #endif
58858a2b000SEvgeniy Ivanov fs->fs_magic != FS_MAGIC) {
58958a2b000SEvgeniy Ivanov rc = EINVAL;
59058a2b000SEvgeniy Ivanov goto out;
59158a2b000SEvgeniy Ivanov }
59258a2b000SEvgeniy Ivanov }
59358a2b000SEvgeniy Ivanov #if defined(LIBSA_LFS) && REQUIRED_LFS_VERSION == 2
59458a2b000SEvgeniy Ivanov /*
59558a2b000SEvgeniy Ivanov * XXX We should check the second superblock and use the eldest
59658a2b000SEvgeniy Ivanov * of the two. See comments near the top of lfs_mountfs()
59758a2b000SEvgeniy Ivanov * in sys/ufs/lfs/lfs_vfsops.c.
59858a2b000SEvgeniy Ivanov * This may need a LIBSA_LFS_SMALL check as well.
59958a2b000SEvgeniy Ivanov */
60058a2b000SEvgeniy Ivanov #endif
601*0a6a1f1dSLionel Sambuc #if defined(LIBSA_LFS)
602*0a6a1f1dSLionel Sambuc fs->lfs_is64 = 0;
603*0a6a1f1dSLionel Sambuc fs->lfs_dobyteswap = 0;
604*0a6a1f1dSLionel Sambuc fs->lfs_hasolddirfmt = (fs->fs_maxsymlinklen <= 0);
605*0a6a1f1dSLionel Sambuc #endif
60658a2b000SEvgeniy Ivanov #endif
60758a2b000SEvgeniy Ivanov
60858a2b000SEvgeniy Ivanov #ifdef LIBSA_FFSv1
60958a2b000SEvgeniy Ivanov ffs_oldfscompat(fs);
61058a2b000SEvgeniy Ivanov #endif
61158a2b000SEvgeniy Ivanov
61258a2b000SEvgeniy Ivanov if (fs->fs_bsize > MAXBSIZE ||
613*0a6a1f1dSLionel Sambuc (size_t)fs->fs_bsize < sizeof(FS)) {
61458a2b000SEvgeniy Ivanov rc = EINVAL;
61558a2b000SEvgeniy Ivanov goto out;
61658a2b000SEvgeniy Ivanov }
61758a2b000SEvgeniy Ivanov
61858a2b000SEvgeniy Ivanov /*
61958a2b000SEvgeniy Ivanov * Calculate indirect block levels.
62058a2b000SEvgeniy Ivanov */
62158a2b000SEvgeniy Ivanov {
62258a2b000SEvgeniy Ivanov indp_t mult;
62358a2b000SEvgeniy Ivanov int ln2;
62458a2b000SEvgeniy Ivanov
62558a2b000SEvgeniy Ivanov /*
62658a2b000SEvgeniy Ivanov * We note that the number of indirect blocks is always
62758a2b000SEvgeniy Ivanov * a power of 2. This lets us use shifts and masks instead
62858a2b000SEvgeniy Ivanov * of divide and remainder and avoinds pulling in the
62958a2b000SEvgeniy Ivanov * 64bit division routine into the boot code.
63058a2b000SEvgeniy Ivanov */
63184d9c625SLionel Sambuc mult = UFS_NINDIR(fs);
63258a2b000SEvgeniy Ivanov #ifdef DEBUG
63358a2b000SEvgeniy Ivanov if (mult & (mult - 1)) {
63458a2b000SEvgeniy Ivanov /* Hummm was't a power of 2 */
63558a2b000SEvgeniy Ivanov rc = EINVAL;
63658a2b000SEvgeniy Ivanov goto out;
63758a2b000SEvgeniy Ivanov }
63858a2b000SEvgeniy Ivanov #endif
63958a2b000SEvgeniy Ivanov for (ln2 = 0; mult != 1; ln2++)
64058a2b000SEvgeniy Ivanov mult >>= 1;
64158a2b000SEvgeniy Ivanov
64258a2b000SEvgeniy Ivanov fp->f_nishift = ln2;
64358a2b000SEvgeniy Ivanov }
64458a2b000SEvgeniy Ivanov
64558a2b000SEvgeniy Ivanov /* alloc a block sized buffer used for all fs transfers */
64658a2b000SEvgeniy Ivanov fp->f_buf = alloc(fs->fs_bsize);
64784d9c625SLionel Sambuc inumber = UFS_ROOTINO;
64858a2b000SEvgeniy Ivanov if ((rc = read_inode(inumber, f)) != 0)
64958a2b000SEvgeniy Ivanov goto out;
65058a2b000SEvgeniy Ivanov
65158a2b000SEvgeniy Ivanov #ifndef LIBSA_FS_SINGLECOMPONENT
65258a2b000SEvgeniy Ivanov cp = path;
65358a2b000SEvgeniy Ivanov while (*cp) {
65458a2b000SEvgeniy Ivanov
65558a2b000SEvgeniy Ivanov /*
65658a2b000SEvgeniy Ivanov * Remove extra separators
65758a2b000SEvgeniy Ivanov */
65858a2b000SEvgeniy Ivanov while (*cp == '/')
65958a2b000SEvgeniy Ivanov cp++;
66058a2b000SEvgeniy Ivanov if (*cp == '\0')
66158a2b000SEvgeniy Ivanov break;
66258a2b000SEvgeniy Ivanov
66358a2b000SEvgeniy Ivanov /*
66458a2b000SEvgeniy Ivanov * Check that current node is a directory.
66558a2b000SEvgeniy Ivanov */
66658a2b000SEvgeniy Ivanov if ((fp->f_di.di_mode & IFMT) != IFDIR) {
66758a2b000SEvgeniy Ivanov rc = ENOTDIR;
66858a2b000SEvgeniy Ivanov goto out;
66958a2b000SEvgeniy Ivanov }
67058a2b000SEvgeniy Ivanov
67158a2b000SEvgeniy Ivanov /*
67258a2b000SEvgeniy Ivanov * Get next component of path name.
67358a2b000SEvgeniy Ivanov */
67458a2b000SEvgeniy Ivanov ncp = cp;
67558a2b000SEvgeniy Ivanov while ((c = *cp) != '\0' && c != '/')
67658a2b000SEvgeniy Ivanov cp++;
67758a2b000SEvgeniy Ivanov
67858a2b000SEvgeniy Ivanov /*
67958a2b000SEvgeniy Ivanov * Look up component in current directory.
68058a2b000SEvgeniy Ivanov * Save directory inumber in case we find a
68158a2b000SEvgeniy Ivanov * symbolic link.
68258a2b000SEvgeniy Ivanov */
68358a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_SYMLINK
68458a2b000SEvgeniy Ivanov parent_inumber = inumber;
68558a2b000SEvgeniy Ivanov #endif
68658a2b000SEvgeniy Ivanov rc = search_directory(ncp, cp - ncp, f, &inumber);
68758a2b000SEvgeniy Ivanov if (rc)
68858a2b000SEvgeniy Ivanov goto out;
68958a2b000SEvgeniy Ivanov
69058a2b000SEvgeniy Ivanov /*
69158a2b000SEvgeniy Ivanov * Open next component.
69258a2b000SEvgeniy Ivanov */
69358a2b000SEvgeniy Ivanov if ((rc = read_inode(inumber, f)) != 0)
69458a2b000SEvgeniy Ivanov goto out;
69558a2b000SEvgeniy Ivanov
69658a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_SYMLINK
69758a2b000SEvgeniy Ivanov /*
69858a2b000SEvgeniy Ivanov * Check for symbolic link.
69958a2b000SEvgeniy Ivanov */
70058a2b000SEvgeniy Ivanov if ((fp->f_di.di_mode & IFMT) == IFLNK) {
70158a2b000SEvgeniy Ivanov int link_len = fp->f_di.di_size;
70258a2b000SEvgeniy Ivanov int len;
70358a2b000SEvgeniy Ivanov
70458a2b000SEvgeniy Ivanov len = strlen(cp);
70558a2b000SEvgeniy Ivanov
70658a2b000SEvgeniy Ivanov if (link_len + len > MAXPATHLEN ||
70758a2b000SEvgeniy Ivanov ++nlinks > MAXSYMLINKS) {
70858a2b000SEvgeniy Ivanov rc = ENOENT;
70958a2b000SEvgeniy Ivanov goto out;
71058a2b000SEvgeniy Ivanov }
71158a2b000SEvgeniy Ivanov
71258a2b000SEvgeniy Ivanov memmove(&namebuf[link_len], cp, len + 1);
71358a2b000SEvgeniy Ivanov
71458a2b000SEvgeniy Ivanov if (link_len < fs->fs_maxsymlinklen) {
71558a2b000SEvgeniy Ivanov memcpy(namebuf, fp->f_di.di_db, link_len);
71658a2b000SEvgeniy Ivanov } else {
71758a2b000SEvgeniy Ivanov /*
71858a2b000SEvgeniy Ivanov * Read file for symbolic link
71958a2b000SEvgeniy Ivanov */
72058a2b000SEvgeniy Ivanov size_t buf_size;
72158a2b000SEvgeniy Ivanov indp_t disk_block;
72258a2b000SEvgeniy Ivanov
72358a2b000SEvgeniy Ivanov buf = fp->f_buf;
72458a2b000SEvgeniy Ivanov rc = block_map(f, (indp_t)0, &disk_block);
72558a2b000SEvgeniy Ivanov if (rc)
72658a2b000SEvgeniy Ivanov goto out;
72758a2b000SEvgeniy Ivanov
72858a2b000SEvgeniy Ivanov twiddle();
72958a2b000SEvgeniy Ivanov rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
73058a2b000SEvgeniy Ivanov F_READ, FSBTODB(fs, disk_block),
73158a2b000SEvgeniy Ivanov fs->fs_bsize, buf, &buf_size);
73258a2b000SEvgeniy Ivanov if (rc)
73358a2b000SEvgeniy Ivanov goto out;
73458a2b000SEvgeniy Ivanov
73558a2b000SEvgeniy Ivanov memcpy(namebuf, buf, link_len);
73658a2b000SEvgeniy Ivanov }
73758a2b000SEvgeniy Ivanov
73858a2b000SEvgeniy Ivanov /*
73958a2b000SEvgeniy Ivanov * If relative pathname, restart at parent directory.
74058a2b000SEvgeniy Ivanov * If absolute pathname, restart at root.
74158a2b000SEvgeniy Ivanov */
74258a2b000SEvgeniy Ivanov cp = namebuf;
74358a2b000SEvgeniy Ivanov if (*cp != '/')
74458a2b000SEvgeniy Ivanov inumber = parent_inumber;
74558a2b000SEvgeniy Ivanov else
74684d9c625SLionel Sambuc inumber = (ino32_t)UFS_ROOTINO;
74758a2b000SEvgeniy Ivanov
74858a2b000SEvgeniy Ivanov if ((rc = read_inode(inumber, f)) != 0)
74958a2b000SEvgeniy Ivanov goto out;
75058a2b000SEvgeniy Ivanov }
75158a2b000SEvgeniy Ivanov #endif /* !LIBSA_NO_FS_SYMLINK */
75258a2b000SEvgeniy Ivanov }
75358a2b000SEvgeniy Ivanov
75458a2b000SEvgeniy Ivanov /*
75558a2b000SEvgeniy Ivanov * Found terminal component.
75658a2b000SEvgeniy Ivanov */
75758a2b000SEvgeniy Ivanov rc = 0;
75858a2b000SEvgeniy Ivanov
75958a2b000SEvgeniy Ivanov #else /* !LIBSA_FS_SINGLECOMPONENT */
76058a2b000SEvgeniy Ivanov
76158a2b000SEvgeniy Ivanov /* look up component in the current (root) directory */
76258a2b000SEvgeniy Ivanov rc = search_directory(path, strlen(path), f, &inumber);
76358a2b000SEvgeniy Ivanov if (rc)
76458a2b000SEvgeniy Ivanov goto out;
76558a2b000SEvgeniy Ivanov
76658a2b000SEvgeniy Ivanov /* open it */
76758a2b000SEvgeniy Ivanov rc = read_inode(inumber, f);
76858a2b000SEvgeniy Ivanov
76958a2b000SEvgeniy Ivanov #endif /* !LIBSA_FS_SINGLECOMPONENT */
77058a2b000SEvgeniy Ivanov
77158a2b000SEvgeniy Ivanov fp->f_seekp = 0; /* reset seek pointer */
77258a2b000SEvgeniy Ivanov
77358a2b000SEvgeniy Ivanov out:
77458a2b000SEvgeniy Ivanov if (rc)
77558a2b000SEvgeniy Ivanov ufs_close(f);
77684d9c625SLionel Sambuc #ifdef FSMOD /* Only defined for lfs */
777*0a6a1f1dSLionel Sambuc else
77858a2b000SEvgeniy Ivanov fsmod = FSMOD;
77958a2b000SEvgeniy Ivanov #endif
78058a2b000SEvgeniy Ivanov return rc;
78158a2b000SEvgeniy Ivanov }
78258a2b000SEvgeniy Ivanov
78358a2b000SEvgeniy Ivanov __compactcall int
ufs_close(struct open_file * f)78458a2b000SEvgeniy Ivanov ufs_close(struct open_file *f)
78558a2b000SEvgeniy Ivanov {
78658a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
78758a2b000SEvgeniy Ivanov
78858a2b000SEvgeniy Ivanov f->f_fsdata = NULL;
78958a2b000SEvgeniy Ivanov if (fp == NULL)
79058a2b000SEvgeniy Ivanov return 0;
79158a2b000SEvgeniy Ivanov
79258a2b000SEvgeniy Ivanov if (fp->f_buf)
79358a2b000SEvgeniy Ivanov dealloc(fp->f_buf, fp->f_fs->fs_bsize);
79458a2b000SEvgeniy Ivanov dealloc(fp->f_fs, SBLOCKSIZE);
79558a2b000SEvgeniy Ivanov dealloc(fp, sizeof(struct file));
79658a2b000SEvgeniy Ivanov return 0;
79758a2b000SEvgeniy Ivanov }
79858a2b000SEvgeniy Ivanov
79958a2b000SEvgeniy Ivanov /*
80058a2b000SEvgeniy Ivanov * Copy a portion of a file into kernel memory.
80158a2b000SEvgeniy Ivanov * Cross block boundaries when necessary.
80258a2b000SEvgeniy Ivanov */
80358a2b000SEvgeniy Ivanov __compactcall int
ufs_read(struct open_file * f,void * start,size_t size,size_t * resid)80458a2b000SEvgeniy Ivanov ufs_read(struct open_file *f, void *start, size_t size, size_t *resid)
80558a2b000SEvgeniy Ivanov {
80658a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
80758a2b000SEvgeniy Ivanov size_t csize;
80858a2b000SEvgeniy Ivanov char *buf;
80958a2b000SEvgeniy Ivanov size_t buf_size;
81058a2b000SEvgeniy Ivanov int rc = 0;
81158a2b000SEvgeniy Ivanov char *addr = start;
81258a2b000SEvgeniy Ivanov
81358a2b000SEvgeniy Ivanov while (size != 0) {
81458a2b000SEvgeniy Ivanov if (fp->f_seekp >= (off_t)fp->f_di.di_size)
81558a2b000SEvgeniy Ivanov break;
81658a2b000SEvgeniy Ivanov
81758a2b000SEvgeniy Ivanov rc = buf_read_file(f, &buf, &buf_size);
81858a2b000SEvgeniy Ivanov if (rc)
81958a2b000SEvgeniy Ivanov break;
82058a2b000SEvgeniy Ivanov
82158a2b000SEvgeniy Ivanov csize = size;
82258a2b000SEvgeniy Ivanov if (csize > buf_size)
82358a2b000SEvgeniy Ivanov csize = buf_size;
82458a2b000SEvgeniy Ivanov
82558a2b000SEvgeniy Ivanov memcpy(addr, buf, csize);
82658a2b000SEvgeniy Ivanov
82758a2b000SEvgeniy Ivanov fp->f_seekp += csize;
82858a2b000SEvgeniy Ivanov addr += csize;
82958a2b000SEvgeniy Ivanov size -= csize;
83058a2b000SEvgeniy Ivanov }
83158a2b000SEvgeniy Ivanov if (resid)
83258a2b000SEvgeniy Ivanov *resid = size;
83358a2b000SEvgeniy Ivanov return rc;
83458a2b000SEvgeniy Ivanov }
83558a2b000SEvgeniy Ivanov
83658a2b000SEvgeniy Ivanov /*
83758a2b000SEvgeniy Ivanov * Not implemented.
83858a2b000SEvgeniy Ivanov */
83958a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_WRITE
84058a2b000SEvgeniy Ivanov __compactcall int
ufs_write(struct open_file * f,void * start,size_t size,size_t * resid)84158a2b000SEvgeniy Ivanov ufs_write(struct open_file *f, void *start, size_t size, size_t *resid)
84258a2b000SEvgeniy Ivanov {
84358a2b000SEvgeniy Ivanov
84458a2b000SEvgeniy Ivanov return EROFS;
84558a2b000SEvgeniy Ivanov }
84658a2b000SEvgeniy Ivanov #endif /* !LIBSA_NO_FS_WRITE */
84758a2b000SEvgeniy Ivanov
84858a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_SEEK
84958a2b000SEvgeniy Ivanov __compactcall off_t
ufs_seek(struct open_file * f,off_t offset,int where)85058a2b000SEvgeniy Ivanov ufs_seek(struct open_file *f, off_t offset, int where)
85158a2b000SEvgeniy Ivanov {
85258a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
85358a2b000SEvgeniy Ivanov
85458a2b000SEvgeniy Ivanov switch (where) {
85558a2b000SEvgeniy Ivanov case SEEK_SET:
85658a2b000SEvgeniy Ivanov fp->f_seekp = offset;
85758a2b000SEvgeniy Ivanov break;
85858a2b000SEvgeniy Ivanov case SEEK_CUR:
85958a2b000SEvgeniy Ivanov fp->f_seekp += offset;
86058a2b000SEvgeniy Ivanov break;
86158a2b000SEvgeniy Ivanov case SEEK_END:
86258a2b000SEvgeniy Ivanov fp->f_seekp = fp->f_di.di_size - offset;
86358a2b000SEvgeniy Ivanov break;
86458a2b000SEvgeniy Ivanov default:
86558a2b000SEvgeniy Ivanov return -1;
86658a2b000SEvgeniy Ivanov }
86758a2b000SEvgeniy Ivanov return fp->f_seekp;
86858a2b000SEvgeniy Ivanov }
86958a2b000SEvgeniy Ivanov #endif /* !LIBSA_NO_FS_SEEK */
87058a2b000SEvgeniy Ivanov
87158a2b000SEvgeniy Ivanov __compactcall int
ufs_stat(struct open_file * f,struct stat * sb)87258a2b000SEvgeniy Ivanov ufs_stat(struct open_file *f, struct stat *sb)
87358a2b000SEvgeniy Ivanov {
87458a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
87558a2b000SEvgeniy Ivanov
87658a2b000SEvgeniy Ivanov /* only important stuff */
87758a2b000SEvgeniy Ivanov memset(sb, 0, sizeof *sb);
87858a2b000SEvgeniy Ivanov sb->st_mode = fp->f_di.di_mode;
87958a2b000SEvgeniy Ivanov sb->st_uid = fp->f_di.di_uid;
88058a2b000SEvgeniy Ivanov sb->st_gid = fp->f_di.di_gid;
88158a2b000SEvgeniy Ivanov sb->st_size = fp->f_di.di_size;
88258a2b000SEvgeniy Ivanov return 0;
88358a2b000SEvgeniy Ivanov }
88458a2b000SEvgeniy Ivanov
88558a2b000SEvgeniy Ivanov #if defined(LIBSA_ENABLE_LS_OP)
886*0a6a1f1dSLionel Sambuc
887*0a6a1f1dSLionel Sambuc #include "ls.h"
888*0a6a1f1dSLionel Sambuc
889*0a6a1f1dSLionel Sambuc static const char *const typestr[] = {
890*0a6a1f1dSLionel Sambuc "unknown",
891*0a6a1f1dSLionel Sambuc "FIFO",
892*0a6a1f1dSLionel Sambuc "CHR",
893*0a6a1f1dSLionel Sambuc 0,
894*0a6a1f1dSLionel Sambuc "DIR",
895*0a6a1f1dSLionel Sambuc 0,
896*0a6a1f1dSLionel Sambuc "BLK",
897*0a6a1f1dSLionel Sambuc 0,
898*0a6a1f1dSLionel Sambuc "REG",
899*0a6a1f1dSLionel Sambuc 0,
900*0a6a1f1dSLionel Sambuc "LNK",
901*0a6a1f1dSLionel Sambuc 0,
902*0a6a1f1dSLionel Sambuc "SOCK",
903*0a6a1f1dSLionel Sambuc 0,
904*0a6a1f1dSLionel Sambuc "WHT"
905*0a6a1f1dSLionel Sambuc };
906*0a6a1f1dSLionel Sambuc
90758a2b000SEvgeniy Ivanov __compactcall void
ufs_ls(struct open_file * f,const char * pattern)908*0a6a1f1dSLionel Sambuc ufs_ls(struct open_file *f, const char *pattern)
90958a2b000SEvgeniy Ivanov {
91058a2b000SEvgeniy Ivanov struct file *fp = (struct file *)f->f_fsdata;
91158a2b000SEvgeniy Ivanov char *buf;
91258a2b000SEvgeniy Ivanov size_t buf_size;
913*0a6a1f1dSLionel Sambuc lsentry_t *names = NULL;
91458a2b000SEvgeniy Ivanov
91558a2b000SEvgeniy Ivanov fp->f_seekp = 0;
91658a2b000SEvgeniy Ivanov while (fp->f_seekp < (off_t)fp->f_di.di_size) {
91758a2b000SEvgeniy Ivanov struct direct *dp, *edp;
91858a2b000SEvgeniy Ivanov int rc = buf_read_file(f, &buf, &buf_size);
91958a2b000SEvgeniy Ivanov if (rc)
92058a2b000SEvgeniy Ivanov goto out;
92158a2b000SEvgeniy Ivanov /* some firmware might use block size larger than DEV_BSIZE */
92284d9c625SLionel Sambuc if (buf_size < UFS_DIRBLKSIZ)
92358a2b000SEvgeniy Ivanov goto out;
92458a2b000SEvgeniy Ivanov
92558a2b000SEvgeniy Ivanov dp = (struct direct *)buf;
92658a2b000SEvgeniy Ivanov edp = (struct direct *)(buf + buf_size);
92758a2b000SEvgeniy Ivanov
92858a2b000SEvgeniy Ivanov for (; dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) {
92958a2b000SEvgeniy Ivanov const char *t;
93058a2b000SEvgeniy Ivanov if (dp->d_ino == 0)
93158a2b000SEvgeniy Ivanov continue;
93258a2b000SEvgeniy Ivanov
93358a2b000SEvgeniy Ivanov if (dp->d_type >= NELEM(typestr) ||
93458a2b000SEvgeniy Ivanov !(t = typestr[dp->d_type])) {
93558a2b000SEvgeniy Ivanov /*
93658a2b000SEvgeniy Ivanov * This does not handle "old"
93758a2b000SEvgeniy Ivanov * filesystems properly. On little
93858a2b000SEvgeniy Ivanov * endian machines, we get a bogus
93958a2b000SEvgeniy Ivanov * type name if the namlen matches a
94058a2b000SEvgeniy Ivanov * valid type identifier. We could
94158a2b000SEvgeniy Ivanov * check if we read namlen "0" and
94258a2b000SEvgeniy Ivanov * handle this case specially, if
94358a2b000SEvgeniy Ivanov * there were a pressing need...
94458a2b000SEvgeniy Ivanov */
94558a2b000SEvgeniy Ivanov printf("bad dir entry\n");
94658a2b000SEvgeniy Ivanov goto out;
94758a2b000SEvgeniy Ivanov }
948*0a6a1f1dSLionel Sambuc lsadd(&names, pattern, dp->d_name, strlen(dp->d_name),
949*0a6a1f1dSLionel Sambuc dp->d_ino, t);
95058a2b000SEvgeniy Ivanov }
95158a2b000SEvgeniy Ivanov fp->f_seekp += buf_size;
95258a2b000SEvgeniy Ivanov }
953*0a6a1f1dSLionel Sambuc lsprint(names);
954*0a6a1f1dSLionel Sambuc out: lsfree(names);
955*0a6a1f1dSLionel Sambuc }
95658a2b000SEvgeniy Ivanov
957*0a6a1f1dSLionel Sambuc #if defined(__minix) && defined(LIBSA_ENABLE_LOAD_MODS_OP)
958*0a6a1f1dSLionel Sambuc __compactcall void
ufs_load_mods(struct open_file * f,const char * pattern,void (* funcp)(char *),char * path)959*0a6a1f1dSLionel Sambuc ufs_load_mods(struct open_file *f, const char *pattern,
960*0a6a1f1dSLionel Sambuc void (*funcp)(char *), char *path)
961*0a6a1f1dSLionel Sambuc {
962*0a6a1f1dSLionel Sambuc load_modsunsup("ufs");
96358a2b000SEvgeniy Ivanov }
964*0a6a1f1dSLionel Sambuc #endif /* defined(__minix) && defined(LIBSA_ENABLE_LOAD_MODS_OP) */
96558a2b000SEvgeniy Ivanov #endif /* LIBSA_ENABLE_LS_OP */
96658a2b000SEvgeniy Ivanov
96758a2b000SEvgeniy Ivanov #ifdef LIBSA_FFSv1
96858a2b000SEvgeniy Ivanov /*
96958a2b000SEvgeniy Ivanov * Sanity checks for old file systems.
97058a2b000SEvgeniy Ivanov *
97158a2b000SEvgeniy Ivanov * XXX - goes away some day.
97258a2b000SEvgeniy Ivanov * Stripped of stuff libsa doesn't need.....
97358a2b000SEvgeniy Ivanov */
97458a2b000SEvgeniy Ivanov static void
ffs_oldfscompat(FS * fs)975*0a6a1f1dSLionel Sambuc ffs_oldfscompat(FS *fs)
97658a2b000SEvgeniy Ivanov {
97758a2b000SEvgeniy Ivanov
97858a2b000SEvgeniy Ivanov #ifdef COMPAT_UFS
97958a2b000SEvgeniy Ivanov /*
98058a2b000SEvgeniy Ivanov * Newer Solaris versions have a slightly incompatible
98158a2b000SEvgeniy Ivanov * superblock - so always calculate this values on the fly, which
98258a2b000SEvgeniy Ivanov * is good enough for libsa purposes
98358a2b000SEvgeniy Ivanov */
98458a2b000SEvgeniy Ivanov if (fs->fs_magic == FS_UFS1_MAGIC
98558a2b000SEvgeniy Ivanov #ifndef COMPAT_SOLARIS_UFS
98658a2b000SEvgeniy Ivanov && fs->fs_old_inodefmt < FS_44INODEFMT
98758a2b000SEvgeniy Ivanov #endif
98858a2b000SEvgeniy Ivanov ) {
98958a2b000SEvgeniy Ivanov fs->fs_qbmask = ~fs->fs_bmask;
99058a2b000SEvgeniy Ivanov fs->fs_qfmask = ~fs->fs_fmask;
99158a2b000SEvgeniy Ivanov }
99258a2b000SEvgeniy Ivanov #endif
99358a2b000SEvgeniy Ivanov }
99458a2b000SEvgeniy Ivanov #endif
995