1 1.15 dholland /* $NetBSD: readufs.c,v 1.15 2013/01/22 09:39:14 dholland Exp $ */ 2 1.4 itohy /* from Id: readufs.c,v 1.8 2003/04/08 09:19:32 itohy Exp */ 3 1.1 minoura 4 1.1 minoura /* 5 1.1 minoura * Read UFS (FFS / LFS) 6 1.1 minoura * 7 1.14 itohy * Written in 1999, 2002, 2003 by ITOH Yasufumi. 8 1.1 minoura * Public domain. 9 1.1 minoura * 10 1.1 minoura * Intended to be used for boot programs (first stage). 11 1.1 minoura * DON'T ADD ANY FANCY FEATURE. THIS SHALL BE COMPACT. 12 1.1 minoura */ 13 1.1 minoura 14 1.1 minoura #include "readufs.h" 15 1.1 minoura 16 1.1 minoura #define fs ufs_info 17 1.1 minoura 18 1.10 dsl static void raw_read_queue(void *buf, daddr_t blkpos, size_t bytelen); 19 1.10 dsl static int ufs_read_indirect(daddr_t blk, int level, uint8_t **buf, 20 1.10 dsl unsigned *poff, size_t count); 21 1.1 minoura 22 1.1 minoura #ifdef DEBUG_WITH_STDIO 23 1.10 dsl void ufs_list_dir(ino32_t dirino); 24 1.10 dsl int main(int argc, char *argv[]); 25 1.1 minoura #endif 26 1.1 minoura 27 1.1 minoura #ifdef DEBUG_WITH_STDIO 28 1.1 minoura int fd; 29 1.1 minoura 30 1.1 minoura void 31 1.11 dsl RAW_READ(void *buf, daddr_t blkpos, size_t bytelen) 32 1.1 minoura { 33 1.4 itohy 34 1.1 minoura if (pread(fd, buf, bytelen, (off_t)dbtob(blkpos)) != (ssize_t) bytelen) 35 1.4 itohy err(1, "pread: buf %p, blk %d, len %u", 36 1.4 itohy buf, (int) blkpos, bytelen); 37 1.1 minoura } 38 1.1 minoura #endif 39 1.1 minoura 40 1.1 minoura struct ufs_info fs; 41 1.1 minoura 42 1.1 minoura /* 43 1.1 minoura * Read contiguous sectors at once for speedup. 44 1.1 minoura */ 45 1.1 minoura static size_t rq_len; 46 1.1 minoura 47 1.1 minoura static void 48 1.12 dsl raw_read_queue(void *buf, daddr_t blkpos, size_t bytelen) 49 1.12 dsl /* bytelen: must be DEV_BSIZE aligned */ 50 1.1 minoura { 51 1.3 fvdl static daddr_t rq_start; 52 1.1 minoura static char *rq_buf; 53 1.1 minoura 54 1.1 minoura if (rq_len) { 55 1.1 minoura if (bytelen && blkpos == rq_start + (ssize_t) btodb(rq_len) 56 1.1 minoura && buf == rq_buf + rq_len) { 57 1.1 minoura rq_len += bytelen; 58 1.1 minoura return; 59 1.1 minoura } else { 60 1.1 minoura #ifdef DEBUG_WITH_STDIO 61 1.1 minoura printf("raw_read_queue: read: buf %p, blk %d, len %d\n", 62 1.4 itohy rq_buf, (int) rq_start, rq_len); 63 1.1 minoura #endif 64 1.2 minoura RAW_READ(rq_buf, rq_start, rq_len); 65 1.1 minoura } 66 1.1 minoura } 67 1.1 minoura rq_buf = buf; 68 1.1 minoura rq_start = blkpos; 69 1.1 minoura rq_len = bytelen; 70 1.1 minoura } 71 1.1 minoura 72 1.1 minoura #define RAW_READ_QUEUE_INIT() (rq_len = 0) 73 1.1 minoura #define RAW_READ_QUEUE_FLUSH() \ 74 1.4 itohy raw_read_queue((void *) 0, (daddr_t) 0, (size_t) 0) 75 1.1 minoura 76 1.1 minoura 77 1.1 minoura /* 78 1.1 minoura * Read a file, specified by dinode. 79 1.1 minoura * No support for holes or (short) symbolic links. 80 1.1 minoura */ 81 1.1 minoura size_t 82 1.12 dsl ufs_read(union ufs_dinode *di, void *buf, unsigned off, size_t count) 83 1.12 dsl /* off: position in block */ 84 1.1 minoura { 85 1.4 itohy struct ufs_info *ufsinfo = &fs; 86 1.4 itohy size_t bsize = ufsinfo->bsize; 87 1.9 tsutsui uint8_t *b = buf; 88 1.1 minoura int i; 89 1.4 itohy size_t disize, nread; 90 1.4 itohy daddr_t pos; 91 1.4 itohy #if defined(USE_UFS1) && defined(USE_UFS2) 92 1.4 itohy enum ufs_ufstype uver = ufsinfo->ufstype; 93 1.4 itohy #endif 94 1.1 minoura 95 1.1 minoura #ifdef DEBUG_WITH_STDIO 96 1.1 minoura printf("ufs_read: off: %d, count %u\n", off, count); 97 1.1 minoura #endif 98 1.4 itohy 99 1.4 itohy disize = DI_SIZE(di); 100 1.4 itohy 101 1.4 itohy if (disize < count + off * bsize) 102 1.4 itohy count = disize - off * bsize; 103 1.1 minoura 104 1.1 minoura /* FS block size alignment. */ 105 1.1 minoura nread = count; 106 1.1 minoura count = (count + bsize - 1) & ~(bsize - 1); 107 1.1 minoura 108 1.1 minoura RAW_READ_QUEUE_INIT(); 109 1.1 minoura 110 1.1 minoura /* Read direct blocks. */ 111 1.15 dholland for ( ; off < UFS_NDADDR && count > 0; off++) { 112 1.4 itohy #if defined(USE_UFS1) && defined(USE_UFS2) 113 1.4 itohy if (uver == UFSTYPE_UFS1) 114 1.4 itohy pos = di->di1.di_db[off]; 115 1.4 itohy else 116 1.4 itohy pos = di->di2.di_db[off]; 117 1.4 itohy #else 118 1.4 itohy pos = di->di_thisver.di_db[off]; 119 1.4 itohy #endif 120 1.1 minoura #if 0 121 1.1 minoura printf("ufs_read: read: blk: %d\n", 122 1.4 itohy (int) pos << ufsinfo->fsbtodb); 123 1.1 minoura #endif 124 1.4 itohy raw_read_queue(b, pos << ufsinfo->fsbtodb, bsize); 125 1.1 minoura b += bsize; 126 1.1 minoura count -= bsize; 127 1.1 minoura } 128 1.15 dholland off -= UFS_NDADDR; 129 1.1 minoura 130 1.1 minoura /* Read indirect blocks. */ 131 1.15 dholland for (i = 0; i < UFS_NIADDR && count > 0; i++) { 132 1.4 itohy #if defined(USE_UFS1) && defined(USE_UFS2) 133 1.4 itohy if (uver == UFSTYPE_UFS1) 134 1.4 itohy pos = di->di1.di_ib[i]; 135 1.4 itohy else 136 1.4 itohy pos = di->di2.di_ib[i]; 137 1.4 itohy #else 138 1.4 itohy pos = di->di_thisver.di_ib[i]; 139 1.4 itohy #endif 140 1.4 itohy count = ufs_read_indirect(pos, i, &b, &off, count); 141 1.4 itohy } 142 1.1 minoura 143 1.1 minoura RAW_READ_QUEUE_FLUSH(); 144 1.1 minoura 145 1.4 itohy return nread; 146 1.1 minoura } 147 1.1 minoura 148 1.1 minoura static int 149 1.12 dsl ufs_read_indirect(daddr_t blk, int level, uint8_t **buf, unsigned *poff, size_t count) 150 1.12 dsl /* poff: position in block */ 151 1.1 minoura { 152 1.4 itohy struct ufs_info *ufsinfo = &fs; 153 1.4 itohy size_t bsize = ufsinfo->bsize; 154 1.4 itohy void *idbuf = alloca(bsize); 155 1.4 itohy #ifdef USE_UFS1 156 1.4 itohy int32_t *idbuf1 = idbuf; 157 1.4 itohy #endif 158 1.4 itohy #ifdef USE_UFS2 159 1.4 itohy int64_t *idbuf2 = idbuf; 160 1.4 itohy #endif 161 1.4 itohy daddr_t pos; 162 1.1 minoura unsigned off = *poff; 163 1.1 minoura unsigned b; 164 1.1 minoura 165 1.1 minoura #ifdef DEBUG_WITH_STDIO 166 1.1 minoura printf("ufs_read_indirect: off: %d, count %u\n", off, count); 167 1.1 minoura #endif 168 1.1 minoura if (off) { 169 1.1 minoura unsigned subindirsize = 1, indirsize; 170 1.1 minoura int i; 171 1.1 minoura 172 1.1 minoura for (i = level; i > 0; i--) 173 1.4 itohy subindirsize *= ufsinfo->nindir; 174 1.4 itohy indirsize = subindirsize * ufsinfo->nindir; 175 1.1 minoura if (off >= indirsize) { 176 1.1 minoura /* no need to read any data */ 177 1.1 minoura *poff = off - indirsize; 178 1.1 minoura return 0; 179 1.1 minoura } 180 1.1 minoura 181 1.1 minoura b = off / subindirsize; 182 1.1 minoura off -= b * subindirsize; 183 1.1 minoura *poff = 0; 184 1.1 minoura } else 185 1.1 minoura b = 0; 186 1.1 minoura 187 1.1 minoura /* read the indirect block */ 188 1.4 itohy RAW_READ(idbuf, blk << ufsinfo->fsbtodb, bsize); 189 1.4 itohy 190 1.4 itohy for ( ; b < ufsinfo->nindir && count > 0; b++) { 191 1.4 itohy #if defined(USE_UFS1) && defined(USE_UFS2) 192 1.4 itohy if (ufsinfo->ufstype == UFSTYPE_UFS1) 193 1.4 itohy #endif 194 1.4 itohy #ifdef USE_UFS1 195 1.4 itohy pos = idbuf1[b]; 196 1.4 itohy #endif 197 1.4 itohy #if defined(USE_UFS1) && defined(USE_UFS2) 198 1.4 itohy else 199 1.4 itohy #endif 200 1.4 itohy #ifdef USE_UFS2 201 1.4 itohy pos = idbuf2[b]; 202 1.4 itohy #endif 203 1.1 minoura 204 1.1 minoura if (level) 205 1.4 itohy count = ufs_read_indirect(pos, level - 1, buf, &off, count); 206 1.1 minoura else { 207 1.1 minoura #if 0 208 1.1 minoura printf("ufs_read: read: blk: %d\n", 209 1.4 itohy (int) pos << ufsinfo->fsbtodb); 210 1.1 minoura #endif 211 1.4 itohy raw_read_queue(*buf, pos << ufsinfo->fsbtodb, bsize); 212 1.1 minoura *buf += bsize; 213 1.1 minoura count -= bsize; 214 1.1 minoura } 215 1.1 minoura } 216 1.1 minoura 217 1.1 minoura return count; 218 1.1 minoura } 219 1.1 minoura 220 1.1 minoura /* 221 1.1 minoura * look-up fn in directory dirino 222 1.1 minoura */ 223 1.6 he ino32_t 224 1.11 dsl ufs_lookup(ino32_t dirino, const char *fn) 225 1.1 minoura { 226 1.4 itohy union ufs_dinode dirdi; 227 1.1 minoura struct direct *pdir; 228 1.2 minoura char *p, *endp; 229 1.4 itohy size_t disize; 230 1.1 minoura 231 1.1 minoura if (ufs_get_inode(dirino, &dirdi)) 232 1.1 minoura return 0; 233 1.1 minoura 234 1.4 itohy if ((dirdi.di_common.di_mode & IFMT) != IFDIR) 235 1.1 minoura return 0; /* Not a directory */ 236 1.1 minoura 237 1.4 itohy disize = DI_SIZE(&dirdi); 238 1.4 itohy 239 1.1 minoura #if 0 240 1.4 itohy p = alloca((disize + fs.bsize - 1) & ~(fs.bsize - 1)); 241 1.1 minoura #else /* simplify calculation to reduce code size */ 242 1.4 itohy p = alloca(disize + fs.bsize); 243 1.1 minoura #endif 244 1.4 itohy ufs_read(&dirdi, p, 0, disize); 245 1.4 itohy endp = p + disize; 246 1.2 minoura for ( ; pdir = (void *) p, p < endp; p += pdir->d_reclen) { 247 1.2 minoura if (pdir->d_ino && !strcmp(fn, pdir->d_name)) 248 1.1 minoura return pdir->d_ino; 249 1.1 minoura } 250 1.1 minoura return 0; /* No such file or directory */ 251 1.1 minoura } 252 1.1 minoura 253 1.1 minoura /* 254 1.1 minoura * look-up a file in absolute pathname from the root directory 255 1.1 minoura */ 256 1.6 he ino32_t 257 1.11 dsl ufs_lookup_path(const char *path) 258 1.1 minoura { 259 1.6 he char fn[FFS_MAXNAMLEN + 1]; 260 1.1 minoura char *p; 261 1.15 dholland ino32_t ino = UFS_ROOTINO; 262 1.1 minoura 263 1.1 minoura do { 264 1.1 minoura while (*path == '/') 265 1.1 minoura path++; 266 1.1 minoura for (p = fn; *path && *path != '/'; ) 267 1.1 minoura *p++ = *path++; 268 1.1 minoura *p++ = '\0'; 269 1.1 minoura ino = ufs_lookup(ino, fn); 270 1.1 minoura } while (ino && *path); 271 1.1 minoura 272 1.1 minoura return ino; 273 1.1 minoura } 274 1.1 minoura 275 1.1 minoura #if 0 276 1.1 minoura size_t 277 1.11 dsl ufs_load_file(void *buf, ino32_t dirino, const char *fn) 278 1.1 minoura { 279 1.4 itohy size_t cnt, disize; 280 1.4 itohy union ufs_dinode dinode; 281 1.1 minoura 282 1.1 minoura if (ufs_fn_inode(dirino, fn, &dinode)) 283 1.1 minoura return (unsigned) 0; 284 1.4 itohy disize = DI_SIZE(&dinode); 285 1.4 itohy cnt = ufs_read(&dinode, buf, 0, disize); 286 1.1 minoura 287 1.1 minoura return cnt; 288 1.1 minoura } 289 1.1 minoura #endif 290 1.1 minoura 291 1.1 minoura int 292 1.13 cegger ufs_init(void) 293 1.1 minoura { 294 1.1 minoura return 1 295 1.1 minoura #ifdef USE_FFS 296 1.1 minoura && try_ffs() 297 1.1 minoura #endif 298 1.1 minoura #ifdef USE_LFS 299 1.1 minoura && try_lfs() 300 1.1 minoura #endif 301 1.1 minoura ; 302 1.1 minoura } 303 1.1 minoura 304 1.1 minoura #ifdef DEBUG_WITH_STDIO 305 1.1 minoura void 306 1.11 dsl ufs_list_dir(ino32_t dirino) 307 1.1 minoura { 308 1.4 itohy union ufs_dinode dirdi; 309 1.1 minoura struct direct *pdir; 310 1.2 minoura char *p, *endp; 311 1.4 itohy size_t disize; 312 1.1 minoura 313 1.1 minoura if (ufs_get_inode(dirino, &dirdi)) 314 1.1 minoura errx(1, "ino = %d: not found", dirino); 315 1.1 minoura 316 1.4 itohy disize = DI_SIZE(&dirdi); 317 1.4 itohy p = alloca((disize + fs.bsize - 1) & ~(fs.bsize - 1)); 318 1.4 itohy ufs_read(&dirdi, p, 0, disize); 319 1.4 itohy endp = p + disize; 320 1.2 minoura for ( ; pdir = (void *) p, p < endp; p += pdir->d_reclen) { 321 1.2 minoura if (pdir->d_ino) 322 1.2 minoura printf("%6d %s\n", pdir->d_ino, pdir->d_name); 323 1.1 minoura } 324 1.1 minoura } 325 1.1 minoura #endif 326 1.1 minoura 327 1.1 minoura #ifdef DEBUG_WITH_STDIO 328 1.1 minoura int 329 1.1 minoura main(argc, argv) 330 1.1 minoura int argc __attribute__((unused)); 331 1.1 minoura char *argv[]; 332 1.1 minoura { 333 1.4 itohy union ufs_dinode dinode; 334 1.1 minoura 335 1.1 minoura if ((fd = open(argv[1], O_RDONLY)) < 0) 336 1.1 minoura err(1, "open: %s", argv[1]); 337 1.1 minoura 338 1.1 minoura if (ufs_init()) 339 1.1 minoura errx(1, "%s: unknown fs", argv[1]); 340 1.1 minoura 341 1.1 minoura #if 1 342 1.15 dholland ufs_list_dir(UFS_ROOTINO); 343 1.1 minoura { 344 1.1 minoura void *p; 345 1.1 minoura size_t cnt; 346 1.6 he ino32_t ino; 347 1.4 itohy size_t disize; 348 1.1 minoura 349 1.1 minoura if ((ino = ufs_lookup_path(argv[2])) == 0) 350 1.1 minoura errx(1, "%s: not found", argv[2]); 351 1.1 minoura ufs_get_inode(ino, &dinode); 352 1.4 itohy disize = DI_SIZE(&dinode); 353 1.4 itohy p = malloc((disize + fs.bsize - 1) & ~(fs.bsize - 1)); 354 1.4 itohy cnt = ufs_read(&dinode, p, 0, disize); 355 1.1 minoura write(3, p, cnt); 356 1.1 minoura free(p); 357 1.1 minoura } 358 1.1 minoura #endif 359 1.1 minoura 360 1.1 minoura return 0; 361 1.1 minoura } 362 1.1 minoura #endif 363