# 系統程式設計 - `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 ```