[インデックス 11063] ファイルの概要
このコミットは、Go言語のosパッケージにおいて、Unixファイルモードからos.FileModeへの変換、およびその逆の変換において、文字デバイスに関する情報が失われないようにするための改善を導入します。具体的には、os.FileModeにModeCharDeviceという新しいビットを追加し、各OS固有のファイル情報取得関数(stat_*.go)で文字デバイスを正しく識別するように変更しています。
コミット
- コミットハッシュ:
cc02ef025831bb6fbf0a662bd11f6be796e4cf33 - 作者: Russ Cox rsc@golang.org
- 日付: 2012年1月9日 月曜日 14:22:53 -0800
- 概要:
osパッケージにModeCharDeviceを追加し、Unixモードとos.FileMode間の変換における情報損失を防ぐ。
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/cc02ef025831bb6fbf0a662bd11f6be796e4cf33
元コミット内容
os: add ModeCharDevice
This should make conversion from Unix mode
to os.FileMode and back not lossy.
R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/5531052
変更の背景
この変更の主な背景は、Go言語のosパッケージがUnix系のシステムコールから取得するファイルモード情報(syscall.Stat_t.Mode)を、Go独自のos.FileMode型に変換する際に、特定のファイルタイプ(特に文字デバイス)に関する情報が失われる可能性があったためです。
従来のos.FileModeには、ブロックデバイスと文字デバイスの両方を包括するModeDeviceというフラグは存在しましたが、両者を区別するための特定のフラグがありませんでした。このため、文字デバイスのファイルモードをos.FileModeに変換し、その後再びUnixモードに戻そうとすると、それが文字デバイスであったという固有の特性が失われ、単なる一般的なデバイスとして扱われてしまう「情報損失(lossy conversion)」が発生していました。
この情報損失は、ファイルシステム操作の正確性や、特定のデバイスタイプに依存するアプリケーションの動作に影響を与える可能性がありました。このコミットは、ModeCharDeviceという新しいフラグを導入することで、この情報損失の問題を解決し、Unixファイルモードとos.FileMode間の変換の正確性を向上させることを目的としています。
前提知識の解説
Unixファイルモードとファイルタイプ
Unix系OSでは、ファイルには様々なタイプがあり、それぞれがファイルモードの一部として表現されます。statシステムコールなどで取得できるファイルモードには、パーミッション情報(読み取り、書き込み、実行権限など)だけでなく、ファイルのタイプを示すビットも含まれています。
主要なファイルタイプを示すビットは以下の通りです(syscallパッケージで定義されている定数):
syscall.S_IFMT: ファイルタイプを示すビットマスク。このマスクをファイルモードに適用することで、ファイルタイプを抽出できます。syscall.S_IFREG: 通常のファイル (regular file)。syscall.S_IFDIR: ディレクトリ (directory)。syscall.S_IFLNK: シンボリックリンク (symbolic link)。syscall.S_IFIFO: 名前付きパイプ (FIFO)。syscall.S_IFSOCK: Unixドメインソケット (Unix domain socket)。syscall.S_IFBLK: ブロックデバイス (block device)。ディスクドライブやCD-ROMドライブなど、ブロック単位でデータを読み書きするデバイスを表します。syscall.S_IFCHR: 文字デバイス (character device)。ターミナル、シリアルポート、プリンターなど、文字単位でデータを読み書きするデバイスを表します。
Go言語のos.FileMode
Go言語のosパッケージには、ファイルパーミッションとファイルタイプを抽象化して表現するためのFileMode型が定義されています。これはuint32のエイリアスであり、特定のビットがファイルタイプや特殊なパーミッション(setuid, setgidなど)を表すために使用されます。
このコミット以前のos.FileModeには、以下のようなファイルタイプを示すフラグがありました:
os.ModeDir: ディレクトリ。os.ModeSymlink: シンボリックリンク。os.ModeNamedPipe: 名前付きパイプ (FIFO)。os.ModeSocket: Unixドメインソケット。os.ModeDevice: デバイスファイル(ブロックデバイスまたは文字デバイス)。
問題は、ModeDeviceがブロックデバイスと文字デバイスの両方をカバーしていたため、syscall.S_IFBLKとsyscall.S_IFCHRの区別がos.FileModeレベルでは失われていた点です。
情報損失 (Lossy Conversion)
「情報損失」とは、ある形式のデータを別の形式に変換する際に、元のデータが持っていた情報の一部が失われ、元の形式に完全に復元できなくなる状態を指します。このコミットの文脈では、Unixのファイルモード(syscall.S_IFCHRで文字デバイスを明示的に区別できる)をGoのos.FileModeに変換する際に、文字デバイスであるという情報がModeDeviceというより一般的なフラグに吸収されてしまい、そのos.FileModeから元のUnixモードを再構築しようとしても、文字デバイスであるという特性が失われてしまうことを意味します。
例えば、/dev/ttyのような文字デバイスのファイルモードをGoで取得し、それをos.FileModeとして保持した後、そのos.FileModeからファイルタイプを判断しようとすると、単に「デバイスファイル」であるとしか認識できず、「文字デバイス」であるという詳細な情報が失われていました。
技術的詳細
このコミットは、上記の情報損失の問題を解決するために、以下の技術的な変更を導入しています。
-
os.ModeCharDeviceの追加:src/pkg/os/types.goに新しいFileModeビットModeCharDeviceが追加されました。このビットは、ModeDeviceが設定されている場合に、そのデバイスが特に文字デバイスであることを示すために使用されます。ModeCharDevice // c: Unix character device, when ModeDevice is setこのコメントが示すように、
ModeCharDeviceは単独で使われるのではなく、ModeDeviceと組み合わせて使われることで、文字デバイスを正確に表現します。 -
fileInfoFromStat関数の変更: 各OS固有のstat_*.goファイル(stat_darwin.go,stat_freebsd.go,stat_linux.go,stat_netbsd.go,stat_openbsd.go)にあるfileInfoFromStat関数が修正されました。この関数は、syscall.Stat_t構造体から取得したファイルモードをos.FileModeに変換する役割を担っています。 変更前は、syscall.S_IFBLK(ブロックデバイス)とsyscall.S_IFCHR(文字デバイス)の両方に対してModeDeviceフラグを設定していました。 変更後は、syscall.S_IFBLKに対しては引き続きModeDeviceのみを設定し、syscall.S_IFCHRに対しては**ModeDevice | ModeCharDevice**を設定するように変更されました。これにより、文字デバイスであることがos.FileModeに正確に反映されるようになります。 -
ModeTypeマスクの更新:os.FileModeのタイプビットを抽出するためのマスクであるModeTypeも更新されました。ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice | ModeCharDeviceこれにより、
ModeCharDeviceもファイルタイプの一部として正しく認識されるようになります。 -
FileMode.String()メソッドの更新:FileModeの文字列表現を生成するString()メソッドも、新しいModeCharDeviceフラグに対応するために更新されました。const str = "daltLDpSugc"cが追加され、ModeCharDeviceが設定されている場合に、FileModeの文字列表現にcが含まれるようになります。
これらの変更により、GoプログラムがUnixファイルシステム上の文字デバイスの情報を取得する際に、そのデバイスが文字デバイスであるという特性を正確に保持し、必要に応じてその情報を利用できるようになります。
コアとなるコードの変更箇所
src/pkg/os/stat_darwin.go, src/pkg/os/stat_freebsd.go, src/pkg/os/stat_linux.go, src/pkg/os/stat_netbsd.go, src/pkg/os/stat_openbsd.go
これらのファイルでは、fileInfoFromStat関数内のswitch st.Mode & syscall.S_IFMTブロックが変更されています。
変更前:
case syscall.S_IFBLK, syscall.S_IFCHR:
fs.mode |= ModeDevice
変更後:
case syscall.S_IFBLK:
fs.mode |= ModeDevice
case syscall.S_IFCHR:
fs.mode |= ModeDevice | ModeCharDevice
(stat_darwin.goにはsyscall.S_IFWHTも含まれますが、変更のロジックは同じです。)
src/pkg/os/types.go
-
FileMode定数にModeCharDeviceが追加されました。 追加:ModeCharDevice // c: Unix character device, when ModeDevice is set -
ModeTypeマスクが更新されました。 変更前:ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice変更後:
ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice | ModeCharDevice -
FileMode.String()メソッド内のstr定数が更新されました。 変更前:const str = "daltLDpSug"変更後:
const str = "daltLDpSugc"
コアとなるコードの解説
fileInfoFromStat関数の変更
この変更は、Unixのstatシステムコールから取得したファイルモード(st.Mode)をGoのos.FileModeに変換する際の、文字デバイスの扱いを改善します。
- 変更前:
syscall.S_IFBLK(ブロックデバイス)とsyscall.S_IFCHR(文字デバイス)の両方が、単一のModeDeviceフラグとしてos.FileModeにマッピングされていました。これは、両者が「デバイスファイル」であるという共通の性質を捉えていましたが、文字デバイス固有の特性を区別していませんでした。 - 変更後:
syscall.S_IFCHRの場合に、既存のModeDeviceに加えて新しく定義されたModeCharDeviceフラグも設定するようにしました。これにより、os.FileModeは、そのファイルが単なるデバイスであるだけでなく、具体的に「文字デバイス」であるという情報を保持できるようになります。この区別は、例えば、特定のデバイスタイプに特化した処理を行うアプリケーションにとって重要です。
src/pkg/os/types.goの変更
ModeCharDeviceの追加: この新しい定数は、os.FileModeが文字デバイスを表すための専用ビットを提供します。これにより、os.FileModeの表現力が向上し、Unixファイルモードとの間の情報損失がなくなります。ModeTypeマスクの更新:ModeTypeは、os.FileModeからファイルタイプ関連のビットのみを抽出するために使用されるマスクです。ModeCharDeviceが追加されたことで、このマスクも更新され、新しい文字デバイスのタイプビットが正しく含まれるようになりました。これにより、ModeTypeを使ってファイルタイプをチェックする既存のコードが、ModeCharDeviceも考慮に入れることができるようになります。FileMode.String()メソッドの更新:FileModeのString()メソッドは、ls -lコマンドの出力のように、ファイルモードを人間が読める形式で表示するために使用されます。ModeCharDeviceが追加されたことで、このメソッドの内部で使用される文字列定数strにcが追加されました。これにより、ModeCharDeviceが設定されているFileModeオブジェクトのString()メソッドを呼び出すと、出力文字列にcが含まれるようになり、そのファイルが文字デバイスであることが視覚的に示されます。
これらの変更は全体として、Goのosパッケージがファイルシステム上のデバイスファイルをより正確に表現し、Unixシステムとの互換性を高めるための重要な改善です。
関連リンク
- Go CL (Change List): https://golang.org/cl/5531052
参考にした情報源リンク
- (特になし。コミット内容とGo言語の一般的な知識に基づいています。)