Sur un ancien système RHEL que j'ai, /bin/catne fait pas de boucle cat x >> x. catdonne le message d'erreur "cat: x: le fichier d'entrée est le fichier de sortie". Je peux tromper /bin/caten faisant ceci: cat < x >> x. Lorsque j'essaie votre code ci-dessus, j'obtiens le "bouclage" que vous décrivez. J'ai également écrit un "chat" basé sur les appels système:
#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;
}
Cela boucle aussi. La seule mise en mémoire tampon ici (contrairement à "mycat" basé sur stdio) est ce qui se passe dans le noyau.
Je pense que ce qui se passe est que le descripteur de fichier 3 (le résultat de open(av[1])) a un décalage dans le fichier de 0. Le descripteur de fichier 1 (stdout) a un décalage de 3, car le ">>" fait que le shell appelant fait un lseek()sur le descripteur de fichier avant de le transmettre au catprocessus enfant.
Faire un read()de n'importe quelle sorte, que ce soit dans un tampon stdio ou un simple, char buf[]avance la position du descripteur de fichier 3. Faire un write()avance la position du descripteur de fichier 1. Ces deux décalages sont des nombres différents. En raison du ">>", le descripteur de fichier 1 a toujours un décalage supérieur ou égal à l'offset du descripteur de fichier 3. Ainsi, tout programme "semblable à un chat" bouclera, à moins qu'il ne fasse un tampon interne. Il est possible, voire probable, qu'une implémentation stdio d'un FILE *(qui est le type des symboles stdoutet fdans votre code) qui inclut son propre tampon. fread()peut en fait faire un appel système read()pour remplir le tampon interne fo f. Cela peut ou ne peut rien changer à l'intérieur de stdout. Appel fwrite()surstdoutpeut ou ne peut rien changer à l'intérieur de f. Un "chat" basé sur stdio peut donc ne pas boucler. Ou peut-être. Difficile à dire sans lire beaucoup de code libc laid et laid.
Je l' ai fait un stracesur la RHEL cat- il fait juste une succession de read()et write()appels système. Mais un catne doit pas fonctionner de cette façon. Il serait possible pour mmap()le fichier d'entrée, alors faites write(1, mapped_address, input_file_size). Le noyau ferait tout le travail. Ou vous pouvez faire un sendfile()appel système entre les descripteurs de fichiers d'entrée et de sortie sur les systèmes Linux. Les vieux systèmes SunOS 4.x étaient censés faire l'affaire de mappage de la mémoire, mais je ne sais pas si quelqu'un a déjà fait un chat basé sur sendfile. Dans les deux cas, le "bouclage" ne se produirait pas, car les deux write()et sendfile()nécessitent un paramètre de longueur à transférer.