1 /*	$NetBSD: ext2fs.c,v 1.20 2014/03/20 03:13:18 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1997 Manuel Bouyer.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 /*-
28  * Copyright (c) 1993
29  *	The Regents of the University of California.  All rights reserved.
30  *
31  * This code is derived from software contributed to Berkeley by
32  * The Mach Operating System project at Carnegie-Mellon University.
33  *
34  * Redistribution and use in source and binary forms, with or without
35  * modification, are permitted provided that the following conditions
36  * are met:
37  * 1. Redistributions of source code must retain the above copyright
38  *    notice, this list of conditions and the following disclaimer.
39  * 2. Redistributions in binary form must reproduce the above copyright
40  *    notice, this list of conditions and the following disclaimer in the
41  *    documentation and/or other materials provided with the distribution.
42  * 3. Neither the name of the University nor the names of its contributors
43  *    may be used to endorse or promote products derived from this software
44  *    without specific prior written permission.
45  *
46  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56  * SUCH DAMAGE.
57  *
58  *
59  * Copyright (c) 1990, 1991 Carnegie Mellon University
60  * All Rights Reserved.
61  *
62  * Author: David Golub
63  *
64  * Permission to use, copy, modify and distribute this software and its
65  * documentation is hereby granted, provided that both the copyright
66  * notice and this permission notice appear in all copies of the
67  * software, derivative works or modified versions, and any portions
68  * thereof, and that both notices appear in supporting documentation.
69  *
70  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
71  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
72  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
73  *
74  * Carnegie Mellon requests users of this software to return to
75  *
76  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
77  *  School of Computer Science
78  *  Carnegie Mellon University
79  *  Pittsburgh PA 15213-3890
80  *
81  * any improvements or extensions that they make and grant Carnegie the
82  * rights to redistribute these changes.
83  */
84 
85 /*
86  *	Stand-alone file reading package for Ext2 file system.
87  */
88 
89 /* #define EXT2FS_DEBUG */
90 
91 #include <sys/param.h>
92 #include <sys/time.h>
93 #include <ufs/ext2fs/ext2fs_dinode.h>
94 #include <ufs/ext2fs/ext2fs_dir.h>
95 #include <ufs/ext2fs/ext2fs.h>
96 #ifdef _STANDALONE
97 #include <lib/libkern/libkern.h>
98 #else
99 #include <string.h>
100 #endif
101 
102 #include "stand.h"
103 #include "ext2fs.h"
104 
105 #if defined(LIBSA_FS_SINGLECOMPONENT) && !defined(LIBSA_NO_FS_SYMLINK)
106 #define LIBSA_NO_FS_SYMLINK
107 #endif
108 
109 #if defined(LIBSA_NO_TWIDDLE)
110 #define twiddle()
111 #endif
112 
113 #ifndef indp_t
114 #define indp_t		int32_t
115 #endif
116 typedef uint32_t	ino32_t;
117 #ifndef FSBTODB
118 #define FSBTODB(fs, indp) EXT2_FSBTODB(fs, indp)
119 #endif
120 
121 /*
122  * To avoid having a lot of filesystem-block sized buffers lurking (which
123  * could be 32k) we only keep a few entries of the indirect block map.
124  * With 8k blocks, 2^8 blocks is ~500k so we reread the indirect block
125  * ~13 times pulling in a 6M kernel.
126  * The cache size must be smaller than the smallest filesystem block,
127  * so LN2_IND_CACHE_SZ <= 9 (UFS2 and 4k blocks).
128  */
129 #define LN2_IND_CACHE_SZ	6
130 #define IND_CACHE_SZ		(1 << LN2_IND_CACHE_SZ)
131 #define IND_CACHE_MASK		(IND_CACHE_SZ - 1)
132 
133 /*
134  * In-core open file.
135  */
136 struct file {
137 	off_t		f_seekp;	/* seek pointer */
138 	struct m_ext2fs	*f_fs;		/* pointer to super-block */
139 	struct ext2fs_dinode	f_di;		/* copy of on-disk inode */
140 	uint		f_nishift;	/* for blocks in indirect block */
141 	indp_t		f_ind_cache_block;
142 	indp_t		f_ind_cache[IND_CACHE_SZ];
143 
144 	char		*f_buf;		/* buffer for data block */
145 	size_t		f_buf_size;	/* size of data block */
146 	daddr_t		f_buf_blkno;	/* block number of data block */
147 };
148 
149 
150 static int read_inode(ino32_t, struct open_file *);
151 static int block_map(struct open_file *, indp_t, indp_t *);
152 static int buf_read_file(struct open_file *, char **, size_t *);
153 static int search_directory(const char *, int, struct open_file *, ino32_t *);
154 static int read_sblock(struct open_file *, struct m_ext2fs *);
155 static int read_gdblock(struct open_file *, struct m_ext2fs *);
156 #ifdef EXT2FS_DEBUG
157 static void dump_sblock(struct m_ext2fs *);
158 #endif
159 
160 /*
161  * Read a new inode into a file structure.
162  */
163 static int
read_inode(ino32_t inumber,struct open_file * f)164 read_inode(ino32_t inumber, struct open_file *f)
165 {
166 	struct file *fp = (struct file *)f->f_fsdata;
167 	struct m_ext2fs *fs = fp->f_fs;
168 	char *buf;
169 	size_t rsize;
170 	int rc;
171 	daddr_t inode_sector;
172 	struct ext2fs_dinode *dip;
173 
174 	inode_sector = FSBTODB(fs, ino_to_fsba(fs, inumber));
175 
176 	/*
177 	 * Read inode and save it.
178 	 */
179 	buf = fp->f_buf;
180 	twiddle();
181 	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
182 	    inode_sector, fs->e2fs_bsize, buf, &rsize);
183 	if (rc)
184 		return rc;
185 	if (rsize != fs->e2fs_bsize)
186 		return EIO;
187 
188 	dip = (struct ext2fs_dinode *)(buf +
189 	    EXT2_DINODE_SIZE(fs) * ino_to_fsbo(fs, inumber));
190 	e2fs_iload(dip, &fp->f_di);
191 
192 	/*
193 	 * Clear out the old buffers
194 	 */
195 	fp->f_ind_cache_block = ~0;
196 	fp->f_buf_blkno = -1;
197 	return rc;
198 }
199 
200 /*
201  * Given an offset in a file, find the disk block number that
202  * contains that block.
203  */
204 static int
block_map(struct open_file * f,indp_t file_block,indp_t * disk_block_p)205 block_map(struct open_file *f, indp_t file_block, indp_t *disk_block_p)
206 {
207 	struct file *fp = (struct file *)f->f_fsdata;
208 	struct m_ext2fs *fs = fp->f_fs;
209 	uint level;
210 	indp_t ind_cache;
211 	indp_t ind_block_num;
212 	size_t rsize;
213 	int rc;
214 	indp_t *buf = (void *)fp->f_buf;
215 
216 	/*
217 	 * Index structure of an inode:
218 	 *
219 	 * e2di_blocks[0..EXT2FS_NDADDR-1]
220 	 *		hold block numbers for blocks
221 	 *		0..EXT2FS_NDADDR-1
222 	 *
223 	 * e2di_blocks[EXT2FS_NDADDR+0]
224 	 *		block EXT2FS_NDADDR+0 is the single indirect block
225 	 *		holds block numbers for blocks
226 	 *		EXT2FS_NDADDR .. EXT2FS_NDADDR + EXT2_NINDIR(fs)-1
227 	 *
228 	 * e2di_blocks[EXT2FS_NDADDR+1]
229 	 *		block EXT2FS_NDADDR+1 is the double indirect block
230 	 *		holds block numbers for INDEX blocks for blocks
231 	 *		EXT2FS_NDADDR + EXT2_NINDIR(fs) ..
232 	 *		EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2 - 1
233 	 *
234 	 * e2di_blocks[EXT2FS_NDADDR+2]
235 	 *		block EXT2FS_NDADDR+2 is the triple indirect block
236 	 *		holds block numbers for	double-indirect
237 	 *		blocks for blocks
238 	 *		EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2 ..
239 	 *		EXT2FS_NDADDR + EXT2_NINDIR(fs) + EXT2_NINDIR(fs)**2
240 	 *			+ EXT2_NINDIR(fs)**3 - 1
241 	 */
242 
243 	if (file_block < EXT2FS_NDADDR) {
244 		/* Direct block. */
245 		*disk_block_p = fs2h32(fp->f_di.e2di_blocks[file_block]);
246 		return 0;
247 	}
248 
249 	file_block -= EXT2FS_NDADDR;
250 
251 	ind_cache = file_block >> LN2_IND_CACHE_SZ;
252 	if (ind_cache == fp->f_ind_cache_block) {
253 		*disk_block_p =
254 		    fs2h32(fp->f_ind_cache[file_block & IND_CACHE_MASK]);
255 		return 0;
256 	}
257 
258 	for (level = 0;;) {
259 		level += fp->f_nishift;
260 		if (file_block < (indp_t)1 << level)
261 			break;
262 		if (level > EXT2FS_NIADDR * fp->f_nishift)
263 			/* Block number too high */
264 			return EFBIG;
265 		file_block -= (indp_t)1 << level;
266 	}
267 
268 	ind_block_num =
269 	    fs2h32(fp->f_di.e2di_blocks[EXT2FS_NDADDR +
270 	    (level / fp->f_nishift - 1)]);
271 
272 	for (;;) {
273 		level -= fp->f_nishift;
274 		if (ind_block_num == 0) {
275 			*disk_block_p = 0;	/* missing */
276 			return 0;
277 		}
278 
279 		twiddle();
280 		/*
281 		 * If we were feeling brave, we could work out the number
282 		 * of the disk sector and read a single disk sector instead
283 		 * of a filesystem block.
284 		 * However we don't do this very often anyway...
285 		 */
286 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
287 			FSBTODB(fp->f_fs, ind_block_num), fs->e2fs_bsize,
288 			buf, &rsize);
289 		if (rc)
290 			return rc;
291 		if (rsize != fs->e2fs_bsize)
292 			return EIO;
293 		ind_block_num = fs2h32(buf[file_block >> level]);
294 		if (level == 0)
295 			break;
296 		file_block &= (1 << level) - 1;
297 	}
298 
299 	/* Save the part of the block that contains this sector */
300 	memcpy(fp->f_ind_cache, &buf[file_block & ~IND_CACHE_MASK],
301 	    IND_CACHE_SZ * sizeof fp->f_ind_cache[0]);
302 	fp->f_ind_cache_block = ind_cache;
303 
304 	*disk_block_p = ind_block_num;
305 
306 	return 0;
307 }
308 
309 /*
310  * Read a portion of a file into an internal buffer.
311  * Return the location in the buffer and the amount in the buffer.
312  */
313 static int
buf_read_file(struct open_file * f,char ** buf_p,size_t * size_p)314 buf_read_file(struct open_file *f, char **buf_p, size_t *size_p)
315 {
316 	struct file *fp = (struct file *)f->f_fsdata;
317 	struct m_ext2fs *fs = fp->f_fs;
318 	long off;
319 	indp_t file_block;
320 	indp_t disk_block = 0;	/* XXX: gcc */
321 	size_t block_size;
322 	int rc;
323 
324 	off = ext2_blkoff(fs, fp->f_seekp);
325 	file_block = ext2_lblkno(fs, fp->f_seekp);
326 	block_size = fs->e2fs_bsize;	/* no fragment */
327 
328 	if (file_block != fp->f_buf_blkno) {
329 		rc = block_map(f, file_block, &disk_block);
330 		if (rc)
331 			return rc;
332 
333 		if (disk_block == 0) {
334 			memset(fp->f_buf, 0, block_size);
335 			fp->f_buf_size = block_size;
336 		} else {
337 			twiddle();
338 			rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
339 				FSBTODB(fs, disk_block),
340 				block_size, fp->f_buf, &fp->f_buf_size);
341 			if (rc)
342 				return rc;
343 		}
344 
345 		fp->f_buf_blkno = file_block;
346 	}
347 
348 	/*
349 	 * Return address of byte in buffer corresponding to
350 	 * offset, and size of remainder of buffer after that
351 	 * byte.
352 	 */
353 	*buf_p = fp->f_buf + off;
354 	*size_p = block_size - off;
355 
356 	/*
357 	 * But truncate buffer at end of file.
358 	 */
359 	/* XXX should handle LARGEFILE */
360 	if (*size_p > fp->f_di.e2di_size - fp->f_seekp)
361 		*size_p = fp->f_di.e2di_size - fp->f_seekp;
362 
363 	return 0;
364 }
365 
366 /*
367  * Search a directory for a name and return its
368  * inode number.
369  */
370 static int
search_directory(const char * name,int length,struct open_file * f,ino32_t * inumber_p)371 search_directory(const char *name, int length, struct open_file *f,
372 	ino32_t *inumber_p)
373 {
374 	struct file *fp = (struct file *)f->f_fsdata;
375 	struct ext2fs_direct *dp;
376 	struct ext2fs_direct *edp;
377 	char *buf;
378 	size_t buf_size;
379 	int namlen;
380 	int rc;
381 
382 	fp->f_seekp = 0;
383 	/* XXX should handle LARGEFILE */
384 	while (fp->f_seekp < (off_t)fp->f_di.e2di_size) {
385 		rc = buf_read_file(f, &buf, &buf_size);
386 		if (rc)
387 			return rc;
388 
389 		dp = (struct ext2fs_direct *)buf;
390 		edp = (struct ext2fs_direct *)(buf + buf_size);
391 		for (; dp < edp;
392 		    dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) {
393 			if (fs2h16(dp->e2d_reclen) <= 0)
394 				break;
395 			if (fs2h32(dp->e2d_ino) == (ino32_t)0)
396 				continue;
397 			namlen = dp->e2d_namlen;
398 			if (namlen == length &&
399 			    !memcmp(name, dp->e2d_name, length)) {
400 				/* found entry */
401 				*inumber_p = fs2h32(dp->e2d_ino);
402 				return 0;
403 			}
404 		}
405 		fp->f_seekp += buf_size;
406 	}
407 	return ENOENT;
408 }
409 
410 int
read_sblock(struct open_file * f,struct m_ext2fs * fs)411 read_sblock(struct open_file *f, struct m_ext2fs *fs)
412 {
413 	static uint8_t sbbuf[SBSIZE];
414 	struct ext2fs ext2fs;
415 	size_t buf_size;
416 	int rc;
417 
418 	rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
419 	    SBOFF / DEV_BSIZE, SBSIZE, sbbuf, &buf_size);
420 	if (rc)
421 		return rc;
422 
423 	if (buf_size != SBSIZE)
424 		return EIO;
425 
426 	e2fs_sbload((void *)sbbuf, &ext2fs);
427 	if (ext2fs.e2fs_magic != E2FS_MAGIC)
428 		return EINVAL;
429 	if (ext2fs.e2fs_rev > E2FS_REV1 ||
430 	    (ext2fs.e2fs_rev == E2FS_REV1 &&
431 	     (ext2fs.e2fs_first_ino != EXT2_FIRSTINO ||
432 	     (ext2fs.e2fs_inode_size != 128 && ext2fs.e2fs_inode_size != 256) ||
433 	      ext2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP))) {
434 		return ENODEV;
435 	}
436 
437 	e2fs_sbload((void *)sbbuf, &fs->e2fs);
438 	/* compute in-memory m_ext2fs values */
439 	fs->e2fs_ncg =
440 	    howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock,
441 	    fs->e2fs.e2fs_bpg);
442 	/* XXX assume hw bsize = 512 */
443 	fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1;
444 	fs->e2fs_bsize = MINBSIZE << fs->e2fs.e2fs_log_bsize;
445 	fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize;
446 	fs->e2fs_qbmask = fs->e2fs_bsize - 1;
447 	fs->e2fs_bmask = ~fs->e2fs_qbmask;
448 	fs->e2fs_ngdb =
449 	    howmany(fs->e2fs_ncg, fs->e2fs_bsize / sizeof(struct ext2_gd));
450 	fs->e2fs_ipb = fs->e2fs_bsize / ext2fs.e2fs_inode_size;
451 	fs->e2fs_itpg = fs->e2fs.e2fs_ipg / fs->e2fs_ipb;
452 
453 	return 0;
454 }
455 
456 int
read_gdblock(struct open_file * f,struct m_ext2fs * fs)457 read_gdblock(struct open_file *f, struct m_ext2fs *fs)
458 {
459 	struct file *fp = (struct file *)f->f_fsdata;
460 	size_t rsize;
461 	uint gdpb;
462 	int i, rc;
463 
464 	gdpb = fs->e2fs_bsize / sizeof(struct ext2_gd);
465 
466 	for (i = 0; i < fs->e2fs_ngdb; i++) {
467 		rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
468 		    FSBTODB(fs, fs->e2fs.e2fs_first_dblock +
469 		    1 /* superblock */ + i),
470 		    fs->e2fs_bsize, fp->f_buf, &rsize);
471 		if (rc)
472 			return rc;
473 		if (rsize != fs->e2fs_bsize)
474 			return EIO;
475 
476 		e2fs_cgload((struct ext2_gd *)fp->f_buf,
477 		    &fs->e2fs_gd[i * gdpb],
478 		    (i == (fs->e2fs_ngdb - 1)) ?
479 		    (fs->e2fs_ncg - gdpb * i) * sizeof(struct ext2_gd):
480 		    fs->e2fs_bsize);
481 	}
482 
483 	return 0;
484 }
485 
486 
487 /*
488  * Open a file.
489  */
490 __compactcall int
ext2fs_open(const char * path,struct open_file * f)491 ext2fs_open(const char *path, struct open_file *f)
492 {
493 #ifndef LIBSA_FS_SINGLECOMPONENT
494 	const char *cp, *ncp;
495 	int c;
496 #endif
497 	ino32_t inumber;
498 	struct file *fp;
499 	struct m_ext2fs *fs;
500 	int rc;
501 #ifndef LIBSA_NO_FS_SYMLINK
502 	ino32_t parent_inumber;
503 	int nlinks = 0;
504 	char namebuf[MAXPATHLEN+1];
505 	char *buf;
506 #endif
507 
508 	/* allocate file system specific data structure */
509 	fp = alloc(sizeof(struct file));
510 	memset(fp, 0, sizeof(struct file));
511 	f->f_fsdata = (void *)fp;
512 
513 	/* allocate space and read super block */
514 	fs = alloc(sizeof(*fs));
515 	memset(fs, 0, sizeof(*fs));
516 	fp->f_fs = fs;
517 	twiddle();
518 
519 	rc = read_sblock(f, fs);
520 	if (rc)
521 		goto out;
522 
523 #ifdef EXT2FS_DEBUG
524 	dump_sblock(fs);
525 #endif
526 
527 	/* alloc a block sized buffer used for all fs transfers */
528 	fp->f_buf = alloc(fs->e2fs_bsize);
529 
530 	/* read group descriptor blocks */
531 	fs->e2fs_gd = alloc(sizeof(struct ext2_gd) * fs->e2fs_ncg);
532 	rc = read_gdblock(f, fs);
533 	if (rc)
534 		goto out;
535 
536 	/*
537 	 * Calculate indirect block levels.
538 	 */
539 	{
540 		indp_t mult;
541 		int ln2;
542 
543 		/*
544 		 * We note that the number of indirect blocks is always
545 		 * a power of 2.  This lets us use shifts and masks instead
546 		 * of divide and remainder and avoinds pulling in the
547 		 * 64bit division routine into the boot code.
548 		 */
549 		mult = EXT2_NINDIR(fs);
550 #ifdef DEBUG
551 		if (!powerof2(mult)) {
552 			/* Hummm was't a power of 2 */
553 			rc = EINVAL;
554 			goto out;
555 		}
556 #endif
557 		for (ln2 = 0; mult != 1; ln2++)
558 			mult >>= 1;
559 
560 		fp->f_nishift = ln2;
561 	}
562 
563 	inumber = EXT2_ROOTINO;
564 	if ((rc = read_inode(inumber, f)) != 0)
565 		goto out;
566 
567 #ifndef LIBSA_FS_SINGLECOMPONENT
568 	cp = path;
569 	while (*cp) {
570 
571 		/*
572 		 * Remove extra separators
573 		 */
574 		while (*cp == '/')
575 			cp++;
576 		if (*cp == '\0')
577 			break;
578 
579 		/*
580 		 * Check that current node is a directory.
581 		 */
582 		if ((fp->f_di.e2di_mode & EXT2_IFMT) != EXT2_IFDIR) {
583 			rc = ENOTDIR;
584 			goto out;
585 		}
586 
587 		/*
588 		 * Get next component of path name.
589 		 */
590 		ncp = cp;
591 		while ((c = *cp) != '\0' && c != '/')
592 			cp++;
593 
594 		/*
595 		 * Look up component in current directory.
596 		 * Save directory inumber in case we find a
597 		 * symbolic link.
598 		 */
599 #ifndef LIBSA_NO_FS_SYMLINK
600 		parent_inumber = inumber;
601 #endif
602 		rc = search_directory(ncp, cp - ncp, f, &inumber);
603 		if (rc)
604 			goto out;
605 
606 		/*
607 		 * Open next component.
608 		 */
609 		if ((rc = read_inode(inumber, f)) != 0)
610 			goto out;
611 
612 #ifndef LIBSA_NO_FS_SYMLINK
613 		/*
614 		 * Check for symbolic link.
615 		 */
616 		if ((fp->f_di.e2di_mode & EXT2_IFMT) == EXT2_IFLNK) {
617 			/* XXX should handle LARGEFILE */
618 			int link_len = fp->f_di.e2di_size;
619 			int len;
620 
621 			len = strlen(cp);
622 
623 			if (link_len + len > MAXPATHLEN ||
624 			    ++nlinks > MAXSYMLINKS) {
625 				rc = ENOENT;
626 				goto out;
627 			}
628 
629 			memmove(&namebuf[link_len], cp, len + 1);
630 
631 			if (link_len < EXT2_MAXSYMLINKLEN) {
632 				memcpy(namebuf, fp->f_di.e2di_blocks, link_len);
633 			} else {
634 				/*
635 				 * Read file for symbolic link
636 				 */
637 				size_t buf_size;
638 				indp_t	disk_block;
639 
640 				buf = fp->f_buf;
641 				rc = block_map(f, (indp_t)0, &disk_block);
642 				if (rc)
643 					goto out;
644 
645 				twiddle();
646 				rc = DEV_STRATEGY(f->f_dev)(f->f_devdata,
647 					F_READ, FSBTODB(fs, disk_block),
648 					fs->e2fs_bsize, buf, &buf_size);
649 				if (rc)
650 					goto out;
651 
652 				memcpy(namebuf, buf, link_len);
653 			}
654 
655 			/*
656 			 * If relative pathname, restart at parent directory.
657 			 * If absolute pathname, restart at root.
658 			 */
659 			cp = namebuf;
660 			if (*cp != '/')
661 				inumber = parent_inumber;
662 			else
663 				inumber = (ino32_t)EXT2_ROOTINO;
664 
665 			if ((rc = read_inode(inumber, f)) != 0)
666 				goto out;
667 		}
668 #endif	/* !LIBSA_NO_FS_SYMLINK */
669 	}
670 
671 	/*
672 	 * Found terminal component.
673 	 */
674 	rc = 0;
675 
676 #else /* !LIBSA_FS_SINGLECOMPONENT */
677 
678 	/* look up component in the current (root) directory */
679 	rc = search_directory(path, strlen(path), f, &inumber);
680 	if (rc)
681 		goto out;
682 
683 	/* open it */
684 	rc = read_inode(inumber, f);
685 
686 #endif /* !LIBSA_FS_SINGLECOMPONENT */
687 
688 	fp->f_seekp = 0;		/* reset seek pointer */
689 
690 out:
691 	if (rc)
692 		ext2fs_close(f);
693 	else
694 		fsmod = "ext2fs";
695 	return rc;
696 }
697 
698 __compactcall int
ext2fs_close(struct open_file * f)699 ext2fs_close(struct open_file *f)
700 {
701 	struct file *fp = (struct file *)f->f_fsdata;
702 
703 	f->f_fsdata = NULL;
704 	if (fp == NULL)
705 		return 0;
706 
707 	if (fp->f_fs->e2fs_gd)
708 		dealloc(fp->f_fs->e2fs_gd,
709 		    sizeof(struct ext2_gd) * fp->f_fs->e2fs_ncg);
710 	if (fp->f_buf)
711 		dealloc(fp->f_buf, fp->f_fs->e2fs_bsize);
712 	dealloc(fp->f_fs, sizeof(*fp->f_fs));
713 	dealloc(fp, sizeof(struct file));
714 	return 0;
715 }
716 
717 /*
718  * Copy a portion of a file into kernel memory.
719  * Cross block boundaries when necessary.
720  */
721 __compactcall int
ext2fs_read(struct open_file * f,void * start,size_t size,size_t * resid)722 ext2fs_read(struct open_file *f, void *start, size_t size, size_t *resid)
723 {
724 	struct file *fp = (struct file *)f->f_fsdata;
725 	size_t csize;
726 	char *buf;
727 	size_t buf_size;
728 	int rc = 0;
729 	char *addr = start;
730 
731 	while (size != 0) {
732 		/* XXX should handle LARGEFILE */
733 		if (fp->f_seekp >= (off_t)fp->f_di.e2di_size)
734 			break;
735 
736 		rc = buf_read_file(f, &buf, &buf_size);
737 		if (rc)
738 			break;
739 
740 		csize = size;
741 		if (csize > buf_size)
742 			csize = buf_size;
743 
744 		memcpy(addr, buf, csize);
745 
746 		fp->f_seekp += csize;
747 		addr += csize;
748 		size -= csize;
749 	}
750 	if (resid)
751 		*resid = size;
752 	return rc;
753 }
754 
755 /*
756  * Not implemented.
757  */
758 #ifndef LIBSA_NO_FS_WRITE
759 __compactcall int
ext2fs_write(struct open_file * f,void * start,size_t size,size_t * resid)760 ext2fs_write(struct open_file *f, void *start, size_t size, size_t *resid)
761 {
762 
763 	return EROFS;
764 }
765 #endif /* !LIBSA_NO_FS_WRITE */
766 
767 #ifndef LIBSA_NO_FS_SEEK
768 __compactcall off_t
ext2fs_seek(struct open_file * f,off_t offset,int where)769 ext2fs_seek(struct open_file *f, off_t offset, int where)
770 {
771 	struct file *fp = (struct file *)f->f_fsdata;
772 
773 	switch (where) {
774 	case SEEK_SET:
775 		fp->f_seekp = offset;
776 		break;
777 	case SEEK_CUR:
778 		fp->f_seekp += offset;
779 		break;
780 	case SEEK_END:
781 		/* XXX should handle LARGEFILE */
782 		fp->f_seekp = fp->f_di.e2di_size - offset;
783 		break;
784 	default:
785 		return -1;
786 	}
787 	return fp->f_seekp;
788 }
789 #endif /* !LIBSA_NO_FS_SEEK */
790 
791 __compactcall int
ext2fs_stat(struct open_file * f,struct stat * sb)792 ext2fs_stat(struct open_file *f, struct stat *sb)
793 {
794 	struct file *fp = (struct file *)f->f_fsdata;
795 
796 	/* only important stuff */
797 	memset(sb, 0, sizeof *sb);
798 	sb->st_mode = fp->f_di.e2di_mode;
799 	sb->st_uid = fp->f_di.e2di_uid;
800 	sb->st_gid = fp->f_di.e2di_gid;
801 	/* XXX should handle LARGEFILE */
802 	sb->st_size = fp->f_di.e2di_size;
803 	return 0;
804 }
805 
806 #if defined(LIBSA_ENABLE_LS_OP)
807 
808 #include "ls.h"
809 
810 static const char    *const typestr[] = {
811 	"unknown",
812 	"REG",
813 	"DIR",
814 	"CHR",
815 	"BLK",
816 	"FIFO",
817 	"SOCK",
818 	"LNK"
819 };
820 
821 __compactcall void
ext2fs_ls(struct open_file * f,const char * pattern)822 ext2fs_ls(struct open_file *f, const char *pattern)
823 {
824 	struct file *fp = (struct file *)f->f_fsdata;
825 	size_t block_size = fp->f_fs->e2fs_bsize;
826 	char *buf;
827 	size_t buf_size;
828 	lsentry_t *names = NULL;
829 
830 	fp->f_seekp = 0;
831 	while (fp->f_seekp < (off_t)fp->f_di.e2di_size) {
832 		struct ext2fs_direct  *dp, *edp;
833 		int rc = buf_read_file(f, &buf, &buf_size);
834 		if (rc)
835 			goto out;
836 		if (buf_size != block_size || buf_size == 0)
837 			goto out;
838 
839 		dp = (struct ext2fs_direct *)buf;
840 		edp = (struct ext2fs_direct *)(buf + buf_size);
841 
842 		for (; dp < edp;
843 		     dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) {
844 			const char *t;
845 
846 			if (fs2h16(dp->e2d_reclen) <= 0)
847 				goto out;
848 
849 			if (fs2h32(dp->e2d_ino) == 0)
850 				continue;
851 
852 			if (dp->e2d_type >= NELEM(typestr) ||
853 			    !(t = typestr[dp->e2d_type])) {
854 				/*
855 				 * This does not handle "old"
856 				 * filesystems properly. On little
857 				 * endian machines, we get a bogus
858 				 * type name if the namlen matches a
859 				 * valid type identifier. We could
860 				 * check if we read namlen "0" and
861 				 * handle this case specially, if
862 				 * there were a pressing need...
863 				 */
864 				printf("bad dir entry\n");
865 				goto out;
866 			}
867 			lsadd(&names, pattern, dp->e2d_name,
868 			    strlen(dp->e2d_name), fs2h32(dp->e2d_ino), t);
869 		}
870 		fp->f_seekp += buf_size;
871 	}
872 
873 	lsprint(names);
874 out:	lsfree(names);
875 }
876 #endif
877 
878 /*
879  * byte swap functions for big endian machines
880  * (ext2fs is always little endian)
881  *
882  * XXX: We should use src/sys/ufs/ext2fs/ext2fs_bswap.c
883  */
884 
885 /* These functions are only needed if native byte order is not big endian */
886 #if BYTE_ORDER == BIG_ENDIAN
887 void
e2fs_sb_bswap(struct ext2fs * old,struct ext2fs * new)888 e2fs_sb_bswap(struct ext2fs *old, struct ext2fs *new)
889 {
890 
891 	/* preserve unused fields */
892 	memcpy(new, old, sizeof(struct ext2fs));
893 	new->e2fs_icount	=	bswap32(old->e2fs_icount);
894 	new->e2fs_bcount	=	bswap32(old->e2fs_bcount);
895 	new->e2fs_rbcount	=	bswap32(old->e2fs_rbcount);
896 	new->e2fs_fbcount	=	bswap32(old->e2fs_fbcount);
897 	new->e2fs_ficount	=	bswap32(old->e2fs_ficount);
898 	new->e2fs_first_dblock	=	bswap32(old->e2fs_first_dblock);
899 	new->e2fs_log_bsize	=	bswap32(old->e2fs_log_bsize);
900 	new->e2fs_fsize		=	bswap32(old->e2fs_fsize);
901 	new->e2fs_bpg		=	bswap32(old->e2fs_bpg);
902 	new->e2fs_fpg		=	bswap32(old->e2fs_fpg);
903 	new->e2fs_ipg		=	bswap32(old->e2fs_ipg);
904 	new->e2fs_mtime		=	bswap32(old->e2fs_mtime);
905 	new->e2fs_wtime		=	bswap32(old->e2fs_wtime);
906 	new->e2fs_mnt_count	=	bswap16(old->e2fs_mnt_count);
907 	new->e2fs_max_mnt_count	=	bswap16(old->e2fs_max_mnt_count);
908 	new->e2fs_magic		=	bswap16(old->e2fs_magic);
909 	new->e2fs_state		=	bswap16(old->e2fs_state);
910 	new->e2fs_beh		=	bswap16(old->e2fs_beh);
911 	new->e2fs_minrev	=	bswap16(old->e2fs_minrev);
912 	new->e2fs_lastfsck	=	bswap32(old->e2fs_lastfsck);
913 	new->e2fs_fsckintv	=	bswap32(old->e2fs_fsckintv);
914 	new->e2fs_creator	=	bswap32(old->e2fs_creator);
915 	new->e2fs_rev		=	bswap32(old->e2fs_rev);
916 	new->e2fs_ruid		=	bswap16(old->e2fs_ruid);
917 	new->e2fs_rgid		=	bswap16(old->e2fs_rgid);
918 	new->e2fs_first_ino	=	bswap32(old->e2fs_first_ino);
919 	new->e2fs_inode_size	=	bswap16(old->e2fs_inode_size);
920 	new->e2fs_block_group_nr =	bswap16(old->e2fs_block_group_nr);
921 	new->e2fs_features_compat =	bswap32(old->e2fs_features_compat);
922 	new->e2fs_features_incompat =	bswap32(old->e2fs_features_incompat);
923 	new->e2fs_features_rocompat =	bswap32(old->e2fs_features_rocompat);
924 	new->e2fs_algo		=	bswap32(old->e2fs_algo);
925 	new->e2fs_reserved_ngdb	=	bswap16(old->e2fs_reserved_ngdb);
926 }
927 
e2fs_cg_bswap(struct ext2_gd * old,struct ext2_gd * new,int size)928 void e2fs_cg_bswap(struct ext2_gd *old, struct ext2_gd *new, int size)
929 {
930 	int i;
931 
932 	for (i = 0; i < (size / sizeof(struct ext2_gd)); i++) {
933 		new[i].ext2bgd_b_bitmap	= bswap32(old[i].ext2bgd_b_bitmap);
934 		new[i].ext2bgd_i_bitmap	= bswap32(old[i].ext2bgd_i_bitmap);
935 		new[i].ext2bgd_i_tables	= bswap32(old[i].ext2bgd_i_tables);
936 		new[i].ext2bgd_nbfree	= bswap16(old[i].ext2bgd_nbfree);
937 		new[i].ext2bgd_nifree	= bswap16(old[i].ext2bgd_nifree);
938 		new[i].ext2bgd_ndirs	= bswap16(old[i].ext2bgd_ndirs);
939 	}
940 }
941 
e2fs_i_bswap(struct ext2fs_dinode * old,struct ext2fs_dinode * new)942 void e2fs_i_bswap(struct ext2fs_dinode *old, struct ext2fs_dinode *new)
943 {
944 
945 	new->e2di_mode		=	bswap16(old->e2di_mode);
946 	new->e2di_uid		=	bswap16(old->e2di_uid);
947 	new->e2di_gid		=	bswap16(old->e2di_gid);
948 	new->e2di_nlink		=	bswap16(old->e2di_nlink);
949 	new->e2di_size		=	bswap32(old->e2di_size);
950 	new->e2di_atime		=	bswap32(old->e2di_atime);
951 	new->e2di_ctime		=	bswap32(old->e2di_ctime);
952 	new->e2di_mtime		=	bswap32(old->e2di_mtime);
953 	new->e2di_dtime		=	bswap32(old->e2di_dtime);
954 	new->e2di_nblock	=	bswap32(old->e2di_nblock);
955 	new->e2di_flags		=	bswap32(old->e2di_flags);
956 	new->e2di_gen		=	bswap32(old->e2di_gen);
957 	new->e2di_facl		=	bswap32(old->e2di_facl);
958 	new->e2di_dacl		=	bswap32(old->e2di_dacl);
959 	new->e2di_faddr		=	bswap32(old->e2di_faddr);
960 	memcpy(&new->e2di_blocks[0], &old->e2di_blocks[0],
961 	    (EXT2FS_NDADDR + EXT2FS_NIADDR) * sizeof(uint32_t));
962 }
963 #endif
964 
965 #ifdef EXT2FS_DEBUG
966 void
dump_sblock(struct m_ext2fs * fs)967 dump_sblock(struct m_ext2fs *fs)
968 {
969 
970 	printf("fs->e2fs.e2fs_bcount = %u\n", fs->e2fs.e2fs_bcount);
971 	printf("fs->e2fs.e2fs_first_dblock = %u\n", fs->e2fs.e2fs_first_dblock);
972 	printf("fs->e2fs.e2fs_log_bsize = %u\n", fs->e2fs.e2fs_log_bsize);
973 	printf("fs->e2fs.e2fs_bpg = %u\n", fs->e2fs.e2fs_bpg);
974 	printf("fs->e2fs.e2fs_ipg = %u\n", fs->e2fs.e2fs_ipg);
975 	printf("fs->e2fs.e2fs_magic = 0x%x\n", fs->e2fs.e2fs_magic);
976 	printf("fs->e2fs.e2fs_rev = %u\n", fs->e2fs.e2fs_rev);
977 
978 	if (fs->e2fs.e2fs_rev == E2FS_REV1) {
979 		printf("fs->e2fs.e2fs_first_ino = %u\n",
980 		    fs->e2fs.e2fs_first_ino);
981 		printf("fs->e2fs.e2fs_inode_size = %u\n",
982 		    fs->e2fs.e2fs_inode_size);
983 		printf("fs->e2fs.e2fs_features_compat = %u\n",
984 		    fs->e2fs.e2fs_features_compat);
985 		printf("fs->e2fs.e2fs_features_incompat = %u\n",
986 		    fs->e2fs.e2fs_features_incompat);
987 		printf("fs->e2fs.e2fs_features_rocompat = %u\n",
988 		    fs->e2fs.e2fs_features_rocompat);
989 		printf("fs->e2fs.e2fs_reserved_ngdb = %u\n",
990 		    fs->e2fs.e2fs_reserved_ngdb);
991 	}
992 
993 	printf("fs->e2fs_bsize = %u\n", fs->e2fs_bsize);
994 	printf("fs->e2fs_fsbtodb = %u\n", fs->e2fs_fsbtodb);
995 	printf("fs->e2fs_ncg = %u\n", fs->e2fs_ncg);
996 	printf("fs->e2fs_ngdb = %u\n", fs->e2fs_ngdb);
997 	printf("fs->e2fs_ipb = %u\n", fs->e2fs_ipb);
998 	printf("fs->e2fs_itpg = %u\n", fs->e2fs_itpg);
999 }
1000 #endif
1001