2017-08-28 93 views

回答

1

首先,如果所提供的路徑是一個掛載點,並且該掛載點可能是也可能不是其文件系統的根目錄,那麼您可以使用標準函數進行真正的檢查。

假設你的系統的唯一f_fsid值分配給每個安裝點,您可以使用POSIX-stanard statvfs() functionf_fsid領域比較與其父路徑組件的相關statvfs structure的:

#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); 
} 

所有錯誤檢查留下來作爲練習(這也會讓這個例子變得更長,更難以理解......)。

如果某個路徑的f_fsid與其父代的f_fsid不同,或者路徑本身是根目錄,則傳入的路徑必須是其文件系統的掛載點。請注意,這不一定是文件系統的實際根目錄。例如,主機可以通過NFS導出文件系統,NFS客戶機可以將遠程文件系統中的任何子目錄作爲「本地根」掛載,或者回送掛載可以引用另一個文件系統的子目錄。

+0

謝謝,這在Linux和Mac OS上都能正常工作。我已經糾正了代碼中的兩個小錯誤,我想這些錯誤也會作爲練習留給讀者:) – Andreas

-1

POSIX有一個realpath函數,它返回任何給定路徑的規範路徑(從而消除/解決點,點,鏈接等)。

現在POSIX沒有定義卷,只有來自唯一給定根/的文件名的層次結構。現在,Unix變體能夠在其他環境中安裝文件樹,以在運行時獲得單個樹。沒有標準的方法來「掛載」這些卷,即使mount是一種非常常見的方式,因爲有很多方法可以實現此功能。因此,您必須閱讀OS變體的文檔,以確定如何獲取所有裝入點的列表。

您也可以閱讀Linux function to get mount pointsHow to get mount point information from an API on Mac?

+0

讓,這不回答這個問題,這實際上是問_a路徑實際上是一個安裝point_(根設備目錄只能是根目錄,或有什麼不一樣,安裝設備的根目錄)對不起,但我不得不倒下你的答案。 :/規範路徑不處理根目錄或掛載點,它只消除路徑中嵌入的'/../'和'/./'字符串,並保持其乾淨。 –

1

那麼,你有幾種方法。歷史上,根inode已經有2 inum,所以只需stat(path, &buf);和檢查if (buf.st_ino == 2)

近年來,隨着不同的文件系統類型的增殖,沒有根inode中不必2 INUM同等的保修,所以你必須遵循一種不同的方法:只要檢查給出的路徑和父目錄(只是追加"/.."到路徑)駐留在不同設備(場struct stat信息st_dev

下面的代碼說明了這一:

#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 */ 

FreeBSD系統上執行

$ 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 

PORTABILITY注意

這應該在任何未* X/Linux上實現了stat(2)系統調用工作。 UNIX v7已經實現了這個功能,所以它應該可以在所有可用的unices中找到。

附加註釋

這種方法不適用於實際的文件系統的根目錄(/),因爲工作的父目錄和根目錄都指向相同的inode。這可以通過檢查父節點和子節點的st_ino是否相等來解決。只要改變測試

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 */ 
+0

感謝您的廣泛答覆!我對Linux不太熟悉,所以我不能確定你或Andrew Henle的答案是否是最好的方法。你的答案對安德魯和安德魯的影響有沒有優勢?我沒有足夠的經驗來告訴Linux。 – Andreas

+0

任何方法都不錯。恕我直言,礦區更保守,因爲它只使用舊的unix系統調用,所以它應該更便攜,但其中任何一個都應該同樣有用。我測試過我的,當路徑不是目錄路徑時(文件未找到,例如由於權限導致目錄不能訪問文件),它會正確調度。就我個人而言,我更喜歡追加「/」的方法。 「,而不是在最後一個路徑元素上切割它。在缺少它的系統中,你將無法使用'statvfs(2)'(但它們中很少有) –

相關問題