저는 dd
이를 소프트웨어 구성 제어 수단으로 광범위하게 사용합니다. 이러한 이미지는 일반적으로 장치를 업데이트하기 위해 플래시 드라이브에 배포됩니다. 나는 종종 이미지 파일에 작은 증분 업데이트를 한 다음 전체 이미지를 블록 장치에 다시 복사해야 한다는 것을 알게 되었습니다. 이미지 크기가 일반적으로 8GB이므로 시간이 많이 걸립니다. 설상가상으로 일단 조립된 이미지는 설치하기 쉬운 형식이 아닙니다. 즉, 블록에서 직접 변경을 수행하는 것은 불가능합니다.
이미지 파일을 블록 장치와 비교하여 업데이트가 필요한 블록만 업데이트할 수 있는 방법이 있는지 알아보고 있습니다. 나는 이것이 전체 디스크에 쓰는 것보다 훨씬 빠를 것이라고 생각합니다. 이는 아마도 이미지 파일에서 10kb 증가에 달할 것이기 때문입니다.
답변1
다음은 두 개의 파일(파일 1, 파일 2)을 블록별로 비교하고, 블록이 다른 경우 해당 블록을 파일 1에서 파일 2로 복사하는 작은 C 프로그램의 빠른 해킹입니다. 파일 및 블록 장치에서도 작동합니다. 원하는 대로 하세요. 단, 위험은 본인 부담입니다!
/*
Small program to blockwise compare two files and write different
blocks from file1 to file2.
Arguments: file1, file2, blocksize in bytes
If blocksize is not given, it is set to 512 (minimum)
No error checking, no intensive tests run - use at your own risk!
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(argc, argv)
int argc;
char *argv[];
{
char *fnamein; /* Input file name */
char *fnameout; /* Output file name */
char *bufin; /* Input buffer */
char *bufout; /* Output buffer */
int bufsize; /* Buffer size (blocksize) */
int fdin; /* Input file descriptor*/
int fdout; /* Output file descriptor*/
int cnt; /* Current block # */
/* Argument processing */
if (argc < 3 || argc > 4) {
fprintf(stderr,"Usage: %s infile outfile [bufsize]\n", argv[0]);
exit(1);
}
fnamein = argv[1];
fnameout = argv[2];
if (argc == 4) {
bufsize = atoi(argv[3]);
if (bufsize < 512) {
fprintf(stderr,"Error: Illegal value for [bufsize]: %s\n", argv[3]);
exit(1);
}
} else {
bufsize = 512;
}
fprintf(stderr, "Copying differing blocks from '%s' to '%s', blocksize is %i\n", fnamein, fnameout, bufsize);
if (! ((bufin = malloc(bufsize)) && (bufout = malloc(bufsize)))) {
fprintf(stderr,"Error: Can't allocate buffers: %i\n", bufsize);
exit(1);
}
fdin = open(fnamein, O_RDONLY);
if (fdin < 0) {
fprintf(stderr,"Error: Can't open input file: %s\n", fnamein);
exit(1);
}
fdout = open(fnameout, O_RDWR | O_SYNC);
if (fdout < 0) {
fprintf(stderr,"Error: Can't open ouput file: %s\n", fnameout);
exit(1);
}
cnt = 0;
while (read(fdin, bufin, bufsize) == bufsize) {
if (read(fdout, bufout, bufsize) == bufsize) {
if (memcmp(bufin, bufout, bufsize) != 0) {
fprintf(stderr, "Differing blocks at block # %i; writing block to %s\n", cnt, fnameout);
if (lseek(fdout, -bufsize, SEEK_CUR) > -1) {
if (write(fdout, bufin, bufsize) != bufsize) {
fprintf(stderr,"Error: Unable to write to output file %s block # %i\n", fnameout, cnt);
exit(1);
}
} else {
fprintf(stderr,"Error: Unable to seek to output file %s block # %i\n", fnameout, cnt);
exit(1);
}
}
} else {
fprintf(stderr,"Error: Unable to read from ouput file %s block # %i\n", fnameout, cnt);
exit(1);
}
cnt++;
}
exit(0);
}
답변2
qemu-img를 보면 원본 파일을 백업 파일로 사용하고 qcow2 형식의 차등디스크를 생성해줍니다.
qemu-nbd를 사용하여 블록 장치로 액세스합니다(nbd 장치로 변환).
그러면 델타가 qcow2 차등 디스크에 기록되고 원본 데이터가 보존됩니다. 변경된 각 블록에 대해 차등 디스크는 더 작은 값만큼 증가합니다.
그런 다음 이러한 델타를 하나 이상의 "원본 파일"에 적용하려면 "커밋" qemu-img 작업을 사용하세요.
답변3
글쎄, 귀하의 질문에 대한 의견에서 언급했듯이 dd
매개변수 bs
, seek
및 skip
는 count
귀하의 친구입니다. 또한 이미지를 일련의 적절한 크기의 청크(예: 청크당 10Mb)로 논리적으로 나누고 각 청크의 md5sum(또는 충돌이 걱정되는 경우 더 긴 해시)을 유지 관리합니다. 새 이미지가 나타나면 해시와 새 이미지를 확인하고(비교 시간을 효과적으로 절반으로 줄임) 변경된 블록만 디스크에 복사하면 됩니다. 일부 블록이 동일하고(모두 0일 수도 있음) 그에 따라 추가 최적화를 수행할 수도 있습니다.