2 * Copyright (c) 2002 Networks Associates Technology, Inc.
5 * This software was developed for the FreeBSD Project by Marshall
6 * Kirk McKusick and Network Associates Laboratories, the Security
7 * Research Division of Network Associates, Inc. under DARPA/SPAWAR
8 * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
11 * Copyright (c) 1998 Robert Nordier
12 * All rights reserved.
14 * Redistribution and use in source and binary forms are freely
15 * permitted provided that the above copyright notice and this
16 * paragraph and the following disclaimer are duplicated in all
19 * This software is provided "AS IS" and without any express or
20 * implied warranties, including, without limitation, the implied
21 * warranties of merchantability and fitness for a particular
24 * $FreeBSD: src/sys/boot/common/ufsread.c,v 1.12 2003/08/25 23:30:41 obrien Exp $
25 * $DragonFly: src/sys/boot/common/ufsread.c,v 1.5 2008/09/13 11:46:28 corecode Exp $
31 #include <sys/param.h>
33 #include <sys/dtype.h>
34 #include <sys/dirent.h>
35 #include <machine/bootinfo.h>
36 #include <machine/elf.h>
37 #include <vfs/ufs/dir.h>
42 /* XXX: Revert to old (broken for over 1.5Tb filesystems) version of cgbase
43 (see sys/ufs/ffs/fs.h rev 1.39) so that i386 boot loader (boot2) can
44 support both UFS1 and UFS2 again. */
46 #define cgbase(fs, c) ((ufs2_daddr_t)((fs)->fs_fpg * (c)))
50 * We use 4k `virtual' blocks for filesystem data, whatever the actual
51 * filesystem block size. FFS blocks are always a multiple of 4k.
54 #define VBLKSIZE (1 << VBLKSHIFT)
55 #define VBLKMASK (VBLKSIZE - 1)
56 #define DBPERVBLK (VBLKSIZE / DEV_BSIZE)
57 #define INDIRPERVBLK(fs) (NINDIR(fs) / ((fs)->fs_bsize >> VBLKSHIFT))
58 #define IPERVBLK(fs) (INOPB(fs) / ((fs)->fs_bsize >> VBLKSHIFT))
59 #define INO_TO_VBA(fs, ipervblk, x) \
60 (fsbtodb(fs, cgimin(fs, ino_to_cg(fs, x))) + \
61 (((x) % (fs)->fs_ipg) / (ipervblk) * DBPERVBLK))
62 #define INO_TO_VBO(ipervblk, x) ((x) % ipervblk)
63 #define FS_TO_VBA(fs, fsb, off) (fsbtodb(fs, fsb) + \
64 ((off) / VBLKSIZE) * DBPERVBLK)
65 #define FS_TO_VBO(fs, fsb, off) ((off) & VBLKMASK)
67 /* Buffers that must not span a 64k boundary. */
69 struct boot2_dmadat boot2;
70 char blkbuf[VBLKSIZE]; /* filesystem blocks */
71 char indbuf[VBLKSIZE]; /* indir blocks */
72 char sbbuf[SBLOCKSIZE]; /* superblock */
75 #define fsdmadat ((struct ufs_dmadat *)boot2_dmadat)
77 static boot2_ino_t boot2_ufs_lookup(const char *);
78 static ssize_t boot2_ufs_read(boot2_ino_t, void *, size_t);
79 static int boot2_ufs_init(void);
81 const struct boot2_fsapi boot2_ufs_api = {
82 .fsinit = boot2_ufs_init,
83 .fslookup = boot2_ufs_lookup,
84 .fsread = boot2_ufs_read
88 fsfind(const char *name, ufs_ino_t *ino)
96 while ((n = boot2_ufs_read(*ino, buf, DEV_BSIZE)) > 0)
97 for (s = buf; s < buf + DEV_BSIZE;) {
100 printf("%s ", d->d_name);
101 else if (!strcmp(name, d->d_name)) {
113 boot2_ufs_lookup(const char *path)
115 char name[MAXNAMLEN + 1];
130 for (s = path; *s && *s != '/'; s++);
131 if ((n = s - path) > MAXNAMLEN)
133 ls = *path == '?' && n == 1 && !*s;
134 memcpy(name, path, n);
137 printf("%s: not a directory.\n", name);
140 if ((dt = fsfind(name, &ino)) <= 0)
144 return dt == DT_REG ? ino : 0;
148 * Possible superblock locations ordered from most to least likely.
150 static int sblock_try[] = SBLOCKSEARCH;
152 #if defined(UFS2_ONLY)
153 #define DIP(field) dp2.field
154 #elif defined(UFS1_ONLY)
155 #define DIP(field) dp1.field
157 #define DIP(field) fs->fs_magic == FS_UFS1_MAGIC ? dp1.field : dp2.field
160 static ufs_ino_t inomap;
161 static ufs2_daddr_t blkmap, indmap;
170 fs = (struct fs *)fsdmadat->sbbuf;
172 for (n = 0; sblock_try[n] != -1; n++) {
173 if (dskread(fs, sblock_try[n] / DEV_BSIZE,
174 SBLOCKSIZE / DEV_BSIZE)) {
178 #if defined(UFS1_ONLY)
179 fs->fs_magic == FS_UFS1_MAGIC
180 #elif defined(UFS2_ONLY)
181 (fs->fs_magic == FS_UFS2_MAGIC &&
182 fs->fs_sblockloc == sblock_try[n])
184 fs->fs_magic == FS_UFS1_MAGIC ||
185 (fs->fs_magic == FS_UFS2_MAGIC &&
186 fs->fs_sblockloc == sblock_try[n])
189 fs->fs_bsize <= MAXBSIZE &&
190 fs->fs_bsize >= sizeof(struct fs))
193 if (sblock_try[n] == -1)
199 boot2_ufs_read(boot2_ino_t boot2_inode, void *buf, size_t nbyte)
202 static struct ufs1_dinode dp1;
205 static struct ufs2_dinode dp2;
207 ufs_ino_t ufs_inode = (ufs_ino_t)boot2_inode;
212 size_t n, nb, size, off, vboff;
214 ufs2_daddr_t addr, vbaddr;
217 blkbuf = fsdmadat->blkbuf;
218 indbuf = fsdmadat->indbuf;
219 fs = (struct fs *)fsdmadat->sbbuf;
223 if (inomap != ufs_inode) {
225 if (dskread(blkbuf, INO_TO_VBA(fs, n, ufs_inode), DBPERVBLK))
227 n = INO_TO_VBO(n, ufs_inode);
228 #if defined(UFS1_ONLY)
229 dp1 = ((struct ufs1_dinode *)blkbuf)[n];
230 #elif defined(UFS2_ONLY)
231 dp2 = ((struct ufs2_dinode *)blkbuf)[n];
233 if (fs->fs_magic == FS_UFS1_MAGIC)
234 dp1 = ((struct ufs1_dinode *)blkbuf)[n];
236 dp2 = ((struct ufs2_dinode *)blkbuf)[n];
249 lbn = lblkno(fs, fs_off);
250 off = blkoff(fs, fs_off);
252 addr = DIP(di_db[lbn]);
253 } else if (lbn < NDADDR + NINDIR(fs)) {
254 n = INDIRPERVBLK(fs);
255 addr = DIP(di_ib[0]);
256 u = (u_int)(lbn - NDADDR) / n * DBPERVBLK;
257 vbaddr = fsbtodb(fs, addr) + u;
258 if (indmap != vbaddr) {
259 if (dskread(indbuf, vbaddr, DBPERVBLK))
263 n = (lbn - NDADDR) & (n - 1);
264 #if defined(UFS1_ONLY)
265 addr = ((ufs1_daddr_t *)indbuf)[n];
266 #elif defined(UFS2_ONLY)
267 addr = ((ufs2_daddr_t *)indbuf)[n];
269 if (fs->fs_magic == FS_UFS1_MAGIC)
270 addr = ((ufs1_daddr_t *)indbuf)[n];
272 addr = ((ufs2_daddr_t *)indbuf)[n];
277 vbaddr = fsbtodb(fs, addr) + (off >> VBLKSHIFT) * DBPERVBLK;
278 vboff = off & VBLKMASK;
279 n = sblksize(fs, size, lbn) - (off & ~VBLKMASK);
282 if (blkmap != vbaddr) {
283 if (dskread(blkbuf, vbaddr, n >> DEV_BSHIFT))
290 memcpy(s, blkbuf + vboff, n);