1 /***************************************************************************
2  *                                                                         *
3  *    LIBDSK: General floppy and diskimage access library                  *
4  *    Copyright (C) 2001-2,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 provides limited read-only support for Teledisk files. It is
24  * based entirely on the file format documentation at
25  * <http://www.fpns.net/willy/wteledsk.htm>. No code from wteledsk has been
26  * used in this file, since it is under GPL and LibDsk is under LGPL.
27  *
28  * (GPL code from wteledsk was incorporated into comptlzh.c / comptlzh.h;
29  *  in that case, it was relicensed as LGPL with permission).
30  *
31  * Current bugs / limitations:
32  * - No write support. The Teledisk format isn't really adapted to
33  *   in-place rewrites of the sort that LibDsk likes to do, but in
34  *   theory it would be possible to support writing to sectors that are
35  *   stored uncompressed (type 0). This would require updating sector CRCs.
36  *
37  * - No support for images split into multiple files (.TD0, .TD1, .TD2...)
38  *
39  * - No support for advanced compression. Rather than having it built-in to
40  *   this driver, we use a compression module to convert advanced-compression
41  *   TD0 files to normal, using code from wteledsk.
42  *
43  *   There's also an "old advanced" compression, which uses 12-bit LZ
44  *   compression in 6k blocks, so another 'comp' driver would be needed for
45  *   that.
46  *
47  */
48 
49 
50 #include "drvi.h"
51 #include "drvtele.h"
52 
53 extern unsigned short teledisk_crc(unsigned char *buf, unsigned short len);
54 
55 DRV_CLASS dc_tele =
56 {
57 	sizeof(TELE_DSK_DRIVER),
58 	"tele",
59 	"TeleDisk file driver",
60 	tele_open,
61 	NULL,			/* tele_creat */
62 	tele_close,
63 	tele_read,
64 	NULL,			/* tele_write */
65 	NULL,			/* tele_format */
66 	tele_getgeom,
67 	tele_secid,
68 	tele_xseek,
69 	tele_status,
70 	tele_xread,
71 	NULL,			/* tele_xwrite */
72 	NULL,			/* tele_tread */
73 	NULL,			/* tele_xtread */
74 	tele_option_enum,
75 	tele_option_set,
76 	tele_option_get,
77 	NULL,			/* tele_trackids */
78 	NULL			/* tele_rtread */
79 };
80 
81 /* #define MONITOR(x) printf x     */
82 
83 #define MONITOR(x)
84 
85 
86 #define DC_CHECK(s) \
87 	TELE_DSK_DRIVER *self; \
88 	if (s->dr_class != &dc_tele) return DSK_ERR_BADPTR; \
89 	self = (TELE_DSK_DRIVER *)s;
90 
91 /* Check that the data rate and recording mode match those used when the
92  * disk was imaged. */
check_rate(TELE_DSK_DRIVER * self,const DSK_GEOMETRY * geom)93 static dsk_err_t check_rate(TELE_DSK_DRIVER *self, const DSK_GEOMETRY *geom)
94 {
95 	int fm;
96 
97 	switch(self->tele_head.datarate & 0x7F)
98 	{
99 /* Allow SD / DD interchangeably with 250/300. */
100 		case 0:
101 		case 1: if (geom->dg_datarate != RATE_SD &&
102 			    geom->dg_datarate != RATE_DD) return DSK_ERR_NOADDR;
103 			break;
104 		case 2: if (geom->dg_datarate != RATE_HD) return DSK_ERR_NOADDR;
105 			break;
106 	}
107 	fm = ((geom->dg_fm & RECMODE_MASK) == RECMODE_FM) ? 0x80 : 0;
108 	if (fm != (self->tele_head.datarate & 0x80))
109 	{
110 		return DSK_ERR_NOADDR;
111 	}
112 	return DSK_ERR_OK;
113 }
114 
tele_fread(TELE_DSK_DRIVER * self,tele_byte * buf,int count)115 static dsk_err_t tele_fread(TELE_DSK_DRIVER *self, tele_byte *buf, int count)
116 {
117 	if (!buf)
118 	{
119 		if (fseek(self->tele_fp, count, SEEK_CUR))
120 		{
121 			return DSK_ERR_SYSERR;
122 		}
123 	}
124 	else
125 	{
126 		if (fread(buf, 1, count, self->tele_fp) < (size_t)count)
127 		{
128 			return DSK_ERR_SYSERR;
129 		}
130 	}
131 	return DSK_ERR_OK;
132 }
133 
tele_readsechead(TELE_DSK_DRIVER * self)134 static dsk_err_t tele_readsechead(TELE_DSK_DRIVER *self)
135 {
136 	dsk_err_t err;
137 	tele_byte buf[6];
138 
139 	memset(&self->tele_sechead, 0, sizeof(self->tele_sechead));
140 	err = tele_fread(self, buf, 6);
141 	if (err) return err;
142 	self->tele_sechead.cylinder_id = buf[0];
143 	self->tele_sechead.head_id     = buf[1];
144 	self->tele_sechead.sector_id   = buf[2];
145 	self->tele_sechead.sector_len  = (128 << buf[3]);
146 	self->tele_sechead.syndrome    = buf[4];
147 	self->tele_sechead.header_crc  = buf[5];
148 
149 	/* Syndromes 0x10 and 0x20 omit sector data */
150 	if ((self->tele_sechead.syndrome & 0x30) == 0)
151 	{
152 		err = tele_fread(self, buf, 3);
153 		if (err) return err;
154 		self->tele_sechead.compressed_len = (((tele_word)buf[1]) << 8) |
155 						buf[0];
156 		self->tele_sechead.encoding   = buf[2];
157 	}
158 	return DSK_ERR_OK;
159 }
160 
161 /* Read the sector described by tele_sechead */
tele_readsec(TELE_DSK_DRIVER * self,unsigned char * buf)162 static dsk_err_t tele_readsec(TELE_DSK_DRIVER *self, unsigned char *buf)
163 {
164 	int n, w, wleft, plen, ptype;
165 	dsk_err_t err;
166 	size_t len = self->tele_sechead.sector_len;
167 	tele_byte pattern[257];
168 
169 	if (self->tele_sechead.syndrome & 0x30)	/* Nothing there */
170 	{
171 		if (buf) memset(buf, 0xF6, len);
172 		return DSK_ERR_OK;
173 	}
174 	switch(self->tele_sechead.encoding)
175 	{
176 		case 0:	/* Uncompressed */
177 			MONITOR(("tele_readsec @ 0x%08lx: Type 0 len %d\n",
178 				 ftell(self->tele_fp), len));
179 			return tele_fread(self, buf, len);
180 		case 1:	/* One pattern */
181 			MONITOR(("tele_readsec @ 0x%08lx: Type 1 len 4\n",
182 				 ftell(self->tele_fp)));
183 			err = tele_fread(self, pattern, 4);
184 			if (err) return err;
185 
186 			if (buf) for (n = 0; n < (int)len; n+= 2)
187 			{
188 				buf[n]   = pattern[2];
189 				buf[n+1] = pattern[3];
190 			}
191 			return DSK_ERR_OK;
192 		case 2:	/* More than one pattern */
193 			w = 0;
194 			MONITOR(("tele_readsec @ 0x%08lx: Type 2 \n",
195 				 ftell(self->tele_fp)));
196 			while ((size_t)w < len)
197 			{
198 				wleft = len - w;
199 				err = tele_fread(self, pattern, 2);
200 				if (err) return err;
201 				ptype = pattern[0];
202 				plen = pattern[1];
203 			MONITOR(("tele_readsec @ 0x%08lx: Type 2 ptype=%d plen=%d\n",
204 				 ftell(self->tele_fp), ptype, plen));
205 				if (ptype == 0)
206 				{
207 					err = tele_fread(self, pattern, plen);
208 					if (err) return err;
209 					if (plen > wleft) plen = wleft;
210 					if (buf) memcpy(buf + w, pattern, plen);
211 					w += plen;
212 					continue;
213 				}
214 				err = tele_fread(self, pattern, (1 << ptype));
215 				for (n = 0; n < plen; n++)
216 				{
217 					if (buf)
218 					{
219 /* Ensure the amount of data written does not exceed len */
220 						if ((1 << ptype) > wleft)
221 							memcpy(buf + w,
222 							  pattern,wleft);
223 						else	memcpy(buf + w,
224 							  pattern, 1 << ptype);
225 					}
226 					w += (1 << ptype);
227 					wleft -= (1 << ptype);
228 				}
229 			}
230 			return DSK_ERR_OK;
231 		default:
232 #ifndef WIN16
233 			fprintf(stderr, "Teledisk: Unsupported sector compression method %d!\n", self->tele_sechead.encoding);
234 #endif
235 			break;
236 	}
237 	return DSK_ERR_NOTIMPL;
238 }
239 
240 /* We cache previously-encountered track addresses in self->tele_track_addr
241  * to avoid doing a linear search every time a track is needed. */
tele_seektrack(TELE_DSK_DRIVER * self,dsk_pcyl_t cylinder,dsk_phead_t head)242 static dsk_err_t tele_seektrack(TELE_DSK_DRIVER *self, dsk_pcyl_t cylinder,
243 		dsk_phead_t head)
244 {
245 	long startpos;
246 	int c, h, s;
247 	dsk_err_t err;
248 
249 	h = head;
250 	c = cylinder;
251 	startpos = 0;
252 	MONITOR(("tele_seektrack: cylinder=%d head=%d\n", cylinder, head));
253 
254 	do
255 	{
256 		MONITOR(("tele_seektrack: Trying c%d h%d\n", c, h));
257 		if (c < 100 && h < 2 && self->tele_track_addr[c][h] != 0)
258 		{
259 			MONITOR(("tele_seektrack: starting at c%d h%d\n", c, h));
260 			startpos = self->tele_track_addr[c][h];
261 		}
262 		if (h == 0)
263 		{
264 			h = 1;
265 			--c;
266 		}
267 		else
268 		{
269 			--h;
270 		}
271 	}
272 	while (startpos == 0 && c >= 0);
273 
274 	if (startpos == 0)
275 	{
276 #ifndef WIN16
277 		fprintf(stderr, "drv_tele internal error: Cannot find cylinder 0 head 0\n");
278 #endif
279 		return DSK_ERR_CTRLR;
280 	}
281 
282 	if (fseek(self->tele_fp, startpos, SEEK_SET))
283 		return DSK_ERR_SYSERR;
284 
285 	do
286 	{
287 		tele_byte buf[4];
288 		startpos = ftell(self->tele_fp);
289 		err = tele_fread(self, buf, 4);
290 		if (err)
291 		{
292 			return DSK_ERR_NOADDR;
293 		}
294 		self->tele_trackhead.sectors  = buf[0];
295 		self->tele_trackhead.cylinder = buf[1];
296 		self->tele_trackhead.head     = buf[2];
297 		self->tele_trackhead.crc      = buf[3];
298 		c = self->tele_trackhead.cylinder;
299 		h = self->tele_trackhead.head;
300 		MONITOR(("tele_seektrack: c%d h%d at 0x%08lx\n", c, h, startpos));
301 		if (c < 100 && h < 2 && self->tele_track_addr[c][h] == 0)
302 		{
303 			self->tele_track_addr[c][h] = startpos;
304 		}
305 		if ((dsk_pcyl_t)c == cylinder && (dsk_phead_t)h == head)
306 		{
307 			return DSK_ERR_OK;
308 		}
309 		for (s = 0; s < self->tele_trackhead.sectors; s++)
310 		{
311 			err = tele_readsechead(self);
312 			if (err) return err;
313 			err = tele_readsec(self, NULL);
314 			if (err) return err;
315 		}
316 
317 	}
318 	while(1);
319 /* Should never happen, but need to shut Pacific C up */
320 	return DSK_ERR_UNKNOWN;
321 }
322 
tele_seeksec(TELE_DSK_DRIVER * self,const DSK_GEOMETRY * geom,dsk_pcyl_t cylinder,dsk_phead_t head,dsk_pcyl_t cyl_expected,dsk_phead_t head_expected,dsk_psect_t sector,size_t * request_len,size_t * sseclen)323 dsk_err_t tele_seeksec(TELE_DSK_DRIVER *self, const DSK_GEOMETRY *geom,
324 		dsk_pcyl_t cylinder, dsk_phead_t head, dsk_pcyl_t cyl_expected,
325 		dsk_phead_t head_expected, dsk_psect_t sector,
326 		size_t *request_len, size_t *sseclen)
327 {
328 	dsk_err_t err;
329 	int s;
330 	long pos;
331 
332 	MONITOR(("tele_seeksec: Searching for c=%d h=%d s=%d on c=%d h=%d\n",
333 				cyl_expected, head_expected, sector,
334 				cylinder, head));
335 	err = tele_seektrack(self, cylinder, head);
336 
337 	for (s = 0; s < self->tele_trackhead.sectors; s++)
338 	{
339 		pos = ftell(self->tele_fp);
340 		err = tele_readsechead(self);
341 		if (err) return err;
342 		MONITOR(("tele_seeksec: c%d h%d s%d at 0x%08lx (%d/%d)\n",
343 				self->tele_sechead.cylinder_id,
344 				self->tele_sechead.head_id,
345 				self->tele_sechead.sector_id, pos,
346 				s, self->tele_trackhead.sectors));
347 		if (self->tele_sechead.sector_id   == sector   &&
348 		    self->tele_sechead.cylinder_id == cyl_expected &&
349 		    self->tele_sechead.head_id     == head_expected)
350 		{
351 			*sseclen = self->tele_sechead.sector_len;
352 /* Sector shorter than expected. Report a data error, and set
353  * request_len to the actual size. */
354 			if (*sseclen < *request_len)
355 			{
356 				*request_len = *sseclen;
357 				err = DSK_ERR_DATAERR;
358 			}
359 /* Sector longer than expected. Report a data error but don't change
360  * request_len */
361 		        else if ((*sseclen) > (*request_len))
362 		        {
363 				err = DSK_ERR_DATAERR;
364 			}
365 			return err;
366 		}
367 		/* Skip over that sector and on to the next */
368 		err = tele_readsec(self, NULL);
369 	}
370 	return DSK_ERR_NOADDR;
371 }
372 
373 
tele_open(DSK_DRIVER * s,const char * filename)374 dsk_err_t tele_open(DSK_DRIVER *s, const char *filename)
375 {
376 	unsigned char header[12];
377 	DC_CHECK(s);
378 
379 	self->tele_fp = fopen(filename, "rb");
380 	if (!self->tele_fp) return DSK_ERR_NOTME;
381 	/* This does use fread not tele_fread, because it's not compressed
382 	 * by the Advanced compression */
383 	if (fread(header, 1, sizeof(header), self->tele_fp) < (int)sizeof(header) ||
384 	    (memcmp(header, "TD", 2) && memcmp(header, "td", 2)))
385 	{
386 		fclose(self->tele_fp);
387 		return DSK_ERR_NOTME;
388 	}
389 	memcpy(self->tele_head.magic, header, 2);
390 	self->tele_head.magic[2] = 0;
391 	self->tele_head.volume_seq  = header[2];
392 	self->tele_head.volume_id   = header[3];
393 	self->tele_head.ver         = header[4];
394 	self->tele_head.datarate    = header[5];
395 	self->tele_head.drivetype   = header[6];
396 	self->tele_head.doubletrack = header[7];
397 	self->tele_head.dosmode     = header[8];
398 	self->tele_head.sides       = header[9];
399 	self->tele_head.crc       = ((tele_word)header[11]) << 8 | header[10];
400 
401 	/* Check header CRC. */
402 	if (teledisk_crc(header, 10) != self->tele_head.crc)
403 	{
404 		fclose(self->tele_fp);
405 		return DSK_ERR_NOTME;
406 	}
407 
408 	/* Advanced compression not supported -- see separate comptele */
409 	if (!strcmp((char *)header, "td"))
410 	{
411 #ifndef WIN16
412 		fprintf(stderr, "LibDsk TD0 driver: Advanced compression not supported\n");
413 #endif
414 		fclose(self->tele_fp);
415 		return DSK_ERR_NOTIMPL;
416 	}
417 	/* Read a comment if there is one */
418 	if (self->tele_head.doubletrack & 0x80)
419 	{
420 		int comment_len, n;
421 		if (tele_fread(self, header, 10))
422 		{
423 			fclose(self->tele_fp);
424 			return DSK_ERR_SYSERR;
425 		}
426 		comment_len = ((int)(header[3])) << 8 | header[2];
427 		self->tele_comment = dsk_malloc(comment_len + sizeof(TELE_COMMENT));
428 		if (!self->tele_comment)
429 		{
430 			fclose(self->tele_fp);
431 			return DSK_ERR_NOMEM;
432 		}
433 		self->tele_comment->year = header[4] + 1900;
434 		self->tele_comment->mon = header[5];
435 		self->tele_comment->day = header[6];
436 		self->tele_comment->hour = header[7];
437 		self->tele_comment->min = header[8];
438 		self->tele_comment->sec = header[9];
439 		if (tele_fread(self, (tele_byte *)self->tele_comment->text, comment_len))
440 		{
441 			fclose(self->tele_fp);
442 			return DSK_ERR_SYSERR;
443 		}
444 		self->tele_comment->text[comment_len] = 0;
445 		for (n = 0; n < comment_len; n++)
446 		{
447 			if (self->tele_comment->text[n] == 0 &&
448 			    self->tele_comment->text[n+1] == 0)
449 			{
450 				self->tele_comment->text[n] = '\r';
451 				self->tele_comment->text[n+1] = '\n';
452 			}
453 		}
454 		dsk_set_comment(s, self->tele_comment->text);
455 	}
456 	self->tele_track_addr[0][0] = ftell(self->tele_fp);
457 
458 	return DSK_ERR_OK;
459 }
460 
tele_creat(DSK_DRIVER * self,const char * filename)461 dsk_err_t tele_creat(DSK_DRIVER *self, const char *filename)
462 {
463 	return DSK_ERR_RDONLY;
464 }
tele_close(DSK_DRIVER * s)465 dsk_err_t tele_close(DSK_DRIVER *s)
466 {
467 	DC_CHECK(s);
468 
469 	if (fclose(self->tele_fp)) return DSK_ERR_SYSERR;
470 	if (self->tele_comment)
471 	{
472 		dsk_free(self->tele_comment);
473 		self->tele_comment = NULL;
474 	}
475 	return DSK_ERR_OK;
476 }
477 
478 
479 
tele_write(DSK_DRIVER * self,const DSK_GEOMETRY * geom,const void * buf,dsk_pcyl_t cylinder,dsk_phead_t head,dsk_psect_t sector)480 dsk_err_t tele_write(DSK_DRIVER *self, const DSK_GEOMETRY *geom,
481                               const void *buf, dsk_pcyl_t cylinder,
482                               dsk_phead_t head, dsk_psect_t sector)
483 {
484 	return DSK_ERR_RDONLY;
485 }
tele_format(DSK_DRIVER * self,DSK_GEOMETRY * geom,dsk_pcyl_t cylinder,dsk_phead_t head,const DSK_FORMAT * format,unsigned char filler)486 dsk_err_t tele_format(DSK_DRIVER *self, DSK_GEOMETRY *geom,
487                                 dsk_pcyl_t cylinder, dsk_phead_t head,
488                                 const DSK_FORMAT *format, unsigned char filler)
489 {
490 	return DSK_ERR_RDONLY;
491 }
tele_secid(DSK_DRIVER * s,const DSK_GEOMETRY * geom,dsk_pcyl_t cylinder,dsk_phead_t head,DSK_FORMAT * result)492 dsk_err_t tele_secid(DSK_DRIVER *s, const DSK_GEOMETRY *geom,
493                                 dsk_pcyl_t cylinder, dsk_phead_t head,
494                                 DSK_FORMAT *result)
495 {
496 	unsigned int n, m;
497 	dsk_err_t err;
498 
499 	DC_CHECK(s);
500 
501 	/* Single-sided? */
502 	if (head > 0 && self->tele_head.sides < 2)
503 	{
504 		return DSK_ERR_NOADDR;
505 	}
506 	err = check_rate(self, geom); if (err) return err;
507 	err = tele_seektrack(self, cylinder, head);
508 	if (err) return err;
509 
510 	m = self->tele_sector % self->tele_trackhead.sectors;
511 	++self->tele_sector;
512 	for (n = 0; n < m; n++)
513 	{
514 		err = tele_readsechead(self);
515 		if (err) return err;
516 		err = tele_readsec(self, NULL);
517 		if (err) return err;
518 	}
519 	err = tele_readsechead(self);
520 	if (result)
521 	{
522 		result->fmt_cylinder = self->tele_sechead.cylinder_id;
523 		result->fmt_head = self->tele_sechead.head_id;
524 		result->fmt_sector = self->tele_sechead.sector_id;
525 		result->fmt_secsize = self->tele_sechead.sector_len;
526 	}
527 	return DSK_ERR_OK;
528 }
tele_xseek(DSK_DRIVER * self,const DSK_GEOMETRY * geom,dsk_pcyl_t cylinder,dsk_phead_t head)529 dsk_err_t tele_xseek(DSK_DRIVER *self, const DSK_GEOMETRY *geom,
530                                 dsk_pcyl_t cylinder, dsk_phead_t head)
531 {
532 	return DSK_ERR_NOTIMPL;
533 }
534 
535 
tele_read(DSK_DRIVER * self,const DSK_GEOMETRY * geom,void * buf,dsk_pcyl_t cylinder,dsk_phead_t head,dsk_psect_t sector)536 dsk_err_t tele_read(DSK_DRIVER *self, const DSK_GEOMETRY *geom,
537                               void *buf, dsk_pcyl_t cylinder,
538                               dsk_phead_t head, dsk_psect_t sector)
539 {
540 	return tele_xread(self, geom, buf, cylinder, head, cylinder,
541 		dg_x_head(geom, head),
542 		dg_x_sector(geom, head, sector), geom->dg_secsize, NULL);
543 }
544 
545 
tele_xread(DSK_DRIVER * s,const DSK_GEOMETRY * geom,void * buf,dsk_pcyl_t cylinder,dsk_phead_t head,dsk_pcyl_t cyl_expected,dsk_phead_t head_expected,dsk_psect_t sector,size_t sector_size,int * deleted)546 dsk_err_t tele_xread(DSK_DRIVER *s, const DSK_GEOMETRY *geom, void *buf,
547                               dsk_pcyl_t cylinder, dsk_phead_t head,
548                               dsk_pcyl_t cyl_expected,
549 			      dsk_phead_t head_expected,
550                               dsk_psect_t sector, size_t sector_size,
551 			      int *deleted)
552 {
553 	dsk_err_t err = DSK_ERR_OK;
554 	unsigned char *secbuf;
555 	size_t len = sector_size;
556 	size_t sseclen;
557 	int want_deleted = 0;
558 	int try_again = 0;
559 
560 	DC_CHECK(s);
561 
562 	/* Single-sided? */
563 	if (head > 0 && self->tele_head.sides < 2)
564 	{
565 		return DSK_ERR_NOADDR;
566 	}
567 
568 /* Check that the requested data rate is compatible. */
569 	err = check_rate(self, geom); if (err) return err;
570 	if (deleted && *deleted) want_deleted = 4;
571 	do
572 	{
573 		err = tele_seeksec(self, geom, cylinder, head,
574 			cyl_expected, head_expected,
575 			sector, &len, &sseclen);
576 /* Are we retrying because we are looking for deleted data and found
577  * nondeleted or vice versa?
578  *
579  * If so, and we have run out of sectors in this track, AND we are on head 0,
580  * AND the disc has 2 heads, AND we are in multitrack mode, then look on head 1
581  * as well. Amazing.
582  * */
583                 if (try_again == 1 && err == DSK_ERR_NOADDR)
584                 {
585                         err = DSK_ERR_NODATA;
586                         if ((!geom->dg_nomulti) && head == 0 &&
587                                   self->tele_head.sides > 1)
588                         {
589                                 head++;
590                                 sector = geom->dg_secbase;
591                                 continue;
592                         }
593                 }
594 		try_again = 0;
595 		if (err == DSK_ERR_NOADDR) self->tele_sector = 0;
596 		if (err != DSK_ERR_DATAERR && err != DSK_ERR_OK)
597 			return err;
598 		/* We have the sector. But does it contain deleted data? */
599 		if (deleted) *deleted = 0;
600 		if ((self->tele_sechead.syndrome & 4) != want_deleted)
601 		{
602 			if (geom->dg_noskip)
603 			{
604 				if (deleted) *deleted = 1;
605 			}
606 			else
607 			{
608 				try_again = 1;
609 				++sector;
610 				continue;
611 			}
612 		}
613 		/* Read the whole sector into the buffer (if it's there) */
614 		secbuf = dsk_malloc(sseclen);
615 		if (!secbuf) return DSK_ERR_NOMEM;
616 		err = tele_readsec(self, secbuf);
617 		if (sseclen > sector_size) sseclen = sector_size;
618 		memcpy(buf, secbuf, sseclen);
619 		dsk_free(secbuf);
620 		err = DSK_ERR_OK;
621 		if (self->tele_sechead.syndrome & 2)  err = DSK_ERR_DATAERR;
622 		if (self->tele_sechead.syndrome & 32) err = DSK_ERR_NODATA;
623 
624 	}
625 	while(try_again);
626 
627 	return err;
628 }
629 
630 
tele_xwrite(DSK_DRIVER * self,const DSK_GEOMETRY * geom,const void * buf,dsk_pcyl_t cylinder,dsk_phead_t head,dsk_pcyl_t cyl_expected,dsk_phead_t head_expected,dsk_psect_t sector,size_t sector_size,int deleted)631 dsk_err_t tele_xwrite(DSK_DRIVER *self, const DSK_GEOMETRY *geom, const void *buf,
632                               dsk_pcyl_t cylinder, dsk_phead_t head,
633                               dsk_pcyl_t cyl_expected, dsk_phead_t head_expected,
634                               dsk_psect_t sector, size_t sector_size, int deleted)
635 {
636 	return DSK_ERR_RDONLY;
637 }
638 
tele_trackids(DSK_DRIVER * self,const DSK_GEOMETRY * geom,dsk_pcyl_t cylinder,dsk_phead_t head,dsk_psect_t * count,DSK_FORMAT ** result)639 dsk_err_t tele_trackids(DSK_DRIVER *self, const DSK_GEOMETRY *geom,
640                             dsk_pcyl_t cylinder, dsk_phead_t head,
641                             dsk_psect_t *count, DSK_FORMAT **result)
642 {
643 	return DSK_ERR_NOTIMPL;
644 }
645 
tele_status(DSK_DRIVER * self,const DSK_GEOMETRY * geom,dsk_phead_t head,unsigned char * result)646 dsk_err_t tele_status(DSK_DRIVER *self, const DSK_GEOMETRY *geom,
647                   dsk_phead_t head, unsigned char *result)
648 {
649 	return DSK_ERR_NOTIMPL;
650 }
651 
tele_option_enum(DSK_DRIVER * self,int idx,char ** optname)652 dsk_err_t tele_option_enum(DSK_DRIVER *self, int idx, char **optname)
653 {
654 	return DSK_ERR_NOTIMPL;
655 }
656 
tele_option_set(DSK_DRIVER * self,const char * optname,int value)657 dsk_err_t tele_option_set(DSK_DRIVER *self, const char *optname, int value)
658 {
659 	return DSK_ERR_NOTIMPL;
660 }
661 
tele_option_get(DSK_DRIVER * self,const char * optname,int * value)662 dsk_err_t tele_option_get(DSK_DRIVER *self, const char *optname, int *value)
663 {
664 	return DSK_ERR_NOTIMPL;
665 }
666 
667 /* Don't bother to implement this one. Fall back on the standard version. */
tele_getgeom(DSK_DRIVER * self,DSK_GEOMETRY * dg)668 dsk_err_t tele_getgeom(DSK_DRIVER *self, DSK_GEOMETRY *dg)
669 {
670 	return DSK_ERR_NOTIMPL;
671 }
672