[apue] Linux / Windows 系統上只能建立不超過 PATH_MAX / MAX_PATH 長度的路徑嗎?

来源:https://www.cnblogs.com/goodcitizen/archive/2020/07/14/13178034.html
-Advertisement-
Play Games

這個最大路徑長度是為了方便程式編寫?還是說底層的文件系統就只能支持這麼長的路徑呢?本文為你揭開謎底 ...


問題的提出

在處理文件系統路徑的時候,我們一般會先開闢一塊記憶體區,用來接收路徑、或者拼接好路徑傳遞給系統調用。這是因為路徑在各個系統上都有最大長度限制,在 Windows 上這個值是 MAX_PATH,一般不能超過 260;在 Linux 上這個值是 PATH_MAX,一般不能超過 4096 (或者通過 pathconf (_PC_PATH_MAX, ...) 來獲取,但是一般也是 4096),就像下麵這段典型的代碼:

 1 int main ()
 2 {
 3 #ifdef WIN32
 4     char buf[MAX_PATH + 1] = { 0 };
 5     if (GetModuleFileNameA(NULL, buf, MAX_PATH) == 0)
 6     {
 7         printf("get current module path failed, errno %d", GetLastError());
 8         return -1;
 9     }
10 #else
11     char buf[PATH_MAX + 1] = { 0 };
12     if (readlink("/proc/self/exe", buf, PATH_MAX) < 0)
13     {
14         printf("read exe path failed, errno %d", errno);
15         return -1;
16     }
17 #endif
18 
19     printf("current executable file path: %s\n", buf);
20     return 0; 
21 }

 

它用來獲取當前可執行文件的完整路徑。在 Windows 與 Linux 上分別調用了 GetModuleFileName 與 readlink 系統調用,且事先在棧上分配了接收完整路徑的記憶體區 buf。最後將成功獲取的路徑列印到控制台。在兩種系統上,輸出分別如下:

Windows

current executable file path: E:\code\apue\02.chapter\Release\path_max.exe

 Linux

current executable file path: /home/yunhai/code/apue/02.chapter/path_max

 

其它與路徑相關的調用也是類似的。那麼問題來了,這個最大路徑長度是為了方便程式編寫 (不然需要動態分配記憶體,且需要兩次調用,其中一次用於獲取最終的路徑長度),還是說底層的文件系統就只能支持這麼長的路徑呢?

問題的驗證

為了弄清楚這個問題,我專門寫了一個測試程式:

path_max.c

  1 #ifdef WIN32
  2 #  ifndef _WIN32_WINNT            // 指定要求的最低平臺是 Windows Vista。
  3 #  define _WIN32_WINNT 0x0600     // 將此值更改為相應的值,以適用於 Windows 的其他版本。
  4 #  endif
  5 #include <windows.h> 
  6 #include <direct.h> 
  7 #else 
  8 #include <limits.h>
  9 #include <unistd.h> 
 10 #include <fcntl.h> 
 11 #include <errno.h> 
 12 #include <sys/stat.h> 
 13 #endif 
 14 #include <string.h>
 15 #include <stdio.h> 
 16 #include <stdlib.h> 
 17 #include <time.h>
 18 
 19 void get_random_name (char *name, int len, int level)
 20 {
 21   int i, n; 
 22   sprintf (name, "%d", level); 
 23   n = strlen (name); 
 24   for (i=n; i<len; ++ i)
 25     name[i] = rand () % 26 + 'a'; 
 26 
 27   name [len] = 0; 
 28 }
 29 
 30 int main (int argc, char *argv[])
 31 {
 32   int dir_len = 0, file_len = 0; 
 33   char *name = 0; 
 34   int ret = 0, level = 0; 
 35 #ifdef WIN32
 36   int name_max = MAX_PATH; 
 37   int path_max = MAX_PATH; 
 38   HANDLE fd = 0; 
 39 #else 
 40   char const* path = "/"; 
 41   int name_max = pathconf (path, _PC_NAME_MAX); 
 42   int path_max = pathconf (path, _PC_PATH_MAX); 
 43 #endif 
 44 
 45   printf ("NAME_MAX = %d, PATH_MAX = %d\n", 
 46     name_max, path_max); 
 47 
 48   // add 1 (/) to 10 to be conveniently to compute how low the path is with level.
 49   dir_len = 9; 
 50   file_len = 100; 
 51 
 52   srand (time(0)); 
 53   name = (char *) calloc (1, (dir_len > file_len ? dir_len : file_len) + 1); 
 54   if (name == 0)
 55     return -1; 
 56 
 57 
 58   do
 59   {
 60     get_random_name (name, dir_len, ++level); 
 61 #ifdef WIN32
 62     //ret = _mkdir (name); 
 63     //if (ret == -1)
 64     ret = CreateDirectory(name, NULL); 
 65     if (!ret)
 66     {
 67       printf ("CreateDirectory %s failed, errno = %d\n", name, GetLastError ()); 
 68       break; 
 69     }
 70 #else 
 71     ret = mkdir (name, 0777); 
 72     if (ret == -1)
 73     {
 74       printf ("mkdir %s failed, errno = %d\n", name, errno); 
 75       break; 
 76     }
 77 #endif 
 78     
 79     printf ("mkdir %s\n", name); 
 80 #ifdef WIN32
 81     //ret = _chdir (name); 
 82     //if (ret == -1)
 83     ret = SetCurrentDirectory(name); 
 84     if (!ret)
 85     {
 86       printf ("SetCurrentDirectory %s failed, errno = %d\n", name, GetLastError ()); 
 87       break; 
 88     }
 89 #else 
 90     ret = chdir (name); 
 91     if (ret == -1)
 92     {
 93       printf ("chdir %s failed, errno = %d\n", name, errno); 
 94       break; 
 95     }
 96 #endif 
 97 
 98     //printf ("change to that dir\n"); 
 99     get_random_name (name, file_len, level); 
100 #ifdef WIN32
101     fd = CreateFile (name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, 0); 
102     if (fd == INVALID_HANDLE_VALUE)
103       printf ("open %s failed, errno = %d\n", name, GetLastError ()); 
104     else 
105     {
106       printf ("open %s OK.\n", name); 
107       CloseHandle (fd); 
108     }
109 #else 
110     int fd = open (name, O_RDWR | O_CREAT, 0644); 
111     if (fd == -1)
112       printf ("open %s failed, errno = %d\n", name, errno); 
113     else 
114     {
115       printf ("open %s OK.\n", name); 
116       close (fd); 
117     }
118 #endif 
119   } while (1); 
120 
121   free (name); 
122   return 0; 
123 }

 

這個小程式很簡單,每次創建一個目錄,切換進去,創建一個文件。這樣周而複始,直到出錯退出。目錄名長度固定為 9,這樣加上目錄分隔符(/ 或 \)就正好湊成 10,方便之後根據目錄深度計算路徑總長度;文件名長度固定為 100,也是為了方便計算路徑總長度。每個名字都是由 26 個字母隨機組成的,同時將目錄深度 (level)記錄在名字開始。例如第 10 級目錄可能長這樣:“10jmvrfqv”,前面的數字 10 明確的標識了目錄層級,同理,文件名前面也是層級數字,也是為了方便計算。好了,我們分別在兩個系統上跑一下這個測試程式。

1. Windows 上的結果 ( Win10 x64)

NAME_MAX = 260, PATH_MAX = 260
mkdir 1tdobxciu
open 1gybhgvdtngozbkzvcuvpnitcpntxgtjhasljfycfowuuqmcvvitsthzdxpckttobaqtccxeabfmnvhoeknyjifabnynkrjwzhiq OK.
mkdir 2wafsehgp
open 2ssywxcafcvpuppgxjcpctjkleftvyhwpuzydlcaaxkbsgumljccmokznqpkvliklndweyegqxvmrmtcrfwzqyllezvneztvqwma OK.
mkdir 3vmkjwgrp
open 3bclyodmcwjgzmokchhkrmharodswgmpbusxozgqogaguvppohpthetfgqxrmihdjjmqsxvdzgondfsirxfmqbmgmexdnbdjyrqr OK.
mkdir 4xmvhqrfh
open 4hclzbqzoniuuolhumysibxonqutbpqgvroamdwdorhypsfkrkyskqykdukfrngtfipgjidvazgsvdfejofbjqqwpthkfxzgwubw OK.
mkdir 5rwoxiiwh
open 5sdeemddmvkhszsubkojdemrconicercdpdcmsmitbbuxowvsqbfghagpwkgmdrytzfnafoqvwsktiwdkjskfukxtxjeknctdjcm OK.
mkdir 6fnmlhdor
open 6vjrqxecbutxcospyzihwjabulwzbvbwimubvvchdxgyhqfjebjnpbbhvtwrkjlowmzbpoqkshwjbzoqysxfthztefvzwgarrdon OK.
mkdir 7sbvhcsxw
open 7ddmdylgkhghdeefydnjfsmiyxwutewbmujsppdezpoamtwodvqvkyaeswywbfnvjctofiaftmkiwapbjawuhjvuqsmefjpfgbew OK.
mkdir 8dwhpsgaj
open 8xepfibfufsaefmghnjukuddbqhyijunkazscfjxkznnylylpcaiauwyrzcfixbjfguvimzwrabcnvxomkaelrwtgnhsjxpiwmii OK.
mkdir 9wmpqcalh
open 9ldugmypucabxtjnpxqdvinxtevztnspuakrwwhebpshzsgbkedvmxbibkwyaoxctfelwjsglvdwjfjffuleijofuoinnrdcdymf OK.
mkdir 10vlwydie
open 10jihhaxrcpsviddxserikiiyrtbiwdumzdsyhkkodreimjxivkpnnxxtgpuathmqatlajmfueupwsdwjhyferopxiqggkywccvz OK.
mkdir 11awvhauw
open 11ypsctazqpuebetmzzgrzasmjmzppymtdabgcajahhwuwilzxlgvpupuksrjtmigjogjyqxhczuunlknxupfixnyxlyjsdhgwuf OK.
mkdir 12pdznsnw
open 12easlcjvcdudtktfkseedbtlbvnjhjtlchtjbbshmjbdsnpifidqjwsttalzwlyjezixtghwortsusrifigbxhpznmiigtvviym OK.
mkdir 13pvvjtcb
open 13lbpsmpbwyzzcnjlixarmvbxpqeketgycbduhzlhhakxykncmxwhmgqrwigcywiehemmhlinrhxnxbktentpvnlazrzgniwgcnf OK.
mkdir 14jrhanvs
open 14nlvfzgxyfzekthrzidzoeugldefwnxlelbntfetdnxvxkcupkpnzxhytidycrstkchdojzrsdjxclkvfgvmmsenysyyinkylsd OK.
mkdir 15yilwbim
open 15dhjbeoeybggfrjpstbyobosrmigtfhmpbajgwhjgczgklphxweefjoliwbuabyxyfsnzjzpiaxdagfbkujrqistslqkffqmilx OK.
mkdir 16owgedmp
open 16cqauvpdzsghgmzdbdxaqdclrvuyophifemvsoygwuhbtlkkmwmwxekwcxgmauagexxtyirthfgjbztmutljstjiwcbwmntkfri failed, errno = 3
mkdir 17xljxtht
open 17umkwtdbxiayekrljssfnxgvcmytthwevlmrxptivqmvwrkpqkvxoircuwadhkyidoaydlvnnafejpssqdewcymluzmrwrrkwmn failed, errno = 3
mkdir 18aywtihk
open 18ynydjmncmakzoezcupoeqfiahsunxhqvczbuapntehglrrhubpbydnnpnbpjdschmrkzkkpvgfajemsfsvofsjoclijforjkex failed, errno = 3
mkdir 19qsvtxwm
open 19qpfdrjgnxthljturhvuymuoqctsmixxrircoievqpgrnxpzufozwvpsjocdxfhjodpfzljbgegutfsquaehjoaswqhwtsqbgmh failed, errno = 3
mkdir 20vzvuovy
open 20zqqxsfnxrccsubxwevfffunrxfugkovltzidalrmppjjyrbnohxgmwnmwcseijuhzabngyfodgodnblmvhmvnmkvqfijucfqfz failed, errno = 3
mkdir 21idgwupz
open 21vlkqahypwulaaykizzvqviqztswdwikvloswluydfyqmgjcaixqqrilsrjireprfrvbgfvspulfmnuksbvsnfkdncybuhxddtw failed, errno = 3
mkdir 22plbyhbe
open 22rbekcixmxcohnvqlyhlppmgqtpsgsjwxhuwlmhnzspkbvdrnzechjbjsglzajiadiqguutgfjfkaqdtfqeevpcrsejiiotytse failed, errno = 3
mkdir 23vggwvra
open 23tlbobatwbdpaxouojluctxqyddllqedqbeotpkkxgddristpprablooxlomgvneixubhxhemtlvipqwzzfgqcxjtdltytpialw failed, errno = 3
mkdir 24dkpkfup
open 24fujnicyzpudgnsuzcqkkgihsousejefcuepnkkxdpdxbxxfryeglrmikgxxckazfokmdrgttnqxavphpoekagfbenjyuxpfntu failed, errno = 3
CreateDirectory 25aajjgcq failed, errno = 206

 

我是在 G:\ 根目錄運行這個程式的,跑到第 16 級目錄時,CreateFile 失敗返回了,錯誤碼為 3 (ERROR_PATH_NOT_FOUND:系統找不到指定的路徑),對於文件創建失敗,這裡忽略,所以程式繼續運行;跑到第 25 級目錄時,CreateDirectory 也失敗返回了,錯誤碼為 206 (ERROR_FILENAME_EXCED_RANGE:文件名或擴展名太長),因為不能再繼續了,所以整個程式終止。看了一下,到 16 級目錄時整個路徑是這樣:

 

總長度達到 162,此時如果想再創建文件的話,總長度會升至 162 + 1 + 100 = 263  > MAX_PATH,所以接下來的文件創建失敗了。然後再看下到 24 級目錄時路徑的樣子:

 

總長度達到 243,如果再加上一個目錄的長度的話,應該是253 < MAX_PATH,按理說應該還可以容納一個目錄的創建,但是我實地在這個目錄下麵嘗試創建目錄,得到了這樣的錯誤:

 

如果是創建文件的話,會發現輸入一定長度的文件名之後,就輸入不了了:

 

這個長度目前是 16 (算上尾碼 .txt 4個字元),加上之前目錄的長度 243,總長度為 243 + 1 + 16 = 260,正好等於 MAX_PATH。可見,對於 Windows 而言,這個 MAX_PATH 就是底層文件系統的限制,再怎麼玩也玩不出這個杠杠。嘗試切換 CreateDirectory / SetCurrentDirectory  實現為 _mkdir / _chdir,看看有什麼不同 :

line 62-65

    ret = _chdir (name); 
    if (ret == -1)
    //ret = SetCurrentDirectory(name); 
    //if (!ret)

line 81-84

    ret = _mkdir (name); 
    if (ret == -1)
    //ret = CreateDirectory(name, NULL); 
    //if (!ret)

 

重跑上面的例子,會得到完全一樣的結果。

2. Linux 上的結果 (neokylin x64)

一開始我是在 CentOS i686 環境上跑的,沒想到一陣跑之後再回來看,虛擬機桌面居然重置了,所有 shell 都退出了,沒有截到任何輸出,無奈只好採用另一個平臺了。在這個中標麒麟的環境跑完了全程:

$ ./path_max
NAME_MAX = 255, PATH_MAX = 4096
mkdir 1rkxtumwh
open 1tovmschzmqujtonfqbqyfomyykrtwqcrezfxbmypesyygmfxpvxvjmvkwnfudhnhgsghgfwkzxkgjpfamcxwotimgniluvucpbl OK.
mkdir 2vijihgsn
open 2rkuswxpuniccqrkbliwpzzaxhkfqqzgklackzrgpclrscduqnsfnrikasrqkswuexwqwqwlshekkigaxyhkrpwrjniuieqodnea OK.
mkdir 3fanxiuju
open 3cqwzqdmivizeyjygopureytlajkkdtehlciegumddnhdxgjnxfedfaofjysmtytfbbjjyxmdmtgjbrwywdddfrkopcclbxqcabn OK.
mkdir 4yazbmsjy
open 4wawuybydgrowjqyutxmxynkypjcbelzaowwoxwsgqiczabtuaftyuezjpbmvomxekutjsnpixuhxxctxhnwdtvmiybemnbrzxmk OK.
mkdir 5sbcaywkx
open 5torqwgobzlqjlrnygrrhqdrigvletvbmjufhcvldjbnuscuavlhmqawwwhcpegeqalzfgkirnvmfaghvuojkpghlnlcsrgkurjz OK.
mkdir 6aujthffp
open 6howeinoseubrjntbgclavxzxrjraqwrzmqdudrphnsaxhtaovootlqqebheteysqoxntpccewcbevcstqimbacfbklwqjqixovs OK.
mkdir 7fzujwwnc
open 7upunhebiffpircfhmxsllpespacnxpptglgnrjxyoohgqopclhqzxuroutdtkumshufydexusgcjwtnhbdiaxaquvvnircaywgy OK.
mkdir 8cmxwffao
open 8btdlwhtygtqaplqxcszcofbsuyqzeqphmssizmjgfziwlyvpsvsjcvbwtsxzkmhwhzhinqovrztezpusmodqjepeyoejdnhkoos OK.
mkdir 9cgjxyiqe
open 9jhydvmgovlfaltguwvegjubndkmbufhdoghmupasahuoackzxohijiwmukpopwueedqbsstvzpjbrtcokkyvuujrfahwwbcdeue OK.
mkdir 10xmzunod
open 10rfytviftdcqmtxmatlewqkqujfvdsjgjqffnpkgtoyhhvwkrhqnxaftkmqphbysrdxeukmpylxigtuxckmbmuwyimopnmkgrjk OK.

……

mkdir 1341932sc
open 1341932rlcbgduqybifdacrgopzdnulnwxjtrlldpmltibrjlzolbhuqytvnpgbmgmhzzscpfniprbbearsezmuxhrnwaqkgcsfb OK.
mkdir 1341933kk
open 1341933qrzyhsckxcbpgcdcckupgufrchjjivvbnvbwndgmgjdomgroqndzjiqnrbwbwuclpejejrtrbwgndzdvoguxqmkhpikoc OK.
mkdir 1341934nz
open 1341934ttlyecrwdpcssdvqrdmovzaeqipeneggxrgbvxzzpbthgrzxwmnsnnwdylilpotohasczrdovzybqxzmjmewcdaaokngy OK.
mkdir 1341935gu
open 1341935hgmjgenwzmuaesbsbozaqccsqmfwmnttufcclrykfvnjnocqebswduovgvusjnlduqhghhspcfypuciafaxivlgdhcwqr OK.
mkdir 1341936jv
open 1341936lzerjlkaqryhndpoisltnwzqfdoxuysfzyzkklkccljqozgyrrrgpsyvvnupnpxonwbzjlblyldomjndcglszlpwyjony OK.
mkdir 1341937le
open 1341937ojfnsspftcjhouwtxderepgcqrqfsdjgmqvejmkcovlcpivonbfttnvjhmqzpahcqeibruffrrijbfxojfhcuelbqdcgd OK.
mkdir 1341938lk
open 1341938wquzhrfoiyytzerpnyyrscewvhadnmplejkncrblpaeqgxhtxhkqkoohxokkczvikgvnzxarxghderybyktkajrxybkca OK.
mkdir 1341939fl
open 1341939lnganfaecgnhmehqftjpvthvtkfvlkiyypynuarzggitnsjsluhhpqckbjgotootfogcoxduglptfylrvuaklevondeit OK.
mkdir 1341940sc
open 1341940bgiduigqotghzgssbmuozylpnqtvjlzktipnqxggrmnsshkwvekvevmtngqwtqjnaacsyiyruljpstlnzxkfuxyhfodyg OK.
mkdir 1341941ol
open 1341941gpqypywgvhpkbkxrlubqoaovfeaelprrghqvimbdwspzemqpgshwsvrabrgmixgohyjpmmuigjikxybfsibnfunjltvws OK.
mkdir 1341942dk failed, errno = 28

 

中間輸出比較多,就省略了,只顯示前後十幾行內容。我是在 /home/vmware/code/apue/02.chapter 目錄下運行這個程式的,跑到 1341942 級目錄時,mkdir 失敗返回了,錯誤碼為 28 (ENOSPC:No space left on device)。總的目錄路徑長度達到 34 + 1341941 * 10 = 13419444,最深層的一個文件總路徑長度達到 34 + 1341941 * 10 + 100 = 13419544,都遠遠大於 PATH_MAX (4096)了。此時我在運行程式的目錄新建文件或目錄,都會失敗。

$ mkdir abc
mkdir: 無法創建目錄"abc": 設備上沒有空間

$ touch abc
touch: 無法創建"abc": 設備上沒有空間

 

所以可以肯定的一點是,Linux 上的 PATH_MAX 並不是底層文件系統對路徑最大長度的限制,只是一種便於程式編寫的常量。那路徑的最大長度到底由什麼決定呢?看了上面 ENOSPC 的錯誤碼,我第一反應是硬碟空間滿了,然而在查看了磁碟剩餘空間後,我否決了這個可能性。下麵是我在執行測試程式前後分別記錄的 df 輸出。

 

可以看到所在的 /home 掛載點使用比例激增 (8%~22%),但是也沒有達到 100%,所以磁碟空間還是比較充足的,很可能只是 inode 用光了(?)。不管怎樣,本質上都是一種資源限制,這使得程式員可以在 Linux 上創建比較長的文件路徑,比 Windows 提供了更大的靈活性。但是這樣長的路徑並不被所有程式所識別,例如,我在剛纔創建測試目錄的地方,遞歸列出所有文件,輸出如下:

$ ls -R
.:
1rkxtumwh  Makefile  name_max.c  path_max    path_max.o    path_max.vcxproj
apue.o     name_max  name_max.o  path_max.c  path_max.sln

./1rkxtumwh:
1tovmschzmqujtonfqbqyfomyykrtwqcrezfxbmypesyygmfxpvxvjmvkwnfudhnhgsghgfwkzxkgjpfamcxwotimgniluvucpbl
2vijihgsn

./1rkxtumwh/2vijihgsn:
2rkuswxpuniccqrkbliwpzzaxhkfqqzgklackzrgpclrscduqnsfnrikasrqkswuexwqwqwlshekkigaxyhkrpwrjniuieqodnea
3fanxiuju

./1rkxtumwh/2vijihgsn/3fanxiuju:
3cqwzqdmivizeyjygopureytlajkkdtehlciegumddnhdxgjnxfedfaofjysmtytfbbjjyxmdmtgjbrwywdddfrkopcclbxqcabn
4yazbmsjy

./1rkxtumwh/2vijihgsn/3fanxiuju/4yazbmsjy:
4wawuybydgrowjqyutxmxynkypjcbelzaowwoxwsgqiczabtuaftyuezjpbmvomxekutjsnpixuhxxctxhnwdtvmiybemnbrzxmk
5sbcaywkx

./1rkxtumwh/2vijihgsn/3fanxiuju/4yazbmsjy/5sbcaywkx:
5torqwgobzlqjlrnygrrhqdrigvletvbmjufhcvldjbnuscuavlhmqawwwhcpegeqalzfgkirnvmfaghvuojkpghlnlcsrgkurjz
6aujthffp

./1rkxtumwh/2vijihgsn/3fanxiuju/4yazbmsjy/5sbcaywkx/6aujthffp:
6howeinoseubrjntbgclavxzxrjraqwrzmqdudrphnsaxhtaovootlqqebheteysqoxntpccewcbevcstqimbacfbklwqjqixovs
7fzujwwnc

./1rkxtumwh/2vijihgsn/3fanxiuju/4yazbmsjy/5sbcaywkx/6aujthffp/7fzujwwnc:
7upunhebiffpircfhmxsllpespacnxpptglgnrjxyoohgqopclhqzxuroutdtkumshufydexusgcjwtnhbdiaxaquvvnircaywgy
8cmxwffao

./1rkxtumwh/2vijihgsn/3fanxiuju/4yazbmsjy/5sbcaywkx/6aujthffp/7fzujwwnc/8cmxwffao:
8btdlwhtygtqaplqxcszcofbsuyqzeqphmssizmjgfziwlyvpsvsjcvbwtsxzkmhwhzhinqovrztezpusmodqjepeyoejdnhkoos
9cgjxyiqe

./1rkxtumwh/2vijihgsn/3fanxiuju/4yazbmsjy/5sbcaywkx/6aujthffp/7fzujwwnc/8cmxwffao/9cgjxyiqe:
10xmzunod
9jhydvmgovlfaltguwvegjubndkmbufhdoghmupasahuoackzxohijiwmukpopwueedqbsstvzpjbrtcokkyvuujrfahwwbcdeue

./1rkxtumwh/2vijihgsn/3fanxiuju/4yazbmsjy/5sbcaywkx/6aujthffp/7fzujwwnc/8cmxwffao/9cgjxyiqe/10xmzunod:
10rfytviftdcqmtxmatlewqkqujfvdsjgjqffnpkgtoyhhvwkrhqnxaftkmqphbysrdxeukmpylxigtuxckmbmuwyimopnmkgrjk

……

410dntuzt
ls: 無法打開目錄./1rkxtumwh/2vijihgsn/3fanxiuju/4yazbmsjy/5sbcaywkx/6aujthffp/7fzujwwnc/8cmxwffao/9cgjx
yiqe/10xmzunod/11ltybuja/12pddukks/13pgjmtme/14yxyuhvt/15qgddfps/16ipghtsx/17hrlvjqw/18mlwamyj/19ycqq
oum/20gdekplr/21mgkqtef/22uxjelyo/23yuogjxv/24gdyuetr/25ekyseyq/26mohxeho/27yhfufeo/28emftmwp/29detfm
nz/30ulhqorq/31lzvmcau/32vrkdiho/33pwrixvt/34ysjlzxm/35anbimen/36aazpcto/37dpzcvhb/38vbxsrwc/39urooly
a/40gabvtkg/41fswpnkc/42eyozjbb/43mbsphto/44szukcad/45lobskag/46njddwrk/47qmyaqip/48qywwpge/49jymbads
/50cevctwp/51dbrvvrg/52alaqbak/53wdxytcx/54iajcocc/55yulgnls/56xdvlohr/57rsyzzme/58avlsjct/59kzwpnmn/
60zuuyott/61cmyywqh/62fyuzvce/63djljats/64aopcwyi/65rxefdvy/66egqsclw/67jxyausw/68atlilhv/69xrxqsel/7
0isglkct/71fwkjdms/72mhygulk/73nlnwbrx/74sroynrd/75dimglds/76ulettre/77cvdbchx/78imrnssw/79uqfezsr/80
lkhipxs/81rbdpqqz/82lvyzxqt/83sgxgrxx/84tsgcvwa/85jaamdba/86zoneybo/87glbanpe/88tkzaefg/89rrwsack/90u
owxuoq/91rabkpyi/92dcnxiyz/93lacaahs/94frjwezd/95yhtpnte/96fblotmh/97mibhekj/98rzonuec/99topwrdn/100d
blgkn/101drisrx/102aqjjso/103uefcom/104yrflxq/105hyfxyh/106tlpbnl/107ndiswq/108uvgksb/109ozcwup/110qx
pxlo/111gttfdp/112nepxhw/113xwflah/114yibgjy/115dffvxj/116ukiosf/117fpvyvt/118kdreee/119ejgwiz/120lpo
qvc/121gihnlr/122umltry/123ajaaeq/124unorwj/125iuipco/126uwghec/127lzrzvo/128zytdwi/129xvkgeh/130mgfx
pr/131kekuik/132fjlbpy/133wogrgw/134eotsoo/135fquige/136smcyju/137obzwup/138fewkay/139dgizof/140gqrvp
w/141lwxiji/142gprlwz/143geyxsn/144otqwya/145ooyfvk/146ucigye/147xstuji/148ziprio/149ufrzci/150lmgpli
/151kczfla/152svbdit/153fzlyns/154yirhkv/155xbdixx/156mogbae/157goxflw/158fixfsg/159ncihug/160bnrvsj/
161ynpfeh/162cmanrm/163utjekr/164qcvzim/165ypxvkh/166ggnvdw/167nszvsr/168uyuayf/169fatffy/170znjsdj/1
71jqobhe/172syewyj/173fbdzgu/174bufnki/175qasxqn/176rigmyh/177zwoexf/178bdrxbg/179ggdmzx/180ljyrtm/18
1qbywid/182wsjhtx/183moknmr/184haaeaa/185jdpxza/186eerxfa/187kpfjiq/188wrdbbh/189uuhvct/190ofpwct/191
qnmtmy/192gqyowy/193eckugg/194oonhah/195dbjuxd/196qzbvuh/197kcqziu/198akbhoa/199hkszfc/200aqieum/201a
hkuqb/202hkikbi/203gywiex/204ibfmca/205vgczdp/206pchnch/207tfkxlo/208orztrq/209foperp/210umtatf/211rf
qqzo/212xuspzm/213bsqdet/214kbvvmg/215qsbepc/216qqqvea/217mtyasr/218eunbgv/219stppxz/220ncqzlb/221qgl
ips/222naqylv/223ymrfpk/224vavwhr/225dznual/226iuraac/227ztobic/228jynnfd/229iatquu/230vuokzi/231ykpc
bl/232wqldxe/233qeebyv/234nvspvv/235iqxfye/236nwnztb/237qjtgnn/238qyzyas/239lhcqon/240piorsv/241upvvm
j/242sjgemx/243ndojai/244whhuvw/245hmojut/246kwaiwh/247ohckmb/248ucmdrh/249eqzimi/250uymmqd/251cnglst
/252iysywl/253jridil/254nmoqzh/255ygguhk/256nwuiap/257zvtolc/258urycli/259kpiuab/260jempzc/261jyqcbe/
262sulagk/263mvljld/264ciiawa/265vjxora/266rxfgkg/267jwvpoy/268mpmgja/269xpxycf/270fjxobt/271zahncm/2
72soljdu/273jcdwrq/274wvrusy/275noyexu/276oksjfe/277wzfwvr/278tcsfue/279uhzgjs/280lfpypw/281cyjibv/28
2jwnlgu/283nnktxs/284udmuma/285xzbwnj/286jemqma/287xnedax/288dcvfle/289ddnbqe/290jheimg/291rscgbr/292
zlyhgw/293jbmjzx/294qocgsi/295mbyvyj/296ntwpkk/297jhofrm/298ibirpc/299kquens/300mbjnmo/301najyhm/302g
yerut/303blongi/304tafajx/305suvetf/306faeoiu/307dunnih/308ifvtsq/309vulqxe/310ilvtjv/311gzknfk/312ju
xeni/313bpaezt/314dcqgbb/315rqnuic/316ejhbrb/317wfzvzo/318hfndtr/319zgsznw/320dqahuh/321mdnyne/322xiu
lms/323lplrvo/324qtvodk/325tiigxk/326kljzob/327lxxopm/328qwjlms/329jwcbic/330nowwgr/331jqqbce/332qael
pn/333vyyvlr/334wvchpm/335afdbpb/336vsrvym/337ktyfii/338gasxaz/339gjjnco/340yqdxcc/341eysxtl/342ipsoc
o/343xrjucz/344aoetoq/345rtnyzv/346ptrthp/347gnxqkl/348vfpcrp/349jmoobg/350glqvzi/351vkznzy/352cmjseg
/353zgxeyh/354vfkgth/355fnhgjo/356cyouso/357hruehw/358jadbhv/359hklsla/360hwsife/361ragklc/362xydtpr/
363tjrhwj/364gpsojy/365sphazl/366fgwang/367tovqhr/368ybyzbe/369wasspn/370jjkehg/371fvmqie/372bdigtd/3
73afocqc/374agluqq/375jlrfsu/376gtbemx/377lqbrlg/378xmxxvu/379pwznpd/380gdryol/381cgzdfe/382egzxfd/38
3ciccll/384mpoifm/385ygdqiy/386ahilzb/387bhmyia/388cmfhah/389kuxsqg/390winlgk/391jnjlim/392vurqut/393
yehkub/394vkgknd/395pxnmgr/396bsnizx/397bzbbbs/398kdfjjs/399ugopik/400klxzic/401kaqhcd/402iyrruo/403d
tncvg/404feosyw/405cbohnn/406hfirse/407tqbohz/408udrjbo/409yhmpsz/410dntuzt: 文件名過長

 

中間輸出比較多,就省略了。跑到 410 級目錄時,ls 報錯了,上一級目錄路徑的總長度達到 34 + 409 * 10 = 4124,其實已經比 PATH_MAX 大了,不過還是因為緩衝區不足而中斷退出了。再嘗試查找文件,輸出如下:

$ find .
.
./name_max.o
./path_max.c
./Makefile
./name_max
./path_max
./path_max.o
./name_max.c
./1rkxtumwh
./1rkxtumwh/1tovmschzmqujtonfqbqyfomyykrtwqcrezfxbmypesyygmfxpvxvjmvkwnfudhnhgsghgfwkzxkgjpfamcxwotimgniluvucpbl
./1rkxtumwh/2vijihgsn
./1rkxtumwh/2vijihgsn/3fanxiuju
./1rkxtumwh/2vijihgsn/3fanxiuju/3cqwzqdmivizeyjygopureytlajkkdtehlciegumddnhdxgjnxfedfaofjysmtytfbbjjyxmdmtgjbrwywdddfrkopcclbxqcabn
./1rkxtumwh/2vijihgsn/3fanxiuju/4yazbmsjy
./1rkxtumwh/2vijihgsn/3fanxiuju/4yazbmsjy/5sbcaywkx
./1rkxtumwh/2vijihgsn/3fanxiuju/4yazbmsjy/5sbcaywkx/6aujthffp
./1rkxtumwh/2vijihgsn/3fanxiuju/4yazbmsjy/5sbcaywkx/6aujthffp/6howeinoseubrjntbgclavxzxrjraqwrzmqdudrphnsaxhtaovootlqqebheteysqoxntpccewcbevcstqimbacfbklwqjqixovs
./1rkxtumwh/2vijihgsn/3fanxiuju/4yazbmsjy/5sbcaywkx/6aujthffp/7fzujwwnc
./1rkxtumwh/2vijihgsn/3fanxiuju/4yazbmsjy/5sbcaywkx/6aujthffp/7fzujwwnc/7upunhebiffpircfhmxsllpespacnxpptglgnrjxyoohgqopclhqzxuroutdtkumshufydexusgcjwtnhbdiaxaquvvnircaywgy
./1rkxtumwh/2vijihgsn/3fanxiuju/4yazbmsjy/5sbcaywkx/6aujthffp/7fzujwwnc/8cmxwffao
./1rkxtumwh/2vijihgsn/3fanxiuju/4yazbmsjy/5sbcaywkx/6aujthffp/7fzujwwnc/8cmxwffao/8btdlwhtygtqaplqxcszcofbsuyqzeqphmssizmjgfziwlyvpsvsjcvbwtsxzkmhwhzhinqovrztezpusmodqjepeyoejdnhkoos
./1rkxtumwh/2vijihgsn/3fanxiuju/4yazbmsjy/5sbcaywkx/6aujthffp/7fzujwwnc/8cmxwffao/9cgjxyiqe
./1rkxtumwh/2vijihgsn/3fanxiuju/4yazbmsjy/5sbcaywkx/6aujthffp/7fzujwwnc/8cmxwffao/9cgjxyiqe/10xmzunod
./1rkxtumwh/2vijihgsn/3fanxiuju/4yazbmsjy/5sbcaywkx/6aujthffp/7fzujwwnc/8cmxwffao/9cgjxyiqe/10xmzunod/10rfytviftdcqmtxmatlewqkqujfvdsjgjqffnpkgtoyhhvwkrhqnxaftkmqphbysrdxeukmpylxigtuxckmbmuwyimopnmkgrjk

……

 

最後有沒有完成我沒有得到結論,因為整個虛擬機歷時 N 天這個命令還沒跑完 (N > 10),運行中的 find 截圖為證:

 

我是按記憶體占用從高到低排序的,可以看到經過 N 天的運行 find 命令的記憶體占用已經超過了整個圖形界面(Xorg),另外與 find 命令關聯的終端 (mate-terminal) 記憶體、CPU也在高位運行。不過至少可以說明 find 並沒有使用 PATH_MAX 來簡單限制路徑長度,可能是通過動態分配記憶體來實現對長路徑支持的。另外個人比較好奇這個命令的句柄開支,於是看了下 lsof 的輸出:

$ lsof -p `pidof find`
COMMAND    PID   USER   FD      TYPE DEVICE  SIZE/OFF    NODE NAME
find    113339 vmware  cwd       DIR    8,5      4096 2095005 /home/vmware/code/apue/02.chapter
find    113339 vmware  rtd       DIR    8,3      4096       2 /
find    113339 vmware  txt       REG    8,3    203296 1180356 /usr/bin/find
find    113339 vmware  mem       REG    8,3 106374736 1187939 /usr/lib/locale/locale-archive
find    113339 vmware  mem       REG    8,3    141880 1191334 /usr/lib64/libpthread-2.20.so
find    113339 vmware  mem       REG    8,3     19512 1190784 /usr/lib64/libdl-2.20.so
find    113339 vmware  mem       REG    8,3    447240 1191294 /usr/lib64/libpcre.so.1.2.3
find    113339 vmware  mem       REG    8,3   2082456 1190695 /usr/lib64/libc-2.20.so
find    113339 vmware  mem       REG    8,3   1167000 1191118 /usr/lib64/libm-2.20.so
find    113339 vmware  mem       REG    8,3    154784 1191415 /usr/lib64/libselinux.so.1
find    113339 vmware  mem       REG    8,3    163184 1190512 /usr/lib64/ld-2.20.so
find    113339 vmware  mem       REG    8,3     26254 1448972 /usr/lib64/gconv/gconv-modules.cache
find    113339 vmware  mem       REG    8,3     30239 3015834 /usr/share/locale/zh_CN/LC_MESSAGES/findutils.mo
find    113339 vmware    0u      CHR  136,0       0t0       3 /dev/pts/0
find    113339 vmware    1u      CHR  136,0       0t0       3 /dev/pts/0
find    113339 vmware    2u      CHR  136,0       0t0       3 /dev/pts/0
find    113339 vmware    3r      DIR    8,5      4096 2095005 /home/vmware/code/apue/02.chapter
find    113339 vmware    4r  unknown                          /proc/113339/fd/4 (readlink: File name too long)
find    113339 vmware    6r  unknown                          /proc/113339/fd/6 (readlink: File name too long)
find    113339 vmware    7r  unknown                          /proc/113339/fd/7 (readlink: File name too long)
find    113339 vmware    9r  unknown                          /proc/113339/fd/9 (readlink: File name too long)
find    113339 vmware   10r  unknown                          /proc/113339/fd/10 (readlink: File name too long)
find    113339 vmware   11r  unknown                          /proc/113339/fd/11 (readlink: File name too long)

 

出人意料的是並沒有很多打開中的文件句柄。按我的理解,每遍歷一層目錄應該有一個目錄文件的句柄被打開,但是現在看沒有,是因為我造的例子比較特殊,每個目錄下只有一個子目錄?還是 find 另闢蹊徑不用占用許多句柄?暫時不得而知。總的來講,find 的表現要好於 ls,頓時對這個神奇的命令產生了敬仰。最後插一句題外話,從上面的輸出我們可以看到另一個現象,就是因為路徑太長了,readlink 返回了錯誤,可見對長路徑,很多系統 api 也是不支持的。最後你可以使用 rm -rf xxxx 來嘗試清理這些目錄與文件:

 

不出所料 rm 占用了很多的記憶體和 CPU,不過好歹可以工作 (而且耗時沒有 find 那麼誇張,也就十幾分鐘),所以我的虛擬機可以恢復到測試前的工況。下麵是 lsof 針對 rm 的一些輸出

$ lsof -p `pidof rm`
COMMAND   PID   USER   FD      TYPE DEVICE  SIZE/OFF    NODE NAME
rm      70867 vmware  cwd       DIR    8,5      4096 2095005 /home/vmware/code/apue/02.chapter
rm      70867 vmware  rtd       DIR    8,3      4096       2 /
rm      70867 vmware  txt       REG    8,3     62872 1181241 /usr/bin/rm
rm      70867 vmware  mem       REG    8,3 106374736 1187939 /usr/lib/locale/locale-archive
rm      70867 vmware  mem       REG    8,3   2082456 1190695 /usr/lib64/libc-2.20.so
rm      70867 vmware  mem       REG    8,3    163184 1190512 /usr/lib64/ld-2.20.so
rm      70867 vmware    0u      CHR  136,0       0t0       3 /dev/pts/0
rm      70867 vmware    1u      CHR  136,0       0t0       3 /dev/pts/0
rm      70867 vmware    2u      CHR  136,0       0t0       3 /dev/pts/0
rm      70867 vmware    3u  unknown                          /proc/70867/fd/3 (readlink: File name too long)
rm      70867 vmware    4u  unknown                          /proc/70867/fd/4 (readlink: No such file or directory)
rm      70867 vmware    5u  unknown                          /proc/70867/fd/5 (readlink: File name too long)
rm      70867 vmware    6u  unknown                          /proc/70867/fd/6 (readlink: File name too long)
rm      70867 vmware    7u  unknown                          /proc/70867/fd/7 (readlink: File name too long)
rm      70867 vmware    8u  unknown                          /proc/70867/fd/8 (readlink: File name too long)

 

和 find 一樣,它沒有多少打開中的文件句柄(否則打開文件句柄數早超限了)。另外從 lsof 的輸出看,有一些節點已經被 rm 刪除了,所以 readlink 報錯。

結論

對超長的文件路徑來說,不同的 Linux 命令的支持程度也是不同的,有的支持,有的不支持。而且考慮到傳遞給進程的命令行總長度也是有限制的,除了一些支持遞歸目錄處理的命令外,普通的命令是不會支持這麼長的路徑的。另一方面,從程式員的角度考慮,對於大路徑的支持也是比較麻煩的,首先是系統支不支持輸入、輸出超長路徑;如果支持,輸入的場景還比較好辦,輸出的場景就比較麻煩了。最簡單的辦法是自己定義一個大於 PATH_MAX 值的常量並使用它分配記憶體,但是這樣也存在問題,一方面日常處理比較浪費記憶體;另一方面如果路徑超過你自己定義的這個值,還是會出現接收截斷的問題。而且程式員沒有辦法去預知要得到的路徑長度,從而提前動態分配記憶體。

總結一下,這個最大路徑限制並不是系統不能支持超長的路徑,而且作為一種系統與應用之間的一個約定,有了

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在不同的區域中使用Convert.ToDouble可能會產生問題。 string str = "20.0"; double val = Convert.ToDouble(str); 比如在某些區域語言中得到的結果是200,如: Thread.CurrentThread.CurrentCulture ...
  • 場景 ASP.NET中新建Web網站並部署到IIS上(詳細圖文教程): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/107199747 前面講過將ASP.NET的項目部署到本機的IIS上。 但是如果將其部署到伺服器上Window ...
  • // from https://stackoverflow.com/questions/35381238/how-to-use-custom-fonts-in-emgucv string text = "塗聚文(Geovin Du)"; // 下麵定義一個矩形區域 int rectWidth = t ...
  • 案例:修改預設線程個數 1.NameValueCollection System.Collections.Specialized.NameValueCollection collection = new System.Collections.Specialized.NameValueCollecti ...
  • 背景 習慣使用markdown的人應該都知道Typora這個神器,它非常簡潔高效。雖然博客園的線上markdown編輯器也不錯,但畢竟是網頁版,每次寫東西需要登錄系統-進後臺-找到文章-編輯-保存草稿。。。非常難受。。。 但是使用Typora來寫的話,文章圖片又是個問題,本地寫完粘貼到網站上,圖片全 ...
  • 一、Linux入門概述 1.1 概述 Linux內核最初由芬蘭人Linus Torvalds在赫爾辛基大學就讀時處於個人愛好編寫的。 Linux是一套免費使用且自由傳播的類Unix操作系統,是一個基於POSIX和Unix的多用戶、多任務、支持多線程和多CPU的操作系統。Linux能運行主要的Unix ...
  • 記一次winserver安裝jdk+tomcat 準備軟體: jdk-8u241-windows-x64 apache-tomcat-8.5.46-windows-x64 一、安裝java 1、安裝jdk-8u241-windows-x64.exe,一路next,直接預設安裝即可,也可選擇安裝在特定 ...
  • #include <Windows.h> #include <stdio.h> #include <tchar.h> #include <assert.h> int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...