読者です 読者をやめる 読者になる 読者になる

by shigemk2

当面は技術的なことしか書かない

pwdコマンド自作 その1

UNIX

pwdでやっていること

  1. ディレクトリを読んで、ディレクトリツリーを上っていく。
  2. 毎回のディレクトリの処理では、"."のiノード番号を記録し、親ディレクトリの中でiノード番号に与えられている名前を参照する。
  3. この処理をルートディレクトリに達するまで続ける。

コード

/* spwd.c:pwdを単純化したバージョン
 *
 * カレントディレクトリからスタートして再帰的にファイルシステムの
 * ルートまで上り、上のディレクトリから順に名前を出力する
 * readdir()を使って個々のディレクトリについての情報を得る
 * バグ: "/"から実行すると空文字列を出力する
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>

ino_t get_inode(char *);
void printpathto(ino_t);
void inum_to_name(ino_t, char *, int );

int main()
{
    printpathto( get_inode( "." ) ); /* ここまでのパスを出力する */
    putchar('\n');
    return 0;
}

void printpathto( ino_t this_inode )
/*
 * this_inodeに対応するディレクトリまでのパスを出力する再帰関数
 */
{
    ino_t my_inode ;
    char its_name[BUFSIZ];

    if ( get_inode("..") != this_inode )
    {
        chdir( ".." );          /* 1つ上のディレクトリへ */

        inum_to_name(this_inode, its_name, BUFSIZ); /* 名前を取得 */

        my_inode = get_inode( "." ); /* 再帰的に */
        printpathto( my_inode );     /* 1つ上のディレクトリ */
        printf("/%s", its_name );     /* までを出力 */
    }                                /* このディレクトリの名前を出力 */
}

void inum_to_name(ino_t inode_to_find, char *namebuf, int buflen)
/* カレントディレクトリから引数のiノード番号を持つファイル */
/* (サブディレクトリ)を探し、名前をnamebufにコピーする */
{
    DIR *dir_ptr;               /* ディレクトリ */
    struct  dirent *direntp;    /* 各エントリ */

    dir_ptr = opendir( "." );
    if ( dir_ptr == NULL ) {
        perror( "." );
        exit(1);
    }

    /* 指定されたiノード番号を持つファイル(サブディレクトリ)を探す */
    while ( ( direntp = readdir( dir_ptr ) ) != NULL )
        if ( direntp->d_ino == inode_to_find )
        {
            strncpy( namebuf, direntp->d_name, buflen);
            namebuf[buflen-1] = '\0'; /* 念の為 */
            closedir( dir_ptr );
            return;
        }
    fprintf(stderr, "error looking for inum %d\n", inode_to_find);
    exit(1);
}

ino_t get_inode( char *fname )
/* ファイルのiノード番号を返す */
{
    struct stat info;

    if ( stat( fname, &info ) == -1 ) {
        fprintf(stderr, "Cannot stat ");
        perror(fname);
        exit(1);
    }

    return info.st_ino;
}