2 * Copyright (c) 2002 McAfee, Inc.
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
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
32 * Copyright (c) 1998 Robert Nordier
33 * All rights reserved.
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
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
46 #include <sys/cdefs.h>
48 #include <ufs/ufs/dinode.h>
49 #include <ufs/ufs/dir.h>
50 #include <ufs/ffs/fs.h>
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. */
57 #define cgbase(fs, c) ((ufs2_daddr_t)((fs)->fs_fpg * (c)))
60 typedef uint32_t ufs_ino_t
;
63 * We use 4k `virtual' blocks for filesystem data, whatever the actual
64 * filesystem block size. FFS blocks are always a multiple of 4k.
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)
80 /* Buffers that must not span a 64k boundary. */
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 */
87 static struct dmadat
*dmadat
;
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
);
93 static uint8_t ls
, dsk_meta
;
94 static uint32_t fs_off
;
97 static struct ufs1_dinode dp1
;
101 static struct ufs2_dinode dp2
;
104 static ufs_ino_t inomap
;
105 static ufs2_daddr_t blkmap
, indmap
;
107 static __inline
uint8_t
108 fsfind(const char *name
, ufs_ino_t
* ino
)
110 static char buf
[DEV_BSIZE
];
116 while ((n
= fsread(*ino
, buf
, DEV_BSIZE
)) > 0)
117 for (s
= buf
; s
< buf
+ DEV_BSIZE
;) {
120 printf("%s ", d
->d_name
);
121 else if (!strcmp(name
, d
->d_name
)) {
123 return inode_type(*ino
);
133 lookup(const char *path
)
135 static char name
[UFS_MAXNAMLEN
+ 1];
148 for (s
= path
; *s
&& *s
!= '/'; s
++);
149 if ((n
= s
- path
) > UFS_MAXNAMLEN
)
151 ls
= *path
== '?' && n
== 1 && !*s
;
152 memcpy(name
, path
, n
);
155 printf("%s: not a directory.\n", name
);
158 if ((dt
= fsfind(name
, &ino
)) <= 0)
162 return dt
== DT_REG
? ino
: 0;
166 * Possible superblock locations ordered from most to least likely.
168 static int sblock_try
[] = SBLOCKSEARCH
;
170 #if defined(UFS2_ONLY)
171 #define DIP(field) dp2.field
172 #elif defined(UFS1_ONLY)
173 #define DIP(field) dp1.field
175 #define DIP(field) fs.fs_magic == FS_UFS1_MAGIC ? dp1.field : dp2.field
179 inode_type(ufs_ino_t inode
)
184 blkbuf
= dmadat
->blkbuf
;
188 if (inomap
!= inode
) {
190 if (dskread(blkbuf
, INO_TO_VBA(&fs
, n
, inode
), DBPERVBLK
))
192 n
= INO_TO_VBO(n
, inode
);
193 #if defined(UFS1_ONLY)
194 memcpy(&dp1
, (struct ufs1_dinode
*)blkbuf
+ n
,
195 sizeof(struct ufs1_dinode
));
196 #elif defined(UFS2_ONLY)
197 memcpy(&dp2
, (struct ufs2_dinode
*)blkbuf
+ n
,
198 sizeof(struct ufs2_dinode
));
200 if (fs
.fs_magic
== FS_UFS1_MAGIC
)
201 memcpy(&dp1
, (struct ufs1_dinode
*)blkbuf
+ n
,
202 sizeof(struct ufs1_dinode
));
204 memcpy(&dp2
, (struct ufs2_dinode
*)blkbuf
+ n
,
205 sizeof(struct ufs2_dinode
));
211 return (IFTODT(DIP(di_mode
)));
215 fsread_size(ufs_ino_t inode
, void *buf
, size_t nbyte
, size_t *fsizep
)
220 size_t n
, nb
, size
, off
, vboff
;
222 ufs2_daddr_t addr2
, vbaddr
;
225 /* Basic parameter validation. */
226 if ((buf
== NULL
&& nbyte
!= 0) || dmadat
== NULL
)
229 blkbuf
= dmadat
->blkbuf
;
230 indbuf
= dmadat
->indbuf
;
233 * Force probe if inode is zero to ensure we have a valid fs, otherwise
234 * when probing multiple paritions, reads from subsequent parititions
235 * will incorrectly succeed.
237 if (!dsk_meta
|| inode
== 0) {
240 for (n
= 0; sblock_try
[n
] != -1; n
++) {
241 if (dskread(dmadat
->sbbuf
, sblock_try
[n
] / DEV_BSIZE
,
242 SBLOCKSIZE
/ DEV_BSIZE
))
244 memcpy(&fs
, dmadat
->sbbuf
, sizeof(struct fs
));
246 #if defined(UFS1_ONLY)
247 fs
.fs_magic
== FS_UFS1_MAGIC
248 #elif defined(UFS2_ONLY)
249 (fs
.fs_magic
== FS_UFS2_MAGIC
&&
250 fs
.fs_sblockloc
== sblock_try
[n
])
252 fs
.fs_magic
== FS_UFS1_MAGIC
||
253 (fs
.fs_magic
== FS_UFS2_MAGIC
&&
254 fs
.fs_sblockloc
== sblock_try
[n
])
257 fs
.fs_bsize
<= MAXBSIZE
&&
258 fs
.fs_bsize
>= (int32_t)sizeof(struct fs
))
261 if (sblock_try
[n
] == -1) {
266 memcpy(&fs
, dmadat
->sbbuf
, sizeof(struct fs
));
269 if (inomap
!= inode
) {
271 if (dskread(blkbuf
, INO_TO_VBA(&fs
, n
, inode
), DBPERVBLK
))
273 n
= INO_TO_VBO(n
, inode
);
274 #if defined(UFS1_ONLY)
275 memcpy(&dp1
, (struct ufs1_dinode
*)(void *)blkbuf
+ n
,
277 #elif defined(UFS2_ONLY)
278 memcpy(&dp2
, (struct ufs2_dinode
*)(void *)blkbuf
+ n
,
281 if (fs
.fs_magic
== FS_UFS1_MAGIC
)
282 memcpy(&dp1
, (struct ufs1_dinode
*)(void *)blkbuf
+ n
,
285 memcpy(&dp2
, (struct ufs2_dinode
*)(void *)blkbuf
+ n
,
299 lbn
= lblkno(&fs
, fs_off
);
300 off
= blkoff(&fs
, fs_off
);
302 addr2
= DIP(di_db
[lbn
]);
303 } else if (lbn
< NDADDR
+ NINDIR(&fs
)) {
304 n
= INDIRPERVBLK(&fs
);
305 addr2
= DIP(di_ib
[0]);
306 u
= (u_int
)(lbn
- NDADDR
) / n
* DBPERVBLK
;
307 vbaddr
= fsbtodb(&fs
, addr2
) + u
;
308 if (indmap
!= vbaddr
) {
309 if (dskread(indbuf
, vbaddr
, DBPERVBLK
))
313 n
= (lbn
- NDADDR
) & (n
- 1);
314 #if defined(UFS1_ONLY)
315 memcpy(&addr1
, (ufs1_daddr_t
*)indbuf
+ n
,
316 sizeof(ufs1_daddr_t
));
318 #elif defined(UFS2_ONLY)
319 memcpy(&addr2
, (ufs2_daddr_t
*)indbuf
+ n
,
320 sizeof(ufs2_daddr_t
));
322 if (fs
.fs_magic
== FS_UFS1_MAGIC
) {
323 memcpy(&addr1
, (ufs1_daddr_t
*)indbuf
+ n
,
324 sizeof(ufs1_daddr_t
));
327 memcpy(&addr2
, (ufs2_daddr_t
*)indbuf
+ n
,
328 sizeof(ufs2_daddr_t
));
332 vbaddr
= fsbtodb(&fs
, addr2
) + (off
>> VBLKSHIFT
) * DBPERVBLK
;
333 vboff
= off
& VBLKMASK
;
334 n
= sblksize(&fs
, (off_t
)size
, lbn
) - (off
& ~VBLKMASK
);
337 if (blkmap
!= vbaddr
) {
338 if (dskread(blkbuf
, vbaddr
, n
>> DEV_BSHIFT
))
345 memcpy(s
, blkbuf
+ vboff
, n
);
358 fsread(ufs_ino_t inode
, void *buf
, size_t nbyte
)
361 return fsread_size(inode
, buf
, nbyte
, NULL
);