1 /***************************************************************************
2  *                                                                         *
3  *    LIBDSK: General floppy and diskimage access library                  *
4  *    Copyright (C) 2001,2007  John Elliott <seasip.webmaster@gmail.com>       *
5  *                                                                         *
6  *    This library is free software; you can redistribute it and/or        *
7  *    modify it under the terms of the GNU Library General Public          *
8  *    License as published by the Free Software Foundation; either         *
9  *    version 2 of the License, or (at your option) any later version.     *
10  *                                                                         *
11  *    This library is distributed in the hope that it will be useful,      *
12  *    but WITHOUT ANY WARRANTY; without even the implied warranty of       *
13  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    *
14  *    Library General Public License for more details.                     *
15  *                                                                         *
16  *    You should have received a copy of the GNU Library General Public    *
17  *    License along with this library; if not, write to the Free           *
18  *    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,      *
19  *    MA 02111-1307, USA                                                   *
20  *                                                                         *
21  ***************************************************************************/
22 
23 /* This driver implements access to a flat file, like drvposix, but with the
24  * sides laid out in the order specified by the disk geometry. What you end
25  * up with is a logical filesystem image, hence the name. */
26 
27 #include <stdio.h>
28 #include "libdsk.h"
29 #include "drvi.h"
30 #include "drvlogi.h"
31 
32 
33 /* This struct contains function pointers to the driver's functions, and the
34  * size of its DSK_DRIVER subclass */
35 
36 DRV_CLASS dc_logical =
37 {
38 	sizeof(LOGICAL_DSK_DRIVER),
39 	"logical",
40 	"Raw file logical sector order",
41 	logical_open,	/* open */
42 	logical_creat,	/* create new */
43 	logical_close,	/* close */
44 	logical_read,	/* read sector, working from physical address */
45 	logical_write,	/* write sector, working from physical address */
46 	logical_format,	/* format track, physical */
47 	NULL,		/* get geometry */
48 	NULL,		/* sector ID */
49 	logical_xseek,	/* seek to track */
50 	logical_status,	/* drive status */
51 };
52 
logical_open(DSK_DRIVER * self,const char * filename)53 dsk_err_t logical_open(DSK_DRIVER *self, const char *filename)
54 {
55 	LOGICAL_DSK_DRIVER *lpxself;
56 
57 	/* Sanity check: Is this meant for our driver? */
58 	if (self->dr_class != &dc_logical) return DSK_ERR_BADPTR;
59 	lpxself = (LOGICAL_DSK_DRIVER *)self;
60 
61 	lpxself->lpx_fp = fopen(filename, "r+b");
62 	if (!lpxself->lpx_fp)
63 	{
64 		lpxself->lpx_readonly = 1;
65 		lpxself->lpx_fp = fopen(filename, "rb");
66 	}
67 	if (!lpxself->lpx_fp) return DSK_ERR_NOTME;
68 /* v0.9.5: Record exact size, so we can tell if we're writing off the end
69  * of the file. Under Windows, writing off the end of the file fills the
70  * gaps with random data, which can cause mess to appear in the directory;
71  * and under UNIX, the entire directory is filled with zeroes. */
72         if (fseek(lpxself->lpx_fp, 0, SEEK_END)) return DSK_ERR_SYSERR;
73         lpxself->lpx_filesize = ftell(lpxself->lpx_fp);
74 
75 	return DSK_ERR_OK;
76 }
77 
78 
logical_creat(DSK_DRIVER * self,const char * filename)79 dsk_err_t logical_creat(DSK_DRIVER *self, const char *filename)
80 {
81 	LOGICAL_DSK_DRIVER *lpxself;
82 
83 	/* Sanity check: Is this meant for our driver? */
84 	if (self->dr_class != &dc_logical) return DSK_ERR_BADPTR;
85 	lpxself = (LOGICAL_DSK_DRIVER *)self;
86 
87 	lpxself->lpx_fp = fopen(filename, "w+b");
88 	lpxself->lpx_readonly = 0;
89 	if (!lpxself->lpx_fp) return DSK_ERR_SYSERR;
90 	lpxself->lpx_filesize = 0;
91 	return DSK_ERR_OK;
92 }
93 
94 
logical_close(DSK_DRIVER * self)95 dsk_err_t logical_close(DSK_DRIVER *self)
96 {
97 	LOGICAL_DSK_DRIVER *lpxself;
98 
99 	if (self->dr_class != &dc_logical) return DSK_ERR_BADPTR;
100 	lpxself = (LOGICAL_DSK_DRIVER *)self;
101 
102 	if (lpxself->lpx_fp)
103 	{
104 		if (fclose(lpxself->lpx_fp) == EOF) return DSK_ERR_SYSERR;
105 		lpxself->lpx_fp = NULL;
106 	}
107 	return DSK_ERR_OK;
108 }
109 
110 
logical_read(DSK_DRIVER * self,const DSK_GEOMETRY * geom,void * buf,dsk_pcyl_t cylinder,dsk_phead_t head,dsk_psect_t sector)111 dsk_err_t logical_read(DSK_DRIVER *self, const DSK_GEOMETRY *geom,
112                              void *buf, dsk_pcyl_t cylinder,
113                               dsk_phead_t head, dsk_psect_t sector)
114 {
115 	LOGICAL_DSK_DRIVER *lpxself;
116 	dsk_lsect_t offset;
117 	dsk_err_t err;
118 
119 	if (!buf || !self || !geom || self->dr_class != &dc_logical) return DSK_ERR_BADPTR;
120 	lpxself = (LOGICAL_DSK_DRIVER *)self;
121 
122 	if (!lpxself->lpx_fp) return DSK_ERR_NOTRDY;
123 
124 	err = dg_ps2ls(geom, cylinder, head, sector, &offset);
125 	if (err) return err;
126 	offset *=  geom->dg_secsize;
127 
128 	if (fseek(lpxself->lpx_fp, offset, SEEK_SET)) return DSK_ERR_SYSERR;
129 
130 	if (fread(buf, 1, geom->dg_secsize, lpxself->lpx_fp) < geom->dg_secsize)
131 	{
132 		return DSK_ERR_NOADDR;
133 	}
134 	return DSK_ERR_OK;
135 }
136 
137 
seekto(LOGICAL_DSK_DRIVER * self,unsigned long offset)138 static dsk_err_t seekto(LOGICAL_DSK_DRIVER *self, unsigned long offset)
139 {
140 	/* 0.9.5: Fill any "holes" in the file with 0xE5. Otherwise, UNIX would
141 	 * fill them with zeroes and Windows would fill them with whatever
142 	 * happened to be lying around */
143 	if (self->lpx_filesize < offset)
144 	{
145 		if (fseek(self->lpx_fp, self->lpx_filesize, SEEK_SET)) return DSK_ERR_SYSERR;
146 		while (self->lpx_filesize < offset)
147 		{
148 			if (fputc(0xE5, self->lpx_fp) == EOF) return DSK_ERR_SYSERR;
149 			++self->lpx_filesize;
150 		}
151 	}
152 	if (fseek(self->lpx_fp, offset, SEEK_SET)) return DSK_ERR_SYSERR;
153 	return DSK_ERR_OK;
154 }
155 
logical_write(DSK_DRIVER * self,const DSK_GEOMETRY * geom,const void * buf,dsk_pcyl_t cylinder,dsk_phead_t head,dsk_psect_t sector)156 dsk_err_t logical_write(DSK_DRIVER *self, const DSK_GEOMETRY *geom,
157                              const void *buf, dsk_pcyl_t cylinder,
158                               dsk_phead_t head, dsk_psect_t sector)
159 {
160 	LOGICAL_DSK_DRIVER *lpxself;
161 	dsk_lsect_t offset;
162 	dsk_err_t err;
163 
164 	if (!buf || !self || !geom || self->dr_class != &dc_logical) return DSK_ERR_BADPTR;
165 	lpxself = (LOGICAL_DSK_DRIVER *)self;
166 
167 	if (!lpxself->lpx_fp) return DSK_ERR_NOTRDY;
168 	if (lpxself->lpx_readonly) return DSK_ERR_RDONLY;
169 
170 	err = dg_ps2ls(geom, cylinder, head, sector, &offset);
171 	if (err) return err;
172 	offset *=  geom->dg_secsize;
173 
174 	err = seekto(lpxself, offset);
175 	if (err) return err;
176 
177 	if (fwrite(buf, 1, geom->dg_secsize, lpxself->lpx_fp) < geom->dg_secsize)
178 	{
179 		return DSK_ERR_NOADDR;
180 	}
181 	if (lpxself->lpx_filesize < offset + geom->dg_secsize)
182 		lpxself->lpx_filesize = offset + geom->dg_secsize;
183 	return DSK_ERR_OK;
184 }
185 
186 
logical_format(DSK_DRIVER * self,DSK_GEOMETRY * geom,dsk_pcyl_t cylinder,dsk_phead_t head,const DSK_FORMAT * format,unsigned char filler)187 dsk_err_t logical_format(DSK_DRIVER *self, DSK_GEOMETRY *geom,
188                                 dsk_pcyl_t cylinder, dsk_phead_t head,
189                                 const DSK_FORMAT *format, unsigned char filler)
190 {
191 /*
192  * Note that we completely ignore the "format" parameter, since raw LOGICAL
193  * images don't hold track headers.
194  */
195 	LOGICAL_DSK_DRIVER *lpxself;
196 	dsk_lsect_t offset;
197 	unsigned long trklen;
198 	dsk_err_t err;
199 
200    (void)format;
201 	if (!self || !geom || self->dr_class != &dc_logical) return DSK_ERR_BADPTR;
202 	lpxself = (LOGICAL_DSK_DRIVER *)self;
203 
204 	if (!lpxself->lpx_fp) return DSK_ERR_NOTRDY;
205 	if (lpxself->lpx_readonly) return DSK_ERR_RDONLY;
206 
207 	trklen = geom->dg_sectors * geom->dg_secsize;
208 
209 	err = dg_ps2ls(geom, cylinder, head, geom->dg_secbase, &offset);
210 	if (err) return err;
211 	offset *= geom->dg_secsize;
212 
213 	err = seekto(lpxself, offset);
214 	if (err) return err;
215 	if (lpxself->lpx_filesize < offset + trklen)
216 		lpxself->lpx_filesize = offset + trklen;
217 
218 	while (trklen--)
219 		if (fputc(filler, lpxself->lpx_fp) == EOF) return DSK_ERR_SYSERR;
220 
221 	return DSK_ERR_OK;
222 }
223 
224 
225 
logical_xseek(DSK_DRIVER * self,const DSK_GEOMETRY * geom,dsk_pcyl_t cylinder,dsk_phead_t head)226 dsk_err_t logical_xseek(DSK_DRIVER *self, const DSK_GEOMETRY *geom,
227                       dsk_pcyl_t cylinder, dsk_phead_t head)
228 {
229 	LOGICAL_DSK_DRIVER *lpxself;
230 	dsk_err_t err;
231 	dsk_lsect_t offset;
232 
233 	if (!self || !geom || self->dr_class != &dc_logical) return DSK_ERR_BADPTR;
234 	lpxself = (LOGICAL_DSK_DRIVER *)self;
235 
236 	if (!lpxself->lpx_fp) return DSK_ERR_NOTRDY;
237 
238 	if (cylinder >= geom->dg_cylinders || head >= geom->dg_heads)
239 		return DSK_ERR_SEEKFAIL;
240 
241 	err = dg_ps2ls(geom, cylinder, head, geom->dg_secbase, &offset);
242 	if (err) return err;
243 	offset *= geom->dg_secsize;
244 
245 	if (fseek(lpxself->lpx_fp, offset, SEEK_SET)) return DSK_ERR_SEEKFAIL;
246 
247 	return DSK_ERR_OK;
248 }
249 
logical_status(DSK_DRIVER * self,const DSK_GEOMETRY * geom,dsk_phead_t head,unsigned char * result)250 dsk_err_t logical_status(DSK_DRIVER *self, const DSK_GEOMETRY *geom,
251                       dsk_phead_t head, unsigned char *result)
252 {
253 	LOGICAL_DSK_DRIVER *lpxself;
254 
255 	if (!self || !geom || self->dr_class != &dc_logical) return DSK_ERR_BADPTR;
256 	lpxself = (LOGICAL_DSK_DRIVER *)self;
257 
258 	if (!lpxself->lpx_fp) *result &= ~DSK_ST3_READY;
259 	if (lpxself->lpx_readonly) *result |= DSK_ST3_RO;
260 	return DSK_ERR_OK;
261 }
262 
263