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