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