1 /*
2 * The ARAnyM MetaDOS driver.
3 *
4 * 2002 STan
5 *
6 * Based on:
7 * dosfile.c,v 1.20 2001/06/13 20:21:14 fna Exp
8 *
9 * This file has been modified as part of the FreeMiNT project. See
10 * the file Changes.MH for details and dates.
11 *
12 *
13 * Copyright 1990,1991,1992 Eric R. Smith.
14 * Copyright 1992,1993,1994 Atari Corporation.
15 * All rights reserved.
16 *
17 */
18
19 /* DOS file handling routines */
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24
25 # include "dosfile.h"
26 # include "bosmeta.h"
27
28 # include "metados.h"
29
30 #if 0
31 #include "nfd.h"
32 #define TRACE(x) NFD(x)
33 #define DEBUG(x) NFD(x)
34 #else
35 #define TRACE(x)
36 #define DEBUG(x)
37 #endif
38
39
40 typedef struct {
41 FCOOKIE *fc;
42 unsigned long offset;
43 } FILEPTR;
44
45
46 static inline long
do_open(FILEPTR * f,FCOOKIE * fc,short mode)47 do_open( FILEPTR *f, FCOOKIE *fc, short mode)
48 {
49 metaopen_t metaopen;
50 long ret = Metaopen(fc->bos_dev, &metaopen);
51 if ( ret ) return ret;
52
53 /* store the FCOOKIE* */
54 f->fc = fc;
55 f->offset = 0;
56 return 0;
57 }
58
59 static inline long
do_close(FILEPTR * f)60 do_close( FILEPTR *f)
61 {
62 Metaclose(f->fc->bos_dev);
63
64 f->fc = NULL;
65 return 0;
66 }
67
68
69 static inline long
tty_read(FILEPTR * f,char * buf,long count)70 tty_read( FILEPTR *f, char *buf, long count)
71 {
72 return Metaread(f->fc->bos_dev, buf, 0, count);
73 }
74
75 static inline long
tty_write(FILEPTR * f,const char * buf,long count)76 tty_write( FILEPTR *f, const char *buf, long count)
77 {
78 return Metawrite(f->fc->bos_dev, buf, 0, count);
79 }
80
81
82 #define BLOCK_SIZE 2048
83
84 static inline long
block_read(FILEPTR * f,char * buf,long count)85 block_read( FILEPTR *f, char *buf, long count)
86 {
87 unsigned long boffset = f->offset / BLOCK_SIZE;
88 unsigned long bcount = ( count + BLOCK_SIZE - 1) / BLOCK_SIZE;
89
90 DEBUG(("block_read: '%s'\n", f->fc->name));
91
92 if ( (f->offset % BLOCK_SIZE) == 0 &&
93 (count % BLOCK_SIZE) == 0) {
94
95 long ret = Metaread(f->fc->bos_dev, buf, boffset, bcount);
96 if ( ret < 0 )
97 return ret;
98 f->offset += ret * BLOCK_SIZE;
99 return ret;
100 } else {
101 char *buffer = malloc( bcount * BLOCK_SIZE);
102 long ret = Metaread(f->fc->bos_dev, buffer, boffset, bcount);
103 if ( ret < 0 ) {
104 free(buffer);
105 return ret;
106 }
107
108 count = (ret * BLOCK_SIZE < count) ? ret * BLOCK_SIZE : count;
109 memcpy( buf, &buffer[f->offset - (boffset * BLOCK_SIZE)], count);
110 free( buffer);
111 return ret;
112 }
113 }
114
115 static inline long
block_write(FILEPTR * f,const char * buf,long count)116 block_write( FILEPTR *f, const char *buf, long count)
117 {
118 unsigned long boffset = f->offset / BLOCK_SIZE;
119 unsigned long bcount = ( count + BLOCK_SIZE - 1) / BLOCK_SIZE;
120
121 DEBUG(("block_write: '%s'\n", f->fc->name));
122
123 if ( (f->offset % BLOCK_SIZE) == 0 &&
124 (count % BLOCK_SIZE) == 0) {
125
126 long ret = Metawrite(f->fc->bos_dev, buf, boffset, bcount);
127 if ( ret < 0 )
128 return ret;
129 return count;
130 } else {
131 char *buffer = malloc( bcount * BLOCK_SIZE);
132 long ret = Metaread(f->fc->bos_dev, buffer, boffset, bcount);
133 if ( ret < 0 ) {
134 free(buffer);
135 return ret;
136 }
137
138 count = (ret * BLOCK_SIZE < count) ? ret * BLOCK_SIZE : count;
139 memcpy( &buffer[f->offset - (boffset * BLOCK_SIZE)], buf, count);
140
141 ret = Metawrite(f->fc->bos_dev, buffer, boffset, bcount);
142 free(buffer);
143 if ( ret < 0 )
144 return ret;
145 return count;
146 }
147 }
148
149
150 static inline long
do_lseek(FILEPTR * f,long place,short how)151 do_lseek( FILEPTR *f, long place, short how)
152 {
153 switch (how) {
154 case 0: /* whence = SEEK_SET; */
155 f->offset = place;
156 break;
157 case 1: /* whence = SEEK_CUR; */
158 f->offset += place;
159 break;
160 case 2: /* whence = SEEK_END; */
161 /* FIXME? How to find the size of a device? */
162 default:
163 ;
164 }
165
166 return -ENOSYS;
167 }
168
169
170
171 long __CDECL
sys_f_open(MetaDOSFile const char * name,short mode)172 sys_f_open (MetaDOSFile const char *name, short mode)
173 {
174 FILEPTR *fp = (FILEPTR*)fpMD;
175 FCOOKIE *fc;
176
177 long ret = path2cookie( name, NULL, &fc);
178 if (ret) return ret;
179
180 #if 0
181 /* make sure the mode is legal */
182 mode &= O_USER;
183
184 /* note: file mode 3 is reserved for the kernel;
185 * for users, transmogrify it into O_RDWR (mode 2)
186 */
187 if ((mode & O_RWMODE) == O_EXEC)
188 mode = (mode & ~O_RWMODE) | O_RDWR;
189 #endif
190
191 return do_open (fp, fc, mode);
192 }
193
194 long __CDECL
sys_f_create(MetaDOSFile const char * name,short attrib)195 sys_f_create (MetaDOSFile const char *name, short attrib)
196 {
197 FILEPTR *fp = (FILEPTR*)fpMD;
198 FCOOKIE *fc;
199
200 long ret = path2cookie( name, NULL, &fc);
201 if (ret) return ret;
202
203 return do_open (fp, fc, 1);
204 // return EPERM;
205 }
206
207 long __CDECL
sys_f_close(MetaDOSFile short fd)208 sys_f_close (MetaDOSFile short fd)
209 {
210 FILEPTR *fp = (FILEPTR*)fpMD;
211 return do_close (fp);
212 }
213
214 long __CDECL
sys_f_read(MetaDOSFile short fd,long count,char * buf)215 sys_f_read (MetaDOSFile short fd, long count, char *buf)
216 {
217 FILEPTR *f = (FILEPTR*)fpMD;
218
219 DEBUG(("f_read: '%s' %lx\n", f->fc->name, f->fc->bos_info_flags));
220 if (is_terminal (f->fc))
221 return tty_read (f, buf, count);
222
223 DEBUG(("f_read: block '%s'\n", f->fc->name));
224 return block_read (f, buf, count);
225 }
226
227 long __CDECL
sys_f_write(MetaDOSFile short fd,long count,const char * buf)228 sys_f_write (MetaDOSFile short fd, long count, const char *buf)
229 {
230 long r;
231 FILEPTR *f = (FILEPTR*)fpMD;
232
233 if (is_terminal (f->fc))
234 return tty_write (f, buf, count);
235
236 /* Prevent broken device drivers from wiping the disk.
237 * We return a zero rather than a negative error code
238 * to help programs those don't handle GEMDOS errors
239 * returned by Fwrite()
240 */
241 if (count <= 0)
242 return 0;
243
244 #if 0
245 /* it would be faster to do this in the device driver, but this
246 * way the drivers are easier to write
247 */
248 if (f->flags & O_APPEND)
249 {
250 r = do_lseek (f, 0L, SEEK_END);
251 /* ignore errors from unseekable files (e.g. pipes) */
252 if (r == EACCES)
253 r = 0;
254 } else
255 #endif
256 r = 0;
257
258 if (r < 0)
259 return r;
260
261 return block_write (f, buf, count);
262 }
263
264 long __CDECL
sys_f_seek(MetaDOSFile long place,short fd,short how)265 sys_f_seek (MetaDOSFile long place, short fd, short how)
266 {
267 FILEPTR *f = (FILEPTR*)fpMD;
268
269 if (is_terminal (f->fc))
270 return 0;
271
272 return do_lseek (f, place, how);
273 }
274
275
276 long __CDECL
sys_f_datime(MetaDOSFile unsigned short * timeptr,short fd,short wflag)277 sys_f_datime (MetaDOSFile unsigned short *timeptr, short fd, short wflag)
278 {
279 FILEPTR *f = (FILEPTR*)fpMD;
280
281 /* some programs use Fdatime to test for TTY devices */
282 if (is_terminal (f->fc))
283 return EACCES;
284
285 return EACCES; //FIXME: xdd_datime (f, timeptr, wflag);
286 }
287
288