era_apply tool to apply the resulting stream
parent
78aa7004e4
commit
54b48b75e7
4
Makefile
4
Makefile
|
@ -1,3 +1,5 @@
|
|||
all: era_copy
|
||||
all: era_copy era_apply
|
||||
era_copy: era_copy.c
|
||||
gcc -o era_copy -Wall era_copy.c
|
||||
era_apply: era_apply.c
|
||||
gcc -o era_apply -Wall era_apply.c
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
/**
|
||||
* Applies `era_copy` output to a file or block device
|
||||
*
|
||||
* Author: Vitaliy Filippov <vitalif@yourcmc.ru>, 2019
|
||||
* License: GNU GPLv3.0 or later
|
||||
*/
|
||||
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define XML_BUFSIZE 1024
|
||||
#define COPY_BUFSIZE 0x400000
|
||||
#define SIGNATURE "ERARANGE"
|
||||
|
||||
static void* copy_buffer = NULL;
|
||||
|
||||
void apply_blocks(int src, int dst, off64_t start, off64_t length)
|
||||
{
|
||||
off64_t copied = 0;
|
||||
ssize_t fact = 0, written = 0, fact_write = 0;
|
||||
if (!copy_buffer)
|
||||
{
|
||||
copy_buffer = malloc(COPY_BUFSIZE);
|
||||
if (!copy_buffer)
|
||||
{
|
||||
fprintf(stderr, "Failed to allocate %d bytes\n", COPY_BUFSIZE);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (lseek64(dst, start, 0) < 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to lseek in output file: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
while (length > copied)
|
||||
{
|
||||
fact = read(src, copy_buffer, length-copied > COPY_BUFSIZE ? COPY_BUFSIZE : length-copied);
|
||||
if (fact <= 0)
|
||||
{
|
||||
fprintf(stderr, "Read error: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
written = 0;
|
||||
while (written < fact)
|
||||
{
|
||||
fact_write = write(dst, copy_buffer, fact-written);
|
||||
if (fact_write <= 0)
|
||||
{
|
||||
fprintf(stderr, "Write error: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
written += fact_write;
|
||||
}
|
||||
copied += fact;
|
||||
}
|
||||
}
|
||||
|
||||
void read_era_copy_and_apply(int src, int dst)
|
||||
{
|
||||
long long sign = 0, start = 0, length = 0;
|
||||
int r;
|
||||
while (1)
|
||||
{
|
||||
r = read(src, &sign, 8);
|
||||
if (r == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (r < 8 ||
|
||||
read(src, &start, 8) < 8 ||
|
||||
read(src, &length, 8) < 8)
|
||||
{
|
||||
if (errno)
|
||||
fprintf(stderr, "read error: %s\n", strerror(errno));
|
||||
else
|
||||
fprintf(stderr, "premature end of file\n");
|
||||
exit(1);
|
||||
}
|
||||
if (sign != *((long long*)SIGNATURE))
|
||||
{
|
||||
fprintf(stderr, "era_copy signature does not match\n");
|
||||
exit(1);
|
||||
}
|
||||
apply_blocks(src, dst, start, length);
|
||||
}
|
||||
}
|
||||
|
||||
void era_apply(char *dst_path)
|
||||
{
|
||||
struct stat sb;
|
||||
int dst;
|
||||
if (stat(dst_path, &sb) != 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to stat %s: %s\n", dst_path, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
// prevent writing to mounted devices
|
||||
dst = open(dst_path, ((sb.st_mode & S_IFBLK) ? O_EXCL : 0) | O_WRONLY | O_LARGEFILE);
|
||||
if (dst < 0)
|
||||
{
|
||||
fprintf(stderr, "Failed to open %s for writing: %s\n", dst_path, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
read_era_copy_and_apply(0, dst);
|
||||
// fsync and close
|
||||
fsync(dst);
|
||||
close(dst);
|
||||
}
|
||||
|
||||
int main(int narg, char *args[])
|
||||
{
|
||||
if (narg < 2)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"era_apply - applies era_copy output to a file or block device\n"
|
||||
"(c) Vitaliy Filippov, 2019+, distributed under the terms of GNU GPLv3.0 or later license\n"
|
||||
"\n"
|
||||
"USAGE:\nera_apply DESTINATION < era_copy_output.bin\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
era_apply(args[1]);
|
||||
return 0;
|
||||
}
|
10
era_copy.c
10
era_copy.c
|
@ -21,6 +21,7 @@
|
|||
|
||||
#define XML_BUFSIZE 1024
|
||||
#define MAX_COPY 0x10000000
|
||||
#define SIGNATURE "ERARANGE"
|
||||
|
||||
void copy_blocks(int src, int dst, off64_t start, off64_t length)
|
||||
{
|
||||
|
@ -42,7 +43,6 @@ void copy_blocks(int src, int dst, off64_t start, off64_t length)
|
|||
void read_era_invalidate_and_copy(FILE *fp, int src, int era_block_size)
|
||||
{
|
||||
// read input XML
|
||||
char* signature = "ERARANGE";
|
||||
char buf[XML_BUFSIZE] = { 0 };
|
||||
char c = 0;
|
||||
long long start = 0, length = 0;
|
||||
|
@ -72,8 +72,8 @@ void read_era_invalidate_and_copy(FILE *fp, int src, int era_block_size)
|
|||
}
|
||||
start = start*era_block_size;
|
||||
length = length*era_block_size;
|
||||
// write a very simple binary format: signature, start, length, data, ...
|
||||
write(1, signature, 8);
|
||||
// write a very simple binary format: SIGNATURE, start, length, data, ...
|
||||
write(1, SIGNATURE, 8);
|
||||
write(1, &start, 8);
|
||||
write(1, &length, 8);
|
||||
copy_blocks(src, 1, start, length);
|
||||
|
@ -103,11 +103,11 @@ int main(int narg, char *args[])
|
|||
if (narg < 3)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"era_copy - parses era_invalidate output and copies specified blocks from one file/device to another\n"
|
||||
"era_copy - parses era_invalidate output and saves changed blocks to a stream\n"
|
||||
"(c) Vitaliy Filippov, 2019+, distributed under the terms of GNU GPLv3.0 or later license\n"
|
||||
"\n"
|
||||
"USAGE:\nera_invalidate --metadata-snapshot --written-since <ERA> <META_DEVICE> |\\\n"
|
||||
" era_copy <ERA_BLOCK_SIZE> <DATA_DEVICE>\n"
|
||||
" era_copy <ERA_BLOCK_SIZE> <DATA_DEVICE> > era_copy.bin\n"
|
||||
"\n"
|
||||
"ERA_BLOCK_SIZE is the block size you used when creating dm-era device\n"
|
||||
"You can take it from `dmsetup table <DATA_DEVICE>`: it's the last number in the table\n"
|
||||
|
|
Loading…
Reference in New Issue