summaryrefslogtreecommitdiffstats
path: root/mtdutils/mtdutils.c
diff options
context:
space:
mode:
Diffstat (limited to 'mtdutils/mtdutils.c')
-rw-r--r--mtdutils/mtdutils.c223
1 files changed, 211 insertions, 12 deletions
diff --git a/mtdutils/mtdutils.c b/mtdutils/mtdutils.c
index 107cbb9a8..a76b8e992 100644
--- a/mtdutils/mtdutils.c
+++ b/mtdutils/mtdutils.c
@@ -28,13 +28,6 @@
#include "mtdutils.h"
-struct MtdPartition {
- int device_index;
- unsigned int size;
- unsigned int erase_size;
- char *name;
-};
-
struct MtdReadContext {
const MtdPartition *partition;
char *buffer;
@@ -328,8 +321,8 @@ static int read_block(const MtdPartition *partition, int fd, char *data)
ssize_t mtd_read_data(MtdReadContext *ctx, char *data, size_t len)
{
- size_t read = 0;
- while (read < len) {
+ ssize_t read = 0;
+ while (read < (int) len) {
if (ctx->consumed < ctx->partition->erase_size) {
size_t avail = ctx->partition->erase_size - ctx->consumed;
size_t copy = len - read < avail ? len - read : avail;
@@ -345,12 +338,12 @@ ssize_t mtd_read_data(MtdReadContext *ctx, char *data, size_t len)
read += ctx->partition->erase_size;
}
- if (read >= len) {
+ if (read >= (int)len) {
return read;
}
// Read the next block into the buffer
- if (ctx->consumed == ctx->partition->erase_size && read < len) {
+ if (ctx->consumed == ctx->partition->erase_size && read < (int) len) {
if (read_block(ctx->partition, ctx->fd, ctx->buffer)) return -1;
ctx->consumed = 0;
}
@@ -457,7 +450,7 @@ static int write_block(MtdWriteContext *ctx, const char *data)
if (retry > 0) {
fprintf(stderr, "mtd: wrote block after %d retries\n", retry);
}
- fprintf(stderr, "mtd: successfully wrote block at %lx\n", pos);
+ fprintf(stderr, "mtd: successfully wrote block at %llx\n", pos);
return 0; // Success!
}
@@ -569,3 +562,209 @@ off_t mtd_find_write_start(MtdWriteContext *ctx, off_t pos) {
}
return pos;
}
+
+#define BLOCK_SIZE 2048
+#define SPARE_SIZE (BLOCK_SIZE >> 5)
+#define HEADER_SIZE 2048
+
+int cmd_mtd_restore_raw_partition(const char *partition_name, const char *filename)
+{
+ const MtdPartition *ptn;
+ MtdWriteContext *write;
+ void *data;
+
+ FILE* f = fopen(filename, "rb");
+ if (f == NULL) {
+ fprintf(stderr, "error opening %s", filename);
+ return -1;
+ }
+
+ if (mtd_scan_partitions() <= 0)
+ {
+ fprintf(stderr, "error scanning partitions");
+ return -1;
+ }
+ const MtdPartition *mtd = mtd_find_partition_by_name(partition_name);
+ if (mtd == NULL)
+ {
+ fprintf(stderr, "can't find %s partition", partition_name);
+ return -1;
+ }
+
+ int fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ {
+ printf("error opening %s", filename);
+ return -1;
+ }
+
+ MtdWriteContext* ctx = mtd_write_partition(mtd);
+ if (ctx == NULL) {
+ printf("error writing %s", partition_name);
+ return -1;
+ }
+
+ int success = 1;
+ char* buffer = malloc(BUFSIZ);
+ int read;
+ while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) {
+ int wrote = mtd_write_data(ctx, buffer, read);
+ success = success && (wrote == read);
+ }
+ free(buffer);
+ fclose(f);
+
+ if (!success) {
+ fprintf(stderr, "error writing %s", partition_name);
+ return -1;
+ }
+
+ if (mtd_erase_blocks(ctx, -1) == -1) {
+ fprintf(stderr, "error erasing blocks of %s\n", partition_name);
+ }
+ if (mtd_write_close(ctx) != 0) {
+ fprintf(stderr, "error closing write of %s\n", partition_name);
+ }
+ printf("%s %s partition\n", success ? "wrote" : "failed to write", partition_name);
+ return 0;
+}
+
+
+int cmd_mtd_backup_raw_partition(const char *partition_name, const char *filename)
+{
+ MtdReadContext *in;
+ const MtdPartition *partition;
+ char buf[BLOCK_SIZE + SPARE_SIZE];
+ size_t partition_size;
+ size_t read_size;
+ size_t total;
+ int fd;
+ int wrote;
+ int len;
+
+ if (mtd_scan_partitions() <= 0)
+ {
+ printf("error scanning partitions");
+ return -1;
+ }
+
+ partition = mtd_find_partition_by_name(partition_name);
+ if (partition == NULL)
+ {
+ printf("can't find %s partition", partition_name);
+ return -1;
+ }
+
+ if (mtd_partition_info(partition, &partition_size, NULL, NULL)) {
+ printf("can't get info of partition %s", partition_name);
+ return -1;
+ }
+
+ if (!strcmp(filename, "-")) {
+ fd = fileno(stdout);
+ }
+ else {
+ fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666);
+ }
+
+ if (fd < 0)
+ {
+ printf("error opening %s", filename);
+ return -1;
+ }
+
+ in = mtd_read_partition(partition);
+ if (in == NULL) {
+ close(fd);
+ unlink(filename);
+ printf("error opening %s: %s\n", partition_name, strerror(errno));
+ return -1;
+ }
+
+ total = 0;
+ while ((len = mtd_read_data(in, buf, BLOCK_SIZE)) > 0) {
+ wrote = write(fd, buf, len);
+ if (wrote != len) {
+ close(fd);
+ unlink(filename);
+ printf("error writing %s", filename);
+ return -1;
+ }
+ total += BLOCK_SIZE;
+ }
+
+ mtd_read_close(in);
+
+ if (close(fd)) {
+ unlink(filename);
+ printf("error closing %s", filename);
+ return -1;
+ }
+ return 0;
+}
+
+int cmd_mtd_erase_raw_partition(const char *partition_name)
+{
+ MtdWriteContext *out;
+ size_t erased;
+ size_t total_size;
+ size_t erase_size;
+
+ if (mtd_scan_partitions() <= 0)
+ {
+ printf("error scanning partitions");
+ return -1;
+ }
+ const MtdPartition *p = mtd_find_partition_by_name(partition_name);
+ if (p == NULL)
+ {
+ printf("can't find %s partition", partition_name);
+ return -1;
+ }
+
+ out = mtd_write_partition(p);
+ if (out == NULL)
+ {
+ printf("could not estabilish write context for %s", partition_name);
+ return -1;
+ }
+
+ // do the actual erase, -1 = full partition erase
+ erased = mtd_erase_blocks(out, -1);
+
+ // erased = bytes erased, if zero, something borked
+ if (!erased)
+ {
+ printf("error erasing %s", partition_name);
+ return -1;
+ }
+
+ return 0;
+}
+
+int cmd_mtd_erase_partition(const char *partition, const char *filesystem)
+{
+ return cmd_mtd_erase_raw_partition(partition);
+}
+
+
+int cmd_mtd_mount_partition(const char *partition, const char *mount_point, const char *filesystem, int read_only)
+{
+ mtd_scan_partitions();
+ const MtdPartition *p;
+ p = mtd_find_partition_by_name(partition);
+ if (p == NULL) {
+ return -1;
+ }
+ return mtd_mount_partition(p, mount_point, filesystem, read_only);
+}
+
+int cmd_mtd_get_partition_device(const char *partition, char *device)
+{
+ mtd_scan_partitions();
+ MtdPartition *p = mtd_find_partition_by_name(partition);
+ if (p == NULL)
+ return -1;
+ sprintf(device, "/dev/block/mtdblock%d", p->device_index);
+ return 0;
+}