fs.c static struct inode* namex(char *path, int nameiparent, char *name)

トップページ
jupiteroak.hatenablog.com


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

static struct inode* namex(char *path, int nameiparent, char *name)
{
  struct inode *ip, *next;

  if(*path == '/')
    ip = iget(ROOTDEV, ROOTINO);
  else
    ip = idup(myproc()->cwd);

  while((path = skipelem(path, name)) != 0){
    ilock(ip);
    if(ip->type != T_DIR){
      iunlockput(ip);
      return 0;
    }
    if(nameiparent && *path == '\0'){
      // Stop one level early.
      iunlock(ip);
      return ip;
    }
    if((next = dirlookup(ip, name, 0)) == 0){
      iunlockput(ip);
      return 0;
    }
    iunlockput(ip);
    ip = next;
  }
  if(nameiparent){
    iput(ip);
    return 0;
  }
  return ip;
}

namex関数は、引数pathで渡されたファイルパスが指定するファイル資源に対応するiノード、または、引数pathで渡されたファイルパスが指定するファイル資源の親ディレクトリに対応するiノードを取得します。

引数 char *path
ファイルパスが保存されているメモリ領域の先頭アドレスです。

引数 int nameiparent
nameiparentが1の時、namex関数はファイルパスが指定するファイル資源の親ディレクトリに対応するiノードを取得します。

引数 char *name
ディレクトリ名(またはファイル名)を保存するメモリ領域の先頭アドレスです。

戻り値 inode* ip または 0
引数pathで渡されたファイルパスが指定するファイル資源に対応するiノードのアドレスが戻り値となります。
ファイルパスが指定するファイル資源を取得できなかった場合は、0が戻り値とまります。


処理の内容

最上位のディレクトリに対応するiノードを取得する

if(*path == '/')
   ip = iget(ROOTDEV, ROOTINO);
else
   ip = idup(myproc()->cwd);

引数pathで指定されたファイルパスの先頭1文字(1バイト)を読み取ります。
*path == '/' が真となる場合→ファイルパスの先頭1文字(1バイト)が “/” の場合は、iget関数を呼び出して、ルートディレクトリに対応するiノードを取得します。
*path == '/' が偽となる場合→それ以外の場合は、idup関数を呼び出して、現在実行しているプロセスのカレントワーキングディレクトリに対応するiノードを取得します。

ファイルパスが指定するファイル資源に対応するiノードを取得する

while((path = skipelem(path, name)) != 0){
    
   ...
    
    if((next = dirlookup(ip, name, 0)) == 0){
      ...
    }
    
    ...
}

skipelem関数を呼び出して引数pathで指定されたファイルパスの先頭からディレクトリ名(またはファイル名)を取得し、dirlookup関数を呼び出してそのディレクトリに対応するiノードを取得する、を繰り返すことで、ファイルパスが指定するファイル資源に対応するiノードを取得します。

ファイルパスの先頭からディレクトリ名を取得する

while((path = skipelem(path, name)) != 0){

skipelem関数を呼び出して、引数pathで指定されたファイルパスの先頭にあるディレクトリ名(またはファイル名)を取得します。
取得したディレクトリ名(またはファイル名)は、アドレスnameで指定されたメモリ領域に格納します。
(path = skipelem(path, name)) != 0 が真となる場合→skipelem関数の戻り値が0ではない場合は、アドレスnameが指定するメモリ領域に格納されているディレクトリ名(またはファイ名)を除いたファイルパス(先頭に/を含まない)が戻り値となります。
(path = skipelem(path, name)) != 0 が偽となる場合→skipelem関数の戻り値が0の場合は、引数pathで指定されたファイルパスにディレクトリ名もファイル名も含まれていないことを示しているので、ループを脱出します。
pathの値は、skipelem関数の戻り値で更新しておきます(pathはアドレス値であり、 *pathはアドレスを使って取得した参照値であることに注意してください)。

親iノードの内容をロードする

ilock(ip);

ilock関数を呼び出して、skipelem関数で取得したディレクトリ名(またはファイル名)に対応しているinodeの上位にあるinode(親inode)のスリープロックを取得します。
次の処理で使用されるip->typeの内容がハードディスクからiノードへロードされていることが保証されていないので、ilock関数を呼び出す必要があります。

親iノードがディレクトリとして利用されていることを確認する

if(ip->type != T_DIR){
       iunlockput(ip);
       return 0;
}

親iノードがディレクトリとして利用されていない場合は、iunlockput関数を呼び出して、iノードのスリープロックを解放し、iノードの参照回数をデクリメントします(iノードの参照回数が0になった場合は、iノードを未使用状態に戻します)。
最後に、0を戻り値にして処理を終了します。

nameiparentのフラグが立っている場合は親iノードをリターンする

if(nameiparent && *path == '\0'){
       iunlock(ip);
       return ip;
}

①nameiparentの値が1、かつ、②ファイルパス先頭の1文字がヌル文字の場合→①nameiparent関数内でnamex関数が呼び出され、かつ、②skipelem関数で取得したnamaがファイル名である場合は、skipelem関数で取得したファイル名に対応しているiノードの親iノードのアドレスを戻り値としてリターンします(pathはアドレス値であり、 *pathはアドレスを使って取得した参照値であることに注意してください)。リターンする前に、iunlock関数を呼び出して、iノードのスリープロックを解放しておきます。

skipelem関数で取得したディレクトリ名に対応するiノードを取得する

 if( (next = dirlookup(ip, name, 0)) == 0){
       iunlockput(ip);
       return 0;
  }
 iunlockput(ip);
 ip = next;

dirlookup関数を呼び出し、skipelem関数で取得したディレクトリ名nameに対応するiノードを親iノードipから取得します。
(next = dirlookup(ip, name, 0)) == 0 が真となる場合→dirlookup関数の戻り値が0の場合→skipelem関数で取得したディレクトリ名nameに対応するiノードを取得できなかった場合は、iunlockput関数を呼び出して、親iノードipのスリープロックを解放・参照回数をデクリメントした後(親iノードの参照回数が0になった場合は、親iノードを未使用状態に戻します)、0を戻り値にして処理を終了します。
(next = dirlookup(ip, name, 0)) == 0 が偽となる場合→dirlookup関数の戻り値が0ではない場合→skipelem関数で取得したディレクトリ名nameに対応するiノードを取得できた場合は、iunlockput関数を呼び出して、親iノードのスリープロックを解放・参照回数をデクリメントした後(親iノードの参照回数が0になった場合は、親iノードを未使用状態に戻します)、取得したiノードnextで変数ipの値を更新します。

ファイル名が不正な値だった場合

if(nameiparent){
  iput(ip);
  return 0;
}

nameiparentの値が1(nameiparent関数内でnamex関数が呼び出された)、かつ、ファイル名が不正な値(ファイル名の後にnull終端文字がないなど)だった場合は、iput関数を呼び出して、iノードの参照回数をデクリメントし(iノードの参照回数が0になった場合は、iノードを未使用状態に戻します)、最後に0を戻り値として処理を終了します。

ファイルパスが指定するファイル資源に対応するiノードのアドレスをリターンする

return ip;