ファイルの属性

システム・プログラム

                                       電子・情報工学系
                                       新城 靖
                                       <yas@is.tsukuba.ac.jp>

このページは、次の URL にあります。
http://www.hlla.is.tsukuba.ac.jp/~yas/coins/syspro-2000/2000-05-01 /file-attr.html
あるいは、次のページから手繰っていくこともできます。
http://www.hlla.is.tsukuba.ac.jp/~yas/coins/
http://www.is.tsukuba.ac.jp/~yas/index-j.html

■ファイルの属性

UNIXでは、stat() (あるいは、lstat(), fstat())システム・コールを 用いてファイルの属性を調べることができる。ファイルの属性を調べ、画面に 出力するプログラムを stat.c に示す。
----------------------------------------------------------------------
   1:	/*
   2:	        ystat.c -- stat システム・コールのシェル・インタフェース
   3:	        ~yas/syspro1/file/ystat.c
   4:	        $Header: /home/lab2/OS/yas/syspro1/file/RCS/ystat.c,v 1.4 1998/05/18 13:20:36 yas Exp $
   5:	        Start: 1995/03/07 20:59:12
   6:	*/
   7:	
   8:	#include <sys/types.h>          /* stat(2) */
   9:	#include <sys/stat.h>           /* stat(2) */
  10:	#include <sys/sysmacros.h>      /* major(), minor() */
  11:	#include <stdio.h>
  12:	
  13:	#if     0
  14:	struct  stat {
  15:	        dev_t   st_dev;
  16:	        long    st_pad1[3];     /* reserved for network id */
  17:	        ino_t   st_ino;
  18:	        mode_t  st_mode;
  19:	        nlink_t st_nlink;
  20:	        uid_t   st_uid;
  21:	        gid_t   st_gid;
  22:	        dev_t   st_rdev;
  23:	        long    st_pad2[2];     /* dev and off_t expansion */
  24:	        off_t   st_size;
  25:	        long    st_pad3;        /* future off_t expansion */
  26:	        timestruc_t st_atim;    
  27:	        timestruc_t st_mtim;    
  28:	        timestruc_t st_ctim;    
  29:	        long    st_blksize;
  30:	        blkcnt_t st_blocks;
  31:	        char    st_fstype[_ST_FSTYPSZ];
  32:	        long    st_pad4[8];     /* expansion area */
  33:	};
  34:	#endif
  35:	
  36:	extern  void stat_print( char *path );
  37:	
  38:	main( int argc, char *argv[] )
  39:	{
  40:	        if( argc != 2 )
  41:	        {
  42:	            fprintf( stderr,"Usage:%% %s filename \n",argv[0] );
  43:	            exit( 1 );
  44:	        }
  45:	        stat_print( argv[1] );  /* 引数はファイル */
  46:	}
  47:	
  48:	void stat_print( char *path )
  49:	{
  50:	    struct stat buf ;
  51:	        if( stat( path,&buf ) == -1 )
  52:	        {
  53:	            perror( path );
  54:	            exit( 1 );
  55:	        }
  56:	
  57:	        printf("path: %s\n",path );
  58:	        printf("dev: %d,%d\n",major(buf.st_dev),minor(buf.st_dev) );
  59:	        printf("ino: %d\n",buf.st_ino );
  60:	        printf("mode: 0%o\n",buf.st_mode );
  61:	        printf("nlink: %d\n",buf.st_nlink );
  62:	        printf("uid: %d\n",buf.st_uid );
  63:	        printf("gid: %d\n",buf.st_gid );
  64:	        printf("rdev: %d,%d\n",major(buf.st_rdev),minor(buf.st_rdev) );
  65:	        printf("size: %d\n",buf.st_size );
  66:	        printf("atime: %s",ctime(&buf.st_atime) );
  67:	        printf("mtime: %s",ctime(&buf.st_mtime) );
  68:	        printf("ctime: %s",ctime(&buf.st_ctime) );
  69:	        printf("blksize: %d\n",buf.st_blksize );
  70:	        printf("blocks: %d\n",buf.st_blocks );
  71:	}
----------------------------------------------------------------------

----------------------------------------------------------------------
% ./ystat ystat.c [←]
path: ystat.c
dev: 8,3
ino: 17639075
mode: 0100644
nlink: 1
uid: 1231
gid: 40
rdev: 0,0
size: 1767
atime: Mon May 18 22:20:44 1998
mtime: Mon May 18 22:20:44 1998
ctime: Mon May 18 22:20:44 1998
blksize: 8192
blocks: 4
% /sbin/stat ystat.c [←]
ystat.c:
        inode 17639075; dev 2097155; links 1; size 1767
        regular; mode is rw-r--r--; uid 1231 (yas); gid 40 (lab)
        st_fstype: nfs3
        change time - Mon May 18 22:20:44 1998 <895497644>
        access time - Mon May 18 22:20:44 1998 <895497644>
        modify time - Mon May 18 22:20:44 1998 <895497644>
% []
----------------------------------------------------------------------

この実行結果から次のようなことがわかる。
  1. ファイル名は、ystat.c である。
  2. 存在するデバイスは、メジャー番号8, マイナー番号3で識別される。
  3. アイノード番号は、17639075である。
  4. モードは、0100644である。
  5. リンク数は、1である。
  6. ファイルの所有者のIDは、1231である。
  7. ファイルのグループは、40である。
  8. デバイスの識別子は、メジャー番号0, マイナー番号0である。 (この場合無効。デバイス・ファイルのみ有効。)
  9. ファイルの大きさは、1767バイトである。
  10. 最終アクセス時刻は、atime: Mon May 18 22:20:44 1998 である。
  11. 最終更新時刻は、mtime: Mon May 18 22:20:44 1998 である。
  12. 最終変更時刻は、ctime: Mon May 18 22:20:44 1998である。
  13. 入出力に適したブロックサイズは、8192バイトである。
  14. ディスク中で実際に消費しているのは、4ブロックである。
ここで、モードが8進数で 0100644 (C言語の文法で、0から始まる数は、8進 数)であることから、ファイルの型(普通のファイルかディレクトリかという 情報)を調べることができる。

UNIXのモード

0100644の上位4ビット、つまり、0170000と AND (C言語のでは、 &演算子)をとった結果は 0100000 となる。この値は、普通のファ イル(regular file)を意味する。ディレクトリの場合、0040000 となる。こ れらの数は、 (/usr/include/sys/stat.h)で定義されている。

----------------------------------------------------------------------
#define S_IFMT          0xF000  /* type of file */
#define S_IFIFO         0x1000  /* fifo */
#define S_IFCHR         0x2000  /* character special */
#define S_IFDIR         0x4000  /* directory */
#define S_IFBLK         0x6000  /* block special */
#define S_IFREG         0x8000  /* regular */
#define S_IFLNK         0xA000  /* symbolic link */
#define S_IFSOCK        0xC000  /* socket */


#define S_ISFIFO(mode)  ((mode&S_IFMT) == S_IFIFO)
#define S_ISCHR(mode)   ((mode&S_IFMT) == S_IFCHR)
#define S_ISDIR(mode)   ((mode&S_IFMT) == S_IFDIR)
#define S_ISBLK(mode)   ((mode&S_IFMT) == S_IFBLK)
#define S_ISREG(mode)   ((mode&S_IFMT) == S_IFREG)
#define S_ISLNK(m)      (((m) & S_IFMT) == S_IFLNK)
#define S_ISSOCK(m)     (((m) & S_IFMT) == S_IFSOCK)
----------------------------------------------------------------------
プログラム中では、次のようにしてファイルの型を調べることができる。
----------------------------------------------------------------------
	switch( buf.st_mode & S_IFMT )
	{
	case S_IFREG: 
	    ファイルの時の処理;
	    break;
	case S_IFDIR: ...
	    ディレクトリの時の処理;
	    break;
	....
	}
----------------------------------------------------------------------
あるいは、 に含まれている S_ISREG(), S_ISDIR() というマク ロを用いて、次のように記述する方法もある。
----------------------------------------------------------------------
	if( S_ISREG(buf.st_mode) )
	{
	    ファイルの時の処理;
	}
	else if( S_ISDIR(buf.st_mode) )
	{
	    ディレクトリの時の処理;
	}
----------------------------------------------------------------------

モードの下位9ビット(上の例では、8進数で 644 )は、許可されたアクセス 方法を表している。その9ビットは、3ビットづつに区切られおり、上位から 所有者(owner)、グループ(group)、その他(others)に許可(permission) されているアクセス方式を表している。所有者(owner)の代りに、利用者 (user)という言葉が使われることもある。

各3ビットは次の様なアクセス方法が許可されていることを意味する。

----------------------------------------------------------------------
ls -l	3ビット値	アクセス権
----------------------------------------------------------------------
r	4		読込み可能
w	2		書込み可能
x	1		実行可能(ディレクトリの場合は、検索可能)
----------------------------------------------------------------------

このように、普通のファイルとディレクトリで "x" の意味が異なる。

■練習問題

★練習問題24 ls-lプログラム

stat() システム・コールを用いて ls -l filename と似たような結果を出力 するプログラムを作りなさい。このプログラムの名前を myls-l とする。

ls -l では、3つの時刻のうち、どの時刻が表示されているのかを調べなさい。 また、他の2つの時刻を表示させる方法を調べなさい。

myls-l の結果の表示形式は、ls -l と完全に一致しなくてもよい。たとえば、 時刻の表示は、上の ystat.c の結果と同じでもよい。 localtime()やstrftime() ライブラリ関数 を利用すると、時刻の表示をより簡単に ls -l の 表示に近づけることができるであろう。

uid (st_uid) については、ls -l では、ユーザ名(ログイン名)で表示され る。myls-l では、数字のままでよい。ライブラリ関数 getpwuid() を使えば、 UID からユーザ名を調べることができる。 ~yas/syspro1/proc/proc-uid-print.c にあるuid2uname(), gid2gname() を参 考にするとよい。

プログラムの引数となるファイルの数は、1個とする。複数のファイルについ て、ls -l と同様の表示をするように拡張してもよい。

引数としてディレクトリの名前が与えられた場合にも、ディレクトリの内容で はなくディレクトリ自身の属性を表示する。シンボリック・リンクには対応し なくてもよい。(よって正確には、ls -l filename ではなく、ls -ldL filename である。)

余裕があれば、lstat() と readlink() の、2つのシステム・コールを用いて、 ls -l と同じようにシンボリック・リンクの内容を表示しなさい。

さらに、opendir(3) や scandir(3) を使って、ディレクトリの内容を表示 するようにしてもよい。

★練習問題25 chmod プログラム

ファイルのモードを変更するコマンド chmod に似たコマンドを作りなさい。

★練習問題26 touch プログラム

ファイルの時刻を変更するコマンド touch に似たコマンドを作りなさい。

★練習問題32 アクセス権を調べるプログラム

ファイルに対するアクセス権を調べるプログラムを作りなさい。 たとえば、
% access_check filename user read
では、ユーザ名(または、UID)が user のユーザがfilename で与えられたファ イルを読むことができるかどうかを調べる。user は、番号(UID)かユーザ名で 与える。アクセス方法には、次のようなものがある。


↑[もどる] ←[4月24日] ・[5月01日] →[5月08日] [課題]
Last updated: 2000/04/30 20:54:28
Yasushi Shinjo / <yas@is.tsukuba.ac.jp>