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