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 48 #include <ufs/ufs/dinode.h> 49 #include <ufs/ufs/dir.h> 50 #include <ufs/ffs/fs.h> 51 52 #ifdef UFS_SMALL_CGBASE 53 /* XXX: Revert to old (broken for over 1.5Tb filesystems) version of cgbase 54 (see sys/ufs/ffs/fs.h rev 1.39) so that small boot loaders (e.g. boot2) can 55 support both UFS1 and UFS2. */ 56 #undef cgbase 57 #define cgbase(fs, c) ((ufs2_daddr_t)((fs)->fs_fpg * (c))) 58 #endif 59 60 typedef uint32_t ufs_ino_t; 61 62 /* 63 * We use 4k `virtual' blocks for filesystem data, whatever the actual 64 * filesystem block size. FFS blocks are always a multiple of 4k. 65 */ 66 #define VBLKSHIFT 12 67 #define VBLKSIZE (1 << VBLKSHIFT) 68 #define VBLKMASK (VBLKSIZE - 1) 69 #define DBPERVBLK (VBLKSIZE / DEV_BSIZE) 70 #define INDIRPERVBLK(fs) (NINDIR(fs) / ((fs)->fs_bsize >> VBLKSHIFT)) 71 #define IPERVBLK(fs) (INOPB(fs) / ((fs)->fs_bsize >> VBLKSHIFT)) 72 #define INO_TO_VBA(fs, ipervblk, x) \ 73 (fsbtodb(fs, cgimin(fs, ino_to_cg(fs, x))) + \ 74 (((x) % (fs)->fs_ipg) / (ipervblk) * DBPERVBLK)) 75 #define INO_TO_VBO(ipervblk, x) ((x) % ipervblk) 76 #define FS_TO_VBA(fs, fsb, off) (fsbtodb(fs, fsb) + \ 77 ((off) / VBLKSIZE) * DBPERVBLK) 78 #define FS_TO_VBO(fs, fsb, off) ((off) & VBLKMASK) 79 80 /* Buffers that must not span a 64k boundary. */ 81 struct dmadat { 82 char blkbuf[VBLKSIZE]; /* filesystem blocks */ 83 char indbuf[VBLKSIZE]; /* indir blocks */ 84 char sbbuf[SBLOCKSIZE]; /* superblock */ 85 char secbuf[DEV_BSIZE]; /* for MBR/disklabel */ 86 }; 87 static struct dmadat *dmadat; 88 89 static ufs_ino_t lookup(const char *); 90 static ssize_t fsread(ufs_ino_t, void *, size_t); 91 static uint8_t inode_type(ufs_ino_t inode); 92 93 static uint8_t ls, dsk_meta; 94 static uint32_t fs_off; 95 96 #ifndef UFS2_ONLY 97 static struct ufs1_dinode dp1; 98 ufs1_daddr_t addr1; 99 #endif 100 #ifndef UFS1_ONLY 101 static struct ufs2_dinode dp2; 102 #endif 103 static struct fs fs; 104 static ufs_ino_t inomap; 105 static ufs2_daddr_t blkmap, indmap; 106 107 static __inline uint8_t 108 fsfind(const char *name, ufs_ino_t * ino) 109 { 110 static char buf[DEV_BSIZE]; 111 struct direct *d; 112 char *s; 113 ssize_t n; 114 115 fs_off = 0; 116 while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) 117 for (s = buf; s < buf + DEV_BSIZE;) { 118 d = (void *)s; 119 if (ls) 120 printf("%s ", d->d_name); 121 else if (!strcmp(name, d->d_name)) { 122 *ino = d->d_ino; 123 return inode_type(*ino); 124 } 125 s += d->d_reclen; 126 } 127 if (n != -1 && ls) 128 printf("\n"); 129 return 0; 130 } 131 132 static ufs_ino_t 133 lookup(const char *path) 134 { 135 static char name[UFS_MAXNAMLEN + 1]; 136 const char *s; 137 ufs_ino_t ino; 138 ssize_t n; 139 uint8_t dt; 140 141 ino = ROOTINO; 142 dt = DT_DIR; 143 for (;;) { 144 if (*path == '/') 145 path++; 146 if (!*path) 147 break; 148 for (s = path; *s && *s != '/'; s++); 149 if ((n = s - path) > UFS_MAXNAMLEN) 150 return 0; 151 ls = *path == '?' && n == 1 && !*s; 152 memcpy(name, path, n); 153 name[n] = 0; 154 if (dt != DT_DIR) { 155 printf("%s: not a directory.\n", name); 156 return (0); 157 } 158 if ((dt = fsfind(name, &ino)) <= 0) 159 break; 160 path = s; 161 } 162 return dt == DT_REG ? ino : 0; 163 } 164 165 /* 166 * Possible superblock locations ordered from most to least likely. 167 */ 168 static int sblock_try[] = SBLOCKSEARCH; 169 170 #if defined(UFS2_ONLY) 171 #define DIP(field) dp2.field 172 #elif defined(UFS1_ONLY) 173 #define DIP(field) dp1.field 174 #else 175 #define DIP(field) fs.fs_magic == FS_UFS1_MAGIC ? dp1.field : dp2.field 176 #endif 177 178 static uint8_t 179 inode_type(ufs_ino_t inode) 180 { 181 char *blkbuf; 182 void *indbuf; 183 size_t n; 184 185 blkbuf = dmadat->blkbuf; 186 indbuf = dmadat->indbuf; 187 188 if (!inode) 189 return (0); 190 if (inomap != inode) { 191 n = IPERVBLK(&fs); 192 if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK)) 193 return (-1); 194 n = INO_TO_VBO(n, inode); 195 #if defined(UFS1_ONLY) 196 memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, 197 sizeof(struct ufs1_dinode)); 198 #elif defined(UFS2_ONLY) 199 memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, 200 sizeof(struct ufs2_dinode)); 201 #else 202 if (fs.fs_magic == FS_UFS1_MAGIC) 203 memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, 204 sizeof(struct ufs1_dinode)); 205 else 206 memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, 207 sizeof(struct ufs2_dinode)); 208 #endif 209 inomap = inode; 210 fs_off = 0; 211 blkmap = indmap = 0; 212 } 213 return (IFTODT(DIP(di_mode))); 214 } 215 216 static ssize_t 217 fsread_size(ufs_ino_t inode, void *buf, size_t nbyte, size_t *fsizep) 218 { 219 char *blkbuf; 220 void *indbuf; 221 char *s; 222 size_t n, nb, size, off, vboff; 223 ufs_lbn_t lbn; 224 ufs2_daddr_t addr2, vbaddr; 225 u_int u; 226 227 /* Basic parameter validation. */ 228 if ((buf == NULL && nbyte != 0) || dmadat == NULL) 229 return (-1); 230 231 blkbuf = dmadat->blkbuf; 232 indbuf = dmadat->indbuf; 233 234 /* 235 * Force probe if inode is zero to ensure we have a valid fs, otherwise 236 * when probing multiple paritions, reads from subsequent parititions 237 * will incorrectly succeed. 238 */ 239 if (!dsk_meta || inode == 0) { 240 inomap = 0; 241 dsk_meta = 0; 242 for (n = 0; sblock_try[n] != -1; n++) { 243 if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE, 244 SBLOCKSIZE / DEV_BSIZE)) 245 return -1; 246 memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 247 if (( 248 #if defined(UFS1_ONLY) 249 fs.fs_magic == FS_UFS1_MAGIC 250 #elif defined(UFS2_ONLY) 251 (fs.fs_magic == FS_UFS2_MAGIC && 252 fs.fs_sblockloc == sblock_try[n]) 253 #else 254 fs.fs_magic == FS_UFS1_MAGIC || 255 (fs.fs_magic == FS_UFS2_MAGIC && 256 fs.fs_sblockloc == sblock_try[n]) 257 #endif 258 ) && 259 fs.fs_bsize <= MAXBSIZE && 260 fs.fs_bsize >= (int32_t)sizeof(struct fs)) 261 break; 262 } 263 if (sblock_try[n] == -1) { 264 return -1; 265 } 266 dsk_meta++; 267 } else 268 memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 269 if (!inode) 270 return 0; 271 if (inomap != inode) { 272 n = IPERVBLK(&fs); 273 if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK)) 274 return -1; 275 n = INO_TO_VBO(n, inode); 276 #if defined(UFS1_ONLY) 277 memcpy(&dp1, (struct ufs1_dinode *)(void *)blkbuf + n, 278 sizeof(dp1)); 279 #elif defined(UFS2_ONLY) 280 memcpy(&dp2, (struct ufs2_dinode *)(void *)blkbuf + n, 281 sizeof(dp2)); 282 #else 283 if (fs.fs_magic == FS_UFS1_MAGIC) 284 memcpy(&dp1, (struct ufs1_dinode *)(void *)blkbuf + n, 285 sizeof(dp1)); 286 else 287 memcpy(&dp2, (struct ufs2_dinode *)(void *)blkbuf + n, 288 sizeof(dp2)); 289 #endif 290 inomap = inode; 291 fs_off = 0; 292 blkmap = indmap = 0; 293 } 294 s = buf; 295 size = DIP(di_size); 296 n = size - fs_off; 297 if (nbyte > n) 298 nbyte = n; 299 nb = nbyte; 300 while (nb) { 301 lbn = lblkno(&fs, fs_off); 302 off = blkoff(&fs, fs_off); 303 if (lbn < NDADDR) { 304 addr2 = DIP(di_db[lbn]); 305 } else if (lbn < NDADDR + NINDIR(&fs)) { 306 n = INDIRPERVBLK(&fs); 307 addr2 = DIP(di_ib[0]); 308 u = (u_int)(lbn - NDADDR) / n * DBPERVBLK; 309 vbaddr = fsbtodb(&fs, addr2) + u; 310 if (indmap != vbaddr) { 311 if (dskread(indbuf, vbaddr, DBPERVBLK)) 312 return -1; 313 indmap = vbaddr; 314 } 315 n = (lbn - NDADDR) & (n - 1); 316 #if defined(UFS1_ONLY) 317 memcpy(&addr1, (ufs1_daddr_t *)indbuf + n, 318 sizeof(ufs1_daddr_t)); 319 addr2 = addr1; 320 #elif defined(UFS2_ONLY) 321 memcpy(&addr2, (ufs2_daddr_t *)indbuf + n, 322 sizeof(ufs2_daddr_t)); 323 #else 324 if (fs.fs_magic == FS_UFS1_MAGIC) { 325 memcpy(&addr1, (ufs1_daddr_t *)indbuf + n, 326 sizeof(ufs1_daddr_t)); 327 addr2 = addr1; 328 } else 329 memcpy(&addr2, (ufs2_daddr_t *)indbuf + n, 330 sizeof(ufs2_daddr_t)); 331 #endif 332 } else 333 return -1; 334 vbaddr = fsbtodb(&fs, addr2) + (off >> VBLKSHIFT) * DBPERVBLK; 335 vboff = off & VBLKMASK; 336 n = sblksize(&fs, (off_t)size, lbn) - (off & ~VBLKMASK); 337 if (n > VBLKSIZE) 338 n = VBLKSIZE; 339 if (blkmap != vbaddr) { 340 if (dskread(blkbuf, vbaddr, n >> DEV_BSHIFT)) 341 return -1; 342 blkmap = vbaddr; 343 } 344 n -= vboff; 345 if (n > nb) 346 n = nb; 347 memcpy(s, blkbuf + vboff, n); 348 s += n; 349 fs_off += n; 350 nb -= n; 351 } 352 353 if (fsizep != NULL) 354 *fsizep = size; 355 356 return nbyte; 357 } 358 359 static ssize_t 360 fsread(ufs_ino_t inode, void *buf, size_t nbyte) 361 { 362 363 return fsread_size(inode, buf, nbyte, NULL); 364 } 365 366