xref: /openbsd/sys/arch/hppa/stand/libsa/lif.c (revision 5a5d8e11)
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