Por que isso funciona: “cp image.bin / dev / mapper / loop0p1”?

2

Por que isso funciona?

cp image.bin /dev/mapper/loop0p1

image.bin é uma imagem de partição.

Eu tentei e funciona, mas por quê? Não deve ser usado um dd ?

    
por Guerrio 17.04.2013 / 13:03

3 respostas

3

GNU coreutils cp funciona porque foi escrito dessa maneira. Escrever para dispositivos de bloco não é complicado, é essencialmente a mesma operação que gravar em um arquivo normal.

No entanto, você não deve usar cp dessa maneira. Você pode fazer isso se tiver certeza que é GNU coreutils, o que funciona. Mas existem outros tipos de cp , por exemplo, busybox cp não suporta a gravação em dispositivos; ele desassocia (elimina) o nó do dispositivo e cria um novo arquivo em seu lugar.

dd é mais seguro a esse respeito. Ele foi feito para escrever em dispositivos e traz as ferramentas (bs, seek, skip, count, ...) que você precisa ao lidar com dispositivos. Deve fazer o esperado em todos os sabores de dd .

    
por 17.04.2013 / 13:53
2

Sua expectativa difere do design do programa / sistema. O que devemos dizer sobre isso? : -)

"Tudo é um arquivo" ...

Você pode executar cp e / ou dd através de strace -e trace=open e verá que o syscall é o mesmo para arquivos regulares e dispositivos de bloco. Se o syscall não diferenciá-lo, por que o cuidado deve ser feito?

    
por 17.04.2013 / 13:24
2

Bem, até onde eu sei, tudo o que o cp faz é

  • abre o arquivo de destino no modo de gravação
  • escreva os dados do arquivo de origem no arquivo de destino (não tenho certeza sobre o tamanho do fragmento, mas são apenas detalhes)

Com arquivos normais, isso pode resultar em

  • criando um novo arquivo que crescerá com cada chamada de gravação
  • Sobrescrevendo um arquivo existente que será sobrescrito:
    A primeira chamada de gravação apagará o conteúdo do arquivo e colocará os novos dados nele. A partir desse ponto, o arquivo cresce exatamente como se fosse novo.

Agora / dev / mapper / * são dispositivos de bloco (ou, para ser específico, links simbólicos para bloquear dispositivos). Aqueles têm tamanhos de arquivos estáticos. Portanto, se você abrir esses arquivos, cada write() irá simplesmente sobrescrever os n bytes do arquivo de destino que você enviou para ele (assumindo que não há fseek() em qualquer lugar).

Então, vamos escrever nosso próprio pobre homem:

#include <stdlib.h>
#include <stdio.h>

void usage() {fprintf(stderr, "Usage: cp <srcFile> <tgtFile>\n"); exit(1);}
void error(const char *msg) {fprintf(stderr, "Error: %s\n", msg); exit(2);}

void printPosAndSize(FILE *f) {
    off_t curPos = ftello(f);
    fseeko(f, 0, SEEK_END);
    off_t size = ftell(f);
    fseeko(f, curPos, SEEK_SET);
    printf("Pos: %llu,\tSize: %llu\n", curPos, size);
}

int main(int argc, const char *argv[]) {
    if (argc != 3) usage();

    const char *srcPath = argv[1];
    const char *tgtPath = argv[2];

    FILE *inFile = fopen(srcPath, "rb");
    FILE *outFile = fopen(tgtPath, "wb");

    printf("inFile: %s, outfile: %s\n", srcPath, tgtPath);

    if (!inFile) error("Couldn't open source file!");
    if (!outFile) error("Couldn't open target file!");

    while (!feof(inFile)) {
        char buff[2048];
        size_t count = fread(buff, 1, sizeof(buff), inFile);
        fwrite(buff, 1, count, outFile);
        printPosAndSize(outFile);
    }

    fclose(inFile);
    fclose(outFile);

    return 0;
}

Este cp irá escrever 2048 pedaços de bytes de arquivo1 para arquivo2. Se você acabou de copiar arquivos regulares, a saída ficará assim:

# copying to new file:
$ sudo ./cp /var/log/syslog /tmp/foo.txt 
inFile: /var/log/syslog, outfile: /tmp/foo.txt
Pos: 2048,      Size: 2048
Pos: 4096,      Size: 4096
Pos: 4949,      Size: 4949

# overwriting existing file:
$ sudo ./cp /var/log/syslog /tmp/foo.txt 
inFile: /var/log/syslog, outfile: /tmp/foo.txt
Pos: 2048,      Size: 2048
Pos: 4096,      Size: 4096
Pos: 4949,      Size: 4949

Estou executando duas vezes para mostrar que não importa se o arquivo de destino existia antes de abri-lo no modo de gravação. Assim que você escreve, seu conteúdo é totalmente sobrescrito e o tamanho do arquivo reflete isso.

Então, vamos tentar algo diferente:     $ sudo ./cp / var / log / syslog / dev / null     inFile: / var / log / syslog, outfile: / dev / null     Pos: 0, tamanho: 0     Pos: 2048, tamanho: 0     Pos: 974, tamanho: 0

/dev/null é um dispositivo de caractere. Esses sempre têm tamanho 0. A saída é simplesmente escrita para eles (por exemplo, para a porta serial) e esquecida depois.

Mas vamos à sua pergunta: O que acontece se você gravar em um dispositivo de bloco ( Cuidado! Executar isso tornará todos os dados no dispositivo ilegíveis, pois destrói as meta informações da unidade! I ' ve usado uma unidade USB antiga para esta demonstração)

$ sudo ./cp /var/log/syslog /dev/sdb
inFile: /var/log/syslog, outfile: /dev/sdb
Pos: 2048,      Size: 2003828736
Pos: 4096,      Size: 2003828736
Pos: 5306,      Size: 2003828736

O arquivo de bloco é simplesmente aberto na posição 0 e substituído byte por byte (sem tocar em todos os outros dados).

    
por 17.04.2013 / 13:25