给定一个文件或目录的path,我如何确定该文件的安装点? 例如,如果将/tmp
挂载为tmpfs
文件系统,那么给定文件名/tmp/foo/bar
我想知道它存储在以/tmp
根的tmpfs
上。
这将在C + +中,我想避免通过system()
调用外部命令。 代码应该是健壮的 – 不一定是有意的篡改,但肯定是面对嵌套的挂载点,符号链接等。
我一直无法find一个简单的系统调用来做到这一点。 看起来我必须自己写检查。 这是我正在计划的一个粗略的轮廓。
readlink
shell命令规范文件名。 怎么样? getmntent()
&co。读取/etc/mtab
。 对于#1是否有一个简单的系统调用,或者我需要读取path的每个目录组件,并解决它们与readlink(2)
如果他们是符号链接? 并处理.
和..
我自己? 看起来像一个痛苦。
对于#3我有如何做到这一点的各种想法。 不知道哪个是最好的。
openat(fd, "..")
open()
文件,其父文件,父文件的父文件等openat(fd, "..")
直到到达/etc/mtab
条目之一。 ( 我怎么知道我什么时候? fstat()
他们和比较inode号码? ) 我倾向于第一个选项,但在我编写代码之前,我想确保我没有忽略任何东西 – 理想情况下,这是一个内置的函数,已经这样做了!
这是我想出来的。 事实证明,通常不需要遍历父目录。 您只需获取文件的设备编号,然后使用相同的设备编号找到相应的安装条目。
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号码。
你可以从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"); }
感谢分心;-)
这在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 }
你应该能够读入/etc/mtab
,解析出已经挂载的所有位置,看看你的任何文件是否位于任何这些位置(或它们的子目录)中。 你不应该为此需要任何特殊的系统函数,如果你有挂载点和文件路径作为字符串,那么你可以使用普通的字符串处理函数来处理它们。
显然,符号链接可能会使整个过程陷入困境。 包含符号链接的任何文件路径在处理之前都必须转换为“实际”路径。 希望有一种方法可以做到这一点,而不是单独检查一个文件和每个父母,但是如果你必须的话,你总是可以蛮横的。 你可能会想使用realpath
来删除符号链接。