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