1 /* $NetBSD: minixfs3.c,v 1.7 2014/03/20 03:13:18 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 <string.h> 126 #endif 127 128 #include "stand.h" 129 #include "minixfs3.h" 130 131 #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK) 132 #define LIBSA_NO_FS_SYMLINK 133 #endif 134 135 #if defined(LIBSA_NO_TWIDDLE) 136 #define twiddle() 137 #endif 138 139 typedef uint32_t ino32_t; 140 #ifndef FSBTODB 141 #define FSBTODB(fs, indp) MFS_FSBTODB(fs, indp) 142 #endif 143 144 /* 145 * To avoid having a lot of filesystem-block sized buffers lurking (which 146 * could be 32k) we only keep a few entries of the indirect block map. 147 * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block 148 * ~13 times pulling in a 6M kernel. 149 * The cache size must be smaller than the smallest filesystem block, 150 * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks). 151 */ 152 #define LN2_IND_CACHE_SZ 6 153 #define IND_CACHE_SZ (1 << LN2_IND_CACHE_SZ) 154 #define IND_CACHE_MASK (IND_CACHE_SZ - 1) 155 156 /* 157 * In-core open file. 158 */ 159 struct file { 160 off_t f_seekp; /* seek pointer */ 161 struct mfs_sblock *f_fs; /* pointer to super-block */ 162 struct mfs_dinode f_di; /* copy of on-disk inode */ 163 uint f_nishift; /* for blocks in indirect block */ 164 block_t f_ind_cache_block; 165 block_t f_ind_cache[IND_CACHE_SZ]; 166 167 char *f_buf; /* buffer for data block */ 168 size_t f_buf_size; /* size of data block */ 169 daddr_t f_buf_blkno; /* block number of data block */ 170 }; 171 172 static int read_inode(ino32_t, struct open_file *); 173 static int block_map(struct open_file *, block_t, block_t *); 174 static int buf_read_file(struct open_file *, void *, size_t *); 175 static int search_directory(const char *, int, struct open_file *, ino32_t *); 176 static int read_sblock(struct open_file *, struct mfs_sblock *); 177 178 /* 179 * Read a new inode into a file structure. 180 */ 181 static int 182 read_inode(ino32_t inumber, struct open_file *f) 183 { 184 struct file *fp = (struct file *)f->f_fsdata; 185 struct mfs_sblock *fs = fp->f_fs; 186 char *buf; 187 size_t rsize; 188 int rc; 189 daddr_t inode_sector; 190 struct mfs_dinode *dip; 191 192 inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber)); 193 194 /* 195 * Read inode and save it. 196 */ 197 buf = fp->f_buf; 198 twiddle(); 199 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 200 inode_sector, fs->mfs_block_size, buf, &rsize); 201 if (rc) 202 return rc; 203 if (rsize != fs->mfs_block_size) 204 return EIO; 205 206 dip = (struct mfs_dinode *)(buf + 207 INODE_SIZE * ino_to_fsbo(fs, inumber)); 208 mfs_iload(dip, &fp->f_di); 209 210 /* 211 * Clear out the old buffers 212 */ 213 fp->f_ind_cache_block = ~0; 214 fp->f_buf_blkno = -1; 215 return rc; 216 } 217 218 /* 219 * Given an offset in a file, find the disk block number (not zone!) 220 * that contains that block. 221 */ 222 static int 223 block_map(struct open_file *f, block_t file_block, block_t *disk_block_p) 224 { 225 struct file *fp = (struct file *)f->f_fsdata; 226 struct mfs_sblock *fs = fp->f_fs; 227 uint level; 228 block_t ind_cache; 229 block_t ind_block_num; 230 zone_t zone; 231 size_t rsize; 232 int rc; 233 int boff; 234 int scale = fs->mfs_log_zone_size; /* for block-zone conversion */ 235 block_t *buf = (void *)fp->f_buf; 236 237 /* 238 * Index structure of an inode: 239 * 240 * mdi_blocks[0..NR_DZONES-1] 241 * hold zone numbers for zones 242 * 0..NR_DZONES-1 243 * 244 * mdi_blocks[NR_DZONES+0] 245 * block NDADDR+0 is the single indirect block 246 * holds zone numbers for zones 247 * NR_DZONES .. NR_DZONES + MFS_NINDIR(fs)-1 248 * 249 * mdi_blocks[NR_DZONES+1] 250 * block NDADDR+1 is the double indirect block 251 * holds zone numbers for INDEX blocks for zones 252 * NR_DZONES + MFS_NINDIR(fs) .. 253 * NR_TZONES + MFS_NINDIR(fs) + MFS_NINDIR(fs)**2 - 1 254 */ 255 256 zone = file_block >> scale; 257 boff = (int) (file_block - (zone << scale) ); /* relative blk in zone */ 258 259 if (zone < NR_DZONES) { 260 /* Direct zone */ 261 zone_t z = fs2h32(fp->f_di.mdi_zone[zone]); 262 if (z == NO_ZONE) { 263 *disk_block_p = NO_BLOCK; 264 return 0; 265 } 266 *disk_block_p = (block_t) ((z << scale) + boff); 267 return 0; 268 } 269 270 zone -= NR_DZONES; 271 272 ind_cache = zone >> LN2_IND_CACHE_SZ; 273 if (ind_cache == fp->f_ind_cache_block) { 274 *disk_block_p = 275 fs2h32(fp->f_ind_cache[zone & IND_CACHE_MASK]); 276 return 0; 277 } 278 279 for (level = 0;;) { 280 level += fp->f_nishift; 281 282 if (zone < (block_t)1 << level) 283 break; 284 if (level > NIADDR * fp->f_nishift) 285 /* Zone number too high */ 286 return EFBIG; 287 zone -= (block_t)1 << level; 288 } 289 290 ind_block_num = 291 fs2h32(fp->f_di.mdi_zone[NR_DZONES + (level / fp->f_nishift - 1)]); 292 293 for (;;) { 294 level -= fp->f_nishift; 295 if (ind_block_num == 0) { 296 *disk_block_p = NO_BLOCK; /* missing */ 297 return 0; 298 } 299 300 twiddle(); 301 /* 302 * If we were feeling brave, we could work out the number 303 * of the disk sector and read a single disk sector instead 304 * of a filesystem block. 305 * However we don't do this very often anyway... 306 */ 307 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 308 FSBTODB(fs, ind_block_num), fs->mfs_block_size, 309 buf, &rsize); 310 if (rc) 311 return rc; 312 if (rsize != fs->mfs_block_size) 313 return EIO; 314 315 ind_block_num = fs2h32(buf[zone >> level]); 316 if (level == 0) 317 break; 318 zone &= (1 << level) - 1; 319 } 320 321 /* Save the part of the block that contains this sector */ 322 memcpy(fp->f_ind_cache, &buf[zone & ~IND_CACHE_MASK], 323 IND_CACHE_SZ * sizeof fp->f_ind_cache[0]); 324 fp->f_ind_cache_block = ind_cache; 325 326 zone = (zone_t)ind_block_num; 327 *disk_block_p = (block_t)((zone << scale) + boff); 328 return 0; 329 } 330 331 /* 332 * Read a portion of a file into an internal buffer. 333 * Return the location in the buffer and the amount in the buffer. 334 */ 335 static int 336 buf_read_file(struct open_file *f, void *v, size_t *size_p) 337 { 338 char **buf_p = v; 339 struct file *fp = (struct file *)f->f_fsdata; 340 struct mfs_sblock *fs = fp->f_fs; 341 long off; 342 block_t file_block; 343 block_t disk_block = 0; /* XXX: gcc */ 344 size_t block_size; 345 int rc; 346 347 off = mfs_blkoff(fs, fp->f_seekp); 348 file_block = mfs_lblkno(fs, fp->f_seekp); 349 block_size = fs->mfs_block_size; 350 351 if (file_block != fp->f_buf_blkno) { 352 rc = block_map(f, file_block, &disk_block); 353 if (rc) 354 return rc; 355 356 if (disk_block == 0) { 357 memset(fp->f_buf, 0, block_size); 358 fp->f_buf_size = block_size; 359 } else { 360 twiddle(); 361 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 362 FSBTODB(fs, disk_block), 363 block_size, fp->f_buf, &fp->f_buf_size); 364 if (rc) 365 return rc; 366 } 367 368 fp->f_buf_blkno = file_block; 369 } 370 371 /* 372 * Return address of byte in buffer corresponding to 373 * offset, and size of remainder of buffer after that 374 * byte. 375 */ 376 *buf_p = fp->f_buf + off; 377 *size_p = block_size - off; 378 379 /* 380 * But truncate buffer at end of file. 381 */ 382 if (*size_p > fp->f_di.mdi_size - fp->f_seekp) 383 *size_p = fp->f_di.mdi_size - fp->f_seekp; 384 385 return 0; 386 } 387 388 /* 389 * Search a directory for a name and return its 390 * inode number. 391 */ 392 static int 393 search_directory(const char *name, int length, struct open_file *f, 394 ino32_t *inumber_p) 395 { 396 struct file *fp = (struct file *)f->f_fsdata; 397 struct mfs_sblock *fs = fp->f_fs; 398 struct mfs_direct *dp; 399 struct mfs_direct *dbuf; 400 size_t buf_size; 401 int namlen; 402 int rc; 403 404 fp->f_seekp = 0; 405 406 while (fp->f_seekp < (off_t)fp->f_di.mdi_size) { 407 rc = buf_read_file(f, (void *)&dbuf, &buf_size); 408 if (rc) 409 return rc; 410 if (buf_size == 0) 411 return EIO; 412 413 /* XXX we assume, that buf_read_file reads an fs block and 414 * doesn't truncate buffer. Currently i_size in MFS doesn't 415 * the same as size of allocated blocks, it makes buf_read_file 416 * to truncate buf_size. 417 */ 418 if (buf_size < fs->mfs_block_size) 419 buf_size = fs->mfs_block_size; 420 421 for (dp = dbuf; dp < &dbuf[NR_DIR_ENTRIES(fs)]; dp++) { 422 char *cp; 423 if (fs2h32(dp->mfsd_ino) == (ino32_t) 0) 424 continue; 425 /* Compute the length of the name */ 426 cp = memchr(dp->mfsd_name, '\0', sizeof(dp->mfsd_name)); 427 if (cp == NULL) 428 namlen = sizeof(dp->mfsd_name); 429 else 430 namlen = cp - (dp->mfsd_name); 431 432 if (namlen == length && 433 !memcmp(name, dp->mfsd_name, length)) { 434 /* found entry */ 435 *inumber_p = fs2h32(dp->mfsd_ino); 436 return 0; 437 } 438 } 439 fp->f_seekp += buf_size; 440 } 441 return ENOENT; 442 } 443 444 int 445 read_sblock(struct open_file *f, struct mfs_sblock *fs) 446 { 447 static uint8_t sbbuf[MINBSIZE]; 448 size_t buf_size; 449 int rc; 450 451 /* We must read amount multiple of sector size, hence we can't 452 * read SBSIZE and read MINBSIZE. 453 */ 454 if (SBSIZE > MINBSIZE) 455 return EINVAL; 456 457 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, 458 SUPER_BLOCK_OFF / DEV_BSIZE, MINBSIZE, sbbuf, &buf_size); 459 if (rc) 460 return rc; 461 462 if (buf_size != MINBSIZE) 463 return EIO; 464 465 mfs_sbload((void *)sbbuf, fs); 466 467 if (fs->mfs_magic != SUPER_MAGIC) 468 return EINVAL; 469 if (fs->mfs_block_size < MINBSIZE) 470 return EINVAL; 471 if ((fs->mfs_block_size % 512) != 0) 472 return EINVAL; 473 if (SBSIZE > fs->mfs_block_size) 474 return EINVAL; 475 if ((fs->mfs_block_size % INODE_SIZE) != 0) 476 return EINVAL; 477 478 /* For even larger disks, a similar problem occurs with s_firstdatazone. 479 * If the on-disk field contains zero, we assume that the value was too 480 * large to fit, and compute it on the fly. 481 */ 482 if (fs->mfs_firstdatazone_old == 0) { 483 block_t offset; 484 offset = START_BLOCK + fs->mfs_imap_blocks + fs->mfs_zmap_blocks; 485 offset += (fs->mfs_ninodes + fs->mfs_inodes_per_block - 1) / 486 fs->mfs_inodes_per_block; 487 488 fs->mfs_firstdatazone = 489 (offset + (1 << fs->mfs_log_zone_size) - 1) >> 490 fs->mfs_log_zone_size; 491 } else { 492 fs->mfs_firstdatazone = (zone_t) fs->mfs_firstdatazone_old; 493 } 494 495 if (fs->mfs_imap_blocks < 1 || fs->mfs_zmap_blocks < 1 496 || fs->mfs_ninodes < 1 || fs->mfs_zones < 1 497 || fs->mfs_firstdatazone <= 4 498 || fs->mfs_firstdatazone >= fs->mfs_zones 499 || (unsigned) fs->mfs_log_zone_size > 4) 500 return EINVAL; 501 502 /* compute in-memory mfs_sblock values */ 503 fs->mfs_inodes_per_block = fs->mfs_block_size / INODE_SIZE; 504 505 506 { 507 int32_t mult = fs->mfs_block_size >> LOG_MINBSIZE; 508 int ln2 = LOG_MINBSIZE; 509 510 for (; mult != 1; ln2++) 511 mult >>= 1; 512 513 fs->mfs_bshift = ln2; 514 /* XXX assume hw bsize = 512 */ 515 fs->mfs_fsbtodb = ln2 - LOG_MINBSIZE + 1; 516 } 517 518 fs->mfs_qbmask = fs->mfs_block_size - 1; 519 fs->mfs_bmask = ~fs->mfs_qbmask; 520 521 return 0; 522 } 523 524 /* 525 * Open a file. 526 */ 527 __compactcall int 528 minixfs3_open(const char *path, struct open_file *f) 529 { 530 #ifndef LIBSA_FS_SINGLECOMPONENT 531 const char *cp, *ncp; 532 int c; 533 #endif 534 ino32_t inumber; 535 struct file *fp; 536 struct mfs_sblock *fs; 537 int rc; 538 #ifndef LIBSA_NO_FS_SYMLINK 539 ino32_t parent_inumber; 540 int nlinks = 0; 541 char namebuf[MAXPATHLEN+1]; 542 char *buf; 543 #endif 544 545 /* allocate file system specific data structure */ 546 fp = alloc(sizeof(struct file)); 547 memset(fp, 0, sizeof(struct file)); 548 f->f_fsdata = (void *)fp; 549 550 /* allocate space and read super block */ 551 fs = alloc(sizeof(*fs)); 552 memset(fs, 0, sizeof(*fs)); 553 fp->f_fs = fs; 554 twiddle(); 555 556 rc = read_sblock(f, fs); 557 if (rc) 558 goto out; 559 560 /* alloc a block sized buffer used for all fs transfers */ 561 fp->f_buf = alloc(fs->mfs_block_size); 562 563 /* 564 * Calculate indirect block levels. 565 */ 566 { 567 int32_t mult; 568 int ln2; 569 570 /* 571 * We note that the number of indirect blocks is always 572 * a power of 2. This lets us use shifts and masks instead 573 * of divide and remainder and avoinds pulling in the 574 * 64bit division routine into the boot code. 575 */ 576 mult = MFS_NINDIR(fs); 577 #ifdef DEBUG 578 if (!powerof2(mult)) { 579 /* Hummm was't a power of 2 */ 580 rc = EINVAL; 581 goto out; 582 } 583 #endif 584 for (ln2 = 0; mult != 1; ln2++) 585 mult >>= 1; 586 587 fp->f_nishift = ln2; 588 } 589 590 inumber = ROOT_INODE; 591 if ((rc = read_inode(inumber, f)) != 0) 592 goto out; 593 594 #ifndef LIBSA_FS_SINGLECOMPONENT 595 cp = path; 596 while (*cp) { 597 598 /* 599 * Remove extra separators 600 */ 601 while (*cp == '/') 602 cp++; 603 if (*cp == '\0') 604 break; 605 606 /* 607 * Check that current node is a directory. 608 */ 609 if ((fp->f_di.mdi_mode & I_TYPE) != I_DIRECTORY) { 610 rc = ENOTDIR; 611 goto out; 612 } 613 614 /* 615 * Get next component of path name. 616 */ 617 ncp = cp; 618 while ((c = *cp) != '\0' && c != '/') 619 cp++; 620 621 /* 622 * Look up component in current directory. 623 * Save directory inumber in case we find a 624 * symbolic link. 625 */ 626 #ifndef LIBSA_NO_FS_SYMLINK 627 parent_inumber = inumber; 628 #endif 629 rc = search_directory(ncp, cp - ncp, f, &inumber); 630 if (rc) 631 goto out; 632 633 /* 634 * Open next component. 635 */ 636 if ((rc = read_inode(inumber, f)) != 0) 637 goto out; 638 639 #ifndef LIBSA_NO_FS_SYMLINK 640 /* 641 * Check for symbolic link. 642 */ 643 if ((fp->f_di.mdi_mode & I_TYPE) == I_SYMBOLIC_LINK) { 644 int link_len = fp->f_di.mdi_size; 645 int len; 646 size_t buf_size; 647 block_t disk_block; 648 649 len = strlen(cp); 650 651 if (link_len + len > MAXPATHLEN || 652 ++nlinks > MAXSYMLINKS) { 653 rc = ENOENT; 654 goto out; 655 } 656 657 memmove(&namebuf[link_len], cp, len + 1); 658 659 /* 660 * Read file for symbolic link 661 */ 662 buf = fp->f_buf; 663 rc = block_map(f, (block_t)0, &disk_block); 664 if (rc) 665 goto out; 666 667 twiddle(); 668 rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, 669 F_READ, FSBTODB(fs, disk_block), 670 fs->mfs_block_size, buf, &buf_size); 671 if (rc) 672 goto out; 673 674 memcpy(namebuf, buf, link_len); 675 676 /* 677 * If relative pathname, restart at parent directory. 678 * If absolute pathname, restart at root. 679 */ 680 cp = namebuf; 681 if (*cp != '/') 682 inumber = parent_inumber; 683 else 684 inumber = (ino32_t) ROOT_INODE; 685 686 if ((rc = read_inode(inumber, f)) != 0) 687 goto out; 688 } 689 #endif /* !LIBSA_NO_FS_SYMLINK */ 690 } 691 692 /* 693 * Found terminal component. 694 */ 695 rc = 0; 696 697 #else /* !LIBSA_FS_SINGLECOMPONENT */ 698 699 /* look up component in the current (root) directory */ 700 rc = search_directory(path, strlen(path), f, &inumber); 701 if (rc) 702 goto out; 703 704 /* open it */ 705 rc = read_inode(inumber, f); 706 707 #endif /* !LIBSA_FS_SINGLECOMPONENT */ 708 709 fp->f_seekp = 0; /* reset seek pointer */ 710 711 out: 712 if (rc) 713 minixfs3_close(f); 714 715 return rc; 716 } 717 718 __compactcall int 719 minixfs3_close(struct open_file *f) 720 { 721 struct file *fp = (struct file *)f->f_fsdata; 722 723 f->f_fsdata = NULL; 724 if (fp == NULL) 725 return 0; 726 727 if (fp->f_buf) 728 dealloc(fp->f_buf, fp->f_fs->mfs_block_size); 729 dealloc(fp->f_fs, sizeof(*fp->f_fs)); 730 dealloc(fp, sizeof(struct file)); 731 return 0; 732 } 733 734 /* 735 * Copy a portion of a file into kernel memory. 736 * Cross block boundaries when necessary. 737 */ 738 __compactcall int 739 minixfs3_read(struct open_file *f, void *start, size_t size, size_t *resid) 740 { 741 struct file *fp = (struct file *)f->f_fsdata; 742 size_t csize; 743 char *buf; 744 size_t buf_size; 745 int rc = 0; 746 char *addr = start; 747 748 while (size != 0) { 749 if (fp->f_seekp >= (off_t)fp->f_di.mdi_size) 750 break; 751 752 rc = buf_read_file(f, &buf, &buf_size); 753 if (rc) 754 break; 755 756 csize = size; 757 if (csize > buf_size) 758 csize = buf_size; 759 760 memcpy(addr, buf, csize); 761 762 fp->f_seekp += csize; 763 addr += csize; 764 size -= csize; 765 } 766 767 if (resid) 768 *resid = size; 769 return rc; 770 } 771 772 /* 773 * Not implemented. 774 */ 775 #ifndef LIBSA_NO_FS_WRITE 776 __compactcall int 777 minixfs3_write(struct open_file *f, void *start, size_t size, size_t *resid) 778 { 779 780 return EROFS; 781 } 782 #endif /* !LIBSA_NO_FS_WRITE */ 783 784 #ifndef LIBSA_NO_FS_SEEK 785 __compactcall off_t 786 minixfs3_seek(struct open_file *f, off_t offset, int where) 787 { 788 struct file *fp = (struct file *)f->f_fsdata; 789 790 switch (where) { 791 case SEEK_SET: 792 fp->f_seekp = offset; 793 break; 794 case SEEK_CUR: 795 fp->f_seekp += offset; 796 break; 797 case SEEK_END: 798 fp->f_seekp = fp->f_di.mdi_size - offset; 799 break; 800 default: 801 return -1; 802 } 803 return fp->f_seekp; 804 } 805 #endif /* !LIBSA_NO_FS_SEEK */ 806 807 __compactcall int 808 minixfs3_stat(struct open_file *f, struct stat *sb) 809 { 810 struct file *fp = (struct file *)f->f_fsdata; 811 812 /* only important stuff */ 813 memset(sb, 0, sizeof *sb); 814 sb->st_mode = fp->f_di.mdi_mode; 815 sb->st_uid = fp->f_di.mdi_uid; 816 sb->st_gid = fp->f_di.mdi_gid; 817 sb->st_size = fp->f_di.mdi_size; 818 return 0; 819 } 820 821 #if defined(LIBSA_ENABLE_LS_OP) 822 #include "ls.h" 823 __compactcall void 824 minixfs3_ls(struct open_file *f, const char *pattern) 825 { 826 struct file *fp = (struct file *)f->f_fsdata; 827 struct mfs_sblock *fs = fp->f_fs; 828 struct mfs_direct *dp; 829 struct mfs_direct *dbuf; 830 size_t buf_size; 831 lsentry_t *names = 0; 832 833 fp->f_seekp = 0; 834 while (fp->f_seekp < (off_t)fp->f_di.mdi_size) { 835 int rc = buf_read_file(f, &dbuf, &buf_size); 836 if (rc) 837 goto out; 838 839 /* XXX we assume, that buf_read_file reads an fs block and 840 * doesn't truncate buffer. Currently i_size in MFS doesn't 841 * the same as size of allocated blocks, it makes buf_read_file 842 * to truncate buf_size. 843 */ 844 if (buf_size < fs->mfs_block_size) 845 buf_size = fs->mfs_block_size; 846 847 for (dp = dbuf; dp < &dbuf[NR_DIR_ENTRIES(fs)]; dp++) { 848 char *cp; 849 int namlen; 850 851 if (fs2h32(dp->mfsd_ino) == 0) 852 continue; 853 854 /* Compute the length of the name, 855 * We don't use strlen and strcpy, because original MFS 856 * code doesn't. 857 */ 858 cp = memchr(dp->mfsd_name, '\0', sizeof(dp->mfsd_name)); 859 if (cp == NULL) 860 namlen = sizeof(dp->mfsd_name); 861 else 862 namlen = cp - (dp->mfsd_name); 863 864 lsadd(&names, pattern, dp->mfsd_name, namlen, 865 fs2h32(dp->mfsd_ino), "?"); 866 } 867 fp->f_seekp += buf_size; 868 } 869 lsprint(names); 870 out: lsfree(names); 871 } 872 #endif 873 874 /* 875 * byte swap functions for big endian machines 876 * (mfs is always little endian) 877 */ 878 879 /* These functions are only needed if native byte order is not big endian */ 880 #if BYTE_ORDER == BIG_ENDIAN 881 void 882 minixfs3_sb_bswap(struct mfs_sblock *old, struct mfs_sblock *new) 883 { 884 new->mfs_ninodes = bswap32(old->mfs_ninodes); 885 new->mfs_nzones = bswap16(old->mfs_nzones); 886 new->mfs_imap_blocks = bswap16(old->mfs_imap_blocks); 887 new->mfs_zmap_blocks = bswap16(old->mfs_zmap_blocks); 888 new->mfs_firstdatazone_old = bswap16(old->mfs_firstdatazone_old); 889 new->mfs_log_zone_size = bswap16(old->mfs_log_zone_size); 890 new->mfs_max_size = bswap32(old->mfs_max_size); 891 new->mfs_zones = bswap32(old->mfs_zones); 892 new->mfs_magic = bswap16(old->mfs_magic); 893 new->mfs_block_size = bswap16(old->mfs_block_size); 894 new->mfs_disk_version = old->mfs_disk_version; 895 } 896 897 void minixfs3_i_bswap(struct mfs_dinode *old, struct mfs_dinode *new) 898 { 899 int i; 900 901 new->mdi_mode = bswap16(old->mdi_mode); 902 new->mdi_nlinks = bswap16(old->mdi_nlinks); 903 new->mdi_uid = bswap16(old->mdi_uid); 904 new->mdi_gid = bswap16(old->mdi_gid); 905 new->mdi_size = bswap32(old->mdi_size); 906 new->mdi_atime = bswap32(old->mdi_atime); 907 new->mdi_mtime = bswap32(old->mdi_mtime); 908 new->mdi_ctime = bswap32(old->mdi_ctime); 909 910 /* We don't swap here, because indirects must be swapped later 911 * anyway, hence everything is done by block_map(). 912 */ 913 for (i = 0; i < NR_TZONES; i++) 914 new->mdi_zone[i] = old->mdi_zone[i]; 915 } 916 #endif 917