1 /* $OpenBSD: lif.c,v 1.10 2004/11/22 18:41:41 mickey Exp $ */
2
3 /*
4 * Copyright (c) 1998-2004 Michael Shalayeff
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 OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 * THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/param.h>
30 #include <sys/disklabel.h>
31 #include "libsa.h"
32
33 extern int debug;
34
35 struct file {
36 char f_buf[LIF_FILESTART];/* buffer for lif volume header and dir */
37 struct lifvol *f_lp; /* lif volume header pointer */
38 struct lifdir *f_ld; /* lif dir pointer */
39 int f_nfiles; /* gross number for lif dir entries */
40
41 off_t f_seek; /* seek pointer for file read */
42 struct lifdir *f_rd; /* lif dir pointer for readdir */
43
44 int f_isdir; /* special hacky flag for '.' dir */
45 int f_count; /* this file length */
46 int f_off; /* this file offset */
47 };
48
49 int
lif_open(path,f)50 lif_open (path, f)
51 char *path;
52 struct open_file *f;
53 {
54 struct file *fp;
55 struct lifdir *dp;
56 char *p, *q;
57 struct lif_load load;
58 size_t buf_size;
59 int err, l;
60
61 #ifdef LIFDEBUG
62 if (debug)
63 printf("lif_open(%s, %p)\n", path, f);
64 #endif
65
66 fp = alloc(sizeof(*fp));
67 /* XXX we're assuming here that sizeof(fp->f_buf) >= LIF_FILESTART */
68 if ((err = (f->f_dev->dv_strategy)(f->f_devdata, F_READ, 0,
69 sizeof(fp->f_buf), &fp->f_buf, &buf_size)) ||
70 buf_size != sizeof(fp->f_buf)) {
71 #ifdef LIFDEBUG
72 if (debug)
73 printf("lif_open: unable to read LIF header (%d)\n", err);
74 #endif
75 } else if ((fp->f_lp = (struct lifvol *)fp->f_buf)->vol_id == LIF_VOL_ID) {
76 f->f_fsdata = fp;
77 fp->f_ld = (struct lifdir *)(fp->f_buf + LIF_DIRSTART);
78 fp->f_seek = 0;
79 fp->f_rd = fp->f_ld;
80 fp->f_nfiles = lifstob(fp->f_lp->vol_dirsize) /
81 sizeof(struct lifdir);
82
83 /* no dirs on the lif */
84 for (p = path + (l = strlen(path)); p >= path; p--)
85 if (*p == '/') {
86 p++;
87 break;
88 }
89 if (p > path)
90 path = p;
91 } else
92 err = EINVAL;
93
94 if (!err && *path != '.') {
95 fp->f_isdir = 0;
96 err = ENOENT;
97 for (dp = fp->f_ld; dp < &fp->f_ld[fp->f_nfiles]; dp++) {
98 #ifdef LIFDEBUG
99 if (debug)
100 printf("lif_open: "
101 "%s <--> '%c%c%c%c%c%c%c%c%c%c'\n",
102 path, dp->dir_name[0], dp->dir_name[1],
103 dp->dir_name[2], dp->dir_name[3],
104 dp->dir_name[4], dp->dir_name[5],
105 dp->dir_name[6], dp->dir_name[7],
106 dp->dir_name[8], dp->dir_name[9]);
107 #endif
108 for (p = path, q = dp->dir_name;
109 *q && *q != ' '; q++, p++)
110 if (tolower(*q) != tolower(*p))
111 break;
112 if ((!*q || *q == ' ') && !*p) {
113 err = 0;
114 break;
115 }
116 }
117 if (!err) {
118 fp->f_off = lifstodb(dp->dir_addr);
119 if (!(err =(f->f_dev->dv_strategy)(f->f_devdata, F_READ,
120 fp->f_off, sizeof(load), &load, &buf_size)) &&
121 buf_size == sizeof(load)) {
122 /* no checksum */
123 fp->f_count = load.count - sizeof(int);
124 fp->f_off = dbtob(fp->f_off) + sizeof(load);
125 #ifdef LIFDEBUG
126 if (debug)
127 printf("lif_open: %u @ %u [%x]\n",
128 fp->f_count, fp->f_off,
129 load.address);
130 #endif
131 } else if (!err)
132 err = EIO;
133 }
134 } else
135 fp->f_isdir = 1;
136
137 if (err) {
138 free (fp, sizeof(*fp));
139 f->f_fsdata = NULL;
140 }
141 #ifdef LIFDEBUG
142 if (debug)
143 printf("ret(%d)\n", err);
144 #endif
145 return err;
146 }
147
148 int
lif_close(f)149 lif_close(f)
150 struct open_file *f;
151 {
152 free (f->f_fsdata, sizeof(struct file));
153 f->f_fsdata = NULL;
154 return 0;
155 }
156
157 int
lif_read(f,buf,size,resid)158 lif_read(f, buf, size, resid)
159 struct open_file *f;
160 void *buf;
161 size_t size;
162 size_t *resid;
163 {
164 struct file *fp = (struct file *)f->f_fsdata;
165 char *p;
166 char bbuf[DEV_BSIZE];
167 size_t bsize, count = sizeof(bbuf);
168 int err = 0;
169 int foff;
170
171 #ifdef LIFDEBUG
172 if (debug)
173 printf("lif_read(%p, %p, %u, %p)\n", f, buf, size, resid);
174 #endif
175
176 for (p = bbuf; size; fp->f_seek += bsize, p += bsize) {
177 twiddle();
178 foff = fp->f_off + fp->f_seek;
179 if (fp->f_seek >= fp->f_count ||
180 (err = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
181 btodb(foff), count, p, &bsize)))
182 break;
183 if (p == bbuf) {
184 bsize = sizeof(bbuf) - (foff & (sizeof(bbuf) - 1));
185 bsize = min(bsize, size);
186 bcopy(bbuf + (foff & (sizeof(bbuf) - 1)), buf, bsize);
187 p = buf;
188 }
189 count = size -= bsize;
190 }
191 if (resid)
192 *resid = size;
193
194 return err;
195 }
196
197 int
lif_write(f,buf,size,resid)198 lif_write(f, buf, size, resid)
199 struct open_file *f;
200 void *buf;
201 size_t size;
202 size_t *resid;
203 {
204 return EOPNOTSUPP;
205 }
206
207 off_t
lif_seek(f,offset,where)208 lif_seek(f, offset, where)
209 struct open_file *f;
210 off_t offset;
211 int where;
212 {
213 struct file *fp = (struct file *)f->f_fsdata;
214
215 switch (where) {
216 case SEEK_SET:
217 fp->f_seek = offset;
218 break;
219 case SEEK_CUR:
220 fp->f_seek += offset;
221 break;
222 case SEEK_END:
223 fp->f_seek = fp->f_count - offset;
224 break;
225 default:
226 return (-1);
227 }
228 return (fp->f_seek);
229 }
230
231 int
lif_stat(f,sb)232 lif_stat(f, sb)
233 struct open_file *f;
234 struct stat *sb;
235 {
236 struct file *fp = (struct file *)f->f_fsdata;
237
238 sb->st_mode = 0755 | (fp->f_isdir? S_IFDIR: 0); /* XXX */
239 sb->st_uid = 0;
240 sb->st_gid = 0;
241 sb->st_size = fp->f_count;
242 return 0;
243 }
244
245 int
lif_readdir(f,name)246 lif_readdir(f, name)
247 struct open_file *f;
248 char *name;
249 {
250 struct file *fp = (struct file *)f->f_fsdata;
251 char *p;
252
253 if (name) {
254 while ((fp->f_rd->dir_name[0] == ' ' ||
255 !fp->f_rd->dir_name[0]) &&
256 (fp->f_rd - fp->f_ld) < fp->f_nfiles)
257 fp->f_rd++;
258 if ((fp->f_rd - fp->f_ld) >= fp->f_nfiles) {
259 *name = '\0';
260 return -1;
261 }
262 strncpy(name, fp->f_rd->dir_name, sizeof(fp->f_rd->dir_name));
263 if ((p = strchr(name, ' ')))
264 *p = '\0';
265 fp->f_rd++;
266 } else
267 fp->f_rd = fp->f_ld;
268
269 return 0;
270 }
271