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
read_inode(ino32_t inumber,struct open_file * f)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
block_map(struct open_file * f,block_t file_block,block_t * disk_block_p)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
buf_read_file(struct open_file * f,void * v,size_t * size_p)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
search_directory(const char * name,int length,struct open_file * f,ino32_t * inumber_p)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
read_sblock(struct open_file * f,struct mfs_sblock * fs)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
minixfs3_open(const char * path,struct open_file * f)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
minixfs3_close(struct open_file * f)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
minixfs3_read(struct open_file * f,void * start,size_t size,size_t * resid)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
minixfs3_write(struct open_file * f,void * start,size_t size,size_t * resid)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
minixfs3_seek(struct open_file * f,off_t offset,int where)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
minixfs3_stat(struct open_file * f,struct stat * sb)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
minixfs3_ls(struct open_file * f,const char * pattern)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
minixfs3_sb_bswap(struct mfs_sblock * old,struct mfs_sblock * new)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 
minixfs3_i_bswap(struct mfs_dinode * old,struct mfs_dinode * new)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