mirror of
https://github.com/peteratebs/rtfsprorelease.git
synced 2025-06-19 09:15:37 -04:00
282 lines
11 KiB
C
282 lines
11 KiB
C
/*
|
|
* EBS - RTFS (Real Time File Manager)
|
|
*
|
|
* Copyright EBS Inc. 2000
|
|
* All rights reserved.
|
|
* This code may not be redistributed in source or linkable object form
|
|
* without the consent of its author.
|
|
*/
|
|
#include "rtfs.h"
|
|
#if (!RTFS_CFG_READONLY) /* Excluded from build if read only */
|
|
|
|
/***************************************************************************
|
|
PC_PARTITION_MEDIA - Write partition table
|
|
|
|
BOOLEAN pc_partition_media(byte *path, struct mbr_specification *pmbrspec)
|
|
|
|
Description
|
|
|
|
Given a drive ID and one or more mbr specifications, write the information in the
|
|
mbr specification to the media.
|
|
|
|
If the underlying device driver provides dynamic partitioning instructions then pmbrspec
|
|
is ignored and is provided by the device driver.
|
|
|
|
Typically one specification structure is provided. This is used to initialize the primary boot record.
|
|
|
|
struct mbr_specification {
|
|
int device_mbr_count - Only used in the first specification. This must contain 1 if there is only one
|
|
partition table. If extended partitons required this must be 1 plus the
|
|
number of EBR (extended boot record) specifications to follow
|
|
dword mbr_sector_location - Location of this primary or extended boot record. (0 for the primary)
|
|
- An array of four structures specifying the filed for this record
|
|
struct mbr_entry_specification entry_specifications[4];
|
|
where (struct mbr_entry_specification) contains the following fields:
|
|
dword partition_start;
|
|
dword partition_size;
|
|
byte partition_type;
|
|
byte partition_boot;
|
|
|
|
If extended partitions are desired then one additional mbr_specification structure is required per virtual
|
|
volume in the extended partition.
|
|
|
|
If the user is providing the specifications they must be provided in a contiguous array pointed to by pmbrspec.
|
|
|
|
If the device driver is dynamically providing the specifications it will be called once for each specification it
|
|
needs, passing the index number as an argument.
|
|
|
|
|
|
Returns
|
|
Returns TRUE if it was able to perform the operation otherwise FALSE.
|
|
|
|
errno is set to one of the following
|
|
0 - No error
|
|
PEINVALIDDRIVEID- Drive component is invalid
|
|
PEINVALIDPARMS - Inconsistent or missing parameters
|
|
PEIOERRORWRITE - Error writing partition table
|
|
An ERTFS system error
|
|
****************************************************************************/
|
|
|
|
|
|
static BOOLEAN partition_provided(DDRIVE *pdr, DEV_GEOMETRY *pgeometry,struct mbr_specification *pmbrspec);
|
|
|
|
BOOLEAN _pc_get_media_parms(DDRIVE *pdr, PDEV_GEOMETRY pgeometry);
|
|
|
|
#if (INCLUDE_CS_UNICODE)
|
|
BOOLEAN pc_partition_media_cs(byte *path , struct mbr_specification *pmbrspec, int use_charset)
|
|
#else
|
|
BOOLEAN pc_partition_media(byte *path, struct mbr_specification *pmbrspec)
|
|
#endif
|
|
{
|
|
DEV_GEOMETRY geometry;
|
|
DDRIVE *pdr;
|
|
void *devhandle;
|
|
BOOLEAN ret_val;
|
|
CHECK_MEM(BOOLEAN, 0)
|
|
rtfs_clear_errno(); /* pc_partition_media: clear error status */
|
|
if (!path || !pmbrspec) /* Make sure it s a valid drive number */
|
|
{
|
|
rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__);
|
|
return(FALSE);
|
|
}
|
|
pdr = check_drive_by_name(path, CS_CHARSET_ARGS);
|
|
if (!pdr)
|
|
return(FALSE);
|
|
devhandle = pdr->pmedia_info->devhandle;
|
|
/* Get media size, we ignore the size values but use heads and sectors per track. _pc_get_media_parms returns valid
|
|
values (either real or synthesized) */
|
|
if (!_pc_get_media_parms(pdr, &geometry))
|
|
ret_val = FALSE;
|
|
else
|
|
ret_val = partition_provided(pdr,&geometry,pmbrspec);
|
|
|
|
rtfs_release_media_and_buffers(pdr->driveno);
|
|
if (devhandle) /* re-mount the media, re-read partition tables */
|
|
pc_rtfs_media_remount(devhandle);
|
|
return(ret_val);
|
|
}
|
|
|
|
static BOOLEAN pc_write_mbr_spec(DDRIVE *pdr, PDEV_GEOMETRY pgeometry, struct mbr_specification *pspec);
|
|
|
|
/* static BOOLEAN partition_provided(DDRIVE *pdr, DEV_GEOMETRY *pgeometry,struct mbr_specification *pmbrspec)
|
|
|
|
Format and write master boot record and any extended boot records.
|
|
|
|
The mbr specifications were provided by the user
|
|
*/
|
|
|
|
static BOOLEAN partition_provided(DDRIVE *pdr, DEV_GEOMETRY *pgeometry,struct mbr_specification *pmbrspec)
|
|
{
|
|
if (!pmbrspec)
|
|
{
|
|
rtfs_set_errno(PEINVALIDPARMS, __FILE__, __LINE__);
|
|
return(FALSE);
|
|
}
|
|
if (!pmbrspec->device_mbr_count) /* device_mbr_count == 0 is a paramater option to clear the MBR */
|
|
return(pc_write_mbr_spec(pdr, pgeometry, 0));
|
|
else
|
|
{ /* primary mbr specified */
|
|
if (!pc_write_mbr_spec(pdr, pgeometry, pmbrspec))
|
|
return(FALSE);
|
|
/* Check if more mbrs to follow, if this is true then the caller is partitioning the
|
|
drive with extended partitions. Each of these additional mbrs must reside inside an extended partition */
|
|
if (pmbrspec->device_mbr_count > 1)
|
|
{
|
|
int extended_mbr_count, mbr_index;
|
|
extended_mbr_count = pmbrspec->device_mbr_count-1;
|
|
pmbrspec++;
|
|
for (mbr_index = 1; mbr_index <= extended_mbr_count; mbr_index++, pmbrspec++)
|
|
{ /* write extended mbrs */
|
|
if (!pc_write_mbr_spec(pdr, pgeometry, pmbrspec))
|
|
return(FALSE);
|
|
}
|
|
}
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
static word pack_cylinder_field(word cyl, word sec);
|
|
static word _lba_to_cylinder(dword lba_val, PDEV_GEOMETRY pgeometry);
|
|
static void mbr_entry_specification_to_mbr(byte *ptable,PDEV_GEOMETRY pgeometry, struct mbr_specification *pspec);
|
|
|
|
static BOOLEAN pc_write_mbr_spec(DDRIVE *pdr, PDEV_GEOMETRY pgeometry, struct mbr_specification *pspec)
|
|
{
|
|
BLKBUFF *pscratch;
|
|
BLKBUFF bbuf_scratch; /* Used by pc_sys_sector build a buffer structure with core from the driver level */
|
|
BOOLEAN ret_val;
|
|
dword mbr_sector_location;
|
|
/* Grab some working space - pass the drive parameter so it allocates a sector buffer */
|
|
pscratch = pc_sys_sector(pdr,&bbuf_scratch);
|
|
if (!pscratch)
|
|
return(FALSE); /* pc_scratch_blk set errno */
|
|
ret_val = FALSE;
|
|
rtfs_memset(pscratch->data, 0, pgeometry->bytespsector);
|
|
|
|
/* Now copy the partition information into the buffer */
|
|
/* The info starts at buf[1be] */
|
|
if (pgeometry && pspec) /* if they are zero just clear the partition table */
|
|
{
|
|
mbr_entry_specification_to_mbr((pscratch->data + 0x1be), pgeometry, pspec);
|
|
mbr_sector_location = pspec->mbr_sector_location;
|
|
#if (INCLUDE_WINDEV)
|
|
if (pdr->driveno==('P'-'A')) /* P: is the host drive */
|
|
{
|
|
rtfs_print_one_string((byte *)"INCLUDE_WINDEV is enabled", PRFLG_NL);
|
|
rtfs_print_one_string((byte*)"Use private boot signature, call hackwin7 to make the volume accessable on windows", PRFLG_NL);
|
|
fr_WORD((pscratch->data + 510), 0xAA66);
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
mbr_sector_location = 0; /* Clearing the MBR. mbr_specification is not valid */
|
|
/* write to pspec->mbr_sector_location */
|
|
if (raw_devio_xfer(pdr, mbr_sector_location, pscratch->data, 1, TRUE, FALSE))
|
|
ret_val = TRUE;
|
|
else
|
|
{
|
|
if (!get_errno())
|
|
rtfs_set_errno(PEIOERRORWRITE, __FILE__, __LINE__); /* pc_partition_media: write failed */
|
|
}
|
|
pc_free_sys_sector(pscratch);
|
|
return(ret_val);
|
|
}
|
|
|
|
static word pack_cylinder_field(word cyl, word sec)
|
|
{
|
|
word utemp, utemp2;
|
|
utemp = (word)((cyl & 0xff) << 8); /* Low 8 bit to hi bite */
|
|
utemp2 = (word)((cyl >> 2) & 0xc0); /* Hi 2 bits to bits 6 + 7 */
|
|
utemp |= utemp2;
|
|
utemp |= sec;
|
|
return(utemp);
|
|
}
|
|
|
|
/* Given a 32 bit sector address, divide it by (heads * secptrack) to convert it to the cylinder number.
|
|
If the result is > 1023, truncate it to 1023.
|
|
The value will be correct if "lba_val" is an exact multiple of (heads * secptrack), and <= 1023, otherwise it won't */
|
|
static word _lba_to_cylinder(dword lba_val, PDEV_GEOMETRY pgeometry)
|
|
{
|
|
dword ltemp;
|
|
|
|
if (pgeometry->dev_geometry_heads == 0 || pgeometry->dev_geometry_secptrack == 0) /* Won't happen */
|
|
ltemp = 1023;
|
|
else
|
|
{
|
|
ltemp = lba_val;
|
|
ltemp /= pgeometry->dev_geometry_heads;
|
|
ltemp /= pgeometry->dev_geometry_secptrack;
|
|
if (ltemp > 1023)
|
|
ltemp = 1023;
|
|
}
|
|
return((word) (ltemp & 0xffff) );
|
|
}
|
|
|
|
/* Convert an lba value to hcn.
|
|
cyl is between 1 and 123
|
|
sec is the same as in the geomerty stucture (1 <= sec <= 63)_
|
|
head is between the same as in the geomerty stucture (0 <= head <= 255)_
|
|
|
|
Note: sec and head will always be correct. cyl will be truncated to 1023 if sector is too
|
|
large to represent as (1023 * 63 * 255)
|
|
*/
|
|
static void _lba_to_chs(dword sector, PDEV_GEOMETRY pgeometry, word *cyl, word *sec, byte *head)
|
|
{
|
|
*cyl = _lba_to_cylinder(sector, pgeometry);
|
|
*sec = (word) (pgeometry->dev_geometry_secptrack & 0x3f);
|
|
*head = (byte) (pgeometry->dev_geometry_heads & 0xff);
|
|
|
|
}
|
|
|
|
|
|
static void mbr_entry_specification_to_mbr(byte *ptable,PDEV_GEOMETRY pgeometry, struct mbr_specification *pspec)
|
|
{
|
|
int i;
|
|
word cyl, sec;
|
|
byte head;
|
|
byte *pentry;
|
|
|
|
/* The table has four 16 bit partition table entries followed by the signature
|
|
Each entry in the table has the followin fields
|
|
byte Name width
|
|
0 boot 1
|
|
1 s_head 1
|
|
2 s_cyl 2
|
|
4 p_typ 1
|
|
5 e_head 1
|
|
6 e_cyl; 2
|
|
8 r_sec 4
|
|
12 p_size 4
|
|
*/
|
|
|
|
pentry = ptable;
|
|
for(i = 0; i < 4; i++)
|
|
{
|
|
if (pspec->entry_specifications[i].partition_size)
|
|
{
|
|
*pentry = pspec->entry_specifications[i].partition_boot;
|
|
/* calculate valid values for starting cyl, sec. head */
|
|
_lba_to_chs(pspec->entry_specifications[i].partition_start, pgeometry, &cyl, &sec, &head);
|
|
*(pentry+1) = head;
|
|
fr_WORD((byte *)(pentry+2), pack_cylinder_field(cyl, sec));
|
|
*(pentry+4) = pspec->entry_specifications[i].partition_type;
|
|
/* calculate partition end and valid values for ending cyl, sec. head */
|
|
{ dword partition_end;
|
|
partition_end = pspec->entry_specifications[i].partition_start + pspec->entry_specifications[i].partition_size - 1;
|
|
_lba_to_chs(partition_end, pgeometry, &cyl, &sec, &head);
|
|
}
|
|
*(pentry+5) = head;
|
|
fr_WORD(pentry+6, pack_cylinder_field(cyl, sec));
|
|
fr_DWORD(pentry+8, pspec->entry_specifications[i].partition_start);
|
|
fr_DWORD(pentry+12, pspec->entry_specifications[i].partition_size);
|
|
}
|
|
pentry += 16;
|
|
}
|
|
/* Now for the signature */
|
|
fr_WORD(ptable+64, 0xAA55);
|
|
}
|
|
|
|
|
|
|
|
#endif /* Exclude from build if read only */
|