bug-parted
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

patch that adds disk access record/replay functionality


From: Håkon Løvdal
Subject: patch that adds disk access record/replay functionality
Date: Mon, 5 Dec 2005 02:56:52 +0100

Hi. I have now finished the record and replay functionality that I
started writing. I think the lower level parts are more or less finished
and properly integrated with parted, but the higher part integration is
not properly done and finished.

With my patch parted is able to record or replay all disk access for
a given device. The saved file format is changed from my previous
patch and is now one single file. A new command line option "-r" with
an required file name argument triggers record. Example: "parted -s
-r saved_disk_access.hda /dev/hda print". This disk access file can
later be used as a device for parted (replay). Example: "parted -s
saved_disk_access.hda print".

For the higher level integration I think it would be good with some
feedback and suggestions on what you think would be the best way to
integrate this.

I have added a member diskaccess [1] of type PedDiskAccess in PedDevice
(I guess this will break binary compatibility, so that would also be a
reason for switching to 1.7).

All the ped_diskaccess_* functions have a PedDiskAccess pointer as
first argument. Even if some of the functions also have a PedDevice
pointer parameter, the diskaccess member of "dev" is never referred,
so the ped_diskaccess_* functions are not dependent on diskaccess being
a member of PedDevice.

I have used a global variable for passing parameters from parted to
libparted (hack). To properly handle this I think the PedDeviceArchOps
_new function must be extended to have a PedDiskAccess argument as well.

[1]
I have renamed from earlier "filespy" to "diskaccess" (I did not use
"disk_access" since that is too similar to all the other disk_* variants
which are something completely different).

BR Håkon  Løvdal

The following patch is against parted-1.6.25.1.

diff -urN parted-1.6.25.1.orig/include/parted/device.h
parted-1.6.25.1/include/parted/device.h
--- parted-1.6.25.1.orig/include/parted/device.h        2005-11-11
13:32:28.000000000 +0100
+++ parted-1.6.25.1/include/parted/device.h     2005-12-04 15:16:29.000000000 
+0100
@@ -46,6 +46,8 @@
        int             sectors;
 };

+struct _PedDiskAccess;
+
 /* A hard disk device - eg. /dev/hda, not /dev/hda3 */
 struct _PedDevice {
        PedDevice*      next;
@@ -68,6 +70,7 @@
        short           host, did;

        void*           arch_specific;
+       struct _PedDiskAccess*  diskaccess;
 };

 struct _PedDeviceArchOps {
diff -urN parted-1.6.25.1.orig/include/parted/diskaccess.h
parted-1.6.25.1/include/parted/diskaccess.h
--- parted-1.6.25.1.orig/include/parted/diskaccess.h    1970-01-01
01:00:00.000000000 +0100
+++ parted-1.6.25.1/include/parted/diskaccess.h 2005-12-05
00:38:15.000000000 +0100
@@ -0,0 +1,52 @@
+/*
+    libparted - a library for manipulating disk partitions
+    Copyright (C) 1999 - 2005 Free Software Foundation, Inc.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+*/
+
+#ifndef PED_DISKACCESS_H_INCLUDED
+#define PED_DISKACCESS_H_INCLUDED
+
+#include <sys/types.h>
+#include <stdio.h>
+
+typedef enum {
+       PED_DISKACCESS_NORMAL,
+       PED_DISKACCESS_RECORD,
+       PED_DISKACCESS_REPLAY
+} PedDiskAccessMode;
+
+typedef struct {
+       PedDiskAccessMode mode;
+       const char *filename;
+} PedDiskAccessParameters;
+
+extern PedDiskAccessParameters linux_diskaccess_parameters;
+
+struct _PedDevice;
+struct _PedDiskAccess;
+
+int ped_diskaccess_create(struct _PedDiskAccess **diskaccess_ptr,
PedDiskAccessMode mode, const char * const filename);
+int ped_diskaccess_destroy(struct _PedDiskAccess **diskaccess_ptr);
+int ped_diskaccess_set_mode(struct _PedDiskAccess * const diskaccess,
PedDiskAccessMode mode, const char * const filename);
+int ped_diskaccess_restore_device_info(struct _PedDiskAccess
*diskaccess, struct _PedDevice * const dev);
+PedDiskAccessMode ped_diskaccess_get_mode(struct _PedDiskAccess *
const diskaccess);
+int ped_diskaccess_open(struct _PedDiskAccess * const diskaccess);
+int ped_diskaccess_close(struct _PedDiskAccess * const diskaccess,
const struct _PedDevice * const dev);
+int ped_diskaccess_save_sectors(struct _PedDiskAccess * const
diskaccess, const struct _PedDevice * const dev, void *buffer,
PedSector start, PedSector count);
+int ped_diskaccess_load_sectors(struct _PedDiskAccess * const
diskaccess, const struct _PedDevice * const dev, void *buffer,
PedSector start, PedSector count);
+
+#endif
diff -urN parted-1.6.25.1.orig/include/parted/Makefile.am
parted-1.6.25.1/include/parted/Makefile.am
--- parted-1.6.25.1.orig/include/parted/Makefile.am     2005-11-11
13:32:28.000000000 +0100
+++ parted-1.6.25.1/include/parted/Makefile.am  2005-11-28
23:46:58.000000000 +0100
@@ -11,7 +11,8 @@
                        natmath.h       \
                        timer.h         \
                        unit.h          \
-                       parted.h
+                       parted.h        \
+                       diskaccess.h

 noinst_HEADERS       = crc32.h         \
                        endian.h
diff -urN parted-1.6.25.1.orig/include/parted/Makefile.in
parted-1.6.25.1/include/parted/Makefile.in
--- parted-1.6.25.1.orig/include/parted/Makefile.in     2005-11-11
13:38:44.000000000 +0100
+++ parted-1.6.25.1/include/parted/Makefile.in  2005-11-29
00:13:23.000000000 +0100
@@ -198,7 +198,8 @@
                        natmath.h       \
                        timer.h         \
                        unit.h          \
-                       parted.h
+                       parted.h        \
+                       diskaccess.h

 noinst_HEADERS = crc32.h               \
                        endian.h
diff -urN parted-1.6.25.1.orig/include/parted/unit.h
parted-1.6.25.1/include/parted/unit.h
--- parted-1.6.25.1.orig/include/parted/unit.h  2005-11-11
13:32:28.000000000 +0100
+++ parted-1.6.25.1/include/parted/unit.h       2005-12-04 15:53:07.000000000 
+0100
@@ -21,6 +21,7 @@
 #define PED_UNIT_H_INCLUDED

 #include <parted/device.h>
+#include <parted/geom.h>

 #include <stdarg.h>
 #include <stdio.h>
diff -urN parted-1.6.25.1.orig/libparted/diskaccess.c
parted-1.6.25.1/libparted/diskaccess.c
--- parted-1.6.25.1.orig/libparted/diskaccess.c 1970-01-01
01:00:00.000000000 +0100
+++ parted-1.6.25.1/libparted/diskaccess.c      2005-12-05 02:27:36.000000000 
+0100
@@ -0,0 +1,629 @@
+/*
+    libparted - a library for manipulating disk partitions
+    Copyright (C) 1999 - 2005 Free Software Foundation, Inc.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+*/
+
+#include <string.h>
+#define __USE_LARGEFILE     // must define to get ftello from stdio.h
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <parted/debug.h>
+#include <parted/device.h>
+#include <parted/diskaccess.h>
+#include <parted/unit.h>
+#include <parted/parted.h>
+
+typedef struct node_s {
+       struct node_s *next;
+       PedSector device_sector;   // within "/dev/hda"
+       off_t file_offset;         // within "/tmp/parted.hda"
+} node_t;
+
+static node_t *new_node(PedSector device_sector, off_t file_offset)
+{
+       node_t *node = ped_malloc(sizeof(node_t));
+       if (node == NULL)
+               return NULL;
+       node->device_sector = device_sector;
+       node->file_offset   = file_offset;
+       return node;
+}
+
+/* The following list functions are copied from the
+ * sl-0.3.3 library by Stig Brautaset <address@hidden>,
+ * http://brautaset.org/software/sl/.
+ *
+ * The functions are specialized and adapted for this file.
+ */
+
+/** BEGIN LIST PART ***/
+
+static node_t *list_insert_node(node_t *root, node_t *q)
+{
+       if (!q)
+               return root;
+
+       q->next = root;
+       return q;
+}
+
+static const node_t *list_find_node_by_sector(const node_t * const
root, PedSector sector)
+{
+       const node_t *p;
+       for (p = root; p != NULL; p = p->next)
+               if (p->device_sector == sector)
+                       return p;
+       return NULL;
+}
+
+static int list_contains_sector(const node_t * const root, PedSector sector)
+{
+       return list_find_node_by_sector(root, sector) != NULL;
+}
+
+static int list_walk(const node_t * const root, int (*func)(const
node_t * const, void *data), void * data)
+{
+       const node_t *p;
+       for (p = root; p != NULL; p = p->next)
+               if (! func(p, data))
+                       return 0;
+       return 1;
+}
+
+/** END LIST PART ***/
+
+#define WRITE_STR(_stream, _str) \
+do { \
+       size_t ret = fwrite(_str, strlen(_str), 1, _stream); \
+       if (ret < 1) { \
+               fprintf(stderr, __FILE__ ":line %d: fwrite failed, ret = %s,
(%s)\n", __LINE__, ret, _str); \
+               goto write_failed; \
+       } \
+} while (0)
+
+#define WRITE_SECTOR(_stream, _sector) \
+do { \
+       size_t res = fwrite(_sector, PED_SECTOR_SIZE, 1, _stream); \
+       if (res < 1) { \
+               fprintf(stderr, __FILE__ ":line %d: fwrite failed (%d)\n", 
__LINE__, res); \
+               goto write_failed; \
+       } \
+} while (0)
+
+#define READ_SECTOR(_stream, _sector) \
+do { \
+       size_t res = fread(_sector, PED_SECTOR_SIZE, 1, _stream); \
+       if (res < 1) { \
+               fprintf(stderr, __FILE__ ":line %d: fread failed (%d)\n", 
__LINE__, res); \
+               goto read_failed; \
+       } \
+} while (0)
+
+#define READ_LINE(_stream, _buffer, _buffer_size) \
+do { \
+       if (fgets(_buffer, _buffer_size, _stream) == NULL) { \
+               fprintf(stderr, __FILE__ ": line %d: fgets failed\n", 
__LINE__); \
+               goto read_failed; \
+       } \
+} while (0)
+
+#define WRITE_ELEM(_stream, _dev, _element, _fmt) \
+do { \
+       size_t res; \
+       char buf[128]; \
+       int max = sizeof(buf)-1; \
+       buf[max] = '\0'; \
+       snprintf(buf, max, #_element "=" _fmt "\n", _dev->_element); \
+       res = fwrite(buf, strlen(buf), 1, _stream); \
+       if (res < 1) { \
+               fprintf(stderr, __FILE__ ":line %d: fwrite failed (%d)\n", 
__LINE__, res); \
+               goto write_failed; \
+       } \
+} while (0)
+
+
+typedef struct _PedDiskAccess {
+       PedDiskAccessMode mode;
+       FILE * stream;
+       char * filename;
+       struct node_s *root;
+} PedDiskAccess;
+
+const char *PedDiskAccessModeName[] = {
+       "PED_DISKACCESS_NORMAL",
+       "PED_DISKACCESS_RECORD",
+       "PED_DISKACCESS_REPLAY"
+};
+
+static int ped_diskaccess_parse_device_info(PedDiskAccess *const
diskaccess, PedDevice *const dev);
+static int ped_diskaccess_write_device_info(PedDiskAccess *const
diskaccess, const PedDevice *const dev);
+
+static int ped_diskaccess_parse_table(PedDiskAccess *const diskaccess);
+static int ped_diskaccess_write_table(PedDiskAccess *const diskaccess);
+static int ped_diskaccess_parse_start_of_file(const PedDiskAccess
*const diskaccess, off_t *device_info_offset_ptr, off_t
*table_offset_ptr);
+static int ped_diskaccess_write_start_of_file(const PedDiskAccess
*const diskaccess, off_t device_info_offset, off_t table_offset);
+
+
+int ped_diskaccess_create(PedDiskAccess **diskaccess_ptr,
PedDiskAccessMode mode, const char * const filename)
+{
+       PED_ASSERT (mode == PED_DISKACCESS_REPLAY
+                || mode == PED_DISKACCESS_RECORD
+                || mode == PED_DISKACCESS_NORMAL, return 0);
+       if (mode == PED_DISKACCESS_NORMAL) {
+               PED_ASSERT (filename == NULL, return 0);
+       } else {
+               PED_ASSERT (filename != NULL, return 0);
+       }
+       //fprintf(stderr, "ped_diskaccess_create, mode = %s, filename = %s\n",
+               //PedDiskAccessModeName[mode], filename ? filename : "NULL");
+       *diskaccess_ptr = (PedDiskAccess*) ped_malloc (sizeof (PedDiskAccess));
+       if (! *diskaccess_ptr)
+               return 0;
+       (*diskaccess_ptr)->mode     = mode;
+       (*diskaccess_ptr)->stream   = NULL;
+       (*diskaccess_ptr)->filename = filename ? strdup(filename) : NULL;
+       (*diskaccess_ptr)->root     = NULL;
+       return 1;
+}
+
+/* This function can be called between ped_diskaccess_create and
ped_diskaccess_open.
+ *
+ * The usual behaviour pattern is the following:
+ *
+ * normal: create(NORMAL) --> open
+ * record: create(RECORD) --> open
+ * replay: create(NORMAL) --> setmode(REPLAY) --> open
+ *
+ */
+int ped_diskaccess_set_mode(PedDiskAccess * const diskaccess,
PedDiskAccessMode mode, const char * const filename)
+{
+       PED_ASSERT (mode == PED_DISKACCESS_REPLAY
+                || mode == PED_DISKACCESS_RECORD
+                || mode == PED_DISKACCESS_NORMAL, return 0);
+       if (mode == PED_DISKACCESS_NORMAL) {
+               PED_ASSERT (filename == NULL, return 0);
+       } else {
+               PED_ASSERT (filename != NULL, return 0);
+       }
+       PED_ASSERT (diskaccess != NULL, return 0);
+       PED_ASSERT (diskaccess->stream == NULL, return 0);
+       PED_ASSERT (diskaccess->root   == NULL, return 0);
+       //fprintf(stderr, "ped_diskaccess_set_mode, mode = %s, filename = %s\n",
+               //PedDiskAccessModeName[mode], filename ? filename : "NULL");
+       if (diskaccess->filename != NULL)
+               ped_free(diskaccess->filename);
+       diskaccess->mode     = mode;
+       diskaccess->filename = filename ? strdup(filename) : NULL;
+       return 1;
+}
+
+PedDiskAccessMode ped_diskaccess_get_mode(PedDiskAccess * const diskaccess)
+{
+       PED_ASSERT (diskaccess != NULL, return PED_DISKACCESS_NORMAL);
+       PED_ASSERT (diskaccess->mode == PED_DISKACCESS_REPLAY
+                || diskaccess->mode == PED_DISKACCESS_RECORD
+                || diskaccess->mode == PED_DISKACCESS_NORMAL, return
PED_DISKACCESS_NORMAL);
+       return diskaccess->mode;
+}
+
+int ped_diskaccess_destroy(PedDiskAccess **diskaccess_ptr)
+{
+       PED_ASSERT (diskaccess_ptr != NULL, return 0);
+       PED_ASSERT (*diskaccess_ptr != NULL, return 0);
+       //fprintf(stderr, "ped_diskaccess_destroy\n");
+       ped_free (*diskaccess_ptr);
+       *diskaccess_ptr = NULL;
+       return 1;
+}
+
+int ped_diskaccess_open(PedDiskAccess * const diskaccess)
+{
+       size_t res;
+       char padding[512];
+       off_t dummy;
+       off_t table_offset;
+       //fprintf(stderr, "ped_diskaccess_open\n");
+
+       PED_ASSERT (diskaccess != NULL, return 0);
+       PED_ASSERT (diskaccess->mode == PED_DISKACCESS_REPLAY ||
diskaccess->mode == PED_DISKACCESS_RECORD, return 0);
+       PED_ASSERT (diskaccess->stream == NULL, return 0);
+
+       switch (diskaccess->mode)
+       {
+       case PED_DISKACCESS_RECORD:
+               // FixMe: should we warn about overwriting existing files?
+               diskaccess->stream = fopen(diskaccess->filename, "w");
+               if (diskaccess->stream == NULL) {
+                       fprintf(stderr, "fopen(\"%s\", \"w\") failed\n", 
diskaccess->filename);
+                       return 0;
+               }
+               memset(padding, 'X', sizeof(padding));
+               res = fwrite(padding, sizeof(padding), 1, diskaccess->stream);
+               if (res < 1) {
+                       fprintf(stderr, __FILE__ ":line %d: fwrite failed, res 
= %d\n", res);
+                       goto close_and_return;
+               }
+               break;
+       case PED_DISKACCESS_REPLAY:
+               diskaccess->stream = fopen(diskaccess->filename, "r");
+               if (diskaccess->stream == NULL) {
+                       fprintf(stderr, "fopen(\"%s\", \"r\") failed\n", 
diskaccess->filename);
+                       return 0;
+               }
+               if (! ped_diskaccess_parse_start_of_file(diskaccess, &dummy, 
&table_offset))
+                       goto close_and_return;
+               // device info already read with 
ped_diskaccess_restore_device_info
+               if (fseeko(diskaccess->stream, table_offset, SEEK_SET) != 0) {
+                       fprintf(stderr, "ped_diskaccess_open: fseeko failed\n");
+                       goto close_and_return;
+               }
+               if (! ped_diskaccess_parse_table(diskaccess)) {
+                       fprintf(stderr, "ped_diskaccess_open: 
ped_diskaccess_parse_table failed\n");
+                       goto close_and_return;
+               }
+               break;
+       }
+       return 1;
+
+close_and_return:
+       fclose(diskaccess->stream);
+       return 0;
+}
+
+int ped_diskaccess_close(PedDiskAccess * const diskaccess, const
PedDevice * const dev)
+{
+       int res;
+       off_t device_info_offset;
+       off_t table_offset;
+       PED_ASSERT (diskaccess != NULL, return 0);
+       PED_ASSERT (diskaccess->mode == PED_DISKACCESS_REPLAY ||
diskaccess->mode == PED_DISKACCESS_RECORD, return 0);
+       PED_ASSERT (diskaccess->stream != NULL, return 0);
+       //fprintf(stderr, "ped_diskaccess_close\n");
+
+       switch (diskaccess->mode)
+       {
+       case PED_DISKACCESS_RECORD:
+               device_info_offset = ftello(diskaccess->stream);
+               if (! ped_diskaccess_write_device_info(diskaccess, dev))
+                       goto close_file;
+               table_offset = ftello(diskaccess->stream);
+               if (! ped_diskaccess_write_table(diskaccess))
+                       goto close_file;
+               rewind(diskaccess->stream);
+               if (! ped_diskaccess_write_start_of_file(diskaccess,
device_info_offset, table_offset))
+                       goto close_file;
+               break;
+       case PED_DISKACCESS_REPLAY:
+               break;
+       }
+
+close_file:
+       res = fclose(diskaccess->stream);
+       diskaccess->stream = NULL;
+       // fixme: memory leak, not freed anywhere else, but here is the wrong 
place
+       //ped_free(diskaccess->filename);
+       //diskaccess->filename = NULL;
+       return res == 0;
+}
+
+int ped_diskaccess_save_sectors(PedDiskAccess * const diskaccess,
const PedDevice * const dev, void *buffer, PedSector start, PedSector
count)
+{
+       node_t *node;
+       PED_ASSERT (diskaccess != NULL, return 0);
+       PED_ASSERT (diskaccess->mode == PED_DISKACCESS_RECORD, return 0);
+       PED_ASSERT (diskaccess->stream != NULL, return 0);
+
+       // FixMe: is this void pointer aritmetic valid? I do not have access
to the standard right now
+       for (; count-- > 0; start++, buffer += PED_SECTOR_SIZE)
+       {
+               if (list_contains_sector(diskaccess->root, start))
+                       continue;
+               node = new_node(start, ftello(diskaccess->stream));
+               if (node == NULL)
+                       return 0;
+               diskaccess->root = list_insert_node(diskaccess->root, node);
+               WRITE_SECTOR(diskaccess->stream, buffer);
+       }
+       return 1;
+
+write_failed:
+       return 0;
+}
+
+static int load_sector(const PedDiskAccess * const diskaccess, char *
const buffer, off_t file_offset)
+{
+       PED_ASSERT (diskaccess != NULL, return 0);
+       if (fseeko(diskaccess->stream, file_offset, SEEK_SET) != 0) {
+               return 0;
+       }
+       READ_SECTOR(diskaccess->stream, buffer);
+       return 1;
+
+read_failed:
+       return 0;
+}
+
+int ped_diskaccess_load_sectors(PedDiskAccess * const diskaccess,
const PedDevice * const dev, void *buffer, PedSector start, PedSector
count)
+{
+       const node_t *node;
+       PedSector current_device_sector;
+       PED_ASSERT (diskaccess != NULL, return 0);
+       PED_ASSERT (diskaccess->mode == PED_DISKACCESS_REPLAY, return 0);
+       PED_ASSERT (diskaccess->stream != NULL, return 0);
+       PED_ASSERT (diskaccess->root != NULL, return 0);
+
+       for (current_device_sector = start;
+            count > 0;
+            // fixme: is this void pointer aritmetic valid? I do not have
access to the standard right now
+            buffer += PED_SECTOR_SIZE, count--, current_device_sector++
+       ) {
+               //fprintf(stderr, "ped_diskaccess_load_sectors:
current_device_sector = %lld, "
+                       //"count = %lld, buffer = %p\n", current_device_sector, 
count, buffer);
+               node = list_find_node_by_sector(diskaccess->root, 
current_device_sector);
+               if (node == NULL) {
+                       fprintf(stderr, "node not found, current_device_sector 
= %lld\n",
current_device_sector);
+                       return 0;
+               }
+               //list_print_node(node);
+               load_sector(diskaccess, buffer, node->file_offset);
+       }
+
+       return 1;
+read_failed:
+       return 0;
+}
+
+int ped_diskaccess_restore_device_info(PedDiskAccess *diskaccess,
PedDevice * const dev)
+{
+       off_t device_info_offset, dummy;
+
+       PED_ASSERT (diskaccess != NULL, return 0);
+       PED_ASSERT (diskaccess->mode == PED_DISKACCESS_REPLAY, return 0);
+       PED_ASSERT (diskaccess->filename != NULL, return 0);
+       PED_ASSERT (diskaccess->stream == NULL, return 0);
+       PED_ASSERT (strcmp(diskaccess->filename, dev->path) == 0, return 0);
+
+       diskaccess->stream = fopen(diskaccess->filename, "r");
+       if (diskaccess->stream == NULL)
+               goto open_error;
+       if (! ped_diskaccess_parse_start_of_file(diskaccess,
&device_info_offset, &dummy))
+               goto parse_error;
+       if (fseeko(diskaccess->stream, device_info_offset, SEEK_SET) != 0)
+               goto parse_error;
+       if (! ped_diskaccess_parse_device_info(diskaccess, dev))
+               goto parse_error;
+
+       fclose(diskaccess->stream);
+       diskaccess->stream = NULL;
+       return 1;
+
+parse_error:
+       fclose(diskaccess->stream);
+open_error:
+       diskaccess->stream = NULL;
+       return 0;
+}
+
+static int ped_diskaccess_parse_device_info(PedDiskAccess *const
diskaccess, PedDevice *const dev)
+{
+       char buf[512];
+       int line;
+       PED_ASSERT (diskaccess != NULL, return 0);
+       PED_ASSERT (diskaccess->mode == PED_DISKACCESS_REPLAY, return 0);
+       PED_ASSERT (diskaccess->stream != NULL, return 0);
+       PED_ASSERT (ftello(diskaccess->stream) != 0, return 0);
+
+       ped_free(dev->path);
+       dev->model = ped_malloc(sizeof(buf));
+       dev->path  = ped_malloc(sizeof(buf));
+
+       for (line=1; ! feof(diskaccess->stream); line++) {
+               READ_LINE(diskaccess->stream, buf, sizeof(buf));
+               //fprintf(stderr, "LINE %d: '%s'\n", line, buf);
+               switch (line) {
+#define LINE(_line, _dev, _member, _fmt) \
+               case _line: \
+                       if (strncmp(buf, #_member "=", strlen(#_member "=")) != 
0) \
+                               goto parse_error; \
+                       sscanf(buf, #_member "=" _fmt "\n", &_dev->_member);
+               LINE(1, dev, bios_geom.cylinders, "%d") break;
+               LINE(2, dev, bios_geom.heads,     "%d") break;
+               LINE(3, dev, bios_geom.sectors,   "%d") break;
+               LINE(4, dev, hw_geom.cylinders, "%d") break;
+               LINE(5, dev, hw_geom.heads,     "%d") break;
+               LINE(6, dev, hw_geom.sectors,   "%d") break;
+               LINE(7, dev, length, "%lld") break;
+               LINE(8, dev, sector_size, "%d") break;
+#define STR_LINE(_line, _dev, _member) \
+               case _line: \
+               { \
+                       const char *start; \
+                       char *end; \
+                       if (strncmp(buf, #_member "=", strlen(#_member "=")) != 
0) \
+                               goto parse_error; \
+                       start = strchr(buf, '=') + 1; \
+                       end   = strchr(buf, '\n'); \
+                       if (end == NULL) \
+                               goto parse_error; \
+                       *end = '\0'; \
+                       _dev->_member = strdup(start); \
+               }
+               STR_LINE(9, dev, model) break;
+               STR_LINE(10, dev, path) break;
+               LINE(11, dev, read_only, "%d") return 1;
+               default:
+                       goto parse_error;
+               }
+       }
+
+read_failed:
+parse_error:
+       ped_free(dev->model);
+       ped_free(dev->path);
+       dev->model = NULL;
+       dev->path  = NULL;
+       return 0;
+}
+
+static int ped_diskaccess_write_device_info(PedDiskAccess *const
diskaccess, const PedDevice *const dev)
+{
+       PED_ASSERT (diskaccess != NULL, return 0);
+       PED_ASSERT (diskaccess->mode == PED_DISKACCESS_REPLAY ||
diskaccess->mode == PED_DISKACCESS_RECORD, return 0);
+       PED_ASSERT (diskaccess->stream != NULL, return 0);
+
+       WRITE_ELEM(diskaccess->stream, dev, bios_geom.cylinders, "%d");
+       WRITE_ELEM(diskaccess->stream, dev, bios_geom.heads, "%d");
+       WRITE_ELEM(diskaccess->stream, dev, bios_geom.sectors, "%d");
+
+       WRITE_ELEM(diskaccess->stream, dev, hw_geom.cylinders, "%d");
+       WRITE_ELEM(diskaccess->stream, dev, hw_geom.heads, "%d");
+       WRITE_ELEM(diskaccess->stream, dev, hw_geom.sectors, "%d");
+
+       WRITE_ELEM(diskaccess->stream, dev, length, "%lld");
+       WRITE_ELEM(diskaccess->stream, dev, sector_size, "%d");
+       WRITE_ELEM(diskaccess->stream, dev, model, "%s");
+       WRITE_ELEM(diskaccess->stream, dev, path, "%s");
+
+       WRITE_ELEM(diskaccess->stream, dev, read_only, "%d");
+       return 1;
+
+write_failed:
+       return 0;
+}
+
+
+#define FILE_OFFSET_DEVICE_SECTOR_TABLE_START "#file offset=device sector\n"
+#define FILE_OFFSET_DEVICE_SECTOR_TABLE_END "\n"
+
+static int ped_diskaccess_parse_table(PedDiskAccess *const diskaccess)
+{
+       char buf[1024];
+       int first_line = 1;
+       off_t file_offset;
+       PedSector device_sector;
+       node_t *node;
+       PED_ASSERT (diskaccess != NULL, return 0);
+       PED_ASSERT (diskaccess->stream != NULL, return 0);
+       PED_ASSERT (diskaccess->root == NULL, return 0);
+       while (! feof(diskaccess->stream)) {
+               READ_LINE(diskaccess->stream, buf, sizeof(buf));
+               //fprintf(stderr, "LINE: '%s'\n", buf);
+               if (first_line) {
+                       first_line = 0;
+                       if (strcmp(buf, FILE_OFFSET_DEVICE_SECTOR_TABLE_START) 
!= 0)
+                               return 0;
+                       else
+                               continue;
+               }
+               if (strcmp(buf, FILE_OFFSET_DEVICE_SECTOR_TABLE_END) == 0)
+                       return 1;
+               sscanf(buf, "%lld=%lld\n", &file_offset, &device_sector);
+               //fprintf(stderr, "ped_diskaccess_parse_table: file_offset = 
%lld,
device_sector = %lld\n",
+                       //file_offset, device_sector);
+               node = new_node(device_sector, file_offset);
+               if (node == NULL)
+                       return 0;
+               diskaccess->root = list_insert_node(diskaccess->root, node);
+       }
+read_failed:
+       return 0;
+}
+
+
+static int walkfn_write_node(const node_t * const node, void *data)
+{
+       FILE *stream = (FILE *)data;
+       char buf[128];
+       int max = sizeof(buf)-1;
+       buf[max] = '\0';
+       snprintf(buf, max, "%lld=%lld\n", node->file_offset, 
node->device_sector);
+       PED_ASSERT (stream != NULL, return 0);
+       WRITE_STR(stream, buf);
+       return 1;
+
+write_failed:
+       return 0;
+}
+
+static int ped_diskaccess_write_table(PedDiskAccess *const diskaccess)
+{
+       PED_ASSERT (diskaccess != NULL, return 0);
+       PED_ASSERT (diskaccess->stream != NULL, return 0);
+
+       WRITE_STR(diskaccess->stream, FILE_OFFSET_DEVICE_SECTOR_TABLE_START);
+       if (! list_walk(diskaccess->root, walkfn_write_node, 
diskaccess->stream))
+               return 0;
+       WRITE_STR(diskaccess->stream, FILE_OFFSET_DEVICE_SECTOR_TABLE_END);
+       return 1;
+
+write_failed:
+       return 0;
+}
+
+
+static int ped_diskaccess_parse_start_of_file(const PedDiskAccess
*const diskaccess, off_t *device_info_offset_ptr, off_t
*table_offset_ptr)
+{
+       char buf[512];
+       int line;
+       PED_ASSERT (diskaccess != NULL, return 0);
+       PED_ASSERT (diskaccess->stream != NULL, return 0);
+       PED_ASSERT (ftello(diskaccess->stream) == 0, return 0);
+
+       for (line=1; ! feof(diskaccess->stream); line++) {
+               READ_LINE(diskaccess->stream, buf, sizeof(buf));
+               //fprintf(stderr, "LINE %d: '%s'\n", line, buf);
+               switch (line) {
+               case 1:
+                       if (strcmp(buf, "parted disk access file, format 
version 0.0\n") != 0) {
+                               fprintf(stderr, "disk access format not 
recogniced\n");
+                               return 0;
+                       }
+                       break;
+               case 2:
+                       if (strncmp(buf, "device_info_offset=", 
strlen("device_info_offset=")) != 0)
+                               return 0;
+                       sscanf(buf, "device_info_offset=%lld\n", 
device_info_offset_ptr);
+                       break;
+               case 3:
+                       if (strncmp(buf, "table_offset=", 
strlen("table_offset=")) != 0)
+                               return 0;
+                       sscanf(buf, "table_offset=%lld\n", table_offset_ptr);
+                       return 1;
+               }
+       }
+read_failed:
+       return 0;
+}
+
+static int ped_diskaccess_write_start_of_file(const PedDiskAccess
*const diskaccess, off_t device_info_offset, off_t table_offset)
+{
+       char buf[128];
+       PED_ASSERT (diskaccess != NULL, return 0);
+       PED_ASSERT (diskaccess->stream != NULL, return 0);
+
+       WRITE_STR(diskaccess->stream, "parted disk access file, format
version 0.0\n");
+       sprintf(buf, "device_info_offset=%lld\n", device_info_offset);
+       WRITE_STR(diskaccess->stream, buf);
+       sprintf(buf, "table_offset=%lld\n", table_offset);
+       WRITE_STR(diskaccess->stream, buf);
+       return 1;
+
+write_failed:
+       return 0;
+}
+
diff -urN parted-1.6.25.1.orig/libparted/linux.c
parted-1.6.25.1/libparted/linux.c
--- parted-1.6.25.1.orig/libparted/linux.c      2005-11-11 13:35:53.000000000 
+0100
+++ parted-1.6.25.1/libparted/linux.c   2005-12-05 02:04:12.000000000 +0100
@@ -22,6 +22,7 @@
 #include <parted/parted.h>
 #include <parted/debug.h>
 #include <parted/linux.h>
+#include <parted/diskaccess.h>

 #include <ctype.h>
 #include <errno.h>
@@ -710,42 +711,13 @@
 static int
 init_file (PedDevice* dev)
 {
-       struct stat     dev_stat;
-
-       if (!_device_stat (dev, &dev_stat))
-               goto error;
-       if (!ped_device_open (dev))
-               goto error;
+       if (! ped_diskaccess_set_mode(dev->diskaccess,
PED_DISKACCESS_REPLAY, dev->path))
+               return 0;

-       if (S_ISBLK(dev_stat.st_mode))
-               dev->length = _device_get_length (dev);
-       else
-               dev->length = dev_stat.st_size / 512;
-       if (dev->length <= 0) {
-               ped_exception_throw (
-                       PED_EXCEPTION_ERROR,
-                       PED_EXCEPTION_CANCEL,
-                       _("The device %s is zero-length, and can't possibly "
-                         "store a file system or partition table.  Perhaps "
-                         "you selected the wrong device?"),
-                       dev->path);
-               goto error_close_dev;
+       if (! ped_diskaccess_restore_device_info(dev->diskaccess, dev)) {
+               return 0;
        }
-
-       ped_device_close (dev);
-
-       dev->bios_geom.cylinders = dev->length / 4 / 32;
-       dev->bios_geom.heads = 4;
-       dev->bios_geom.sectors = 32;
-       dev->hw_geom = dev->bios_geom;
-       dev->sector_size = 512;
-       dev->model = strdup ("");
        return 1;
-
-error_close_dev:
-       ped_device_close (dev);
-error:
-       return 0;
 }

 static int
@@ -803,6 +775,8 @@
        return 0;
 }

+PedDiskAccessParameters linux_diskaccess_parameters;
+
 static PedDevice*
 linux_new (const char* path)
 {
@@ -823,6 +797,9 @@
        if (!dev->arch_specific)
                goto error_free_path;

+       if (! ped_diskaccess_create(&dev->diskaccess,
linux_diskaccess_parameters.mode,
linux_diskaccess_parameters.filename))
+               goto error_free_arch_specific;
+
        dev->open_count = 0;
        dev->read_only = 0;
        dev->external_mode = 0;
@@ -830,62 +807,68 @@
        dev->boot_dirty = 0;

        if (!_device_probe_type (dev))
-               goto error_free_arch_specific;
+               goto error_free_diskaccess;

        switch (dev->type) {
        case PED_DEVICE_IDE:
                if (!init_ide (dev))
-                       goto error_free_arch_specific;
+                       goto error_free_diskaccess;
                break;

        case PED_DEVICE_SCSI:
                if (!init_scsi (dev))
-                       goto error_free_arch_specific;
+                       goto error_free_diskaccess;
                break;

        case PED_DEVICE_DAC960:
                if (!init_generic (dev, _("DAC960 RAID controller")))
-                       goto error_free_arch_specific;
+                       goto error_free_diskaccess;
                break;

        case PED_DEVICE_CPQARRAY:
                if (!init_generic (dev, _("Compaq Smart Array")))
-                       goto error_free_arch_specific;
+                       goto error_free_diskaccess;
                break;

        case PED_DEVICE_ATARAID:
                if (!init_generic (dev, _("ATARAID Controller")))
-                       goto error_free_arch_specific;
+                       goto error_free_diskaccess;
                break;

        case PED_DEVICE_I2O:
                if (!init_generic (dev, _("I2O Controller")))
-                       goto error_free_arch_specific;
+                       goto error_free_diskaccess;
                break;

        case PED_DEVICE_UBD:
                if (!init_generic (dev, _("User-Mode Linux UBD")))
-                       goto error_free_dev;
+                       goto error_free_diskaccess;
                break;

        case PED_DEVICE_FILE:
+               if (linux_diskaccess_parameters.mode == PED_DISKACCESS_RECORD) {
+                       fprintf(stderr, "you cannot use both record and replay 
at the same time\n");
+                       goto error_free_diskaccess;
+               }
                if (!init_file (dev))
-                       goto error_free_arch_specific;
+                       goto error_free_diskaccess;
                break;

        case PED_DEVICE_UNKNOWN:
                if (!init_generic (dev, _("Unknown")))
-                       goto error_free_arch_specific;
+                       goto error_free_diskaccess;
                break;

        default:
                ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
                                PED_EXCEPTION_CANCEL,
                                _("ped_device_new()  Unsupported device type"));
-               goto error_free_arch_specific;
+               goto error_free_diskaccess;
        }
        return dev;

+error_free_diskaccess:
+       ped_diskaccess_destroy(&dev->diskaccess);
 error_free_arch_specific:
        ped_free (dev->arch_specific);
 error_free_path:
@@ -968,7 +951,7 @@
 }

 static int
-linux_open (PedDevice* dev)
+linux_open_normal (PedDevice* dev)
 {
        LinuxSpecific*  arch_specific = LINUX_SPECIFIC (dev);

@@ -1008,13 +991,35 @@
 }

 static int
+linux_open (PedDevice* dev)
+{
+       int status;
+       switch (ped_diskaccess_get_mode(dev->diskaccess)) {
+       default:
+       case PED_DISKACCESS_NORMAL:
+               status = linux_open_normal(dev);
+               break;
+       case PED_DISKACCESS_REPLAY:
+               status = 1;
+               ped_diskaccess_open(dev->diskaccess);
+               break;
+       case PED_DISKACCESS_RECORD:
+               status = linux_open_normal(dev);
+               if (status)
+                       ped_diskaccess_open(dev->diskaccess);
+               break;
+       };
+       return status;
+}
+
+static int
 linux_refresh_open (PedDevice* dev)
 {
        return 1;
 }

 static int
-linux_close (PedDevice* dev)
+linux_close_normal (PedDevice* dev)
 {
        LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);

@@ -1025,6 +1030,28 @@
 }

 static int
+linux_close (PedDevice* dev)
+{
+       int status;
+       switch (ped_diskaccess_get_mode(dev->diskaccess)) {
+       default:
+       case PED_DISKACCESS_NORMAL:
+               status = linux_close_normal(dev);
+               break;
+       case PED_DISKACCESS_REPLAY:
+               status = 1;
+               ped_diskaccess_close(dev->diskaccess, dev);
+               break;
+       case PED_DISKACCESS_RECORD:
+               status = linux_close_normal(dev);
+               if (status)
+                       ped_diskaccess_close(dev->diskaccess, dev);
+               break;
+       };
+       return status;
+}
+
+static int
 linux_refresh_close (PedDevice* dev)
 {
        if (dev->dirty)
@@ -1113,7 +1140,7 @@
 }

 static int
-linux_read (PedDevice* dev, void* buffer, PedSector start, PedSector count)
+linux_read_normal (PedDevice* dev, void* buffer, PedSector start,
PedSector count)
 {
        LinuxSpecific*          arch_specific = LINUX_SPECIFIC (dev);
        int                     status;
@@ -1189,6 +1216,27 @@
 }

 static int
+linux_read (PedDevice* dev, void* buffer, PedSector start, PedSector count)
+{
+       int status;
+       switch (ped_diskaccess_get_mode(dev->diskaccess)) {
+       default:
+       case PED_DISKACCESS_NORMAL:
+               status = linux_read_normal(dev, buffer, start, count);
+               break;
+       case PED_DISKACCESS_REPLAY:
+               status = ped_diskaccess_load_sectors(dev->diskaccess, dev, 
buffer,
start, count);
+               break;
+       case PED_DISKACCESS_RECORD:
+               status = linux_read_normal(dev, buffer, start, count);
+               if (status)
+                       status = ped_diskaccess_save_sectors(dev->diskaccess, 
dev, buffer,
start, count);
+               break;
+       };
+       return status;
+}
+
+static int
 _write_lastoddsector (PedDevice* dev, const void* buffer)
 {
        LinuxSpecific*                  arch_specific;
diff -urN parted-1.6.25.1.orig/libparted/Makefile.am
parted-1.6.25.1/libparted/Makefile.am
--- parted-1.6.25.1.orig/libparted/Makefile.am  2005-11-11
13:35:53.000000000 +0100
+++ parted-1.6.25.1/libparted/Makefile.am       2005-12-04 16:02:12.000000000 
+0100
@@ -44,6 +44,7 @@
                        disk_pc98.c             \
                        disk_sun.c              \
                        disk_amiga.c            \
+                       diskaccess.c            \
                        @address@hidden

 EXTRA_libparted_la_SOURCES    = linux.c                \
diff -urN parted-1.6.25.1.orig/libparted/Makefile.in
parted-1.6.25.1/libparted/Makefile.in
--- parted-1.6.25.1.orig/libparted/Makefile.in  2005-11-11
13:38:44.000000000 +0100
+++ parted-1.6.25.1/libparted/Makefile.in       2005-12-04 16:14:54.000000000 
+0100
@@ -71,7 +71,7 @@
        exception.lo filesys.lo geom.lo libparted.lo natmath.lo \
        timer.lo unit.lo disk.lo disk_bsd.lo disk_dos.lo disk_gpt.lo \
        disk_loop.lo disk_mac.lo disk_dvh.lo disk_pc98.lo disk_sun.lo \
-       disk_amiga.lo @address@hidden
+       disk_amiga.lo diskaccess.lo @address@hidden
 libparted_la_OBJECTS = $(am_libparted_la_OBJECTS)
 DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
 depcomp = $(SHELL) $(top_srcdir)/depcomp
@@ -256,6 +256,7 @@
                        disk_pc98.c             \
                        disk_sun.c              \
                        disk_amiga.c            \
+                       diskaccess.c            \
                        @address@hidden

 EXTRA_libparted_la_SOURCES = linux.c           \
@@ -361,6 +362,7 @@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
address@hidden@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
diff -urN parted-1.6.25.1.orig/parted/parted.c parted-1.6.25.1/parted/parted.c
--- parted-1.6.25.1.orig/parted/parted.c        2005-11-11 13:32:14.000000000 
+0100
+++ parted-1.6.25.1/parted/parted.c     2005-12-05 02:34:35.000000000 +0100
@@ -33,6 +33,7 @@

 #include <parted/parted.h>
 #include <parted/debug.h>
+#include <parted/diskaccess.h>

 #include <ctype.h>
 #include <stdarg.h>
@@ -1738,10 +1739,10 @@
        while (1)
        {
 #ifdef HAVE_GETOPT_H
-               opt = getopt_long (*argc_ptr, *argv_ptr, "hisv",
+               opt = getopt_long (*argc_ptr, *argv_ptr, "hisvr:",
                                   options, NULL);
 #else
-               opt = getopt (*argc_ptr, *argv_ptr, "hisv");
+               opt = getopt (*argc_ptr, *argv_ptr, "hisvr:");
 #endif
                if (opt == -1)
                        break;
@@ -1751,6 +1752,10 @@
                        case 'i': opt_script_mode = 0; break;
                        case 's': opt_script_mode = 1; break;
                        case 'v': _version (); break;
+                       case 'r':
+                               linux_diskaccess_parameters.mode = 
PED_DISKACCESS_RECORD;
+                               linux_diskaccess_parameters.filename = optarg;
+                               break;
                }
        }




reply via email to

[Prev in Thread] Current Thread [Next in Thread]