linux _max_path,[apue] Linux / Windows 系统上只能建立不超过 PATH_MAX / MAX_PATH 长度的路径吗?...
這個最大路徑長度是為了方便程序編寫?還是說底層的文件系統就只能支持這么長的路徑呢?本文為你揭開謎底
問題的提出
在處理文件系統路徑的時候,我們一般會先開辟一塊內存區,用來接收路徑、或者拼接好路徑傳遞給系統調用。這是因為路徑在各個系統上都有最大長度限制,在 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?#else11?????char?buf[PATH_MAX?+?1]?=?{?0?};12?????if?(readlink("/proc/self/exe",?buf,?PATH_MAX)?
21?}
它用來獲取當前可執行文件的完整路徑。在 Windows 與 Linux 上分別調用了 GetModuleFileName 與 readlink 系統調用,且事先在棧上分配了接收完整路徑的內存區 buf。最后將成功獲取的路徑打印到控制臺。在兩種系統上,輸出分別如下:
Windowscurrent?executable?file?path:?E:\code\apue\02.chapter\Release\path_max.exe
Linuxcurrent?executable?file?path:?/home/yunhai/code/apue/02.chapter/path_max
其它與路徑相關的調用也是類似的。那么問題來了,這個最大路徑長度是為了方便程序編寫 (不然需要動態分配內存,且需要兩次調用,其中一次用于獲取最終的路徑長度),還是說底層的文件系統就只能支持這么長的路徑呢?
問題的驗證
為了弄清楚這個問題,我專門寫了一個測試程序:
path_max.c1?#ifdef?WIN32??2?#??ifndef?_WIN32_WINNT????????????//?指定要求的最低平臺是?Windows?Vista。??3?#??define?_WIN32_WINNT?0x0600?????//?將此值更改為相應的值,以適用于?Windows?的其他版本。??4?#??endif??5?#include??6?#include??7?#else???8?#include??9?#include?10?#include?11?#include?12?#include?13?#endif??14?#include??15?#include?16?#include?17?#include?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
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?WIN32101?????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?=?260mkdir?1tdobxciu
open?1gybhgvdtngozbkzvcu***itcpntxgtjhasljfycfowuuqmcvvitsthzdxpckttobaqtccxeabfmnvhoeknyjifabnynkrjwzhiq?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?=?3mkdir?17xljxtht
open?17umkwtdbxiayekrljssfnxgvcmytthwevlmrxptivqmvwrkpqkvxoircuwadhkyidoaydlvnnafejpssqdewcymluzmrwrrkwmn?failed,?errno?=?3mkdir?18aywtihk
open?18ynydjmncmakzoezcupoeqfiahsunxhqvczbuapntehglrrhubpbydnnpnbpjdschmrkzkkpvgfajemsfsvofsjoclijforjkex?failed,?errno?=?3mkdir?19qsvtxwm
open?19qpfdrjgnxthljturhvuymuoqctsmixxrircoievqpgrnxpzufozwvpsjocdxfhjodpfzljbgegutfsquaehjoaswqhwtsqbgmh?failed,?errno?=?3mkdir?20vzvuovy
open?20zqqxsfnxrccsubxwevfffunrxfugkovltzidalrmppjjyrbnohxgmwnmwcseijuhzabngyfodgodnblmvhmvnmkvqfijucfqfz?failed,?errno?=?3mkdir?21idgwupz
open?21vlkqahypwulaaykizzvqviqztswdwikvloswluydfyqmgjcaixqqrilsrjireprfrvbgfvspulfmnuksbvsnfkdncybuhxddtw?failed,?errno?=?3mkdir?22plbyhbe
open?22rbekcixmxcohnvqlyhlppmgqtpsgsjwxhuwlmhnzspkbvdrnzechjbjsglzajiadiqguutgfjfkaqdtfqeevpcrsejiiotytse?failed,?errno?=?3mkdir?23vggwvra
open?23tlbobatwbdpaxouojluctxqyddllqedqbeotpkkxgddristpprablooxlomgvneixubhxhemtlvipqwzzfgqcxjtdltytpialw?failed,?errno?=?3mkdir?24dkpkfup
open?24fujnicyzpudgnsuzcqkkgihsousejefcuepnkkxdpdxbxxfryeglrmikgxxckazfokmdrgttnqxavphpoekagfbenjyuxpfntu?failed,?errno?=?3CreateDirectory?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-65ret?=?_chdir?(name);
if?(ret?==?-1)
//ret?=?SetCurrentDirectory(name);
//if?(!ret)
line 81-84ret?=?_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?=?4096mkdir?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
……
410dntuztls:?無法打開目錄./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/70isglkct/71fwkjdms/72mhygulk/73nlnwbrx/74sroynrd/75dimglds/76ulettre/77cvdbchx/78imrnssw/79uqfezsr/80lkhipxs/81rbdpqqz/82lvyzxqt/83sgxgrxx/84tsgcvwa/85jaamdba/86zoneybo/87glbanpe/88tkzaefg/89rrwsack/90uowxuoq/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/130mgfxpr/131kekuik/132fjlbpy/133wogrgw/134eotsoo/135fquige/136smcyju/137obzwup/138fewkay/139dgizof/140gqrvpw/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/171jqobhe/172syewyj/173fbdzgu/174bufnki/175qasxqn/176rigmyh/177zwoexf/178bdrxbg/179ggdmzx/180ljyrtm/181qbywid/182wsjhtx/183moknmr/184haaeaa/185jdpxza/186eerxfa/187kpfjiq/188wrdbbh/189uuhvct/190ofpwct/191qnmtmy/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/272soljdu/273jcdwrq/274wvrusy/275noyexu/276oksjfe/277wzfwvr/278tcsfue/279uhzgjs/280lfpypw/281cyjibv/282jwnlgu/283nnktxs/284udmuma/285xzbwnj/286jemqma/287xnedax/288dcvfle/289ddnbqe/290jheimg/291rscgbr/292zlyhgw/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/373afocqc/374agluqq/375jlrfsu/376gtbemx/377lqbrlg/378xmxxvu/379pwznpd/380gdryol/381cgzdfe/382egzxfd/383ciccll/384mpoifm/385ygdqiy/386ahilzb/387bhmyia/388cmfhah/389kuxsqg/390winlgk/391jnjlim/392vurqut/393yehkub/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?NAMEfind????113339?vmware??cwd???????DIR????8,5??????4096?2095005?/home/vmware/code/apue/02.chapterfind????113339?vmware??rtd???????DIR????8,3??????4096???????2?/find????113339?vmware??txt???????REG????8,3????203296?1180356?/usr/bin/findfind????113339?vmware??mem???????REG????8,3?106374736?1187939?/usr/lib/locale/locale-archivefind????113339?vmware??mem???????REG????8,3????141880?1191334?/usr/lib64/libpthread-2.20.sofind????113339?vmware??mem???????REG????8,3?????19512?1190784?/usr/lib64/libdl-2.20.sofind????113339?vmware??mem???????REG????8,3????447240?1191294?/usr/lib64/libpcre.so.1.2.3find????113339?vmware??mem???????REG????8,3???2082456?1190695?/usr/lib64/libc-2.20.sofind????113339?vmware??mem???????REG????8,3???1167000?1191118?/usr/lib64/libm-2.20.sofind????113339?vmware??mem???????REG????8,3????154784?1191415?/usr/lib64/libselinux.so.1find????113339?vmware??mem???????REG????8,3????163184?1190512?/usr/lib64/ld-2.20.sofind????113339?vmware??mem???????REG????8,3?????26254?1448972?/usr/lib64/gconv/gconv-modules.cachefind????113339?vmware??mem???????REG????8,3?????30239?3015834?/usr/share/locale/zh_CN/LC_MESSAGES/findutils.mofind????113339?vmware????0u??????CHR??136,0???????0t0???????3?/dev/pts/0find????113339?vmware????1u??????CHR??136,0???????0t0???????3?/dev/pts/0find????113339?vmware????2u??????CHR??136,0???????0t0???????3?/dev/pts/0find????113339?vmware????3r??????DIR????8,5??????4096?2095005?/home/vmware/code/apue/02.chapterfind????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?NAMErm??????70867?vmware??cwd???????DIR????8,5??????4096?2095005?/home/vmware/code/apue/02.chapterrm??????70867?vmware??rtd???????DIR????8,3??????4096???????2?/rm??????70867?vmware??txt???????REG????8,3?????62872?1181241?/usr/bin/rmrm??????70867?vmware??mem???????REG????8,3?106374736?1187939?/usr/lib/locale/locale-archiverm??????70867?vmware??mem???????REG????8,3???2082456?1190695?/usr/lib64/libc-2.20.sorm??????70867?vmware??mem???????REG????8,3????163184?1190512?/usr/lib64/ld-2.20.sorm??????70867?vmware????0u??????CHR??136,0???????0t0???????3?/dev/pts/0rm??????70867?vmware????1u??????CHR??136,0???????0t0???????3?/dev/pts/0rm??????70867?vmware????2u??????CHR??136,0???????0t0???????3?/dev/pts/0rm??????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 值的常量并使用它分配內存,但是這樣也存在問題,一方面日常處理比較浪費內存;另一方面如果路徑超過你自己定義的這個值,還是會出現接收截斷的問題。而且程序員沒有辦法去預知要得到的路徑長度,從而提前動態分配內存。
總結一下,這個最大路徑限制并不是系統不能支持超長的路徑,而且作為一種系統與應用之間的一個約定,有了這個約定之后,程序對路徑的處理將得到簡化。況且我們沒有對超長路徑的硬需求,絕大部分 Windows 應用在 260 個字符路徑的限制下就跑得很好,Linux 4096 的限制就更不用說了。
這個測試程序的一個額外用處就是耗盡所在分區的 inode(?),并觀察系統在這種極限情況下的一些表現,例如,當我試圖截取屏幕時不能成功,得到下面的提示框:
當你需要驗證程序在這種極限狀態下的行為時,這個程序不失為一種有用工具。
總結
以上是生活随笔為你收集整理的linux _max_path,[apue] Linux / Windows 系统上只能建立不超过 PATH_MAX / MAX_PATH 长度的路径吗?...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 运行快捷指令无法连接服务器失败,快捷指令
- 下一篇: 问题 seata_架构设计 | 基于Se