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