1 /* $NetBSD: minixfs3.c,v 1.8 2019/03/31 20:08:45 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2012 5 * Vrije Universiteit, Amsterdam, The Netherlands. All rights reserved. 6 * 7 * Author: Evgeniy Ivanov (based on libsa/ext2fs.c). 8 * 9 * This code is derived from src/sys/lib/libsa/ext2fs.c contributed to 10 * The NetBSD Foundation, see copyrights below. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS 22 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE 25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * Copyright (c) 1997 Manuel Bouyer. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 46 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 49 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 50 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 51 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 52 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 53 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 54 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 55 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 */ 57 58 /*- 59 * Copyright (c) 1993 60 * The Regents of the University of California. All rights reserved. 61 * 62 * This code is derived from software contributed to Berkeley by 63 * The Mach Operating System project at Carnegie-Mellon University. 64 * 65 * Redistribution and use in source and binary forms, with or without 66 * modification, are permitted provided that the following conditions 67 * are met: 68 * 1. Redistributions of source code must retain the above copyright 69 * notice, this list of conditions and the following disclaimer. 70 * 2. Redistributions in binary form must reproduce the above copyright 71 * notice, this list of conditions and the following disclaimer in the 72 * documentation and/or other materials provided with the distribution. 73 * 3. Neither the name of the University nor the names of its contributors 74 * may be used to endorse or promote products derived from this software 75 * without specific prior written permission. 76 * 77 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 78 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 79 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 80 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 81 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 82 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 83 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 84 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 85 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 86 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 87 * SUCH DAMAGE. 88 * 89 * 90 * Copyright (c) 1990, 1991 Carnegie Mellon University 91 * All Rights Reserved. 92 * 93 * Author: David Golub 94 * 95 * Permission to use, copy, modify and distribute this software and its 96 * documentation is hereby granted, provided that both the copyright 97 * notice and this permission notice appear in all copies of the 98 * software, derivative works or modified versions, and any portions 99 * thereof, and that both notices appear in supporting documentation. 100 * 101 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 102 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 103 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 104 * 105 * Carnegie Mellon requests users of this software to return to 106 * 107 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 108 * School of Computer Science 109 * Carnegie Mellon University 110 * Pittsburgh PA 15213-3890 111 * 112 * any improvements or extensions that they make and grant Carnegie the 113 * rights to redistribute these changes. 114 */ 115 116 /* 117 * Stand-alone file reading package for MFS file system. 118 */ 119 120 #include <sys/param.h> 121 #include <sys/time.h> 122 #ifdef _STANDALONE 123 #include <lib/libkern/libkern.h> 124 #else 125 #include <stddef.h> 126 #include <string.h> 127 #endif 128 129 #include "stand.h" 130 #include "minixfs3.h" 131 132 #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK) 133 #define LIBSA_NO_FS_SYMLINK 134 #endif 135 136 #if defined(LIBSA_NO_TWIDDLE) 137 #define twiddle() 138 #endif 139 140 typedef uint32_t ino32_t; 141 #ifndef FSBTODB 142 #define FSBTODB(fs, indp) MFS_FSBTODB(fs, indp) 143 #endif 144 145 /* 146 * To avoid having a lot of filesystem-block sized buffers lurking (which 147 * could be 32k) we only keep a few entries of the indirect block map. 148 * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block 149 * ~13 times pulling in a 6M kernel. 150 * The cache size must be smaller than the smallest filesystem block, 151 * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks). 152 */ 153 #define LN2_IND_CACHE_SZ 6 154 #define IND_CACHE_SZ (1 << LN2_IND_CACHE_SZ) 155 #define IND_CACHE_MASK (IND_CACHE_SZ - 1) 156 157 /* 158 * In-core open file. 159 */ 160 struct file { 161 off_t f_seekp; /* seek pointer */ 162 struct mfs_sblock *f_fs; /* pointer to super-block */ 163 struct mfs_dinode f_di; /* copy of on-disk inode */ 164 uint f_nishift; /* for blocks in indirect block */ 165 block_t f_ind_cache_block; 166 block_t f_ind_cache[IND_CACHE_SZ]; 167 168 char *f_buf; /* buffer for data block */ 169 size_t f_buf_size; /* size of data block */ 170 daddr_t f_buf_blkno; /* block number of data block */ 171 }; 172 173 static int read_inode(ino32_t, struct open_file *); 174 static int block_map(struct open_file *, block_t, block_t *); 175 static int buf_read_file(struct open_file *, void *, size_t *); 176 static int search_directory(const char *, int, struct open_file *, ino32_t *); 177 static int read_sblock(struct open_file *, struct mfs_sblock *); 178 179 /* 180 * Read a new inode into a file structure. 181 */ 182 static int 183 read_inode(ino32_t inumber, struct open_file *f) 184 { 185 struct file *fp = (struct file *)f->f_fsdata; 186 struct mfs_sblock *fs = fp->f_fs; 187 char *buf; 188 size_t rsize; 189 int rc; 190 daddr_t inode_sector; 191 struct mfs_dinode *dip; 192 193 inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber)); 194 195 /* 196 * Read inode and save it. 197 */ 198 buf = fp->f_buf; 199 twiddle(); 200 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 201 inode_sector, fs->mfs_block_size, buf, &rsize); 202 if (rc) 203 return rc; 204 if (rsize != fs->mfs_block_size) 205 return EIO; 206 207 dip = (struct mfs_dinode *)(buf + 208 INODE_SIZE * ino_to_fsbo(fs, inumber)); 209 mfs_iload(dip, &fp->f_di); 210 211 /* 212 * Clear out the old buffers 213 */ 214 fp->f_ind_cache_block = ~0; 215 fp->f_buf_blkno = -1; 216 return rc; 217 } 218 219 /* 220 * Given an offset in a file, find the disk block number (not zone!) 221 * that contains that block. 222 */ 223 static int 224 block_map(struct open_file *f, block_t file_block, block_t *disk_block_p) 225 { 226 struct file *fp = (struct file *)f->f_fsdata; 227 struct mfs_sblock *fs = fp->f_fs; 228 uint level; 229 block_t ind_cache; 230 block_t ind_block_num; 231 zone_t zone; 232 size_t rsize; 233 int rc; 234 int boff; 235 int scale = fs->mfs_log_zone_size; /* for block-zone conversion */ 236 block_t *buf = (void *)fp->f_buf; 237 238 /* 239 * Index structure of an inode: 240 * 241 * mdi_blocks[0..NR_DZONES-1] 242 * hold zone numbers for zones 243 * 0..NR_DZONES-1 244 * 245 * mdi_blocks[NR_DZONES+0] 246 * block NDADDR+0 is the single indirect block 247 * holds zone numbers for zones 248 * NR_DZONES .. NR_DZONES + MFS_NINDIR(fs)-1 249 * 250 * mdi_blocks[NR_DZONES+1] 251 * block NDADDR+1 is the double indirect block 252 * holds zone numbers for INDEX blocks for zones 253 * NR_DZONES + MFS_NINDIR(fs) .. 254 * NR_TZONES + MFS_NINDIR(fs) + MFS_NINDIR(fs)**2 - 1 255 */ 256 257 zone = file_block >> scale; 258 boff = (int) (file_block - (zone << scale) ); /* relative blk in zone */ 259 260 if (zone < NR_DZONES) { 261 /* Direct zone */ 262 zone_t z = fs2h32(fp->f_di.mdi_zone[zone]); 263 if (z == NO_ZONE) { 264 *disk_block_p = NO_BLOCK; 265 return 0; 266 } 267 *disk_block_p = (block_t) ((z << scale) + boff); 268 return 0; 269 } 270 271 zone -= NR_DZONES; 272 273 ind_cache = zone >> LN2_IND_CACHE_SZ; 274 if (ind_cache == fp->f_ind_cache_block) { 275 *disk_block_p = 276 fs2h32(fp->f_ind_cache[zone & IND_CACHE_MASK]); 277 return 0; 278 } 279 280 for (level = 0;;) { 281 level += fp->f_nishift; 282 283 if (zone < (block_t)1 << level) 284 break; 285 if (level > NIADDR * fp->f_nishift) 286 /* Zone number too high */ 287 return EFBIG; 288 zone -= (block_t)1 << level; 289 } 290 291 ind_block_num = 292 fs2h32(fp->f_di.mdi_zone[NR_DZONES + (level / fp->f_nishift - 1)]); 293 294 for (;;) { 295 level -= fp->f_nishift; 296 if (ind_block_num == 0) { 297 *disk_block_p = NO_BLOCK; /* missing */ 298 return 0; 299 } 300 301 twiddle(); 302 /* 303 * If we were feeling brave, we could work out the number 304 * of the disk sector and read a single disk sector instead 305 * of a filesystem block. 306 * However we don't do this very often anyway... 307 */ 308 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 309 FSBTODB(fs, ind_block_num), fs->mfs_block_size, 310 buf, &rsize); 311 if (rc) 312 return rc; 313 if (rsize != fs->mfs_block_size) 314 return EIO; 315 316 ind_block_num = fs2h32(buf[zone >> level]); 317 if (level == 0) 318 break; 319 zone &= (1 << level) - 1; 320 } 321 322 /* Save the part of the block that contains this sector */ 323 memcpy(fp->f_ind_cache, &buf[zone & ~IND_CACHE_MASK], 324 IND_CACHE_SZ * sizeof fp->f_ind_cache[0]); 325 fp->f_ind_cache_block = ind_cache; 326 327 zone = (zone_t)ind_block_num; 328 *disk_block_p = (block_t)((zone << scale) + boff); 329 return 0; 330 } 331 332 /* 333 * Read a portion of a file into an internal buffer. 334 * Return the location in the buffer and the amount in the buffer. 335 */ 336 static int 337 buf_read_file(struct open_file *f, void *v, size_t *size_p) 338 { 339 char **buf_p = v; 340 struct file *fp = (struct file *)f->f_fsdata; 341 struct mfs_sblock *fs = fp->f_fs; 342 long off; 343 block_t file_block; 344 block_t disk_block = 0; /* XXX: gcc */ 345 size_t block_size, nsz; 346 int rc; 347 348 off = mfs_blkoff(fs, fp->f_seekp); 349 file_block = mfs_lblkno(fs, fp->f_seekp); 350 block_size = fs->mfs_block_size; 351 352 if (file_block != fp->f_buf_blkno) { 353 rc = block_map(f, file_block, &disk_block); 354 if (rc) 355 return rc; 356 357 if (disk_block == 0) { 358 memset(fp->f_buf, 0, block_size); 359 fp->f_buf_size = block_size; 360 } else { 361 twiddle(); 362 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 363 FSBTODB(fs, disk_block), 364 block_size, fp->f_buf, &fp->f_buf_size); 365 if (rc) 366 return rc; 367 } 368 369 fp->f_buf_blkno = file_block; 370 } 371 372 /* 373 * Return address of byte in buffer corresponding to 374 * offset, and size of remainder of buffer after that 375 * byte. 376 */ 377 *buf_p = fp->f_buf + off; 378 *size_p = block_size - off; 379 380 /* 381 * But truncate buffer at end of file. 382 */ 383 nsz = (size_t)(fp->f_di.mdi_size - fp->f_seekp); 384 if (*size_p > nsz) 385 *size_p = nsz; 386 387 return 0; 388 } 389 390 /* 391 * Search a directory for a name and return its 392 * inode number. 393 */ 394 static int 395 search_directory(const char *name, int length, struct open_file *f, 396 ino32_t *inumber_p) 397 { 398 struct file *fp = (struct file *)f->f_fsdata; 399 struct mfs_sblock *fs = fp->f_fs; 400 struct mfs_direct *dp; 401 struct mfs_direct *dbuf; 402 size_t buf_size; 403 int namlen; 404 int rc; 405 406 fp->f_seekp = 0; 407 408 while (fp->f_seekp < (off_t)fp->f_di.mdi_size) { 409 rc = buf_read_file(f, (void *)&dbuf, &buf_size); 410 if (rc) 411 return rc; 412 if (buf_size == 0) 413 return EIO; 414 415 /* XXX we assume, that buf_read_file reads an fs block and 416 * doesn't truncate buffer. Currently i_size in MFS doesn't 417 * the same as size of allocated blocks, it makes buf_read_file 418 * to truncate buf_size. 419 */ 420 if (buf_size < fs->mfs_block_size) 421 buf_size = fs->mfs_block_size; 422 423 for (dp = dbuf; dp < &dbuf[NR_DIR_ENTRIES(fs)]; dp++) { 424 char *cp; 425 if (fs2h32(dp->mfsd_ino) == (ino32_t) 0) 426 continue; 427 /* Compute the length of the name */ 428 cp = memchr(dp->mfsd_name, '\0', sizeof(dp->mfsd_name)); 429 if (cp == NULL) 430 namlen = sizeof(dp->mfsd_name); 431 else 432 namlen = cp - (dp->mfsd_name); 433 434 if (namlen == length && 435 !memcmp(name, dp->mfsd_name, length)) { 436 /* found entry */ 437 *inumber_p = fs2h32(dp->mfsd_ino); 438 return 0; 439 } 440 } 441 fp->f_seekp += buf_size; 442 } 443 return ENOENT; 444 } 445 446 int 447 read_sblock(struct open_file *f, struct mfs_sblock *fs) 448 { 449 static uint8_t sbbuf[MINBSIZE]; 450 size_t buf_size; 451 int rc; 452 453 /* We must read amount multiple of sector size, hence we can't 454 * read SBSIZE and read MINBSIZE. 455 */ 456 if (SBSIZE > MINBSIZE) 457 return EINVAL; 458 459 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 460 SUPER_BLOCK_OFF / DEV_BSIZE, MINBSIZE, sbbuf, &buf_size); 461 if (rc) 462 return rc; 463 464 if (buf_size != MINBSIZE) 465 return EIO; 466 467 mfs_sbload((void *)sbbuf, fs); 468 469 if (fs->mfs_magic != SUPER_MAGIC) 470 return EINVAL; 471 if (fs->mfs_block_size < MINBSIZE) 472 return EINVAL; 473 if ((fs->mfs_block_size % 512) != 0) 474 return EINVAL; 475 if (SBSIZE > fs->mfs_block_size) 476 return EINVAL; 477 if ((fs->mfs_block_size % INODE_SIZE) != 0) 478 return EINVAL; 479 480 /* For even larger disks, a similar problem occurs with s_firstdatazone. 481 * If the on-disk field contains zero, we assume that the value was too 482 * large to fit, and compute it on the fly. 483 */ 484 if (fs->mfs_firstdatazone_old == 0) { 485 block_t offset; 486 offset = START_BLOCK + fs->mfs_imap_blocks + fs->mfs_zmap_blocks; 487 offset += (fs->mfs_ninodes + fs->mfs_inodes_per_block - 1) / 488 fs->mfs_inodes_per_block; 489 490 fs->mfs_firstdatazone = 491 (offset + (1 << fs->mfs_log_zone_size) - 1) >> 492 fs->mfs_log_zone_size; 493 } else { 494 fs->mfs_firstdatazone = (zone_t) fs->mfs_firstdatazone_old; 495 } 496 497 if (fs->mfs_imap_blocks < 1 || fs->mfs_zmap_blocks < 1 498 || fs->mfs_ninodes < 1 || fs->mfs_zones < 1 499 || fs->mfs_firstdatazone <= 4 500 || fs->mfs_firstdatazone >= fs->mfs_zones 501 || (unsigned) fs->mfs_log_zone_size > 4) 502 return EINVAL; 503 504 /* compute in-memory mfs_sblock values */ 505 fs->mfs_inodes_per_block = fs->mfs_block_size / INODE_SIZE; 506 507 508 { 509 int32_t mult = fs->mfs_block_size >> LOG_MINBSIZE; 510 int ln2 = LOG_MINBSIZE; 511 512 for (; mult != 1; ln2++) 513 mult >>= 1; 514 515 fs->mfs_bshift = ln2; 516 /* XXX assume hw bsize = 512 */ 517 fs->mfs_fsbtodb = ln2 - LOG_MINBSIZE + 1; 518 } 519 520 fs->mfs_qbmask = fs->mfs_block_size - 1; 521 fs->mfs_bmask = ~fs->mfs_qbmask; 522 523 return 0; 524 } 525 526 /* 527 * Open a file. 528 */ 529 __compactcall int 530 minixfs3_open(const char *path, struct open_file *f) 531 { 532 #ifndef LIBSA_FS_SINGLECOMPONENT 533 const char *cp, *ncp; 534 int c; 535 #endif 536 ino32_t inumber; 537 struct file *fp; 538 struct mfs_sblock *fs; 539 int rc; 540 #ifndef LIBSA_NO_FS_SYMLINK 541 ino32_t parent_inumber; 542 int nlinks = 0; 543 char namebuf[MAXPATHLEN+1]; 544 char *buf; 545 #endif 546 547 /* allocate file system specific data structure */ 548 fp = alloc(sizeof(struct file)); 549 memset(fp, 0, sizeof(struct file)); 550 f->f_fsdata = (void *)fp; 551 552 /* allocate space and read super block */ 553 fs = alloc(sizeof(*fs)); 554 memset(fs, 0, sizeof(*fs)); 555 fp->f_fs = fs; 556 twiddle(); 557 558 rc = read_sblock(f, fs); 559 if (rc) 560 goto out; 561 562 /* alloc a block sized buffer used for all fs transfers */ 563 fp->f_buf = alloc(fs->mfs_block_size); 564 565 /* 566 * Calculate indirect block levels. 567 */ 568 { 569 int32_t mult; 570 int ln2; 571 572 /* 573 * We note that the number of indirect blocks is always 574 * a power of 2. This lets us use shifts and masks instead 575 * of divide and remainder and avoinds pulling in the 576 * 64bit division routine into the boot code. 577 */ 578 mult = MFS_NINDIR(fs); 579 #ifdef DEBUG 580 if (!powerof2(mult)) { 581 /* Hummm was't a power of 2 */ 582 rc = EINVAL; 583 goto out; 584 } 585 #endif 586 for (ln2 = 0; mult != 1; ln2++) 587 mult >>= 1; 588 589 fp->f_nishift = ln2; 590 } 591 592 inumber = ROOT_INODE; 593 if ((rc = read_inode(inumber, f)) != 0) 594 goto out; 595 596 #ifndef LIBSA_FS_SINGLECOMPONENT 597 cp = path; 598 while (*cp) { 599 600 /* 601 * Remove extra separators 602 */ 603 while (*cp == '/') 604 cp++; 605 if (*cp == '\0') 606 break; 607 608 /* 609 * Check that current node is a directory. 610 */ 611 if ((fp->f_di.mdi_mode & I_TYPE) != I_DIRECTORY) { 612 rc = ENOTDIR; 613 goto out; 614 } 615 616 /* 617 * Get next component of path name. 618 */ 619 ncp = cp; 620 while ((c = *cp) != '\0' && c != '/') 621 cp++; 622 623 /* 624 * Look up component in current directory. 625 * Save directory inumber in case we find a 626 * symbolic link. 627 */ 628 #ifndef LIBSA_NO_FS_SYMLINK 629 parent_inumber = inumber; 630 #endif 631 rc = search_directory(ncp, cp - ncp, f, &inumber); 632 if (rc) 633 goto out; 634 635 /* 636 * Open next component. 637 */ 638 if ((rc = read_inode(inumber, f)) != 0) 639 goto out; 640 641 #ifndef LIBSA_NO_FS_SYMLINK 642 /* 643 * Check for symbolic link. 644 */ 645 if ((fp->f_di.mdi_mode & I_TYPE) == I_SYMBOLIC_LINK) { 646 int link_len = fp->f_di.mdi_size; 647 int len; 648 size_t buf_size; 649 block_t disk_block; 650 651 len = strlen(cp); 652 653 if (link_len + len > MAXPATHLEN || 654 ++nlinks > MAXSYMLINKS) { 655 rc = ENOENT; 656 goto out; 657 } 658 659 memmove(&namebuf[link_len], cp, len + 1); 660 661 /* 662 * Read file for symbolic link 663 */ 664 buf = fp->f_buf; 665 rc = block_map(f, (block_t)0, &disk_block); 666 if (rc) 667 goto out; 668 669 twiddle(); 670 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, 671 F_READ, FSBTODB(fs, disk_block), 672 fs->mfs_block_size, buf, &buf_size); 673 if (rc) 674 goto out; 675 676 memcpy(namebuf, buf, link_len); 677 678 /* 679 * If relative pathname, restart at parent directory. 680 * If absolute pathname, restart at root. 681 */ 682 cp = namebuf; 683 if (*cp != '/') 684 inumber = parent_inumber; 685 else 686 inumber = (ino32_t) ROOT_INODE; 687 688 if ((rc = read_inode(inumber, f)) != 0) 689 goto out; 690 } 691 #endif /* !LIBSA_NO_FS_SYMLINK */ 692 } 693 694 /* 695 * Found terminal component. 696 */ 697 rc = 0; 698 699 #else /* !LIBSA_FS_SINGLECOMPONENT */ 700 701 /* look up component in the current (root) directory */ 702 rc = search_directory(path, strlen(path), f, &inumber); 703 if (rc) 704 goto out; 705 706 /* open it */ 707 rc = read_inode(inumber, f); 708 709 #endif /* !LIBSA_FS_SINGLECOMPONENT */ 710 711 fp->f_seekp = 0; /* reset seek pointer */ 712 713 out: 714 if (rc) 715 minixfs3_close(f); 716 717 return rc; 718 } 719 720 __compactcall int 721 minixfs3_close(struct open_file *f) 722 { 723 struct file *fp = (struct file *)f->f_fsdata; 724 725 f->f_fsdata = NULL; 726 if (fp == NULL) 727 return 0; 728 729 if (fp->f_buf) 730 dealloc(fp->f_buf, fp->f_fs->mfs_block_size); 731 dealloc(fp->f_fs, sizeof(*fp->f_fs)); 732 dealloc(fp, sizeof(struct file)); 733 return 0; 734 } 735 736 /* 737 * Copy a portion of a file into kernel memory. 738 * Cross block boundaries when necessary. 739 */ 740 __compactcall int 741 minixfs3_read(struct open_file *f, void *start, size_t size, size_t *resid) 742 { 743 struct file *fp = (struct file *)f->f_fsdata; 744 size_t csize; 745 char *buf; 746 size_t buf_size; 747 int rc = 0; 748 char *addr = start; 749 750 while (size != 0) { 751 if (fp->f_seekp >= (off_t)fp->f_di.mdi_size) 752 break; 753 754 rc = buf_read_file(f, &buf, &buf_size); 755 if (rc) 756 break; 757 758 csize = size; 759 if (csize > buf_size) 760 csize = buf_size; 761 762 memcpy(addr, buf, csize); 763 764 fp->f_seekp += csize; 765 addr += csize; 766 size -= csize; 767 } 768 769 if (resid) 770 *resid = size; 771 return rc; 772 } 773 774 /* 775 * Not implemented. 776 */ 777 #ifndef LIBSA_NO_FS_WRITE 778 __compactcall int 779 minixfs3_write(struct open_file *f, void *start, size_t size, size_t *resid) 780 { 781 782 return EROFS; 783 } 784 #endif /* !LIBSA_NO_FS_WRITE */ 785 786 #ifndef LIBSA_NO_FS_SEEK 787 __compactcall off_t 788 minixfs3_seek(struct open_file *f, off_t offset, int where) 789 { 790 struct file *fp = (struct file *)f->f_fsdata; 791 792 switch (where) { 793 case SEEK_SET: 794 fp->f_seekp = offset; 795 break; 796 case SEEK_CUR: 797 fp->f_seekp += offset; 798 break; 799 case SEEK_END: 800 fp->f_seekp = fp->f_di.mdi_size - offset; 801 break; 802 default: 803 return -1; 804 } 805 return fp->f_seekp; 806 } 807 #endif /* !LIBSA_NO_FS_SEEK */ 808 809 __compactcall int 810 minixfs3_stat(struct open_file *f, struct stat *sb) 811 { 812 struct file *fp = (struct file *)f->f_fsdata; 813 814 /* only important stuff */ 815 memset(sb, 0, sizeof *sb); 816 sb->st_mode = fp->f_di.mdi_mode; 817 sb->st_uid = fp->f_di.mdi_uid; 818 sb->st_gid = fp->f_di.mdi_gid; 819 sb->st_size = fp->f_di.mdi_size; 820 return 0; 821 } 822 823 #if defined(LIBSA_ENABLE_LS_OP) 824 #include "ls.h" 825 __compactcall void 826 minixfs3_ls(struct open_file *f, const char *pattern) 827 { 828 struct file *fp = (struct file *)f->f_fsdata; 829 struct mfs_sblock *fs = fp->f_fs; 830 struct mfs_direct *dp; 831 struct mfs_direct *dbuf; 832 size_t buf_size; 833 lsentry_t *names = 0; 834 835 fp->f_seekp = 0; 836 while (fp->f_seekp < (off_t)fp->f_di.mdi_size) { 837 int rc = buf_read_file(f, &dbuf, &buf_size); 838 if (rc) 839 goto out; 840 841 /* XXX we assume, that buf_read_file reads an fs block and 842 * doesn't truncate buffer. Currently i_size in MFS doesn't 843 * the same as size of allocated blocks, it makes buf_read_file 844 * to truncate buf_size. 845 */ 846 if (buf_size < fs->mfs_block_size) 847 buf_size = fs->mfs_block_size; 848 849 for (dp = dbuf; dp < &dbuf[NR_DIR_ENTRIES(fs)]; dp++) { 850 char *cp; 851 int namlen; 852 853 if (fs2h32(dp->mfsd_ino) == 0) 854 continue; 855 856 /* Compute the length of the name, 857 * We don't use strlen and strcpy, because original MFS 858 * code doesn't. 859 */ 860 cp = memchr(dp->mfsd_name, '\0', sizeof(dp->mfsd_name)); 861 if (cp == NULL) 862 namlen = sizeof(dp->mfsd_name); 863 else 864 namlen = cp - (dp->mfsd_name); 865 866 lsadd(&names, pattern, dp->mfsd_name, namlen, 867 fs2h32(dp->mfsd_ino), "?"); 868 } 869 fp->f_seekp += buf_size; 870 } 871 lsprint(names); 872 out: lsfree(names); 873 } 874 #endif 875 876 /* 877 * byte swap functions for big endian machines 878 * (mfs is always little endian) 879 */ 880 881 /* These functions are only needed if native byte order is not big endian */ 882 #if BYTE_ORDER == BIG_ENDIAN 883 void 884 minixfs3_sb_bswap(struct mfs_sblock *old, struct mfs_sblock *new) 885 { 886 new->mfs_ninodes = bswap32(old->mfs_ninodes); 887 new->mfs_nzones = bswap16(old->mfs_nzones); 888 new->mfs_imap_blocks = bswap16(old->mfs_imap_blocks); 889 new->mfs_zmap_blocks = bswap16(old->mfs_zmap_blocks); 890 new->mfs_firstdatazone_old = bswap16(old->mfs_firstdatazone_old); 891 new->mfs_log_zone_size = bswap16(old->mfs_log_zone_size); 892 new->mfs_max_size = bswap32(old->mfs_max_size); 893 new->mfs_zones = bswap32(old->mfs_zones); 894 new->mfs_magic = bswap16(old->mfs_magic); 895 new->mfs_block_size = bswap16(old->mfs_block_size); 896 new->mfs_disk_version = old->mfs_disk_version; 897 } 898 899 void minixfs3_i_bswap(struct mfs_dinode *old, struct mfs_dinode *new) 900 { 901 int i; 902 903 new->mdi_mode = bswap16(old->mdi_mode); 904 new->mdi_nlinks = bswap16(old->mdi_nlinks); 905 new->mdi_uid = bswap16(old->mdi_uid); 906 new->mdi_gid = bswap16(old->mdi_gid); 907 new->mdi_size = bswap32(old->mdi_size); 908 new->mdi_atime = bswap32(old->mdi_atime); 909 new->mdi_mtime = bswap32(old->mdi_mtime); 910 new->mdi_ctime = bswap32(old->mdi_ctime); 911 912 /* We don't swap here, because indirects must be swapped later 913 * anyway, hence everything is done by block_map(). 914 */ 915 for (i = 0; i < NR_TZONES; i++) 916 new->mdi_zone[i] = old->mdi_zone[i]; 917 } 918 #endif 919