ufsread.c revision 173040
1/*- 2 * Copyright (c) 2002 McAfee, Inc. 3 * All rights reserved. 4 * 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 173040 2007-10-26 21:02:31Z jhb $"); 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