Frage

Problem:

Auf einem Linux-Computer möchte ich die Zielzeichenfolge eines Links lesen.Aus der Dokumentation habe ich das folgende Codebeispiel (ohne Fehlerverarbeitung) gefunden:

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);

Das Problem ist, dass sb.st_size 0 für Links auf meinem System zurückgibt.

Wie ordnet man Speicher dynamisch für Readline auf solchen Systemen zu?

Vielen Dank!


Eine mögliche Lösung:

Zum späteren Nachschlagen.Verwenden Sie die Punkte von 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

War es hilfreich?

Lösung

POSIX sagt, dass das Feld st_size für einen Symlink auf die Länge des Pfadnamens im Link gesetzt werden soll (ohne '\0').Das /proc-Dateisystem unter Linux ist jedoch nicht POSIX-kompatibel.(Es gibt mehr Verstöße als nur diesen, z. B. wenn bestimmte Dateien byteweise gelesen werden.)

Sie können einen Puffer einer bestimmten Größe zuweisen, readlink() versuchen und es mit einem größeren Puffer wiederholen, wenn der Puffer nicht groß genug war (readlink() hat so viele Bytes zurückgegeben, wie in den Puffer passen), bis der Puffer groß genug ist.

Alternativ können Sie PATH_MAX verwenden und die Portabilität auf Systeme unterbrechen, bei denen es sich nicht um eine Konstante für die Kompilierungszeit handelt oder bei denen der Pfadname möglicherweise länger ist (POSIX erlaubt dies auch).

Andere Tipps

Die anderen Antworten erwähnen es nicht, aber es gibt die realpath-Funktion, die genau das tut, was Sie wollen, und die in POSIX.1-2001 angegeben ist.

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

von der Manpage:

realpath () erweitert alle symbolischen Links und löst Verweise auf auf /./, /../ und zusätzliche '/' Zeichen in der nullterminierten Zeichenfolge mit dem Namen über den Pfad, um einen kanonisierten absoluten Pfadnamen zu erstellen.

realpath übernimmt bei Bedarf auch die dynamische Speicherzuweisung für Sie.Wieder ein Auszug aus der Manpage:

Wenn aufgelöster_Pfad als NULL angegeben wird, wird realpath () verwendet malloc (3), um einen Puffer von bis zu PATH_MAX Bytes zuzuweisen, um die zu halten Pfadname aufgelöst und gibt einen Zeiger auf diesen Puffer zurück.Der Anrufer sollte diesen Puffer mit free (3) freigeben.

Als einfaches, vollständiges Beispiel:

#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;
}

st_size gibt auf / proc nicht die richtige Antwort.

Stattdessen können Sie PATH_MAX- oder pathconf-Bytes (_PC_PATH_MAX) zuordnen.Das sollte für die meisten Fälle ausreichen.Wenn Sie in der Lage sein möchten, längere Pfade zu verarbeiten, können Sie readlink in einer Schleife aufrufen und Ihren Puffer neu zuweisen, wenn der Readlink-Rückgabewert angibt, dass der Puffer zu kurz ist.Beachten Sie jedoch, dass viele andere POSIX-Funktionen einfach davon ausgehen, dass PATH_MAX ausreicht.

Ich bin ein bisschen verwirrt darüber, warum st_size Null ist. Per POSIX:

Bei symbolischen Links muss das Mitglied st_mode aussagekräftige Informationen enthalten, wenn es mit den Dateitypmakros verwendet wird. Die Dateimodusbits in st_mode sind nicht angegeben. Die Strukturelemente st_ino, st_dev, st_uid, st_gid, st_atim, st_ctim und st_mtim müssen aussagekräftige Werte haben, und der Wert des st_nlink-Elements muss auf die Anzahl der (harten) Links zum symbolischen Link festgelegt werden. Der Wert des Mitglieds st_size wird auf die Länge des Pfadnamens festgelegt, der in der symbolischen Verknüpfung enthalten ist, ohne ein abschließendes Nullbyte.

Quelle: http://pubs.opengroup.org/onlinepubs/9699919799/ Funktionen / lstat.html

Wenn st_size nicht funktioniert, besteht Ihre einzige Möglichkeit darin, einen Puffer dynamisch zuzuweisen und seine Größe weiter zu ändern, solange der Rückgabewert von readlink der Puffergröße entspricht.

Die Manpage für readlink(2) besagt, dass sie stillschweigend abgeschnitten wird, wenn der Puffer zu klein ist.Wenn Sie wirklich unbegrenzt sein möchten (und nichts dagegen haben, einige Kosten für zusätzliche Arbeit zu zahlen), können Sie mit einer bestimmten Zuordnungsgröße beginnen und diese weiter erhöhen und den readlink-Aufruf erneut versuchen.Sie können das Wachstum des Puffers beenden, wenn der nächste Aufruf von readlink dieselbe Zeichenfolge zurückgibt, die er für die letzte Iteration verwendet hat.

Was genau versuchen Sie mit dem lstat zu erreichen?

Sie sollten in der Lage sein, das Ziel mit nur den folgenden zu erreichen

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

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

Wenn Sie versuchen, die Länge der Dateinamengröße zu ermitteln, ist st_size meiner Meinung nach nicht die richtige Variable dafür ... Aber das ist möglicherweise eine andere Frage.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top