บนระบบเก่า RHEL ฉันมี, /bin/cat
ไม่ได้cat x >> x
ห่วงสำหรับ cat
ให้ข้อความแสดงข้อผิดพลาด "cat: x: ไฟล์อินพุตเป็นไฟล์เอาต์พุต" ฉันสามารถหลอกโดยการทำเช่นนี้:/bin/cat
cat < x >> x
เมื่อฉันลองโค้ดของคุณด้านบนฉันจะได้ "ลูป" ที่คุณอธิบาย ฉันยังเขียน "cat" ตามสายระบบ:
#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;
}
ลูปนี้เช่นกัน บัฟเฟอร์เดียวที่นี่ (ซึ่งแตกต่างจาก stdio ตาม "mycat") คือสิ่งที่เกิดขึ้นในเคอร์เนล
ฉันคิดว่าสิ่งที่เกิดขึ้นคือ file descriptor 3 (ผลลัพธ์ของopen(av[1])
) มี offset เป็นไฟล์ 0 Filed descriptor 1 (stdout) มี offset ของ 3 เพราะ ">>" ทำให้เชลล์ที่อ้างถึงทำlseek()
บน file descriptor ก่อนส่งไปยังcat
กระบวนการ child
การread()
เรียงลำดับใด ๆ ไม่ว่าจะเป็นบัฟเฟอร์ stdio หรือธรรมดาจะchar buf[]
เลื่อนตำแหน่งของไฟล์ descriptor 3 การทำwrite()
ตำแหน่งของไฟล์ descriptor ขั้นสูง 1 การออฟเซ็ตทั้งสองนั้นเป็นตัวเลขที่แตกต่างกัน เนื่องจาก ">>" file descriptor 1 มักจะมี offset มากกว่าหรือเท่ากับ offset ของ file descriptor 3 ดังนั้นโปรแกรม "cat-like" ใด ๆ ก็ตามจะวนซ้ำจนกว่าจะมีการบัฟเฟอร์ภายใน อาจเป็นไปได้หรืออาจเป็นไปได้ว่าการใช้ stdio ของFILE *
(ซึ่งเป็นประเภทของสัญลักษณ์stdout
และf
ในรหัสของคุณ) ที่มีบัฟเฟอร์ของตัวเอง fread()
จริงอาจจะเรียกระบบที่จะเติมบัฟเฟอร์ภายในสำหรับread()
f
stdout
นี้อาจหรือไม่อาจมีการเปลี่ยนแปลงอะไรในอวัยวะภายในของCalling fwrite()
บนstdout
f
หรืออาจจะไม่เปลี่ยนอะไรภายในของ ดังนั้น "cat" ที่ใช้ stdio อาจไม่วนซ้ำ หรืออาจ ยากที่จะพูดโดยไม่ต้องอ่านรหัส libc ที่น่าเกลียดและน่าเกลียดมาก
ฉันทำstrace
บน RHEL cat
- มันเป็นการต่อเนื่องread()
และการwrite()
เรียกของระบบ แต่cat
ไม่ต้องทำงานแบบนี้ มันจะเป็นไปได้ที่จะใส่ไฟล์แล้วทำmmap()
write(1, mapped_address, input_file_size)
เคอร์เนลจะทำงานทั้งหมด หรือคุณสามารถทำการsendfile()
เรียกระบบระหว่างตัวอธิบายไฟล์อินพุตและเอาต์พุตบนระบบ Linux ระบบเก่า SunOS 4.x มีข่าวลือว่าทำเคล็ดลับการจับคู่หน่วยความจำ แต่ฉันไม่รู้ว่ามีใครทำแมวที่ใช้ sendfile หรือไม่ ในทั้งสองกรณี "ลูป" จะไม่เกิดขึ้นเนื่องจากทั้งคู่write()
และsendfile()
ต้องการพารามิเตอร์แบบยาวต่อการถ่ายโอน