#ifndef LIB_FDISK_H
#define LIB_FDISK_H

/* Function prototypes and data type definitions for the hard drive */
/* partitioning library.                                            */
/*                                                                  */
/* Michael Fulbright <msf@redhat.com>  June 1997                    */


/* some includes we'll need for our data types */
#include <linux/hdreg.h>
#include <limits.h>

/* stuff to handle errors */
extern int fdisk_nerr;
extern char *fdisk_errlist[];

/* internal defines */

#include "constraints.h"

/* some useful defines */
#define SECTORSIZE 512

/* offsets within the sector containing partition table of different values */
#define PARTTBLOFF 446    /* start of partition table entries */
#define PARTMAGOFF 510    /* offset of magic bytes */
#define PARTMAGIC  0x55aa /* magic */

/* partition types */
#define UNALLOCATED_PARTITION                   0x00
#define DOS_PRIMARY_lt32MEG_PARTITION           0x04
#define DOS_EXTENDED_PARTITION                  0x05
#define DOS_PRIMARY_gt32MEG_PARTITION           0x06
#define WIN_VFAT32_PARTITION                    0x0b
#define LINUX_LEGACY_PARTITION                  0x81
#define LINUX_SWAP_PARTITION                    0x82
#define LINUX_NATIVE_PARTITION                  0x83
#define LINUX_EXTENDED_PARTITION                0x85

/* use > 255 values for non-physical partitions (remote) */
#define NFS_REMOTE_PARTITION                    0x1000

/* some libfdisk errors */
#define FDISK_ERR_SYSTEM      -1       /* system error, use errno       */
#define FDISK_SUCCESS          0       /* Good job no problems          */
#define FDISK_ERR_USERABORT    1       /* user aborted                  */

#define FDISK_ERR_BADNUM      10       /* bad numeric value passed      */
#define FDISK_ERR_BADPTR      11       /* bad ptr value passed          */
#define FDISK_ERR_BADMAGIC    12       /* partition table has bad magic */

#define FDISK_ERR_TWOEXT      15       /* two extended partitions!      */
#define FDISK_ERR_TWOLOG      16       /* two LP per EPT!               */
#define FDISK_ERR_CORRUPT     17       /* something in PT is corrupt    */

#define FDISK_ERR_NOFREE      20       /* unable to allocate a resource */
#define FDISK_ERR_NOFREEPRIM  21       /* unable to allocate a primary  */
#define FDISK_ERR_NOFREEEXT   22       /* unable to allocate a extended */
#define FDISK_ERR_INUSE       23       /* resource currently in use     */
#define FDISK_ERR_NOPEP       24       /* No Primary Extended Partition */
#define FDISK_ERR_CNSTRFAIL   30       /* constraint(s) failed          */

/* Limits for each constraint type (some like 'type' doesnt make sense) */
#define FDISK_START_MIN            0
#define FDISK_START_MAX     UINT_MAX
#define FDISK_SIZE_MIN             1
#define FDISK_SIZE_MAX      UINT_MAX
#define FDISK_ENDCYL_MIN           0
#define FDISK_ENDCYL_MAX    UINT_MAX
#define FDISK_OFFSET_MIN           0
#define FDISK_OFFSET_MAX    UNIT_MAX
#define FDISK_DRIVE_MIN            0
#define FDISK_DRIVE_MAX           64

/* types of partitions, used by allocation routines internally */
#define PRIMARY           1
#define LOGICAL           2
#define PRIMARY_EXTENDED  4
   
/* some low-level data types */
/* these are used only to manipulate sectors read off the disk */
/* ASAP it is converted from this form into a higher level form*/
/* which is easier to manipulate                               */
struct raw_PartitionEntry {
    unsigned char active;
    unsigned char start_head;
    unsigned char start_sec;
    unsigned char start_cyl;
    unsigned char type;
    unsigned char end_head;
    unsigned char end_sec;
    unsigned char end_cyl;
    unsigned int  start;
    unsigned int  size;
};

struct raw_PartitionTable {
    struct raw_PartitionEntry entry[4];
};

/* make these easier to type! */
typedef struct raw_PartitionTable  RawPartitionTable;
typedef struct raw_PartitionEntry  RawPartition;

/* THESE ARE THE NEW HIGH LEVEL STRUCTURES */
/* IN PROCESS OF RECODING                  */

/*                                                                  */
/* A partition defines a portion of the disk                        */
/*                                                                  */
/* Partitions have various attributes:                              */
/*     size & start -> define region of space used                  */
/*     offset       -> defined start of data inside partition       */
/*                     used for logical partititons in extended     */
/*     type         -> defines which OS(s) are using partition      */
/*     active       -> can we boot from the partition. used by DOS  */
/*     num          -> Partition #, start at 1. Logical start at 5  */
/*     drive        -> Which drive can/is the partition on          */
/*     status       -> Various flags used when allocating partitions*/
/*     immutable    -> If non-zero, do nothing to disturb any of the*/
/*                     above values. Used to preserve existing part.*/
/*                                                                  */
/* Partitions DO NOT have to actually define a space on disk used by*/
/* an OS! Can be used (internally by this code) to represent a region*/
/* which is free for allocation, but cannot be moved. Usually this  */
/* code tries to rearrange partitions to keep free space in one big */
/* contiguous region. Extended/logical partitions, because of how   */
/* they work, can't always be moved around. So it is possible to    */
/* have a extended/logical partition pair which exists but is not   */
/* allocated to a partition type other than 0. This space is prime  */
/* for allocating to the next requested partition.                  */
/*                                                                  */

struct fdisk_partition {
    Constraint     num;        /* for /dev/hda1, num = 1 */
    Constraint     start;      /* start sector, from start of drive */
    Constraint     size;       /* size in sectors */
    Constraint     endcyl;     /* ending cylinder, exclusive w start*/
    Constraint     offset;
    Constraint     type;
    Constraint     active;
    DriveSet       drive;

    unsigned int   status;     /* used to store info for allocating */
    unsigned int   immutable;  /* if non-zero, do not touch anything*/
};

typedef struct fdisk_partition                Partition;


/* status values */
/* UNAVAILABLE means work has to be done to use it (like make an extended) */
/* UNUSABLE means there is no way to map this space                        */
#define AVAILABLE         0
#define UNAVAILABLE       1
#define ALLOCATED         2
#define UNUSABLE          4


/*                                                                          */
/* A hard drive describes a collection of partitions                        */
/* Each hard drive has several physical characteristics which can affect    */
/* the attributes that a partition can contain:                             */
/*                                                                          */
/*    geometry -> sectors/heads/cylinders of drive                          */
/*                partitions have to start and end on cylinder boundaries   */
/*                                                                          */
/*    name     -> something like "/dev/hda1"                                */
/*                                                                          */
/*    fd       -> the file descriptor being used to access this drive       */
/*                                                                          */
/*    pep      -> slot number of the Primary Extended Partion, 0 if none    */
/*                                                                          */
/*    table    -> array of partition descriptors, indexed by the number     */
/*                of the partition. Primary partitions range in number from */
/*                1 to 4, while logical partitions start at number 5.       */
/*                You can have any or all of the primaries defined, but the */
/*                logicals always start with 5 and increment upwards. If you*/
/*                remove a logical then all the other logicals get renumbred*/
/*                Note that sometimes you can remove a logical but the      */
/*                associated extended partition DOES NOT get removed. This  */
/*                can happen when a logical partition down the chain of     */
/*                extended partitions is immutable.                         */
/*                                                                          */
/*    eptable  -> array of extended partition descriptors, indexed by the   */
/*                number of the logical partition which it encapsulates.    */
/*                                                                          */
/* The partition table describes existing partitions. Entries 1 thru 4 are  */
/* for the primary partitions (PPs). At most 1 of these can be an           */
/* extended partition (EP). The primary extended partition (PEP) describes  */
/* the chunk of the disk in which ALL other logical partitions (LPs) can be.*/
/* Each LP has an associated EP. At the start of each EP is an extended     */
/* partition table (EPT). It is possible that an EPT could have up to 4 LPs */
/* defined within a given EP, but we (and all other partitioning software I */
/* can find) limit you to 1 LP per EP.  To make more LP within the space    */
/* described by the PEP, you make an entry in the EPT describing another EP.*/
/* These EPT make a chain, starting with the PEP and working down. The first*/
/* link on this chain gets a partition number of 5, and the number goes up  */
/* by one for each link down the chain.                                     */
/*                                                                          */
/* Deleting a PP involved just setting its size and type to 0. However,     */
/* because of the way the EPT chain works, deleting anything but the tail   */
/* link in the EPT chain can have numerous consequences.                    */
/* Say you have LPs 5 thru 7. You delete LP 5. The EPT for LP 6 now has to  */
/* move to the location of the EPT for LP 5, since LP 6 has now become LP 5.*/
/* The old EPT for LP 6 is not used anymore, but LP 6 (now LP 5) will occupy*/
/* at the exact same space on disk. The write routine which takes the       */
/* HardDrive structure and writes it to the disk must be aware of these     */
/* facts so that EPT and LP stay in the same places as read in.             */
/* This routine will write LP 5 first, then 6, etc etc, linking each with   */
/* the following. At some point it would be nice if the automatic allocation*/
/* routines could straighten the EPT chain out.                             */
/*                                                                          */
/* We mark a partition table entry as available by:                         */
/*     setting its size and type to 0                                       */
/*     settting its status to AVAILABLE <- use this for testing status      */
/* We mark a partition used by:                                             */
/*     setting its size and type to != 0                                    */
/*     setting its status to ALLOCATED  <- use this for testing status      */


#define MAX_HD_NAMELEN 128
#define MAX_PARTITIONS   16
struct hd_device {
    char                            name[MAX_HD_NAMELEN];
    unsigned int                    num; /* 'BIOS' number of drive */
    struct hd_geometry              geom;
    unsigned int                    totalsectors;
    int                             fd;
    unsigned int                    pep;
    Partition                       table[MAX_PARTITIONS+1];
    Partition                       eptable[MAX_PARTITIONS+1];
};

typedef struct hd_device           HardDrive;
typedef struct hd_geometry         HDGeometry;




/* functions everyone should see */
#include "rawio.h"
#include "primary.h"
#include "extended.h"
#include "partition.h"
#include "partspec.h"
#include "alloc.h"

#endif