ghc_filesystem.h 187 KB

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