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 6197860Sphk/* 6297860Sphk * We use 4k `virtual' blocks for filesystem data, whatever the actual 6397860Sphk * filesystem block size. FFS blocks are always a multiple of 4k. 6497860Sphk */ 65104678Sphk#define VBLKSHIFT 12 66104678Sphk#define VBLKSIZE (1 << VBLKSHIFT) 6797860Sphk#define VBLKMASK (VBLKSIZE - 1) 6897860Sphk#define DBPERVBLK (VBLKSIZE / DEV_BSIZE) 69104678Sphk#define INDIRPERVBLK(fs) (NINDIR(fs) / ((fs)->fs_bsize >> VBLKSHIFT)) 70104678Sphk#define IPERVBLK(fs) (INOPB(fs) / ((fs)->fs_bsize >> VBLKSHIFT)) 7198542Smckusick#define INO_TO_VBA(fs, ipervblk, x) \ 7298542Smckusick (fsbtodb(fs, cgimin(fs, ino_to_cg(fs, x))) + \ 7398542Smckusick (((x) % (fs)->fs_ipg) / (ipervblk) * DBPERVBLK)) 7498542Smckusick#define INO_TO_VBO(ipervblk, x) ((x) % ipervblk) 7597860Sphk#define FS_TO_VBA(fs, fsb, off) (fsbtodb(fs, fsb) + \ 7697860Sphk ((off) / VBLKSIZE) * DBPERVBLK) 7797860Sphk#define FS_TO_VBO(fs, fsb, off) ((off) & VBLKMASK) 7897860Sphk 7997860Sphk/* Buffers that must not span a 64k boundary. */ 8097864Sphkstruct dmadat { 8198542Smckusick char blkbuf[VBLKSIZE]; /* filesystem blocks */ 8298542Smckusick char indbuf[VBLKSIZE]; /* indir blocks */ 8398542Smckusick char sbbuf[SBLOCKSIZE]; /* superblock */ 8498542Smckusick char secbuf[DEV_BSIZE]; /* for MBR/disklabel */ 8597864Sphk}; 8697864Sphkstatic struct dmadat *dmadat; 8797860Sphk 8897860Sphkstatic ino_t lookup(const char *); 8997860Sphkstatic ssize_t fsread(ino_t, void *, size_t); 9097860Sphk 91219452Srdivackystatic uint8_t ls, dsk_meta; 9297860Sphkstatic uint32_t fs_off; 9397860Sphk 94223938Smariusstatic __inline uint8_t 9597860Sphkfsfind(const char *name, ino_t * ino) 9697860Sphk{ 97233468Smarius static char buf[DEV_BSIZE]; 98192972Sdfr struct direct *d; 9997861Sphk char *s; 10097861Sphk ssize_t n; 10197860Sphk 10297861Sphk fs_off = 0; 10397861Sphk while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) 10498542Smckusick for (s = buf; s < buf + DEV_BSIZE;) { 10598542Smckusick d = (void *)s; 10698542Smckusick if (ls) 10798542Smckusick printf("%s ", d->d_name); 10898542Smckusick else if (!strcmp(name, d->d_name)) { 109192972Sdfr *ino = d->d_ino; 11098542Smckusick return d->d_type; 11198542Smckusick } 11298542Smckusick s += d->d_reclen; 11397861Sphk } 11497861Sphk if (n != -1 && ls) 11597864Sphk printf("\n"); 11697861Sphk return 0; 11797860Sphk} 11897860Sphk 11997860Sphkstatic ino_t 12097860Sphklookup(const char *path) 12197860Sphk{ 122233468Smarius static char name[MAXNAMLEN + 1]; 12397861Sphk const char *s; 12497861Sphk ino_t ino; 12597861Sphk ssize_t n; 126218716Sdim uint8_t dt; 12797860Sphk 12897861Sphk ino = ROOTINO; 12997861Sphk dt = DT_DIR; 13097861Sphk for (;;) { 13197861Sphk if (*path == '/') 13297861Sphk path++; 13397861Sphk if (!*path) 13497861Sphk break; 13597861Sphk for (s = path; *s && *s != '/'; s++); 13698542Smckusick if ((n = s - path) > MAXNAMLEN) 13798542Smckusick return 0; 13897861Sphk ls = *path == '?' && n == 1 && !*s; 13997861Sphk memcpy(name, path, n); 14097861Sphk name[n] = 0; 14197864Sphk if (dt != DT_DIR) { 14297864Sphk printf("%s: not a directory.\n", name); 14397864Sphk return (0); 14497864Sphk } 14597861Sphk if ((dt = fsfind(name, &ino)) <= 0) 14697861Sphk break; 14797861Sphk path = s; 14897861Sphk } 14997861Sphk return dt == DT_REG ? ino : 0; 15097860Sphk} 15197860Sphk 15298542Smckusick/* 15398542Smckusick * Possible superblock locations ordered from most to least likely. 15498542Smckusick */ 15598542Smckusickstatic int sblock_try[] = SBLOCKSEARCH; 15698542Smckusick 157107877Sphk#if defined(UFS2_ONLY) 158107877Sphk#define DIP(field) dp2.field 159107877Sphk#elif defined(UFS1_ONLY) 160107877Sphk#define DIP(field) dp1.field 161107877Sphk#else 162223938Smarius#define DIP(field) fs.fs_magic == FS_UFS1_MAGIC ? dp1.field : dp2.field 163107877Sphk#endif 16498542Smckusick 16598542Smckusickstatic ssize_t 16698542Smckusickfsread(ino_t inode, void *buf, size_t nbyte) 16798542Smckusick{ 168107877Sphk#ifndef UFS2_ONLY 16998542Smckusick static struct ufs1_dinode dp1; 170233468Smarius ufs1_daddr_t addr1; 171107877Sphk#endif 172107877Sphk#ifndef UFS1_ONLY 17398542Smckusick static struct ufs2_dinode dp2; 174107877Sphk#endif 175233468Smarius static struct fs fs; 17698542Smckusick static ino_t inomap; 17798542Smckusick char *blkbuf; 178104678Sphk void *indbuf; 17998542Smckusick char *s; 18098542Smckusick size_t n, nb, size, off, vboff; 18198542Smckusick ufs_lbn_t lbn; 182233468Smarius ufs2_daddr_t addr2, vbaddr; 18398542Smckusick static ufs2_daddr_t blkmap, indmap; 184104678Sphk u_int u; 18598542Smckusick 18698542Smckusick blkbuf = dmadat->blkbuf; 18798542Smckusick indbuf = dmadat->indbuf; 18898542Smckusick if (!dsk_meta) { 18998542Smckusick inomap = 0; 19098542Smckusick for (n = 0; sblock_try[n] != -1; n++) { 191223938Smarius if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE, 19298542Smckusick SBLOCKSIZE / DEV_BSIZE)) 19398542Smckusick return -1; 194223938Smarius memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 195107877Sphk if (( 196107877Sphk#if defined(UFS1_ONLY) 197223938Smarius fs.fs_magic == FS_UFS1_MAGIC 198107877Sphk#elif defined(UFS2_ONLY) 199223938Smarius (fs.fs_magic == FS_UFS2_MAGIC && 200223938Smarius fs.fs_sblockloc == sblock_try[n]) 201107877Sphk#else 202223938Smarius fs.fs_magic == FS_UFS1_MAGIC || 203223938Smarius (fs.fs_magic == FS_UFS2_MAGIC && 204223938Smarius fs.fs_sblockloc == sblock_try[n]) 205107877Sphk#endif 206107877Sphk ) && 207223938Smarius fs.fs_bsize <= MAXBSIZE && 208223938Smarius fs.fs_bsize >= sizeof(struct fs)) 20998542Smckusick break; 21098542Smckusick } 21198542Smckusick if (sblock_try[n] == -1) { 21298542Smckusick printf("Not ufs\n"); 21398542Smckusick return -1; 21498542Smckusick } 21598542Smckusick dsk_meta++; 216223938Smarius } else 217223938Smarius memcpy(&fs, dmadat->sbbuf, sizeof(struct fs)); 21898542Smckusick if (!inode) 21998542Smckusick return 0; 22098542Smckusick if (inomap != inode) { 221223938Smarius n = IPERVBLK(&fs); 222223938Smarius if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK)) 22398542Smckusick return -1; 22498542Smckusick n = INO_TO_VBO(n, inode); 225107877Sphk#if defined(UFS1_ONLY) 226211747Srpaulo memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, 227211747Srpaulo sizeof(struct ufs1_dinode)); 228107877Sphk#elif defined(UFS2_ONLY) 229211747Srpaulo memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, 230211747Srpaulo sizeof(struct ufs2_dinode)); 231107877Sphk#else 232223938Smarius if (fs.fs_magic == FS_UFS1_MAGIC) 233211747Srpaulo memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n, 234211747Srpaulo sizeof(struct ufs1_dinode)); 23598542Smckusick else 236211747Srpaulo memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n, 237211747Srpaulo sizeof(struct ufs2_dinode)); 238107877Sphk#endif 23998542Smckusick inomap = inode; 24098542Smckusick fs_off = 0; 24198542Smckusick blkmap = indmap = 0; 24298542Smckusick } 24398542Smckusick s = buf; 24498542Smckusick size = DIP(di_size); 24598542Smckusick n = size - fs_off; 24698542Smckusick if (nbyte > n) 24798542Smckusick nbyte = n; 24898542Smckusick nb = nbyte; 24998542Smckusick while (nb) { 250223938Smarius lbn = lblkno(&fs, fs_off); 251223938Smarius off = blkoff(&fs, fs_off); 25298542Smckusick if (lbn < NDADDR) { 253233468Smarius addr2 = DIP(di_db[lbn]); 254223938Smarius } else if (lbn < NDADDR + NINDIR(&fs)) { 255223938Smarius n = INDIRPERVBLK(&fs); 256233468Smarius addr2 = DIP(di_ib[0]); 257179634Skib u = (u_int)(lbn - NDADDR) / n * DBPERVBLK; 258233468Smarius vbaddr = fsbtodb(&fs, addr2) + u; 25998542Smckusick if (indmap != vbaddr) { 26098542Smckusick if (dskread(indbuf, vbaddr, DBPERVBLK)) 26198542Smckusick return -1; 26298542Smckusick indmap = vbaddr; 26398542Smckusick } 264104678Sphk n = (lbn - NDADDR) & (n - 1); 265107877Sphk#if defined(UFS1_ONLY) 266233468Smarius memcpy(&addr1, (ufs1_daddr_t *)indbuf + n, 267232962Smarius sizeof(ufs1_daddr_t)); 268233468Smarius addr2 = addr1; 269107877Sphk#elif defined(UFS2_ONLY) 270233468Smarius memcpy(&addr2, (ufs2_daddr_t *)indbuf + n, 271223938Smarius sizeof(ufs2_daddr_t)); 272107877Sphk#else 273233468Smarius if (fs.fs_magic == FS_UFS1_MAGIC) { 274233468Smarius memcpy(&addr1, (ufs1_daddr_t *)indbuf + n, 275223938Smarius sizeof(ufs1_daddr_t)); 276233468Smarius addr2 = addr1; 277233468Smarius } else 278233468Smarius memcpy(&addr2, (ufs2_daddr_t *)indbuf + n, 279223938Smarius sizeof(ufs2_daddr_t)); 280107877Sphk#endif 281233468Smarius } else 28298542Smckusick return -1; 283233468Smarius vbaddr = fsbtodb(&fs, addr2) + (off >> VBLKSHIFT) * DBPERVBLK; 28498542Smckusick vboff = off & VBLKMASK; 285223938Smarius n = sblksize(&fs, size, lbn) - (off & ~VBLKMASK); 28698542Smckusick if (n > VBLKSIZE) 28798542Smckusick n = VBLKSIZE; 28898542Smckusick if (blkmap != vbaddr) { 28998542Smckusick if (dskread(blkbuf, vbaddr, n >> DEV_BSHIFT)) 29098542Smckusick return -1; 29198542Smckusick blkmap = vbaddr; 29298542Smckusick } 29398542Smckusick n -= vboff; 29498542Smckusick if (n > nb) 29598542Smckusick n = nb; 29698542Smckusick memcpy(s, blkbuf + vboff, n); 29798542Smckusick s += n; 29898542Smckusick fs_off += n; 29998542Smckusick nb -= n; 30098542Smckusick } 30198542Smckusick return nbyte; 30298542Smckusick} 303