Пример #1
0
STDMETHODIMP CLibrary::pcwgeom(VARIANT *buffer, IGeometry **geom)
{
	unsigned char *header;
	DSK_GEOMETRY dg;

	HRESULT hr = GetBuffer(buffer, &header, 512);
	if (FAILED(hr)) return hr;
	hr = MapError(dg_pcwgeom(&dg, header));
	dsk_free(header);
	if (!FAILED(hr)) hr = CGeometry::CreateInstance(geom);
	if (!FAILED(hr)) dg_to_g(&dg, *geom);
	return hr;
}
Пример #2
0
/* Probe the geometry of a disc. This will always use the boot sector. */
dsk_err_t dsk_defgetgeom(DSK_DRIVER *self, DSK_GEOMETRY *geom)
{
	DSK_FORMAT secid;
	dsk_err_t e;
	unsigned char *secbuf;
	unsigned long dsksize;
	dsk_rate_t oldrate;

        if (!self || !geom || !self->dr_class) return DSK_ERR_BADPTR;

	memset(geom, 0, sizeof(*geom));

	/* Switch to a minimal format */
	e = dg_stdformat(geom, FMT_180K, NULL, NULL);
	if (e) return e;
	/* Allocate buffer for boot sector (512 bytes) */
	secbuf = dsk_malloc(geom->dg_secsize);
	if (!secbuf) return DSK_ERR_NOMEM;


	/* Check for CPC6128 type discs. Also probe the data rate; if we get a 
	 * missing address mark, then the data rate is wrong.
	 */ 
	e = dg_stdformat(geom, FMT_180K, NULL, NULL);
	if (e) return e;
	e = dsk_lsecid(self, geom, 0, &secid);
	/* Check for HD discs */
	if (e == DSK_ERR_NOADDR)
	{
		geom->dg_datarate = RATE_HD;
		e = dsk_lsecid(self, geom, 0, &secid);
	}
	/* Check for DD 5.25" disc in HD 5.25" drive */
	if (e == DSK_ERR_NOADDR)
	{
		geom->dg_datarate = RATE_DD;
		e = dsk_lsecid(self, geom, 0, &secid);
	}
	/* Check for BBC micro DFS discs (FM encoded) */
	if (e == DSK_ERR_NOADDR)
	{
		e = dg_stdformat(geom, FMT_BBC100, NULL, NULL);
		if (!e) e = dsk_lsecid(self, geom, 0, &secid);
	}
	if (!e)	/* We could get the sector ID */
	{
		if ((secid.fmt_sector & 0xF0) == 0x10 &&
		     secid.fmt_secsize == 512) 	/* Ampro 40 track double sided */
		{
			dsk_free(secbuf);
			e = dg_stdformat(geom, FMT_AMPRO400D, NULL, NULL);
			if (!e) set_fixed_fs(self, FMT_AMPRO400D);
			return e;
		}
		if ((secid.fmt_sector & 0xC0) == 0x40 &&
		     secid.fmt_secsize == 512) 	/* CPC system */
		{
			dsk_free(secbuf);
			e = dg_stdformat(geom, FMT_CPCSYS, NULL, NULL);
			if (!e) set_pcw_fs(self, geom, boot_cpcsys);
			return e;
		}
		if ((secid.fmt_sector & 0xC0) == 0xC0 &&
		     secid.fmt_secsize == 512)	/* CPC data */
		{
			dsk_free(secbuf);
			e = dg_stdformat(geom, FMT_CPCDATA, NULL, NULL);
			if (!e) set_pcw_fs(self, geom, boot_cpcdata);
			return e;
		}
		/* [v0.6.0] Handle discs with non-512 byte sectors */
		if (secid.fmt_secsize == 256)
		{
			if (geom->dg_fm)	/* BBC Micro FM floppy */
			{
				unsigned int tot_sectors;
				e = dsk_lread(self, geom, secbuf, 1);

				tot_sectors = secbuf[7] + 256 * (secbuf[6] & 3);
			
/* If disc is FM recorded but does not have 400 or 800 sectors, fail. */	
				if (e == DSK_ERR_OK && tot_sectors != 400 && tot_sectors != 800) e = DSK_ERR_BADFMT; 

				geom->dg_cylinders = tot_sectors / (geom->dg_heads * geom->dg_sectors);	
				dsk_free(secbuf);
				return e;
			}
			else	/* MFM */
			{
				e = dg_stdformat(geom, FMT_ACORN160, NULL, NULL);
				if (!e) e = dsk_lread(self, geom, secbuf, 0);
				if (e)
				{
					dsk_free(secbuf);
					return DSK_ERR_BADFMT;
				}
				/* Acorn ADFS discs have a size in sectors at 0xFC in the
				 * first sector */
				dsksize = secbuf[0xFC] + 256 * secbuf[0xFD] +
					65536L * secbuf[0xFE];
				dsk_free(secbuf);
				if (dsksize ==  640) return dg_stdformat(geom, FMT_ACORN160, NULL, NULL);
				if (dsksize == 1280) return dg_stdformat(geom, FMT_ACORN320, NULL, NULL);
				if (dsksize == 2560) return dg_stdformat(geom, FMT_ACORN640, NULL, NULL);
				/* The DOS Plus boot floppy has 2720 here for
				 * some reason */
				if (dsksize == 2720) return dg_stdformat(geom, FMT_ACORN640, NULL, NULL);
				return DSK_ERR_BADFMT;
			}
		}
		if (secid.fmt_secsize == 1024)
		{
			dsk_rate_t rate;
			/* Ampro 80 track double sided */
			if ((secid.fmt_sector & 0xF0) == 0x10)
			{
				dsk_free(secbuf);
				e = dg_stdformat(geom, FMT_AMPRO800, NULL, NULL);
				if (!e) set_fixed_fs(self, FMT_AMPRO800);
				return e;	
			}
			/* Save the data rate, which we know to be correct */
			rate = geom->dg_datarate;

			dsk_free(secbuf);
			/* Switch to a format with 1k sectors */
			if (geom->dg_datarate == RATE_HD)
				e = dg_stdformat(geom, FMT_ACORN1600, NULL, NULL);	
			else	e = dg_stdformat(geom, FMT_ACORN800, NULL, NULL);
			if (e) return e;
			/* And restore it. */
			geom->dg_datarate = rate;
			/* Allocate buffer for boot sector (1k bytes) */
			secbuf = dsk_malloc(geom->dg_secsize);
			if (!secbuf) return DSK_ERR_NOMEM;
			e = dsk_lread(self, geom, secbuf, 0);
			if (!e)
			{
				dsksize = secbuf[0xFC] + 256 * secbuf[0xFD] +
					65536L * secbuf[0xFE];
				/* Check for 1600k-format */
				if (geom->dg_datarate == RATE_HD)
				{
				/* XXX Need a better check for Acorn 1600k */
					dsk_free(secbuf);
					return DSK_ERR_OK;
				}
				/* Check for D-format magic */
				if (dsksize == 3200) 
				{
					dsk_free(secbuf);
					return DSK_ERR_OK;
				}
				/* Check for E-format magic */
				if (secbuf[4] == 10 && secbuf[5] == 5 &&
				    secbuf[6] == 2  && secbuf[7] == 2)
				{
					dsk_free(secbuf);
					return DSK_ERR_OK;
				}
			}
			/* Check for DOS Plus magic. DOS Plus has sectors
			 * based at 1, not 0. */
			geom->dg_secbase = 1;
			e = dsk_lread(self, geom, secbuf, 0);
			if (!e)
			{
				if (secbuf[0] == 0xFD && 
				    secbuf[1] == 0xFF && 
				    secbuf[2] == 0xFF)
				{
					dsk_free(secbuf);
					return DSK_ERR_OK;
				}
			}
			dsk_free(secbuf);
			return DSK_ERR_BADFMT;
		}	
		/* Can't handle other discs with non-512 sector sizes. */
		if ((secid.fmt_secsize != 512))
		{
			dsk_free(secbuf);
			return DSK_ERR_BADFMT;
		}
	}
	/* If the driver couldn't do a READ ID call, then ignore it */
	if (e == DSK_ERR_NOTIMPL) e = DSK_ERR_OK;
	/* Try to ID the disc from its boot sector */
	if (!e) e = dsk_lread(self, geom, secbuf, 0);
	if (e) 
	{ 	
		dsk_free(secbuf);
		return e; 
	}

	/* Save the data rate, because what we have is right, and what's
	 * in the sector might not be. */
	oldrate = geom->dg_datarate;	
	/* We have the sector. Let's try to guess what it is */
	e = dg_dosgeom(geom, secbuf);	
	if (e == DSK_ERR_OK)
	{
		set_dos_fs(self, geom, secbuf + 11);
	}
	if (e == DSK_ERR_BADFMT)
	{
/* If dg_pcwgeom succeeded, we have a CP/M filesystem with known parameters */
		e = dg_pcwgeom(geom, secbuf);
		if (e == DSK_ERR_OK)
	   		set_pcw_fs(self, geom, secbuf);
	}
	if (e == DSK_ERR_BADFMT) 
	{
		e = dg_aprigeom(geom, secbuf);
		if (e == DSK_ERR_OK)
		{
			set_dos_fs(self, geom, secbuf + 80);
		}
	}
	if (e == DSK_ERR_BADFMT) 
	{
		e = dg_cpm86geom(geom, secbuf);
		if (e == DSK_ERR_OK)
			set_cpm86_fs(self, geom, secbuf);
	}
/* Check for Oups Discovery 1 */
	if (e == DSK_ERR_BADFMT) 
	{
		e = dg_opusgeom(geom, secbuf);
/*		if (e == DSK_ERR_OK)
			set_opus_fs(self, geom, secbuf); */
	}
	geom->dg_datarate = oldrate;
	
	dsk_free(secbuf);
	return e;
}
Пример #3
0
dsk_err_t p3fs_mkfs(PLUS3FS *pfs, const char *name, const char *type,
	       const char *compression, unsigned char *boot_spec, 
	       int timestamped)
{
	dsk_err_t err;
	dsk_ltrack_t track;
	int heads, dirent;
	char msg[50];
	PLUS3FS fs;

	if (pfs == NULL)
	{
		return DSK_ERR_BADPTR;
	}
	fs = malloc(sizeof(PLUS3FS_IMPL));
	*pfs = fs;
	memset(fs, 0, sizeof(*fs));

	heads = (boot_spec[1] & 3) ? 2 : 1;
	/* Work out how big the buffers for the boot sector and directory
	 * need to be. Start by getting the drive geometry straight. */
	err = dg_pcwgeom(&fs->geom, boot_spec);
	if (err) return err;

	/* Now the CP/M filesystem parameters */
	fs->blocksize       = 128 << (boot_spec[6]);	/* Block size */
	fs->offset          = boot_spec[5];		/* Reserved tracks */
	fs->maxtrack        = heads * boot_spec[2];
	fs->dirblocks       = boot_spec[7];
	fs->nextblock       = fs->dirblocks;		/* First free block */
	fs->maxdir          = (fs->dirblocks * fs->blocksize) / 32;

	/* Max block number is number of usable sectors divided by 
	 * sectors per block */
	fs->maxblock = ((fs->maxtrack - fs->offset) * fs->geom.dg_sectors)
			/ (fs->blocksize / fs->geom.dg_secsize);
	--fs->maxblock;

	if (fs->maxblock < 256) fs->exm = (fs->blocksize / 1024) - 1;
	else			fs->exm = (fs->blocksize / 2048) - 1;

	/* Allocate the buffers */
	fs->bootsec = malloc(fs->geom.dg_secsize + 32 * fs->maxdir);
	if (!fs->bootsec) return DSK_ERR_NOMEM;
	fs->cpmdir = fs->bootsec + fs->geom.dg_secsize;
	memset(fs->cpmdir, 0xE5, 32 * fs->maxdir);

	fs->timestamped = timestamped;
	if (timestamped)
	{
		for (dirent = 3; dirent < fs->maxdir; dirent += 4)
		{
			memset(fs->cpmdir + 32 * dirent, 0, 32);
			fs->cpmdir[32 * dirent] = 0x21;
		}
	}
	memset(fs->bootsec, 0xe5, fs->geom.dg_secsize);
	memcpy(fs->bootsec, boot_spec, 10);

	/* Create a new DSK file */
	err = dsk_creat(&fs->drive, name, type, compression);
	if (err) return err;

	/* Format all its tracks */
	for (track = 0; track < fs->maxtrack; track++)
	{
		sprintf(msg, "Formatting track %d/%d", track, fs->maxtrack);
		dsk_report(msg);
		if (!err) err = dsk_alform(fs->drive, &fs->geom, track, 0xe5);
	}
	dsk_report("Writing boot sector");
	if (!err) err = dsk_lwrite(fs->drive, &fs->geom, fs->bootsec, 0);
	dsk_report_end();
	return err;
}