fs.c int dirlink(struct inode *dp, char *name, uint inum)

トップページ
jupiteroak.hatenablog.com


fs.c
https://github.com/mit-pdos/xv6-public/blob/master/fs.c#L551

int dirlink(struct inode *dp, char *name, uint inum)
{
  int off;
  struct dirent de;
  struct inode *ip;

  // Check that name is not present.
  if((ip = dirlookup(dp, name, 0)) != 0){
    iput(ip);
    return -1;
  }

  // Look for an empty dirent.
  for(off = 0; off < dp->size; off += sizeof(de)){
    if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
      panic("dirlink read");
    if(de.inum == 0)
      break;
  }

  strncpy(de.name, name, DIRSIZ);
  de.inum = inum;
  if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
    panic("dirlink");

  return 0;
}

dirlink関数は、引数dpで指定されたiノード内にディレクトリエントリを作成し、引数nameで指定された名前のディレクトリと引数inumで指定された番号を持つiノードを対応させます。

引数 struct inode *dp
ディレクトリエントリが作成されるハードディスク上のiノードを表現したdinode構造体を指定するアドレスです。

引数 char *name
ディレクトリ名となる文字列データの先頭アドレスです。

引数 uint inum
ディレクトリに対応させるiノードのiノード番号です。

戻り値 0 または -1
ディレクトリエントリの作成に成功した場合は、0が戻り値となります。
引数nameで指定された名前のディレクトリが既に存在する場合は、-1が戻り値となります。


処理の内容

iノードdpにディレクトリ名nameを含んだディレクトリエントリが存在しないことを確認する

if((ip = dirlookup(dp, name, 0)) != 0){
    iput(ip);
    return -1;
  }

dirlookup関数を呼び出して、iノードdpにディレクトリ名nameを含んだディレクトリエントリが存在しないことを確認します。
dirlookup関数は、iノードdpからディレクトリ名nameを含んだディレクトリエントリを探し、そのディレクトリ名に対応するiノードを取得します(iノードdpにおいて、ディレクトリ名nameを含んだディレクトリエントリの位置(バイトオフセット)を取得する必要がないので、第3引数を0にしています)。
(ip = dirlookup(dp, name, 0)) != 0 が真となる場合→dirlookup関数の戻り値が0ではない場合→iノードdpからディレクトリ名nameに対応するiノードが取得できてしまった場合は、iput関数を呼び出して、iノードの参照回数をデクリメントし(iノードの参照回数が0になった場合は、iノードを未使用状態に戻します)、-1を戻り値として処理を終了します。

iノードdpから使用されていないディレクトリエントリを探す

 for(off = 0; off < dp->size; off += sizeof(de)){
   ...
  }

iノードdpが所有するデータを、ディレクトリエントリのサイズ分(sizeof(de))ずつ、先頭から順番に読み込み、使用されていないディレクトリエントリ(dirent構造体)を探します(前述のdirlookup関数内でも、これと同じように、iノードdpが所有するデータを ディレクトリエントリのサイズ分(sizeof(de))ずつ 先頭から順番に読み込んで 探しているので、効率が悪い)。

ディレクトリエントリのサイズ分のデータを読み込む

 if(readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
      panic("dirlink read");

readi関数を呼び出して、iノードdpが所有するデータの範囲内において、引数offで指定された位置から、引数sizeof(de))で指定されたディレクトリエントリのサイズ分のデータを読み込み、その読み込んだデータを引数&deを先頭アドレスとするメモリ領域(dirent構造体の変数)に保存します。
readi(dp, (char*)&de, off, sizeof(de)) != sizeof(de)が真となる場合→readi関数がディレクトリエントリのサイズ分(sizeof(de))のデータを読み込めなかった場合は、panic関数を呼び出してメッセージを出力します。

使用されていないディレクトリエントリが見つかった場合

if(de.inum == 0)
      break;

de.inum == 0が真となる場合→ディレクトリエントリに対応するiノードの番号が設定されていない場合→使用されていないディレクトリエントリが見つかった場合は、ループを脱出します。

ディレクトリ名nameを含んだディレクトリエントリを作成する

ディレクトリエントリにディレクトリ名nameを設定する

strncpy(de.name, name, DIRSIZ);

strcpy関数を呼び出して、ディレクトリエントリを表現したdirent構造体のnameメンバ(de.name)に、引数nameで指定された文字列データをコピーします。

ディレクトリエントリにiノードを対応させる

 de.inum = inum;

ディレクトリエントリを表現したdirent構造体のinumメンバ(de.inum)に、そのディレクトリエントリに対応させたいiノードのiノード番号を設定します。

新規にディレクトリエントリを作成する

if(writei(dp, (char*)&de, off, sizeof(de)) != sizeof(de))
    panic("dirlink");

writei関数を呼び出して、引数dpで指定されたiノードへ、新規に作成したディレクトリエントリを書き出します。
writei関数は、引数dpで指定されたiノードが所有するデータブロックの範囲において、引数offで指定された位置へ、dirent構造体deに保存されているデータを書き出します。

0を戻り値としてリターンする

return 0;