1 /* $NetBSD: ext2fs.c,v 1.20 2014/03/20 03:13:18 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Manuel Bouyer. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 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. Neither the name of the University nor the names of its contributors 43 * may be used to endorse or promote products derived from this software 44 * without specific prior written permission. 45 * 46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 56 * SUCH DAMAGE. 57 * 58 * 59 * Copyright (c) 1990, 1991 Carnegie Mellon University 60 * All Rights Reserved. 61 * 62 * Author: David Golub 63 * 64 * Permission to use, copy, modify and distribute this software and its 65 * documentation is hereby granted, provided that both the copyright 66 * notice and this permission notice appear in all copies of the 67 * software, derivative works or modified versions, and any portions 68 * thereof, and that both notices appear in supporting documentation. 69 * 70 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 71 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 72 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 73 * 74 * Carnegie Mellon requests users of this software to return to 75 * 76 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 77 * School of Computer Science 78 * Carnegie Mellon University 79 * Pittsburgh PA 15213-3890 80 * 81 * any improvements or extensions that they make and grant Carnegie the 82 * rights to redistribute these changes. 83 */ 84 85 /* 86 * Stand-alone file reading package for Ext2 file system. 87 */ 88 89 /* #define EXT2FS_DEBUG */ 90 91 #include <sys/param.h> 92 #include <sys/time.h> 93 #include <ufs/ext2fs/ext2fs_dinode.h> 94 #include <ufs/ext2fs/ext2fs_dir.h> 95 #include <ufs/ext2fs/ext2fs.h> 96 #ifdef _STANDALONE 97 #include <lib/libkern/libkern.h> 98 #else 99 #include <string.h> 100 #endif 101 102 #include "stand.h" 103 #include "ext2fs.h" 104 105 #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK) 106 #define LIBSA_NO_FS_SYMLINK 107 #endif 108 109 #if defined(LIBSA_NO_TWIDDLE) 110 #define twiddle() 111 #endif 112 113 #ifndef indp_t 114 #define indp_t int32_t 115 #endif 116 typedef uint32_t ino32_t; 117 #ifndef FSBTODB 118 #define FSBTODB(fs, indp) EXT2_FSBTODB(fs, indp) 119 #endif 120 121 /* 122 * To avoid having a lot of filesystem-block sized buffers lurking (which 123 * could be 32k) we only keep a few entries of the indirect block map. 124 * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block 125 * ~13 times pulling in a 6M kernel. 126 * The cache size must be smaller than the smallest filesystem block, 127 * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks). 128 */ 129 #define LN2_IND_CACHE_SZ 6 130 #define IND_CACHE_SZ (1 << LN2_IND_CACHE_SZ) 131 #define IND_CACHE_MASK (IND_CACHE_SZ - 1) 132 133 /* 134 * In-core open file. 135 */ 136 struct file { 137 off_t f_seekp; /* seek pointer */ 138 struct m_ext2fs *f_fs; /* pointer to super-block */ 139 struct ext2fs_dinode f_di; /* copy of on-disk inode */ 140 uint f_nishift; /* for blocks in indirect block */ 141 indp_t f_ind_cache_block; 142 indp_t f_ind_cache[IND_CACHE_SZ]; 143 144 char *f_buf; /* buffer for data block */ 145 size_t f_buf_size; /* size of data block */ 146 daddr_t f_buf_blkno; /* block number of data block */ 147 }; 148 149 150 static int read_inode(ino32_t, struct open_file *); 151 static int block_map(struct open_file *, indp_t, indp_t *); 152 static int buf_read_file(struct open_file *, char **, size_t *); 153 static int search_directory(const char *, int, struct open_file *, ino32_t *); 154 static int read_sblock(struct open_file *, struct m_ext2fs *); 155 static int read_gdblock(struct open_file *, struct m_ext2fs *); 156 #ifdef EXT2FS_DEBUG 157 static void dump_sblock(struct m_ext2fs *); 158 #endif 159 160 /* 161 * Read a new inode into a file structure. 162 */ 163 static int 164 read_inode(ino32_t inumber, struct open_file *f) 165 { 166 struct file *fp = (struct file *)f->f_fsdata; 167 struct m_ext2fs *fs = fp->f_fs; 168 char *buf; 169 size_t rsize; 170 int rc; 171 daddr_t inode_sector; 172 struct ext2fs_dinode *dip; 173 174 inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber)); 175 176 /* 177 * Read inode and save it. 178 */ 179 buf = fp->f_buf; 180 twiddle(); 181 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 182 inode_sector, fs->e2fs_bsize, buf, &rsize); 183 if (rc) 184 return rc; 185 if (rsize != fs->e2fs_bsize) 186 return EIO; 187 188 dip = (struct ext2fs_dinode *)(buf + 189 EXT2_DINODE_SIZE(fs) * ino_to_fsbo(fs, inumber)); 190 e2fs_iload(dip, &fp->f_di); 191 192 /* 193 * Clear out the old buffers 194 */ 195 fp->f_ind_cache_block = ~0; 196 fp->f_buf_blkno = -1; 197 return rc; 198 } 199 200 /* 201 * Given an offset in a file, find the disk block number that 202 * contains that block. 203 */ 204 static int 205 block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p) 206 { 207 struct file *fp = (struct file *)f->f_fsdata; 208 struct m_ext2fs *fs = fp->f_fs; 209 uint level; 210 indp_t ind_cache; 211 indp_t ind_block_num; 212 size_t rsize; 213 int rc; 214 indp_t *buf = (void *)fp->f_buf; 215 216 /* 217 * Index structure of an inode: 218 * 219 * e2di_blocks[0..EXT2FS_NDADDR-1] 220 * hold block numbers for blocks 221 * 0..EXT2FS_NDADDR-1 222 * 223 * e2di_blocks[EXT2FS_NDADDR+0] 224 * block EXT2FS_NDADDR+0 is the single indirect block 225 * holds block numbers for blocks 226 * EXT2FS_NDADDR .. EXT2FS_NDADDR + EXT2_NINDIR(fs)-1 227 * 228 * e2di_blocks[EXT2FS_NDADDR+1] 229 * block EXT2FS_NDADDR+1 is the double indirect block 230 * holds block numbers for INDEX blocks for blocks 231 * EXT2FS_NDADDR + EXT2_NINDIR(fs) .. 232 * EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2 - 1 233 * 234 * e2di_blocks[EXT2FS_NDADDR+2] 235 * block EXT2FS_NDADDR+2 is the triple indirect block 236 * holds block numbers for double-indirect 237 * blocks for blocks 238 * EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2 .. 239 * EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2 240 * + EXT2_NINDIR(fs)**3 - 1 241 */ 242 243 if (file_block < EXT2FS_NDADDR) { 244 /* Direct block. */ 245 *disk_block_p = fs2h32(fp->f_di.e2di_blocks[file_block]); 246 return 0; 247 } 248 249 file_block -= EXT2FS_NDADDR; 250 251 ind_cache = file_block >> LN2_IND_CACHE_SZ; 252 if (ind_cache == fp->f_ind_cache_block) { 253 *disk_block_p = 254 fs2h32(fp->f_ind_cache[file_block & IND_CACHE_MASK]); 255 return 0; 256 } 257 258 for (level = 0;;) { 259 level += fp->f_nishift; 260 if (file_block < (indp_t)1 << level) 261 break; 262 if (level > EXT2FS_NIADDR * fp->f_nishift) 263 /* Block number too high */ 264 return EFBIG; 265 file_block -= (indp_t)1 << level; 266 } 267 268 ind_block_num = 269 fs2h32(fp->f_di.e2di_blocks[EXT2FS_NDADDR + 270 (level / fp->f_nishift - 1)]); 271 272 for (;;) { 273 level -= fp->f_nishift; 274 if (ind_block_num == 0) { 275 *disk_block_p = 0; /* missing */ 276 return 0; 277 } 278 279 twiddle(); 280 /* 281 * If we were feeling brave, we could work out the number 282 * of the disk sector and read a single disk sector instead 283 * of a filesystem block. 284 * However we don't do this very often anyway... 285 */ 286 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 287 FSBTODB(fp->f_fs, ind_block_num), fs->e2fs_bsize, 288 buf, &rsize); 289 if (rc) 290 return rc; 291 if (rsize != fs->e2fs_bsize) 292 return EIO; 293 ind_block_num = fs2h32(buf[file_block >> level]); 294 if (level == 0) 295 break; 296 file_block &= (1 << level) - 1; 297 } 298 299 /* Save the part of the block that contains this sector */ 300 memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK], 301 IND_CACHE_SZ * sizeof fp->f_ind_cache[0]); 302 fp->f_ind_cache_block = ind_cache; 303 304 *disk_block_p = ind_block_num; 305 306 return 0; 307 } 308 309 /* 310 * Read a portion of a file into an internal buffer. 311 * Return the location in the buffer and the amount in the buffer. 312 */ 313 static int 314 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p) 315 { 316 struct file *fp = (struct file *)f->f_fsdata; 317 struct m_ext2fs *fs = fp->f_fs; 318 long off; 319 indp_t file_block; 320 indp_t disk_block = 0; /* XXX: gcc */ 321 size_t block_size; 322 int rc; 323 324 off = ext2_blkoff(fs, fp->f_seekp); 325 file_block = ext2_lblkno(fs, fp->f_seekp); 326 block_size = fs->e2fs_bsize; /* no fragment */ 327 328 if (file_block != fp->f_buf_blkno) { 329 rc = block_map(f, file_block, &disk_block); 330 if (rc) 331 return rc; 332 333 if (disk_block == 0) { 334 memset(fp->f_buf, 0, block_size); 335 fp->f_buf_size = block_size; 336 } else { 337 twiddle(); 338 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 339 FSBTODB(fs, disk_block), 340 block_size, fp->f_buf, &fp->f_buf_size); 341 if (rc) 342 return rc; 343 } 344 345 fp->f_buf_blkno = file_block; 346 } 347 348 /* 349 * Return address of byte in buffer corresponding to 350 * offset, and size of remainder of buffer after that 351 * byte. 352 */ 353 *buf_p = fp->f_buf + off; 354 *size_p = block_size - off; 355 356 /* 357 * But truncate buffer at end of file. 358 */ 359 /* XXX should handle LARGEFILE */ 360 if (*size_p > fp->f_di.e2di_size - fp->f_seekp) 361 *size_p = fp->f_di.e2di_size - fp->f_seekp; 362 363 return 0; 364 } 365 366 /* 367 * Search a directory for a name and return its 368 * inode number. 369 */ 370 static int 371 search_directory(const char *name, int length, struct open_file *f, 372 ino32_t *inumber_p) 373 { 374 struct file *fp = (struct file *)f->f_fsdata; 375 struct ext2fs_direct *dp; 376 struct ext2fs_direct *edp; 377 char *buf; 378 size_t buf_size; 379 int namlen; 380 int rc; 381 382 fp->f_seekp = 0; 383 /* XXX should handle LARGEFILE */ 384 while (fp->f_seekp < (off_t)fp->f_di.e2di_size) { 385 rc = buf_read_file(f, &buf, &buf_size); 386 if (rc) 387 return rc; 388 389 dp = (struct ext2fs_direct *)buf; 390 edp = (struct ext2fs_direct *)(buf + buf_size); 391 for (; dp < edp; 392 dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) { 393 if (fs2h16(dp->e2d_reclen) <= 0) 394 break; 395 if (fs2h32(dp->e2d_ino) == (ino32_t)0) 396 continue; 397 namlen = dp->e2d_namlen; 398 if (namlen == length && 399 !memcmp(name, dp->e2d_name, length)) { 400 /* found entry */ 401 *inumber_p = fs2h32(dp->e2d_ino); 402 return 0; 403 } 404 } 405 fp->f_seekp += buf_size; 406 } 407 return ENOENT; 408 } 409 410 int 411 read_sblock(struct open_file *f, struct m_ext2fs *fs) 412 { 413 static uint8_t sbbuf[SBSIZE]; 414 struct ext2fs ext2fs; 415 size_t buf_size; 416 int rc; 417 418 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 419 SBOFF / DEV_BSIZE, SBSIZE, sbbuf, &buf_size); 420 if (rc) 421 return rc; 422 423 if (buf_size != SBSIZE) 424 return EIO; 425 426 e2fs_sbload((void *)sbbuf, &ext2fs); 427 if (ext2fs.e2fs_magic != E2FS_MAGIC) 428 return EINVAL; 429 if (ext2fs.e2fs_rev > E2FS_REV1 || 430 (ext2fs.e2fs_rev == E2FS_REV1 && 431 (ext2fs.e2fs_first_ino != EXT2_FIRSTINO || 432 (ext2fs.e2fs_inode_size != 128 && ext2fs.e2fs_inode_size != 256) || 433 ext2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP))) { 434 return ENODEV; 435 } 436 437 e2fs_sbload((void *)sbbuf, &fs->e2fs); 438 /* compute in-memory m_ext2fs values */ 439 fs->e2fs_ncg = 440 howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock, 441 fs->e2fs.e2fs_bpg); 442 /* XXX assume hw bsize = 512 */ 443 fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1; 444 fs->e2fs_bsize = MINBSIZE << fs->e2fs.e2fs_log_bsize; 445 fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize; 446 fs->e2fs_qbmask = fs->e2fs_bsize - 1; 447 fs->e2fs_bmask = ~fs->e2fs_qbmask; 448 fs->e2fs_ngdb = 449 howmany(fs->e2fs_ncg, fs->e2fs_bsize / sizeof(struct ext2_gd)); 450 fs->e2fs_ipb = fs->e2fs_bsize / ext2fs.e2fs_inode_size; 451 fs->e2fs_itpg = fs->e2fs.e2fs_ipg / fs->e2fs_ipb; 452 453 return 0; 454 } 455 456 int 457 read_gdblock(struct open_file *f, struct m_ext2fs *fs) 458 { 459 struct file *fp = (struct file *)f->f_fsdata; 460 size_t rsize; 461 uint gdpb; 462 int i, rc; 463 464 gdpb = fs->e2fs_bsize / sizeof(struct ext2_gd); 465 466 for (i = 0; i < fs->e2fs_ngdb; i++) { 467 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 468 FSBTODB(fs, fs->e2fs.e2fs_first_dblock + 469 1 /* superblock */ + i), 470 fs->e2fs_bsize, fp->f_buf, &rsize); 471 if (rc) 472 return rc; 473 if (rsize != fs->e2fs_bsize) 474 return EIO; 475 476 e2fs_cgload((struct ext2_gd *)fp->f_buf, 477 &fs->e2fs_gd[i * gdpb], 478 (i == (fs->e2fs_ngdb - 1)) ? 479 (fs->e2fs_ncg - gdpb * i) * sizeof(struct ext2_gd): 480 fs->e2fs_bsize); 481 } 482 483 return 0; 484 } 485 486 487 /* 488 * Open a file. 489 */ 490 __compactcall int 491 ext2fs_open(const char *path, struct open_file *f) 492 { 493 #ifndef LIBSA_FS_SINGLECOMPONENT 494 const char *cp, *ncp; 495 int c; 496 #endif 497 ino32_t inumber; 498 struct file *fp; 499 struct m_ext2fs *fs; 500 int rc; 501 #ifndef LIBSA_NO_FS_SYMLINK 502 ino32_t parent_inumber; 503 int nlinks = 0; 504 char namebuf[MAXPATHLEN+1]; 505 char *buf; 506 #endif 507 508 /* allocate file system specific data structure */ 509 fp = alloc(sizeof(struct file)); 510 memset(fp, 0, sizeof(struct file)); 511 f->f_fsdata = (void *)fp; 512 513 /* allocate space and read super block */ 514 fs = alloc(sizeof(*fs)); 515 memset(fs, 0, sizeof(*fs)); 516 fp->f_fs = fs; 517 twiddle(); 518 519 rc = read_sblock(f, fs); 520 if (rc) 521 goto out; 522 523 #ifdef EXT2FS_DEBUG 524 dump_sblock(fs); 525 #endif 526 527 /* alloc a block sized buffer used for all fs transfers */ 528 fp->f_buf = alloc(fs->e2fs_bsize); 529 530 /* read group descriptor blocks */ 531 fs->e2fs_gd = alloc(sizeof(struct ext2_gd) * fs->e2fs_ncg); 532 rc = read_gdblock(f, fs); 533 if (rc) 534 goto out; 535 536 /* 537 * Calculate indirect block levels. 538 */ 539 { 540 indp_t mult; 541 int ln2; 542 543 /* 544 * We note that the number of indirect blocks is always 545 * a power of 2. This lets us use shifts and masks instead 546 * of divide and remainder and avoinds pulling in the 547 * 64bit division routine into the boot code. 548 */ 549 mult = EXT2_NINDIR(fs); 550 #ifdef DEBUG 551 if (!powerof2(mult)) { 552 /* Hummm was't a power of 2 */ 553 rc = EINVAL; 554 goto out; 555 } 556 #endif 557 for (ln2 = 0; mult != 1; ln2++) 558 mult >>= 1; 559 560 fp->f_nishift = ln2; 561 } 562 563 inumber = EXT2_ROOTINO; 564 if ((rc = read_inode(inumber, f)) != 0) 565 goto out; 566 567 #ifndef LIBSA_FS_SINGLECOMPONENT 568 cp = path; 569 while (*cp) { 570 571 /* 572 * Remove extra separators 573 */ 574 while (*cp == '/') 575 cp++; 576 if (*cp == '\0') 577 break; 578 579 /* 580 * Check that current node is a directory. 581 */ 582 if ((fp->f_di.e2di_mode & EXT2_IFMT) != EXT2_IFDIR) { 583 rc = ENOTDIR; 584 goto out; 585 } 586 587 /* 588 * Get next component of path name. 589 */ 590 ncp = cp; 591 while ((c = *cp) != '\0' && c != '/') 592 cp++; 593 594 /* 595 * Look up component in current directory. 596 * Save directory inumber in case we find a 597 * symbolic link. 598 */ 599 #ifndef LIBSA_NO_FS_SYMLINK 600 parent_inumber = inumber; 601 #endif 602 rc = search_directory(ncp, cp - ncp, f, &inumber); 603 if (rc) 604 goto out; 605 606 /* 607 * Open next component. 608 */ 609 if ((rc = read_inode(inumber, f)) != 0) 610 goto out; 611 612 #ifndef LIBSA_NO_FS_SYMLINK 613 /* 614 * Check for symbolic link. 615 */ 616 if ((fp->f_di.e2di_mode & EXT2_IFMT) == EXT2_IFLNK) { 617 /* XXX should handle LARGEFILE */ 618 int link_len = fp->f_di.e2di_size; 619 int len; 620 621 len = strlen(cp); 622 623 if (link_len + len > MAXPATHLEN || 624 ++nlinks > MAXSYMLINKS) { 625 rc = ENOENT; 626 goto out; 627 } 628 629 memmove(&namebuf[link_len], cp, len + 1); 630 631 if (link_len < EXT2_MAXSYMLINKLEN) { 632 memcpy(namebuf, fp->f_di.e2di_blocks, link_len); 633 } else { 634 /* 635 * Read file for symbolic link 636 */ 637 size_t buf_size; 638 indp_t disk_block; 639 640 buf = fp->f_buf; 641 rc = block_map(f, (indp_t)0, &disk_block); 642 if (rc) 643 goto out; 644 645 twiddle(); 646 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, 647 F_READ, FSBTODB(fs, disk_block), 648 fs->e2fs_bsize, buf, &buf_size); 649 if (rc) 650 goto out; 651 652 memcpy(namebuf, buf, link_len); 653 } 654 655 /* 656 * If relative pathname, restart at parent directory. 657 * If absolute pathname, restart at root. 658 */ 659 cp = namebuf; 660 if (*cp != '/') 661 inumber = parent_inumber; 662 else 663 inumber = (ino32_t)EXT2_ROOTINO; 664 665 if ((rc = read_inode(inumber, f)) != 0) 666 goto out; 667 } 668 #endif /* !LIBSA_NO_FS_SYMLINK */ 669 } 670 671 /* 672 * Found terminal component. 673 */ 674 rc = 0; 675 676 #else /* !LIBSA_FS_SINGLECOMPONENT */ 677 678 /* look up component in the current (root) directory */ 679 rc = search_directory(path, strlen(path), f, &inumber); 680 if (rc) 681 goto out; 682 683 /* open it */ 684 rc = read_inode(inumber, f); 685 686 #endif /* !LIBSA_FS_SINGLECOMPONENT */ 687 688 fp->f_seekp = 0; /* reset seek pointer */ 689 690 out: 691 if (rc) 692 ext2fs_close(f); 693 else 694 fsmod = "ext2fs"; 695 return rc; 696 } 697 698 __compactcall int 699 ext2fs_close(struct open_file *f) 700 { 701 struct file *fp = (struct file *)f->f_fsdata; 702 703 f->f_fsdata = NULL; 704 if (fp == NULL) 705 return 0; 706 707 if (fp->f_fs->e2fs_gd) 708 dealloc(fp->f_fs->e2fs_gd, 709 sizeof(struct ext2_gd) * fp->f_fs->e2fs_ncg); 710 if (fp->f_buf) 711 dealloc(fp->f_buf, fp->f_fs->e2fs_bsize); 712 dealloc(fp->f_fs, sizeof(*fp->f_fs)); 713 dealloc(fp, sizeof(struct file)); 714 return 0; 715 } 716 717 /* 718 * Copy a portion of a file into kernel memory. 719 * Cross block boundaries when necessary. 720 */ 721 __compactcall int 722 ext2fs_read(struct open_file *f, void *start, size_t size, size_t *resid) 723 { 724 struct file *fp = (struct file *)f->f_fsdata; 725 size_t csize; 726 char *buf; 727 size_t buf_size; 728 int rc = 0; 729 char *addr = start; 730 731 while (size != 0) { 732 /* XXX should handle LARGEFILE */ 733 if (fp->f_seekp >= (off_t)fp->f_di.e2di_size) 734 break; 735 736 rc = buf_read_file(f, &buf, &buf_size); 737 if (rc) 738 break; 739 740 csize = size; 741 if (csize > buf_size) 742 csize = buf_size; 743 744 memcpy(addr, buf, csize); 745 746 fp->f_seekp += csize; 747 addr += csize; 748 size -= csize; 749 } 750 if (resid) 751 *resid = size; 752 return rc; 753 } 754 755 /* 756 * Not implemented. 757 */ 758 #ifndef LIBSA_NO_FS_WRITE 759 __compactcall int 760 ext2fs_write(struct open_file *f, void *start, size_t size, size_t *resid) 761 { 762 763 return EROFS; 764 } 765 #endif /* !LIBSA_NO_FS_WRITE */ 766 767 #ifndef LIBSA_NO_FS_SEEK 768 __compactcall off_t 769 ext2fs_seek(struct open_file *f, off_t offset, int where) 770 { 771 struct file *fp = (struct file *)f->f_fsdata; 772 773 switch (where) { 774 case SEEK_SET: 775 fp->f_seekp = offset; 776 break; 777 case SEEK_CUR: 778 fp->f_seekp += offset; 779 break; 780 case SEEK_END: 781 /* XXX should handle LARGEFILE */ 782 fp->f_seekp = fp->f_di.e2di_size - offset; 783 break; 784 default: 785 return -1; 786 } 787 return fp->f_seekp; 788 } 789 #endif /* !LIBSA_NO_FS_SEEK */ 790 791 __compactcall int 792 ext2fs_stat(struct open_file *f, struct stat *sb) 793 { 794 struct file *fp = (struct file *)f->f_fsdata; 795 796 /* only important stuff */ 797 memset(sb, 0, sizeof *sb); 798 sb->st_mode = fp->f_di.e2di_mode; 799 sb->st_uid = fp->f_di.e2di_uid; 800 sb->st_gid = fp->f_di.e2di_gid; 801 /* XXX should handle LARGEFILE */ 802 sb->st_size = fp->f_di.e2di_size; 803 return 0; 804 } 805 806 #if defined(LIBSA_ENABLE_LS_OP) 807 808 #include "ls.h" 809 810 static const char *const typestr[] = { 811 "unknown", 812 "REG", 813 "DIR", 814 "CHR", 815 "BLK", 816 "FIFO", 817 "SOCK", 818 "LNK" 819 }; 820 821 __compactcall void 822 ext2fs_ls(struct open_file *f, const char *pattern) 823 { 824 struct file *fp = (struct file *)f->f_fsdata; 825 size_t block_size = fp->f_fs->e2fs_bsize; 826 char *buf; 827 size_t buf_size; 828 lsentry_t *names = NULL; 829 830 fp->f_seekp = 0; 831 while (fp->f_seekp < (off_t)fp->f_di.e2di_size) { 832 struct ext2fs_direct *dp, *edp; 833 int rc = buf_read_file(f, &buf, &buf_size); 834 if (rc) 835 goto out; 836 if (buf_size != block_size || buf_size == 0) 837 goto out; 838 839 dp = (struct ext2fs_direct *)buf; 840 edp = (struct ext2fs_direct *)(buf + buf_size); 841 842 for (; dp < edp; 843 dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) { 844 const char *t; 845 846 if (fs2h16(dp->e2d_reclen) <= 0) 847 goto out; 848 849 if (fs2h32(dp->e2d_ino) == 0) 850 continue; 851 852 if (dp->e2d_type >= NELEM(typestr) || 853 !(t = typestr[dp->e2d_type])) { 854 /* 855 * This does not handle "old" 856 * filesystems properly. On little 857 * endian machines, we get a bogus 858 * type name if the namlen matches a 859 * valid type identifier. We could 860 * check if we read namlen "0" and 861 * handle this case specially, if 862 * there were a pressing need... 863 */ 864 printf("bad dir entry\n"); 865 goto out; 866 } 867 lsadd(&names, pattern, dp->e2d_name, 868 strlen(dp->e2d_name), fs2h32(dp->e2d_ino), t); 869 } 870 fp->f_seekp += buf_size; 871 } 872 873 lsprint(names); 874 out: lsfree(names); 875 } 876 #endif 877 878 /* 879 * byte swap functions for big endian machines 880 * (ext2fs is always little endian) 881 * 882 * XXX: We should use src/sys/ufs/ext2fs/ext2fs_bswap.c 883 */ 884 885 /* These functions are only needed if native byte order is not big endian */ 886 #if BYTE_ORDER == BIG_ENDIAN 887 void 888 e2fs_sb_bswap(struct ext2fs *old, struct ext2fs *new) 889 { 890 891 /* preserve unused fields */ 892 memcpy(new, old, sizeof(struct ext2fs)); 893 new->e2fs_icount = bswap32(old->e2fs_icount); 894 new->e2fs_bcount = bswap32(old->e2fs_bcount); 895 new->e2fs_rbcount = bswap32(old->e2fs_rbcount); 896 new->e2fs_fbcount = bswap32(old->e2fs_fbcount); 897 new->e2fs_ficount = bswap32(old->e2fs_ficount); 898 new->e2fs_first_dblock = bswap32(old->e2fs_first_dblock); 899 new->e2fs_log_bsize = bswap32(old->e2fs_log_bsize); 900 new->e2fs_fsize = bswap32(old->e2fs_fsize); 901 new->e2fs_bpg = bswap32(old->e2fs_bpg); 902 new->e2fs_fpg = bswap32(old->e2fs_fpg); 903 new->e2fs_ipg = bswap32(old->e2fs_ipg); 904 new->e2fs_mtime = bswap32(old->e2fs_mtime); 905 new->e2fs_wtime = bswap32(old->e2fs_wtime); 906 new->e2fs_mnt_count = bswap16(old->e2fs_mnt_count); 907 new->e2fs_max_mnt_count = bswap16(old->e2fs_max_mnt_count); 908 new->e2fs_magic = bswap16(old->e2fs_magic); 909 new->e2fs_state = bswap16(old->e2fs_state); 910 new->e2fs_beh = bswap16(old->e2fs_beh); 911 new->e2fs_minrev = bswap16(old->e2fs_minrev); 912 new->e2fs_lastfsck = bswap32(old->e2fs_lastfsck); 913 new->e2fs_fsckintv = bswap32(old->e2fs_fsckintv); 914 new->e2fs_creator = bswap32(old->e2fs_creator); 915 new->e2fs_rev = bswap32(old->e2fs_rev); 916 new->e2fs_ruid = bswap16(old->e2fs_ruid); 917 new->e2fs_rgid = bswap16(old->e2fs_rgid); 918 new->e2fs_first_ino = bswap32(old->e2fs_first_ino); 919 new->e2fs_inode_size = bswap16(old->e2fs_inode_size); 920 new->e2fs_block_group_nr = bswap16(old->e2fs_block_group_nr); 921 new->e2fs_features_compat = bswap32(old->e2fs_features_compat); 922 new->e2fs_features_incompat = bswap32(old->e2fs_features_incompat); 923 new->e2fs_features_rocompat = bswap32(old->e2fs_features_rocompat); 924 new->e2fs_algo = bswap32(old->e2fs_algo); 925 new->e2fs_reserved_ngdb = bswap16(old->e2fs_reserved_ngdb); 926 } 927 928 void e2fs_cg_bswap(struct ext2_gd *old, struct ext2_gd *new, int size) 929 { 930 int i; 931 932 for (i = 0; i < (size / sizeof(struct ext2_gd)); i++) { 933 new[i].ext2bgd_b_bitmap = bswap32(old[i].ext2bgd_b_bitmap); 934 new[i].ext2bgd_i_bitmap = bswap32(old[i].ext2bgd_i_bitmap); 935 new[i].ext2bgd_i_tables = bswap32(old[i].ext2bgd_i_tables); 936 new[i].ext2bgd_nbfree = bswap16(old[i].ext2bgd_nbfree); 937 new[i].ext2bgd_nifree = bswap16(old[i].ext2bgd_nifree); 938 new[i].ext2bgd_ndirs = bswap16(old[i].ext2bgd_ndirs); 939 } 940 } 941 942 void e2fs_i_bswap(struct ext2fs_dinode *old, struct ext2fs_dinode *new) 943 { 944 945 new->e2di_mode = bswap16(old->e2di_mode); 946 new->e2di_uid = bswap16(old->e2di_uid); 947 new->e2di_gid = bswap16(old->e2di_gid); 948 new->e2di_nlink = bswap16(old->e2di_nlink); 949 new->e2di_size = bswap32(old->e2di_size); 950 new->e2di_atime = bswap32(old->e2di_atime); 951 new->e2di_ctime = bswap32(old->e2di_ctime); 952 new->e2di_mtime = bswap32(old->e2di_mtime); 953 new->e2di_dtime = bswap32(old->e2di_dtime); 954 new->e2di_nblock = bswap32(old->e2di_nblock); 955 new->e2di_flags = bswap32(old->e2di_flags); 956 new->e2di_gen = bswap32(old->e2di_gen); 957 new->e2di_facl = bswap32(old->e2di_facl); 958 new->e2di_dacl = bswap32(old->e2di_dacl); 959 new->e2di_faddr = bswap32(old->e2di_faddr); 960 memcpy(&new->e2di_blocks[0], &old->e2di_blocks[0], 961 (EXT2FS_NDADDR + EXT2FS_NIADDR) * sizeof(uint32_t)); 962 } 963 #endif 964 965 #ifdef EXT2FS_DEBUG 966 void 967 dump_sblock(struct m_ext2fs *fs) 968 { 969 970 printf("fs->e2fs.e2fs_bcount = %u\n", fs->e2fs.e2fs_bcount); 971 printf("fs->e2fs.e2fs_first_dblock = %u\n", fs->e2fs.e2fs_first_dblock); 972 printf("fs->e2fs.e2fs_log_bsize = %u\n", fs->e2fs.e2fs_log_bsize); 973 printf("fs->e2fs.e2fs_bpg = %u\n", fs->e2fs.e2fs_bpg); 974 printf("fs->e2fs.e2fs_ipg = %u\n", fs->e2fs.e2fs_ipg); 975 printf("fs->e2fs.e2fs_magic = 0x%x\n", fs->e2fs.e2fs_magic); 976 printf("fs->e2fs.e2fs_rev = %u\n", fs->e2fs.e2fs_rev); 977 978 if (fs->e2fs.e2fs_rev == E2FS_REV1) { 979 printf("fs->e2fs.e2fs_first_ino = %u\n", 980 fs->e2fs.e2fs_first_ino); 981 printf("fs->e2fs.e2fs_inode_size = %u\n", 982 fs->e2fs.e2fs_inode_size); 983 printf("fs->e2fs.e2fs_features_compat = %u\n", 984 fs->e2fs.e2fs_features_compat); 985 printf("fs->e2fs.e2fs_features_incompat = %u\n", 986 fs->e2fs.e2fs_features_incompat); 987 printf("fs->e2fs.e2fs_features_rocompat = %u\n", 988 fs->e2fs.e2fs_features_rocompat); 989 printf("fs->e2fs.e2fs_reserved_ngdb = %u\n", 990 fs->e2fs.e2fs_reserved_ngdb); 991 } 992 993 printf("fs->e2fs_bsize = %u\n", fs->e2fs_bsize); 994 printf("fs->e2fs_fsbtodb = %u\n", fs->e2fs_fsbtodb); 995 printf("fs->e2fs_ncg = %u\n", fs->e2fs_ncg); 996 printf("fs->e2fs_ngdb = %u\n", fs->e2fs_ngdb); 997 printf("fs->e2fs_ipb = %u\n", fs->e2fs_ipb); 998 printf("fs->e2fs_itpg = %u\n", fs->e2fs_itpg); 999 } 1000 #endif 1001