[インデックス 1652] ファイルの概要
このコミットは、Go言語の初期のos
パッケージにおいて、ファイルやディレクトリのモードビット(パーミッションやファイルタイプ)にアクセスするためのシンプルなアクセサメソッドを追加するものです。具体的には、Dir
構造体にファイルタイプを判定するIs*
系のメソッドと、パーミッションを取得するPermission
メソッドが追加されています。
コミット
commit cad7a3aefcdfed3176a64a16b2a6151b2fabfd4e
Author: Rob Pike <r@golang.org>
Date: Mon Feb 9 12:50:54 2009 -0800
simple accessors for Dir mode bits
R=rsc
DELTA=71 (71 added, 0 deleted, 0 changed)
OCL=24687
CL=24694
---
src/lib/os/os_types.go | 34 ++++++++++++++++++++++++++++++++++
src/lib/syscall/types_amd64_darwin.go | 19 +++++++++++++++++++
src/lib/syscall/types_amd64_linux.go | 18 ++++++++++++++++++
3 files changed, 71 insertions(+)
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/cad7a3aefcdfed3176a64a16b2a6151b2fabfd4e
元コミット内容
simple accessors for Dir mode bits
変更の背景
このコミットが行われた2009年2月は、Go言語がまだ一般に公開される前の非常に初期の段階でした。Go言語の設計目標の一つに、システムプログラミングにおけるC言語のような低レベルアクセスと、より高レベルな抽象化のバランスを取ることがありました。ファイルシステムへのアクセスは、システムプログラミングにおいて非常に基本的な操作であり、そのファイルの種類やパーミッションを効率的かつ安全に取得する手段は不可欠です。
当時のGo言語のos
パッケージ(当時はsrc/lib/os
に位置)には、ファイルやディレクトリのメタデータを含むDir
構造体が存在していましたが、そのMode
フィールドから具体的なファイルタイプ(ディレクトリ、通常ファイル、シンボリックリンクなど)やパーミッション情報を直接的に抽出するための便利なメソッドが提供されていませんでした。ユーザーがこれらの情報を得るためには、Mode
フィールドのビットマスクを手動で操作する必要があり、これは冗長でエラーを起こしやすいものでした。
このコミットは、このような低レベルなビット操作を抽象化し、より直感的でGoらしい(Go idiomaticな)方法でファイルモード情報にアクセスできるようにすることを目的としています。これにより、ファイルシステム関連のコードの可読性と保守性が向上し、開発者がより簡単にファイルタイプに応じた処理を記述できるようになります。
前提知識の解説
このコミットを理解するためには、以下の前提知識が必要です。
-
Unix/Linuxのファイルパーミッションとファイルタイプ:
- Unix系OSでは、ファイルやディレクトリには「モード」と呼ばれる属性が関連付けられています。このモードは、ファイルのタイプ(通常ファイル、ディレクトリ、シンボリックリンク、デバイスファイルなど)と、そのファイルに対するユーザー、グループ、その他のアクセス権限(読み取り、書き込み、実行)をビット列で表現したものです。
- ファイルタイプは通常、モードの最上位ビット(
S_IFMT
マスクで抽出される部分)で表現されます。例えば、S_IFDIR
はディレクトリ、S_IFREG
は通常ファイルを示します。 - パーミッションは、通常、モードの下位9ビットで表現され、所有者、グループ、その他のユーザーに対する読み取り(r)、書き込み(w)、実行(x)の権限を示します。これらは8進数表記で
rwx
が7
、rw-
が6
のように表現されます(例:0755
)。
-
ビット演算:
- ファイルモードはビット列であるため、特定の情報を抽出するにはビット演算が用いられます。
- AND演算子 (
&
): 特定のビットがセットされているかを確認したり、特定のビット群を抽出したりするために使用されます。例えば、mode & S_IFMT
はファイルタイプを示すビット群を抽出します。 - 比較演算子 (
==
): 抽出したビット群が特定のファイルタイプ定数と一致するかどうかを判定します。
-
Go言語の構造体とメソッド:
- Go言語では、構造体(
struct
)は関連するデータの集合を定義します。 - メソッドは、特定の型(この場合は
Dir
構造体)に関連付けられた関数です。メソッドはレシーバ(この場合はdir *Dir
)を通じて構造体のフィールドにアクセスできます。
- Go言語では、構造体(
-
syscall
パッケージ:- Go言語の
syscall
パッケージは、オペレーティングシステムが提供する低レベルなシステムコールへのインターフェースを提供します。ファイルモードの定数(S_IFMT
,S_IFDIR
など)は、OS固有の定義に基づいてこのパッケージ内で提供されます。このコミットでは、これらの定数を利用してファイルタイプを判定しています。
- Go言語の
技術的詳細
このコミットの主要な変更点は、os.Dir
構造体に以下のアクセサメソッドを追加したことです。
IsFifo() bool
IsChar() bool
IsDirectory() bool
IsBlock() bool
IsRegular() bool
IsSymlink() bool
IsSocket() bool
Permission() int
これらのメソッドは、Dir
構造体のMode
フィールド(ファイルモードを表す整数値)に対してビット演算を行い、ファイルの種類を判定したり、パーミッション部分を抽出したりします。
ファイルタイプ判定メソッド (Is*
系):
これらのメソッドは、dir.Mode
とsyscall.S_IFMT
(ファイルタイプを示すビットマスク)のビットAND演算を行い、その結果を特定のファイルタイプ定数(例: syscall.S_IFDIR
)と比較することで、ファイルがそのタイプであるかどうかを真偽値で返します。
例: (dir.Mode & syscall.S_IFMT) == syscall.S_IFDIR
syscall.S_IFMT
は、ファイルモードのビット列のうち、ファイルタイプを示す部分(通常は最上位の数ビット)を抽出するためのマスクです。例えば、Unix系システムでは通常0170000
(8進数)のような値になります。
syscall.S_IFIFO
, syscall.S_IFCHR
, syscall.S_IFDIR
, syscall.S_IFBLK
, syscall.S_IFREG
, syscall.S_IFLNK
, syscall.S_IFSOCK
はそれぞれ、FIFO(名前付きパイプ)、キャラクタースペシャルファイル、ディレクトリ、ブロックスペシャルファイル、通常ファイル、シンボリックリンク、ソケットに対応するファイルタイプ定数です。
パーミッション取得メソッド (Permission
):
Permission()
メソッドは、dir.Mode
と0777
(8進数)のビットAND演算を行うことで、ファイルモードからパーミッション部分のみを抽出します。0777
は、所有者、グループ、その他のユーザーに対する読み取り、書き込み、実行の全パーミッションビットがセットされたマスクです。これにより、ファイルタイプ情報を含まない純粋なパーミッション値(例: 0644
)が得られます。
また、このコミットでは、src/lib/syscall/types_amd64_darwin.go
とsrc/lib/syscall/types_amd64_linux.go
に、これらのファイルタイプ定数とパーミッション関連の定数(S_ISUID
, S_ISGID
, S_ISVTX
, S_IRUSR
, S_IWUSR
, S_IXUSR
など)が追加されています。これらはOS固有の定義に基づいており、Goのsyscall
パッケージが各OSのシステムコールと連携するために必要です。
コアとなるコードの変更箇所
src/lib/os/os_types.go
// An operating-system independent representation of Unix data structures.
// OS-specific routines in this directory convert the OS-local versions to these.
@@ -24,3 +26,35 @@ type Dir struct {
Ctime_ns uint64; // nanoseconds since 1970
Name string;
}
+
+func (dir *Dir) IsFifo() bool {
+ return (dir.Mode & syscall.S_IFMT) == syscall.S_IFIFO
+}
+
+func (dir *Dir) IsChar() bool {
+ return (dir.Mode & syscall.S_IFMT) == syscall.S_IFCHR
+}
+
+func (dir *Dir) IsDirectory() bool {
+ return (dir.Mode & syscall.S_IFMT) == syscall.S_IFDIR
+}
+
+func (dir *Dir) IsBlock() bool {
+ return (dir.Mode & syscall.S_IFMT) == syscall.S_IFBLK
+}
+
+func (dir *Dir) IsRegular() bool {
+ return (dir.Mode & syscall.S_IFMT) == syscall.S_IFREG
+}
+
+func (dir *Dir) IsSymlink() bool {
+ return (dir.Mode & syscall.S_IFMT) == syscall.S_IFLNK
+}
+
+func (dir *Dir) IsSocket() bool {
+ return (dir.Mode & syscall.S_IFMT) == syscall.S_IFSOCK
+}
+
+func (dir *Dir) Permission() int {
+ return int(dir.Mode & 0777)
+}
src/lib/syscall/types_amd64_darwin.go
@@ -69,6 +69,25 @@ const (
NAME_MAX = 255;
)
+// Dir.Mode bits
+const (
+ S_IFMT = 0170000; /* type of file */
+ S_IFIFO = 0010000; /* named pipe (fifo) */
+ S_IFCHR = 0020000; /* character special */
+ S_IFDIR = 0040000; /* directory */
+ S_IFBLK = 0060000; /* block special */
+ S_IFREG = 0100000; /* regular */
+ S_IFLNK = 0120000; /* symbolic link */
+ S_IFSOCK = 0140000; /* socket */
+ S_IFWHT = 0160000; /* whiteout */
+ S_ISUID = 0004000; /* set user id on execution */
+ S_ISGID = 0002000; /* set group id on execution */
+ S_ISVTX = 0001000; /* save swapped text even after use */
+ S_IRUSR = 0000400; /* read permission, owner */
+ S_IWUSR = 0000200; /* write permission, owner */
+ S_IXUSR = 0000100; /* execute/search permission, owner */
+)
+
type Stat_t struct {
Dev uint32;
Mode uint16;
src/lib/syscall/types_amd64_linux.go
@@ -69,6 +69,24 @@ const (
NAME_MAX = 255;
)
+// Dir.Mode bits
+const (
+ S_IFMT = 0170000; /* type of file */
+ S_IFIFO = 0010000; /* named pipe (fifo) */
+ S_IFCHR = 0020000; /* character special */
+ S_IFDIR = 0040000; /* directory */
+ S_IFBLK = 0060000; /* block special */
+ S_IFREG = 0100000; /* regular */
+ S_IFLNK = 0120000; /* symbolic link */
+ S_IFSOCK = 0140000; /* socket */
+ S_ISUID = 0004000; /* set user id on execution */
+ S_ISGID = 0002000; /* set group id on execution */
+ S_ISVTX = 0001000; /* save swapped text even after use */
+ S_IRUSR = 0000400; /* read permission, owner */
+ S_IWUSR = 0000200; /* write permission, owner */
+ S_IXUSR = 0000100; /* execute/search permission, owner */
+)
+
type Stat_t struct {
Dev uint64;
Ino uint64;
コアとなるコードの解説
このコミットの核心は、os.Dir
構造体に対する新しいメソッドの追加と、それらのメソッドが依存するsyscall
パッケージ内の定数の定義です。
os_types.go
では、Dir
構造体に以下のメソッドが追加されています。
-
IsFifo()
,IsChar()
,IsDirectory()
,IsBlock()
,IsRegular()
,IsSymlink()
,IsSocket()
: これらのメソッドは、Dir
構造体のMode
フィールド(ファイルモードを表す整数値)からファイルタイプを判定します。dir.Mode & syscall.S_IFMT
という式は、Mode
フィールドからファイルタイプを示すビット群を抽出します。syscall.S_IFMT
は、ファイルモードのビット列のうち、ファイルタイプを示す部分(通常は最上位の数ビット)を抽出するためのマスクです。 抽出されたファイルタイプビットが、それぞれのファイルタイプに対応するsyscall
定数(例:syscall.S_IFDIR
)と等しいかどうかを比較することで、ファイルがそのタイプであるかを判定し、bool
値を返します。 これにより、例えばファイルがディレクトリであるかを判定するために、if (dir.Mode & 0170000) == 0040000
のような低レベルなビット操作を直接書く必要がなくなり、if dir.IsDirectory()
のように、より読みやすく、意図が明確なコードを書けるようになります。 -
Permission() int
: このメソッドは、dir.Mode & 0777
というビットAND演算によって、ファイルモードからパーミッション部分のみを抽出します。0777
(8進数)は、所有者、グループ、その他のユーザーに対する読み取り、書き込み、実行の全パーミッションビットがセットされたマスクです。これにより、ファイルタイプ情報を含まない純粋なパーミッション値(例:0644
)が整数として返されます。
types_amd64_darwin.go
とtypes_amd64_linux.go
では、syscall
パッケージ内にファイルモードに関連する定数が定義されています。これらは、各OSのシステムヘッダファイルで定義されているファイルモードビットに対応するGoの定数です。
S_IFMT
: ファイルタイプを抽出するためのマスク。S_IFIFO
,S_IFCHR
,S_IFDIR
,S_IFBLK
,S_IFREG
,S_IFLNK
,S_IFSOCK
: それぞれのファイルタイプを示す定数。S_ISUID
,S_ISGID
,S_ISVTX
: 特殊パーミッションビット(SetUID, SetGID, スティッキービット)を示す定数。S_IRUSR
,S_IWUSR
,S_IXUSR
: 所有者の読み取り、書き込み、実行パーミッションを示す定数。
これらの定数は、os.Dir
のアクセサメソッドがファイルモードを正しく解釈するために不可欠です。OSごとにこれらの定数の値が異なる場合があるため、amd64_darwin.go
とamd64_linux.go
のようにOS固有のファイルで定義されています。
このコミットは、Go言語の標準ライブラリが、低レベルなシステム情報を抽象化し、開発者にとって使いやすいAPIを提供するという設計哲学の一例を示しています。
関連リンク
- Go言語の
os
パッケージのドキュメント (現在のバージョン): https://pkg.go.dev/os - Go言語の
syscall
パッケージのドキュメント (現在のバージョン): https://pkg.go.dev/syscall - Unixファイルパーミッションに関する一般的な情報: https://ja.wikipedia.org/wiki/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%83%91%E3%83%BC%E3%83%9F%E3%83%83%E3%82%B7%E3%83%A7%E3%83%B3
参考にした情報源リンク
- Go言語のGitHubリポジトリ: https://github.com/golang/go
- Unix系OSのファイルモードに関する一般的な知識 (例:
stat
システムコール、sys/stat.h
ヘッダファイルの内容) - Go言語の初期の設計に関する議論やドキュメント (公開前の情報のため、特定のURLは提示できませんが、Go言語の歴史的背景を理解する上で参照しました)
- コミットメッセージと変更されたコードの内容