1 /* $NetBSD: ext2fs.c,v 1.28 2019/06/24 13:58:24 pgoyette 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 != (size_t)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, EXT2_DINODE_SIZE(fs)); 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 != (size_t)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, tsz; 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 tsz = (size_t)(fp->f_di.e2di_size - fp->f_seekp); 361 if (*size_p > tsz) 362 *size_p = tsz; 363 364 return 0; 365 } 366 367 /* 368 * Search a directory for a name and return its 369 * inode number. 370 */ 371 static int 372 search_directory(const char *name, int length, struct open_file *f, 373 ino32_t *inumber_p) 374 { 375 struct file *fp = (struct file *)f->f_fsdata; 376 struct ext2fs_direct *dp; 377 struct ext2fs_direct *edp; 378 char *buf; 379 size_t buf_size; 380 int namlen; 381 int rc; 382 383 fp->f_seekp = 0; 384 /* XXX should handle LARGEFILE */ 385 while (fp->f_seekp < (off_t)fp->f_di.e2di_size) { 386 rc = buf_read_file(f, &buf, &buf_size); 387 if (rc) 388 return rc; 389 390 dp = (struct ext2fs_direct *)buf; 391 edp = (struct ext2fs_direct *)(buf + buf_size); 392 for (; dp < edp; 393 dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) { 394 if (fs2h16(dp->e2d_reclen) <= 0) 395 break; 396 if (fs2h32(dp->e2d_ino) == (ino32_t)0) 397 continue; 398 namlen = dp->e2d_namlen; 399 if (namlen == length && 400 !memcmp(name, dp->e2d_name, length)) { 401 /* found entry */ 402 *inumber_p = fs2h32(dp->e2d_ino); 403 return 0; 404 } 405 } 406 fp->f_seekp += buf_size; 407 } 408 return ENOENT; 409 } 410 411 int 412 read_sblock(struct open_file *f, struct m_ext2fs *fs) 413 { 414 static uint8_t sbbuf[SBSIZE]; 415 struct ext2fs ext2fs; 416 size_t buf_size; 417 int rc; 418 419 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 420 SBOFF / DEV_BSIZE, SBSIZE, sbbuf, &buf_size); 421 if (rc) 422 return rc; 423 424 if (buf_size != SBSIZE) 425 return EIO; 426 427 e2fs_sbload((void *)sbbuf, &ext2fs); 428 if (ext2fs.e2fs_magic != E2FS_MAGIC) 429 return EINVAL; 430 if (ext2fs.e2fs_rev > E2FS_REV1 || 431 (ext2fs.e2fs_rev == E2FS_REV1 && 432 (ext2fs.e2fs_first_ino != EXT2_FIRSTINO || 433 (ext2fs.e2fs_inode_size != 128 && ext2fs.e2fs_inode_size != 256) || 434 ext2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP))) { 435 return ENODEV; 436 } 437 438 e2fs_sbload((void *)sbbuf, &fs->e2fs); 439 /* compute in-memory m_ext2fs values */ 440 fs->e2fs_ncg = 441 howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock, 442 fs->e2fs.e2fs_bpg); 443 /* XXX assume hw bsize = 512 */ 444 fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1; 445 fs->e2fs_bsize = MINBSIZE << fs->e2fs.e2fs_log_bsize; 446 fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize; 447 fs->e2fs_qbmask = fs->e2fs_bsize - 1; 448 fs->e2fs_bmask = ~fs->e2fs_qbmask; 449 fs->e2fs_ngdb = 450 howmany(fs->e2fs_ncg, fs->e2fs_bsize / sizeof(struct ext2_gd)); 451 fs->e2fs_ipb = fs->e2fs_bsize / ext2fs.e2fs_inode_size; 452 fs->e2fs_itpg = fs->e2fs.e2fs_ipg / fs->e2fs_ipb; 453 454 return 0; 455 } 456 457 int 458 read_gdblock(struct open_file *f, struct m_ext2fs *fs) 459 { 460 struct file *fp = (struct file *)f->f_fsdata; 461 size_t rsize; 462 uint gdpb; 463 int i, rc; 464 465 gdpb = fs->e2fs_bsize / sizeof(struct ext2_gd); 466 467 for (i = 0; i < fs->e2fs_ngdb; i++) { 468 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 469 FSBTODB(fs, fs->e2fs.e2fs_first_dblock + 470 1 /* superblock */ + i), 471 fs->e2fs_bsize, fp->f_buf, &rsize); 472 if (rc) 473 return rc; 474 if (rsize != (size_t)fs->e2fs_bsize) 475 return EIO; 476 477 e2fs_cgload((struct ext2_gd *)fp->f_buf, 478 &fs->e2fs_gd[i * gdpb], 479 (i == (fs->e2fs_ngdb - 1)) ? 480 (fs->e2fs_ncg - gdpb * i) * sizeof(struct ext2_gd): 481 (size_t)fs->e2fs_bsize); 482 } 483 484 return 0; 485 } 486 487 488 /* 489 * Open a file. 490 */ 491 __compactcall int 492 ext2fs_open(const char *path, struct open_file *f) 493 { 494 #ifndef LIBSA_FS_SINGLECOMPONENT 495 const char *cp, *ncp; 496 int c; 497 #endif 498 ino32_t inumber; 499 struct file *fp; 500 struct m_ext2fs *fs; 501 int rc; 502 #ifndef LIBSA_NO_FS_SYMLINK 503 ino32_t parent_inumber; 504 int nlinks = 0; 505 char namebuf[MAXPATHLEN+1]; 506 char *buf; 507 #endif 508 509 /* allocate file system specific data structure */ 510 fp = alloc(sizeof(struct file)); 511 memset(fp, 0, sizeof(struct file)); 512 f->f_fsdata = (void *)fp; 513 514 /* allocate space and read super block */ 515 fs = alloc(sizeof(*fs)); 516 memset(fs, 0, sizeof(*fs)); 517 fp->f_fs = fs; 518 twiddle(); 519 520 rc = read_sblock(f, fs); 521 if (rc) 522 goto out; 523 524 #ifdef EXT2FS_DEBUG 525 dump_sblock(fs); 526 #endif 527 528 /* alloc a block sized buffer used for all fs transfers */ 529 fp->f_buf = alloc(fs->e2fs_bsize); 530 531 /* read group descriptor blocks */ 532 fs->e2fs_gd = alloc(sizeof(struct ext2_gd) * fs->e2fs_ncg); 533 rc = read_gdblock(f, fs); 534 if (rc) 535 goto out; 536 537 /* 538 * Calculate indirect block levels. 539 */ 540 { 541 indp_t mult; 542 int ln2; 543 544 /* 545 * We note that the number of indirect blocks is always 546 * a power of 2. This lets us use shifts and masks instead 547 * of divide and remainder and avoinds pulling in the 548 * 64bit division routine into the boot code. 549 */ 550 mult = EXT2_NINDIR(fs); 551 #ifdef DEBUG 552 if (!powerof2(mult)) { 553 /* Hummm was't a power of 2 */ 554 rc = EINVAL; 555 goto out; 556 } 557 #endif 558 for (ln2 = 0; mult != 1; ln2++) 559 mult >>= 1; 560 561 fp->f_nishift = ln2; 562 } 563 564 inumber = EXT2_ROOTINO; 565 if ((rc = read_inode(inumber, f)) != 0) 566 goto out; 567 568 #ifndef LIBSA_FS_SINGLECOMPONENT 569 cp = path; 570 while (*cp) { 571 572 /* 573 * Remove extra separators 574 */ 575 while (*cp == '/') 576 cp++; 577 if (*cp == '\0') 578 break; 579 580 /* 581 * Check that current node is a directory. 582 */ 583 if ((fp->f_di.e2di_mode & EXT2_IFMT) != EXT2_IFDIR) { 584 rc = ENOTDIR; 585 goto out; 586 } 587 588 /* 589 * Get next component of path name. 590 */ 591 ncp = cp; 592 while ((c = *cp) != '\0' && c != '/') 593 cp++; 594 595 /* 596 * Look up component in current directory. 597 * Save directory inumber in case we find a 598 * symbolic link. 599 */ 600 #ifndef LIBSA_NO_FS_SYMLINK 601 parent_inumber = inumber; 602 #endif 603 rc = search_directory(ncp, cp - ncp, f, &inumber); 604 if (rc) 605 goto out; 606 607 /* 608 * Open next component. 609 */ 610 if ((rc = read_inode(inumber, f)) != 0) 611 goto out; 612 613 #ifndef LIBSA_NO_FS_SYMLINK 614 /* 615 * Check for symbolic link. 616 */ 617 if ((fp->f_di.e2di_mode & EXT2_IFMT) == EXT2_IFLNK) { 618 /* XXX should handle LARGEFILE */ 619 size_t link_len = fp->f_di.e2di_size; 620 size_t len; 621 622 len = strlen(cp); 623 624 if (link_len + len > MAXPATHLEN || 625 ++nlinks > MAXSYMLINKS) { 626 rc = ENOENT; 627 goto out; 628 } 629 630 memmove(&namebuf[link_len], cp, len + 1); 631 632 if (link_len < EXT2_MAXSYMLINKLEN) { 633 memcpy(namebuf, fp->f_di.e2di_blocks, link_len); 634 } else { 635 /* 636 * Read file for symbolic link 637 */ 638 size_t buf_size; 639 indp_t disk_block; 640 641 buf = fp->f_buf; 642 rc = block_map(f, (indp_t)0, &disk_block); 643 if (rc) 644 goto out; 645 646 twiddle(); 647 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, 648 F_READ, FSBTODB(fs, disk_block), 649 fs->e2fs_bsize, buf, &buf_size); 650 if (rc) 651 goto out; 652 653 memcpy(namebuf, buf, link_len); 654 } 655 656 /* 657 * If relative pathname, restart at parent directory. 658 * If absolute pathname, restart at root. 659 */ 660 cp = namebuf; 661 if (*cp != '/') 662 inumber = parent_inumber; 663 else 664 inumber = (ino32_t)EXT2_ROOTINO; 665 666 if ((rc = read_inode(inumber, f)) != 0) 667 goto out; 668 } 669 #endif /* !LIBSA_NO_FS_SYMLINK */ 670 } 671 672 /* 673 * Found terminal component. 674 */ 675 rc = 0; 676 677 #else /* !LIBSA_FS_SINGLECOMPONENT */ 678 679 /* look up component in the current (root) directory */ 680 rc = search_directory(path, strlen(path), f, &inumber); 681 if (rc) 682 goto out; 683 684 /* open it */ 685 rc = read_inode(inumber, f); 686 687 #endif /* !LIBSA_FS_SINGLECOMPONENT */ 688 689 fp->f_seekp = 0; /* reset seek pointer */ 690 691 out: 692 if (rc) 693 ext2fs_close(f); 694 else 695 fsmod = "ufs/ext2fs"; 696 return rc; 697 } 698 699 __compactcall int 700 ext2fs_close(struct open_file *f) 701 { 702 struct file *fp = (struct file *)f->f_fsdata; 703 704 f->f_fsdata = NULL; 705 if (fp == NULL) 706 return 0; 707 708 if (fp->f_fs->e2fs_gd) 709 dealloc(fp->f_fs->e2fs_gd, 710 sizeof(struct ext2_gd) * fp->f_fs->e2fs_ncg); 711 if (fp->f_buf) 712 dealloc(fp->f_buf, fp->f_fs->e2fs_bsize); 713 dealloc(fp->f_fs, sizeof(*fp->f_fs)); 714 dealloc(fp, sizeof(struct file)); 715 return 0; 716 } 717 718 /* 719 * Copy a portion of a file into kernel memory. 720 * Cross block boundaries when necessary. 721 */ 722 __compactcall int 723 ext2fs_read(struct open_file *f, void *start, size_t size, size_t *resid) 724 { 725 struct file *fp = (struct file *)f->f_fsdata; 726 size_t csize; 727 char *buf; 728 size_t buf_size; 729 int rc = 0; 730 char *addr = start; 731 732 while (size != 0) { 733 /* XXX should handle LARGEFILE */ 734 if (fp->f_seekp >= (off_t)fp->f_di.e2di_size) 735 break; 736 737 rc = buf_read_file(f, &buf, &buf_size); 738 if (rc) 739 break; 740 741 csize = size; 742 if (csize > buf_size) 743 csize = buf_size; 744 745 memcpy(addr, buf, csize); 746 747 fp->f_seekp += csize; 748 addr += csize; 749 size -= csize; 750 } 751 if (resid) 752 *resid = size; 753 return rc; 754 } 755 756 /* 757 * Not implemented. 758 */ 759 #ifndef LIBSA_NO_FS_WRITE 760 __compactcall int 761 ext2fs_write(struct open_file *f, void *start, size_t size, size_t *resid) 762 { 763 764 return EROFS; 765 } 766 #endif /* !LIBSA_NO_FS_WRITE */ 767 768 #ifndef LIBSA_NO_FS_SEEK 769 __compactcall off_t 770 ext2fs_seek(struct open_file *f, off_t offset, int where) 771 { 772 struct file *fp = (struct file *)f->f_fsdata; 773 774 switch (where) { 775 case SEEK_SET: 776 fp->f_seekp = offset; 777 break; 778 case SEEK_CUR: 779 fp->f_seekp += offset; 780 break; 781 case SEEK_END: 782 /* XXX should handle LARGEFILE */ 783 fp->f_seekp = fp->f_di.e2di_size - offset; 784 break; 785 default: 786 return -1; 787 } 788 return fp->f_seekp; 789 } 790 #endif /* !LIBSA_NO_FS_SEEK */ 791 792 __compactcall int 793 ext2fs_stat(struct open_file *f, struct stat *sb) 794 { 795 struct file *fp = (struct file *)f->f_fsdata; 796 797 /* only important stuff */ 798 memset(sb, 0, sizeof *sb); 799 sb->st_mode = fp->f_di.e2di_mode; 800 sb->st_uid = fp->f_di.e2di_uid; 801 sb->st_gid = fp->f_di.e2di_gid; 802 /* XXX should handle LARGEFILE */ 803 sb->st_size = fp->f_di.e2di_size; 804 return 0; 805 } 806 807 #if defined(LIBSA_ENABLE_LS_OP) 808 809 #include "ls.h" 810 811 static const char *const typestr[] = { 812 "unknown", 813 "REG", 814 "DIR", 815 "CHR", 816 "BLK", 817 "FIFO", 818 "SOCK", 819 "LNK" 820 }; 821 822 __compactcall void 823 ext2fs_ls(struct open_file *f, const char *pattern) 824 { 825 struct file *fp = (struct file *)f->f_fsdata; 826 size_t block_size = fp->f_fs->e2fs_bsize; 827 char *buf; 828 size_t buf_size; 829 lsentry_t *names = NULL; 830 831 fp->f_seekp = 0; 832 while (fp->f_seekp < (off_t)fp->f_di.e2di_size) { 833 struct ext2fs_direct *dp, *edp; 834 int rc = buf_read_file(f, &buf, &buf_size); 835 if (rc) 836 goto out; 837 if (buf_size != block_size || buf_size == 0) 838 goto out; 839 840 dp = (struct ext2fs_direct *)buf; 841 edp = (struct ext2fs_direct *)(buf + buf_size); 842 843 for (; dp < edp; 844 dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) { 845 const char *t; 846 847 if (fs2h16(dp->e2d_reclen) <= 0) 848 goto out; 849 850 if (fs2h32(dp->e2d_ino) == 0) 851 continue; 852 853 if (dp->e2d_type >= NELEM(typestr) || 854 !(t = typestr[dp->e2d_type])) { 855 /* 856 * This does not handle "old" 857 * filesystems properly. On little 858 * endian machines, we get a bogus 859 * type name if the namlen matches a 860 * valid type identifier. We could 861 * check if we read namlen "0" and 862 * handle this case specially, if 863 * there were a pressing need... 864 */ 865 printf("bad dir entry\n"); 866 goto out; 867 } 868 lsadd(&names, pattern, dp->e2d_name, 869 strlen(dp->e2d_name), fs2h32(dp->e2d_ino), t); 870 } 871 fp->f_seekp += buf_size; 872 } 873 874 lsprint(names); 875 out: lsfree(names); 876 } 877 #endif 878 879 /* 880 * byte swap functions for big endian machines 881 * (ext2fs is always little endian) 882 * 883 * XXX: We should use src/sys/ufs/ext2fs/ext2fs_bswap.c 884 */ 885 886 /* These functions are only needed if native byte order is not big endian */ 887 #if BYTE_ORDER == BIG_ENDIAN 888 void 889 e2fs_sb_bswap(struct ext2fs *old, struct ext2fs *new) 890 { 891 892 /* preserve unused fields */ 893 memcpy(new, old, sizeof(struct ext2fs)); 894 new->e2fs_icount = bswap32(old->e2fs_icount); 895 new->e2fs_bcount = bswap32(old->e2fs_bcount); 896 new->e2fs_rbcount = bswap32(old->e2fs_rbcount); 897 new->e2fs_fbcount = bswap32(old->e2fs_fbcount); 898 new->e2fs_ficount = bswap32(old->e2fs_ficount); 899 new->e2fs_first_dblock = bswap32(old->e2fs_first_dblock); 900 new->e2fs_log_bsize = bswap32(old->e2fs_log_bsize); 901 new->e2fs_fsize = bswap32(old->e2fs_fsize); 902 new->e2fs_bpg = bswap32(old->e2fs_bpg); 903 new->e2fs_fpg = bswap32(old->e2fs_fpg); 904 new->e2fs_ipg = bswap32(old->e2fs_ipg); 905 new->e2fs_mtime = bswap32(old->e2fs_mtime); 906 new->e2fs_wtime = bswap32(old->e2fs_wtime); 907 new->e2fs_mnt_count = bswap16(old->e2fs_mnt_count); 908 new->e2fs_max_mnt_count = bswap16(old->e2fs_max_mnt_count); 909 new->e2fs_magic = bswap16(old->e2fs_magic); 910 new->e2fs_state = bswap16(old->e2fs_state); 911 new->e2fs_beh = bswap16(old->e2fs_beh); 912 new->e2fs_minrev = bswap16(old->e2fs_minrev); 913 new->e2fs_lastfsck = bswap32(old->e2fs_lastfsck); 914 new->e2fs_fsckintv = bswap32(old->e2fs_fsckintv); 915 new->e2fs_creator = bswap32(old->e2fs_creator); 916 new->e2fs_rev = bswap32(old->e2fs_rev); 917 new->e2fs_ruid = bswap16(old->e2fs_ruid); 918 new->e2fs_rgid = bswap16(old->e2fs_rgid); 919 new->e2fs_first_ino = bswap32(old->e2fs_first_ino); 920 new->e2fs_inode_size = bswap16(old->e2fs_inode_size); 921 new->e2fs_block_group_nr = bswap16(old->e2fs_block_group_nr); 922 new->e2fs_features_compat = bswap32(old->e2fs_features_compat); 923 new->e2fs_features_incompat = bswap32(old->e2fs_features_incompat); 924 new->e2fs_features_rocompat = bswap32(old->e2fs_features_rocompat); 925 new->e2fs_algo = bswap32(old->e2fs_algo); 926 new->e2fs_reserved_ngdb = bswap16(old->e2fs_reserved_ngdb); 927 } 928 929 void e2fs_i_bswap(struct ext2fs_dinode *old, struct ext2fs_dinode *new, 930 size_t isize) 931 { 932 /* preserve non-swapped and unused fields */ 933 memcpy(new, old, isize); 934 935 /* swap what needs to be swapped */ 936 new->e2di_mode = bswap16(old->e2di_mode); 937 new->e2di_uid = bswap16(old->e2di_uid); 938 new->e2di_gid = bswap16(old->e2di_gid); 939 new->e2di_nlink = bswap16(old->e2di_nlink); 940 new->e2di_size = bswap32(old->e2di_size); 941 new->e2di_atime = bswap32(old->e2di_atime); 942 new->e2di_ctime = bswap32(old->e2di_ctime); 943 new->e2di_mtime = bswap32(old->e2di_mtime); 944 new->e2di_dtime = bswap32(old->e2di_dtime); 945 new->e2di_nblock = bswap32(old->e2di_nblock); 946 new->e2di_flags = bswap32(old->e2di_flags); 947 new->e2di_version = bswap32(old->e2di_version); 948 new->e2di_gen = bswap32(old->e2di_gen); 949 new->e2di_facl = bswap32(old->e2di_facl); 950 new->e2di_size_high = bswap32(old->e2di_size_high); 951 new->e2di_nblock_high = bswap16(old->e2di_nblock_high); 952 new->e2di_facl_high = bswap16(old->e2di_facl_high); 953 new->e2di_uid_high = bswap16(old->e2di_uid_high); 954 new->e2di_gid_high = bswap16(old->e2di_gid_high); 955 new->e2di_checksum_low = bswap16(old->e2di_checksum_low); 956 957 /* 958 * Following fields are only supported for inode sizes bigger 959 * than the old ext2 one 960 */ 961 if (isize == EXT2_REV0_DINODE_SIZE) 962 return; 963 964 new->e2di_extra_isize = bswap16(old->e2di_extra_isize); 965 new->e2di_checksum_high = bswap16(old->e2di_checksum_high); 966 967 /* Following fields are ext4, might not be actually present */ 968 if (EXT2_DINODE_FITS(new, e2di_ctime_extra, isize)) 969 new->e2di_ctime_extra = bswap32(old->e2di_ctime_extra); 970 if (EXT2_DINODE_FITS(new, e2di_mtime_extra, isize)) 971 new->e2di_mtime_extra = bswap32(old->e2di_mtime_extra); 972 if (EXT2_DINODE_FITS(new, e2di_atime_extra, isize)) 973 new->e2di_atime_extra = bswap32(old->e2di_atime_extra); 974 if (EXT2_DINODE_FITS(new, e2di_crtime, isize)) 975 new->e2di_crtime = bswap32(old->e2di_crtime); 976 if (EXT2_DINODE_FITS(new, e2di_crtime_extra, isize)) 977 new->e2di_crtime_extra = bswap32(old->e2di_crtime_extra); 978 if (EXT2_DINODE_FITS(new, e2di_version_high, isize)) 979 new->e2di_version_high = bswap32(old->e2di_version_high); 980 if (EXT2_DINODE_FITS(new, e2di_projid, isize)) 981 new->e2di_projid = bswap32(old->e2di_projid); 982 } 983 #endif 984 985 #ifdef EXT2FS_DEBUG 986 void 987 dump_sblock(struct m_ext2fs *fs) 988 { 989 990 printf("fs->e2fs.e2fs_bcount = %u\n", fs->e2fs.e2fs_bcount); 991 printf("fs->e2fs.e2fs_first_dblock = %u\n", fs->e2fs.e2fs_first_dblock); 992 printf("fs->e2fs.e2fs_log_bsize = %u\n", fs->e2fs.e2fs_log_bsize); 993 printf("fs->e2fs.e2fs_bpg = %u\n", fs->e2fs.e2fs_bpg); 994 printf("fs->e2fs.e2fs_ipg = %u\n", fs->e2fs.e2fs_ipg); 995 printf("fs->e2fs.e2fs_magic = 0x%x\n", fs->e2fs.e2fs_magic); 996 printf("fs->e2fs.e2fs_rev = %u\n", fs->e2fs.e2fs_rev); 997 998 if (fs->e2fs.e2fs_rev == E2FS_REV1) { 999 printf("fs->e2fs.e2fs_first_ino = %u\n", 1000 fs->e2fs.e2fs_first_ino); 1001 printf("fs->e2fs.e2fs_inode_size = %u\n", 1002 fs->e2fs.e2fs_inode_size); 1003 printf("fs->e2fs.e2fs_features_compat = %u\n", 1004 fs->e2fs.e2fs_features_compat); 1005 printf("fs->e2fs.e2fs_features_incompat = %u\n", 1006 fs->e2fs.e2fs_features_incompat); 1007 printf("fs->e2fs.e2fs_features_rocompat = %u\n", 1008 fs->e2fs.e2fs_features_rocompat); 1009 printf("fs->e2fs.e2fs_reserved_ngdb = %u\n", 1010 fs->e2fs.e2fs_reserved_ngdb); 1011 } 1012 1013 printf("fs->e2fs_bsize = %u\n", fs->e2fs_bsize); 1014 printf("fs->e2fs_fsbtodb = %u\n", fs->e2fs_fsbtodb); 1015 printf("fs->e2fs_ncg = %u\n", fs->e2fs_ncg); 1016 printf("fs->e2fs_ngdb = %u\n", fs->e2fs_ngdb); 1017 printf("fs->e2fs_ipb = %u\n", fs->e2fs_ipb); 1018 printf("fs->e2fs_itpg = %u\n", fs->e2fs_itpg); 1019 } 1020 #endif 1021