Something went wrong. Try again.
javascript for 🐜's, a tiny runtime with big ambitions antjs.org
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003// TODO: split into multiple files src/fs
#include <compat.h> // IWYU pragma: keep
#include <uv.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdbool.h>#include <limits.h>#include <sys/stat.h>#include <fcntl.h>#ifndef _WIN32#include <unistd.h>#endif#include <uthash.h>#include <errno.h>
#include "ant.h"#include "list.h"#include "cfunc.h"#include "ptr.h"#include "utf8.h"#include "utils.h"#include "base64.h"#include "errors.h"#include "modules/process.h"#include "watch.h"#include "internal.h"#include "descriptors.h"
#include "gc.h"#include "gc/uv.h"#include "gc/roots.h"#include "gc/modules.h"#include "silver/call.h"
#include "loop.h"#include "modules/fs.h"#include "modules/date.h"#include "modules/buffer.h"#include "modules/abort.h"#include "modules/events.h"#include "modules/stream.h"#include "modules/url.h"#include "modules/iterator.h"#include "esm/loader.h"#include "esm/commonjs.h"
typedef enum { FS_ENC_NONE = 0, FS_ENC_UTF8, FS_ENC_UTF16LE, FS_ENC_LATIN1, FS_ENC_BASE64, FS_ENC_BASE64URL, FS_ENC_HEX, FS_ENC_ASCII,} fs_encoding_t;
typedef enum { FS_OP_READ, FS_OP_WRITE, FS_OP_UNLINK, FS_OP_MKDIR, FS_OP_RMDIR, FS_OP_STAT, FS_OP_READ_BYTES, FS_OP_EXISTS, FS_OP_READDIR, FS_OP_ACCESS, FS_OP_REALPATH, FS_OP_WRITE_FD, FS_OP_READ_FD, FS_OP_OPEN, FS_OP_CLOSE, FS_OP_MKDTEMP, FS_OP_CHMOD, FS_OP_RENAME, FS_OP_SYMLINK, FS_OP_LINK, FS_OP_FSYNC, FS_OP_OPENDIR, FS_OP_DIR_READ, FS_OP_DIR_CLOSE, FS_OP_DIR_ITER_NEXT, FS_OP_DIR_ITER_RETURN, FS_OP_DIR_ITER_CLOSE} fs_op_type_t;
struct fs_request_s { fs_request_t *next; fs_request_t **pprev; uv_fs_t uv_req; ant_value_t promise; ant_value_t target_buffer; ant_value_t callback_fn; ant_value_t owner; ant_value_t signal;
char *path; char *path2; char *data; char *error_msg; const char *syscall; size_t data_len; size_t data_cap; size_t buf_offset;
fs_op_type_t op_type; fs_encoding_t encoding; uv_file fd;
int completed; int failed; int recursive; int error_code; int with_file_types; bool buffer_encoding; bool retried; fs_request_t *dir_next;};
typedef struct { const char *data; size_t len;} fs_write_data_t;
static bool fs_view_bytes(ant_value_t value, uint8_t **bytes, size_t *len) { TypedArrayData *ta = buffer_get_typedarray_data(value); DataViewData *dv = ta ? NULL : buffer_get_dataview_data(value); if (ta) Ant_Buffer_GetViewBytes(ta, bytes, len); else if (dv) Ant_Buffer_GetViewBytes(dv, bytes, len); else return false; return true;}
static ant_value_t fs_get_write_data_arg( ant_t *js, ant_value_t value, const char *fn_name, fs_write_data_t *out) { out->data = NULL; out->len = 0;
if (vtype(value) == kTypeString) { out->data = js_getstr(js, value, &out->len); if (!out->data) return js_mkerr(js, "Failed to get string"); return js_mkundef(); }
uint8_t *bytes; if (!fs_view_bytes(value, &bytes, &out->len)) return js_mkerr(js, "%s() data must be a Buffer, TypedArray, DataView, or string", fn_name);
out->data = (const char *)bytes; return js_mkundef();}
typedef enum { FS_WATCH_MODE_EVENT = 0, FS_WATCH_MODE_STAT} fs_watch_mode_t;
typedef union { uv_fs_event_t event; uv_fs_poll_t poll;} fs_watcher_handle_t;
struct fs_watcher_s { fs_watcher_t *next; fs_watcher_t **pprev; ant_value_t obj; ant_value_t callback; fs_watcher_handle_t handle; uv_stat_t last_stat; char *path; bool last_stat_valid; bool closing; bool handle_closed; bool finalized; bool persistent; bool buffer_encoding; fs_watch_mode_t mode;};
static inline ant_t *fs_req_isolate(fs_request_t *req) { return Ant_Loop_Isolate(req->uv_req.loop);}
static inline ant_t *fs_watcher_isolate(fs_watcher_t *watcher) { return Ant_Loop_Isolate(((uv_handle_t *)&watcher->handle)->loop);}
typedef struct { bool persistent; bool recursive; bool buffer_encoding; ant_value_t listener;} fs_watch_options_t;
typedef struct { bool persistent; unsigned int interval_ms; ant_value_t listener;} fs_watchfile_options_t;
typedef struct { mode_t mode; double dev, ino, nlink, uid, gid, rdev, size, blksize, blocks; double atime_ms, mtime_ms, ctime_ms, birthtime_ms;} fs_stat_fields_t;
static constexpr uint32_t FS_WATCHER_NATIVE_TAG = Ant_NativeTag("FSWT");static constexpr uint32_t FS_FILEHANDLE_NATIVE_TAG = Ant_NativeTag("FSFH");static constexpr uint32_t FS_DIR_NATIVE_TAG = Ant_NativeTag("FSDR");
static fs_watcher_t *fs_watcher_data(ant_value_t value) { return (fs_watcher_t *)js_get_native(value, FS_WATCHER_NATIVE_TAG);}
static void fs_add_active_watcher(fs_watcher_t *watcher) { if (watcher) Ant_List_Insert(&fs_watcher_isolate(watcher)->fs_watchers, watcher);}
static ant_value_t fs_call_callback( ant_t *js, ant_value_t fn, ant_value_t *args, int nargs) { ant_value_t result = Ant_Error_CallCallback(js, fn, js_mkundef(), args, nargs); process_report_uncaught_exception_if_pending(js); return result;}
#define FS_WRITE_FLAGS (O_WRONLY | O_CREAT | O_TRUNC)#define FS_APPEND_FLAGS (O_WRONLY | O_CREAT | O_APPEND)
static int parse_open_flags(ant_t *js, ant_value_t arg);static bool fs_open_flags_of(ant_t *js, ant_value_t arg, int *out);static ant_value_t fs_coerce_path(ant_t *js, ant_value_t arg);static bool fs_buffer_encoding(ant_t *js, ant_value_t options);static ant_value_t fs_path_result(ant_t *js, const char *data, size_t len, bool as_buffer);
static ant_value_t fs_mk_errno_error( ant_t *js, int err_num, const char *syscall, const char *path, const char *dest);
static ant_value_t fs_mk_uv_error( ant_t *js, int uv_code, const char *syscall, const char *path, const char *dest);
static bool fs_parse_mode(ant_t *js, ant_value_t arg, mode_t *out) { if (vtype(arg) == kTypeNumber) { double mode = js_getnum(arg); if (!(mode >= 0 && mode <= 0xFFFFFFFF) || mode != (double)(uint32_t)mode) return false; *out = (mode_t)mode; return true; }
if (vtype(arg) != kTypeString) return false;
size_t len = 0; const char *str = js_getstr(js, arg, &len); if (!str) return false;
size_t start = 0; if (len > 2 && str[0] == '0' && (str[1] == 'o' || str[1] == 'O')) start = 2; if (start == len) return false;
mode_t mode = 0; for (size_t i = start; i < len; i++) { if (str[i] < '0' || str[i] > '7') return false; mode = (mode_t)((mode << 3) + (str[i] - '0')); }
*out = mode; return true;}
static ant_value_t fs_stream_error(ant_t *js, ant_value_t stream_obj, const char *op, int uv_code) { ant_value_t props = Ant_Object_CreateBare(js); ant_value_t path_val = js_get(js, stream_obj, "path"); const char *code = uv_err_name(uv_code);
if (code) js_set(js, props, "code", js_mkstr(js, code, strlen(code))); js_set(js, props, "errno", js_mknum((double)uv_code)); if (vtype(path_val) == kTypeString) js_set(js, props, "path", path_val); ant_value_t err = js_mkerr_props(js, JS_ERR_TYPE, props, "%s failed: %s", op, uv_strerror(uv_code)); return js_take_thrown(js, err);}
static ant_value_t fs_stream_push_chunk(ant_t *js, ant_value_t stream_obj, ant_value_t chunk) { return stream_readable_push(js, stream_obj, chunk, js_mkundef());}
static ant_value_t fs_stream_callback(ant_t *js, ant_value_t callback, ant_value_t value) { if (!is_callable(callback)) { Ant_Error_ConsumeMarker(js, value); return js_mkundef(); } return Ant_Error_CallCallback(js, callback, js_mkundef(), &value, 1);}
static int fs_stream_close_fd_sync(ant_t *js, ant_value_t stream_obj) { ant_value_t fd_val = js_get(js, stream_obj, "fd"); uv_fs_t req; int result = 0;
if (vtype(fd_val) != kTypeNumber) { js_set(js, stream_obj, "pending", js_false); js_set(js, stream_obj, "closed", js_true); return 0; }
result = uv_fs_close(js->loop, &req, (uv_file)js_getnum(fd_val), NULL); uv_fs_req_cleanup(&req);
js_set(js, stream_obj, "fd", js_mknull()); js_set(js, stream_obj, "pending", js_false); js_set(js, stream_obj, "closed", js_true); return result;}
static void free_fs_request(fs_request_t *req) { if (!req) return; Ant_List_Remove(req);
if (req->path) free(req->path); if (req->path2) free(req->path2); if (req->data) free(req->data); if (req->error_msg) free(req->error_msg); uv_fs_req_cleanup(&req->uv_req); free(req);}
static void fs_stream_on_open(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data; ant_t *js = fs_req_isolate(req); ant_value_t stream_obj = req->owner; ant_value_t callback = req->callback_fn; int result = (int)uv_req->result;
GC_ROOT_SAVE(mark, js); GC_ROOT_PIN(js, stream_obj); GC_ROOT_PIN(js, callback); free_fs_request(req);
if (result < 0) { fs_stream_callback(js, callback, fs_stream_error(js, stream_obj, "open", result)); } else { ant_value_t fd = js_mknum((double)result); js_set(js, stream_obj, "fd", fd); js_set(js, stream_obj, "pending", js_false); eventemitter_emit_args(js, stream_obj, "open", &fd, 1); eventemitter_emit_args(js, stream_obj, "ready", NULL, 0); fs_stream_callback(js, callback, js_mknull()); }
GC_ROOT_RESTORE(js, mark);}
static ant_value_t fs_stream_construct(ant_params_t) { ant_value_t stream_obj = js_getthis(js); ant_value_t callback = nargs > 0 ? args[0] : js_mkundef(); ant_value_t path_val = js_get(js, stream_obj, "path"); ant_value_t mode_val = js_get(js, stream_obj, "mode"); ant_value_t flags_val = js_get_slot(stream_obj, SLOT_FS_FLAGS);
if (vtype(js_get(js, stream_obj, "fd")) == kTypeNumber) return fs_stream_callback(js, callback, js_mknull()); if (vtype(path_val) != kTypeString) return fs_stream_callback(js, callback, fs_stream_error(js, stream_obj, "open", UV_EINVAL));
size_t path_len = 0; const char *path = js_getstr(js, path_val, &path_len); fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (req) req->path = strndup(path, path_len); if (!req || !req->path) { free(req); return fs_stream_callback(js, callback, fs_stream_error(js, stream_obj, "open", UV_ENOMEM)); }
req->uv_req.loop = js->loop; req->uv_req.data = req; req->op_type = FS_OP_OPEN; req->promise = js_mkundef(); req->owner = stream_obj; req->callback_fn = callback; Ant_List_Insert(&js->fs_requests, req);
int flags = vtype(flags_val) == kTypeNumber ? (int)js_getnum(flags_val) : O_RDONLY; int mode = vtype(mode_val) == kTypeNumber ? (int)js_getnum(mode_val) : 0666; int rc = uv_fs_open(js->loop, &req->uv_req, req->path, flags, mode, fs_stream_on_open); if (rc < 0) { free_fs_request(req); return fs_stream_callback(js, callback, fs_stream_error(js, stream_obj, "open", rc)); }
return js_mkundef();}
static int fs_stream_fd(ant_t *js, ant_value_t stream_obj) { ant_value_t fd_val = js_get(js, stream_obj, "fd"); return vtype(fd_val) == kTypeNumber ? (int)js_getnum(fd_val) : UV_EBADF;}
static ant_value_t fs_stream_destroy(ant_params_t) { ant_value_t stream_obj = js_getthis(js); ant_value_t err = nargs > 0 ? args[0] : js_mknull(); ant_value_t callback = nargs > 1 ? args[1] : js_mkundef(); int result = fs_stream_close_fd_sync(js, stream_obj);
if (result < 0 && (is_null(err) || is_undefined(err))) err = fs_stream_error(js, stream_obj, "close", result); if (is_undefined(err)) err = js_mknull();
return fs_stream_callback(js, callback, err);}
static ant_value_t fs_stream_close(ant_params_t) { ant_value_t stream_obj = js_getthis(js);
if (nargs > 0 && is_callable(args[0])) { eventemitter_add_listener(js, stream_obj, "close", args[0], true); if (js_truthy(js, js_get(js, stream_obj, "closed"))) sv_call_value(js, args[0], js_mkundef(), NULL, 0); }
if (!js_truthy(js, js_get(js, stream_obj, "destroyed"))) stream_destroy(js, stream_obj, js_mkundef());
return stream_obj;}
static ant_value_t fs_readstream__read(ant_params_t) { ant_value_t stream_obj = js_getthis(js); ant_value_t pos_val = js_get(js, stream_obj, "pos"); ant_value_t end_val = js_get(js, stream_obj, "end"); ant_value_t bytes_read_val = js_get(js, stream_obj, "bytesRead"); int fd = fs_stream_fd(js, stream_obj); int64_t pos = (vtype(pos_val) == kTypeNumber) ? (int64_t)js_getnum(pos_val) : 0; int64_t end = (vtype(end_val) == kTypeNumber) ? (int64_t)js_getnum(end_val) : -1; size_t want = 16384; bool reached_eof = false;
if (fd < 0) { stream_destroy(js, stream_obj, fs_stream_error(js, stream_obj, "read", fd)); return js_mkundef(); }
if (nargs > 0 && vtype(args[0]) == kTypeNumber && js_getnum(args[0]) > 0) want = (size_t)js_getnum(args[0]);
if (end >= 0) { if (pos > end) { if (js_truthy(js, js_get(js, stream_obj, "autoClose"))) fs_stream_close_fd_sync(js, stream_obj); return fs_stream_push_chunk(js, stream_obj, js_mknull()); } if ((int64_t)want > (end - pos + 1)) want = (size_t)(end - pos + 1); }
ArrayBufferData *ab = create_array_buffer_data(js, want); if (!ab) { stream_destroy(js, stream_obj, js_take_thrown(js, js_mkerr(js, "Failed to allocate ReadStream buffer"))); return js_mkundef(); }
uv_fs_t req; uv_buf_t buf = uv_buf_init((char *)ab->data, (unsigned int)want); int result = uv_fs_read(js->loop, &req, fd, &buf, 1, pos, NULL); uv_fs_req_cleanup(&req);
if (result < 0) { free_array_buffer_data(js, ab); stream_destroy(js, stream_obj, fs_stream_error(js, stream_obj, "read", result)); return js_mkundef(); }
if (result == 0) { free_array_buffer_data(js, ab); if (js_truthy(js, js_get(js, stream_obj, "autoClose"))) (void)fs_stream_close_fd_sync(js, stream_obj); return fs_stream_push_chunk(js, stream_obj, js_mknull()); }
ant_value_t chunk = create_typed_array(js, TYPED_ARRAY_UINT8, ab, 0, (size_t)result, js->builtins.buffer_proto); if (is_err(chunk)) return chunk;
if (result < (int)want) reached_eof = true; if (end >= 0 && (pos + result - 1) >= end) reached_eof = true;
js_set(js, stream_obj, "pos", js_mknum((double)(pos + result))); js_set(js, stream_obj, "bytesRead", js_mknum( (vtype(bytes_read_val) == kTypeNumber ? js_getnum(bytes_read_val) : 0.0) + (double)result )); fs_stream_push_chunk(js, stream_obj, chunk);
if (reached_eof) { if (js_truthy(js, js_get(js, stream_obj, "autoClose"))) fs_stream_close_fd_sync(js, stream_obj); return fs_stream_push_chunk(js, stream_obj, js_mknull()); }
return js_mkundef();}
static ant_value_t fs_writestream__write(ant_params_t) { ant_value_t stream_obj = js_getthis(js); ant_value_t callback = nargs > 2 ? args[2] : js_mkundef(); ant_value_t pos_val = js_get(js, stream_obj, "pos"); ant_value_t bytes_written_val = js_get(js, stream_obj, "bytesWritten"); const uint8_t *bytes = NULL; size_t len = 0; int fd = fs_stream_fd(js, stream_obj); int64_t pos = (vtype(pos_val) == kTypeNumber) ? (int64_t)js_getnum(pos_val) : -1; size_t offset = 0;
if (fd < 0) return fs_stream_callback(js, callback, fs_stream_error(js, stream_obj, "write", fd));
if (vtype(args[0]) == kTypeString) { bytes = (const uint8_t *)js_getstr(js, args[0], &len); } else if (!buffer_source_get_bytes(js, args[0], &bytes, &len)) { return fs_stream_callback(js, callback, js_mkerr(js, "WriteStream chunk must be a string or ArrayBufferView")); }
while (offset < len) { uv_fs_t req; uv_buf_t buf = uv_buf_init((char *)(bytes + offset), (unsigned int)(len - offset)); int result = uv_fs_write(js->loop, &req, fd, &buf, 1, pos, NULL); uv_fs_req_cleanup(&req);
if (result < 0) { if (js_truthy(js, js_get(js, stream_obj, "autoClose"))) fs_stream_close_fd_sync(js, stream_obj); return fs_stream_callback(js, callback, fs_stream_error(js, stream_obj, "write", result)); } if (result == 0) { if (js_truthy(js, js_get(js, stream_obj, "autoClose"))) fs_stream_close_fd_sync(js, stream_obj); return fs_stream_callback(js, callback, js_mkerr(js, "write failed: short write")); }
offset += (size_t)result; if (pos >= 0) pos += result; }
if (pos >= 0) js_set(js, stream_obj, "pos", js_mknum((double)pos)); js_set(js, stream_obj, "bytesWritten", js_mknum( (vtype(bytes_written_val) == kTypeNumber ? js_getnum(bytes_written_val) : 0.0) + (double)offset )); return fs_stream_callback(js, callback, js_mknull());}
static ant_value_t fs_writestream__final(ant_params_t) { ant_value_t stream_obj = js_getthis(js); ant_value_t callback = nargs > 0 ? args[0] : js_mkundef(); ant_value_t value = js_mknull();
if (js_truthy(js, js_get(js, stream_obj, "autoClose"))) { int result = fs_stream_close_fd_sync(js, stream_obj); if (result < 0) value = fs_stream_error(js, stream_obj, "close", result); }
return fs_stream_callback(js, callback, value);}
static ant_value_t fs_create_readstream_impl(ant_t *js, ant_value_t path_arg, ant_value_t options_arg, ant_value_t proto, ant_value_t new_target) { ant_value_t path_val = fs_coerce_path(js, path_arg); if (is_err(path_val)) return path_val; ant_value_t options = is_object_type(options_arg) ? options_arg : Ant_Object_CreateBare(js); ant_value_t stream_options = Ant_Object_CreateBare(js); ant_value_t hwm = js_get(js, options, "highWaterMark"); ant_value_t flags_raw = js_get(js, options, "flags"); ant_value_t fd_val = js_get(js, options, "fd"); ant_value_t start_val = js_get(js, options, "start"); ant_value_t end_val = js_get(js, options, "end"); ant_value_t mode_val = js_get(js, options, "mode"); ant_value_t auto_close_val = js_get(js, options, "autoClose"); ant_value_t emit_close_val = js_get(js, options, "emitClose"); ant_value_t stream_obj = 0; int flags = parse_open_flags(js, is_undefined(flags_raw) ? js_mkstr(js, "r", 1) : flags_raw); if (vtype(path_val) != kTypeString) return js_mkerr(js, "ReadStream path must be a string"); if (vtype(hwm) == kTypeNumber && js_getnum(hwm) > 0) js_set(js, stream_options, "highWaterMark", hwm);
stream_obj = stream_construct_readable(js, proto, stream_options, new_target); if (is_err(stream_obj)) return stream_obj;
js_set(js, stream_obj, "path", path_val); js_set(js, stream_obj, "flags", is_undefined(flags_raw) ? js_mkstr(js, "r", 1) : flags_raw); js_set(js, stream_obj, "mode", vtype(mode_val) == kTypeNumber ? mode_val : js_mknum(0666)); js_set(js, stream_obj, "fd", vtype(fd_val) == kTypeNumber ? fd_val : js_mkundef()); js_set(js, stream_obj, "pending", js_bool(vtype(fd_val) != kTypeNumber)); js_set(js, stream_obj, "closed", js_false); js_set(js, stream_obj, "autoClose", is_undefined(auto_close_val) ? js_true : js_bool(js_truthy(js, auto_close_val))); js_set(js, stream_obj, "emitClose", is_undefined(emit_close_val) ? js_true : js_bool(js_truthy(js, emit_close_val))); js_set(js, stream_obj, "bytesRead", js_mknum(0)); js_set(js, stream_obj, "start", vtype(start_val) == kTypeNumber ? start_val : js_mkundef()); js_set(js, stream_obj, "end", vtype(end_val) == kTypeNumber ? end_val : js_mkundef()); js_set(js, stream_obj, "pos", js_mknum(vtype(start_val) == kTypeNumber ? js_getnum(start_val) : 0.0)); js_set_slot(stream_obj, SLOT_FS_FLAGS, js_mknum((double)flags)); if (vtype(fd_val) != kTypeNumber) stream_begin_construct(js, stream_obj); return stream_obj;}
static ant_value_t fs_create_writestream_impl(ant_t *js, ant_value_t path_arg, ant_value_t options_arg, ant_value_t proto, ant_value_t new_target) { ant_value_t path_val = fs_coerce_path(js, path_arg); if (is_err(path_val)) return path_val; ant_value_t options = is_object_type(options_arg) ? options_arg : Ant_Object_CreateBare(js); ant_value_t stream_options = Ant_Object_CreateBare(js); ant_value_t flags_raw = js_get(js, options, "flags"); ant_value_t fd_val = js_get(js, options, "fd"); ant_value_t start_val = js_get(js, options, "start"); ant_value_t mode_val = js_get(js, options, "mode"); ant_value_t auto_close_val = js_get(js, options, "autoClose"); ant_value_t emit_close_val = js_get(js, options, "emitClose"); ant_value_t hwm = js_get(js, options, "highWaterMark"); ant_value_t stream_obj = 0; int flags = parse_open_flags(js, is_undefined(flags_raw) ? js_mkstr(js, "w", 1) : flags_raw); double start_pos = (vtype(start_val) == kTypeNumber) ? js_getnum(start_val) : ((flags & O_APPEND) ? -1.0 : 0.0);
if (vtype(path_val) != kTypeString) return js_mkerr(js, "WriteStream path must be a string"); if (vtype(hwm) == kTypeNumber && js_getnum(hwm) > 0) js_set(js, stream_options, "highWaterMark", hwm);
stream_obj = stream_construct_writable(js, proto, stream_options, new_target); if (is_err(stream_obj)) return stream_obj;
js_set(js, stream_obj, "path", path_val); js_set(js, stream_obj, "flags", is_undefined(flags_raw) ? js_mkstr(js, "w", 1) : flags_raw); js_set(js, stream_obj, "mode", vtype(mode_val) == kTypeNumber ? mode_val : js_mknum(0666)); js_set(js, stream_obj, "fd", vtype(fd_val) == kTypeNumber ? fd_val : js_mkundef()); js_set(js, stream_obj, "pending", js_bool(vtype(fd_val) != kTypeNumber)); js_set(js, stream_obj, "closed", js_false); js_set(js, stream_obj, "autoClose", is_undefined(auto_close_val) ? js_true : js_bool(js_truthy(js, auto_close_val))); js_set(js, stream_obj, "emitClose", is_undefined(emit_close_val) ? js_true : js_bool(js_truthy(js, emit_close_val))); js_set(js, stream_obj, "bytesWritten", js_mknum(0)); js_set(js, stream_obj, "start", vtype(start_val) == kTypeNumber ? start_val : js_mkundef()); js_set(js, stream_obj, "pos", js_mknum(start_pos)); js_set_slot(stream_obj, SLOT_FS_FLAGS, js_mknum((double)flags)); if (vtype(fd_val) != kTypeNumber) stream_begin_construct(js, stream_obj); return stream_obj;}
static ant_value_t js_readstream_ctor(ant_params_t) { if (nargs < 1) return js_mkerr(js, "ReadStream() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; return fs_create_readstream_impl(js, args[0], nargs > 1 ? args[1] : js_mkundef(), js->builtins.readstream_proto, call_new_target);}
static ant_value_t js_writestream_ctor(ant_params_t) { if (nargs < 1) return js_mkerr(js, "WriteStream() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; return fs_create_writestream_impl(js, args[0], nargs > 1 ? args[1] : js_mkundef(), js->builtins.writestream_proto, call_new_target);}
static ant_value_t builtin_fs_createReadStream(ant_params_t) { if (nargs < 1) return js_mkerr(js, "createReadStream() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; return fs_create_readstream_impl(js, args[0], nargs > 1 ? args[1] : js_mkundef(), js->builtins.readstream_proto, js_mkundef());}
static ant_value_t builtin_fs_createWriteStream(ant_params_t) { if (nargs < 1) return js_mkerr(js, "createWriteStream() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; return fs_create_writestream_impl(js, args[0], nargs > 1 ? args[1] : js_mkundef(), js->builtins.writestream_proto, js_mkundef());}
static void fs_init_stream_constructors(ant_t *js) { if (js->builtins.readstream_ctor && js->builtins.writestream_ctor) return;
stream_init_constructors(js);
js->builtins.readstream_proto = Ant_Object_CreateBare(js); js_set_proto_init(js->builtins.readstream_proto, stream_readable_prototype(js)); js_set(js, js->builtins.readstream_proto, "close", Ant_Function_Create(fs_stream_close)); js_set(js, js->builtins.readstream_proto, "_construct", Ant_Function_CreateWithArity(fs_stream_construct, 1)); js_set(js, js->builtins.readstream_proto, "_read", Ant_Function_CreateWithArity(fs_readstream__read, 1)); js_set(js, js->builtins.readstream_proto, "_destroy", Ant_Function_CreateWithArity(fs_stream_destroy, 2)); js_set_tostringtag(js, js->builtins.readstream_proto, js_mkstr(js, "ReadStream", 10)); js->builtins.readstream_ctor = Ant_Function_CreateConstructor(js, js_readstream_ctor, js->builtins.readstream_proto, "ReadStream", 2); js_set_proto_init(js->builtins.readstream_ctor, stream_readable_constructor(js));
js->builtins.writestream_proto = Ant_Object_CreateBare(js); js_set_proto_init(js->builtins.writestream_proto, stream_writable_prototype(js)); js_set(js, js->builtins.writestream_proto, "close", Ant_Function_Create(fs_stream_close)); js_set(js, js->builtins.writestream_proto, "_construct", Ant_Function_CreateWithArity(fs_stream_construct, 1)); js_set(js, js->builtins.writestream_proto, "_write", Ant_Function_CreateWithArity(fs_writestream__write, 3)); js_set(js, js->builtins.writestream_proto, "_final", Ant_Function_CreateWithArity(fs_writestream__final, 1)); js_set(js, js->builtins.writestream_proto, "_destroy", Ant_Function_CreateWithArity(fs_stream_destroy, 2)); js_set_tostringtag(js, js->builtins.writestream_proto, js_mkstr(js, "WriteStream", 11)); js->builtins.writestream_ctor = Ant_Function_CreateConstructor(js, js_writestream_ctor, js->builtins.writestream_proto, "WriteStream", 2); js_set_proto_init(js->builtins.writestream_ctor, stream_writable_constructor(js));}
typedef enum { FS_STATS_DEV, FS_STATS_INO, FS_STATS_SIZE, FS_STATS_MODE, FS_STATS_NLINK, FS_STATS_UID, FS_STATS_GID, FS_STATS_RDEV, FS_STATS_BLKSIZE, FS_STATS_BLOCKS, FS_STATS_ATIME_MS, FS_STATS_MTIME_MS, FS_STATS_CTIME_MS, FS_STATS_BIRTHTIME_MS, FS_STATS_ATIME, FS_STATS_MTIME, FS_STATS_CTIME, FS_STATS_BIRTHTIME,} fs_stats_slot_t;
enum { FS_IO_BYTES, FS_IO_BUFFER };
static ant_value_t fs_new_stats_record(ant_t *js) { ant_value_t seed = js->mutable_roots.fs_stats_template; if (vtype(seed) != kTypeObject) { seed = Ant_Object_CreateBare(js); if (is_err(seed)) return seed; GC_ROOT_SAVE(mark, js); GC_ROOT_PIN(js, seed); js_mkprop_fast(js, seed, "dev", 3, js_mkundef()); js_mkprop_fast(js, seed, "ino", 3, js_mkundef()); js_mkprop_fast(js, seed, "size", 4, js_mkundef()); js_mkprop_fast(js, seed, "mode", 4, js_mkundef()); js_mkprop_fast(js, seed, "nlink", 5, js_mkundef()); js_mkprop_fast(js, seed, "uid", 3, js_mkundef()); js_mkprop_fast(js, seed, "gid", 3, js_mkundef()); js_mkprop_fast(js, seed, "rdev", 4, js_mkundef()); js_mkprop_fast(js, seed, "blksize", 7, js_mkundef()); js_mkprop_fast(js, seed, "blocks", 6, js_mkundef()); js_mkprop_fast(js, seed, "atimeMs", 7, js_mkundef()); js_mkprop_fast(js, seed, "mtimeMs", 7, js_mkundef()); js_mkprop_fast(js, seed, "ctimeMs", 7, js_mkundef()); js_mkprop_fast(js, seed, "birthtimeMs", 11, js_mkundef()); js_mkprop_fast(js, seed, "atime", 5, js_mkundef()); js_mkprop_fast(js, seed, "mtime", 5, js_mkundef()); js_mkprop_fast(js, seed, "ctime", 5, js_mkundef()); js_mkprop_fast(js, seed, "birthtime", 9, js_mkundef()); GC_ROOT_RESTORE(js, mark); if (Ant_Exception_Pending(js)) return Ant_Exception_Current(js); js->mutable_roots.fs_stats_template = seed; } return js_mkobj_from_template(js, seed);}
static ant_value_t fs_new_io_result(ant_t *js, bool written, double bytes, ant_value_t buffer) { GC_ROOT_SAVE(mark, js); GC_ROOT_PIN(js, buffer); ant_value_t *cache = written ? &js->mutable_roots.fs_write_result_template : &js->mutable_roots.fs_read_result_template; ant_value_t seed = *cache; if (vtype(seed) != kTypeObject) { seed = Ant_Object_CreateBare(js); if (is_err(seed)) { GC_ROOT_RESTORE(js, mark); return seed; } GC_ROOT_PIN(js, seed); if (written) js_mkprop_fast(js, seed, "bytesWritten", 12, js_mknum(0)); else js_mkprop_fast(js, seed, "bytesRead", 9, js_mknum(0)); js_mkprop_fast(js, seed, "buffer", 6, js_mkundef()); if (Ant_Exception_Pending(js)) { GC_ROOT_RESTORE(js, mark); return Ant_Exception_Current(js); } *cache = seed; } ant_value_t result = js_mkobj_from_template(js, seed); if (!is_err(result)) { ant_object_t *obj = js_obj_ptr(result); ant_object_prop_set_unchecked(obj, FS_IO_BYTES, js_mknum(bytes)); ant_object_prop_set_unchecked(obj, FS_IO_BUFFER, buffer); gc_write_barrier(js, obj, buffer); } GC_ROOT_RESTORE(js, mark); return result;}
static bool fs_stats_set_date(ant_t *js, ant_value_t record, fs_stats_slot_t slot, double ms) { ant_value_t date = js_mkdate(js, ms); if (is_err(date)) return false; ant_object_t *obj = js_obj_ptr(record); ant_object_prop_set_unchecked(obj, slot, date); gc_write_barrier(js, obj, date); return true;}
static ant_value_t fs_stats_object_new(ant_t *js, const fs_stat_fields_t *f) { ant_value_t stat_obj = fs_new_stats_record(js); if (is_err(stat_obj)) return stat_obj; GC_ROOT_SAVE(mark, js); GC_ROOT_PIN(js, stat_obj); js_set_proto_init(stat_obj, js->builtins.stats_proto);
js_set_slot(stat_obj, SLOT_DATA, js_mknum((double)f->mode)); ant_object_t *obj = js_obj_ptr(stat_obj); ant_object_prop_set_unchecked(obj, FS_STATS_DEV, js_mknum(f->dev)); ant_object_prop_set_unchecked(obj, FS_STATS_INO, js_mknum(f->ino)); ant_object_prop_set_unchecked(obj, FS_STATS_SIZE, js_mknum(f->size)); ant_object_prop_set_unchecked(obj, FS_STATS_MODE, js_mknum((double)f->mode)); ant_object_prop_set_unchecked(obj, FS_STATS_NLINK, js_mknum(f->nlink)); ant_object_prop_set_unchecked(obj, FS_STATS_UID, js_mknum(f->uid)); ant_object_prop_set_unchecked(obj, FS_STATS_GID, js_mknum(f->gid)); ant_object_prop_set_unchecked(obj, FS_STATS_RDEV, js_mknum(f->rdev)); ant_object_prop_set_unchecked(obj, FS_STATS_BLKSIZE, js_mknum(f->blksize)); ant_object_prop_set_unchecked(obj, FS_STATS_BLOCKS, js_mknum(f->blocks)); ant_object_prop_set_unchecked(obj, FS_STATS_ATIME_MS, js_mknum(f->atime_ms)); ant_object_prop_set_unchecked(obj, FS_STATS_MTIME_MS, js_mknum(f->mtime_ms)); ant_object_prop_set_unchecked(obj, FS_STATS_CTIME_MS, js_mknum(f->ctime_ms)); ant_object_prop_set_unchecked(obj, FS_STATS_BIRTHTIME_MS, js_mknum(f->birthtime_ms));
if ( !fs_stats_set_date(js, stat_obj, FS_STATS_ATIME, f->atime_ms) || !fs_stats_set_date(js, stat_obj, FS_STATS_MTIME, f->mtime_ms) || !fs_stats_set_date(js, stat_obj, FS_STATS_CTIME, f->ctime_ms) || !fs_stats_set_date(js, stat_obj, FS_STATS_BIRTHTIME, f->birthtime_ms) ) { GC_ROOT_RESTORE(js, mark); return Ant_Exception_Current(js); } GC_ROOT_RESTORE(js, mark); return stat_obj;}
static double uv_ts_to_ms(uv_timespec_t ts) { return (double)ts.tv_sec * 1000.0 + (double)ts.tv_nsec / 1e6;}
static double posix_ts_to_ms(struct timespec ts) { return (double)ts.tv_sec * 1000.0 + (double)ts.tv_nsec / 1e6;}
#ifdef _WIN32 #define POSIX_ATIME_MS(st) ((double)(st)->st_atime * 1000.0) #define POSIX_MTIME_MS(st) ((double)(st)->st_mtime * 1000.0) #define POSIX_CTIME_MS(st) ((double)(st)->st_ctime * 1000.0) #define POSIX_BIRTH_MS(st) 0.0#elif defined(__APPLE__) #define POSIX_ATIME_MS(st) posix_ts_to_ms((st)->st_atimespec) #define POSIX_MTIME_MS(st) posix_ts_to_ms((st)->st_mtimespec) #define POSIX_CTIME_MS(st) posix_ts_to_ms((st)->st_ctimespec) #define POSIX_BIRTH_MS(st) posix_ts_to_ms((st)->st_birthtimespec)#elif defined(__linux__) #define POSIX_ATIME_MS(st) posix_ts_to_ms((st)->st_atim) #define POSIX_MTIME_MS(st) posix_ts_to_ms((st)->st_mtim) #define POSIX_CTIME_MS(st) posix_ts_to_ms((st)->st_ctim) #define POSIX_BIRTH_MS(st) 0.0#else #define POSIX_ATIME_MS(st) posix_ts_to_ms((st)->st_atim) #define POSIX_MTIME_MS(st) posix_ts_to_ms((st)->st_mtim) #define POSIX_CTIME_MS(st) posix_ts_to_ms((st)->st_ctim) #define POSIX_BIRTH_MS(st) 0.0#endif
static const fs_stat_fields_t fs_stat_fields_zero = {0};
static ant_value_t fs_stats_object_from_uv(ant_t *js, const uv_stat_t *st) { if (!st) return fs_stats_object_new(js, &fs_stat_fields_zero); return fs_stats_object_new(js, &(fs_stat_fields_t){ .dev = (double)st->st_dev, .ino = (double)st->st_ino, .mode = (mode_t)st->st_mode, .nlink = (double)st->st_nlink, .size = (double)st->st_size, .uid = (double)st->st_uid, .gid = (double)st->st_gid, .rdev = (double)st->st_rdev, .blksize = (double)st->st_blksize, .blocks = (double)st->st_blocks, .atime_ms = uv_ts_to_ms(st->st_atim), .mtime_ms = uv_ts_to_ms(st->st_mtim), .ctime_ms = uv_ts_to_ms(st->st_ctim), .birthtime_ms = uv_ts_to_ms(st->st_birthtim), });}
static ant_value_t fs_stats_object_from_posix(ant_t *js, const struct stat *st) { if (!st) return fs_stats_object_new(js, &fs_stat_fields_zero); return fs_stats_object_new(js, &(fs_stat_fields_t){ .dev = (double)st->st_dev, .ino = (double)st->st_ino, .mode = st->st_mode, .nlink = (double)st->st_nlink, .size = (double)st->st_size, .uid = (double)st->st_uid, .gid = (double)st->st_gid, .rdev = (double)st->st_rdev,#if defined(_WIN32) .blksize = 0.0, .blocks = 0.0,#else .blksize = (double)st->st_blksize, .blocks = (double)st->st_blocks,#endif .atime_ms = POSIX_ATIME_MS(st), .mtime_ms = POSIX_MTIME_MS(st), .ctime_ms = POSIX_CTIME_MS(st), .birthtime_ms = POSIX_BIRTH_MS(st), });}
static bool fs_stat_path_sync(const char *path, uv_stat_t *out) { uv_fs_t req; int rc = 0;
if (!path || !out) return false; memset(out, 0, sizeof(*out));
rc = uv_fs_stat(NULL, &req, path, NULL); if (rc < 0) { uv_fs_req_cleanup(&req); return false; }
*out = req.statbuf; uv_fs_req_cleanup(&req); return true;}
static const char *fs_watch_basename(const char *path) { const char *name = NULL;
if (!path || !*path) return NULL; name = strrchr(path, '/');#ifdef _WIN32 { const char *alt = strrchr(path, '\\'); if (!name || (alt && alt > name)) name = alt; }#endif return name ? name + 1 : path;}
static ant_value_t fs_watch_error(ant_t *js, int status, const char *path) { ant_value_t props = Ant_Object_CreateBare(js); const char *code = uv_err_name(status); js_set(js, props, "code", js_mkstr(js, code, strlen(code))); return js_mkerr_props( js, JS_ERR_TYPE, props, "%s: %s", path ? path : "watch", uv_strerror(status) );}
static void fs_watcher_free(fs_watcher_t *watcher) { if (!watcher) return; Ant_List_Remove(watcher); free(watcher->path); free(watcher);}
static uv_handle_t *fs_watcher_uv_handle(fs_watcher_t *watcher) { if (!watcher) return NULL; if (watcher->mode == FS_WATCH_MODE_STAT) return (uv_handle_t *)&watcher->handle.poll; return (uv_handle_t *)&watcher->handle.event;}
static void fs_watcher_on_handle_closed(uv_handle_t *handle) { fs_watcher_t *watcher = (fs_watcher_t *)handle->data;
if (!watcher) return; watcher->handle_closed = true; watcher->closing = false; if (watcher->finalized || !is_object_type(watcher->obj)) fs_watcher_free(watcher);}
static void fs_watcher_close_native(fs_watcher_t *watcher) { uv_handle_t *handle = NULL;
if (!watcher) return; if (watcher->closing || watcher->handle_closed) return;
handle = fs_watcher_uv_handle(watcher); if (!handle) return;
Ant_List_Remove(watcher); if (watcher->mode == FS_WATCH_MODE_STAT) uv_fs_poll_stop(&watcher->handle.poll); else ant_watch_stop(&watcher->handle.event); watcher->closing = true; uv_close(handle, fs_watcher_on_handle_closed);}
static void fs_watcher_emit_error(fs_watcher_t *watcher, int status) { ant_value_t args[1];
if (!watcher || vtype(watcher->obj) != kTypeObject) return; args[0] = fs_watch_error(fs_watcher_isolate(watcher), status, watcher->path); args[0] = js_take_thrown(fs_watcher_isolate(watcher), args[0]); eventemitter_emit_args(fs_watcher_isolate(watcher), watcher->obj, "error", args, 1);}
static void fs_watcher_emit_change(fs_watcher_t *watcher, const char *filename, int events) { ant_value_t args[2]; const char *event_name = "change"; const char *name = filename;
if (!watcher || vtype(watcher->obj) != kTypeObject) return; if ((events & UV_RENAME) != 0) event_name = "rename"; if (!name || !*name) name = fs_watch_basename(watcher->path);
args[0] = js_mkstr(fs_watcher_isolate(watcher), event_name, strlen(event_name)); args[1] = name ? fs_path_result(fs_watcher_isolate(watcher), name, strlen(name), watcher->buffer_encoding) : js_mkundef(); if (is_err(args[1])) { ant_value_t error = js_take_thrown(fs_watcher_isolate(watcher), args[1]); eventemitter_emit_args(fs_watcher_isolate(watcher), watcher->obj, "error", &error, 1); return; } eventemitter_emit_args(fs_watcher_isolate(watcher), watcher->obj, "change", args, 2);}
static void fs_watcher_invoke_watchfile_stats( fs_watcher_t *watcher, const uv_stat_t *curr, const uv_stat_t *prev) { uv_stat_t curr_stat; uv_stat_t prev_stat; ant_value_t args[2];
if (!watcher || !is_callable(watcher->callback)) return;
memset(&curr_stat, 0, sizeof(curr_stat)); memset(&prev_stat, 0, sizeof(prev_stat)); if (curr) curr_stat = *curr; if (prev) prev_stat = *prev;
watcher->last_stat = curr_stat; watcher->last_stat_valid = curr != NULL;
args[0] = fs_stats_object_from_uv(fs_watcher_isolate(watcher), &curr_stat); args[1] = fs_stats_object_from_uv(fs_watcher_isolate(watcher), &prev_stat); fs_call_callback(fs_watcher_isolate(watcher), watcher->callback, args, 2);}
static void fs_watcher_on_event( uv_fs_event_t *handle, const char *filename, int events, int status) { fs_watcher_t *watcher = (fs_watcher_t *)handle->data;
if (!watcher) return; if (status < 0) { fs_watcher_emit_error(watcher, status); return; }
if ((events & (UV_CHANGE | UV_RENAME)) == 0) return; fs_watcher_emit_change(watcher, filename, events);}
static void fs_watcher_on_poll( uv_fs_poll_t *handle, int status, const uv_stat_t *prev, const uv_stat_t *curr) { fs_watcher_t *watcher = (fs_watcher_t *)handle->data; uv_stat_t missing = {0};
if (!watcher) return; if (status < 0 && status != UV_ENOENT) return; if (status == UV_ENOENT) { if (watcher->last_stat_valid) fs_watcher_invoke_watchfile_stats(watcher, &missing, &watcher->last_stat); else fs_watcher_invoke_watchfile_stats(watcher, &missing, &missing); return; }
fs_watcher_invoke_watchfile_stats(watcher, curr, prev);}
static ant_value_t js_fswatcher_close(ant_params_t) { fs_watcher_t *watcher = fs_watcher_data(js->this_val);
if (!watcher) return js->this_val; fs_watcher_close_native(watcher); return js->this_val;}
static ant_value_t js_fswatcher_ref(ant_params_t) { fs_watcher_t *watcher = fs_watcher_data(js->this_val); uv_handle_t *handle = NULL;
if (!watcher || watcher->handle_closed) return js->this_val; handle = fs_watcher_uv_handle(watcher); if (handle) uv_ref(handle); watcher->persistent = true; return js->this_val;}
static ant_value_t js_fswatcher_unref(ant_params_t) { fs_watcher_t *watcher = fs_watcher_data(js->this_val); uv_handle_t *handle = NULL;
if (!watcher || watcher->handle_closed) return js->this_val; handle = fs_watcher_uv_handle(watcher); if (handle) uv_unref(handle); watcher->persistent = false; return js->this_val;}
static ant_value_t js_fswatcher_ctor(ant_params_t) { return js_mkerr_typed(js, JS_ERR_TYPE, "FSWatcher cannot be constructed directly");}
static void fs_watcher_finalize(ant_t *js, ant_object_t *obj) { fs_watcher_t *watcher = NULL; ant_value_t value = js_obj_from_ptr(obj);
watcher = (fs_watcher_t *)js_get_native(value, FS_WATCHER_NATIVE_TAG); js_clear_native(value, FS_WATCHER_NATIVE_TAG); if (!watcher) return;
watcher->finalized = true; fs_watcher_close_native(watcher); if (watcher->handle_closed) fs_watcher_free(watcher);}
static void fs_init_watch_constructors(ant_t *js) { ant_value_t events = 0; ant_value_t ee_ctor = 0; ant_value_t ee_proto = 0;
if (js->builtins.fswatcher_proto && js->builtins.fswatcher_ctor) return;
events = events_library(js); ee_ctor = js_get(js, events, "EventEmitter"); ee_proto = js_get(js, ee_ctor, "prototype");
js->builtins.fswatcher_proto = Ant_Object_CreateBare(js); js_set_proto_init(js->builtins.fswatcher_proto, ee_proto); js_set(js, js->builtins.fswatcher_proto, "close", Ant_Function_Create(js_fswatcher_close)); js_set(js, js->builtins.fswatcher_proto, "ref", Ant_Function_Create(js_fswatcher_ref)); js_set(js, js->builtins.fswatcher_proto, "unref", Ant_Function_Create(js_fswatcher_unref)); js_set_tostringtag(js, js->builtins.fswatcher_proto, js_mkstr(js, "FSWatcher", 9)); js->builtins.fswatcher_ctor = Ant_Function_CreateConstructor(js, js_fswatcher_ctor, js->builtins.fswatcher_proto, "FSWatcher", 0);}
static bool fs_parse_watch_options(ant_native_params_t, fs_watch_options_t *out) { ant_value_t options = js_mkundef(); ant_value_t persistent_val = js_mkundef();
if (!out) return false;
memset(out, 0, sizeof(*out)); out->persistent = true; out->listener = js_mkundef();
if (nargs > 1) { if (is_callable(args[1])) out->listener = args[1]; else options = args[1]; }
if (nargs > 2 && is_callable(args[2])) out->listener = args[2]; out->buffer_encoding = fs_buffer_encoding(js, options); if (vtype(options) == kTypeUndefined || vtype(options) == kTypeNull || vtype(options) == kTypeString) return true; if (vtype(options) != kTypeObject) return false;
persistent_val = js_get(js, options, "persistent"); if (vtype(persistent_val) != kTypeUndefined) out->persistent = js_truthy(js, persistent_val); out->recursive = js_truthy(js, js_get(js, options, "recursive")); return true;}
static bool fs_parse_watchfile_options( ant_native_params_t, fs_watchfile_options_t *out) { ant_value_t options = js_mkundef(); ant_value_t persistent_val = js_mkundef();
if (!out) return false;
memset(out, 0, sizeof(*out)); out->persistent = true; out->interval_ms = 5007; out->listener = js_mkundef();
if (nargs > 1) { if (is_callable(args[1])) { out->listener = args[1]; return true; } options = args[1]; }
if (nargs > 2 && is_callable(args[2])) out->listener = args[2]; if (!is_callable(out->listener)) return false; if (vtype(options) == kTypeUndefined || vtype(options) == kTypeNull) return true; if (vtype(options) != kTypeObject) return false;
persistent_val = js_get(js, options, "persistent"); if (vtype(persistent_val) != kTypeUndefined) out->persistent = js_truthy(js, persistent_val); { ant_value_t interval_val = js_get(js, options, "interval"); if (vtype(interval_val) == kTypeNumber && js_getnum(interval_val) > 0) out->interval_ms = (unsigned int)js_getnum(interval_val); } return true;}
static fs_watcher_t *fs_watcher_new(ant_t *js, fs_watch_mode_t mode) { fs_watcher_t *watcher = calloc(1, sizeof(*watcher));
if (!watcher) return NULL; watcher->obj = js_mkundef(); watcher->callback = js_mkundef(); watcher->persistent = true; watcher->mode = mode; return watcher;}
static int fs_watcher_start_event(ant_t *js, fs_watcher_t *watcher, const char *path, bool persistent, bool recursive) { unsigned int flags = 0;
if (!watcher || !path) return UV_EINVAL;#ifdef UV_FS_EVENT_RECURSIVE if (recursive) flags |= UV_FS_EVENT_RECURSIVE;#else (void)recursive;#endif
watcher->persistent = persistent; return ant_watch_start( js->loop, &watcher->handle.event, path, fs_watcher_on_event, watcher, flags, &watcher->path );}
static int fs_watcher_start_poll(ant_t *js, fs_watcher_t *watcher, const char *path, bool persistent, unsigned int interval_ms) { int rc = 0;
if (!watcher || !path) return UV_EINVAL;
watcher->path = ant_watch_resolve_path(path); if (!watcher->path) return UV_ENOMEM;
rc = uv_fs_poll_init(js->loop, &watcher->handle.poll); if (rc != 0) goto fail;
watcher->handle.poll.data = watcher; rc = uv_fs_poll_start(&watcher->handle.poll, fs_watcher_on_poll, watcher->path, interval_ms); if (rc != 0) goto fail;
watcher->persistent = persistent; return 0;
fail: free(watcher->path); watcher->path = NULL; return rc;}
static ant_value_t fs_watcher_make_object(ant_t *js, fs_watcher_t *watcher) { ant_value_t obj = 0;
if (!watcher) return js_mkerr(js, "Out of memory"); fs_init_watch_constructors(js);
obj = Ant_Object_CreateBare(js); js_set_proto_init(obj, js->builtins.fswatcher_proto); js_set_native(obj, watcher, FS_WATCHER_NATIVE_TAG); js_set_finalizer(obj, fs_watcher_finalize); watcher->obj = obj; return obj;}
static const char *fs_uv_syscall_name(uv_fs_type type) { switch (type) { case UV_FS_OPEN: return "open"; case UV_FS_CLOSE: return "close"; case UV_FS_READ: return "read"; case UV_FS_WRITE: return "write"; case UV_FS_STAT: return "stat"; case UV_FS_LSTAT: return "lstat"; case UV_FS_FSTAT: return "fstat"; case UV_FS_FTRUNCATE: return "ftruncate"; case UV_FS_UTIME: return "utime"; case UV_FS_FUTIME: return "futime"; case UV_FS_ACCESS: return "access"; case UV_FS_CHMOD: return "chmod"; case UV_FS_FSYNC: return "fsync"; case UV_FS_UNLINK: return "unlink"; case UV_FS_RMDIR: return "rmdir"; case UV_FS_MKDIR: return "mkdir"; case UV_FS_MKDTEMP: return "mkdtemp"; case UV_FS_RENAME: return "rename"; case UV_FS_SCANDIR: return "scandir"; case UV_FS_LINK: return "link"; case UV_FS_SYMLINK: return "symlink"; case UV_FS_READLINK: return "readlink"; case UV_FS_REALPATH: return "realpath"; case UV_FS_COPYFILE: return "copyfile"; case UV_FS_OPENDIR: return "opendir"; case UV_FS_READDIR: return "readdir"; case UV_FS_CLOSEDIR: return "closedir"; default: return NULL; }}
static void fs_request_fail(fs_request_t *req, int uv_code) { req->failed = 1; req->error_code = uv_code; req->syscall = fs_uv_syscall_name(req->uv_req.fs_type); if (req->error_msg) free(req->error_msg); req->error_msg = strdup(uv_strerror(uv_code));}
static ant_value_t fs_coerce_file_url_path(ant_t *js, ant_value_t arg) { ant_value_t href = js_getprop_fallback(js, arg, "href"); if (vtype(href) != kTypeString) return js_mkundef();
const char *href_str = js_getstr(js, href, NULL); if (!href_str) return js_mkundef();
url_state_t parsed = {0}; if (parse_url_to_state(href_str, NULL, &parsed) != 0) return js_mkundef();
ant_value_t path = js_mkundef(); if (parsed.protocol && strcmp(parsed.protocol, "file:") == 0) { char *decoded = url_decode_component(parsed.pathname); if (decoded) { path = js_mkstr(js, decoded, strlen(decoded)); free(decoded); }}
url_state_clear(&parsed); return path;}
static ant_value_t fs_coerce_path(ant_t *js, ant_value_t arg) { if (vtype(arg) != kTypeString) { TypedArrayData *ta = buffer_get_typedarray_data(arg); if (ta && ta->type == TYPED_ARRAY_UINT8) { uint8_t *bytes; size_t len; if (!Ant_Buffer_GetViewBytes(ta, &bytes, &len)) return js_mkerr_typed(js, JS_ERR_TYPE, "path must not be detached"); arg = js_mkstr(js, len ? (const char *)bytes : "", len); } else { if (!is_object_type(arg)) return js_mkundef(); ant_value_t path = fs_coerce_file_url_path(js, arg); if (is_undefined(path)) path = js_get(js, arg, "pathname"); arg = path; } } if (is_err(arg)) return arg; if (vtype(arg) != kTypeString) return js_mkundef(); size_t len; const char *bytes = js_getstr(js, arg, &len); if (bytes && memchr(bytes, '\0', len)) return js_mkerr_typed(js, JS_ERR_TYPE, "path must not contain null bytes"); return arg;}
static int fs_remove_path_recursive(const char *path, bool recursive, bool force) { uv_fs_t req; int result = uv_fs_lstat(NULL, &req, path, NULL); if (result < 0) { uv_fs_req_cleanup(&req); return (force && result == UV_ENOENT) ? 0 : result; }
uv_stat_t statbuf = req.statbuf; uv_fs_req_cleanup(&req);
if ((statbuf.st_mode & S_IFMT) != S_IFDIR) { result = uv_fs_unlink(NULL, &req, path, NULL); uv_fs_req_cleanup(&req); return (force && result == UV_ENOENT) ? 0 : result; }
if (!recursive) return UV_EISDIR; result = uv_fs_scandir(NULL, &req, path, 0, NULL); if (result < 0) { uv_fs_req_cleanup(&req); return (force && result == UV_ENOENT) ? 0 : result; }
for (;;) { uv_dirent_t entry; result = uv_fs_scandir_next(&req, &entry); if (result == UV_EOF) break; if (result < 0) { uv_fs_req_cleanup(&req); return result; } size_t path_len = strlen(path); size_t name_len = strlen(entry.name); bool needs_sep = path_len > 0 && path[path_len - 1] != '/'; char *child = malloc(path_len + (needs_sep ? 1u : 0u) + name_len + 1u); if (!child) { uv_fs_req_cleanup(&req); return UV_ENOMEM; } memcpy(child, path, path_len); if (needs_sep) child[path_len++] = '/'; memcpy(child + path_len, entry.name, name_len + 1u); result = fs_remove_path_recursive(child, true, force); free(child); if (result < 0) { uv_fs_req_cleanup(&req); return result; } }
uv_fs_req_cleanup(&req); result = uv_fs_rmdir(NULL, &req, path, NULL); uv_fs_req_cleanup(&req); return (force && result == UV_ENOENT) ? 0 : result;}
static bool fs_parse_rm_options(ant_t *js, ant_value_t options, bool *recursive_out, bool *force_out) { if (recursive_out) *recursive_out = false; if (force_out) *force_out = false;
if (vtype(options) == kTypeUndefined || vtype(options) == kTypeNull) return true; if (vtype(options) != kTypeObject) return false;
if (recursive_out) *recursive_out = js_truthy(js, js_get(js, options, "recursive")); if (force_out) *force_out = js_truthy(js, js_get(js, options, "force")); return true;}
static ant_value_t fs_rm_impl(ant_native_params_t, bool return_promise) { ant_value_t promise = 0; ant_value_t path_val; size_t path_len = 0; const char *path = NULL; bool recursive = false; bool force = false; int result;
if (return_promise) promise = js_mkpromise(js); if (nargs < 1) { ant_value_t err = js_mkerr(js, "rm() requires a path argument"); if (!return_promise) return err; js_reject_promise(js, promise, err); return promise; }
path_val = args[0] = fs_coerce_path(js, args[0]); if (is_err(path_val)) return path_val; if (vtype(path_val) != kTypeString) { ant_value_t err = js_mkerr(js, "rm() path must be a string"); if (!return_promise) return err; js_reject_promise(js, promise, err); return promise; }
path = js_getstr(js, path_val, &path_len); if (!path) { ant_value_t err = js_mkerr(js, "Failed to get path string"); if (!return_promise) return err; js_reject_promise(js, promise, err); return promise; }
if (!fs_parse_rm_options(js, nargs >= 2 ? args[1] : js_mkundef(), &recursive, &force)) { ant_value_t err = js_mkerr_typed(js, JS_ERR_TYPE, "rm() options must be an object"); if (!return_promise) return err; js_reject_promise(js, promise, err); return promise; }
result = fs_remove_path_recursive(path, recursive, force); if (result < 0) { ant_value_t err = js_mkerr(js, "%s", uv_strerror(result)); if (!return_promise) return err; js_reject_promise(js, promise, err); return promise; }
if (!return_promise) return js_mkundef(); js_resolve_promise(js, promise, js_mkundef()); return promise;}
static fs_encoding_t parse_encoding(ant_t *js, ant_value_t arg) { size_t len; const char *str = NULL;
if (vtype(arg) == kTypeString) str = js_getstr(js, arg, &len); else if (vtype(arg) == kTypeObject) { ant_value_t enc = js_get(js, arg, "encoding"); if (vtype(enc) == kTypeString) str = js_getstr(js, enc, &len); }
if (!str) return FS_ENC_NONE;
if (len == 4 && memcmp(str, "utf8", 4) == 0) return FS_ENC_UTF8; if (len == 5 && memcmp(str, "utf-8", 5) == 0) return FS_ENC_UTF8; if (len == 7 && memcmp(str, "utf16le", 7) == 0) return FS_ENC_UTF16LE; if (len == 4 && memcmp(str, "ucs2", 4) == 0) return FS_ENC_UTF16LE; if (len == 5 && memcmp(str, "ucs-2", 5) == 0) return FS_ENC_UTF16LE; if (len == 6 && memcmp(str, "latin1", 6) == 0) return FS_ENC_LATIN1; if (len == 6 && memcmp(str, "binary", 6) == 0) return FS_ENC_LATIN1; if (len == 6 && memcmp(str, "base64", 6) == 0) return FS_ENC_BASE64; if (len == 9 && memcmp(str, "base64url", 9) == 0) return FS_ENC_BASE64URL; if (len == 3 && memcmp(str, "hex", 3) == 0) return FS_ENC_HEX; if (len == 5 && memcmp(str, "ascii", 5) == 0) return FS_ENC_ASCII;
return FS_ENC_NONE;}
static ant_value_t encode_data(ant_t *js, const char *data, size_t len, fs_encoding_t enc) { switch (enc) { case FS_ENC_UTF8: case FS_ENC_LATIN1: case FS_ENC_ASCII: return js_mkstr(js, data, len);
case FS_ENC_HEX: { char *out = malloc(len * 2); if (!out) return js_mkerr(js, "Out of memory"); for (size_t i = 0; i < len; i++) { out[i * 2] = hex_char((unsigned char)data[i] >> 4); out[i * 2 + 1] = hex_char(data[i]); } ant_value_t result = js_mkstr(js, out, len * 2); free(out); return result; }
case FS_ENC_BASE64: { size_t out_len; char *out = ant_base64_encode((const uint8_t *)data, len, &out_len); if (!out) return js_mkerr(js, "Out of memory"); ant_value_t result = js_mkstr(js, out, out_len); free(out); return result; }
case FS_ENC_BASE64URL: { size_t out_len; char *out = ant_base64_encode((const uint8_t *)data, len, &out_len); if (!out) return js_mkerr(js, "Out of memory"); for (size_t i = 0; i < out_len; i++) { if (out[i] == '+') out[i] = '-'; else if (out[i] == '/') out[i] = '_'; } while (out_len > 0 && out[out_len - 1] == '=') out_len--; ant_value_t result = js_mkstr(js, out, out_len); free(out); return result; }
case FS_ENC_UTF16LE: { const unsigned char *s = (const unsigned char *)data; char *out = malloc((len / 2) * 4); if (!out) return js_mkerr(js, "Out of memory"); size_t j = 0; for (size_t i = 0; i + 1 < len; i += 2) { uint32_t cp = s[i] | (s[i + 1] << 8); bool is_hi = cp >= 0xD800 && cp <= 0xDBFF && i + 3 < len; uint32_t lo = is_hi ? s[i + 2] | (s[i + 3] << 8) : 0; bool is_pair = is_hi && lo >= 0xDC00 && lo <= 0xDFFF; if (is_pair) { cp = 0x10000 + ((cp - 0xD800) << 10) + (lo - 0xDC00); i += 2; } j += utf8_encode(cp, out + j); } ant_value_t result = js_mkstr(js, out, j); free(out); return result; }
default: return js_mkstr(js, data, len); }}
static ant_value_t fs_rejected_promise(ant_t *js, ant_value_t err) { GC_ROOT_SAVE(mark, js); if (is_err(err)) err = js_take_thrown(js, err); GC_ROOT_PIN(js, err);
ant_value_t promise = js_mkpromise(js); if (!is_err(promise)) js_reject_promise(js, promise, err); GC_ROOT_RESTORE(js, mark); return promise;}
static ant_value_t fs_resolved_promise(ant_t *js, ant_value_t value) { GC_ROOT_SAVE(mark, js); GC_ROOT_PIN(js, value); ant_value_t promise = js_mkpromise(js); if (is_err(promise)) { GC_ROOT_RESTORE(js, mark); return promise; } GC_ROOT_PIN(js, promise); js_resolve_promise(js, promise, value); GC_ROOT_RESTORE(js, mark); return promise;}
static ant_value_t fs_filehandle_require_this(ant_t *js) { ant_value_t this_obj = js_getthis(js); if (!is_object_type(this_obj) || !js_check_native_tag(this_obj, FS_FILEHANDLE_NATIVE_TAG)) return js_mkerr_typed(js, JS_ERR_TYPE, "FileHandle method called on incompatible receiver"); return this_obj;}
static ant_value_t fs_filehandle_fd_value(ant_t *js, ant_value_t handle_obj) { ant_value_t fd_val = js_get_slot(handle_obj, SLOT_DATA); if (vtype(fd_val) != kTypeNumber) fd_val = js_get(js, handle_obj, "fd"); return fd_val;}
static ant_value_t fs_filehandle_get_fd(ant_t *js, ant_value_t handle_obj) { ant_value_t fd_val = fs_filehandle_fd_value(js, handle_obj); if (vtype(fd_val) != kTypeNumber || js_getnum(fd_val) < 0) return js_mkerr_typed(js, JS_ERR_TYPE, "FileHandle is closed"); return fd_val;}
static void fs_filehandle_mark_closed(ant_t *js, ant_value_t handle_obj) { js_set_slot(handle_obj, SLOT_DATA, js_mkundef()); js_set(js, handle_obj, "fd", js_mknum(-1));}
static ant_value_t builtin_fs_filehandle_close(ant_params_t) { ant_value_t handle_obj = fs_filehandle_require_this(js); if (is_err(handle_obj)) return fs_rejected_promise(js, handle_obj);
ant_value_t fd_val = fs_filehandle_fd_value(js, handle_obj); if (vtype(fd_val) != kTypeNumber || js_getnum(fd_val) < 0) return fs_resolved_promise(js, js_mkundef()); uv_fs_t req; int result = uv_fs_close(js->loop, &req, (uv_file)(int)js_getnum(fd_val), NULL); uv_fs_req_cleanup(&req); if (result < 0) return fs_rejected_promise(js, fs_mk_uv_error(js, result, "close", NULL, NULL));
fs_filehandle_mark_closed(js, handle_obj); return fs_resolved_promise(js, js_mkundef());}
static ant_value_t builtin_fs_filehandle_stat(ant_params_t) { ant_value_t handle_obj = fs_filehandle_require_this(js); if (is_err(handle_obj)) return fs_rejected_promise(js, handle_obj);
ant_value_t fd_val = fs_filehandle_get_fd(js, handle_obj); if (is_err(fd_val)) return fs_rejected_promise(js, fd_val);
uv_fs_t req; int result = uv_fs_fstat(NULL, &req, (uv_file)(int)js_getnum(fd_val), NULL); if (result < 0) { ant_value_t err = fs_mk_uv_error(js, result, "fstat", NULL, NULL); uv_fs_req_cleanup(&req); return fs_rejected_promise(js, err); }
ant_value_t stat_obj = fs_stats_object_from_uv(js, &req.statbuf); uv_fs_req_cleanup(&req); return fs_resolved_promise(js, stat_obj);}
static ant_value_t builtin_fs_filehandle_sync(ant_params_t) { ant_value_t handle_obj = fs_filehandle_require_this(js); if (is_err(handle_obj)) return fs_rejected_promise(js, handle_obj);
ant_value_t fd_val = fs_filehandle_get_fd(js, handle_obj); if (is_err(fd_val)) return fs_rejected_promise(js, fd_val);
uv_fs_t req; int result = uv_fs_fsync(js->loop, &req, (uv_file)(int)js_getnum(fd_val), NULL); uv_fs_req_cleanup(&req); if (result < 0) return fs_rejected_promise(js, fs_mk_uv_error(js, result, "fsync", NULL, NULL));
return fs_resolved_promise(js, js_mkundef());}
static ant_value_t builtin_fs_filehandle_read(ant_params_t) { ant_value_t handle_obj = fs_filehandle_require_this(js); if (is_err(handle_obj)) return fs_rejected_promise(js, handle_obj);
ant_value_t fd_val = fs_filehandle_get_fd(js, handle_obj); if (is_err(fd_val)) return fs_rejected_promise(js, fd_val); if (nargs < 1) return fs_rejected_promise(js, js_mkerr(js, "FileHandle.read() requires a buffer argument"));
TypedArrayData *ta_data = buffer_get_typedarray_data(args[0]); uint8_t *buf_data; size_t buf_len; if (!Ant_Buffer_GetViewBytes(ta_data, &buf_data, &buf_len)) return fs_rejected_promise(js, js_mkerr(js, "FileHandle.read() buffer must be a Buffer or TypedArray"));
size_t offset = 0; size_t length = buf_len; int64_t position = -1;
if (nargs >= 2 && vtype(args[1]) == kTypeNumber) offset = (size_t)js_getnum(args[1]); if (nargs >= 3 && vtype(args[2]) == kTypeNumber) length = (size_t)js_getnum(args[2]); if (nargs >= 4 && vtype(args[3]) == kTypeNumber) position = (int64_t)js_getnum(args[3]);
if (offset > buf_len) return fs_rejected_promise(js, js_mkerr(js, "offset is out of bounds")); if (offset + length > buf_len) return fs_rejected_promise(js, js_mkerr(js, "length extends beyond buffer"));
uv_buf_t buf = uv_buf_init((char *)(buf_data + offset), (unsigned int)length); uv_fs_t req; int result = uv_fs_read(js->loop, &req, (uv_file)(int)js_getnum(fd_val), &buf, 1, position, NULL); uv_fs_req_cleanup(&req); if (result < 0) return fs_rejected_promise(js, fs_mk_uv_error(js, result, "read", NULL, NULL));
ant_value_t out = fs_new_io_result(js, false, (double)result, args[0]); if (is_err(out)) return fs_rejected_promise(js, out); return fs_resolved_promise(js, out);}
static ant_value_t builtin_fs_filehandle_write(ant_params_t) { ant_value_t handle_obj = fs_filehandle_require_this(js); if (is_err(handle_obj)) return fs_rejected_promise(js, handle_obj);
ant_value_t fd_val = fs_filehandle_get_fd(js, handle_obj); if (is_err(fd_val)) return fs_rejected_promise(js, fd_val); if (nargs < 1) return fs_rejected_promise(js, js_mkerr(js, "FileHandle.write() requires a data argument"));
const char *write_data = NULL; size_t write_len = 0; int64_t position = -1;
if (vtype(args[0]) == kTypeString) { write_data = js_getstr(js, args[0], &write_len); if (!write_data) return fs_rejected_promise(js, js_mkerr(js, "Failed to get string")); if (nargs >= 2 && vtype(args[1]) == kTypeNumber) position = (int64_t)js_getnum(args[1]); } else { uint8_t *buf_data; size_t buf_len; if (!fs_view_bytes(args[0], &buf_data, &buf_len)) return fs_rejected_promise(js, js_mkerr(js, "FileHandle.write() data must be a Buffer, TypedArray, DataView, or string")); size_t offset = 0; size_t length = buf_len;
if (nargs >= 2) { if (vtype(args[1]) == kTypeObject) { ant_value_t off_val = js_get(js, args[1], "offset"); ant_value_t len_val = js_get(js, args[1], "length"); ant_value_t pos_val = js_get(js, args[1], "position"); if (vtype(off_val) == kTypeNumber) offset = (size_t)js_getnum(off_val); if (vtype(len_val) == kTypeNumber) length = (size_t)js_getnum(len_val); else length = buf_len - offset; if (vtype(pos_val) == kTypeNumber) position = (int64_t)js_getnum(pos_val); } else if (vtype(args[1]) == kTypeNumber) { offset = (size_t)js_getnum(args[1]); length = buf_len - offset; if (nargs >= 3 && vtype(args[2]) == kTypeNumber) length = (size_t)js_getnum(args[2]); if (nargs >= 4 && vtype(args[3]) == kTypeNumber) position = (int64_t)js_getnum(args[3]); }}
if (offset > buf_len) return fs_rejected_promise(js, js_mkerr(js, "offset is out of bounds")); if (offset + length > buf_len) return fs_rejected_promise(js, js_mkerr(js, "length extends beyond buffer")); write_data = (const char *)(buf_data + offset); write_len = length; }
uv_buf_t buf = uv_buf_init((char *)write_data, (unsigned int)write_len); uv_fs_t req; int result = uv_fs_write(js->loop, &req, (uv_file)(int)js_getnum(fd_val), &buf, 1, position, NULL); uv_fs_req_cleanup(&req); if (result < 0) return fs_rejected_promise(js, fs_mk_uv_error(js, result, "write", NULL, NULL));
ant_value_t out = fs_new_io_result(js, true, (double)result, args[0]); if (is_err(out)) return fs_rejected_promise(js, out); return fs_resolved_promise(js, out);}
static ant_value_t builtin_fs_filehandle_writeFile(ant_params_t) { ant_value_t handle_obj = fs_filehandle_require_this(js); if (is_err(handle_obj)) return fs_rejected_promise(js, handle_obj);
ant_value_t fd_val = fs_filehandle_get_fd(js, handle_obj); if (is_err(fd_val)) return fs_rejected_promise(js, fd_val); if (nargs < 1) return fs_rejected_promise(js, js_mkerr(js, "FileHandle.writeFile() requires data"));
const char *data = NULL; size_t len = 0;
if (vtype(args[0]) == kTypeString) { data = js_getstr(js, args[0], &len); if (!data) return fs_rejected_promise(js, js_mkerr(js, "Failed to get string")); } else { uint8_t *bytes; if (!fs_view_bytes(args[0], &bytes, &len)) return fs_rejected_promise(js, js_mkerr(js, "FileHandle.writeFile() data must be a Buffer, TypedArray, DataView, or string")); data = (const char *)bytes; }
size_t written = 0; while (written < len) { uv_buf_t buf = uv_buf_init((char *)(data + written), (unsigned int)(len - written)); uv_fs_t req; int result = uv_fs_write(js->loop, &req, (uv_file)(int)js_getnum(fd_val), &buf, 1, -1, NULL); uv_fs_req_cleanup(&req); if (result < 0) return fs_rejected_promise(js, fs_mk_uv_error(js, result, "write", NULL, NULL)); if (result == 0) return fs_rejected_promise(js, js_mkerr(js, "short write")); written += (size_t)result; }
return fs_resolved_promise(js, js_mkundef());}
static void fs_init_filehandle_proto(ant_t *js) { if (is_object_type(js->builtins.filehandle_proto)) return; js->builtins.filehandle_proto = Ant_Object_CreateBare(js); js_set_native(js->builtins.filehandle_proto, NULL, FS_FILEHANDLE_NATIVE_TAG); js_set(js, js->builtins.filehandle_proto, "close", Ant_Function_Create(builtin_fs_filehandle_close)); js_set(js, js->builtins.filehandle_proto, "stat", Ant_Function_Create(builtin_fs_filehandle_stat)); js_set(js, js->builtins.filehandle_proto, "sync", Ant_Function_Create(builtin_fs_filehandle_sync)); js_set(js, js->builtins.filehandle_proto, "read", Ant_Function_Create(builtin_fs_filehandle_read)); js_set(js, js->builtins.filehandle_proto, "write", Ant_Function_Create(builtin_fs_filehandle_write)); js_set(js, js->builtins.filehandle_proto, "writeFile", Ant_Function_Create(builtin_fs_filehandle_writeFile)); js_set_tostringtag(js, js->builtins.filehandle_proto, js_mkstr(js, "FileHandle", 10));}
static ant_value_t fs_make_filehandle(ant_t *js, int fd) { fs_init_filehandle_proto(js); ant_value_t handle = Ant_Object_CreateBare(js); js_set_native(handle, NULL, FS_FILEHANDLE_NATIVE_TAG); js_set_proto_init(handle, js->builtins.filehandle_proto); js_set_slot(handle, SLOT_DATA, js_mknum((double)fd)); js_set(js, handle, "fd", js_mknum((double)fd)); return handle;}
static bool fs_buffer_encoding(ant_t *js, ant_value_t options) { ant_value_t encoding = is_object_type(options) ? js_get(js, options, "encoding") : options; if (vtype(encoding) != kTypeString) return false; size_t len; const char *value = js_getstr(js, encoding, &len); return value && len == 6 && memcmp(value, "buffer", 6) == 0;}
static ant_value_t fs_read_to_uint8array(ant_t *js, const char *data, size_t len) { ArrayBufferData *ab = create_array_buffer_data(js, len); if (!ab) return js_mkerr(js, "Out of memory"); memcpy(ab->data, data, len); return create_typed_array(js, TYPED_ARRAY_UINT8, ab, 0, len, js->builtins.buffer_proto);}
static ant_value_t fs_path_result(ant_t *js, const char *data, size_t len, bool as_buffer) { return as_buffer ? fs_read_to_uint8array(js, data, len) : js_mkstr(js, data, len);}
static ant_value_t fs_mk_uv_error( ant_t *js, int uv_code, const char *syscall, const char *path, const char *dest);
static void complete_request(fs_request_t *req) { if (req->failed) { const char *err_msg = req->error_msg ? req->error_msg : "Unknown error"; ant_value_t reject_value;
if (req->error_code && req->syscall) reject_value = fs_mk_uv_error( fs_req_isolate(req), req->error_code, req->syscall, req->path, req->path2 ); else if (req->error_code) { ant_value_t props = Ant_Object_CreateBare(fs_req_isolate(req)); const char *code = uv_err_name(req->error_code); js_set(fs_req_isolate(req), props, "code", js_mkstr(fs_req_isolate(req), code, strlen(code))); js_set(fs_req_isolate(req), props, "errno", js_mknum((double)req->error_code)); if (req->path) js_set(fs_req_isolate(req), props, "path", js_mkstr(fs_req_isolate(req), req->path, strlen(req->path))); if (req->path2) js_set(fs_req_isolate(req), props, "dest", js_mkstr(fs_req_isolate(req), req->path2, strlen(req->path2))); reject_value = js_mkerr_props(fs_req_isolate(req), JS_ERR_TYPE, props, "%s", err_msg); } else reject_value = js_mkerr(fs_req_isolate(req), "%s", err_msg);
if (is_err(reject_value)) { reject_value = js_take_thrown(fs_req_isolate(req), js_mkundef()); if (is_undefined(reject_value)) reject_value = js_mkstr(fs_req_isolate(req), err_msg, strlen(err_msg)); } js_reject_promise(fs_req_isolate(req), req->promise, reject_value); } else if (abort_signal_is_aborted(req->signal)) { js_reject_promise(fs_req_isolate(req), req->promise, abort_signal_make_error(fs_req_isolate(req), req->signal)); } else { ant_value_t result = js_mkundef(); if (req->op_type == FS_OP_READ && req->data) { if (req->encoding != FS_ENC_NONE) result = encode_data(fs_req_isolate(req), req->data, req->data_len, req->encoding); else result = fs_read_to_uint8array(fs_req_isolate(req), req->data, req->data_len); } else if (req->op_type == FS_OP_READ_BYTES && req->data) result = js_mkstr(fs_req_isolate(req), req->data, req->data_len); else if ((req->op_type == FS_OP_REALPATH || req->op_type == FS_OP_MKDTEMP) && req->data) result = fs_path_result(fs_req_isolate(req), req->data, req->data_len, req->buffer_encoding); if (is_err(result)) js_reject_promise(fs_req_isolate(req), req->promise, result); else js_resolve_promise(fs_req_isolate(req), req->promise, result); } Ant_List_Remove(req); free_fs_request(req);}
static void fs_read_close_and_complete(fs_request_t *req) { uv_fs_t close_req; uv_fs_close(req->uv_req.loop, &close_req, req->fd, NULL); uv_fs_req_cleanup(&close_req); req->completed = 1; complete_request(req);}
static void on_read_complete(uv_fs_t *uv_req);
static int fs_read_next_chunk(fs_request_t *req) { if (req->data_len == req->data_cap) { size_t cap = req->data_cap ? req->data_cap * 2 : 64 * 1024; char *grown = realloc(req->data, cap + 1); if (!grown) return UV_ENOMEM; req->data = grown; req->data_cap = cap; }
size_t want = req->data_cap - req->data_len; if (want > INT_MAX) want = INT_MAX;
uv_buf_t buf = uv_buf_init(req->data + req->data_len, (unsigned int)want); return uv_fs_read(req->uv_req.loop, &req->uv_req, req->fd, &buf, 1, -1, on_read_complete);}
static void on_read_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data; ssize_t n = uv_req->result; uv_fs_req_cleanup(uv_req);
if (n < 0) { fs_request_fail(req, (int)n); fs_read_close_and_complete(req); return; }
if (n == 0) { fs_read_close_and_complete(req); return; }
req->data_len += (size_t)n; int result = fs_read_next_chunk(req); if (result < 0) { fs_request_fail(req, result); fs_read_close_and_complete(req); }}
static void on_open_for_read(uv_fs_t *uv_req) { fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; } req->fd = (int)uv_req->result; uv_fs_req_cleanup(uv_req); uv_fs_t stat_req; int stat_result = uv_fs_fstat(uv_req->loop, &stat_req, req->fd, NULL); if (stat_result < 0) { fs_request_fail(req, stat_result); req->completed = 1; uv_fs_t close_req; uv_fs_close(uv_req->loop, &close_req, req->fd, NULL); uv_fs_req_cleanup(&close_req); complete_request(req); return; } size_t file_size = stat_req.statbuf.st_size; uv_fs_req_cleanup(&stat_req); req->data_cap = file_size + 1; req->data = malloc(req->data_cap + 1); if (!req->data) { req->failed = 1; req->error_msg = strdup("Out of memory"); fs_read_close_and_complete(req); return; } int read_result = fs_read_next_chunk(req); if (read_result < 0) { fs_request_fail(req, read_result); fs_read_close_and_complete(req); }}
static void on_write_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { fs_request_fail(req, (int)uv_req->result); } uv_fs_t close_req; uv_fs_close(uv_req->loop, &close_req, req->fd, NULL); uv_fs_req_cleanup(&close_req); req->completed = 1; complete_request(req);}
static void on_open_for_write(uv_fs_t *uv_req) { fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; } req->fd = (int)uv_req->result; uv_fs_req_cleanup(uv_req); uv_buf_t buf = uv_buf_init(req->data, (unsigned int)req->data_len); int write_result = uv_fs_write(uv_req->loop, uv_req, req->fd, &buf, 1, 0, on_write_complete); if (write_result < 0) { fs_request_fail(req, write_result); req->completed = 1; uv_fs_t close_req; uv_fs_close(uv_req->loop, &close_req, req->fd, NULL); uv_fs_req_cleanup(&close_req); complete_request(req); return; }}
static void on_unlink_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { fs_request_fail(req, (int)uv_req->result); } uv_fs_req_cleanup(uv_req); req->completed = 1; complete_request(req);}
static void on_rename_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data;
if (uv_req->result < 0) { fs_request_fail(req, (int)uv_req->result); }
uv_fs_req_cleanup(uv_req); req->completed = 1; complete_request(req);}
static void on_symlink_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data;
if (uv_req->result < 0) { fs_request_fail(req, (int)uv_req->result); }
uv_fs_req_cleanup(uv_req); req->completed = 1; complete_request(req);}
static void on_link_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data;
if (uv_req->result < 0) { fs_request_fail(req, (int)uv_req->result); }
uv_fs_req_cleanup(uv_req); req->completed = 1; complete_request(req);}
static bool mkdirp_is_separator(char ch) {#ifdef _WIN32 return ch == '/' || ch == '\\';#else return ch == '/';#endif}
static size_t mkdirp_root_length(const char *path, size_t len) { if (len == 0) return 0;
#ifdef _WIN32 if (len >= 2 && mkdirp_is_separator(path[0]) && mkdirp_is_separator(path[1])) { size_t i = 2; for (int parts = 0; parts < 2; parts++) { while (i < len && mkdirp_is_separator(path[i])) i++; size_t start = i; while (i < len && !mkdirp_is_separator(path[i])) i++; if (i == start) return 2; } while (i < len && mkdirp_is_separator(path[i])) i++; return i; }
if (len >= 2 && path[1] == ':') return len >= 3 && mkdirp_is_separator(path[2]) ? 3 : 2;#endif
return mkdirp_is_separator(path[0]) ? 1 : 0;}
static int mkdirp(const char *path, mode_t mode) { int result = -1; char *tmp = strdup(path); if (!tmp) goto done;
size_t len = strlen(tmp);#ifdef _WIN32 if (len >= 2 && tmp[1] == ':' && (len == 2 || !mkdirp_is_separator(tmp[2]))) { errno = EINVAL; goto cleanup; }#endif
size_t root_len = mkdirp_root_length(tmp, len); while (len > root_len && mkdirp_is_separator(tmp[len - 1])) tmp[--len] = '\0'; if (len == 0) { errno = ENOENT; goto cleanup; }
for (char *p = tmp + root_len; *p; p++) { if (!mkdirp_is_separator(*p)) continue; if (p == tmp + root_len || mkdirp_is_separator(p[-1])) continue; char separator = *p; *p = '\0'; #ifdef _WIN32 _mkdir(tmp); #else mkdir(tmp, mode); #endif *p = separator; }
#ifdef _WIN32 result = _mkdir(tmp);#else result = mkdir(tmp, mode);#endif if (result != 0 && errno == EEXIST) result = 0;
cleanup: free(tmp);done: return result;}
static void on_mkdir_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { if (!req->recursive || uv_req->result != UV_EEXIST) { fs_request_fail(req, (int)uv_req->result); }} uv_fs_req_cleanup(uv_req); req->completed = 1; complete_request(req);}
static void on_rmdir_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { fs_request_fail(req, (int)uv_req->result); } uv_fs_req_cleanup(uv_req); req->completed = 1; complete_request(req);}
static void on_stat_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; } ant_value_t stat_obj = fs_stats_object_from_uv(fs_req_isolate(req), &uv_req->statbuf); req->completed = 1; js_resolve_promise(fs_req_isolate(req), req->promise, stat_obj); Ant_List_Remove(req); free_fs_request(req);}
static void on_realpath_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data;
if (uv_req->result < 0 || !uv_req->ptr) { fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; }
req->data = strdup((const char *)uv_req->ptr); if (!req->data) { req->failed = 1; req->error_msg = strdup("Out of memory"); req->completed = 1; complete_request(req); return; }
req->data_len = strlen(req->data); req->completed = 1; complete_request(req);}
static ant_value_t fs_path_join(ant_t *js, const char *a, const char *b) { bool found = false; ant_value_t path_ns = js_esm_load_node_builtin(js, "node:path", 9, &found); if (is_err(path_ns)) return path_ns; if (!found) return js_mkerr(js, "node:path is unavailable");
GC_ROOT_SAVE(root_mark, js); ant_value_t path_mod = esm_require_unwrap(js, path_ns); GC_ROOT_PIN(js, path_mod); ant_value_t join = js_get(js, path_mod, "join"); GC_ROOT_PIN(js, join); ant_value_t join_args[2] = { js_mkstr(js, a, strlen(a)), js_mkundef() }; GC_ROOT_PIN(js, join_args[0]); join_args[1] = js_mkstr(js, b, strlen(b)); GC_ROOT_PIN(js, join_args[1]); ant_value_t joined = sv_call_value(js, join, path_mod, join_args, 2); GC_ROOT_RESTORE(js, root_mark); if (is_err(joined)) return joined; if (vtype(joined) != kTypeString) return js_mkerr(js, "path.join() did not return a string"); return joined;}
static ant_value_t fs_parent_path_value(ant_value_t original, ant_value_t coerced) { return buffer_get_typedarray_data(original) ? original : coerced;}
static ant_value_t create_dirent_object( ant_t *js, const char *name, size_t name_len, uv_dirent_type_t type, bool as_buffer, ant_value_t parent_path) { ant_value_t name_value = fs_path_result(js, name, name_len, as_buffer); if (is_err(name_value)) return name_value; GC_ROOT_SAVE(root_mark, js); GC_ROOT_PIN(js, name_value); ant_value_t obj = Ant_Object_Create(js); js_set_proto(js, obj, js->builtins.dirent_proto); js_set(js, obj, "name", name_value); js_set(js, obj, "parentPath", parent_path); js_set_slot(obj, SLOT_DATA, tov((double)type)); GC_ROOT_RESTORE(js, root_mark); return obj;}
static void on_mkdtemp_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data;
if (uv_req->result < 0) { fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); uv_fs_req_cleanup(uv_req); return; }
req->data = strdup(uv_req->path); if (!req->data) { req->failed = 1; req->error_msg = strdup("Out of memory"); req->completed = 1; complete_request(req); uv_fs_req_cleanup(uv_req); return; }
req->data_len = strlen(req->data); req->completed = 1; uv_fs_req_cleanup(uv_req); complete_request(req);}
static void on_exists_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data; ant_value_t result = js_bool(uv_req->result >= 0); req->completed = 1; js_resolve_promise(fs_req_isolate(req), req->promise, result); Ant_List_Remove(req); free_fs_request(req);}
static void on_access_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; } req->completed = 1; js_resolve_promise(fs_req_isolate(req), req->promise, js_mkundef()); Ant_List_Remove(req); free_fs_request(req);}
static void on_chmod_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data;
if (uv_req->result < 0) { fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; }
req->completed = 1; js_resolve_promise(fs_req_isolate(req), req->promise, js_mkundef()); Ant_List_Remove(req); free_fs_request(req);}
static void on_readdir_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; } ant_t *js = fs_req_isolate(req); GC_ROOT_SAVE(root_mark, js); ant_value_t parent = is_object_type(req->owner) ? req->owner : js_mkstr(js, req->path, strlen(req->path)); GC_ROOT_PIN(js, parent); ant_value_t arr = js_mkarr(js); GC_ROOT_PIN(js, arr); uv_dirent_t dirent; while (uv_fs_scandir_next(uv_req, &dirent) != UV_EOF) { ant_value_t entry = req->with_file_types ? create_dirent_object(js, dirent.name, strlen(dirent.name), dirent.type, req->buffer_encoding, parent) : fs_path_result(js, dirent.name, strlen(dirent.name), req->buffer_encoding); if (is_err(entry)) { GC_ROOT_RESTORE(js, root_mark); js_reject_promise(js, req->promise, entry); req->completed = 1; Ant_List_Remove(req); free_fs_request(req); return; } js_arr_push(js, arr, entry); } GC_ROOT_RESTORE(js, root_mark); req->completed = 1; js_resolve_promise(fs_req_isolate(req), req->promise, arr); Ant_List_Remove(req); free_fs_request(req);}
static int fs_read_all_fd(uv_file fd, char **out, size_t *out_len) { uv_fs_t req; size_t cap = 64 * 1024; size_t len = 0;
if (uv_fs_fstat(NULL, &req, fd, NULL) == 0 && req.statbuf.st_size > 0) cap = (size_t)req.statbuf.st_size + 1; uv_fs_req_cleanup(&req);
char *data = malloc(cap); if (!data) return UV_ENOMEM;
for (;;) { if (len == cap) { char *grown = realloc(data, cap * 2); if (!grown) { free(data); return UV_ENOMEM; } data = grown; cap *= 2; }
uv_buf_t buf = uv_buf_init(data + len, (unsigned int)(cap - len)); int n = uv_fs_read(NULL, &req, fd, &buf, 1, -1, NULL); uv_fs_req_cleanup(&req);
if (n < 0) { free(data); return n; } if (n == 0) break; len += (size_t)n; }
*out = data; *out_len = len; return 0;}
static bool fs_fd_arg(ant_value_t arg, uv_file *out) { if (vtype(arg) != kTypeNumber) return false; double fd = js_getnum(arg); if (!(fd >= 0 && fd <= INT32_MAX) || fd != (double)(int32_t)fd) return false; *out = (uv_file)fd; return true;}
static ant_value_t builtin_fs_readFileSync(ant_params_t) { if (nargs < 1) return js_mkerr(js, "readFileSync() requires a path argument");
char *path_cstr = NULL; char *data = NULL; size_t file_size = 0; uv_file fd = -1; uv_fs_t req;
bool owns_fd = !fs_fd_arg(args[0], &fd); if (owns_fd) { ant_value_t path_val = args[0] = fs_coerce_path(js, args[0]); if (is_err(path_val)) return path_val; if (vtype(path_val) != kTypeString) return js_mkerr(js, "readFileSync() path must be a string or URL");
size_t path_len; char *path = js_getstr(js, path_val, &path_len); if (!path) return js_mkerr(js, "Failed to get path string");
path_cstr = strndup(path, path_len); if (!path_cstr) return js_mkerr(js, "Out of memory");
fd = uv_fs_open(NULL, &req, path_cstr, O_RDONLY, 0, NULL); uv_fs_req_cleanup(&req); if (fd < 0) { ant_value_t err = fs_mk_uv_error(js, fd, "open", path_cstr, NULL); free(path_cstr); return err; } }
int rc = fs_read_all_fd(fd, &data, &file_size); if (owns_fd) { uv_fs_close(NULL, &req, fd, NULL); uv_fs_req_cleanup(&req); }
if (rc < 0) { ant_value_t err = rc == UV_ENOMEM ? js_mkerr(js, "Out of memory") : fs_mk_uv_error(js, rc, "read", path_cstr, NULL); free(path_cstr); return err; } free(path_cstr); fs_encoding_t enc = (nargs > 1) ? parse_encoding(js, args[1]) : FS_ENC_NONE; ant_value_t result = (enc != FS_ENC_NONE) ? encode_data(js, data, file_size, enc) : fs_read_to_uint8array(js, data, file_size);
free(data); return result;}
static ant_value_t builtin_fs_readFile(ant_params_t) { if (nargs < 1) return js_mkerr(js, "readFile() requires a path argument"); ant_value_t path_val = args[0] = fs_coerce_path(js, args[0]); if (is_err(path_val)) return path_val; if (vtype(path_val) != kTypeString) return js_mkerr(js, "readFile() path must be a string or URL"); size_t path_len; char *path = js_getstr(js, path_val, &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); ant_value_t signal = nargs > 1 && is_object_type(args[1]) ? js_get(js, args[1], "signal") : js_mkundef(); if (abort_signal_is_aborted(signal)) return fs_rejected_promise(js, abort_signal_make_error(js, signal)); fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory"); req->uv_req.loop = js->loop; req->signal = signal; req->op_type = FS_OP_READ; req->encoding = (nargs > 1) ? parse_encoding(js, args[1]) : FS_ENC_NONE; req->promise = js_mkpromise(js); req->path = strndup(path, path_len); req->uv_req.data = req; Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_open(js->loop, &req->uv_req, req->path, O_RDONLY, 0, on_open_for_read); if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); } return req->promise;}
static ant_value_t builtin_fs_stream(ant_params_t) { if (nargs < 1) return js_mkerr(js, "stream() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "stream() path must be a string"); size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory"); req->uv_req.loop = js->loop; req->op_type = FS_OP_READ_BYTES; req->promise = js_mkpromise(js); req->path = strndup(path, path_len); req->uv_req.data = req; Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_open(js->loop, &req->uv_req, req->path, O_RDONLY, 0, on_open_for_read); if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); } return req->promise;}
typedef struct { int flags; mode_t mode;} fs_write_options_t;
static ant_value_t fs_parse_write_options(ant_t *js, ant_value_t options, fs_write_options_t *out) { if (!is_object_type(options)) return js_mkundef();
ant_value_t flag = js_get(js, options, "flag"); if (!is_undefined(flag) && !fs_open_flags_of(js, flag, &out->flags)) return js_mkerr_code(js, JS_ERR_TYPE, "ERR_INVALID_ARG_VALUE", "The argument 'flag' is invalid");
ant_value_t mode = js_get(js, options, "mode"); if (!is_undefined(mode) && !fs_parse_mode(js, mode, &out->mode)) return js_mkerr_code(js, JS_ERR_TYPE, "ERR_INVALID_ARG_VALUE", "The argument 'mode' must be a 32-bit unsigned integer or an octal string");
return js_mkundef();}
static ant_value_t fs_write_file_sync_impl( ant_native_params_t, const char *fn_name, int default_flags) { if (nargs < 2) return js_mkerr(js, "%s() requires path and data arguments", fn_name);
fs_write_options_t opts = { default_flags, 0666 }; ant_value_t opts_result = fs_parse_write_options(js, nargs > 2 ? args[2] : js_mkundef(), &opts); if (is_err(opts_result)) return opts_result;
args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "%s() path must be a string", fn_name);
size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get arguments");
fs_write_data_t write_data; ant_value_t data_result = fs_get_write_data_arg(js, args[1], fn_name, &write_data); if (is_err(data_result)) return data_result;
char *path_cstr = strndup(path, path_len); if (!path_cstr) return js_mkerr(js, "Out of memory");
uv_fs_t req; int fd = uv_fs_open(NULL, &req, path_cstr, opts.flags, opts.mode, NULL); uv_fs_req_cleanup(&req); if (fd < 0) { ant_value_t err = fs_mk_uv_error(js, fd, "open", path_cstr, NULL); free(path_cstr); return err; }
size_t written = 0; int rc = 0; while (written < write_data.len) { uv_buf_t buf = uv_buf_init( (char *)write_data.data + written, (unsigned int)(write_data.len - written) ); rc = uv_fs_write(NULL, &req, fd, &buf, 1, -1, NULL); uv_fs_req_cleanup(&req); if (rc <= 0) break; written += (size_t)rc; }
int closed = uv_fs_close(NULL, &req, fd, NULL); uv_fs_req_cleanup(&req);
if (written == write_data.len && closed < 0) { ant_value_t err = fs_mk_uv_error(js, closed, "close", path_cstr, NULL); free(path_cstr); return err; }
if (written != write_data.len) { ant_value_t err = fs_mk_uv_error(js, rc < 0 ? rc : UV_EIO, "write", path_cstr, NULL); free(path_cstr); return err; }
free(path_cstr); return js_mkundef();}
static ant_value_t builtin_fs_writeFileSync(ant_params_t) { return fs_write_file_sync_impl(js, args, nargs, "writeFileSync", FS_WRITE_FLAGS);}
typedef struct { bool recursive; bool force; bool error_on_exist; bool dereference; bool verbatim_symlinks; ant_value_t filter;} fs_cp_options_t;
static void fs_parse_cp_options(ant_t *js, ant_value_t value, fs_cp_options_t *opts) { opts->recursive = false; opts->force = true; opts->error_on_exist = false; opts->dereference = false; opts->verbatim_symlinks = false; opts->filter = js_mkundef();
if (vtype(value) != kTypeObject) return;
ant_value_t recursive = js_get(js, value, "recursive"); ant_value_t force = js_get(js, value, "force"); ant_value_t error_on_exist = js_get(js, value, "errorOnExist"); ant_value_t dereference = js_get(js, value, "dereference"); ant_value_t verbatim_symlinks = js_get(js, value, "verbatimSymlinks"); ant_value_t filter = js_get(js, value, "filter");
if (!is_undefined(recursive)) opts->recursive = js_truthy(js, recursive); if (!is_undefined(force)) opts->force = js_truthy(js, force); if (!is_undefined(error_on_exist)) opts->error_on_exist = js_truthy(js, error_on_exist); if (!is_undefined(dereference)) opts->dereference = js_truthy(js, dereference); if (!is_undefined(verbatim_symlinks)) { opts->verbatim_symlinks = js_truthy(js, verbatim_symlinks); } if (is_callable(filter)) opts->filter = filter;}
static char *fs_join_path(const char *base, const char *name) { size_t base_len = strlen(base); size_t name_len = strlen(name); bool need_sep = base_len > 0 && base[base_len - 1] != '/'; size_t total_len = base_len + (need_sep ? 1 : 0) + name_len;
char *joined = calloc(total_len + 1, 1); if (!joined) return NULL;
memcpy(joined, base, base_len); if (need_sep) joined[base_len++] = '/'; memcpy(joined + base_len, name, name_len); joined[total_len] = '\0'; return joined;}
static ant_value_t fs_copy_file_sync_impl( ant_t *js, const char *src_cstr, const char *dest_cstr, const fs_cp_options_t *opts, const char *op_name) { struct stat src_st; if (stat(src_cstr, &src_st) != 0) { return fs_mk_errno_error(js, errno, op_name, src_cstr, dest_cstr); }
struct stat dest_st; if (!opts->force && stat(dest_cstr, &dest_st) == 0) { if (opts->error_on_exist) return fs_mk_errno_error(js, EEXIST, op_name, src_cstr, dest_cstr); return js_mkundef(); }
FILE *in = fopen(src_cstr, "rb"); if (!in) return fs_mk_errno_error(js, errno, op_name, src_cstr, dest_cstr);
FILE *out = fopen(dest_cstr, "wb"); if (!out) { ant_value_t err = fs_mk_errno_error(js, errno, op_name, src_cstr, dest_cstr); fclose(in); return err; }
char buf[8192]; size_t n = 0; while ((n = fread(buf, 1, sizeof(buf), in)) > 0) { if (fwrite(buf, 1, n, out) != n) { ant_value_t err = fs_mk_errno_error(js, errno ? errno : EIO, op_name, src_cstr, dest_cstr); fclose(in); fclose(out); return err; }}
fclose(in); fclose(out);
#ifndef _WIN32 if (chmod(dest_cstr, (mode_t)(src_st.st_mode & 0777)) != 0) { return fs_mk_errno_error(js, errno, op_name, src_cstr, dest_cstr); }#endif return js_mkundef();}
static ant_value_t builtin_fs_copyFile(ant_params_t) { if (nargs < 2) return js_mkerr(js, "copyFile() requires src and dest arguments"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "copyFile() src must be a string"); args[1] = fs_coerce_path(js, args[1]); if (is_err(args[1])) return args[1]; if (vtype(args[1]) != kTypeString) return js_mkerr(js, "copyFile() dest must be a string");
size_t src_len = 0, dest_len = 0; const char *src = js_getstr(js, args[0], &src_len); const char *dest = js_getstr(js, args[1], &dest_len); if (!src || !dest) return js_mkerr(js, "Failed to get arguments");
char *src_cstr = strndup(src, src_len); char *dest_cstr = strndup(dest, dest_len); if (!src_cstr || !dest_cstr) { free(src_cstr); free(dest_cstr); return js_mkerr(js, "Out of memory"); }
fs_cp_options_t opts = { .recursive = false, .force = true, .error_on_exist = false, .dereference = false, .verbatim_symlinks = false, .filter = 0, };
ant_value_t promise = js_mkpromise(js); ant_value_t result = fs_copy_file_sync_impl(js, src_cstr, dest_cstr, &opts, "copyFile"); free(src_cstr); free(dest_cstr);
if (is_err(result)) js_reject_promise(js, promise, result); else js_resolve_promise(js, promise, js_mkundef());
return promise;}
static ant_value_t builtin_fs_copyFileSync(ant_params_t) { if (nargs < 2) return js_mkerr(js, "copyFileSync() requires src and dest arguments");
args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "copyFileSync() src must be a string"); args[1] = fs_coerce_path(js, args[1]); if (is_err(args[1])) return args[1]; if (vtype(args[1]) != kTypeString) return js_mkerr(js, "copyFileSync() dest must be a string");
size_t src_len = 0, dest_len = 0; const char *src = js_getstr(js, args[0], &src_len); const char *dest = js_getstr(js, args[1], &dest_len); if (!src || !dest) return js_mkerr(js, "Failed to get arguments");
char *src_cstr = strndup(src, src_len); char *dest_cstr = strndup(dest, dest_len); if (!src_cstr || !dest_cstr) { free(src_cstr); free(dest_cstr); return js_mkerr(js, "Out of memory"); }
int mode = nargs > 2 && vtype(args[2]) == kTypeNumber ? (int)js_getnum(args[2]) : 0; bool exclusive = (mode & 1) != 0;
fs_cp_options_t opts = { .recursive = false, .force = !exclusive, .error_on_exist = exclusive, .dereference = false, .verbatim_symlinks = false, .filter = 0, };
ant_value_t result = fs_copy_file_sync_impl(js, src_cstr, dest_cstr, &opts, "copyfile"); free(src_cstr); free(dest_cstr); return result;}
static ant_value_t fs_copy_symlink_sync_impl( ant_t *js, const char *src_cstr, const char *dest_cstr, const fs_cp_options_t *opts, const char *op_name) { struct stat dest_st; if (lstat(dest_cstr, &dest_st) == 0) { if (!opts->force) { if (opts->error_on_exist) { return fs_mk_errno_error(js, EEXIST, op_name, src_cstr, dest_cstr); } return js_mkundef(); } if (unlink(dest_cstr) != 0) { return fs_mk_errno_error(js, errno, op_name, src_cstr, dest_cstr); } } else if (errno != ENOENT) { return fs_mk_errno_error(js, errno, op_name, src_cstr, dest_cstr); }
uv_fs_t read_req; int rc = uv_fs_readlink(NULL, &read_req, src_cstr, NULL); if (rc < 0 || !read_req.ptr) { ant_value_t err = fs_mk_uv_error(js, rc, "readlink", src_cstr, dest_cstr); uv_fs_req_cleanup(&read_req); return err; }
int flags = 0;#ifdef _WIN32 struct stat target_st; if (stat(src_cstr, &target_st) == 0 && (target_st.st_mode & S_IFMT) == S_IFDIR) { flags = UV_FS_SYMLINK_DIR; } if (!opts->verbatim_symlinks) flags |= UV_FS_SYMLINK_JUNCTION;#else (void)opts->verbatim_symlinks;#endif
uv_fs_t write_req; rc = uv_fs_symlink( NULL, &write_req, (const char *)read_req.ptr, dest_cstr, flags, NULL ); uv_fs_req_cleanup(&read_req); if (rc < 0) { ant_value_t err = fs_mk_uv_error(js, rc, "symlink", src_cstr, dest_cstr); uv_fs_req_cleanup(&write_req); return err; } uv_fs_req_cleanup(&write_req); return js_mkundef();}
static ant_value_t fs_copy_path_sync_impl( ant_t *js, const char *src_cstr, const char *dest_cstr, const fs_cp_options_t *opts, const char *op_name) { if (is_callable(opts->filter)) { ant_value_t filter_args[] = { js_mkstr(js, src_cstr, strlen(src_cstr)), js_mkstr(js, dest_cstr, strlen(dest_cstr)) }; ant_value_t included = sv_call_value( js, opts->filter, js_mkundef(), filter_args, 2 ); if (is_err(included)) return included; if (!js_truthy(js, included)) return js_mkundef(); }
struct stat src_st; int stat_result = opts->dereference ? stat(src_cstr, &src_st) : lstat(src_cstr, &src_st); if (stat_result != 0) { return fs_mk_errno_error(js, errno, op_name, src_cstr, dest_cstr); }
if ((src_st.st_mode & S_IFMT) == S_IFLNK) { return fs_copy_symlink_sync_impl( js, src_cstr, dest_cstr, opts, op_name ); }
if ((src_st.st_mode & S_IFMT) == S_IFDIR) { if (!opts->recursive) { return js_mkerr(js, "%s() recursive option is required to copy directories", op_name); }
struct stat dest_st; if (stat(dest_cstr, &dest_st) != 0) { if (errno != ENOENT) return fs_mk_errno_error(js, errno, op_name, src_cstr, dest_cstr); #ifdef _WIN32 if (_mkdir(dest_cstr) != 0) return fs_mk_errno_error(js, errno, op_name, src_cstr, dest_cstr); #else if (mkdir(dest_cstr, (mode_t)(src_st.st_mode & 0777)) != 0) { return fs_mk_errno_error(js, errno, op_name, src_cstr, dest_cstr); } #endif } else if ((dest_st.st_mode & S_IFMT) != S_IFDIR) { return fs_mk_errno_error(js, EEXIST, op_name, src_cstr, dest_cstr); }
uv_fs_t req; int rc = uv_fs_scandir(NULL, &req, src_cstr, 0, NULL); if (rc < 0) { ant_value_t err = fs_mk_uv_error(js, rc, "scandir", src_cstr, dest_cstr); uv_fs_req_cleanup(&req); return err; }
uv_dirent_t dirent; ant_value_t result = js_mkundef(); while (uv_fs_scandir_next(&req, &dirent) != UV_EOF) { if ( strcmp(dirent.name, ".") == 0 || strcmp(dirent.name, "..") == 0 ) continue; char *child_src = fs_join_path(src_cstr, dirent.name); char *child_dest = fs_join_path(dest_cstr, dirent.name); if (!child_src || !child_dest) { free(child_src); free(child_dest); result = js_mkerr(js, "Out of memory"); break; } result = fs_copy_path_sync_impl(js, child_src, child_dest, opts, op_name); free(child_src); free(child_dest); if (is_err(result)) break; } uv_fs_req_cleanup(&req); return result; }
return fs_copy_file_sync_impl(js, src_cstr, dest_cstr, opts, op_name);}
static ant_value_t fs_cp_sync_common( ant_native_params_t, const char *fn_name) { if (nargs < 2) return js_mkerr(js, "%s() requires src and dest arguments", fn_name); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "%s() src must be a string", fn_name); args[1] = fs_coerce_path(js, args[1]); if (is_err(args[1])) return args[1]; if (vtype(args[1]) != kTypeString) return js_mkerr(js, "%s() dest must be a string", fn_name);
size_t src_len = 0, dest_len = 0; const char *src = js_getstr(js, args[0], &src_len); const char *dest = js_getstr(js, args[1], &dest_len); if (!src || !dest) return js_mkerr(js, "Failed to get arguments");
fs_cp_options_t opts; fs_parse_cp_options(js, nargs >= 3 ? args[2] : js_mkundef(), &opts);
char *src_cstr = strndup(src, src_len); char *dest_cstr = strndup(dest, dest_len); if (!src_cstr || !dest_cstr) { free(src_cstr); free(dest_cstr); return js_mkerr(js, "Out of memory"); }
ant_value_t result = fs_copy_path_sync_impl(js, src_cstr, dest_cstr, &opts, fn_name); free(src_cstr); free(dest_cstr); return result;}
static ant_value_t builtin_fs_cpSync(ant_params_t) { return fs_cp_sync_common(js, args, nargs, "cpSync");}
static ant_value_t builtin_fs_cp(ant_params_t) { ant_value_t promise = js_mkpromise(js); ant_value_t result = fs_cp_sync_common(js, args, nargs, "cp"); if (is_err(result)) js_reject_promise(js, promise, result); else js_resolve_promise(js, promise, js_mkundef()); return promise;}
static ant_value_t builtin_fs_renameSync(ant_params_t) { if (nargs < 2) return js_mkerr(js, "renameSync() requires oldPath and newPath arguments"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "renameSync() oldPath must be a string"); args[1] = fs_coerce_path(js, args[1]); if (is_err(args[1])) return args[1]; if (vtype(args[1]) != kTypeString) return js_mkerr(js, "renameSync() newPath must be a string"); size_t old_len, new_len; char *old_path = js_getstr(js, args[0], &old_len); char *new_path = js_getstr(js, args[1], &new_len); if (!old_path || !new_path) return js_mkerr(js, "Failed to get arguments"); char *old_cstr = strndup(old_path, old_len); char *new_cstr = strndup(new_path, new_len); if (!old_cstr || !new_cstr) { free(old_cstr); free(new_cstr); return js_mkerr(js, "Out of memory"); } int result = rename(old_cstr, new_cstr); if (result != 0) { ant_value_t err = fs_mk_errno_error(js, errno, "rename", old_cstr, new_cstr); free(old_cstr); free(new_cstr); return err; } free(old_cstr); free(new_cstr); return js_mkundef();}
static ant_value_t builtin_fs_rename(ant_params_t) { if (nargs < 2) return js_mkerr(js, "rename() requires oldPath and newPath arguments"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "rename() oldPath must be a string"); args[1] = fs_coerce_path(js, args[1]); if (is_err(args[1])) return args[1]; if (vtype(args[1]) != kTypeString) return js_mkerr(js, "rename() newPath must be a string");
size_t old_len = 0, new_len = 0; const char *old_path = js_getstr(js, args[0], &old_len); const char *new_path = js_getstr(js, args[1], &new_len); if (!old_path || !new_path) return js_mkerr(js, "Failed to get arguments");
fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory");
req->uv_req.loop = js->loop; req->op_type = FS_OP_RENAME; req->promise = js_mkpromise(js); req->path = strndup(old_path, old_len); req->path2 = strndup(new_path, new_len); req->uv_req.data = req;
if (!req->path || !req->path2) { free_fs_request(req); return js_mkerr(js, "Out of memory"); }
Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_rename(js->loop, &req->uv_req, req->path, req->path2, on_rename_complete);
if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); }
return req->promise;}
static double fs_time_arg_to_seconds(ant_t *js, ant_value_t v) { if (is_date_instance(v)) { ant_value_t t = js_get_slot(js_as_obj(v), SLOT_DATA); return (vtype(t) == kTypeNumber) ? js_getnum(t) / 1000.0 : 0.0; } return js_to_number(js, v);}
static ant_value_t builtin_fs_utimesSync(ant_params_t) { if (nargs < 3) return js_mkerr(js, "utimesSync() requires path, atime, and mtime"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "utimesSync() path must be a string");
size_t path_len = 0; const char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string");
char *path_cstr = strndup(path, path_len); if (!path_cstr) return js_mkerr(js, "Out of memory");
double atime = fs_time_arg_to_seconds(js, args[1]); double mtime = fs_time_arg_to_seconds(js, args[2]);
uv_fs_t req; int rc = uv_fs_utime(NULL, &req, path_cstr, atime, mtime, NULL); uv_fs_req_cleanup(&req);
if (rc < 0) { ant_value_t err = js_mkerr(js, "utimesSync %s: %s", path_cstr, uv_strerror(rc)); free(path_cstr); return err; }
free(path_cstr); return js_mkundef();}
static ant_value_t builtin_fs_utimes(ant_params_t) { return builtin_fs_utimesSync(js, args, nargs, js_mkundef());}
static ant_value_t builtin_fs_futimesSync(ant_params_t) { if (nargs < 3) return js_mkerr(js, "futimesSync() requires fd, atime, and mtime"); int fd = (int)js_to_number(js, args[0]); double atime = fs_time_arg_to_seconds(js, args[1]); double mtime = fs_time_arg_to_seconds(js, args[2]);
uv_fs_t req; int rc = uv_fs_futime(NULL, &req, fd, atime, mtime, NULL); uv_fs_req_cleanup(&req);
if (rc < 0) return js_mkerr(js, "futimesSync: %s", uv_strerror(rc)); return js_mkundef();}
static ant_value_t builtin_fs_futimes(ant_params_t) { return builtin_fs_futimesSync(js, args, nargs, js_mkundef());}
static ant_value_t builtin_fs_truncateSync(ant_params_t) { if (nargs < 1) return js_mkerr(js, "truncateSync() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "truncateSync() path must be a string");
size_t path_len = 0; const char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string");
char *path_cstr = strndup(path, path_len); if (!path_cstr) return js_mkerr(js, "Out of memory");
int64_t len = 0; if (nargs >= 2 && vtype(args[1]) != kTypeUndefined) len = (int64_t)js_to_number(js, args[1]);
int rc;#ifdef _WIN32 uv_fs_t req; rc = uv_fs_open(NULL, &req, path_cstr, O_WRONLY, 0, NULL); if (rc >= 0) { uv_file fd = (uv_file)rc; uv_fs_req_cleanup(&req); rc = uv_fs_ftruncate(NULL, &req, fd, len, NULL); uv_fs_req_cleanup(&req); uv_fs_t close_req; uv_fs_close(NULL, &close_req, fd, NULL); uv_fs_req_cleanup(&close_req); } else uv_fs_req_cleanup(&req);#else rc = truncate(path_cstr, (off_t)len); if (rc != 0) rc = -errno;#endif
if (rc < 0) { ant_value_t err = fs_mk_uv_error(js, rc, "truncate", path_cstr, NULL); free(path_cstr); return err; }
free(path_cstr); return js_mkundef();}
static ant_value_t builtin_fs_ftruncateSync(ant_params_t) { if (nargs < 1) return js_mkerr(js, "ftruncateSync() requires an fd argument"); if (vtype(args[0]) != kTypeNumber) return js_mkerr(js, "ftruncateSync() fd must be a number");
int fd = (int)js_getnum(args[0]); int64_t len = 0; if (nargs >= 2 && vtype(args[1]) != kTypeUndefined) len = (int64_t)js_to_number(js, args[1]);
uv_fs_t req; int rc = uv_fs_ftruncate(NULL, &req, fd, len, NULL); uv_fs_req_cleanup(&req);
if (rc < 0) return fs_mk_uv_error(js, rc, "ftruncate", NULL, NULL); return js_mkundef();}
static ant_value_t builtin_fs_fsyncSync(ant_params_t) { if (nargs < 1) return js_mkerr(js, "fsyncSync() requires an fd argument"); if (vtype(args[0]) != kTypeNumber) return js_mkerr(js, "fsyncSync() fd must be a number");
int fd = (int)js_getnum(args[0]); uv_fs_t req; int rc = uv_fs_fsync(js->loop, &req, fd, NULL); uv_fs_req_cleanup(&req);
if (rc < 0) return fs_mk_uv_error(js, rc, "fsync", NULL, NULL); return js_mkundef();}
static ant_value_t builtin_fs_appendFileSync(ant_params_t) { return fs_write_file_sync_impl(js, args, nargs, "appendFileSync", FS_APPEND_FLAGS);}
static ant_value_t builtin_fs_appendFile(ant_params_t) { ant_value_t promise = js_mkpromise(js); ant_value_t result = fs_write_file_sync_impl(js, args, nargs, "appendFile", FS_APPEND_FLAGS); if (is_err(result)) js_reject_promise(js, promise, result); else js_resolve_promise(js, promise, js_mkundef()); return promise;}
static ant_value_t builtin_fs_writeFile(ant_params_t) { if (nargs < 2) return js_mkerr(js, "writeFile() requires path and data arguments");
fs_write_options_t opts = { FS_WRITE_FLAGS, 0666 }; ant_value_t opts_result = fs_parse_write_options(js, nargs > 2 ? args[2] : js_mkundef(), &opts); if (is_err(opts_result)) return opts_result;
args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "writeFile() path must be a string"); size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get arguments"); fs_write_data_t write_data; ant_value_t data_result = fs_get_write_data_arg(js, args[1], "writeFile", &write_data); if (is_err(data_result)) return data_result;
fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory"); req->uv_req.loop = js->loop; req->op_type = FS_OP_WRITE; req->promise = js_mkpromise(js); req->path = strndup(path, path_len); req->data = malloc(write_data.len > 0 ? write_data.len : 1); if (!req->data) { free(req->path); free(req); return js_mkerr(js, "Out of memory"); } if (write_data.len > 0) memcpy(req->data, write_data.data, write_data.len); req->data_len = write_data.len; req->uv_req.data = req; Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_open(js->loop, &req->uv_req, req->path, opts.flags, opts.mode, on_open_for_write); if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); } return req->promise;}
static ant_value_t builtin_fs_unlinkSync(ant_params_t) { if (nargs < 1) return js_mkerr(js, "unlinkSync() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "unlinkSync() path must be a string"); size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); char *path_cstr = strndup(path, path_len); if (!path_cstr) return js_mkerr(js, "Out of memory"); int result = unlink(path_cstr); if (result != 0) { ant_value_t err = fs_mk_errno_error(js, errno, "unlink", path_cstr, NULL); free(path_cstr); return err; } free(path_cstr); return js_mkundef();}
static ant_value_t builtin_fs_unlink(ant_params_t) { if (nargs < 1) return js_mkerr(js, "unlink() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "unlink() path must be a string"); size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory"); req->uv_req.loop = js->loop; req->op_type = FS_OP_UNLINK; req->promise = js_mkpromise(js); req->path = strndup(path, path_len); req->uv_req.data = req; Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_unlink(js->loop, &req->uv_req, req->path, on_unlink_complete); if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); } return req->promise;}
static ant_value_t builtin_fs_mkdirSync(ant_params_t) { if (nargs < 1) return js_mkerr(js, "mkdirSync() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "mkdirSync() path must be a string"); size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); int mode = 0755; int recursive = 0; if (nargs < 2) goto do_mkdir; switch (vtype(args[1])) { case kTypeNumber: mode = (int)js_getnum(args[1]); break; case kTypeObject: { ant_value_t opt = args[1]; recursive = js_get(js, opt, "recursive") == js_true; ant_value_t mode_val = js_get(js, opt, "mode"); if (vtype(mode_val) == kTypeNumber) mode = (int)js_getnum(mode_val); break; } default: break; } do_mkdir: char *path_cstr = strndup(path, path_len); if (!path_cstr) return js_mkerr(js, "Out of memory"); int result; if (recursive) { result = mkdirp(path_cstr, (mode_t)mode); } else {#ifdef _WIN32 (void)mode; result = _mkdir(path_cstr);#else result = mkdir(path_cstr, (mode_t)mode);#endif } if (result != 0) { ant_value_t err = fs_mk_errno_error(js, errno, "mkdir", path_cstr, NULL); free(path_cstr); return err; } free(path_cstr); return js_mkundef();}
static ant_value_t builtin_fs_mkdir(ant_params_t) { if (nargs < 1) return js_mkerr(js, "mkdir() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "mkdir() path must be a string"); size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); int mode = 0755; int recursive = 0; if (nargs >= 2) { switch (vtype(args[1])) { case kTypeNumber: mode = (int)js_getnum(args[1]); break; case kTypeObject: { ant_value_t opt = args[1]; recursive = js_get(js, opt, "recursive") == js_true; ant_value_t mode_val = js_get(js, opt, "mode"); if (vtype(mode_val) == kTypeNumber) mode = (int)js_getnum(mode_val); break; } default: break; } }
if (recursive) { ant_value_t promise = js_mkpromise(js); char *path_cstr = strndup(path, path_len); if (!path_cstr) return js_mkerr(js, "Out of memory"); int result = mkdirp(path_cstr, (mode_t)mode); free(path_cstr); if (result != 0) { ant_value_t err = js_mkerr(js, "Failed to create directory: %s", strerror(errno)); js_reject_promise(js, promise, err); } else js_resolve_promise(js, promise, js_mkundef()); return promise; }
fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory");
req->uv_req.loop = js->loop; req->op_type = FS_OP_MKDIR; req->promise = js_mkpromise(js); req->path = strndup(path, path_len); req->recursive = recursive; req->uv_req.data = req; Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_mkdir(js->loop, &req->uv_req, req->path, mode, on_mkdir_complete); if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); } return req->promise;}
static ant_value_t builtin_fs_mkdtempSync(ant_params_t) { if (nargs > 0) { args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; } if (nargs < 1 || vtype(args[0]) != kTypeString) return js_mkerr(js, "mkdtempSync() requires a prefix string");
size_t prefix_len; const char *prefix = js_getstr(js, args[0], &prefix_len); if (!prefix) return js_mkerr(js, "Failed to get prefix string");
size_t tpl_len = prefix_len + 6; char *tpl = malloc(tpl_len + 1); if (!tpl) return js_mkerr(js, "Out of memory");
memcpy(tpl, prefix, prefix_len); memcpy(tpl + prefix_len, "XXXXXX", 6); tpl[tpl_len] = '\0';
char *result = mkdtemp(tpl); if (!result) { free(tpl); return js_mkerr(js, "mkdtempSync failed: %s", strerror(errno)); }
ant_value_t ret = fs_path_result(js, result, strlen(result), nargs > 1 && fs_buffer_encoding(js, args[1])); free(tpl); return ret;}
static ant_value_t builtin_fs_mkdtemp(ant_params_t) { if (nargs > 0) { args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; } if (nargs < 1 || vtype(args[0]) != kTypeString) return js_mkerr(js, "mkdtemp() requires a prefix string");
size_t prefix_len; const char *prefix = js_getstr(js, args[0], &prefix_len); if (!prefix) return js_mkerr(js, "Failed to get prefix string");
size_t tpl_len = prefix_len + 6; char *tpl = malloc(tpl_len + 1); if (!tpl) return js_mkerr(js, "Out of memory");
memcpy(tpl, prefix, prefix_len); memcpy(tpl + prefix_len, "XXXXXX", 6); tpl[tpl_len] = '\0';
fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) { free(tpl); return js_mkerr(js, "Out of memory"); }
req->uv_req.loop = js->loop; req->op_type = FS_OP_MKDTEMP; req->buffer_encoding = nargs > 1 && fs_buffer_encoding(js, args[1]); req->promise = js_mkpromise(js); req->path = tpl; req->uv_req.data = req;
Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_mkdtemp(js->loop, &req->uv_req, req->path, on_mkdtemp_complete);
if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); }
return req->promise;}
static ant_value_t builtin_fs_rmdirSync(ant_params_t) { if (nargs < 1) return js_mkerr(js, "rmdirSync() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "rmdirSync() path must be a string"); size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); char *path_cstr = strndup(path, path_len); if (!path_cstr) return js_mkerr(js, "Out of memory"); #ifdef _WIN32 int result = _rmdir(path_cstr);#else int result = rmdir(path_cstr);#endif if (result != 0) { ant_value_t err = fs_mk_errno_error(js, errno, "rmdir", path_cstr, NULL); free(path_cstr); return err; } free(path_cstr); return js_mkundef();}
static ant_value_t builtin_fs_rmdir(ant_params_t) { if (nargs < 1) return js_mkerr(js, "rmdir() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "rmdir() path must be a string"); size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory"); req->uv_req.loop = js->loop; req->op_type = FS_OP_RMDIR; req->promise = js_mkpromise(js); req->path = strndup(path, path_len); req->uv_req.data = req; Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_rmdir(js->loop, &req->uv_req, req->path, on_rmdir_complete); if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); } return req->promise;}
static ant_value_t builtin_fs_rmSync(ant_params_t) { return fs_rm_impl(js, args, nargs, false);}
static ant_value_t builtin_fs_rm(ant_params_t) { return fs_rm_impl(js, args, nargs, true);}
static ant_value_t stat_mode_is(ant_t *js, mode_t type) { ant_value_t mode_val = js_get_slot(js_getthis(js), SLOT_DATA); if (vtype(mode_val) != kTypeNumber) return js_false; return js_bool(((mode_t)js_getnum(mode_val) & S_IFMT) == type);}
static ant_value_t dirent_type_is(ant_t *js, uv_dirent_type_t type) { ant_value_t type_val = js_get_slot(js_getthis(js), SLOT_DATA); return js_bool(vtype(type_val) == kTypeNumber && (int)js_getnum(type_val) == (int)type);}
#define FS_FILE_TYPE(name, mode, dirent) \ static ant_value_t stat_##name(ant_params_t) { return stat_mode_is(js, mode); } \ static ant_value_t dirent_##name(ant_params_t) { return dirent_type_is(js, dirent); }#include "fs/file_types.h"
static const ant_cfunc_meta_t stat_methods[] = { #define FS_FILE_TYPE(name, mode, dirent) { stat_##name, #name, 0, 0 }, #include "fs/file_types.h"};
static const ant_cfunc_meta_t dirent_methods[] = { #define FS_FILE_TYPE(name, mode, dirent) { dirent_##name, #name, 0, 0 }, #include "fs/file_types.h"};
static ant_value_t stats_ctor(ant_params_t) { ant_value_t obj = Ant_Object_CreateBare(js); js_set_proto_init(obj, js_instance_proto_from_new_target(js, js->builtins.stats_proto, call_new_target)); return obj;}
static ant_value_t dirent_ctor(ant_params_t) { if (!is_object_type(call_new_target)) return js_mkerr_typed(js, JS_ERR_TYPE, "Class constructor Dirent cannot be invoked without 'new'"); ant_value_t obj = Ant_Object_CreateBare(js); js_set_proto_init(obj, js_instance_proto_from_new_target(js, js->builtins.dirent_proto, call_new_target)); js_set(js, obj, "name", nargs > 0 ? args[0] : js_mkundef()); js_set(js, obj, "parentPath", nargs > 2 ? args[2] : js_mkundef()); if (nargs > 1 && vtype(args[1]) == kTypeNumber) js_set_slot(obj, SLOT_DATA, args[1]); return obj;}
static ant_value_t create_stats_object(ant_t *js, struct stat *st) { return fs_stats_object_from_posix(js, st);}
static const char *errno_to_code(int err_num) {switch (err_num) { case ENOENT: return "ENOENT"; case EACCES: return "EACCES"; case ENOTDIR: return "ENOTDIR"; case ELOOP: return "ELOOP"; case ENAMETOOLONG: return "ENAMETOOLONG"; case EOVERFLOW: return "EOVERFLOW"; case EROFS: return "EROFS"; case ETXTBSY: return "ETXTBSY"; case EEXIST: return "EEXIST"; case ENOTEMPTY: return "ENOTEMPTY"; case EISDIR: return "EISDIR"; case EBUSY: return "EBUSY"; case EINVAL: return "EINVAL"; case EPERM: return "EPERM"; case EIO: return "EIO"; default: return "UNKNOWN";}}
static ant_value_t fs_mk_syscall_error( ant_t *js, const char *code, double err_num, const char *message, const char *syscall, const char *path, const char *dest) { ant_value_t props = Ant_Object_CreateBare(js);
if (!code) code = "UNKNOWN"; if (!message) message = "Unknown error";
js_set(js, props, "code", js_mkstr(js, code, strlen(code))); js_set(js, props, "errno", js_mknum(err_num)); if (syscall) js_set(js, props, "syscall", js_mkstr(js, syscall, strlen(syscall))); if (path) js_set(js, props, "path", js_mkstr(js, path, strlen(path))); if (dest) js_set(js, props, "dest", js_mkstr(js, dest, strlen(dest)));
if (path && dest) return js_mkerr_props( js, JS_ERR_GENERIC, props, "%s: %s, %s '%s' -> '%s'", code, message, syscall, path, dest ); if (path) return js_mkerr_props( js, JS_ERR_GENERIC, props, "%s: %s, %s '%s'", code, message, syscall, path ); return js_mkerr_props( js, JS_ERR_GENERIC, props, "%s: %s, %s", code, message, syscall );}
static ant_value_t fs_mk_errno_error( ant_t *js, int err_num, const char *syscall, const char *path, const char *dest) { int uv_code = uv_translate_sys_error(err_num); if (uv_code == 0) uv_code = -err_num; return fs_mk_syscall_error( js, errno_to_code(err_num), (double)uv_code, uv_strerror(uv_code), syscall, path, dest );}
static ant_value_t fs_mk_uv_error( ant_t *js, int uv_code, const char *syscall, const char *path, const char *dest) { return fs_mk_syscall_error( js, uv_err_name(uv_code), (double)uv_code, uv_strerror(uv_code), syscall, path, dest );}
static ant_value_t builtin_fs_statSync(ant_params_t) { if (nargs < 1) return js_mkerr(js, "statSync() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "statSync() path must be a string"); ant_value_t throw_option = nargs > 1 && is_object_type(args[1]) ? js_get(js, args[1], "throwIfNoEntry") : js_mkundef(); if (is_err(throw_option)) return throw_option; bool no_throw = throw_option == js_false;
size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); char *path_cstr = strndup(path, path_len); if (!path_cstr) return js_mkerr(js, "Out of memory"); struct stat st; int result = stat(path_cstr, &st); if (result != 0) { if (no_throw && (errno == ENOENT || errno == ENOTDIR)) { free(path_cstr); return js_mkundef(); } ant_value_t err = fs_mk_errno_error(js, errno, "stat", path_cstr, NULL); free(path_cstr); return err; } free(path_cstr); return create_stats_object(js, &st);}
static ant_value_t builtin_fs_stat(ant_params_t) { if (nargs < 1) return js_mkerr(js, "stat() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "stat() path must be a string"); size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory"); req->uv_req.loop = js->loop; req->op_type = FS_OP_STAT; req->promise = js_mkpromise(js); req->path = strndup(path, path_len); req->uv_req.data = req; Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_stat(js->loop, &req->uv_req, req->path, on_stat_complete); if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); } return req->promise;}
static ant_value_t builtin_fs_lstatSync(ant_params_t) { if (nargs < 1) return js_mkerr(js, "lstatSync() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "lstatSync() path must be a string"); ant_value_t throw_option = nargs > 1 && is_object_type(args[1]) ? js_get(js, args[1], "throwIfNoEntry") : js_mkundef(); if (is_err(throw_option)) return throw_option; bool no_throw = throw_option == js_false;
size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); char *path_cstr = strndup(path, path_len); if (!path_cstr) return js_mkerr(js, "Out of memory"); uv_fs_t req; int result = uv_fs_lstat(NULL, &req, path_cstr, NULL);
if (result < 0) { if (no_throw && (result == UV_ENOENT || result == UV_ENOTDIR)) { uv_fs_req_cleanup(&req); free(path_cstr); return js_mkundef(); } ant_value_t err = fs_mk_uv_error(js, result, "lstat", path_cstr, NULL); uv_fs_req_cleanup(&req); free(path_cstr); return err; }
ant_value_t stat_obj = fs_stats_object_from_uv(js, &req.statbuf); uv_fs_req_cleanup(&req); free(path_cstr); return stat_obj;}
static ant_value_t builtin_fs_lstat(ant_params_t) { if (nargs < 1) return js_mkerr(js, "lstat() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "lstat() path must be a string"); size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory"); req->uv_req.loop = js->loop; req->op_type = FS_OP_STAT; req->promise = js_mkpromise(js); req->path = strndup(path, path_len); req->uv_req.data = req; Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_lstat(js->loop, &req->uv_req, req->path, on_stat_complete); if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); } return req->promise;}
static ant_value_t builtin_fs_fstatSync(ant_params_t) { if (nargs < 1) return js_mkerr(js, "fstatSync() requires an fd argument"); if (vtype(args[0]) != kTypeNumber) return js_mkerr(js, "fstatSync() fd must be a number");
uv_file fd = (uv_file)(int)js_getnum(args[0]); uv_fs_t req; int result = uv_fs_fstat(NULL, &req, fd, NULL);
if (result < 0) { ant_value_t err = fs_mk_uv_error(js, result, "fstat", NULL, NULL); uv_fs_req_cleanup(&req); return err; }
ant_value_t stat_obj = fs_stats_object_from_uv(js, &req.statbuf); uv_fs_req_cleanup(&req); return stat_obj;}
static ant_value_t builtin_fs_fstat(ant_params_t) { if (nargs < 1) return js_mkerr(js, "fstat() requires an fd argument"); if (vtype(args[0]) != kTypeNumber) return js_mkerr(js, "fstat() fd must be a number");
fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory");
req->uv_req.loop = js->loop; req->op_type = FS_OP_STAT; req->promise = js_mkpromise(js); req->fd = (uv_file)(int)js_getnum(args[0]); req->uv_req.data = req;
Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_fstat(js->loop, &req->uv_req, req->fd, on_stat_complete);
if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); }
return req->promise;}
static ant_value_t builtin_fs_existsSync(ant_params_t) { if (nargs < 1) return js_mkerr(js, "existsSync() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "existsSync() path must be a string"); size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); char *path_cstr = strndup(path, path_len); if (!path_cstr) return js_mkerr(js, "Out of memory"); struct stat st; int result = stat(path_cstr, &st); free(path_cstr); return js_bool(result == 0);}
static ant_value_t builtin_fs_exists(ant_params_t) { if (nargs < 1) return js_mkerr(js, "exists() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "exists() path must be a string"); size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory"); req->uv_req.loop = js->loop; req->op_type = FS_OP_EXISTS; req->promise = js_mkpromise(js); req->path = strndup(path, path_len); req->uv_req.data = req; Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_stat(js->loop, &req->uv_req, req->path, on_exists_complete); if (result < 0) { req->completed = 1; js_resolve_promise(js, req->promise, js_false); Ant_List_Remove(req); free_fs_request(req); } return req->promise;}
static ant_value_t builtin_fs_accessSync(ant_params_t) { if (nargs < 1) return js_mkerr(js, "accessSync() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "accessSync() path must be a string"); size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); int mode = F_OK; if (nargs >= 2 && vtype(args[1]) == kTypeNumber) { mode = (int)js_getnum(args[1]); } char *path_cstr = strndup(path, path_len); if (!path_cstr) return js_mkerr(js, "Out of memory"); int result = access(path_cstr, mode); if (result != 0) { ant_value_t err = fs_mk_errno_error(js, errno, "access", path_cstr, NULL); free(path_cstr); return err; } free(path_cstr); return js_mkundef();}
static ant_value_t builtin_fs_chmodSync(ant_params_t) { if (nargs < 1) return js_mkerr(js, "chmodSync() requires a path argument"); if (nargs < 2) return js_mkerr(js, "chmodSync() requires a mode argument");
ant_value_t path_val = args[0] = fs_coerce_path(js, args[0]); if (is_err(path_val)) return path_val; if (vtype(path_val) != kTypeString) return js_mkerr(js, "chmodSync() path must be a string or URL");
mode_t mode = 0; if (!fs_parse_mode(js, args[1], &mode)) { return js_mkerr(js, "chmodSync() mode must be a number or octal string"); }
size_t path_len = 0; char *path = js_getstr(js, path_val, &path_len); if (!path) return js_mkerr(js, "Failed to get path string");
char *path_cstr = strndup(path, path_len); if (!path_cstr) return js_mkerr(js, "Out of memory");
uv_fs_t req; int result = uv_fs_chmod(js->loop, &req, path_cstr, mode, NULL);
if (result < 0) { ant_value_t err = fs_mk_uv_error(js, result, "chmod", path_cstr, NULL); uv_fs_req_cleanup(&req); free(path_cstr); return err; }
uv_fs_req_cleanup(&req); free(path_cstr); return js_mkundef();}
static ant_value_t builtin_fs_chmod(ant_params_t) { if (nargs < 1) return js_mkerr(js, "chmod() requires a path argument"); if (nargs < 2) return js_mkerr(js, "chmod() requires a mode argument");
ant_value_t path_val = args[0] = fs_coerce_path(js, args[0]); if (is_err(path_val)) return path_val; if (vtype(path_val) != kTypeString) return js_mkerr(js, "chmod() path must be a string or URL");
mode_t mode = 0; if (!fs_parse_mode(js, args[1], &mode)) { return js_mkerr(js, "chmod() mode must be a number or octal string"); }
size_t path_len = 0; char *path = js_getstr(js, path_val, &path_len); if (!path) return js_mkerr(js, "Failed to get path string");
fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory");
req->uv_req.loop = js->loop; req->op_type = FS_OP_CHMOD; req->promise = js_mkpromise(js); req->path = strndup(path, path_len); req->uv_req.data = req;
if (!req->path) { free_fs_request(req); return js_mkerr(js, "Out of memory"); }
Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_chmod(js->loop, &req->uv_req, req->path, mode, on_chmod_complete);
if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); }
return req->promise;}
static ant_value_t builtin_fs_access(ant_params_t) { if (nargs < 1) return js_mkerr(js, "access() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "access() path must be a string"); size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); int mode = F_OK; if (nargs >= 2 && vtype(args[1]) == kTypeNumber) { mode = (int)js_getnum(args[1]); } fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory"); req->uv_req.loop = js->loop; req->op_type = FS_OP_ACCESS; req->promise = js_mkpromise(js); req->path = strndup(path, path_len); req->uv_req.data = req; Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_access(js->loop, &req->uv_req, req->path, mode, on_access_complete); if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); } return req->promise;}
static ant_value_t builtin_fs_realpathSync(ant_params_t) { if (nargs < 1) return js_mkerr(js, "realpathSync() requires a path argument");
ant_value_t path_val = args[0] = fs_coerce_path(js, args[0]); if (is_err(path_val)) return path_val; if (vtype(path_val) != kTypeString) return js_mkerr(js, "realpathSync() path must be a string");
size_t path_len = 0; const char *path = js_getstr(js, path_val, &path_len); if (!path) return js_mkerr(js, "Failed to get path string");
char *resolved = realpath(path, NULL); if (!resolved) return js_mkerr(js, "realpathSync failed for '%s'", path);
ant_value_t result = fs_path_result(js, resolved, strlen(resolved), nargs > 1 && fs_buffer_encoding(js, args[1])); free(resolved); return result;}
static ant_value_t builtin_fs_realpath(ant_params_t) { if (nargs < 1) return js_mkerr(js, "realpath() requires a path argument");
ant_value_t path_val = args[0] = fs_coerce_path(js, args[0]); if (is_err(path_val)) return path_val; if (vtype(path_val) != kTypeString) return js_mkerr(js, "realpath() path must be a string");
size_t path_len = 0; const char *path = js_getstr(js, path_val, &path_len); if (!path) return js_mkerr(js, "Failed to get path string");
fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory");
req->uv_req.loop = js->loop; req->op_type = FS_OP_REALPATH; req->buffer_encoding = nargs > 1 && fs_buffer_encoding(js, args[1]); req->promise = js_mkpromise(js); req->path = strndup(path, path_len); req->uv_req.data = req;
if (!req->path) { free_fs_request(req); return js_mkerr(js, "Out of memory"); }
Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_realpath(js->loop, &req->uv_req, req->path, on_realpath_complete);
if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); }
return req->promise;}
static ant_value_t builtin_fs_readlinkSync(ant_params_t) { if (nargs < 1) return js_mkerr(js, "readlinkSync() requires a path argument");
ant_value_t path_val = args[0] = fs_coerce_path(js, args[0]); if (is_err(path_val)) return path_val; if (vtype(path_val) != kTypeString) return js_mkerr(js, "readlinkSync() path must be a string");
size_t path_len = 0; const char *path = js_getstr(js, path_val, &path_len); if (!path) return js_mkerr(js, "Failed to get path string");
char *path_cstr = strndup(path, path_len); if (!path_cstr) return js_mkerr(js, "Out of memory");
uv_fs_t req; int result = uv_fs_readlink(NULL, &req, path_cstr, NULL);
if (result < 0 || !req.ptr) { ant_value_t err = fs_mk_uv_error(js, result, "readlink", path_cstr, NULL); uv_fs_req_cleanup(&req); free(path_cstr); return err; }
ant_value_t link = fs_path_result(js, (const char *)req.ptr, strlen((const char *)req.ptr), nargs > 1 && fs_buffer_encoding(js, args[1])); uv_fs_req_cleanup(&req); free(path_cstr); return link;}
static ant_value_t fs_parse_symlink_type( ant_t *js, ant_value_t type_val, const char *fn_name, int *flags) { *flags = 0; if (vtype(type_val) == kTypeUndefined || vtype(type_val) == kTypeNull) return js_mkundef();
if (vtype(type_val) == kTypeString) { size_t type_len = 0; const char *type = js_getstr(js, type_val, &type_len);
if (type && type_len == 4 && memcmp(type, "file", 4) == 0) return js_mkundef(); if (type && type_len == 3 && memcmp(type, "dir", 3) == 0) { #ifdef _WIN32 *flags = UV_FS_SYMLINK_DIR; #endif return js_mkundef(); } if (type && type_len == 8 && memcmp(type, "junction", 8) == 0) { #ifdef _WIN32 *flags = UV_FS_SYMLINK_JUNCTION; #endif return js_mkundef(); } }
return js_mkerr_typed( js,JS_ERR_TYPE, "%s() type must be 'dir', 'file', 'junction', null, or undefined", fn_name );}
static ant_value_t builtin_fs_symlinkSync(ant_params_t) { if (nargs < 2) return js_mkerr(js, "symlinkSync() requires target and path arguments");
ant_value_t target_val = args[0] = fs_coerce_path(js, args[0]); if (is_err(target_val)) return target_val; ant_value_t path_val = args[1] = fs_coerce_path(js, args[1]); if (is_err(path_val)) return path_val; if (vtype(target_val) != kTypeString || vtype(path_val) != kTypeString) { return js_mkerr(js, "symlinkSync() target and path must be strings"); }
size_t target_len = 0; size_t path_len = 0; const char *target = js_getstr(js, target_val, &target_len); const char *path = js_getstr(js, path_val, &path_len); if (!target || !path) return js_mkerr(js, "Failed to get symlink path strings");
char *target_cstr = strndup(target, target_len); char *path_cstr = strndup(path, path_len); if (!target_cstr || !path_cstr) { free(target_cstr); free(path_cstr); return js_mkerr(js, "Out of memory"); }
int flags = 0;#ifdef _WIN32 if (nargs > 2 && vtype(args[2]) == kTypeString) { size_t type_len = 0; const char *type = js_getstr(js, args[2], &type_len); if (type && type_len == 3 && memcmp(type, "dir", 3) == 0) { flags = UV_FS_SYMLINK_DIR; } else if (type && type_len == 8 && memcmp(type, "junction", 8) == 0) { flags = UV_FS_SYMLINK_JUNCTION; } }#endif
uv_fs_t req; int result = uv_fs_symlink(NULL, &req, target_cstr, path_cstr, flags, NULL); uv_fs_req_cleanup(&req); if (result < 0) { ant_value_t err = fs_mk_uv_error(js, result, "symlink", target_cstr, path_cstr); free(target_cstr); free(path_cstr); return err; }
free(target_cstr); free(path_cstr); return js_mkundef();}
static ant_value_t builtin_fs_symlink(ant_params_t) { if (nargs < 2) return js_mkerr(js, "symlink() requires target and path arguments");
ant_value_t target_val = args[0] = fs_coerce_path(js, args[0]); if (is_err(target_val)) return target_val; ant_value_t path_val = args[1] = fs_coerce_path(js, args[1]); if (is_err(path_val)) return path_val; if (vtype(target_val) != kTypeString || vtype(path_val) != kTypeString) { return js_mkerr(js, "symlink() target and path must be strings"); }
int flags = 0; ant_value_t type_result = fs_parse_symlink_type( js, nargs > 2 ? args[2] : js_mkundef(), "symlink", &flags ); if (is_err(type_result)) return type_result;
size_t target_len = 0; size_t path_len = 0; const char *target = js_getstr(js, target_val, &target_len); const char *path = js_getstr(js, path_val, &path_len); if (!target || !path) return js_mkerr(js, "Failed to get symlink path strings");
fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory");
req->uv_req.loop = js->loop; req->op_type = FS_OP_SYMLINK; req->promise = js_mkpromise(js); ant_value_t promise = req->promise; req->path = strndup(target, target_len); req->path2 = strndup(path, path_len); req->uv_req.data = req;
if (!req->path || !req->path2) { free_fs_request(req); return js_mkerr(js, "Out of memory"); }
Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_symlink( js->loop, &req->uv_req, req->path, req->path2, flags, on_symlink_complete );
if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); }
return promise;}
static ant_value_t builtin_fs_linkSync(ant_params_t) { if (nargs < 2) return js_mkerr(js, "linkSync() requires existingPath and newPath arguments");
ant_value_t existing_val = args[0] = fs_coerce_path(js, args[0]); if (is_err(existing_val)) return existing_val; ant_value_t new_val = args[1] = fs_coerce_path(js, args[1]); if (is_err(new_val)) return new_val; if (vtype(existing_val) != kTypeString || vtype(new_val) != kTypeString) { return js_mkerr(js, "linkSync() existingPath and newPath must be strings"); }
size_t existing_len = 0; size_t new_len = 0; const char *existing = js_getstr(js, existing_val, &existing_len); const char *new_path = js_getstr(js, new_val, &new_len); if (!existing || !new_path) return js_mkerr(js, "Failed to get link path strings");
char *existing_cstr = strndup(existing, existing_len); char *new_cstr = strndup(new_path, new_len); if (!existing_cstr || !new_cstr) { free(existing_cstr); free(new_cstr); return js_mkerr(js, "Out of memory"); }
uv_fs_t req; int result = uv_fs_link(NULL, &req, existing_cstr, new_cstr, NULL); uv_fs_req_cleanup(&req); ant_value_t out = result < 0 ? fs_mk_uv_error(js, result, "link", existing_cstr, new_cstr) : js_mkundef();
free(existing_cstr); free(new_cstr); return out;}
static ant_value_t builtin_fs_link(ant_params_t) { if (nargs < 2) return js_mkerr(js, "link() requires existingPath and newPath arguments");
ant_value_t existing_val = args[0] = fs_coerce_path(js, args[0]); if (is_err(existing_val)) return existing_val; ant_value_t new_val = args[1] = fs_coerce_path(js, args[1]); if (is_err(new_val)) return new_val; if (vtype(existing_val) != kTypeString || vtype(new_val) != kTypeString) { return js_mkerr(js, "link() existingPath and newPath must be strings"); }
size_t existing_len = 0; size_t new_len = 0; const char *existing = js_getstr(js, existing_val, &existing_len); const char *new_path = js_getstr(js, new_val, &new_len); if (!existing || !new_path) return js_mkerr(js, "Failed to get link path strings");
fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory");
req->uv_req.loop = js->loop; req->op_type = FS_OP_LINK; req->promise = js_mkpromise(js); ant_value_t promise = req->promise; req->path = strndup(existing, existing_len); req->path2 = strndup(new_path, new_len); req->uv_req.data = req;
if (!req->path || !req->path2) { free_fs_request(req); return js_mkerr(js, "Out of memory"); }
Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_link(js->loop, &req->uv_req, req->path, req->path2, on_link_complete);
if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); }
return promise;}
static ant_value_t builtin_fs_readlink(ant_params_t) { if (nargs < 1) return js_mkerr(js, "readlink() requires a path argument");
ant_value_t path_val = args[0] = fs_coerce_path(js, args[0]); if (is_err(path_val)) return path_val; if (vtype(path_val) != kTypeString) return js_mkerr(js, "readlink() path must be a string");
size_t path_len = 0; const char *path = js_getstr(js, path_val, &path_len); if (!path) return js_mkerr(js, "Failed to get path string");
fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory");
req->uv_req.loop = js->loop; req->op_type = FS_OP_REALPATH; req->buffer_encoding = nargs > 1 && fs_buffer_encoding(js, args[1]); req->promise = js_mkpromise(js); req->path = strndup(path, path_len); req->uv_req.data = req;
if (!req->path) { free_fs_request(req); return js_mkerr(js, "Out of memory"); }
Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_readlink(js->loop, &req->uv_req, req->path, on_realpath_complete);
if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); }
return req->promise;}
#ifdef _WIN32#define FS_REL_SEP '\\'#else#define FS_REL_SEP '/'#endif
typedef struct { char *name; uv_dirent_type_t type;} fs_walk_entry_t;
typedef struct { char *rel; size_t first; size_t count; size_t parent; uint64_t dev, ino; bool has_id;} fs_walk_dir_t;
typedef struct { char *root; fs_walk_dir_t *dirs; fs_walk_entry_t *entries; size_t dir_len, dir_cap; size_t entry_len, entry_cap; size_t error_dir; int error;} fs_walk_t;
static void fs_walk_free(fs_walk_t *w) { for (size_t i = 0; i < w->dir_len; i++) free(w->dirs[i].rel); for (size_t i = 0; i < w->entry_len; i++) free(w->entries[i].name); free(w->dirs); free(w->entries); free(w->root); memset(w, 0, sizeof(*w));}
static bool fs_walk_push_dir(fs_walk_t *w, char *rel, size_t parent, const uv_stat_t *id) { if (w->dir_len == w->dir_cap) { size_t cap = w->dir_cap ? w->dir_cap * 2 : 16; fs_walk_dir_t *grown = realloc(w->dirs, cap * sizeof(*grown)); if (!grown) return false; w->dirs = grown; w->dir_cap = cap; } w->dirs[w->dir_len++] = (fs_walk_dir_t){ .rel = rel, .parent = parent, .dev = id ? id->st_dev : 0, .ino = id ? id->st_ino : 0, .has_id = id != NULL, }; return true;}
static bool fs_walk_push_entry(fs_walk_t *w, const char *name, uv_dirent_type_t type) { if (w->entry_len == w->entry_cap) { size_t cap = w->entry_cap ? w->entry_cap * 2 : 64; fs_walk_entry_t *grown = realloc(w->entries, cap * sizeof(*grown)); if (!grown) return false; w->entries = grown; w->entry_cap = cap; } char *copy = strdup(name); if (!copy) return false; w->entries[w->entry_len++] = (fs_walk_entry_t){ .name = copy, .type = type }; return true;}
static char *fs_walk_rel(const char *prefix, const char *name) { if (!prefix) return strdup(name); size_t prefix_len = strlen(prefix), name_len = strlen(name); char *rel = malloc(prefix_len + name_len + 2); if (!rel) return NULL; memcpy(rel, prefix, prefix_len); rel[prefix_len] = FS_REL_SEP; memcpy(rel + prefix_len + 1, name, name_len + 1); return rel;}
static bool fs_walk_is_dir(const char *dir, const uv_dirent_t *dirent, uv_stat_t *id, bool *has_id) { *has_id = false; if (dirent->type == UV_DIRENT_DIR) return true; if (dirent->type != UV_DIRENT_LINK && dirent->type != UV_DIRENT_UNKNOWN) return false;
char *child = fs_join_path(dir, dirent->name); if (!child) return false;
uv_fs_t req; bool is_dir = uv_fs_stat(NULL, &req, child, NULL) == 0 && (req.statbuf.st_mode & S_IFMT) == S_IFDIR; if (is_dir) { *id = req.statbuf; *has_id = true; } uv_fs_req_cleanup(&req); free(child);
return is_dir;}
static bool fs_walk_dir_id(fs_walk_t *w, size_t index) { fs_walk_dir_t *d = &w->dirs[index]; if (d->has_id) return true;
char *path = d->rel ? fs_join_path(w->root, d->rel) : strdup(w->root); if (!path) return false;
uv_fs_t req; if (uv_fs_stat(NULL, &req, path, NULL) == 0) { d->dev = req.statbuf.st_dev; d->ino = req.statbuf.st_ino; d->has_id = true; } uv_fs_req_cleanup(&req); free(path);
return d->has_id;}
static bool fs_walk_is_ancestor(fs_walk_t *w, size_t index, const uv_stat_t *id) { for (size_t i = index; i != SIZE_MAX; i = w->dirs[i].parent) { if (!fs_walk_dir_id(w, i)) continue; if (w->dirs[i].dev == id->st_dev && w->dirs[i].ino == id->st_ino) return true; } return false;}
static void fs_walk_run(fs_walk_t *w, char *root) { w->root = root; if (!fs_walk_push_dir(w, NULL, SIZE_MAX, NULL)) { w->error = UV_ENOMEM; return; }
for (size_t i = 0; i < w->dir_len && !w->error; i++) { char *dir = w->dirs[i].rel ? fs_join_path(w->root, w->dirs[i].rel) : strdup(w->root); if (!dir) { w->error = UV_ENOMEM; break; }
uv_fs_t req; int rc = uv_fs_scandir(NULL, &req, dir, 0, NULL); if (rc < 0) { uv_fs_req_cleanup(&req); free(dir); w->error = rc; w->error_dir = i; break; }
w->dirs[i].first = w->entry_len; uv_dirent_t dirent;
while (!w->error && uv_fs_scandir_next(&req, &dirent) != UV_EOF) { if (!fs_walk_push_entry(w, dirent.name, dirent.type)) { w->error = UV_ENOMEM; break; } w->dirs[i].count++;
uv_stat_t id; bool has_id; if (!fs_walk_is_dir(dir, &dirent, &id, &has_id)) continue; if (has_id && fs_walk_is_ancestor(w, i, &id)) continue;
char *rel = fs_walk_rel(w->dirs[i].rel, dirent.name); if (!rel || !fs_walk_push_dir(w, rel, i, has_id ? &id : NULL)) { free(rel); w->error = UV_ENOMEM; } }
uv_fs_req_cleanup(&req); free(dir); }}
static ant_value_t fs_walk_dir_path(ant_t *js, const fs_walk_t *w, size_t index) { const char *rel = w->dirs[index].rel; if (!rel) return js_mkstr(js, w->root, strlen(w->root)); return fs_path_join(js, w->root, rel);}
static ant_value_t fs_walk_result( ant_t *js, const fs_walk_t *w, ant_value_t root_value, bool with_file_types, bool as_buffer) { if (w->error == UV_ENOMEM) return js_mkerr(js, "Out of memory"); if (w->error) { ant_value_t dir_path = fs_walk_dir_path(js, w, w->error_dir); if (is_err(dir_path)) return dir_path; const char *path = js_getstr(js, dir_path, NULL); return fs_mk_uv_error(js, w->error, "scandir", path ? path : w->root, NULL); }
GC_ROOT_SAVE(root_mark, js); ant_value_t arr = js_mkarr(js); GC_ROOT_PIN(js, arr); ant_value_t result = arr;
for (size_t d = 0; d < w->dir_len && !is_err(result); d++) { const fs_walk_dir_t *dir = &w->dirs[d]; ant_value_t parent = js_mkundef();
if (with_file_types) { parent = dir->rel ? fs_walk_dir_path(js, w, d) : root_value; if (is_err(parent)) { result = parent; break; } } GC_ROOT_PIN(js, parent);
for (size_t i = dir->first; i < dir->first + dir->count; i++) { const fs_walk_entry_t *entry = &w->entries[i]; ant_value_t value;
if (with_file_types) value = create_dirent_object( js, entry->name, strlen(entry->name), entry->type, as_buffer, parent ); else { char *rel = fs_walk_rel(dir->rel, entry->name); value = rel ? fs_path_result(js, rel, strlen(rel), as_buffer) : js_mkerr(js, "Out of memory"); free(rel); }
if (is_err(value)) { result = value; break; } js_arr_push(js, arr, value); } }
GC_ROOT_RESTORE(js, root_mark); return result;}
typedef struct { uv_work_t work; fs_request_t *req; fs_walk_t walk;} fs_walk_job_t;
static void fs_walk_work(uv_work_t *work) { fs_walk_job_t *job = (fs_walk_job_t *)work->data; fs_walk_run(&job->walk, job->req->path2); job->req->path2 = NULL;}
static void fs_walk_after_work(uv_work_t *work, int status) { GC_UV_CALLBACK(); fs_walk_job_t *job = (fs_walk_job_t *)work->data; fs_request_t *req = job->req; ant_t *js = fs_req_isolate(req);
GC_ROOT_SAVE(root_mark, js); ant_value_t root_value = is_object_type(req->owner) ? req->owner : js_mkstr(js, req->path, strlen(req->path)); GC_ROOT_PIN(js, root_value);
ant_value_t result = status < 0 ? fs_mk_uv_error(js, status, "scandir", req->path, NULL) : fs_walk_result(js, &job->walk, root_value, req->with_file_types, req->buffer_encoding); GC_ROOT_RESTORE(js, root_mark);
if (is_err(result)) js_reject_promise(js, req->promise, js_take_thrown(js, result)); else js_resolve_promise(js, req->promise, result);
fs_walk_free(&job->walk); free(job); req->completed = 1; Ant_List_Remove(req); free_fs_request(req);}
static bool fs_readdir_recursive_option(ant_t *js, ant_value_t options) { return is_object_type(options) && js_truthy(js, js_get(js, options, "recursive"));}
static ant_value_t builtin_fs_readdirSync(ant_params_t) { if (nargs < 1) return js_mkerr(js, "readdirSync() requires a path argument"); ant_value_t original_path = args[0]; args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "readdirSync() path must be a string"); bool as_buffer = nargs > 1 && fs_buffer_encoding(js, args[1]); bool with_file_types = false; if (nargs >= 2 && vtype(args[1]) == kTypeObject) { ant_value_t wft = js_get(js, args[1], "withFileTypes"); with_file_types = js_truthy(js, wft); }
size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); char *path_cstr = strndup(path, path_len); if (!path_cstr) return js_mkerr(js, "Out of memory");
if (nargs > 1 && fs_readdir_recursive_option(js, args[1])) { fs_walk_t walk = {0}; fs_walk_run(&walk, path_cstr); GC_ROOT_SAVE(root_mark, js); ant_value_t root_value = fs_parent_path_value(original_path, args[0]); GC_ROOT_PIN(js, root_value); ant_value_t walked = fs_walk_result(js, &walk, root_value, with_file_types, as_buffer); GC_ROOT_RESTORE(js, root_mark); fs_walk_free(&walk); return walked; } uv_fs_t req; int result = uv_fs_scandir(NULL, &req, path_cstr, 0, NULL); if (result < 0) { ant_value_t err = fs_mk_uv_error(js, result, "scandir", path_cstr, NULL); uv_fs_req_cleanup(&req); free(path_cstr); return err; } free(path_cstr); GC_ROOT_SAVE(root_mark, js); ant_value_t parent = fs_parent_path_value(original_path, args[0]); GC_ROOT_PIN(js, parent); ant_value_t arr = js_mkarr(js); GC_ROOT_PIN(js, arr); uv_dirent_t dirent; while (uv_fs_scandir_next(&req, &dirent) != UV_EOF) { ant_value_t entry = with_file_types ? create_dirent_object(js, dirent.name, strlen(dirent.name), dirent.type, as_buffer, parent) : fs_path_result(js, dirent.name, strlen(dirent.name), as_buffer); if (is_err(entry)) { uv_fs_req_cleanup(&req); GC_ROOT_RESTORE(js, root_mark); return entry; } js_arr_push(js, arr, entry); } uv_fs_req_cleanup(&req); GC_ROOT_RESTORE(js, root_mark); return arr;}
static ant_value_t builtin_fs_readdir(ant_params_t) { if (nargs < 1) return js_mkerr(js, "readdir() requires a path argument"); ant_value_t original_path = args[0]; args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "readdir() path must be a string"); bool with_file_types = false; if (nargs >= 2 && vtype(args[1]) == kTypeObject) { ant_value_t wft = js_get(js, args[1], "withFileTypes"); with_file_types = js_truthy(js, wft); }
size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory"); req->uv_req.loop = js->loop; req->op_type = FS_OP_READDIR; req->buffer_encoding = nargs > 1 && fs_buffer_encoding(js, args[1]); req->with_file_types = with_file_types; req->owner = buffer_get_typedarray_data(original_path) ? original_path : js_mkundef(); req->promise = js_mkpromise(js); req->path = strndup(path, path_len); req->uv_req.data = req;
if (!req->path) { free_fs_request(req); return js_mkerr(js, "Out of memory"); }
if (nargs > 1 && fs_readdir_recursive_option(js, args[1])) { fs_walk_job_t *job = calloc(1, sizeof(fs_walk_job_t)); req->path2 = strdup(req->path); if (!job || !req->path2) { free(job); free_fs_request(req); return js_mkerr(js, "Out of memory"); } job->req = req; job->work.data = job; ant_value_t promise = req->promise; Ant_List_Insert(&js->fs_requests, req); int rc = uv_queue_work(js->loop, &job->work, fs_walk_work, fs_walk_after_work); if (rc < 0) { free(job); fs_request_fail(req, rc); req->completed = 1; complete_request(req); } return promise; } Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_scandir(js->loop, &req->uv_req, req->path, 0, on_readdir_complete); if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); } return req->promise;}
static void on_fsync_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data;
if (uv_req->result < 0) { ant_value_t err = fs_mk_uv_error(fs_req_isolate(req), (int)uv_req->result, "fsync", NULL, NULL); ant_value_t cb_args[1] = { err }; fs_call_callback(fs_req_isolate(req), req->callback_fn, cb_args, 1); } else { ant_value_t cb_args[1] = { js_mknull() }; fs_call_callback(fs_req_isolate(req), req->callback_fn, cb_args, 1); }
Ant_List_Remove(req); free_fs_request(req);}
static ant_value_t builtin_fs_fsync(ant_params_t) { if (nargs < 1) return js_mkerr(js, "fsync() requires an fd argument"); if (vtype(args[0]) != kTypeNumber) return js_mkerr(js, "fsync() fd must be a number"); if (nargs < 2 || !is_callable(args[1])) return js_mkerr_typed(js, JS_ERR_TYPE, "The \"cb\" argument must be a function");
fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory");
req->uv_req.loop = js->loop; req->op_type = FS_OP_FSYNC; req->promise = js_mkundef(); req->target_buffer = js_mkundef(); req->callback_fn = args[1]; req->fd = (uv_file)(int)js_getnum(args[0]); req->uv_req.data = req;
Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_fsync(js->loop, &req->uv_req, req->fd, on_fsync_complete);
if (result < 0) { ant_value_t err = fs_mk_uv_error(js, result, "fsync", NULL, NULL); err = js_take_thrown(js, err); ant_value_t cb_args[1] = { err }; sv_call_value(js, req->callback_fn, js_mkundef(), cb_args, 1); Ant_List_Remove(req); free_fs_request(req); }
return js_mkundef();}
static void on_write_fd_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; } req->completed = 1; js_resolve_promise(fs_req_isolate(req), req->promise, js_mknum((double)uv_req->result)); Ant_List_Remove(req); free_fs_request(req);}
static void on_read_fd_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data;
if (uv_req->result < 0) { if (is_callable(req->callback_fn)) { ant_value_t err = fs_mk_uv_error(fs_req_isolate(req), (int)uv_req->result, "read", NULL, NULL); ant_value_t cb_args[1] = { err }; fs_call_callback(fs_req_isolate(req), req->callback_fn, cb_args, 1); Ant_List_Remove(req); free_fs_request(req); return; } fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; }
ssize_t bytes_read = uv_req->result;
if (req->data && bytes_read > 0) { TypedArrayData *ta = buffer_get_typedarray_data(req->target_buffer); uint8_t *bytes; size_t len; if (Ant_Buffer_GetViewBytes(ta, &bytes, &len)) { uint8_t *dest = bytes + req->buf_offset; memcpy(dest, req->data, (size_t)bytes_read); } }
if (is_callable(req->callback_fn)) { ant_value_t cb_args[3] = { js_mknull(), js_mknum((double)bytes_read), req->target_buffer }; fs_call_callback(fs_req_isolate(req), req->callback_fn, cb_args, 3); Ant_List_Remove(req); free_fs_request(req); return; }
req->completed = 1; js_resolve_promise(fs_req_isolate(req), req->promise, js_mknum((double)bytes_read)); Ant_List_Remove(req); free_fs_request(req);}
static ant_value_t builtin_fs_read_fd(ant_params_t) { if (nargs < 2) return js_mkerr(js, "read() requires fd and buffer arguments"); if (vtype(args[0]) != kTypeNumber) return js_mkerr(js, "read() fd must be a number");
int fd = (int)js_getnum(args[0]);
ant_value_t buf_arg = args[1]; TypedArrayData *ta_data = buffer_get_typedarray_data(buf_arg); if (!Ant_Buffer_ViewIsLive(ta_data)) return js_mkerr(js, "read() buffer argument must be a Buffer or TypedArray");
size_t buf_len = ta_data->byte_length; size_t offset = 0; size_t length = buf_len; int64_t position = -1;
ant_value_t callback = js_mkundef(); int data_nargs = nargs; if (nargs >= 3 && is_callable(args[nargs - 1])) { callback = args[nargs - 1]; data_nargs = nargs - 1; }
if (data_nargs >= 3 && vtype(args[2]) == kTypeNumber) offset = (size_t)js_getnum(args[2]); if (data_nargs >= 4 && vtype(args[3]) == kTypeNumber) length = (size_t)js_getnum(args[3]); if (data_nargs >= 5 && vtype(args[4]) == kTypeNumber) position = (int64_t)js_getnum(args[4]);
if (offset > buf_len) return js_mkerr(js, "read() offset out of bounds"); if (offset + length > buf_len) return js_mkerr(js, "read() length extends beyond buffer");
fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory");
req->uv_req.loop = js->loop; req->op_type = FS_OP_READ_FD; req->promise = js_mkpromise(js); req->fd = fd; req->target_buffer = buf_arg; req->buf_offset = offset; req->data_len = length; req->callback_fn = callback; req->data = malloc(length > 0 ? length : 1); if (!req->data) { free(req); return js_mkerr(js, "Out of memory"); } req->uv_req.data = req;
Ant_List_Insert(&js->fs_requests, req);
uv_buf_t buf = uv_buf_init(req->data, (unsigned int)length); int result = uv_fs_read(js->loop, &req->uv_req, req->fd, &buf, 1, position, on_read_fd_complete);
if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); }
return req->promise;}
static ant_value_t builtin_fs_readSync(ant_params_t) { if (nargs < 2) return js_mkerr(js, "readSync() requires fd and buffer arguments"); if (vtype(args[0]) != kTypeNumber) return js_mkerr(js, "readSync() fd must be a number"); int fd = (int)js_getnum(args[0]); TypedArrayData *ta_data = buffer_get_typedarray_data(args[1]); uint8_t *buf_data; size_t buf_len; if (!Ant_Buffer_GetViewBytes(ta_data, &buf_data, &buf_len)) return js_mkerr(js, "readSync() second argument must be a Buffer, TypedArray, or DataView"); size_t offset = 0; size_t length = buf_len; int64_t position = -1; if (nargs >= 3) { if (vtype(args[2]) == kTypeObject) { ant_value_t off_val = js_get(js, args[2], "offset"); ant_value_t len_val = js_get(js, args[2], "length"); ant_value_t pos_val = js_get(js, args[2], "position"); if (vtype(off_val) == kTypeNumber) offset = (size_t)js_getnum(off_val); if (vtype(len_val) == kTypeNumber) length = (size_t)js_getnum(len_val); else length = buf_len - offset; if (vtype(pos_val) == kTypeNumber) position = (int64_t)js_getnum(pos_val); } else if (vtype(args[2]) == kTypeNumber) { offset = (size_t)js_getnum(args[2]); length = buf_len - offset; if (nargs >= 4 && vtype(args[3]) == kTypeNumber) length = (size_t)js_getnum(args[3]); if (nargs >= 5 && vtype(args[4]) == kTypeNumber) position = (int64_t)js_getnum(args[4]); }} if (offset > buf_len) return js_mkerr(js, "offset is out of bounds"); if (offset + length > buf_len) return js_mkerr(js, "length extends beyond buffer"); uv_fs_t req; uv_buf_t buf = uv_buf_init((char *)(buf_data + offset), (unsigned int)length); int result = uv_fs_read(js->loop, &req, fd, &buf, 1, position, NULL); uv_fs_req_cleanup(&req); if (result < 0) return js_mkerr(js, "readSync failed: %s", uv_strerror(result)); return js_mknum((double)result);}
static ant_value_t builtin_fs_writeSync(ant_params_t) { if (nargs < 2) return js_mkerr(js, "writeSync() requires fd and data arguments"); if (vtype(args[0]) != kTypeNumber) return js_mkerr(js, "writeSync() fd must be a number"); int fd = (int)js_getnum(args[0]); if (vtype(args[1]) == kTypeString) { size_t str_len; const char *str = js_getstr(js, args[1], &str_len); if (!str) return js_mkerr(js, "Failed to get string"); int64_t position = -1; if (nargs >= 3 && vtype(args[2]) == kTypeNumber) position = (int64_t)js_getnum(args[2]); uv_fs_t req; uv_buf_t buf = uv_buf_init((char *)str, (unsigned int)str_len); int result = uv_fs_write(js->loop, &req, fd, &buf, 1, position, NULL); uv_fs_req_cleanup(&req); if (result < 0) return js_mkerr(js, "writeSync failed: %s", uv_strerror(result)); return js_mknum((double)result); } uint8_t *buf_data; size_t buf_len; if (!fs_view_bytes(args[1], &buf_data, &buf_len)) return js_mkerr(js, "writeSync() second argument must be a Buffer, TypedArray, DataView, or string"); size_t offset = 0; size_t length = buf_len; int64_t position = -1; if (nargs >= 3) { if (vtype(args[2]) == kTypeObject) { ant_value_t off_val = js_get(js, args[2], "offset"); ant_value_t len_val = js_get(js, args[2], "length"); ant_value_t pos_val = js_get(js, args[2], "position"); if (vtype(off_val) == kTypeNumber) offset = (size_t)js_getnum(off_val); if (vtype(len_val) == kTypeNumber) length = (size_t)js_getnum(len_val); else length = buf_len - offset; if (vtype(pos_val) == kTypeNumber) position = (int64_t)js_getnum(pos_val); } else if (vtype(args[2]) == kTypeNumber) { offset = (size_t)js_getnum(args[2]); length = buf_len - offset; if (nargs >= 4 && vtype(args[3]) == kTypeNumber) length = (size_t)js_getnum(args[3]); if (nargs >= 5 && vtype(args[4]) == kTypeNumber) position = (int64_t)js_getnum(args[4]); } } if (offset > buf_len) return js_mkerr(js, "offset is out of bounds"); if (offset + length > buf_len) return js_mkerr(js, "length extends beyond buffer"); uv_fs_t req; uv_buf_t buf = uv_buf_init((char *)(buf_data + offset), (unsigned int)length); int result = uv_fs_write(js->loop, &req, fd, &buf, 1, position, NULL); uv_fs_req_cleanup(&req); if (result < 0) return js_mkerr(js, "writeSync failed: %s", uv_strerror(result)); return js_mknum((double)result);}
static ant_value_t builtin_fs_write_fd(ant_params_t) { if (nargs < 2) return js_mkerr(js, "write() requires fd and data arguments"); if (vtype(args[0]) != kTypeNumber) return js_mkerr(js, "write() fd must be a number"); int fd = (int)js_getnum(args[0]); const char *write_data; size_t write_len; int64_t position = -1; if (vtype(args[1]) == kTypeString) { size_t str_len; const char *str = js_getstr(js, args[1], &str_len); if (!str) return js_mkerr(js, "Failed to get string"); if (nargs >= 3 && vtype(args[2]) == kTypeNumber) position = (int64_t)js_getnum(args[2]); write_data = str; write_len = str_len; } else { uint8_t *buf_data; size_t buf_len; if (!fs_view_bytes(args[1], &buf_data, &buf_len)) return js_mkerr(js, "write() second argument must be a Buffer, TypedArray, DataView, or string"); size_t offset = 0; size_t length = buf_len; if (nargs >= 3) { if (vtype(args[2]) == kTypeObject) { ant_value_t off_val = js_get(js, args[2], "offset"); ant_value_t len_val = js_get(js, args[2], "length"); ant_value_t pos_val = js_get(js, args[2], "position"); if (vtype(off_val) == kTypeNumber) offset = (size_t)js_getnum(off_val); if (vtype(len_val) == kTypeNumber) length = (size_t)js_getnum(len_val); else length = buf_len - offset; if (vtype(pos_val) == kTypeNumber) position = (int64_t)js_getnum(pos_val); } else if (vtype(args[2]) == kTypeNumber) { offset = (size_t)js_getnum(args[2]); length = buf_len - offset; if (nargs >= 4 && vtype(args[3]) == kTypeNumber) length = (size_t)js_getnum(args[3]); if (nargs >= 5 && vtype(args[4]) == kTypeNumber) position = (int64_t)js_getnum(args[4]); }} if (offset > buf_len) return js_mkerr(js, "offset is out of bounds"); if (offset + length > buf_len) return js_mkerr(js, "length extends beyond buffer"); write_data = (const char *)(buf_data + offset); write_len = length; } fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory"); req->uv_req.loop = js->loop; req->op_type = FS_OP_WRITE_FD; req->promise = js_mkpromise(js); req->fd = fd; req->data = malloc(write_len); if (!req->data) { free(req); return js_mkerr(js, "Out of memory"); } memcpy(req->data, write_data, write_len); req->data_len = write_len; req->uv_req.data = req; Ant_List_Insert(&js->fs_requests, req); uv_buf_t buf = uv_buf_init(req->data, (unsigned int)req->data_len); int result = uv_fs_write(js->loop, &req->uv_req, req->fd, &buf, 1, position, on_write_fd_complete); if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); } return req->promise;}
static ant_value_t builtin_fs_writevSync(ant_params_t) { if (nargs < 2) return js_mkerr(js, "writevSync() requires fd and buffers arguments"); if (vtype(args[0]) != kTypeNumber) return js_mkerr(js, "writevSync() fd must be a number"); int fd = (int)js_getnum(args[0]); ant_offset_t arr_len = js_arr_len(js, args[1]); if (arr_len == 0) return js_mknum(0); int64_t position = -1; if (nargs >= 3 && vtype(args[2]) == kTypeNumber) position = (int64_t)js_getnum(args[2]); uv_buf_t *bufs = calloc((size_t)arr_len, sizeof(uv_buf_t)); if (!bufs) return js_mkerr(js, "Out of memory"); for (ant_offset_t i = 0; i < arr_len; i++) { ant_value_t item = js_arr_get(js, args[1], i); uint8_t *bytes; size_t len; if (!fs_view_bytes(item, &bytes, &len)) { free(bufs); return js_mkerr(js, "writevSync() buffers must contain ArrayBufferViews"); } bufs[i] = uv_buf_init((char *)bytes, (unsigned int)len); } uv_fs_t req; int result = uv_fs_write(js->loop, &req, fd, bufs, (unsigned int)arr_len, position, NULL); uv_fs_req_cleanup(&req); free(bufs); if (result < 0) return js_mkerr(js, "writevSync failed: %s", uv_strerror(result)); return js_mknum((double)result);}
static ant_value_t builtin_fs_writev_fd(ant_params_t) { if (nargs < 2) return js_mkerr(js, "writev() requires fd and buffers arguments"); if (vtype(args[0]) != kTypeNumber) return js_mkerr(js, "writev() fd must be a number"); int fd = (int)js_getnum(args[0]); ant_offset_t arr_len = js_arr_len(js, args[1]); if (arr_len == 0) { ant_value_t promise = js_mkpromise(js); js_resolve_promise(js, promise, js_mknum(0)); return promise; } int64_t position = -1; if (nargs >= 3 && vtype(args[2]) == kTypeNumber) position = (int64_t)js_getnum(args[2]); size_t total_len = 0; for (ant_offset_t i = 0; i < arr_len; i++) { uint8_t *bytes; size_t len; if (!fs_view_bytes(js_arr_get(js, args[1], i), &bytes, &len)) return js_mkerr(js, "writev() buffers must contain ArrayBufferViews"); total_len += len; } fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory"); req->data = malloc(total_len ? total_len : 1); if (!req->data) { free(req); return js_mkerr(js, "Out of memory"); } size_t off = 0; for (ant_offset_t i = 0; i < arr_len; i++) { uint8_t *bytes; size_t len; fs_view_bytes(js_arr_get(js, args[1], i), &bytes, &len); if (len) memcpy(req->data + off, bytes, len); off += len; } req->uv_req.loop = js->loop; req->op_type = FS_OP_WRITE_FD; req->promise = js_mkpromise(js); req->fd = fd; req->data_len = total_len; req->uv_req.data = req; Ant_List_Insert(&js->fs_requests, req); uv_buf_t buf = uv_buf_init(req->data, (unsigned int)total_len); int result = uv_fs_write(js->loop, &req->uv_req, req->fd, &buf, 1, position, on_write_fd_complete); if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); } return req->promise;}
typedef struct { const char *name; int flags;} fs_open_flag_t;
static const fs_open_flag_t fs_open_flag_names[] = { { "r", O_RDONLY }, { "rs", O_RDONLY | UV_FS_O_SYNC }, { "sr", O_RDONLY | UV_FS_O_SYNC }, { "r+", O_RDWR }, { "rs+", O_RDWR | UV_FS_O_SYNC }, { "sr+", O_RDWR | UV_FS_O_SYNC }, { "w", O_WRONLY | O_CREAT | O_TRUNC }, { "wx", O_WRONLY | O_CREAT | O_TRUNC | O_EXCL }, { "xw", O_WRONLY | O_CREAT | O_TRUNC | O_EXCL }, { "w+", O_RDWR | O_CREAT | O_TRUNC }, { "wx+", O_RDWR | O_CREAT | O_TRUNC | O_EXCL }, { "xw+", O_RDWR | O_CREAT | O_TRUNC | O_EXCL }, { "a", O_WRONLY | O_CREAT | O_APPEND }, { "ax", O_WRONLY | O_CREAT | O_APPEND | O_EXCL }, { "xa", O_WRONLY | O_CREAT | O_APPEND | O_EXCL }, { "as", O_WRONLY | O_CREAT | O_APPEND | UV_FS_O_SYNC }, { "sa", O_WRONLY | O_CREAT | O_APPEND | UV_FS_O_SYNC }, { "a+", O_RDWR | O_CREAT | O_APPEND }, { "ax+", O_RDWR | O_CREAT | O_APPEND | O_EXCL }, { "xa+", O_RDWR | O_CREAT | O_APPEND | O_EXCL }, { "as+", O_RDWR | O_CREAT | O_APPEND | UV_FS_O_SYNC }, { "sa+", O_RDWR | O_CREAT | O_APPEND | UV_FS_O_SYNC },};
static bool fs_open_flags_of(ant_t *js, ant_value_t arg, int *out) { if (vtype(arg) == kTypeNumber) { double flags = js_getnum(arg); if (!(flags >= INT32_MIN && flags <= INT32_MAX) || flags != (double)(int32_t)flags) return false; *out = (int)flags; return true; } if (vtype(arg) != kTypeString) return false;
size_t len = 0; const char *str = js_getstr(js, arg, &len); if (!str) return false;
for (size_t i = 0; i < countof(fs_open_flag_names); i++) { const fs_open_flag_t *entry = &fs_open_flag_names[i]; if (strlen(entry->name) == len && memcmp(entry->name, str, len) == 0) { *out = entry->flags; return true; } }
return false;}
static int parse_open_flags(ant_t *js, ant_value_t arg) { int flags = O_RDONLY; fs_open_flags_of(js, arg, &flags); return flags;}
static ant_value_t builtin_fs_openSync(ant_params_t) { if (nargs < 1) return js_mkerr(js, "openSync() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "openSync() path must be a string"); size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); int flags = (nargs >= 2) ? parse_open_flags(js, args[1]) : O_RDONLY; int mode = (nargs >= 3 && vtype(args[2]) == kTypeNumber) ? (int)js_getnum(args[2]) : 0666; char *path_cstr = strndup(path, path_len); if (!path_cstr) return js_mkerr(js, "Out of memory"); uv_fs_t req; int result = uv_fs_open(js->loop, &req, path_cstr, flags, mode, NULL); if (result < 0) { ant_value_t err = fs_mk_uv_error(js, result, "open", path_cstr, NULL); uv_fs_req_cleanup(&req); free(path_cstr); return err; } uv_fs_req_cleanup(&req); free(path_cstr); return js_mknum((double)result);}
static ant_value_t builtin_fs_closeSync(ant_params_t) { if (nargs < 1) return js_mkerr(js, "closeSync() requires a fd argument"); if (vtype(args[0]) != kTypeNumber) return js_mkerr(js, "closeSync() fd must be a number"); int fd = (int)js_getnum(args[0]); uv_fs_t req; int result = uv_fs_close(js->loop, &req, fd, NULL); uv_fs_req_cleanup(&req); if (result < 0) return js_mkerr(js, "closeSync failed: %s", uv_strerror(result)); return js_mkundef();}
static void on_open_fd_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; } req->completed = 1; js_resolve_promise(fs_req_isolate(req), req->promise, js_mknum((double)uv_req->result)); Ant_List_Remove(req); free_fs_request(req);}
static void on_open_filehandle_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data;
if (uv_req->result < 0) { fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; }
req->completed = 1; js_resolve_promise( fs_req_isolate(req), req->promise, fs_make_filehandle(fs_req_isolate(req), (int)uv_req->result) ); Ant_List_Remove(req); free_fs_request(req);}
static ant_value_t builtin_fs_open_fd(ant_params_t) { if (nargs < 1) return js_mkerr(js, "open() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "open() path must be a string"); size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string"); int flags = (nargs >= 2) ? parse_open_flags(js, args[1]) : O_RDONLY; int mode = (nargs >= 3 && vtype(args[2]) == kTypeNumber) ? (int)js_getnum(args[2]) : 0666; fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory"); req->uv_req.loop = js->loop; req->op_type = FS_OP_OPEN; req->promise = js_mkpromise(js); req->path = strndup(path, path_len); req->uv_req.data = req; Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_open(js->loop, &req->uv_req, req->path, flags, mode, on_open_fd_complete); if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); } return req->promise;}
static ant_value_t builtin_fs_open_filehandle(ant_params_t) { if (nargs < 1) return js_mkerr(js, "open() requires a path argument"); args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "open() path must be a string");
size_t path_len; char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string");
int flags = (nargs >= 2) ? parse_open_flags(js, args[1]) : O_RDONLY; int mode = (nargs >= 3 && vtype(args[2]) == kTypeNumber) ? (int)js_getnum(args[2]) : 0666;
fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory");
req->uv_req.loop = js->loop; req->op_type = FS_OP_OPEN; req->promise = js_mkpromise(js); req->path = strndup(path, path_len); req->uv_req.data = req;
Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_open( js->loop, &req->uv_req, req->path, flags, mode, on_open_filehandle_complete );
if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); }
return req->promise;}
static void on_close_fd_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data; if (uv_req->result < 0) { fs_request_fail(req, (int)uv_req->result); req->completed = 1; complete_request(req); return; } req->completed = 1; js_resolve_promise(fs_req_isolate(req), req->promise, js_mkundef()); Ant_List_Remove(req); free_fs_request(req);}
static ant_value_t builtin_fs_close_fd(ant_params_t) { if (nargs < 1) return js_mkerr(js, "close() requires a fd argument"); if (vtype(args[0]) != kTypeNumber) return js_mkerr(js, "close() fd must be a number"); int fd = (int)js_getnum(args[0]); fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory"); req->uv_req.loop = js->loop; req->op_type = FS_OP_CLOSE; req->promise = js_mkpromise(js); req->fd = fd; req->uv_req.data = req; Ant_List_Insert(&js->fs_requests, req); int result = uv_fs_close(js->loop, &req->uv_req, req->fd, on_close_fd_complete); if (result < 0) { fs_request_fail(req, result); req->completed = 1; complete_request(req); } return req->promise;}
static ant_value_t builtin_fs_watch(ant_params_t) { ant_value_t path_val = 0; ant_value_t watcher_obj = 0; fs_watch_options_t opts; fs_watcher_t *watcher = NULL; uv_handle_t *handle = NULL; const char *path = NULL; size_t path_len = 0; int rc = 0;
if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "watch() requires a path argument"); if (!fs_parse_watch_options(js, args, nargs, &opts)) return js_mkerr_typed(js, JS_ERR_TYPE, "watch() options must be a string, object, or callback");
path_val = args[0] = fs_coerce_path(js, args[0]); if (is_err(path_val)) return path_val; if (vtype(path_val) != kTypeString) return js_mkerr_typed(js, JS_ERR_TYPE, "watch() path must be a string or URL");
path = js_getstr(js, path_val, &path_len); if (!path || path_len == 0) return js_mkerr(js, "watch() path must not be empty");
watcher = fs_watcher_new(js, FS_WATCH_MODE_EVENT); if (!watcher) return js_mkerr(js, "Out of memory");
watcher_obj = fs_watcher_make_object(js, watcher); if (is_err(watcher_obj)) { fs_watcher_free(watcher); return watcher_obj; }
watcher->buffer_encoding = opts.buffer_encoding; rc = fs_watcher_start_event(js, watcher, path, opts.persistent, opts.recursive); if (rc != 0) { js_clear_native(watcher_obj, FS_WATCHER_NATIVE_TAG); fs_watcher_free(watcher); return fs_watch_error(js, rc, path); }
fs_add_active_watcher(watcher); if (!opts.persistent) { handle = fs_watcher_uv_handle(watcher); if (handle) uv_unref(handle); } if (is_callable(opts.listener)) eventemitter_add_listener(js, watcher_obj, "change", opts.listener, false); return watcher_obj;}
static ant_value_t builtin_fs_watchFile(ant_params_t) { ant_value_t path_val = 0; fs_watchfile_options_t opts; fs_watcher_t *watcher = NULL; uv_handle_t *handle = NULL; const char *path = NULL; size_t path_len = 0; int rc = 0;
if (nargs < 2) return js_mkerr_typed(js, JS_ERR_TYPE, "watchFile() requires a path and listener"); if (!fs_parse_watchfile_options(js, args, nargs, &opts)) return js_mkerr_typed(js, JS_ERR_TYPE, "watchFile() requires a listener callback");
path_val = args[0] = fs_coerce_path(js, args[0]); if (is_err(path_val)) return path_val; if (vtype(path_val) != kTypeString) return js_mkerr_typed(js, JS_ERR_TYPE, "watchFile() path must be a string or URL");
path = js_getstr(js, path_val, &path_len); if (!path || path_len == 0) return js_mkerr(js, "watchFile() path must not be empty");
watcher = fs_watcher_new(js, FS_WATCH_MODE_STAT); if (!watcher) return js_mkerr(js, "Out of memory");
watcher->callback = opts.listener; watcher->last_stat_valid = fs_stat_path_sync(path, &watcher->last_stat);
rc = fs_watcher_start_poll(js, watcher, path, opts.persistent, opts.interval_ms); if (rc != 0) { fs_watcher_free(watcher); return fs_watch_error(js, rc, path); }
fs_add_active_watcher(watcher); if (!opts.persistent) { handle = fs_watcher_uv_handle(watcher); if (handle) uv_unref(handle); } return js_mkundef();}
void cleanup_fs_module(ant_t *js) { for (fs_watcher_t *watcher = js->fs_watchers, *next; watcher; watcher = next) { next = watcher->next; fs_watcher_close_native(watcher); } for (fs_request_t *req = js->fs_requests; req; req = req->next) uv_cancel((uv_req_t *)&req->uv_req);}
static ant_value_t builtin_fs_unwatchFile(ant_params_t) { ant_value_t path_val = 0; ant_value_t listener = js_mkundef(); char *resolved = NULL; fs_watcher_t *watcher = NULL; fs_watcher_t *next = NULL; const char *path = NULL; size_t path_len = 0;
if (nargs < 1) return js_mkundef();
path_val = args[0] = fs_coerce_path(js, args[0]); if (is_err(path_val)) return path_val; if (vtype(path_val) != kTypeString) return js_mkundef();
path = js_getstr(js, path_val, &path_len); if (!path || path_len == 0) return js_mkundef(); if (nargs > 1 && is_callable(args[1])) listener = args[1];
resolved = ant_watch_resolve_path(path); if (!resolved) return js_mkundef();
for (watcher = js->fs_watchers; watcher; watcher = next) { next = watcher->next; if (watcher->mode != FS_WATCH_MODE_STAT) continue; if (!watcher->path || strcmp(watcher->path, resolved) != 0) continue; if (is_callable(listener) && watcher->callback != listener) continue; fs_watcher_close_native(watcher); }
free(resolved); return js_mkundef();}
void init_fs_module(ant_t *js) { js->builtins.stats_proto = Ant_Object_Create(js); js_define_methods(js, js->builtins.stats_proto, stat_methods, countof(stat_methods), ANT_PROP_ATTR_DEFAULT); js_set_tostringtag(js, js->builtins.stats_proto, js_mkstr(js, "Stats", 5)); js->builtins.stats_ctor = Ant_Function_CreateConstructor(js, stats_ctor, js->builtins.stats_proto, "Stats", 0);
js->builtins.dirent_proto = Ant_Object_Create(js); js_define_methods(js, js->builtins.dirent_proto, dirent_methods, countof(dirent_methods), ANT_PROP_ATTR_METHOD); js_set_tostringtag(js, js->builtins.dirent_proto, js_mkstr(js, "Dirent", 6)); js->builtins.dirent_ctor = Ant_Function_CreateConstructor(js, dirent_ctor, js->builtins.dirent_proto, "Dirent", 3);}
static ant_value_t fs_callback_success_handler(ant_params_t) { ant_value_t ctx = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); ant_value_t callback = js_get_slot(ctx, SLOT_DATA);
if (!is_callable(callback)) return js_mkundef();
if (js_truthy(js, js_get(js, ctx, "existsStyle"))) { ant_value_t cb_args[1] = { nargs > 0 ? args[0] : js_false }; fs_call_callback(js, callback, cb_args, 1); return js_mkundef(); }
ant_value_t cb_args[2] = { js_mknull(), nargs > 0 ? args[0] : js_mkundef() }; fs_call_callback(js, callback, cb_args, 2); return js_mkundef();}
static ant_value_t fs_callback_error_handler(ant_params_t) { ant_value_t ctx = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); ant_value_t callback = js_get_slot(ctx, SLOT_DATA); ant_value_t cb_args[1];
if (!is_callable(callback)) return js_mkundef();
if (js_truthy(js, js_get(js, ctx, "existsStyle"))) { cb_args[0] = js_false; fs_call_callback(js, callback, cb_args, 1); return js_mkundef(); }
cb_args[0] = nargs > 0 ? args[0] : js_mkundef(); fs_call_callback(js, callback, cb_args, 1); return js_mkundef();}
static void fs_callback_emit_success( ant_t *js, ant_value_t callback, bool exists_style, ant_value_t value) { if (exists_style) { ant_value_t cb_args[1] = { value }; fs_call_callback(js, callback, cb_args, 1); return; }
ant_value_t cb_args[2] = { js_mknull(), value }; fs_call_callback(js, callback, cb_args, 2);}
static void fs_callback_emit_error( ant_t *js, ant_value_t callback, bool exists_style, ant_value_t error) { ant_value_t cb_args[1];
cb_args[0] = exists_style ? js_false : error; fs_call_callback(js, callback, cb_args, 1);}
static ant_value_t fs_callback_attach_promise( ant_t *js, ant_value_t promise, ant_value_t callback, bool exists_style) { GC_ROOT_SAVE(root_mark, js); ant_value_t success_fn = js_mkundef(); ant_value_t error_fn = js_mkundef();
GC_ROOT_PIN(js, promise); GC_ROOT_PIN(js, callback);
ant_value_t success_ctx = Ant_Object_CreateBare(js); GC_ROOT_PIN(js, success_ctx); ant_value_t error_ctx = Ant_Object_CreateBare(js); GC_ROOT_PIN(js, error_ctx);
js_set_slot(success_ctx, SLOT_DATA, callback); js_set_slot(error_ctx, SLOT_DATA, callback); if (exists_style) { js_set(js, success_ctx, "existsStyle", js_true); js_set(js, error_ctx, "existsStyle", js_true); }
success_fn = js_heavy_mkfun(js, fs_callback_success_handler, success_ctx); GC_ROOT_PIN(js, success_fn); error_fn = js_heavy_mkfun(js, fs_callback_error_handler, error_ctx); GC_ROOT_PIN(js, error_fn);
Ant_Promise_Observe(js, promise, success_fn, error_fn); GC_ROOT_RESTORE(js, root_mark); return js_mkundef();}
static ant_value_t fs_callback_wrapper_call(ant_params_t) { GC_ROOT_SAVE(root_mark, js); ant_value_t wrapper = js_getcurrentfunc(js); ant_value_t config = js_get_slot(wrapper, SLOT_DATA); ant_value_t original = js_get_slot(config, SLOT_DATA); ant_value_t callback = js_mkundef(); ant_value_t result = js_mkundef(); ant_value_t this_arg = js_getthis(js); ant_value_t ex = js_mkundef(); bool exists_style = false; int call_nargs = nargs;
GC_ROOT_PIN(js, original); GC_ROOT_PIN(js, this_arg);
exists_style = js_truthy(js, js_get(js, config, "existsStyle")); if (nargs > 0 && is_callable(args[nargs - 1])) { callback = args[nargs - 1]; GC_ROOT_PIN(js, callback); call_nargs--; }
result = sv_call_value(js, original, this_arg, args, call_nargs); GC_ROOT_PIN(js, result);
if (!is_callable(callback)) { GC_ROOT_RESTORE(js, root_mark); return result; }
if (is_err(result) || Ant_Exception_Pending(js)) { ex = js_take_thrown(js, result); GC_ROOT_PIN(js, ex); fs_callback_emit_error(js, callback, exists_style, ex); GC_ROOT_RESTORE(js, root_mark); return js_mkundef(); }
if (vtype(result) != kTypePromise) { fs_callback_emit_success(js, callback, exists_style, result); GC_ROOT_RESTORE(js, root_mark); return js_mkundef(); }
ant_value_t attach_result = fs_callback_attach_promise(js, result, callback, exists_style); GC_ROOT_RESTORE(js, root_mark); return attach_result;}
static ant_value_t fs_make_callback_wrapper(ant_t *js, ant_value_t original, bool exists_style, const char *name, int length) { ant_value_t config = Ant_Object_CreateBare(js);
js_set_slot(config, SLOT_DATA, original); if (exists_style) js_set(js, config, "existsStyle", js_true);
ant_value_t wrapper = js_heavy_mkfun(js, fs_callback_wrapper_call, config); js_define_function_length(js, wrapper, length); js_set_function_name(js, wrapper, name, strlen(name)); return wrapper;}
static ant_value_t fs_promise_wrapper_call(ant_params_t) { GC_ROOT_SAVE(root_mark, js); ant_value_t wrapper = js_getcurrentfunc(js); ant_value_t original = js_get_slot(wrapper, SLOT_DATA); ant_value_t this_arg = js_getthis(js); ant_value_t result = js_mkundef(); ant_value_t error = js_mkundef();
GC_ROOT_PIN(js, original); GC_ROOT_PIN(js, this_arg);
result = sv_call_value(js, original, this_arg, args, nargs); GC_ROOT_PIN(js, result);
if (is_err(result) || Ant_Exception_Pending(js)) { error = js_take_thrown(js, result); GC_ROOT_PIN(js, error); result = fs_rejected_promise(js, error); } else if (vtype(result) != kTypePromise) result = fs_resolved_promise(js, result);
GC_ROOT_RESTORE(js, root_mark); return result;}
static ant_value_t fs_make_promise_wrapper(ant_t *js, ant_value_t original, const char *name, int length) { ant_value_t wrapper = js_heavy_mkfun(js, fs_promise_wrapper_call, original); js_define_function_length(js, wrapper, length); js_set_function_name(js, wrapper, name, strlen(name)); return wrapper;}
typedef struct { char *name; uv_dirent_type_t type;} fs_dir_entry_t;
typedef struct { uv_dir_t *dir; uv_dirent_t *dirents; fs_dir_entry_t *entries;
char *path; char *current; char **pending;
fs_request_t *ops_head; fs_request_t *ops_tail;
size_t nentries; size_t pos; size_t count; size_t pending_head; size_t pending_len; size_t pending_cap;
bool buffer_encoding; bool recursive; bool closed;} fs_dir_t;
static void fs_dir_clear_entries(fs_dir_t *d) { for (size_t i = 0; i < d->count; i++) free(d->entries[i].name); d->pos = d->count = 0;}
static void fs_dir_store_entries(fs_dir_t *d, size_t count) { fs_dir_clear_entries(d); for (size_t i = 0; i < count; i++) { char *name = strdup(d->dirents[i].name); if (!name) continue; d->entries[d->count].name = name; d->entries[d->count++].type = d->dirents[i].type; }}
static bool fs_dir_push_pending(fs_dir_t *d, char *path) { if (d->pending_head + d->pending_len == d->pending_cap) { if (d->pending_head > 0) { memmove(d->pending, d->pending + d->pending_head, d->pending_len * sizeof(char *)); d->pending_head = 0; } else { size_t cap = d->pending_cap ? d->pending_cap * 2 : 8; char **grown = realloc(d->pending, cap * sizeof(char *)); if (!grown) return false; d->pending = grown; d->pending_cap = cap; } } d->pending[d->pending_head + d->pending_len++] = path; return true;}
static char *fs_dir_pop_pending(fs_dir_t *d) { if (d->pending_len == 0) return NULL; d->pending_len--; return d->pending[d->pending_head++];}
static const char *fs_dir_current_path(fs_dir_t *d) { return d->current ? d->current : d->path;}
static int fs_dir_close_handle(fs_dir_t *d) { if (!d->dir) return 0; uv_fs_t req; int rc = uv_fs_closedir(NULL, &req, d->dir, NULL); uv_fs_req_cleanup(&req); d->dir = NULL; return rc;}
static int fs_dir_release(fs_dir_t *d) { int rc = fs_dir_close_handle(d); fs_dir_clear_entries(d); while (d->pending_len > 0) free(fs_dir_pop_pending(d)); free(d->current); d->current = NULL; d->closed = true; return rc;}
static void fs_dir_finalize(ant_t *js, ant_object_t *obj) { ant_value_t value = js_obj_from_ptr(obj); fs_dir_t *d = (fs_dir_t *)js_get_native(value, FS_DIR_NATIVE_TAG); js_clear_native(value, FS_DIR_NATIVE_TAG); if (!d) return;
fs_dir_release(d); free(d->pending); free(d->entries); free(d->dirents); free(d->path); free(d);}
static ant_value_t fs_dir_closed_error(ant_t *js) { return js_mkerr_code(js, JS_ERR_GENERIC, "ERR_DIR_CLOSED", "Directory handle was closed");}
static fs_dir_t *fs_dir_data(ant_t *js, ant_value_t obj, ant_value_t *err) { fs_dir_t *d = is_object_type(obj) ? (fs_dir_t *)js_get_native(obj, FS_DIR_NATIVE_TAG) : NULL; if (!d) *err = js_mkerr_typed(js, JS_ERR_TYPE, "Value of \"this\" must be of type Dir"); return d;}
static fs_dir_t *fs_dir_sync_data(ant_t *js, ant_value_t obj, ant_value_t *err) { fs_dir_t *d = fs_dir_data(js, obj, err); if (!d) return NULL; if (d->closed) { *err = fs_dir_closed_error(js); return NULL; } if (d->ops_head) { *err = js_mkerr_code(js, JS_ERR_GENERIC, "ERR_DIR_CONCURRENT_OPERATION", "Cannot do synchronous work on directory handle with concurrent asynchronous operations" ); return NULL; } return d;}
static ant_value_t fs_dir_queue_subdir(ant_t *js, fs_dir_t *d, const char *name) { ant_value_t joined = fs_path_join(js, fs_dir_current_path(d), name); if (is_err(joined)) return joined;
size_t len = 0; const char *str = js_getstr(js, joined, &len); char *copy = str ? strndup(str, len) : NULL; if (!copy || !fs_dir_push_pending(d, copy)) { free(copy); return js_mkerr(js, "Out of memory"); }
return js_mkundef();}
static ant_value_t fs_dir_take_entry(ant_t *js, ant_value_t dir_obj, fs_dir_t *d) { fs_dir_entry_t *entry = &d->entries[d->pos++]; GC_ROOT_SAVE(root_mark, js);
ant_value_t parent = d->current ? js_mkstr(js, d->current, strlen(d->current)) : js_get(js, dir_obj, "path"); GC_ROOT_PIN(js, parent);
ant_value_t dirent = create_dirent_object( js, entry->name, strlen(entry->name), entry->type, d->buffer_encoding, parent );
if (!is_err(dirent) && d->recursive && entry->type == UV_DIRENT_DIR) { GC_ROOT_PIN(js, dirent); ant_value_t queued = fs_dir_queue_subdir(js, d, entry->name); if (is_err(queued)) dirent = queued; }
GC_ROOT_RESTORE(js, root_mark); return dirent;}
static ant_value_t fs_dir_read_sync(ant_t *js, ant_value_t dir_obj, fs_dir_t *d) { for (;;) { if (d->pos < d->count) return fs_dir_take_entry(js, dir_obj, d);
uv_fs_t req; if (!d->dir) { char *next = fs_dir_pop_pending(d); if (!next) return js_mknull();
int rc = uv_fs_opendir(NULL, &req, next, NULL); uv_dir_t *handle = rc < 0 ? NULL : (uv_dir_t *)req.ptr; uv_fs_req_cleanup(&req);
if (rc < 0) { ant_value_t err = fs_mk_uv_error(js, rc, "opendir", next, NULL); free(next); return err; }
free(d->current); d->current = next; d->dir = handle; }
d->dir->dirents = d->dirents; d->dir->nentries = d->nentries; int rc = uv_fs_readdir(NULL, &req, d->dir, NULL);
if (rc < 0) { uv_fs_req_cleanup(&req); return fs_mk_uv_error(js, rc, "readdir", fs_dir_current_path(d), NULL); }
fs_dir_store_entries(d, (size_t)rc); uv_fs_req_cleanup(&req); if (rc == 0) fs_dir_close_handle(d); }}
static void fs_dir_run_ops(fs_dir_t *d);
static void fs_dir_complete_op(fs_request_t *req, fs_dir_t *d, ant_value_t value, bool reject) { ant_t *js = fs_req_isolate(req); if (reject) js_reject_promise(js, req->promise, value); else js_resolve_promise(js, req->promise, value);
d->ops_head = req->dir_next; if (!d->ops_head) d->ops_tail = NULL;
Ant_List_Remove(req); free_fs_request(req); if (d->ops_head) fs_dir_run_ops(d);}
static void fs_dir_finish_op(fs_request_t *req, fs_dir_t *d, ant_value_t result) { if (is_err(result)) fs_dir_complete_op(req, d, js_take_thrown(fs_req_isolate(req), result), true); else fs_dir_complete_op(req, d, result, false);}
static fs_dir_t *fs_dir_of_op(fs_request_t *req) { return (fs_dir_t *)js_get_native(req->owner, FS_DIR_NATIVE_TAG);}
static void fs_dir_iter_finish(fs_request_t *req, fs_dir_t *d, ant_value_t outcome) { if (d->closed) { fs_dir_finish_op(req, d, outcome); return; } req->failed = is_err(outcome); req->target_buffer = req->failed ? js_take_thrown(fs_req_isolate(req), outcome) : outcome; req->op_type = FS_OP_DIR_ITER_CLOSE; fs_dir_run_ops(d);}
static void fs_dir_settle_read(fs_request_t *req, fs_dir_t *d, ant_value_t value) { ant_t *js = fs_req_isolate(req); if (req->op_type != FS_OP_DIR_ITER_NEXT) { fs_dir_finish_op(req, d, value); return; }
if (is_err(value)) { fs_dir_iter_finish(req, d, value); return; }
if (vtype(value) == kTypeNull) { fs_dir_iter_finish(req, d, js_iter_result(js, false, js_mkundef())); return; }
fs_dir_finish_op(req, d, js_iter_result(js, true, value));}
static void on_dir_op_closed(uv_fs_t *uv_req);static void fs_dir_after_close(fs_request_t *req, fs_dir_t *d, int rc);
static void on_dir_op_opened(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data; fs_dir_t *d = fs_dir_of_op(req); int rc = (int)uv_req->result; uv_dir_t *handle = rc < 0 ? NULL : (uv_dir_t *)uv_req->ptr; uv_fs_req_cleanup(uv_req);
if (rc < 0) { fs_dir_settle_read(req, d, fs_mk_uv_error(fs_req_isolate(req), rc, "opendir", req->path, NULL)); return; }
free(d->current); d->current = req->path; req->path = NULL; d->dir = handle; fs_dir_run_ops(d);}
static void on_dir_op_read(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data; fs_dir_t *d = fs_dir_of_op(req); int rc = (int)uv_req->result;
if (rc < 0) { uv_fs_req_cleanup(uv_req); fs_dir_settle_read(req, d, fs_mk_uv_error(fs_req_isolate(req), rc, "readdir", fs_dir_current_path(d), NULL)); return; }
fs_dir_store_entries(d, (size_t)rc); uv_fs_req_cleanup(uv_req);
if (rc > 0) { fs_dir_run_ops(d); return; }
uv_dir_t *handle = d->dir; d->dir = NULL; int close_rc = uv_fs_closedir(uv_req->loop, &req->uv_req, handle, on_dir_op_closed); if (close_rc < 0) fs_dir_after_close(req, d, close_rc);}
static void fs_dir_after_close(fs_request_t *req, fs_dir_t *d, int rc) { if (req->op_type == FS_OP_DIR_READ || req->op_type == FS_OP_DIR_ITER_NEXT) { fs_dir_run_ops(d); return; }
if (req->op_type == FS_OP_DIR_ITER_CLOSE) { fs_dir_complete_op(req, d, req->target_buffer, req->failed); return; }
fs_dir_finish_op(req, d, rc < 0 ? fs_mk_uv_error(fs_req_isolate(req), rc, "closedir", d->path, NULL) : js_mkundef() );}
static void on_dir_op_closed(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data; int rc = (int)uv_req->result; uv_fs_req_cleanup(uv_req); fs_dir_after_close(req, fs_dir_of_op(req), rc);}
static void fs_dir_run_ops(fs_dir_t *d) { fs_request_t *req = d->ops_head; if (!req) return; ant_t *js = fs_req_isolate(req);
bool closing = req->op_type == FS_OP_DIR_CLOSE || req->op_type == FS_OP_DIR_ITER_CLOSE || req->op_type == FS_OP_DIR_ITER_RETURN;
if (closing) { if (d->closed && req->op_type == FS_OP_DIR_CLOSE) { fs_dir_finish_op(req, d, fs_dir_closed_error(js)); return; } if (req->op_type == FS_OP_DIR_ITER_RETURN) req->op_type = FS_OP_DIR_ITER_CLOSE;
uv_dir_t *handle = d->dir; d->dir = NULL; fs_dir_release(d);
int rc = handle ? uv_fs_closedir(js->loop, &req->uv_req, handle, on_dir_op_closed) : 0; if (!handle || rc < 0) fs_dir_after_close(req, d, rc); return; }
if (d->closed) { fs_dir_settle_read(req, d, fs_dir_closed_error(js)); return; }
if (d->pos < d->count) { fs_dir_settle_read(req, d, fs_dir_take_entry(js, req->owner, d)); return; }
int rc = 0; if (!d->dir) { char *next = fs_dir_pop_pending(d); if (!next) { fs_dir_settle_read(req, d, js_mknull()); return; } free(req->path); req->path = next; rc = uv_fs_opendir(js->loop, &req->uv_req, req->path, on_dir_op_opened); if (rc < 0) fs_dir_settle_read(req, d, fs_mk_uv_error(js, rc, "opendir", req->path, NULL)); return; }
d->dir->dirents = d->dirents; d->dir->nentries = d->nentries; rc = uv_fs_readdir(js->loop, &req->uv_req, d->dir, on_dir_op_read); if (rc < 0) fs_dir_settle_read(req, d, fs_mk_uv_error(js, rc, "readdir", fs_dir_current_path(d), NULL));}
static ant_value_t fs_dir_enqueue( ant_t *js, ant_value_t dir_obj, fs_dir_t *d, fs_op_type_t op_type, ant_value_t stash) { fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) return js_mkerr(js, "Out of memory");
req->uv_req.loop = js->loop; req->op_type = op_type; req->promise = js_mkpromise(js); req->owner = dir_obj; req->target_buffer = stash; req->uv_req.data = req;
Ant_List_Insert(&js->fs_requests, req); ant_value_t promise = req->promise;
if (d->ops_tail) d->ops_tail->dir_next = req; else d->ops_head = req; d->ops_tail = req;
if (d->ops_head == req) fs_dir_run_ops(d); return promise;}
static ant_value_t builtin_fs_dir_readSync(ant_params_t) { ant_value_t err = js_mkundef(); fs_dir_t *d = fs_dir_sync_data(js, js->this_val, &err); if (!d) return err; return fs_dir_read_sync(js, js->this_val, d);}
static ant_value_t builtin_fs_dir_read(ant_params_t) { ant_value_t err = js_mkundef(); fs_dir_t *d = fs_dir_data(js, js->this_val, &err); if (!d) return fs_rejected_promise(js, err); if (d->closed && !d->ops_head) return fs_rejected_promise(js, fs_dir_closed_error(js)); return fs_dir_enqueue(js, js->this_val, d, FS_OP_DIR_READ, js_mkundef());}
static ant_value_t builtin_fs_dir_closeSync(ant_params_t) { ant_value_t err = js_mkundef(); fs_dir_t *d = fs_dir_sync_data(js, js->this_val, &err); if (!d) return err;
int rc = fs_dir_release(d); if (rc < 0) return fs_mk_uv_error(js, rc, "closedir", d->path, NULL); return js_mkundef();}
static ant_value_t builtin_fs_dir_close(ant_params_t) { ant_value_t err = js_mkundef(); fs_dir_t *d = fs_dir_data(js, js->this_val, &err); if (!d) return fs_rejected_promise(js, err); if (d->closed && !d->ops_head) return fs_rejected_promise(js, fs_dir_closed_error(js)); return fs_dir_enqueue(js, js->this_val, d, FS_OP_DIR_CLOSE, js_mkundef());}
static ant_value_t builtin_fs_dir_dispose(ant_params_t) { fs_dir_t *d = (fs_dir_t *)js_get_native(js->this_val, FS_DIR_NATIVE_TAG); if (!d || d->closed) return js_mkundef(); return builtin_fs_dir_closeSync(js, args, nargs, call_new_target);}
static ant_value_t builtin_fs_dir_asyncDispose(ant_params_t) { fs_dir_t *d = (fs_dir_t *)js_get_native(js->this_val, FS_DIR_NATIVE_TAG); if (!d || d->closed) return fs_resolved_promise(js, js_mkundef()); return fs_dir_enqueue(js, js->this_val, d, FS_OP_DIR_CLOSE, js_mkundef());}
static ant_value_t fs_dir_iter_next(ant_params_t) { ant_value_t dir_obj = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); ant_value_t err = js_mkundef();
fs_dir_t *d = fs_dir_data(js, dir_obj, &err); if (!d) return fs_rejected_promise(js, err); if (d->closed && !d->ops_head) return fs_rejected_promise(js, fs_dir_closed_error(js));
return fs_dir_enqueue(js, dir_obj, d, FS_OP_DIR_ITER_NEXT, js_mkundef());}
static ant_value_t fs_dir_iter_return(ant_params_t) { ant_value_t dir_obj = js_get_slot(js_getcurrentfunc(js), SLOT_DATA); ant_value_t value = nargs > 0 ? args[0] : js_mkundef();
fs_dir_t *d = (fs_dir_t *)js_get_native(dir_obj, FS_DIR_NATIVE_TAG); GC_ROOT_SAVE(root_mark, js); ant_value_t done = Ant_Iterator_CreateResult(js, value, true); GC_ROOT_PIN(js, done);
ant_value_t promise = (!d || (d->closed && !d->ops_head)) ? fs_resolved_promise(js, done) : fs_dir_enqueue(js, dir_obj, d, FS_OP_DIR_ITER_RETURN, done); GC_ROOT_RESTORE(js, root_mark); return promise;}
static ant_value_t builtin_fs_dir_asyncIterator(ant_params_t) { ant_value_t dir_obj = js->this_val; if (!js_get_native(dir_obj, FS_DIR_NATIVE_TAG)) return js_mkerr_typed(js, JS_ERR_TYPE, "Value of \"this\" must be of type Dir");
GC_ROOT_SAVE(root_mark, js); ant_value_t iter = Ant_Object_CreateBare(js); GC_ROOT_PIN(js, iter);
js_set_proto_init(iter, js->sym.async_iterator_proto); js_set(js, iter, "next", js_heavy_mkfun(js, fs_dir_iter_next, dir_obj)); js_set(js, iter, "return", js_heavy_mkfun(js, fs_dir_iter_return, dir_obj));
GC_ROOT_RESTORE(js, root_mark); return iter;}
static void fs_init_dir_proto(ant_t *js) { if (is_object_type(js->builtins.dir_proto)) return; ant_value_t proto = js->builtins.dir_proto = Ant_Object_CreateBare(js);
js_set(js, proto, "read", fs_make_callback_wrapper(js, Ant_Function_Create(builtin_fs_dir_read), false, "read", 1)); js_set(js, proto, "readSync", Ant_Function_Create(builtin_fs_dir_readSync)); js_set(js, proto, "close", fs_make_callback_wrapper(js, Ant_Function_Create(builtin_fs_dir_close), false, "close", 1)); js_set(js, proto, "closeSync", Ant_Function_Create(builtin_fs_dir_closeSync));
js_set_sym(js, proto, js->sym.asyncIterator_sym, Ant_Function_Create(builtin_fs_dir_asyncIterator)); js_set_sym(js, proto, js->sym.dispose_sym, Ant_Function_Create(builtin_fs_dir_dispose)); js_set_sym(js, proto, js->sym.asyncDispose_sym, Ant_Function_Create(builtin_fs_dir_asyncDispose)); js_set_tostringtag(js, proto, js_mkstr(js, "Dir", 3));}
typedef struct { ant_value_t path_value; char *path; size_t nentries; bool buffer_encoding; bool recursive;} fs_opendir_options_t;
static ant_value_t fs_parse_opendir_args( ant_t *js, ant_value_t *args, int nargs, const char *fn_name, fs_opendir_options_t *out) { memset(out, 0, sizeof(*out)); out->nentries = 32;
if (nargs < 1) return js_mkerr(js, "%s() requires a path argument", fn_name); ant_value_t original_path = args[0];
args[0] = fs_coerce_path(js, args[0]); if (is_err(args[0])) return args[0]; if (vtype(args[0]) != kTypeString) return js_mkerr(js, "%s() path must be a string", fn_name);
ant_value_t options = nargs > 1 ? args[1] : js_mkundef(); if (is_object_type(options)) { ant_value_t size_val = js_get(js, options, "bufferSize"); if (is_err(size_val)) return size_val; if (vtype(size_val) != kTypeUndefined) { double size = vtype(size_val) == kTypeNumber ? js_getnum(size_val) : 0; if (!(size >= 1 && size <= 4294967295.0) || size != (double)(size_t)size) return js_mkerr_typed( js, JS_ERR_RANGE, "The value of \"options.bufferSize\" is out of range. It must be >= 1 && <= 4294967295. Received %g", size ); out->nentries = (size_t)size; }
ant_value_t recursive = js_get(js, options, "recursive"); if (is_err(recursive)) return recursive; out->recursive = js_truthy(js, recursive); }
size_t path_len = 0; const char *path = js_getstr(js, args[0], &path_len); if (!path) return js_mkerr(js, "Failed to get path string");
out->path = strndup(path, path_len); if (!out->path) return js_mkerr(js, "Out of memory");
out->buffer_encoding = fs_buffer_encoding(js, options); out->path_value = fs_parent_path_value(original_path, args[0]);
return js_mkundef();}
static ant_value_t fs_make_dir(ant_t *js, uv_dir_t *handle, fs_opendir_options_t *opts) { fs_dir_t *d = calloc(1, sizeof(fs_dir_t)); if (d) { d->dirents = calloc(opts->nentries, sizeof(uv_dirent_t)); d->entries = calloc(opts->nentries, sizeof(fs_dir_entry_t)); }
if (!d || !d->dirents || !d->entries) { if (d) { free(d->dirents); free(d->entries); } free(d); uv_fs_t req; uv_fs_closedir(NULL, &req, handle, NULL); uv_fs_req_cleanup(&req); free(opts->path); return js_mkerr(js, "Out of memory"); }
d->dir = handle; d->path = opts->path; d->nentries = opts->nentries; d->buffer_encoding = opts->buffer_encoding; d->recursive = opts->recursive;
fs_init_dir_proto(js); GC_ROOT_SAVE(root_mark, js);
ant_value_t obj = Ant_Object_CreateBare(js); GC_ROOT_PIN(js, obj);
js_set_proto_init(obj, js->builtins.dir_proto); js_set_native(obj, d, FS_DIR_NATIVE_TAG); js_set_finalizer(obj, fs_dir_finalize); js_set(js, obj, "path", opts->path_value);
GC_ROOT_RESTORE(js, root_mark); return obj;}
static ant_value_t builtin_fs_opendirSync(ant_params_t) { fs_opendir_options_t opts; ant_value_t parsed = fs_parse_opendir_args(js, args, nargs, "opendirSync", &opts); if (is_err(parsed)) { free(opts.path); return parsed; }
GC_ROOT_SAVE(root_mark, js); GC_ROOT_PIN(js, opts.path_value);
uv_fs_t req; int rc = uv_fs_opendir(NULL, &req, opts.path, NULL);
if (rc == UV_EMFILE || rc == UV_ENFILE) { uv_fs_req_cleanup(&req); gc_run(js); rc = uv_fs_opendir(NULL, &req, opts.path, NULL); }
uv_dir_t *handle = rc < 0 ? NULL : (uv_dir_t *)req.ptr; uv_fs_req_cleanup(&req);
ant_value_t result = rc < 0 ? fs_mk_uv_error(js, rc, "opendir", opts.path, NULL) : fs_make_dir(js, handle, &opts);
if (rc < 0) free(opts.path); GC_ROOT_RESTORE(js, root_mark);
return result;}
static void on_opendir_complete(uv_fs_t *uv_req) { GC_UV_CALLBACK(); fs_request_t *req = (fs_request_t *)uv_req->data; ant_t *js = fs_req_isolate(req); int rc = (int)uv_req->result; uv_dir_t *handle = rc < 0 ? NULL : (uv_dir_t *)uv_req->ptr; uv_fs_req_cleanup(uv_req);
if ((rc == UV_EMFILE || rc == UV_ENFILE) && !req->retried) { req->retried = true; gc_run(js); if (uv_fs_opendir(js->loop, &req->uv_req, req->path, on_opendir_complete) == 0) return; }
ant_value_t result; if (rc < 0) result = fs_mk_uv_error(js, rc, "opendir", req->path, NULL); else { fs_opendir_options_t opts = { .path_value = is_object_type(req->owner) ? req->owner : js_mkstr(js, req->path, strlen(req->path)), .path = req->path, .nentries = req->data_len, .buffer_encoding = req->buffer_encoding, .recursive = req->recursive, }; GC_ROOT_SAVE(root_mark, js); GC_ROOT_PIN(js, opts.path_value); req->path = NULL; result = fs_make_dir(js, handle, &opts); GC_ROOT_RESTORE(js, root_mark); }
if (is_err(result)) js_reject_promise(js, req->promise, js_take_thrown(js, result)); else js_resolve_promise(js, req->promise, result);
req->completed = 1; Ant_List_Remove(req); free_fs_request(req);}
static ant_value_t builtin_fs_opendir(ant_params_t) { fs_opendir_options_t opts; ant_value_t parsed = fs_parse_opendir_args(js, args, nargs, "opendir", &opts); if (is_err(parsed)) { free(opts.path); return fs_rejected_promise(js, parsed); }
fs_request_t *req = calloc(1, sizeof(fs_request_t)); if (!req) { free(opts.path); return js_mkerr(js, "Out of memory"); }
req->uv_req.loop = js->loop; req->op_type = FS_OP_OPENDIR; req->promise = js_mkpromise(js); req->path = opts.path; req->owner = is_object_type(opts.path_value) ? opts.path_value : js_mkundef(); req->data_len = opts.nentries; req->buffer_encoding = opts.buffer_encoding; req->recursive = opts.recursive; req->uv_req.data = req;
ant_value_t promise = req->promise; Ant_List_Insert(&js->fs_requests, req);
int rc = uv_fs_opendir(js->loop, &req->uv_req, req->path, on_opendir_complete); if (rc < 0) { fs_request_fail(req, rc); req->completed = 1; complete_request(req); }
return promise;}
typedef struct { const char *name; ant_cfunc_t promise_fn; ant_cfunc_t callback_fn; uint8_t promise_length; uint8_t callback_length; bool exists_style;} fs_wrapped_method_t;
static const fs_wrapped_method_t fs_wrapped_methods[] = { { "appendFile", builtin_fs_appendFile, builtin_fs_appendFile, 3, 4, false }, { "cp", builtin_fs_cp, builtin_fs_cp, 3, 4, false }, { "copyFile", builtin_fs_copyFile, builtin_fs_copyFile, 3, 4, false }, { "readFile", builtin_fs_readFile, builtin_fs_readFile, 2, 3, false }, { "open", builtin_fs_open_filehandle, builtin_fs_open_fd, 3, 4, false }, { "close", builtin_fs_close_fd, builtin_fs_close_fd, 1, 1, false }, { "writeFile", builtin_fs_writeFile, builtin_fs_writeFile, 3, 4, false }, { "write", builtin_fs_write_fd, builtin_fs_write_fd, 5, 6, false }, { "writev", builtin_fs_writev_fd, builtin_fs_writev_fd, 3, 4, false }, { "rename", builtin_fs_rename, builtin_fs_rename, 2, 3, false }, { "rm", builtin_fs_rm, builtin_fs_rm, 2, 3, false }, { "unlink", builtin_fs_unlink, builtin_fs_unlink, 1, 2, false }, { "mkdir", builtin_fs_mkdir, builtin_fs_mkdir, 2, 3, false }, { "mkdtemp", builtin_fs_mkdtemp, builtin_fs_mkdtemp, 2, 3, false }, { "rmdir", builtin_fs_rmdir, builtin_fs_rmdir, 2, 3, false }, { "stat", builtin_fs_stat, builtin_fs_stat, 1, 1, false }, { "lstat", builtin_fs_lstat, builtin_fs_lstat, 1, 1, false }, { "fstat", builtin_fs_fstat, builtin_fs_fstat, 1, 1, false }, { "utimes", builtin_fs_utimes, builtin_fs_utimes, 3, 4, false }, { "futimes", builtin_fs_futimes, builtin_fs_futimes, 3, 4, false }, { "exists", builtin_fs_exists, builtin_fs_exists, 1, 2, true }, { "access", builtin_fs_access, builtin_fs_access, 1, 3, false }, { "chmod", builtin_fs_chmod, builtin_fs_chmod, 2, 3, false }, { "readdir", builtin_fs_readdir, builtin_fs_readdir, 2, 3, false }, { "realpath", builtin_fs_realpath, builtin_fs_realpath, 2, 3, false }, { "readlink", builtin_fs_readlink, builtin_fs_readlink, 2, 3, false }, { "symlink", builtin_fs_symlink, builtin_fs_symlink, 3, 4, false }, { "link", builtin_fs_link, builtin_fs_link, 2, 3, false }, { "opendir", builtin_fs_opendir, builtin_fs_opendir, 3, 3, false },};
static void fs_set_promise_methods(ant_t *js, ant_value_t lib) { for (size_t i = 0; i < countof(fs_wrapped_methods); i++) { const fs_wrapped_method_t *m = &fs_wrapped_methods[i]; js_set(js, lib, m->name, fs_make_promise_wrapper(js, js_mkfun_dyn(m->promise_fn), m->name, m->promise_length)); }}
static void fs_set_callback_compatible_methods(ant_t *js, ant_value_t lib) { for (size_t i = 0; i < countof(fs_wrapped_methods); i++) { const fs_wrapped_method_t *m = &fs_wrapped_methods[i]; js_set(js, lib, m->name, fs_make_callback_wrapper(js, js_mkfun_dyn(m->callback_fn), m->exists_style, m->name, m->callback_length)); }
ant_value_t realpath = js_get(js, lib, "realpath"); js_set(js, realpath, "native", realpath);}
ant_value_t fs_make_constants(ant_t *js) { ant_value_t constants = Ant_Object_Create(js); js_set(js, constants, "F_OK", js_mknum(F_OK)); js_set(js, constants, "R_OK", js_mknum(R_OK)); js_set(js, constants, "W_OK", js_mknum(W_OK)); js_set(js, constants, "X_OK", js_mknum(X_OK)); js_set(js, constants, "COPYFILE_EXCL", js_mknum(UV_FS_COPYFILE_EXCL)); js_set(js, constants, "COPYFILE_FICLONE", js_mknum(UV_FS_COPYFILE_FICLONE)); js_set(js, constants, "COPYFILE_FICLONE_FORCE", js_mknum(UV_FS_COPYFILE_FICLONE_FORCE)); js_set(js, constants, "O_RDONLY", js_mknum(O_RDONLY)); js_set(js, constants, "O_WRONLY", js_mknum(O_WRONLY)); js_set(js, constants, "O_RDWR", js_mknum(O_RDWR)); js_set(js, constants, "O_CREAT", js_mknum(O_CREAT)); js_set(js, constants, "O_EXCL", js_mknum(O_EXCL));#ifdef O_NOCTTY js_set(js, constants, "O_NOCTTY", js_mknum(O_NOCTTY));#else js_set(js, constants, "O_NOCTTY", js_mknum(0));#endif js_set(js, constants, "O_TRUNC", js_mknum(O_TRUNC)); js_set(js, constants, "O_APPEND", js_mknum(O_APPEND));#ifdef O_SYNC js_set(js, constants, "O_SYNC", js_mknum(O_SYNC));#else js_set(js, constants, "O_SYNC", js_mknum(0));#endif#ifdef O_SYMLINK js_set(js, constants, "O_SYMLINK", js_mknum(O_SYMLINK));#endif#ifdef O_NOFOLLOW js_set(js, constants, "O_NOFOLLOW", js_mknum(O_NOFOLLOW));#endif#ifdef S_IFMT js_set(js, constants, "S_IFMT", js_mknum(S_IFMT));#endif#ifdef S_IFREG js_set(js, constants, "S_IFREG", js_mknum(S_IFREG));#endif#ifdef S_IFDIR js_set(js, constants, "S_IFDIR", js_mknum(S_IFDIR));#endif#ifdef S_IFLNK js_set(js, constants, "S_IFLNK", js_mknum(S_IFLNK));#endif return constants;}
static ant_value_t builtin_fs_promises_getter(ant_params_t) { ant_value_t getter_fn = js_getcurrentfunc(js); ant_value_t cached = js_get_slot(getter_fn, SLOT_DATA); if (is_object_type(cached)) return cached;
ant_value_t promises = fs_promises_library(js); js_set_slot(getter_fn, SLOT_DATA, promises); return promises;}
ant_value_t fs_library(ant_t *js) { ant_value_t lib = Ant_Object_CreateBare(js); ant_value_t realpath_sync = Ant_Function_CreateWithData(js, builtin_fs_realpathSync, "realpathSync", 2, js_mkundef()); fs_set_callback_compatible_methods(js, lib); fs_init_watch_constructors(js); fs_init_stream_constructors(js);
js_set(js, lib, "read", Ant_Function_CreateWithArity(builtin_fs_read_fd, 6)); js_set(js, lib, "readFileSync", Ant_Function_CreateWithArity(builtin_fs_readFileSync, 2)); js_set(js, lib, "readSync", Ant_Function_CreateWithArity(builtin_fs_readSync, 5)); js_set(js, lib, "fsync", Ant_Function_CreateWithArity(builtin_fs_fsync, 2)); js_set(js, lib, "stream", Ant_Function_Create(builtin_fs_stream)); js_set(js, lib, "createReadStream", Ant_Function_CreateWithArity(builtin_fs_createReadStream, 2)); js_set(js, lib, "createWriteStream", Ant_Function_CreateWithArity(builtin_fs_createWriteStream, 2)); js_set(js, lib, "openSync", Ant_Function_CreateWithArity(builtin_fs_openSync, 3)); js_set(js, lib, "closeSync", Ant_Function_CreateWithArity(builtin_fs_closeSync, 1)); js_set(js, lib, "writeFileSync", Ant_Function_CreateWithArity(builtin_fs_writeFileSync, 3)); js_set(js, lib, "writeSync", Ant_Function_CreateWithArity(builtin_fs_writeSync, 5)); js_set(js, lib, "writevSync", Ant_Function_CreateWithArity(builtin_fs_writevSync, 3)); js_set(js, lib, "appendFileSync", Ant_Function_CreateWithArity(builtin_fs_appendFileSync, 3)); js_set(js, lib, "cpSync", Ant_Function_CreateWithArity(builtin_fs_cpSync, 3)); js_set(js, lib, "copyFileSync", Ant_Function_CreateWithArity(builtin_fs_copyFileSync, 3)); js_set(js, lib, "renameSync", Ant_Function_CreateWithArity(builtin_fs_renameSync, 2)); js_set(js, lib, "rmSync", Ant_Function_CreateWithArity(builtin_fs_rmSync, 2)); js_set(js, lib, "unlinkSync", Ant_Function_CreateWithArity(builtin_fs_unlinkSync, 1)); js_set(js, lib, "mkdirSync", Ant_Function_CreateWithArity(builtin_fs_mkdirSync, 2)); js_set(js, lib, "mkdtempSync", Ant_Function_CreateWithArity(builtin_fs_mkdtempSync, 2)); js_set(js, lib, "rmdirSync", Ant_Function_CreateWithArity(builtin_fs_rmdirSync, 2)); js_set(js, lib, "statSync", Ant_Function_CreateWithArity(builtin_fs_statSync, 1)); js_set(js, lib, "lstatSync", Ant_Function_CreateWithArity(builtin_fs_lstatSync, 1)); js_set(js, lib, "fstatSync", Ant_Function_CreateWithArity(builtin_fs_fstatSync, 1)); js_set(js, lib, "fsyncSync", Ant_Function_CreateWithArity(builtin_fs_fsyncSync, 1)); js_set(js, lib, "utimesSync", Ant_Function_CreateWithArity(builtin_fs_utimesSync, 3)); js_set(js, lib, "futimesSync", Ant_Function_CreateWithArity(builtin_fs_futimesSync, 3)); js_set(js, lib, "truncateSync", Ant_Function_CreateWithArity(builtin_fs_truncateSync, 2)); js_set(js, lib, "ftruncateSync", Ant_Function_CreateWithArity(builtin_fs_ftruncateSync, 1)); js_set(js, lib, "existsSync", Ant_Function_CreateWithArity(builtin_fs_existsSync, 1)); js_set(js, lib, "accessSync", Ant_Function_CreateWithArity(builtin_fs_accessSync, 2)); js_set(js, lib, "chmodSync", Ant_Function_CreateWithArity(builtin_fs_chmodSync, 2)); js_set(js, lib, "readdirSync", Ant_Function_CreateWithArity(builtin_fs_readdirSync, 2)); js_set(js, lib, "realpathSync", realpath_sync); js_set(js, lib, "readlinkSync", Ant_Function_CreateWithArity(builtin_fs_readlinkSync, 2)); js_set(js, lib, "symlinkSync", Ant_Function_CreateWithArity(builtin_fs_symlinkSync, 3)); js_set(js, lib, "linkSync", Ant_Function_CreateWithArity(builtin_fs_linkSync, 2)); js_set(js, lib, "opendirSync", Ant_Function_CreateWithArity(builtin_fs_opendirSync, 2)); js_set(js, lib, "watch", Ant_Function_CreateWithArity(builtin_fs_watch, 3)); js_set(js, lib, "watchFile", Ant_Function_CreateWithArity(builtin_fs_watchFile, 3)); js_set(js, lib, "unwatchFile", Ant_Function_CreateWithArity(builtin_fs_unwatchFile, 2)); js_set(js, lib, "FSWatcher", js->builtins.fswatcher_ctor); js_set(js, lib, "ReadStream", js->builtins.readstream_ctor); js_set(js, lib, "WriteStream", js->builtins.writestream_ctor); js_set(js, lib, "Stats", js->builtins.stats_ctor); js_set(js, lib, "Dirent", js->builtins.dirent_ctor); js_set(js, realpath_sync, "native", realpath_sync); js_set_getter_desc( js, lib, "promises", 8, js_heavy_mkfun(js, builtin_fs_promises_getter, js_mkundef()), JS_DESC_E | JS_DESC_C ); js_set(js, lib, "constants", fs_make_constants(js)); js_set_tostringtag(js, lib, js_mkstr(js, "fs", 2)); return lib;}
ant_value_t fs_promises_library(ant_t *js) { ant_value_t lib = Ant_Object_CreateBare(js);
fs_set_promise_methods(js, lib); js_set(js, lib, "constants", fs_make_constants(js));
js_set_tostringtag(js, lib, js_mkstr(js, "fs/promises", 11)); return lib;}
ant_value_t fs_constants_library(ant_t *js) { ant_value_t constants = fs_make_constants(js); js_set(js, constants, "default", constants); js_set_slot_wb(js, constants, SLOT_DEFAULT, constants); js_set_tostringtag(js, constants, js_mkstr(js, "constants", 9)); return constants;}
int has_pending_fs_ops(ant_t *js) { return js->fs_requests != NULL;}
void gc_mark_fs(ant_t *js, gc_mark_fn mark) { for (fs_request_t *req = js->fs_requests; req; req = req->next) { mark(js, req->promise); if (is_object_type(req->target_buffer)) mark(js, req->target_buffer); if (is_object_type(req->owner)) mark(js, req->owner); if (is_callable(req->callback_fn)) mark(js, req->callback_fn); if (is_object_type(req->signal)) mark(js, req->signal); }
for (fs_watcher_t *watcher = js->fs_watchers; watcher; watcher = watcher->next) { if (vtype(watcher->obj) == kTypeObject) mark(js, watcher->obj); if (vtype(watcher->callback) != kTypeUndefined) mark(js, watcher->callback); }}