在 C/C++ 程式中呼叫 mkdir() 建立目錄時,權限模式設定常踩坑。本文詳解 mode_t 參數正確寫法、umask 影響機制、建立特定群組目錄流程,並提供除錯技巧。
#include <sys/stat.h> #include <sys/types.h> int mkdir(const char *path, mode_t mode);
path:目錄路徑(相對或絕對),如 "test"、"/var/www/project"mode:權限位元遮罩,八進制表示(必須加前綴 0)errnoLinux 權限採「擁有者-群組-其他人」三組,各含「讀-寫-執行」三位元:
| 身分 | 讀 | 寫 | 執行 | 八進制值 |
|---|---|---|---|---|
| 擁有者 | r | w | x | 4+2+1=7 |
| 群組 | r | w | x | 4+2+1=7 |
| 其他人 | r | w | x | 4+2+1=7 |
常見組合:
0777:所有人完整權限0755:擁有者完整,群組/其他人讀+執行0700:僅擁有者完整權限(私密目錄)// 錯誤:777 被視為十進制,實際權限錯誤
mkdir("test", 777);
// 正確:0777 明確指定八進制
mkdir("test", 0777);
C 語言中以 0 開頭的整數字面值為八進制。寫成 777 會被編譯器視為十進制 777,轉換成八進制為 01411,導致權限異常。習慣在 mode 參數前加 0。
進程的 umask(預設 0022)會「遮蔽」掉指定權限:
實際權限 = mode & ~umask
例:mkdir("dir", 0777),umask=0022 → 實際權限 0755。
mode_t old_umask = umask(0);
mkdir("dir", 0777);
umask(old_umask);
0755。mkdir() 只能建立屬於目前進程有效 UID/GID 的目錄。若需指定擁有者,需建立後再調整:
// 1. 建立目錄
mkdir("/var/project", 0770);
// 2. 修改擁有者(需 root 權限)
chown("/var/project", uid, gid); // 或 system("chown user:group /var/project");
// 3. 微調權限
chmod("/var/project", 0750);
UID/GID 可從 /etc/passwd、/etc/group 查詢,或用 getpwnam()、getgrnam() 取得。
ls -ld /var/project # 輸出範例:drwxr-x--- 2 user group 4096 Jan 1 12:00 /var/project # 對應 0750
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>
#include <string.h>
int create_project_dir(const char *path, const char *owner, const char *group, mode_t mode) {
// 暫時關閉 umask 確保權限精確
mode_t old_umask = umask(0);
int ret = mkdir(path, mode);
umask(old_umask);
if (ret == -1) {
if (errno == EEXIST) {
fprintf(stderr, "目錄已存在: %s\n", path);
} else {
perror("mkdir 失敗");
}
return -1;
}
// 解析 UID/GID
struct passwd *pw = getpwnam(owner);
struct group *gr = getgrnam(group);
if (!pw || !gr) {
fprintf(stderr, "使用者/群組不存在\n");
return -1;
}
if (chown(path, pw->pw_uid, gr->gr_gid) == -1) {
perror("chown 失敗");
return -1;
}
return 0;
}
int main() {
return create_project_dir("/var/myproject", "www-data", "www-data", 0750);
}
0755 而非 755mkdir -p 系統呼叫