本篇主要介紹文件和文件系統(tǒng)中常用的一些函數(shù),文件系統(tǒng)的組織結(jié)構(gòu)和硬鏈接、符號鏈接。
通過對這些知識的了解,可以對linux文件系統(tǒng)有更為全面的了解。
?
1 umask函數(shù)之前我們已經(jīng)了解了每個文件與權(quán)限相關(guān)的9個位(bit),我們現(xiàn)在來了解一下當每個進程創(chuàng)建文件時默認會設(shè)置該文件的文件權(quán)限(the file mode creation mask)。
umask函數(shù)設(shè)置該進程默認創(chuàng)建文件的權(quán)限掩碼(the file mode creation mask),并且返回之前的權(quán)限掩碼值。
#include <sys/stat.h>
mode_t umask(mode_t cmask);
the file mode creation mask的作用:當進程創(chuàng)建新文件時,會根據(jù)這個掩碼值創(chuàng)建文件,在掩碼值中打開的位,對應(yīng)的新文件的權(quán)限位會被關(guān)閉。
umask的功能簡單地說就是創(chuàng)建新文件時屏蔽掉用戶不希望生效的權(quán)限位。
Example:
#include "apue.h"
#include <fcntl.h>
?
#define RWRWRW (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
?
int
main(void)
{
? ? umask(0);
? ? if (creat("foo", RWRWRW) < 0)
? ? ? ? err_sys("creat error for foo");
? ? umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
? ? if (creat("bar", RWRWRW) < 0)
? ? ? ? err_sys("creat error for bar");
? ? exit(0);
}
運行截圖:

結(jié)果說明:
shell的umask命令顯示當前文件創(chuàng)建權(quán)限掩碼。
0022表示創(chuàng)建出來的新文件,組用戶和other用戶沒有寫該文件的權(quán)限。
在程序中,首先用默認的權(quán)限設(shè)置創(chuàng)建了文件foo,它的權(quán)限位666,至于為什么當前用戶也沒有執(zhí)行權(quán)限,我還沒搞清楚,留一個坑 @suzhou。
然后修改umask值為0077,這樣就屏蔽掉了組用戶和其他用戶的讀寫權(quán)限位,因此再創(chuàng)建新文件bar,它的權(quán)限位是600。
?
2 chmod、fchmod和fchmodat函數(shù)函數(shù)作用:修改已有文件的權(quán)限位。
函數(shù)聲明:
#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);
int fchmod(int fd, mode_t mode);
int fchmodeat(int fd, const char *pathname, mode_t mode, int flag);
?區(qū)別:
權(quán)限要求:要修改一個文件的權(quán)限,需要當前進程的effective user ID和文件的所有者ID相同,或者進程有超級用戶權(quán)限。
代表各個權(quán)限位的常量如下表所示:

Example:
修改在上例中創(chuàng)建的兩個文件foo和bar的權(quán)限。
#include "apue.h"
?
int
main(void)
{
? ? struct stat ? ? statbuf;
?
? ? /* turn on set-group-ID and turn off group-execute */
?
? ? if (stat("foo", &statbuf) < 0)
? ? ? ? err_sys("stat error for foo");
? ? if (chmod("foo", (statbuf.st_mode & ~S_IXGRP) | S_ISGID) < 0)
? ? ? ? err_sys("chmod error for foo");
?
? ? /* set absolute mode to "rw-r--r--" */
?
? ? if (chmod("bar", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0)
? ? ? ? err_sys("chmod error for bar");
?
? ? exit(0);
}
運行結(jié)果:

結(jié)果說明:
高級權(quán)限(SUID/SGID/Sticky Bit )檔案特殊權(quán)限 說明:
?
3 Sticky Bit(S_ISVTX)Sticky bit有一個冗長的歷史,這里并不贅述。
作用:如果文件夾的sticky bit被打開,則文件夾中的文件被刪除或者重命名需要滿足一下的條件之一:當前用戶對該文件夾有寫權(quán)限;當前用戶是該文件的所有者;當前用戶是該文件夾的所有者;當前用戶是超級用戶。
典型的打開了sticky bit的兩個文件夾是/tmp 和/var/tmp,這兩個文件夾對所有用戶都有讀寫和執(zhí)行權(quán)限,這樣所有用戶都可以在該文件夾下創(chuàng)建文件,但是并不能刪除由其他用戶所有的文件。


?
4 chown、fchown、fchownat和lchown函數(shù)函數(shù)作用:修改文件所屬的用戶ID和組ID,如果參數(shù)owner和group有一個的值為-1,對應(yīng)的ID值不變。
#include <unistd.h>
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 grou, int flag);
int lchown(const char* pathname, uid_t owner, gid_t group);
區(qū)別:
當目標文件不是一個符號鏈接時,上面的四個函數(shù)的作用基本相同。
當目標文件是一個符號鏈接文件時,并且函數(shù)lchown和fchownat的flag設(shè)置為AT_SYMLINK_NOFOLLOW時,這兩個函數(shù)修改符號鏈接文件本身的所有者,而不是符號鏈接指向的文件。
fchown函數(shù)修改fd代表的已打開文件的所有者。因為fchown操作的是已經(jīng)打開的文件,所以它不可以用來修改符號鏈接的所有者。
fchownat函數(shù)的行為:當參數(shù)pathname是絕對路徑,或者參數(shù)fd的值為AT_FDCWD并且pathname為相對路徑時,fchownat函數(shù)的行為和chown和lchown類似;具體來說,flag取值A(chǔ)T_SYMLINK_NOFOLLOW時,行為和lchown類似;否則行為和chown類似。當fd代表已打開的文件夾,pathname為一個相對路徑時,目標文件為以fd為父目錄,pathname為相對的子目錄所指的文件。
?
5 文件大?。‵ile Size)stat結(jié)構(gòu)體中的成員st_size表示文件大小字節(jié)數(shù)。
字段st_size只對常規(guī)文件(regular files)、目錄文件(directories)和符號鏈接文件(symbolic links)。
更多的細節(jié):
?
6 文件截斷(File Truncation)有時候我們需要通過丟棄文件結(jié)尾一部分來截短文件。
函數(shù)聲明:
#include <unistd.h>
int truncate(const char* pathname, off_t length);
itn ftruncate(int fd, off_t length);
函數(shù)作用:把目標文件截斷到參數(shù)length指定的長度。
參數(shù):如果參數(shù)length的值比指定文件的長度小,則文件超過length長度的部分不可讀;如果length的值比指定文件的長度大,文件長度擴大到length,擴充部分填充0(可能是一個hole)
?
7 文件系統(tǒng)(File Systems)為了理解文件鏈接,我們需要對Unix文件系統(tǒng)的結(jié)構(gòu)有一個概念性地認識。
一個磁盤(disk drive)可以被分為多個分區(qū)(partition),每個分區(qū)都可以包含一個文件系統(tǒng)(file system)。
inode是一個定長的索引,包含了一個文件的大部分信息。

關(guān)于 i-nodes和data blocks的內(nèi)存布局如下圖所示:

說明:
我們再了解一下目錄文件的link count字段。
當我們執(zhí)行下面的命令:
mkdir testdir
?內(nèi)存中數(shù)據(jù)組織結(jié)構(gòu)如下所示:

從上圖可以看到,目錄下每多加一個文件或文件夾,link count都會加1。
圖中顯示的都很清楚,不做過多贅述(其實是我懶了,哈哈...)
?
8 link、linkat、unlink、unlinkat和remove函數(shù)從前面可以知道,多個目錄索引可以指向同一個文件,即多個目錄可以包含同一個文件。
link和linkat的作用是創(chuàng)建一個已存在文件的鏈接。
函數(shù)聲明:
#include <unistd.h>
int link(const char* existingpath, const char* newpath);
int linkat(int efd, const char* existingpath, int nfd, const char* newpath, int flag);
函數(shù)細節(jié):
函數(shù)聲明:
#include <unistd.h>
int unlink(const char* pathname);
int unlinkat(int fd, const char* pathname, int flag);
函數(shù)細節(jié):
和unlink類似功能的函數(shù)remove:
#include <stdio.h>
int remove(const char* pathname);
函數(shù)細節(jié):
?
9 rename和renameat函數(shù)函數(shù)聲明:
#include <stdio.h>
int rename(const char* oldname, const char* newname);
int renameat(int oldfd, const char* oldname, int newfd, const char* newname);
函數(shù)細節(jié):
對renameat函數(shù)的參數(shù)含義不再贅述。
?
10 符號鏈接(Symbolic Links)符號鏈接可以認為是文件的非直接指針,而硬鏈接(hard link)可以看做是文件的直接指針,因為它直接指向文件的inode。
符號鏈接并沒有文件系統(tǒng)間的限制。
由于符號鏈接的存在,我們在操作文件或目錄時,總是需要知道該文件是否是一個符號鏈接,然后判斷該函數(shù)的操作對象是符號鏈接指向的文件還是符號鏈接本身。
下圖總結(jié)了一些常用函數(shù)是否追蹤鏈接,僅供參考:

Example:

鏈接情況如下圖所示:

可以發(fā)現(xiàn),由于符號鏈接而出現(xiàn)了一個環(huán)。
再來試驗一下:

我們發(fā)現(xiàn),這樣會無限循環(huán)下去。
解除循環(huán)的方法就是使用unlink刪除該符號鏈接。需要注意的一點是,如果這里出現(xiàn)的鏈接是硬鏈接,則刪除這個循環(huán)鏈接會困難得多。因此只有管理員權(quán)限才可以用link函數(shù)對一個文件建立硬鏈接。
有時候符號鏈接會造成一些迷惑的事情,如果使用者對符號鏈接不熟悉的話。
如下所示:

符號鏈接可以鏈接一個不存在的文件,如果使用者對符號鏈接不熟悉,則很容易被這種情況迷惑。
這時,可以使用ls的”-l"命令看到有 “->"符號,或者前面符號位第一位的”l”表示符號鏈接,或者用ls得“-F”命令,符號鏈接文件后面會跟一個@符。
?
11 創(chuàng)建和讀取符號鏈接(Symbolic Links)函數(shù)作用:創(chuàng)建符號鏈接
函數(shù)聲明:
#include <unistd.h>
int symlink(const char *actualpath, const char* sympath);
int symlinkat(const char* actualpath, int fd, const char* sympath);
參數(shù)說明:
因為open函數(shù)會打開符號鏈接指向的實際文件,所以需要一個函數(shù)打開符號鏈接本身。
函數(shù)聲明:
#include <unistd.h>
ssize_t readlink(const char* restrict pathname, char* restrict buf, size_t bufsize);
ssize_t readlinkat(int fd, const char* restrict pathname, char* restrict buf, size_t bufsize);
如果調(diào)用成功,函數(shù)從符號鏈接中讀取buf長的內(nèi)容。
?
?
參考資料:
《Advanced PRogramming in the UNIX Envinronment 3rd》
?
新聞熱點
疑難解答