[インデックス 11377] ファイルの概要
このコミットは、Go言語のos
パッケージにおけるPlan 9オペレーティングシステム向けのファイル操作(特にタイムスタンプの変更)に関するバグを修正し、テストが再びパスするようにするためのものです。具体的には、os.Chtimes
関数の引数型をint64
(ナノ秒単位)からtime.Time
型に変更し、Plan 9のシステムコールが期待する形式(Unixエポック秒)に変換することで、ファイルアクセス時刻と更新時刻の設定が正しく行われるようにしています。また、テストのためにFileInfo
からアクセス時刻を取得するヘルパー関数atime
が追加されています。
コミット
commit c93ca600eca4cee6dae2495772ae910eb768cec3
Author: Fazlul Shahriar <fshahriar@gmail.com>
Date: Wed Jan 25 00:15:44 2012 -0800
os: pass tests on Plan 9 again
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5563046
---
src/pkg/os/file_plan9.go | 12 ++++++------
src/pkg/os/stat_plan9.go | 5 +++++
2 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/src/pkg/os/file_plan9.go b/src/pkg/os/file_plan9.go
index 6ee57ff239..7d136eb368 100644
--- a/src/pkg/os/file_plan9.go
+++ b/src/pkg/os/file_plan9.go
@@ -7,6 +7,7 @@ package os
import (
"runtime"
"syscall"
+ "time"
)
// File represents an open file descriptor.
@@ -299,15 +300,14 @@ func Chmod(name string, mode FileMode) error {
// Chtimes changes the access and modification times of the named
// file, similar to the Unix utime() or utimes() functions.
//
-// The argument times are in nanoseconds, although the underlying
-// filesystem may truncate or round the values to a more
-// coarse time unit.\n-func Chtimes(name string, atimeNs int64, mtimeNs int64) error {
+// The underlying filesystem may truncate or round the values to a
+// less precise time unit.\n+func Chtimes(name string, atime time.Time, mtime time.Time) error {
var d Dir
d.Null()
-\td.Atime = uint32(atimeNs / 1e9)\n-\td.Mtime = uint32(mtimeNs / 1e9)\n+\td.Atime = uint32(atime.Unix())\n+\td.Mtime = uint32(mtime.Unix())\n
\tif e := syscall.Wstat(name, pdir(nil, &d)); e != nil {
\t\treturn &PathError{\"chtimes\", name, e}\ndiff --git a/src/pkg/os/stat_plan9.go b/src/pkg/os/stat_plan9.go
index 8d3b8a84d5..f731e43740 100644
--- a/src/pkg/os/stat_plan9.go
+++ b/src/pkg/os/stat_plan9.go
@@ -97,3 +97,8 @@ func Stat(name string) (FileInfo, error) {
func Lstat(name string) (FileInfo, error) {
return Stat(name)
}
+\n+// For testing.\n+func atime(fi FileInfo) time.Time {
+\treturn time.Unix(int64(fi.(*FileStat).Sys.(*Dir).Atime), 0)\n+}\n
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c93ca600eca4cee6dae2495772ae910eb768cec3
元コミット内容
os: pass tests on Plan 9 again
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5563046
変更の背景
このコミットの主な目的は、「Plan 9上でのテストを再びパスさせる」ことです。これは、Go言語のos
パッケージがPlan 9オペレーティングシステム上で正しく動作していなかったことを示唆しています。特に、ファイルアクセス時刻と更新時刻を変更するos.Chtimes
関数が、Plan 9のシステムコールと期待される引数の形式が合致していなかったために問題が発生していたと考えられます。
Go言語は、その設計思想やツールチェインにおいて、UnixやPlan 9の影響を強く受けています。Goの主要な設計者であるRob PikeとKen Thompsonは、Plan 9の開発にも携わっていました。そのため、Goは様々なプラットフォームに対応していますが、特にPlan 9のようなニッチなOSに対しても互換性を維持しようとする努力が見られます。
このコミットが行われた2012年当時、Goはまだ比較的新しい言語であり、様々なプラットフォームでの安定性確保が重要なフェーズでした。特定のOS(この場合はPlan 9)でテストが失敗するということは、そのOS上でのGoアプリケーションの信頼性に直接影響するため、早急な修正が必要とされた背景があります。
前提知識の解説
Plan 9 from Bell Labs
Plan 9は、ベル研究所で開発された分散オペレーティングシステムです。Unixの「すべてはファイルである」という哲学をさらに推し進め、ネットワーク上のリソース(CPU、ストレージ、デバイスなど)もすべてファイルとして表現し、9Pプロトコルという独自のプロトコルを通じてアクセスすることを特徴としています。Plan 9は、その革新的な設計思想が後の多くのシステムに影響を与えましたが、Unixほど広く普及することはありませんでした。しかし、Go言語の設計にはPlan 9の思想が色濃く反映されており、Goのツールチェインや標準ライブラリの一部はPlan 9のそれから派生しています。
os
パッケージ
Go言語の標準ライブラリの一部であり、オペレーティングシステムとの基本的な相互作用を提供します。ファイル操作(作成、読み書き、削除)、ディレクトリ操作、プロセス管理、環境変数へのアクセスなど、OSレベルの機能を提供します。
os.Chmod
ファイルのパーミッション(アクセス権)を変更する関数です。Unix系のシステムにおけるchmod
コマンドに相当します。
os.Chtimes
ファイルのアクセス時刻(atime)と更新時刻(mtime)を変更する関数です。Unix系のシステムにおけるutime()
やutimes()
関数に相当します。このコミットの主要な変更点はこの関数にあります。
FileInfo
インターフェース
os
パッケージで定義されているインターフェースで、ファイルに関する情報(ファイル名、サイズ、パーミッション、更新時刻など)を提供します。os.Stat
やos.Lstat
関数がこのインターフェースを実装した値を返します。
Dir
構造体 (Plan 9固有)
Plan 9のシステムコールで使用されるファイル属性を表現する構造体です。ファイル名、所有者、グループ、パーミッション、アクセス時刻、更新時刻などが含まれます。syscall.Wstat
関数に渡されることで、ファイルのメタデータを変更するために使用されます。
syscall.Wstat
Plan 9のシステムコールの一つで、ファイルのメタデータ(属性)を変更するために使用されます。Dir
構造体を引数として受け取り、指定されたファイルの属性を更新します。
time.Time
型
Go言語の標準ライブラリtime
パッケージで定義されている、特定の時点を表す型です。日付、時刻、タイムゾーン情報を含みます。
time.Time.Unix()
メソッド
time.Time
型のメソッドで、その時刻をUnixエポック(1970年1月1日UTC)からの経過秒数(int64
型)として返します。この秒数は、多くのシステムコールやファイルシステムがタイムスタンプを扱う際に使用する一般的な形式です。
PathError
構造体
os
パッケージで定義されているエラー型の一つで、パスに関連する操作(ファイルが見つからない、パーミッションがないなど)でエラーが発生した場合に返されます。操作名、パス、元のエラー情報を含みます。
技術的詳細
このコミットの核心は、os.Chtimes
関数がPlan 9のシステムコールsyscall.Wstat
と連携する際のタイムスタンプの扱いにあります。
変更前、os.Chtimes
はatimeNs int64
とmtimeNs int64
という引数を受け取っていました。これは、アクセス時刻と更新時刻をナノ秒単位のint64
で表現していました。しかし、Plan 9のsyscall.Wstat
が期待するDir
構造体のAtime
とMtime
フィールドはuint32
型であり、これは通常、Unixエポックからの秒数を表します。
変更前は、atimeNs / 1e9
とすることでナノ秒を秒に変換していましたが、これはGoのtime.Time
型が提供する高精度な時刻表現と、Plan 9のシステムコールが期待する秒単位の表現との間のミスマッチを引き起こしていました。特に、time.Time
型はナノ秒精度を扱うことができますが、syscall.Wstat
は秒単位でしかタイムスタンプを扱えないため、ナノ秒単位のint64
を直接渡すのは適切ではありませんでした。
このコミットでは、os.Chtimes
の引数をatime time.Time
とmtime time.Time
に変更しました。これにより、Goの標準的な時刻型を使用するようになり、より自然で型安全なAPIになりました。そして、time.Time
型のUnix()
メソッドを使用して、time.Time
オブジェクトをUnixエポックからの秒数(int64
)に変換し、それをuint32
にキャストしてDir
構造体のAtime
とMtime
フィールドに設定しています。
// 変更前
d.Atime = uint32(atimeNs / 1e9)
d.Mtime = uint32(mtimeNs / 1e9)
// 変更後
d.Atime = uint32(atime.Unix())
d.Mtime = uint32(mtime.Unix())
この変更により、os.Chtimes
はGoのtime.Time
型で時刻を受け取り、それをPlan 9のシステムコールが理解できるUnixエポック秒に正確に変換して渡すことができるようになりました。これにより、Plan 9上でのファイルタイムスタンプの変更が正しく行われ、関連するテストがパスするようになったと考えられます。
また、src/pkg/os/stat_plan9.go
にatime
というヘルパー関数が追加されています。これは、FileInfo
インターフェースを実装したオブジェクトからアクセス時刻(atime)をtime.Time
型で取得するためのものです。これは主にテスト目的で追加されたものであり、FileInfo
からFileStat
、さらにそのSys
フィールド(Plan 9固有のDir
構造体)を型アサーションで取り出し、Atime
フィールド(Unixエポック秒)をtime.Unix
関数に渡してtime.Time
型に変換しています。
// For testing.
func atime(fi FileInfo) time.Time {
return time.Unix(int64(fi.(*FileStat).Sys.(*Dir).Atime), 0)
}
このヘルパー関数は、os.Chtimes
で設定した時刻が、os.Stat
などで取得したFileInfo
から正しく読み取れることを検証するために使用されます。
コアとなるコードの変更箇所
diff --git a/src/pkg/os/file_plan9.go b/src/pkg/os/file_plan9.go
index 6ee57ff239..7d136eb368 100644
--- a/src/pkg/os/file_plan9.go
+++ b/src/pkg/os/file_plan9.go
@@ -7,6 +7,7 @@ package os
import (
"runtime"
"syscall"
+ "time"
)
// File represents an open file descriptor.
@@ -299,15 +300,14 @@ func Chmod(name string, mode FileMode) error {
// Chtimes changes the access and modification times of the named
// file, similar to the Unix utime() or utimes() functions.
//
-// The argument times are in nanoseconds, although the underlying
-// filesystem may truncate or round the values to a more
-// coarse time unit.\n-func Chtimes(name string, atimeNs int64, mtimeNs int64) error {
+// The underlying filesystem may truncate or round the values to a
+// less precise time unit.\n+func Chtimes(name string, atime time.Time, mtime time.Time) error {
var d Dir
d.Null()
-\td.Atime = uint32(atimeNs / 1e9)\n-\td.Mtime = uint32(mtimeNs / 1e9)\n+\td.Atime = uint32(atime.Unix())\n+\td.Mtime = uint32(mtime.Unix())\n
\tif e := syscall.Wstat(name, pdir(nil, &d)); e != nil {
\t\treturn &PathError{\"chtimes\", name, e}\ndiff --git a/src/pkg/os/stat_plan9.go b/src/pkg/os/stat_plan9.go
index 8d3b8a84d5..f731e43740 100644
--- a/src/pkg/os/stat_plan9.go
+++ b/src/pkg/os/stat_plan9.go
@@ -97,3 +97,8 @@ func Stat(name string) (FileInfo, error) {
func Lstat(name string) (FileInfo, error) {
return Stat(name)
}
+\n+// For testing.\n+func atime(fi FileInfo) time.Time {
+\treturn time.Unix(int64(fi.(*FileStat).Sys.(*Dir).Atime), 0)\n+}\n
コアとなるコードの解説
src/pkg/os/file_plan9.go
の変更
-
import "time"
の追加:os.Chtimes
関数の引数にtime.Time
型を使用するため、time
パッケージがインポートされました。 -
Chtimes
関数のシグネチャ変更:- 変更前:
func Chtimes(name string, atimeNs int64, mtimeNs int64) error
- アクセス時刻と更新時刻をナノ秒単位の
int64
で受け取っていました。
- アクセス時刻と更新時刻をナノ秒単位の
- 変更後:
func Chtimes(name string, atime time.Time, mtime time.Time) error
- アクセス時刻と更新時刻を
time.Time
型で受け取るようになりました。これにより、Goの標準的な時刻表現に統一され、APIの使いやすさと型安全性が向上しました。
- アクセス時刻と更新時刻を
- 変更前:
-
Dir
構造体へのタイムスタンプ設定ロジックの変更:- 変更前:
d.Atime = uint32(atimeNs / 1e9) d.Mtime = uint32(mtimeNs / 1e9)
- ナノ秒単位の
int64
を1e9
(10億)で割ることで秒に変換し、uint32
にキャストしていました。
- ナノ秒単位の
- 変更後:
d.Atime = uint32(atime.Unix()) d.Mtime = uint32(mtime.Unix())
time.Time
型のUnix()
メソッドを呼び出すことで、Unixエポックからの経過秒数(int64
)を取得し、それをuint32
にキャストしてDir
構造体のAtime
とMtime
フィールドに設定しています。これにより、Plan 9のシステムコールが期待する秒単位のタイムスタンプが正確に渡されるようになりました。
- 変更前:
src/pkg/os/stat_plan9.go
の変更
atime
ヘルパー関数の追加:// For testing. func atime(fi FileInfo) time.Time { return time.Unix(int64(fi.(*FileStat).Sys.(*Dir).Atime), 0) }
- この関数は、
FileInfo
インターフェースを引数として受け取り、そのファイル情報のアクセス時刻(atime)をtime.Time
型で返します。 fi.(*FileStat)
:FileInfo
インターフェースの具体的な実装が*FileStat
型であることを型アサーションで確認しています。FileStat
はPlan 9固有のファイル情報構造体です。(*FileStat).Sys.(*Dir)
:FileStat
構造体のSys
フィールドは、基盤となるシステム固有の情報を保持しており、Plan 9の場合は*Dir
型(syscall.Dir
のエイリアス)に型アサーションされます。(*Dir).Atime
:Dir
構造体のAtime
フィールドは、Unixエポックからのアクセス秒数をuint32
で保持しています。time.Unix(int64(...), 0)
:time.Unix
関数は、Unixエポックからの秒数(int64
)とナノ秒オフセット(int64
)を引数として受け取り、対応するtime.Time
オブジェクトを生成します。ここでは、Atime
をint64
にキャストし、ナノ秒オフセットは0
としています。- この関数は、
os.Chtimes
で設定した時刻が、os.Stat
などでファイル情報を取得した際に正しく読み取れることをテストするために使用されます。
- この関数は、
これらの変更により、Goのos
パッケージはPlan 9上でファイルタイムスタンプをより正確かつGoのイディオムに沿った形で扱えるようになり、テストのパスに貢献しました。
関連リンク
- GitHubコミットページ: https://github.com/golang/go/commit/c93ca600eca4cee6dae2495772ae910eb768cec3
- Go Code Review (CL): https://golang.org/cl/5563046
参考にした情報源リンク
- Plan 9 from Bell Labs - Wikipedia: https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs
- The Go Programming Language and Plan 9: https://go.dev/blog/plan9
- Why Go is the spiritual successor to Plan 9: https://dev.to/jmfayard/why-go-is-the-spiritual-successor-to-plan-9-2020-10-20
- Plan 9 from Bell Labs - 9p.io: https://9p.io/plan9/
- Go and Plan 9 - Drew DeVault's Blog: https://drewdevault.com/2020/07/27/Go-and-Plan9.html
- Go's relationship with Plan 9 - Hacker News: https://news.ycombinator.com/item?id=23987650
- Go's Plan 9 heritage - Reddit: https://www.reddit.com/r/golang/comments/100000/gos_plan_9_heritage/