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$"); 48 49#include <ufs/ufs/dinode.h> 50#include <ufs/ufs/dir.h> 51#include <ufs/ffs/fs.h> 52 53#ifdef UFS_SMALL_CGBASE 54/* XXX: Revert to old (broken for over 1.5Tb filesystems) version of cgbase 55 (see sys/ufs/ffs/fs.h rev 1.39) so that small boot loaders (e.g. boot2) can 56 support both UFS1 and UFS2. */ 57#undef cgbase 58#define cgbase(fs, c) ((ufs2_daddr_t)((fs)->fs_fpg * (c))) 59#endif 60 61/* 62 * We use 4k `virtual' blocks for filesystem data, whatever the actual 63 * filesystem block size. FFS blocks are always a multiple of 4k. 64 */ 65#define VBLKSHIFT 12 66#define VBLKSIZE (1 << VBLKSHIFT) 67#define VBLKMASK (VBLKSIZE - 1) 68#define DBPERVBLK (VBLKSIZE / DEV_BSIZE) 69#define INDIRPERVBLK(fs) (NINDIR(fs) / ((fs)->fs_bsize >> VBLKSHIFT)) 70#define IPERVBLK(fs) (INOPB(fs) / ((fs)->fs_bsize >> VBLKSHIFT)) 71#define INO_TO_VBA(fs, ipervblk, x) \ 72 (fsbtodb(fs, cgimin(fs, ino_to_cg(fs, x))) + \ 73 (((x) % (fs)->fs_ipg) / (ipervblk) * DBPERVBLK)) 74#define INO_TO_VBO(ipervblk, x) ((x) % ipervblk) 75#define FS_TO_VBA(fs, fsb, off) (fsbtodb(fs, fsb) + \ 76 ((off) / VBLKSIZE) * DBPERVBLK) 77#define FS_TO_VBO(fs, fsb, off) ((off) & VBLKMASK) 78 79/* Buffers that must not span a 64k boundary. */ 80struct dmadat { 81 char blkbuf[VBLKSIZE]; /* filesystem blocks */ 82 char indbuf[VBLKSIZE]; /* indir blocks */ 83 char sbbuf[SBLOCKSIZE]; /* superblock */ 84 char secbuf[DEV_BSIZE]; /* for MBR/disklabel */ 85}; 86static struct dmadat *dmadat; 87 88static ino_t lookup(const char *); 89static ssize_t fsread(ino_t, void *, size_t); 90 91static uint8_t ls, dsk_meta; 92static uint32_t fs_off; 93 94static __inline uint8_t 95fsfind(const char *name, ino_t * ino) 96{ 97 static char buf[DEV_BSIZE]; 98 struct direct *d; 99 char *s; 100 ssize_t n; 101 102 fs_off = 0; 103 while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) 104 for (s = buf; s < buf + DEV_BSIZE;) { 105 d = (void *)s; 106 if (ls) 107 printf("%s ", d->d_name); 108 else if (!strcmp(name, d->d_name)) { 109 *ino = d->d_ino; 110 return d->d_type; 111 } 112 s += d->d_reclen; 113 } 114 if (n != -1 && ls) 115 printf("\n"); 116 return 0; 117} 118 119static ino_t 120lookup(const char *path) 121{ 122 static char name[MAXNAMLEN + 1]; 123 const char *s; 124 ino_t ino; 125 ssize_t n; 126 uint8_t dt; 127 128 ino = ROOTINO; 129 dt = DT_DIR; 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 ufs1_daddr_t addr1; 171#endif 172#ifndef UFS1_ONLY 173 static struct ufs2_dinode dp2; 174#endif 175 static struct fs fs; 176 static ino_t inomap; 177 char *blkbuf; 178 void *indbuf; 179 char *s; 180 size_t n, nb, size, off, vboff; 181 ufs_lbn_t lbn; 182 ufs2_daddr_t addr2, vbaddr; 183 static ufs2_daddr_t blkmap, indmap; 184 u_int u; 185 186 blkbuf = dmadat->blkbuf; 187 indbuf = dmadat->indbuf; 188 if (!dsk_meta) { 189 inomap = 0; 190 for (n = 0; sblock_try[n] != -1; n++) { 191 if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE, 192 SBLOCKSIZE / DEV_BSIZE)) 193 return -1; 194 memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 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 } else 217 memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 218 if (!inode) 219 return 0; 220 if (inomap != inode) { 221 n = IPERVBLK(&fs); 222 if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK)) 223 return -1; 224 n = INO_TO_VBO(n, inode); 225#if defined(UFS1_ONLY) 226 memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, 227 sizeof(struct ufs1_dinode)); 228#elif defined(UFS2_ONLY) 229 memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, 230 sizeof(struct ufs2_dinode)); 231#else 232 if (fs.fs_magic == FS_UFS1_MAGIC) 233 memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, 234 sizeof(struct ufs1_dinode)); 235 else 236 memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, 237 sizeof(struct ufs2_dinode)); 238#endif 239 inomap = inode; 240 fs_off = 0; 241 blkmap = indmap = 0; 242 } 243 s = buf; 244 size = DIP(di_size); 245 n = size - fs_off; 246 if (nbyte > n) 247 nbyte = n; 248 nb = nbyte; 249 while (nb) { 250 lbn = lblkno(&fs, fs_off); 251 off = blkoff(&fs, fs_off); 252 if (lbn < NDADDR) { 253 addr2 = DIP(di_db[lbn]); 254 } else if (lbn < NDADDR + NINDIR(&fs)) { 255 n = INDIRPERVBLK(&fs); 256 addr2 = DIP(di_ib[0]); 257 u = (u_int)(lbn - NDADDR) / n * DBPERVBLK; 258 vbaddr = fsbtodb(&fs, addr2) + u; 259 if (indmap != vbaddr) { 260 if (dskread(indbuf, vbaddr, DBPERVBLK)) 261 return -1; 262 indmap = vbaddr; 263 } 264 n = (lbn - NDADDR) & (n - 1); 265#if defined(UFS1_ONLY) 266 memcpy(&addr1, (ufs1_daddr_t *)indbuf + n, 267 sizeof(ufs1_daddr_t)); 268 addr2 = addr1; 269#elif defined(UFS2_ONLY) 270 memcpy(&addr2, (ufs2_daddr_t *)indbuf + n, 271 sizeof(ufs2_daddr_t)); 272#else 273 if (fs.fs_magic == FS_UFS1_MAGIC) { 274 memcpy(&addr1, (ufs1_daddr_t *)indbuf + n, 275 sizeof(ufs1_daddr_t)); 276 addr2 = addr1; 277 } else 278 memcpy(&addr2, (ufs2_daddr_t *)indbuf + n, 279 sizeof(ufs2_daddr_t)); 280#endif 281 } else 282 return -1; 283 vbaddr = fsbtodb(&fs, addr2) + (off >> VBLKSHIFT) * DBPERVBLK; 284 vboff = off & VBLKMASK; 285 n = sblksize(&fs, size, lbn) - (off & ~VBLKMASK); 286 if (n > VBLKSIZE) 287 n = VBLKSIZE; 288 if (blkmap != vbaddr) { 289 if (dskread(blkbuf, vbaddr, n >> DEV_BSHIFT)) 290 return -1; 291 blkmap = vbaddr; 292 } 293 n -= vboff; 294 if (n > nb) 295 n = nb; 296 memcpy(s, blkbuf + vboff, n); 297 s += n; 298 fs_off += n; 299 nb -= n; 300 } 301 return nbyte; 302} 303