はじめに

CIFS プロトコルを勉強している.

CIFS プロトコルは, ファイル読み書きのシステムコールを そのままネットワーク上に流したような仕様になっている.

エクスプローラから見れば, ファイルシステムがリモートにあろうが ローカルにあろうが, 意識することなくファイルにアクセスできる. それは, ファイルアクセスをすると, Windows のカーネル・モードにあるリダイレクタが呼び出されて, 適切なデバイスに対してコマンドを発行してくれるから.

つまり, ファイルアクセスの仕組みを理解すれば, CIFS のプロトコルも理解が深まると言うことだ!

ということで, C 言語で システムコールを利用して ファイルアクセスをしてみた.

つごうにより, 環境は ArchLinux だけど.

ファイル作成

やること

/home/tsu-nera/tmp 配下に test というファイルを新規作成する.

touch で作成する

Unix のコマンド touch で作成する.

touch /home/tsu-nera/tmp/test

touch のソースを眺める

GNU coreutils のソースを眺める.

そして,fd_reopen という関数の中で open/close が利用されている. https://github.com/goj/coreutils/blob/master/lib/fd-reopen.c

strace でみてみる

プログラムが使用するシステムコールおよび受け取るシグナルを監視するツール.

strace touch /home/tsu-nera/tmp/test

こうなった.

追記: 書式壊れました.

[sourcecode language=“text” title="" ] execve ("/usr/bin/touch", [“touch”, “/home/tsu-nera/tmp/test”], [/* 50 vars */]) = 0 brk (0) = 0x6ce000 access ("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open ("/usr/local/lib/tls/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) stat ("/usr/local/lib/tls/x86_64", 0x7ffffbbac6d0) = -1 ENOENT (No such file or directory) open ("/usr/local/lib/tls/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) stat ("/usr/local/lib/tls", 0x7ffffbbac6d0) = -1 ENOENT (No such file or directory) open ("/usr/local/lib/x86_64/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) stat ("/usr/local/lib/x86_64", 0x7ffffbbac6d0) = -1 ENOENT (No such file or directory) open ("/usr/local/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory) stat ("/usr/local/lib", {st_mode=S_IFDIR|0755, st_size=4096, }) = 0 open ("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 4 fstat (4, {st_mode=S_IFREG|0644, st_size=166490, }) = 0 mmap (NULL, 166490, PROT_READ, MAP_PRIVATE, 4, 0) = 0x7f042abdd000 close (4) = 0 open ("/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 4 read (4, “\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`\1\2\0\0\0\0\0”, 832) = 832 fstat (4, {st_mode=S_IFREG|0755, st_size=1984416, }) = 0 mmap (NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f042abdc000 mmap (NULL, 3813200, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 4, 0) = 0x7f042a642000 mprotect (0x7f042a7db000, 2097152, PROT_NONE) = 0 mmap (0x7f042a9db000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 4, 0x199000) = 0x7f042a9db000 mmap (0x7f042a9e1000, 16208, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f042a9e1000 close (4) = 0 mmap (NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f042abdb000 mmap (NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f042abda000 arch_prctl (ARCH_SET_FS, 0x7f042abdb700) = 0 mprotect (0x7f042a9db000, 16384, PROT_READ) = 0 mprotect (0x60d000, 4096, PROT_READ) = 0 mprotect (0x7f042ac06000, 4096, PROT_READ) = 0 munmap (0x7f042abdd000, 166490) = 0 brk (0) = 0x6ce000 brk (0x6ef000) = 0x6ef000 open ("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 4 fstat (4, {st_mode=S_IFREG|0644, st_size=2581856, }) = 0 mmap (NULL, 2581856, PROT_READ, MAP_PRIVATE, 4, 0) = 0x7f042a3cb000 close (4) = 0 open ("/home/tsu-nera/tmp/test", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = 4 dup2 (4, 0) = 0 close (4) = 0 utimensat (0, NULL, NULL, 0) = 0 close (0) = 0 close (1) = 0 close (2) = 0 exit_group (0) = ? +++ exited with 0 +++ [/sourcecode]

見にくいので, 統計情報を出力する.

あるディレクトリ配下にファイルを作成すだけでも, 結構な数のシステムコールが呼ばれていることが分かる.

[sourcecode language=“text” title="" ] [tsu-nera]% strace -c touch /home/tsu-nera/tmp/test % time seconds usecs/call calls errors syscall – —- —- — — —— 0.00 0.000000 0 1 read 0.00 0.000000 0 8 4 open 0.00 0.000000 0 7 close 0.00 0.000000 0 4 3 stat 0.00 0.000000 0 3 fstat 0.00 0.000000 0 8 mmap 0.00 0.000000 0 4 mprotect 0.00 0.000000 0 1 munmap 0.00 0.000000 0 3 brk 0.00 0.000000 0 1 1 access 0.00 0.000000 0 1 dup2 0.00 0.000000 0 1 execve 0.00 0.000000 0 1 arch_prctl 0.00 0.000000 0 1 utimensat – —- —- — — —— 100.00 0.000000 44 8 total [/sourcecode]

C 言語 ライブラリで実装してみる

C 言語で ファイル操作を行うために, fopen, fclose を利用する.

[sourcecode language=“c” title="" ] #include <stdio.h> int main (void) { FILE *fp; fp = fopen ("/home/tsu-nera/tmp/test", “w”); fclose (fp); return 0; } [/sourcecode]