ustarfs.c revision 1.1 1 /* $NetBSD: ustarfs.c,v 1.1 1998/09/24 05:23:33 ross Exp $ */
2
3 /* [Notice revision 2.2]
4 * Copyright (c) 1997, 1998 Avalon Computer Systems, Inc.
5 * All rights reserved.
6 *
7 * Author: Ross Harvey
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright and
13 * author notice, this list of conditions, and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of Avalon Computer Systems, Inc. nor the names of
18 * its contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 * 4. This copyright will be assigned to The NetBSD Foundation on
21 * 1/1/2000 unless these terms (including possibly the assignment
22 * date) are updated in writing by Avalon prior to the latest specified
23 * assignment date.
24 *
25 * THIS SOFTWARE IS PROVIDED BY AVALON COMPUTER SYSTEMS, INC. AND CONTRIBUTORS
26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AVALON OR THE CONTRIBUTORS
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38
39 /*
40 ******************************* USTAR FS *******************************
41 */
42
43 /*
44 * Implement an ROFS with an 8K boot area followed by ustar-format data.
45 * The point: minimal FS overhead, and it's easy (well, `possible') to
46 * split files over multiple volumes.
47 *
48 * XXX - TODO LIST
49 * --- - ---- ----
50 * XXX - tag volume numbers and verify that the correct volume is
51 * inserted after volume swaps.
52 *
53 * XXX - stop hardwiring FS metadata for floppies...embed it in a file,
54 * file name, or something. (Remember __SYMDEF? :-)
55 *
56 */
57
58 #include <lib/libkern/libkern.h>
59 #include "stand.h"
60 #include "ustarfs.h"
61
62 #define USTAR_NAME_BLOCK 512
63
64 typedef struct ustar_struct {
65 char ust_name[100],
66 ust_mode[8],
67 ust_uid[8],
68 ust_gid[8],
69 ust_size[12],
70 ust_misc[12 + 8 + 1 + 100],
71 ust_magic[6];
72 /* there is more, but we don't care */
73 } ustar_t;
74
75 /*
76 * We buffer one even cylindar of data...it's actually only really one
77 * cyl on a 1.44M floppy, but on other devices it's fast enough with any
78 * kind of block buffering, so we optimize for the slowest device.
79 */
80
81 typedef struct ust_active_struct {
82 ustar_t uas_active;
83 char uas_1cyl[18 * 2 * 512];
84 off_t uas_volsize; /* XXX this is hardwired now */
85 off_t uas_windowbase; /* relative to volume 0 */
86 off_t uas_filestart; /* relative to volume 0 */
87 off_t uas_fseek; /* relative to file */
88 int uas_init_window; /* data present in window */
89 int uas_init_fs; /* ust FS actually found */
90 off_t uas_filesize; /* relative to volume 0 */
91 } ust_active_t;
92
93 #define BBSIZE 8192
94
95 static int ustarfs_mode_offset = BBSIZE;
96
97 static int ustarfs_cylinder_read __P((struct open_file *, off_t));
98 static int read512block __P((struct open_file *, off_t, char block[512]));
99 static void ustarfs_sscanf __P((const char *, const char *, int *));
100 static int convert __P((const char *, int, int));
101
102 static int
103 convert(f, base, fw)
104 const char *f;
105 int base, fw;
106 {
107 int i, c, result = 0;
108
109 while(fw > 0 && *f == ' ') {
110 --fw;
111 ++f;
112 }
113 for(i = 0; i < fw; ++i) {
114 c = f[i];
115 if ('0' <= c && c < '0' + base) {
116 c -= '0';
117 result = result * base + c;
118 } else break;
119 }
120 return result;
121 }
122
123 static void
124 ustarfs_sscanf(s,f,xi)
125 const char *s,*f;
126 int *xi;
127 {
128 *xi = convert(s, 8, convert(f + 1, 10, 99));
129 }
130
131 static int
132 ustarfs_cylinder_read(f, seek2)
133 struct open_file *f;
134 off_t seek2;
135 {
136 int e;
137 size_t xfercount;
138 ust_active_t *ustf;
139
140 ustf = f->f_fsdata;
141 e = f->f_dev->dv_strategy(f->f_devdata, F_READ, seek2/512,
142 sizeof ustf->uas_1cyl, ustf->uas_1cyl, &xfercount);
143 if (e == 0 && xfercount != sizeof ustf->uas_1cyl)
144 printf("Warning, unexpected short transfer %d/%d\n",
145 (int)xfercount, (int) sizeof ustf->uas_1cyl);
146 return e;
147 }
148
149 static int
150 read512block(f, offset, block)
151 struct open_file *f;
152 off_t offset;
153 char block[512];
154 {
155 ssize_t e;
156 int needvolume, havevolume, dienow = 0;
157 off_t lastbase, seek2;
158 ust_active_t *ustf;
159
160 ustf = f->f_fsdata;
161 tryagain:
162 if(ustf->uas_init_window
163 && ustf->uas_windowbase <= offset
164 && offset - ustf->uas_windowbase < sizeof ustf->uas_1cyl) {
165 memcpy(block, ustf->uas_1cyl + offset - ustf->uas_windowbase,
166 512);
167 return 0;
168 }
169 if (dienow++)
170 panic("ustarfs read512block");
171 lastbase = ustf->uas_windowbase;
172 seek2 = ustf->uas_windowbase = offset - offset % sizeof ustf->uas_1cyl;
173 if(ustf->uas_volsize) {
174 havevolume = lastbase / ustf->uas_volsize;
175 needvolume = ustf->uas_windowbase / ustf->uas_volsize;
176 if (havevolume != needvolume) {
177 if (needvolume != havevolume + 1)
178 printf("Caution: the disk required is not the"
179 " next disk in ascending sequence.\n");
180 printf("Please insert disk number %d"
181 " and type return...", needvolume + 1);
182 getchar();
183 }
184 seek2 %= ustf->uas_volsize;
185 }
186 e = ustarfs_cylinder_read(f, seek2);
187 if (e)
188 return e;
189 ustf->uas_init_window = 1;
190 goto tryagain;
191 }
192
193 int
194 ustarfs_open(path, f)
195 char *path;
196 struct open_file *f;
197
198 {
199 ust_active_t *ustf;
200 off_t offset;
201 char block[512];
202 int filesize;
203 int e, e2;
204
205 if (*path == '/')
206 ++path;
207 e = EINVAL;
208 f->f_fsdata = ustf = alloc(sizeof *ustf);
209 memset(ustf, 0, sizeof *ustf);
210 offset = ustarfs_mode_offset;
211 ustf->uas_fseek = 0;
212 for(;;) {
213 ustf->uas_filestart = offset;
214 e2 = read512block(f, offset, block);
215 if (e2) {
216 e = e2;
217 break;
218 }
219 memcpy(&ustf->uas_active, block, sizeof ustf->uas_active);
220 if(strncmp(ustf->uas_active.ust_magic, "ustar", 5))
221 break;
222 e = ENOENT; /* it must be an actual ustarfs */
223 ustf->uas_init_fs = 1;
224 /*
225 * XXX - the right way to store FS metadata on ustarfs
226 * is to embed the data within a file. For now, we
227 * will avoid complexity by hardwiring metadata for
228 * a floppy.
229 */
230 ustf->uas_volsize = 80 * 2 * 18 * 512; /* XXX */
231 ustarfs_sscanf(ustf->uas_active.ust_size,"%12o",&filesize);
232 if(strncmp(ustf->uas_active.ust_name, path,
233 sizeof ustf->uas_active.ust_name) == 0) {
234 ustf->uas_filesize = filesize;
235 e = 0;
236 break;
237 }
238 offset += USTAR_NAME_BLOCK + filesize;
239 filesize %= 512;
240 if (filesize)
241 offset += 512 - filesize;
242 }
243 if (e) {
244 free(ustf, sizeof *ustf);
245 f->f_fsdata = 0;
246 }
247 return e;
248 }
249
250 int
251 ustarfs_write(f, start, size, resid)
252 struct open_file *f;
253 void *start;
254 size_t size;
255 size_t *resid;
256 {
257 return (EROFS);
258 }
259
260 off_t
261 ustarfs_seek(f, offs, whence)
262 struct open_file *f;
263 off_t offs;
264 int whence;
265 {
266 ust_active_t *ustf;
267
268 ustf = f->f_fsdata;
269 switch (whence) {
270 case SEEK_SET:
271 ustf->uas_fseek = offs;
272 break;
273 case SEEK_CUR:
274 ustf->uas_fseek += offs;
275 break;
276 case SEEK_END:
277 ustf->uas_fseek = ustf->uas_filesize - offs;
278 break;
279 default:
280 return -1;
281 }
282 return ustf->uas_fseek;
283 }
284
285 int
286 ustarfs_read(f, start, size, resid)
287 struct open_file *f;
288 void *start;
289 size_t size;
290 size_t *resid;
291 {
292 ust_active_t *ustf;
293 int e;
294 char *space512;
295 int blkoffs,
296 readoffs,
297 bufferoffset;
298 size_t seg;
299 int infile,
300 inbuffer;
301
302 e = 0;
303 space512 = alloc(512);
304 ustf = f->f_fsdata;
305 while(size != 0) {
306 if (ustf->uas_fseek >= ustf->uas_filesize)
307 break;
308 bufferoffset = ustf->uas_fseek % 512;
309 blkoffs = ustf->uas_fseek - bufferoffset;
310 readoffs = ustf->uas_filestart + 512 + blkoffs;
311 e = read512block(f, readoffs, space512);
312 if (e)
313 break;
314 seg = size;
315 inbuffer = 512 - bufferoffset;
316 if (inbuffer < seg)
317 seg = inbuffer;
318 infile = ustf->uas_filesize - ustf->uas_fseek;
319 if (infile < seg)
320 seg = infile;
321 memcpy(start, space512 + bufferoffset, seg);
322 ustf->uas_fseek += seg;
323 start += seg;
324 size -= seg;
325 }
326 if (resid)
327 *resid = size;
328 free(space512, 512);
329 return e;
330 }
331
332 int
333 ustarfs_stat(f, sb)
334 struct open_file *f;
335 struct stat *sb;
336 {
337 int mode, uid, gid;
338 ust_active_t *ustf;
339
340 if (f == NULL)
341 return EINVAL;
342 ustf = f->f_fsdata;
343 memset(sb, 0, sizeof *sb);
344 ustarfs_sscanf(ustf->uas_active.ust_mode, "%8o", &mode);
345 ustarfs_sscanf(ustf->uas_active.ust_uid, "%8o", &uid);
346 ustarfs_sscanf(ustf->uas_active.ust_gid, "%8o", &gid);
347 sb->st_mode = mode;
348 sb->st_uid = uid;
349 sb->st_gid = gid;
350 sb->st_size = ustf->uas_filesize;
351 return 0;
352 }
353
354 int
355 ustarfs_close(f)
356 struct open_file *f;
357 {
358 if (f == NULL || f->f_fsdata == NULL)
359 return EINVAL;
360 free(f->f_fsdata, sizeof(ust_active_t));
361 f->f_fsdata = 0;
362 return 0;
363 }
364