6

問題:

Linux マシンで、リンクのターゲット文字列を読みたいと思っています。ドキュメントから、次のコード サンプルを見つけました (エラー処理なし)。

struct stat sb;
ssize_t r;
char * linkname;

lstat("<some link>", &sb);
linkname = malloc(sb.st_size + 1);
r = readlink("/proc/self/exe", linkname, sb.st_size + 1);

問題は、システム上のリンクに対して sb.st_size が 0 を返すことです。

では、そのようなシステムで readline にメモリを動的に割り当てるにはどうすればよいでしょうか?

どうもありがとう!


考えられる解決策の 1 つ:

今後の参考のために。jilles によって作成されたポイントを使用する:

struct stat sb;
ssize_t r = INT_MAX;
int linkSize = 0;
const int growthRate = 255;

char * linkTarget = NULL;

// get length of the pathname the link points to
if (lstat("/proc/self/exe", &sb) == -1) {   // could not lstat: insufficient permissions on directory?
    perror("lstat");
    return;
}

// read the link target into a string
linkSize = sb.st_size + 1 - growthRate;
while (r >= linkSize) { // i.e. symlink increased in size since lstat() or non-POSIX compliant filesystem
    // allocate sufficient memory to hold the link
    linkSize += growthRate;
    free(linkTarget);
    linkTarget = malloc(linkSize);
    if (linkTarget == NULL) {           // insufficient memory
        fprintf(stderr, "setProcessName(): insufficient memory\n");
        return;
    }

    // read the link target into variable linkTarget
    r = readlink("/proc/self/exe", linkTarget, linkSize);
    if (r < 0) {        // readlink failed: link was deleted?
        perror("lstat");
        return;
    }
}
linkTarget[r] = '\0';   // readlink does not null-terminate the string
4

6 に答える 6

7

POSIX によるとst_size、シンボリック リンクのフィールドは、リンク内のパス名の長さに設定する必要があります ( なし'\0')。ただし、/procLinux のファイルシステムは POSIX に準拠していません。(特定のファイルを一度に 1 バイトずつ読み取る場合など、これ以外にも多くの違反があります。)

特定のサイズのバッファーを割り当て、バッファーがreadlink()十分に大きくない場合は、バッファーが十分に大きくなるまで、より大きなバッファーで試行および再試行することができます (readlink()バッファーに収まる数のバイトが返されます)。

あるいはPATH_MAX、コンパイル時の定数ではないシステムや、パス名がそれよりも長い可能性があるシステムへの移植性を使用して壊すことができます (POSIX ではど​​ちらも許可されています)。

于 2012-02-21T22:03:24.450 に答える
3

他の回答では言及されていませんがrealpath、POSIX.1-2001で指定されている、まさにあなたが望むことを行う機能があります。

char *realpath(const char *path, char *resolved_path);

マンページから:

realpath() は、すべてのシンボリック リンクを展開し、/./、/../、および path で指定されたヌル終了文字列内の追加の「/」文字への参照を解決して、正規化された絶対パス名を生成します。

realpath必要に応じて、動的メモリ割り当ても処理します。繰り返しますが、マンページからの抜粋:

resolve_path が NULL として指定されている場合、realpath() は malloc(3) を使用して、解決されたパス名を保持するために PATH_MAX バイトまでのバッファーを割り当て、このバッファーへのポインターを返します。呼び出し元は、free(3) を使用してこのバッファの割り当てを解除する必要があります。

簡単で完全な例として:

#include <limits.h>
#include <stdlib.h>
#include <stdio.h>    

int
resolve_link (const char *filename)
{
  char *res = realpath(filename, NULL);
  if (res == NULL)
    {
      perror("realpath failed");
      return -1;
    }

  printf("%s -> %s\n", filename, res);
  free(res);

  return 0;
}

int
main (void)
{
  resolve_link("/proc/self/exe");
  return 0;
}
于 2014-12-13T15:19:17.640 に答える
1

st_sizeは/procに正しい答えを与えません。

代わりに、PATH_MAXまたはpathconf(_PC_PATH_MAX)バイトをmallocできます。ほとんどの場合、これで十分です。それより長いパスを処理できるようにする場合は、ループ内でreadlinkを呼び出し、readlinkの戻り値がバッファーが短すぎることを示している場合はバッファーを再割り当てできます。ただし、他の多くのPOSIX関数は、PATH_MAXで十分であると単純に想定していることに注意してください。

于 2012-02-21T21:37:22.593 に答える
0

マンページにreadlink(2)は、バッファが小さすぎる場合、サイレントに切り捨てられると書かれています。本当に無制限にしたい場合 (余分な作業に多少のコストを支払うことを気にしない場合) は、特定の割り当てサイズから始めて、それを増やし続け、readlink呼び出しを再試行することができます。readlinkへの次の呼び出しが最後の反復で行ったのと同じ文字列を返すときに、バッファーの拡大を停止できます。

于 2012-02-21T22:09:07.077 に答える
0

なぜst_sizeゼロなのか、ちょっと不思議です。POSIX ごと:

シンボリック リンクの場合、st_mode メンバーには、ファイル タイプ マクロで使用される場合に意味のある情報が含まれます。st_mode のファイル モード ビットは指定されていません。構造体メンバ st_ino、st_dev、st_uid、st_gid、st_atim、st_ctim、および st_mtim は意味のある値を持ち、st_nlink メンバの値はシンボリック リンクへの (ハード) リンクの数に設定されます。st_size メンバの値は、終端のヌル バイトを含まない、シンボリック リンクに含まれるパス名の長さに設定されます。

ソース: http://pubs.opengroup.org/onlinepubs/9699919799/functions/lstat.html

うまくいかない場合、唯一のオプションは、バッファを動的に割り当て、戻り値がバッファサイズと等しいst_size限り、サイズを大きくし続けることだと思います。readlink

于 2012-02-21T22:07:00.967 に答える
-1

lstatで何を達成しようとしていますか?

次のようにターゲットを取得できるはずです

char buffer[1024];
ssize_t r = readlink ("/proc/self/exe", buffer, 1024);
buffer[r] = 0;

printf ("%s\n", buffer);

ファイル名のサイズの長さを取得しようとしている場合、st_sizeがそのための適切な変数ではないと思います...しかし、それはおそらく別の質問です。

于 2012-02-21T21:35:58.897 に答える