[インデックス 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プログラムがファイルを作成する際のデフォルト値になってしまい、元のファイルのパーミッションが失われるという問題がありました。
この変更では、以下のステップが追加されています。
- コピー元ファイルのパーミッションの取得:
sf.Stat()
を呼び出してコピー元ファイル(sf
)のファイル情報を取得し、その情報からfi.Mode()
を使ってファイルモード(パーミッション)を取得します。 - コピー先ファイルへのパーミッションの適用: コピー先ファイル(
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
への内容コピーの前後で実行されます。
-
fi, err := sf.Stat()
:sf
はコピー元ファイルを表す*os.File
オブジェクトです。sf.Stat()
は、このファイルに関するメタデータ(ファイルサイズ、変更時刻、パーミッションなど)を含むos.FileInfo
インターフェースを返します。- この行は、コピー元ファイルの情報を取得し、それを
fi
変数に格納します。エラーが発生した場合は、すぐにそのエラーを返します。
-
if err != nil { return err }
:sf.Stat()
の呼び出しでエラーが発生した場合(例: ファイルが存在しない、アクセス権がないなど)、そのエラーを呼び出し元に伝播させます。
-
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 Code Review 7221055: https://go-review.googlesource.com/c/go/+/7221055
- Go
os
パッケージのドキュメント: https://pkg.go.dev/os - Go
io
パッケージのドキュメント: https://pkg.go.dev/io
参考にした情報源リンク
- Go
os
パッケージの公式ドキュメント: https://pkg.go.dev/os - Go
io
パッケージの公式ドキュメント: https://pkg.go.dev/io - Unixファイルパーミッションに関する一般的な情報源 (例: Wikipedia, Linux man pagesなど)
- Goのコードレビューシステム (Gerrit) のインターフェースとコミットメッセージの慣習