Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux mkdir() 權限模式設定完全指南:mode_t、umask 與實戰陷阱

編輯:Linux 教學

在 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)
  • 回傳:成功 0,失敗 -1 並設定 errno

權限位元組合邏輯

Linux 權限採「擁有者-群組-其他人」三組,各含「讀-寫-執行」三位元:

身分讀寫執行八進制值
擁有者rwx4+2+1=7
群組rwx4+2+1=7
其他人rwx4+2+1=7

常見組合:

  • 0777:所有人完整權限
  • 0755:擁有者完整,群組/其他人讀+執行
  • 0700:僅擁有者完整權限(私密目錄)

常見錯誤:忘記八進制前綴 0

// 錯誤:777 被視為十進制,實際權限錯誤
mkdir("test", 777);

// 正確:0777 明確指定八進制
mkdir("test", 0777);

C 語言中以 0 開頭的整數字面值為八進制。寫成 777 會被編譯器視為十進制 777,轉換成八進制為 01411,導致權限異常。習慣在 mode 參數前加 0。

umask 影響實際權限

進程的 umask(預設 0022)會「遮蔽」掉指定權限:

實際權限 = mode & ~umask

例:mkdir("dir", 0777),umask=0022 → 實際權限 0755。

解決方案

  1. 暫時關閉 umask(僅影響目前進程):
    mode_t old_umask = umask(0);
    mkdir("dir", 0777);
    umask(old_umask);
  2. 在 mode 中預先扣除 umask:若預期 umask=0022,直接指定 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);
}

關鍵提醒總結

  • mode 必須用八進制(前綴 0):0755 而非 755
  • umask 會修改最終權限,需評估是否暫時關閉
  • mkdir() 不支援遞迴建立父目錄,需自行實作或用 mkdir -p 系統呼叫
  • 跨檔案系統建立目錄需權限,目標掛載點需可寫入
  • 錯誤處理檢查 errno:EEXIST、EACCES、ENOENT、ENOSPC 等
Copyright © Windows教程網 All Rights Reserved