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