【问题标题】:Example of realpath function in CC中的realpath函数示例
【发布时间】:2010-12-06 11:56:05
【问题描述】:

我正在寻找如何在 C 程序中使用 realpath 函数的示例。我似乎在网上或我的任何 C 编程书籍中都找不到。

【问题讨论】:

    标签: c posix realpath


    【解决方案1】:
    • 注意

      • realpath() 函数未在 C 标准中描述
    • 示例代码

    #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 是路径的最大长度。这是一个奇怪的小发明;保证有一个值 _POSIX_PATH_MAX ,它是 PATH_MAX 可能的最小值。但是,许多系统有一个&lt;limits.h&gt; 没有设置 PATH_MAX,这意味着机器上路径的最大长度没有规定的限制。无论如何,它也可以依赖于文件系统。因此,您可以使用 sysconf() 或 pathconf() 查找值,或者您可以猜测大多数理智的人不会使用超过 1024 字节的路径并使用它。
    • 您应该考虑在调用realpath 并从res 结束后调用free(res);。由于realpath 在堆中分配返回值。来源:man realpath
    • @JalalMostafa:POSIX realpath(),如我的答案中的链接中所述,不分配内存。我怀疑您的系统不兼容 POSIX。使用NULL 调用符合POSIX 的realpath() 作为第二个参数调用UB
    • @JalalMostafa:有一个新版本的 POSIX 规范 (realpath() in POSIX 2008),第二个参数可以为 NULL,然后调用 malloc()。在我的示例中,缓冲区是一个本地数组,因此没有理由调用free()。感谢您的提醒。
    【解决方案2】:

    单行构建命令行

    极简主义,但能胜任!

    构建

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

    测试

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

    要求

    • 编译链接
    • 代表 &lt;&lt;&lt;$' ... \n ... '

    崩溃

    我的极简单行命令行构建了一个可执行文件realpath,当路径不存在时会生成一个Segmentation fault。我没有在我的回答中写 if/else blocs 来处理这个问题,而是在下面添加了一些链接,让您查看 realpathreadlink 的 Busybox 实现。


    Busybox 实现

    要获得更完整的源代码,请查看这个简单的实现。

    官方 Git 存储库

    GitHub 镜像仓库

    【讨论】:

    • /usr/bin/readlink -f 不需要路径存在。但是,realpath api 可以。你能帮忙评论一下如何在这方面模仿 readlink 吗?
    • 嗨@SOUser。感谢您的反馈意见。没错,我的极简单行命令行构建了一个可执行文件realpath,当路径不存在时,它会生成一个Segmentation fault。我没有在我的回答中编写if/else blocs 来处理这个问题,而是添加了链接,让您查看realpathreadlink 的Busybox 实现。我希望你喜欢 Busybox 源代码。如果我能提供帮助,请告诉我。干杯
    【解决方案3】:

    realpath() 函数的作用是在解析所有符号链接后告诉您文件的路径名。如果您提供的值是相对名称,则不一定是绝对路径名,但这部分取决于您是否遍历任何具有绝对名称的符号链接作为链接值 - 如果您这样做,那么输出毕竟是绝对名称.此外,如果相对名称遍历到根目录(或“超越”,如“../../../../../..”,当目录层次结构只有三个层次时)。

    您的机器上可能已经有一个“realpath”程序。这是我写的(非标准)版本。

    /*
    @(#)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);
    }
    

    我需要它来测试一些评估路径安全性的软件,并且需要确保我的代码评估给定路径到与realpath() 相同的解析位置。使用“-a”选项扩展它可能是明智的,以确保名称映射到绝对名称(通过将 getcwd() 的结果作为相对路径名的前缀)。

    (stderr.c、stderr.h 的来源可以在网上找到,如果你知道在哪里可以找到。或者联系我 - 查看我的个人资料。)

    【讨论】:

    • 不,它确实必须给你一个绝对路径名。 The documentation 说“realpath() 函数应从 file_name 指向的路径名派生出一个绝对路径名,该路径名命名相同的文件,...”跨度>
    • 这很奇怪;你是对的,但是......我一定是从某个地方得到了错误的想法。编写代码近四年后的困难,以及编写答案后两年的大部分时间,是知道我从哪里得到错误信息。需要对晦涩的系统进行一些调查。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-28
    • 2011-05-12
    相关资源
    最近更新 更多