[インデックス 14520] ファイルの概要
このコミットは、Go言語のos
パッケージにおいて、Windows環境でのディレクトリのファイルモードに実行パーミッション(0111
)を含めるように修正するものです。これにより、Windows上でのディレクトリの振る舞いが、Unix系システムにおけるディレクトリの実行権限の解釈(ディレクトリの検索・アクセス権)とより整合性が取れるようになります。
コミット
commit 5b6502356391a59441dee6056f92832295e66f65
Author: Alex Brainman <alex.brainman@gmail.com>
Date: Wed Nov 28 17:01:59 2012 +1100
os: include 0111 in directory file mode on windows
Fixes #4444.
R=golang-dev, minux.ma, rsc
CC=golang-dev
https://golang.org/cl/6858079
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/5b6502356391a59441dee6056f92832295e66f65
元コミット内容
os: include 0111 in directory file mode on windows
Fixes #4444.
R=golang-dev, minux.ma, rsc
CC=golang-dev
https://golang.org/cl/6858079
変更の背景
この変更は、Go言語のos
パッケージがWindows上でディレクトリのファイルモードを正しく報告しないという問題(Issue #4444)を修正するために行われました。Unix系システムでは、ディレクトリの実行権限(x
ビット、八進数表記で1
)は、そのディレクトリの中身をリストしたり、そのディレクトリをパスの一部として辿ったりするために必要です。しかし、Windowsのファイルシステム(NTFSなど)は、Unixのような厳密な実行権限の概念をディレクトリに適用しません。代わりに、ディレクトリへのアクセスは「フォルダの走査/ファイルの実行」や「コンテンツのリスト/データの読み取り」といった属性によって制御されます。
Goのos.FileMode
は、クロスプラットフォームでファイルパーミッションを表現するための抽象化を提供しています。Windows上でディレクトリのStat
情報を取得した際に、Unix系システムとの互換性を保つために、ディレクトリには常に実行権限が付与されていると見なす必要がありました。以前の実装では、Windowsのディレクトリに対してStat
を実行しても、0111
(実行権限)がモードに含まれていなかったため、一部のアプリケーションやテストで予期せぬ動作を引き起こす可能性がありました。このコミットは、この不整合を解消し、Windows上でもディレクトリが「実行可能」(走査可能)であることを明示的に示すように修正しています。
前提知識の解説
ファイルパーミッション(Unix系)
Unix系オペレーティングシステムでは、ファイルやディレクトリには所有者、グループ、その他のユーザーに対する読み取り(r)、書き込み(w)、実行(x)の3種類のパーミッションが設定されます。これらは通常、八進数(オクタル)表記で表現されます。
- 読み取り (r): 4
- 書き込み (w): 2
- 実行 (x): 1
これらの値を組み合わせてパーミッションを表します。例えば、755
は以下を意味します。
- 所有者:
rwx
(4+2+1=7) - グループ:
r-x
(4+0+1=5) - その他:
r-x
(4+0+1=5)
ディレクトリの場合、実行権限(x
)は、そのディレクトリの中身をリストする(ls
コマンドなど)ため、またはそのディレクトリをパスの一部として辿る(cd
コマンドなど)ために必要です。実行権限がないディレクトリは、たとえ読み取り権限があっても中身を見ることができません。
0111
の意味
八進数表記の0111
は、所有者、グループ、その他のユーザーに対してそれぞれ実行権限(x
)のみが付与されている状態を意味します。ディレクトリにおいては、これは「誰でもこのディレクトリを走査できる」ということを示唆します。
Go言語のos.FileMode
Go言語のos
パッケージは、ファイルやディレクトリの情報を抽象化するためにos.FileInfo
インターフェースとos.FileMode
型を提供しています。os.FileMode
は、ファイルの種類(ディレクトリ、シンボリックリンクなど)とパーミッションビットを組み合わせたものです。
os.ModeDir
: ディレクトリであることを示すビット。os.Stat(path string)
: 指定されたパスのファイルまたはディレクトリのos.FileInfo
を返します。この情報にはファイルモードも含まれます。
Windowsのファイル属性とUnixパーミッションの対応
Windowsのファイルシステム(NTFS)は、Unixのようなビット単位のパーミッションモデルとは異なるアクセス制御リスト(ACL)を使用します。しかし、Goのようなクロスプラットフォーム言語では、Windowsのファイル属性をUnixのパーミッションモデルにマッピングする必要があります。
syscall.FILE_ATTRIBUTE_DIRECTORY
: Windows APIでディレクトリを示すファイル属性。syscall.FILE_ATTRIBUTE_READONLY
: Windows APIで読み取り専用を示すファイル属性。
Goのos
パッケージは、mkMode
のような内部関数を使って、Windowsのファイル属性をos.FileMode
に変換しています。
技術的詳細
このコミットの核心は、Windowsのファイル属性をGoのos.FileMode
に変換するロジックの変更です。具体的には、src/pkg/os/stat_windows.go
内のmkMode
関数が修正されました。
mkMode
関数は、Windowsのファイル属性(fa
)を受け取り、対応するos.FileMode
を生成します。変更前は、ディレクトリの場合にModeDir
ビットのみを設定していました。
// 変更前
if fa&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
m |= ModeDir
}
変更後は、ModeDir
に加えて、八進数0111
(所有者、グループ、その他の実行権限)もOR演算で追加しています。
// 変更後
if fa&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
m |= ModeDir | 0111 // ここが変更点
}
この変更により、Windows上のディレクトリに対してos.Stat
を実行すると、返されるos.FileMode
には常にModeDir
と0111
の両方が含まれるようになります。これは、Unix系システムにおけるディレクトリの「走査可能」という性質をWindows上でも表現するための重要な対応です。Windowsではディレクトリの実行権限という概念は直接存在しませんが、Goの抽象化レイヤーでこのビットを追加することで、クロスプラットフォームでの一貫した動作を保証します。
また、この変更を検証するために、src/pkg/os/os_test.go
に新しいテストケースTestStatDirModeExec
が追加されました。このテストは、現在のディレクトリ(.
)に対してStat
を実行し、そのモードに0111
が含まれていることを確認します。これにより、Windows上でのディレクトリモードの修正が正しく機能していることが保証されます。
コアとなるコードの変更箇所
diff --git a/src/pkg/os/os_test.go b/src/pkg/os/os_test.go
index 1940f562de..ecae0f2029 100644
--- a/src/pkg/os/os_test.go
+++ b/src/pkg/os/os_test.go
@@ -1095,3 +1095,15 @@ func TestLargeWriteToConsole(t *testing.T) {
t.Errorf("Write to os.Stderr should return %d; got %d", len(b), n)
}
}
+
+func TestStatDirModeExec(t *testing.T) {
+ const mode = 0111
+ const path = "."
+ dir, err := Stat(path)
+ if err != nil {
+ t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
+ }
+ if dir.Mode()&mode != mode {
+ t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode(), mode)
+ }
+}
diff --git a/src/pkg/os/stat_windows.go b/src/pkg/os/stat_windows.go
index 4fc6f457e3..c0441a42ae 100644
--- a/src/pkg/os/stat_windows.go
+++ b/src/pkg/os/stat_windows.go
@@ -190,7 +190,7 @@ func mkModTime(mtime syscall.Filetime) time.Time {
func mkMode(fa uint32) (m FileMode) {
if fa&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
- m |= ModeDir
+ m |= ModeDir | 0111
}
if fa&syscall.FILE_ATTRIBUTE_READONLY != 0 {
m |= 0444
コアとなるコードの解説
src/pkg/os/os_test.go
の変更
TestStatDirModeExec
という新しいテスト関数が追加されました。- このテストは、現在のディレクトリ(
.
)のos.FileMode
を取得し、そのモードに0111
(実行権限ビット)が設定されていることを検証します。 dir.Mode()&mode != mode
という条件で、取得したモードと期待するモード(0111
)のビットAND演算を行い、期待するビットが全てセットされているかを確認しています。これにより、Windows上でのディレクトリの実行権限の報告が正しく行われることを保証します。
src/pkg/os/stat_windows.go
の変更
mkMode
関数内の、Windowsのファイル属性からos.FileMode
を生成する部分が修正されました。- 以前は、ファイル属性がディレクトリ(
syscall.FILE_ATTRIBUTE_DIRECTORY
)である場合、m |= ModeDir
としてModeDir
ビットのみを設定していました。 - 変更後は、
m |= ModeDir | 0111
とすることで、ModeDir
ビットに加えて、八進数0111
(所有者、グループ、その他の実行権限)も強制的に設定されるようになりました。 - この修正により、Windows上でディレクトリの
os.FileMode
を取得した際に、Unix系システムとの互換性を持たせるために、ディレクトリが「実行可能」(走査可能)であるという情報が正しく含まれるようになります。
関連リンク
- Go Change-ID: https://golang.org/cl/6858079
- GitHubコミットページ: https://github.com/golang/go/commit/5b6502356391a59441dee6056f92832295e66f65
参考にした情報源リンク
- Go言語の公式ドキュメント(
os
パッケージ、os.FileMode
など) - Unix系ファイルパーミッションに関する一般的な情報
- Windowsファイル属性に関する一般的な情報
- Go言語のIssueトラッカー(Issue #4444に関する詳細情報があれば、より深く掘り下げることができた可能性がありますが、今回の検索では直接的な情報は見つかりませんでした。)
- Go言語のGerritコードレビューシステム(Change-IDからアクセス可能)