В более старой системе RHEL, которая у меня есть, цикл не/bin/cat выполняется . выдает сообщение об ошибке «cat: x: input file is output file». Я могу обмануть , делая это . Когда я пробую ваш код выше, я получаю "зацикливание", которое вы описываете. Я также написал системный вызов на основе «кота»: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;
}
Это петли тоже. Единственная буферизация здесь (в отличие от "mycat" на основе stdio) - это то, что происходит в ядре.
Я думаю, что происходит то, что файловый дескриптор 3 (результат open(av[1])) имеет смещение в файл 0. Файловый дескриптор 1 (stdout) имеет смещение 3, потому что ">>" заставляет вызывающую оболочку делать lseek()на дескриптор файла перед передачей его catдочернему процессу.
Выполнение read()любого вида, будь то в stdio-буфере или обычном char buf[]улучшении позиции файлового дескриптора 3. Выполнение write()улучшении позиции файлового дескриптора 1. Эти два смещения - это разные числа. Из-за «>>» файловый дескриптор 1 всегда имеет смещение, большее или равное смещению файлового дескриптора 3. Таким образом, любая «подобная кошке» программа будет зацикливаться, если она не выполняет некоторую внутреннюю буферизацию. Возможно, возможно даже вероятно, что реализация stdio FILE *(которая является типом символов stdoutи fв вашем коде), которая включает в себя свой собственный буфер. fread()может на самом деле сделать системный вызов read()для заполнения внутреннего буфера fo f.stdout . Вызов fwrite()наstdoutможет или не может изменить что-либо внутриf, Так что основанный на stdio «кот» может не зацикливаться. Или это может. Трудно сказать, не читая много уродливого, уродливого кода libc.
Я сделал straceна RHEL cat- он просто выполняет последовательность read()и write()системные вызовы. Но catне нужно работать таким образом. Это было бы возможно для mmap()входного файла, а затем сделать write(1, mapped_address, input_file_size). Ядро сделало бы всю работу. Или вы можете сделать sendfile()системный вызов между дескрипторами входного и выходного файлов в системах Linux. По слухам, старые системы SunOS 4.x делали трюк с отображением памяти, но я не знаю, делал ли кто-нибудь когда-нибудь кошку на основе sendfile. В любом случае , «зацикливание» бы не произошло, так как оба write()и sendfile()требуют параметра длины к передаче.