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).