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

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

このコミットは、Go言語の os パッケージにおけるWindowsビルドの修正を目的としています。具体的には、ファイル情報の取得と変換に関するWindows固有の処理において、タイムスタンプの扱いを修正し、テスト用のエクスポートを調整しています。これにより、Windows環境での os パッケージの安定性と正確性が向上します。

コミット

commit 12eee9edbc0a63ba5802541ec9bfec4a925637ee
Author: Russ Cox <rsc@golang.org>
Date:   Wed Nov 30 12:38:54 2011 -0500

    os: fix windows build
    
    TBR=brainman
    CC=golang-dev
    https://golang.org/cl/5449048

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

https://github.com/golang/go/commit/12eee9edbc0a63ba5802541ec9bfec4a925637ee

元コミット内容

os: fix windows build

TBR=brainman
CC=golang-dev
https://golang.org/cl/5449048

変更の背景

このコミットの背景には、Go言語の os パッケージがWindows環境で正しくビルドまたは動作しない問題があったことが示唆されています。コミットメッセージの「os: fix windows build」という記述から、Windows固有の環境におけるファイルシステム操作やファイル情報の取得に関するバグや不整合が存在し、それを修正する必要があったと考えられます。特に、ファイルタイムスタンプの扱いが原因であった可能性が高いです。Go言語はクロスプラットフォーム対応を目指しているため、各OS固有の挙動に合わせた調整が不可欠であり、このコミットはその一環としてWindows環境での互換性と正確性を確保するために行われました。

前提知識の解説

このコミットを理解するためには、以下のGo言語およびWindows OSに関する前提知識が必要です。

  • Go言語の os パッケージ:

    • os パッケージは、オペレーティングシステムと対話するための機能を提供します。これには、ファイルシステム操作(ファイルの読み書き、ディレクトリの作成など)、プロセス管理、環境変数へのアクセスなどが含まれます。
    • os.FileInfo インターフェース: ファイルに関する抽象的な情報(ファイル名、サイズ、パーミッション、更新時刻など)を提供するインターフェースです。
    • os.FileStat 構造体: os.FileInfo インターフェースを実装する具体的な構造体で、ファイルシステムから取得した詳細なファイル情報を保持します。
    • time.Time: Go言語で時刻を扱うための型です。
    • time.Unix(sec int64, nsec int64) time.Time: Unixエポックからの秒数とナノ秒数から time.Time オブジェクトを生成する関数です。
  • Windows APIとファイルタイムスタンプ:

    • Windows OSでは、ファイルの作成時刻 (Creation Time)、最終アクセス時刻 (Last Access Time)、最終書き込み時刻 (Last Write Time) を FILETIME 構造体で管理します。
    • syscall.Filetime: Go言語の syscall パッケージで定義されている FILETIME 構造体に対応する型です。これは、1601年1月1日からの100ナノ秒間隔の数を表す64ビットの値(LowDateTimeHighDateTime の2つの uint32 で構成される)として表現されます。
    • syscall.Filetime.Nanoseconds(): syscall.Filetime 型のメソッドで、FILETIME の値をUnixエポック(1970年1月1日)からのナノ秒数に変換します。この変換は、Go言語の time.Time 型と互換性を持たせるために重要です。
  • export_test.go ファイル:

    • Go言語では、内部的な関数や変数をテスト目的で外部に公開するために、慣習的に _test.go サフィックスを持つファイル内で Export というコメントを付けてエクスポートすることがあります。export_test.go は、パッケージの内部関数をテストパッケージからアクセス可能にするためのファイルです。

技術的詳細

このコミットの技術的な核心は、Windowsにおけるファイルタイムスタンプの正確な変換と、それに伴う内部構造の調整にあります。

  1. src/pkg/os/stat_windows.go の変更:

    • toFileInfo 関数のシグネチャ変更:
      • 変更前: func toFileInfo(name string, fa, sizehi, sizelo uint32, ctime, atime, wtime syscall.Filetime) FileInfo
      • 変更後: func toFileInfo(name string, fa, sizehi, sizelo uint32, ctime, atime, mtime syscall.Filetime) FileInfo
      • wtime (write time) が mtime (modification time) に変更されています。これは、Windows APIで一般的に「最終書き込み時刻」が「最終更新時刻」として扱われることと整合性を取るための変更と考えられます。
    • winTimes 構造体の導入:
      • type winTimes struct { atime, ctime syscall.Filetime }
      • FileStat 構造体の Sys フィールド(OS固有の情報を保持するためのインターフェース)に、atime (アクセス時刻) と ctime (作成時刻) を格納するための新しい構造体 winTimes が導入されました。これにより、Windows固有のタイムスタンプ情報をより構造化された形で保持できるようになります。
    • fs.modTime の修正:
      • 変更前: fs.modTime = time.Unix(0, wtime.Nanoseconds())
      • 変更後: fs.modTime = time.Unix(0, mtime.Nanoseconds())
      • modTime (最終更新時刻) の設定において、wtime から mtime に変更された引数を使用するように修正されました。これは、toFileInfo 関数のシグネチャ変更と連動しています。
    • fs.Sys への winTimes の割り当て:
      • fs.Sys = &winTimes{atime, ctime}
      • FileStatSys フィールドに、新しく定義された winTimes 構造体のインスタンスが割り当てられるようになりました。これにより、atimectimeFileStat オブジェクトの一部として保持されるようになります。
    • atime 関数の追加:
      • func atime(fi FileInfo) time.Time { return time.Unix(0, fi.(*FileStat).Sys.(*winTimes).atime.Nanoseconds()) }
      • テスト目的で、FileInfo から atime (最終アクセス時刻) を取得するためのヘルパー関数 atime が追加されました。この関数は、FileInfo*FileStat に型アサートし、さらにその Sys フィールドを *winTimes に型アサートすることで、内部に保持されている atimetime.Time 型に変換して返します。
  2. src/pkg/os/export_test.go の変更:

    • TimespecToTime の削除:
      • var TimespecToTime = timespecToTime の行が削除されました。
      • TimespecToTime は、Unix系のシステムで使われる timespec 構造体を time.Time に変換するためのテスト用エクスポートだったと考えられます。Windowsビルドの修正に関連して、Windows固有のタイムスタンプ処理(syscall.Filetime)に焦点を当てるため、またはこの変換が不要になったため、削除されたと推測されます。Windowsでは timespec は直接使用されないため、Windowsビルドの修正においては不要なエクスポートであった可能性があります。

これらの変更は、Windowsにおけるファイル情報の取得、特にタイムスタンプの正確なマッピングと、Go言語の os パッケージの内部構造との整合性を確保するために行われました。

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

--- a/src/pkg/os/export_test.go
+++ b/src/pkg/os/export_test.go
@@ -6,5 +6,4 @@ package os
 
 // Export for testing.
 
-var TimespecToTime = timespecToTime
 var Atime = atime
diff --git a/src/pkg/os/stat_windows.go b/src/pkg/os/stat_windows.go
index d024915ee0..ddecd1118f 100644
--- a/src/pkg/os/stat_windows.go
+++ b/src/pkg/os/stat_windows.go
@@ -77,7 +77,11 @@ func basename(name string) string {
 	return name
 }
 
-func toFileInfo(name string, fa, sizehi, sizelo uint32, ctime, atime, wtime syscall.Filetime) FileInfo {
+type winTimes struct {
+	atime, ctime syscall.Filetime
+}
+
+func toFileInfo(name string, fa, sizehi, sizelo uint32, ctime, atime, mtime syscall.Filetime) FileInfo {
 	fs := new(FileStat)
 	fs.mode = 0
 	if fa&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
@@ -90,10 +94,16 @@ func toFileInfo(name string, fa, sizehi, sizelo uint32, ctime, atime, wtime sysc
 	}
 	fs.size = int64(sizehi)<<32 + int64(sizelo)
 	fs.name = name
-	fs.modTime = time.Unix(0, wtime.Nanoseconds())
+	fs.modTime = time.Unix(0, mtime.Nanoseconds())
+	fs.Sys = &winTimes{atime, ctime}
 	return fs
 }
 
 func sameFile(fs1, fs2 *FileStat) bool {
 	return false
 }
+
+// For testing.
+func atime(fi FileInfo) time.Time {
+	return time.Unix(0, fi.(*FileStat).Sys.(*winTimes).atime.Nanoseconds())
+}

コアとなるコードの解説

src/pkg/os/export_test.go

  • - var TimespecToTime = timespecToTime: この行は削除されました。timespecToTime はUnix系のシステムで使われる timespec 構造体を time.Time に変換するための内部関数であり、テスト目的でエクスポートされていました。Windowsビルドの修正においては、Windows固有の syscall.Filetime を扱うため、このUnix系システム向けの変換関数は不要と判断され、削除されたと考えられます。

src/pkg/os/stat_windows.go

  • + type winTimes struct { atime, ctime syscall.Filetime }:

    • winTimes という新しい構造体が定義されました。この構造体は、Windowsのファイルシステムから取得される最終アクセス時刻 (atime) と作成時刻 (ctime) を syscall.Filetime 型で保持します。
    • これは、os.FileStat 構造体の Sys フィールド(OS固有の情報を格納するためのインターフェース)に、より具体的なWindows固有のタイムスタンプ情報を格納するための準備です。
  • - func toFileInfo(name string, fa, sizehi, sizelo uint32, ctime, atime, wtime syscall.Filetime) FileInfo {

  • + func toFileInfo(name string, fa, sizehi, sizelo uint32, ctime, atime, mtime syscall.Filetime) FileInfo {

    • toFileInfo 関数のシグネチャが変更されました。引数の wtime (write time) が mtime (modification time) に変更されています。これは、Windows APIにおける「最終書き込み時刻」が、Go言語の os.FileInfo インターフェースの ModTime() メソッドが返す「最終更新時刻」と概念的に一致するため、より適切な命名に修正されたものです。
  • - fs.modTime = time.Unix(0, wtime.Nanoseconds())

  • + fs.modTime = time.Unix(0, mtime.Nanoseconds())

    • FileStatmodTime フィールドに値を設定する際に、変更された引数 mtime を使用するように修正されました。これにより、os.FileInfo.ModTime() がWindowsの最終書き込み時刻を正確に反映するようになります。
  • + fs.Sys = &winTimes{atime, ctime}

    • FileStatSys フィールドに、新しく定義された winTimes 構造体のインスタンスが割り当てられます。これにより、FileStat オブジェクトは、Windows固有の最終アクセス時刻と作成時刻を内部的に保持できるようになります。これは、後述の atime 関数でこれらの情報にアクセスするために必要です。
  • + // For testing.

  • + func atime(fi FileInfo) time.Time {

  • + return time.Unix(0, fi.(*FileStat).Sys.(*winTimes).atime.Nanoseconds())

  • + }

    • テスト目的で、FileInfo インターフェースから最終アクセス時刻 (atime) を取得するためのヘルパー関数 atime が追加されました。
    • この関数は、FileInfo*FileStat に型アサートし、さらにその Sys フィールドを *winTimes に型アサートすることで、winTimes 構造体内に格納されている atime (syscall.Filetime 型) にアクセスします。
    • 最後に、syscall.Filetime.Nanoseconds() メソッドを使用して atime をナノ秒単位のUnixエポックからの時間として取得し、time.Unix 関数で time.Time 型に変換して返します。これにより、テストコードからWindows固有のアクセス時刻を簡単に検証できるようになります。

これらの変更は、Windows環境におけるファイル情報の取得、特にタイムスタンプの正確なマッピングと、Go言語の os パッケージの内部構造との整合性を確保するために不可欠です。

関連リンク

参考にした情報源リンク