ufs.c revision 84221
1/*	$NetBSD: ufs.c,v 1.20 1998/03/01 07:15:39 ross Exp $	*/
2
3/*-
4 * Copyright (c) 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * The Mach Operating System project at Carnegie-Mellon University.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *	This product includes software developed by the University of
21 *	California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 *
39 * Copyright (c) 1990, 1991 Carnegie Mellon University
40 * All Rights Reserved.
41 *
42 * Author: David Golub
43 *
44 * Permission to use, copy, modify and distribute this software and its
45 * documentation is hereby granted, provided that both the copyright
46 * notice and this permission notice appear in all copies of the
47 * software, derivative works or modified versions, and any portions
48 * thereof, and that both notices appear in supporting documentation.
49 *
50 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
51 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
52 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
53 *
54 * Carnegie Mellon requests users of this software to return to
55 *
56 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
57 *  School of Computer Science
58 *  Carnegie Mellon University
59 *  Pittsburgh PA 15213-3890
60 *
61 * any improvements or extensions that they make and grant Carnegie the
62 * rights to redistribute these changes.
63 */
64
65#include <sys/cdefs.h>
66__FBSDID("$FreeBSD: head/lib/libstand/ufs.c 84221 2001-09-30 22:28:01Z dillon $");
67
68/*
69 *	Stand-alone file reading package.
70 */
71
72#include <sys/param.h>
73#include <sys/time.h>
74#include <ufs/ufs/dinode.h>
75#include <ufs/ufs/dir.h>
76#include <ufs/ffs/fs.h>
77#include "stand.h"
78#include "string.h"
79
80#ifdef __alpha__
81#define COMPAT_UFS		/* DUX has old format file systems */
82#endif
83
84static int	ufs_open(const char *path, struct open_file *f);
85static int	ufs_close(struct open_file *f);
86static int	ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
87static off_t	ufs_seek(struct open_file *f, off_t offset, int where);
88static int	ufs_stat(struct open_file *f, struct stat *sb);
89static int	ufs_readdir(struct open_file *f, struct dirent *d);
90
91struct fs_ops ufs_fsops = {
92	"ufs",
93	ufs_open,
94	ufs_close,
95	ufs_read,
96	null_write,
97	ufs_seek,
98	ufs_stat,
99	ufs_readdir
100};
101
102/*
103 * In-core open file.
104 */
105struct file {
106	off_t		f_seekp;	/* seek pointer */
107	struct fs	*f_fs;		/* pointer to super-block */
108	struct dinode	f_di;		/* copy of on-disk inode */
109	int		f_nindir[NIADDR];
110					/* number of blocks mapped by
111					   indirect block at level i */
112	char		*f_blk[NIADDR];	/* buffer for indirect block at
113					   level i */
114	size_t		f_blksize[NIADDR];
115					/* size of buffer */
116	daddr_t		f_blkno[NIADDR];/* disk address of block in buffer */
117	char		*f_buf;		/* buffer for data block */
118	size_t		f_buf_size;	/* size of data block */
119	daddr_t		f_buf_blkno;	/* block number of data block */
120};
121
122static int	read_inode(ino_t, struct open_file *);
123static int	block_map(struct open_file *, daddr_t, daddr_t *);
124static int	buf_read_file(struct open_file *, char **, size_t *);
125static int	search_directory(char *, struct open_file *, ino_t *);
126#ifdef COMPAT_UFS
127static void	ffs_oldfscompat(struct fs *);
128#endif
129
130/*
131 * Read a new inode into a file structure.
132 */
133static int
134read_inode(inumber, f)
135	ino_t inumber;
136	struct open_file *f;
137{
138	register struct file *fp = (struct file *)f->f_fsdata;
139	register struct fs *fs = fp->f_fs;
140	char *buf;
141	size_t rsize;
142	int rc;
143
144	if (fs == NULL)
145	    panic("fs == NULL");
146
147	/*
148	 * Read inode and save it.
149	 */
150	buf = malloc(fs->fs_bsize);
151	twiddle();
152	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
153		fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
154		buf, &rsize);
155	if (rc)
156		goto out;
157	if (rsize != fs->fs_bsize) {
158		rc = EIO;
159		goto out;
160	}
161
162	{
163		register struct dinode *dp;
164
165		dp = (struct dinode *)buf;
166		fp->f_di = dp[ino_to_fsbo(fs, inumber)];
167	}
168
169	/*
170	 * Clear out the old buffers
171	 */
172	{
173		register int level;
174
175		for (level = 0; level < NIADDR; level++)
176			fp->f_blkno[level] = -1;
177		fp->f_buf_blkno = -1;
178	}
179out:
180	free(buf);
181	return (rc);
182}
183
184/*
185 * Given an offset in a file, find the disk block number that
186 * contains that block.
187 */
188static int
189block_map(f, file_block, disk_block_p)
190	struct open_file *f;
191	daddr_t file_block;
192	daddr_t *disk_block_p;	/* out */
193{
194	register struct file *fp = (struct file *)f->f_fsdata;
195	register struct fs *fs = fp->f_fs;
196	int level;
197	int idx;
198	daddr_t ind_block_num;
199	daddr_t *ind_p;
200	int rc;
201
202	/*
203	 * Index structure of an inode:
204	 *
205	 * di_db[0..NDADDR-1]	hold block numbers for blocks
206	 *			0..NDADDR-1
207	 *
208	 * di_ib[0]		index block 0 is the single indirect block
209	 *			holds block numbers for blocks
210	 *			NDADDR .. NDADDR + NINDIR(fs)-1
211	 *
212	 * di_ib[1]		index block 1 is the double indirect block
213	 *			holds block numbers for INDEX blocks for blocks
214	 *			NDADDR + NINDIR(fs) ..
215	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
216	 *
217	 * di_ib[2]		index block 2 is the triple indirect block
218	 *			holds block numbers for double-indirect
219	 *			blocks for blocks
220	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
221	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2
222	 *				+ NINDIR(fs)**3 - 1
223	 */
224
225	if (file_block < NDADDR) {
226		/* Direct block. */
227		*disk_block_p = fp->f_di.di_db[file_block];
228		return (0);
229	}
230
231	file_block -= NDADDR;
232
233	/*
234	 * nindir[0] = NINDIR
235	 * nindir[1] = NINDIR**2
236	 * nindir[2] = NINDIR**3
237	 *	etc
238	 */
239	for (level = 0; level < NIADDR; level++) {
240		if (file_block < fp->f_nindir[level])
241			break;
242		file_block -= fp->f_nindir[level];
243	}
244	if (level == NIADDR) {
245		/* Block number too high */
246		return (EFBIG);
247	}
248
249	ind_block_num = fp->f_di.di_ib[level];
250
251	for (; level >= 0; level--) {
252		if (ind_block_num == 0) {
253			*disk_block_p = 0;	/* missing */
254			return (0);
255		}
256
257		if (fp->f_blkno[level] != ind_block_num) {
258			if (fp->f_blk[level] == (char *)0)
259				fp->f_blk[level] =
260					malloc(fs->fs_bsize);
261			twiddle();
262			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
263				fsbtodb(fp->f_fs, ind_block_num),
264				fs->fs_bsize,
265				fp->f_blk[level],
266				&fp->f_blksize[level]);
267			if (rc)
268				return (rc);
269			if (fp->f_blksize[level] != fs->fs_bsize)
270				return (EIO);
271			fp->f_blkno[level] = ind_block_num;
272		}
273
274		ind_p = (daddr_t *)fp->f_blk[level];
275
276		if (level > 0) {
277			idx = file_block / fp->f_nindir[level - 1];
278			file_block %= fp->f_nindir[level - 1];
279		} else
280			idx = file_block;
281
282		ind_block_num = ind_p[idx];
283	}
284
285	*disk_block_p = ind_block_num;
286
287	return (0);
288}
289
290/*
291 * Read a portion of a file into an internal buffer.  Return
292 * the location in the buffer and the amount in the buffer.
293 */
294static int
295buf_read_file(f, buf_p, size_p)
296	struct open_file *f;
297	char **buf_p;		/* out */
298	size_t *size_p;		/* out */
299{
300	register struct file *fp = (struct file *)f->f_fsdata;
301	register struct fs *fs = fp->f_fs;
302	long off;
303	register daddr_t file_block;
304	daddr_t	disk_block;
305	size_t block_size;
306	int rc;
307
308	off = blkoff(fs, fp->f_seekp);
309	file_block = lblkno(fs, fp->f_seekp);
310	block_size = dblksize(fs, &fp->f_di, file_block);
311
312	if (file_block != fp->f_buf_blkno) {
313		rc = block_map(f, file_block, &disk_block);
314		if (rc)
315			return (rc);
316
317		if (fp->f_buf == (char *)0)
318			fp->f_buf = malloc(fs->fs_bsize);
319
320		if (disk_block == 0) {
321			bzero(fp->f_buf, block_size);
322			fp->f_buf_size = block_size;
323		} else {
324			twiddle();
325			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
326				fsbtodb(fs, disk_block),
327				block_size, fp->f_buf, &fp->f_buf_size);
328			if (rc)
329				return (rc);
330		}
331
332		fp->f_buf_blkno = file_block;
333	}
334
335	/*
336	 * Return address of byte in buffer corresponding to
337	 * offset, and size of remainder of buffer after that
338	 * byte.
339	 */
340	*buf_p = fp->f_buf + off;
341	*size_p = block_size - off;
342
343	/*
344	 * But truncate buffer at end of file.
345	 */
346	if (*size_p > fp->f_di.di_size - fp->f_seekp)
347		*size_p = fp->f_di.di_size - fp->f_seekp;
348
349	return (0);
350}
351
352/*
353 * Search a directory for a name and return its
354 * i_number.
355 */
356static int
357search_directory(name, f, inumber_p)
358	char *name;
359	struct open_file *f;
360	ino_t *inumber_p;		/* out */
361{
362	register struct file *fp = (struct file *)f->f_fsdata;
363	register struct direct *dp;
364	struct direct *edp;
365	char *buf;
366	size_t buf_size;
367	int namlen, length;
368	int rc;
369
370	length = strlen(name);
371
372	fp->f_seekp = 0;
373	while (fp->f_seekp < fp->f_di.di_size) {
374		rc = buf_read_file(f, &buf, &buf_size);
375		if (rc)
376			return (rc);
377
378		dp = (struct direct *)buf;
379		edp = (struct direct *)(buf + buf_size);
380		while (dp < edp) {
381			if (dp->d_ino == (ino_t)0)
382				goto next;
383#if BYTE_ORDER == LITTLE_ENDIAN
384			if (fp->f_fs->fs_maxsymlinklen <= 0)
385				namlen = dp->d_type;
386			else
387#endif
388				namlen = dp->d_namlen;
389			if (namlen == length &&
390			    !strcmp(name, dp->d_name)) {
391				/* found entry */
392				*inumber_p = dp->d_ino;
393				return (0);
394			}
395		next:
396			dp = (struct direct *)((char *)dp + dp->d_reclen);
397		}
398		fp->f_seekp += buf_size;
399	}
400	return (ENOENT);
401}
402
403/*
404 * Open a file.
405 */
406static int
407ufs_open(upath, f)
408	const char *upath;
409	struct open_file *f;
410{
411	register char *cp, *ncp;
412	register int c;
413	ino_t inumber, parent_inumber;
414	struct file *fp;
415	struct fs *fs;
416	int rc;
417	size_t buf_size;
418	int nlinks = 0;
419	char namebuf[MAXPATHLEN+1];
420	char *buf = NULL;
421	char *path = NULL;
422
423	/* allocate file system specific data structure */
424	fp = malloc(sizeof(struct file));
425	bzero(fp, sizeof(struct file));
426	f->f_fsdata = (void *)fp;
427
428	/* allocate space and read super block */
429	fs = malloc(SBSIZE);
430	fp->f_fs = fs;
431	twiddle();
432	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
433		SBLOCK, SBSIZE, (char *)fs, &buf_size);
434	if (rc)
435		goto out;
436
437	if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
438	    fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
439		rc = EINVAL;
440		goto out;
441	}
442#ifdef COMPAT_UFS
443	ffs_oldfscompat(fs);
444#endif
445
446	/*
447	 * Calculate indirect block levels.
448	 */
449	{
450		register int mult;
451		register int level;
452
453		mult = 1;
454		for (level = 0; level < NIADDR; level++) {
455			mult *= NINDIR(fs);
456			fp->f_nindir[level] = mult;
457		}
458	}
459
460	inumber = ROOTINO;
461	if ((rc = read_inode(inumber, f)) != 0)
462		goto out;
463
464	cp = path = strdup(upath);
465	if (path == NULL) {
466	    rc = ENOMEM;
467	    goto out;
468	}
469	while (*cp) {
470
471		/*
472		 * Remove extra separators
473		 */
474		while (*cp == '/')
475			cp++;
476		if (*cp == '\0')
477			break;
478
479		/*
480		 * Check that current node is a directory.
481		 */
482		if ((fp->f_di.di_mode & IFMT) != IFDIR) {
483			rc = ENOTDIR;
484			goto out;
485		}
486
487		/*
488		 * Get next component of path name.
489		 */
490		{
491			register int len = 0;
492
493			ncp = cp;
494			while ((c = *cp) != '\0' && c != '/') {
495				if (++len > MAXNAMLEN) {
496					rc = ENOENT;
497					goto out;
498				}
499				cp++;
500			}
501			*cp = '\0';
502		}
503
504		/*
505		 * Look up component in current directory.
506		 * Save directory inumber in case we find a
507		 * symbolic link.
508		 */
509		parent_inumber = inumber;
510		rc = search_directory(ncp, f, &inumber);
511		*cp = c;
512		if (rc)
513			goto out;
514
515		/*
516		 * Open next component.
517		 */
518		if ((rc = read_inode(inumber, f)) != 0)
519			goto out;
520
521		/*
522		 * Check for symbolic link.
523		 */
524		if ((fp->f_di.di_mode & IFMT) == IFLNK) {
525			int link_len = fp->f_di.di_size;
526			int len;
527
528			len = strlen(cp);
529
530			if (link_len + len > MAXPATHLEN ||
531			    ++nlinks > MAXSYMLINKS) {
532				rc = ENOENT;
533				goto out;
534			}
535
536			bcopy(cp, &namebuf[link_len], len + 1);
537
538			if (link_len < fs->fs_maxsymlinklen) {
539				bcopy(fp->f_di.di_shortlink, namebuf,
540				      (unsigned) link_len);
541			} else {
542				/*
543				 * Read file for symbolic link
544				 */
545				size_t buf_size;
546				daddr_t	disk_block;
547				register struct fs *fs = fp->f_fs;
548
549				if (!buf)
550					buf = malloc(fs->fs_bsize);
551				rc = block_map(f, (daddr_t)0, &disk_block);
552				if (rc)
553					goto out;
554
555				twiddle();
556				rc = (f->f_dev->dv_strategy)(f->f_devdata,
557					F_READ, fsbtodb(fs, disk_block),
558					fs->fs_bsize, buf, &buf_size);
559				if (rc)
560					goto out;
561
562				bcopy((char *)buf, namebuf, (unsigned)link_len);
563			}
564
565			/*
566			 * If relative pathname, restart at parent directory.
567			 * If absolute pathname, restart at root.
568			 */
569			cp = namebuf;
570			if (*cp != '/')
571				inumber = parent_inumber;
572			else
573				inumber = (ino_t)ROOTINO;
574
575			if ((rc = read_inode(inumber, f)) != 0)
576				goto out;
577		}
578	}
579
580	/*
581	 * Found terminal component.
582	 */
583	rc = 0;
584out:
585	if (buf)
586		free(buf);
587	if (path)
588		free(path);
589	if (rc) {
590		if (fp->f_buf)
591			free(fp->f_buf);
592		free(fp->f_fs);
593		free(fp);
594	}
595	return (rc);
596}
597
598static int
599ufs_close(f)
600	struct open_file *f;
601{
602	register struct file *fp = (struct file *)f->f_fsdata;
603	int level;
604
605	f->f_fsdata = (void *)0;
606	if (fp == (struct file *)0)
607		return (0);
608
609	for (level = 0; level < NIADDR; level++) {
610		if (fp->f_blk[level])
611			free(fp->f_blk[level]);
612	}
613	if (fp->f_buf)
614		free(fp->f_buf);
615	free(fp->f_fs);
616	free(fp);
617	return (0);
618}
619
620/*
621 * Copy a portion of a file into kernel memory.
622 * Cross block boundaries when necessary.
623 */
624static int
625ufs_read(f, start, size, resid)
626	struct open_file *f;
627	void *start;
628	size_t size;
629	size_t *resid;	/* out */
630{
631	register struct file *fp = (struct file *)f->f_fsdata;
632	register size_t csize;
633	char *buf;
634	size_t buf_size;
635	int rc = 0;
636	register char *addr = start;
637
638	while (size != 0) {
639		if (fp->f_seekp >= fp->f_di.di_size)
640			break;
641
642		rc = buf_read_file(f, &buf, &buf_size);
643		if (rc)
644			break;
645
646		csize = size;
647		if (csize > buf_size)
648			csize = buf_size;
649
650		bcopy(buf, addr, csize);
651
652		fp->f_seekp += csize;
653		addr += csize;
654		size -= csize;
655	}
656	if (resid)
657		*resid = size;
658	return (rc);
659}
660
661static off_t
662ufs_seek(f, offset, where)
663	struct open_file *f;
664	off_t offset;
665	int where;
666{
667	register struct file *fp = (struct file *)f->f_fsdata;
668
669	switch (where) {
670	case SEEK_SET:
671		fp->f_seekp = offset;
672		break;
673	case SEEK_CUR:
674		fp->f_seekp += offset;
675		break;
676	case SEEK_END:
677		fp->f_seekp = fp->f_di.di_size - offset;
678		break;
679	default:
680		return (-1);
681	}
682	return (fp->f_seekp);
683}
684
685static int
686ufs_stat(f, sb)
687	struct open_file *f;
688	struct stat *sb;
689{
690	register struct file *fp = (struct file *)f->f_fsdata;
691
692	/* only important stuff */
693	sb->st_mode = fp->f_di.di_mode;
694	sb->st_uid = fp->f_di.di_uid;
695	sb->st_gid = fp->f_di.di_gid;
696	sb->st_size = fp->f_di.di_size;
697	return (0);
698}
699
700static int
701ufs_readdir(struct open_file *f, struct dirent *d)
702{
703	struct file *fp = (struct file *)f->f_fsdata;
704	struct direct *dp;
705	char *buf;
706	size_t buf_size;
707	int error;
708
709	/*
710	 * assume that a directory entry will not be split across blocks
711	 */
712again:
713	if (fp->f_seekp >= fp->f_di.di_size)
714		return (ENOENT);
715	error = buf_read_file(f, &buf, &buf_size);
716	if (error)
717		return (error);
718	dp = (struct direct *)buf;
719	fp->f_seekp += dp->d_reclen;
720	if (dp->d_ino == (ino_t)0)
721		goto again;
722	d->d_type = dp->d_type;
723	strcpy(d->d_name, dp->d_name);
724	return (0);
725}
726
727#ifdef COMPAT_UFS
728/*
729 * Sanity checks for old file systems.
730 *
731 * XXX - goes away some day.
732 */
733static void
734ffs_oldfscompat(fs)
735	struct fs *fs;
736{
737	int i;
738
739	fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);	/* XXX */
740	fs->fs_interleave = max(fs->fs_interleave, 1);		/* XXX */
741	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
742		fs->fs_nrpos = 8;				/* XXX */
743	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
744		quad_t sizepb = fs->fs_bsize;			/* XXX */
745								/* XXX */
746		fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;	/* XXX */
747		for (i = 0; i < NIADDR; i++) {			/* XXX */
748			sizepb *= NINDIR(fs);			/* XXX */
749			fs->fs_maxfilesize += sizepb;		/* XXX */
750		}						/* XXX */
751		fs->fs_qbmask = ~fs->fs_bmask;			/* XXX */
752		fs->fs_qfmask = ~fs->fs_fmask;			/* XXX */
753	}							/* XXX */
754}
755#endif
756