2017-08-24 7 views
0

getcwd関数を使用して、アプリケーションの現在の作業ディレクトリを取得しています。 場合によっては失敗し、errnoはENOENTです。私は別のスレッドからgetcwdを呼び出しますが、連続してENOENTに直面することもありますが、理由はわかりません。 上記のリンクでは、ENOENTは「現在の作業ディレクトリがリンク解除されています」という意味です。ディレクトリは存在します。getcwdがerrnoで失敗する理由ENOENT

UPDATE::コードは@Aganjuと@molbdniloからのアドバイスを更新:ここで

は、私が使う機能の抜粋である私はENOENTに直面している場合は

std::string get_working_dir() 
{ 
    char buf[PATH_MAX]; 
    memset(buf, 0, sizeof(buf)); 
    char * result = getcwd(buf, sizeof(buf)); 
    std::string working_path = buf; 
    // Check for possible errors. 
    if (result == NULL) 
    {   
     switch (errno) 
     { 
      case EACCES: 
       break; 
      case EFAULT: 
       break; 
      case EINVAL: 
       break; 
      case ENAMETOOLONG: 
       break; 
      case ENOENT: 
      { 
       if (working_path.empty()) 
       { 
        const char* pwd = getenv("PWD"); 
        working_path = (pwd) ? pwd : ""; 
       } 
       break; 
      } 
      case ERANGE: 
       break; 
      default: 
       break; 
     } 
     return working_path; 
    } 
} 

、私は "PWD" を取得します私はCentOS 5.11とUbuntu 16.04で動作し、CentOSでgetcwdが失敗すると空のバッファを返します。

UPDATE:

私はメインスレッドからの呼び出しは失敗しませんが、私は別のスレッドからの関数を呼び出すとき、それは失敗し、errnoにENOENTであることに気づきました。

+0

おそらく '-f'フラグで' strace'を実行し、どのシステムコールが 'ENOENT'を返すかを観察します。これは何が起こっているのかについての最初の手掛かりになります。 –

+3

最初に 'getcwd'の戻り値をチェックする必要があります。 'getcwd'がヌルポインタを返さない限り、' errno'は無意味です。 – molbdnilo

+0

あなたと@Aganjuが推奨するようにNULLをチェックしました。 CentOS 5では 'getcwd'はNULLを返し、errnoはENOENTです。サンプルコードを更新します。 私が気づいたことの1つは、自分のアプリケーションがマルチスレッドであるため、ENOENTで失敗した呼び出しがメインスレッドから呼び出されなかったことです。 – rboc

答えて

2

molbdniloと言っていたので、最初に戻り値を確認する必要があります。

マニュアルでは、あなたは状態にリンクされています

[...]失敗した場合、これらの関数はNULLを返し、errnoが に設定されているエラーを示す[...]

つまり、にはが存在しない場合、errnoではありません。に設定されていて、これまでに発生した呼び出しに含まれていたものを含みます。

使用char * result = getcwd(buf, sizeof(buf));のようなもの、そしてif (result == NULL) { switch (errno) ...をチェックするなど

+0

私はあなたが推奨するようにNULLをチェックしました。 CentOS 5でgetcwdはNULLを返し、errnoはENOENTです。私は質問を更新しました。 – rboc

1

これは、シェルスクリプトの構文を使用して、我々はマルチプロセスのシーケンス図で説明することができ、次のような状況で発生します

process A      process B 
$ cd ~      $ cd ~ 
user $ mkdir foo    
user $ cd foo 
           user $ rm -rf foo    
user/foo $ pwd 
/home/user/foo 
user/foo $ cd . 
cd: error retrieving current 
directory: getcwd: cannot access 
parent directories: No such file or directory 

Unixライクなオペレーティングシステムのすべてのプロセスには、現在の作業ディレクトリがあります。このディレクトリには、ファイルシステム内のオブジェクトへの参照が格納されています。そのオブジェクトは、そのプロセスが現在のディレクトリを削除するまで空き領域として再利用することはできません。

以上、プロセスAは、~/fooであった以前のディレクトリを保持し続けています。そのパスはディレクトリ構造に存在しなくなりましたが、ディレクトリオブジェクトが引き続き存在します。

getcwdgetcwdシステムコールでは、現在の作業ディレクトリが呼び出し元のプロセスがディレクトリ構造にリンクされていないため、パスがないことがわかり、エラーが報告されます。

pwdシェルコマンドは、getcwdを呼び出さずにシェルが知っているデータを逆流させるだけで機能します。 cd .を試してみると、エラーが発生します(GNU/LinuxシステムでBashで再現され、結果は異なる場合があります)。

+0

私のアプリはシングルプロセスですが、マルチスレッドです。とにかくこれが起こっていますか?スレッドは作業ディレクトリを共有するはずです。 – rboc

+0

POSIXには、 'chdir'システムコールにプロセス全体の副作用があることが間違っています。実際には、マルチスレッドプロセスは起動時に作業ディレクトリを確立し、再度起動しないことを意味します。また、 'chdir'を暗黙的に呼び出す関数は' nftw'などのように避けなければなりません。 – Kaz