Em um sistema RHEL mais antigo que eu tenho, não/bin/cat faz loop para . dá a mensagem de erro "cat: x: arquivo de entrada é arquivo de saída". I pode enganar , fazendo isso: . Quando tento seu código acima, recebo o "loop" que você descreve. Também escrevi um "gato" baseado em chamada de sistema:cat x >> xcat/bin/catcat < x >> x
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int
main(int ac, char **av)
{
char buf[4906];
int fd, cc;
fd = open(av[1], O_RDONLY);
while ((cc = read(fd, buf, sizeof(buf))) > 0)
if (cc > 0) write(1, buf, cc);
close(fd);
return 0;
}
Isso dá laços também. O único buffer aqui (ao contrário do "mycat" baseado em stdio) é o que acontece no kernel.
Acho que o que está acontecendo é que o descritor de arquivo 3 (o resultado de open(av[1])) tem um deslocamento no arquivo de 0. O descritor arquivado 1 (stdout) tem um deslocamento de 3, porque o ">>" faz com que o shell de chamada faça um lseek()no descritor de arquivo antes de entregá-lo ao catprocesso filho.
Executar read()qualquer tipo, seja em um buffer stdio ou em uma planilha, char buf[]avança a posição do descritor de arquivo 3. Executar a write()avança a posição do descritor de arquivo 1. Esses dois deslocamentos são números diferentes. Por causa do ">>", o descritor de arquivo 1 sempre tem um deslocamento maior ou igual ao deslocamento do descritor de arquivo 3. Portanto, qualquer programa "semelhante a um gato" fará um loop, a menos que faça algum buffer interno. É possível, talvez até provável, que uma implementação stdio de a FILE *(que é o tipo dos símbolos stdoute fno seu código) inclua seu próprio buffer. fread()pode realmente fazer uma chamada do sistema read()para preencher o buffer interno fo f. Isso pode ou não mudar nada no interior de stdout. chamando fwrite()emstdoutpode ou não alterar nada dentro de f. Portanto, um "gato" baseado em stdio pode não ser repetido. Ou pode. Difícil dizer sem ler muitos códigos libc feios e feios.
Eu fiz uma straceno RHEL cat- ele só faz uma sucessão de read()e write()chamadas do sistema. Mas a catnão precisa funcionar dessa maneira. Seria possível para mmap()o arquivo de entrada, então faça write(1, mapped_address, input_file_size). O kernel faria todo o trabalho. Ou você pode fazer uma sendfile()chamada do sistema entre os descritores de arquivo de entrada e saída nos sistemas Linux. Dizia-se que os antigos sistemas SunOS 4.x faziam o truque de mapeamento de memória, mas não sei se alguém já fez um gato baseado em arquivo de envio. Em ambos os casos, o "loop" não aconteceria, pois ambos write()e sendfile()requerem um parâmetro de comprimento para transferir.