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