ufs.c revision 39665
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/*
66 *	Stand-alone file reading package.
67 */
68
69#include <sys/param.h>
70#include <sys/time.h>
71#include <ufs/ufs/dinode.h>
72#include <ufs/ufs/dir.h>
73#include <ufs/ffs/fs.h>
74#include "stand.h"
75#include "string.h"
76
77static int	ufs_open(const char *path, struct open_file *f);
78static int	ufs_close(struct open_file *f);
79static int	ufs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
80static off_t	ufs_seek(struct open_file *f, off_t offset, int where);
81static int	ufs_stat(struct open_file *f, struct stat *sb);
82
83struct fs_ops ufs_fsops = {
84	"ufs", ufs_open, ufs_close, ufs_read, null_write, ufs_seek, ufs_stat
85};
86
87/*
88 * In-core open file.
89 */
90struct file {
91	off_t		f_seekp;	/* seek pointer */
92	struct fs	*f_fs;		/* pointer to super-block */
93	struct dinode	f_di;		/* copy of on-disk inode */
94	int		f_nindir[NIADDR];
95					/* number of blocks mapped by
96					   indirect block at level i */
97	char		*f_blk[NIADDR];	/* buffer for indirect block at
98					   level i */
99	size_t		f_blksize[NIADDR];
100					/* size of buffer */
101	daddr_t		f_blkno[NIADDR];/* disk address of block in buffer */
102	char		*f_buf;		/* buffer for data block */
103	size_t		f_buf_size;	/* size of data block */
104	daddr_t		f_buf_blkno;	/* block number of data block */
105};
106
107static int	read_inode(ino_t, struct open_file *);
108static int	block_map(struct open_file *, daddr_t, daddr_t *);
109static int	buf_read_file(struct open_file *, char **, size_t *);
110static int	search_directory(char *, struct open_file *, ino_t *);
111#ifdef COMPAT_UFS
112static void	ffs_oldfscompat(struct fs *);
113#endif
114
115/*
116 * Read a new inode into a file structure.
117 */
118static int
119read_inode(inumber, f)
120	ino_t inumber;
121	struct open_file *f;
122{
123	register struct file *fp = (struct file *)f->f_fsdata;
124	register struct fs *fs = fp->f_fs;
125	char *buf;
126	size_t rsize;
127	int rc;
128
129	if (fs == NULL)
130	    panic("fs == NULL");
131
132	/*
133	 * Read inode and save it.
134	 */
135	buf = malloc(fs->fs_bsize);
136	twiddle();
137	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
138		fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
139		buf, &rsize);
140	if (rc)
141		goto out;
142	if (rsize != fs->fs_bsize) {
143		rc = EIO;
144		goto out;
145	}
146
147	{
148		register struct dinode *dp;
149
150		dp = (struct dinode *)buf;
151		fp->f_di = dp[ino_to_fsbo(fs, inumber)];
152	}
153
154	/*
155	 * Clear out the old buffers
156	 */
157	{
158		register int level;
159
160		for (level = 0; level < NIADDR; level++)
161			fp->f_blkno[level] = -1;
162		fp->f_buf_blkno = -1;
163	}
164out:
165	free(buf);
166	return (rc);
167}
168
169/*
170 * Given an offset in a file, find the disk block number that
171 * contains that block.
172 */
173static int
174block_map(f, file_block, disk_block_p)
175	struct open_file *f;
176	daddr_t file_block;
177	daddr_t *disk_block_p;	/* out */
178{
179	register struct file *fp = (struct file *)f->f_fsdata;
180	register struct fs *fs = fp->f_fs;
181	int level;
182	int idx;
183	daddr_t ind_block_num;
184	daddr_t *ind_p;
185	int rc;
186
187	/*
188	 * Index structure of an inode:
189	 *
190	 * di_db[0..NDADDR-1]	hold block numbers for blocks
191	 *			0..NDADDR-1
192	 *
193	 * di_ib[0]		index block 0 is the single indirect block
194	 *			holds block numbers for blocks
195	 *			NDADDR .. NDADDR + NINDIR(fs)-1
196	 *
197	 * di_ib[1]		index block 1 is the double indirect block
198	 *			holds block numbers for INDEX blocks for blocks
199	 *			NDADDR + NINDIR(fs) ..
200	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
201	 *
202	 * di_ib[2]		index block 2 is the triple indirect block
203	 *			holds block numbers for double-indirect
204	 *			blocks for blocks
205	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
206	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2
207	 *				+ NINDIR(fs)**3 - 1
208	 */
209
210	if (file_block < NDADDR) {
211		/* Direct block. */
212		*disk_block_p = fp->f_di.di_db[file_block];
213		return (0);
214	}
215
216	file_block -= NDADDR;
217
218	/*
219	 * nindir[0] = NINDIR
220	 * nindir[1] = NINDIR**2
221	 * nindir[2] = NINDIR**3
222	 *	etc
223	 */
224	for (level = 0; level < NIADDR; level++) {
225		if (file_block < fp->f_nindir[level])
226			break;
227		file_block -= fp->f_nindir[level];
228	}
229	if (level == NIADDR) {
230		/* Block number too high */
231		return (EFBIG);
232	}
233
234	ind_block_num = fp->f_di.di_ib[level];
235
236	for (; level >= 0; level--) {
237		if (ind_block_num == 0) {
238			*disk_block_p = 0;	/* missing */
239			return (0);
240		}
241
242		if (fp->f_blkno[level] != ind_block_num) {
243			if (fp->f_blk[level] == (char *)0)
244				fp->f_blk[level] =
245					malloc(fs->fs_bsize);
246			twiddle();
247			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
248				fsbtodb(fp->f_fs, ind_block_num),
249				fs->fs_bsize,
250				fp->f_blk[level],
251				&fp->f_blksize[level]);
252			if (rc)
253				return (rc);
254			if (fp->f_blksize[level] != fs->fs_bsize)
255				return (EIO);
256			fp->f_blkno[level] = ind_block_num;
257		}
258
259		ind_p = (daddr_t *)fp->f_blk[level];
260
261		if (level > 0) {
262			idx = file_block / fp->f_nindir[level - 1];
263			file_block %= fp->f_nindir[level - 1];
264		} else
265			idx = file_block;
266
267		ind_block_num = ind_p[idx];
268	}
269
270	*disk_block_p = ind_block_num;
271
272	return (0);
273}
274
275/*
276 * Read a portion of a file into an internal buffer.  Return
277 * the location in the buffer and the amount in the buffer.
278 */
279static int
280buf_read_file(f, buf_p, size_p)
281	struct open_file *f;
282	char **buf_p;		/* out */
283	size_t *size_p;		/* out */
284{
285	register struct file *fp = (struct file *)f->f_fsdata;
286	register struct fs *fs = fp->f_fs;
287	long off;
288	register daddr_t file_block;
289	daddr_t	disk_block;
290	size_t block_size;
291	int rc;
292
293	off = blkoff(fs, fp->f_seekp);
294	file_block = lblkno(fs, fp->f_seekp);
295	block_size = dblksize(fs, &fp->f_di, file_block);
296
297	if (file_block != fp->f_buf_blkno) {
298		rc = block_map(f, file_block, &disk_block);
299		if (rc)
300			return (rc);
301
302		if (fp->f_buf == (char *)0)
303			fp->f_buf = malloc(fs->fs_bsize);
304
305		if (disk_block == 0) {
306			bzero(fp->f_buf, block_size);
307			fp->f_buf_size = block_size;
308		} else {
309			twiddle();
310			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
311				fsbtodb(fs, disk_block),
312				block_size, fp->f_buf, &fp->f_buf_size);
313			if (rc)
314				return (rc);
315		}
316
317		fp->f_buf_blkno = file_block;
318	}
319
320	/*
321	 * Return address of byte in buffer corresponding to
322	 * offset, and size of remainder of buffer after that
323	 * byte.
324	 */
325	*buf_p = fp->f_buf + off;
326	*size_p = block_size - off;
327
328	/*
329	 * But truncate buffer at end of file.
330	 */
331	if (*size_p > fp->f_di.di_size - fp->f_seekp)
332		*size_p = fp->f_di.di_size - fp->f_seekp;
333
334	return (0);
335}
336
337/*
338 * Search a directory for a name and return its
339 * i_number.
340 */
341static int
342search_directory(name, f, inumber_p)
343	char *name;
344	struct open_file *f;
345	ino_t *inumber_p;		/* out */
346{
347	register struct file *fp = (struct file *)f->f_fsdata;
348	register struct direct *dp;
349	struct direct *edp;
350	char *buf;
351	size_t buf_size;
352	int namlen, length;
353	int rc;
354
355	length = strlen(name);
356
357	fp->f_seekp = 0;
358	while (fp->f_seekp < fp->f_di.di_size) {
359		rc = buf_read_file(f, &buf, &buf_size);
360		if (rc)
361			return (rc);
362
363		dp = (struct direct *)buf;
364		edp = (struct direct *)(buf + buf_size);
365		while (dp < edp) {
366			if (dp->d_ino == (ino_t)0)
367				goto next;
368#if BYTE_ORDER == LITTLE_ENDIAN
369			if (fp->f_fs->fs_maxsymlinklen <= 0)
370				namlen = dp->d_type;
371			else
372#endif
373				namlen = dp->d_namlen;
374			if (namlen == length &&
375			    !strcmp(name, dp->d_name)) {
376				/* found entry */
377				*inumber_p = dp->d_ino;
378				return (0);
379			}
380		next:
381			dp = (struct direct *)((char *)dp + dp->d_reclen);
382		}
383		fp->f_seekp += buf_size;
384	}
385	return (ENOENT);
386}
387
388/*
389 * Open a file.
390 */
391static int
392ufs_open(upath, f)
393	const char *upath;
394	struct open_file *f;
395{
396	register char *cp, *ncp;
397	register int c;
398	ino_t inumber, parent_inumber;
399	struct file *fp;
400	struct fs *fs;
401	int rc;
402	size_t buf_size;
403	int nlinks = 0;
404	char namebuf[MAXPATHLEN+1];
405	char *buf = NULL;
406	char *path = NULL;
407
408	/* allocate file system specific data structure */
409	fp = malloc(sizeof(struct file));
410	bzero(fp, sizeof(struct file));
411	f->f_fsdata = (void *)fp;
412
413	/* allocate space and read super block */
414	fs = malloc(SBSIZE);
415	fp->f_fs = fs;
416	twiddle();
417	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
418		SBLOCK, SBSIZE, (char *)fs, &buf_size);
419	if (rc)
420		goto out;
421
422	if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
423	    fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
424		rc = EINVAL;
425		goto out;
426	}
427#ifdef COMPAT_UFS
428	ffs_oldfscompat(fs);
429#endif
430
431	/*
432	 * Calculate indirect block levels.
433	 */
434	{
435		register int mult;
436		register int level;
437
438		mult = 1;
439		for (level = 0; level < NIADDR; level++) {
440			mult *= NINDIR(fs);
441			fp->f_nindir[level] = mult;
442		}
443	}
444
445	inumber = ROOTINO;
446	if ((rc = read_inode(inumber, f)) != 0)
447		goto out;
448
449	cp = path = strdup(upath);
450	if (path == NULL) {
451	    rc = ENOMEM;
452	    goto out;
453	}
454	while (*cp) {
455
456		/*
457		 * Remove extra separators
458		 */
459		while (*cp == '/')
460			cp++;
461		if (*cp == '\0')
462			break;
463
464		/*
465		 * Check that current node is a directory.
466		 */
467		if ((fp->f_di.di_mode & IFMT) != IFDIR) {
468			rc = ENOTDIR;
469			goto out;
470		}
471
472		/*
473		 * Get next component of path name.
474		 */
475		{
476			register int len = 0;
477
478			ncp = cp;
479			while ((c = *cp) != '\0' && c != '/') {
480				if (++len > MAXNAMLEN) {
481					rc = ENOENT;
482					goto out;
483				}
484				cp++;
485			}
486			*cp = '\0';
487		}
488
489		/*
490		 * Look up component in current directory.
491		 * Save directory inumber in case we find a
492		 * symbolic link.
493		 */
494		parent_inumber = inumber;
495		rc = search_directory(ncp, f, &inumber);
496		*cp = c;
497		if (rc)
498			goto out;
499
500		/*
501		 * Open next component.
502		 */
503		if ((rc = read_inode(inumber, f)) != 0)
504			goto out;
505
506		/*
507		 * Check for symbolic link.
508		 */
509		if ((fp->f_di.di_mode & IFMT) == IFLNK) {
510			int link_len = fp->f_di.di_size;
511			int len;
512
513			len = strlen(cp);
514
515			if (link_len + len > MAXPATHLEN ||
516			    ++nlinks > MAXSYMLINKS) {
517				rc = ENOENT;
518				goto out;
519			}
520
521			bcopy(cp, &namebuf[link_len], len + 1);
522
523			if (link_len < fs->fs_maxsymlinklen) {
524				bcopy(fp->f_di.di_shortlink, namebuf,
525				      (unsigned) link_len);
526			} else {
527				/*
528				 * Read file for symbolic link
529				 */
530				size_t buf_size;
531				daddr_t	disk_block;
532				register struct fs *fs = fp->f_fs;
533
534				if (!buf)
535					buf = malloc(fs->fs_bsize);
536				rc = block_map(f, (daddr_t)0, &disk_block);
537				if (rc)
538					goto out;
539
540				twiddle();
541				rc = (f->f_dev->dv_strategy)(f->f_devdata,
542					F_READ, fsbtodb(fs, disk_block),
543					fs->fs_bsize, buf, &buf_size);
544				if (rc)
545					goto out;
546
547				bcopy((char *)buf, namebuf, (unsigned)link_len);
548			}
549
550			/*
551			 * If relative pathname, restart at parent directory.
552			 * If absolute pathname, restart at root.
553			 */
554			cp = namebuf;
555			if (*cp != '/')
556				inumber = parent_inumber;
557			else
558				inumber = (ino_t)ROOTINO;
559
560			if ((rc = read_inode(inumber, f)) != 0)
561				goto out;
562		}
563	}
564
565	/*
566	 * Found terminal component.
567	 */
568	rc = 0;
569out:
570	if (buf)
571		free(buf);
572	if (path)
573		free(path);
574	if (rc) {
575		if (fp->f_buf)
576			free(fp->f_buf);
577		free(fp->f_fs);
578		free(fp);
579	}
580	return (rc);
581}
582
583static int
584ufs_close(f)
585	struct open_file *f;
586{
587	register struct file *fp = (struct file *)f->f_fsdata;
588	int level;
589
590	f->f_fsdata = (void *)0;
591	if (fp == (struct file *)0)
592		return (0);
593
594	for (level = 0; level < NIADDR; level++) {
595		if (fp->f_blk[level])
596			free(fp->f_blk[level]);
597	}
598	if (fp->f_buf)
599		free(fp->f_buf);
600	free(fp->f_fs);
601	free(fp);
602	return (0);
603}
604
605/*
606 * Copy a portion of a file into kernel memory.
607 * Cross block boundaries when necessary.
608 */
609static int
610ufs_read(f, start, size, resid)
611	struct open_file *f;
612	void *start;
613	size_t size;
614	size_t *resid;	/* out */
615{
616	register struct file *fp = (struct file *)f->f_fsdata;
617	register size_t csize;
618	char *buf;
619	size_t buf_size;
620	int rc = 0;
621	register char *addr = start;
622
623	while (size != 0) {
624		if (fp->f_seekp >= fp->f_di.di_size)
625			break;
626
627		rc = buf_read_file(f, &buf, &buf_size);
628		if (rc)
629			break;
630
631		csize = size;
632		if (csize > buf_size)
633			csize = buf_size;
634
635		bcopy(buf, addr, csize);
636
637		fp->f_seekp += csize;
638		addr += csize;
639		size -= csize;
640	}
641	if (resid)
642		*resid = size;
643	return (rc);
644}
645
646static off_t
647ufs_seek(f, offset, where)
648	struct open_file *f;
649	off_t offset;
650	int where;
651{
652	register struct file *fp = (struct file *)f->f_fsdata;
653
654	switch (where) {
655	case SEEK_SET:
656		fp->f_seekp = offset;
657		break;
658	case SEEK_CUR:
659		fp->f_seekp += offset;
660		break;
661	case SEEK_END:
662		fp->f_seekp = fp->f_di.di_size - offset;
663		break;
664	default:
665		return (-1);
666	}
667	return (fp->f_seekp);
668}
669
670static int
671ufs_stat(f, sb)
672	struct open_file *f;
673	struct stat *sb;
674{
675	register struct file *fp = (struct file *)f->f_fsdata;
676
677	/* only important stuff */
678	sb->st_mode = fp->f_di.di_mode;
679	sb->st_uid = fp->f_di.di_uid;
680	sb->st_gid = fp->f_di.di_gid;
681	sb->st_size = fp->f_di.di_size;
682	return (0);
683}
684
685#ifdef COMPAT_UFS
686/*
687 * Sanity checks for old file systems.
688 *
689 * XXX - goes away some day.
690 */
691static void
692ffs_oldfscompat(fs)
693	struct fs *fs;
694{
695	int i;
696
697	fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect);	/* XXX */
698	fs->fs_interleave = max(fs->fs_interleave, 1);		/* XXX */
699	if (fs->fs_postblformat == FS_42POSTBLFMT)		/* XXX */
700		fs->fs_nrpos = 8;				/* XXX */
701	if (fs->fs_inodefmt < FS_44INODEFMT) {			/* XXX */
702		quad_t sizepb = fs->fs_bsize;			/* XXX */
703								/* XXX */
704		fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1;	/* XXX */
705		for (i = 0; i < NIADDR; i++) {			/* XXX */
706			sizepb *= NINDIR(fs);			/* XXX */
707			fs->fs_maxfilesize += sizepb;		/* XXX */
708		}						/* XXX */
709		fs->fs_qbmask = ~fs->fs_bmask;			/* XXX */
710		fs->fs_qfmask = ~fs->fs_fmask;			/* XXX */
711	}							/* XXX */
712}
713#endif
714