Transcript ppt file

システムプログラミング
第7回、8回
ファイルシステム関連の
システムコール
情報工学科 篠埜 功
ディレクトリファイル
ディレクトリファイルには、ファイル名からiノード
番号(iノードはindex nodeの略)への対応がファ
イルの数だけ格納されている。(実際のデータ
構造は、ハッシュテーブルや線形リストなど。)
ファイルのiノード番号は
$ ls –li
等、lsに-iオプションを与えると確認できる。
ファイルシステムの実装
ファイルシステムは、ブートブロック、スーパーブロック、
iノードリスト、データブロックの4つの領域から構成され
る。
• ブートブロック --- OSを起動するためのプログラムを
格納。
• スーパーブロック --- ファイルシステムの大きさ、ブ
ロック数、ブロックサイズ、空きブロック、iノードリストの
大きさ、空きiノードリストの情報などを格納。
• iノードリスト --- iノードのリスト。iノードには各ファイル
の種類、所有者、permission、変更時刻、ファイルサイ
ズ、データブロック内の場所などが格納されている。
• データブロック --- ファイルの中身が格納されている。
openシステムコール
ファイルからのデータの読み込み、ファイルへのデー
タの書き込みをするには、まずファイルをオープンす
る。これを行うのがopenシステムコールである。
openシステムコールを使う場合、types.h, stat.h,
fcntl.hをインクルードする。
openシステムコールの引数
openシステムコールは、パス名、フラグの2引数ある
いは、これらにモードを加えた3引数で呼び出す。
パス名で指定されたファイルを、フラグに従ってオープ
ンし、ファイル記述子(file descriptor, int型)を返す。フ
ラグがO_CREATの場合、モードが必要。
ファイル記述子は、利用者ファイル記述子表の
何番目かを表す。
オープンするとは、データ入出力用のバッファを確保し、
利用者ファイル記述子表中の1つの構造体を割り当て、
構造体の各メンバーに初期値を設定することをいう。
利用者ファイル記述子表についてはdupシステムコー
ルの説明時に説明する。
openシステムコールの代表的なフラグ
O_RDONLY --- 読みだしのみ
O_WRONLY --- 書き込みのみ
O_RDWR --- 読み出し、書き込みの両方を行う
O_CREAT --- ファイルが存在しない場合作成する。第3引
数のモードでファイルのpermission等を設定する。
これらのフラグはfcntl.hに記述されているので、インク
ルードして使う。
モード
openシステムコールの第3引数に与えられるモー
ドでは、ファイルのpermissionおよびセットユーザID
ビット、セットグループIDビット、stickyビット(/tmpな
どで使用)を12桁の2進数で表す。代表的な数値
はstat.hでマクロとして提供されているが、数値で
直接指定してよい。
(例)S_IRWXU --- 所有者はread, write, executeが
できる。
その他にもあるが、
$ man –S 2 open
で確認。
readシステムコール
ファイルからデータを読み出すためのシステムコー
ルがreadシステムコールである。
unistd.hをインクルードする。
ファイル記述子、データ格納領域へのポインタ、読み
出しバイト数を引数に与える。返り値は読み出したバ
イト数。これが0のときはファイルの最後まで読み終
わっているということになる。
readシステムコールが正常終了しなかった場合は-1
が返ってくる。このときはperrorでエラーメッセージを
表示する。
writeシステムコール
ファイルへデータを書き込むためのシステムコール
がwriteシステムコールである。
unistd.hをインクルードする。
ファイル記述子、書き込むデータが格納されている
領域へのポインタ、書き込みバイト数を引数に与える。
返り値は書きこんだバイト数。
writeシステムコールが正常終了しなかった場合は-1
が返ってくる。このときはperrorでエラーメッセージを
表示する。
closeシステムコール
closeシステムは、ファイル記述子を引数に受け取
り、そのファイルをクローズする。
クローズするとは、入出力用バッファを解放し、利
用者記述子表内の構造体を解放することをいう。
(同時に開けるファイル数に制限があるので、閉じ
るのがよい。閉じなければプロセス終了時に閉じ
られる。)
例1:テキストファイルの先頭にaを書き込む
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main (void) {
int fd, n;
char c = 'a';
if ((fd = open ("test", O_WRONLY))
== -1) {
perror ("open");
exit(1);
}
/* 続き */
if (write (fd, &c, 1) != 1){
perror ("write");
exit(1);
}
if (close (fd) == -1) {
perror ("close");
exit(1);
}
return 0;
}
演習課題2
• テキストファイル(ファイル名はtestなど)の先
頭文字を読み取り、その文字を2文字目に書
きこむ。Openシステムコールの第2引数(フラ
グ)はO_RDWRにする。
read, writeシステムコールを呼ぶたびに、読
み書きのためのポインタ(kernel内部のポイン
タ)が1つ進むので、readで読み取ったあとに
writeで書き込めば、2文字目に書きこまれる
ことになる。
例2
/* テキストファイル全部表示 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
int main (int argc, char * argv []) {
int fd, n;
char c;
if (argc!=2) {
fprintf (stderr,
"Usage: %s filename\n",
argv[0]);
exit(1);
}
/* 続き */
if ((fd = open (argv[1], O_RDONLY))
== -1) {
perror ("open");
exit(1);
}
while ((n = read (fd, &c, 1) ) > 0)
printf ("%c", c);
if (n==-1) {
perror ("read");
exit(1);
}
if (close (fd) == -1) {
perror ("close");
exit(1);
}
return 0;
}
複数バイトずつ読み込む
readシステムコールで、複数バイト単位で読み込む
こともできる。
readシステムコールの返り値は、
(1) 正の場合、読み込んだバイト数を表す。
(2) 0 の場合、ファイルの内容を既に全部読み終
わっていたことを表す。
(3) -1の場合、システムコールが何らかの理由で正
常終了しなかったことを表す。この場合はライブラリ
関数perrorでエラー内容を表示するべき。
例えば、ファイルサイズ260バイトのファイルを100バ
イト単位で読み込むと、最後の回は60バイト(返り値
も60)になり、その後は返り値は0となる。
例3
/* テキストファイル全部表示 */
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main (int argc, char * argv []) {
int fd, n;
char c[100];
if (argc!=2) {
fprintf (stderr,
"Usage: %s filename\n",
argv[0]);
exit(1);
}
/* 続き */
if ((fd = open (argv[1], O_RDONLY))
== -1) {
perror ("open");
exit(1); }
while ((n = read (fd, c, 100) ) > 0)
if (write (1, c, n) != n) {
perror ("write"); 1は標準出力
exit(1); };
if (n == -1) {
perror ("read");
exit(1); }
if (close (fd) == -1) {
perror ("close");
exit(1); }
return 0;
}
例4
/* 標準入力を標準出力へ書きだ
す*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
int main (int argc, char * argv []) {
int fd, n;
char c[100];
while ((n = read (0, c, 100) ) > 0)
if (write (1, c, n) != n) {
perror ("write");
exit(1);
};
/* 続き */
if (n == -1) {
perror ("read");
exit(1);
}
return 0;
}
0は標準入力
1は標準出力
新しいファイルの作成
新しいファイルの作成は、openシステムコールの
第2引数のフラグにO_CREATを指定する。(ファイ
ルが存在していたらそのファイルを使う。存在しな
ければファイルを新しく作る。)
他のフラグと組み合わせて指定できる。組み合わ
せるときはビットのor演算子|を用いる。
例えば、write onlyで開きたい場合は、openシス
テムコールの第2引数に
O_WRONLY | O_CREAT
を指定する。さらに、存在しているときに内容を消
したいときは O_TRUNCをさらに追加で指定する。
例5
/* 入力をファイルへ書きだす*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
int main (int argc, char * argv []) {
int fd, n;
char c[100];
if (argc!=2) {
fprintf (stderr,
"Usage: %s filename\n",
argv[0]);
exit(1);
}
/* 続き */
if ((fd = open (argv[1],
O_WRONLY | O_CREAT |
O_TRUNC, 0644)) == -1) {
perror ("open");
0は標準入力
exit(1); }
while ((n = read (0, c, 100) ) > 0)
if (write (fd, c, n) != n) {
perror ("write");
exit(1); };
if (n == -1) {
perror ("read");
exit(1); }
if (close (fd) == -1) {
perror ("close");
exit(1); }
return 0;
}
演習課題3
実行ファイルの引数に2つのファイル名を受けとり、
1つ目のファイル(存在するファイル)のコピーを2つ
目のファイルに作成するプログラムを作成せよ。(コ
ピーコマンド)
コピー先ファイルのopen時の引数
第2引数 --- O_WRONLY | O_CREAT | O_TRUNC
第3引数 --- 0644(8進表記)
とせよ。これにより、コピー先のファイル名が存在し
ていたら、内容が消去されてから書き込まれる。
レポート課題3
catコマンドの以下の機能を、システムコール(open,
close, read, write)を使って実装せよ。
引数無しの場合 --- 標準入力を標準出力へコピー
引数がある場合(1個以上のファイル名を引数にと
る) --- それらのファイルの内容を結合したものを
標準出力に書き出す。
catコマンドを使った場合と挙動を比較し、同じであ
ることを確認したのち提出すること。
レポートの提出方法
□ 下記のファイルを作成し、提出
• kadai3.c, kadai3.txt
□ 提出方法
システムプログラミング講義用の課題提出用フォルダ内に
あるkadai3というフォルダの中に自分の学籍番号を名前と
するフォルダを作成し、その中に上記ファイルを置く。
kadai3.txt内に学籍番号、氏名、日付、および作成したプロ
グラムの簡単な説明を記載する。
□ 提出期限
12月6日の23:59まで。締め切り後に提出した場合、成績へ
の反映を保証しない。
参考: ライブラリ関数を使った場合
#include <stdio.h>
void filecopy (FILE *fpin,
FILE *fpout)
{
int c;
while ((c = getc(fpin))
!= EOF)
putc (c, fpout);
}
この実装では1バイトず
つコピーしている。複数
バイトまとめて読み込ん
で書き込んだ方が速い。
int main (int argc, char * argv []) {
FILE *fp;
if (argc==1)
filecopy (stdin, stdout);
else
while (--argc > 0)
if ((fp = fopen (*++argv, "r"))
== NULL) {
printf ("cat: can't open %s\n", *argv);
return 1;
} else {
filecopy (fp, stdout);
fclose (fp);
}
return 0;
}