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