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