1119483Sobrien/*-
2141060Srwatson * Copyright (c) 2002 McAfee, Inc.
398542Smckusick * All rights reserved.
498542Smckusick *
598542Smckusick * This software was developed for the FreeBSD Project by Marshall
6141060Srwatson * Kirk McKusick and McAfee Research,, the Security Research Division of
7141060Srwatson * McAfee, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as
8141060Srwatson * part of the DARPA CHATS research program
998542Smckusick *
10141060Srwatson * Redistribution and use in source and binary forms, with or without
11141060Srwatson * modification, are permitted provided that the following conditions
12141060Srwatson * are met:
13141060Srwatson * 1. Redistributions of source code must retain the above copyright
14141060Srwatson *    notice, this list of conditions and the following disclaimer.
15141060Srwatson * 2. Redistributions in binary form must reproduce the above copyright
16141060Srwatson *    notice, this list of conditions and the following disclaimer in the
17141060Srwatson *    documentation and/or other materials provided with the distribution.
18141060Srwatson *
19141060Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20141060Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21141060Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22141060Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23141060Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24141060Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25141060Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26141060Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27141060Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28141060Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29141060Srwatson * SUCH DAMAGE.
30141060Srwatson */
31141060Srwatson/*-
3297860Sphk * Copyright (c) 1998 Robert Nordier
3397860Sphk * All rights reserved.
3497860Sphk *
3597860Sphk * Redistribution and use in source and binary forms are freely
3697860Sphk * permitted provided that the above copyright notice and this
3797860Sphk * paragraph and the following disclaimer are duplicated in all
3897860Sphk * such forms.
3997860Sphk *
4097860Sphk * This software is provided "AS IS" and without any express or
4197860Sphk * implied warranties, including, without limitation, the implied
4297860Sphk * warranties of merchantability and fitness for a particular
4397860Sphk * purpose.
4497860Sphk */
4597860Sphk
46119483Sobrien#include <sys/cdefs.h>
47119483Sobrien__FBSDID("$FreeBSD$");
4897860Sphk
4998542Smckusick#include <ufs/ufs/dinode.h>
50192972Sdfr#include <ufs/ufs/dir.h>
5197860Sphk#include <ufs/ffs/fs.h>
52223938Smarius
53173040Sjhb#ifdef UFS_SMALL_CGBASE
54111456Sobrien/* XXX: Revert to old (broken for over 1.5Tb filesystems) version of cgbase
55173040Sjhb   (see sys/ufs/ffs/fs.h rev 1.39) so that small boot loaders (e.g. boot2) can
56173040Sjhb   support both UFS1 and UFS2. */
57111410Smckusick#undef cgbase
58111410Smckusick#define cgbase(fs, c)   ((ufs2_daddr_t)((fs)->fs_fpg * (c)))
59111456Sobrien#endif
6097860Sphk
6197860Sphk/*
6297860Sphk * We use 4k `virtual' blocks for filesystem data, whatever the actual
6397860Sphk * filesystem block size. FFS blocks are always a multiple of 4k.
6497860Sphk */
65104678Sphk#define VBLKSHIFT	12
66104678Sphk#define VBLKSIZE	(1 << VBLKSHIFT)
6797860Sphk#define VBLKMASK	(VBLKSIZE - 1)
6897860Sphk#define DBPERVBLK	(VBLKSIZE / DEV_BSIZE)
69104678Sphk#define INDIRPERVBLK(fs) (NINDIR(fs) / ((fs)->fs_bsize >> VBLKSHIFT))
70104678Sphk#define IPERVBLK(fs)	(INOPB(fs) / ((fs)->fs_bsize >> VBLKSHIFT))
7198542Smckusick#define INO_TO_VBA(fs, ipervblk, x) \
7298542Smckusick    (fsbtodb(fs, cgimin(fs, ino_to_cg(fs, x))) + \
7398542Smckusick    (((x) % (fs)->fs_ipg) / (ipervblk) * DBPERVBLK))
7498542Smckusick#define INO_TO_VBO(ipervblk, x) ((x) % ipervblk)
7597860Sphk#define FS_TO_VBA(fs, fsb, off) (fsbtodb(fs, fsb) + \
7697860Sphk    ((off) / VBLKSIZE) * DBPERVBLK)
7797860Sphk#define FS_TO_VBO(fs, fsb, off) ((off) & VBLKMASK)
7897860Sphk
7997860Sphk/* Buffers that must not span a 64k boundary. */
8097864Sphkstruct dmadat {
8198542Smckusick	char blkbuf[VBLKSIZE];	/* filesystem blocks */
8298542Smckusick	char indbuf[VBLKSIZE];	/* indir blocks */
8398542Smckusick	char sbbuf[SBLOCKSIZE];	/* superblock */
8498542Smckusick	char secbuf[DEV_BSIZE];	/* for MBR/disklabel */
8597864Sphk};
8697864Sphkstatic struct dmadat *dmadat;
8797860Sphk
8897860Sphkstatic ino_t lookup(const char *);
8997860Sphkstatic ssize_t fsread(ino_t, void *, size_t);
9097860Sphk
91219452Srdivackystatic uint8_t ls, dsk_meta;
9297860Sphkstatic uint32_t fs_off;
9397860Sphk
94223938Smariusstatic __inline uint8_t
9597860Sphkfsfind(const char *name, ino_t * ino)
9697860Sphk{
97233468Smarius	static char buf[DEV_BSIZE];
98192972Sdfr	struct direct *d;
9997861Sphk	char *s;
10097861Sphk	ssize_t n;
10197860Sphk
10297861Sphk	fs_off = 0;
10397861Sphk	while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0)
10498542Smckusick		for (s = buf; s < buf + DEV_BSIZE;) {
10598542Smckusick			d = (void *)s;
10698542Smckusick			if (ls)
10798542Smckusick				printf("%s ", d->d_name);
10898542Smckusick			else if (!strcmp(name, d->d_name)) {
109192972Sdfr				*ino = d->d_ino;
11098542Smckusick				return d->d_type;
11198542Smckusick			}
11298542Smckusick			s += d->d_reclen;
11397861Sphk		}
11497861Sphk	if (n != -1 && ls)
11597864Sphk		printf("\n");
11697861Sphk	return 0;
11797860Sphk}
11897860Sphk
11997860Sphkstatic ino_t
12097860Sphklookup(const char *path)
12197860Sphk{
122233468Smarius	static char name[MAXNAMLEN + 1];
12397861Sphk	const char *s;
12497861Sphk	ino_t ino;
12597861Sphk	ssize_t n;
126218716Sdim	uint8_t dt;
12797860Sphk
12897861Sphk	ino = ROOTINO;
12997861Sphk	dt = DT_DIR;
13097861Sphk	for (;;) {
13197861Sphk		if (*path == '/')
13297861Sphk			path++;
13397861Sphk		if (!*path)
13497861Sphk			break;
13597861Sphk		for (s = path; *s && *s != '/'; s++);
13698542Smckusick		if ((n = s - path) > MAXNAMLEN)
13798542Smckusick			return 0;
13897861Sphk		ls = *path == '?' && n == 1 && !*s;
13997861Sphk		memcpy(name, path, n);
14097861Sphk		name[n] = 0;
14197864Sphk		if (dt != DT_DIR) {
14297864Sphk			printf("%s: not a directory.\n", name);
14397864Sphk			return (0);
14497864Sphk		}
14597861Sphk		if ((dt = fsfind(name, &ino)) <= 0)
14697861Sphk			break;
14797861Sphk		path = s;
14897861Sphk	}
14997861Sphk	return dt == DT_REG ? ino : 0;
15097860Sphk}
15197860Sphk
15298542Smckusick/*
15398542Smckusick * Possible superblock locations ordered from most to least likely.
15498542Smckusick */
15598542Smckusickstatic int sblock_try[] = SBLOCKSEARCH;
15698542Smckusick
157107877Sphk#if defined(UFS2_ONLY)
158107877Sphk#define DIP(field) dp2.field
159107877Sphk#elif defined(UFS1_ONLY)
160107877Sphk#define DIP(field) dp1.field
161107877Sphk#else
162223938Smarius#define DIP(field) fs.fs_magic == FS_UFS1_MAGIC ? dp1.field : dp2.field
163107877Sphk#endif
16498542Smckusick
16598542Smckusickstatic ssize_t
16698542Smckusickfsread(ino_t inode, void *buf, size_t nbyte)
16798542Smckusick{
168107877Sphk#ifndef UFS2_ONLY
16998542Smckusick	static struct ufs1_dinode dp1;
170233468Smarius	ufs1_daddr_t addr1;
171107877Sphk#endif
172107877Sphk#ifndef UFS1_ONLY
17398542Smckusick	static struct ufs2_dinode dp2;
174107877Sphk#endif
175233468Smarius	static struct fs fs;
17698542Smckusick	static ino_t inomap;
17798542Smckusick	char *blkbuf;
178104678Sphk	void *indbuf;
17998542Smckusick	char *s;
18098542Smckusick	size_t n, nb, size, off, vboff;
18198542Smckusick	ufs_lbn_t lbn;
182233468Smarius	ufs2_daddr_t addr2, vbaddr;
18398542Smckusick	static ufs2_daddr_t blkmap, indmap;
184104678Sphk	u_int u;
18598542Smckusick
18698542Smckusick	blkbuf = dmadat->blkbuf;
18798542Smckusick	indbuf = dmadat->indbuf;
18898542Smckusick	if (!dsk_meta) {
18998542Smckusick		inomap = 0;
19098542Smckusick		for (n = 0; sblock_try[n] != -1; n++) {
191223938Smarius			if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE,
19298542Smckusick			    SBLOCKSIZE / DEV_BSIZE))
19398542Smckusick				return -1;
194223938Smarius			memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
195107877Sphk			if ((
196107877Sphk#if defined(UFS1_ONLY)
197223938Smarius			    fs.fs_magic == FS_UFS1_MAGIC
198107877Sphk#elif defined(UFS2_ONLY)
199223938Smarius			    (fs.fs_magic == FS_UFS2_MAGIC &&
200223938Smarius			    fs.fs_sblockloc == sblock_try[n])
201107877Sphk#else
202223938Smarius			    fs.fs_magic == FS_UFS1_MAGIC ||
203223938Smarius			    (fs.fs_magic == FS_UFS2_MAGIC &&
204223938Smarius			    fs.fs_sblockloc == sblock_try[n])
205107877Sphk#endif
206107877Sphk			    ) &&
207223938Smarius			    fs.fs_bsize <= MAXBSIZE &&
208223938Smarius			    fs.fs_bsize >= sizeof(struct fs))
20998542Smckusick				break;
21098542Smckusick		}
21198542Smckusick		if (sblock_try[n] == -1) {
21298542Smckusick			printf("Not ufs\n");
21398542Smckusick			return -1;
21498542Smckusick		}
21598542Smckusick		dsk_meta++;
216223938Smarius	} else
217223938Smarius		memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
21898542Smckusick	if (!inode)
21998542Smckusick		return 0;
22098542Smckusick	if (inomap != inode) {
221223938Smarius		n = IPERVBLK(&fs);
222223938Smarius		if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK))
22398542Smckusick			return -1;
22498542Smckusick		n = INO_TO_VBO(n, inode);
225107877Sphk#if defined(UFS1_ONLY)
226211747Srpaulo		memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
227211747Srpaulo		    sizeof(struct ufs1_dinode));
228107877Sphk#elif defined(UFS2_ONLY)
229211747Srpaulo		memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
230211747Srpaulo		    sizeof(struct ufs2_dinode));
231107877Sphk#else
232223938Smarius		if (fs.fs_magic == FS_UFS1_MAGIC)
233211747Srpaulo			memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
234211747Srpaulo			    sizeof(struct ufs1_dinode));
23598542Smckusick		else
236211747Srpaulo			memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
237211747Srpaulo			    sizeof(struct ufs2_dinode));
238107877Sphk#endif
23998542Smckusick		inomap = inode;
24098542Smckusick		fs_off = 0;
24198542Smckusick		blkmap = indmap = 0;
24298542Smckusick	}
24398542Smckusick	s = buf;
24498542Smckusick	size = DIP(di_size);
24598542Smckusick	n = size - fs_off;
24698542Smckusick	if (nbyte > n)
24798542Smckusick		nbyte = n;
24898542Smckusick	nb = nbyte;
24998542Smckusick	while (nb) {
250223938Smarius		lbn = lblkno(&fs, fs_off);
251223938Smarius		off = blkoff(&fs, fs_off);
25298542Smckusick		if (lbn < NDADDR) {
253233468Smarius			addr2 = DIP(di_db[lbn]);
254223938Smarius		} else if (lbn < NDADDR + NINDIR(&fs)) {
255223938Smarius			n = INDIRPERVBLK(&fs);
256233468Smarius			addr2 = DIP(di_ib[0]);
257179634Skib			u = (u_int)(lbn - NDADDR) / n * DBPERVBLK;
258233468Smarius			vbaddr = fsbtodb(&fs, addr2) + u;
25998542Smckusick			if (indmap != vbaddr) {
26098542Smckusick				if (dskread(indbuf, vbaddr, DBPERVBLK))
26198542Smckusick					return -1;
26298542Smckusick				indmap = vbaddr;
26398542Smckusick			}
264104678Sphk			n = (lbn - NDADDR) & (n - 1);
265107877Sphk#if defined(UFS1_ONLY)
266233468Smarius			memcpy(&addr1, (ufs1_daddr_t *)indbuf + n,
267232962Smarius			    sizeof(ufs1_daddr_t));
268233468Smarius			addr2 = addr1;
269107877Sphk#elif defined(UFS2_ONLY)
270233468Smarius			memcpy(&addr2, (ufs2_daddr_t *)indbuf + n,
271223938Smarius			    sizeof(ufs2_daddr_t));
272107877Sphk#else
273233468Smarius			if (fs.fs_magic == FS_UFS1_MAGIC) {
274233468Smarius				memcpy(&addr1, (ufs1_daddr_t *)indbuf + n,
275223938Smarius				    sizeof(ufs1_daddr_t));
276233468Smarius				addr2 = addr1;
277233468Smarius			} else
278233468Smarius				memcpy(&addr2, (ufs2_daddr_t *)indbuf + n,
279223938Smarius				    sizeof(ufs2_daddr_t));
280107877Sphk#endif
281233468Smarius		} else
28298542Smckusick			return -1;
283233468Smarius		vbaddr = fsbtodb(&fs, addr2) + (off >> VBLKSHIFT) * DBPERVBLK;
28498542Smckusick		vboff = off & VBLKMASK;
285223938Smarius		n = sblksize(&fs, size, lbn) - (off & ~VBLKMASK);
28698542Smckusick		if (n > VBLKSIZE)
28798542Smckusick			n = VBLKSIZE;
28898542Smckusick		if (blkmap != vbaddr) {
28998542Smckusick			if (dskread(blkbuf, vbaddr, n >> DEV_BSHIFT))
29098542Smckusick				return -1;
29198542Smckusick			blkmap = vbaddr;
29298542Smckusick		}
29398542Smckusick		n -= vboff;
29498542Smckusick		if (n > nb)
29598542Smckusick			n = nb;
29698542Smckusick		memcpy(s, blkbuf + vboff, n);
29798542Smckusick		s += n;
29898542Smckusick		fs_off += n;
29998542Smckusick		nb -= n;
30098542Smckusick	}
30198542Smckusick	return nbyte;
30298542Smckusick}
303