rawfs.c revision 1.10 1 /* $NetBSD: rawfs.c,v 1.10 2008/01/12 09:54:30 tsutsui Exp $ */
2
3 /*
4 * Copyright (c) 1995 Gordon W. Ross
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 * 4. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Gordon W. Ross
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * Raw file system - for stream devices like tapes.
35 * No random access, only sequential read allowed.
36 * This exists only to allow upper level code to be
37 * shielded from the fact that the device must be
38 * read only with whole block position and size.
39 */
40
41 #include <sys/param.h>
42 #include <lib/libsa/stand.h>
43 #include <rawfs.h>
44
45 extern int debug;
46
47 #define RAWFS_BSIZE 8192
48
49 /*
50 * In-core open file.
51 */
52 struct file {
53 daddr_t fs_nextblk; /* block number to read next */
54 daddr_t fs_curblk; /* block number currently in buffer */
55 int fs_len; /* amount left in f_buf */
56 char *fs_ptr; /* read pointer into f_buf */
57 char fs_buf[RAWFS_BSIZE];
58 };
59
60 static int rawfs_get_block(struct open_file *);
61
62 int rawfs_open(const char *path, struct open_file *f)
63 {
64 struct file *fs;
65
66 /*
67 * The actual PROM driver has already been opened.
68 * Just allocate the I/O buffer, etc.
69 */
70 fs = alloc(sizeof(struct file));
71 fs->fs_nextblk = 0;
72 fs->fs_curblk = -1;
73 fs->fs_len = 0;
74 fs->fs_ptr = fs->fs_buf;
75
76 f->f_fsdata = fs;
77 return 0;
78 }
79
80 int rawfs_close(struct open_file *f)
81 {
82 struct file *fs;
83
84 fs = (struct file *)f->f_fsdata;
85 f->f_fsdata = NULL;
86
87 if (fs != NULL)
88 dealloc(fs, sizeof(*fs));
89
90 return 0;
91 }
92
93 int rawfs_read(struct open_file *f, void *start, u_int size, u_int *resid)
94 {
95 struct file *fs = (struct file *)f->f_fsdata;
96 char *addr = start;
97 int error = 0;
98 size_t csize;
99
100 while (size != 0) {
101
102 if (fs->fs_len == 0)
103 if ((error = rawfs_get_block(f)) != 0)
104 break;
105
106 if (fs->fs_len <= 0)
107 break; /* EOF */
108
109 csize = size;
110 if (csize > fs->fs_len)
111 csize = fs->fs_len;
112
113 memcpy(addr, fs->fs_ptr, csize);
114 fs->fs_ptr += csize;
115 fs->fs_len -= csize;
116 addr += csize;
117 size -= csize;
118 }
119 if (resid)
120 *resid = size;
121
122 if (error) {
123 errno = error;
124 error = -1;
125 }
126
127 return error;
128 }
129
130 int rawfs_write(struct open_file *f, void *start, size_t size, size_t *resid)
131 {
132
133 errno = EROFS;
134 return -1;
135 }
136
137 off_t rawfs_seek(struct open_file *f, off_t offset, int where)
138 {
139 struct file *fs = (struct file *)f->f_fsdata;
140 daddr_t curblk, targblk;
141 off_t newoff;
142 int err, idx;
143
144 /*
145 * We support a very minimal feature set for lseek(2); just
146 * enough to allow loadfile() to work with the parameters
147 * we pass to it on boot.
148 *
149 * In all cases, we can't seek back past the start of the
150 * current block.
151 */
152 curblk = (fs->fs_curblk < 0) ? 0 : fs->fs_curblk;
153
154 /*
155 * Only support SEEK_SET and SEEK_CUR which result in offsets
156 * which don't require seeking backwards.
157 */
158 switch (where) {
159 case SEEK_SET:
160 newoff = offset;
161 break;
162
163 case SEEK_CUR:
164 if (fs->fs_curblk < 0)
165 newoff = 0;
166 else {
167 newoff = fs->fs_curblk * RAWFS_BSIZE;
168 newoff += RAWFS_BSIZE - fs->fs_len;
169 }
170 newoff += offset;
171 break;
172
173 default:
174 errno = EINVAL;
175 return -1;
176 }
177
178 if (newoff < (curblk * RAWFS_BSIZE)) {
179 errno = EINVAL;
180 return -1;
181 }
182
183 targblk = newoff / RAWFS_BSIZE;
184
185 /*
186 * If necessary, skip blocks until we hit the required target
187 */
188 err = 0;
189 while (fs->fs_curblk != targblk && (err = rawfs_get_block(f)) == 0)
190 ;
191
192 if (err) {
193 errno = err;
194 return -1;
195 }
196
197 /*
198 * Update the index within the loaded block
199 */
200 idx = newoff % RAWFS_BSIZE;
201 fs->fs_len = RAWFS_BSIZE - idx;
202 fs->fs_ptr = &fs->fs_buf[idx];
203
204 return newoff;
205 }
206
207 int rawfs_stat(struct open_file *f, struct stat *sb)
208 {
209
210 errno = EFTYPE;
211 return -1;
212 }
213
214
215 /*
216 * Read a block from the underlying stream device
217 * (In our case, a tape drive.)
218 */
219 static int
220 rawfs_get_block(struct open_file *f)
221 {
222 struct file *fs;
223 int error;
224 size_t len;
225
226 fs = (struct file *)f->f_fsdata;
227 fs->fs_ptr = fs->fs_buf;
228
229 twiddle();
230 error = f->f_dev->dv_strategy(f->f_devdata, F_READ,
231 fs->fs_nextblk * (RAWFS_BSIZE / DEV_BSIZE),
232 RAWFS_BSIZE, fs->fs_buf, &len);
233
234 if (error == 0) {
235 fs->fs_len = len;
236 fs->fs_curblk = fs->fs_nextblk;
237 fs->fs_nextblk += 1;
238 } else {
239 errno = error;
240 error = -1;
241 }
242
243 return error;
244 }
245