xref: /netbsd/sys/arch/i386/stand/lib/dosfile.c (revision 6550d01e)
1 /*	$NetBSD: dosfile.c,v 1.14 2008/12/14 17:03:43 christos Exp $	 */
2 
3 /*
4  * Copyright (c) 1996
5  *	Matthias Drochner.  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 /*
30  * DOS filesystem for libsa
31  * standalone - uses no device, works only with DOS running
32  * needs lowlevel parts from dos_file.S
33  */
34 
35 #include <lib/libsa/stand.h>
36 
37 #include "diskbuf.h"
38 #include "dosfile.h"
39 
40 extern int dosopen(const char *);
41 extern void dosclose(int);
42 extern int dosread(int, char *, int);
43 extern int dosseek(int, int, int);
44 
45 struct dosfile {
46 	int doshandle, off;
47 };
48 
49 extern int doserrno;	/* in dos_file.S */
50 
51 static int dos2errno(void);
52 
53 static int
54 dos2errno(void)
55 {
56 	int err;
57 
58 	switch (doserrno) {
59 	    case 1:
60 	    case 4:
61 	    case 12:
62 	    default:
63 		err = EIO;
64 	    case 2:
65 	    case 3:
66 		err = ENOENT;
67 	    case 5:
68 		err = EPERM;
69 	    case 6:
70 		err = EINVAL;
71 	}
72 	return err;
73 }
74 
75 int
76 dos_open(const char *path, struct open_file *f)
77 {
78 	struct dosfile *df;
79 
80 	df = (struct dosfile *) alloc(sizeof(*df));
81 	if (!df)
82 		return -1;
83 
84 	df->off = 0;
85 	df->doshandle = dosopen(path);
86 	if (df->doshandle < 0) {
87 #ifdef DEBUG
88 		printf("DOS error %d\n", doserrno);
89 #endif
90 		dealloc(df, sizeof(*df));
91 		return dos2errno();
92 	}
93 	f->f_fsdata = (void *) df;
94 	return 0;
95 }
96 
97 int
98 dos_read(struct open_file *f, void *addr, size_t size, size_t *resid)
99 {
100 	struct dosfile *df;
101 	int             got;
102 	static int      tc = 0;
103 
104 	df = (struct dosfile *) f->f_fsdata;
105 
106 	if (!(tc++ % 4))
107 		twiddle();
108 
109 	if ((unsigned long) addr >= 0x10000) {
110 		u_int           lsize = size;
111 
112 		while (lsize > 0) {
113 			u_int           tsize;
114 			size_t          tgot;
115 			char		*p = addr;
116 
117 			tsize = lsize;
118 
119 			if (tsize > DISKBUFSIZE)
120 				tsize = DISKBUFSIZE;
121 
122 			alloc_diskbuf(dos_read);
123 
124 			tgot = dosread(df->doshandle, diskbufp, tsize);
125 			if (tgot < 0) {
126 #ifdef DEBUG
127 				printf("DOS error %d\n", doserrno);
128 #endif
129 				return dos2errno();
130 			}
131 			memcpy(p, diskbufp, tgot);
132 
133 			p += tgot;
134 			lsize -= tgot;
135 
136 			if (tgot != tsize)
137 				break;	/* EOF */
138 		}
139 		got = size - lsize;
140 	} else {
141 		got = dosread(df->doshandle, addr, size);
142 
143 		if (got < 0) {
144 #ifdef DEBUG
145 			printf("DOS error %d\n", doserrno);
146 #endif
147 			return dos2errno();
148 		}
149 	}
150 
151 	df->off += got;
152 	size -= got;
153 
154 	if (resid)
155 		*resid = size;
156 	return 0;
157 }
158 
159 int
160 dos_close(struct open_file *f)
161 {
162 	struct dosfile *df;
163 	df = (struct dosfile *) f->f_fsdata;
164 
165 	dosclose(df->doshandle);
166 
167 	if (df)
168 		dealloc(df, sizeof(*df));
169 	return 0;
170 }
171 
172 int
173 dos_write(struct open_file *f, void *start, size_t size, size_t *resid)
174 {
175 	return EROFS;
176 }
177 
178 int
179 dos_stat(struct open_file *f, struct stat *sb)
180 {
181 	struct dosfile *df;
182 	df = (struct dosfile *) f->f_fsdata;
183 
184 	sb->st_mode = 0444;
185 	sb->st_nlink = 1;
186 	sb->st_uid = 0;
187 	sb->st_gid = 0;
188 	sb->st_size = -1;
189 	return 0;
190 }
191 
192 off_t
193 dos_seek(struct open_file *f, off_t offset, int where)
194 {
195 	struct dosfile *df;
196 	int             doswhence, res;
197 #ifdef DOS_CHECK
198 	int             checkoffs;
199 #endif
200 	df = (struct dosfile *) f->f_fsdata;
201 
202 	switch (where) {
203 	case SEEK_SET:
204 		doswhence = 0;
205 #ifdef DOS_CHECK
206 		checkoffs = offset;	/* don't trust DOS */
207 #endif
208 		break;
209 	case SEEK_CUR:
210 		doswhence = 1;
211 #ifdef DOS_CHECK
212 		checkoffs = df->off + offset;
213 #endif
214 		break;
215 	case SEEK_END:
216 		doswhence = 2;
217 #ifdef DOS_CHECK
218 		checkoffs = -1;	/* we dont know len */
219 #endif
220 		break;
221 	default:
222 		errno = EOFFSET;
223 		return -1;
224 	}
225 	res = dosseek(df->doshandle, offset, doswhence);
226 	if (res == -1) {
227 		errno = dos2errno();
228 		return -1;
229 	}
230 #ifdef DOS_CHECK
231 	if ((checkoffs != -1) && (res != checkoffs)) {
232 		printf("dosfile: unexpected seek result (%d+%d(%d)=%d)\n",
233 		       df->off, offset, where, res);
234 		errno = EOFFSET;
235 		return -1;
236 	}
237 #endif
238 	df->off = res;
239 	return res;
240 }
241