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
61235988Sglebtypedef	uint32_t	ufs_ino_t;
62235988Sgleb
6397860Sphk/*
6497860Sphk * We use 4k `virtual' blocks for filesystem data, whatever the actual
6597860Sphk * filesystem block size. FFS blocks are always a multiple of 4k.
6697860Sphk */
67104678Sphk#define VBLKSHIFT	12
68104678Sphk#define VBLKSIZE	(1 << VBLKSHIFT)
6997860Sphk#define VBLKMASK	(VBLKSIZE - 1)
7097860Sphk#define DBPERVBLK	(VBLKSIZE / DEV_BSIZE)
71104678Sphk#define INDIRPERVBLK(fs) (NINDIR(fs) / ((fs)->fs_bsize >> VBLKSHIFT))
72104678Sphk#define IPERVBLK(fs)	(INOPB(fs) / ((fs)->fs_bsize >> VBLKSHIFT))
7398542Smckusick#define INO_TO_VBA(fs, ipervblk, x) \
7498542Smckusick    (fsbtodb(fs, cgimin(fs, ino_to_cg(fs, x))) + \
7598542Smckusick    (((x) % (fs)->fs_ipg) / (ipervblk) * DBPERVBLK))
7698542Smckusick#define INO_TO_VBO(ipervblk, x) ((x) % ipervblk)
7797860Sphk#define FS_TO_VBA(fs, fsb, off) (fsbtodb(fs, fsb) + \
7897860Sphk    ((off) / VBLKSIZE) * DBPERVBLK)
7997860Sphk#define FS_TO_VBO(fs, fsb, off) ((off) & VBLKMASK)
8097860Sphk
8197860Sphk/* Buffers that must not span a 64k boundary. */
8297864Sphkstruct dmadat {
8398542Smckusick	char blkbuf[VBLKSIZE];	/* filesystem blocks */
8498542Smckusick	char indbuf[VBLKSIZE];	/* indir blocks */
8598542Smckusick	char sbbuf[SBLOCKSIZE];	/* superblock */
8698542Smckusick	char secbuf[DEV_BSIZE];	/* for MBR/disklabel */
8797864Sphk};
8897864Sphkstatic struct dmadat *dmadat;
8997860Sphk
90235988Sglebstatic ufs_ino_t lookup(const char *);
91235988Sglebstatic ssize_t fsread(ufs_ino_t, void *, size_t);
9297860Sphk
93219452Srdivackystatic uint8_t ls, dsk_meta;
9497860Sphkstatic uint32_t fs_off;
9597860Sphk
96223938Smariusstatic __inline uint8_t
97235988Sglebfsfind(const char *name, ufs_ino_t * ino)
9897860Sphk{
99233105Smarius	static char buf[DEV_BSIZE];
100192972Sdfr	struct direct *d;
10197861Sphk	char *s;
10297861Sphk	ssize_t n;
10397860Sphk
10497861Sphk	fs_off = 0;
10597861Sphk	while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0)
10698542Smckusick		for (s = buf; s < buf + DEV_BSIZE;) {
10798542Smckusick			d = (void *)s;
10898542Smckusick			if (ls)
10998542Smckusick				printf("%s ", d->d_name);
11098542Smckusick			else if (!strcmp(name, d->d_name)) {
111192972Sdfr				*ino = d->d_ino;
11298542Smckusick				return d->d_type;
11398542Smckusick			}
11498542Smckusick			s += d->d_reclen;
11597861Sphk		}
11697861Sphk	if (n != -1 && ls)
11797864Sphk		printf("\n");
11897861Sphk	return 0;
11997860Sphk}
12097860Sphk
121235988Sglebstatic ufs_ino_t
12297860Sphklookup(const char *path)
12397860Sphk{
124233105Smarius	static char name[MAXNAMLEN + 1];
12597861Sphk	const char *s;
126235988Sgleb	ufs_ino_t ino;
12797861Sphk	ssize_t n;
128218716Sdim	uint8_t dt;
12997860Sphk
13097861Sphk	ino = ROOTINO;
13197861Sphk	dt = DT_DIR;
13297861Sphk	for (;;) {
13397861Sphk		if (*path == '/')
13497861Sphk			path++;
13597861Sphk		if (!*path)
13697861Sphk			break;
13797861Sphk		for (s = path; *s && *s != '/'; s++);
13898542Smckusick		if ((n = s - path) > MAXNAMLEN)
13998542Smckusick			return 0;
14097861Sphk		ls = *path == '?' && n == 1 && !*s;
14197861Sphk		memcpy(name, path, n);
14297861Sphk		name[n] = 0;
14397864Sphk		if (dt != DT_DIR) {
14497864Sphk			printf("%s: not a directory.\n", name);
14597864Sphk			return (0);
14697864Sphk		}
14797861Sphk		if ((dt = fsfind(name, &ino)) <= 0)
14897861Sphk			break;
14997861Sphk		path = s;
15097861Sphk	}
15197861Sphk	return dt == DT_REG ? ino : 0;
15297860Sphk}
15397860Sphk
15498542Smckusick/*
15598542Smckusick * Possible superblock locations ordered from most to least likely.
15698542Smckusick */
15798542Smckusickstatic int sblock_try[] = SBLOCKSEARCH;
15898542Smckusick
159107877Sphk#if defined(UFS2_ONLY)
160107877Sphk#define DIP(field) dp2.field
161107877Sphk#elif defined(UFS1_ONLY)
162107877Sphk#define DIP(field) dp1.field
163107877Sphk#else
164223938Smarius#define DIP(field) fs.fs_magic == FS_UFS1_MAGIC ? dp1.field : dp2.field
165107877Sphk#endif
16698542Smckusick
16798542Smckusickstatic ssize_t
168235988Sglebfsread(ufs_ino_t inode, void *buf, size_t nbyte)
16998542Smckusick{
170107877Sphk#ifndef UFS2_ONLY
17198542Smckusick	static struct ufs1_dinode dp1;
172233105Smarius	ufs1_daddr_t addr1;
173107877Sphk#endif
174107877Sphk#ifndef UFS1_ONLY
17598542Smckusick	static struct ufs2_dinode dp2;
176107877Sphk#endif
177233105Smarius	static struct fs fs;
178235988Sgleb	static ufs_ino_t inomap;
17998542Smckusick	char *blkbuf;
180104678Sphk	void *indbuf;
18198542Smckusick	char *s;
18298542Smckusick	size_t n, nb, size, off, vboff;
18398542Smckusick	ufs_lbn_t lbn;
184233105Smarius	ufs2_daddr_t addr2, vbaddr;
18598542Smckusick	static ufs2_daddr_t blkmap, indmap;
186104678Sphk	u_int u;
18798542Smckusick
18898542Smckusick	blkbuf = dmadat->blkbuf;
18998542Smckusick	indbuf = dmadat->indbuf;
19098542Smckusick	if (!dsk_meta) {
19198542Smckusick		inomap = 0;
19298542Smckusick		for (n = 0; sblock_try[n] != -1; n++) {
193223938Smarius			if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE,
19498542Smckusick			    SBLOCKSIZE / DEV_BSIZE))
19598542Smckusick				return -1;
196223938Smarius			memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
197107877Sphk			if ((
198107877Sphk#if defined(UFS1_ONLY)
199223938Smarius			    fs.fs_magic == FS_UFS1_MAGIC
200107877Sphk#elif defined(UFS2_ONLY)
201223938Smarius			    (fs.fs_magic == FS_UFS2_MAGIC &&
202223938Smarius			    fs.fs_sblockloc == sblock_try[n])
203107877Sphk#else
204223938Smarius			    fs.fs_magic == FS_UFS1_MAGIC ||
205223938Smarius			    (fs.fs_magic == FS_UFS2_MAGIC &&
206223938Smarius			    fs.fs_sblockloc == sblock_try[n])
207107877Sphk#endif
208107877Sphk			    ) &&
209223938Smarius			    fs.fs_bsize <= MAXBSIZE &&
210223938Smarius			    fs.fs_bsize >= sizeof(struct fs))
21198542Smckusick				break;
21298542Smckusick		}
21398542Smckusick		if (sblock_try[n] == -1) {
21498542Smckusick			printf("Not ufs\n");
21598542Smckusick			return -1;
21698542Smckusick		}
21798542Smckusick		dsk_meta++;
218223938Smarius	} else
219223938Smarius		memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
22098542Smckusick	if (!inode)
22198542Smckusick		return 0;
22298542Smckusick	if (inomap != inode) {
223223938Smarius		n = IPERVBLK(&fs);
224223938Smarius		if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK))
22598542Smckusick			return -1;
22698542Smckusick		n = INO_TO_VBO(n, inode);
227107877Sphk#if defined(UFS1_ONLY)
228211747Srpaulo		memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
229211747Srpaulo		    sizeof(struct ufs1_dinode));
230107877Sphk#elif defined(UFS2_ONLY)
231211747Srpaulo		memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
232211747Srpaulo		    sizeof(struct ufs2_dinode));
233107877Sphk#else
234223938Smarius		if (fs.fs_magic == FS_UFS1_MAGIC)
235211747Srpaulo			memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
236211747Srpaulo			    sizeof(struct ufs1_dinode));
23798542Smckusick		else
238211747Srpaulo			memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
239211747Srpaulo			    sizeof(struct ufs2_dinode));
240107877Sphk#endif
24198542Smckusick		inomap = inode;
24298542Smckusick		fs_off = 0;
24398542Smckusick		blkmap = indmap = 0;
24498542Smckusick	}
24598542Smckusick	s = buf;
24698542Smckusick	size = DIP(di_size);
24798542Smckusick	n = size - fs_off;
24898542Smckusick	if (nbyte > n)
24998542Smckusick		nbyte = n;
25098542Smckusick	nb = nbyte;
25198542Smckusick	while (nb) {
252223938Smarius		lbn = lblkno(&fs, fs_off);
253223938Smarius		off = blkoff(&fs, fs_off);
25498542Smckusick		if (lbn < NDADDR) {
255233105Smarius			addr2 = DIP(di_db[lbn]);
256223938Smarius		} else if (lbn < NDADDR + NINDIR(&fs)) {
257223938Smarius			n = INDIRPERVBLK(&fs);
258233105Smarius			addr2 = DIP(di_ib[0]);
259179634Skib			u = (u_int)(lbn - NDADDR) / n * DBPERVBLK;
260233105Smarius			vbaddr = fsbtodb(&fs, addr2) + u;
26198542Smckusick			if (indmap != vbaddr) {
26298542Smckusick				if (dskread(indbuf, vbaddr, DBPERVBLK))
26398542Smckusick					return -1;
26498542Smckusick				indmap = vbaddr;
26598542Smckusick			}
266104678Sphk			n = (lbn - NDADDR) & (n - 1);
267107877Sphk#if defined(UFS1_ONLY)
268233105Smarius			memcpy(&addr1, (ufs1_daddr_t *)indbuf + n,
269232822Smarius			    sizeof(ufs1_daddr_t));
270233105Smarius			addr2 = addr1;
271107877Sphk#elif defined(UFS2_ONLY)
272233105Smarius			memcpy(&addr2, (ufs2_daddr_t *)indbuf + n,
273223938Smarius			    sizeof(ufs2_daddr_t));
274107877Sphk#else
275233105Smarius			if (fs.fs_magic == FS_UFS1_MAGIC) {
276233105Smarius				memcpy(&addr1, (ufs1_daddr_t *)indbuf + n,
277223938Smarius				    sizeof(ufs1_daddr_t));
278233105Smarius				addr2 = addr1;
279233105Smarius			} else
280233105Smarius				memcpy(&addr2, (ufs2_daddr_t *)indbuf + n,
281223938Smarius				    sizeof(ufs2_daddr_t));
282107877Sphk#endif
283233105Smarius		} else
28498542Smckusick			return -1;
285233105Smarius		vbaddr = fsbtodb(&fs, addr2) + (off >> VBLKSHIFT) * DBPERVBLK;
28698542Smckusick		vboff = off & VBLKMASK;
287223938Smarius		n = sblksize(&fs, size, lbn) - (off & ~VBLKMASK);
28898542Smckusick		if (n > VBLKSIZE)
28998542Smckusick			n = VBLKSIZE;
29098542Smckusick		if (blkmap != vbaddr) {
29198542Smckusick			if (dskread(blkbuf, vbaddr, n >> DEV_BSHIFT))
29298542Smckusick				return -1;
29398542Smckusick			blkmap = vbaddr;
29498542Smckusick		}
29598542Smckusick		n -= vboff;
29698542Smckusick		if (n > nb)
29798542Smckusick			n = nb;
29898542Smckusick		memcpy(s, blkbuf + vboff, n);
29998542Smckusick		s += n;
30098542Smckusick		fs_off += n;
30198542Smckusick		nb -= n;
30298542Smckusick	}
30398542Smckusick	return nbyte;
30498542Smckusick}
305