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