1 /*- 2 * Copyright (c) 1999,2000 Jonathan Lemon <jlemon@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/lib/libstand/ext2fs.c,v 1.1.2.2 2001/03/05 06:26:07 kris Exp $ 27 */ 28 /*- 29 * Copyright (c) 1993 30 * The Regents of the University of California. All rights reserved. 31 * 32 * This code is derived from software contributed to Berkeley by 33 * The Mach Operating System project at Carnegie-Mellon University. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 3. Neither the name of the University nor the names of its contributors 44 * may be used to endorse or promote products derived from this software 45 * without specific prior written permission. 46 * 47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 57 * SUCH DAMAGE. 58 * 59 * 60 * Copyright (c) 1990, 1991 Carnegie Mellon University 61 * All Rights Reserved. 62 * 63 * Author: David Golub 64 * 65 * Permission to use, copy, modify and distribute this software and its 66 * documentation is hereby granted, provided that both the copyright 67 * notice and this permission notice appear in all copies of the 68 * software, derivative works or modified versions, and any portions 69 * thereof, and that both notices appear in supporting documentation. 70 * 71 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 72 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 73 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 74 * 75 * Carnegie Mellon requests users of this software to return to 76 * 77 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 78 * School of Computer Science 79 * Carnegie Mellon University 80 * Pittsburgh PA 15213-3890 81 * 82 * any improvements or extensions that they make and grant Carnegie the 83 * rights to redistribute these changes. 84 */ 85 86 #include <sys/param.h> 87 #include <sys/time.h> 88 #include "stand.h" 89 #include "string.h" 90 91 static int ext2fs_open(const char *path, struct open_file *f); 92 static int ext2fs_close(struct open_file *f); 93 static int ext2fs_read(struct open_file *f, void *buf, 94 size_t size, size_t *resid); 95 static off_t ext2fs_seek(struct open_file *f, off_t offset, int where); 96 static int ext2fs_stat(struct open_file *f, struct stat *sb); 97 static int ext2fs_readdir(struct open_file *f, struct dirent *d); 98 99 static int dtmap[] = { DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, 100 DT_BLK, DT_FIFO, DT_SOCK, DT_LNK }; 101 #define EXTFTODT(x) (x) > NELEM(dtmap) ? DT_UNKNOWN : dtmap[(x)] 102 103 struct fs_ops ext2fs_fsops = { 104 "ext2fs", 105 ext2fs_open, 106 ext2fs_close, 107 ext2fs_read, 108 null_write, 109 ext2fs_seek, 110 ext2fs_stat, 111 ext2fs_readdir 112 }; 113 114 #define EXT2_SBSIZE 1024 115 #define EXT2_SBLOCK (1024 / DEV_BSIZE) /* block offset of superblock */ 116 #define EXT2_MAGIC 0xef53 117 #define EXT2_ROOTINO 2 118 119 #define EXT2_REV0 0 /* original revision of ext2 */ 120 #define EXT2_R0_ISIZE 128 /* inode size */ 121 #define EXT2_R0_FIRSTINO 11 /* first inode */ 122 123 #define EXT2_MINBSHIFT 10 /* mininum block shift */ 124 #define EXT2_MINFSHIFT 10 /* mininum frag shift */ 125 126 #define NDADDR 12 /* # of direct blocks */ 127 #define NIADDR 3 /* # of indirect blocks */ 128 129 /* 130 * file system block to disk address 131 */ 132 #define fsb_to_db(fs, blk) ((blk) << (fs)->fs_fsbtodb) 133 134 /* 135 * inode to block group offset 136 * inode to block group 137 * inode to disk address 138 * inode to block offset 139 */ 140 #define ino_to_bgo(fs, ino) (((ino) - 1) % (fs)->fs_ipg) 141 #define ino_to_bg(fs, ino) (((ino) - 1) / (fs)->fs_ipg) 142 #define ino_to_db(fs, bg, ino) \ 143 fsb_to_db(fs, ((bg)[ino_to_bg(fs, ino)].bg_inotbl + \ 144 ino_to_bgo(fs, ino) / (fs)->fs_ipb)) 145 #define ino_to_bo(fs, ino) (ino_to_bgo(fs, ino) % (fs)->fs_ipb) 146 147 #define nindir(fs) \ 148 ((fs)->fs_bsize / sizeof(u_int32_t)) 149 #define lblkno(fs, loc) /* loc / bsize */ \ 150 ((loc) >> (fs)->fs_bshift) 151 #define smalllblktosize(fs, blk) /* blk * bsize */ \ 152 ((blk) << (fs)->fs_bshift) 153 #define blkoff(fs, loc) /* loc % bsize */ \ 154 ((loc) & (fs)->fs_bmask) 155 #define fragroundup(fs, size) /* roundup(size, fsize) */ \ 156 (((size) + (fs)->fs_fmask) & ~(fs)->fs_fmask) 157 #define dblksize(fs, dip, lbn) \ 158 (((lbn) >= NDADDR || (dip)->di_size >= smalllblktosize(fs, (lbn) + 1)) \ 159 ? (fs)->fs_bsize \ 160 : (fragroundup(fs, blkoff(fs, (dip)->di_size)))) 161 162 /* 163 * superblock describing ext2fs 164 */ 165 struct ext2fs_disk { 166 u_int32_t fd_inodes; /* # of inodes */ 167 u_int32_t fd_blocks; /* # of blocks */ 168 u_int32_t fd_resblk; /* # of reserved blocks */ 169 u_int32_t fd_freeblk; /* # of free blocks */ 170 u_int32_t fd_freeino; /* # of free inodes */ 171 u_int32_t fd_firstblk; /* first data block */ 172 u_int32_t fd_bsize; /* block size */ 173 u_int32_t fd_fsize; /* frag size */ 174 u_int32_t fd_bpg; /* blocks per group */ 175 u_int32_t fd_fpg; /* frags per group */ 176 u_int32_t fd_ipg; /* inodes per group */ 177 u_int32_t fd_mtime; /* mount time */ 178 u_int32_t fd_wtime; /* write time */ 179 u_int16_t fd_mount; /* # of mounts */ 180 int16_t fd_maxmount; /* max # of mounts */ 181 u_int16_t fd_magic; /* magic number */ 182 u_int16_t fd_state; /* state */ 183 u_int16_t fd_eflag; /* error flags */ 184 u_int16_t fd_mnrrev; /* minor revision */ 185 u_int32_t fd_lastchk; /* last check */ 186 u_int32_t fd_chkintvl; /* maximum check interval */ 187 u_int32_t fd_os; /* os */ 188 u_int32_t fd_revision; /* revision */ 189 u_int16_t fd_uid; /* uid for reserved blocks */ 190 u_int16_t fd_gid; /* gid for reserved blocks */ 191 192 u_int32_t fd_firstino; /* first non-reserved inode */ 193 u_int16_t fd_isize; /* inode size */ 194 u_int16_t fd_nblkgrp; /* block group # of superblock */ 195 u_int32_t fd_fcompat; /* compatible features */ 196 u_int32_t fd_fincompat; /* incompatible features */ 197 u_int32_t fd_frocompat; /* read-only compatibilties */ 198 u_int8_t fd_uuid[16]; /* volume uuid */ 199 char fd_volname[16]; /* volume name */ 200 char fd_fsmnt[64]; /* name last mounted on */ 201 u_int32_t fd_bitmap; /* compression bitmap */ 202 203 u_int8_t fd_nblkpa; /* # of blocks to preallocate */ 204 u_int8_t fd_ndblkpa; /* # of dir blocks to preallocate */ 205 }; 206 207 struct ext2fs_core { 208 int fc_bsize; /* block size */ 209 int fc_bshift; /* block shift amount */ 210 int fc_bmask; /* block mask */ 211 int fc_fsize; /* frag size */ 212 int fc_fshift; /* frag shift amount */ 213 int fc_fmask; /* frag mask */ 214 int fc_isize; /* inode size */ 215 int fc_imask; /* inode mask */ 216 int fc_firstino; /* first non-reserved inode */ 217 int fc_ipb; /* inodes per block */ 218 int fc_fsbtodb; /* fsb to ds shift */ 219 }; 220 221 struct ext2fs { 222 struct ext2fs_disk fs_fd; 223 char fs_pad[EXT2_SBSIZE - sizeof(struct ext2fs_disk)]; 224 struct ext2fs_core fs_fc; 225 226 #define fs_magic fs_fd.fd_magic 227 #define fs_revision fs_fd.fd_revision 228 #define fs_blocks fs_fd.fd_blocks 229 #define fs_firstblk fs_fd.fd_firstblk 230 #define fs_bpg fs_fd.fd_bpg 231 #define fs_ipg fs_fd.fd_ipg 232 233 #define fs_bsize fs_fc.fc_bsize 234 #define fs_bshift fs_fc.fc_bshift 235 #define fs_bmask fs_fc.fc_bmask 236 #define fs_fsize fs_fc.fc_fsize 237 #define fs_fshift fs_fc.fc_fshift 238 #define fs_fmask fs_fc.fc_fmask 239 #define fs_isize fs_fc.fc_isize 240 #define fs_imask fs_fc.fc_imask 241 #define fs_firstino fs_fc.fc_firstino 242 #define fs_ipb fs_fc.fc_ipb 243 #define fs_fsbtodb fs_fc.fc_fsbtodb 244 }; 245 246 struct ext2blkgrp { 247 u_int32_t bg_blkmap; /* block bitmap */ 248 u_int32_t bg_inomap; /* inode bitmap */ 249 u_int32_t bg_inotbl; /* inode table */ 250 u_int16_t bg_nfblk; /* # of free blocks */ 251 u_int16_t bg_nfino; /* # of free inodes */ 252 u_int16_t bg_ndirs; /* # of dirs */ 253 char bg_pad[14]; 254 }; 255 256 struct ext2dinode { 257 u_int16_t di_mode; /* mode */ 258 u_int16_t di_uid; /* uid */ 259 u_int32_t di_size; /* byte size */ 260 u_int32_t di_atime; /* access time */ 261 u_int32_t di_ctime; /* creation time */ 262 u_int32_t di_mtime; /* modification time */ 263 u_int32_t di_dtime; /* deletion time */ 264 u_int16_t di_gid; /* gid */ 265 u_int16_t di_nlink; /* link count */ 266 u_int32_t di_nblk; /* block count */ 267 u_int32_t di_flags; /* file flags */ 268 269 u_int32_t di_osdep1; /* os dependent stuff */ 270 271 u_int32_t di_db[NDADDR]; /* direct blocks */ 272 u_int32_t di_ib[NIADDR]; /* indirect blocks */ 273 u_int32_t di_version; /* version */ 274 u_int32_t di_facl; /* file acl */ 275 u_int32_t di_dacl; /* dir acl */ 276 u_int32_t di_faddr; /* fragment addr */ 277 278 u_int8_t di_frag; /* fragment number */ 279 u_int8_t di_fsize; /* fragment size */ 280 281 char di_pad[10]; 282 283 #define di_shortlink di_db 284 }; 285 286 #define EXT2_MAXNAMLEN 255 287 288 struct ext2dirent { 289 u_int32_t d_ino; /* inode */ 290 u_int16_t d_reclen; /* directory entry length */ 291 u_int8_t d_namlen; /* name length */ 292 u_int8_t d_type; /* file type */ 293 char d_name[EXT2_MAXNAMLEN]; 294 }; 295 296 struct file { 297 off_t f_seekp; /* seek pointer */ 298 struct ext2fs *f_fs; /* pointer to super-block */ 299 struct ext2blkgrp *f_bg; /* pointer to blkgrp map */ 300 struct ext2dinode f_di; /* copy of on-disk inode */ 301 int f_nindir[NIADDR]; /* number of blocks mapped by 302 indirect block at level i */ 303 char *f_blk[NIADDR]; /* buffer for indirect block 304 at level i */ 305 size_t f_blksize[NIADDR]; /* size of buffer */ 306 daddr_t f_blkno[NIADDR]; /* disk address of block in 307 buffer */ 308 char *f_buf; /* buffer for data block */ 309 size_t f_buf_size; /* size of data block */ 310 daddr_t f_buf_blkno; /* block number of data block */ 311 }; 312 313 /* forward decls */ 314 static int read_inode(ino_t inumber, struct open_file *f); 315 static int block_map(struct open_file *f, daddr_t file_block, 316 daddr_t *disk_block_p); 317 static int buf_read_file(struct open_file *f, char **buf_p, 318 size_t *size_p); 319 static int search_directory(char *name, struct open_file *f, 320 ino_t *inumber_p); 321 322 /* 323 * Open a file. 324 */ 325 static int 326 ext2fs_open(const char *upath, struct open_file *f) 327 { 328 struct file *fp; 329 struct ext2fs *fs; 330 size_t buf_size; 331 ino_t inumber, parent_inumber; 332 int i, len, groups, bg_per_blk, blkgrps, mult; 333 int nlinks = 0; 334 int error = 0; 335 char *cp, *ncp, *path = NULL, *buf = NULL; 336 char namebuf[MAXPATHLEN+1]; 337 char c; 338 339 /* allocate file system specific data structure */ 340 fp = malloc(sizeof(struct file)); 341 if (fp == NULL) 342 return (ENOMEM); 343 bzero(fp, sizeof(struct file)); 344 f->f_fsdata = (void *)fp; 345 346 /* allocate space and read super block */ 347 fs = (struct ext2fs *)malloc(sizeof(*fs)); 348 fp->f_fs = fs; 349 twiddle(); 350 error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 351 EXT2_SBLOCK, EXT2_SBSIZE, (char *)fs, &buf_size); 352 if (error) 353 goto out; 354 355 if (buf_size != EXT2_SBSIZE || fs->fs_magic != EXT2_MAGIC) { 356 error = EINVAL; 357 goto out; 358 } 359 360 /* 361 * compute in-core values for the superblock 362 */ 363 fs->fs_bshift = EXT2_MINBSHIFT + fs->fs_fd.fd_bsize; 364 fs->fs_bsize = 1 << fs->fs_bshift; 365 fs->fs_bmask = fs->fs_bsize - 1; 366 367 fs->fs_fshift = EXT2_MINFSHIFT + fs->fs_fd.fd_fsize; 368 fs->fs_fsize = 1 << fs->fs_fshift; 369 fs->fs_fmask = fs->fs_fsize - 1; 370 371 if (fs->fs_revision == EXT2_REV0) { 372 fs->fs_isize = EXT2_R0_ISIZE; 373 fs->fs_firstino = EXT2_R0_FIRSTINO; 374 } else { 375 fs->fs_isize = fs->fs_fd.fd_isize; 376 fs->fs_firstino = fs->fs_fd.fd_firstino; 377 } 378 fs->fs_imask = fs->fs_isize - 1; 379 fs->fs_ipb = fs->fs_bsize / fs->fs_isize; 380 fs->fs_fsbtodb = (fs->fs_bsize / DEV_BSIZE) - 1; 381 382 /* 383 * we have to load in the "group descriptors" here 384 */ 385 groups = howmany(fs->fs_blocks - fs->fs_firstblk, fs->fs_bpg); 386 bg_per_blk = fs->fs_bsize / sizeof(struct ext2blkgrp); 387 blkgrps = howmany(groups, bg_per_blk); 388 len = blkgrps * fs->fs_bsize; 389 390 fp->f_bg = malloc(len); 391 twiddle(); 392 error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 393 EXT2_SBLOCK + EXT2_SBSIZE / DEV_BSIZE, len, 394 (char *)fp->f_bg, &buf_size); 395 if (error) 396 goto out; 397 398 /* 399 * XXX 400 * validation of values? (blocksize, descriptors, etc?) 401 */ 402 403 /* 404 * Calculate indirect block levels. 405 */ 406 mult = 1; 407 for (i = 0; i < NIADDR; i++) { 408 mult *= nindir(fs); 409 fp->f_nindir[i] = mult; 410 } 411 412 inumber = EXT2_ROOTINO; 413 if ((error = read_inode(inumber, f)) != 0) 414 goto out; 415 416 path = strdup(upath); 417 if (path == NULL) { 418 error = ENOMEM; 419 goto out; 420 } 421 cp = path; 422 while (*cp) { 423 /* 424 * Remove extra separators 425 */ 426 while (*cp == '/') 427 cp++; 428 if (*cp == '\0') 429 break; 430 431 /* 432 * Check that current node is a directory. 433 */ 434 if (! S_ISDIR(fp->f_di.di_mode)) { 435 error = ENOTDIR; 436 goto out; 437 } 438 439 /* 440 * Get next component of path name. 441 */ 442 len = 0; 443 444 ncp = cp; 445 while ((c = *cp) != '\0' && c != '/') { 446 if (++len > EXT2_MAXNAMLEN) { 447 error = ENOENT; 448 goto out; 449 } 450 cp++; 451 } 452 *cp = '\0'; 453 454 /* 455 * Look up component in current directory. 456 * Save directory inumber in case we find a 457 * symbolic link. 458 */ 459 parent_inumber = inumber; 460 error = search_directory(ncp, f, &inumber); 461 *cp = c; 462 if (error) 463 goto out; 464 465 /* 466 * Open next component. 467 */ 468 if ((error = read_inode(inumber, f)) != 0) 469 goto out; 470 471 /* 472 * Check for symbolic link. 473 */ 474 if (S_ISLNK(fp->f_di.di_mode)) { 475 int link_len = fp->f_di.di_size; 476 int len; 477 478 len = strlen(cp); 479 if (link_len + len > MAXPATHLEN || 480 ++nlinks > MAXSYMLINKS) { 481 error = ENOENT; 482 goto out; 483 } 484 485 bcopy(cp, &namebuf[link_len], len + 1); 486 if (fp->f_di.di_nblk == 0) { 487 bcopy(fp->f_di.di_shortlink, 488 namebuf, link_len); 489 } else { 490 /* 491 * Read file for symbolic link 492 */ 493 struct ext2fs *fs = fp->f_fs; 494 daddr_t disk_block; 495 size_t buf_size; 496 497 if (! buf) 498 buf = malloc(fs->fs_bsize); 499 error = block_map(f, (daddr_t)0, &disk_block); 500 if (error) 501 goto out; 502 503 twiddle(); 504 error = (f->f_dev->dv_strategy)(f->f_devdata, 505 F_READ, fsb_to_db(fs, disk_block), 506 fs->fs_bsize, buf, &buf_size); 507 if (error) 508 goto out; 509 510 bcopy((char *)buf, namebuf, link_len); 511 } 512 513 /* 514 * If relative pathname, restart at parent directory. 515 * If absolute pathname, restart at root. 516 */ 517 cp = namebuf; 518 if (*cp != '/') 519 inumber = parent_inumber; 520 else 521 inumber = (ino_t)EXT2_ROOTINO; 522 523 if ((error = read_inode(inumber, f)) != 0) 524 goto out; 525 } 526 } 527 528 /* 529 * Found terminal component. 530 */ 531 error = 0; 532 out: 533 if (buf) 534 free(buf); 535 if (path) 536 free(path); 537 if (error) { 538 f->f_fsdata = NULL; 539 if (fp->f_buf) 540 free(fp->f_buf); 541 free(fp->f_fs); 542 free(fp); 543 } 544 return (error); 545 } 546 547 /* 548 * Read a new inode into a file structure. 549 */ 550 static int 551 read_inode(ino_t inumber, struct open_file *f) 552 { 553 struct file *fp = (struct file *)f->f_fsdata; 554 struct ext2fs *fs = fp->f_fs; 555 struct ext2dinode *dp; 556 char *buf; 557 size_t rsize; 558 int level, error = 0; 559 560 /* 561 * Read inode and save it. 562 */ 563 buf = malloc(fs->fs_bsize); 564 twiddle(); 565 error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 566 ino_to_db(fs, fp->f_bg, inumber), fs->fs_bsize, buf, &rsize); 567 if (error) 568 goto out; 569 if (rsize != fs->fs_bsize) { 570 error = EIO; 571 goto out; 572 } 573 574 dp = (struct ext2dinode *)buf; 575 fp->f_di = dp[ino_to_bo(fs, inumber)]; 576 577 /* clear out old buffers */ 578 for (level = 0; level < NIADDR; level++) 579 fp->f_blkno[level] = -1; 580 fp->f_buf_blkno = -1; 581 582 out: 583 free(buf); 584 return (error); 585 } 586 587 /* 588 * Given an offset in a file, find the disk block number that 589 * contains that block. 590 */ 591 static int 592 block_map(struct open_file *f, daddr_t file_block, daddr_t *disk_block_p) 593 { 594 struct file *fp = (struct file *)f->f_fsdata; 595 struct ext2fs *fs = fp->f_fs; 596 daddr_t ind_block_num; 597 daddr_t *ind_p; 598 int idx, level; 599 int error; 600 601 /* 602 * Index structure of an inode: 603 * 604 * di_db[0..NDADDR-1] hold block numbers for blocks 605 * 0..NDADDR-1 606 * 607 * di_ib[0] index block 0 is the single indirect block 608 * holds block numbers for blocks 609 * NDADDR .. NDADDR + NINDIR(fs)-1 610 * 611 * di_ib[1] index block 1 is the double indirect block 612 * holds block numbers for INDEX blocks for blocks 613 * NDADDR + NINDIR(fs) .. 614 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1 615 * 616 * di_ib[2] index block 2 is the triple indirect block 617 * holds block numbers for double-indirect 618 * blocks for blocks 619 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 .. 620 * NDADDR + NINDIR(fs) + NINDIR(fs)**2 621 * + NINDIR(fs)**3 - 1 622 */ 623 624 if (file_block < NDADDR) { 625 /* Direct block. */ 626 *disk_block_p = fp->f_di.di_db[file_block]; 627 return (0); 628 } 629 630 file_block -= NDADDR; 631 632 /* 633 * nindir[0] = NINDIR 634 * nindir[1] = NINDIR**2 635 * nindir[2] = NINDIR**3 636 * etc 637 */ 638 for (level = 0; level < NIADDR; level++) { 639 if (file_block < fp->f_nindir[level]) 640 break; 641 file_block -= fp->f_nindir[level]; 642 } 643 if (level == NIADDR) { 644 /* Block number too high */ 645 return (EFBIG); 646 } 647 648 ind_block_num = fp->f_di.di_ib[level]; 649 650 for (; level >= 0; level--) { 651 if (ind_block_num == 0) { 652 *disk_block_p = 0; /* missing */ 653 return (0); 654 } 655 656 if (fp->f_blkno[level] != ind_block_num) { 657 if (fp->f_blk[level] == NULL) 658 fp->f_blk[level] = 659 malloc(fs->fs_bsize); 660 twiddle(); 661 error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 662 fsb_to_db(fp->f_fs, ind_block_num), fs->fs_bsize, 663 fp->f_blk[level], &fp->f_blksize[level]); 664 if (error) 665 return (error); 666 if (fp->f_blksize[level] != fs->fs_bsize) 667 return (EIO); 668 fp->f_blkno[level] = ind_block_num; 669 } 670 671 ind_p = (daddr_t *)fp->f_blk[level]; 672 673 if (level > 0) { 674 idx = file_block / fp->f_nindir[level - 1]; 675 file_block %= fp->f_nindir[level - 1]; 676 } else { 677 idx = file_block; 678 } 679 ind_block_num = ind_p[idx]; 680 } 681 682 *disk_block_p = ind_block_num; 683 684 return (0); 685 } 686 687 /* 688 * Read a portion of a file into an internal buffer. Return 689 * the location in the buffer and the amount in the buffer. 690 */ 691 static int 692 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) 693 { 694 struct file *fp = (struct file *)f->f_fsdata; 695 struct ext2fs *fs = fp->f_fs; 696 long off; 697 daddr_t file_block; 698 daddr_t disk_block; 699 size_t block_size; 700 int error = 0; 701 702 off = blkoff(fs, fp->f_seekp); 703 file_block = lblkno(fs, fp->f_seekp); 704 block_size = dblksize(fs, &fp->f_di, file_block); 705 706 if (file_block != fp->f_buf_blkno) { 707 error = block_map(f, file_block, &disk_block); 708 if (error) 709 goto done; 710 711 if (fp->f_buf == NULL) 712 fp->f_buf = malloc(fs->fs_bsize); 713 714 if (disk_block == 0) { 715 bzero(fp->f_buf, block_size); 716 fp->f_buf_size = block_size; 717 } else { 718 twiddle(); 719 error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 720 fsb_to_db(fs, disk_block), block_size, 721 fp->f_buf, &fp->f_buf_size); 722 if (error) 723 goto done; 724 } 725 fp->f_buf_blkno = file_block; 726 } 727 728 /* 729 * Return address of byte in buffer corresponding to 730 * offset, and size of remainder of buffer after that 731 * byte. 732 */ 733 *buf_p = fp->f_buf + off; 734 *size_p = block_size - off; 735 736 /* 737 * But truncate buffer at end of file. 738 */ 739 if (*size_p > fp->f_di.di_size - fp->f_seekp) 740 *size_p = fp->f_di.di_size - fp->f_seekp; 741 done: 742 return (error); 743 } 744 745 /* 746 * Search a directory for a name and return its 747 * i_number. 748 */ 749 static int 750 search_directory(char *name, struct open_file *f, ino_t *inumber_p) 751 { 752 struct file *fp = (struct file *)f->f_fsdata; 753 struct ext2dirent *dp, *edp; 754 char *buf; 755 size_t buf_size; 756 int namlen, length; 757 int error; 758 759 length = strlen(name); 760 fp->f_seekp = 0; 761 while (fp->f_seekp < fp->f_di.di_size) { 762 error = buf_read_file(f, &buf, &buf_size); 763 if (error) 764 return (error); 765 dp = (struct ext2dirent *)buf; 766 edp = (struct ext2dirent *)(buf + buf_size); 767 while (dp < edp) { 768 if (dp->d_ino == (ino_t)0) 769 goto next; 770 namlen = dp->d_namlen; 771 if (namlen == length && 772 strncmp(name, dp->d_name, length) == 0) { 773 /* found entry */ 774 *inumber_p = dp->d_ino; 775 return (0); 776 } 777 next: 778 dp = (struct ext2dirent *)((char *)dp + dp->d_reclen); 779 } 780 fp->f_seekp += buf_size; 781 } 782 return (ENOENT); 783 } 784 785 static int 786 ext2fs_close(struct open_file *f) 787 { 788 struct file *fp = (struct file *)f->f_fsdata; 789 int level; 790 791 f->f_fsdata = NULL; 792 if (fp == NULL) 793 return (0); 794 795 for (level = 0; level < NIADDR; level++) { 796 if (fp->f_blk[level]) 797 free(fp->f_blk[level]); 798 } 799 if (fp->f_buf) 800 free(fp->f_buf); 801 if (fp->f_bg) 802 free(fp->f_bg); 803 free(fp->f_fs); 804 free(fp); 805 return (0); 806 } 807 808 static int 809 ext2fs_read(struct open_file *f, void *addr, size_t size, size_t *resid) 810 { 811 struct file *fp = (struct file *)f->f_fsdata; 812 size_t csize, buf_size; 813 char *buf; 814 int error = 0; 815 816 while (size != 0) { 817 if (fp->f_seekp >= fp->f_di.di_size) 818 break; 819 820 error = buf_read_file(f, &buf, &buf_size); 821 if (error) 822 break; 823 824 csize = size; 825 if (csize > buf_size) 826 csize = buf_size; 827 828 bcopy(buf, addr, csize); 829 830 fp->f_seekp += csize; 831 addr += csize; 832 size -= csize; 833 } 834 if (resid) 835 *resid = size; 836 return (error); 837 } 838 839 static off_t 840 ext2fs_seek(struct open_file *f, off_t offset, int where) 841 { 842 struct file *fp = (struct file *)f->f_fsdata; 843 844 switch (where) { 845 case SEEK_SET: 846 fp->f_seekp = offset; 847 break; 848 case SEEK_CUR: 849 fp->f_seekp += offset; 850 break; 851 case SEEK_END: 852 fp->f_seekp = fp->f_di.di_size - offset; 853 break; 854 default: 855 return (-1); 856 } 857 return (fp->f_seekp); 858 } 859 860 static int 861 ext2fs_stat(struct open_file *f, struct stat *sb) 862 { 863 struct file *fp = (struct file *)f->f_fsdata; 864 865 /* only important stuff */ 866 sb->st_mode = fp->f_di.di_mode; 867 sb->st_uid = fp->f_di.di_uid; 868 sb->st_gid = fp->f_di.di_gid; 869 sb->st_size = fp->f_di.di_size; 870 return (0); 871 } 872 873 static int 874 ext2fs_readdir(struct open_file *f, struct dirent *d) 875 { 876 struct file *fp = (struct file *)f->f_fsdata; 877 struct ext2dirent *ed; 878 char *buf; 879 size_t buf_size; 880 int error; 881 882 /* 883 * assume that a directory entry will not be split across blocks 884 */ 885 again: 886 if (fp->f_seekp >= fp->f_di.di_size) 887 return (ENOENT); 888 error = buf_read_file(f, &buf, &buf_size); 889 if (error) 890 return (error); 891 ed = (struct ext2dirent *)buf; 892 fp->f_seekp += ed->d_reclen; 893 if (ed->d_ino == (ino_t)0) 894 goto again; 895 d->d_type = EXTFTODT(ed->d_type); 896 strncpy(d->d_name, ed->d_name, ed->d_namlen); 897 d->d_name[ed->d_namlen] = '\0'; 898 return (0); 899 } 900