Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 11282] ファイルの概要

このコミットは、Go言語のosパッケージおよび関連するユーティリティにおいて、ファイルパーミッションを表す型をuint32からos.FileModeへ変更するものです。これにより、ファイルモードの表現がより型安全になり、可読性と移植性が向上します。

コミット

commit 6454a3eb150218e13e71cecd48638e673dc6c304
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date:   Thu Jan 19 15:45:18 2012 -0800

    os: use FileMode instead of uint32 in various functions
    
    Fixes #2733
    
    R=chickencha, ality, rsc
    CC=golang-dev
    https://golang.org/cl/5553064

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/6454a3eb150218e13e71cecd48638e673dc6c304

元コミット内容

os: use FileMode instead of uint32 in various functions

Fixes #2733

R=chickencha, ality, rsc
CC=golang-dev
https://golang.org/cl/5553064

変更の背景

この変更の背景には、Go言語のファイル操作における型安全性の向上と、より表現豊かなAPIの提供という目的があります。従来のuint32型は、ファイルパーミッションだけでなく、様々なビットフラグを表現するために汎用的に使用される整数型です。しかし、ファイルパーミッションのような特定の意味を持つ値に対してuint32を使用すると、以下のような問題が生じる可能性があります。

  1. 型安全性の欠如: uint32は単なる数値であるため、誤った値(例えば、ファイルパーミッションとして意味をなさない値)が渡されてもコンパイル時に検出できません。os.FileModeのような専用の型を導入することで、Goの型システムがこれらのエラーを早期に捕捉できるようになります。
  2. 可読性の低下: コードを読む際に、uint32がファイルパーミッションを表しているのか、それとも別の目的の数値なのかを判断するために、追加のコンテキストが必要になります。os.FileModeを使用することで、その変数がファイルパーミッションに関連するものであることが一目で明確になります。
  3. 移植性の問題: ファイルパーミッションは、Unix系システムとWindows系システムでその表現方法や意味合いが異なる場合があります。os.FileModeは、Go言語が提供する抽象化レイヤーであり、異なるOS間でのファイルパーミッションの取り扱いを統一し、開発者がプラットフォームの違いを意識することなくコードを書けるようにします。uint32を直接使用すると、OS固有のパーミッションビットを直接操作することになり、移植性の問題を引き起こす可能性があります。
  4. 拡張性: os.FileModeは単なる数値ではなく、メソッドを持つ型として定義されています。これにより、将来的にファイルモードに関連する追加の機能や操作を、この型に直接関連付けることが容易になります。例えば、Perm()メソッドのように、パーミッションビットのみを抽出する機能などが提供されます。

これらの理由から、ファイルパーミッションを扱うGoの標準ライブラリ関数において、より適切で堅牢なos.FileMode型への移行が進められました。

前提知識の解説

このコミットを理解するためには、以下の概念について理解しておく必要があります。

1. ファイルパーミッション (File Permissions)

Unix系OSにおいて、ファイルやディレクトリにはアクセス権限が設定されています。これは、誰がそのファイルに対して読み取り(read)、書き込み(write)、実行(execute)の操作を行えるかを定義します。パーミッションは通常、3桁または4桁の8進数で表現されます。

  • 所有者 (Owner): ファイルを作成したユーザーの権限。
  • グループ (Group): ファイルの所有グループに属するユーザーの権限。
  • その他 (Others): 上記以外のすべてのユーザーの権限。

各権限は以下の数値に対応します。

  • 読み取り (r): 4
  • 書き込み (w): 2
  • 実行 (x): 1

例えば、0644というパーミッションは以下を意味します。

  • 所有者: 6 (4+2 = 読み取り+書き込み)
  • グループ: 4 (読み取りのみ)
  • その他: 4 (読み取りのみ)

先頭の0は8進数であることを示します。4桁の場合、先頭の桁は特殊なパーミッション(SetUID, SetGID, Sticky Bit)を表します。

2. uint32

uint32はGo言語の組み込み型で、32ビットの符号なし整数を表します。0から4,294,967,295までの値を格納できます。汎用的な数値計算やビットフラグの操作によく使用されます。

3. os.FileMode

Go言語のosパッケージで定義されている型で、ファイルやディレクトリのモードビット(パーミッションや種類)を表します。これはuint32のエイリアスとして定義されていますが、Goの型システムによってuint32とは異なる型として扱われます。これにより、ファイルモードとして意味のある値のみが渡されることを期待できるようになります。

os.FileModeは、ファイルパーミッション(rwxビット)だけでなく、ファイルの種類(ディレクトリ、シンボリックリンクなど)や特殊なパーミッション(SetUID, SetGID, Sticky Bit)も表現できます。

  • os.ModeDir: ディレクトリ
  • os.ModeAppend: 追記専用ファイル
  • os.ModeExclusive: 排他ロックファイル
  • os.ModeTemporary: 一時ファイル
  • os.ModeSymlink: シンボリックリンク
  • os.ModeDevice: デバイスファイル
  • os.ModeNamedPipe: 名前付きパイプ (FIFO)
  • os.ModeSocket: Unixドメインソケット
  • os.ModeSetuid: SetUIDビット
  • os.ModeSetgid: SetGIDビット
  • os.ModeSticky: スティッキービット

これらのモードはビットマスクとして定義されており、os.FileModeの値はこれらのビットの組み合わせで構成されます。

4. システムコール (System Calls)

システムコールは、オペレーティングシステムが提供するサービスをプログラムが利用するためのインターフェースです。ファイルを作成したり、パーミッションを変更したりする操作は、直接ハードウェアを操作するのではなく、OSのカーネルが提供するシステムコールを介して行われます。

例えば、Unix系OSでは、ファイルのパーミッションを変更するためにchmodシステムコールが使用されます。このシステムコールは、パーミッションを数値(通常はuint32のような整数型)で受け取ります。Go言語のsyscallパッケージは、これらの低レベルなシステムコールをGoプログラムから呼び出すための機能を提供します。

技術的詳細

このコミットの核心は、Go言語のosパッケージが提供するファイルモードの抽象化と、基盤となるシステムコールとの間の変換メカニズムにあります。

os.FileModeの役割

os.FileModeは、Go言語がファイルパーミッションやファイルの種類を表現するために導入した型です。これは単なるuint32のエイリアスですが、Goの型システムはこれを独立した型として扱います。これにより、開発者はファイルモードを扱う際に、より意味のある型を使用できるようになります。

os.FileModeは、ファイルパーミッション(rwxビット)だけでなく、os.ModeDir(ディレクトリ)、os.ModeSymlink(シンボリックリンク)、os.ModeSetuid(SetUIDビット)などの特殊なモードビットも保持できます。これらのモードビットは、os.FileMode型の値に対してビット演算を行うことで、設定したり、確認したりすることができます。

例えば、os.FileMode(0644)は、所有者に読み書き、グループとその他に読み取り権限を与えるファイルモードを表します。

syscallMode関数の導入

Goのosパッケージは、クロスプラットフォームなファイル操作APIを提供しますが、その内部では各OS固有のシステムコールを呼び出しています。Unix系OSのchmodmkdirなどのシステムコールは、パーミッションをuint32のような整数型で受け取ります。

このコミットで導入されたsyscallMode関数(src/pkg/os/file_posix.goに追加)は、os.FileMode型の値を、基盤となるシステムコールが期待するuint32型のパーミッションビットに変換する役割を担っています。

// syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
func syscallMode(i FileMode) (o uint32) {
	o |= uint32(i.Perm()) // Goのパーミッションビットをuint32に変換
	if i&ModeSetuid != 0 {
		o |= syscall.S_ISUID // SetUIDビットをシステムコール用のフラグに変換
	}
	if i&ModeSetgid != 0 {
		o |= syscall.S_ISGID // SetGIDビットをシステムコール用のフラグに変換
	}
	if i&ModeSticky != 0 {
		o |= syscall.S_ISVTX // スティッキービットをシステムコール用のフラグに変換
	}
	// No mapping for Go's ModeTemporary (plan9 only).
	return
}

この関数は、以下の変換を行います。

  1. i.Perm(): os.FileModePerm()メソッドは、ファイルパーミッションのrwxビットのみを抽出して返します。これをuint32にキャストします。
  2. ModeSetuid, ModeSetgid, ModeSticky: os.FileModeがこれらの特殊なモードビットを含んでいる場合、それぞれ対応するsyscallパッケージの定数(syscall.S_ISUID, syscall.S_ISGID, syscall.S_ISVTX)を結果のuint32にOR演算で追加します。これらの定数は、Unix系システムコールが特殊なパーミッションを表現するために使用するビットフラグです。

このsyscallMode関数を介することで、Goのコードはos.FileModeという高レベルな抽象化された型を使用しつつ、内部的にはOS固有のシステムコールと正しく連携できるようになります。これにより、Goのファイル操作APIの移植性と堅牢性が向上します。

影響範囲

この変更は、osパッケージだけでなく、osパッケージのファイルモード関連の関数を呼び出している他の標準ライブラリパッケージ(io/ioutilcmd/gocmd/hgpatchなど)にも波及しています。これらのパッケージの関数シグネチャも、uint32からos.FileModeに変更されています。

コアとなるコードの変更箇所

このコミットでは、主に以下のファイルでuint32からos.FileModeへの型変更が行われています。

  • src/cmd/go/build.go: builder.copyFile関数とbuilder.install関数で、ファイルパーミッションの型がuint32からos.FileModeに変更されました。
  • src/cmd/hgpatch/main.go: os.Chmodの呼び出しとmkdirAll関数のパーミッション引数がuint32からos.FileModeに変更されました。
  • src/pkg/io/ioutil/ioutil.go: WriteFile関数のパーミッション引数がuint32からos.FileModeに変更されました。
  • src/pkg/os/file.go: Mkdir関数とFile.Chmod関数のパーミッション引数がuint32からos.FileModeに変更されました。また、Mkdir関数内でsyscallModeが使用されています。
  • src/pkg/os/file_posix.go:
    • syscallMode関数が新しく追加されました。
    • Chmod関数とFile.Chmod関数で、パーミッション引数がuint32からos.FileModeに変更され、syscallMode関数が使用されるようになりました。
  • src/pkg/os/file_unix.go: OpenFile関数のパーミッション引数がuint32からos.FileModeに変更され、syscallMode関数が使用されるようになりました。
  • src/pkg/os/file_windows.go: openFile関数とOpenFile関数のパーミッション引数がuint32からos.FileModeに変更され、syscallMode関数が使用されるようになりました。
  • src/pkg/os/path.go: MkdirAll関数のパーミッション引数がuint32からos.FileModeに変更されました。

例: src/pkg/os/file_posix.goの変更

--- a/src/pkg/os/file_posix.go
+++ b/src/pkg/os/file_posix.go
@@ -81,18 +81,34 @@ func Rename(oldname, newname string) error {
 	return nil
 }
 
+// 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&ModeSetuid != 0 {
+		o |= syscall.S_ISUID
+	}
+	if i&ModeSetgid != 0 {
+		o |= syscall.S_ISGID
+	}
+	if i&ModeSticky != 0 {
+		o |= syscall.S_ISVTX
+	}
+	// No mapping for Go's ModeTemporary (plan9 only).
+	return
+}
+
 // Chmod changes the mode of the named file to mode.
 // If the file is a symbolic link, it changes the mode of the link's target.
-func Chmod(name string, mode uint32) error {
-	if e := syscall.Chmod(name, mode); e != nil {
+func Chmod(name string, mode FileMode) error {
+	if e := syscall.Chmod(name, syscallMode(mode)); e != nil {
 		return &PathError{"chmod", name, e}
 	}
 	return nil
 }
 
 // Chmod changes the mode of the file to mode.
-func (f *File) Chmod(mode uint32) error {
-	if e := syscall.Fchmod(f.fd, mode); e != nil {
+func (f *File) Chmod(mode FileMode) error {
+	if e := syscall.Fchmod(f.fd, syscallMode(mode)); e != nil {
 		return &PathError{"chmod", f.name, e}
 	}
 	return nil

コアとなるコードの解説

このコミットの最も重要な変更は、src/pkg/os/file_posix.gosyscallMode関数が追加され、osパッケージ内のファイル操作関数がこの新しいヘルパー関数を使用してos.FileModeをシステムコールが期待するuint32に変換するようになった点です。

以前は、os.Mkdiros.Chmodのような関数は、直接uint32型のパーミッション引数を受け取り、それをsyscallパッケージの対応する関数に渡していました。このアプローチは、Goの型システムがファイルパーミッションのセマンティクスを強制しないため、誤った値が渡されるリスクがありました。

新しいアプローチでは、これらの関数はos.FileMode型の引数を受け取るようになります。そして、内部でsyscallMode関数を呼び出して、os.FileModeの値をuint32に変換してからsyscall関数に渡します。

例えば、os.Chmod関数の変更を見てみましょう。

変更前:

func Chmod(name string, mode uint32) error {
	if e := syscall.Chmod(name, mode); e != nil {
		return &PathError{"chmod", name, e}
	}
	return nil
}

変更後:

func Chmod(name string, mode FileMode) error {
	if e := syscall.Chmod(name, syscallMode(mode)); e != nil {
		return &PathError{"chmod", name, e}
	}
	return nil
}

この変更により、os.Chmodを呼び出す側はos.FileMode型の値を渡すことが期待されるため、コードの意図がより明確になります。また、os.FileModeが持つPerm()メソッドや、ModeSetuidなどのビットフラグを直接利用できるため、より表現力豊かなコードを書くことができます。

syscallMode関数は、Goのポータブルなファイルモード表現(os.FileMode)と、Unix系OSのシステムコールが要求する低レベルなパーミッションビット(uint32)との間の橋渡しをします。これにより、Goのosパッケージは、異なるOS環境下でも一貫したファイル操作APIを提供しつつ、内部的には各OSのネイティブなシステムコールを効率的に利用できるようになります。これは、Go言語のクロスプラットフォーム設計における重要な側面の一つです。

関連リンク

参考にした情報源リンク

[インデックス 11282] ファイルの概要

このコミットは、Go言語のosパッケージおよび関連するユーティリティにおいて、ファイルパーミッションを表す型をuint32からos.FileModeへ変更するものです。これにより、ファイルモードの表現がより型安全になり、可読性と移植性が向上します。

コミット

commit 6454a3eb150218e13e71cecd48638e673dc6c304
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date:   Thu Jan 19 15:45:18 2012 -0800

    os: use FileMode instead of uint32 in various functions
    
    Fixes #2733
    
    R=chickencha, ality, rsc
    CC=golang-dev
    https://golang.org/cl/5553064

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/6454a3eb150218e13e71cecd48638e673dc6c304

元コミット内容

os: use FileMode instead of uint32 in various functions

Fixes #2733

R=chickencha, ality, rsc
CC=golang-dev
https://golang.org/cl/5553064

変更の背景

この変更の背景には、Go言語のファイル操作における型安全性の向上と、より表現豊かなAPIの提供という目的があります。従来のuint32型は、ファイルパーミッションだけでなく、様々なビットフラグを表現するために汎用的に使用される整数型です。しかし、ファイルパーミッションのような特定の意味を持つ値に対してuint32を使用すると、以下のような問題が生じる可能性があります。

  1. 型安全性の欠如: uint32は単なる数値であるため、誤った値(例えば、ファイルパーミッションとして意味をなさない値)が渡されてもコンパイル時に検出できません。os.FileModeのような専用の型を導入することで、Goの型システムがこれらのエラーを早期に捕捉できるようになります。
  2. 可読性の低下: コードを読む際に、uint32がファイルパーミッションを表しているのか、それとも別の目的の数値なのかを判断するために、追加のコンテキストが必要になります。os.FileModeを使用することで、その変数がファイルパーミッションに関連するものであることが一目で明確になります。
  3. 移植性の問題: ファイルパーミッションは、Unix系システムとWindows系システムでその表現方法や意味合いが異なる場合があります。os.FileModeは、Go言語が提供する抽象化レイヤーであり、異なるOS間でのファイルパーミッションの取り扱いを統一し、開発者がプラットフォームの違いを意識することなくコードを書けるようにします。uint32を直接使用すると、OS固有のパーミッションビットを直接操作することになり、移植性の問題を引き起こす可能性があります。
  4. 拡張性: os.FileModeは単なる数値ではなく、メソッドを持つ型として定義されています。これにより、将来的にファイルモードに関連する追加の機能や操作を、この型に直接関連付けることが容易になります。例えば、Perm()メソッドのように、パーミッションビットのみを抽出する機能などが提供されます。

これらの理由から、ファイルパーミッションを扱うGoの標準ライブラリ関数において、より適切で堅牢なos.FileMode型への移行が進められました。

前提知識の解説

このコミットを理解するためには、以下の概念について理解しておく必要があります。

1. ファイルパーミッション (File Permissions)

Unix系OSにおいて、ファイルやディレクトリにはアクセス権限が設定されています。これは、誰がそのファイルに対して読み取り(read)、書き込み(write)、実行(execute)の操作を行えるかを定義します。パーミッションは通常、3桁または4桁の8進数で表現されます。

  • 所有者 (Owner): ファイルを作成したユーザーの権限。
  • グループ (Group): ファイルの所有グループに属するユーザーの権限。
  • その他 (Others): 上記以外のすべてのユーザーの権限。

各権限は以下の数値に対応します。

  • 読み取り (r): 4
  • 書き込み (w): 2
  • 実行 (x): 1

例えば、0644というパーミッションは以下を意味します。

  • 所有者: 6 (4+2 = 読み取り+書き込み)
  • グループ: 4 (読み取りのみ)
  • その他: 4 (読み取りのみ)

先頭の0は8進数であることを示します。4桁の場合、先頭の桁は特殊なパーミッション(SetUID, SetGID, Sticky Bit)を表します。

2. uint32

uint32はGo言語の組み込み型で、32ビットの符号なし整数を表します。0から4,294,967,295までの値を格納できます。汎用的な数値計算やビットフラグの操作によく使用されます。

3. os.FileMode

Go言語のosパッケージで定義されている型で、ファイルやディレクトリのモードビット(パーミッションや種類)を表します。これはuint32のエイリアスとして定義されていますが、Goの型システムによってuint32とは異なる型として扱われます。これにより、ファイルモードとして意味のある値のみが渡されることを期待できるようになります。

os.FileModeは、ファイルパーミッション(rwxビット)だけでなく、ファイルの種類(ディレクトリ、シンボリックリンクなど)や特殊なパーミッション(SetUID, SetGID, Sticky Bit)も表現できます。

  • os.ModeDir: ディレクトリ
  • os.ModeAppend: 追記専用ファイル
  • os.ModeExclusive: 排他ロックファイル
  • os.ModeTemporary: 一時ファイル
  • os.ModeSymlink: シンボリックリンク
  • os.ModeDevice: デバイスファイル
  • os.ModeNamedPipe: 名前付きパイプ (FIFO)
  • os.ModeSocket: Unixドメインソケット
  • os.ModeSetuid: SetUIDビット
  • os.ModeSetgid: SetGIDビット
  • os.ModeSticky: スティッキービット

これらのモードはビットマスクとして定義されており、os.FileModeの値はこれらのビットの組み合わせで構成されます。

4. システムコール (System Calls)

システムコールは、オペレーティングシステムが提供するサービスをプログラムが利用するためのインターフェースです。ファイルを作成したり、パーミッションを変更したりする操作は、直接ハードウェアを操作するのではなく、OSのカーネルが提供するシステムコールを介して行われます。

例えば、Unix系OSでは、ファイルのパーミッションを変更するためにchmodシステムコールが使用されます。このシステムコールは、パーミッションを数値(通常はuint32のような整数型)で受け取ります。Go言語のsyscallパッケージは、これらの低レベルなシステムコールをGoプログラムから呼び出すための機能を提供します。

技術的詳細

このコミットの核心は、Go言語のosパッケージが提供するファイルモードの抽象化と、基盤となるシステムコールとの間の変換メカニズムにあります。

os.FileModeの役割

os.FileModeは、Go言語がファイルパーミッションやファイルの種類を表現するために導入した型です。これは単なるuint32のエイリアスですが、Goの型システムはこれを独立した型として扱います。これにより、開発者はファイルモードを扱う際に、より意味のある型を使用できるようになります。

os.FileModeは、ファイルパーミッション(rwxビット)だけでなく、os.ModeDir(ディレクトリ)、os.ModeSymlink(シンボリックリンク)、os.ModeSetuid(SetUIDビット)などの特殊なモードビットも保持できます。これらのモードビットは、os.FileMode型の値に対してビット演算を行うことで、設定したり、確認したりすることができます。

例えば、os.FileMode(0644)は、所有者に読み書き、グループとその他に読み取り権限を与えるファイルモードを表します。

syscallMode関数の導入

Goのosパッケージは、クロスプラットフォームなファイル操作APIを提供しますが、その内部では各OS固有のシステムコールを呼び出しています。Unix系OSのchmodmkdirなどのシステムコールは、パーミッションをuint32のような整数型で受け取ります。

このコミットで導入されたsyscallMode関数(src/pkg/os/file_posix.goに追加)は、os.FileMode型の値を、基盤となるシステムコールが期待するuint32型のパーミッションビットに変換する役割を担っています。

// syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
func syscallMode(i FileMode) (o uint32) {
	o |= uint32(i.Perm()) // Goのパーミッションビットをuint32に変換
	if i&ModeSetuid != 0 {
		o |= syscall.S_ISUID // SetUIDビットをシステムコール用のフラグに変換
	}
	if i&ModeSetgid != 0 {
		o |= syscall.S_ISGID // SetGIDビットをシステムコール用のフラグに変換
	}
	if i&ModeSticky != 0 {
		o |= syscall.S_ISVTX // スティッキービットをシステムコール用のフラグに変換
	}
	// No mapping for Go's ModeTemporary (plan9 only).
	return
}

この関数は、以下の変換を行います。

  1. i.Perm(): os.FileModePerm()メソッドは、ファイルパーミッションのrwxビットのみを抽出して返します。これをuint32にキャストします。
  2. ModeSetuid, ModeSetgid, ModeSticky: os.FileModeがこれらの特殊なモードビットを含んでいる場合、それぞれ対応するsyscallパッケージの定数(syscall.S_ISUID, syscall.S_ISGID, syscall.S_ISVTX)を結果のuint32にOR演算で追加します。これらの定数は、Unix系システムコールが特殊なパーミッションを表現するために使用するビットフラグです。

このsyscallMode関数を介することで、Goのコードはos.FileModeという高レベルな抽象化された型を使用しつつ、内部的にはOS固有のシステムコールと正しく連携できるようになります。これにより、Goのファイル操作APIの移植性と堅牢性が向上します。

影響範囲

この変更は、osパッケージだけでなく、osパッケージのファイルモード関連の関数を呼び出している他の標準ライブラリパッケージ(io/ioutilcmd/gocmd/hgpatchなど)にも波及しています。これらのパッケージの関数シグネチャも、uint32からos.FileModeに変更されています。

コアとなるコードの変更箇所

このコミットでは、主に以下のファイルでuint32からos.FileModeへの型変更が行われています。

  • src/cmd/go/build.go: builder.copyFile関数とbuilder.install関数で、ファイルパーミッションの型がuint32からos.FileModeに変更されました。
  • src/cmd/hgpatch/main.go: os.Chmodの呼び出しとmkdirAll関数のパーミッション引数がuint32からos.FileModeに変更されました。
  • src/pkg/io/ioutil/ioutil.go: WriteFile関数のパーミッション引数がuint32からos.FileModeに変更されました。
  • src/pkg/os/file.go: Mkdir関数とFile.Chmod関数のパーミッション引数がuint32からos.FileModeに変更されました。また、Mkdir関数内でsyscallModeが使用されています。
  • src/pkg/os/file_posix.go:
    • syscallMode関数が新しく追加されました。
    • Chmod関数とFile.Chmod関数で、パーミッション引数がuint32からos.FileModeに変更され、syscallMode関数が使用されるようになりました。
  • src/pkg/os/file_unix.go: OpenFile関数のパーミッション引数がuint32からos.FileModeに変更され、syscallMode関数が使用されるようになりました。
  • src/pkg/os/file_windows.go: openFile関数とOpenFile関数のパーミッション引数がuint32からos.FileModeに変更され、syscallMode関数が使用されるようになりました。
  • src/pkg/os/path.go: MkdirAll関数のパーミッション引数がuint32からos.FileModeに変更されました。

例: src/pkg/os/file_posix.goの変更

--- a/src/pkg/os/file_posix.go
+++ b/src/pkg/os/file_posix.go
@@ -81,18 +81,34 @@ func Rename(oldname, newname string) error {
 	return nil
 }
 
+// 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&ModeSetuid != 0 {
+		o |= syscall.S_ISUID
+	}
+	if i&ModeSetgid != 0 {
+		o |= syscall.S_ISGID
+	}
+	if i&ModeSticky != 0 {
+		o |= syscall.S_ISVTX
+	}
+	// No mapping for Go's ModeTemporary (plan9 only).
+	return
+}
+
 // Chmod changes the mode of the named file to mode.
 // If the file is a symbolic link, it changes the mode of the link's target.
-func Chmod(name string, mode uint32) error {
-	if e := syscall.Chmod(name, mode); e != nil {
+func Chmod(name string, mode FileMode) error {
+	if e := syscall.Chmod(name, syscallMode(mode)); e != nil {
 		return &PathError{"chmod", name, e}
 	}
 	return nil
 }
 
 // Chmod changes the mode of the file to mode.
-func (f *File) Chmod(mode uint32) error {
-	if e := syscall.Fchmod(f.fd, mode); e != nil {
+func (f *File) Chmod(mode FileMode) error {
+	if e := syscall.Fchmod(f.fd, syscallMode(mode)); e != nil {
 		return &PathError{"chmod", f.name, e}
 	}
 	return nil

コアとなるコードの解説

このコミットの最も重要な変更は、src/pkg/os/file_posix.gosyscallMode関数が追加され、osパッケージ内のファイル操作関数がこの新しいヘルパー関数を使用してos.FileModeをシステムコールが期待するuint32に変換するようになった点です。

以前は、os.Mkdiros.Chmodのような関数は、直接uint32型のパーミッション引数を受け取り、それをsyscallパッケージの対応する関数に渡していました。このアプローチは、Goの型システムがファイルパーミッションのセマンティクスを強制しないため、誤った値が渡されるリスクがありました。

新しいアプローチでは、これらの関数はos.FileMode型の引数を受け取るようになります。そして、内部でsyscallMode関数を呼び出して、os.FileModeの値をuint32に変換してからsyscall関数に渡します。

例えば、os.Chmod関数の変更を見てみましょう。

変更前:

func Chmod(name string, mode uint32) error {
	if e := syscall.Chmod(name, mode); e != nil {
		return &PathError{"chmod", name, e}
	}
	return nil
}

変更後:

func Chmod(name string, mode FileMode) error {
	if e := syscall.Chmod(name, syscallMode(mode)); e != nil {
		return &PathError{"chmod", name, e}
	}
	return nil
}

この変更により、os.Chmodを呼び出す側はos.FileMode型の値を渡すことが期待されるため、コードの意図がより明確になります。また、os.FileModeが持つPerm()メソッドや、ModeSetuidなどのビットフラグを直接利用できるため、より表現力豊かなコードを書くことができます。

syscallMode関数は、Goのポータブルなファイルモード表現(os.FileMode)と、Unix系OSのシステムコールが要求する低レベルなパーミッションビット(uint32)との間の橋渡しをします。これにより、Goのosパッケージは、異なるOS環境下でも一貫したファイル操作APIを提供しつつ、内部的には各OSのネイティブなシステムコールを効率的に利用できるようになります。これは、Go言語のクロスプラットフォーム設計における重要な側面の一つです。

関連リンク

参考にした情報源リンク