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