文件安装在哪里?

时间:2010-02-25 19:53:27

标签: c++ linux mount

给定文件或目录的路径,如何确定该文件的挂载点?例如,如果将/tmp作为tmpfs文件系统挂载,则会给出文件名/tmp/foo/bar,我想知道它存储在tmpfs /tmp的{​​{1}}上

这将是在C ++中,我想避免通过system()调用外部命令。代码应该是健壮的 - 不一定是针对故意篡改,但绝对面对嵌套的挂载点,符号链接等。

我无法找到一个简单的系统调用来执行此操作。看起来我必须自己写支票。这是我正在计划的大致概述。

  1. 将文件名规范化为readlink shell命令。 如何?
  2. 使用/etc/mtab&阅读getmntent()有限公司
  3. 确定文件的相应安装条目。 如何?
  4. #1是一个简单的系统调用,还是我需要读取路径的每个目录组件,如果它们是符号链接,请用readlink(2)解决它们?并自己处理...?看起来像是一种痛苦。

    对于#3,我对如何做到这一点有各种各样的想法。不确定哪个最好。

    1. open()文件,其父级,父级的父级等,使用openat(fd, ".."),直到我到达其中一个/etc/mtab条目。 (我怎么知道我做什么?fstat()他们并比较inode数字?
    2. 在mount表中找到最长的目录名,它是我文件名的子字符串。
    3. 我倾向于第一个选项但是在我编码之前我想确保我没有忽略任何东西 - 理想情况下是一个已经完成此功能的内置函数!

4 个答案:

答案 0 :(得分:18)

这就是我想出来的。事实证明,通常不需要遍历父目录。您所要做的就是获取文件的设备编号,然后找到具有相同设备编号的相应安装条目。

struct mntent *mountpoint(char *filename, struct mntent *mnt, char *buf, size_t buflen)
{
    struct stat s;
    FILE *      fp;
    dev_t       dev;

    if (stat(filename, &s) != 0) {
        return NULL;
    }

    dev = s.st_dev;

    if ((fp = setmntent("/proc/mounts", "r")) == NULL) {
        return NULL;
    }

    while (getmntent_r(fp, mnt, buf, buflen)) {
        if (stat(mnt->mnt_dir, &s) != 0) {
            continue;
        }

        if (s.st_dev == dev) {
            endmntent(fp);
            return mnt;
        }
    }

    endmntent(fp);

    // Should never reach here.
    errno = EINVAL;
    return NULL;
}

感谢@RichardPennington对realpath()的提示,以及比较设备号而不是inode号。

答案 1 :(得分:4)

你可以从realpath开始,然后按照stat查看每个目录,看看它是否在同一台设备上。看起来似乎应该有一种更简单的方法。

<小时/> 编辑:

#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    char *p;
    char path[PATH_MAX];
    struct stat buf;
    dev_t dev;

    if (realpath(argv[1], path) == NULL) {
        fprintf(stderr, "can't find %s\n", argv[1]);
        exit(1);
    }

    if (stat(path, &buf) != 0) {
        fprintf(stderr, "can't statind %s\n", path);
    exit(1);
    }

    dev = buf.st_dev;
    while((p = strrchr(path, '/'))) {
        *p = '\0';
        stat(path, &buf);
        if (buf.st_dev != dev) {
            printf("mount point = %s\n", path);
            exit(0);
        }
   }
    printf("mount point = /\n");
}

感谢分心; - )

答案 2 :(得分:2)

这对我来说对OSX有用,它不提供强大的功能。在C ++中:

struct stat fileStat;
int result = stat(path, &fileStat);
if (result != 0) {
    // handle error
}    

struct statfs* mounts;
int numMounts = getmntinfo(&mounts, MNT_WAIT);
if (numMounts == 0) {
    // handle error
}    

for (int i = 0; i < numMounts; i++) {
    if (fileStat.st_dev == mounts[i].f_fsid.val[0])
        // mounts[i].f_mntonname is the mount path
}

答案 3 :(得分:0)

您应该能够阅读/etc/mtab,解析已装载某些内容的所有位置,并查看您所讨论的任何文件是否位于任何这些位置(或其子目录)中。你不需要任何特殊的系统函数,如果你有挂载点和文件路径作为字符串,那么你可以使用普通的字符串处理函数处理它们。

显然,符号链接可能会给整个过程带来麻烦。包含符号链接的任何文件路径在处理之前都必须转换为其“实际”路径。 希望有一种方法可以在不单独检查文件及其每个父项的情况下执行此操作,但如果必须,可以随时强制执行。您可能希望使用realpath来执行此操作删除符号链接。