1

Cプログラムのシンボリックリンクのループを検出しようとしています:

$ ln -s self self
$ ln -s a b
$ ln -s b a

ここに私がこれまでに持っているものがあります:

#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

int 
main(int argc, char *argv[])
{
     struct stat buffer;
     int status;

     if (argc != 2) {
          fprintf(stderr, "error: file name required\n");
          return 0;
     }

     errno = 0;
     status = lstat(argv[1], &buffer);

     if (errno == ELOOP) {
          fprintf(stderr, "loop found");
     }

     return 1;
}

私は次のようにプログラムを実行しています:

$ findloops self
$ findloops a

私が間違っていることは何か分かりますか?

これは宿題ではありません。

ここから着想を得ました

4

4 に答える 4

1

問題は、' lstat()' がシンボリック リンクとそのプロパティを調べ、シンボリック リンクが実際に存在することです。

呼び出しを ' stat()' に置き換えると、ELOOP エラーが発生します。これは、シンボリック リンクの遠端にある情報を取得しようとしますが、ELOOP 条件のために見つけることができません。

失敗を示すerrnoことを確認した後にのみテストする必要があります。status本物のシステム コールでは、呼び出しが成功したときに errno が設定されることはほとんどありませんが、ライブラリ関数では、呼び出しが成功しても errno が設定されていることがわかります。たとえば、一部の標準 I/O ライブラリの実装では、errno == ENOTTY関数呼び出しが成功した後でも保持できます。このコードは、ファイル記述子が端末を表しているかどうかをチェックし、そうでないことを示すために errno が設定されていますが、関数が成功したため、チェックすることは正当ではありませんerrno

于 2009-12-13T18:52:32.797 に答える
1

返されたバッファを見てみましょう。lstat のドキュメントによると、バッファには関連する 2 つの項目が含まれています。

  • st_ino - ファイルの i ノード (この番号は、Linux ファイル システム上の各ファイルおよびすべてのディレクトリに固有のものですが、同じ i ノード番号が異なるファイル システムに表示される可能性があることに注意してください)。
  • st_dev - ファイルが現在存在するデバイス。

要素ごとにこれら 2 つの項目 + リンクが配置されているディレクトリを以前にアクセスした要素として含むリストを作成すると、ループを検出できます。また、それらが作成されたディレクトリを離れるときは、それらをポップオフすることを忘れないでください.

私は、ELOOP があなたが考えている値であるとは確信していません。thisによると、クラスパスで許容される最大リンクを識別しますが、どのリンクが最初にループしたかはわかりません。

このページのドキュメントには、「ELOOP: パス名の変換中にシンボリック リンクが多すぎます。」

于 2009-12-13T18:05:12.363 に答える
0

コードをいじった後、lstat(2) の機能またはバグを見つけたようです。stat と fstat でもある lstat のマニュアル ページによると、stat と lstat の違いは次のとおりです。

stat() は、パスが指すファイルを統計し、buf を埋めます。

lstat() は stat() と同じですが、path がシンボリック リンクの場合、参照先のファイルではなく、リンク自体が stat される点が異なります。

私はあなたのプログラムを取り、それで少し遊んだ。リンクを確認するために、lstat、stat、および fopen を使用しました。コードは以下です。要するに、stat と fopen の両方がリンクを適切に検出しましたが、lstat は失敗しました。これについては説明がありません。

以下のプログラムは、「ln -s bar bar」として作成されたファイル bar で実行され、次の出力が得られました。

./foo ./bar
Errno as returned from lstat = 0
Errno as returned from stat = 92
loop found
Errno as returned from fopen = 92
loop found

コード:

#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

int
main(int argc, char *argv[])
{
     struct stat buffer;
     int status;
     int savedErrno1;
     int savedErrno2;
     int savedErrno3;
     FILE *theFile;

     if (argc != 2) {
          printf("error: file name required\n");
          return 0;
     }

     errno = 0;
     status = lstat(argv[1], &buffer);
     savedErrno1 = errno;

     printf("Errno as returned from lstat = %d\n", savedErrno1);

     if (savedErrno1 == ELOOP) {
          printf("loop found\n");
     }

     errno = 0;
     status = stat(argv[1], &buffer);
     savedErrno2 = errno;

     printf("Errno as returned from stat = %d\n", savedErrno2);

     if (savedErrno2 == ELOOP) {
          printf("loop found\n");
     }

     errno = 0;
     theFile = fopen(argv[1], "w");
     savedErrno3 = errno;

     printf("Errno as returned from fopen = %d\n", savedErrno3);

     if (savedErrno3 == ELOOP) {
          printf("loop found\n");
     }

     return 1;
}
于 2009-12-14T02:24:03.790 に答える
0

ELOOP は、ループがあることを意味する必要はありません。次のように、ソースからターゲットへのシンボリック リンクが多すぎることも意味します。

a -> b -> c -> d -> e ... -> z

これを十分な回数行うと、OS カーネル (特に Linux の場合) は、リンクがすべて有効で循環的でない場合でも、リンクをたどろうとするのをあきらめます。

man 2 readlink にも興味があるかもしれません。

于 2009-12-13T20:40:56.103 に答える