# 系統程式設計 - `link()`, `linkat()` and `unlink()`
[TOC]
## 課程影片
### W6-3: inode, hard link and soft link, directory structure (08:53 ~ FIN)
{%youtube H1xHT9SnQHA %}
### sp-04-08 (00:00 ~ 21:00)
{%youtube 4qnVMCwE8Dk %}
## 命令列工具
主要的命令列工具是 `ln`、`link`。可以先建立一個檔案:
```
$ touch AAAAA
```
然後使用 `stat`:
```
$ stat AAAAA
```
查看他的編號:
```
File: AAAAA
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: b302h/45826d Inode: 643011 Links: 1
Access: (0664/-rw-rw-r--) Uid: ( 1000/ ubuntu) Gid: ( 1000/ ubuntu)
Access: 2021-10-20 06:54:14.897970317 +0000
Modify: 2021-10-20 06:54:14.897970317 +0000
Change: 2021-10-20 06:54:14.897970317 +0000
Birth: -
```
## Hard Link:幫一個檔案增加新名稱
除了 `ln` 之外,Hard Link 可以用 `link` 命令來製造,而它的行為可以在 `man 1 link` 跟 `man 2 link` 查。如果查:
```
$ man 2 link
```
裡面會開宗名義說:*link, linkat - make a new name for a file*,並且在 **DESCRIPTION** 中說明了 hard link 的行為:
> **DESCRIPTION**
> `link()` creates a new link (also known as a hard link) to an existing file.
> ...
> ==This new name may be used exactly as the old one for any operation== ; both names refer to the same file (and so have the same permissions and ownership) and ==it is impossible to tell which name was the "original"== .
言下之意,使用 hard link 這個「新名稱」所做的一切操作,都跟直接用原來的檔案名稱操作會有一樣的結果,兩者是無法區分。
### 例子:`ln`
比如建立一個叫做 `AAAAA-hard` 的 hard link:
```
$ ln AAAAA AAAAA-hard
```
就會發現這兩個檔案的 inode 根本一樣:
```
$ ls -li
total 8
643011 -rw-rw-r-- 2 ubuntu ubuntu 6 Oct 20 06:57 AAAAA
643011 -rw-rw-r-- 2 ubuntu ubuntu 6 Oct 20 06:57 AAAAA-hard
```
如果去 `stat` 這個檔案:
```
$ stat AAAAA-hard
```
會發現裡面出現的東西跟 `AAAAA` 一樣。不過,在建立之後,`Link` 欄位的數目由 `1` 變成了 `2`:
```
File: AAAAA-hard
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: b302h/45826d Inode: 643011 Links: 2
Access: (0664/-rw-rw-r--) Uid: ( 1000/ ubuntu) Gid: ( 1000/ ubuntu)
Access: 2021-10-20 06:54:14.897970317 +0000
Modify: 2021-10-20 06:54:14.897970317 +0000
Change: 2021-10-20 06:55:25.773340588 +0000
Birth: -
```
另外,如果修改這個 `AAAAA-hard`,比如:
```
$ echo "BBBBB" > AAAAA-hard
```
然後檢視 `AAAAA`:
```
$ cat AAAAA
```
就會發現跟著改變:
```
BBBBB
```
這個跟 C++ 的 reference 類似。另外,如果直接 `rm AAAAA-hard` 的話,那麼 `AAAAA` 會連同本來的 `AAAAA-hard` 一起被刪掉。
### 移除 Hard Link --- `unlink`
如果直接 `rm` 一個 *ahrd link* 會刪掉原來的檔案,那這個 hard link 到底要怎麼移除?答案是使用 `unlink`。在 `man` 裡面提到:
> **DESCRIPTION**
> **`unlink()`** deletes a name from the filesystem. If that name was the last link to a file and no processes have the file open, the file is deleted and the space it was using is made available for reuse.
## Soft Link
在 `man` 裡面的 `synlink` 有介紹:
```
$ man symlink
```
裡面提到:
> **DESCRIPTION**
> Symbolic links are interpreted at run time as if the contents of the link had been substituted into the path being.
>
> Symbolic links may contain **`..`** path components, which (if used at the start of the link) refer to the parent directories of that in which the link resides.
>
> A symbolic link (also known as a soft link) may point to an existing file or to a nonexistent one; the latter case is known as a dangling link.
>
> The permissions of a symbolic link are irrelevant; the ownership is ignored when following the link, but is checked when removal or renaming of the link is requested and the link is in a directory with the sticky bit (**`S_ISVTX`**) set.
### 例子:`ln -s`
使用 `ln -s` 建立。
```
$ ln -s AAAAA AAAAA-soft
```
如果這時候再 `ls -li` 一次:
```
$ ls -li
total 8
643011 -rw-rw-r-- 2 ubuntu ubuntu 6 Oct 20 06:57 AAAAA
643011 -rw-rw-r-- 2 ubuntu ubuntu 6 Oct 20 06:57 AAAAA-hard
643013 lrwxrwxrwx 1 ubuntu ubuntu 5 Oct 20 07:05 AAAAA-soft -> AAAAA
```
會發現這個 `AAAAA-soft` 跟原來的 `AAAAA` 是不同的檔案。如果去 `stat` 它也會發現這件事情:
```
$ stat AAAAA-soft
```
它是一個「另外一個紀錄著路徑的檔案」,而不是「同一個檔的不同名稱」:
```
File: AAAAA-soft -> AAAAA
Size: 5 Blocks: 0 IO Block: 4096 symbolic link
Device: b302h/45826d Inode: 643013 Links: 1
Access: (0777/lrwxrwxrwx) Uid: ( 1000/ ubuntu) Gid: ( 1000/ ubuntu)
Access: 2021-10-20 07:00:29.454111680 +0000
Modify: 2021-10-20 07:00:29.454111680 +0000
Change: 2021-10-20 07:00:29.454111680 +0000
Birth: -
```
### 例子:`unlink` 原來的檔案
一個比較 hard link 跟 soft link 差別的方式,是對上面原先的 `AAAAA` 使用 `unlink`:
```
$ unlink AAAAA
```
所以這時候,如果檢視目錄的內容:
```
$ ls -li
```
就會發現剩下 `AAAAA-hard` 與 `AAAAA-soft`:
```
643011 -rw-rw-r-- 1 ubuntu ubuntu 6 Oct 20 06:57 AAAAA-hard
643013 lrwxrwxrwx 1 ubuntu ubuntu 5 Oct 20 07:05 AAAAA-soft -> AAAAA
```
這時,如果檢視 `AAAAA-hard` 當中的內容,會發現它跟原來一樣:
```
$ cat AAAAA-hard
BBBBB
```
若使用 `stat` :
```
$ stat AAAAA-hard
```
也會呈現出一樣的資訊:
```
File: AAAAA-hard
Size: 6 Blocks: 8 IO Block: 4096 regular file
Device: b302h/45826d Inode: 643011 Links: 1
Access: (0664/-rw-rw-r--) Uid: ( 1000/ ubuntu) Gid: ( 1000/ ubuntu)
Access: 2021-10-20 08:10:28.714712243 +0000
Modify: 2021-10-20 06:57:22.844185536 +0000
Change: 2021-10-20 08:07:48.431877136 +0000
Birth: -
```
但這時,若檢視 `AAAAA-soft` 這個 soft link 的內容,他會抱怨這個檔案不存在:
```
$ cat AAAAA-soft
cat: AAAAA-soft: No such file or directory
```