[インデックス 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言語の一般的な知識に基づいています。)