UNIX 环境高级编程 文件和目录
函數stat , fstat , fstatat , lstat
? ? ?stat函數返回與此文件有關的信息結構。
? ? ?fstat函數使用已打開的文件描述符(而stat則使用文件名)?
? ? ?fstatat函數 為一個相對于當前打開目錄的路徑名返回文件信息。
? ? ?lstat函數返回該符號鏈接的有關信息,而不是該符號鏈接引用的文件的信息。
? ? ?使用stat最多的地方可能就是 ls -l 命令。
?
????? st_mode? 與 S_IFMT 進行 與 運算 在與 S_IFXXX常量相比較,來判斷類型。
?
? ? ?
文件類型
? ? ?1.普通文件: 無論是文本文件還是二進制文件對UNIX內核來說沒有區別。
? ? ?2.目錄文件: 這種文件包含了其他文件的名字以及指向與這些文件有關信息的指針。
? ? ?3.塊特殊文件: 提供對設備帶緩沖的訪問。
? ? ?4.字符特殊文件: 提供對設備不帶緩沖的訪問
? ? ?5.FIFO : 用于進程通信, 稱之為 管道
? ? ?6.socket:用于網絡通信
? ? ?7.符號鏈接:這種文件指向另一個文件
? ? ? ? ? 文件類型信息包含在stat結構的 st_mode 成員中。
設置用戶ID 和 設置組ID
? ? ?實際用戶ID :
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 我們實際上是誰
? ? ?實際組ID ? ? :?
? ? ?有效用戶ID: ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ??用于文件訪問權限檢查
? ? ?有效組ID ? ?:
? ? ?保存的設置用戶ID:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 由exec函數保存
? ? ?保存的設置組ID ? :
?實際用戶ID和組ID : 表示我們究竟是誰。取自口令文件中的登陸項
? ??
?有效用戶ID,有效組ID ,附屬組ID : 決定了我們的文件訪問權限
?保存的設置用戶ID和設置組ID : 執行一個程序時,包含了有效用戶ID和有效組ID的副本。(8.11節詳細說明)
? ? ?通常 ? ?有效用戶ID等于實際用戶ID。有效組ID等于實際組ID
? ? 每個文件有一個所有者和組所有者。 分別由 stat結構中的 st_uid 和 st_gid指定。
? ? ?執行程序時,進程的 有效ID 通常就是 實際ID。
? ??
? ?? ?????但是,可以在文件模式字(st_mode)中設置一個特殊標識,含義是“當執行此文件時,將進程的有效用戶ID設置為文件所有者的用戶ID(st_uid),同樣可以設置組ID。
? ?? ?????在文件模式字中的這兩位,被稱為?設置用戶ID(set-user-id)?和 設置組ID(set-group-id)?位。
? ? ? ? ? ? ? ?例如:
? ? ? ? ? ? ? ? ? ? 若文件的所有者是root,并且設置了該文件的設置用戶ID位,那么該程序由一個進程執行時,該進程具有root權限。無論執行此進程的實際用戶ID是什么都是這樣。
? ? ?
? ? ? ? ? 設置用戶ID 和 設置組ID 都包含在文件的 st_mode 值中。 可以分別用常量 S_ISUID 和 S_ISGID 測試。
?
文件訪問權限
? ? ?st_mode 也包含對文件的訪問權限位 。
? ? ?每個文件有 9 個權限位, 分成 3 類:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?S_IRUSR ? ? ? ? ?用戶讀
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?S_IWUSR ? ? ? ? 用戶寫
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?S_IXUSR ? ? ? ? ?用戶執行
? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?S_IRGRP ? ? ? ? ?組讀
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?S_IWGRP ? ? ? ? 組寫
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?S_IXGRP ? ? ? ? ?組執行
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?S_IROTH ? ? ? ? ?其他讀
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?S_IWOTH ? ? ? ? 其他寫
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?S_IXOTH ? ? ? ? ?其他執行
? ? ?用戶指的是 文件所有者(owner) 。
- ?用名字打開文件時,對該名字包含的沒一個目錄,包括可能隱含的當前工作目錄 都應具有執行權限。對于目錄的讀權限,允許我們獲取該目錄中所有文件名的列表。對目錄的執行權限可使我們通過該目錄,進而搜索該目錄,尋找一個特定的文件名。
- 對于一個文件的讀權限,決定了我們能否打開現有文件進行讀操作。與 open函數的 O_RDONLY 和 O_RDWR標志相關。
- 對于一個文件的寫權限,決定了我們能否打開現有文件進行寫操作。與 open函數的 O_WRONLY 和 O_RDWR標志相關。 ? ? ??
- 為了在 open函數中對一個文件指定 O_TRUNC標志,必須對該文件具有寫權限。
- 為了在一個目錄中創建一個新文件,必須對該目錄具有寫權限和執行權限。
- 問了刪除一個現有文件,必須對包含該文件的目錄具有寫權限和執行權限。對該文件本身不需要有讀,寫權限。
- 如果用 7 個 exec函數中的任何一個執行某個文件,都必須對該文件具有執行權限。并且該文件必須是一個普通文件。
? ? ? 進程每次打開,創建或刪除一個文件時,內核就進行文件訪問權限測試。
? ? ? 測試分為4步,順序執行:
? ? ? ? ? 1.若 有效ID?是 root , 則允許訪問。
? ? ? ? ? 2.若 有效ID 等于 所有者ID 的情況下。 那么如果所有者適當的訪問權限被設置則允許訪問,否則拒絕。
? ? ? ? ? 3.若 有限組ID 或 進程的附屬組ID 之一?等于文件的組ID。如果適當的訪問權限被設置,則允許訪問,否則拒絕。
? ? ? ? ? 4.若 其他用戶?適當的訪問權限位被設置,則允許訪問, 否則拒絕。
?
??
新文件和目錄的所有權
? ? ?新文件的用戶ID設置為進程的有效用戶ID。
? ? ?關于組ID,可選擇下列其一作為新文件的組ID:
? ? ? ? ? 1.新文件的組ID可以是進程的有效組ID。
? ? ? ? ? 2.新文件的組ID可以是他所在目錄的組ID。
?
函數 access 和 faccessat
? ? ?內核以 進程的有效用戶ID 和 有效組ID 為基礎測試訪問權限測試。
? ? ?如果希望按 實際用戶ID 和 實際組ID 來測試訪問能力。既可以用 access 和 faccessat 函數來進行訪問權限測試(該測試與默認的一樣,但將 有效ID 改為 實際ID)
? ? ?
? ? ?int access ( const char * pathname , int mode );
? ? ?int faccessat ( int fd , const char * pathname , int mode , int flag );
? ? ?
? ? ?若成功返回 0 , 否則返回-1
?
? ? ?如果測試文件是否已存在,mode 為 F_OK;否則 mode 是下列常量的 按位或:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?R_OK ? ? ?測試讀權限
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? W_OK ? ? 測試寫權限
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? X_OK ? ? ?測試執行權限
?????
? ? ? ? ? ? ? ?
函數 umask
? ? ?mode_t umask ( mode_t cmask )
? ? ?相當于設置創建文件時,默認的權限。
? ? ? cmask 由 9個訪問權限位 中的 若干個 ”或“ 構成。
? ? ? 在文件模式創建屏蔽字中為1的位,在文件mode中的相應位會被關閉。
? ? ?
? ? ?若希望任何用戶都能讀文件,則應將umask設置為0。
函數 chmod , fchmod , fchmodat
? ? ? ? ? ? ? ? ? ? ?????用來改變現有文件的訪問權限
?????
? ? ?int chmod ( const char *pathname , mode_t mode );
? ? ?int fchmod ( int fd , mode_t mode );
? ? ?int fchmodat ( int fd , const char *pathname , mode_t mode , int flag );
? ? ?chmod函數 在指定的文件上進行操作, fchmod對已打開的文件進行操作 , fchmodat函數的fd參數可以指定相對的目錄。若pathname為絕對路徑,或fd參數取值為AT_FDCWD的時候與chmod是相同的。
? ? ?fchmodat函數的flag參數 可以用來改變fchmodat的行為,設置AT_SYMLINK_NOFOLLOW標志時,fchmodat 不會跟隨符號鏈接。
? ? ?為了改變一個文件的權限位 , 進程的有效ID必須等于文件的所有者ID , 除非該進程具有ROOT權限。
? ? ?參數mode是如下常量按位或:
? ? ? ? ? S_ISUID ? ? ? ? ? ? ? ? ? ?執行時設置用戶ID
? ? ? ? ? S_ISGID ? ? ? ? ? ? ? ? ? ?執行時設置組ID
? ? ? ? ? S_ISVTX ? ? ? ? ? ? ? ? ? ?保存正文(黏著位)
? ? ? ? ? S_IRWXU ? ? ? ? ? ? ? ? ? ?用戶(所有者)讀,寫,執行
? ? ? ? ? ? ? ?S_IRUSR ? ? ? ? ? ? ? ?用戶(所有者)讀
? ? ? ? ? ? ? ?S_IWUSR ? ? ? ? ? ? ? 用戶(所有者)寫
? ? ? ? ? ? ? ?S_IXUSR ? ? ? ? ? ? ? ? 用戶(所有者)執行
? ? ? ? ? S_IRWXG ? ? ? ? ? ? ? ? ? ?組讀,寫,執行
? ? ? ? ? ? ? ?S_IRGRP ? ? ? ? ? ? ? ?組讀
? ? ? ? ? ? ? ?S_IWGRP ? ? ? ? ? ? ? 組寫
? ? ? ? ? ? ? ?S_IXGRP ? ? ? ? ? ? ?? 組執行
? ? ? ? ? S_IRWXO ? ? ? ? ? ? ? ? ? ?其他讀,寫,執行
? ? ? ? ? ? ? ?S_IROTH ? ? ? ? ? ? ? ?其他讀
? ? ? ? ? ? ? ?S_IWOTH ? ? ? ? ? ? ? 其他寫
? ? ? ? ? ? ? ?S_IXOTH ? ? ? ? ? ? ? ?其他執行
?
? ? ? ? ? 只有root才能設置黏著位。
? ? ? ? ? 新創建文件的組ID可能不是調用進程所屬的組。也可能是父目錄的組ID。人如果新文件的組ID不等于進程的有效組ID或者進程附屬組ID的一個,而且進程沒有root權限,那么設置組ID會被自動關閉。防止用戶創建一個設置組ID文件。
?
黏著位
? ? ?如果一個可執行程序被設置了黏著位,那么當程序第一次被執行,在終止的時候,程序正文部分的一個副本仍被保存在交換區。使得下次執行的時候能較快將其載入內存。
? ? ?如果對一個目錄設置了黏著位,那么只有對該目錄具有寫權限的用戶并且滿足下列條件之一,才能刪除或重命名該目錄下的文件:
- 擁有此文件
- 擁有此目錄
- 是超級用戶
?
?????
?
?
函數 chown , fchown , fchownat , lchown
? ? ?可用于更改用戶ID和組ID。如果參數owner或group中的任意一個是-1,則對應的ID不變。
int chown ( const char *pathname , uid_t owner , gid_t group)
int fchown ?( int fd , uid_t owner , gid_t group )
int fchownat ( int fd , const char *pathname , uid_t owner , gid_t group , int flag )
int lchown ( const char *pathname , uid_t owner , gid_t group )
在符號鏈接的情況下, lchown 和 設置了 AT_SYMLINK_NOFOLLOW標志的fchownat 更改符號鏈接本身的所有者。
fchown函數改變fd參數指向的打開文件的所有者。
?
?
文件長度
? ? ?stat結構成員 st_size 表示 以字節為單位的文件的長度。只對普通文件,目錄文件,符號鏈接有意義。
? ? ?對于普通文件,長度可為0
? ? ?對于目錄文件,文件長度一般是一個數(如16或512)的倍數。
? ? ?對于符號鏈接,文件長度就是文件名中的實際字節數。
?
?
文件的空洞
? ? ?空洞是由所設置的偏移量超過文件尾端,并寫入了某些數據后造成的。
? ? ?對于沒有寫過的字節位置,read函數讀到的字節是0。
? ? ?如果使用實用程序(如cat)復制這個文件,那么所有空洞將被填滿。其中所有書記數據字節皆填寫為0。
?
文件截斷
? ? ?為了截斷文件可以調用函數 truncate 和 ftruncate
? ? ?
int truncate ( const char *pathname , off_t length );
int ftruncate ( const char *pathname , off_t length);
這兩個函數將一個現有文件長度截斷為length。如果文件長度大于length,則超過length以外的數據就不能再訪問。如果以前的長度小于length,文件長度將增加。
? ? ?
文件系統
? ? ?書113頁
?
函數 link , linkat , unlink , unlinkat , remove
? ? ?創建一個指向現有文件的鏈接的方法是使用 link 函數 或 linkat 函數。
int link (const char *existingpath , const char *newpath )
int linkat ( int efd , const char *existingpath , int nfd , const char *newpath , int flag )
這兩個函數創建一個新目錄項newpath,它引用現有文件existingpath。如果 newpath已存在,則返回出錯。只創建newpath中的最后一個分量,路徑中的其他部分應當已經存在。
對于linkat函數,現有文件是通過efd和existingpath參數指定的,新的路徑名通過nfd和newpath參數指定。
當有文件是符號鏈接時,有flag來控制linkat函數指向?現有符號鏈接的鏈接 還是 創建指向現有符號鏈接所指向的文件的鏈接(AT_SYMLINK_FOLLOW )
創建新目錄項和增加鏈接計數應當是一個原子操作。
?
?
為了刪除一個現有的目錄項,可以調用unlink函數
int unlink ( const char *pathname )
int unlinkat ( int fd , const char *pathname , int flag)
這兩個函數刪除目錄項 , 并將由 pathname 所引用文件的鏈接計數減1
只有當鏈接計數為0,該文件的內容才可被刪除,如果有進程打開了該文件,其內容也不能刪除。
如果 flag?參數設置為 AT_REMOVEDIR 。 函數可以類似于 rmdir 一樣刪除目錄。
?
也可以用 remove 函數解除一個文件或目錄的鏈接。 對于文件 remove的功能與unlink功能相同。對于目錄 remove 與 rmdir 相同
int remove ( const char *pathname )
?
?
函數 rename 和 renameat
? ? ?文件或目錄可以用rename函數或者renameat函數進行重命名
? ? ?
? ? ?根據oldname是指文件,目錄還是符號鏈接。有幾種情況需要加以說明。
? ? ?
? ? ? ? ? ???????
?
符號鏈接
? ? ?符號鏈接是對一個文件的間接指針,與硬鏈接有所不同,硬鏈接直接指向文件的i節點。
- 硬鏈接通常要求鏈接和文件位于同一文件系統中。
- 只有ROOT才能創建指向目錄的硬鏈接
? ? ?
? ? ?符號鏈接已經它指向和中對象并無任何文件系統的限制。任何用戶都可以創建指向目錄的符號鏈接。符號鏈接一般用于將一個文件或整個目錄結構移至系統中另一位置。
? ? ?當使用以名字引用文件的函數時,應當了解該函數是否處理符號鏈接。
?
?
創建和讀取符號鏈接
可以用 symlink 或 symlinkat 函數創建一個符號鏈接。
int symlink ( const char * actualpath , const char *sympath ) ;
int symlinkat ( const char *actualpath , int fd , const char *sympath) ;
?
函數創建一個指向 actualpath 的新目錄項 sympath。創建符號鏈接時,不要求 actualpath已存在。并且不需要位于同一文件系統。
?
由于open函數跟隨符號鏈接,使用 readlink 和 readlinkat 函數 可以打開該鏈接本身。
ssize_t readlink ( const char *restrict pathname , char *restrict buf , size_t bufsize ) ;
ssize_t readlinkat ( const char *restrict pathname , int fd , char * restrict buf , size_t bufsize );
這兩個函數組合了open,read,close的所有操作。如果成功則返回讀入buf的字節數。
?
?
文件時間
在 stat 結構中,對每個文件維護了 3 個 時間字段。
| 字段 | 說明 | 例子 | ls 選項 |
| st_atim | 文件數據最后的訪問時間 | read | -u |
| st_stim | 文件數據的最后修改時間 | write | 默認 |
| st_ctim | i節點狀態的最后更改時間 | chown,chmod | -c |
?
?
函數 futimens , utimensat 和 utimes
可以用來修改一個文件的訪問時間和修改時間。
int futimens ( int fd , const struct timespec times[2] ) ;
int utimensat ( int fd , const char *path, const struct timespec times[2] , int flag );
times數組的第一個元素包含訪問時間,第二個元素包含修改時間。
時間戳可按下列4種方式之一進行指定:
?
?
?
函數 mkdir, mkdirat , rmdir
mkdir 和 mkdirat 用來創建目錄 , rmdir 用來刪除目錄
int mkdir ( const char *pathname , mode_t mode );
int mkdirat ( int fd , const char *pathname , mode_t mode );
int rmdir ( const char *pathname );
?
?
讀目錄
DIR *opendir ( const char *pathname );
DIR *fdopendir ( int fd );
?
struct dirent *readdir ( DIR *dp );
?
void rewinddir ( DIR *dp )
int closedir (DIR *dp )
?
long telldur (DIR *dp )
?
void seekdir ( DIR *dp , long loc )
?
?
在頭文件 <dirent.h> 中的dirent結構與實現有關。
至少包含兩個成員:
ino_t d_ino;???? //i-node number
char d_name[];???
?
?
?
函數 chdir , fchdir , getcwd
每個進程都有一個當前工作目錄,此目錄是所有相對路徑名的起點。
int chdir ( const char *pathname );
int fchdir ( int fd );
兩個函數分別用pathname 和 打開文件描述符 指定新的當前工作目錄。
?
當前工作目錄是進程的一個屬性,所以它只影響調用 chdir 的進程本身。
?
char *getcwd ( char *buf , size_t size );
該緩沖區必須有足夠的長度容納絕對路徑名加上終止null字節。
轉載于:https://www.cnblogs.com/wchyi/p/5540651.html
總結
以上是生活随笔為你收集整理的UNIX 环境高级编程 文件和目录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: (王道408考研数据结构)第二章线性表-
- 下一篇: TCP/IP编程之SO_REUSEADD