1119483Sobrien/*- 2141060Srwatson * Copyright (c) 2002 McAfee, Inc. 398542Smckusick * All rights reserved. 498542Smckusick * 598542Smckusick * This software was developed for the FreeBSD Project by Marshall 6141060Srwatson * Kirk McKusick and McAfee Research,, the Security Research Division of 7141060Srwatson * McAfee, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as 8141060Srwatson * part of the DARPA CHATS research program 998542Smckusick * 10141060Srwatson * Redistribution and use in source and binary forms, with or without 11141060Srwatson * modification, are permitted provided that the following conditions 12141060Srwatson * are met: 13141060Srwatson * 1. Redistributions of source code must retain the above copyright 14141060Srwatson * notice, this list of conditions and the following disclaimer. 15141060Srwatson * 2. Redistributions in binary form must reproduce the above copyright 16141060Srwatson * notice, this list of conditions and the following disclaimer in the 17141060Srwatson * documentation and/or other materials provided with the distribution. 18141060Srwatson * 19141060Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20141060Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21141060Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22141060Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23141060Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24141060Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25141060Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26141060Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27141060Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28141060Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29141060Srwatson * SUCH DAMAGE. 30141060Srwatson */ 31141060Srwatson/*- 3297860Sphk * Copyright (c) 1998 Robert Nordier 3397860Sphk * All rights reserved. 3497860Sphk * 3597860Sphk * Redistribution and use in source and binary forms are freely 3697860Sphk * permitted provided that the above copyright notice and this 3797860Sphk * paragraph and the following disclaimer are duplicated in all 3897860Sphk * such forms. 3997860Sphk * 4097860Sphk * This software is provided "AS IS" and without any express or 4197860Sphk * implied warranties, including, without limitation, the implied 4297860Sphk * warranties of merchantability and fitness for a particular 4397860Sphk * purpose. 4497860Sphk */ 4597860Sphk 46119483Sobrien#include <sys/cdefs.h> 47119483Sobrien__FBSDID("$FreeBSD$"); 4897860Sphk 4998542Smckusick#include <ufs/ufs/dinode.h> 50192972Sdfr#include <ufs/ufs/dir.h> 5197860Sphk#include <ufs/ffs/fs.h> 52223938Smarius 53173040Sjhb#ifdef UFS_SMALL_CGBASE 54111456Sobrien/* XXX: Revert to old (broken for over 1.5Tb filesystems) version of cgbase 55173040Sjhb (see sys/ufs/ffs/fs.h rev 1.39) so that small boot loaders (e.g. boot2) can 56173040Sjhb support both UFS1 and UFS2. */ 57111410Smckusick#undef cgbase 58111410Smckusick#define cgbase(fs, c) ((ufs2_daddr_t)((fs)->fs_fpg * (c))) 59111456Sobrien#endif 6097860Sphk 61235988Sglebtypedef uint32_t ufs_ino_t; 62235988Sgleb 6397860Sphk/* 6497860Sphk * We use 4k `virtual' blocks for filesystem data, whatever the actual 6597860Sphk * filesystem block size. FFS blocks are always a multiple of 4k. 6697860Sphk */ 67104678Sphk#define VBLKSHIFT 12 68104678Sphk#define VBLKSIZE (1 << VBLKSHIFT) 6997860Sphk#define VBLKMASK (VBLKSIZE - 1) 7097860Sphk#define DBPERVBLK (VBLKSIZE / DEV_BSIZE) 71104678Sphk#define INDIRPERVBLK(fs) (NINDIR(fs) / ((fs)->fs_bsize >> VBLKSHIFT)) 72104678Sphk#define IPERVBLK(fs) (INOPB(fs) / ((fs)->fs_bsize >> VBLKSHIFT)) 7398542Smckusick#define INO_TO_VBA(fs, ipervblk, x) \ 7498542Smckusick (fsbtodb(fs, cgimin(fs, ino_to_cg(fs, x))) + \ 7598542Smckusick (((x) % (fs)->fs_ipg) / (ipervblk) * DBPERVBLK)) 7698542Smckusick#define INO_TO_VBO(ipervblk, x) ((x) % ipervblk) 7797860Sphk#define FS_TO_VBA(fs, fsb, off) (fsbtodb(fs, fsb) + \ 7897860Sphk ((off) / VBLKSIZE) * DBPERVBLK) 7997860Sphk#define FS_TO_VBO(fs, fsb, off) ((off) & VBLKMASK) 8097860Sphk 8197860Sphk/* Buffers that must not span a 64k boundary. */ 8297864Sphkstruct dmadat { 8398542Smckusick char blkbuf[VBLKSIZE]; /* filesystem blocks */ 8498542Smckusick char indbuf[VBLKSIZE]; /* indir blocks */ 8598542Smckusick char sbbuf[SBLOCKSIZE]; /* superblock */ 8698542Smckusick char secbuf[DEV_BSIZE]; /* for MBR/disklabel */ 8797864Sphk}; 8897864Sphkstatic struct dmadat *dmadat; 8997860Sphk 90235988Sglebstatic ufs_ino_t lookup(const char *); 91235988Sglebstatic ssize_t fsread(ufs_ino_t, void *, size_t); 9297860Sphk 93219452Srdivackystatic uint8_t ls, dsk_meta; 9497860Sphkstatic uint32_t fs_off; 9597860Sphk 96223938Smariusstatic __inline uint8_t 97235988Sglebfsfind(const char *name, ufs_ino_t * ino) 9897860Sphk{ 99233105Smarius static char buf[DEV_BSIZE]; 100192972Sdfr struct direct *d; 10197861Sphk char *s; 10297861Sphk ssize_t n; 10397860Sphk 10497861Sphk fs_off = 0; 10597861Sphk while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) 10698542Smckusick for (s = buf; s < buf + DEV_BSIZE;) { 10798542Smckusick d = (void *)s; 10898542Smckusick if (ls) 10998542Smckusick printf("%s ", d->d_name); 11098542Smckusick else if (!strcmp(name, d->d_name)) { 111192972Sdfr *ino = d->d_ino; 11298542Smckusick return d->d_type; 11398542Smckusick } 11498542Smckusick s += d->d_reclen; 11597861Sphk } 11697861Sphk if (n != -1 && ls) 11797864Sphk printf("\n"); 11897861Sphk return 0; 11997860Sphk} 12097860Sphk 121235988Sglebstatic ufs_ino_t 12297860Sphklookup(const char *path) 12397860Sphk{ 124233105Smarius static char name[MAXNAMLEN + 1]; 12597861Sphk const char *s; 126235988Sgleb ufs_ino_t ino; 12797861Sphk ssize_t n; 128218716Sdim uint8_t dt; 12997860Sphk 13097861Sphk ino = ROOTINO; 13197861Sphk dt = DT_DIR; 13297861Sphk for (;;) { 13397861Sphk if (*path == '/') 13497861Sphk path++; 13597861Sphk if (!*path) 13697861Sphk break; 13797861Sphk for (s = path; *s && *s != '/'; s++); 13898542Smckusick if ((n = s - path) > MAXNAMLEN) 13998542Smckusick return 0; 14097861Sphk ls = *path == '?' && n == 1 && !*s; 14197861Sphk memcpy(name, path, n); 14297861Sphk name[n] = 0; 14397864Sphk if (dt != DT_DIR) { 14497864Sphk printf("%s: not a directory.\n", name); 14597864Sphk return (0); 14697864Sphk } 14797861Sphk if ((dt = fsfind(name, &ino)) <= 0) 14897861Sphk break; 14997861Sphk path = s; 15097861Sphk } 15197861Sphk return dt == DT_REG ? ino : 0; 15297860Sphk} 15397860Sphk 15498542Smckusick/* 15598542Smckusick * Possible superblock locations ordered from most to least likely. 15698542Smckusick */ 15798542Smckusickstatic int sblock_try[] = SBLOCKSEARCH; 15898542Smckusick 159107877Sphk#if defined(UFS2_ONLY) 160107877Sphk#define DIP(field) dp2.field 161107877Sphk#elif defined(UFS1_ONLY) 162107877Sphk#define DIP(field) dp1.field 163107877Sphk#else 164223938Smarius#define DIP(field) fs.fs_magic == FS_UFS1_MAGIC ? dp1.field : dp2.field 165107877Sphk#endif 16698542Smckusick 16798542Smckusickstatic ssize_t 168235988Sglebfsread(ufs_ino_t inode, void *buf, size_t nbyte) 16998542Smckusick{ 170107877Sphk#ifndef UFS2_ONLY 17198542Smckusick static struct ufs1_dinode dp1; 172233105Smarius ufs1_daddr_t addr1; 173107877Sphk#endif 174107877Sphk#ifndef UFS1_ONLY 17598542Smckusick static struct ufs2_dinode dp2; 176107877Sphk#endif 177233105Smarius static struct fs fs; 178235988Sgleb static ufs_ino_t inomap; 17998542Smckusick char *blkbuf; 180104678Sphk void *indbuf; 18198542Smckusick char *s; 18298542Smckusick size_t n, nb, size, off, vboff; 18398542Smckusick ufs_lbn_t lbn; 184233105Smarius ufs2_daddr_t addr2, vbaddr; 18598542Smckusick static ufs2_daddr_t blkmap, indmap; 186104678Sphk u_int u; 18798542Smckusick 18898542Smckusick blkbuf = dmadat->blkbuf; 18998542Smckusick indbuf = dmadat->indbuf; 19098542Smckusick if (!dsk_meta) { 19198542Smckusick inomap = 0; 19298542Smckusick for (n = 0; sblock_try[n] != -1; n++) { 193223938Smarius if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE, 19498542Smckusick SBLOCKSIZE / DEV_BSIZE)) 19598542Smckusick return -1; 196223938Smarius memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 197107877Sphk if (( 198107877Sphk#if defined(UFS1_ONLY) 199223938Smarius fs.fs_magic == FS_UFS1_MAGIC 200107877Sphk#elif defined(UFS2_ONLY) 201223938Smarius (fs.fs_magic == FS_UFS2_MAGIC && 202223938Smarius fs.fs_sblockloc == sblock_try[n]) 203107877Sphk#else 204223938Smarius fs.fs_magic == FS_UFS1_MAGIC || 205223938Smarius (fs.fs_magic == FS_UFS2_MAGIC && 206223938Smarius fs.fs_sblockloc == sblock_try[n]) 207107877Sphk#endif 208107877Sphk ) && 209223938Smarius fs.fs_bsize <= MAXBSIZE && 210223938Smarius fs.fs_bsize >= sizeof(struct fs)) 21198542Smckusick break; 21298542Smckusick } 21398542Smckusick if (sblock_try[n] == -1) { 21498542Smckusick printf("Not ufs\n"); 21598542Smckusick return -1; 21698542Smckusick } 21798542Smckusick dsk_meta++; 218223938Smarius } else 219223938Smarius memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 22098542Smckusick if (!inode) 22198542Smckusick return 0; 22298542Smckusick if (inomap != inode) { 223223938Smarius n = IPERVBLK(&fs); 224223938Smarius if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK)) 22598542Smckusick return -1; 22698542Smckusick n = INO_TO_VBO(n, inode); 227107877Sphk#if defined(UFS1_ONLY) 228211747Srpaulo memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, 229211747Srpaulo sizeof(struct ufs1_dinode)); 230107877Sphk#elif defined(UFS2_ONLY) 231211747Srpaulo memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, 232211747Srpaulo sizeof(struct ufs2_dinode)); 233107877Sphk#else 234223938Smarius if (fs.fs_magic == FS_UFS1_MAGIC) 235211747Srpaulo memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, 236211747Srpaulo sizeof(struct ufs1_dinode)); 23798542Smckusick else 238211747Srpaulo memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, 239211747Srpaulo sizeof(struct ufs2_dinode)); 240107877Sphk#endif 24198542Smckusick inomap = inode; 24298542Smckusick fs_off = 0; 24398542Smckusick blkmap = indmap = 0; 24498542Smckusick } 24598542Smckusick s = buf; 24698542Smckusick size = DIP(di_size); 24798542Smckusick n = size - fs_off; 24898542Smckusick if (nbyte > n) 24998542Smckusick nbyte = n; 25098542Smckusick nb = nbyte; 25198542Smckusick while (nb) { 252223938Smarius lbn = lblkno(&fs, fs_off); 253223938Smarius off = blkoff(&fs, fs_off); 25498542Smckusick if (lbn < NDADDR) { 255233105Smarius addr2 = DIP(di_db[lbn]); 256223938Smarius } else if (lbn < NDADDR + NINDIR(&fs)) { 257223938Smarius n = INDIRPERVBLK(&fs); 258233105Smarius addr2 = DIP(di_ib[0]); 259179634Skib u = (u_int)(lbn - NDADDR) / n * DBPERVBLK; 260233105Smarius vbaddr = fsbtodb(&fs, addr2) + u; 26198542Smckusick if (indmap != vbaddr) { 26298542Smckusick if (dskread(indbuf, vbaddr, DBPERVBLK)) 26398542Smckusick return -1; 26498542Smckusick indmap = vbaddr; 26598542Smckusick } 266104678Sphk n = (lbn - NDADDR) & (n - 1); 267107877Sphk#if defined(UFS1_ONLY) 268233105Smarius memcpy(&addr1, (ufs1_daddr_t *)indbuf + n, 269232822Smarius sizeof(ufs1_daddr_t)); 270233105Smarius addr2 = addr1; 271107877Sphk#elif defined(UFS2_ONLY) 272233105Smarius memcpy(&addr2, (ufs2_daddr_t *)indbuf + n, 273223938Smarius sizeof(ufs2_daddr_t)); 274107877Sphk#else 275233105Smarius if (fs.fs_magic == FS_UFS1_MAGIC) { 276233105Smarius memcpy(&addr1, (ufs1_daddr_t *)indbuf + n, 277223938Smarius sizeof(ufs1_daddr_t)); 278233105Smarius addr2 = addr1; 279233105Smarius } else 280233105Smarius memcpy(&addr2, (ufs2_daddr_t *)indbuf + n, 281223938Smarius sizeof(ufs2_daddr_t)); 282107877Sphk#endif 283233105Smarius } else 28498542Smckusick return -1; 285233105Smarius vbaddr = fsbtodb(&fs, addr2) + (off >> VBLKSHIFT) * DBPERVBLK; 28698542Smckusick vboff = off & VBLKMASK; 287223938Smarius n = sblksize(&fs, size, lbn) - (off & ~VBLKMASK); 28898542Smckusick if (n > VBLKSIZE) 28998542Smckusick n = VBLKSIZE; 29098542Smckusick if (blkmap != vbaddr) { 29198542Smckusick if (dskread(blkbuf, vbaddr, n >> DEV_BSHIFT)) 29298542Smckusick return -1; 29398542Smckusick blkmap = vbaddr; 29498542Smckusick } 29598542Smckusick n -= vboff; 29698542Smckusick if (n > nb) 29798542Smckusick n = nb; 29898542Smckusick memcpy(s, blkbuf + vboff, n); 29998542Smckusick s += n; 30098542Smckusick fs_off += n; 30198542Smckusick nb -= n; 30298542Smckusick } 30398542Smckusick return nbyte; 30498542Smckusick} 305