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