【问题标题】:How to check if a directory is on a local disk or a remote disk in C or Fortran?如何检查目录是在 C 或 Fortran 中的本地磁盘还是远程磁盘上?
【发布时间】:2020-04-28 10:26:06
【问题描述】:

我想在我的 C/Fortran 代码中知道工作目录是在主机本地还是实际远程安装,例如NFS 磁盘?希望在 Windows 和 Linux 上都这样做。

【问题讨论】:

  • 这不是编程语言的特性,而是操作系统的特性。您可以运行 shell 命令来执行此操作,这取决于操作系统。
  • @EugeneSh。 POSIX provides [f]statvfs()。将初始目录的文件系统 ID 与所有已安装文件系统的文件系统 ID 进行比较应该可以工作。而Linux特有的statfs()调用直接提供了文件系统类型,可能就够用了。
  • @AndrewHenle 您也可以挂载 NFS。这会被检测到吗?更新:是的,statfs 似乎不错。
  • 对于 Linux,您可以简单地阅读 /proc/mounts 并扫描当前目录的开头以确定目录的挂载位置。只需在终端中cat /proc/mounts 即可检查文件。
  • @EugeneSh。 statfs() 提供f_type,其中NFS_SUPER_MAGIC 可能就足够了。不过,我还没有彻底测试过。

标签: c


【解决方案1】:

在 Windows 上的 C 中,您可能正在寻找 Windows API 函数GetDriveType。要查找当前工作目录,可以使用函数GetCurrentDirectory。但是,根据文档,只需调用

GetDriveType( NULL );

如果你想检查当前工作目录的驱动器。

我不知道 Fortran 和 Linux 的等效函数是什么。

【讨论】:

    【解决方案2】:

    Linux 解决方案

    首先,您需要找到挂载目录的文件系统。

    除非你想通过路径解析,你可以使用来自the statfs() call的文件系统ID:

    概要

       #include <sys/vfs.h>    /* or <sys/statfs.h> */
    
       int statfs(const char *path, struct statfs *buf);
       int fstatfs(int fd, struct statfs *buf);
    

    描述

    statfs() 系统调用返回有关已挂载的信息 文件系统。 path 是挂载中任何文件的路径名 文件系统。 buf 是一个指向已定义的 statfs 结构的指针 大致如下:

           struct statfs {
               __fsword_t f_type;    /* Type of filesystem (see below) */
               __fsword_t f_bsize;   /* Optimal transfer block size */
               fsblkcnt_t f_blocks;  /* Total data blocks in filesystem */
               fsblkcnt_t f_bfree;   /* Free blocks in filesystem */
               fsblkcnt_t f_bavail;  /* Free blocks available to
                                        unprivileged user */
               fsfilcnt_t f_files;   /* Total file nodes in filesystem */
               fsfilcnt_t f_ffree;   /* Free file nodes in filesystem */
               fsid_t     f_fsid;    /* Filesystem ID */
               __fsword_t f_namelen; /* Maximum length of filenames */
               __fsword_t f_frsize;  /* Fragment size (since Linux 2.6) */
               __fsword_t f_flags;   /* Mount flags of filesystem
                                        (since Linux 2.6.36) */
               __fsword_t f_spare[xxx];
                               /* Padding bytes reserved for future use */
           };
    

    f_type 中可能出现以下文件系统类型:

    ...

    可能足以满足您的目的 - f_type 中的数据可能足以通知您该文件位于本地或远程磁盘上(只要您忽略了NFS 挂载从本地计算机导出的本地文件系统,以及下面提到的其他问题。)

    对于更便携的解决方案,您可以使用POSIX-standardized available-on-Linux statvfs() call 作为给定路径的文件系统 ID:

    概要

       #include <sys/statvfs.h>
    
       int statvfs(const char *path, struct statvfs *buf);
       int fstatvfs(int fd, struct statvfs *buf);
    

    描述

    函数statvfs() 返回有关已挂载的信息 文件系统。 path 是挂载的任何文件的路径名 文件系统。 buf 是指向已定义的statvfs 结构的指针 大致如下:

           struct statvfs {
               unsigned long  f_bsize;    /* Filesystem block size */
               unsigned long  f_frsize;   /* Fragment size */
               fsblkcnt_t     f_blocks;   /* Size of fs in f_frsize units */
               fsblkcnt_t     f_bfree;    /* Number of free blocks */
               fsblkcnt_t     f_bavail;   /* Number of free blocks for
                                             unprivileged users */
               fsfilcnt_t     f_files;    /* Number of inodes */
               fsfilcnt_t     f_ffree;    /* Number of free inodes */
               fsfilcnt_t     f_favail;   /* Number of free inodes for
                                             unprivileged users */
               unsigned long  f_fsid;     /* Filesystem ID */
               unsigned long  f_flag;     /* Mount flags */
               unsigned long  f_namemax;  /* Maximum filename length */
           };
    

    一旦您获得目录的f_fsid 值,您需要找到该文件系统的挂载点。

    Linux provides getmntent() et al for this purpose:

    概要

       #include <stdio.h>
       #include <mntent.h>
    
       FILE *setmntent(const char *filename, const char *type);
    
       struct mntent *getmntent(FILE *stream);
    
       int addmntent(FILE *stream, const struct mntent *mnt);
    
       int endmntent(FILE *streamp);
    
       char *hasmntopt(const struct mntent *mnt, const char *opt);
    
       /* GNU extension */
       #include <mntent.h>
    
       struct mntent *getmntent_r(FILE *streamp, struct mntent *mntbuf,
                                  char *buf, int buflen);
    

    glibc 的功能测试宏要求(请参阅 feature_test_macros(7)):

       getmntent_r():
           Since glibc 2.19:
               _DEFAULT_SOURCE
           Glibc 2.19 and earlier:
               _BSD_SOURCE || _SVID_SOURCE
    

    描述

    这些例程用于访问文件系统描述文件 /etc/fstab 和挂载的文件系统描述文件/etc/mtab

    setmntent()函数打开文件系统描述文件 文件名并返回一个可以被getmntent() 使用的文件指针。 参数类型是所需的访问类型,可以采用 与fopen(3) 的模式参数相同的值。返回的流 应使用endmntent() 而不是fclose(3) 关闭。

    getmntent() 函数读取文件系统的下一行 来自流的描述文件并返回指向结构的指针 包含文件中某一行的细分字段。这 指针指向被覆盖的内存的静态区域 随后调用getmntent()

    addmntent() 函数将mntent 结构mnt 添加到 结束 开放的流。

    endmntent() 函数关闭与 文件系统描述文件。

    hasmntopt() 函数扫描 mntent 结构 mnt 用于匹配 opt 的子字符串。看 &lt;mntent.h&gt;mount(8) 获取有效的挂载选项。

    可重入getmntent_r()函数类似于getmntent(), 但 将struct mount 存储在提供的*mntbuf 中并存储 提供的该结构中的条目所指向的字符串 数组buf,大小为buflen

    mntent结构在中定义如下:

           struct mntent {
               char *mnt_fsname;   /* name of mounted filesystem */
               char *mnt_dir;      /* filesystem path prefix */
               char *mnt_type;     /* mount type (see mntent.h) */
               char *mnt_opts;     /* mount options (see mntent.h) */
               int   mnt_freq;     /* dump frequency in days */
               int   mnt_passno;   /* pass number on parallel fsck */
           };
    

    有关一些代码示例,请参阅Linux function to get mount points

    在您的情况下,您将在 struct mntentmnt_dir 字段中保存的路径上调用 statfs()statvfs() 并获取该文件系统的文件系统 ID,并且当它与您的文件系统 ID 匹配时目录,您将拥有挂载点 - 以及文件系统的所有详细信息。

    您还可以解析文件路径并在从getmntent() 返回的已挂载文件系统中找到与您的目录的规范路径匹配的最长mnt_dir。但在这种情况下,您需要处理跨越文件系统边界的软链接。而且我不确定是否仍然严格禁止指向目录的硬链接 - 如果没有,使用路径名永远无法确定。

    关于回送设备的注意事项

    loopback device 是一种将文件挂载为文件系统的方法。您必须决定是否将安装在环回设备上的文件或目录视为本地文件,或者是否将其追溯到用作环回文件系统的实际文件并使用它来确定您的原始目录是否是本地或远程。

    关于 bind 挂载的注意事项

    Linux 提供了执行bind mounts 的功能,其中一个目录可以“挂载”到另一个位置。这是另一种情况,您必须决定是否需要通过挂载回溯以确定您的原始目录是本地目录还是远程目录。

    【讨论】:

      猜你喜欢
      • 2014-10-27
      • 1970-01-01
      • 2012-05-13
      • 2014-11-27
      • 2011-01-21
      • 2012-11-13
      • 2010-12-31
      • 1970-01-01
      • 2012-07-17
      相关资源
      最近更新 更多