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