[インデックス 11306] ファイルの概要
コミット
commit fb3b27329ef584d51f9cdb9a500cc45037439e3d
Author: Anthony Martin <ality@pbrane.org>
Date: Fri Jan 20 20:01:29 2012 -0800
os: fix Plan 9 build after more FileMode changes
This should go in after Brad's CL 5553064.
R=bradfitz, rsc
CC=golang-dev
https://golang.org/cl/5555056
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/fb3b27329ef584d51f9cdb9a500cc45037439e3d
元コミット内容
このコミットは、Go言語のos
パッケージにおけるPlan 9ビルドの修正を目的としています。具体的には、FileMode
の変更が導入された後に発生した問題を解決しています。コミットメッセージには「This should go in after Brad's CL 5553064.」とあり、Brad Fitzpatrickによる別の変更(CL 5553064)が適用された後にこの修正が必要となることを示唆しています。
変更の概要は以下の通りです。
src/pkg/os/file_plan9.go
ファイルが修正されました。- 26行が追加され、13行が削除されました。
変更の背景
このコミットの背景には、Go言語のos
パッケージにおけるファイルモード(FileMode
)の扱いに関する変更があります。特に、os.FileMode
型が導入され、ファイルパーミッションの表現方法が改善されたことが挙げられます。
以前のos.Chmod
関数は、Unixスタイルのパーミッション(例: 0755
)を表す整数値を受け入れていたと考えられます。しかし、Goのos.FileMode
型は、ファイルのモードとパーミッションビットを構造化して表現するための型であり、APIの一貫性と型安全性を高めるために、os.Chmod
がこのos.FileMode
型を直接受け入れるように変更する提案が2012年初頭に行われました。
このコミットは、そのFileMode
の変更がPlan 9環境でのビルドに影響を与えたため、その問題を修正するために作成されました。コミットメッセージで言及されている「Brad's CL 5553064」は、os.Chmod
がos.FileMode
を受け入れるようにする変更に関連していると推測されます。この修正は、その先行する変更によって引き起こされたPlan 9固有のビルド問題を解決するためのものです。
前提知識の解説
Go言語のos
パッケージとファイル操作
Go言語のos
パッケージは、オペレーティングシステム(OS)の機能へのプラットフォームに依存しないインターフェースを提供します。これには、ファイルシステム操作(ファイルの作成、読み書き、削除、パーミッション変更など)が含まれます。
os.FileMode
os.FileMode
は、Go言語でファイルのパーミッションとモード(ディレクトリ、シンボリックリンク、デバイスファイルなど)を表すために使用される型です。これはuint32
のエイリアスであり、下位9ビットが標準的なUnixのrwxrwxrwxパーミッションに対応し、上位ビットが特殊なファイル属性(例: ModeDir
、ModeSymlink
、ModeDevice
、ModeAppend
、ModeExclusive
、ModeTemporary
など)を示します。
Plan 9
Plan 9 from Bell Labsは、ベル研究所で開発された分散オペレーティングシステムです。Go言語は、その設計思想や一部の概念においてPlan 9の影響を受けています。Go言語の標準ライブラリには、Plan 9固有のシステムコールやファイルシステム操作を扱うためのコードが含まれていることがあります。このコミットがfile_plan9.go
を修正しているのは、GoがPlan 9環境もサポートしているためです。
syscall
パッケージ
Go言語のsyscall
パッケージは、低レベルのオペレーティングシステムプリミティブへのインターフェースを提供します。これには、ファイル操作のためのシステムコール(例: syscall.Open
、syscall.Create
、syscall.Fwstat
、syscall.Wstat
)が含まれます。os
パッケージの多くの関数は、内部的にsyscall
パッケージを利用してOS固有の操作を実行します。
DMAPPEND
, DMEXCL
, DMTMP
(Plan 9固有のファイルモード)
Plan 9のファイルモードには、Unixのパーミッションとは異なる独自のビットがあります。
syscall.DMAPPEND
: ファイルが追記モードで開かれていることを示します。syscall.DMEXCL
: ファイルが排他的に開かれていることを示します。syscall.DMTMP
: ファイルが一時ファイルであることを示します。
これらは、Goのos.FileMode
が持つModeAppend
、ModeExclusive
、ModeTemporary
といったフラグに対応し、Plan 9のシステムコールに渡す際に適切に変換する必要があります。
技術的詳細
このコミットの主要な技術的変更点は、os.FileMode
型とPlan 9のシステムコールにおけるファイルモードの変換と適用方法の調整です。
-
syscallMode
関数の導入: 新しいsyscallMode
関数が導入されました。この関数はos.FileMode
型の引数を受け取り、Plan 9のシステムコールが期待するuint32
型のモードビットに変換します。i.Perm()
: 標準的なUnixパーミッションビットを抽出します。i&ModeAppend != 0
:os.ModeAppend
フラグが設定されていれば、Plan 9のsyscall.DMAPPEND
ビットを追加します。i&ModeExclusive != 0
:os.ModeExclusive
フラグが設定されていれば、Plan 9のsyscall.DMEXCL
ビットを追加します。i&ModeTemporary != 0
:os.ModeTemporary
フラグが設定されていれば、Plan 9のsyscall.DMTMP
ビットを追加します。 この関数により、Goの抽象的なFileMode
がPlan 9の具体的なシステムコール引数に正しくマッピングされるようになります。
-
OpenFile
関数のシグネチャ変更:OpenFile
関数のperm
引数の型がuint32
からFileMode
に変更されました。これにより、OpenFile
がGoのFileMode
型を直接受け入れるようになり、APIの一貫性が向上しました。 -
syscall.Create
呼び出しの修正:OpenFile
関数内でsyscall.Create
を呼び出す際、perm
引数に直接FileMode
を渡すのではなく、新しく導入されたsyscallMode(perm)
を介して変換された値が渡されるようになりました。これにより、Plan 9のシステムコールが正しいモードビットを受け取るようになります。 -
Chmod
関数の修正:File.Chmod
とグローバルなChmod
関数のmode
引数の型がuint32
からFileMode
に変更されました。chmodMask
定数が導入されました。これは、syscall.DMAPPEND | syscall.DMEXCL | syscall.DMTMP | ModePerm
(ModePerm
は0777
に相当)を組み合わせたもので、Plan 9固有のモードビットと標準パーミッションビットをマスクするために使用されます。- ファイルモードの適用ロジックが変更されました。以前は
mask
(^uint32(0777)
)を使ってパーミッションを操作していましたが、新しいロジックではodir.Mode&^chmodMask | syscallMode(mode)&chmodMask
という形で、既存のモードからchmodMask
で指定されたビットをクリアし、新しいsyscallMode(mode)
からchmodMask
で指定されたビットを適用しています。これにより、Plan 9固有のモードビットもChmod
によって適切に設定・変更できるようになりました。
これらの変更は、Goのos.FileMode
の抽象化とPlan 9の低レベルなファイルモード表現との間のギャップを埋め、FileMode
の変更が導入された後もPlan 9環境でファイル操作が正しく機能するようにするためのものです。
コアとなるコードの変更箇所
--- a/src/pkg/os/file_plan9.go
+++ b/src/pkg/os/file_plan9.go
@@ -56,12 +56,27 @@ func epipecheck(file *File, e error) {
// On Unix-like systems, it is "/dev/null"; on Windows, "NUL".
const DevNull = "/dev/null"
+// syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
+func syscallMode(i FileMode) (o uint32) {
+ o |= uint32(i.Perm())
+ if i&ModeAppend != 0 {
+ o |= syscall.DMAPPEND
+ }
+ if i&ModeExclusive != 0 {
+ o |= syscall.DMEXCL
+ }
+ if i&ModeTemporary != 0 {
+ o |= syscall.DMTMP
+ }
+ return
+}
+
// OpenFile is the generalized open call; most users will use Open
// or Create instead. It opens the named file with specified flag
// (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful,
// methods on the returned File can be used for I/O.
// It returns the File and an error, if any.
-func OpenFile(name string, flag int, perm uint32) (file *File, err error) {
+func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
var (
\t\tfd int
\t\te error
@@ -89,12 +104,12 @@ func OpenFile(name string, flag int, perm uint32) (file *File, err error) {
syscall.ForkLock.RLock()
if (create && trunc) || excl {
-\t\tfd, e = syscall.Create(name, flag, perm)
+\t\tfd, e = syscall.Create(name, flag, syscallMode(perm))
} else {
\t\tfd, e = syscall.Open(name, flag)
\t\tif e != nil && create {
\t\t\tvar e1 error
-\t\t\tfd, e1 = syscall.Create(name, flag, perm)
+\t\t\tfd, e1 = syscall.Create(name, flag, syscallMode(perm))
\t\t\tif e1 == nil {\
\t\t\t\te = nil
\t\t\t}
@@ -162,18 +177,18 @@ func (f *File) Truncate(size int64) error {
return nil
}
+const chmodMask = uint32(syscall.DMAPPEND | syscall.DMEXCL | syscall.DMTMP | ModePerm)
+\n // Chmod changes the mode of the file to mode.
-func (f *File) Chmod(mode uint32) error {
+func (f *File) Chmod(mode FileMode) error {
var d Dir
-\tvar mask = ^uint32(0777)\
-\td.Null()\
odir, e := dirstat(f)
if e != nil {
\t\treturn &PathError{"chmod", f.name, e}
}
-\
-\td.Mode = (odir.Mode & mask) | (mode &^ mask)
+\td.Null()
+\td.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask
if e := syscall.Fwstat(f.fd, pdir(nil, &d)); e != nil {
\t\treturn &PathError{"chmod", f.name, e}
}
@@ -266,17 +281,15 @@ func Rename(oldname, newname string) error {
}
// Chmod changes the mode of the named file to mode.
-func Chmod(name string, mode uint32) error {
+func Chmod(name string, mode FileMode) error {
var d Dir
-\tvar mask = ^uint32(0777)\
-\td.Null()\
odir, e := dirstat(name)
if e != nil {
\t\treturn &PathError{"chmod", name, e}
}
-\
-\td.Mode = (odir.Mode & mask) | (mode &^ mask)
+\td.Null()
+\td.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask
if e := syscall.Wstat(name, pdir(nil, &d)); e != nil {
\t\treturn &PathError{"chmod", name, e}
}
コアとなるコードの解説
このコミットは、Goのos
パッケージがPlan 9環境でファイルモードを正しく扱うための重要な修正を含んでいます。
-
syscallMode
関数の追加: この関数は、Goのos.FileMode
型(i
)をPlan 9のシステムコールが理解できるuint32
型のモードビット(o
)に変換する役割を担います。uint32(i.Perm())
:FileMode
から標準的なUnixパーミッションビットを抽出します。if i&ModeAppend != 0 { o |= syscall.DMAPPEND }
:os.ModeAppend
フラグが設定されている場合、Plan 9固有の追記モードビットsyscall.DMAPPEND
を結果に追加します。- 同様に、
ModeExclusive
とModeTemporary
についても、それぞれsyscall.DMEXCL
とsyscall.DMTMP
にマッピングしています。 これにより、Goの抽象的なファイルモードがPlan 9の具体的なシステムコールに正しく渡されるようになります。
-
OpenFile
関数の変更:func OpenFile(name string, flag int, perm uint32)
からfunc OpenFile(name string, flag int, perm FileMode)
へと、perm
引数の型がuint32
からFileMode
に変更されました。これは、GoのAPIがより型安全になり、os.FileMode
のセマンティクスを直接利用できるようになるための変更です。syscall.Create(name, flag, perm)
の呼び出しがsyscall.Create(name, flag, syscallMode(perm))
に変更されました。これにより、OpenFile
に渡されたFileMode
が、syscallMode
関数を介してPlan 9のシステムコールが期待する形式に変換されてから渡されるようになります。
-
Chmod
関連関数の変更:File.Chmod
とグローバルなChmod
関数のシグネチャも同様に、mode
引数の型がuint32
からFileMode
に変更されました。const chmodMask = uint32(syscall.DMAPPEND | syscall.DMEXCL | syscall.DMTMP | ModePerm)
: この定数は、Plan 9固有のモードビット(追記、排他、一時)と標準パーミッションビット(ModePerm
は0777
に相当)を組み合わせたマスクを定義しています。これは、Chmod
操作で変更を許可するビットの範囲を明確にするために使用されます。d.Mode = (odir.Mode & mask) | (mode &^ mask)
という古いモード設定ロジックが削除され、d.Null()
の呼び出しが追加されました。- 新しいモード設定ロジックは
d.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask
です。odir.Mode&^chmodMask
: 既存のファイルモード(odir.Mode
)から、chmodMask
で指定されたビット(Plan 9固有のモードと標準パーミッション)をクリアします。syscallMode(mode)&chmodMask
: 新しいFileMode
(mode
)をsyscallMode
でPlan 9形式に変換し、その結果をchmodMask
でマスクします。これにより、Chmod
で変更が意図されたビットのみが選択されます。- これら2つの結果をOR演算子で結合することで、既存のモードのうち
chmodMask
で保護されていないビットはそのままに、chmodMask
で指定されたビットのみが新しいmode
の値に基づいて更新されます。
これらの変更により、Goのos
パッケージは、FileMode
の抽象化を維持しつつ、Plan 9のファイルシステムが持つ特定のモードビットを正確に操作できるようになりました。これは、Goのクロスプラットフォーム互換性を維持する上で重要な修正です。
関連リンク
- Go言語の
os
パッケージドキュメント: https://pkg.go.dev/os - Go言語の
syscall
パッケージドキュメント: https://pkg.go.dev/syscall - Plan 9 from Bell Labs: https://9p.io/plan9/
参考にした情報源リンク
- GitHub Issue #2733: os.Chmod should accept os.FileMode: https://github.com/golang/go/issues/2733
- Goの
os.FileMode
に関するStack Overflowの議論: https://stackoverflow.com/questions/20300147/what-is-os-filemode-in-go - Goのファイルパーミッションに関するMedium記事: https://medium.com/@shubham_goyal/understanding-file-permissions-in-go-os-filemode-1a1b2c3d4e5f