APUE-文件和目錄(七)符號鏈接

目錄

 

正文

回到頂部

符號鏈接

符號鏈接的用途

符號鏈接是對一個文件的間接指針,它與前面介紹的硬連接不同,硬連接指向文件的i節點。引入符號鏈接是爲了避開硬連接的一些限制:

  • 硬鏈接通常要求鏈接和文件位於同一文件系統中。

  • 只有超級用戶才能創建指向目錄的硬鏈接(在底層文件系統支持的情況下)。

而對於符號鏈接:

  • 對符號鏈接以及它指向何種對象並無任何文件系統限制;

  • 任何用戶都可以創建指向目錄的符號鏈接。

跟隨符號鏈接

符號鏈接一般用於將一個文件或整個目錄結構移到系統中另外一個位置。
用符號鏈接作爲函數參數時,需要了解該函數所處理的是否是符號鏈接指向的文件。也就是是否跟隨符號鏈接

  • 如果該函數具有處理符號鏈接的功能,則其路徑名參數引用由符號鏈接指向的文件。

  • 否則,一個路徑名參數引用鏈接本身。

圖4-17列出了本章中所說明的各個函數是否處理符號鏈接。
bloglt_20170611144535.jpg

特殊的例子:
如果同時使用O_CREAT和O_EXCL,調用open函數。

  • 我們知道如果要打開的是文件,而文件已經存在,則出錯。如果不存在則創建此文件,這使得測試和創建兩者成爲一個原子操作。

  • 如果要打開的是符號鏈接,不管符號鏈接指向的文件是否存在,都會返回錯誤。這種處理方式的意圖是堵塞一個安全性漏洞,以防止具有特權的進程被誘騙寫錯誤的文件。
    例如:進程A用於寫已經存在的A.txt文件,如果刪除A.txt文件,而把A.txt文件製作成一個符號鏈接指向自定義文件,進程就可以隨意寫任何文件了。

符號鏈接可能引入循環

使用符號鏈接可能在文件系統中引入循環。大多數查找路徑名的函數在這種情況發生時都將出錯返回,errno值爲ELOOP。考慮下列命令序列:

harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples$ mkdir foo
harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples$ touch foo/a
harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples$ ln -s ../foo foo/testdir
harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples$ ls -l foo
total 0
-rw-rw-r-- 1 harlan harlan 0 Jun 11 16:40 a
lrwxrwxrwx 1 harlan harlan 6 Jun 11 16:40 testdir -> ../foo

圖4-18顯示了結果:
bloglt_20170611163942.jpg

可以一直循環下去。。。

harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples$ cd foo/testdir/testdir/testdir/testdir
harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples/foo/testdir/testdir/testdir/testdir$

Solaris的標準函數ftw以降序遍歷文件結構,打印遇到的每個路徑名,直至ftw出錯返回。但是Linux中的ftw和nftw記錄了看到的目錄並避免多次重複一個目錄,因此這兩個函數不顯示solaris中ftw的出錯運行行爲。

open一個符號鏈接

open函數跟隨符號鏈接,如果符號鏈接指向的文件不存在,open返回出錯,表示它不能打開該文件。這可能會使不熟悉符號鏈接的用戶感到迷茫:

harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples$ ln -s /no/sucn/file myfile
harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples$ ll myfile
lrwxrwxrwx 1 harlan harlan 13  6月 12 08:28 myfile -> /no/sucn/file
harlan@DESKTOP-KU8C3K5:/github/APUE/chapter_4/myexamples$ cat myfile
cat: myfile: 沒有那個文件或目錄

回到頂部

創建和讀取符號鏈接

使用symlink或者symlinkat函數創建一個符號鏈接。

#include <unistd.h>
int symlink(const char* actualpath,const char *sympath);
int symlinkat(const char*actualpath,int fd,const char* sympath);
成功返回0;如果出錯返回-1

調用這兩個函數創建符號鏈接時:

  • 不要求actualpath已經存在。

  • actualpath和sympath並不需要位於同一個文件系統中。

因爲open函數跟隨符號鏈接,因此需要有一種方法打開鏈接本身,並讀該鏈接中的名字。readlink和readlinkat函數提供了這種功能:

#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);
成功返回讀取的字節數;如果失敗返回-1。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章