首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

UNIX 系統程式設計筆記(二):檔案與目錄權限深度解析

     編輯:關於C語言

Linux 安全機制核心觀察

Linux 權限模型以「使用者/群組/其他」三層,配合 r/w/x、setuid/setgid、sticky bit 構成靈活防護網。目錄與檔案的權限語義差異是新手最易混淆處。

實用程式碼片段

1. 複製檔案並保留「洞」(Sparse File)

標準 cp 會將洞(未寫入區塊)展開為實體 \\0,導致檔案膨脹。以下程式碼以單位元組讀取,跳過 \\0 實現「複製時保留洞」:


#include <apue.h>
#include <fcntl.h>

int main() {
    char buf[1];
    int fd_in = open("temp_in_hole", O_RDONLY);
    int fd_out = open("temp_out_hole", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    int n;

    while ((n = read(fd_in, buf, 1)) > 0) {
        if (buf[0] != '\\0') {
            if (write(fd_out, buf, 1) != n)
                err_sys("write error");
        } else {
            lseek(fd_out, 1, SEEK_CUR);  // 跳過輸出端對應位置,形成洞
        }
    }
    close(fd_in);
    close(fd_out);
    return 0;
}
效能註記:單位元組 I/O 極慢。生產環境應用 lseek 掃描輸入檔案的洞邊界,再以大塊 read/write 或 copy_file_range 系統呼叫處理。

2. 遞迴遍歷目錄樹(ftw 風格)


static int dopath(Myfunc *func) {
    struct stat statbuf;
    struct dirent *dirp;
    DIR *dp;
    int ret;
    char *ptr;

    if (lstat(fullpath, &statbuf) < 0)
        return func(fullpath, &statbuf, FTW_NS);

    if (!S_ISDIR(statbuf.st_mode))
        return func(fullpath, &statbuf, FTW_F);

    if ((ret = func(fullpath, &statbuf, FTW_D)) != 0)
        return ret;

    ptr = fullpath + strlen(fullpath);
    *ptr++ = '/';
    *ptr = '\\0';

    if (chdir(fullpath) < 0) {  // 切換工作目錄提升效能
        err_ret("chdir failed for %s", fullpath);
        return -1;
    }

    if ((dp = opendir(".")) == NULL)
        return func(fullpath, &statbuf, FTW_DNR);

    while ((dirp = readdir(dp)) != NULL) {
        if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0)
            continue;
        strcpy(ptr, dirp->d_name);
        if ((ret = dopath(func)) != 0)
            break;
    }

    ptr[-1] = '\\0';
    closedir(dp);
    chdir("..");
    return ret;
}

技巧:chdir 進入子目錄後用相對路徑 opendir("."),避免長路徑字串拼接,並減少 lstat 的路徑解析開銷。

關鍵知識點整理

  1. 資料無二進制/文字之分:核心視所有檔案為位元組流。
  2. FIFO (Named Pipe):特殊檔案類型,用於進程間通訊。
  3. stat vs lstat:stat 會追蹤符號連結,lstat 回傳連結本身資訊。
  4. setuid 實例:passwd 程式擁有 root 擁有者與 setuid 位,一般使用者執行時取得 root 權限,得以修改 /etc/passwd。
  5. 目錄的 x 權限 = search bit:必須擁有目錄的 x 才能 open() 其下檔案;r 僅能列出檔名。
  6. 建立/刪除檔案:需目錄的 w + x;刪除不需檔案本身的 w。
  7. 硬連結目錄危險:可能形成循環,導致 fsck/find 等工具死循環,故多數 UNIX 禁止對目錄建立硬連結。
  8. sticky bit 目錄(如 /tmp):擁有 w+x 且滿足「檔案擁有者 / 目錄擁有者 / root」任一條件才能刪除檔案。
  9. ln -s ../foo link:符號連結目標可不存在;相對路徑按連結檔案位置解析。
  10. inode:固定長度條目,儲存檔案元資料(權限、時間戳、區塊指標等),stat 多數資訊來自 inode。
  11. 目錄本質:包含 (檔名, inode號) 對應表的特殊檔案。
  12. typedef 簡化函數指標:typedef int Func(int, int); static Func my_func; 等同 static int my_func(int, int);,增強可讀性。
  13. 指標運算優先序:*p++ = '0' 先賦值再遞增指標;*++p = '0' 先遞增再賦值。
  14. ptr[-1] 等價 *(ptr-1),存取前一個元素。
  15. 當前工作目錄屬於進程:chdir 只影響呼叫進程及其子進程。
  16. open(..., O_TRUNC) 會清空現有檔案內容但保留權限位。
  17. 目錄大小永不為 0:至少含 . 和 .. 兩項;符號連結大小 = 路徑字串長度。
  18. time ./prog 量測程式總執行時間。
  19. PATH_MAX 限制:核心無目錄深度限制,但許多工具(如 getcwd)在路徑超過 PATH_MAX 會失敗。

參考資料

《Advanced Programming in the UNIX Environment (APUE)》

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved