Linux 權限模型以「使用者/群組/其他」三層,配合 r/w/x、setuid/setgid、sticky bit 構成靈活防護網。目錄與檔案的權限語義差異是新手最易混淆處。
標準 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系統呼叫處理。
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 的路徑解析開銷。
stat 會追蹤符號連結,lstat 回傳連結本身資訊。passwd 程式擁有 root 擁有者與 setuid 位,一般使用者執行時取得 root 權限,得以修改 /etc/passwd。x 才能 open() 其下檔案;r 僅能列出檔名。w + x;刪除不需檔案本身的 w。fsck/find 等工具死循環,故多數 UNIX 禁止對目錄建立硬連結。/tmp):擁有 w+x 且滿足「檔案擁有者 / 目錄擁有者 / root」任一條件才能刪除檔案。ln -s ../foo link:符號連結目標可不存在;相對路徑按連結檔案位置解析。stat 多數資訊來自 inode。(檔名, inode號) 對應表的特殊檔案。typedef int Func(int, int); static Func my_func; 等同 static int my_func(int, int);,增強可讀性。*p++ = '0' 先賦值再遞增指標;*++p = '0' 先遞增再賦值。ptr[-1] 等價 *(ptr-1),存取前一個元素。chdir 只影響呼叫進程及其子進程。open(..., O_TRUNC) 會清空現有檔案內容但保留權限位。. 和 .. 兩項;符號連結大小 = 路徑字串長度。time ./prog 量測程式總執行時間。PATH_MAX 限制:核心無目錄深度限制,但許多工具(如 getcwd)在路徑超過 PATH_MAX 會失敗。《Advanced Programming in the UNIX Environment (APUE)》