Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何检查路径是否指定卷根目录_C_Linux_Macos_Posix_Stdio - Fatal编程技术网

C 如何检查路径是否指定卷根目录

C 如何检查路径是否指定卷根目录,c,linux,macos,posix,stdio,C,Linux,Macos,Posix,Stdio,如何检查给定路径(绝对路径或相对路径)是否使用POSIX或标准C运行时调用指定卷的根目录?理想情况下,该代码应该可以在Linux和Mac OS X上运行。POSIX有一个函数,可以返回任何给定路径的规范路径(从而消除/解析点、点、链接等) 现在POSIX不定义卷,只定义来自唯一给定根的文件名的层次结构。现在Unix变体能够一个接一个地挂载文件树,以便在运行时获得单个树。没有“装载”这些卷的标准方法,即使mount是一种非常常见的方法,因为有很多方法可以实现此功能。因此,您必须阅读操作系统变体的文

如何检查给定路径(绝对路径或相对路径)是否使用POSIX或标准C运行时调用指定卷的根目录?理想情况下,该代码应该可以在Linux和Mac OS X上运行。

POSIX有一个函数,可以返回任何给定路径的规范路径(从而消除/解析点、点、链接等)

现在POSIX不定义卷,只定义来自唯一给定根的文件名的层次结构。现在Unix变体能够一个接一个地挂载文件树,以便在运行时获得单个树。没有“装载”这些卷的标准方法,即使
mount
是一种非常常见的方法,因为有很多方法可以实现此功能。因此,您必须阅读操作系统变体的文档,以确定如何获得所有装入点的列表


您还可以阅读和。

首先,您可以使用标准函数真正检查的是显示的路径是否是装载点,并且该装载点可能是也可能不是其文件系统的根

假设您的系统为每个装载点分配了唯一的
f_fsid
值,您可以使用并将路径组件的相关部分的
f_fsid
字段与其父项进行比较:

#include <stdlib.h>
#include <string.h>
#include <sys/statvfs.h>


int isMountPoint( const char *path )
{
    struct statvfs sv1, sv2;

    char *realP = realpath( path, NULL );

    // if the real path is "/", yeah, it's the root
    if ( !strcmp( realP, "/" ) )
    {
        free( realP );
        return( 1 );
    }

    statvfs( realP, &sv1 );

    // find the parent by truncating at the last "/"
    char *pp = strrchr( realP, '/' );

    // if there is no parent, must be root
    if ( NULL == pp )
    {
        free( realP );
        return( 1 );
    }

    // keep the final / (makes handling things like "/mnt"
    // much easier)
    pp++;
    *pp = '\0';

    statvfs( realP, &sv2 );
    free( realP );

    // if f_fsid differs, it's the root of
    // the mounted filesystem
    return( sv1.f_fsid != sv2.f_fsid );
}
#包括
#包括
#包括
int isMountPoint(常量字符*路径)
{
结构statvfs sv1、sv2;
char*realP=realpath(路径,NULL);
//如果真正的路径是“/”,是的,它是根
如果(!strcmp(realP,“/”)
{
免费(realP);
申报表(1);
}
国家体育场馆(realP和sv1);
//通过在最后一个“/”处截断来查找父级
char*pp=strrchr(realP,“/”);
//如果没有父级,则必须是根
if(NULL==pp)
{
免费(realP);
申报表(1);
}
//保留最后一个选项,以便处理诸如“/mnt”之类的事情
//(容易得多)
pp++;
*pp='\0';
国家体育场馆(realP和sv2);
免费(realP);
//如果f_fsid不同,则它是
//装载的文件系统
返回(sv1.f_fsid!=sv2.f_fsid);
}
所有的错误检查都只是一个练习(这也会使这个示例变得更长、更难理解……)


如果路径的
f_fsid
与其父路径的
f_fsid
不同,或者如果路径本身是根目录,则传入的路径必须是其文件系统的装入点。请注意,这不一定是文件系统的实际根。例如,主机可以通过NFS导出文件系统,NFS客户端可以将远程文件系统中的任何子目录装载为“本地根目录”,或者环回装载可以引用另一个文件系统的子目录。

好的,有几种方法。历史上,根inode的inum为
2
,因此只需
stat(path,&buf)并检查
是否(buf.st_ino==2)

最近,随着不同文件系统类型的激增,无法保证根inode中的inum等于
2
,因此必须采用不同的方法:只需检查给定路径和父目录(只需将
“/…”
附加到路径)是否位于不同的设备中(
st_dev
struct stat的
field
info)

以下代码说明了这一点:

#include <unistd.h>
#include <limits.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>

int is_mount(char *path)
{
    struct stat sdir; /* inode info */
    struct stat spdir; /* parent inode info */
    char buffer[PATH_MAX];
    int res = stat(path, &sdir);
    if (res < 0) return -1;
    if (snprintf(buffer, sizeof buffer, "%s/..", path) >= sizeof buffer) {
            errno = ENAMETOOLONG;
            return -1;
    }
    res = stat(buffer, &spdir);
    if (res < 0) return -1;
    return sdir.st_dev != spdir.st_dev;  /* SEE ADDITIONAL NOTE */
}

int main(int argc, char **argv)
{
    int i;
    for (i = 1; i < argc; i++) {
            int res = is_mount(argv[i]);
            if ( res < 0 ) {
                    fprintf(stderr,
                            "%s: %s (errno = %d)\n", 
                            argv[i], strerror(errno), errno);
                    continue;
            }
            printf("%5s\t%s\n", res ? "true" : "false", argv[i]);
    } /* for */
} /* main */

谢谢,这在Linux和Mac操作系统上都能很好地工作。我已经纠正了您代码中的两个小错误,我想这也是留给读者的练习:)Jean,这并没有回答问题,实际上是问路径是否真的是装载点(根设备目录只能是已安装设备的根目录或相同的根目录)很抱歉,我不得不否决你的答案。:/canonical path不处理根目录或装载点,它只删除路径中嵌入的
/../
/./
字符串,并保持干净。感谢你的广泛回答!我对Linux不太熟悉,所以我无法确定你的或Andrew Henle是否是nswer是最好的方法。你的答案比Andrew或Andrew的答案有什么优势吗?我没有足够的Linux经验告诉你。任何方法都是好的。IMHO mine更保守,因为它只使用旧的unix系统调用,所以它应该更具可移植性,但它们中的任何一个都应该同样有用。我已经测试了我的一个d当路径不是目录路径(例如,文件未找到、不是目录或由于权限而无法访问文件)时,它会正确调度。就我个人而言,我更喜欢在路径上附加“/…”的方法,而不是在最后一个路径元素上剪切它。您将无法使用
statvfs(2)
在缺乏it的系统中(但很少有这样的系统)
$ ismount /home/luis/usr.ports/german/geonext/Makefile /home/luis/usr.ports/german/geonext /home/luis/usr.ports/german /home/luis/usr.ports /home/luis  /home / /var/run/cups /var/run /var pru3.c
/home/luis/usr.ports/german/geonext/Makefile: Not a directory (errno = 20)
pru3.c: Not a directory (errno = 20)
false       /home/luis/usr.ports/german/geonext
false       /home/luis/usr.ports/german
 true       /home/luis/usr.ports
false       /home/luis
false       /home
 true       /             <-- in the above code, this returns false, see ADDITIONAL NOTE.
false       /var/run/cups
 true       /var/run
false       /var
return    (sdir.st_dev != spdir.st_dev)  /* different devices */
       || ( /* sdir.st_dev == spdir.st_dev && ---redundant */ 
               sdir.st_ino == spdir.st_ino); /* root dir case */