Auf einem älteren RHEL System , das ich habe, /bin/cattut nicht Schleife für cat x >> x. catgibt die Fehlermeldung "cat: x: Eingabedatei ist Ausgabedatei" aus. Ich kann täuschen , /bin/catindem Sie diese: cat < x >> x. Wenn ich Ihren obigen Code ausprobiere, erhalte ich die von Ihnen beschriebene "Schleife". Ich habe auch einen Systemaufruf geschrieben, der auf "cat" basiert:
#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;
}
Dies ist auch eine Schleife. Die einzige Pufferung hier (im Gegensatz zu stdio-basierten "mycat") ist, was im Kernel vor sich geht.
Ich denke, was passiert ist, dass Dateideskriptor 3 (das Ergebnis von open(av[1])) einen Versatz in die Datei von 0 hat. Abgelegtes Deskriptor 1 (stdout) hat einen Versatz von 3, weil das ">>" die aufrufende Shell veranlasst, ein lseek()auf dem Dateideskriptor, bevor er an den catuntergeordneten Prozess übergeben wird.
Wenn Sie eine read()beliebige Art ausführen, sei es in einem Stdio-Puffer oder in einer Ebene, wird char buf[]die Position des Dateideskriptors vorgerückt. 3. Wenn Sie eine beliebige Art ausführen, wird write()die Position des Dateideskriptors vorgerückt. Aufgrund des ">>" hat Dateideskriptor 1 immer einen Versatz, der größer oder gleich dem Versatz von Dateideskriptor 3 ist. Daher wird jedes "katzenartige" Programm eine Schleife ausführen, es sei denn, es führt eine interne Pufferung durch. Es ist möglich, vielleicht sogar wahrscheinlich, dass eine stdio-Implementierung von a FILE *(das ist der Typ der Symbole stdoutund fin Ihrem Code) einen eigenen Puffer enthält. fread()kann tatsächlich einen Systemaufruf ausführen read(), um den internen Puffer fo zu füllen f. Dies kann oder kann nichts an den Innenseiten von ändern stdout. Ich rufe fwrite()anstdoutkann oder kann nichts innerhalb von ändern f. Eine stdio-basierte "Katze" kann also keine Schleife bilden. Oder es könnte. Schwer zu sagen, ohne viel hässlichen, hässlichen libc-Code durchzulesen.
Ich habe eine straceauf dem RHEL cat- es macht nur eine Abfolge von read()und write()Systemaufrufen. Aber so catmuss man nicht arbeiten. Es wäre dann möglich mmap()die Eingabedatei zu machen write(1, mapped_address, input_file_size). Der Kernel würde die ganze Arbeit machen. sendfile()Auf Linux-Systemen können Sie auch einen Systemaufruf zwischen den Eingabe- und Ausgabedateideskriptoren ausführen. Es wurde gemunkelt, dass alte SunOS 4.x-Systeme den Memory-Mapping-Trick ausführen, aber ich weiß nicht, ob jemals jemand eine sendfile-basierte Katze erstellt hat. In jedem Fall wäre die „Looping“ nicht passieren, da beide write()und sendfile()erfordern eine Länge-zu-Übertragungsparameter.