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