LaTeX957300 views
雑学1472593 views
高校日本史189857 views
ヒストリア284143 views
中学英語808712 views
Computer365120 views
小学算数1194618 views
中学理科1626207 views
教育148875 views
中学社会667106 views
Help
Tools

English

umask とファイル作成時のパーミッション決定

Python でファイルを作成するとき、パーミッションが意図どおりにならないことがある。これは umask の仕組みを理解していないと解決できない。

umask とは

umask はファイル作成時のパーミッションから「引かれる」ビットマスクだ。

指定したパーミッション

ファイル作成時に指定するパーミッション(例: 0o666)

実際のパーミッション

指定したパーミッションから umask を引いた値

# 現在の umask を確認
umask
# 0022

# 意味: 新規ファイルから w(書き込み)を group と other から除去

umask の計算

実際のパーミッションは以下の式で計算される。

# 実際のパーミッション = 指定パーミッション & ~umask

# 例: mode=0o666, umask=0o022 の場合
mode = 0o666      # 110 110 110
umask = 0o022     # 000 010 010
result = mode & ~umask
print(oct(result))  # 0o644 (110 100 100)

umask が 0o022 なら、group と other から書き込み権限が除去される。

Python でのファイル作成と umask

open() でファイルを作成すると、umask が適用される。

import os
import stat

# 現在の umask を確認
current_umask = os.umask(0)
os.umask(current_umask)  # 元に戻す
print(f"umask: {oct(current_umask)}")  # 0o22

# ファイルを作成(デフォルトは 0o666 から umask を引いた値)
with open("test.txt", "w") as f:
    f.write("hello")

# パーミッションを確認
mode = os.stat("test.txt").st_mode & 0o777
print(f"permission: {oct(mode)}")  # 0o644

umask を一時的に変更する

特定のパーミッションでファイルを作成したい場合、umask を一時的に変更する。

import os

def create_with_mode(path, mode, content):
    """指定したパーミッションでファイルを作成"""
    old_umask = os.umask(0)  # umask を 0 にして影響を無効化
    try:
        fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, mode)
        try:
            os.write(fd, content.encode())
        finally:
            os.close(fd)
    finally:
        os.umask(old_umask)  # umask を元に戻す

# 0o600(所有者のみ読み書き可能)でファイルを作成
create_with_mode("secret.txt", 0o600, "secret data")

os.open() と open() の違い

open()

Python レベルの関数。モード指定は文字列(“r”, “w” など)。パーミッションは指定できない

os.open()

システムコールの薄いラッパー。パーミッションを直接指定できる

import os

# os.open() でパーミッションを指定
fd = os.open("data.txt", os.O_WRONLY | os.O_CREAT, 0o600)
os.write(fd, b"hello")
os.close(fd)

# open() はパーミッションを指定できない(umask 依存)
with open("data2.txt", "w") as f:
    f.write("hello")
# パーミッションは umask に従う

ディレクトリの umask

ディレクトリ作成時も umask が適用される。ディレクトリのデフォルトパーミッションは 0o777 だ。

import os

# umask=0o022 の場合
os.mkdir("newdir")  # 0o777 & ~0o022 = 0o755

# 指定したパーミッションで作成(umask は適用される)
os.mkdir("newdir2", mode=0o700)  # 実際は 0o700 & ~umask
# シェルでディレクトリを作成
mkdir testdir
ls -ld testdir
# drwxr-xr-x 2 user user 4096 Jan 15 10:00 testdir (0o755)

chmod で事後変更

umask を経由せずにパーミッションを設定したい場合は、作成後に chmod する方法もある。

import os
import stat

# ファイルを作成
with open("secret.txt", "w") as f:
    f.write("secret")

# パーミッションを変更
os.chmod("secret.txt", 0o600)

# stat モジュールの定数を使う方法
os.chmod("secret.txt", stat.S_IRUSR | stat.S_IWUSR)  # 0o600 と同じ

ただし、作成と chmod の間に一瞬のすきまがある。機密ファイルの場合は os.open() で最初から正しいパーミッションを設定するほうが安全だ。

umask のセキュリティ上の意味

umask 0o022(一般的)

group と other から書き込み権限を除去。ファイルは 0o644、ディレクトリは 0o755 になる

umask 0o077(厳格)

group と other からすべての権限を除去。ファイルは 0o600、ディレクトリは 0o700 になる

umask 0o000(危険)

制限なし。すべてのユーザーが読み書き可能なファイルが作成される可能性がある

Python スクリプト全体で umask を設定

スクリプトの開始時に umask を設定しておくと、以降のすべてのファイル作成に適用される。

import os

# スクリプト開始時に厳格な umask を設定
os.umask(0o077)

# 以降、作成されるファイルはすべて 0o600
with open("file1.txt", "w") as f:
    f.write("data1")

with open("file2.txt", "w") as f:
    f.write("data2")

まとめ

関数パーミッション指定umask 適用
open()不可される
os.open()可能される
os.mkdir()可能される
os.chmod()可能されない
umask を意識すべき場面

セキュリティが重要なファイル、他ユーザーとの共有ファイル、サービスで作成するファイル

ベストプラクティス

機密ファイルは os.open() で明示的にパーミッションを指定し、作成後に chmod で再確認する