代码之家  ›  专栏  ›  技术社区  ›  John Kugelman Michael Hodel

文件装载在哪里?

  •  21
  • John Kugelman Michael Hodel  · 技术社区  · 16 年前

    给定文件或目录的路径,如何确定该文件的装入点?例如,如果 /tmp 安装为 tmpfs 然后指定文件名 /tmp/foo/bar 我想知道它是储存在 临时文件系统 根植于 /tmp公司

    system()

    我找不到一个简单的系统调用来实现这一点。看来我得自己开支票了。这是我计划的大致轮廓。

    1. readlink shell命令。 怎么用?
    2. 阅读 /etc/mtab getmntent()
    3. 怎么用?

    readlink(2) 如果它们是符号链接?和手柄 . .. 我自己好像很痛。

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

    1. open() 文件、其父级、其父级的父级等 openat(fd, "..") 直到我到达一个 /etc/mtab公司 条目( fstat() )
    2. 在mount表中查找最长的目录名,它是我的文件名的子字符串。

    我倾向于第一个选项,但在我编写所有代码之前,我想确保我没有忽略任何东西——理想情况下是一个内置函数,它已经做到了!

    4 回复  |  直到 16 年前
        1
  •  18
  •   John Kugelman Michael Hodel    13 年前

    这就是我想到的。结果发现,通常不需要遍历父目录。您所要做的就是获取文件的设备号,然后找到具有相同设备号的相应装载条目。

    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() ,以及比较设备编号而不是索引节点编号。

        2
  •  4
  •   Richard Pennington    16 年前

    你可以从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");
    }
    

    谢谢你分心;-)

        3
  •  2
  •   Peter Tseng    12 年前

    这在OSX上对我有用,它不提供mntent函数。在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
    }
    
        4
  •  0
  •   bta    16 年前

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

    希望有一种方法可以做到这一点,而不必单独检查一个文件和它的每一个父文件,但是如果必须的话,您可以一直强制执行它。 realpath