150276Speter/*- 2262685Sdelphij * Copyright (c) 2002 McAfee, Inc. 350276Speter * All rights reserved. 450276Speter * 550276Speter * This software was developed for the FreeBSD Project by Marshall 650276Speter * Kirk McKusick and McAfee Research,, the Security Research Division of 750276Speter * McAfee, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as 850276Speter * part of the DARPA CHATS research program 950276Speter * 1050276Speter * Redistribution and use in source and binary forms, with or without 1150276Speter * modification, are permitted provided that the following conditions 1250276Speter * are met: 1350276Speter * 1. Redistributions of source code must retain the above copyright 1450276Speter * notice, this list of conditions and the following disclaimer. 1550276Speter * 2. Redistributions in binary form must reproduce the above copyright 1650276Speter * notice, this list of conditions and the following disclaimer in the 1750276Speter * documentation and/or other materials provided with the distribution. 1850276Speter * 1950276Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2050276Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2150276Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2250276Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2350276Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2450276Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2550276Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2650276Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2750276Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2850276Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2950276Speter * SUCH DAMAGE. 30166124Srafan */ 3150276Speter/*- 3250276Speter * Copyright (c) 1998 Robert Nordier 3350276Speter * All rights reserved. 3450276Speter * 35262685Sdelphij * Redistribution and use in source and binary forms are freely 3650276Speter * permitted provided that the above copyright notice and this 3750276Speter * paragraph and the following disclaimer are duplicated in all 3850276Speter * such forms. 3950276Speter * 4050276Speter * This software is provided "AS IS" and without any express or 4150276Speter * implied warranties, including, without limitation, the implied 4250276Speter * warranties of merchantability and fitness for a particular 4350276Speter * purpose. 4450276Speter */ 4550276Speter 4650276Speter#include <sys/cdefs.h> 4776726Speter__FBSDID("$FreeBSD$"); 48166124Srafan 4950276Speter#include <ufs/ufs/dinode.h> 50262629Sdelphij#include <ufs/ufs/dir.h> 51166124Srafan#include <ufs/ffs/fs.h> 52262685Sdelphij 53262685Sdelphij#ifdef UFS_SMALL_CGBASE 5450276Speter/* XXX: Revert to old (broken for over 1.5Tb filesystems) version of cgbase 5550276Speter (see sys/ufs/ffs/fs.h rev 1.39) so that small boot loaders (e.g. boot2) can 5650276Speter support both UFS1 and UFS2. */ 57166124Srafan#undef cgbase 5850276Speter#define cgbase(fs, c) ((ufs2_daddr_t)((fs)->fs_fpg * (c))) 5950276Speter#endif 6050276Speter 6150276Spetertypedef uint32_t ufs_ino_t; 6250276Speter 6350276Speter/* 6450276Speter * We use 4k `virtual' blocks for filesystem data, whatever the actual 6550276Speter * filesystem block size. FFS blocks are always a multiple of 4k. 6650276Speter */ 6750276Speter#define VBLKSHIFT 12 6850276Speter#define VBLKSIZE (1 << VBLKSHIFT) 6950276Speter#define VBLKMASK (VBLKSIZE - 1) 7076726Speter#define DBPERVBLK (VBLKSIZE / DEV_BSIZE) 71166124Srafan#define INDIRPERVBLK(fs) (NINDIR(fs) / ((fs)->fs_bsize >> VBLKSHIFT)) 7250276Speter#define IPERVBLK(fs) (INOPB(fs) / ((fs)->fs_bsize >> VBLKSHIFT)) 73262629Sdelphij#define INO_TO_VBA(fs, ipervblk, x) \ 74262685Sdelphij (fsbtodb(fs, cgimin(fs, ino_to_cg(fs, x))) + \ 7550276Speter (((x) % (fs)->fs_ipg) / (ipervblk) * DBPERVBLK)) 7650276Speter#define INO_TO_VBO(ipervblk, x) ((x) % ipervblk) 7750276Speter#define FS_TO_VBA(fs, fsb, off) (fsbtodb(fs, fsb) + \ 7850276Speter ((off) / VBLKSIZE) * DBPERVBLK) 7950276Speter#define FS_TO_VBO(fs, fsb, off) ((off) & VBLKMASK) 8050276Speter 8150276Speter/* Buffers that must not span a 64k boundary. */ 8250276Speterstruct dmadat { 8350276Speter char blkbuf[VBLKSIZE]; /* filesystem blocks */ 8450276Speter char indbuf[VBLKSIZE]; /* indir blocks */ 8550276Speter char sbbuf[SBLOCKSIZE]; /* superblock */ 8650276Speter char secbuf[DEV_BSIZE]; /* for MBR/disklabel */ 8776726Speter}; 88166124Srafanstatic struct dmadat *dmadat; 8950276Speter 90262629Sdelphijstatic ufs_ino_t lookup(const char *); 91166124Srafanstatic ssize_t fsread(ufs_ino_t, void *, size_t); 92262685Sdelphij 93262685Sdelphijstatic uint8_t ls, dsk_meta; 9450276Speterstatic uint32_t fs_off; 9550276Speter 9650276Speterstatic __inline uint8_t 97166124Srafanfsfind(const char *name, ufs_ino_t * ino) 9850276Speter{ 9950276Speter static char buf[DEV_BSIZE]; 10050276Speter struct direct *d; 10150276Speter char *s; 10250276Speter ssize_t n; 10350276Speter 10450276Speter fs_off = 0; 10550276Speter while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) 10650276Speter for (s = buf; s < buf + DEV_BSIZE;) { 10750276Speter d = (void *)s; 10850276Speter if (ls) 10950276Speter printf("%s ", d->d_name); 11050276Speter else if (!strcmp(name, d->d_name)) { 11150276Speter *ino = d->d_ino; 11276726Speter return d->d_type; 113166124Srafan } 11450276Speter s += d->d_reclen; 115262629Sdelphij } 116166124Srafan if (n != -1 && ls) 117262685Sdelphij printf("\n"); 118262685Sdelphij return 0; 11950276Speter} 12050276Speter 12150276Speterstatic ufs_ino_t 12250276Speterlookup(const char *path) 12350276Speter{ 12450276Speter static char name[MAXNAMLEN + 1]; 12550276Speter const char *s; 12650276Speter ufs_ino_t ino; 12750276Speter ssize_t n; 128 uint8_t dt; 129 130 ino = ROOTINO; 131 dt = DT_DIR; 132 for (;;) { 133 if (*path == '/') 134 path++; 135 if (!*path) 136 break; 137 for (s = path; *s && *s != '/'; s++); 138 if ((n = s - path) > MAXNAMLEN) 139 return 0; 140 ls = *path == '?' && n == 1 && !*s; 141 memcpy(name, path, n); 142 name[n] = 0; 143 if (dt != DT_DIR) { 144 printf("%s: not a directory.\n", name); 145 return (0); 146 } 147 if ((dt = fsfind(name, &ino)) <= 0) 148 break; 149 path = s; 150 } 151 return dt == DT_REG ? ino : 0; 152} 153 154/* 155 * Possible superblock locations ordered from most to least likely. 156 */ 157static int sblock_try[] = SBLOCKSEARCH; 158 159#if defined(UFS2_ONLY) 160#define DIP(field) dp2.field 161#elif defined(UFS1_ONLY) 162#define DIP(field) dp1.field 163#else 164#define DIP(field) fs.fs_magic == FS_UFS1_MAGIC ? dp1.field : dp2.field 165#endif 166 167static ssize_t 168fsread_size(ufs_ino_t inode, void *buf, size_t nbyte, size_t *fsizep) 169{ 170#ifndef UFS2_ONLY 171 static struct ufs1_dinode dp1; 172 ufs1_daddr_t addr1; 173#endif 174#ifndef UFS1_ONLY 175 static struct ufs2_dinode dp2; 176#endif 177 static struct fs fs; 178 static ufs_ino_t inomap; 179 char *blkbuf; 180 void *indbuf; 181 char *s; 182 size_t n, nb, size, off, vboff; 183 ufs_lbn_t lbn; 184 ufs2_daddr_t addr2, vbaddr; 185 static ufs2_daddr_t blkmap, indmap; 186 u_int u; 187 188 /* Basic parameter validation. */ 189 if ((buf == NULL && nbyte != 0) || dmadat == NULL) 190 return (-1); 191 192 blkbuf = dmadat->blkbuf; 193 indbuf = dmadat->indbuf; 194 195 /* 196 * Force probe if inode is zero to ensure we have a valid fs, otherwise 197 * when probing multiple paritions, reads from subsequent parititions 198 * will incorrectly succeed. 199 */ 200 if (!dsk_meta || inode == 0) { 201 inomap = 0; 202 dsk_meta = 0; 203 for (n = 0; sblock_try[n] != -1; n++) { 204 if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE, 205 SBLOCKSIZE / DEV_BSIZE)) 206 return -1; 207 memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 208 if (( 209#if defined(UFS1_ONLY) 210 fs.fs_magic == FS_UFS1_MAGIC 211#elif defined(UFS2_ONLY) 212 (fs.fs_magic == FS_UFS2_MAGIC && 213 fs.fs_sblockloc == sblock_try[n]) 214#else 215 fs.fs_magic == FS_UFS1_MAGIC || 216 (fs.fs_magic == FS_UFS2_MAGIC && 217 fs.fs_sblockloc == sblock_try[n]) 218#endif 219 ) && 220 fs.fs_bsize <= MAXBSIZE && 221 fs.fs_bsize >= (int32_t)sizeof(struct fs)) 222 break; 223 } 224 if (sblock_try[n] == -1) { 225 return -1; 226 } 227 dsk_meta++; 228 } else 229 memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 230 if (!inode) 231 return 0; 232 if (inomap != inode) { 233 n = IPERVBLK(&fs); 234 if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK)) 235 return -1; 236 n = INO_TO_VBO(n, inode); 237#if defined(UFS1_ONLY) 238 memcpy(&dp1, (struct ufs1_dinode *)(void *)blkbuf + n, 239 sizeof(dp1)); 240#elif defined(UFS2_ONLY) 241 memcpy(&dp2, (struct ufs2_dinode *)(void *)blkbuf + n, 242 sizeof(dp2)); 243#else 244 if (fs.fs_magic == FS_UFS1_MAGIC) 245 memcpy(&dp1, (struct ufs1_dinode *)(void *)blkbuf + n, 246 sizeof(dp1)); 247 else 248 memcpy(&dp2, (struct ufs2_dinode *)(void *)blkbuf + n, 249 sizeof(dp2)); 250#endif 251 inomap = inode; 252 fs_off = 0; 253 blkmap = indmap = 0; 254 } 255 s = buf; 256 size = DIP(di_size); 257 n = size - fs_off; 258 if (nbyte > n) 259 nbyte = n; 260 nb = nbyte; 261 while (nb) { 262 lbn = lblkno(&fs, fs_off); 263 off = blkoff(&fs, fs_off); 264 if (lbn < NDADDR) { 265 addr2 = DIP(di_db[lbn]); 266 } else if (lbn < NDADDR + NINDIR(&fs)) { 267 n = INDIRPERVBLK(&fs); 268 addr2 = DIP(di_ib[0]); 269 u = (u_int)(lbn - NDADDR) / n * DBPERVBLK; 270 vbaddr = fsbtodb(&fs, addr2) + u; 271 if (indmap != vbaddr) { 272 if (dskread(indbuf, vbaddr, DBPERVBLK)) 273 return -1; 274 indmap = vbaddr; 275 } 276 n = (lbn - NDADDR) & (n - 1); 277#if defined(UFS1_ONLY) 278 memcpy(&addr1, (ufs1_daddr_t *)indbuf + n, 279 sizeof(ufs1_daddr_t)); 280 addr2 = addr1; 281#elif defined(UFS2_ONLY) 282 memcpy(&addr2, (ufs2_daddr_t *)indbuf + n, 283 sizeof(ufs2_daddr_t)); 284#else 285 if (fs.fs_magic == FS_UFS1_MAGIC) { 286 memcpy(&addr1, (ufs1_daddr_t *)indbuf + n, 287 sizeof(ufs1_daddr_t)); 288 addr2 = addr1; 289 } else 290 memcpy(&addr2, (ufs2_daddr_t *)indbuf + n, 291 sizeof(ufs2_daddr_t)); 292#endif 293 } else 294 return -1; 295 vbaddr = fsbtodb(&fs, addr2) + (off >> VBLKSHIFT) * DBPERVBLK; 296 vboff = off & VBLKMASK; 297 n = sblksize(&fs, (off_t)size, lbn) - (off & ~VBLKMASK); 298 if (n > VBLKSIZE) 299 n = VBLKSIZE; 300 if (blkmap != vbaddr) { 301 if (dskread(blkbuf, vbaddr, n >> DEV_BSHIFT)) 302 return -1; 303 blkmap = vbaddr; 304 } 305 n -= vboff; 306 if (n > nb) 307 n = nb; 308 memcpy(s, blkbuf + vboff, n); 309 s += n; 310 fs_off += n; 311 nb -= n; 312 } 313 314 if (fsizep != NULL) 315 *fsizep = size; 316 317 return nbyte; 318} 319 320static ssize_t 321fsread(ufs_ino_t inode, void *buf, size_t nbyte) 322{ 323 324 return fsread_size(inode, buf, nbyte, NULL); 325} 326 327