という手順で処理するための(UNIX標準)ライブラリ関数が用意されている。ディレク トリから1つずつ要素が取り出されてできるストリーム(ディレクトリストリームと呼ぶ) が仮想的に構成され、そのストリームを介してディレクトリ要素を受け取ることになる。
ディレクトリ・オープンのライブラリ関数 DIR *opendir(const char *path):
• この関数を使うためにはヘッダファイル <dirent.h> を必要とする。
• opendir( ) が呼ばれると、引数で指定されたディレクトリファイルをオープンし、
ディレクトリストリームへのポインタを関数値として返す。これに失敗した場合は NULLを返す。この関数値は一般ファイルの場合の「ファイル記述子」に相当するも ので、以後ディレクトリファイルからデータを取りこむ際のキーとなる。
• DIR は <dirent.h>の中で定義された構造体である。
• 関数引数のpath は、オープンするディレクトリをフルパスで指定した文字列を表す。
ディレクトリ・クローズのライブラリ関数 int closedir(DIR *dir):
• この関数を使うためにはヘッダファイル <dirent.h> を必要とする。
• closedir( ) が呼ばれると、引数で指定されたディレクトリストリームの領域は解放
されディレクトリがクローズされる。成功すると 0を返し、失敗すると−1 を返す。
• 関数引数 dir の箇所にはディレクトリストリームへのポインタを指定する。
ディレクトリストリームから次の要素を探し出すライブラリ関数 readdir( ):
• 関数プロトタイプは次の通り。
struct dirent *readdir(DIR *dir);
• この関数を使うためにはヘッダファイル <dirent.h> を必要とする。
• readdir( ) が呼ばれると、引数で指定されたディレクトリストリームから次の要素
を探し出し、そこへのポインタを関数値として返す。そして、「次の読み出し位置」を 保持する変数を更新する。要素が無くなった場合、および失敗した場合はNULLを 返す。
• 関数引数 dir の箇所にはディレクトリストリームへのポインタを指定する。
• 関数値のデータ型であるstruct dirent は 次の様に定義された構造体である。
struct dirent {
long d_ino; /* ファイルのi-ノード番号 */
off_t d_off; /* 次の要素へのオフセット */
unsigned short d_reclen; /* このレコードの長さ */
char d_name[NAME_MAX+1]; /* ファイルの名前 */
};
10.7. ディレクトリ操作のライブラリ関数 137
'
&
$
% 補足:
Vine Linux 2.1.5 においては、実際には構造体 struct dirent は<bits/
dirent.h>の中で次の様に定義されている。
struct dirent {
#ifndef USE FILE OFFSET64 ino t d ino;
off t d off;
#else
ino64 t d ino;
off64 t d off;
#endif
unsigned short int d reclen;
unsigned char d type;
char d name[256]; /* We must not include limits.h! */
};
例 10.4 (ディレクトリ内のファイルのリストを表示) ディレクトリファイル内に蓄えら
れているファイル名を列挙するプログラムを次に示す。
[motoki@x205a]$ nl list-directory-contents.c
1 /*************************************************************/
2 /* Operating-Systems/C-Programs/list-directory-contents.c */
3 /*---*/
4 /* ディレクトリ内のファイルのリストを表示するプログラム */
5 /* C.オール「例題で学ぶLinuxプログラミング」ピアソン,8.3.3節 */
6 /*************************************************************/
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <dirent.h>
10 int main(int argc, char *argv[]) 11 {
12 DIR *dir;
13 struct dirent *ptr_to_dir_entry;
14 int num;
15 if (argc != 2) {
16 printf("Give a directory_name as a command parameter.\n");
17 exit(EXIT_FAILURE);
18 }else if ((dir=opendir(argv[1])) == NULL) { 19 perror("opendir");
20 exit(EXIT_FAILURE);
21 } 22 num=0;
23 while ((ptr_to_dir_entry=readdir(dir)) != NULL)
24 printf("%3d : %s\n", ++num, ptr_to_dir_entry->d_name);
25 printf("Given directory contains %d files.\n", num);
26
27 closedir(dir);
28 return 0;
29 }
[motoki@x205a]$ gcc list-directory-contents.c [motoki@x205a]$ ./a.out /
1 : net 2 : opt 3 : dev 4 : srv 5 : media 6 : lib64 7 : lost+found 8 : misc
9 : ..
10 : tmp 11 : proc 12 : usr 13 : home 14 : etc 15 : . 16 : boot 17 : bin 18 : sbin 19 : .autofsck 20 : var
21 : sys 22 : initrd 23 : root 24 : selinux 25 : mnt 26 : lib
Given directory contains 26 files.
[motoki@x205a]$
ここで、
• プログラム18行目 のopendir( )ライブラリ関数で、ディレクトリファイルをオープ ンしディレクトリストリームから情報を取り出す準備をしている。
• プログラム23行目 のreaddir( )ライブラリ関数で、ディレクトリストリームの次の 要素へのポインタを受け取っている。
• プログラム24行目 のd nameは構造体を構成する配列の名前である。この配列にディ レクトリ内のファイルの名前が記録されている。
• プログラム27行目 のclosedir( )ライブラリ関数で、ディレクトリファイルをクロー ズしている。
10.7. ディレクトリ操作のライブラリ関数 139
例 10.5 (ディレクトリ内のファイルのリストを表示2) 先の例10.4ではディレクトリファ イル内に蓄えられている情報だけを使ってファイル名を列挙するだけであったので、この 機能の拡張を次に考える。ディレクトリ内の各ファイルの各種属性をlstat( )システム コールで取り込んで種類、保護モード、サイズも一緒に表示したプログラムを次に示す。
[motoki@x205a]$ nl list-directory-contents2.c
1 /*************************************************************/
2 /* Operating-Systems/C-Programs/list-directory-contents2.c */
3 /*---*/
4 /* ディレクトリ内のファイルのリストを表示するプログラム */
5 /* C.オール「例題で学ぶLinuxプログラミング」ピアソン,8.3.3節 */
6 /* D.A.Curry「UNIX Cプログラミング」アスキー出版局,4.4節 */
7 /*************************************************************/
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <dirent.h>
11 #include <unistd.h>
12 #include <sys/stat.h>
13 int main(int argc, char *argv[]) 14 {
15 DIR *dir;
16 struct dirent *ptr_to_dir_entry;
17 int num, filetype;
18 char filename[256];
19 char *mode[]={"---", "--x", "-w-", "-wx", 20 "r--", "r-x", "rw-", "rwx"};
21 struct stat filestatus;
22 if (argc != 2) {
23 printf("Give a directory_name as a command parameter.\n");
24 exit(EXIT_FAILURE);
25 }else if ((dir=opendir(argv[1])) == NULL) { 26 perror("opendir");
27 exit(EXIT_FAILURE);
28 }
29 printf("Given directory \"%s\" contains following files:\n\n"
30 " mode size(bytes) filename\n"
31 "--- --- ---\n",
32 argv[1]);
33 num=0;
34 while ((ptr_to_dir_entry=readdir(dir)) != NULL) { 35 ++num;
36 sprintf(filename, "%s/%s", argv[1], ptr_to_dir_entry->d_name);
37 if (lstat(filename, &filestatus) < 0) { 38 perror("lstat");
39 fprintf(stderr, " (lstat(%s, &filestatus))\n",
40 filename);
41 continue;
42 }
43 switch (filestatus.st_mode & S_IFMT) { 44 case S_IFREG: filetype=’-’; break;
45 case S_IFDIR: filetype=’d’; break;
46 case S_IFLNK: filetype=’l’; break;
47 case S_IFBLK: filetype=’b’; break;
48 case S_IFCHR: filetype=’c’; break;
49 case S_IFSOCK: filetype=’s’; break;
50 case S_IFIFO: filetype=’p’; break;
51 default: filetype=’?’; break;
52 }
53 printf("%c%s%s%s %10d %s\n",
54 filetype,
55 mode[(filestatus.st_mode>>6) & 07], 56 mode[(filestatus.st_mode>>3) & 07], 57 mode[filestatus.st_mode & 07],
58 filestatus.st_size,
59 ptr_to_dir_entry->d_name);
60 }
61 printf("Totally %d files exist.\n", num);
62 closedir(dir);
63 return 0;
64 }
[motoki@x205a]$ gcc list-directory-contents2.c [motoki@x205a]$ ./a.out ~/Operating-Systems2011
Given directory "/home/motoki/Operating-Systems2011" contains following files:
mode size(bytes) filename
--- --- ---rw-r--r-- 201351 OS-PROJ.log -rw-r--r-- 11871 sec-hardware.tex drwxr-xr-x 4096 Shukketsu
-rw-r--r-- 25199 sec-role-and-structure.tex -rw-r--r-- 108851 sec-UNIX-file-system-PROJ.tex -rw-r--r-- 110109 sec-process-management.tex drwxr-xr-x 36864 Figs
10.7. ディレクトリ操作のライブラリ関数 141
-rw--- 22398 Diff-lecture2011-2009.tex~
-rw-r--r-- 121267 sec-UNIX-file-system.tex~
-rw-r--r-- 34400 sec-how-os-manages-io-devices.tex~
...(途中省略)...
-rw-r--r-- 97624 sec-paging-policy-PROJ.tex -rw-r--r-- 65086 sec-file-management-PROJ.tex -rw-r--r-- 8113 sec-virtual-storage-interface.tex -rw--- 22687 Diff-lecture2011-2009.tex
-rw-r--r-- 51762 sec-getting-process-features-PROJ.tex -rw-r--r-- 73579 sec-pipe-PROJ.tex
-rw-r--r-- 28492 sec-mutual-exclusion-basics.tex~
-rw-r--r-- 62458 OS-lecture.ind
-rw-r--r-- 25202 sec-role-and-structure.tex~
-rw-r--r-- 76589 sec-paging-policy.tex Totally 103 files exist.
[motoki@x205a]$
ここで、
• プログラム43行目 のS IFMTはi-ノードのモード要素の中の「型」の部分を識別する ためのビットマスクである。
• プログラム44〜50行目 の S IFREG, S IFREG, S IFDIR, S IFLNK, S IFBLK, S IFCHR, S IFSOCK, S IFIFOは i-ノードのモード要素中の「型」の部分に来れる値 を表すマクロである。
補足:
Vine Linux 2.1.5での具体的な定義がp.134の補足の中で示されている。
ディレクトリを再度最初から読みたい時のライブラリ関数 void rewinddir(DIR *dir):
• この関数を使うためにはヘッダファイル <dirent.h> を必要とする。
• rewinddir( ) が呼ばれると、引数で指定されたディレクトリストリームの最初の位
置にストリームポインタが戻される。
• 関数引数 dir の箇所にはディレクトリストリームへのポインタを指定する。
現在の作業ディレクトリを知るためのライブラリ関数 getcwd( ):
• 関数プロトタイプは<unistd.h> で次の様に定義されている。
char *getcwd(char *buf, int size);
• この関数を使うためにはヘッダファイル <unistd.h> を必要とする。
• getcwd( ) が呼ばれると、現在の作業ディレクトリの絶対パス名を引数で指定された
領域に格納する。成功するとパス名格納の領域へのポインタを関数値として返し、(格 納領域が小さすぎるなどの理由で)失敗するとNULLを返す。
• 関数引数の bufは パス名を格納するchar型配列へのポインタを表す。
• 関数引数の sizeは 配列bufの大きさを表す。
現在の作業ディレクトリ変更のためのシステムコール chdir( ) と fchdir( ):
• 各々の関数のプロトタイプは<unistd.h> で次の様に定義されている。
int chdir(char *path);
int fchdir(int fd);
• この関数を使うためにはヘッダファイル <unistd.h> を必要とする。
• chdir( ) や fchdir( )が呼ばれると、引数で指定されたディレクトリに作業ディレ クトリを移す。成功すると 0 を返し、失敗すると −1 を返す。
• 関数引数の path は ファイルをフルパスで指定した文字列を表す。
• 関数引数の fd は ファイル記述子を表す。
ディレクトリ作成のためのシステムコール int mkdir(char *path, mode t mode):
• この関数を使うためにはヘッダファイル <unistd.h> と<fcntl.h> を必要とする。
• mkdir( ) が呼ばれると、引数の指定に従ってディレクトリが新たに作成される。成
功すると 0 を返し、失敗すると −1を返す。
• 関数引数の path は、作成するディレクトリを指定した文字列を表す。
• 関数引数の mode は、作成ディレクトリの保護モードを表す。
ディレクトリ削除のためのシステムコール int rmdir(char *path):
• この関数を使うためにはヘッダファイル <unistd.h> を必要とする。
• rmdir( ) が呼ばれると、引数で指定されたディレクトリが削除される。削除するディ
レクトリは空でなければならない。成功すると 0を返し、失敗すると −1 を返す。
• 関数引数の path は、作成するディレクトリを指定した文字列を表す。