ufsread.c revision 179634
1156932Sru/*-
2156932Sru * Copyright (c) 2002 McAfee, Inc.
3156932Sru * All rights reserved.
4156932Sru *
5 * This software was developed for the FreeBSD Project by Marshall
6 * Kirk McKusick and McAfee Research,, the Security Research Division of
7 * McAfee, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as
8 * part of the DARPA CHATS research program
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31/*-
32 * Copyright (c) 1998 Robert Nordier
33 * All rights reserved.
34 *
35 * Redistribution and use in source and binary forms are freely
36 * permitted provided that the above copyright notice and this
37 * paragraph and the following disclaimer are duplicated in all
38 * such forms.
39 *
40 * This software is provided "AS IS" and without any express or
41 * implied warranties, including, without limitation, the implied
42 * warranties of merchantability and fitness for a particular
43 * purpose.
44 */
45
46#include <sys/cdefs.h>
47__FBSDID("$FreeBSD: head/sys/boot/common/ufsread.c 179634 2008-06-07 05:49:24Z kib $");
48
49#include <ufs/ufs/dinode.h>
50#include <ufs/ffs/fs.h>
51#ifdef UFS_SMALL_CGBASE
52/* XXX: Revert to old (broken for over 1.5Tb filesystems) version of cgbase
53   (see sys/ufs/ffs/fs.h rev 1.39) so that small boot loaders (e.g. boot2) can
54   support both UFS1 and UFS2. */
55#undef cgbase
56#define cgbase(fs, c)   ((ufs2_daddr_t)((fs)->fs_fpg * (c)))
57#endif
58
59/*
60 * We use 4k `virtual' blocks for filesystem data, whatever the actual
61 * filesystem block size. FFS blocks are always a multiple of 4k.
62 */
63#define VBLKSHIFT	12
64#define VBLKSIZE	(1 << VBLKSHIFT)
65#define VBLKMASK	(VBLKSIZE - 1)
66#define DBPERVBLK	(VBLKSIZE / DEV_BSIZE)
67#define INDIRPERVBLK(fs) (NINDIR(fs) / ((fs)->fs_bsize >> VBLKSHIFT))
68#define IPERVBLK(fs)	(INOPB(fs) / ((fs)->fs_bsize >> VBLKSHIFT))
69#define INO_TO_VBA(fs, ipervblk, x) \
70    (fsbtodb(fs, cgimin(fs, ino_to_cg(fs, x))) + \
71    (((x) % (fs)->fs_ipg) / (ipervblk) * DBPERVBLK))
72#define INO_TO_VBO(ipervblk, x) ((x) % ipervblk)
73#define FS_TO_VBA(fs, fsb, off) (fsbtodb(fs, fsb) + \
74    ((off) / VBLKSIZE) * DBPERVBLK)
75#define FS_TO_VBO(fs, fsb, off) ((off) & VBLKMASK)
76
77/* Buffers that must not span a 64k boundary. */
78struct dmadat {
79	char blkbuf[VBLKSIZE];	/* filesystem blocks */
80	char indbuf[VBLKSIZE];	/* indir blocks */
81	char sbbuf[SBLOCKSIZE];	/* superblock */
82	char secbuf[DEV_BSIZE];	/* for MBR/disklabel */
83};
84static struct dmadat *dmadat;
85
86static ino_t lookup(const char *);
87static ssize_t fsread(ino_t, void *, size_t);
88
89static int ls, dsk_meta;
90static uint32_t fs_off;
91
92static __inline int
93fsfind(const char *name, ino_t * ino)
94{
95	char buf[DEV_BSIZE];
96	struct dirent *d;
97	char *s;
98	ssize_t n;
99
100	fs_off = 0;
101	while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0)
102		for (s = buf; s < buf + DEV_BSIZE;) {
103			d = (void *)s;
104			if (ls)
105				printf("%s ", d->d_name);
106			else if (!strcmp(name, d->d_name)) {
107				*ino = d->d_fileno;
108				return d->d_type;
109			}
110			s += d->d_reclen;
111		}
112	if (n != -1 && ls)
113		printf("\n");
114	return 0;
115}
116
117static ino_t
118lookup(const char *path)
119{
120	char name[MAXNAMLEN + 1];
121	const char *s;
122	ino_t ino;
123	ssize_t n;
124	int dt;
125
126	ino = ROOTINO;
127	dt = DT_DIR;
128	name[0] = '/';
129	name[1] = '\0';
130	for (;;) {
131		if (*path == '/')
132			path++;
133		if (!*path)
134			break;
135		for (s = path; *s && *s != '/'; s++);
136		if ((n = s - path) > MAXNAMLEN)
137			return 0;
138		ls = *path == '?' && n == 1 && !*s;
139		memcpy(name, path, n);
140		name[n] = 0;
141		if (dt != DT_DIR) {
142			printf("%s: not a directory.\n", name);
143			return (0);
144		}
145		if ((dt = fsfind(name, &ino)) <= 0)
146			break;
147		path = s;
148	}
149	return dt == DT_REG ? ino : 0;
150}
151
152/*
153 * Possible superblock locations ordered from most to least likely.
154 */
155static int sblock_try[] = SBLOCKSEARCH;
156
157#if defined(UFS2_ONLY)
158#define DIP(field) dp2.field
159#elif defined(UFS1_ONLY)
160#define DIP(field) dp1.field
161#else
162#define DIP(field) fs->fs_magic == FS_UFS1_MAGIC ? dp1.field : dp2.field
163#endif
164
165static ssize_t
166fsread(ino_t inode, void *buf, size_t nbyte)
167{
168#ifndef UFS2_ONLY
169	static struct ufs1_dinode dp1;
170#endif
171#ifndef UFS1_ONLY
172	static struct ufs2_dinode dp2;
173#endif
174	static ino_t inomap;
175	char *blkbuf;
176	void *indbuf;
177	struct fs *fs;
178	char *s;
179	size_t n, nb, size, off, vboff;
180	ufs_lbn_t lbn;
181	ufs2_daddr_t addr, vbaddr;
182	static ufs2_daddr_t blkmap, indmap;
183	u_int u;
184
185
186	blkbuf = dmadat->blkbuf;
187	indbuf = dmadat->indbuf;
188	fs = (struct fs *)dmadat->sbbuf;
189	if (!dsk_meta) {
190		inomap = 0;
191		for (n = 0; sblock_try[n] != -1; n++) {
192			if (dskread(fs, sblock_try[n] / DEV_BSIZE,
193			    SBLOCKSIZE / DEV_BSIZE))
194				return -1;
195			if ((
196#if defined(UFS1_ONLY)
197			     fs->fs_magic == FS_UFS1_MAGIC
198#elif defined(UFS2_ONLY)
199			    (fs->fs_magic == FS_UFS2_MAGIC &&
200			    fs->fs_sblockloc == sblock_try[n])
201#else
202			     fs->fs_magic == FS_UFS1_MAGIC ||
203			    (fs->fs_magic == FS_UFS2_MAGIC &&
204			    fs->fs_sblockloc == sblock_try[n])
205#endif
206			    ) &&
207			    fs->fs_bsize <= MAXBSIZE &&
208			    fs->fs_bsize >= sizeof(struct fs))
209				break;
210		}
211		if (sblock_try[n] == -1) {
212			printf("Not ufs\n");
213			return -1;
214		}
215		dsk_meta++;
216	}
217	if (!inode)
218		return 0;
219	if (inomap != inode) {
220		n = IPERVBLK(fs);
221		if (dskread(blkbuf, INO_TO_VBA(fs, n, inode), DBPERVBLK))
222			return -1;
223		n = INO_TO_VBO(n, inode);
224#if defined(UFS1_ONLY)
225		dp1 = ((struct ufs1_dinode *)blkbuf)[n];
226#elif defined(UFS2_ONLY)
227		dp2 = ((struct ufs2_dinode *)blkbuf)[n];
228#else
229		if (fs->fs_magic == FS_UFS1_MAGIC)
230			dp1 = ((struct ufs1_dinode *)blkbuf)[n];
231		else
232			dp2 = ((struct ufs2_dinode *)blkbuf)[n];
233#endif
234		inomap = inode;
235		fs_off = 0;
236		blkmap = indmap = 0;
237	}
238	s = buf;
239	size = DIP(di_size);
240	n = size - fs_off;
241	if (nbyte > n)
242		nbyte = n;
243	nb = nbyte;
244	while (nb) {
245		lbn = lblkno(fs, fs_off);
246		off = blkoff(fs, fs_off);
247		if (lbn < NDADDR) {
248			addr = DIP(di_db[lbn]);
249		} else if (lbn < NDADDR + NINDIR(fs)) {
250			n = INDIRPERVBLK(fs);
251			addr = DIP(di_ib[0]);
252			u = (u_int)(lbn - NDADDR) / n * DBPERVBLK;
253			vbaddr = fsbtodb(fs, addr) + u;
254			if (indmap != vbaddr) {
255				if (dskread(indbuf, vbaddr, DBPERVBLK))
256					return -1;
257				indmap = vbaddr;
258			}
259			n = (lbn - NDADDR) & (n - 1);
260#if defined(UFS1_ONLY)
261			addr = ((ufs1_daddr_t *)indbuf)[n];
262#elif defined(UFS2_ONLY)
263			addr = ((ufs2_daddr_t *)indbuf)[n];
264#else
265			if (fs->fs_magic == FS_UFS1_MAGIC)
266				addr = ((ufs1_daddr_t *)indbuf)[n];
267			else
268				addr = ((ufs2_daddr_t *)indbuf)[n];
269#endif
270		} else {
271			return -1;
272		}
273		vbaddr = fsbtodb(fs, addr) + (off >> VBLKSHIFT) * DBPERVBLK;
274		vboff = off & VBLKMASK;
275		n = sblksize(fs, size, lbn) - (off & ~VBLKMASK);
276		if (n > VBLKSIZE)
277			n = VBLKSIZE;
278		if (blkmap != vbaddr) {
279			if (dskread(blkbuf, vbaddr, n >> DEV_BSHIFT))
280				return -1;
281			blkmap = vbaddr;
282		}
283		n -= vboff;
284		if (n > nb)
285			n = nb;
286		memcpy(s, blkbuf + vboff, n);
287		s += n;
288		fs_off += n;
289		nb -= n;
290	}
291	return nbyte;
292}
293