6
votes

Comment utiliser ReadLink avec une allocation de mémoire dynamique

Problème:

sur une machine Linux, je veux lire la chaîne cible d'un lien. De la documentation, j'ai trouvé l'échantillon de code suivant (sans traitement d'erreur): p> xxx pré>

Le probelm est que sb.st_size renvoie 0 pour des liens sur mon système. P> Alors, comment allouez-en une mémoire de manière dynamique pour readline sur de tels systèmes? p>

Merci beaucoup! P>


une solution possible: H2>

pour référence future. Utilisation des points fabriqués par Jilles: P>

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


0 commentaires

6 Réponses :


-1
votes

Qu'est-ce que vous essayez exactement d'atteindre avec le LSTAT?

Vous devriez pouvoir obtenir la cible avec juste le suivant xxx

si vous essayez de Obtenez la longueur de la taille du nom du fichier, je ne pense pas que ST_SIZE est la bonne variable pour cela ... mais c'est peut-être une question différente.


1 commentaires

Cela n'aide pas comme je cherche un moyen d'allouer de manière dynamique la taille requise. Vous limitez implicitement la longueur des chemins à 1024 caractères. Cela suffira dans la plupart des cas - mais il n'ya aucune garantie.



1
votes

st_size ne donne pas la bonne réponse sur / proc.

à la place, vous pouvez Malloc path_max, ou pathconf (_pc_path_max) octets. Cela devrait suffire à la plupart des cas. Si vous voulez pouvoir gérer les chemins plus longtemps que cela, vous pouvez appeler la lecture de lecture dans une boucle et réaffecter votre tampon si la valeur de retour Readlink indique que le tampon est trop court. Notez que de nombreuses autres fonctions POSIX supposent simplement Path_max suffisent.


1 commentaires

Malheureusement, path_max n'aide pas. Sur mon système, il est 4096 mais sur un système de fichiers ext3, rien ne vous empêche d'avoir des chemins plus longtemps que cela.



7
votes

POSIX dit que le champ st_size pour un lien symbolique doit être réglé sur la longueur du chemin du chemin dans la liaison (sans '\ 0' ). Cependant, le système de fichiers / proc sur Linux n'est pas conforme à POSIX. (Il a plus de violations que celle-ci, comme lors de la lecture de certains fichiers un octet à la fois.)

Vous pouvez attribuer un tampon d'une certaine taille, essayez readlink () et réessayer avec un tampon plus grand si le tampon n'était pas assez grand ( readlink () retourné de nombreux octets comme adapté dans le tampon), jusqu'à ce que le tampon soit suffisamment grand.

Vous pouvez également utiliser path_max et casser la portabilité vers des systèmes où il n'est pas une constante de temps de compilation ou où le chemin peut être plus long que celui (POSIX permet non plus).


2 commentaires

Merci pour le point sur le système de fichiers / proc. Je n'étais pas au courant. Donc, st_size "devrait" travailler n'importe où sauf dans / proc. Il semble que une approche itérative doit être utilisée comme solution de retombée pour le code universel.


@Arikraffaelfunke: Au mieux que le champ st_size est uniquement indicatif de toute façon, car le lien pourrait être modifié entre le lstat () appel et le readlink () appel. Vous devez donc être prêt à gérer la taille étant insuffisante de toute façon.



0
votes

Je suis un peu perplexe quant à pourquoi st_size est zéro. PAR POSIX:

Pour des liens symboliques, l'élément ST_MODE doit contenir des informations significatives lorsqu'il est utilisé avec les macros de type de fichier. Les bits de mode fichier dans ST_MODE sont indéterminés. Les membres de la structure ST_INO, ST_DEV, ST_UID, ST_GID, ST_ATIM, ST_GID, ST_ATIM, ST_CTIM et ST_MTIM doivent avoir des valeurs significatives et la valeur de l'élément ST_NLINK doit être définie sur le nombre de liens (durs) à la liaison symbolique. La valeur de l'élément ST_SIZE doit être réglée sur la longueur du chemin nominal contenu dans la liaison symbolique n'incluant aucun octet nul de terminaison.

Source: http://pubs.opengroup.org/onlinepubs/9699919799/ Fonctions / lstat.html

si st_size ne fonctionne pas, je pense que votre seule option est d'allouer de manière dynamique un tampon et de continuer à le redimensionner aussi longtemps que la valeur de retour de readlink est égale à la taille de la mémoire tampon.


2 commentaires

Même si st_size fonctionne, la destination de liaison pourrait être modifiée entre le lstat () appel et le readlink () appel.


En effet, auquel cas vous devrez détecter la troncature et réessayer.



0
votes

the Manpage pour Readlink (2) dit Trondez silencieusement si le tampon est trop petit. Si vous voulez vraiment être illimité (et ne vous dérangerez pas de payer des coûts pour un travail supplémentaire), vous pouvez commencer par une taille d'allocation donnée et continuer à augmenter et à réapprendre le readlink appel. Vous pouvez arrêter de développer le tampon lorsque l'appel suivant à readlink renvoie la même chaîne qu'elle a fait pour la dernière itération.


0 commentaires

3
votes

Les autres réponses ne le mentionnent pas, mais il y a la fonction realpath code>, qui est exactement ce que vous voulez, qui est spécifié par POSIX.1-2001.

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


1 commentaires

J'aimerais que plus de fonctions de bibliothèque avaient la possibilité d'allouer automatiquement le tampon à cordes. Pourquoi n'est-ce pas?