disklib: Change read/write interface
authorPierre-Alexandre Meyer <pierre@mouraf.org>
Wed, 5 Aug 2009 19:42:37 +0000 (12:42 -0700)
committerPierre-Alexandre Meyer <pierre@mouraf.org>
Wed, 5 Aug 2009 19:44:25 +0000 (12:44 -0700)
Get rid of the error pointer and use a errno-like error reporting mechanism.
Intent is to make these more like the standard read/write system calls.

Signed-off-by: Pierre-Alexandre Meyer <pierre@mouraf.org>
com32/gplinclude/disk/errno_disk.h [new file with mode: 0644]
com32/gplinclude/disk/read.h
com32/gplinclude/disk/write.h
com32/gpllib/disk/errno_disk.c [new file with mode: 0644]
com32/gpllib/disk/error.c
com32/gpllib/disk/msdos.c
com32/gpllib/disk/read.c
com32/gpllib/disk/write.c

diff --git a/com32/gplinclude/disk/errno_disk.h b/com32/gplinclude/disk/errno_disk.h
new file mode 100644 (file)
index 0000000..0c4dccb
--- /dev/null
@@ -0,0 +1,49 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2009 Pierre-Alexandre Meyer
+ *
+ *   This file is part of Syslinux, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef _ERRNO_DISK_H
+#define _ERRNO_DISK_H
+
+extern int errno_disk;
+
+#define        EINV    0x01    /* Invalid function in AH or invalid parameter */
+#define        EADDR   0x02    /* Address mark not found */
+#define        ERO     0x03    /* Disk write-protected */
+#define        ENOFND  0x04    /* Sector not found/read error */
+#define        ERFAIL  0x05    /* Reset failed (hard disk) */
+#define        ECHANG  0x06    /* Disk changed (floppy) */
+#define        EDFAIL  0x07    /* Drive parameter activity failed (hard disk) */
+#define        EDMA    0x08    /* DMA overrun */
+#define        EBOUND  0x09    /* Data boundary error (attempted DMA across 64K boundary or >80h sectors) */
+#define        EBADS   0x0A    /* Bad sector detected (hard disk) */
+#define        EBADT   0x0B    /* Bad track detected (hard disk) */
+#define        EINVM   0x0C    /* Unsupported track or invalid media */
+#define        EINVS   0x0D    /* Invalid number of sectors on format (PS/2 hard disk) */
+#define        EADDRM  0x0E    /* Control data address mark detected (hard disk) */
+#define        EDMARG  0x0F    /* DMA arbitration level out of range (hard disk) */
+#define        ECRCF   0x10    /* Uncorrectable CRC or ECC error on read */
+#define        ECRCV   0x11    /* Data ECC corrected (hard disk) */
+#define        ECTRL   0x20    /* Controller failure */
+#define        EMEDIA  0x31    /* No media in drive (IBM/MS INT 13 extensions) */
+#define        ECMOS   0x32    /* Incorrect drive type stored in CMOS (Compaq) */
+#define        ESEEKF  0x40    /* Seek failed */
+#define        ETIME   0x80    /* Timeout (not ready) */
+#define        EREADY  0xAA    /* Drive not ready (hard disk) */
+#define        ENLOCK  0xB0    /* Volume not locked in drive (INT 13 extensions) */
+#define        ELOCK   0xB1    /* Volume locked in drive (INT 13 extensions) */
+#define        EREMOV  0xB2    /* Volume not removable (INT 13 extensions) */
+#define        EUSED   0xB3    /* Volume in use (INT 13 extensions) */
+#define        ECOUNT  0xB4    /* Lock count exceeded (INT 13 extensions) */
+#define        EEJF    0xB5    /* Valid eject request failed (INT 13 extensions) */
+#define        EUNKOWN 0xBB    /* Undefined error (hard disk) */
+#define        EWF     0xCC    /* Write fault (hard disk) */
+#define        ERF     0xE0    /* Status register error (hard disk) */
+#define        ESF     0xFF    /* Sense operation failed (hard disk) */
+
+#endif /* _ERRNO_DISK_H */
index 6d6d9fe..43762a6 100644 (file)
@@ -12,8 +12,7 @@
 
 #include <disk/geom.h>
 
-void *read_mbr(int, int*);
-void *dev_read(int, unsigned int, int, int*);
-void *read_sectors(struct driveinfo*, const unsigned int,
-                  const int, int *);
+int read_mbr(int, void*);
+int dev_read(int, void*, unsigned int, int);
+int read_sectors(struct driveinfo*, void*, const unsigned int, const int);
 #endif /* _READ_H */
index fe251f9..faa80c7 100644 (file)
 #include <disk/geom.h>
 
 int write_sectors(const struct driveinfo*, const unsigned int,
-                 const void *, const int, int *);
+                 const void *, const int);
 int write_verify_sector(struct driveinfo* drive_info,
                        const unsigned int,
-                       const void *, int*);
+                       const void *);
 int write_verify_sectors(struct driveinfo*,
                         const unsigned int,
-                        const void *, const int, int *);
+                        const void *, const int);
 #endif
diff --git a/com32/gpllib/disk/errno_disk.c b/com32/gpllib/disk/errno_disk.c
new file mode 100644 (file)
index 0000000..8a68802
--- /dev/null
@@ -0,0 +1,12 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2009 Pierre-Alexandre Meyer
+ *
+ *   This file is part of Syslinux, and is made available under
+ *   the terms of the GNU General Public License version 2.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <disk/errno_disk.h>
+
+int errno_disk;
index 6848ef3..5491b99 100644 (file)
 
 #include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
+
+#include <disk/errno_disk.h>
 
 /**
  * get_error - decode a disk error status
- * @status:    Error code
- * @buffer_ptr:        Pointer to set to the error message
+ * @buffer_ptr:        Preallocated buffer
  *
- * A buffer will be allocated to contain the error message.
- * @buffer_ptr will point to it. The caller will need to free it.
+ * Fill @buffer_ptr with the last errno_disk
  **/
-void get_error(int status, char** buffer_ptr)
+void get_error(void* buffer_ptr)
 {
-       int buffer_size = (80 * sizeof(char));
-       char* buffer = malloc(buffer_size);
-       *buffer_ptr = buffer;
-
-       switch (status) {
-       case 0x0:
-       strncpy(buffer, "successful completion", buffer_size);
-       break;
-       case 0x01:
-       strncpy(buffer, "invalid function in AH or invalid parameter", buffer_size);
-       break;
-       case 0x02:
-       strncpy(buffer, "address mark not found", buffer_size);
-       break;
-       case 0x03:
-       strncpy(buffer, "disk write-protected", buffer_size);
-       break;
-       case 0x04:
-       strncpy(buffer, "sector not found/read error", buffer_size);
-       break;
-       case 0x05:
-       strncpy(buffer, "reset failed (hard disk)", buffer_size);
-       //strncpy(buffer, "data did not verify correctly (TI Professional PC)", buffer_size);
-       break;
-       case 0x06:
-       strncpy(buffer, "disk changed (floppy)", buffer_size);
-       break;
-       case 0x07:
-       strncpy(buffer, "drive parameter activity failed (hard disk)", buffer_size);
-       break;
-       case 0x08:
-       strncpy(buffer, "DMA overrun", buffer_size);
-       break;
-       case 0x09:
-       strncpy(buffer, "data boundary error (attempted DMA across 64K boundary or >80h sectors)", buffer_size);
-       break;
-       case 0x0A:
-       strncpy(buffer, "bad sector detected (hard disk)", buffer_size);
-       break;
-       case 0x0B:
-       strncpy(buffer, "bad track detected (hard disk)", buffer_size);
-       break;
-       case 0x0C:
-       strncpy(buffer, "unsupported track or invalid media", buffer_size);
-       break;
-       case 0x0D:
-       strncpy(buffer, "invalid number of sectors on format (PS/2 hard disk)", buffer_size);
-       break;
-       case 0x0E:
-       strncpy(buffer, "control data address mark detected (hard disk)", buffer_size);
-       break;
-       case 0x0F:
-       strncpy(buffer, "DMA arbitration level out of range (hard disk)", buffer_size);
-       break;
-       case 0x10:
-       strncpy(buffer, "uncorrectable CRC or ECC error on read", buffer_size);
-       break;
-       case 0x11:
-       strncpy(buffer, "data ECC corrected (hard disk)", buffer_size);
-       break;
-       case 0x20:
-       strncpy(buffer, "controller failure", buffer_size);
-       break;
-       case 0x31:
-       strncpy(buffer, "no media in drive (IBM/MS INT 13 extensions)", buffer_size);
-       break;
-       case 0x32:
-       strncpy(buffer, "incorrect drive type stored in CMOS (Compaq)", buffer_size);
-       break;
-       case 0x40:
-       strncpy(buffer, "seek failed", buffer_size);
-       break;
-       case 0x80:
-       strncpy(buffer, "timeout (not ready)", buffer_size);
-       break;
-       case 0xAA:
-       strncpy(buffer, "drive not ready (hard disk)", buffer_size);
-       break;
-       case 0xB0:
-       strncpy(buffer, "volume not locked in drive (INT 13 extensions)", buffer_size);
-       break;
-       case 0xB1:
-       strncpy(buffer, "volume locked in drive (INT 13 extensions)", buffer_size);
-       break;
-       case 0xB2:
-       strncpy(buffer, "volume not removable (INT 13 extensions)", buffer_size);
-       break;
-       case 0xB3:
-       strncpy(buffer, "volume in use (INT 13 extensions)", buffer_size);
-       break;
-       case 0xB4:
-       strncpy(buffer, "lock count exceeded (INT 13 extensions)", buffer_size);
-       break;
-       case 0xB5:
-       strncpy(buffer, "valid eject request failed (INT 13 extensions)", buffer_size);
-       break;
-       case 0xBB:
-       strncpy(buffer, "undefined error (hard disk)", buffer_size);
-       break;
-       case 0xCC:
-       strncpy(buffer, "write fault (hard disk)", buffer_size);
-       break;
-       case 0xE0:
-       strncpy(buffer, "status register error (hard disk)", buffer_size);
-       break;
-       case 0xFF:
-       strncpy(buffer, "sense operation failed (hard disk)", buffer_size);
-       break;
-       default:
-       snprintf(buffer, buffer_size, "unknown error 0x%X, buggy bios?", status);
-       break;
-       }
+       sprintf(buffer_ptr, "Disklib: error %d\n", errno_disk);
 }
index 3b31dd0..249d39c 100644 (file)
@@ -13,6 +13,8 @@
  * ----------------------------------------------------------------------- */
 
 #include <stdlib.h>
+
+#include <disk/common.h>
 #include <disk/geom.h>
 #include <disk/partition.h>
 #include <disk/read.h>
@@ -23,7 +25,7 @@ static inline int is_extended_partition(struct part_entry *ptab)
                ptab->ostype == 0x0f ||
                ptab->ostype == 0x85);
 }
-static inline int msdos_magic_present(char *ptab)
+static inline int msdos_magic_present(const char *ptab)
 {
        return ( *(uint16_t *)(ptab + 0x1fe) == 0xaa55 );
 }
@@ -36,25 +38,28 @@ static inline int msdos_magic_present(char *ptab)
  * @error:             Buffer for I/O errors
  * @nb_part_seen:      Number of partitions found on the disk so far
  **/
-static void process_extended_partition(struct driveinfo *drive_info,
+static int process_extended_partition(struct driveinfo *drive_info,
                                       int partition_offset,
                                       void *callback(struct driveinfo *, struct part_entry *, int, int),
-                                      int *error, int nb_part_seen)
+                                      int nb_part_seen)
 {
+       int status = 0;
        /* The ebr is located at the first sector of the extended partition */
-       char* ebr = read_sectors(drive_info, partition_offset, 1, error);
+       char* ebr = malloc(SECTOR * sizeof(char));
 
-       /* If something bad during the read happens, we can't do much: bail out */
-       if (*error)
-               return;
+       if (read_sectors(drive_info, ebr, partition_offset, 1) == -1)
+               return -1;
 
        /* Check msdos magic signature */
        if (!msdos_magic_present(ebr))
-               return;
+               return -1;
 
        struct part_entry *ptab = (struct part_entry *)(ebr + PARTITION_TABLES_OFFSET);
 
        for (int i = 0; i < 4; i++) {
+               if (status == -1)
+                       return -1;
+
                if (!is_extended_partition(&ptab[i])) {
                        /*
                         * This EBR partition table entry points to the
@@ -81,11 +86,13 @@ static void process_extended_partition(struct driveinfo *drive_info,
                                 logical_partition_start,
                                 nb_part_seen);
                } else
-                       process_extended_partition(drive_info,
+                       status = process_extended_partition(drive_info,
                                                   partition_offset + ptab[i].start_lba,
                                                   callback,
-                                                  error, nb_part_seen);
+                                                  nb_part_seen);
        }
+
+       return 0;
 }
 
 /**
@@ -93,15 +100,15 @@ static void process_extended_partition(struct driveinfo *drive_info,
  * @drive_info:        driveinfo struct describing the drive
  * @ptab:      Pointer to the partition table
  * @callback:  Callback to execute
- * @error:     Return the error code (I/O), if needed
  **/
-static void process_mbr(struct driveinfo *drive_info, struct part_entry *ptab,
-                       void *callback(struct driveinfo *, struct part_entry *, int, int),
-                       int *error)
+static int process_mbr(struct driveinfo *drive_info, struct part_entry *ptab,
+                      void *callback(struct driveinfo *, struct part_entry *, int, int))
 {
+       int status = 0;
+
        for (int i = 0; i < 4; i++) {
-               if (*error)
-                       return;
+               if (status == -1)
+                       return -1;
 
                if (ptab[i].start_sect > 0) {
                        if (is_extended_partition(&ptab[i])) {
@@ -109,7 +116,7 @@ static void process_mbr(struct driveinfo *drive_info, struct part_entry *ptab,
                                         &ptab[i],
                                         ptab[i].start_lba,
                                         i+1);
-                               process_extended_partition(drive_info, ptab[i].start_lba, callback, error, 4);
+                               status = process_extended_partition(drive_info, ptab[i].start_lba, callback, 4);
                        } else
                                callback(drive_info,
                                         &ptab[i],
@@ -117,6 +124,8 @@ static void process_mbr(struct driveinfo *drive_info, struct part_entry *ptab,
                                         i+1);
                }
        }
+
+       return 0;
 }
 
 /**
@@ -132,10 +141,11 @@ static void process_mbr(struct driveinfo *drive_info, struct part_entry *ptab,
  *              int offset_root,
  *              int nb_part_seen)
  **/
-int parse_partition_table(struct driveinfo *d, void *callback, int *error)
+int parse_partition_table(struct driveinfo *d, void *callback)
 {
-       char *mbr = read_mbr(d->disk, error);
-       if (!mbr)
+       char *mbr = malloc(SECTOR * sizeof(char));
+
+       if (read_mbr(d->disk, mbr) == -1)
                return -1;
        else {
                /* Check msdos magic signature */
@@ -143,10 +153,6 @@ int parse_partition_table(struct driveinfo *d, void *callback, int *error)
                        return -1;
 
                struct part_entry *ptab = (struct part_entry *)(mbr + PARTITION_TABLES_OFFSET);
-               process_mbr(d, ptab, callback, error);
-               if (*error)
-                       return -1;
-               else
-                       return 0;
+               return process_mbr(d, ptab, callback);
        }
 }
index 3fc0e0c..7484082 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
+#include <disk/errno_disk.h>
 #include <disk/geom.h>
 #include <disk/read.h>
 #include <disk/util.h>
 #include <disk/common.h>
 
+/*
+ * TODO: implement file descriptors to cache metadata (geometry, ...)
+ */
+
 /**
  * read_mbr - return a pointer to a malloced buffer containing the mbr
  * @drive:     Drive number
- * @error:     Return the error code on failure
+ * @buf:       Pre-allocated buffer for output
+ *
+ * Return the number of sectors read on success or -1 on failure.
+ * errno_disk contains the error number.
  **/
-void *read_mbr(int drive, int *error)
+int read_mbr(int drive, void *buf)
 {
        struct driveinfo drive_info;
        drive_info.disk = drive;
 
        /* MBR: lba = 0, 1 sector */
-       return read_sectors(&drive_info, 0, 1, error);
+       return read_sectors(&drive_info, buf, 0, 1);
 }
 
 /**
  * dev_read - read from a drive
  * @drive:     Drive number
+ * @buf:       Pre-allocated buffer for output
  * @lba:       Position to start reading from
  * @sectors:   Number of sectors to read
- * @error:     Return the error code on failure
  *
  * High-level routine to read from a hard drive.
+ * Return the number of sectors read on success or -1 on failure.
+ * errno_disk contains the error number.
  **/
-void *dev_read(int drive, unsigned int lba, int sectors, int *error)
+int dev_read(int drive, void * buf, unsigned int lba, int sectors)
 {
        struct driveinfo drive_info;
        drive_info.disk = drive;
 
-       return read_sectors(&drive_info, lba, sectors, error);
+       return read_sectors(&drive_info, buf, lba, sectors);
 }
 
 /**
  * read_sectors - read several sectors from disk
  * @drive_info:                driveinfo struct describing the disk
+ * @data:              Pre-allocated buffer for output
  * @lba:               Position to read
  * @sectors:           Number of sectors to read
- * @error:             Return the error code on failure
  *
- * Return a pointer to a malloc'ed buffer containing the data.
+ * Return the number of sectors read on success or -1 on failure.
+ * errno_disk contains the error number.
  **/
-void *read_sectors(struct driveinfo* drive_info, const unsigned int lba,
-                  const int sectors, int *error)
+int read_sectors(struct driveinfo* drive_info, void *data,
+                const unsigned int lba, const int sectors)
 {
        com32sys_t inreg, outreg;
        struct ebios_dapa *dapa = __com32.cs_bounce;
        void *buf = (char *)__com32.cs_bounce + sectors * SECTOR;
-       void *data;
+       char *bufp = data;
 
        if (get_drive_parameters(drive_info) == -1)
-               return NULL;
+               return -1;
 
        memset(&inreg, 0, sizeof inreg);
 
@@ -88,17 +99,18 @@ void *read_sectors(struct driveinfo* drive_info, const unsigned int lba,
        } else {
                unsigned int c, h, s;
 
-               if (!drive_info->cbios) {
+               if (!drive_info->cbios) { // XXX errno
                        /* We failed to get the geometry */
                        if (lba)
-                               return NULL;    /* Can only read MBR */
+                               return -1;      /* Can only read MBR */
 
                        s = 1;  h = 0;  c = 0;
                } else
                        lba_to_chs(drive_info, lba, &s, &h, &c);
 
+               // XXX errno
                if ( s > 63 || h > 256 || c > 1023 )
-                       return NULL;
+                       return -1;
 
                inreg.eax.w[0] = 0x0201;        /* Read one sector */
                inreg.ecx.b[1] = c & 0xff;
@@ -111,17 +123,11 @@ void *read_sectors(struct driveinfo* drive_info, const unsigned int lba,
 
        /* Perform the read */
        if (int13_retry(&inreg, &outreg)) {
-               if (error)
-                       *error = outreg.eax.b[1];
-               return NULL;    /* Give up */
-       } else {
-               if (error)
-                       *error = 0;
+               errno_disk = outreg.eax.b[1];
+               return -1;      /* Give up */
        }
 
-       data = malloc(sectors * SECTOR);
-       if (data)
-               memcpy(data, buf, sectors * SECTOR);
+       memcpy(bufp, buf, sectors * SECTOR);
 
-       return data;
+       return sectors;
 }
index b772ba7..a236f37 100644 (file)
 #include <com32.h>
 #include <stdlib.h>
 #include <string.h>
-#include <disk/read.h>
-#include <disk/write.h>
+
 #include <disk/common.h>
+#include <disk/errno_disk.h>
+#include <disk/read.h>
 #include <disk/util.h>
+#include <disk/write.h>
 
 /**
  * write_sectors - write several sectors from disk
  * @lba:               Position to write
  * @data:              Buffer to write
  * @size:              Size of the buffer (number of sectors)
- * @error:             Return the error code on failure
+ *
+ * Return the number of sectors write on success or -1 on failure.
+ * errno_disk contains the error number.
  **/
 int write_sectors(const struct driveinfo* drive_info, const unsigned int lba,
-                 const void *data, const int size, int *error)
+                 const void *data, const int size)
 {
        com32sys_t inreg, outreg;
        struct ebios_dapa *dapa = __com32.cs_bounce;
@@ -38,7 +42,7 @@ int write_sectors(const struct driveinfo* drive_info, const unsigned int lba,
        memcpy(buf, data, size);
        memset(&inreg, 0, sizeof inreg);
 
-       if ( drive_info->ebios ) {
+       if (drive_info->ebios) {
                dapa->len = sizeof(*dapa);
                dapa->count = size;
                dapa->off = OFFS(buf);
@@ -52,16 +56,16 @@ int write_sectors(const struct driveinfo* drive_info, const unsigned int lba,
        } else {
                unsigned int c, h, s;
 
-               if ( !drive_info->cbios ) {
-                 /* We failed to get the geometry */
-
-                 if ( lba )
-                   return -1;          /* Can only write MBR */
+               if (!drive_info->cbios) { // XXX errno
+                       /* We failed to get the geometry */
+                       if (lba)
+                               return -1;      /* Can only write MBR */
 
-                 s = 1;  h = 0;  c = 0;
+                       s = 1;  h = 0;  c = 0;
                } else
                    lba_to_chs(drive_info, lba, &s, &h, &c);
 
+               // XXX errno
                if ( s > 63 || h > 256 || c > 1023 )
                  return -1;
 
@@ -76,14 +80,10 @@ int write_sectors(const struct driveinfo* drive_info, const unsigned int lba,
 
        /* Perform the write */
        if (int13_retry(&inreg, &outreg)) {
-               if (error)
-                       *error = outreg.eax.b[1];
+               errno_disk = outreg.eax.b[1];
                return -1;      /* Give up */
-       } else {
-               if (error)
-                       *error = 0;
-               return 0;
-       }
+       } else
+               return size;
 }
 
 /**
@@ -94,9 +94,9 @@ int write_sectors(const struct driveinfo* drive_info, const unsigned int lba,
  **/
 int write_verify_sector(struct driveinfo* drive_info,
                        const unsigned int lba,
-                       const void *data, int *error)
+                       const void *data)
 {
-       return write_verify_sectors(drive_info, lba, data, SECTOR, error);
+       return write_verify_sectors(drive_info, lba, data, SECTOR);
 }
 
 /**
@@ -108,20 +108,18 @@ int write_verify_sector(struct driveinfo* drive_info,
  **/
 int write_verify_sectors(struct driveinfo* drive_info,
                         const unsigned int lba,
-                        const void *data, const int size, int* error)
+                        const void *data, const int size)
 {
-       char *rb;
-       int rv;
+       char *rb = malloc(SECTOR * size * sizeof(char));
+       int status;
 
-       rv = write_sectors(drive_info, lba, data, size, error);
-       if (rv)
-               return rv;              /* Write failure */
+       if (write_sectors(drive_info, lba, data, size) == -1)
+               return -1;      /* Write failure */
 
-       rb = read_sectors(drive_info, lba, size, error);
-       if (!rb)
-               return -1;              /* Readback failure */
+       if (read_sectors(drive_info, rb, lba, size) == -1)
+               return -1;      /* Readback failure */
 
-       rv = memcmp(data, rb, SECTOR * size);
+       status = memcmp(data, rb, SECTOR * size);
        free(rb);
-       return rv ? -1 : 0;
+       return status ? -1 : 0;
 }