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

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

このコミットは、Go言語のソースコードリポジトリ内の misc/dist/bindist.go ファイルに対する変更です。このファイルは、Goのバイナリ配布(bindist)プロセスに関連するユーティリティ関数を含んでいると推測されます。具体的には、ファイルのコピー操作 cp 関数において、コピー元ファイルのパーミッション(ファイルモード)をコピー先ファイルに保持するように修正が加えられています。

コミット

commit ba4197851606c9cd95e98b75d86c47604c5ffce8
Author: Francesc Campoy <campoy@golang.org>
Date:   Tue Jan 29 15:17:39 2013 -0800

    go/misc/dist: Keep file modes when copying.
    
    R=adg
    CC=golang-dev
    https://golang.org/cl/7221055

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

https://github.com/golang/go/commit/ba4197851606c9cd95e98b75d86c47604c5ffce8

元コミット内容

go/misc/dist: Keep file modes when copying.

R=adg
CC=golang-dev
https://golang.org/cl/7221055

変更の背景

この変更の背景には、Go言語のバイナリ配布プロセスにおいて、ファイルをコピーする際に元のファイルのパーミッション(実行権限など)が正しく引き継がれないという問題があったと考えられます。特に、実行可能ファイルやスクリプトなどを配布する場合、それらのファイルが適切な実行権限を持っていなければ、ユーザーがGoのツールやアプリケーションをインストールした際に正しく動作しない可能性があります。

misc/dist/bindist.go は、Goの公式バイナリ配布物を生成する際に使用されるユーティリティの一部であるため、このファイルコピーの挙動はGoの配布物の品質と機能性に直接影響します。このコミットは、コピー操作の堅牢性を高め、配布されるバイナリが意図したパーミッションを保持するようにするために行われました。

前提知識の解説

ファイルモード(パーミッション)

Unix系OS(Linux, macOSなど)では、ファイルやディレクトリには「ファイルモード」と呼ばれる属性が設定されています。これは、そのファイルに対して誰がどのような操作(読み取り、書き込み、実行)を許可されているかを定義するものです。通常、3つのカテゴリ(所有者、グループ、その他)と3つの権限(読み取り r、書き込み w、実行 x)の組み合わせで表現されます。例えば、rwxr-xr-x は、所有者には読み書き実行、グループとその他には読み取りと実行が許可されていることを意味します。

プログラムがファイルをコピーする際、デフォルトではコピー先ファイルのパーミッションは、プログラムがファイルを作成する際のデフォルトのパーミッション(umask設定などによる)になることが多く、元のファイルのパーミッションが自動的に引き継がれるわけではありません。

Go言語のファイル操作

Go言語の標準ライブラリ os パッケージは、ファイルシステム操作のための機能を提供します。

  • os.Open(name string) (*File, error): 指定されたパスのファイルを読み取り専用で開きます。成功すると *File 型のポインタを返します。
  • os.Create(name string) (*File, error): 指定されたパスに新しいファイルを作成します。ファイルが既に存在する場合は、その内容を切り詰めて(truncate)サイズを0にします。成功すると *File 型のポインタを返します。作成されるファイルのデフォルトパーミッションは、通常 0666 からプロセスのumaskを引いた値になります。
  • *File.Stat() (FileInfo, error): 開いているファイル(*File)のファイル情報を取得します。FileInfo インターフェースは、ファイル名、サイズ、変更時刻、そしてファイルモードなどの情報を提供します。
  • FileInfo.Mode() FileMode: FileInfo からファイルモード(パーミッション)を取得します。
  • *File.Chmod(mode FileMode) error: 開いているファイル(*File)のパーミッションを指定された FileMode に変更します。
  • io.Copy(dst Writer, src Reader) (written int64, err error): src から dst へデータをコピーします。これはファイルの内容を効率的にコピーするためによく使われます。

技術的詳細

このコミットは、misc/dist/bindist.go 内の cp 関数、すなわちファイルコピー関数に焦点を当てています。元の cp 関数は、単にコピー元ファイルの内容をコピー先ファイルにコピーするだけでした。しかし、この方法ではコピー先ファイルのパーミッションが、Goプログラムがファイルを作成する際のデフォルト値になってしまい、元のファイルのパーミッションが失われるという問題がありました。

この変更では、以下のステップが追加されています。

  1. コピー元ファイルのパーミッションの取得: sf.Stat() を呼び出してコピー元ファイル(sf)のファイル情報を取得し、その情報から fi.Mode() を使ってファイルモード(パーミッション)を取得します。
  2. コピー先ファイルへのパーミッションの適用: コピー先ファイル(df)が作成された後、df.Chmod(fi.Mode()) を呼び出して、取得したコピー元ファイルのパーミッションをコピー先ファイルに設定します。

これにより、ファイルの内容だけでなく、そのパーミッションも正確にコピーされるようになり、Goのバイナリ配布物の整合性が保たれます。

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

misc/dist/bindist.go ファイルの cp 関数に以下の7行が追加されました。

--- a/misc/dist/bindist.go
+++ b/misc/dist/bindist.go
@@ -611,11 +611,18 @@ func cp(dst, src string) error {
 		return err
 	}
 	defer sf.Close()
+	fi, err := sf.Stat()
+	if err != nil {
+		return err
+	}
 	df, err := os.Create(dst)
 	if err != nil {
 		return err
 	}
 	defer df.Close()
+	if err := df.Chmod(fi.Mode()); err != nil {
+		return err
+	}
 	_, err = io.Copy(df, sf)
 	return err
 }

コアとなるコードの解説

追加されたコードは cp 関数内で、コピー元ファイル sf からコピー先ファイル df への内容コピーの前後で実行されます。

  1. fi, err := sf.Stat():

    • sf はコピー元ファイルを表す *os.File オブジェクトです。
    • sf.Stat() は、このファイルに関するメタデータ(ファイルサイズ、変更時刻、パーミッションなど)を含む os.FileInfo インターフェースを返します。
    • この行は、コピー元ファイルの情報を取得し、それを fi 変数に格納します。エラーが発生した場合は、すぐにそのエラーを返します。
  2. if err != nil { return err }:

    • sf.Stat() の呼び出しでエラーが発生した場合(例: ファイルが存在しない、アクセス権がないなど)、そのエラーを呼び出し元に伝播させます。
  3. if err := df.Chmod(fi.Mode()); err != nil { return err }:

    • df はコピー先ファイルを表す *os.File オブジェクトです。
    • fi.Mode() は、先ほど sf.Stat() で取得した fi から、コピー元ファイルのパーミッション(os.FileMode 型)を抽出します。
    • df.Chmod() は、df で開かれているファイルのパーミッションを、引数で指定された FileMode に変更します。
    • この行は、コピー元ファイルのパーミッションをコピー先ファイルに適用します。ここでもエラーチェックが行われ、パーミッションの変更に失敗した場合はエラーが返されます。

これらの変更により、cp 関数はファイルの内容だけでなく、そのパーミッションも正確に複製するようになり、Goのバイナリ配布プロセスにおけるファイルの整合性が向上しました。

関連リンク

参考にした情報源リンク

  • Go os パッケージの公式ドキュメント: https://pkg.go.dev/os
  • Go io パッケージの公式ドキュメント: https://pkg.go.dev/io
  • Unixファイルパーミッションに関する一般的な情報源 (例: Wikipedia, Linux man pagesなど)
  • Goのコードレビューシステム (Gerrit) のインターフェースとコミットメッセージの慣習