Operating Systems. Exercise 12

I. ファイル情報 (準備課題, 配点無し)

ファイルにはそれぞれパーミッションや更新日時などの情報が付加されており, OSが管理するファイルシステムがユーザにそれらの情報を提供します。


ファイル情報取得インターフェース

C言語にはファイル情報を取得する仕組みが用意されています。
それを使って, ファイルパーミッション, 所有者名, 所属グループ名, ファイルサイズ, 更新日時などの情報を取得することが出来ます。

以下のプログラムの流れを読んで、処理を理解してください。

FileStat.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>

void PrintInfo(char *);

void PrintFileInfo(struct stat *pStat);

void PrintPermission(struct stat *pStat);
void PrintNumDirectories(struct stat *pStat);
void PrintUserInfo(struct stat *pStat);
void PrintGroupInfo(struct stat *pStat);
void PrintSize(struct stat *pStat);
void PrintFileAccessTime(struct stat *pStat);

int main (int argc, char *argv[]) {

  if (argc != 2) {
    fprintf(stderr,"usage:\n\t%s filename or\n\t%s directory_name\n", argv[0], argv[0]);
    exit(1);
  }

  PrintInfo(argv[1]);

  return 0;
}

void PrintInfo(char *sPath) {
  
  //fileStatのアドレスを渡して, fileStatに"sPath"で渡されたファイル情報を格納する
  struct stat fileStat;
  int nStat = stat(sPath, &fileStat);
  
  if (nStat != 0) {
    printf("stat failed.... (parameter=[%s])\n", sPath);
    exit(1);
  }
  
  //与えられた"sPath" が 通常ファイルでもディレクトリでもなければexitする
  if ( !(fileStat.st_mode & S_IFREG) && !(fileStat.st_mode & S_IFDIR) ){
    printf("%s seems neither a regular file nor a directory\n", sPath);
    exit(1);
  }

  printf("FileName = %s\n", sPath);

  PrintFileInfo(&fileStat);

}

void PrintFileInfo(struct stat *pStat) {
  PrintPermission(pStat);
  PrintNumDirectories(pStat);
  PrintUserInfo(pStat);
  PrintGroupInfo(pStat);
  PrintSize(pStat);
  PrintFileAccessTime(pStat);
}

void PrintPermission(struct stat *pStat) {

  char sPermissionString[11] = "----------";

  if (pStat->st_mode & S_IFDIR) sPermissionString[0] = 'd';  //ディレクトリか否か
  if (pStat->st_mode & S_IRUSR) sPermissionString[1] = 'r';  //userに読み込み許可があるか
  if (pStat->st_mode & S_IWUSR) sPermissionString[2] = 'w';  //userに書き込み許可があるか
  if (pStat->st_mode & S_IXUSR) sPermissionString[3] = 'x';  //userに実行許可があるか
  if (pStat->st_mode & S_IRGRP) sPermissionString[4] = 'r';
  if (pStat->st_mode & S_IWGRP) sPermissionString[5] = 'w';
  if (pStat->st_mode & S_IXGRP) sPermissionString[6] = 'x';
  if (pStat->st_mode & S_IROTH) sPermissionString[7] = 'r';
  if (pStat->st_mode & S_IWOTH) sPermissionString[8] = 'w';
  if (pStat->st_mode & S_IXOTH) sPermissionString[9] = 'x';

  printf("\tpermission = %12s\n", sPermissionString);
}

void PrintNumDirectories(struct stat *pStat) {
  //pStatで状態を取得した"パス"の 子ディレクトリ/子ファイルの数("パス"がファイルの場合は1)
  printf("\tdirectories =  %ld\n", (long)pStat->st_nlink);
}

void PrintUserInfo(struct stat *pStat) {

  //uid(ユーザID)に相当するユーザ情報をpPasswdに受け取る
  struct passwd *pPasswd = getpwuid(pStat->st_uid);

  //ユーザ情報のうちユーザ名とuidを出力する
  printf("\tuser  name = %8s  (uid=%d)\n", pPasswd->pw_name, pStat->st_uid);
}

void PrintGroupInfo(struct stat *pStat) {

  struct group  *pGroup = getgrgid(pStat->st_gid);

  printf("\tgroup name = %8s  (gid=%d)\n", pGroup->gr_name, pStat->st_gid);
}

void PrintSize(struct stat *pStat) {
  printf("\tsize = %lld bytes\n", (long long)pStat->st_size);
}

void PrintFileAccessTime(struct stat *pStat) {

  //最終アクセス日時をstruct tm型に変換して受け取る
  struct tm *pLastAccess = localtime(&(pStat->st_atime));    

  //最終更新日時をstruct tm型に変換して受け取る
  struct tm *pLastModify = localtime(&(pStat->st_mtime));    

  //最終ファイル情報修正日時をstruct tm型に変換して受け取る
  struct tm *pLastStatChange = localtime(&(pStat->st_ctime)); 

  printf("\tLast access      = %s", asctime(pLastAccess));
  printf("\tLast modify      = %s", asctime(pLastModify));
  printf("\tLast stat change = %s", asctime(pLastStatChange));

}
      

II. ファイル情報表示 (配点100%)

導入: お馴染みの"ls -l"コマンドは引数として与えられたファイルの情報を表示します

コマンド


    % ls -l FileStat.c
	
結果

-rw-------  1 user  group   3758  8 17 18:08 FileStat.c
	

表示される情報は左から "パーミッション", "子ディレクトリ数"(ファイルの場合1), "所有者名", "所属グループ名",
"ファイルサイズ"(バイト単位), "最終更新月日と時間", "ファイル名"となっています。

課題

stat関数で得た情報を使って, 引数として与えられたファイルの情報を"ls -l"と同じ形式で出力するプログラム"lsl"を 作成してください。
ただし, 引数にはファイルのみが与えられるとします。

:

コマンド

% ./lsl FileStat.c
      
結果

-rw-------  1 user  group   3758  8 17 18:08 FileStat.c
      

補足
struct tm型は以下のメンバ変数を保持しています


    struct tm {
        int tm_sec;        // 秒
        int tm_min;        // 分
        int tm_hour;       // 時
        int tm_mday;       // 日
        int tm_mon;        // 月( 1月=0 )
        int tm_year;       // 西暦年 - 1900
        int tm_wday;       // 曜日( 日=0 )
        int tm_yday;       // 日(年を通して)
        int tm_isdst;      // サマータイムフラグ
    };