Beispiel einer realpath-Funktion in C

Lesezeit: 7 Minuten

Benutzer-Avatar
Ralf

Ich suche ein Beispiel für die Verwendung der Realpath-Funktion in einem C-Programm. Ich kann anscheinend keine im Internet oder in einem meiner C-Programmierbücher finden.

Benutzer-Avatar
pmg

  • Notiz

    • Das realpath() Funktion ist im C-Standard nicht beschrieben
  • Beispielcode

#include <limits.h> /* PATH_MAX */
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    char buf[PATH_MAX]; /* PATH_MAX incudes the \0 so +1 is not required */
    char *res = realpath("this_source.c", buf);
    if (res) { // or: if (res != NULL)
        printf("This source is at %s.\n", buf);
    } else {
        char* errStr = strerror(errno);
        printf("error string: %s\n", errStr);

        perror("realpath");
        exit(EXIT_FAILURE);
    }
    return 0;
}

  • PATH_MAX ist die maximale Länge für einen Pfad. Es ist ein seltsames Gizmo; Es gibt garantiert einen Wert _POSIX_PATH_MAX, der der Mindestwert ist, den PATH_MAX haben kann. Viele Systeme haben jedoch eine <limits.h> Dadurch wird PATH_MAX nicht festgelegt, was bedeutet, dass es keine vorgeschriebene Grenze für die maximale Länge eines Pfads auf der Maschine gibt. Es kann sowieso auch vom Dateisystem abhängig sein. Sie können also mit sysconf() oder mit pathconf() nach einem Wert suchen, oder Sie können vermuten, dass die meisten vernünftigen Leute keine Pfade verwenden, die länger als 1024 Bytes sind, und diese verwenden.

    – Jonathan Leffler

    13. Oktober 2009 um 22:36 Uhr

  • Sie sollten in Betracht ziehen, anzurufen free(res); nach Anruf realpath und Abschluss von res. Wie realpath weist den Rückgabewert im Heap zu. Quelle: man realpath

    – Dschalal Mostafa

    3. März 2016 um 17:44 Uhr

  • @JalalMostafa: POSIX realpath(), wie im Link in meiner Antwort beschrieben, weist keinen Speicher zu. Ich vermute, Ihr System ist nicht POSIX-kompatibel. Anrufe POSIX-konform realpath() mit NULL für das 2. Argument ruft UB.

    – pmg

    3. März 2016 um 19:12 Uhr


  • @JalalMostafa: Es gibt eine neue Version der POSIX-Spezifikation (realpath() in POSIX 2008) dort kann das 2. Argument NULL sein und dann malloc() wird genannt. In meinem Beispiel ist der Puffer ein lokales Array, also kein Grund für einen Aufruf free(). Danke für die Warnung.

    – pmg

    3. März 2016 um 19:22 Uhr

Benutzer-Avatar
oho

Einzeilige Build-Befehlszeile

Minimalistisch, aber es macht den Job!

Bauen

gcc -o realpath -x c - <<< $'#include<stdlib.h>\n#include<stdio.h>\nint main(int c,char**v){puts(realpath(v[1],0));}'

Prüfen

$> ./realpath  ~/../../../usr/./bin/./awk
/bin/gawk 

$> readlink -f ~/../../../usr/./bin/./awk
/bin/gawk

Anforderungen

  • gcc zum Kompilieren und Linken
  • bash für <<< und $' ... \n ... '

Absturz

Meine minimalistische einzeilige Befehlszeile erstellt eine ausführbare Datei realpath das erzeugt a Segmentation fault wenn der Pfad nicht existiert. Anstatt zu schreiben if/else Um dieses Problem in meiner Antwort zu behandeln, habe ich unten einige Links hinzugefügt, damit Sie einen Blick auf die Busybox-Implementierung von werfen können realpath und readlink.


Busybox-Implementierung

Einen vollständigeren Quellcode finden Sie in dieser einfachen Implementierung.

Offizielles Git-Repository

GitHub-Spiegel-Repository

  • /usr/bin/readlink -f erfordert nicht, dass der Pfad existiert. Realpath-API tut dies jedoch. Könnten Sie helfen, zu kommentieren, wie man Readlink in dieser Hinsicht nachahmt?

    – SOBenutzer

    11. November 2017 um 13:05 Uhr

  • Hallo @SOUser. Danke für deine Rückmeldung. Sie haben Recht, meine minimalistische einzeilige Befehlszeile erstellt eine ausführbare Datei realpath das erzeugt a Segmentation fault wenn Pfad nicht existiert. Anstatt zu schreiben if/else Blöcke, um dies in meiner Antwort zu handhaben, habe ich Links hinzugefügt, damit Sie einen Blick auf die Busybox-Implementierung von werfen können realpath und readlink. Ich hoffe, Sie wissen den Busybox-Quellcode zu schätzen. Bitte lassen Sie mich wissen, wenn ich helfen kann. Prost

    – oho

    17. November 2017 um 10:04 Uhr

Benutzer-Avatar
Jonathan Leffler

Was zum realpath() Die Funktion teilt Ihnen den Pfadnamen einer Datei mit, wenn alle symbolischen Links aufgelöst wurden. Es ist nicht unbedingt ein absoluter Pfadname, wenn der von Ihnen angegebene Wert ein relativer Name ist, aber das hängt teilweise davon ab, ob Sie symbolische Links mit absoluten Namen für den Linkwert durchlaufen – wenn Sie dies tun, ist die Ausgabe schließlich ein absoluter Name . Auch, wenn der relative Name bis zum Stammverzeichnis reicht (oder „jenseits“, wie in „../../../../../..“ wenn nur drei Ebenen tief in der Verzeichnishierarchie).

Möglicherweise haben Sie bereits ein ‘realpath’-Programm auf Ihrem Computer. Hier ist die (nicht standardmäßige) Version, die ich geschrieben habe.

/*
@(#)File:           $RCSfile: realpath.c,v $
@(#)Version:        $Revision: 1.3 $
@(#)Last changed:   $Date: 2007/10/23 20:23:44 $
@(#)Purpose:        Command to evaluate realpath(3) on given arguments.
@(#)Author:         J Leffler
@(#)Copyright:      (C) JLSS 2007
@(#)Product:        :PRODUCT:
*/

/*TABSTOP=4*/

#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600
#else
#define _XOPEN_SOURCE 500
#endif /* __STDC_VERSION__ */

#include <unistd.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include "stderr.h"

static const char optstr[] = "hlsV";
static const char usestr[] = "[-hslV] given-path [...]";
static const char hlpstr[] =
    "  -h   Print this help message\n"
    "  -l   Long format: print given-path and real-path\n"
    "  -s   Short format: print just real-path\n"
    "  -V   Print version and exit\n"
    ;

enum { FMT_LONG, FMT_SHORT };
static int format_type = FMT_LONG;

#ifndef lint
/* Prevent over-aggressive optimizers from eliminating ID string */
extern const char jlss_id_realpath_c[];
const char jlss_id_realpath_c[] = "@(#)$Id: realpath.c,v 1.3 2007/10/23 20:23:44 jleffler Exp $";
#endif /* lint */

static int eval_realpath(const char *given)
{
    char realname[_POSIX_PATH_MAX];
    int rc = 0;

    if (realpath(given, realname) == 0)
    {
        rc = -1;
        err_sysrem("failed to resolve real path name for %s\n", given);
    }
    else if (format_type == FMT_SHORT)
        printf("%s\n", realname);
    else
        printf("%s %s\n", given, realname);
    return(rc);
}

int main(int argc, char **argv)
{
    int i;
    int rc = EXIT_SUCCESS;
    int opt;

    err_setarg0(argv[0]);
    while ((opt = getopt(argc, argv, optstr)) != -1)
    {
        switch (opt)
        {
        case 'V':
            err_version("REALPATH", &"@(#)$Revision: 1.3 $ ($Date: 2007/10/23 20:23:44 $)"[4]);
            break;
        case 'h':
            err_help(usestr, hlpstr);
            break;
        case 'l':
            format_type = FMT_LONG;
            break;
        case 's':
            format_type = FMT_SHORT;
            break;
        default:
            err_usage(usestr);
            break;
        }
    }

    for (i = optind; i < argc; i++)
    {
        if (eval_realpath(argv[i]) != 0)
            rc = EXIT_FAILURE;
    }

    return(rc);
}

Ich brauchte es, um eine Software zu testen, die die Sicherheit eines Pfads auswertete, und musste sicher sein, dass mein Code den angegebenen Pfad zu demselben aufgelösten Speicherort wie auswertete realpath() tut. Es wäre wahrscheinlich sinnvoll, es mit einer Option ‚-a‘ zu erweitern, um sicherzustellen, dass Namen absoluten Namen zugeordnet werden (indem dem Ergebnis von vorangestellt wird getcwd() zu relativen Pfadnamen).

(Der zusätzliche Quellcode ist in my SOQ (Stack Overflow Questions)-Repository auf GitHub als Dateien stderr.c, stderr.h und errhelp.c in dem src/libsoq Unterverzeichnis.)

  • Nein, es tut geben Sie unbedingt einen absoluten Pfadnamen an. Die Dokumentation sagt „Die realpath() Funktion abgeleitet werden soll, von dem Pfadnamen, auf den gezeigt wird Dateinameein absoluter Pfadname, der dieselbe Datei benennt, …”

    – Adam Rosenfield

    20. August 2011 um 2:46 Uhr

  • Das ist seltsam; Du hast Recht, aber … ich muss irgendwo auf die falsche Idee gekommen sein. Die Schwierigkeit besteht fast vier Jahre nach dem Schreiben des Codes und meistens zwei Jahre nach dem Schreiben der Antwort darin, zu wissen, woher ich die Fehlinformationen habe. Bei obskuren Systemen sind einige Untersuchungen erforderlich.

    – Jonathan Leffler

    20. August 2011 um 3:08 Uhr

  • Hi. Es ist 2022. Ich versuche, Ihre Antwort zu verstehen. Ich tue gcc -g -Wall reallink1.c stderr.c stderr.h es wird nicht kompiliert. Der Fehler ist undefined reference to err_help’` / @JonathanLeffler

    – jian

    21. Juli um 16:37 Uhr


  • @Mark: Entschuldigung – Sie werden brauchen errhelp.c too , das in meinem SOQ-Repository verfügbar ist, wie im Ende der Frage dokumentiert. Wenn Sie eine andere nicht standardmäßige Datei benötigen, sollte sich die Quelle/der Header im selben Verzeichnis des Repositorys befinden. Wenn etwas ganz fehlt, lassen Sie es mich bitte wissen.

    – Jonathan Leffler

    21. Juli um 18:14 Uhr


1246460cookie-checkBeispiel einer realpath-Funktion in C

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy