filesystem.hpp 180 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456
  1. //---------------------------------------------------------------------------------------
  2. //
  3. // ghc::filesystem - A C++17-like filesystem implementation for
  4. // C++11/C++14/C++17
  5. //
  6. //---------------------------------------------------------------------------------------
  7. //
  8. // Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining a copy
  11. // of this software and associated documentation files (the "Software"), to deal
  12. // in the Software without restriction, including without limitation the rights
  13. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  14. // copies of the Software, and to permit persons to whom the Software is
  15. // furnished to do so, subject to the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be included in
  18. // all copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  21. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  23. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  24. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  25. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  26. // SOFTWARE.
  27. //
  28. //---------------------------------------------------------------------------------------
  29. //
  30. // To dynamically select std::filesystem where available, you could use:
  31. //
  32. // #if defined(__cplusplus) && __cplusplus >= 201703L && defined(__has_include)
  33. // && __has_include(<filesystem>) #include <filesystem> namespace fs =
  34. // std::filesystem; #else #include <ghc/filesystem.hpp> namespace fs =
  35. // ghc::filesystem; #endif
  36. //
  37. //---------------------------------------------------------------------------------------
  38. #ifndef GHC_FILESYSTEM_H
  39. #define GHC_FILESYSTEM_H
  40. // #define BSD manifest constant only in
  41. // sys/param.h
  42. #ifndef _WIN32
  43. #include <sys/param.h>
  44. #endif
  45. #ifndef GHC_OS_DETECTED
  46. #if defined(__APPLE__) && defined(__MACH__)
  47. #define GHC_OS_MACOS
  48. #elif defined(__linux__)
  49. #define GHC_OS_LINUX
  50. #if defined(__ANDROID__)
  51. #define GHC_OS_ANDROID
  52. #endif
  53. #elif defined(_WIN64)
  54. #define GHC_OS_WINDOWS
  55. #define GHC_OS_WIN64
  56. #elif defined(_WIN32)
  57. #define GHC_OS_WINDOWS
  58. #define GHC_OS_WIN32
  59. #elif defined(__svr4__)
  60. #define GHC_OS_SYS5R4
  61. #elif defined(BSD)
  62. #define GHC_OS_BSD
  63. #elif defined(__EMSCRIPTEN__)
  64. #define GHC_OS_WEB
  65. #include <wasi/api.h>
  66. #else
  67. #error "Operating system currently not supported!"
  68. #endif
  69. #define GHC_OS_DETECTED
  70. #endif
  71. #if defined(GHC_FILESYSTEM_IMPLEMENTATION)
  72. #define GHC_EXPAND_IMPL
  73. #define GHC_INLINE
  74. #ifdef GHC_OS_WINDOWS
  75. #define GHC_FS_API
  76. #define GHC_FS_API_CLASS
  77. #else
  78. #define GHC_FS_API __attribute__((visibility("default")))
  79. #define GHC_FS_API_CLASS __attribute__((visibility("default")))
  80. #endif
  81. #elif defined(GHC_FILESYSTEM_FWD)
  82. #define GHC_INLINE
  83. #ifdef GHC_OS_WINDOWS
  84. #define GHC_FS_API extern
  85. #define GHC_FS_API_CLASS
  86. #else
  87. #define GHC_FS_API extern
  88. #define GHC_FS_API_CLASS
  89. #endif
  90. #else
  91. #define GHC_EXPAND_IMPL
  92. #define GHC_INLINE inline
  93. #define GHC_FS_API
  94. #define GHC_FS_API_CLASS
  95. #endif
  96. #ifdef GHC_EXPAND_IMPL
  97. #ifdef GHC_OS_WINDOWS
  98. #include <windows.h>
  99. // additional includes
  100. #include <shellapi.h>
  101. #include <sys/stat.h>
  102. #include <sys/types.h>
  103. #include <wchar.h>
  104. #include <winioctl.h>
  105. #else
  106. #include <dirent.h>
  107. #include <fcntl.h>
  108. #include <limits.h>
  109. #include <sys/param.h>
  110. #include <sys/stat.h>
  111. #include <sys/time.h>
  112. #include <sys/types.h>
  113. #include <unistd.h>
  114. #ifdef GHC_OS_ANDROID
  115. #include <android/api-level.h>
  116. #if __ANDROID_API__ < 12
  117. #include <sys/syscall.h>
  118. #endif
  119. #include <sys/vfs.h>
  120. #define statvfs statfs
  121. #else
  122. #include <sys/statvfs.h>
  123. #endif
  124. #if !defined(__ANDROID__) || __ANDROID_API__ >= 26
  125. #include <langinfo.h>
  126. #endif
  127. #endif
  128. #ifdef GHC_OS_MACOS
  129. #include <Availability.h>
  130. #endif
  131. #include <algorithm>
  132. #include <cctype>
  133. #include <chrono>
  134. #include <clocale>
  135. #include <cstdlib>
  136. #include <cstring>
  137. #include <fstream>
  138. #include <functional>
  139. #include <memory>
  140. #include <stack>
  141. #include <stdexcept>
  142. #include <string>
  143. #include <system_error>
  144. #include <type_traits>
  145. #include <utility>
  146. #include <vector>
  147. #else // GHC_EXPAND_IMPL
  148. #include <chrono>
  149. #include <fstream>
  150. #include <memory>
  151. #include <stack>
  152. #include <stdexcept>
  153. #include <string>
  154. #include <system_error>
  155. #ifdef GHC_OS_WINDOWS
  156. #include <vector>
  157. #endif
  158. #endif // GHC_EXPAND_IMPL
  159. //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  160. //- - - - - - - - -
  161. // Behaviour Switches (see README.md, should match the config in
  162. // test/filesystem_test.cpp):
  163. //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  164. //- - - - - - - - -
  165. // LWG #2682 disables the since then invalid use of the copy option
  166. // create_symlinks on directories configure LWG conformance ()
  167. #define LWG_2682_BEHAVIOUR
  168. //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  169. //- - - - - - - - -
  170. // LWG #2395 makes crate_directory/create_directories not emit an error if there
  171. // is a regular file with that name, it is superceded by P1164R1, so only
  172. // activate if really needed #define LWG_2935_BEHAVIOUR
  173. //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  174. //- - - - - - - - -
  175. // LWG #2937 enforces that fs::equivalent emits an error, if
  176. // !fs::exists(p1)||!exists(p2)
  177. #define LWG_2937_BEHAVIOUR
  178. //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  179. //- - - - - - - - -
  180. // UTF8-Everywhere is the original behaviour of ghc::filesystem. With this
  181. // define you can enable the more standard conforming implementation option that
  182. // uses wstring on Windows as ghc::filesystem::string_type. #define
  183. // GHC_WIN_WSTRING_STRING_TYPE
  184. //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  185. //- - - - - - - - -
  186. // Raise errors/exceptions when invalid unicode codepoints or UTF-8 sequences
  187. // are found, instead of replacing them with the unicode replacement character
  188. // (U+FFFD). #define GHC_RAISE_UNICODE_ERRORS
  189. //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  190. //- - - - - - - - -
  191. // ghc::filesystem version in decimal (major * 10000 + minor * 100 + patch)
  192. #define GHC_FILESYSTEM_VERSION 10304L
  193. #if !defined(GHC_WITH_EXCEPTIONS) && \
  194. (defined(__EXCEPTIONS) || defined(__cpp_exceptions) || \
  195. defined(_CPPUNWIND))
  196. #define GHC_WITH_EXCEPTIONS
  197. #endif
  198. #if !defined(GHC_WITH_EXCEPTIONS) && defined(GHC_RAISE_UNICODE_ERRORS)
  199. #error "Can't raise unicode errors whith exception support disabled"
  200. #endif
  201. namespace ghc { namespace filesystem {
  202. // temporary existing exception type for yet unimplemented parts
  203. class GHC_FS_API_CLASS not_implemented_exception : public std::logic_error {
  204. public:
  205. not_implemented_exception()
  206. : std::logic_error("function not implemented yet.") {}
  207. };
  208. template <typename char_type> class path_helper_base {
  209. public:
  210. using value_type = char_type;
  211. #ifdef GHC_OS_WINDOWS
  212. static constexpr value_type preferred_separator = '\\';
  213. #else
  214. static constexpr value_type preferred_separator = '/';
  215. #endif
  216. };
  217. #if __cplusplus < 201703L
  218. template <typename char_type>
  219. constexpr char_type path_helper_base<char_type>::preferred_separator;
  220. #endif
  221. // 30.10.8 class path
  222. class GHC_FS_API_CLASS path
  223. #if defined(GHC_OS_WINDOWS) && defined(GHC_WIN_WSTRING_STRING_TYPE)
  224. #define GHC_USE_WCHAR_T
  225. : private path_helper_base<std::wstring::value_type> {
  226. public:
  227. using path_helper_base<std::wstring::value_type>::value_type;
  228. #else
  229. : private path_helper_base<std::string::value_type> {
  230. public:
  231. using path_helper_base<std::string::value_type>::value_type;
  232. #endif
  233. using string_type = std::basic_string<value_type>;
  234. using path_helper_base<value_type>::preferred_separator;
  235. // 30.10.10.1 enumeration format
  236. /// The path format in wich the constructor argument is given.
  237. enum format {
  238. generic_format, ///< The generic format, internally used by
  239. ///< ghc::filesystem::path with slashes
  240. native_format, ///< The format native to the current platform this code
  241. ///< is build for
  242. auto_format, ///< Try to auto-detect the format, fallback to native
  243. };
  244. template <class T> struct _is_basic_string : std::false_type {};
  245. template <class CharT, class Traits, class Alloc>
  246. struct _is_basic_string<std::basic_string<CharT, Traits, Alloc>>
  247. : std::true_type {};
  248. #ifdef __cpp_lib_string_view
  249. template <class CharT>
  250. struct _is_basic_string<std::basic_string_view<CharT>> : std::true_type {};
  251. #endif
  252. template <typename T1, typename T2 = void>
  253. using path_type =
  254. typename std::enable_if<!std::is_same<path, T1>::value, path>::type;
  255. #ifdef GHC_USE_WCHAR_T
  256. template <typename T>
  257. using path_from_string = typename std::enable_if<
  258. _is_basic_string<T>::value ||
  259. std::is_same<char const *, typename std::decay<T>::type>::value ||
  260. std::is_same<char *, typename std::decay<T>::type>::value ||
  261. std::is_same<wchar_t const *,
  262. typename std::decay<T>::type>::value ||
  263. std::is_same<wchar_t *, typename std::decay<T>::type>::value,
  264. path>::type;
  265. template <typename T>
  266. using path_type_EcharT =
  267. typename std::enable_if<std::is_same<T, char>::value ||
  268. std::is_same<T, char16_t>::value ||
  269. std::is_same<T, char32_t>::value,
  270. path>::type;
  271. #else
  272. template <typename T>
  273. using path_from_string = typename std::enable_if<
  274. _is_basic_string<T>::value ||
  275. std::is_same<char const *, typename std::decay<T>::type>::value ||
  276. std::is_same<char *, typename std::decay<T>::type>::value,
  277. path>::type;
  278. template <typename T>
  279. using path_type_EcharT = typename std::enable_if<
  280. std::is_same<T, char>::value || std::is_same<T, char16_t>::value ||
  281. std::is_same<T, char32_t>::value || std::is_same<T, wchar_t>::value,
  282. path>::type;
  283. #endif
  284. // 30.10.8.4.1 constructors and destructor
  285. path() noexcept;
  286. path(const path & p);
  287. path(path && p) noexcept;
  288. path(string_type && source, format fmt = auto_format);
  289. template <class Source, typename = path_from_string<Source>>
  290. path(const Source & source, format fmt = auto_format);
  291. template <class InputIterator>
  292. path(InputIterator first, InputIterator last, format fmt = auto_format);
  293. #ifdef GHC_WITH_EXCEPTIONS
  294. template <class Source, typename = path_from_string<Source>>
  295. path(const Source & source, const std::locale & loc,
  296. format fmt = auto_format);
  297. template <class InputIterator>
  298. path(InputIterator first, InputIterator last, const std::locale & loc,
  299. format fmt = auto_format);
  300. #endif
  301. ~path();
  302. // 30.10.8.4.2 assignments
  303. path & operator=(const path & p);
  304. path & operator=(path && p) noexcept;
  305. path & operator=(string_type && source);
  306. path & assign(string_type && source);
  307. template <class Source> path & operator=(const Source & source);
  308. template <class Source> path & assign(const Source & source);
  309. template <class InputIterator>
  310. path & assign(InputIterator first, InputIterator last);
  311. // 30.10.8.4.3 appends
  312. path & operator/=(const path & p);
  313. template <class Source> path & operator/=(const Source & source);
  314. template <class Source> path & append(const Source & source);
  315. template <class InputIterator>
  316. path & append(InputIterator first, InputIterator last);
  317. // 30.10.8.4.4 concatenation
  318. path & operator+=(const path & x);
  319. path & operator+=(const string_type & x);
  320. #ifdef __cpp_lib_string_view
  321. path & operator+=(std::basic_string_view<value_type> x);
  322. #endif
  323. path & operator+=(const value_type * x);
  324. path & operator+=(value_type x);
  325. template <class Source>
  326. path_from_string<Source> & operator+=(const Source & x);
  327. template <class EcharT> path_type_EcharT<EcharT> & operator+=(EcharT x);
  328. template <class Source> path & concat(const Source & x);
  329. template <class InputIterator>
  330. path & concat(InputIterator first, InputIterator last);
  331. // 30.10.8.4.5 modifiers
  332. void clear() noexcept;
  333. path & make_preferred();
  334. path & remove_filename();
  335. path & replace_filename(const path & replacement);
  336. path & replace_extension(const path & replacement = path());
  337. void swap(path & rhs) noexcept;
  338. // 30.10.8.4.6 native format observers
  339. const string_type &
  340. native() const; // this implementation doesn't support noexcept for native()
  341. const value_type *
  342. c_str() const; // this implementation doesn't support noexcept for c_str()
  343. operator string_type() const;
  344. template <class EcharT, class traits = std::char_traits<EcharT>,
  345. class Allocator = std::allocator<EcharT>>
  346. std::basic_string<EcharT, traits, Allocator>
  347. string(const Allocator & a = Allocator()) const;
  348. std::string string() const;
  349. std::wstring wstring() const;
  350. std::string u8string() const;
  351. std::u16string u16string() const;
  352. std::u32string u32string() const;
  353. // 30.10.8.4.7 generic format observers
  354. template <class EcharT, class traits = std::char_traits<EcharT>,
  355. class Allocator = std::allocator<EcharT>>
  356. std::basic_string<EcharT, traits, Allocator>
  357. generic_string(const Allocator & a = Allocator()) const;
  358. const std::string & generic_string()
  359. const; // this is different from the standard, that returns by value
  360. std::wstring generic_wstring() const;
  361. std::string generic_u8string() const;
  362. std::u16string generic_u16string() const;
  363. std::u32string generic_u32string() const;
  364. // 30.10.8.4.8 compare
  365. int compare(const path & p) const noexcept;
  366. int compare(const string_type & s) const;
  367. #ifdef __cpp_lib_string_view
  368. int compare(std::basic_string_view<value_type> s) const;
  369. #endif
  370. int compare(const value_type * s) const;
  371. // 30.10.8.4.9 decomposition
  372. path root_name() const;
  373. path root_directory() const;
  374. path root_path() const;
  375. path relative_path() const;
  376. path parent_path() const;
  377. path filename() const;
  378. path stem() const;
  379. path extension() const;
  380. // 30.10.8.4.10 query
  381. bool empty() const noexcept;
  382. bool has_root_name() const;
  383. bool has_root_directory() const;
  384. bool has_root_path() const;
  385. bool has_relative_path() const;
  386. bool has_parent_path() const;
  387. bool has_filename() const;
  388. bool has_stem() const;
  389. bool has_extension() const;
  390. bool is_absolute() const;
  391. bool is_relative() const;
  392. // 30.10.8.4.11 generation
  393. path lexically_normal() const;
  394. path lexically_relative(const path & base) const;
  395. path lexically_proximate(const path & base) const;
  396. // 30.10.8.5 iterators
  397. class iterator;
  398. using const_iterator = iterator;
  399. iterator begin() const;
  400. iterator end() const;
  401. private:
  402. using impl_value_type = std::string::value_type;
  403. using impl_string_type = std::basic_string<impl_value_type>;
  404. friend class directory_iterator;
  405. void append_name(const char * name);
  406. static constexpr impl_value_type generic_separator = '/';
  407. template <typename InputIterator> class input_iterator_range {
  408. public:
  409. typedef InputIterator iterator;
  410. typedef InputIterator const_iterator;
  411. typedef typename InputIterator::difference_type difference_type;
  412. input_iterator_range(const InputIterator & first,
  413. const InputIterator & last)
  414. : _first(first), _last(last) {}
  415. InputIterator begin() const { return _first; }
  416. InputIterator end() const { return _last; }
  417. private:
  418. InputIterator _first;
  419. InputIterator _last;
  420. };
  421. friend void swap(path & lhs, path & rhs) noexcept;
  422. friend size_t hash_value(const path & p) noexcept;
  423. static void postprocess_path_with_format(impl_string_type & p, format fmt);
  424. impl_string_type _path;
  425. #ifdef GHC_OS_WINDOWS
  426. impl_string_type native_impl() const;
  427. mutable string_type _native_cache;
  428. #else
  429. const impl_string_type & native_impl() const;
  430. #endif
  431. };
  432. // 30.10.8.6 path non-member functions
  433. GHC_FS_API void swap(path & lhs, path & rhs) noexcept;
  434. GHC_FS_API size_t hash_value(const path & p) noexcept;
  435. GHC_FS_API bool operator==(const path & lhs, const path & rhs) noexcept;
  436. GHC_FS_API bool operator!=(const path & lhs, const path & rhs) noexcept;
  437. GHC_FS_API bool operator<(const path & lhs, const path & rhs) noexcept;
  438. GHC_FS_API bool operator<=(const path & lhs, const path & rhs) noexcept;
  439. GHC_FS_API bool operator>(const path & lhs, const path & rhs) noexcept;
  440. GHC_FS_API bool operator>=(const path & lhs, const path & rhs) noexcept;
  441. GHC_FS_API path operator/(const path & lhs, const path & rhs);
  442. // 30.10.8.6.1 path inserter and extractor
  443. template <class charT, class traits>
  444. std::basic_ostream<charT, traits> &
  445. operator<<(std::basic_ostream<charT, traits> & os, const path & p);
  446. template <class charT, class traits>
  447. std::basic_istream<charT, traits> &
  448. operator>>(std::basic_istream<charT, traits> & is, path & p);
  449. // 30.10.8.6.2 path factory functions
  450. template <class Source, typename = path::path_from_string<Source>>
  451. path u8path(const Source & source);
  452. template <class InputIterator>
  453. path u8path(InputIterator first, InputIterator last);
  454. // 30.10.9 class filesystem_error
  455. class GHC_FS_API_CLASS filesystem_error : public std::system_error {
  456. public:
  457. filesystem_error(const std::string & what_arg, std::error_code ec);
  458. filesystem_error(const std::string & what_arg, const path & p1,
  459. std::error_code ec);
  460. filesystem_error(const std::string & what_arg, const path & p1,
  461. const path & p2, std::error_code ec);
  462. const path & path1() const noexcept;
  463. const path & path2() const noexcept;
  464. const char * what() const noexcept override;
  465. private:
  466. std::string _what_arg;
  467. std::error_code _ec;
  468. path _p1, _p2;
  469. };
  470. class GHC_FS_API_CLASS path::iterator {
  471. public:
  472. using value_type = const path;
  473. using difference_type = std::ptrdiff_t;
  474. using pointer = const path *;
  475. using reference = const path &;
  476. using iterator_category = std::bidirectional_iterator_tag;
  477. iterator();
  478. iterator(const impl_string_type::const_iterator & first,
  479. const impl_string_type::const_iterator & last,
  480. const impl_string_type::const_iterator & pos);
  481. iterator & operator++();
  482. iterator operator++(int);
  483. iterator & operator--();
  484. iterator operator--(int);
  485. bool operator==(const iterator & other) const;
  486. bool operator!=(const iterator & other) const;
  487. reference operator*() const;
  488. pointer operator->() const;
  489. private:
  490. impl_string_type::const_iterator
  491. increment(const std::string::const_iterator & pos) const;
  492. impl_string_type::const_iterator
  493. decrement(const std::string::const_iterator & pos) const;
  494. void updateCurrent();
  495. impl_string_type::const_iterator _first;
  496. impl_string_type::const_iterator _last;
  497. impl_string_type::const_iterator _root;
  498. impl_string_type::const_iterator _iter;
  499. path _current;
  500. };
  501. struct space_info {
  502. uintmax_t capacity;
  503. uintmax_t free;
  504. uintmax_t available;
  505. };
  506. // 30.10.10, enumerations
  507. enum class file_type {
  508. none,
  509. not_found,
  510. regular,
  511. directory,
  512. symlink,
  513. block,
  514. character,
  515. fifo,
  516. socket,
  517. unknown,
  518. };
  519. enum class perms : uint16_t {
  520. none = 0,
  521. owner_read = 0400,
  522. owner_write = 0200,
  523. owner_exec = 0100,
  524. owner_all = 0700,
  525. group_read = 040,
  526. group_write = 020,
  527. group_exec = 010,
  528. group_all = 070,
  529. others_read = 04,
  530. others_write = 02,
  531. others_exec = 01,
  532. others_all = 07,
  533. all = 0777,
  534. set_uid = 04000,
  535. set_gid = 02000,
  536. sticky_bit = 01000,
  537. mask = 07777,
  538. unknown = 0xffff
  539. };
  540. enum class perm_options : uint16_t {
  541. replace = 3,
  542. add = 1,
  543. remove = 2,
  544. nofollow = 4,
  545. };
  546. enum class copy_options : uint16_t {
  547. none = 0,
  548. skip_existing = 1,
  549. overwrite_existing = 2,
  550. update_existing = 4,
  551. recursive = 8,
  552. copy_symlinks = 0x10,
  553. skip_symlinks = 0x20,
  554. directories_only = 0x40,
  555. create_symlinks = 0x80,
  556. #ifndef GHC_OS_WEB
  557. create_hard_links = 0x100
  558. #endif
  559. };
  560. enum class directory_options : uint16_t {
  561. none = 0,
  562. follow_directory_symlink = 1,
  563. skip_permission_denied = 2,
  564. };
  565. // 30.10.11 class file_status
  566. class GHC_FS_API_CLASS file_status {
  567. public:
  568. // 30.10.11.1 constructors and destructor
  569. file_status() noexcept;
  570. explicit file_status(file_type ft, perms prms = perms::unknown) noexcept;
  571. file_status(const file_status &) noexcept;
  572. file_status(file_status &&) noexcept;
  573. ~file_status();
  574. // assignments:
  575. file_status & operator=(const file_status &) noexcept;
  576. file_status & operator=(file_status &&) noexcept;
  577. // 30.10.11.3 modifiers
  578. void type(file_type ft) noexcept;
  579. void permissions(perms prms) noexcept;
  580. // 30.10.11.2 observers
  581. file_type type() const noexcept;
  582. perms permissions() const noexcept;
  583. private:
  584. file_type _type;
  585. perms _perms;
  586. };
  587. using file_time_type = std::chrono::time_point<std::chrono::system_clock>;
  588. // 30.10.12 Class directory_entry
  589. class GHC_FS_API_CLASS directory_entry {
  590. public:
  591. // 30.10.12.1 constructors and destructor
  592. directory_entry() noexcept = default;
  593. directory_entry(const directory_entry &) = default;
  594. directory_entry(directory_entry &&) noexcept = default;
  595. #ifdef GHC_WITH_EXCEPTIONS
  596. explicit directory_entry(const path & p);
  597. #endif
  598. directory_entry(const path & p, std::error_code & ec);
  599. ~directory_entry();
  600. // assignments:
  601. directory_entry & operator=(const directory_entry &) = default;
  602. directory_entry & operator=(directory_entry &&) noexcept = default;
  603. // 30.10.12.2 modifiers
  604. #ifdef GHC_WITH_EXCEPTIONS
  605. void assign(const path & p);
  606. #endif
  607. void assign(const path & p, std::error_code & ec);
  608. #ifdef GHC_WITH_EXCEPTIONS
  609. void replace_filename(const path & p);
  610. #endif
  611. void replace_filename(const path & p, std::error_code & ec);
  612. #ifdef GHC_WITH_EXCEPTIONS
  613. void refresh();
  614. #endif
  615. void refresh(std::error_code & ec) noexcept;
  616. // 30.10.12.3 observers
  617. const filesystem::path & path() const noexcept;
  618. operator const filesystem::path &() const noexcept;
  619. #ifdef GHC_WITH_EXCEPTIONS
  620. bool exists() const;
  621. #endif
  622. bool exists(std::error_code & ec) const noexcept;
  623. #ifdef GHC_WITH_EXCEPTIONS
  624. bool is_block_file() const;
  625. #endif
  626. bool is_block_file(std::error_code & ec) const noexcept;
  627. #ifdef GHC_WITH_EXCEPTIONS
  628. bool is_character_file() const;
  629. #endif
  630. bool is_character_file(std::error_code & ec) const noexcept;
  631. #ifdef GHC_WITH_EXCEPTIONS
  632. bool is_directory() const;
  633. #endif
  634. bool is_directory(std::error_code & ec) const noexcept;
  635. #ifdef GHC_WITH_EXCEPTIONS
  636. bool is_fifo() const;
  637. #endif
  638. bool is_fifo(std::error_code & ec) const noexcept;
  639. #ifdef GHC_WITH_EXCEPTIONS
  640. bool is_other() const;
  641. #endif
  642. bool is_other(std::error_code & ec) const noexcept;
  643. #ifdef GHC_WITH_EXCEPTIONS
  644. bool is_regular_file() const;
  645. #endif
  646. bool is_regular_file(std::error_code & ec) const noexcept;
  647. #ifdef GHC_WITH_EXCEPTIONS
  648. bool is_socket() const;
  649. #endif
  650. bool is_socket(std::error_code & ec) const noexcept;
  651. #ifdef GHC_WITH_EXCEPTIONS
  652. bool is_symlink() const;
  653. #endif
  654. bool is_symlink(std::error_code & ec) const noexcept;
  655. #ifdef GHC_WITH_EXCEPTIONS
  656. uintmax_t file_size() const;
  657. #endif
  658. uintmax_t file_size(std::error_code & ec) const noexcept;
  659. #ifndef GHC_OS_WEB
  660. #ifdef GHC_WITH_EXCEPTIONS
  661. uintmax_t hard_link_count() const;
  662. #endif
  663. uintmax_t hard_link_count(std::error_code & ec) const noexcept;
  664. #endif
  665. #ifdef GHC_WITH_EXCEPTIONS
  666. file_time_type last_write_time() const;
  667. #endif
  668. file_time_type last_write_time(std::error_code & ec) const noexcept;
  669. #ifdef GHC_WITH_EXCEPTIONS
  670. file_status status() const;
  671. #endif
  672. file_status status(std::error_code & ec) const noexcept;
  673. #ifdef GHC_WITH_EXCEPTIONS
  674. file_status symlink_status() const;
  675. #endif
  676. file_status symlink_status(std::error_code & ec) const noexcept;
  677. bool operator<(const directory_entry & rhs) const noexcept;
  678. bool operator==(const directory_entry & rhs) const noexcept;
  679. bool operator!=(const directory_entry & rhs) const noexcept;
  680. bool operator<=(const directory_entry & rhs) const noexcept;
  681. bool operator>(const directory_entry & rhs) const noexcept;
  682. bool operator>=(const directory_entry & rhs) const noexcept;
  683. private:
  684. friend class directory_iterator;
  685. filesystem::path _path;
  686. file_status _status;
  687. file_status _symlink_status;
  688. uintmax_t _file_size = 0;
  689. #ifndef GHC_OS_WINDOWS
  690. uintmax_t _hard_link_count = 0;
  691. #endif
  692. time_t _last_write_time = 0;
  693. };
  694. // 30.10.13 Class directory_iterator
  695. class GHC_FS_API_CLASS directory_iterator {
  696. public:
  697. class GHC_FS_API_CLASS proxy {
  698. public:
  699. const directory_entry & operator*() const & noexcept {
  700. return _dir_entry;
  701. }
  702. directory_entry operator*() && noexcept { return std::move(_dir_entry); }
  703. private:
  704. explicit proxy(const directory_entry & dir_entry)
  705. : _dir_entry(dir_entry) {}
  706. friend class directory_iterator;
  707. friend class recursive_directory_iterator;
  708. directory_entry _dir_entry;
  709. };
  710. using iterator_category = std::input_iterator_tag;
  711. using value_type = directory_entry;
  712. using difference_type = std::ptrdiff_t;
  713. using pointer = const directory_entry *;
  714. using reference = const directory_entry &;
  715. // 30.10.13.1 member functions
  716. directory_iterator() noexcept;
  717. #ifdef GHC_WITH_EXCEPTIONS
  718. explicit directory_iterator(const path & p);
  719. directory_iterator(const path & p, directory_options options);
  720. #endif
  721. directory_iterator(const path & p, std::error_code & ec) noexcept;
  722. directory_iterator(const path & p, directory_options options,
  723. std::error_code & ec) noexcept;
  724. directory_iterator(const directory_iterator & rhs);
  725. directory_iterator(directory_iterator && rhs) noexcept;
  726. ~directory_iterator();
  727. directory_iterator & operator=(const directory_iterator & rhs);
  728. directory_iterator & operator=(directory_iterator && rhs) noexcept;
  729. const directory_entry & operator*() const;
  730. const directory_entry * operator->() const;
  731. #ifdef GHC_WITH_EXCEPTIONS
  732. directory_iterator & operator++();
  733. #endif
  734. directory_iterator & increment(std::error_code & ec) noexcept;
  735. // other members as required by 27.2.3, input iterators
  736. #ifdef GHC_WITH_EXCEPTIONS
  737. proxy operator++(int) {
  738. proxy p{**this};
  739. ++*this;
  740. return p;
  741. }
  742. #endif
  743. bool operator==(const directory_iterator & rhs) const;
  744. bool operator!=(const directory_iterator & rhs) const;
  745. private:
  746. friend class recursive_directory_iterator;
  747. class impl;
  748. std::shared_ptr<impl> _impl;
  749. };
  750. // 30.10.13.2 directory_iterator non-member functions
  751. GHC_FS_API directory_iterator begin(directory_iterator iter) noexcept;
  752. GHC_FS_API directory_iterator end(const directory_iterator &) noexcept;
  753. // 30.10.14 class recursive_directory_iterator
  754. class GHC_FS_API_CLASS recursive_directory_iterator {
  755. public:
  756. using iterator_category = std::input_iterator_tag;
  757. using value_type = directory_entry;
  758. using difference_type = std::ptrdiff_t;
  759. using pointer = const directory_entry *;
  760. using reference = const directory_entry &;
  761. // 30.10.14.1 constructors and destructor
  762. recursive_directory_iterator() noexcept;
  763. #ifdef GHC_WITH_EXCEPTIONS
  764. explicit recursive_directory_iterator(const path & p);
  765. recursive_directory_iterator(const path & p, directory_options options);
  766. #endif
  767. recursive_directory_iterator(const path & p, directory_options options,
  768. std::error_code & ec) noexcept;
  769. recursive_directory_iterator(const path & p, std::error_code & ec) noexcept;
  770. recursive_directory_iterator(const recursive_directory_iterator & rhs);
  771. recursive_directory_iterator(recursive_directory_iterator && rhs) noexcept;
  772. ~recursive_directory_iterator();
  773. // 30.10.14.1 observers
  774. directory_options options() const;
  775. int depth() const;
  776. bool recursion_pending() const;
  777. const directory_entry & operator*() const;
  778. const directory_entry * operator->() const;
  779. // 30.10.14.1 modifiers recursive_directory_iterator&
  780. recursive_directory_iterator &
  781. operator=(const recursive_directory_iterator & rhs);
  782. recursive_directory_iterator &
  783. operator=(recursive_directory_iterator && rhs) noexcept;
  784. #ifdef GHC_WITH_EXCEPTIONS
  785. recursive_directory_iterator & operator++();
  786. #endif
  787. recursive_directory_iterator & increment(std::error_code & ec) noexcept;
  788. #ifdef GHC_WITH_EXCEPTIONS
  789. void pop();
  790. #endif
  791. void pop(std::error_code & ec);
  792. void disable_recursion_pending();
  793. // other members as required by 27.2.3, input iterators
  794. #ifdef GHC_WITH_EXCEPTIONS
  795. directory_iterator::proxy operator++(int) {
  796. directory_iterator::proxy proxy{**this};
  797. ++*this;
  798. return proxy;
  799. }
  800. #endif
  801. bool operator==(const recursive_directory_iterator & rhs) const;
  802. bool operator!=(const recursive_directory_iterator & rhs) const;
  803. private:
  804. struct recursive_directory_iterator_impl {
  805. directory_options _options;
  806. bool _recursion_pending;
  807. std::stack<directory_iterator> _dir_iter_stack;
  808. recursive_directory_iterator_impl(directory_options options,
  809. bool recursion_pending)
  810. : _options(options), _recursion_pending(recursion_pending) {}
  811. };
  812. std::shared_ptr<recursive_directory_iterator_impl> _impl;
  813. };
  814. // 30.10.14.2 directory_iterator non-member functions
  815. GHC_FS_API recursive_directory_iterator
  816. begin(recursive_directory_iterator iter) noexcept;
  817. GHC_FS_API recursive_directory_iterator
  818. end(const recursive_directory_iterator &) noexcept;
  819. // 30.10.15 filesystem operations
  820. #ifdef GHC_WITH_EXCEPTIONS
  821. GHC_FS_API path absolute(const path & p);
  822. #endif
  823. GHC_FS_API path absolute(const path & p, std::error_code & ec);
  824. #ifdef GHC_WITH_EXCEPTIONS
  825. GHC_FS_API path canonical(const path & p);
  826. #endif
  827. GHC_FS_API path canonical(const path & p, std::error_code & ec);
  828. #ifdef GHC_WITH_EXCEPTIONS
  829. GHC_FS_API void copy(const path & from, const path & to);
  830. #endif
  831. GHC_FS_API void copy(const path & from, const path & to,
  832. std::error_code & ec) noexcept;
  833. #ifdef GHC_WITH_EXCEPTIONS
  834. GHC_FS_API void copy(const path & from, const path & to,
  835. copy_options options);
  836. #endif
  837. GHC_FS_API void copy(const path & from, const path & to,
  838. copy_options options, std::error_code & ec) noexcept;
  839. #ifdef GHC_WITH_EXCEPTIONS
  840. GHC_FS_API bool copy_file(const path & from, const path & to);
  841. #endif
  842. GHC_FS_API bool copy_file(const path & from, const path & to,
  843. std::error_code & ec) noexcept;
  844. #ifdef GHC_WITH_EXCEPTIONS
  845. GHC_FS_API bool copy_file(const path & from, const path & to,
  846. copy_options option);
  847. #endif
  848. GHC_FS_API bool copy_file(const path & from, const path & to,
  849. copy_options option,
  850. std::error_code & ec) noexcept;
  851. #ifdef GHC_WITH_EXCEPTIONS
  852. GHC_FS_API void copy_symlink(const path & existing_symlink,
  853. const path & new_symlink);
  854. #endif
  855. GHC_FS_API void copy_symlink(const path & existing_symlink,
  856. const path & new_symlink,
  857. std::error_code & ec) noexcept;
  858. #ifdef GHC_WITH_EXCEPTIONS
  859. GHC_FS_API bool create_directories(const path & p);
  860. #endif
  861. GHC_FS_API bool create_directories(const path & p,
  862. std::error_code & ec) noexcept;
  863. #ifdef GHC_WITH_EXCEPTIONS
  864. GHC_FS_API bool create_directory(const path & p);
  865. #endif
  866. GHC_FS_API bool create_directory(const path & p,
  867. std::error_code & ec) noexcept;
  868. #ifdef GHC_WITH_EXCEPTIONS
  869. GHC_FS_API bool create_directory(const path & p, const path & attributes);
  870. #endif
  871. GHC_FS_API bool create_directory(const path & p, const path & attributes,
  872. std::error_code & ec) noexcept;
  873. #ifdef GHC_WITH_EXCEPTIONS
  874. GHC_FS_API void create_directory_symlink(const path & to,
  875. const path & new_symlink);
  876. #endif
  877. GHC_FS_API void create_directory_symlink(const path & to,
  878. const path & new_symlink,
  879. std::error_code & ec) noexcept;
  880. #ifndef GHC_OS_WEB
  881. #ifdef GHC_WITH_EXCEPTIONS
  882. GHC_FS_API void create_hard_link(const path & to,
  883. const path & new_hard_link);
  884. #endif
  885. GHC_FS_API void create_hard_link(const path & to,
  886. const path & new_hard_link,
  887. std::error_code & ec) noexcept;
  888. #endif
  889. #ifdef GHC_WITH_EXCEPTIONS
  890. GHC_FS_API void create_symlink(const path & to, const path & new_symlink);
  891. #endif
  892. GHC_FS_API void create_symlink(const path & to, const path & new_symlink,
  893. std::error_code & ec) noexcept;
  894. #ifdef GHC_WITH_EXCEPTIONS
  895. GHC_FS_API path current_path();
  896. #endif
  897. GHC_FS_API path current_path(std::error_code & ec);
  898. #ifdef GHC_WITH_EXCEPTIONS
  899. GHC_FS_API void current_path(const path & p);
  900. #endif
  901. GHC_FS_API void current_path(const path & p, std::error_code & ec) noexcept;
  902. GHC_FS_API bool exists(file_status s) noexcept;
  903. #ifdef GHC_WITH_EXCEPTIONS
  904. GHC_FS_API bool exists(const path & p);
  905. #endif
  906. GHC_FS_API bool exists(const path & p, std::error_code & ec) noexcept;
  907. #ifdef GHC_WITH_EXCEPTIONS
  908. GHC_FS_API bool equivalent(const path & p1, const path & p2);
  909. #endif
  910. GHC_FS_API bool equivalent(const path & p1, const path & p2,
  911. std::error_code & ec) noexcept;
  912. #ifdef GHC_WITH_EXCEPTIONS
  913. GHC_FS_API uintmax_t file_size(const path & p);
  914. #endif
  915. GHC_FS_API uintmax_t file_size(const path & p,
  916. std::error_code & ec) noexcept;
  917. #ifndef GHC_OS_WEB
  918. #ifdef GHC_WITH_EXCEPTIONS
  919. GHC_FS_API uintmax_t hard_link_count(const path & p);
  920. #endif
  921. GHC_FS_API uintmax_t hard_link_count(const path & p,
  922. std::error_code & ec) noexcept;
  923. #endif
  924. GHC_FS_API bool is_block_file(file_status s) noexcept;
  925. #ifdef GHC_WITH_EXCEPTIONS
  926. GHC_FS_API bool is_block_file(const path & p);
  927. #endif
  928. GHC_FS_API bool is_block_file(const path & p,
  929. std::error_code & ec) noexcept;
  930. GHC_FS_API bool is_character_file(file_status s) noexcept;
  931. #ifdef GHC_WITH_EXCEPTIONS
  932. GHC_FS_API bool is_character_file(const path & p);
  933. #endif
  934. GHC_FS_API bool is_character_file(const path & p,
  935. std::error_code & ec) noexcept;
  936. GHC_FS_API bool is_directory(file_status s) noexcept;
  937. #ifdef GHC_WITH_EXCEPTIONS
  938. GHC_FS_API bool is_directory(const path & p);
  939. #endif
  940. GHC_FS_API bool is_directory(const path & p, std::error_code & ec) noexcept;
  941. #ifdef GHC_WITH_EXCEPTIONS
  942. GHC_FS_API bool is_empty(const path & p);
  943. #endif
  944. GHC_FS_API bool is_empty(const path & p, std::error_code & ec) noexcept;
  945. GHC_FS_API bool is_fifo(file_status s) noexcept;
  946. #ifdef GHC_WITH_EXCEPTIONS
  947. GHC_FS_API bool is_fifo(const path & p);
  948. #endif
  949. GHC_FS_API bool is_fifo(const path & p, std::error_code & ec) noexcept;
  950. GHC_FS_API bool is_other(file_status s) noexcept;
  951. #ifdef GHC_WITH_EXCEPTIONS
  952. GHC_FS_API bool is_other(const path & p);
  953. #endif
  954. GHC_FS_API bool is_other(const path & p, std::error_code & ec) noexcept;
  955. GHC_FS_API bool is_regular_file(file_status s) noexcept;
  956. #ifdef GHC_WITH_EXCEPTIONS
  957. GHC_FS_API bool is_regular_file(const path & p);
  958. #endif
  959. GHC_FS_API bool is_regular_file(const path & p,
  960. std::error_code & ec) noexcept;
  961. GHC_FS_API bool is_socket(file_status s) noexcept;
  962. #ifdef GHC_WITH_EXCEPTIONS
  963. GHC_FS_API bool is_socket(const path & p);
  964. #endif
  965. GHC_FS_API bool is_socket(const path & p, std::error_code & ec) noexcept;
  966. GHC_FS_API bool is_symlink(file_status s) noexcept;
  967. #ifdef GHC_WITH_EXCEPTIONS
  968. GHC_FS_API bool is_symlink(const path & p);
  969. #endif
  970. GHC_FS_API bool is_symlink(const path & p, std::error_code & ec) noexcept;
  971. #ifdef GHC_WITH_EXCEPTIONS
  972. GHC_FS_API file_time_type last_write_time(const path & p);
  973. #endif
  974. GHC_FS_API file_time_type last_write_time(const path & p,
  975. std::error_code & ec) noexcept;
  976. #ifdef GHC_WITH_EXCEPTIONS
  977. GHC_FS_API void last_write_time(const path & p, file_time_type new_time);
  978. #endif
  979. GHC_FS_API void last_write_time(const path & p, file_time_type new_time,
  980. std::error_code & ec) noexcept;
  981. #ifdef GHC_WITH_EXCEPTIONS
  982. GHC_FS_API void permissions(const path & p, perms prms,
  983. perm_options opts = perm_options::replace);
  984. #endif
  985. GHC_FS_API void permissions(const path & p, perms prms,
  986. std::error_code & ec) noexcept;
  987. GHC_FS_API void permissions(const path & p, perms prms, perm_options opts,
  988. std::error_code & ec);
  989. #ifdef GHC_WITH_EXCEPTIONS
  990. GHC_FS_API path proximate(const path & p, std::error_code & ec);
  991. GHC_FS_API path proximate(const path & p,
  992. const path & base = current_path());
  993. #endif
  994. GHC_FS_API path proximate(const path & p, const path & base,
  995. std::error_code & ec);
  996. #ifdef GHC_WITH_EXCEPTIONS
  997. GHC_FS_API path read_symlink(const path & p);
  998. #endif
  999. GHC_FS_API path read_symlink(const path & p, std::error_code & ec);
  1000. GHC_FS_API path relative(const path & p, std::error_code & ec);
  1001. #ifdef GHC_WITH_EXCEPTIONS
  1002. GHC_FS_API path relative(const path & p,
  1003. const path & base = current_path());
  1004. #endif
  1005. GHC_FS_API path relative(const path & p, const path & base,
  1006. std::error_code & ec);
  1007. #ifdef GHC_WITH_EXCEPTIONS
  1008. GHC_FS_API bool remove(const path & p);
  1009. #endif
  1010. GHC_FS_API bool remove(const path & p, std::error_code & ec) noexcept;
  1011. #ifdef GHC_WITH_EXCEPTIONS
  1012. GHC_FS_API uintmax_t remove_all(const path & p);
  1013. #endif
  1014. GHC_FS_API uintmax_t remove_all(const path & p,
  1015. std::error_code & ec) noexcept;
  1016. #ifdef GHC_WITH_EXCEPTIONS
  1017. GHC_FS_API void rename(const path & from, const path & to);
  1018. #endif
  1019. GHC_FS_API void rename(const path & from, const path & to,
  1020. std::error_code & ec) noexcept;
  1021. #ifdef GHC_WITH_EXCEPTIONS
  1022. GHC_FS_API void resize_file(const path & p, uintmax_t size);
  1023. #endif
  1024. GHC_FS_API void resize_file(const path & p, uintmax_t size,
  1025. std::error_code & ec) noexcept;
  1026. #ifdef GHC_WITH_EXCEPTIONS
  1027. GHC_FS_API space_info space(const path & p);
  1028. #endif
  1029. GHC_FS_API space_info space(const path & p, std::error_code & ec) noexcept;
  1030. #ifdef GHC_WITH_EXCEPTIONS
  1031. GHC_FS_API file_status status(const path & p);
  1032. #endif
  1033. GHC_FS_API file_status status(const path & p,
  1034. std::error_code & ec) noexcept;
  1035. GHC_FS_API bool status_known(file_status s) noexcept;
  1036. #ifdef GHC_WITH_EXCEPTIONS
  1037. GHC_FS_API file_status symlink_status(const path & p);
  1038. #endif
  1039. GHC_FS_API file_status symlink_status(const path & p,
  1040. std::error_code & ec) noexcept;
  1041. #ifdef GHC_WITH_EXCEPTIONS
  1042. GHC_FS_API path temp_directory_path();
  1043. #endif
  1044. GHC_FS_API path temp_directory_path(std::error_code & ec) noexcept;
  1045. #ifdef GHC_WITH_EXCEPTIONS
  1046. GHC_FS_API path weakly_canonical(const path & p);
  1047. #endif
  1048. GHC_FS_API path weakly_canonical(const path & p,
  1049. std::error_code & ec) noexcept;
  1050. // Non-C++17 add-on std::fstream wrappers with path
  1051. template <class charT, class traits = std::char_traits<charT>>
  1052. class basic_filebuf : public std::basic_filebuf<charT, traits> {
  1053. public:
  1054. basic_filebuf() {}
  1055. ~basic_filebuf() override {}
  1056. basic_filebuf(const basic_filebuf &) = delete;
  1057. const basic_filebuf & operator=(const basic_filebuf &) = delete;
  1058. basic_filebuf<charT, traits> * open(const path & p,
  1059. std::ios_base::openmode mode) {
  1060. #if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)
  1061. return std::basic_filebuf<charT, traits>::open(p.wstring().c_str(),
  1062. mode)
  1063. ? this
  1064. : 0;
  1065. #else
  1066. return std::basic_filebuf<charT, traits>::open(p.string().c_str(), mode)
  1067. ? this
  1068. : 0;
  1069. #endif
  1070. }
  1071. };
  1072. template <class charT, class traits = std::char_traits<charT>>
  1073. class basic_ifstream : public std::basic_ifstream<charT, traits> {
  1074. public:
  1075. basic_ifstream() {}
  1076. #if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)
  1077. explicit basic_ifstream(const path & p,
  1078. std::ios_base::openmode mode = std::ios_base::in)
  1079. : std::basic_ifstream<charT, traits>(p.wstring().c_str(), mode) {}
  1080. void open(const path & p,
  1081. std::ios_base::openmode mode = std::ios_base::in) {
  1082. std::basic_ifstream<charT, traits>::open(p.wstring().c_str(), mode);
  1083. }
  1084. #else
  1085. explicit basic_ifstream(const path & p,
  1086. std::ios_base::openmode mode = std::ios_base::in)
  1087. : std::basic_ifstream<charT, traits>(p.string().c_str(), mode) {}
  1088. void open(const path & p,
  1089. std::ios_base::openmode mode = std::ios_base::in) {
  1090. std::basic_ifstream<charT, traits>::open(p.string().c_str(), mode);
  1091. }
  1092. #endif
  1093. basic_ifstream(const basic_ifstream &) = delete;
  1094. const basic_ifstream & operator=(const basic_ifstream &) = delete;
  1095. ~basic_ifstream() override {}
  1096. };
  1097. template <class charT, class traits = std::char_traits<charT>>
  1098. class basic_ofstream : public std::basic_ofstream<charT, traits> {
  1099. public:
  1100. basic_ofstream() {}
  1101. #if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)
  1102. explicit basic_ofstream(const path & p,
  1103. std::ios_base::openmode mode = std::ios_base::out)
  1104. : std::basic_ofstream<charT, traits>(p.wstring().c_str(), mode) {}
  1105. void open(const path & p,
  1106. std::ios_base::openmode mode = std::ios_base::out) {
  1107. std::basic_ofstream<charT, traits>::open(p.wstring().c_str(), mode);
  1108. }
  1109. #else
  1110. explicit basic_ofstream(const path & p,
  1111. std::ios_base::openmode mode = std::ios_base::out)
  1112. : std::basic_ofstream<charT, traits>(p.string().c_str(), mode) {}
  1113. void open(const path & p,
  1114. std::ios_base::openmode mode = std::ios_base::out) {
  1115. std::basic_ofstream<charT, traits>::open(p.string().c_str(), mode);
  1116. }
  1117. #endif
  1118. basic_ofstream(const basic_ofstream &) = delete;
  1119. const basic_ofstream & operator=(const basic_ofstream &) = delete;
  1120. ~basic_ofstream() override {}
  1121. };
  1122. template <class charT, class traits = std::char_traits<charT>>
  1123. class basic_fstream : public std::basic_fstream<charT, traits> {
  1124. public:
  1125. basic_fstream() {}
  1126. #if defined(GHC_OS_WINDOWS) && !defined(__GLIBCXX__)
  1127. explicit basic_fstream(const path & p,
  1128. std::ios_base::openmode mode = std::ios_base::in |
  1129. std::ios_base::out)
  1130. : std::basic_fstream<charT, traits>(p.wstring().c_str(), mode) {}
  1131. void open(const path & p,
  1132. std::ios_base::openmode mode = std::ios_base::in |
  1133. std::ios_base::out) {
  1134. std::basic_fstream<charT, traits>::open(p.wstring().c_str(), mode);
  1135. }
  1136. #else
  1137. explicit basic_fstream(const path & p,
  1138. std::ios_base::openmode mode = std::ios_base::in |
  1139. std::ios_base::out)
  1140. : std::basic_fstream<charT, traits>(p.string().c_str(), mode) {}
  1141. void open(const path & p,
  1142. std::ios_base::openmode mode = std::ios_base::in |
  1143. std::ios_base::out) {
  1144. std::basic_fstream<charT, traits>::open(p.string().c_str(), mode);
  1145. }
  1146. #endif
  1147. basic_fstream(const basic_fstream &) = delete;
  1148. const basic_fstream & operator=(const basic_fstream &) = delete;
  1149. ~basic_fstream() override {}
  1150. };
  1151. typedef basic_filebuf<char> filebuf;
  1152. typedef basic_filebuf<wchar_t> wfilebuf;
  1153. typedef basic_ifstream<char> ifstream;
  1154. typedef basic_ifstream<wchar_t> wifstream;
  1155. typedef basic_ofstream<char> ofstream;
  1156. typedef basic_ofstream<wchar_t> wofstream;
  1157. typedef basic_fstream<char> fstream;
  1158. typedef basic_fstream<wchar_t> wfstream;
  1159. class GHC_FS_API_CLASS u8arguments {
  1160. public:
  1161. u8arguments(int & argc, char **& argv);
  1162. ~u8arguments() {
  1163. _refargc = _argc;
  1164. _refargv = _argv;
  1165. }
  1166. bool valid() const { return _isvalid; }
  1167. private:
  1168. int _argc;
  1169. char ** _argv;
  1170. int & _refargc;
  1171. char **& _refargv;
  1172. bool _isvalid;
  1173. #ifdef GHC_OS_WINDOWS
  1174. std::vector<std::string> _args;
  1175. std::vector<char *> _argp;
  1176. #endif
  1177. };
  1178. //-------------------------------------------------------------------------------------------------
  1179. // Implementation
  1180. //-------------------------------------------------------------------------------------------------
  1181. namespace detail {
  1182. // GHC_FS_API void postprocess_path_with_format(path::impl_string_type& p,
  1183. // path::format fmt);
  1184. enum utf8_states_t { S_STRT = 0, S_RJCT = 8 };
  1185. GHC_FS_API void appendUTF8(std::string & str, uint32_t unicode);
  1186. GHC_FS_API bool is_surrogate(uint32_t c);
  1187. GHC_FS_API bool is_high_surrogate(uint32_t c);
  1188. GHC_FS_API bool is_low_surrogate(uint32_t c);
  1189. GHC_FS_API unsigned consumeUtf8Fragment(const unsigned state,
  1190. const uint8_t fragment,
  1191. uint32_t & codepoint);
  1192. enum class portable_error {
  1193. none = 0,
  1194. exists,
  1195. not_found,
  1196. not_supported,
  1197. not_implemented,
  1198. invalid_argument,
  1199. is_a_directory,
  1200. };
  1201. GHC_FS_API std::error_code make_error_code(portable_error err);
  1202. #ifdef GHC_OS_WINDOWS
  1203. GHC_FS_API std::error_code make_system_error(uint32_t err = 0);
  1204. #else
  1205. GHC_FS_API std::error_code make_system_error(int err = 0);
  1206. #endif
  1207. } // namespace detail
  1208. namespace detail {
  1209. #ifdef GHC_EXPAND_IMPL
  1210. GHC_INLINE std::error_code make_error_code(portable_error err) {
  1211. #ifdef GHC_OS_WINDOWS
  1212. switch (err) {
  1213. case portable_error::none:
  1214. return std::error_code();
  1215. case portable_error::exists:
  1216. return std::error_code(ERROR_ALREADY_EXISTS, std::system_category());
  1217. case portable_error::not_found:
  1218. return std::error_code(ERROR_PATH_NOT_FOUND, std::system_category());
  1219. case portable_error::not_supported:
  1220. return std::error_code(ERROR_NOT_SUPPORTED, std::system_category());
  1221. case portable_error::not_implemented:
  1222. return std::error_code(ERROR_CALL_NOT_IMPLEMENTED,
  1223. std::system_category());
  1224. case portable_error::invalid_argument:
  1225. return std::error_code(ERROR_INVALID_PARAMETER,
  1226. std::system_category());
  1227. case portable_error::is_a_directory:
  1228. #ifdef ERROR_DIRECTORY_NOT_SUPPORTED
  1229. return std::error_code(ERROR_DIRECTORY_NOT_SUPPORTED,
  1230. std::system_category());
  1231. #else
  1232. return std::error_code(ERROR_NOT_SUPPORTED, std::system_category());
  1233. #endif
  1234. }
  1235. #else
  1236. switch (err) {
  1237. case portable_error::none:
  1238. return std::error_code();
  1239. case portable_error::exists:
  1240. return std::error_code(EEXIST, std::system_category());
  1241. case portable_error::not_found:
  1242. return std::error_code(ENOENT, std::system_category());
  1243. case portable_error::not_supported:
  1244. return std::error_code(ENOTSUP, std::system_category());
  1245. case portable_error::not_implemented:
  1246. return std::error_code(ENOSYS, std::system_category());
  1247. case portable_error::invalid_argument:
  1248. return std::error_code(EINVAL, std::system_category());
  1249. case portable_error::is_a_directory:
  1250. return std::error_code(EISDIR, std::system_category());
  1251. }
  1252. #endif
  1253. return std::error_code();
  1254. }
  1255. #ifdef GHC_OS_WINDOWS
  1256. GHC_INLINE std::error_code make_system_error(uint32_t err) {
  1257. return std::error_code(err ? static_cast<int>(err)
  1258. : static_cast<int>(::GetLastError()),
  1259. std::system_category());
  1260. }
  1261. #else
  1262. GHC_INLINE std::error_code make_system_error(int err) {
  1263. return std::error_code(err ? err : errno, std::system_category());
  1264. }
  1265. #endif
  1266. #endif // GHC_EXPAND_IMPL
  1267. template <typename Enum>
  1268. using EnableBitmask = typename std::enable_if<
  1269. std::is_same<Enum, perms>::value ||
  1270. std::is_same<Enum, perm_options>::value ||
  1271. std::is_same<Enum, copy_options>::value ||
  1272. std::is_same<Enum, directory_options>::value,
  1273. Enum>::type;
  1274. } // namespace detail
  1275. template <typename Enum>
  1276. detail::EnableBitmask<Enum> operator&(Enum X, Enum Y) {
  1277. using underlying = typename std::underlying_type<Enum>::type;
  1278. return static_cast<Enum>(static_cast<underlying>(X) &
  1279. static_cast<underlying>(Y));
  1280. }
  1281. template <typename Enum>
  1282. detail::EnableBitmask<Enum> operator|(Enum X, Enum Y) {
  1283. using underlying = typename std::underlying_type<Enum>::type;
  1284. return static_cast<Enum>(static_cast<underlying>(X) |
  1285. static_cast<underlying>(Y));
  1286. }
  1287. template <typename Enum>
  1288. detail::EnableBitmask<Enum> operator^(Enum X, Enum Y) {
  1289. using underlying = typename std::underlying_type<Enum>::type;
  1290. return static_cast<Enum>(static_cast<underlying>(X) ^
  1291. static_cast<underlying>(Y));
  1292. }
  1293. template <typename Enum> detail::EnableBitmask<Enum> operator~(Enum X) {
  1294. using underlying = typename std::underlying_type<Enum>::type;
  1295. return static_cast<Enum>(~static_cast<underlying>(X));
  1296. }
  1297. template <typename Enum>
  1298. detail::EnableBitmask<Enum> & operator&=(Enum & X, Enum Y) {
  1299. X = X & Y;
  1300. return X;
  1301. }
  1302. template <typename Enum>
  1303. detail::EnableBitmask<Enum> & operator|=(Enum & X, Enum Y) {
  1304. X = X | Y;
  1305. return X;
  1306. }
  1307. template <typename Enum>
  1308. detail::EnableBitmask<Enum> & operator^=(Enum & X, Enum Y) {
  1309. X = X ^ Y;
  1310. return X;
  1311. }
  1312. #ifdef GHC_EXPAND_IMPL
  1313. namespace detail {
  1314. GHC_INLINE bool in_range(uint32_t c, uint32_t lo, uint32_t hi) {
  1315. return (static_cast<uint32_t>(c - lo) < (hi - lo + 1));
  1316. }
  1317. GHC_INLINE bool is_surrogate(uint32_t c) {
  1318. return in_range(c, 0xd800, 0xdfff);
  1319. }
  1320. GHC_INLINE bool is_high_surrogate(uint32_t c) {
  1321. return (c & 0xfffffc00) == 0xd800;
  1322. }
  1323. GHC_INLINE bool is_low_surrogate(uint32_t c) {
  1324. return (c & 0xfffffc00) == 0xdc00;
  1325. }
  1326. GHC_INLINE void appendUTF8(std::string & str, uint32_t unicode) {
  1327. if (unicode <= 0x7f) {
  1328. str.push_back(static_cast<char>(unicode));
  1329. } else if (unicode >= 0x80 && unicode <= 0x7ff) {
  1330. str.push_back(static_cast<char>((unicode >> 6) + 192));
  1331. str.push_back(static_cast<char>((unicode & 0x3f) + 128));
  1332. } else if ((unicode >= 0x800 && unicode <= 0xd7ff) ||
  1333. (unicode >= 0xe000 && unicode <= 0xffff)) {
  1334. str.push_back(static_cast<char>((unicode >> 12) + 224));
  1335. str.push_back(static_cast<char>(((unicode & 0xfff) >> 6) + 128));
  1336. str.push_back(static_cast<char>((unicode & 0x3f) + 128));
  1337. } else if (unicode >= 0x10000 && unicode <= 0x10ffff) {
  1338. str.push_back(static_cast<char>((unicode >> 18) + 240));
  1339. str.push_back(static_cast<char>(((unicode & 0x3ffff) >> 12) + 128));
  1340. str.push_back(static_cast<char>(((unicode & 0xfff) >> 6) + 128));
  1341. str.push_back(static_cast<char>((unicode & 0x3f) + 128));
  1342. } else {
  1343. #ifdef GHC_RAISE_UNICODE_ERRORS
  1344. throw filesystem_error(
  1345. "Illegal code point for unicode character.", str,
  1346. std::make_error_code(std::errc::illegal_byte_sequence));
  1347. #else
  1348. appendUTF8(str, 0xfffd);
  1349. #endif
  1350. }
  1351. }
  1352. // Thanks to Bjoern Hoehrmann
  1353. // (https://bjoern.hoehrmann.de/utf-8/decoder/dfa/) and Taylor R Campbell
  1354. // for the ideas to this DFA approach of UTF-8 decoding; Generating
  1355. // debugging and shrinking my own DFA from scratch was a day of fun!
  1356. GHC_INLINE unsigned consumeUtf8Fragment(const unsigned state,
  1357. const uint8_t fragment,
  1358. uint32_t & codepoint) {
  1359. static const uint32_t utf8_state_info[] = {
  1360. // encoded states
  1361. 0x11111111u, 0x11111111u, 0x77777777u, 0x77777777u, 0x88888888u,
  1362. 0x88888888u, 0x88888888u, 0x88888888u, 0x22222299u, 0x22222222u,
  1363. 0x22222222u, 0x22222222u, 0x3333333au, 0x33433333u, 0x9995666bu,
  1364. 0x99999999u, 0x88888880u, 0x22818108u, 0x88888881u, 0x88888882u,
  1365. 0x88888884u, 0x88888887u, 0x88888886u, 0x82218108u, 0x82281108u,
  1366. 0x88888888u, 0x88888883u, 0x88888885u, 0u, 0u,
  1367. 0u, 0u,
  1368. };
  1369. uint8_t category = fragment < 128
  1370. ? 0
  1371. : (utf8_state_info[(fragment >> 3) & 0xf] >>
  1372. ((fragment & 7) << 2)) &
  1373. 0xf;
  1374. codepoint = (state ? (codepoint << 6) | (fragment & 0x3fu)
  1375. : (0xffu >> category) & fragment);
  1376. return state == S_RJCT
  1377. ? static_cast<unsigned>(S_RJCT)
  1378. : static_cast<unsigned>(
  1379. (utf8_state_info[category + 16] >> (state << 2)) &
  1380. 0xf);
  1381. }
  1382. GHC_INLINE bool validUtf8(const std::string & utf8String) {
  1383. std::string::const_iterator iter = utf8String.begin();
  1384. unsigned utf8_state = S_STRT;
  1385. std::uint32_t codepoint = 0;
  1386. while (iter < utf8String.end()) {
  1387. if ((utf8_state = consumeUtf8Fragment(utf8_state,
  1388. static_cast<uint8_t>(*iter++),
  1389. codepoint)) == S_RJCT) {
  1390. return false;
  1391. }
  1392. }
  1393. if (utf8_state) { return false; }
  1394. return true;
  1395. }
  1396. } // namespace detail
  1397. #endif
  1398. namespace detail {
  1399. template <class StringType, typename std::enable_if<(
  1400. sizeof(typename StringType::value_type) ==
  1401. 1)>::type * = nullptr>
  1402. inline StringType
  1403. fromUtf8(const std::string & utf8String,
  1404. const typename StringType::allocator_type & alloc =
  1405. typename StringType::allocator_type()) {
  1406. return StringType(utf8String.begin(), utf8String.end(), alloc);
  1407. }
  1408. template <class StringType, typename std::enable_if<(
  1409. sizeof(typename StringType::value_type) ==
  1410. 2)>::type * = nullptr>
  1411. inline StringType
  1412. fromUtf8(const std::string & utf8String,
  1413. const typename StringType::allocator_type & alloc =
  1414. typename StringType::allocator_type()) {
  1415. StringType result(alloc);
  1416. result.reserve(utf8String.length());
  1417. std::string::const_iterator iter = utf8String.begin();
  1418. unsigned utf8_state = S_STRT;
  1419. std::uint32_t codepoint = 0;
  1420. while (iter < utf8String.end()) {
  1421. if ((utf8_state = consumeUtf8Fragment(utf8_state,
  1422. static_cast<uint8_t>(*iter++),
  1423. codepoint)) == S_STRT) {
  1424. if (codepoint <= 0xffff) {
  1425. result += static_cast<typename StringType::value_type>(codepoint);
  1426. } else {
  1427. codepoint -= 0x10000;
  1428. result += static_cast<typename StringType::value_type>(
  1429. (codepoint >> 10) + 0xd800);
  1430. result += static_cast<typename StringType::value_type>(
  1431. (codepoint & 0x3ff) + 0xdc00);
  1432. }
  1433. codepoint = 0;
  1434. } else if (utf8_state == S_RJCT) {
  1435. #ifdef GHC_RAISE_UNICODE_ERRORS
  1436. throw filesystem_error(
  1437. "Illegal byte sequence for unicode character.", utf8String,
  1438. std::make_error_code(std::errc::illegal_byte_sequence));
  1439. #else
  1440. result += static_cast<typename StringType::value_type>(0xfffd);
  1441. utf8_state = S_STRT;
  1442. codepoint = 0;
  1443. #endif
  1444. }
  1445. }
  1446. if (utf8_state) {
  1447. #ifdef GHC_RAISE_UNICODE_ERRORS
  1448. throw filesystem_error(
  1449. "Illegal byte sequence for unicode character.", utf8String,
  1450. std::make_error_code(std::errc::illegal_byte_sequence));
  1451. #else
  1452. result += static_cast<typename StringType::value_type>(0xfffd);
  1453. #endif
  1454. }
  1455. return result;
  1456. }
  1457. template <class StringType, typename std::enable_if<(
  1458. sizeof(typename StringType::value_type) ==
  1459. 4)>::type * = nullptr>
  1460. inline StringType
  1461. fromUtf8(const std::string & utf8String,
  1462. const typename StringType::allocator_type & alloc =
  1463. typename StringType::allocator_type()) {
  1464. StringType result(alloc);
  1465. result.reserve(utf8String.length());
  1466. std::string::const_iterator iter = utf8String.begin();
  1467. unsigned utf8_state = S_STRT;
  1468. std::uint32_t codepoint = 0;
  1469. while (iter < utf8String.end()) {
  1470. if ((utf8_state = consumeUtf8Fragment(utf8_state,
  1471. static_cast<uint8_t>(*iter++),
  1472. codepoint)) == S_STRT) {
  1473. result += static_cast<typename StringType::value_type>(codepoint);
  1474. codepoint = 0;
  1475. } else if (utf8_state == S_RJCT) {
  1476. #ifdef GHC_RAISE_UNICODE_ERRORS
  1477. throw filesystem_error(
  1478. "Illegal byte sequence for unicode character.", utf8String,
  1479. std::make_error_code(std::errc::illegal_byte_sequence));
  1480. #else
  1481. result += static_cast<typename StringType::value_type>(0xfffd);
  1482. utf8_state = S_STRT;
  1483. codepoint = 0;
  1484. #endif
  1485. }
  1486. }
  1487. if (utf8_state) {
  1488. #ifdef GHC_RAISE_UNICODE_ERRORS
  1489. throw filesystem_error(
  1490. "Illegal byte sequence for unicode character.", utf8String,
  1491. std::make_error_code(std::errc::illegal_byte_sequence));
  1492. #else
  1493. result += static_cast<typename StringType::value_type>(0xfffd);
  1494. #endif
  1495. }
  1496. return result;
  1497. }
  1498. template <
  1499. typename charT, typename traits, typename Alloc,
  1500. typename std::enable_if<(sizeof(charT) == 1), int>::type size = 1>
  1501. inline std::string
  1502. toUtf8(const std::basic_string<charT, traits, Alloc> & unicodeString) {
  1503. return std::string(unicodeString.begin(), unicodeString.end());
  1504. }
  1505. template <
  1506. typename charT, typename traits, typename Alloc,
  1507. typename std::enable_if<(sizeof(charT) == 2), int>::type size = 2>
  1508. inline std::string
  1509. toUtf8(const std::basic_string<charT, traits, Alloc> & unicodeString) {
  1510. std::string result;
  1511. for (auto iter = unicodeString.begin(); iter != unicodeString.end();
  1512. ++iter) {
  1513. char32_t c = *iter;
  1514. if (is_surrogate(c)) {
  1515. ++iter;
  1516. if (iter != unicodeString.end() && is_high_surrogate(c) &&
  1517. is_low_surrogate(*iter)) {
  1518. appendUTF8(result, (char32_t(c) << 10) + *iter - 0x35fdc00);
  1519. } else {
  1520. #ifdef GHC_RAISE_UNICODE_ERRORS
  1521. throw filesystem_error(
  1522. "Illegal code point for unicode character.", result,
  1523. std::make_error_code(std::errc::illegal_byte_sequence));
  1524. #else
  1525. appendUTF8(result, 0xfffd);
  1526. if (iter == unicodeString.end()) { break; }
  1527. #endif
  1528. }
  1529. } else {
  1530. appendUTF8(result, c);
  1531. }
  1532. }
  1533. return result;
  1534. }
  1535. template <
  1536. typename charT, typename traits, typename Alloc,
  1537. typename std::enable_if<(sizeof(charT) == 4), int>::type size = 4>
  1538. inline std::string
  1539. toUtf8(const std::basic_string<charT, traits, Alloc> & unicodeString) {
  1540. std::string result;
  1541. for (auto c : unicodeString) {
  1542. appendUTF8(result, static_cast<uint32_t>(c));
  1543. }
  1544. return result;
  1545. }
  1546. template <typename charT>
  1547. inline std::string toUtf8(const charT * unicodeString) {
  1548. return toUtf8(
  1549. std::basic_string<charT, std::char_traits<charT>>(unicodeString));
  1550. }
  1551. } // namespace detail
  1552. #ifdef GHC_EXPAND_IMPL
  1553. namespace detail {
  1554. GHC_INLINE bool startsWith(const std::string & what,
  1555. const std::string & with) {
  1556. return with.length() <= what.length() &&
  1557. equal(with.begin(), with.end(), what.begin());
  1558. }
  1559. } // namespace detail
  1560. GHC_INLINE void
  1561. path::postprocess_path_with_format(path::impl_string_type & p,
  1562. path::format fmt) {
  1563. #ifdef GHC_RAISE_UNICODE_ERRORS
  1564. if (!detail::validUtf8(p)) {
  1565. path t;
  1566. t._path = p;
  1567. throw filesystem_error(
  1568. "Illegal byte sequence for unicode character.", t,
  1569. std::make_error_code(std::errc::illegal_byte_sequence));
  1570. }
  1571. #endif
  1572. switch (fmt) {
  1573. #ifndef GHC_OS_WINDOWS
  1574. case path::auto_format:
  1575. case path::native_format:
  1576. #endif
  1577. case path::generic_format:
  1578. // nothing to do
  1579. break;
  1580. #ifdef GHC_OS_WINDOWS
  1581. case path::auto_format:
  1582. case path::native_format:
  1583. if (detail::startsWith(p, std::string("\\\\?\\"))) {
  1584. // remove Windows long filename marker
  1585. p.erase(0, 4);
  1586. if (detail::startsWith(p, std::string("UNC\\"))) {
  1587. p.erase(0, 2);
  1588. p[0] = '\\';
  1589. }
  1590. }
  1591. for (auto & c : p) {
  1592. if (c == '\\') { c = '/'; }
  1593. }
  1594. break;
  1595. #endif
  1596. }
  1597. if (p.length() > 2 && p[0] == '/' && p[1] == '/' && p[2] != '/') {
  1598. std::string::iterator new_end =
  1599. std::unique(p.begin() + 2, p.end(),
  1600. [](path::value_type lhs, path::value_type rhs) {
  1601. return lhs == rhs && lhs == '/';
  1602. });
  1603. p.erase(new_end, p.end());
  1604. } else {
  1605. std::string::iterator new_end = std::unique(
  1606. p.begin(), p.end(), [](path::value_type lhs, path::value_type rhs) {
  1607. return lhs == rhs && lhs == '/';
  1608. });
  1609. p.erase(new_end, p.end());
  1610. }
  1611. }
  1612. #endif // GHC_EXPAND_IMPL
  1613. template <class Source, typename>
  1614. inline path::path(const Source & source, format fmt)
  1615. : _path(detail::toUtf8(source)) {
  1616. postprocess_path_with_format(_path, fmt);
  1617. }
  1618. template <> inline path::path(const std::wstring & source, format fmt) {
  1619. _path = detail::toUtf8(source);
  1620. postprocess_path_with_format(_path, fmt);
  1621. }
  1622. template <> inline path::path(const std::u16string & source, format fmt) {
  1623. _path = detail::toUtf8(source);
  1624. postprocess_path_with_format(_path, fmt);
  1625. }
  1626. template <> inline path::path(const std::u32string & source, format fmt) {
  1627. _path = detail::toUtf8(source);
  1628. postprocess_path_with_format(_path, fmt);
  1629. }
  1630. #ifdef __cpp_lib_string_view
  1631. template <> inline path::path(const std::string_view & source, format fmt) {
  1632. _path = detail::toUtf8(std::string(source));
  1633. postprocess_path_with_format(_path, fmt);
  1634. }
  1635. #ifdef GHC_USE_WCHAR_T
  1636. template <>
  1637. inline path::path(const std::wstring_view & source, format fmt) {
  1638. _path = detail::toUtf8(std::wstring(source).c_str());
  1639. postprocess_path_with_format(_path, fmt);
  1640. }
  1641. #endif
  1642. #endif
  1643. template <class Source, typename>
  1644. inline path u8path(const Source & source) {
  1645. return path(source);
  1646. }
  1647. template <class InputIterator>
  1648. inline path u8path(InputIterator first, InputIterator last) {
  1649. return path(first, last);
  1650. }
  1651. template <class InputIterator>
  1652. inline path::path(InputIterator first, InputIterator last, format fmt)
  1653. : path(std::basic_string<
  1654. typename std::iterator_traits<InputIterator>::value_type>(
  1655. first, last),
  1656. fmt) {
  1657. // delegated
  1658. }
  1659. #ifdef GHC_EXPAND_IMPL
  1660. namespace detail {
  1661. GHC_INLINE bool equals_simple_insensitive(const char * str1,
  1662. const char * str2) {
  1663. #ifdef GHC_OS_WINDOWS
  1664. #ifdef __GNUC__
  1665. while (::tolower((unsigned char)*str1) ==
  1666. ::tolower((unsigned char)*str2++)) {
  1667. if (*str1++ == 0) return true;
  1668. }
  1669. return false;
  1670. #else
  1671. return 0 == ::_stricmp(str1, str2);
  1672. #endif
  1673. #else
  1674. return 0 == ::strcasecmp(str1, str2);
  1675. #endif
  1676. }
  1677. GHC_INLINE const char * strerror_adapter(char * gnu, char *) {
  1678. return gnu;
  1679. }
  1680. GHC_INLINE const char * strerror_adapter(int posix, char * buffer) {
  1681. if (posix) { return "Error in strerror_r!"; }
  1682. return buffer;
  1683. }
  1684. template <typename ErrorNumber>
  1685. GHC_INLINE std::string systemErrorText(ErrorNumber code = 0) {
  1686. #if defined(GHC_OS_WINDOWS)
  1687. LPVOID msgBuf;
  1688. DWORD dw = code ? static_cast<DWORD>(code) : ::GetLastError();
  1689. FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1690. FORMAT_MESSAGE_FROM_SYSTEM |
  1691. FORMAT_MESSAGE_IGNORE_INSERTS,
  1692. NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  1693. (LPWSTR)&msgBuf, 0, NULL);
  1694. std::string msg = toUtf8(std::wstring((LPWSTR)msgBuf));
  1695. LocalFree(msgBuf);
  1696. return msg;
  1697. #else
  1698. char buffer[512];
  1699. return strerror_adapter(
  1700. strerror_r(code ? code : errno, buffer, sizeof(buffer)), buffer);
  1701. #endif
  1702. }
  1703. #ifdef GHC_OS_WINDOWS
  1704. using CreateSymbolicLinkW_fp = BOOLEAN(WINAPI *)(LPCWSTR, LPCWSTR, DWORD);
  1705. using CreateHardLinkW_fp = BOOLEAN(WINAPI *)(LPCWSTR, LPCWSTR,
  1706. LPSECURITY_ATTRIBUTES);
  1707. GHC_INLINE void create_symlink(const path & target_name,
  1708. const path & new_symlink,
  1709. bool to_directory, std::error_code & ec) {
  1710. std::error_code tec;
  1711. auto fs = status(target_name, tec);
  1712. if ((fs.type() == file_type::directory && !to_directory) ||
  1713. (fs.type() == file_type::regular && to_directory)) {
  1714. ec = detail::make_error_code(detail::portable_error::not_supported);
  1715. return;
  1716. }
  1717. #if defined(__GNUC__) && __GNUC__ >= 8
  1718. #pragma GCC diagnostic push
  1719. #pragma GCC diagnostic ignored "-Wcast-function-type"
  1720. #endif
  1721. static CreateSymbolicLinkW_fp api_call =
  1722. reinterpret_cast<CreateSymbolicLinkW_fp>(GetProcAddress(
  1723. GetModuleHandleW(L"kernel32.dll"), "CreateSymbolicLinkW"));
  1724. #if defined(__GNUC__) && __GNUC__ >= 8
  1725. #pragma GCC diagnostic pop
  1726. #endif
  1727. if (api_call) {
  1728. if (api_call(detail::fromUtf8<std::wstring>(new_symlink.u8string())
  1729. .c_str(),
  1730. detail::fromUtf8<std::wstring>(target_name.u8string())
  1731. .c_str(),
  1732. to_directory ? 1 : 0) == 0) {
  1733. auto result = ::GetLastError();
  1734. if (result == ERROR_PRIVILEGE_NOT_HELD &&
  1735. api_call(detail::fromUtf8<std::wstring>(new_symlink.u8string())
  1736. .c_str(),
  1737. detail::fromUtf8<std::wstring>(target_name.u8string())
  1738. .c_str(),
  1739. to_directory ? 3 : 2) != 0) {
  1740. return;
  1741. }
  1742. ec = detail::make_system_error(result);
  1743. }
  1744. } else {
  1745. ec = detail::make_system_error(ERROR_NOT_SUPPORTED);
  1746. }
  1747. }
  1748. GHC_INLINE void create_hardlink(const path & target_name,
  1749. const path & new_hardlink,
  1750. std::error_code & ec) {
  1751. #if defined(__GNUC__) && __GNUC__ >= 8
  1752. #pragma GCC diagnostic push
  1753. #pragma GCC diagnostic ignored "-Wcast-function-type"
  1754. #endif
  1755. static CreateHardLinkW_fp api_call =
  1756. reinterpret_cast<CreateHardLinkW_fp>(GetProcAddress(
  1757. GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW"));
  1758. #if defined(__GNUC__) && __GNUC__ >= 8
  1759. #pragma GCC diagnostic pop
  1760. #endif
  1761. if (api_call) {
  1762. if (api_call(detail::fromUtf8<std::wstring>(new_hardlink.u8string())
  1763. .c_str(),
  1764. detail::fromUtf8<std::wstring>(target_name.u8string())
  1765. .c_str(),
  1766. NULL) == 0) {
  1767. ec = detail::make_system_error();
  1768. }
  1769. } else {
  1770. ec = detail::make_system_error(ERROR_NOT_SUPPORTED);
  1771. }
  1772. }
  1773. #else
  1774. GHC_INLINE void create_symlink(const path & target_name,
  1775. const path & new_symlink, bool,
  1776. std::error_code & ec) {
  1777. if (::symlink(target_name.c_str(), new_symlink.c_str()) != 0) {
  1778. ec = detail::make_system_error();
  1779. }
  1780. }
  1781. #ifndef GHC_OS_WEB
  1782. GHC_INLINE void create_hardlink(const path & target_name,
  1783. const path & new_hardlink,
  1784. std::error_code & ec) {
  1785. if (::link(target_name.c_str(), new_hardlink.c_str()) != 0) {
  1786. ec = detail::make_system_error();
  1787. }
  1788. }
  1789. #endif
  1790. #endif
  1791. template <typename T>
  1792. GHC_INLINE file_status file_status_from_st_mode(T mode) {
  1793. #ifdef GHC_OS_WINDOWS
  1794. file_type ft = file_type::unknown;
  1795. if ((mode & _S_IFDIR) == _S_IFDIR) {
  1796. ft = file_type::directory;
  1797. } else if ((mode & _S_IFREG) == _S_IFREG) {
  1798. ft = file_type::regular;
  1799. } else if ((mode & _S_IFCHR) == _S_IFCHR) {
  1800. ft = file_type::character;
  1801. }
  1802. perms prms = static_cast<perms>(mode & 0xfff);
  1803. return file_status(ft, prms);
  1804. #else
  1805. file_type ft = file_type::unknown;
  1806. if (S_ISDIR(mode)) {
  1807. ft = file_type::directory;
  1808. } else if (S_ISREG(mode)) {
  1809. ft = file_type::regular;
  1810. } else if (S_ISCHR(mode)) {
  1811. ft = file_type::character;
  1812. } else if (S_ISBLK(mode)) {
  1813. ft = file_type::block;
  1814. } else if (S_ISFIFO(mode)) {
  1815. ft = file_type::fifo;
  1816. } else if (S_ISLNK(mode)) {
  1817. ft = file_type::symlink;
  1818. } else if (S_ISSOCK(mode)) {
  1819. ft = file_type::socket;
  1820. }
  1821. perms prms = static_cast<perms>(mode & 0xfff);
  1822. return file_status(ft, prms);
  1823. #endif
  1824. }
  1825. GHC_INLINE path resolveSymlink(const path & p, std::error_code & ec) {
  1826. #ifdef GHC_OS_WINDOWS
  1827. #ifndef REPARSE_DATA_BUFFER_HEADER_SIZE
  1828. typedef struct _REPARSE_DATA_BUFFER {
  1829. ULONG ReparseTag;
  1830. USHORT ReparseDataLength;
  1831. USHORT Reserved;
  1832. union {
  1833. struct {
  1834. USHORT SubstituteNameOffset;
  1835. USHORT SubstituteNameLength;
  1836. USHORT PrintNameOffset;
  1837. USHORT PrintNameLength;
  1838. ULONG Flags;
  1839. WCHAR PathBuffer[1];
  1840. } SymbolicLinkReparseBuffer;
  1841. struct {
  1842. USHORT SubstituteNameOffset;
  1843. USHORT SubstituteNameLength;
  1844. USHORT PrintNameOffset;
  1845. USHORT PrintNameLength;
  1846. WCHAR PathBuffer[1];
  1847. } MountPointReparseBuffer;
  1848. struct {
  1849. UCHAR DataBuffer[1];
  1850. } GenericReparseBuffer;
  1851. } DUMMYUNIONNAME;
  1852. } REPARSE_DATA_BUFFER;
  1853. #ifndef MAXIMUM_REPARSE_DATA_BUFFER_SIZE
  1854. #define MAXIMUM_REPARSE_DATA_BUFFER_SIZE (16 * 1024)
  1855. #endif
  1856. #endif
  1857. std::shared_ptr<void> file(
  1858. CreateFileW(
  1859. p.wstring().c_str(), 0,
  1860. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0,
  1861. OPEN_EXISTING,
  1862. FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, 0),
  1863. CloseHandle);
  1864. if (file.get() == INVALID_HANDLE_VALUE) {
  1865. ec = detail::make_system_error();
  1866. return path();
  1867. }
  1868. std::shared_ptr<REPARSE_DATA_BUFFER> reparseData(
  1869. (REPARSE_DATA_BUFFER *)std::calloc(
  1870. 1, MAXIMUM_REPARSE_DATA_BUFFER_SIZE),
  1871. std::free);
  1872. ULONG bufferUsed;
  1873. path result;
  1874. if (DeviceIoControl(file.get(), FSCTL_GET_REPARSE_POINT, 0, 0,
  1875. reparseData.get(), MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
  1876. &bufferUsed, 0)) {
  1877. if (IsReparseTagMicrosoft(reparseData->ReparseTag)) {
  1878. switch (reparseData->ReparseTag) {
  1879. case IO_REPARSE_TAG_SYMLINK:
  1880. result = std::wstring(
  1881. &reparseData->SymbolicLinkReparseBuffer.PathBuffer
  1882. [reparseData->SymbolicLinkReparseBuffer.PrintNameOffset /
  1883. sizeof(WCHAR)],
  1884. reparseData->SymbolicLinkReparseBuffer.PrintNameLength /
  1885. sizeof(WCHAR));
  1886. break;
  1887. case IO_REPARSE_TAG_MOUNT_POINT:
  1888. result = std::wstring(
  1889. &reparseData->MountPointReparseBuffer.PathBuffer
  1890. [reparseData->MountPointReparseBuffer.PrintNameOffset /
  1891. sizeof(WCHAR)],
  1892. reparseData->MountPointReparseBuffer.PrintNameLength /
  1893. sizeof(WCHAR));
  1894. break;
  1895. default:
  1896. break;
  1897. }
  1898. }
  1899. } else {
  1900. ec = detail::make_system_error();
  1901. }
  1902. return result;
  1903. #else
  1904. size_t bufferSize = 256;
  1905. while (true) {
  1906. std::vector<char> buffer(bufferSize, static_cast<char>(0));
  1907. auto rc = ::readlink(p.c_str(), buffer.data(), buffer.size());
  1908. if (rc < 0) {
  1909. ec = detail::make_system_error();
  1910. return path();
  1911. } else if (rc < static_cast<int>(bufferSize)) {
  1912. return path(std::string(buffer.data(),
  1913. static_cast<std::string::size_type>(rc)));
  1914. }
  1915. bufferSize *= 2;
  1916. }
  1917. return path();
  1918. #endif
  1919. }
  1920. #ifdef GHC_OS_WINDOWS
  1921. GHC_INLINE time_t timeFromFILETIME(const FILETIME & ft) {
  1922. ULARGE_INTEGER ull;
  1923. ull.LowPart = ft.dwLowDateTime;
  1924. ull.HighPart = ft.dwHighDateTime;
  1925. return static_cast<time_t>(ull.QuadPart / 10000000ULL - 11644473600ULL);
  1926. }
  1927. GHC_INLINE void timeToFILETIME(time_t t, FILETIME & ft) {
  1928. LONGLONG ll;
  1929. ll = Int32x32To64(t, 10000000) + 116444736000000000;
  1930. ft.dwLowDateTime = static_cast<DWORD>(ll);
  1931. ft.dwHighDateTime = static_cast<DWORD>(ll >> 32);
  1932. }
  1933. template <typename INFO>
  1934. GHC_INLINE uintmax_t hard_links_from_INFO(const INFO * info) {
  1935. return static_cast<uintmax_t>(-1);
  1936. }
  1937. template <>
  1938. GHC_INLINE uintmax_t hard_links_from_INFO<BY_HANDLE_FILE_INFORMATION>(
  1939. const BY_HANDLE_FILE_INFORMATION * info) {
  1940. return info->nNumberOfLinks;
  1941. }
  1942. template <typename INFO>
  1943. GHC_INLINE file_status status_from_INFO(const path & p, const INFO * info,
  1944. std::error_code &,
  1945. uintmax_t * sz = nullptr,
  1946. time_t * lwt = nullptr) noexcept {
  1947. file_type ft = file_type::unknown;
  1948. if ((info->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
  1949. ft = file_type::symlink;
  1950. } else {
  1951. if ((info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  1952. ft = file_type::directory;
  1953. } else {
  1954. ft = file_type::regular;
  1955. }
  1956. }
  1957. perms prms = perms::owner_read | perms::group_read | perms::others_read;
  1958. if (!(info->dwFileAttributes & FILE_ATTRIBUTE_READONLY)) {
  1959. prms = prms | perms::owner_write | perms::group_write |
  1960. perms::others_write;
  1961. }
  1962. std::string ext = p.extension().generic_string();
  1963. if (equals_simple_insensitive(ext.c_str(), ".exe") ||
  1964. equals_simple_insensitive(ext.c_str(), ".cmd") ||
  1965. equals_simple_insensitive(ext.c_str(), ".bat") ||
  1966. equals_simple_insensitive(ext.c_str(), ".com")) {
  1967. prms =
  1968. prms | perms::owner_exec | perms::group_exec | perms::others_exec;
  1969. }
  1970. if (sz) {
  1971. *sz = static_cast<uintmax_t>(info->nFileSizeHigh)
  1972. << (sizeof(info->nFileSizeHigh) * 8) |
  1973. info->nFileSizeLow;
  1974. }
  1975. if (lwt) { *lwt = detail::timeFromFILETIME(info->ftLastWriteTime); }
  1976. return file_status(ft, prms);
  1977. }
  1978. #endif
  1979. GHC_INLINE bool is_not_found_error(std::error_code & ec) {
  1980. #ifdef GHC_OS_WINDOWS
  1981. return ec.value() == ERROR_FILE_NOT_FOUND ||
  1982. ec.value() == ERROR_PATH_NOT_FOUND ||
  1983. ec.value() == ERROR_INVALID_NAME;
  1984. #else
  1985. return ec.value() == ENOENT || ec.value() == ENOTDIR;
  1986. #endif
  1987. }
  1988. GHC_INLINE file_status symlink_status_ex(
  1989. const path & p, std::error_code & ec, uintmax_t * sz = nullptr,
  1990. uintmax_t * nhl = nullptr, time_t * lwt = nullptr) noexcept {
  1991. #ifdef GHC_OS_WINDOWS
  1992. file_status fs;
  1993. WIN32_FILE_ATTRIBUTE_DATA attr;
  1994. if (!GetFileAttributesExW(
  1995. detail::fromUtf8<std::wstring>(p.u8string()).c_str(),
  1996. GetFileExInfoStandard, &attr)) {
  1997. ec = detail::make_system_error();
  1998. } else {
  1999. ec.clear();
  2000. fs = detail::status_from_INFO(p, &attr, ec, sz, lwt);
  2001. if (nhl) { *nhl = 0; }
  2002. if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
  2003. fs.type(file_type::symlink);
  2004. }
  2005. }
  2006. if (detail::is_not_found_error(ec)) {
  2007. return file_status(file_type::not_found);
  2008. }
  2009. return ec ? file_status(file_type::none) : fs;
  2010. #else
  2011. (void)sz;
  2012. (void)nhl;
  2013. (void)lwt;
  2014. struct ::stat fs;
  2015. auto result = ::lstat(p.c_str(), &fs);
  2016. if (result == 0) {
  2017. ec.clear();
  2018. file_status f_s = detail::file_status_from_st_mode(fs.st_mode);
  2019. return f_s;
  2020. }
  2021. ec = detail::make_system_error();
  2022. if (detail::is_not_found_error(ec)) {
  2023. return file_status(file_type::not_found, perms::unknown);
  2024. }
  2025. return file_status(file_type::none);
  2026. #endif
  2027. }
  2028. GHC_INLINE file_status status_ex(const path & p, std::error_code & ec,
  2029. file_status * sls = nullptr,
  2030. uintmax_t * sz = nullptr,
  2031. uintmax_t * nhl = nullptr,
  2032. time_t * lwt = nullptr,
  2033. int recurse_count = 0) noexcept {
  2034. ec.clear();
  2035. #ifdef GHC_OS_WINDOWS
  2036. if (recurse_count > 16) {
  2037. ec = detail::make_system_error(0x2A9 /*ERROR_STOPPED_ON_SYMLINK*/);
  2038. return file_status(file_type::unknown);
  2039. }
  2040. WIN32_FILE_ATTRIBUTE_DATA attr;
  2041. if (!::GetFileAttributesExW(p.wstring().c_str(), GetFileExInfoStandard,
  2042. &attr)) {
  2043. ec = detail::make_system_error();
  2044. } else if (attr.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
  2045. path target = resolveSymlink(p, ec);
  2046. file_status result;
  2047. if (!ec && !target.empty()) {
  2048. if (sls) { *sls = status_from_INFO(p, &attr, ec); }
  2049. return detail::status_ex(target, ec, nullptr, sz, nhl, lwt,
  2050. recurse_count + 1);
  2051. }
  2052. return file_status(file_type::unknown);
  2053. }
  2054. if (ec) {
  2055. if (detail::is_not_found_error(ec)) {
  2056. return file_status(file_type::not_found);
  2057. }
  2058. return file_status(file_type::none);
  2059. }
  2060. if (nhl) { *nhl = 0; }
  2061. return detail::status_from_INFO(p, &attr, ec, sz, lwt);
  2062. #else
  2063. (void)recurse_count;
  2064. struct ::stat st;
  2065. auto result = ::lstat(p.c_str(), &st);
  2066. if (result == 0) {
  2067. ec.clear();
  2068. file_status fs = detail::file_status_from_st_mode(st.st_mode);
  2069. if (fs.type() == file_type::symlink) {
  2070. result = ::stat(p.c_str(), &st);
  2071. if (result == 0) {
  2072. if (sls) { *sls = fs; }
  2073. fs = detail::file_status_from_st_mode(st.st_mode);
  2074. }
  2075. }
  2076. if (sz) { *sz = static_cast<uintmax_t>(st.st_size); }
  2077. if (nhl) { *nhl = st.st_nlink; }
  2078. if (lwt) { *lwt = st.st_mtime; }
  2079. return fs;
  2080. } else {
  2081. ec = detail::make_system_error();
  2082. if (detail::is_not_found_error(ec)) {
  2083. return file_status(file_type::not_found, perms::unknown);
  2084. }
  2085. return file_status(file_type::none);
  2086. }
  2087. #endif
  2088. }
  2089. } // namespace detail
  2090. GHC_INLINE u8arguments::u8arguments(int & argc, char **& argv)
  2091. : _argc(argc), _argv(argv), _refargc(argc), _refargv(argv),
  2092. _isvalid(false) {
  2093. #ifdef GHC_OS_WINDOWS
  2094. LPWSTR * p;
  2095. p = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
  2096. _args.reserve(static_cast<size_t>(argc));
  2097. _argp.reserve(static_cast<size_t>(argc));
  2098. for (size_t i = 0; i < static_cast<size_t>(argc); ++i) {
  2099. _args.push_back(detail::toUtf8(std::wstring(p[i])));
  2100. _argp.push_back((char *)_args[i].data());
  2101. }
  2102. argv = _argp.data();
  2103. ::LocalFree(p);
  2104. _isvalid = true;
  2105. #else
  2106. std::setlocale(LC_ALL, "");
  2107. #if defined(__ANDROID__) && __ANDROID_API__ < 26
  2108. _isvalid = true;
  2109. #else
  2110. if (detail::equals_simple_insensitive(::nl_langinfo(CODESET), "UTF-8")) {
  2111. _isvalid = true;
  2112. }
  2113. #endif
  2114. #endif
  2115. }
  2116. //-----------------------------------------------------------------------------
  2117. // 30.10.8.4.1 constructors and destructor
  2118. GHC_INLINE path::path() noexcept {}
  2119. GHC_INLINE path::path(const path & p) : _path(p._path) {}
  2120. GHC_INLINE path::path(path && p) noexcept : _path(std::move(p._path)) {}
  2121. GHC_INLINE path::path(string_type && source, format fmt)
  2122. #ifdef GHC_USE_WCHAR_T
  2123. : _path(detail::toUtf8(source))
  2124. #else
  2125. : _path(std::move(source))
  2126. #endif
  2127. {
  2128. postprocess_path_with_format(_path, fmt);
  2129. }
  2130. #endif // GHC_EXPAND_IMPL
  2131. #ifdef GHC_WITH_EXCEPTIONS
  2132. template <class Source, typename>
  2133. inline path::path(const Source & source, const std::locale & loc,
  2134. format fmt)
  2135. : path(source, fmt) {
  2136. std::string locName = loc.name();
  2137. if (!(locName.length() >= 5 &&
  2138. (locName.substr(locName.length() - 5) == "UTF-8" ||
  2139. locName.substr(locName.length() - 5) == "utf-8"))) {
  2140. throw filesystem_error(
  2141. "This implementation only supports UTF-8 locales!", path(_path),
  2142. detail::make_error_code(detail::portable_error::not_supported));
  2143. }
  2144. }
  2145. template <class InputIterator>
  2146. inline path::path(InputIterator first, InputIterator last,
  2147. const std::locale & loc, format fmt)
  2148. : path(std::basic_string<
  2149. typename std::iterator_traits<InputIterator>::value_type>(
  2150. first, last),
  2151. fmt) {
  2152. std::string locName = loc.name();
  2153. if (!(locName.length() >= 5 &&
  2154. (locName.substr(locName.length() - 5) == "UTF-8" ||
  2155. locName.substr(locName.length() - 5) == "utf-8"))) {
  2156. throw filesystem_error(
  2157. "This implementation only supports UTF-8 locales!", path(_path),
  2158. detail::make_error_code(detail::portable_error::not_supported));
  2159. }
  2160. }
  2161. #endif
  2162. #ifdef GHC_EXPAND_IMPL
  2163. GHC_INLINE path::~path() {}
  2164. //-----------------------------------------------------------------------------
  2165. // 30.10.8.4.2 assignments
  2166. GHC_INLINE path & path::operator=(const path & p) {
  2167. _path = p._path;
  2168. return *this;
  2169. }
  2170. GHC_INLINE path & path::operator=(path && p) noexcept {
  2171. _path = std::move(p._path);
  2172. return *this;
  2173. }
  2174. GHC_INLINE path & path::operator=(path::string_type && source) {
  2175. return assign(source);
  2176. }
  2177. GHC_INLINE path & path::assign(path::string_type && source) {
  2178. #ifdef GHC_USE_WCHAR_T
  2179. _path = detail::toUtf8(source);
  2180. #else
  2181. _path = std::move(source);
  2182. #endif
  2183. postprocess_path_with_format(_path, native_format);
  2184. return *this;
  2185. }
  2186. #endif // GHC_EXPAND_IMPL
  2187. template <class Source>
  2188. inline path & path::operator=(const Source & source) {
  2189. return assign(source);
  2190. }
  2191. template <class Source> inline path & path::assign(const Source & source) {
  2192. _path.assign(detail::toUtf8(source));
  2193. postprocess_path_with_format(_path, native_format);
  2194. return *this;
  2195. }
  2196. template <> inline path & path::assign<path>(const path & source) {
  2197. _path = source._path;
  2198. return *this;
  2199. }
  2200. template <class InputIterator>
  2201. inline path & path::assign(InputIterator first, InputIterator last) {
  2202. _path.assign(first, last);
  2203. postprocess_path_with_format(_path, native_format);
  2204. return *this;
  2205. }
  2206. #ifdef GHC_EXPAND_IMPL
  2207. //-----------------------------------------------------------------------------
  2208. // 30.10.8.4.3 appends
  2209. GHC_INLINE path & path::operator/=(const path & p) {
  2210. if (p.empty()) {
  2211. // was: if ((!has_root_directory() && is_absolute()) || has_filename())
  2212. if (!_path.empty() && _path[_path.length() - 1] != '/' &&
  2213. _path[_path.length() - 1] != ':') {
  2214. _path += '/';
  2215. }
  2216. return *this;
  2217. }
  2218. if ((p.is_absolute() && (_path != root_name() || p._path != "/")) ||
  2219. (p.has_root_name() && p.root_name() != root_name())) {
  2220. assign(p);
  2221. return *this;
  2222. }
  2223. if (p.has_root_directory()) {
  2224. assign(root_name());
  2225. } else if ((!has_root_directory() && is_absolute()) || has_filename()) {
  2226. _path += '/';
  2227. }
  2228. auto iter = p.begin();
  2229. bool first = true;
  2230. if (p.has_root_name()) { ++iter; }
  2231. while (iter != p.end()) {
  2232. if (!first && !(!_path.empty() && _path[_path.length() - 1] == '/')) {
  2233. _path += '/';
  2234. }
  2235. first = false;
  2236. _path += (*iter++).generic_string();
  2237. }
  2238. return *this;
  2239. }
  2240. GHC_INLINE void path::append_name(const char * name) {
  2241. if (_path.empty()) {
  2242. this->operator/=(path(name));
  2243. } else {
  2244. if (_path.back() != path::generic_separator) {
  2245. _path.push_back(path::generic_separator);
  2246. }
  2247. _path += name;
  2248. }
  2249. }
  2250. #endif // GHC_EXPAND_IMPL
  2251. template <class Source>
  2252. inline path & path::operator/=(const Source & source) {
  2253. return append(source);
  2254. }
  2255. template <class Source> inline path & path::append(const Source & source) {
  2256. return this->operator/=(path(detail::toUtf8(source)));
  2257. }
  2258. template <> inline path & path::append<path>(const path & p) {
  2259. return this->operator/=(p);
  2260. }
  2261. template <class InputIterator>
  2262. inline path & path::append(InputIterator first, InputIterator last) {
  2263. std::basic_string<
  2264. typename std::iterator_traits<InputIterator>::value_type>
  2265. part(first, last);
  2266. return append(part);
  2267. }
  2268. #ifdef GHC_EXPAND_IMPL
  2269. //-----------------------------------------------------------------------------
  2270. // 30.10.8.4.4 concatenation
  2271. GHC_INLINE path & path::operator+=(const path & x) {
  2272. return concat(x._path);
  2273. }
  2274. GHC_INLINE path & path::operator+=(const string_type & x) {
  2275. return concat(x);
  2276. }
  2277. #ifdef __cpp_lib_string_view
  2278. GHC_INLINE path & path::operator+=(std::basic_string_view<value_type> x) {
  2279. return concat(x);
  2280. }
  2281. #endif
  2282. GHC_INLINE path & path::operator+=(const value_type * x) {
  2283. return concat(string_type(x));
  2284. }
  2285. GHC_INLINE path & path::operator+=(value_type x) {
  2286. #ifdef GHC_OS_WINDOWS
  2287. if (x == '\\') { x = generic_separator; }
  2288. #endif
  2289. if (_path.empty() || _path.back() != generic_separator) {
  2290. #ifdef GHC_USE_WCHAR_T
  2291. _path += detail::toUtf8(string_type(1, x));
  2292. #else
  2293. _path += x;
  2294. #endif
  2295. }
  2296. return *this;
  2297. }
  2298. #endif // GHC_EXPAND_IMPL
  2299. template <class Source>
  2300. inline path::path_from_string<Source> & path::operator+=(const Source & x) {
  2301. return concat(x);
  2302. }
  2303. template <class EcharT>
  2304. inline path::path_type_EcharT<EcharT> & path::operator+=(EcharT x) {
  2305. std::basic_string<EcharT> part(1, x);
  2306. concat(detail::toUtf8(part));
  2307. return *this;
  2308. }
  2309. template <class Source> inline path & path::concat(const Source & x) {
  2310. path p(x);
  2311. postprocess_path_with_format(p._path, native_format);
  2312. _path += p._path;
  2313. return *this;
  2314. }
  2315. template <class InputIterator>
  2316. inline path & path::concat(InputIterator first, InputIterator last) {
  2317. _path.append(first, last);
  2318. postprocess_path_with_format(_path, native_format);
  2319. return *this;
  2320. }
  2321. #ifdef GHC_EXPAND_IMPL
  2322. //-----------------------------------------------------------------------------
  2323. // 30.10.8.4.5 modifiers
  2324. GHC_INLINE void path::clear() noexcept { _path.clear(); }
  2325. GHC_INLINE path & path::make_preferred() {
  2326. // as this filesystem implementation only uses generic_format
  2327. // internally, this must be a no-op
  2328. return *this;
  2329. }
  2330. GHC_INLINE path & path::remove_filename() {
  2331. if (has_filename()) {
  2332. _path.erase(_path.size() - filename()._path.size());
  2333. }
  2334. return *this;
  2335. }
  2336. GHC_INLINE path & path::replace_filename(const path & replacement) {
  2337. remove_filename();
  2338. return append(replacement);
  2339. }
  2340. GHC_INLINE path & path::replace_extension(const path & replacement) {
  2341. if (has_extension()) {
  2342. _path.erase(_path.size() - extension()._path.size());
  2343. }
  2344. if (!replacement.empty() && replacement._path[0] != '.') { _path += '.'; }
  2345. return concat(replacement);
  2346. }
  2347. GHC_INLINE void path::swap(path & rhs) noexcept { _path.swap(rhs._path); }
  2348. //-----------------------------------------------------------------------------
  2349. // 30.10.8.4.6, native format observers
  2350. #ifdef GHC_OS_WINDOWS
  2351. GHC_INLINE path::impl_string_type path::native_impl() const {
  2352. impl_string_type result;
  2353. if (is_absolute() && _path.length() > MAX_PATH - 10) {
  2354. // expand long Windows filenames with marker
  2355. if (has_root_name() && _path[0] == '/') {
  2356. result = "\\\\?\\UNC" + _path.substr(1);
  2357. } else {
  2358. result = "\\\\?\\" + _path;
  2359. }
  2360. } else {
  2361. result = _path;
  2362. }
  2363. /*if (has_root_name() && root_name()._path[0] == '/') {
  2364. return _path;
  2365. }*/
  2366. for (auto & c : result) {
  2367. if (c == '/') { c = '\\'; }
  2368. }
  2369. return result;
  2370. }
  2371. #else
  2372. GHC_INLINE const path::impl_string_type & path::native_impl() const {
  2373. return _path;
  2374. }
  2375. #endif
  2376. GHC_INLINE const path::string_type & path::native() const {
  2377. #ifdef GHC_OS_WINDOWS
  2378. #ifdef GHC_USE_WCHAR_T
  2379. _native_cache = detail::fromUtf8<string_type>(native_impl());
  2380. #else
  2381. _native_cache = native_impl();
  2382. #endif
  2383. return _native_cache;
  2384. #else
  2385. return _path;
  2386. #endif
  2387. }
  2388. GHC_INLINE const path::value_type * path::c_str() const {
  2389. return native().c_str();
  2390. }
  2391. GHC_INLINE path::operator path::string_type() const { return native(); }
  2392. #endif // GHC_EXPAND_IMPL
  2393. template <class EcharT, class traits, class Allocator>
  2394. inline std::basic_string<EcharT, traits, Allocator>
  2395. path::string(const Allocator & a) const {
  2396. return detail::fromUtf8<std::basic_string<EcharT, traits, Allocator>>(
  2397. native_impl(), a);
  2398. }
  2399. #ifdef GHC_EXPAND_IMPL
  2400. GHC_INLINE std::string path::string() const { return native_impl(); }
  2401. GHC_INLINE std::wstring path::wstring() const {
  2402. #ifdef GHC_USE_WCHAR_T
  2403. return native();
  2404. #else
  2405. return detail::fromUtf8<std::wstring>(native());
  2406. #endif
  2407. }
  2408. GHC_INLINE std::string path::u8string() const { return native_impl(); }
  2409. GHC_INLINE std::u16string path::u16string() const {
  2410. return detail::fromUtf8<std::u16string>(native_impl());
  2411. }
  2412. GHC_INLINE std::u32string path::u32string() const {
  2413. return detail::fromUtf8<std::u32string>(native_impl());
  2414. }
  2415. #endif // GHC_EXPAND_IMPL
  2416. //-----------------------------------------------------------------------------
  2417. // 30.10.8.4.7, generic format observers
  2418. template <class EcharT, class traits, class Allocator>
  2419. inline std::basic_string<EcharT, traits, Allocator>
  2420. path::generic_string(const Allocator & a) const {
  2421. return detail::fromUtf8<std::basic_string<EcharT, traits, Allocator>>(
  2422. _path, a);
  2423. }
  2424. #ifdef GHC_EXPAND_IMPL
  2425. GHC_INLINE const std::string & path::generic_string() const {
  2426. return _path;
  2427. }
  2428. GHC_INLINE std::wstring path::generic_wstring() const {
  2429. return detail::fromUtf8<std::wstring>(_path);
  2430. }
  2431. GHC_INLINE std::string path::generic_u8string() const { return _path; }
  2432. GHC_INLINE std::u16string path::generic_u16string() const {
  2433. return detail::fromUtf8<std::u16string>(_path);
  2434. }
  2435. GHC_INLINE std::u32string path::generic_u32string() const {
  2436. return detail::fromUtf8<std::u32string>(_path);
  2437. }
  2438. //-----------------------------------------------------------------------------
  2439. // 30.10.8.4.8, compare
  2440. GHC_INLINE int path::compare(const path & p) const noexcept {
  2441. return native().compare(p.native());
  2442. }
  2443. GHC_INLINE int path::compare(const string_type & s) const {
  2444. return native().compare(path(s).native());
  2445. }
  2446. #ifdef __cpp_lib_string_view
  2447. GHC_INLINE int path::compare(std::basic_string_view<value_type> s) const {
  2448. return native().compare(path(s).native());
  2449. }
  2450. #endif
  2451. GHC_INLINE int path::compare(const value_type * s) const {
  2452. return native().compare(path(s).native());
  2453. }
  2454. //-----------------------------------------------------------------------------
  2455. // 30.10.8.4.9, decomposition
  2456. GHC_INLINE path path::root_name() const {
  2457. #ifdef GHC_OS_WINDOWS
  2458. if (_path.length() >= 2 &&
  2459. std::toupper(static_cast<unsigned char>(_path[0])) >= 'A' &&
  2460. std::toupper(static_cast<unsigned char>(_path[0])) <= 'Z' &&
  2461. _path[1] == ':') {
  2462. return path(_path.substr(0, 2));
  2463. }
  2464. #endif
  2465. if (_path.length() > 2 && _path[0] == '/' && _path[1] == '/' &&
  2466. _path[2] != '/' && std::isprint(_path[2])) {
  2467. impl_string_type::size_type pos = _path.find_first_of("/\\", 3);
  2468. if (pos == impl_string_type::npos) {
  2469. return path(_path);
  2470. } else {
  2471. return path(_path.substr(0, pos));
  2472. }
  2473. }
  2474. return path();
  2475. }
  2476. GHC_INLINE path path::root_directory() const {
  2477. path root = root_name();
  2478. if (_path.length() > root._path.length() &&
  2479. _path[root._path.length()] == '/') {
  2480. return path("/");
  2481. }
  2482. return path();
  2483. }
  2484. GHC_INLINE path path::root_path() const {
  2485. return root_name().generic_string() + root_directory().generic_string();
  2486. }
  2487. GHC_INLINE path path::relative_path() const {
  2488. std::string root = root_path()._path;
  2489. return path(_path.substr((std::min)(root.length(), _path.length())),
  2490. generic_format);
  2491. }
  2492. GHC_INLINE path path::parent_path() const {
  2493. if (has_relative_path()) {
  2494. if (empty() || begin() == --end()) {
  2495. return path();
  2496. } else {
  2497. path pp;
  2498. for (string_type s :
  2499. input_iterator_range<iterator>(begin(), --end())) {
  2500. if (s == "/") {
  2501. // don't use append to join a path-
  2502. pp += s;
  2503. } else {
  2504. pp /= s;
  2505. }
  2506. }
  2507. return pp;
  2508. }
  2509. } else {
  2510. return *this;
  2511. }
  2512. }
  2513. GHC_INLINE path path::filename() const {
  2514. return relative_path().empty() ? path() : path(*--end());
  2515. }
  2516. GHC_INLINE path path::stem() const {
  2517. impl_string_type fn = filename().string();
  2518. if (fn != "." && fn != "..") {
  2519. impl_string_type::size_type n = fn.rfind('.');
  2520. if (n != impl_string_type::npos && n != 0) {
  2521. return path{fn.substr(0, n)};
  2522. }
  2523. }
  2524. return path{fn};
  2525. }
  2526. GHC_INLINE path path::extension() const {
  2527. impl_string_type fn = filename().string();
  2528. impl_string_type::size_type pos = fn.find_last_of('.');
  2529. if (pos == std::string::npos || pos == 0) { return ""; }
  2530. return fn.substr(pos);
  2531. }
  2532. //-----------------------------------------------------------------------------
  2533. // 30.10.8.4.10, query
  2534. GHC_INLINE bool path::empty() const noexcept { return _path.empty(); }
  2535. GHC_INLINE bool path::has_root_name() const { return !root_name().empty(); }
  2536. GHC_INLINE bool path::has_root_directory() const {
  2537. return !root_directory().empty();
  2538. }
  2539. GHC_INLINE bool path::has_root_path() const { return !root_path().empty(); }
  2540. GHC_INLINE bool path::has_relative_path() const {
  2541. return !relative_path().empty();
  2542. }
  2543. GHC_INLINE bool path::has_parent_path() const {
  2544. return !parent_path().empty();
  2545. }
  2546. GHC_INLINE bool path::has_filename() const { return !filename().empty(); }
  2547. GHC_INLINE bool path::has_stem() const { return !stem().empty(); }
  2548. GHC_INLINE bool path::has_extension() const { return !extension().empty(); }
  2549. GHC_INLINE bool path::is_absolute() const {
  2550. #ifdef GHC_OS_WINDOWS
  2551. return has_root_name() && has_root_directory();
  2552. #else
  2553. return has_root_directory();
  2554. #endif
  2555. }
  2556. GHC_INLINE bool path::is_relative() const { return !is_absolute(); }
  2557. //-----------------------------------------------------------------------------
  2558. // 30.10.8.4.11, generation
  2559. GHC_INLINE path path::lexically_normal() const {
  2560. path dest;
  2561. bool lastDotDot = false;
  2562. for (string_type s : *this) {
  2563. if (s == ".") {
  2564. dest /= "";
  2565. continue;
  2566. } else if (s == ".." && !dest.empty()) {
  2567. auto root = root_path();
  2568. if (dest == root) {
  2569. continue;
  2570. } else if (*(--dest.end()) != "..") {
  2571. if (dest._path.back() == generic_separator) {
  2572. dest._path.pop_back();
  2573. }
  2574. dest.remove_filename();
  2575. continue;
  2576. }
  2577. }
  2578. if (!(s.empty() && lastDotDot)) { dest /= s; }
  2579. lastDotDot = s == "..";
  2580. }
  2581. if (dest.empty()) { dest = "."; }
  2582. return dest;
  2583. }
  2584. GHC_INLINE path path::lexically_relative(const path & base) const {
  2585. if (root_name() != base.root_name() ||
  2586. is_absolute() != base.is_absolute() ||
  2587. (!has_root_directory() && base.has_root_directory())) {
  2588. return path();
  2589. }
  2590. const_iterator a = begin(), b = base.begin();
  2591. while (a != end() && b != base.end() && *a == *b) {
  2592. ++a;
  2593. ++b;
  2594. }
  2595. if (a == end() && b == base.end()) { return path("."); }
  2596. int count = 0;
  2597. for (const auto & element :
  2598. input_iterator_range<const_iterator>(b, base.end())) {
  2599. if (element != "." && element != "" && element != "..") {
  2600. ++count;
  2601. } else if (element == "..") {
  2602. --count;
  2603. }
  2604. }
  2605. if (count < 0) { return path(); }
  2606. path result;
  2607. for (int i = 0; i < count; ++i) {
  2608. result /= "..";
  2609. }
  2610. for (const auto & element :
  2611. input_iterator_range<const_iterator>(a, end())) {
  2612. result /= element;
  2613. }
  2614. return result;
  2615. }
  2616. GHC_INLINE path path::lexically_proximate(const path & base) const {
  2617. path result = lexically_relative(base);
  2618. return result.empty() ? *this : result;
  2619. }
  2620. //-----------------------------------------------------------------------------
  2621. // 30.10.8.5, iterators
  2622. GHC_INLINE path::iterator::iterator() {}
  2623. GHC_INLINE path::iterator::iterator(
  2624. const path::impl_string_type::const_iterator & first,
  2625. const path::impl_string_type::const_iterator & last,
  2626. const path::impl_string_type::const_iterator & pos)
  2627. : _first(first), _last(last), _iter(pos) {
  2628. updateCurrent();
  2629. // find the position of a potential root directory slash
  2630. #ifdef GHC_OS_WINDOWS
  2631. if (_last - _first >= 3 &&
  2632. std::toupper(static_cast<unsigned char>(*first)) >= 'A' &&
  2633. std::toupper(static_cast<unsigned char>(*first)) <= 'Z' &&
  2634. *(first + 1) == ':' && *(first + 2) == '/') {
  2635. _root = _first + 2;
  2636. } else
  2637. #endif
  2638. {
  2639. if (_first != _last && *_first == '/') {
  2640. if (_last - _first >= 2 && *(_first + 1) == '/' &&
  2641. !(_last - _first >= 3 && *(_first + 2) == '/')) {
  2642. _root = increment(_first);
  2643. } else {
  2644. _root = _first;
  2645. }
  2646. } else {
  2647. _root = _last;
  2648. }
  2649. }
  2650. }
  2651. GHC_INLINE path::impl_string_type::const_iterator path::iterator::increment(
  2652. const path::impl_string_type::const_iterator & pos) const {
  2653. path::impl_string_type::const_iterator i = pos;
  2654. bool fromStart = i == _first;
  2655. if (i != _last) {
  2656. // we can only sit on a slash if it is a network name or a root
  2657. if (*i++ == '/') {
  2658. if (i != _last && *i == '/') {
  2659. if (fromStart && !(i + 1 != _last && *(i + 1) == '/')) {
  2660. // leadind double slashes detected, treat this and the
  2661. // following until a slash as one unit
  2662. i = std::find(++i, _last, '/');
  2663. } else {
  2664. // skip redundant slashes
  2665. while (i != _last && *i == '/') {
  2666. ++i;
  2667. }
  2668. }
  2669. }
  2670. } else {
  2671. if (fromStart && i != _last && *i == ':') {
  2672. ++i;
  2673. } else {
  2674. i = std::find(i, _last, '/');
  2675. }
  2676. }
  2677. }
  2678. return i;
  2679. }
  2680. GHC_INLINE path::impl_string_type::const_iterator path::iterator::decrement(
  2681. const path::impl_string_type::const_iterator & pos) const {
  2682. path::impl_string_type::const_iterator i = pos;
  2683. if (i != _first) {
  2684. --i;
  2685. // if this is now the root slash or the trailing slash, we are done,
  2686. // else check for network name
  2687. if (i != _root && (pos != _last || *i != '/')) {
  2688. #ifdef GHC_OS_WINDOWS
  2689. static const std::string seps = "/:";
  2690. i = std::find_first_of(
  2691. std::reverse_iterator<path::impl_string_type::const_iterator>(
  2692. i),
  2693. std::reverse_iterator<path::impl_string_type::const_iterator>(
  2694. _first),
  2695. seps.begin(), seps.end())
  2696. .base();
  2697. if (i > _first && *i == ':') { i++; }
  2698. #else
  2699. i = std::find(
  2700. std::reverse_iterator<path::impl_string_type::const_iterator>(
  2701. i),
  2702. std::reverse_iterator<path::impl_string_type::const_iterator>(
  2703. _first),
  2704. '/')
  2705. .base();
  2706. #endif
  2707. // Now we have to check if this is a network name
  2708. if (i - _first == 2 && *_first == '/' && *(_first + 1) == '/') {
  2709. i -= 2;
  2710. }
  2711. }
  2712. }
  2713. return i;
  2714. }
  2715. GHC_INLINE void path::iterator::updateCurrent() {
  2716. if (_iter != _first && _iter != _last &&
  2717. (*_iter == '/' && _iter != _root) && (_iter + 1 == _last)) {
  2718. _current = "";
  2719. } else {
  2720. _current.assign(_iter, increment(_iter));
  2721. if (_current.generic_string().size() > 1 &&
  2722. _current.generic_string()[0] == '/' &&
  2723. _current.generic_string()[_current.generic_string().size() - 1] ==
  2724. '/') {
  2725. // shrink successive slashes to one
  2726. _current = "/";
  2727. }
  2728. }
  2729. }
  2730. GHC_INLINE path::iterator & path::iterator::operator++() {
  2731. _iter = increment(_iter);
  2732. while (_iter != _last && // we didn't reach the end
  2733. _iter != _root && // this is not a root position
  2734. *_iter == '/' && // we are on a slash
  2735. (_iter + 1) != _last // the slash is not the last char
  2736. ) {
  2737. ++_iter;
  2738. }
  2739. updateCurrent();
  2740. return *this;
  2741. }
  2742. GHC_INLINE path::iterator path::iterator::operator++(int) {
  2743. path::iterator i{*this};
  2744. ++(*this);
  2745. return i;
  2746. }
  2747. GHC_INLINE path::iterator & path::iterator::operator--() {
  2748. _iter = decrement(_iter);
  2749. updateCurrent();
  2750. return *this;
  2751. }
  2752. GHC_INLINE path::iterator path::iterator::operator--(int) {
  2753. auto i = *this;
  2754. --(*this);
  2755. return i;
  2756. }
  2757. GHC_INLINE bool
  2758. path::iterator::operator==(const path::iterator & other) const {
  2759. return _iter == other._iter;
  2760. }
  2761. GHC_INLINE bool
  2762. path::iterator::operator!=(const path::iterator & other) const {
  2763. return _iter != other._iter;
  2764. }
  2765. GHC_INLINE path::iterator::reference path::iterator::operator*() const {
  2766. return _current;
  2767. }
  2768. GHC_INLINE path::iterator::pointer path::iterator::operator->() const {
  2769. return &_current;
  2770. }
  2771. GHC_INLINE path::iterator path::begin() const {
  2772. return iterator(_path.begin(), _path.end(), _path.begin());
  2773. }
  2774. GHC_INLINE path::iterator path::end() const {
  2775. return iterator(_path.begin(), _path.end(), _path.end());
  2776. }
  2777. //-----------------------------------------------------------------------------
  2778. // 30.10.8.6, path non-member functions
  2779. GHC_INLINE void swap(path & lhs, path & rhs) noexcept {
  2780. swap(lhs._path, rhs._path);
  2781. }
  2782. GHC_INLINE size_t hash_value(const path & p) noexcept {
  2783. return std::hash<std::string>()(p.generic_string());
  2784. }
  2785. GHC_INLINE bool operator==(const path & lhs, const path & rhs) noexcept {
  2786. return lhs.generic_string() == rhs.generic_string();
  2787. }
  2788. GHC_INLINE bool operator!=(const path & lhs, const path & rhs) noexcept {
  2789. return lhs.generic_string() != rhs.generic_string();
  2790. }
  2791. GHC_INLINE bool operator<(const path & lhs, const path & rhs) noexcept {
  2792. return lhs.generic_string() < rhs.generic_string();
  2793. }
  2794. GHC_INLINE bool operator<=(const path & lhs, const path & rhs) noexcept {
  2795. return lhs.generic_string() <= rhs.generic_string();
  2796. }
  2797. GHC_INLINE bool operator>(const path & lhs, const path & rhs) noexcept {
  2798. return lhs.generic_string() > rhs.generic_string();
  2799. }
  2800. GHC_INLINE bool operator>=(const path & lhs, const path & rhs) noexcept {
  2801. return lhs.generic_string() >= rhs.generic_string();
  2802. }
  2803. GHC_INLINE path operator/(const path & lhs, const path & rhs) {
  2804. path result(lhs);
  2805. result /= rhs;
  2806. return result;
  2807. }
  2808. #endif // GHC_EXPAND_IMPL
  2809. //-----------------------------------------------------------------------------
  2810. // 30.10.8.6.1 path inserter and extractor
  2811. template <class charT, class traits>
  2812. inline std::basic_ostream<charT, traits> &
  2813. operator<<(std::basic_ostream<charT, traits> & os, const path & p) {
  2814. os << "\"";
  2815. auto ps = p.string<charT, traits>();
  2816. for (auto c : ps) {
  2817. if (c == '"' || c == '\\') { os << '\\'; }
  2818. os << c;
  2819. }
  2820. os << "\"";
  2821. return os;
  2822. }
  2823. template <class charT, class traits>
  2824. inline std::basic_istream<charT, traits> &
  2825. operator>>(std::basic_istream<charT, traits> & is, path & p) {
  2826. std::basic_string<charT, traits> tmp;
  2827. charT c;
  2828. is >> c;
  2829. if (c == '"') {
  2830. auto sf = is.flags();
  2831. is >> std::noskipws;
  2832. while (is) {
  2833. auto c2 = is.get();
  2834. if (is) {
  2835. if (c2 == '\\') {
  2836. c2 = is.get();
  2837. if (is) { tmp += static_cast<charT>(c2); }
  2838. } else if (c2 == '"') {
  2839. break;
  2840. } else {
  2841. tmp += static_cast<charT>(c2);
  2842. }
  2843. }
  2844. }
  2845. if ((sf & std::ios_base::skipws) == std::ios_base::skipws) {
  2846. is >> std::skipws;
  2847. }
  2848. p = path(tmp);
  2849. } else {
  2850. is >> tmp;
  2851. p = path(static_cast<charT>(c) + tmp);
  2852. }
  2853. return is;
  2854. }
  2855. #ifdef GHC_EXPAND_IMPL
  2856. //-----------------------------------------------------------------------------
  2857. // 30.10.9 Class filesystem_error
  2858. GHC_INLINE filesystem_error::filesystem_error(const std::string & what_arg,
  2859. std::error_code ec)
  2860. : std::system_error(ec, what_arg), _what_arg(what_arg), _ec(ec) {}
  2861. GHC_INLINE filesystem_error::filesystem_error(const std::string & what_arg,
  2862. const path & p1,
  2863. std::error_code ec)
  2864. : std::system_error(ec, what_arg), _what_arg(what_arg), _ec(ec),
  2865. _p1(p1) {
  2866. if (!_p1.empty()) { _what_arg += ": '" + _p1.u8string() + "'"; }
  2867. }
  2868. GHC_INLINE filesystem_error::filesystem_error(const std::string & what_arg,
  2869. const path & p1,
  2870. const path & p2,
  2871. std::error_code ec)
  2872. : std::system_error(ec, what_arg), _what_arg(what_arg), _ec(ec),
  2873. _p1(p1), _p2(p2) {
  2874. if (!_p1.empty()) { _what_arg += ": '" + _p1.u8string() + "'"; }
  2875. if (!_p2.empty()) { _what_arg += ", '" + _p2.u8string() + "'"; }
  2876. }
  2877. GHC_INLINE const path & filesystem_error::path1() const noexcept {
  2878. return _p1;
  2879. }
  2880. GHC_INLINE const path & filesystem_error::path2() const noexcept {
  2881. return _p2;
  2882. }
  2883. GHC_INLINE const char * filesystem_error::what() const noexcept {
  2884. return _what_arg.c_str();
  2885. }
  2886. //-----------------------------------------------------------------------------
  2887. // 30.10.15, filesystem operations
  2888. #ifdef GHC_WITH_EXCEPTIONS
  2889. GHC_INLINE path absolute(const path & p) {
  2890. std::error_code ec;
  2891. path result = absolute(p, ec);
  2892. if (ec) {
  2893. throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
  2894. }
  2895. return result;
  2896. }
  2897. #endif
  2898. GHC_INLINE path absolute(const path & p, std::error_code & ec) {
  2899. ec.clear();
  2900. #ifdef GHC_OS_WINDOWS
  2901. if (p.empty()) { return absolute(current_path(ec), ec) / ""; }
  2902. ULONG size = ::GetFullPathNameW(p.wstring().c_str(), 0, 0, 0);
  2903. if (size) {
  2904. std::vector<wchar_t> buf(size, 0);
  2905. ULONG s2 =
  2906. GetFullPathNameW(p.wstring().c_str(), size, buf.data(), nullptr);
  2907. if (s2 && s2 < size) {
  2908. path result = path(std::wstring(buf.data(), s2));
  2909. if (p.filename() == ".") { result /= "."; }
  2910. return result;
  2911. }
  2912. }
  2913. ec = detail::make_system_error();
  2914. return path();
  2915. #else
  2916. path base = current_path(ec);
  2917. if (!ec) {
  2918. if (p.empty()) { return base / p; }
  2919. if (p.has_root_name()) {
  2920. if (p.has_root_directory()) {
  2921. return p;
  2922. } else {
  2923. return p.root_name() / base.root_directory() /
  2924. base.relative_path() / p.relative_path();
  2925. }
  2926. } else {
  2927. if (p.has_root_directory()) {
  2928. return base.root_name() / p;
  2929. } else {
  2930. return base / p;
  2931. }
  2932. }
  2933. }
  2934. ec = detail::make_system_error();
  2935. return path();
  2936. #endif
  2937. }
  2938. #ifdef GHC_WITH_EXCEPTIONS
  2939. GHC_INLINE path canonical(const path & p) {
  2940. std::error_code ec;
  2941. auto result = canonical(p, ec);
  2942. if (ec) {
  2943. throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
  2944. }
  2945. return result;
  2946. }
  2947. #endif
  2948. GHC_INLINE path canonical(const path & p, std::error_code & ec) {
  2949. if (p.empty()) {
  2950. ec = detail::make_error_code(detail::portable_error::not_found);
  2951. return path();
  2952. }
  2953. path work = p.is_absolute() ? p : absolute(p, ec);
  2954. path root = work.root_path();
  2955. path result;
  2956. auto fs = status(work, ec);
  2957. if (ec) { return path(); }
  2958. if (fs.type() == file_type::not_found) {
  2959. ec = detail::make_error_code(detail::portable_error::not_found);
  2960. return path();
  2961. }
  2962. bool redo;
  2963. do {
  2964. redo = false;
  2965. result.clear();
  2966. for (auto pe : work) {
  2967. if (pe.empty() || pe == ".") {
  2968. continue;
  2969. } else if (pe == "..") {
  2970. result = result.parent_path();
  2971. continue;
  2972. } else if ((result / pe).string().length() <=
  2973. root.string().length()) {
  2974. result /= pe;
  2975. continue;
  2976. }
  2977. auto sls = symlink_status(result / pe, ec);
  2978. if (ec) { return path(); }
  2979. if (is_symlink(sls)) {
  2980. redo = true;
  2981. auto target = read_symlink(result / pe, ec);
  2982. if (ec) { return path(); }
  2983. if (target.is_absolute()) {
  2984. result = target;
  2985. continue;
  2986. } else {
  2987. result /= target;
  2988. continue;
  2989. }
  2990. } else {
  2991. result /= pe;
  2992. }
  2993. }
  2994. work = result;
  2995. } while (redo);
  2996. ec.clear();
  2997. return result;
  2998. }
  2999. #ifdef GHC_WITH_EXCEPTIONS
  3000. GHC_INLINE void copy(const path & from, const path & to) {
  3001. copy(from, to, copy_options::none);
  3002. }
  3003. #endif
  3004. GHC_INLINE void copy(const path & from, const path & to,
  3005. std::error_code & ec) noexcept {
  3006. copy(from, to, copy_options::none, ec);
  3007. }
  3008. #ifdef GHC_WITH_EXCEPTIONS
  3009. GHC_INLINE void copy(const path & from, const path & to,
  3010. copy_options options) {
  3011. std::error_code ec;
  3012. copy(from, to, options, ec);
  3013. if (ec) {
  3014. throw filesystem_error(detail::systemErrorText(ec.value()), from, to,
  3015. ec);
  3016. }
  3017. }
  3018. #endif
  3019. GHC_INLINE void copy(const path & from, const path & to,
  3020. copy_options options, std::error_code & ec) noexcept {
  3021. std::error_code tec;
  3022. file_status fs_from, fs_to;
  3023. ec.clear();
  3024. if ((options &
  3025. (copy_options::skip_symlinks | copy_options::copy_symlinks |
  3026. copy_options::create_symlinks)) != copy_options::none) {
  3027. fs_from = symlink_status(from, ec);
  3028. } else {
  3029. fs_from = status(from, ec);
  3030. }
  3031. if (!exists(fs_from)) {
  3032. if (!ec) {
  3033. ec = detail::make_error_code(detail::portable_error::not_found);
  3034. }
  3035. return;
  3036. }
  3037. if ((options & (copy_options::skip_symlinks |
  3038. copy_options::create_symlinks)) != copy_options::none) {
  3039. fs_to = symlink_status(to, tec);
  3040. } else {
  3041. fs_to = status(to, tec);
  3042. }
  3043. if (is_other(fs_from) || is_other(fs_to) ||
  3044. (is_directory(fs_from) && is_regular_file(fs_to)) ||
  3045. (exists(fs_to) && equivalent(from, to, ec))) {
  3046. ec = detail::make_error_code(detail::portable_error::invalid_argument);
  3047. } else if (is_symlink(fs_from)) {
  3048. if ((options & copy_options::skip_symlinks) == copy_options::none) {
  3049. if (!exists(fs_to) &&
  3050. (options & copy_options::copy_symlinks) != copy_options::none) {
  3051. copy_symlink(from, to, ec);
  3052. } else {
  3053. ec = detail::make_error_code(
  3054. detail::portable_error::invalid_argument);
  3055. }
  3056. }
  3057. } else if (is_regular_file(fs_from)) {
  3058. if ((options & copy_options::directories_only) == copy_options::none) {
  3059. if ((options & copy_options::create_symlinks) != copy_options::none) {
  3060. create_symlink(from.is_absolute() ? from : canonical(from, ec), to,
  3061. ec);
  3062. }
  3063. #ifndef GHC_OS_WEB
  3064. else if ((options & copy_options::create_hard_links) !=
  3065. copy_options::none) {
  3066. create_hard_link(from, to, ec);
  3067. }
  3068. #endif
  3069. else if (is_directory(fs_to)) {
  3070. copy_file(from, to / from.filename(), options, ec);
  3071. } else {
  3072. copy_file(from, to, options, ec);
  3073. }
  3074. }
  3075. }
  3076. #ifdef LWG_2682_BEHAVIOUR
  3077. else if (is_directory(fs_from) &&
  3078. (options & copy_options::create_symlinks) !=
  3079. copy_options::none) {
  3080. ec = detail::make_error_code(detail::portable_error::is_a_directory);
  3081. }
  3082. #endif
  3083. else if (is_directory(fs_from) &&
  3084. (options == copy_options::none ||
  3085. (options & copy_options::recursive) != copy_options::none)) {
  3086. if (!exists(fs_to)) {
  3087. create_directory(to, from, ec);
  3088. if (ec) { return; }
  3089. }
  3090. for (auto iter = directory_iterator(from, ec);
  3091. iter != directory_iterator(); iter.increment(ec)) {
  3092. if (!ec) {
  3093. copy(iter->path(), to / iter->path().filename(),
  3094. options | static_cast<copy_options>(0x8000), ec);
  3095. }
  3096. if (ec) { return; }
  3097. }
  3098. }
  3099. return;
  3100. }
  3101. #ifdef GHC_WITH_EXCEPTIONS
  3102. GHC_INLINE bool copy_file(const path & from, const path & to) {
  3103. return copy_file(from, to, copy_options::none);
  3104. }
  3105. #endif
  3106. GHC_INLINE bool copy_file(const path & from, const path & to,
  3107. std::error_code & ec) noexcept {
  3108. return copy_file(from, to, copy_options::none, ec);
  3109. }
  3110. #ifdef GHC_WITH_EXCEPTIONS
  3111. GHC_INLINE bool copy_file(const path & from, const path & to,
  3112. copy_options option) {
  3113. std::error_code ec;
  3114. auto result = copy_file(from, to, option, ec);
  3115. if (ec) {
  3116. throw filesystem_error(detail::systemErrorText(ec.value()), from, to,
  3117. ec);
  3118. }
  3119. return result;
  3120. }
  3121. #endif
  3122. GHC_INLINE bool copy_file(const path & from, const path & to,
  3123. copy_options options,
  3124. std::error_code & ec) noexcept {
  3125. std::error_code tecf, tect;
  3126. auto sf = status(from, tecf);
  3127. auto st = status(to, tect);
  3128. bool overwrite = false;
  3129. ec.clear();
  3130. if (!is_regular_file(sf)) {
  3131. ec = tecf;
  3132. return false;
  3133. }
  3134. if (exists(st) &&
  3135. (!is_regular_file(st) || equivalent(from, to, ec) ||
  3136. (options &
  3137. (copy_options::skip_existing | copy_options::overwrite_existing |
  3138. copy_options::update_existing)) == copy_options::none)) {
  3139. ec = tect ? tect
  3140. : detail::make_error_code(detail::portable_error::exists);
  3141. return false;
  3142. }
  3143. if (exists(st)) {
  3144. if ((options & copy_options::update_existing) ==
  3145. copy_options::update_existing) {
  3146. auto from_time = last_write_time(from, ec);
  3147. if (ec) {
  3148. ec = detail::make_system_error();
  3149. return false;
  3150. }
  3151. auto to_time = last_write_time(to, ec);
  3152. if (ec) {
  3153. ec = detail::make_system_error();
  3154. return false;
  3155. }
  3156. if (from_time <= to_time) { return false; }
  3157. }
  3158. overwrite = true;
  3159. }
  3160. #ifdef GHC_OS_WINDOWS
  3161. if (!::CopyFileW(detail::fromUtf8<std::wstring>(from.u8string()).c_str(),
  3162. detail::fromUtf8<std::wstring>(to.u8string()).c_str(),
  3163. !overwrite)) {
  3164. ec = detail::make_system_error();
  3165. return false;
  3166. }
  3167. return true;
  3168. #else
  3169. std::vector<char> buffer(16384, '\0');
  3170. int in = -1, out = -1;
  3171. if ((in = ::open(from.c_str(), O_RDONLY)) < 0) {
  3172. ec = detail::make_system_error();
  3173. return false;
  3174. }
  3175. int mode = O_CREAT | O_WRONLY | O_TRUNC;
  3176. if (!overwrite) { mode |= O_EXCL; }
  3177. if ((out = ::open(to.c_str(), mode,
  3178. static_cast<int>(sf.permissions() & perms::all))) < 0) {
  3179. ec = detail::make_system_error();
  3180. ::close(in);
  3181. return false;
  3182. }
  3183. ssize_t br, bw;
  3184. while ((br = ::read(in, buffer.data(), buffer.size())) > 0) {
  3185. ssize_t offset = 0;
  3186. do {
  3187. if ((bw = ::write(out, buffer.data() + offset,
  3188. static_cast<size_t>(br))) > 0) {
  3189. br -= bw;
  3190. offset += bw;
  3191. } else if (bw < 0) {
  3192. ec = detail::make_system_error();
  3193. ::close(in);
  3194. ::close(out);
  3195. return false;
  3196. }
  3197. } while (br);
  3198. }
  3199. ::close(in);
  3200. ::close(out);
  3201. return true;
  3202. #endif
  3203. }
  3204. #ifdef GHC_WITH_EXCEPTIONS
  3205. GHC_INLINE void copy_symlink(const path & existing_symlink,
  3206. const path & new_symlink) {
  3207. std::error_code ec;
  3208. copy_symlink(existing_symlink, new_symlink, ec);
  3209. if (ec) {
  3210. throw filesystem_error(detail::systemErrorText(ec.value()),
  3211. existing_symlink, new_symlink, ec);
  3212. }
  3213. }
  3214. #endif
  3215. GHC_INLINE void copy_symlink(const path & existing_symlink,
  3216. const path & new_symlink,
  3217. std::error_code & ec) noexcept {
  3218. ec.clear();
  3219. auto to = read_symlink(existing_symlink, ec);
  3220. if (!ec) {
  3221. if (exists(to, ec) && is_directory(to, ec)) {
  3222. create_directory_symlink(to, new_symlink, ec);
  3223. } else {
  3224. create_symlink(to, new_symlink, ec);
  3225. }
  3226. }
  3227. }
  3228. #ifdef GHC_WITH_EXCEPTIONS
  3229. GHC_INLINE bool create_directories(const path & p) {
  3230. std::error_code ec;
  3231. auto result = create_directories(p, ec);
  3232. if (ec) {
  3233. throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
  3234. }
  3235. return result;
  3236. }
  3237. #endif
  3238. GHC_INLINE bool create_directories(const path & p,
  3239. std::error_code & ec) noexcept {
  3240. path current;
  3241. ec.clear();
  3242. bool didCreate = false;
  3243. for (path::string_type part : p) {
  3244. current /= part;
  3245. if (current != p.root_name() && current != p.root_path()) {
  3246. std::error_code tec;
  3247. auto fs = status(current, tec);
  3248. if (tec && fs.type() != file_type::not_found) {
  3249. ec = tec;
  3250. return false;
  3251. }
  3252. if (!exists(fs)) {
  3253. create_directory(current, ec);
  3254. if (ec) {
  3255. std::error_code tmp_ec;
  3256. if (is_directory(current, tmp_ec)) {
  3257. ec.clear();
  3258. } else {
  3259. return false;
  3260. }
  3261. }
  3262. didCreate = true;
  3263. }
  3264. #ifndef LWG_2935_BEHAVIOUR
  3265. else if (!is_directory(fs)) {
  3266. ec = detail::make_error_code(detail::portable_error::exists);
  3267. return false;
  3268. }
  3269. #endif
  3270. }
  3271. }
  3272. return didCreate;
  3273. }
  3274. #ifdef GHC_WITH_EXCEPTIONS
  3275. GHC_INLINE bool create_directory(const path & p) {
  3276. std::error_code ec;
  3277. auto result = create_directory(p, path(), ec);
  3278. if (ec) {
  3279. throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
  3280. }
  3281. return result;
  3282. }
  3283. #endif
  3284. GHC_INLINE bool create_directory(const path & p,
  3285. std::error_code & ec) noexcept {
  3286. return create_directory(p, path(), ec);
  3287. }
  3288. #ifdef GHC_WITH_EXCEPTIONS
  3289. GHC_INLINE bool create_directory(const path & p, const path & attributes) {
  3290. std::error_code ec;
  3291. auto result = create_directory(p, attributes, ec);
  3292. if (ec) {
  3293. throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
  3294. }
  3295. return result;
  3296. }
  3297. #endif
  3298. GHC_INLINE bool create_directory(const path & p, const path & attributes,
  3299. std::error_code & ec) noexcept {
  3300. std::error_code tec;
  3301. ec.clear();
  3302. auto fs = status(p, tec);
  3303. #ifdef LWG_2935_BEHAVIOUR
  3304. if (status_known(fs) && exists(fs)) { return false; }
  3305. #else
  3306. if (status_known(fs) && exists(fs) && is_directory(fs)) { return false; }
  3307. #endif
  3308. #ifdef GHC_OS_WINDOWS
  3309. if (!attributes.empty()) {
  3310. if (!::CreateDirectoryExW(
  3311. detail::fromUtf8<std::wstring>(attributes.u8string()).c_str(),
  3312. detail::fromUtf8<std::wstring>(p.u8string()).c_str(), NULL)) {
  3313. ec = detail::make_system_error();
  3314. return false;
  3315. }
  3316. } else if (!::CreateDirectoryW(
  3317. detail::fromUtf8<std::wstring>(p.u8string()).c_str(),
  3318. NULL)) {
  3319. ec = detail::make_system_error();
  3320. return false;
  3321. }
  3322. #else
  3323. ::mode_t attribs = static_cast<mode_t>(perms::all);
  3324. if (!attributes.empty()) {
  3325. struct ::stat fileStat;
  3326. if (::stat(attributes.c_str(), &fileStat) != 0) {
  3327. ec = detail::make_system_error();
  3328. return false;
  3329. }
  3330. attribs = fileStat.st_mode;
  3331. }
  3332. if (::mkdir(p.c_str(), attribs) != 0) {
  3333. ec = detail::make_system_error();
  3334. return false;
  3335. }
  3336. #endif
  3337. return true;
  3338. }
  3339. #ifdef GHC_WITH_EXCEPTIONS
  3340. GHC_INLINE void create_directory_symlink(const path & to,
  3341. const path & new_symlink) {
  3342. std::error_code ec;
  3343. create_directory_symlink(to, new_symlink, ec);
  3344. if (ec) {
  3345. throw filesystem_error(detail::systemErrorText(ec.value()), to,
  3346. new_symlink, ec);
  3347. }
  3348. }
  3349. #endif
  3350. GHC_INLINE void create_directory_symlink(const path & to,
  3351. const path & new_symlink,
  3352. std::error_code & ec) noexcept {
  3353. detail::create_symlink(to, new_symlink, true, ec);
  3354. }
  3355. #ifndef GHC_OS_WEB
  3356. #ifdef GHC_WITH_EXCEPTIONS
  3357. GHC_INLINE void create_hard_link(const path & to,
  3358. const path & new_hard_link) {
  3359. std::error_code ec;
  3360. create_hard_link(to, new_hard_link, ec);
  3361. if (ec) {
  3362. throw filesystem_error(detail::systemErrorText(ec.value()), to,
  3363. new_hard_link, ec);
  3364. }
  3365. }
  3366. #endif
  3367. GHC_INLINE void create_hard_link(const path & to,
  3368. const path & new_hard_link,
  3369. std::error_code & ec) noexcept {
  3370. detail::create_hardlink(to, new_hard_link, ec);
  3371. }
  3372. #endif
  3373. #ifdef GHC_WITH_EXCEPTIONS
  3374. GHC_INLINE void create_symlink(const path & to, const path & new_symlink) {
  3375. std::error_code ec;
  3376. create_symlink(to, new_symlink, ec);
  3377. if (ec) {
  3378. throw filesystem_error(detail::systemErrorText(ec.value()), to,
  3379. new_symlink, ec);
  3380. }
  3381. }
  3382. #endif
  3383. GHC_INLINE void create_symlink(const path & to, const path & new_symlink,
  3384. std::error_code & ec) noexcept {
  3385. detail::create_symlink(to, new_symlink, false, ec);
  3386. }
  3387. #ifdef GHC_WITH_EXCEPTIONS
  3388. GHC_INLINE path current_path() {
  3389. std::error_code ec;
  3390. auto result = current_path(ec);
  3391. if (ec) {
  3392. throw filesystem_error(detail::systemErrorText(ec.value()), ec);
  3393. }
  3394. return result;
  3395. }
  3396. #endif
  3397. GHC_INLINE path current_path(std::error_code & ec) {
  3398. ec.clear();
  3399. #ifdef GHC_OS_WINDOWS
  3400. DWORD pathlen = ::GetCurrentDirectoryW(0, 0);
  3401. std::unique_ptr<wchar_t[]> buffer(new wchar_t[size_t(pathlen) + 1]);
  3402. if (::GetCurrentDirectoryW(pathlen, buffer.get()) == 0) {
  3403. ec = detail::make_system_error();
  3404. return path();
  3405. }
  3406. return path(std::wstring(buffer.get()), path::native_format);
  3407. #else
  3408. size_t pathlen = static_cast<size_t>(
  3409. std::max(int(::pathconf(".", _PC_PATH_MAX)), int(PATH_MAX)));
  3410. std::unique_ptr<char[]> buffer(new char[pathlen + 1]);
  3411. if (::getcwd(buffer.get(), pathlen) == nullptr) {
  3412. ec = detail::make_system_error();
  3413. return path();
  3414. }
  3415. return path(buffer.get());
  3416. #endif
  3417. }
  3418. #ifdef GHC_WITH_EXCEPTIONS
  3419. GHC_INLINE void current_path(const path & p) {
  3420. std::error_code ec;
  3421. current_path(p, ec);
  3422. if (ec) {
  3423. throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
  3424. }
  3425. }
  3426. #endif
  3427. GHC_INLINE void current_path(const path & p,
  3428. std::error_code & ec) noexcept {
  3429. ec.clear();
  3430. #ifdef GHC_OS_WINDOWS
  3431. if (!::SetCurrentDirectoryW(
  3432. detail::fromUtf8<std::wstring>(p.u8string()).c_str())) {
  3433. ec = detail::make_system_error();
  3434. }
  3435. #else
  3436. if (::chdir(p.string().c_str()) == -1) {
  3437. ec = detail::make_system_error();
  3438. }
  3439. #endif
  3440. }
  3441. GHC_INLINE bool exists(file_status s) noexcept {
  3442. return status_known(s) && s.type() != file_type::not_found;
  3443. }
  3444. #ifdef GHC_WITH_EXCEPTIONS
  3445. GHC_INLINE bool exists(const path & p) { return exists(status(p)); }
  3446. #endif
  3447. GHC_INLINE bool exists(const path & p, std::error_code & ec) noexcept {
  3448. file_status s = status(p, ec);
  3449. if (status_known(s)) { ec.clear(); }
  3450. return exists(s);
  3451. }
  3452. #ifdef GHC_WITH_EXCEPTIONS
  3453. GHC_INLINE bool equivalent(const path & p1, const path & p2) {
  3454. std::error_code ec;
  3455. bool result = equivalent(p1, p2, ec);
  3456. if (ec) {
  3457. throw filesystem_error(detail::systemErrorText(ec.value()), p1, p2, ec);
  3458. }
  3459. return result;
  3460. }
  3461. #endif
  3462. GHC_INLINE bool equivalent(const path & p1, const path & p2,
  3463. std::error_code & ec) noexcept {
  3464. ec.clear();
  3465. #ifdef GHC_OS_WINDOWS
  3466. std::shared_ptr<void> file1(
  3467. ::CreateFileW(p1.wstring().c_str(), 0,
  3468. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  3469. 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0),
  3470. CloseHandle);
  3471. auto e1 = ::GetLastError();
  3472. std::shared_ptr<void> file2(
  3473. ::CreateFileW(p2.wstring().c_str(), 0,
  3474. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  3475. 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0),
  3476. CloseHandle);
  3477. if (file1.get() == INVALID_HANDLE_VALUE ||
  3478. file2.get() == INVALID_HANDLE_VALUE) {
  3479. #ifdef LWG_2937_BEHAVIOUR
  3480. ec = detail::make_system_error(e1 ? e1 : ::GetLastError());
  3481. #else
  3482. if (file1 == file2) {
  3483. ec = detail::make_system_error(e1 ? e1 : ::GetLastError());
  3484. }
  3485. #endif
  3486. return false;
  3487. }
  3488. BY_HANDLE_FILE_INFORMATION inf1, inf2;
  3489. if (!::GetFileInformationByHandle(file1.get(), &inf1)) {
  3490. ec = detail::make_system_error();
  3491. return false;
  3492. }
  3493. if (!::GetFileInformationByHandle(file2.get(), &inf2)) {
  3494. ec = detail::make_system_error();
  3495. return false;
  3496. }
  3497. return inf1.ftLastWriteTime.dwLowDateTime ==
  3498. inf2.ftLastWriteTime.dwLowDateTime &&
  3499. inf1.ftLastWriteTime.dwHighDateTime ==
  3500. inf2.ftLastWriteTime.dwHighDateTime &&
  3501. inf1.nFileIndexHigh == inf2.nFileIndexHigh &&
  3502. inf1.nFileIndexLow == inf2.nFileIndexLow &&
  3503. inf1.nFileSizeHigh == inf2.nFileSizeHigh &&
  3504. inf1.nFileSizeLow == inf2.nFileSizeLow &&
  3505. inf1.dwVolumeSerialNumber == inf2.dwVolumeSerialNumber;
  3506. #else
  3507. struct ::stat s1, s2;
  3508. auto rc1 = ::stat(p1.c_str(), &s1);
  3509. auto e1 = errno;
  3510. auto rc2 = ::stat(p2.c_str(), &s2);
  3511. if (rc1 || rc2) {
  3512. #ifdef LWG_2937_BEHAVIOUR
  3513. ec = detail::make_system_error(e1 ? e1 : errno);
  3514. #else
  3515. if (rc1 && rc2) { ec = detail::make_system_error(e1 ? e1 : errno); }
  3516. #endif
  3517. return false;
  3518. }
  3519. return s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino &&
  3520. s1.st_size == s2.st_size && s1.st_mtime == s2.st_mtime;
  3521. #endif
  3522. }
  3523. #ifdef GHC_WITH_EXCEPTIONS
  3524. GHC_INLINE uintmax_t file_size(const path & p) {
  3525. std::error_code ec;
  3526. auto result = file_size(p, ec);
  3527. if (ec) {
  3528. throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
  3529. }
  3530. return result;
  3531. }
  3532. #endif
  3533. GHC_INLINE uintmax_t file_size(const path & p,
  3534. std::error_code & ec) noexcept {
  3535. ec.clear();
  3536. #ifdef GHC_OS_WINDOWS
  3537. WIN32_FILE_ATTRIBUTE_DATA attr;
  3538. if (!GetFileAttributesExW(
  3539. detail::fromUtf8<std::wstring>(p.u8string()).c_str(),
  3540. GetFileExInfoStandard, &attr)) {
  3541. ec = detail::make_system_error();
  3542. return static_cast<uintmax_t>(-1);
  3543. }
  3544. return static_cast<uintmax_t>(attr.nFileSizeHigh)
  3545. << (sizeof(attr.nFileSizeHigh) * 8) |
  3546. attr.nFileSizeLow;
  3547. #else
  3548. struct ::stat fileStat;
  3549. if (::stat(p.c_str(), &fileStat) == -1) {
  3550. ec = detail::make_system_error();
  3551. return static_cast<uintmax_t>(-1);
  3552. }
  3553. return static_cast<uintmax_t>(fileStat.st_size);
  3554. #endif
  3555. }
  3556. #ifndef GHC_OS_WEB
  3557. #ifdef GHC_WITH_EXCEPTIONS
  3558. GHC_INLINE uintmax_t hard_link_count(const path & p) {
  3559. std::error_code ec;
  3560. auto result = hard_link_count(p, ec);
  3561. if (ec) {
  3562. throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
  3563. }
  3564. return result;
  3565. }
  3566. #endif
  3567. GHC_INLINE uintmax_t hard_link_count(const path & p,
  3568. std::error_code & ec) noexcept {
  3569. ec.clear();
  3570. #ifdef GHC_OS_WINDOWS
  3571. uintmax_t result = static_cast<uintmax_t>(-1);
  3572. std::shared_ptr<void> file(
  3573. ::CreateFileW(p.wstring().c_str(), 0,
  3574. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  3575. 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0),
  3576. CloseHandle);
  3577. BY_HANDLE_FILE_INFORMATION inf;
  3578. if (file.get() == INVALID_HANDLE_VALUE) {
  3579. ec = detail::make_system_error();
  3580. } else {
  3581. if (!::GetFileInformationByHandle(file.get(), &inf)) {
  3582. ec = detail::make_system_error();
  3583. } else {
  3584. result = inf.nNumberOfLinks;
  3585. }
  3586. }
  3587. return result;
  3588. #else
  3589. uintmax_t result = 0;
  3590. file_status fs =
  3591. detail::status_ex(p, ec, nullptr, nullptr, &result, nullptr);
  3592. if (fs.type() == file_type::not_found) {
  3593. ec = detail::make_error_code(detail::portable_error::not_found);
  3594. }
  3595. return ec ? static_cast<uintmax_t>(-1) : result;
  3596. #endif
  3597. }
  3598. #endif
  3599. GHC_INLINE bool is_block_file(file_status s) noexcept {
  3600. return s.type() == file_type::block;
  3601. }
  3602. #ifdef GHC_WITH_EXCEPTIONS
  3603. GHC_INLINE bool is_block_file(const path & p) {
  3604. return is_block_file(status(p));
  3605. }
  3606. #endif
  3607. GHC_INLINE bool is_block_file(const path & p,
  3608. std::error_code & ec) noexcept {
  3609. return is_block_file(status(p, ec));
  3610. }
  3611. GHC_INLINE bool is_character_file(file_status s) noexcept {
  3612. return s.type() == file_type::character;
  3613. }
  3614. #ifdef GHC_WITH_EXCEPTIONS
  3615. GHC_INLINE bool is_character_file(const path & p) {
  3616. return is_character_file(status(p));
  3617. }
  3618. #endif
  3619. GHC_INLINE bool is_character_file(const path & p,
  3620. std::error_code & ec) noexcept {
  3621. return is_character_file(status(p, ec));
  3622. }
  3623. GHC_INLINE bool is_directory(file_status s) noexcept {
  3624. return s.type() == file_type::directory;
  3625. }
  3626. #ifdef GHC_WITH_EXCEPTIONS
  3627. GHC_INLINE bool is_directory(const path & p) {
  3628. return is_directory(status(p));
  3629. }
  3630. #endif
  3631. GHC_INLINE bool is_directory(const path & p,
  3632. std::error_code & ec) noexcept {
  3633. return is_directory(status(p, ec));
  3634. }
  3635. #ifdef GHC_WITH_EXCEPTIONS
  3636. GHC_INLINE bool is_empty(const path & p) {
  3637. if (is_directory(p)) {
  3638. return directory_iterator(p) == directory_iterator();
  3639. } else {
  3640. return file_size(p) == 0;
  3641. }
  3642. }
  3643. #endif
  3644. GHC_INLINE bool is_empty(const path & p, std::error_code & ec) noexcept {
  3645. auto fs = status(p, ec);
  3646. if (ec) { return false; }
  3647. if (is_directory(fs)) {
  3648. directory_iterator iter(p, ec);
  3649. if (ec) { return false; }
  3650. return iter == directory_iterator();
  3651. } else {
  3652. auto sz = file_size(p, ec);
  3653. if (ec) { return false; }
  3654. return sz == 0;
  3655. }
  3656. }
  3657. GHC_INLINE bool is_fifo(file_status s) noexcept {
  3658. return s.type() == file_type::fifo;
  3659. }
  3660. #ifdef GHC_WITH_EXCEPTIONS
  3661. GHC_INLINE bool is_fifo(const path & p) { return is_fifo(status(p)); }
  3662. #endif
  3663. GHC_INLINE bool is_fifo(const path & p, std::error_code & ec) noexcept {
  3664. return is_fifo(status(p, ec));
  3665. }
  3666. GHC_INLINE bool is_other(file_status s) noexcept {
  3667. return exists(s) && !is_regular_file(s) && !is_directory(s) &&
  3668. !is_symlink(s);
  3669. }
  3670. #ifdef GHC_WITH_EXCEPTIONS
  3671. GHC_INLINE bool is_other(const path & p) { return is_other(status(p)); }
  3672. #endif
  3673. GHC_INLINE bool is_other(const path & p, std::error_code & ec) noexcept {
  3674. return is_other(status(p, ec));
  3675. }
  3676. GHC_INLINE bool is_regular_file(file_status s) noexcept {
  3677. return s.type() == file_type::regular;
  3678. }
  3679. #ifdef GHC_WITH_EXCEPTIONS
  3680. GHC_INLINE bool is_regular_file(const path & p) {
  3681. return is_regular_file(status(p));
  3682. }
  3683. #endif
  3684. GHC_INLINE bool is_regular_file(const path & p,
  3685. std::error_code & ec) noexcept {
  3686. return is_regular_file(status(p, ec));
  3687. }
  3688. GHC_INLINE bool is_socket(file_status s) noexcept {
  3689. return s.type() == file_type::socket;
  3690. }
  3691. #ifdef GHC_WITH_EXCEPTIONS
  3692. GHC_INLINE bool is_socket(const path & p) { return is_socket(status(p)); }
  3693. #endif
  3694. GHC_INLINE bool is_socket(const path & p, std::error_code & ec) noexcept {
  3695. return is_socket(status(p, ec));
  3696. }
  3697. GHC_INLINE bool is_symlink(file_status s) noexcept {
  3698. return s.type() == file_type::symlink;
  3699. }
  3700. #ifdef GHC_WITH_EXCEPTIONS
  3701. GHC_INLINE bool is_symlink(const path & p) {
  3702. return is_symlink(symlink_status(p));
  3703. }
  3704. #endif
  3705. GHC_INLINE bool is_symlink(const path & p, std::error_code & ec) noexcept {
  3706. return is_symlink(symlink_status(p, ec));
  3707. }
  3708. #ifdef GHC_WITH_EXCEPTIONS
  3709. GHC_INLINE file_time_type last_write_time(const path & p) {
  3710. std::error_code ec;
  3711. auto result = last_write_time(p, ec);
  3712. if (ec) {
  3713. throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
  3714. }
  3715. return result;
  3716. }
  3717. #endif
  3718. GHC_INLINE file_time_type last_write_time(const path & p,
  3719. std::error_code & ec) noexcept {
  3720. time_t result = 0;
  3721. ec.clear();
  3722. file_status fs =
  3723. detail::status_ex(p, ec, nullptr, nullptr, nullptr, &result);
  3724. return ec ? (file_time_type::min)()
  3725. : std::chrono::system_clock::from_time_t(result);
  3726. }
  3727. #ifdef GHC_WITH_EXCEPTIONS
  3728. GHC_INLINE void last_write_time(const path & p, file_time_type new_time) {
  3729. std::error_code ec;
  3730. last_write_time(p, new_time, ec);
  3731. if (ec) {
  3732. throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
  3733. }
  3734. }
  3735. #endif
  3736. GHC_INLINE void last_write_time(const path & p, file_time_type new_time,
  3737. std::error_code & ec) noexcept {
  3738. ec.clear();
  3739. auto d = new_time.time_since_epoch();
  3740. #ifdef GHC_OS_WINDOWS
  3741. std::shared_ptr<void> file(
  3742. ::CreateFileW(p.wstring().c_str(), FILE_WRITE_ATTRIBUTES,
  3743. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  3744. NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL),
  3745. ::CloseHandle);
  3746. FILETIME ft;
  3747. auto tt =
  3748. std::chrono::duration_cast<std::chrono::microseconds>(d).count() *
  3749. 10 +
  3750. 116444736000000000;
  3751. ft.dwLowDateTime = static_cast<DWORD>(tt);
  3752. ft.dwHighDateTime = static_cast<DWORD>(tt >> 32);
  3753. if (!::SetFileTime(file.get(), 0, 0, &ft)) {
  3754. ec = detail::make_system_error();
  3755. }
  3756. #elif defined(GHC_OS_MACOS)
  3757. #ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
  3758. #if __MAC_OS_X_VERSION_MIN_REQUIRED < 101300
  3759. struct ::stat fs;
  3760. if (::stat(p.c_str(), &fs) == 0) {
  3761. struct ::timeval tv[2];
  3762. tv[0].tv_sec = fs.st_atimespec.tv_sec;
  3763. tv[0].tv_usec = static_cast<int>(fs.st_atimespec.tv_nsec / 1000);
  3764. tv[1].tv_sec =
  3765. std::chrono::duration_cast<std::chrono::seconds>(d).count();
  3766. tv[1].tv_usec = static_cast<int>(
  3767. std::chrono::duration_cast<std::chrono::microseconds>(d).count() %
  3768. 1000000);
  3769. if (::utimes(p.c_str(), tv) == 0) { return; }
  3770. }
  3771. ec = detail::make_system_error();
  3772. return;
  3773. #else
  3774. struct ::timespec times[2];
  3775. times[0].tv_sec = 0;
  3776. times[0].tv_nsec = UTIME_OMIT;
  3777. times[1].tv_sec =
  3778. std::chrono::duration_cast<std::chrono::seconds>(d).count();
  3779. times[1].tv_nsec =
  3780. 0; // std::chrono::duration_cast<std::chrono::nanoseconds>(d).count()
  3781. // % 1000000000;
  3782. if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) {
  3783. ec = detail::make_system_error();
  3784. }
  3785. return;
  3786. #endif
  3787. #endif
  3788. #else
  3789. #ifndef UTIME_OMIT
  3790. #define UTIME_OMIT ((1l << 30) - 2l)
  3791. #endif
  3792. struct ::timespec times[2];
  3793. times[0].tv_sec = 0;
  3794. times[0].tv_nsec = UTIME_OMIT;
  3795. times[1].tv_sec = static_cast<decltype(times[1].tv_sec)>(
  3796. std::chrono::duration_cast<std::chrono::seconds>(d).count());
  3797. times[1].tv_nsec = static_cast<decltype(times[1].tv_nsec)>(
  3798. std::chrono::duration_cast<std::chrono::nanoseconds>(d).count() %
  3799. 1000000000);
  3800. #if defined(__ANDROID_API__) && __ANDROID_API__ < 12
  3801. if (syscall(__NR_utimensat, AT_FDCWD, p.c_str(), times,
  3802. AT_SYMLINK_NOFOLLOW) != 0) {
  3803. #else
  3804. if (::utimensat(AT_FDCWD, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) {
  3805. #endif
  3806. ec = detail::make_system_error();
  3807. }
  3808. return;
  3809. #endif
  3810. }
  3811. #ifdef GHC_WITH_EXCEPTIONS
  3812. GHC_INLINE void permissions(const path & p, perms prms, perm_options opts) {
  3813. std::error_code ec;
  3814. permissions(p, prms, opts, ec);
  3815. if (ec) {
  3816. throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
  3817. }
  3818. }
  3819. #endif
  3820. GHC_INLINE void permissions(const path & p, perms prms,
  3821. std::error_code & ec) noexcept {
  3822. permissions(p, prms, perm_options::replace, ec);
  3823. }
  3824. GHC_INLINE void permissions(const path & p, perms prms, perm_options opts,
  3825. std::error_code & ec) {
  3826. if (static_cast<int>(opts & (perm_options::replace | perm_options::add |
  3827. perm_options::remove)) == 0) {
  3828. ec = detail::make_error_code(detail::portable_error::invalid_argument);
  3829. return;
  3830. }
  3831. auto fs = symlink_status(p, ec);
  3832. if ((opts & perm_options::replace) != perm_options::replace) {
  3833. if ((opts & perm_options::add) == perm_options::add) {
  3834. prms = fs.permissions() | prms;
  3835. } else {
  3836. prms = fs.permissions() & ~prms;
  3837. }
  3838. }
  3839. #ifdef GHC_OS_WINDOWS
  3840. #ifdef __GNUC__
  3841. auto oldAttr = GetFileAttributesW(p.wstring().c_str());
  3842. if (oldAttr != INVALID_FILE_ATTRIBUTES) {
  3843. DWORD newAttr =
  3844. ((prms & perms::owner_write) == perms::owner_write)
  3845. ? oldAttr & ~(static_cast<DWORD>(FILE_ATTRIBUTE_READONLY))
  3846. : oldAttr | FILE_ATTRIBUTE_READONLY;
  3847. if (oldAttr == newAttr ||
  3848. SetFileAttributesW(p.wstring().c_str(), newAttr)) {
  3849. return;
  3850. }
  3851. }
  3852. ec = detail::make_system_error();
  3853. #else
  3854. int mode = 0;
  3855. if ((prms & perms::owner_read) == perms::owner_read) { mode |= _S_IREAD; }
  3856. if ((prms & perms::owner_write) == perms::owner_write) {
  3857. mode |= _S_IWRITE;
  3858. }
  3859. if (::_wchmod(p.wstring().c_str(), mode) != 0) {
  3860. ec = detail::make_system_error();
  3861. }
  3862. #endif
  3863. #else
  3864. if ((opts & perm_options::nofollow) != perm_options::nofollow) {
  3865. if (::chmod(p.c_str(), static_cast<mode_t>(prms)) != 0) {
  3866. ec = detail::make_system_error();
  3867. }
  3868. }
  3869. #endif
  3870. }
  3871. #ifdef GHC_WITH_EXCEPTIONS
  3872. GHC_INLINE path proximate(const path & p, std::error_code & ec) {
  3873. return proximate(p, current_path(), ec);
  3874. }
  3875. #endif
  3876. #ifdef GHC_WITH_EXCEPTIONS
  3877. GHC_INLINE path proximate(const path & p, const path & base) {
  3878. return weakly_canonical(p).lexically_proximate(weakly_canonical(base));
  3879. }
  3880. #endif
  3881. GHC_INLINE path proximate(const path & p, const path & base,
  3882. std::error_code & ec) {
  3883. return weakly_canonical(p, ec).lexically_proximate(
  3884. weakly_canonical(base, ec));
  3885. }
  3886. #ifdef GHC_WITH_EXCEPTIONS
  3887. GHC_INLINE path read_symlink(const path & p) {
  3888. std::error_code ec;
  3889. auto result = read_symlink(p, ec);
  3890. if (ec) {
  3891. throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
  3892. }
  3893. return result;
  3894. }
  3895. #endif
  3896. GHC_INLINE path read_symlink(const path & p, std::error_code & ec) {
  3897. file_status fs = symlink_status(p, ec);
  3898. if (fs.type() != file_type::symlink) {
  3899. ec = detail::make_error_code(detail::portable_error::invalid_argument);
  3900. return path();
  3901. }
  3902. auto result = detail::resolveSymlink(p, ec);
  3903. return ec ? path() : result;
  3904. }
  3905. GHC_INLINE path relative(const path & p, std::error_code & ec) {
  3906. return relative(p, current_path(ec), ec);
  3907. }
  3908. #ifdef GHC_WITH_EXCEPTIONS
  3909. GHC_INLINE path relative(const path & p, const path & base) {
  3910. return weakly_canonical(p).lexically_relative(weakly_canonical(base));
  3911. }
  3912. #endif
  3913. GHC_INLINE path relative(const path & p, const path & base,
  3914. std::error_code & ec) {
  3915. return weakly_canonical(p, ec).lexically_relative(
  3916. weakly_canonical(base, ec));
  3917. }
  3918. #ifdef GHC_WITH_EXCEPTIONS
  3919. GHC_INLINE bool remove(const path & p) {
  3920. std::error_code ec;
  3921. auto result = remove(p, ec);
  3922. if (ec) {
  3923. throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
  3924. }
  3925. return result;
  3926. }
  3927. #endif
  3928. GHC_INLINE bool remove(const path & p, std::error_code & ec) noexcept {
  3929. ec.clear();
  3930. #ifdef GHC_OS_WINDOWS
  3931. std::wstring np = detail::fromUtf8<std::wstring>(p.u8string());
  3932. DWORD attr = GetFileAttributesW(np.c_str());
  3933. if (attr == INVALID_FILE_ATTRIBUTES) {
  3934. auto error = ::GetLastError();
  3935. if (error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND) {
  3936. return false;
  3937. }
  3938. ec = detail::make_system_error(error);
  3939. }
  3940. if (!ec) {
  3941. if (attr & FILE_ATTRIBUTE_DIRECTORY) {
  3942. if (!RemoveDirectoryW(np.c_str())) {
  3943. ec = detail::make_system_error();
  3944. }
  3945. } else {
  3946. if (!DeleteFileW(np.c_str())) { ec = detail::make_system_error(); }
  3947. }
  3948. }
  3949. #else
  3950. if (::remove(p.c_str()) == -1) {
  3951. auto error = errno;
  3952. if (error == ENOENT) { return false; }
  3953. ec = detail::make_system_error();
  3954. }
  3955. #endif
  3956. return ec ? false : true;
  3957. }
  3958. #ifdef GHC_WITH_EXCEPTIONS
  3959. GHC_INLINE uintmax_t remove_all(const path & p) {
  3960. std::error_code ec;
  3961. auto result = remove_all(p, ec);
  3962. if (ec) {
  3963. throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
  3964. }
  3965. return result;
  3966. }
  3967. #endif
  3968. GHC_INLINE uintmax_t remove_all(const path & p,
  3969. std::error_code & ec) noexcept {
  3970. ec.clear();
  3971. uintmax_t count = 0;
  3972. if (p == "/") {
  3973. ec = detail::make_error_code(detail::portable_error::not_supported);
  3974. return static_cast<uintmax_t>(-1);
  3975. }
  3976. std::error_code tec;
  3977. auto fs = status(p, tec);
  3978. if (exists(fs) && is_directory(fs)) {
  3979. for (auto iter = directory_iterator(p, ec);
  3980. iter != directory_iterator(); iter.increment(ec)) {
  3981. if (ec) { break; }
  3982. bool is_symlink_result = iter->is_symlink(ec);
  3983. if (ec) return static_cast<uintmax_t>(-1);
  3984. bool is_directory_result = iter->is_directory(ec);
  3985. if (ec) return static_cast<uintmax_t>(-1);
  3986. if (!is_symlink_result && is_directory_result) {
  3987. count += remove_all(iter->path(), ec);
  3988. if (ec) { return static_cast<uintmax_t>(-1); }
  3989. } else {
  3990. remove(iter->path(), ec);
  3991. if (ec) { return static_cast<uintmax_t>(-1); }
  3992. ++count;
  3993. }
  3994. }
  3995. }
  3996. if (!ec) {
  3997. if (remove(p, ec)) { ++count; }
  3998. }
  3999. if (ec) { return static_cast<uintmax_t>(-1); }
  4000. return count;
  4001. }
  4002. #ifdef GHC_WITH_EXCEPTIONS
  4003. GHC_INLINE void rename(const path & from, const path & to) {
  4004. std::error_code ec;
  4005. rename(from, to, ec);
  4006. if (ec) {
  4007. throw filesystem_error(detail::systemErrorText(ec.value()), from, to,
  4008. ec);
  4009. }
  4010. }
  4011. #endif
  4012. GHC_INLINE void rename(const path & from, const path & to,
  4013. std::error_code & ec) noexcept {
  4014. ec.clear();
  4015. #ifdef GHC_OS_WINDOWS
  4016. if (from != to) {
  4017. if (!MoveFileExW(
  4018. detail::fromUtf8<std::wstring>(from.u8string()).c_str(),
  4019. detail::fromUtf8<std::wstring>(to.u8string()).c_str(),
  4020. (DWORD)MOVEFILE_REPLACE_EXISTING)) {
  4021. ec = detail::make_system_error();
  4022. }
  4023. }
  4024. #else
  4025. if (from != to) {
  4026. if (::rename(from.c_str(), to.c_str()) != 0) {
  4027. ec = detail::make_system_error();
  4028. }
  4029. }
  4030. #endif
  4031. }
  4032. #ifdef GHC_WITH_EXCEPTIONS
  4033. GHC_INLINE void resize_file(const path & p, uintmax_t size) {
  4034. std::error_code ec;
  4035. resize_file(p, size, ec);
  4036. if (ec) {
  4037. throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
  4038. }
  4039. }
  4040. #endif
  4041. GHC_INLINE void resize_file(const path & p, uintmax_t size,
  4042. std::error_code & ec) noexcept {
  4043. ec.clear();
  4044. #ifdef GHC_OS_WINDOWS
  4045. LARGE_INTEGER lisize;
  4046. lisize.QuadPart = static_cast<LONGLONG>(size);
  4047. if (lisize.QuadPart < 0) {
  4048. #ifdef ERROR_FILE_TOO_LARGE
  4049. ec = detail::make_system_error(ERROR_FILE_TOO_LARGE);
  4050. #else
  4051. ec = detail::make_system_error(223);
  4052. #endif
  4053. return;
  4054. }
  4055. std::shared_ptr<void> file(
  4056. CreateFileW(detail::fromUtf8<std::wstring>(p.u8string()).c_str(),
  4057. GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL),
  4058. CloseHandle);
  4059. if (file.get() == INVALID_HANDLE_VALUE) {
  4060. ec = detail::make_system_error();
  4061. } else if (SetFilePointerEx(file.get(), lisize, NULL, FILE_BEGIN) == 0 ||
  4062. SetEndOfFile(file.get()) == 0) {
  4063. ec = detail::make_system_error();
  4064. }
  4065. #else
  4066. if (::truncate(p.c_str(), static_cast<off_t>(size)) != 0) {
  4067. ec = detail::make_system_error();
  4068. }
  4069. #endif
  4070. }
  4071. #ifdef GHC_WITH_EXCEPTIONS
  4072. GHC_INLINE space_info space(const path & p) {
  4073. std::error_code ec;
  4074. auto result = space(p, ec);
  4075. if (ec) {
  4076. throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
  4077. }
  4078. return result;
  4079. }
  4080. #endif
  4081. GHC_INLINE space_info space(const path & p, std::error_code & ec) noexcept {
  4082. ec.clear();
  4083. #ifdef GHC_OS_WINDOWS
  4084. ULARGE_INTEGER freeBytesAvailableToCaller = {{ 0, 0 }};
  4085. ULARGE_INTEGER totalNumberOfBytes = {{ 0, 0 }};
  4086. ULARGE_INTEGER totalNumberOfFreeBytes = {{ 0, 0 }};
  4087. if (!GetDiskFreeSpaceExW(
  4088. detail::fromUtf8<std::wstring>(p.u8string()).c_str(),
  4089. &freeBytesAvailableToCaller, &totalNumberOfBytes,
  4090. &totalNumberOfFreeBytes)) {
  4091. ec = detail::make_system_error();
  4092. return {static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1),
  4093. static_cast<uintmax_t>(-1)};
  4094. }
  4095. return {static_cast<uintmax_t>(totalNumberOfBytes.QuadPart),
  4096. static_cast<uintmax_t>(totalNumberOfFreeBytes.QuadPart),
  4097. static_cast<uintmax_t>(freeBytesAvailableToCaller.QuadPart)};
  4098. #else
  4099. struct ::statvfs sfs;
  4100. if (::statvfs(p.c_str(), &sfs) != 0) {
  4101. ec = detail::make_system_error();
  4102. return {static_cast<uintmax_t>(-1), static_cast<uintmax_t>(-1),
  4103. static_cast<uintmax_t>(-1)};
  4104. }
  4105. return {static_cast<uintmax_t>(sfs.f_blocks * sfs.f_frsize),
  4106. static_cast<uintmax_t>(sfs.f_bfree * sfs.f_frsize),
  4107. static_cast<uintmax_t>(sfs.f_bavail * sfs.f_frsize)};
  4108. #endif
  4109. }
  4110. #ifdef GHC_WITH_EXCEPTIONS
  4111. GHC_INLINE file_status status(const path & p) {
  4112. std::error_code ec;
  4113. auto result = status(p, ec);
  4114. if (result.type() == file_type::none) {
  4115. throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
  4116. }
  4117. return result;
  4118. }
  4119. #endif
  4120. GHC_INLINE file_status status(const path & p,
  4121. std::error_code & ec) noexcept {
  4122. return detail::status_ex(p, ec);
  4123. }
  4124. GHC_INLINE bool status_known(file_status s) noexcept {
  4125. return s.type() != file_type::none;
  4126. }
  4127. #ifdef GHC_WITH_EXCEPTIONS
  4128. GHC_INLINE file_status symlink_status(const path & p) {
  4129. std::error_code ec;
  4130. auto result = symlink_status(p, ec);
  4131. if (result.type() == file_type::none) {
  4132. throw filesystem_error(detail::systemErrorText(ec.value()), ec);
  4133. }
  4134. return result;
  4135. }
  4136. #endif
  4137. GHC_INLINE file_status symlink_status(const path & p,
  4138. std::error_code & ec) noexcept {
  4139. return detail::symlink_status_ex(p, ec);
  4140. }
  4141. #ifdef GHC_WITH_EXCEPTIONS
  4142. GHC_INLINE path temp_directory_path() {
  4143. std::error_code ec;
  4144. path result = temp_directory_path(ec);
  4145. if (ec) {
  4146. throw filesystem_error(detail::systemErrorText(ec.value()), ec);
  4147. }
  4148. return result;
  4149. }
  4150. #endif
  4151. GHC_INLINE path temp_directory_path(std::error_code & ec) noexcept {
  4152. ec.clear();
  4153. #ifdef GHC_OS_WINDOWS
  4154. wchar_t buffer[512];
  4155. auto rc = GetTempPathW(511, buffer);
  4156. if (!rc || rc > 511) {
  4157. ec = detail::make_system_error();
  4158. return path();
  4159. }
  4160. return path(std::wstring(buffer));
  4161. #else
  4162. static const char * temp_vars[] = {"TMPDIR", "TMP", "TEMP", "TEMPDIR",
  4163. nullptr};
  4164. const char * temp_path = nullptr;
  4165. for (auto temp_name = temp_vars; *temp_name != nullptr; ++temp_name) {
  4166. temp_path = std::getenv(*temp_name);
  4167. if (temp_path) { return path(temp_path); }
  4168. }
  4169. return path("/tmp");
  4170. #endif
  4171. }
  4172. #ifdef GHC_WITH_EXCEPTIONS
  4173. GHC_INLINE path weakly_canonical(const path & p) {
  4174. std::error_code ec;
  4175. auto result = weakly_canonical(p, ec);
  4176. if (ec) {
  4177. throw filesystem_error(detail::systemErrorText(ec.value()), p, ec);
  4178. }
  4179. return result;
  4180. }
  4181. #endif
  4182. GHC_INLINE path weakly_canonical(const path & p,
  4183. std::error_code & ec) noexcept {
  4184. path result;
  4185. ec.clear();
  4186. bool scan = true;
  4187. for (auto pe : p) {
  4188. if (scan) {
  4189. std::error_code tec;
  4190. if (exists(result / pe, tec)) {
  4191. result /= pe;
  4192. } else {
  4193. if (ec) { return path(); }
  4194. scan = false;
  4195. if (!result.empty()) {
  4196. result = canonical(result, ec) / pe;
  4197. if (ec) { break; }
  4198. } else {
  4199. result /= pe;
  4200. }
  4201. }
  4202. } else {
  4203. result /= pe;
  4204. }
  4205. }
  4206. if (scan) {
  4207. if (!result.empty()) { result = canonical(result, ec); }
  4208. }
  4209. return ec ? path() : result.lexically_normal();
  4210. }
  4211. //-----------------------------------------------------------------------------
  4212. // 30.10.11 class file_status
  4213. // 30.10.11.1 constructors and destructor
  4214. GHC_INLINE file_status::file_status() noexcept
  4215. : file_status(file_type::none) {}
  4216. GHC_INLINE file_status::file_status(file_type ft, perms prms) noexcept
  4217. : _type(ft), _perms(prms) {}
  4218. GHC_INLINE file_status::file_status(const file_status & other) noexcept
  4219. : _type(other._type), _perms(other._perms) {}
  4220. GHC_INLINE file_status::file_status(file_status && other) noexcept
  4221. : _type(other._type), _perms(other._perms) {}
  4222. GHC_INLINE file_status::~file_status() {}
  4223. // assignments:
  4224. GHC_INLINE file_status &
  4225. file_status::operator=(const file_status & rhs) noexcept {
  4226. _type = rhs._type;
  4227. _perms = rhs._perms;
  4228. return *this;
  4229. }
  4230. GHC_INLINE file_status &
  4231. file_status::operator=(file_status && rhs) noexcept {
  4232. _type = rhs._type;
  4233. _perms = rhs._perms;
  4234. return *this;
  4235. }
  4236. // 30.10.11.3 modifiers
  4237. GHC_INLINE void file_status::type(file_type ft) noexcept { _type = ft; }
  4238. GHC_INLINE void file_status::permissions(perms prms) noexcept {
  4239. _perms = prms;
  4240. }
  4241. // 30.10.11.2 observers
  4242. GHC_INLINE file_type file_status::type() const noexcept { return _type; }
  4243. GHC_INLINE perms file_status::permissions() const noexcept {
  4244. return _perms;
  4245. }
  4246. //-----------------------------------------------------------------------------
  4247. // 30.10.12 class directory_entry
  4248. // 30.10.12.1 constructors and destructor
  4249. // directory_entry::directory_entry() noexcept = default;
  4250. // directory_entry::directory_entry(const directory_entry&) = default;
  4251. // directory_entry::directory_entry(directory_entry&&) noexcept = default;
  4252. #ifdef GHC_WITH_EXCEPTIONS
  4253. GHC_INLINE directory_entry::directory_entry(const filesystem::path & p)
  4254. : _path(p), _file_size(0)
  4255. #ifndef GHC_OS_WINDOWS
  4256. ,
  4257. _hard_link_count(0)
  4258. #endif
  4259. ,
  4260. _last_write_time(0) {
  4261. refresh();
  4262. }
  4263. #endif
  4264. GHC_INLINE directory_entry::directory_entry(const filesystem::path & p,
  4265. std::error_code & ec)
  4266. : _path(p), _file_size(0)
  4267. #ifndef GHC_OS_WINDOWS
  4268. ,
  4269. _hard_link_count(0)
  4270. #endif
  4271. ,
  4272. _last_write_time(0) {
  4273. refresh(ec);
  4274. }
  4275. GHC_INLINE directory_entry::~directory_entry() {}
  4276. // assignments:
  4277. // directory_entry& directory_entry::operator=(const directory_entry&) =
  4278. // default; directory_entry& directory_entry::operator=(directory_entry&&)
  4279. // noexcept = default;
  4280. // 30.10.12.2 directory_entry modifiers
  4281. #ifdef GHC_WITH_EXCEPTIONS
  4282. GHC_INLINE void directory_entry::assign(const filesystem::path & p) {
  4283. _path = p;
  4284. refresh();
  4285. }
  4286. #endif
  4287. GHC_INLINE void directory_entry::assign(const filesystem::path & p,
  4288. std::error_code & ec) {
  4289. _path = p;
  4290. refresh(ec);
  4291. }
  4292. #ifdef GHC_WITH_EXCEPTIONS
  4293. GHC_INLINE void
  4294. directory_entry::replace_filename(const filesystem::path & p) {
  4295. _path.replace_filename(p);
  4296. refresh();
  4297. }
  4298. #endif
  4299. GHC_INLINE void
  4300. directory_entry::replace_filename(const filesystem::path & p,
  4301. std::error_code & ec) {
  4302. _path.replace_filename(p);
  4303. refresh(ec);
  4304. }
  4305. #ifdef GHC_WITH_EXCEPTIONS
  4306. GHC_INLINE void directory_entry::refresh() {
  4307. std::error_code ec;
  4308. refresh(ec);
  4309. if (ec) {
  4310. throw filesystem_error(detail::systemErrorText(ec.value()), _path, ec);
  4311. }
  4312. }
  4313. #endif
  4314. GHC_INLINE void directory_entry::refresh(std::error_code & ec) noexcept {
  4315. #ifdef GHC_OS_WINDOWS
  4316. _status = detail::status_ex(_path, ec, &_symlink_status, &_file_size,
  4317. nullptr, &_last_write_time);
  4318. #else
  4319. _status = detail::status_ex(_path, ec, &_symlink_status, &_file_size,
  4320. &_hard_link_count, &_last_write_time);
  4321. #endif
  4322. }
  4323. // 30.10.12.3 directory_entry observers
  4324. GHC_INLINE const filesystem::path & directory_entry::path() const noexcept {
  4325. return _path;
  4326. }
  4327. GHC_INLINE
  4328. directory_entry::operator const filesystem::path &() const noexcept {
  4329. return _path;
  4330. }
  4331. #ifdef GHC_WITH_EXCEPTIONS
  4332. GHC_INLINE bool directory_entry::exists() const {
  4333. return filesystem::exists(status());
  4334. }
  4335. #endif
  4336. GHC_INLINE bool
  4337. directory_entry::exists(std::error_code & ec) const noexcept {
  4338. return filesystem::exists(status(ec));
  4339. }
  4340. #ifdef GHC_WITH_EXCEPTIONS
  4341. GHC_INLINE bool directory_entry::is_block_file() const {
  4342. return filesystem::is_block_file(status());
  4343. }
  4344. #endif
  4345. GHC_INLINE bool
  4346. directory_entry::is_block_file(std::error_code & ec) const noexcept {
  4347. return filesystem::is_block_file(status(ec));
  4348. }
  4349. #ifdef GHC_WITH_EXCEPTIONS
  4350. GHC_INLINE bool directory_entry::is_character_file() const {
  4351. return filesystem::is_character_file(status());
  4352. }
  4353. #endif
  4354. GHC_INLINE bool
  4355. directory_entry::is_character_file(std::error_code & ec) const noexcept {
  4356. return filesystem::is_character_file(status(ec));
  4357. }
  4358. #ifdef GHC_WITH_EXCEPTIONS
  4359. GHC_INLINE bool directory_entry::is_directory() const {
  4360. return filesystem::is_directory(status());
  4361. }
  4362. #endif
  4363. GHC_INLINE bool
  4364. directory_entry::is_directory(std::error_code & ec) const noexcept {
  4365. return filesystem::is_directory(status(ec));
  4366. }
  4367. #ifdef GHC_WITH_EXCEPTIONS
  4368. GHC_INLINE bool directory_entry::is_fifo() const {
  4369. return filesystem::is_fifo(status());
  4370. }
  4371. #endif
  4372. GHC_INLINE bool
  4373. directory_entry::is_fifo(std::error_code & ec) const noexcept {
  4374. return filesystem::is_fifo(status(ec));
  4375. }
  4376. #ifdef GHC_WITH_EXCEPTIONS
  4377. GHC_INLINE bool directory_entry::is_other() const {
  4378. return filesystem::is_other(status());
  4379. }
  4380. #endif
  4381. GHC_INLINE bool
  4382. directory_entry::is_other(std::error_code & ec) const noexcept {
  4383. return filesystem::is_other(status(ec));
  4384. }
  4385. #ifdef GHC_WITH_EXCEPTIONS
  4386. GHC_INLINE bool directory_entry::is_regular_file() const {
  4387. return filesystem::is_regular_file(status());
  4388. }
  4389. #endif
  4390. GHC_INLINE bool
  4391. directory_entry::is_regular_file(std::error_code & ec) const noexcept {
  4392. return filesystem::is_regular_file(status(ec));
  4393. }
  4394. #ifdef GHC_WITH_EXCEPTIONS
  4395. GHC_INLINE bool directory_entry::is_socket() const {
  4396. return filesystem::is_socket(status());
  4397. }
  4398. #endif
  4399. GHC_INLINE bool
  4400. directory_entry::is_socket(std::error_code & ec) const noexcept {
  4401. return filesystem::is_socket(status(ec));
  4402. }
  4403. #ifdef GHC_WITH_EXCEPTIONS
  4404. GHC_INLINE bool directory_entry::is_symlink() const {
  4405. return filesystem::is_symlink(symlink_status());
  4406. }
  4407. #endif
  4408. GHC_INLINE bool
  4409. directory_entry::is_symlink(std::error_code & ec) const noexcept {
  4410. return filesystem::is_symlink(symlink_status(ec));
  4411. }
  4412. #ifdef GHC_WITH_EXCEPTIONS
  4413. GHC_INLINE uintmax_t directory_entry::file_size() const {
  4414. if (_status.type() != file_type::none) { return _file_size; }
  4415. return filesystem::file_size(path());
  4416. }
  4417. #endif
  4418. GHC_INLINE uintmax_t
  4419. directory_entry::file_size(std::error_code & ec) const noexcept {
  4420. if (_status.type() != file_type::none) {
  4421. ec.clear();
  4422. return _file_size;
  4423. }
  4424. return filesystem::file_size(path(), ec);
  4425. }
  4426. #ifndef GHC_OS_WEB
  4427. #ifdef GHC_WITH_EXCEPTIONS
  4428. GHC_INLINE uintmax_t directory_entry::hard_link_count() const {
  4429. #ifndef GHC_OS_WINDOWS
  4430. if (_status.type() != file_type::none) { return _hard_link_count; }
  4431. #endif
  4432. return filesystem::hard_link_count(path());
  4433. }
  4434. #endif
  4435. GHC_INLINE uintmax_t
  4436. directory_entry::hard_link_count(std::error_code & ec) const noexcept {
  4437. #ifndef GHC_OS_WINDOWS
  4438. if (_status.type() != file_type::none) {
  4439. ec.clear();
  4440. return _hard_link_count;
  4441. }
  4442. #endif
  4443. return filesystem::hard_link_count(path(), ec);
  4444. }
  4445. #endif
  4446. #ifdef GHC_WITH_EXCEPTIONS
  4447. GHC_INLINE file_time_type directory_entry::last_write_time() const {
  4448. if (_status.type() != file_type::none) {
  4449. return std::chrono::system_clock::from_time_t(_last_write_time);
  4450. }
  4451. return filesystem::last_write_time(path());
  4452. }
  4453. #endif
  4454. GHC_INLINE file_time_type
  4455. directory_entry::last_write_time(std::error_code & ec) const noexcept {
  4456. if (_status.type() != file_type::none) {
  4457. ec.clear();
  4458. return std::chrono::system_clock::from_time_t(_last_write_time);
  4459. }
  4460. return filesystem::last_write_time(path(), ec);
  4461. }
  4462. #ifdef GHC_WITH_EXCEPTIONS
  4463. GHC_INLINE file_status directory_entry::status() const {
  4464. if (_status.type() != file_type::none) { return _status; }
  4465. return filesystem::status(path());
  4466. }
  4467. #endif
  4468. GHC_INLINE file_status
  4469. directory_entry::status(std::error_code & ec) const noexcept {
  4470. if (_status.type() != file_type::none) {
  4471. ec.clear();
  4472. return _status;
  4473. }
  4474. return filesystem::status(path(), ec);
  4475. }
  4476. #ifdef GHC_WITH_EXCEPTIONS
  4477. GHC_INLINE file_status directory_entry::symlink_status() const {
  4478. if (_symlink_status.type() != file_type::none) { return _symlink_status; }
  4479. return filesystem::symlink_status(path());
  4480. }
  4481. #endif
  4482. GHC_INLINE file_status
  4483. directory_entry::symlink_status(std::error_code & ec) const noexcept {
  4484. if (_symlink_status.type() != file_type::none) {
  4485. ec.clear();
  4486. return _symlink_status;
  4487. }
  4488. return filesystem::symlink_status(path(), ec);
  4489. }
  4490. GHC_INLINE bool
  4491. directory_entry::operator<(const directory_entry & rhs) const noexcept {
  4492. return _path < rhs._path;
  4493. }
  4494. GHC_INLINE bool
  4495. directory_entry::operator==(const directory_entry & rhs) const noexcept {
  4496. return _path == rhs._path;
  4497. }
  4498. GHC_INLINE bool
  4499. directory_entry::operator!=(const directory_entry & rhs) const noexcept {
  4500. return _path != rhs._path;
  4501. }
  4502. GHC_INLINE bool
  4503. directory_entry::operator<=(const directory_entry & rhs) const noexcept {
  4504. return _path <= rhs._path;
  4505. }
  4506. GHC_INLINE bool
  4507. directory_entry::operator>(const directory_entry & rhs) const noexcept {
  4508. return _path > rhs._path;
  4509. }
  4510. GHC_INLINE bool
  4511. directory_entry::operator>=(const directory_entry & rhs) const noexcept {
  4512. return _path >= rhs._path;
  4513. }
  4514. //-----------------------------------------------------------------------------
  4515. // 30.10.13 class directory_iterator
  4516. #ifdef GHC_OS_WINDOWS
  4517. class directory_iterator::impl {
  4518. public:
  4519. impl(const path & p, directory_options options)
  4520. : _base(p), _options(options), _dirHandle(INVALID_HANDLE_VALUE) {
  4521. if (!_base.empty()) {
  4522. ZeroMemory(&_findData, sizeof(WIN32_FIND_DATAW));
  4523. if ((_dirHandle = FindFirstFileW(
  4524. detail::fromUtf8<std::wstring>((_base / "*").u8string())
  4525. .c_str(),
  4526. &_findData)) != INVALID_HANDLE_VALUE) {
  4527. if (std::wstring(_findData.cFileName) == L"." ||
  4528. std::wstring(_findData.cFileName) == L"..") {
  4529. increment(_ec);
  4530. } else {
  4531. _current = _base / std::wstring(_findData.cFileName);
  4532. copyToDirEntry(_ec);
  4533. }
  4534. } else {
  4535. auto error = ::GetLastError();
  4536. _base = filesystem::path();
  4537. if (error != ERROR_ACCESS_DENIED ||
  4538. (options & directory_options::skip_permission_denied) ==
  4539. directory_options::none) {
  4540. _ec = detail::make_system_error();
  4541. }
  4542. }
  4543. }
  4544. }
  4545. impl(const impl & other) = delete;
  4546. ~impl() {
  4547. if (_dirHandle != INVALID_HANDLE_VALUE) {
  4548. FindClose(_dirHandle);
  4549. _dirHandle = INVALID_HANDLE_VALUE;
  4550. }
  4551. }
  4552. void increment(std::error_code & ec) {
  4553. if (_dirHandle != INVALID_HANDLE_VALUE) {
  4554. do {
  4555. if (FindNextFileW(_dirHandle, &_findData)) {
  4556. _current = _base;
  4557. #ifdef GHC_RAISE_UNICODE_ERRORS
  4558. try {
  4559. _current.append_name(
  4560. detail::toUtf8(_findData.cFileName).c_str());
  4561. } catch (filesystem_error & fe) {
  4562. ec = fe.code();
  4563. return;
  4564. }
  4565. #else
  4566. _current.append_name(detail::toUtf8(_findData.cFileName).c_str());
  4567. #endif
  4568. copyToDirEntry(ec);
  4569. } else {
  4570. auto err = ::GetLastError();
  4571. if (err != ERROR_NO_MORE_FILES) {
  4572. _ec = ec = detail::make_system_error(err);
  4573. }
  4574. FindClose(_dirHandle);
  4575. _dirHandle = INVALID_HANDLE_VALUE;
  4576. _current = filesystem::path();
  4577. break;
  4578. }
  4579. } while (std::wstring(_findData.cFileName) == L"." ||
  4580. std::wstring(_findData.cFileName) == L"..");
  4581. } else {
  4582. ec = _ec;
  4583. }
  4584. }
  4585. void copyToDirEntry(std::error_code & ec) {
  4586. _dir_entry._path = _current;
  4587. if (_findData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
  4588. _dir_entry._status = detail::status_ex(
  4589. _current, ec, &_dir_entry._symlink_status, &_dir_entry._file_size,
  4590. nullptr, &_dir_entry._last_write_time);
  4591. } else {
  4592. _dir_entry._status = detail::status_from_INFO(
  4593. _current, &_findData, ec, &_dir_entry._file_size,
  4594. &_dir_entry._last_write_time);
  4595. _dir_entry._symlink_status = _dir_entry._status;
  4596. }
  4597. if (ec) {
  4598. if (_dir_entry._status.type() != file_type::none &&
  4599. _dir_entry._symlink_status.type() != file_type::none) {
  4600. ec.clear();
  4601. } else {
  4602. _dir_entry._file_size = static_cast<uintmax_t>(-1);
  4603. _dir_entry._last_write_time = 0;
  4604. }
  4605. }
  4606. }
  4607. path _base;
  4608. directory_options _options;
  4609. WIN32_FIND_DATAW _findData;
  4610. HANDLE _dirHandle;
  4611. path _current;
  4612. directory_entry _dir_entry;
  4613. std::error_code _ec;
  4614. };
  4615. #else
  4616. // POSIX implementation
  4617. class directory_iterator::impl {
  4618. public:
  4619. impl(const path & path, directory_options options)
  4620. : _base(path), _options(options), _dir(nullptr), _entry(nullptr) {
  4621. if (!path.empty()) { _dir = ::opendir(path.native().c_str()); }
  4622. if (!path.empty()) {
  4623. if (!_dir) {
  4624. auto error = errno;
  4625. _base = filesystem::path();
  4626. if (error != EACCES ||
  4627. (options & directory_options::skip_permission_denied) ==
  4628. directory_options::none) {
  4629. _ec = detail::make_system_error();
  4630. }
  4631. } else {
  4632. increment(_ec);
  4633. }
  4634. }
  4635. }
  4636. impl(const impl & other) = delete;
  4637. ~impl() {
  4638. if (_dir) { ::closedir(_dir); }
  4639. }
  4640. void increment(std::error_code & ec) {
  4641. if (_dir) {
  4642. bool skip;
  4643. do {
  4644. skip = false;
  4645. errno = 0;
  4646. _entry = ::readdir(_dir);
  4647. if (_entry) {
  4648. _current = _base;
  4649. _current.append_name(_entry->d_name);
  4650. _dir_entry = directory_entry(_current, ec);
  4651. if (ec && (ec.value() == EACCES || ec.value() == EPERM) &&
  4652. (_options & directory_options::skip_permission_denied) ==
  4653. directory_options::skip_permission_denied) {
  4654. ec.clear();
  4655. skip = true;
  4656. }
  4657. } else {
  4658. ::closedir(_dir);
  4659. _dir = nullptr;
  4660. _current = path();
  4661. if (errno) { ec = detail::make_system_error(); }
  4662. break;
  4663. }
  4664. } while (skip || std::strcmp(_entry->d_name, ".") == 0 ||
  4665. std::strcmp(_entry->d_name, "..") == 0);
  4666. }
  4667. }
  4668. path _base;
  4669. directory_options _options;
  4670. path _current;
  4671. DIR * _dir;
  4672. struct ::dirent * _entry;
  4673. directory_entry _dir_entry;
  4674. std::error_code _ec;
  4675. };
  4676. #endif
  4677. // 30.10.13.1 member functions
  4678. GHC_INLINE directory_iterator::directory_iterator() noexcept
  4679. : _impl(new impl(path(), directory_options::none)) {}
  4680. #ifdef GHC_WITH_EXCEPTIONS
  4681. GHC_INLINE directory_iterator::directory_iterator(const path & p)
  4682. : _impl(new impl(p, directory_options::none)) {
  4683. if (_impl->_ec) {
  4684. throw filesystem_error(detail::systemErrorText(_impl->_ec.value()), p,
  4685. _impl->_ec);
  4686. }
  4687. _impl->_ec.clear();
  4688. }
  4689. GHC_INLINE directory_iterator::directory_iterator(const path & p,
  4690. directory_options options)
  4691. : _impl(new impl(p, options)) {
  4692. if (_impl->_ec) {
  4693. throw filesystem_error(detail::systemErrorText(_impl->_ec.value()), p,
  4694. _impl->_ec);
  4695. }
  4696. }
  4697. #endif
  4698. GHC_INLINE
  4699. directory_iterator::directory_iterator(const path & p,
  4700. std::error_code & ec) noexcept
  4701. : _impl(new impl(p, directory_options::none)) {
  4702. if (_impl->_ec) { ec = _impl->_ec; }
  4703. }
  4704. GHC_INLINE
  4705. directory_iterator::directory_iterator(const path & p,
  4706. directory_options options,
  4707. std::error_code & ec) noexcept
  4708. : _impl(new impl(p, options)) {
  4709. if (_impl->_ec) { ec = _impl->_ec; }
  4710. }
  4711. GHC_INLINE
  4712. directory_iterator::directory_iterator(const directory_iterator & rhs)
  4713. : _impl(rhs._impl) {}
  4714. GHC_INLINE
  4715. directory_iterator::directory_iterator(directory_iterator && rhs) noexcept
  4716. : _impl(std::move(rhs._impl)) {}
  4717. GHC_INLINE directory_iterator::~directory_iterator() {}
  4718. GHC_INLINE directory_iterator &
  4719. directory_iterator::operator=(const directory_iterator & rhs) {
  4720. _impl = rhs._impl;
  4721. return *this;
  4722. }
  4723. GHC_INLINE directory_iterator &
  4724. directory_iterator::operator=(directory_iterator && rhs) noexcept {
  4725. _impl = std::move(rhs._impl);
  4726. return *this;
  4727. }
  4728. GHC_INLINE const directory_entry & directory_iterator::operator*() const {
  4729. return _impl->_dir_entry;
  4730. }
  4731. GHC_INLINE const directory_entry * directory_iterator::operator->() const {
  4732. return &_impl->_dir_entry;
  4733. }
  4734. #ifdef GHC_WITH_EXCEPTIONS
  4735. GHC_INLINE directory_iterator & directory_iterator::operator++() {
  4736. std::error_code ec;
  4737. _impl->increment(ec);
  4738. if (ec) {
  4739. throw filesystem_error(detail::systemErrorText(ec.value()),
  4740. _impl->_current, ec);
  4741. }
  4742. return *this;
  4743. }
  4744. #endif
  4745. GHC_INLINE directory_iterator &
  4746. directory_iterator::increment(std::error_code & ec) noexcept {
  4747. _impl->increment(ec);
  4748. return *this;
  4749. }
  4750. GHC_INLINE bool
  4751. directory_iterator::operator==(const directory_iterator & rhs) const {
  4752. return _impl->_current == rhs._impl->_current;
  4753. }
  4754. GHC_INLINE bool
  4755. directory_iterator::operator!=(const directory_iterator & rhs) const {
  4756. return _impl->_current != rhs._impl->_current;
  4757. }
  4758. // 30.10.13.2 directory_iterator non-member functions
  4759. GHC_INLINE directory_iterator begin(directory_iterator iter) noexcept {
  4760. return iter;
  4761. }
  4762. GHC_INLINE directory_iterator end(const directory_iterator &) noexcept {
  4763. return directory_iterator();
  4764. }
  4765. //-----------------------------------------------------------------------------
  4766. // 30.10.14 class recursive_directory_iterator
  4767. GHC_INLINE
  4768. recursive_directory_iterator::recursive_directory_iterator() noexcept
  4769. : _impl(new recursive_directory_iterator_impl(directory_options::none,
  4770. true)) {
  4771. _impl->_dir_iter_stack.push(directory_iterator());
  4772. }
  4773. #ifdef GHC_WITH_EXCEPTIONS
  4774. GHC_INLINE
  4775. recursive_directory_iterator::recursive_directory_iterator(const path & p)
  4776. : _impl(new recursive_directory_iterator_impl(directory_options::none,
  4777. true)) {
  4778. _impl->_dir_iter_stack.push(directory_iterator(p));
  4779. }
  4780. GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(
  4781. const path & p, directory_options options)
  4782. : _impl(new recursive_directory_iterator_impl(options, true)) {
  4783. _impl->_dir_iter_stack.push(directory_iterator(p, options));
  4784. }
  4785. #endif
  4786. GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(
  4787. const path & p, directory_options options,
  4788. std::error_code & ec) noexcept
  4789. : _impl(new recursive_directory_iterator_impl(options, true)) {
  4790. _impl->_dir_iter_stack.push(directory_iterator(p, options, ec));
  4791. }
  4792. GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(
  4793. const path & p, std::error_code & ec) noexcept
  4794. : _impl(new recursive_directory_iterator_impl(directory_options::none,
  4795. true)) {
  4796. _impl->_dir_iter_stack.push(directory_iterator(p, ec));
  4797. }
  4798. GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(
  4799. const recursive_directory_iterator & rhs)
  4800. : _impl(rhs._impl) {}
  4801. GHC_INLINE recursive_directory_iterator::recursive_directory_iterator(
  4802. recursive_directory_iterator && rhs) noexcept
  4803. : _impl(std::move(rhs._impl)) {}
  4804. GHC_INLINE recursive_directory_iterator::~recursive_directory_iterator() {}
  4805. // 30.10.14.1 observers
  4806. GHC_INLINE directory_options recursive_directory_iterator::options() const {
  4807. return _impl->_options;
  4808. }
  4809. GHC_INLINE int recursive_directory_iterator::depth() const {
  4810. return static_cast<int>(_impl->_dir_iter_stack.size() - 1);
  4811. }
  4812. GHC_INLINE bool recursive_directory_iterator::recursion_pending() const {
  4813. return _impl->_recursion_pending;
  4814. }
  4815. GHC_INLINE const directory_entry &
  4816. recursive_directory_iterator::operator*() const {
  4817. return *(_impl->_dir_iter_stack.top());
  4818. }
  4819. GHC_INLINE const directory_entry *
  4820. recursive_directory_iterator::operator->() const {
  4821. return &(*(_impl->_dir_iter_stack.top()));
  4822. }
  4823. // 30.10.14.1 modifiers recursive_directory_iterator&
  4824. GHC_INLINE recursive_directory_iterator &
  4825. recursive_directory_iterator::operator=(
  4826. const recursive_directory_iterator & rhs) {
  4827. _impl = rhs._impl;
  4828. return *this;
  4829. }
  4830. GHC_INLINE recursive_directory_iterator &
  4831. recursive_directory_iterator::operator=(
  4832. recursive_directory_iterator && rhs) noexcept {
  4833. _impl = std::move(rhs._impl);
  4834. return *this;
  4835. }
  4836. #ifdef GHC_WITH_EXCEPTIONS
  4837. GHC_INLINE recursive_directory_iterator &
  4838. recursive_directory_iterator::operator++() {
  4839. std::error_code ec;
  4840. increment(ec);
  4841. if (ec) {
  4842. throw filesystem_error(detail::systemErrorText(ec.value()),
  4843. _impl->_dir_iter_stack.empty()
  4844. ? path()
  4845. : _impl->_dir_iter_stack.top()->path(),
  4846. ec);
  4847. }
  4848. return *this;
  4849. }
  4850. #endif
  4851. GHC_INLINE recursive_directory_iterator &
  4852. recursive_directory_iterator::increment(std::error_code & ec) noexcept {
  4853. auto status = (*this)->status(ec);
  4854. if (ec) return *this;
  4855. auto symlink_status = (*this)->symlink_status(ec);
  4856. if (ec) return *this;
  4857. if (recursion_pending() && is_directory(status) &&
  4858. (!is_symlink(symlink_status) ||
  4859. (options() & directory_options::follow_directory_symlink) !=
  4860. directory_options::none)) {
  4861. _impl->_dir_iter_stack.push(
  4862. directory_iterator((*this)->path(), _impl->_options, ec));
  4863. } else {
  4864. _impl->_dir_iter_stack.top().increment(ec);
  4865. }
  4866. if (!ec) {
  4867. while (depth() &&
  4868. _impl->_dir_iter_stack.top() == directory_iterator()) {
  4869. _impl->_dir_iter_stack.pop();
  4870. _impl->_dir_iter_stack.top().increment(ec);
  4871. }
  4872. } else if (!_impl->_dir_iter_stack.empty()) {
  4873. _impl->_dir_iter_stack.pop();
  4874. }
  4875. _impl->_recursion_pending = true;
  4876. return *this;
  4877. }
  4878. #ifdef GHC_WITH_EXCEPTIONS
  4879. GHC_INLINE void recursive_directory_iterator::pop() {
  4880. std::error_code ec;
  4881. pop(ec);
  4882. if (ec) {
  4883. throw filesystem_error(detail::systemErrorText(ec.value()),
  4884. _impl->_dir_iter_stack.empty()
  4885. ? path()
  4886. : _impl->_dir_iter_stack.top()->path(),
  4887. ec);
  4888. }
  4889. }
  4890. #endif
  4891. GHC_INLINE void recursive_directory_iterator::pop(std::error_code & ec) {
  4892. if (depth() == 0) {
  4893. *this = recursive_directory_iterator();
  4894. } else {
  4895. do {
  4896. _impl->_dir_iter_stack.pop();
  4897. _impl->_dir_iter_stack.top().increment(ec);
  4898. } while (depth() &&
  4899. _impl->_dir_iter_stack.top() == directory_iterator());
  4900. }
  4901. }
  4902. GHC_INLINE void recursive_directory_iterator::disable_recursion_pending() {
  4903. _impl->_recursion_pending = false;
  4904. }
  4905. // other members as required by 27.2.3, input iterators
  4906. GHC_INLINE bool recursive_directory_iterator::operator==(
  4907. const recursive_directory_iterator & rhs) const {
  4908. return _impl->_dir_iter_stack.top() == rhs._impl->_dir_iter_stack.top();
  4909. }
  4910. GHC_INLINE bool recursive_directory_iterator::operator!=(
  4911. const recursive_directory_iterator & rhs) const {
  4912. return _impl->_dir_iter_stack.top() != rhs._impl->_dir_iter_stack.top();
  4913. }
  4914. // 30.10.14.2 directory_iterator non-member functions
  4915. GHC_INLINE recursive_directory_iterator
  4916. begin(recursive_directory_iterator iter) noexcept {
  4917. return iter;
  4918. }
  4919. GHC_INLINE recursive_directory_iterator
  4920. end(const recursive_directory_iterator &) noexcept {
  4921. return recursive_directory_iterator();
  4922. }
  4923. #endif // GHC_EXPAND_IMPL
  4924. } // namespace filesystem
  4925. } // namespace ghc
  4926. // cleanup some macros
  4927. #undef GHC_INLINE
  4928. #undef GHC_EXPAND_IMPL
  4929. #endif // GHC_FILESYSTEM_H