open() - Unix,Linux系統呼叫
廣告
名稱
open, creat - 開啟並可能建立檔案或裝置
概要
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
int creat(const char *pathname, mode_t mode);
|
描述
給定檔案的路徑名,open() 返回一個檔案描述符,一個小的非負整數,用於後續的系統呼叫(read(2), write(2), lseek(2), fcntl(2) 等)。成功呼叫返回的檔案描述符將是程序當前未開啟的最低編號的檔案描述符。
新的檔案描述符設定為在 execve(2) 中保持開啟(即,fcntl(2) 中描述的 FD_CLOEXEC 檔案描述符標誌最初被停用)。檔案偏移量設定為檔案的開頭(參見 lseek(2))。
呼叫 open() 會建立一個新的開啟的檔案描述,這是系統範圍的開啟檔案表中的一個條目。此條目記錄檔案偏移量和檔案狀態標誌(可透過 fcntl() F_SETFL 操作進行修改)。檔案描述符是對這些條目之一的引用;如果路徑名隨後被刪除或修改為引用不同的檔案,則此引用不受影響。新的開啟的檔案描述最初不與任何其他程序共享,但共享可能透過 fork(2) 產生。
引數flags必須包含以下訪問模式之一:O_RDONLY、O_WRONLY 或 O_RDWR。這些分別請求以只讀、只寫或讀寫方式開啟檔案。
此外,零個或多個檔案建立標誌和檔案狀態標誌可以按位或到flags中。檔案建立標誌是 O_CREAT、O_EXCL、O_NOCTTY 和 O_TRUNC。檔案狀態標誌是下面列出的所有其餘標誌。這兩組標誌之間的區別在於,可以使用 fcntl(2) 獲取並(在某些情況下)修改檔案狀態標誌。
檔案建立標誌和檔案狀態標誌的完整列表如下所示
錯誤程式碼 | 描述 |
O_APPEND | 檔案以追加模式開啟。在每次write() 之前,檔案偏移量都定位在檔案的末尾,就像使用lseek() 一樣。如果多個程序同時向一個檔案追加資料,O_APPEND 可能會導致 NFS 檔案系統上的檔案損壞。這是因為 NFS 不支援向檔案追加資料,因此客戶端核心必須模擬它,這在沒有競爭條件的情況下是無法完成的。 |
O_ASYNC | 啟用訊號驅動的 I/O:當此檔案描述符上可能進行輸入或輸出時,生成一個訊號(預設為 SIGIO,但這可以透過 fcntl(2) 更改)。此功能僅適用於終端、偽終端、套接字以及(自 Linux 2.6 起)管道和 FIFO。有關更多詳細資訊,請參見 fcntl(2)。 |
O_CREAT | 如果檔案不存在,則將建立它。檔案的擁有者(使用者 ID)設定為程序的有效使用者 ID。組所有權(組 ID)設定為程序的有效組 ID 或父目錄的組 ID(取決於檔案系統型別和掛載選項以及父目錄的模式,例如,請參見 ext2 檔案系統的掛載選項bsdgroups 和 sysvgroups,如 mount(8) 中所述)。 |
O_DIRECT | 嘗試最大限度地減少與此檔案進行 I/O 的快取效應。通常,這會降低效能,但在特殊情況下很有用,例如當應用程式進行自己的快取時。檔案 I/O 直接在使用者空間緩衝區之間進行。I/O 是同步的,即在read(2) 或write(2) 完成時,保證資料已傳輸。在 Linux 2.4 中,傳輸大小以及使用者緩衝區和檔案偏移量的對齊方式都必須是檔案系統邏輯塊大小的倍數。在 Linux 2.6 中,對齊方式必須適合裝置的塊大小。 raw(8) 中描述了塊裝置的語義相似(但已棄用)的介面。 |
O_DIRECTORY | 如果路徑名不是目錄,則導致開啟失敗。此標誌是 Linux 特定的,是在核心版本 2.1.126 中新增的,目的是為了避免在對 FIFO 或磁帶裝置呼叫opendir(3) 時出現拒絕服務問題,但不應在opendir的實現之外使用。 |
O_EXCL | 當與O_CREAT一起使用時,如果檔案已存在,則這是一個錯誤,並且open() 將失敗。在這種情況下,符號連結存在,無論它指向哪裡。O_EXCL 在 NFS 檔案系統上已損壞;依賴於它來執行鎖定任務的程式將包含競爭條件。使用鎖檔案執行原子檔案鎖定的解決方案是在同一個檔案系統上建立一個唯一檔案(例如,包含主機名和 pid),使用link(2) 建立到鎖檔案的連結。如果link() 返回 0,則鎖定成功。否則,使用stat(2) 檢查唯一檔案的連結計數是否已增加到 2,在這種情況下,鎖定也成功。 |
O_LARGEFILE | (LFS) 允許開啟大小無法用off_t表示(但可以用off64_t表示)的檔案。 |
O_NOATIME | (自 Linux 2.6.8 起) 當read(2) 檔案時,不更新檔案上次訪問時間(inode 中的 st_atime)。此標誌旨在供索引或備份程式使用,在這些程式中,它的使用可以顯著減少磁碟活動量。此標誌可能並非對所有檔案系統都有效。一個例子是 NFS,其中伺服器維護訪問時間。 |
O_NOCTTY | 如果路徑名引用終端裝置——參見tty(4)——即使程序沒有終端,它也不會成為程序的控制終端。 |
O_NOFOLLOW | 如果路徑名是符號連結,則開啟失敗。這是 FreeBSD 擴充套件,在 2.1.126 版本中新增到 Linux。路徑名中較早的元件中的符號連結仍將被跟蹤。 |
O_NONBLOCK 或 O_NDELAY | 如果可能,則以非阻塞模式開啟檔案。返回的檔案描述符上的open() 或任何後續操作都不會導致呼叫程序等待。對於 FIFO(命名管道)的處理,另請參見fifo(7)。有關O_NONBLOCK 與強制檔案鎖和檔案租約結合使用效果的討論,請參見fcntl(2)。
|
O_SYNC | 檔案以同步 I/O 方式開啟。結果檔案描述符上的任何write() 都將阻塞呼叫程序,直到資料被物理寫入底層硬體。但請參見下面的限制。 |
O_TRUNC | 如果檔案已存在並且是常規檔案,並且開啟模式允許寫入(即為 O_RDWR 或 O_WRONLY),則它將被截斷為長度 0。如果檔案是 FIFO 或終端裝置檔案,則忽略 O_TRUNC 標誌。否則,O_TRUNC 的效果未指定。 |
開啟檔案後,可以使用fcntl() 更改其中一些可選標誌。
引數mode指定在建立新檔案時要使用的許可權。它以通常的方式由程序的umask修改:建立檔案的許可權為(mode & ~umask)。請注意,此模式僅適用於新建立檔案的未來訪問;建立只讀檔案的open() 呼叫很可能會返回讀寫檔案描述符。
|
以下符號常量用於
mode: |
S_IRWXU | 00700 使用者(檔案所有者)具有讀、寫和執行許可權 |
S_IRUSR | 00400 使用者具有讀取許可權 |
S_IWUSR | 00200 使用者具有寫入許可權 |
S_IXUSR | 00100 使用者具有執行許可權 |
S_IRWXG | 00070 組具有讀、寫和執行許可權 |
S_IRGRP | 00040 組具有讀取許可權 |
S_IWGRP | 00020 組具有寫入許可權 |
S_IXGRP | 00010 組具有執行許可權 |
S_IRWXO | 00007 其他使用者具有讀、寫和執行許可權 |
S_IROTH | 00004 其他使用者具有讀取許可權 |
S_IWOTH | 00002 其他使用者具有寫入許可權 |
S_IXOTH | 00001 其他使用者具有執行許可權 |
當O_CREAT在flags中時,必須指定mode,否則將被忽略。
creat() 等效於flags等於O_CREAT|O_WRONLY|O_TRUNC的open()。
返回值
open() 和 creat() 返回新的檔案描述符,或者如果發生錯誤則返回 -1(在這種情況下,errno 將被相應設定)。
備註
請注意,open() 可以開啟裝置特殊檔案,但creat() 無法建立它們;請改用mknod(2)。
在啟用了 UID 對映的 NFS 檔案系統上,open() 可能會返回檔案描述符,但例如read(2) 請求會被拒絕並顯示EACCES。這是因為客戶端透過檢查許可權來執行open(),但 UID 對映是在讀取和寫入請求時由伺服器執行的。
如果檔案是新建立的,則其st_atime、st_ctime、st_mtime欄位(分別表示最後訪問時間、最後狀態更改時間和最後修改時間;參見stat(2))將設定為當前時間,其父目錄的st_ctime和st_mtime欄位也是如此。否則,如果由於O_TRUNC標誌導致檔案被修改,則其st_ctime和st_mtime欄位將設定為當前時間。
錯誤
錯誤程式碼 | 描述 |
EACCES | 不允許請求的檔案訪問,或者拒絕搜尋pathname路徑字首中的某個目錄的許可權,或者檔案尚不存在且不允許對父目錄進行寫訪問。(另見path_resolution(2)。) |
EEXIST |
pathname已存在,並且使用了O_CREAT和O_EXCL。 |
EFAULT |
pathname指向您可訪問的地址空間之外。 |
EISDIR |
pathname指向一個目錄,並且請求的訪問涉及寫入(即,設定了O_WRONLY或O_RDWR)。 |
ELOOP | 在解析pathname時遇到太多符號連結,或者指定了O_NOFOLLOW但pathname是符號連結。 |
EMFILE | 程序已開啟最大數量的檔案。 |
ENAMETOOLONG |
pathname太長。 |
ENFILE | 已達到系統對開啟檔案總數的限制。 |
ENODEV |
pathname指向一個裝置特殊檔案,並且不存在相應的裝置。(這是一個Linux核心錯誤;在這種情況下,必須返回ENXIO。) |
ENOENT | 未設定O_CREAT並且指定的 檔案不存在。或者,pathname中的目錄元件不存在或是一個懸空符號連結。 |
ENOMEM | 核心可用記憶體不足。 |
ENOSPC |
要建立pathname,但包含pathname的裝置沒有足夠空間容納新檔案。 |
ENOTDIR | pathname中用作目錄的元件實際上並非目錄,或者指定了O_DIRECTORY但pathname不是目錄。 |
ENXIO | 設定了O_NONBLOCK | O_WRONLY,指定的檔案是FIFO且沒有程序開啟該檔案以進行讀取。或者,該檔案是裝置特殊檔案,並且不存在相應的裝置。 |
EOVERFLOW |
pathname指向一個常規檔案,太大而無法開啟;請參見上面的O_LARGEFILE。 |
EPERM | 指定了O_NOATIME標誌,但呼叫者的有效使用者ID與檔案所有者不匹配,並且呼叫者沒有特權(CAP_FOWNER)。 |
EROFS |
pathname指向只讀檔案系統上的檔案,並且請求了寫訪問。 |
ETXTBSY |
pathname指向當前正在執行的可執行映像,並且請求了寫訪問。 |
EWOULDBLOCK | 指定了O_NONBLOCK標誌,並且在該檔案上存在不相容的租約(參見fcntl(2))。 |
注意
在Linux下,O_NONBLOCK標誌表示想要開啟但並不一定打算讀取或寫入。這通常用於開啟裝置以獲取用於ioctl(2)的檔案描述符。
符合標準
SVr4、4.3BSD、POSIX.1-2001。O_NOATIME、O_NOFOLLOW和O_DIRECTORY標誌是Linux特有的。可能需要定義_GNU_SOURCE宏才能獲得它們的定義。
O_RDONLY | O_TRUNC的(未定義的)效果在不同的實現中有所不同。在許多系統上,檔案實際上會被截斷。
O_DIRECT標誌是在SGI IRIX中引入的,它具有與Linux 2.4相似的對齊限制。IRIX還有一個fcntl(2)呼叫來查詢適當的對齊方式和大小。
FreeBSD 4.x引入了相同名稱的標誌,但沒有對齊限制。在核心版本2.4.10中添加了對Linux的支援。較舊的Linux核心會忽略此標誌。可能需要定義_GNU_SOURCE宏才能獲得其定義。
錯誤
“O_DIRECT一直讓我困擾的一件事是,整個介面都很愚蠢,可能是在某種嚴重的控制精神的物質作用下由一隻瘋猴設計的。”——Linus
當前,在呼叫open()時,無法透過指定O_ASYNC來啟用訊號驅動的I/O;使用fcntl(2)來啟用此標誌。
限制
底層NFS協議中存在許多不完善之處,影響到O_SYNC和O_NDELAY等。 POSIX提供了三種不同的同步I/O變體,分別對應於標誌O_SYNC、O_DSYNC和O_RSYNC。目前(2.1.130)在Linux下它們都是同義詞。
參見
廣告
|