2

我在看K&R 2(8.6示例 - 列表目錄)中的一個示例。這是一個精簡版的Linux命令ls或Windows'dir。該示例顯示了功能的實現,如opendir,readdir。我已經嘗試過逐字輸入代碼,但它仍然不起作用。它所做的只是打印一個點(用於當前目錄)並退出。在目錄上使用`read`系統調用

我在代碼中發現了一件有趣的事情(在執行readdir時),它在目錄上調用系統調用如openread。喜歡的東西 -

int fd, n; 
char buf[1000], *bufp; 

bufp = buf; 
fd = open("dirname", O_RDONLY, 0); 
n = read(fd, bufp, 1000); 
write(fd, bufp, n); 

當我運行這段代碼我沒有得到任何輸出,即使文件夾名稱"dirname"中有一些文件。

此外,該書說,實施是針對版本7和System V UNIX系統。這是它不在Linux上工作的原因嗎?

這裏的代碼是http://ideone.com/tw8ouX

那麼Linux不允許read系統調用目錄?還是別的什麼造成了這個?

回答

1

事實上,Linux不允許使用read作爲目錄。請參閱man page並搜索errno EISDIR。你會發現

如果職能失敗read()和PREAD()...

fildes參數是指一個目錄,並實行不允許要讀取的目錄使用read()或pread()。應該使用readdir()函數。

。儘管如此,其他UNIX仍然允許。

+0

所以'readdir'是Linux中的系統調用? – ShuklaSannidhya

+0

老實說我不知道​​'readdir()'本身是系統調用還是調用別的東西。寫一個測試程序,用'strace'運行,找出並告訴我。我也很好奇。 –

5

在第7版UNIX中,只有一個unix文件系統,其目錄具有簡單的磁盤格式:數組爲struct direct。讀它並解釋結果是微不足道的。系統調用可能是多餘的。

在現代,Linux和其他類Unix系統(ext4,ZFS,NTFS!)可安裝的文件系統種類很多,其中一些文件系統具有複雜的目錄格式。你不能對任意目錄的原始字節做任何事情。所以內核承擔了爲目錄提供通用接口作爲抽象對象的責任。 readdir是該界面的核心部分。

一些現代統計仍然允許read()在目錄上,因爲它是他們歷史的一部分。 Linux的歷史開始於90年代,當時很明顯,目錄上的read()永遠不會有用,所以Linux從未允許它。

Linux確實提供了一個readdir系統調用,但它不再使用太多,因爲有更好的東西出現:getdents。 readdir一次只返回一個目錄條目,所以如果你在循環中使用readdir syscall來獲取目錄中的文件列表,你可以在每個循環迭代中輸入內核。 getdents將多個條目返回到緩衝區。

readdir是標準接口,所以glibc提供了一個readdir函數,它調用getdents系統調用而不是readdir系統調用。在一個普通的程序中,你會在源代碼中看到readdir,但是在strace中會看到getdent。 C庫正在通過緩衝來幫助性能,就像它在常規文件的stdio中一樣,當你撥打getchar()並且它一次執行幾千字節的read()而不是一堆單字節read()s。

除非您運行很久以前編譯的可執行文件,否則您將無法在現代Linux系統上使用原始無緩衝的readdir系統調用,或者繞過C庫進行操作。

+0

我花了太多時間試圖找出爲什麼這是失敗。儘管如此,這已經證明了C的長久性,我已經使它成爲K&R書的180頁,沒有遇到與當前實現差異很大的差異 – mickadoo

+0

readdir不是系統調用嗎? – Alex

+0

@Alex它在原始的Linux中,並且仍然支持i386(32位),因爲刪除它會創建一個不兼容的用戶空間ABI,因此沒有任何好處。像amd64那樣在getdent之後到達的體系結構沒有舊的系統調用。 –