ActorsParent.cpp 195 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  4. * You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "ActorsParent.h"
  6. #include "mozIStorageConnection.h"
  7. #include "mozIStorageService.h"
  8. #include "nsIBinaryInputStream.h"
  9. #include "nsIBinaryOutputStream.h"
  10. #include "nsIFile.h"
  11. #include "nsIFileStreams.h"
  12. #include "nsIObserverService.h"
  13. #include "nsIPermissionManager.h"
  14. #include "nsIPrincipal.h"
  15. #include "nsIRunnable.h"
  16. #include "nsISimpleEnumerator.h"
  17. #include "nsIScriptObjectPrincipal.h"
  18. #include "nsIScriptSecurityManager.h"
  19. #include "nsITimer.h"
  20. #include "nsIURI.h"
  21. #include "nsPIDOMWindow.h"
  22. #include <algorithm>
  23. #include "GeckoProfiler.h"
  24. #include "mozilla/Atomics.h"
  25. #include "mozilla/BasePrincipal.h"
  26. #include "mozilla/CondVar.h"
  27. #include "mozilla/dom/PContent.h"
  28. #include "mozilla/dom/asmjscache/AsmJSCache.h"
  29. #include "mozilla/dom/cache/QuotaClient.h"
  30. #include "mozilla/dom/indexedDB/ActorsParent.h"
  31. #include "mozilla/dom/quota/PQuotaParent.h"
  32. #include "mozilla/dom/quota/PQuotaRequestParent.h"
  33. #include "mozilla/dom/quota/PQuotaUsageRequestParent.h"
  34. #include "mozilla/ipc/BackgroundParent.h"
  35. #include "mozilla/ipc/BackgroundUtils.h"
  36. #include "mozilla/IntegerRange.h"
  37. #include "mozilla/Mutex.h"
  38. #include "mozilla/LazyIdleThread.h"
  39. #include "mozilla/Preferences.h"
  40. #include "mozilla/Services.h"
  41. #include "mozilla/StaticPtr.h"
  42. #include "mozilla/TypeTraits.h"
  43. #include "mozilla/Unused.h"
  44. #include "mozStorageCID.h"
  45. #include "mozStorageHelper.h"
  46. #include "nsAppDirectoryServiceDefs.h"
  47. #include "nsComponentManagerUtils.h"
  48. #include "nsAboutProtocolUtils.h"
  49. #include "nsCharSeparatedTokenizer.h"
  50. #include "nsContentUtils.h"
  51. #include "nsCRTGlue.h"
  52. #include "nsDirectoryServiceUtils.h"
  53. #include "nsEscape.h"
  54. #include "nsNetUtil.h"
  55. #include "nsPrintfCString.h"
  56. #include "nsScriptSecurityManager.h"
  57. #include "nsThreadUtils.h"
  58. #include "nsXULAppAPI.h"
  59. #include "prio.h"
  60. #include "xpcpublic.h"
  61. #include "OriginScope.h"
  62. #include "QuotaManager.h"
  63. #include "QuotaManagerService.h"
  64. #include "QuotaObject.h"
  65. #include "UsageInfo.h"
  66. #define DISABLE_ASSERTS_FOR_FUZZING 0
  67. #if DISABLE_ASSERTS_FOR_FUZZING
  68. #define ASSERT_UNLESS_FUZZING(...) do { } while (0)
  69. #else
  70. #define ASSERT_UNLESS_FUZZING(...) MOZ_ASSERT(false, __VA_ARGS__)
  71. #endif
  72. // The amount of time, in milliseconds, that our IO thread will stay alive
  73. // after the last event it processes.
  74. #define DEFAULT_THREAD_TIMEOUT_MS 30000
  75. // The amount of time, in milliseconds, that we will wait for active storage
  76. // transactions on shutdown before aborting them.
  77. #define DEFAULT_SHUTDOWN_TIMER_MS 30000
  78. // Preference that users can set to override temporary storage smart limit
  79. // calculation.
  80. #define PREF_FIXED_LIMIT "dom.quotaManager.temporaryStorage.fixedLimit"
  81. #define PREF_CHUNK_SIZE "dom.quotaManager.temporaryStorage.chunkSize"
  82. // Preference that is used to enable testing features
  83. #define PREF_TESTING_FEATURES "dom.quotaManager.testing"
  84. // profile-before-change, when we need to shut down quota manager
  85. #define PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID "profile-before-change-qm"
  86. #define KB * 1024ULL
  87. #define MB * 1024ULL KB
  88. #define GB * 1024ULL MB
  89. namespace mozilla {
  90. namespace dom {
  91. namespace quota {
  92. using namespace mozilla::ipc;
  93. // We want profiles to be platform-independent so we always need to replace
  94. // the same characters on every platform. Windows has the most extensive set
  95. // of illegal characters so we use its FILE_ILLEGAL_CHARACTERS and
  96. // FILE_PATH_SEPARATOR.
  97. const char QuotaManager::kReplaceChars[] = CONTROL_CHARACTERS "/:*?\"<>|\\";
  98. namespace {
  99. /*******************************************************************************
  100. * Constants
  101. ******************************************************************************/
  102. const uint32_t kSQLitePageSizeOverride = 512;
  103. // Major storage version. Bump for backwards-incompatible changes.
  104. const uint32_t kMajorStorageVersion = 1;
  105. // Minor storage version. Bump for backwards-compatible changes.
  106. const uint32_t kMinorStorageVersion = 0;
  107. // The storage version we store in the SQLite database is a (signed) 32-bit
  108. // integer. The major version is left-shifted 16 bits so the max value is
  109. // 0xFFFF. The minor version occupies the lower 16 bits and its max is 0xFFFF.
  110. static_assert(kMajorStorageVersion <= 0xFFFF,
  111. "Major version needs to fit in 16 bits.");
  112. static_assert(kMinorStorageVersion <= 0xFFFF,
  113. "Minor version needs to fit in 16 bits.");
  114. const int32_t kStorageVersion =
  115. int32_t((kMajorStorageVersion << 16) + kMinorStorageVersion);
  116. static_assert(
  117. static_cast<uint32_t>(StorageType::Persistent) ==
  118. static_cast<uint32_t>(PERSISTENCE_TYPE_PERSISTENT),
  119. "Enum values should match.");
  120. static_assert(
  121. static_cast<uint32_t>(StorageType::Temporary) ==
  122. static_cast<uint32_t>(PERSISTENCE_TYPE_TEMPORARY),
  123. "Enum values should match.");
  124. static_assert(
  125. static_cast<uint32_t>(StorageType::Default) ==
  126. static_cast<uint32_t>(PERSISTENCE_TYPE_DEFAULT),
  127. "Enum values should match.");
  128. const char kChromeOrigin[] = "chrome";
  129. const char kAboutHomeOriginPrefix[] = "moz-safe-about:home";
  130. const char kIndexedDBOriginPrefix[] = "indexeddb://";
  131. const char kResourceOriginPrefix[] = "resource://";
  132. #define INDEXEDDB_DIRECTORY_NAME "indexedDB"
  133. #define STORAGE_DIRECTORY_NAME "storage"
  134. #define PERSISTENT_DIRECTORY_NAME "persistent"
  135. #define PERMANENT_DIRECTORY_NAME "permanent"
  136. #define TEMPORARY_DIRECTORY_NAME "temporary"
  137. #define DEFAULT_DIRECTORY_NAME "default"
  138. enum AppId {
  139. kNoAppId = nsIScriptSecurityManager::NO_APP_ID,
  140. kUnknownAppId = nsIScriptSecurityManager::UNKNOWN_APP_ID
  141. };
  142. #define STORAGE_FILE_NAME "storage.sqlite"
  143. // The name of the file that we use to load/save the last access time of an
  144. // origin.
  145. #define METADATA_FILE_NAME ".metadata"
  146. #define METADATA_V2_FILE_NAME ".metadata-v2"
  147. /******************************************************************************
  148. * SQLite functions
  149. ******************************************************************************/
  150. #if 0
  151. int32_t
  152. MakeStorageVersion(uint32_t aMajorStorageVersion,
  153. uint32_t aMinorStorageVersion)
  154. {
  155. return int32_t((aMajorStorageVersion << 16) + aMinorStorageVersion);
  156. }
  157. #endif
  158. uint32_t
  159. GetMajorStorageVersion(int32_t aStorageVersion)
  160. {
  161. return uint32_t(aStorageVersion >> 16);
  162. }
  163. /******************************************************************************
  164. * Quota manager class declarations
  165. ******************************************************************************/
  166. } // namespace
  167. class DirectoryLockImpl final
  168. : public DirectoryLock
  169. {
  170. RefPtr<QuotaManager> mQuotaManager;
  171. const Nullable<PersistenceType> mPersistenceType;
  172. const nsCString mGroup;
  173. const OriginScope mOriginScope;
  174. const Nullable<bool> mIsApp;
  175. const Nullable<Client::Type> mClientType;
  176. RefPtr<OpenDirectoryListener> mOpenListener;
  177. nsTArray<DirectoryLockImpl*> mBlocking;
  178. nsTArray<DirectoryLockImpl*> mBlockedOn;
  179. const bool mExclusive;
  180. // Internal quota manager operations use this flag to prevent directory lock
  181. // registraction/unregistration from updating origin access time, etc.
  182. const bool mInternal;
  183. bool mInvalidated;
  184. public:
  185. DirectoryLockImpl(QuotaManager* aQuotaManager,
  186. Nullable<PersistenceType> aPersistenceType,
  187. const nsACString& aGroup,
  188. const OriginScope& aOriginScope,
  189. Nullable<bool> aIsApp,
  190. Nullable<Client::Type> aClientType,
  191. bool aExclusive,
  192. bool aInternal,
  193. OpenDirectoryListener* aOpenListener);
  194. void
  195. AssertIsOnOwningThread() const
  196. #ifdef DEBUG
  197. ;
  198. #else
  199. { }
  200. #endif
  201. const Nullable<PersistenceType>&
  202. GetPersistenceType() const
  203. {
  204. return mPersistenceType;
  205. }
  206. const nsACString&
  207. GetGroup() const
  208. {
  209. return mGroup;
  210. }
  211. const OriginScope&
  212. GetOriginScope() const
  213. {
  214. return mOriginScope;
  215. }
  216. const Nullable<bool>&
  217. GetIsApp() const
  218. {
  219. return mIsApp;
  220. }
  221. const Nullable<Client::Type>&
  222. GetClientType() const
  223. {
  224. return mClientType;
  225. }
  226. bool
  227. IsInternal() const
  228. {
  229. return mInternal;
  230. }
  231. bool
  232. ShouldUpdateLockTable()
  233. {
  234. return !mInternal &&
  235. mPersistenceType.Value() != PERSISTENCE_TYPE_PERSISTENT;
  236. }
  237. // Test whether this DirectoryLock needs to wait for the given lock.
  238. bool
  239. MustWaitFor(const DirectoryLockImpl& aLock);
  240. void
  241. AddBlockingLock(DirectoryLockImpl* aLock)
  242. {
  243. AssertIsOnOwningThread();
  244. mBlocking.AppendElement(aLock);
  245. }
  246. const nsTArray<DirectoryLockImpl*>&
  247. GetBlockedOnLocks()
  248. {
  249. return mBlockedOn;
  250. }
  251. void
  252. AddBlockedOnLock(DirectoryLockImpl* aLock)
  253. {
  254. AssertIsOnOwningThread();
  255. mBlockedOn.AppendElement(aLock);
  256. }
  257. void
  258. MaybeUnblock(DirectoryLockImpl* aLock)
  259. {
  260. AssertIsOnOwningThread();
  261. mBlockedOn.RemoveElement(aLock);
  262. if (mBlockedOn.IsEmpty()) {
  263. NotifyOpenListener();
  264. }
  265. }
  266. void
  267. NotifyOpenListener();
  268. void
  269. Invalidate()
  270. {
  271. AssertIsOnOwningThread();
  272. mInvalidated = true;
  273. }
  274. NS_INLINE_DECL_REFCOUNTING(DirectoryLockImpl)
  275. private:
  276. ~DirectoryLockImpl();
  277. };
  278. class QuotaManager::CreateRunnable final
  279. : public BackgroundThreadObject
  280. , public Runnable
  281. {
  282. nsTArray<nsCOMPtr<nsIRunnable>> mCallbacks;
  283. nsString mBaseDirPath;
  284. RefPtr<QuotaManager> mManager;
  285. nsresult mResultCode;
  286. enum class State
  287. {
  288. Initial,
  289. CreatingManager,
  290. RegisteringObserver,
  291. CallingCallbacks,
  292. Completed
  293. };
  294. State mState;
  295. public:
  296. CreateRunnable()
  297. : mResultCode(NS_OK)
  298. , mState(State::Initial)
  299. {
  300. AssertIsOnBackgroundThread();
  301. }
  302. void
  303. AddCallback(nsIRunnable* aCallback)
  304. {
  305. AssertIsOnOwningThread();
  306. MOZ_ASSERT(aCallback);
  307. mCallbacks.AppendElement(aCallback);
  308. }
  309. private:
  310. ~CreateRunnable()
  311. { }
  312. nsresult
  313. Init();
  314. nsresult
  315. CreateManager();
  316. nsresult
  317. RegisterObserver();
  318. void
  319. CallCallbacks();
  320. State
  321. GetNextState(nsCOMPtr<nsIEventTarget>& aThread);
  322. NS_DECL_NSIRUNNABLE
  323. };
  324. class QuotaManager::ShutdownRunnable final
  325. : public Runnable
  326. {
  327. // Only touched on the main thread.
  328. bool& mDone;
  329. public:
  330. explicit ShutdownRunnable(bool& aDone)
  331. : mDone(aDone)
  332. {
  333. MOZ_ASSERT(NS_IsMainThread());
  334. }
  335. private:
  336. ~ShutdownRunnable()
  337. { }
  338. NS_DECL_NSIRUNNABLE
  339. };
  340. class QuotaManager::ShutdownObserver final
  341. : public nsIObserver
  342. {
  343. nsCOMPtr<nsIEventTarget> mBackgroundThread;
  344. public:
  345. explicit ShutdownObserver(nsIEventTarget* aBackgroundThread)
  346. : mBackgroundThread(aBackgroundThread)
  347. {
  348. MOZ_ASSERT(NS_IsMainThread());
  349. }
  350. NS_DECL_ISUPPORTS
  351. NS_DECL_NSIOBSERVER
  352. private:
  353. ~ShutdownObserver()
  354. {
  355. MOZ_ASSERT(NS_IsMainThread());
  356. }
  357. };
  358. namespace {
  359. /*******************************************************************************
  360. * Local class declarations
  361. ******************************************************************************/
  362. } // namespace
  363. class OriginInfo final
  364. {
  365. friend class GroupInfo;
  366. friend class QuotaManager;
  367. friend class QuotaObject;
  368. public:
  369. OriginInfo(GroupInfo* aGroupInfo, const nsACString& aOrigin, bool aIsApp,
  370. uint64_t aUsage, int64_t aAccessTime)
  371. : mGroupInfo(aGroupInfo), mOrigin(aOrigin), mUsage(aUsage),
  372. mAccessTime(aAccessTime), mIsApp(aIsApp)
  373. {
  374. MOZ_COUNT_CTOR(OriginInfo);
  375. }
  376. NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OriginInfo)
  377. int64_t
  378. AccessTime() const
  379. {
  380. return mAccessTime;
  381. }
  382. private:
  383. // Private destructor, to discourage deletion outside of Release():
  384. ~OriginInfo()
  385. {
  386. MOZ_COUNT_DTOR(OriginInfo);
  387. MOZ_ASSERT(!mQuotaObjects.Count());
  388. }
  389. void
  390. LockedDecreaseUsage(int64_t aSize);
  391. void
  392. LockedUpdateAccessTime(int64_t aAccessTime)
  393. {
  394. AssertCurrentThreadOwnsQuotaMutex();
  395. mAccessTime = aAccessTime;
  396. }
  397. nsDataHashtable<nsStringHashKey, QuotaObject*> mQuotaObjects;
  398. GroupInfo* mGroupInfo;
  399. const nsCString mOrigin;
  400. uint64_t mUsage;
  401. int64_t mAccessTime;
  402. const bool mIsApp;
  403. };
  404. class OriginInfoLRUComparator
  405. {
  406. public:
  407. bool
  408. Equals(const OriginInfo* a, const OriginInfo* b) const
  409. {
  410. return
  411. a && b ? a->AccessTime() == b->AccessTime() : !a && !b ? true : false;
  412. }
  413. bool
  414. LessThan(const OriginInfo* a, const OriginInfo* b) const
  415. {
  416. return a && b ? a->AccessTime() < b->AccessTime() : b ? true : false;
  417. }
  418. };
  419. class GroupInfo final
  420. {
  421. friend class GroupInfoPair;
  422. friend class OriginInfo;
  423. friend class QuotaManager;
  424. friend class QuotaObject;
  425. public:
  426. GroupInfo(GroupInfoPair* aGroupInfoPair, PersistenceType aPersistenceType,
  427. const nsACString& aGroup)
  428. : mGroupInfoPair(aGroupInfoPair), mPersistenceType(aPersistenceType),
  429. mGroup(aGroup), mUsage(0)
  430. {
  431. MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
  432. MOZ_COUNT_CTOR(GroupInfo);
  433. }
  434. NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GroupInfo)
  435. private:
  436. // Private destructor, to discourage deletion outside of Release():
  437. ~GroupInfo()
  438. {
  439. MOZ_COUNT_DTOR(GroupInfo);
  440. }
  441. already_AddRefed<OriginInfo>
  442. LockedGetOriginInfo(const nsACString& aOrigin);
  443. void
  444. LockedAddOriginInfo(OriginInfo* aOriginInfo);
  445. void
  446. LockedRemoveOriginInfo(const nsACString& aOrigin);
  447. void
  448. LockedRemoveOriginInfos();
  449. bool
  450. LockedHasOriginInfos()
  451. {
  452. AssertCurrentThreadOwnsQuotaMutex();
  453. return !mOriginInfos.IsEmpty();
  454. }
  455. nsTArray<RefPtr<OriginInfo> > mOriginInfos;
  456. GroupInfoPair* mGroupInfoPair;
  457. PersistenceType mPersistenceType;
  458. nsCString mGroup;
  459. uint64_t mUsage;
  460. };
  461. class GroupInfoPair
  462. {
  463. friend class QuotaManager;
  464. friend class QuotaObject;
  465. public:
  466. GroupInfoPair()
  467. {
  468. MOZ_COUNT_CTOR(GroupInfoPair);
  469. }
  470. ~GroupInfoPair()
  471. {
  472. MOZ_COUNT_DTOR(GroupInfoPair);
  473. }
  474. private:
  475. already_AddRefed<GroupInfo>
  476. LockedGetGroupInfo(PersistenceType aPersistenceType)
  477. {
  478. AssertCurrentThreadOwnsQuotaMutex();
  479. MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
  480. RefPtr<GroupInfo> groupInfo =
  481. GetGroupInfoForPersistenceType(aPersistenceType);
  482. return groupInfo.forget();
  483. }
  484. void
  485. LockedSetGroupInfo(PersistenceType aPersistenceType, GroupInfo* aGroupInfo)
  486. {
  487. AssertCurrentThreadOwnsQuotaMutex();
  488. MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
  489. RefPtr<GroupInfo>& groupInfo =
  490. GetGroupInfoForPersistenceType(aPersistenceType);
  491. groupInfo = aGroupInfo;
  492. }
  493. void
  494. LockedClearGroupInfo(PersistenceType aPersistenceType)
  495. {
  496. AssertCurrentThreadOwnsQuotaMutex();
  497. MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
  498. RefPtr<GroupInfo>& groupInfo =
  499. GetGroupInfoForPersistenceType(aPersistenceType);
  500. groupInfo = nullptr;
  501. }
  502. bool
  503. LockedHasGroupInfos()
  504. {
  505. AssertCurrentThreadOwnsQuotaMutex();
  506. return mTemporaryStorageGroupInfo || mDefaultStorageGroupInfo;
  507. }
  508. RefPtr<GroupInfo>&
  509. GetGroupInfoForPersistenceType(PersistenceType aPersistenceType);
  510. RefPtr<GroupInfo> mTemporaryStorageGroupInfo;
  511. RefPtr<GroupInfo> mDefaultStorageGroupInfo;
  512. };
  513. namespace {
  514. class CollectOriginsHelper final
  515. : public Runnable
  516. {
  517. uint64_t mMinSizeToBeFreed;
  518. Mutex& mMutex;
  519. CondVar mCondVar;
  520. // The members below are protected by mMutex.
  521. nsTArray<RefPtr<DirectoryLockImpl>> mLocks;
  522. uint64_t mSizeToBeFreed;
  523. bool mWaiting;
  524. public:
  525. CollectOriginsHelper(mozilla::Mutex& aMutex,
  526. uint64_t aMinSizeToBeFreed);
  527. // Blocks the current thread until origins are collected on the main thread.
  528. // The returned value contains an aggregate size of those origins.
  529. int64_t
  530. BlockAndReturnOriginsForEviction(
  531. nsTArray<RefPtr<DirectoryLockImpl>>& aLocks);
  532. private:
  533. ~CollectOriginsHelper()
  534. { }
  535. NS_IMETHOD
  536. Run() override;
  537. };
  538. class OriginOperationBase
  539. : public BackgroundThreadObject
  540. , public Runnable
  541. {
  542. protected:
  543. nsresult mResultCode;
  544. enum State {
  545. // Not yet run.
  546. State_Initial,
  547. // Running initialization on the main thread.
  548. State_Initializing,
  549. // Running initialization on the owning thread.
  550. State_FinishingInit,
  551. // Running quota manager initialization on the owning thread.
  552. State_CreatingQuotaManager,
  553. // Running on the owning thread in the listener for OpenDirectory.
  554. State_DirectoryOpenPending,
  555. // Running on the IO thread.
  556. State_DirectoryWorkOpen,
  557. // Running on the owning thread after all work is done.
  558. State_UnblockingOpen,
  559. // All done.
  560. State_Complete
  561. };
  562. private:
  563. State mState;
  564. bool mActorDestroyed;
  565. protected:
  566. bool mNeedsMainThreadInit;
  567. bool mNeedsQuotaManagerInit;
  568. public:
  569. void
  570. NoteActorDestroyed()
  571. {
  572. AssertIsOnOwningThread();
  573. mActorDestroyed = true;
  574. }
  575. bool
  576. IsActorDestroyed() const
  577. {
  578. AssertIsOnOwningThread();
  579. return mActorDestroyed;
  580. }
  581. protected:
  582. explicit OriginOperationBase(
  583. nsIEventTarget* aOwningThread = NS_GetCurrentThread())
  584. : BackgroundThreadObject(aOwningThread)
  585. , mResultCode(NS_OK)
  586. , mState(State_Initial)
  587. , mActorDestroyed(false)
  588. , mNeedsMainThreadInit(false)
  589. , mNeedsQuotaManagerInit(false)
  590. { }
  591. // Reference counted.
  592. virtual ~OriginOperationBase()
  593. {
  594. MOZ_ASSERT(mState == State_Complete);
  595. MOZ_ASSERT(mActorDestroyed);
  596. }
  597. State
  598. GetState() const
  599. {
  600. return mState;
  601. }
  602. void
  603. SetState(State aState)
  604. {
  605. MOZ_ASSERT(mState == State_Initial);
  606. mState = aState;
  607. }
  608. void
  609. AdvanceState()
  610. {
  611. switch (mState) {
  612. case State_Initial:
  613. mState = State_Initializing;
  614. return;
  615. case State_Initializing:
  616. mState = State_FinishingInit;
  617. return;
  618. case State_FinishingInit:
  619. mState = State_CreatingQuotaManager;
  620. return;
  621. case State_CreatingQuotaManager:
  622. mState = State_DirectoryOpenPending;
  623. return;
  624. case State_DirectoryOpenPending:
  625. mState = State_DirectoryWorkOpen;
  626. return;
  627. case State_DirectoryWorkOpen:
  628. mState = State_UnblockingOpen;
  629. return;
  630. case State_UnblockingOpen:
  631. mState = State_Complete;
  632. return;
  633. default:
  634. MOZ_CRASH("Bad state!");
  635. }
  636. }
  637. NS_IMETHOD
  638. Run() override;
  639. virtual nsresult
  640. DoInitOnMainThread()
  641. {
  642. return NS_OK;
  643. }
  644. virtual void
  645. Open() = 0;
  646. nsresult
  647. DirectoryOpen();
  648. virtual nsresult
  649. DoDirectoryWork(QuotaManager* aQuotaManager) = 0;
  650. void
  651. Finish(nsresult aResult);
  652. virtual void
  653. UnblockOpen() = 0;
  654. private:
  655. nsresult
  656. Init();
  657. nsresult
  658. InitOnMainThread();
  659. nsresult
  660. FinishInit();
  661. nsresult
  662. QuotaManagerOpen();
  663. nsresult
  664. DirectoryWork();
  665. };
  666. class FinalizeOriginEvictionOp
  667. : public OriginOperationBase
  668. {
  669. nsTArray<RefPtr<DirectoryLockImpl>> mLocks;
  670. public:
  671. FinalizeOriginEvictionOp(nsIEventTarget* aBackgroundThread,
  672. nsTArray<RefPtr<DirectoryLockImpl>>& aLocks)
  673. : OriginOperationBase(aBackgroundThread)
  674. {
  675. MOZ_ASSERT(!NS_IsMainThread());
  676. mLocks.SwapElements(aLocks);
  677. }
  678. void
  679. Dispatch();
  680. void
  681. RunOnIOThreadImmediately();
  682. private:
  683. ~FinalizeOriginEvictionOp()
  684. { }
  685. virtual void
  686. Open() override;
  687. virtual nsresult
  688. DoDirectoryWork(QuotaManager* aQuotaManager) override;
  689. virtual void
  690. UnblockOpen() override;
  691. };
  692. class NormalOriginOperationBase
  693. : public OriginOperationBase
  694. , public OpenDirectoryListener
  695. {
  696. RefPtr<DirectoryLock> mDirectoryLock;
  697. protected:
  698. Nullable<PersistenceType> mPersistenceType;
  699. OriginScope mOriginScope;
  700. mozilla::Atomic<bool> mCanceled;
  701. const bool mExclusive;
  702. public:
  703. void
  704. RunImmediately()
  705. {
  706. MOZ_ASSERT(GetState() == State_Initial);
  707. MOZ_ALWAYS_SUCCEEDS(this->Run());
  708. }
  709. protected:
  710. NormalOriginOperationBase(Nullable<PersistenceType> aPersistenceType,
  711. const OriginScope& aOriginScope,
  712. bool aExclusive)
  713. : mPersistenceType(aPersistenceType)
  714. , mOriginScope(aOriginScope)
  715. , mExclusive(aExclusive)
  716. {
  717. AssertIsOnOwningThread();
  718. }
  719. ~NormalOriginOperationBase()
  720. { }
  721. private:
  722. NS_DECL_ISUPPORTS_INHERITED
  723. virtual void
  724. Open() override;
  725. virtual void
  726. UnblockOpen() override;
  727. // OpenDirectoryListener overrides.
  728. virtual void
  729. DirectoryLockAcquired(DirectoryLock* aLock) override;
  730. virtual void
  731. DirectoryLockFailed() override;
  732. // Used to send results before unblocking open.
  733. virtual void
  734. SendResults() = 0;
  735. };
  736. class SaveOriginAccessTimeOp
  737. : public NormalOriginOperationBase
  738. {
  739. int64_t mTimestamp;
  740. public:
  741. SaveOriginAccessTimeOp(PersistenceType aPersistenceType,
  742. const nsACString& aOrigin,
  743. int64_t aTimestamp)
  744. : NormalOriginOperationBase(Nullable<PersistenceType>(aPersistenceType),
  745. OriginScope::FromOrigin(aOrigin),
  746. /* aExclusive */ false)
  747. , mTimestamp(aTimestamp)
  748. {
  749. AssertIsOnOwningThread();
  750. }
  751. private:
  752. ~SaveOriginAccessTimeOp()
  753. { }
  754. virtual nsresult
  755. DoDirectoryWork(QuotaManager* aQuotaManager) override;
  756. virtual void
  757. SendResults() override;
  758. };
  759. /*******************************************************************************
  760. * Actor class declarations
  761. ******************************************************************************/
  762. class Quota final
  763. : public PQuotaParent
  764. {
  765. #ifdef DEBUG
  766. bool mActorDestroyed;
  767. #endif
  768. public:
  769. Quota();
  770. NS_INLINE_DECL_THREADSAFE_REFCOUNTING(mozilla::dom::quota::Quota)
  771. private:
  772. ~Quota();
  773. void
  774. StartIdleMaintenance();
  775. // IPDL methods.
  776. virtual void
  777. ActorDestroy(ActorDestroyReason aWhy) override;
  778. virtual PQuotaUsageRequestParent*
  779. AllocPQuotaUsageRequestParent(const UsageRequestParams& aParams) override;
  780. virtual bool
  781. RecvPQuotaUsageRequestConstructor(PQuotaUsageRequestParent* aActor,
  782. const UsageRequestParams& aParams) override;
  783. virtual bool
  784. DeallocPQuotaUsageRequestParent(PQuotaUsageRequestParent* aActor) override;
  785. virtual PQuotaRequestParent*
  786. AllocPQuotaRequestParent(const RequestParams& aParams) override;
  787. virtual bool
  788. RecvPQuotaRequestConstructor(PQuotaRequestParent* aActor,
  789. const RequestParams& aParams) override;
  790. virtual bool
  791. DeallocPQuotaRequestParent(PQuotaRequestParent* aActor) override;
  792. virtual bool
  793. RecvStartIdleMaintenance() override;
  794. virtual bool
  795. RecvStopIdleMaintenance() override;
  796. };
  797. class QuotaUsageRequestBase
  798. : public NormalOriginOperationBase
  799. , public PQuotaUsageRequestParent
  800. {
  801. public:
  802. // May be overridden by subclasses if they need to perform work on the
  803. // background thread before being run.
  804. virtual bool
  805. Init(Quota* aQuota);
  806. protected:
  807. QuotaUsageRequestBase()
  808. : NormalOriginOperationBase(Nullable<PersistenceType>(),
  809. OriginScope::FromNull(),
  810. /* aExclusive */ false)
  811. { }
  812. nsresult
  813. GetUsageForOrigin(QuotaManager* aQuotaManager,
  814. PersistenceType aPersistenceType,
  815. const nsACString& aGroup,
  816. const nsACString& aOrigin,
  817. bool aIsApp,
  818. UsageInfo* aUsageInfo);
  819. // Subclasses use this override to set the IPDL response value.
  820. virtual void
  821. GetResponse(UsageRequestResponse& aResponse) = 0;
  822. private:
  823. void
  824. SendResults() override;
  825. // IPDL methods.
  826. void
  827. ActorDestroy(ActorDestroyReason aWhy) override;
  828. bool
  829. RecvCancel() override;
  830. };
  831. class GetUsageOp final
  832. : public QuotaUsageRequestBase
  833. {
  834. nsTArray<OriginUsage> mOriginUsages;
  835. nsDataHashtable<nsCStringHashKey, uint32_t> mOriginUsagesIndex;
  836. bool mGetAll;
  837. public:
  838. explicit GetUsageOp(const UsageRequestParams& aParams);
  839. private:
  840. ~GetUsageOp()
  841. { }
  842. nsresult
  843. TraverseRepository(QuotaManager* aQuotaManager,
  844. PersistenceType aPersistenceType);
  845. nsresult
  846. DoDirectoryWork(QuotaManager* aQuotaManager) override;
  847. void
  848. GetResponse(UsageRequestResponse& aResponse) override;
  849. };
  850. class GetOriginUsageOp final
  851. : public QuotaUsageRequestBase
  852. {
  853. // If mGetGroupUsage is false, we use mUsageInfo to record the origin usage
  854. // and the file usage. Otherwise, we use it to record the group usage and the
  855. // limit.
  856. UsageInfo mUsageInfo;
  857. const OriginUsageParams mParams;
  858. nsCString mSuffix;
  859. nsCString mGroup;
  860. bool mIsApp;
  861. bool mGetGroupUsage;
  862. public:
  863. explicit GetOriginUsageOp(const UsageRequestParams& aParams);
  864. MOZ_IS_CLASS_INIT bool
  865. Init(Quota* aQuota) override;
  866. private:
  867. ~GetOriginUsageOp()
  868. { }
  869. MOZ_IS_CLASS_INIT virtual nsresult
  870. DoInitOnMainThread() override;
  871. virtual nsresult
  872. DoDirectoryWork(QuotaManager* aQuotaManager) override;
  873. void
  874. GetResponse(UsageRequestResponse& aResponse) override;
  875. };
  876. class QuotaRequestBase
  877. : public NormalOriginOperationBase
  878. , public PQuotaRequestParent
  879. {
  880. public:
  881. // May be overridden by subclasses if they need to perform work on the
  882. // background thread before being run.
  883. virtual bool
  884. Init(Quota* aQuota);
  885. protected:
  886. explicit QuotaRequestBase(bool aExclusive)
  887. : NormalOriginOperationBase(Nullable<PersistenceType>(),
  888. OriginScope::FromNull(),
  889. aExclusive)
  890. { }
  891. // Subclasses use this override to set the IPDL response value.
  892. virtual void
  893. GetResponse(RequestResponse& aResponse) = 0;
  894. private:
  895. virtual void
  896. SendResults() override;
  897. // IPDL methods.
  898. virtual void
  899. ActorDestroy(ActorDestroyReason aWhy) override;
  900. };
  901. class ResetOrClearOp final
  902. : public QuotaRequestBase
  903. {
  904. const bool mClear;
  905. public:
  906. explicit ResetOrClearOp(bool aClear)
  907. : QuotaRequestBase(/* aExclusive */ true)
  908. , mClear(aClear)
  909. {
  910. AssertIsOnOwningThread();
  911. }
  912. private:
  913. ~ResetOrClearOp()
  914. { }
  915. void
  916. DeleteFiles(QuotaManager* aQuotaManager);
  917. virtual nsresult
  918. DoDirectoryWork(QuotaManager* aQuotaManager) override;
  919. virtual void
  920. GetResponse(RequestResponse& aResponse) override;
  921. };
  922. class OriginClearOp final
  923. : public QuotaRequestBase
  924. {
  925. const RequestParams mParams;
  926. const bool mMultiple;
  927. public:
  928. explicit OriginClearOp(const RequestParams& aParams);
  929. virtual bool
  930. Init(Quota* aQuota) override;
  931. private:
  932. ~OriginClearOp()
  933. { }
  934. virtual nsresult
  935. DoInitOnMainThread() override;
  936. void
  937. DeleteFiles(QuotaManager* aQuotaManager,
  938. PersistenceType aPersistenceType);
  939. virtual nsresult
  940. DoDirectoryWork(QuotaManager* aQuotaManager) override;
  941. virtual void
  942. GetResponse(RequestResponse& aResponse) override;
  943. };
  944. /*******************************************************************************
  945. * Helper Functions
  946. ******************************************************************************/
  947. template <typename T, bool = mozilla::IsUnsigned<T>::value>
  948. struct IntChecker
  949. {
  950. static void
  951. Assert(T aInt)
  952. {
  953. static_assert(mozilla::IsIntegral<T>::value, "Not an integer!");
  954. MOZ_ASSERT(aInt >= 0);
  955. }
  956. };
  957. template <typename T>
  958. struct IntChecker<T, true>
  959. {
  960. static void
  961. Assert(T aInt)
  962. {
  963. static_assert(mozilla::IsIntegral<T>::value, "Not an integer!");
  964. }
  965. };
  966. template <typename T>
  967. void
  968. AssertNoOverflow(uint64_t aDest, T aArg)
  969. {
  970. IntChecker<T>::Assert(aDest);
  971. IntChecker<T>::Assert(aArg);
  972. MOZ_ASSERT(UINT64_MAX - aDest >= uint64_t(aArg));
  973. }
  974. template <typename T, typename U>
  975. void
  976. AssertNoUnderflow(T aDest, U aArg)
  977. {
  978. IntChecker<T>::Assert(aDest);
  979. IntChecker<T>::Assert(aArg);
  980. MOZ_ASSERT(uint64_t(aDest) >= uint64_t(aArg));
  981. }
  982. } // namespace
  983. BackgroundThreadObject::BackgroundThreadObject()
  984. : mOwningThread(NS_GetCurrentThread())
  985. {
  986. AssertIsOnOwningThread();
  987. }
  988. BackgroundThreadObject::BackgroundThreadObject(nsIEventTarget* aOwningThread)
  989. : mOwningThread(aOwningThread)
  990. {
  991. }
  992. #ifdef DEBUG
  993. void
  994. BackgroundThreadObject::AssertIsOnOwningThread() const
  995. {
  996. AssertIsOnBackgroundThread();
  997. MOZ_ASSERT(mOwningThread);
  998. bool current;
  999. MOZ_ASSERT(NS_SUCCEEDED(mOwningThread->IsOnCurrentThread(&current)));
  1000. MOZ_ASSERT(current);
  1001. }
  1002. #endif // DEBUG
  1003. nsIEventTarget*
  1004. BackgroundThreadObject::OwningThread() const
  1005. {
  1006. MOZ_ASSERT(mOwningThread);
  1007. return mOwningThread;
  1008. }
  1009. bool
  1010. IsOnIOThread()
  1011. {
  1012. QuotaManager* quotaManager = QuotaManager::Get();
  1013. NS_ASSERTION(quotaManager, "Must have a manager here!");
  1014. bool currentThread;
  1015. return NS_SUCCEEDED(quotaManager->IOThread()->
  1016. IsOnCurrentThread(&currentThread)) && currentThread;
  1017. }
  1018. void
  1019. AssertIsOnIOThread()
  1020. {
  1021. NS_ASSERTION(IsOnIOThread(), "Running on the wrong thread!");
  1022. }
  1023. void
  1024. AssertCurrentThreadOwnsQuotaMutex()
  1025. {
  1026. #ifdef DEBUG
  1027. QuotaManager* quotaManager = QuotaManager::Get();
  1028. NS_ASSERTION(quotaManager, "Must have a manager here!");
  1029. quotaManager->AssertCurrentThreadOwnsQuotaMutex();
  1030. #endif
  1031. }
  1032. void
  1033. ReportInternalError(const char* aFile, uint32_t aLine, const char* aStr)
  1034. {
  1035. // Get leaf of file path
  1036. for (const char* p = aFile; *p; ++p) {
  1037. if (*p == '/' && *(p + 1)) {
  1038. aFile = p + 1;
  1039. }
  1040. }
  1041. nsContentUtils::LogSimpleConsoleError(
  1042. NS_ConvertUTF8toUTF16(nsPrintfCString(
  1043. "Quota %s: %s:%lu", aStr, aFile, aLine)),
  1044. "quota");
  1045. }
  1046. namespace {
  1047. StaticRefPtr<QuotaManager> gInstance;
  1048. bool gCreateFailed = false;
  1049. StaticRefPtr<QuotaManager::CreateRunnable> gCreateRunnable;
  1050. mozilla::Atomic<bool> gShutdown(false);
  1051. // Constants for temporary storage limit computing.
  1052. static const int32_t kDefaultFixedLimitKB = -1;
  1053. static const uint32_t kDefaultChunkSizeKB = 10 * 1024;
  1054. int32_t gFixedLimitKB = kDefaultFixedLimitKB;
  1055. uint32_t gChunkSizeKB = kDefaultChunkSizeKB;
  1056. bool gTestingEnabled = false;
  1057. class StorageDirectoryHelper
  1058. : public Runnable
  1059. {
  1060. mozilla::Mutex mMutex;
  1061. mozilla::CondVar mCondVar;
  1062. nsresult mMainThreadResultCode;
  1063. bool mWaiting;
  1064. protected:
  1065. struct OriginProps;
  1066. nsTArray<OriginProps> mOriginProps;
  1067. nsCOMPtr<nsIFile> mDirectory;
  1068. public:
  1069. StorageDirectoryHelper(nsIFile* aDirectory)
  1070. : mMutex("StorageDirectoryHelper::mMutex")
  1071. , mCondVar(mMutex, "StorageDirectoryHelper::mCondVar")
  1072. , mMainThreadResultCode(NS_OK)
  1073. , mWaiting(true)
  1074. , mDirectory(aDirectory)
  1075. {
  1076. AssertIsOnIOThread();
  1077. }
  1078. protected:
  1079. ~StorageDirectoryHelper()
  1080. { }
  1081. nsresult
  1082. AddOriginDirectory(nsIFile* aDirectory,
  1083. OriginProps** aOriginProps);
  1084. nsresult
  1085. ProcessOriginDirectories();
  1086. virtual nsresult
  1087. DoProcessOriginDirectories() = 0;
  1088. private:
  1089. nsresult
  1090. RunOnMainThread();
  1091. NS_IMETHOD
  1092. Run() override;
  1093. };
  1094. struct StorageDirectoryHelper::OriginProps
  1095. {
  1096. enum Type
  1097. {
  1098. eChrome,
  1099. eContent
  1100. };
  1101. nsCOMPtr<nsIFile> mDirectory;
  1102. nsCString mSpec;
  1103. PrincipalOriginAttributes mAttrs;
  1104. int64_t mTimestamp;
  1105. nsCString mSuffix;
  1106. nsCString mGroup;
  1107. nsCString mOrigin;
  1108. Type mType;
  1109. bool mIsApp;
  1110. bool mNeedsRestore;
  1111. bool mIgnore;
  1112. public:
  1113. explicit OriginProps()
  1114. : mTimestamp(0)
  1115. , mType(eContent)
  1116. , mIsApp(false)
  1117. , mNeedsRestore(false)
  1118. , mIgnore(false)
  1119. { }
  1120. };
  1121. class MOZ_STACK_CLASS OriginParser final
  1122. {
  1123. static bool
  1124. IgnoreWhitespace(char16_t /* aChar */)
  1125. {
  1126. return false;
  1127. }
  1128. typedef nsCCharSeparatedTokenizerTemplate<IgnoreWhitespace> Tokenizer;
  1129. enum SchemaType {
  1130. eNone,
  1131. eFile,
  1132. eAbout
  1133. };
  1134. enum State {
  1135. eExpectingAppIdOrSchema,
  1136. eExpectingInMozBrowser,
  1137. eExpectingSchema,
  1138. eExpectingEmptyToken1,
  1139. eExpectingEmptyToken2,
  1140. eExpectingEmptyToken3,
  1141. eExpectingHost,
  1142. eExpectingPort,
  1143. eExpectingEmptyTokenOrDriveLetterOrPathnameComponent,
  1144. eExpectingEmptyTokenOrPathnameComponent,
  1145. eComplete,
  1146. eHandledTrailingSeparator
  1147. };
  1148. const nsCString mOrigin;
  1149. const PrincipalOriginAttributes mOriginAttributes;
  1150. Tokenizer mTokenizer;
  1151. uint32_t mAppId;
  1152. nsCString mSchema;
  1153. nsCString mHost;
  1154. Nullable<uint32_t> mPort;
  1155. nsTArray<nsCString> mPathnameComponents;
  1156. nsCString mHandledTokens;
  1157. SchemaType mSchemaType;
  1158. State mState;
  1159. bool mInIsolatedMozBrowser;
  1160. bool mMaybeDriveLetter;
  1161. bool mError;
  1162. public:
  1163. OriginParser(const nsACString& aOrigin,
  1164. const PrincipalOriginAttributes& aOriginAttributes)
  1165. : mOrigin(aOrigin)
  1166. , mOriginAttributes(aOriginAttributes)
  1167. , mTokenizer(aOrigin, '+')
  1168. , mAppId(kNoAppId)
  1169. , mPort()
  1170. , mSchemaType(eNone)
  1171. , mState(eExpectingAppIdOrSchema)
  1172. , mInIsolatedMozBrowser(false)
  1173. , mMaybeDriveLetter(false)
  1174. , mError(false)
  1175. { }
  1176. static bool
  1177. ParseOrigin(const nsACString& aOrigin,
  1178. nsCString& aSpec,
  1179. PrincipalOriginAttributes* aAttrs);
  1180. bool
  1181. Parse(nsACString& aSpec, PrincipalOriginAttributes* aAttrs);
  1182. private:
  1183. void
  1184. HandleSchema(const nsDependentCSubstring& aSchema);
  1185. void
  1186. HandlePathnameComponent(const nsDependentCSubstring& aSchema);
  1187. void
  1188. HandleToken(const nsDependentCSubstring& aToken);
  1189. void
  1190. HandleTrailingSeparator();
  1191. };
  1192. class CreateOrUpgradeDirectoryMetadataHelper final
  1193. : public StorageDirectoryHelper
  1194. {
  1195. const bool mPersistent;
  1196. public:
  1197. CreateOrUpgradeDirectoryMetadataHelper(nsIFile* aDirectory,
  1198. bool aPersistent)
  1199. : StorageDirectoryHelper(aDirectory)
  1200. , mPersistent(aPersistent)
  1201. { }
  1202. nsresult
  1203. CreateOrUpgradeMetadataFiles();
  1204. private:
  1205. nsresult
  1206. MaybeUpgradeOriginDirectory(nsIFile* aDirectory);
  1207. nsresult
  1208. GetDirectoryMetadata(nsIFile* aDirectory,
  1209. int64_t* aTimestamp,
  1210. nsACString& aGroup,
  1211. nsACString& aOrigin,
  1212. bool* aHasIsApp);
  1213. virtual nsresult
  1214. DoProcessOriginDirectories();
  1215. };
  1216. class UpgradeDirectoryMetadataFrom1To2Helper final
  1217. : public StorageDirectoryHelper
  1218. {
  1219. const bool mPersistent;
  1220. public:
  1221. UpgradeDirectoryMetadataFrom1To2Helper(nsIFile* aDirectory,
  1222. bool aPersistent)
  1223. : StorageDirectoryHelper(aDirectory)
  1224. , mPersistent(aPersistent)
  1225. { }
  1226. nsresult
  1227. UpgradeMetadataFiles();
  1228. private:
  1229. nsresult
  1230. GetDirectoryMetadata(nsIFile* aDirectory,
  1231. int64_t* aTimestamp,
  1232. nsACString& aGroup,
  1233. nsACString& aOrigin,
  1234. bool* aIsApp);
  1235. virtual nsresult
  1236. DoProcessOriginDirectories() override;
  1237. };
  1238. class RestoreDirectoryMetadata2Helper final
  1239. : public StorageDirectoryHelper
  1240. {
  1241. const bool mPersistent;
  1242. public:
  1243. RestoreDirectoryMetadata2Helper(nsIFile* aDirectory,
  1244. bool aPersistent)
  1245. : StorageDirectoryHelper(aDirectory)
  1246. , mPersistent(aPersistent)
  1247. { }
  1248. nsresult
  1249. RestoreMetadata2File();
  1250. private:
  1251. virtual nsresult
  1252. DoProcessOriginDirectories();
  1253. };
  1254. class OriginKey : public nsAutoCString
  1255. {
  1256. public:
  1257. OriginKey(PersistenceType aPersistenceType,
  1258. const nsACString& aOrigin)
  1259. {
  1260. PersistenceTypeToText(aPersistenceType, *this);
  1261. Append(':');
  1262. Append(aOrigin);
  1263. }
  1264. };
  1265. void
  1266. SanitizeOriginString(nsCString& aOrigin)
  1267. {
  1268. #ifdef XP_WIN
  1269. NS_ASSERTION(!strcmp(QuotaManager::kReplaceChars,
  1270. FILE_ILLEGAL_CHARACTERS FILE_PATH_SEPARATOR),
  1271. "Illegal file characters have changed!");
  1272. #endif
  1273. aOrigin.ReplaceChar(QuotaManager::kReplaceChars, '+');
  1274. }
  1275. bool
  1276. IsTreatedAsPersistent(PersistenceType aPersistenceType,
  1277. bool aIsApp)
  1278. {
  1279. if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT ||
  1280. (aPersistenceType == PERSISTENCE_TYPE_DEFAULT && aIsApp)) {
  1281. return true;
  1282. }
  1283. return false;
  1284. }
  1285. bool
  1286. IsTreatedAsTemporary(PersistenceType aPersistenceType,
  1287. bool aIsApp)
  1288. {
  1289. return !IsTreatedAsPersistent(aPersistenceType, aIsApp);
  1290. }
  1291. nsresult
  1292. CloneStoragePath(nsIFile* aBaseDir,
  1293. const nsAString& aStorageName,
  1294. nsAString& aStoragePath)
  1295. {
  1296. nsresult rv;
  1297. nsCOMPtr<nsIFile> storageDir;
  1298. rv = aBaseDir->Clone(getter_AddRefs(storageDir));
  1299. if (NS_WARN_IF(NS_FAILED(rv))) {
  1300. return rv;
  1301. }
  1302. rv = storageDir->Append(aStorageName);
  1303. if (NS_WARN_IF(NS_FAILED(rv))) {
  1304. return rv;
  1305. }
  1306. rv = storageDir->GetPath(aStoragePath);
  1307. if (NS_WARN_IF(NS_FAILED(rv))) {
  1308. return rv;
  1309. }
  1310. return NS_OK;
  1311. }
  1312. nsresult
  1313. GetLastModifiedTime(nsIFile* aFile, int64_t* aTimestamp)
  1314. {
  1315. AssertIsOnIOThread();
  1316. MOZ_ASSERT(aFile);
  1317. MOZ_ASSERT(aTimestamp);
  1318. class MOZ_STACK_CLASS Helper final
  1319. {
  1320. public:
  1321. static nsresult
  1322. GetLastModifiedTime(nsIFile* aFile, int64_t* aTimestamp)
  1323. {
  1324. AssertIsOnIOThread();
  1325. MOZ_ASSERT(aFile);
  1326. MOZ_ASSERT(aTimestamp);
  1327. bool isDirectory;
  1328. nsresult rv = aFile->IsDirectory(&isDirectory);
  1329. if (NS_WARN_IF(NS_FAILED(rv))) {
  1330. return rv;
  1331. }
  1332. if (!isDirectory) {
  1333. nsString leafName;
  1334. rv = aFile->GetLeafName(leafName);
  1335. if (NS_WARN_IF(NS_FAILED(rv))) {
  1336. return rv;
  1337. }
  1338. if (leafName.EqualsLiteral(METADATA_FILE_NAME) ||
  1339. leafName.EqualsLiteral(METADATA_V2_FILE_NAME) ||
  1340. leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
  1341. return NS_OK;
  1342. }
  1343. int64_t timestamp;
  1344. rv = aFile->GetLastModifiedTime(&timestamp);
  1345. if (NS_WARN_IF(NS_FAILED(rv))) {
  1346. return rv;
  1347. }
  1348. // Need to convert from milliseconds to microseconds.
  1349. MOZ_ASSERT((INT64_MAX / PR_USEC_PER_MSEC) > timestamp);
  1350. timestamp *= int64_t(PR_USEC_PER_MSEC);
  1351. if (timestamp > *aTimestamp) {
  1352. *aTimestamp = timestamp;
  1353. }
  1354. return NS_OK;
  1355. }
  1356. nsCOMPtr<nsISimpleEnumerator> entries;
  1357. rv = aFile->GetDirectoryEntries(getter_AddRefs(entries));
  1358. if (NS_WARN_IF(NS_FAILED(rv))) {
  1359. return rv;
  1360. }
  1361. bool hasMore;
  1362. while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
  1363. nsCOMPtr<nsISupports> entry;
  1364. rv = entries->GetNext(getter_AddRefs(entry));
  1365. if (NS_WARN_IF(NS_FAILED(rv))) {
  1366. return rv;
  1367. }
  1368. nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
  1369. MOZ_ASSERT(file);
  1370. rv = GetLastModifiedTime(file, aTimestamp);
  1371. if (NS_WARN_IF(NS_FAILED(rv))) {
  1372. return rv;
  1373. }
  1374. }
  1375. if (NS_WARN_IF(NS_FAILED(rv))) {
  1376. return rv;
  1377. }
  1378. return NS_OK;
  1379. }
  1380. };
  1381. int64_t timestamp = INT64_MIN;
  1382. nsresult rv = Helper::GetLastModifiedTime(aFile, &timestamp);
  1383. if (NS_WARN_IF(NS_FAILED(rv))) {
  1384. return rv;
  1385. }
  1386. *aTimestamp = timestamp;
  1387. return NS_OK;
  1388. }
  1389. nsresult
  1390. EnsureDirectory(nsIFile* aDirectory, bool* aCreated)
  1391. {
  1392. AssertIsOnIOThread();
  1393. nsresult rv = aDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
  1394. if (rv == NS_ERROR_FILE_ALREADY_EXISTS) {
  1395. bool isDirectory;
  1396. rv = aDirectory->IsDirectory(&isDirectory);
  1397. NS_ENSURE_SUCCESS(rv, rv);
  1398. NS_ENSURE_TRUE(isDirectory, NS_ERROR_UNEXPECTED);
  1399. *aCreated = false;
  1400. }
  1401. else {
  1402. NS_ENSURE_SUCCESS(rv, rv);
  1403. *aCreated = true;
  1404. }
  1405. return NS_OK;
  1406. }
  1407. enum FileFlag {
  1408. kTruncateFileFlag,
  1409. kUpdateFileFlag,
  1410. kAppendFileFlag
  1411. };
  1412. nsresult
  1413. GetOutputStream(nsIFile* aDirectory,
  1414. const nsAString& aFilename,
  1415. FileFlag aFileFlag,
  1416. nsIOutputStream** aStream)
  1417. {
  1418. AssertIsOnIOThread();
  1419. nsCOMPtr<nsIFile> file;
  1420. nsresult rv = aDirectory->Clone(getter_AddRefs(file));
  1421. if (NS_WARN_IF(NS_FAILED(rv))) {
  1422. return rv;
  1423. }
  1424. rv = file->Append(aFilename);
  1425. if (NS_WARN_IF(NS_FAILED(rv))) {
  1426. return rv;
  1427. }
  1428. nsCOMPtr<nsIOutputStream> outputStream;
  1429. switch (aFileFlag) {
  1430. case kTruncateFileFlag: {
  1431. rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream),
  1432. file);
  1433. if (NS_WARN_IF(NS_FAILED(rv))) {
  1434. return rv;
  1435. }
  1436. break;
  1437. }
  1438. case kUpdateFileFlag: {
  1439. bool exists;
  1440. rv = file->Exists(&exists);
  1441. if (NS_WARN_IF(NS_FAILED(rv))) {
  1442. return rv;
  1443. }
  1444. if (!exists) {
  1445. *aStream = nullptr;
  1446. return NS_OK;
  1447. }
  1448. nsCOMPtr<nsIFileStream> stream;
  1449. rv = NS_NewLocalFileStream(getter_AddRefs(stream), file);
  1450. if (NS_WARN_IF(NS_FAILED(rv))) {
  1451. return rv;
  1452. }
  1453. outputStream = do_QueryInterface(stream);
  1454. if (NS_WARN_IF(!outputStream)) {
  1455. return NS_ERROR_FAILURE;
  1456. }
  1457. break;
  1458. }
  1459. case kAppendFileFlag: {
  1460. rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream),
  1461. file,
  1462. PR_WRONLY | PR_CREATE_FILE | PR_APPEND);
  1463. if (NS_WARN_IF(NS_FAILED(rv))) {
  1464. return rv;
  1465. }
  1466. break;
  1467. }
  1468. default:
  1469. MOZ_CRASH("Should never get here!");
  1470. }
  1471. outputStream.forget(aStream);
  1472. return NS_OK;
  1473. }
  1474. nsresult
  1475. GetBinaryOutputStream(nsIFile* aDirectory,
  1476. const nsAString& aFilename,
  1477. FileFlag aFileFlag,
  1478. nsIBinaryOutputStream** aStream)
  1479. {
  1480. nsCOMPtr<nsIOutputStream> outputStream;
  1481. nsresult rv = GetOutputStream(aDirectory,
  1482. aFilename,
  1483. aFileFlag,
  1484. getter_AddRefs(outputStream));
  1485. if (NS_WARN_IF(NS_FAILED(rv))) {
  1486. return rv;
  1487. }
  1488. nsCOMPtr<nsIBinaryOutputStream> binaryStream =
  1489. do_CreateInstance("@mozilla.org/binaryoutputstream;1");
  1490. if (NS_WARN_IF(!binaryStream)) {
  1491. return NS_ERROR_FAILURE;
  1492. }
  1493. rv = binaryStream->SetOutputStream(outputStream);
  1494. if (NS_WARN_IF(NS_FAILED(rv))) {
  1495. return rv;
  1496. }
  1497. binaryStream.forget(aStream);
  1498. return NS_OK;
  1499. }
  1500. void
  1501. GetJarPrefix(uint32_t aAppId,
  1502. bool aInIsolatedMozBrowser,
  1503. nsACString& aJarPrefix)
  1504. {
  1505. MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
  1506. if (aAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
  1507. aAppId = nsIScriptSecurityManager::NO_APP_ID;
  1508. }
  1509. aJarPrefix.Truncate();
  1510. // Fallback.
  1511. if (aAppId == nsIScriptSecurityManager::NO_APP_ID && !aInIsolatedMozBrowser) {
  1512. return;
  1513. }
  1514. // aJarPrefix = appId + "+" + { 't', 'f' } + "+";
  1515. aJarPrefix.AppendInt(aAppId);
  1516. aJarPrefix.Append('+');
  1517. aJarPrefix.Append(aInIsolatedMozBrowser ? 't' : 'f');
  1518. aJarPrefix.Append('+');
  1519. }
  1520. nsresult
  1521. CreateDirectoryMetadata(nsIFile* aDirectory, int64_t aTimestamp,
  1522. const nsACString& aSuffix, const nsACString& aGroup,
  1523. const nsACString& aOrigin, bool aIsApp)
  1524. {
  1525. AssertIsOnIOThread();
  1526. PrincipalOriginAttributes groupAttributes;
  1527. nsCString groupNoSuffix;
  1528. bool ok = groupAttributes.PopulateFromOrigin(aGroup, groupNoSuffix);
  1529. if (!ok) {
  1530. return NS_ERROR_FAILURE;
  1531. }
  1532. nsCString groupPrefix;
  1533. GetJarPrefix(groupAttributes.mAppId,
  1534. groupAttributes.mInIsolatedMozBrowser,
  1535. groupPrefix);
  1536. nsCString group = groupPrefix + groupNoSuffix;
  1537. PrincipalOriginAttributes originAttributes;
  1538. nsCString originNoSuffix;
  1539. ok = originAttributes.PopulateFromOrigin(aOrigin, originNoSuffix);
  1540. if (!ok) {
  1541. return NS_ERROR_FAILURE;
  1542. }
  1543. nsCString originPrefix;
  1544. GetJarPrefix(originAttributes.mAppId,
  1545. originAttributes.mInIsolatedMozBrowser,
  1546. originPrefix);
  1547. nsCString origin = originPrefix + originNoSuffix;
  1548. MOZ_ASSERT(groupPrefix == originPrefix);
  1549. nsCOMPtr<nsIBinaryOutputStream> stream;
  1550. nsresult rv = GetBinaryOutputStream(aDirectory,
  1551. NS_LITERAL_STRING(METADATA_FILE_NAME),
  1552. kTruncateFileFlag,
  1553. getter_AddRefs(stream));
  1554. if (NS_WARN_IF(NS_FAILED(rv))) {
  1555. return rv;
  1556. }
  1557. MOZ_ASSERT(stream);
  1558. rv = stream->Write64(aTimestamp);
  1559. if (NS_WARN_IF(NS_FAILED(rv))) {
  1560. return rv;
  1561. }
  1562. rv = stream->WriteStringZ(group.get());
  1563. if (NS_WARN_IF(NS_FAILED(rv))) {
  1564. return rv;
  1565. }
  1566. rv = stream->WriteStringZ(origin.get());
  1567. if (NS_WARN_IF(NS_FAILED(rv))) {
  1568. return rv;
  1569. }
  1570. rv = stream->WriteBoolean(aIsApp);
  1571. if (NS_WARN_IF(NS_FAILED(rv))) {
  1572. return rv;
  1573. }
  1574. return NS_OK;
  1575. }
  1576. nsresult
  1577. CreateDirectoryMetadata2(nsIFile* aDirectory, int64_t aTimestamp,
  1578. const nsACString& aSuffix, const nsACString& aGroup,
  1579. const nsACString& aOrigin, bool aIsApp)
  1580. {
  1581. AssertIsOnIOThread();
  1582. nsCOMPtr<nsIBinaryOutputStream> stream;
  1583. nsresult rv = GetBinaryOutputStream(aDirectory,
  1584. NS_LITERAL_STRING(METADATA_V2_FILE_NAME),
  1585. kTruncateFileFlag,
  1586. getter_AddRefs(stream));
  1587. if (NS_WARN_IF(NS_FAILED(rv))) {
  1588. return rv;
  1589. }
  1590. MOZ_ASSERT(stream);
  1591. rv = stream->Write64(aTimestamp);
  1592. if (NS_WARN_IF(NS_FAILED(rv))) {
  1593. return rv;
  1594. }
  1595. // Reserved for navigator.persist()
  1596. rv = stream->WriteBoolean(false);
  1597. if (NS_WARN_IF(NS_FAILED(rv))) {
  1598. return rv;
  1599. }
  1600. // Reserved data 1
  1601. rv = stream->Write32(0);
  1602. if (NS_WARN_IF(NS_FAILED(rv))) {
  1603. return rv;
  1604. }
  1605. // Reserved data 2
  1606. rv = stream->Write32(0);
  1607. if (NS_WARN_IF(NS_FAILED(rv))) {
  1608. return rv;
  1609. }
  1610. rv = stream->WriteStringZ(PromiseFlatCString(aSuffix).get());
  1611. if (NS_WARN_IF(NS_FAILED(rv))) {
  1612. return rv;
  1613. }
  1614. rv = stream->WriteStringZ(PromiseFlatCString(aGroup).get());
  1615. if (NS_WARN_IF(NS_FAILED(rv))) {
  1616. return rv;
  1617. }
  1618. rv = stream->WriteStringZ(PromiseFlatCString(aOrigin).get());
  1619. if (NS_WARN_IF(NS_FAILED(rv))) {
  1620. return rv;
  1621. }
  1622. rv = stream->WriteBoolean(aIsApp);
  1623. if (NS_WARN_IF(NS_FAILED(rv))) {
  1624. return rv;
  1625. }
  1626. return NS_OK;
  1627. }
  1628. nsresult
  1629. GetBinaryInputStream(nsIFile* aDirectory,
  1630. const nsAString& aFilename,
  1631. nsIBinaryInputStream** aStream)
  1632. {
  1633. MOZ_ASSERT(!NS_IsMainThread());
  1634. MOZ_ASSERT(aDirectory);
  1635. MOZ_ASSERT(aStream);
  1636. nsCOMPtr<nsIFile> file;
  1637. nsresult rv = aDirectory->Clone(getter_AddRefs(file));
  1638. if (NS_WARN_IF(NS_FAILED(rv))) {
  1639. return rv;
  1640. }
  1641. rv = file->Append(aFilename);
  1642. if (NS_WARN_IF(NS_FAILED(rv))) {
  1643. return rv;
  1644. }
  1645. nsCOMPtr<nsIInputStream> stream;
  1646. rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), file);
  1647. if (NS_WARN_IF(NS_FAILED(rv))) {
  1648. return rv;
  1649. }
  1650. nsCOMPtr<nsIInputStream> bufferedStream;
  1651. rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream), stream, 512);
  1652. if (NS_WARN_IF(NS_FAILED(rv))) {
  1653. return rv;
  1654. }
  1655. nsCOMPtr<nsIBinaryInputStream> binaryStream =
  1656. do_CreateInstance("@mozilla.org/binaryinputstream;1");
  1657. if (NS_WARN_IF(!binaryStream)) {
  1658. return NS_ERROR_FAILURE;
  1659. }
  1660. rv = binaryStream->SetInputStream(bufferedStream);
  1661. if (NS_WARN_IF(NS_FAILED(rv))) {
  1662. return rv;
  1663. }
  1664. binaryStream.forget(aStream);
  1665. return NS_OK;
  1666. }
  1667. // This method computes and returns our best guess for the temporary storage
  1668. // limit (in bytes), based on the amount of space users have free on their hard
  1669. // drive and on given temporary storage usage (also in bytes).
  1670. nsresult
  1671. GetTemporaryStorageLimit(nsIFile* aDirectory, uint64_t aCurrentUsage,
  1672. uint64_t* aLimit)
  1673. {
  1674. // Check for free space on device where temporary storage directory lives.
  1675. int64_t bytesAvailable;
  1676. nsresult rv = aDirectory->GetDiskSpaceAvailable(&bytesAvailable);
  1677. NS_ENSURE_SUCCESS(rv, rv);
  1678. NS_ASSERTION(bytesAvailable >= 0, "Negative bytes available?!");
  1679. uint64_t availableKB =
  1680. static_cast<uint64_t>((bytesAvailable + aCurrentUsage) / 1024);
  1681. // Grow/shrink in gChunkSizeKB units, deliberately, so that in the common case
  1682. // we don't shrink temporary storage and evict origin data every time we
  1683. // initialize.
  1684. availableKB = (availableKB / gChunkSizeKB) * gChunkSizeKB;
  1685. // Allow temporary storage to consume up to half the available space.
  1686. uint64_t resultKB = availableKB * .50;
  1687. *aLimit = resultKB * 1024;
  1688. return NS_OK;
  1689. }
  1690. } // namespace
  1691. /*******************************************************************************
  1692. * Exported functions
  1693. ******************************************************************************/
  1694. PQuotaParent*
  1695. AllocPQuotaParent()
  1696. {
  1697. AssertIsOnBackgroundThread();
  1698. if (NS_WARN_IF(QuotaManager::IsShuttingDown())) {
  1699. return nullptr;
  1700. }
  1701. RefPtr<Quota> actor = new Quota();
  1702. return actor.forget().take();
  1703. }
  1704. bool
  1705. DeallocPQuotaParent(PQuotaParent* aActor)
  1706. {
  1707. AssertIsOnBackgroundThread();
  1708. MOZ_ASSERT(aActor);
  1709. RefPtr<Quota> actor = dont_AddRef(static_cast<Quota*>(aActor));
  1710. return true;
  1711. }
  1712. /*******************************************************************************
  1713. * Directory lock
  1714. ******************************************************************************/
  1715. DirectoryLockImpl::DirectoryLockImpl(QuotaManager* aQuotaManager,
  1716. Nullable<PersistenceType> aPersistenceType,
  1717. const nsACString& aGroup,
  1718. const OriginScope& aOriginScope,
  1719. Nullable<bool> aIsApp,
  1720. Nullable<Client::Type> aClientType,
  1721. bool aExclusive,
  1722. bool aInternal,
  1723. OpenDirectoryListener* aOpenListener)
  1724. : mQuotaManager(aQuotaManager)
  1725. , mPersistenceType(aPersistenceType)
  1726. , mGroup(aGroup)
  1727. , mOriginScope(aOriginScope)
  1728. , mIsApp(aIsApp)
  1729. , mClientType(aClientType)
  1730. , mOpenListener(aOpenListener)
  1731. , mExclusive(aExclusive)
  1732. , mInternal(aInternal)
  1733. , mInvalidated(false)
  1734. {
  1735. AssertIsOnOwningThread();
  1736. MOZ_ASSERT(aQuotaManager);
  1737. MOZ_ASSERT_IF(aOriginScope.IsOrigin(), !aOriginScope.GetOrigin().IsEmpty());
  1738. MOZ_ASSERT_IF(!aInternal, !aPersistenceType.IsNull());
  1739. MOZ_ASSERT_IF(!aInternal,
  1740. aPersistenceType.Value() != PERSISTENCE_TYPE_INVALID);
  1741. MOZ_ASSERT_IF(!aInternal, !aGroup.IsEmpty());
  1742. MOZ_ASSERT_IF(!aInternal, aOriginScope.IsOrigin());
  1743. MOZ_ASSERT_IF(!aInternal, !aIsApp.IsNull());
  1744. MOZ_ASSERT_IF(!aInternal, !aClientType.IsNull());
  1745. MOZ_ASSERT_IF(!aInternal, aClientType.Value() != Client::TYPE_MAX);
  1746. MOZ_ASSERT_IF(!aInternal, aOpenListener);
  1747. }
  1748. DirectoryLockImpl::~DirectoryLockImpl()
  1749. {
  1750. AssertIsOnOwningThread();
  1751. MOZ_ASSERT(mQuotaManager);
  1752. for (DirectoryLockImpl* blockingLock : mBlocking) {
  1753. blockingLock->MaybeUnblock(this);
  1754. }
  1755. mBlocking.Clear();
  1756. mQuotaManager->UnregisterDirectoryLock(this);
  1757. }
  1758. #ifdef DEBUG
  1759. void
  1760. DirectoryLockImpl::AssertIsOnOwningThread() const
  1761. {
  1762. MOZ_ASSERT(mQuotaManager);
  1763. mQuotaManager->AssertIsOnOwningThread();
  1764. }
  1765. #endif // DEBUG
  1766. bool
  1767. DirectoryLockImpl::MustWaitFor(const DirectoryLockImpl& aExistingLock)
  1768. {
  1769. AssertIsOnOwningThread();
  1770. // Waiting is never required if the ops in comparison represent shared locks.
  1771. if (!aExistingLock.mExclusive && !mExclusive) {
  1772. return false;
  1773. }
  1774. // If the persistence types don't overlap, the op can proceed.
  1775. if (!aExistingLock.mPersistenceType.IsNull() && !mPersistenceType.IsNull() &&
  1776. aExistingLock.mPersistenceType.Value() != mPersistenceType.Value()) {
  1777. return false;
  1778. }
  1779. // If the origin scopes don't overlap, the op can proceed.
  1780. bool match = aExistingLock.mOriginScope.Matches(mOriginScope);
  1781. if (!match) {
  1782. return false;
  1783. }
  1784. // If the client types don't overlap, the op can proceed.
  1785. if (!aExistingLock.mClientType.IsNull() && !mClientType.IsNull() &&
  1786. aExistingLock.mClientType.Value() != mClientType.Value()) {
  1787. return false;
  1788. }
  1789. // Otherwise, when all attributes overlap (persistence type, origin scope and
  1790. // client type) the op must wait.
  1791. return true;
  1792. }
  1793. void
  1794. DirectoryLockImpl::NotifyOpenListener()
  1795. {
  1796. AssertIsOnOwningThread();
  1797. MOZ_ASSERT(mQuotaManager);
  1798. MOZ_ASSERT(mOpenListener);
  1799. if (mInvalidated) {
  1800. mOpenListener->DirectoryLockFailed();
  1801. } else {
  1802. mOpenListener->DirectoryLockAcquired(this);
  1803. }
  1804. mOpenListener = nullptr;
  1805. mQuotaManager->RemovePendingDirectoryLock(this);
  1806. }
  1807. nsresult
  1808. QuotaManager::
  1809. CreateRunnable::Init()
  1810. {
  1811. MOZ_ASSERT(NS_IsMainThread());
  1812. MOZ_ASSERT(mState == State::Initial);
  1813. nsresult rv;
  1814. nsCOMPtr<nsIFile> baseDir;
  1815. rv = NS_GetSpecialDirectory(NS_APP_INDEXEDDB_PARENT_DIR,
  1816. getter_AddRefs(baseDir));
  1817. if (NS_FAILED(rv)) {
  1818. rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
  1819. getter_AddRefs(baseDir));
  1820. }
  1821. if (NS_WARN_IF(NS_FAILED(rv))) {
  1822. return rv;
  1823. }
  1824. rv = baseDir->GetPath(mBaseDirPath);
  1825. if (NS_WARN_IF(NS_FAILED(rv))) {
  1826. return rv;
  1827. }
  1828. return NS_OK;
  1829. }
  1830. nsresult
  1831. QuotaManager::
  1832. CreateRunnable::CreateManager()
  1833. {
  1834. AssertIsOnOwningThread();
  1835. MOZ_ASSERT(mState == State::CreatingManager);
  1836. mManager = new QuotaManager();
  1837. nsresult rv = mManager->Init(mBaseDirPath);
  1838. if (NS_WARN_IF(NS_FAILED(rv))) {
  1839. return rv;
  1840. }
  1841. return NS_OK;
  1842. }
  1843. nsresult
  1844. QuotaManager::
  1845. CreateRunnable::RegisterObserver()
  1846. {
  1847. MOZ_ASSERT(NS_IsMainThread());
  1848. MOZ_ASSERT(mState == State::RegisteringObserver);
  1849. if (NS_FAILED(Preferences::AddIntVarCache(&gFixedLimitKB, PREF_FIXED_LIMIT,
  1850. kDefaultFixedLimitKB)) ||
  1851. NS_FAILED(Preferences::AddUintVarCache(&gChunkSizeKB,
  1852. PREF_CHUNK_SIZE,
  1853. kDefaultChunkSizeKB))) {
  1854. NS_WARNING("Unable to respond to temp storage pref changes!");
  1855. }
  1856. if (NS_FAILED(Preferences::AddBoolVarCache(&gTestingEnabled,
  1857. PREF_TESTING_FEATURES, false))) {
  1858. NS_WARNING("Unable to respond to testing pref changes!");
  1859. }
  1860. nsCOMPtr<nsIObserverService> observerService =
  1861. mozilla::services::GetObserverService();
  1862. if (NS_WARN_IF(!observerService)) {
  1863. return NS_ERROR_FAILURE;
  1864. }
  1865. nsCOMPtr<nsIObserver> observer = new ShutdownObserver(mOwningThread);
  1866. nsresult rv =
  1867. observerService->AddObserver(observer,
  1868. PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID,
  1869. false);
  1870. if (NS_WARN_IF(NS_FAILED(rv))) {
  1871. return rv;
  1872. }
  1873. // This service has to be started on the main thread currently.
  1874. nsCOMPtr<mozIStorageService> ss =
  1875. do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
  1876. if (NS_WARN_IF(NS_FAILED(rv))) {
  1877. return rv;
  1878. }
  1879. QuotaManagerService* qms = QuotaManagerService::GetOrCreate();
  1880. if (NS_WARN_IF(!qms)) {
  1881. return rv;
  1882. }
  1883. qms->NoteLiveManager(mManager);
  1884. for (RefPtr<Client>& client : mManager->mClients) {
  1885. client->DidInitialize(mManager);
  1886. }
  1887. return NS_OK;
  1888. }
  1889. void
  1890. QuotaManager::
  1891. CreateRunnable::CallCallbacks()
  1892. {
  1893. AssertIsOnOwningThread();
  1894. MOZ_ASSERT(mState == State::CallingCallbacks);
  1895. gCreateRunnable = nullptr;
  1896. if (NS_FAILED(mResultCode)) {
  1897. gCreateFailed = true;
  1898. } else {
  1899. gInstance = mManager;
  1900. }
  1901. mManager = nullptr;
  1902. nsTArray<nsCOMPtr<nsIRunnable>> callbacks;
  1903. mCallbacks.SwapElements(callbacks);
  1904. for (nsCOMPtr<nsIRunnable>& callback : callbacks) {
  1905. Unused << callback->Run();
  1906. }
  1907. }
  1908. auto
  1909. QuotaManager::
  1910. CreateRunnable::GetNextState(nsCOMPtr<nsIEventTarget>& aThread) -> State
  1911. {
  1912. switch (mState) {
  1913. case State::Initial:
  1914. aThread = mOwningThread;
  1915. return State::CreatingManager;
  1916. case State::CreatingManager:
  1917. aThread = do_GetMainThread();
  1918. return State::RegisteringObserver;
  1919. case State::RegisteringObserver:
  1920. aThread = mOwningThread;
  1921. return State::CallingCallbacks;
  1922. case State::CallingCallbacks:
  1923. aThread = nullptr;
  1924. return State::Completed;
  1925. default:
  1926. MOZ_CRASH("Bad state!");
  1927. }
  1928. }
  1929. NS_IMETHODIMP
  1930. QuotaManager::
  1931. CreateRunnable::Run()
  1932. {
  1933. nsresult rv;
  1934. switch (mState) {
  1935. case State::Initial:
  1936. rv = Init();
  1937. break;
  1938. case State::CreatingManager:
  1939. rv = CreateManager();
  1940. break;
  1941. case State::RegisteringObserver:
  1942. rv = RegisterObserver();
  1943. break;
  1944. case State::CallingCallbacks:
  1945. CallCallbacks();
  1946. rv = NS_OK;
  1947. break;
  1948. case State::Completed:
  1949. default:
  1950. MOZ_CRASH("Bad state!");
  1951. }
  1952. nsCOMPtr<nsIEventTarget> thread;
  1953. if (NS_WARN_IF(NS_FAILED(rv))) {
  1954. if (NS_SUCCEEDED(mResultCode)) {
  1955. mResultCode = rv;
  1956. }
  1957. mState = State::CallingCallbacks;
  1958. thread = mOwningThread;
  1959. } else {
  1960. mState = GetNextState(thread);
  1961. }
  1962. if (thread) {
  1963. MOZ_ALWAYS_SUCCEEDS(thread->Dispatch(this, NS_DISPATCH_NORMAL));
  1964. }
  1965. return NS_OK;
  1966. }
  1967. NS_IMETHODIMP
  1968. QuotaManager::
  1969. ShutdownRunnable::Run()
  1970. {
  1971. if (NS_IsMainThread()) {
  1972. mDone = true;
  1973. return NS_OK;
  1974. }
  1975. AssertIsOnBackgroundThread();
  1976. RefPtr<QuotaManager> quotaManager = gInstance.get();
  1977. if (quotaManager) {
  1978. quotaManager->Shutdown();
  1979. gInstance = nullptr;
  1980. }
  1981. MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
  1982. return NS_OK;
  1983. }
  1984. NS_IMPL_ISUPPORTS(QuotaManager::ShutdownObserver, nsIObserver)
  1985. NS_IMETHODIMP
  1986. QuotaManager::
  1987. ShutdownObserver::Observe(nsISupports* aSubject,
  1988. const char* aTopic,
  1989. const char16_t* aData)
  1990. {
  1991. MOZ_ASSERT(NS_IsMainThread());
  1992. MOZ_ASSERT(!strcmp(aTopic, PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID));
  1993. MOZ_ASSERT(gInstance);
  1994. nsCOMPtr<nsIObserverService> observerService =
  1995. mozilla::services::GetObserverService();
  1996. if (NS_WARN_IF(!observerService)) {
  1997. return NS_ERROR_FAILURE;
  1998. }
  1999. // Unregister ourselves from the observer service first to make sure the
  2000. // nested event loop below will not cause re-entrancy issues.
  2001. Unused <<
  2002. observerService->RemoveObserver(this,
  2003. PROFILE_BEFORE_CHANGE_QM_OBSERVER_ID);
  2004. QuotaManagerService* qms = QuotaManagerService::Get();
  2005. MOZ_ASSERT(qms);
  2006. qms->NoteShuttingDownManager();
  2007. for (RefPtr<Client>& client : gInstance->mClients) {
  2008. client->WillShutdown();
  2009. }
  2010. bool done = false;
  2011. RefPtr<ShutdownRunnable> shutdownRunnable = new ShutdownRunnable(done);
  2012. MOZ_ALWAYS_SUCCEEDS(
  2013. mBackgroundThread->Dispatch(shutdownRunnable, NS_DISPATCH_NORMAL));
  2014. nsIThread* currentThread = NS_GetCurrentThread();
  2015. MOZ_ASSERT(currentThread);
  2016. while (!done) {
  2017. MOZ_ALWAYS_TRUE(NS_ProcessNextEvent(currentThread));
  2018. }
  2019. return NS_OK;
  2020. }
  2021. /*******************************************************************************
  2022. * Quota object
  2023. ******************************************************************************/
  2024. void
  2025. QuotaObject::AddRef()
  2026. {
  2027. QuotaManager* quotaManager = QuotaManager::Get();
  2028. if (!quotaManager) {
  2029. NS_ERROR("Null quota manager, this shouldn't happen, possible leak!");
  2030. ++mRefCnt;
  2031. return;
  2032. }
  2033. MutexAutoLock lock(quotaManager->mQuotaMutex);
  2034. ++mRefCnt;
  2035. }
  2036. void
  2037. QuotaObject::Release()
  2038. {
  2039. QuotaManager* quotaManager = QuotaManager::Get();
  2040. if (!quotaManager) {
  2041. NS_ERROR("Null quota manager, this shouldn't happen, possible leak!");
  2042. nsrefcnt count = --mRefCnt;
  2043. if (count == 0) {
  2044. mRefCnt = 1;
  2045. delete this;
  2046. }
  2047. return;
  2048. }
  2049. {
  2050. MutexAutoLock lock(quotaManager->mQuotaMutex);
  2051. --mRefCnt;
  2052. if (mRefCnt > 0) {
  2053. return;
  2054. }
  2055. if (mOriginInfo) {
  2056. mOriginInfo->mQuotaObjects.Remove(mPath);
  2057. }
  2058. }
  2059. delete this;
  2060. }
  2061. bool
  2062. QuotaObject::MaybeUpdateSize(int64_t aSize, bool aTruncate)
  2063. {
  2064. QuotaManager* quotaManager = QuotaManager::Get();
  2065. MOZ_ASSERT(quotaManager);
  2066. MutexAutoLock lock(quotaManager->mQuotaMutex);
  2067. if (mQuotaCheckDisabled) {
  2068. return true;
  2069. }
  2070. if (mSize == aSize) {
  2071. return true;
  2072. }
  2073. if (!mOriginInfo) {
  2074. mSize = aSize;
  2075. return true;
  2076. }
  2077. GroupInfo* groupInfo = mOriginInfo->mGroupInfo;
  2078. MOZ_ASSERT(groupInfo);
  2079. if (mSize > aSize) {
  2080. if (aTruncate) {
  2081. const int64_t delta = mSize - aSize;
  2082. AssertNoUnderflow(quotaManager->mTemporaryStorageUsage, delta);
  2083. quotaManager->mTemporaryStorageUsage -= delta;
  2084. AssertNoUnderflow(groupInfo->mUsage, delta);
  2085. groupInfo->mUsage -= delta;
  2086. AssertNoUnderflow(mOriginInfo->mUsage, delta);
  2087. mOriginInfo->mUsage -= delta;
  2088. mSize = aSize;
  2089. }
  2090. return true;
  2091. }
  2092. MOZ_ASSERT(mSize < aSize);
  2093. RefPtr<GroupInfo> complementaryGroupInfo =
  2094. groupInfo->mGroupInfoPair->LockedGetGroupInfo(
  2095. ComplementaryPersistenceType(groupInfo->mPersistenceType));
  2096. uint64_t delta = aSize - mSize;
  2097. AssertNoOverflow(mOriginInfo->mUsage, delta);
  2098. uint64_t newUsage = mOriginInfo->mUsage + delta;
  2099. // Temporary storage has no limit for origin usage (there's a group and the
  2100. // global limit though).
  2101. AssertNoOverflow(groupInfo->mUsage, delta);
  2102. uint64_t newGroupUsage = groupInfo->mUsage + delta;
  2103. uint64_t groupUsage = groupInfo->mUsage;
  2104. if (complementaryGroupInfo) {
  2105. AssertNoOverflow(groupUsage, complementaryGroupInfo->mUsage);
  2106. groupUsage += complementaryGroupInfo->mUsage;
  2107. }
  2108. // Temporary storage has a hard limit for group usage (20 % of the global
  2109. // limit).
  2110. AssertNoOverflow(groupUsage, delta);
  2111. if (groupUsage + delta > quotaManager->GetGroupLimit()) {
  2112. return false;
  2113. }
  2114. AssertNoOverflow(quotaManager->mTemporaryStorageUsage, delta);
  2115. uint64_t newTemporaryStorageUsage = quotaManager->mTemporaryStorageUsage +
  2116. delta;
  2117. if (newTemporaryStorageUsage > quotaManager->mTemporaryStorageLimit) {
  2118. // This will block the thread without holding the lock while waitting.
  2119. AutoTArray<RefPtr<DirectoryLockImpl>, 10> locks;
  2120. uint64_t sizeToBeFreed =
  2121. quotaManager->LockedCollectOriginsForEviction(delta, locks);
  2122. if (!sizeToBeFreed) {
  2123. return false;
  2124. }
  2125. NS_ASSERTION(sizeToBeFreed >= delta, "Huh?");
  2126. {
  2127. MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex);
  2128. for (RefPtr<DirectoryLockImpl>& lock : locks) {
  2129. MOZ_ASSERT(!lock->GetPersistenceType().IsNull());
  2130. MOZ_ASSERT(lock->GetOriginScope().IsOrigin());
  2131. MOZ_ASSERT(!lock->GetOriginScope().GetOrigin().IsEmpty());
  2132. quotaManager->DeleteFilesForOrigin(lock->GetPersistenceType().Value(),
  2133. lock->GetOriginScope().GetOrigin());
  2134. }
  2135. }
  2136. // Relocked.
  2137. NS_ASSERTION(mOriginInfo, "How come?!");
  2138. for (DirectoryLockImpl* lock : locks) {
  2139. MOZ_ASSERT(!lock->GetPersistenceType().IsNull());
  2140. MOZ_ASSERT(!lock->GetGroup().IsEmpty());
  2141. MOZ_ASSERT(lock->GetOriginScope().IsOrigin());
  2142. MOZ_ASSERT(!lock->GetOriginScope().GetOrigin().IsEmpty());
  2143. MOZ_ASSERT(lock->GetOriginScope().GetOrigin() != mOriginInfo->mOrigin,
  2144. "Deleted itself!");
  2145. quotaManager->LockedRemoveQuotaForOrigin(
  2146. lock->GetPersistenceType().Value(),
  2147. lock->GetGroup(),
  2148. lock->GetOriginScope().GetOrigin());
  2149. }
  2150. // We unlocked and relocked several times so we need to recompute all the
  2151. // essential variables and recheck the group limit.
  2152. AssertNoUnderflow(aSize, mSize);
  2153. delta = aSize - mSize;
  2154. AssertNoOverflow(mOriginInfo->mUsage, delta);
  2155. newUsage = mOriginInfo->mUsage + delta;
  2156. AssertNoOverflow(groupInfo->mUsage, delta);
  2157. newGroupUsage = groupInfo->mUsage + delta;
  2158. groupUsage = groupInfo->mUsage;
  2159. if (complementaryGroupInfo) {
  2160. AssertNoOverflow(groupUsage, complementaryGroupInfo->mUsage);
  2161. groupUsage += complementaryGroupInfo->mUsage;
  2162. }
  2163. AssertNoOverflow(groupUsage, delta);
  2164. if (groupUsage + delta > quotaManager->GetGroupLimit()) {
  2165. // Unfortunately some other thread increased the group usage in the
  2166. // meantime and we are not below the group limit anymore.
  2167. // However, the origin eviction must be finalized in this case too.
  2168. MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex);
  2169. quotaManager->FinalizeOriginEviction(locks);
  2170. return false;
  2171. }
  2172. AssertNoOverflow(quotaManager->mTemporaryStorageUsage, delta);
  2173. newTemporaryStorageUsage = quotaManager->mTemporaryStorageUsage + delta;
  2174. NS_ASSERTION(newTemporaryStorageUsage <=
  2175. quotaManager->mTemporaryStorageLimit, "How come?!");
  2176. // Ok, we successfully freed enough space and the operation can continue
  2177. // without throwing the quota error.
  2178. mOriginInfo->mUsage = newUsage;
  2179. groupInfo->mUsage = newGroupUsage;
  2180. quotaManager->mTemporaryStorageUsage = newTemporaryStorageUsage;;
  2181. // Some other thread could increase the size in the meantime, but no more
  2182. // than this one.
  2183. MOZ_ASSERT(mSize < aSize);
  2184. mSize = aSize;
  2185. // Finally, release IO thread only objects and allow next synchronized
  2186. // ops for the evicted origins.
  2187. MutexAutoUnlock autoUnlock(quotaManager->mQuotaMutex);
  2188. quotaManager->FinalizeOriginEviction(locks);
  2189. return true;
  2190. }
  2191. mOriginInfo->mUsage = newUsage;
  2192. groupInfo->mUsage = newGroupUsage;
  2193. quotaManager->mTemporaryStorageUsage = newTemporaryStorageUsage;
  2194. mSize = aSize;
  2195. return true;
  2196. }
  2197. void
  2198. QuotaObject::DisableQuotaCheck()
  2199. {
  2200. QuotaManager* quotaManager = QuotaManager::Get();
  2201. MOZ_ASSERT(quotaManager);
  2202. MutexAutoLock lock(quotaManager->mQuotaMutex);
  2203. mQuotaCheckDisabled = true;
  2204. }
  2205. void
  2206. QuotaObject::EnableQuotaCheck()
  2207. {
  2208. QuotaManager* quotaManager = QuotaManager::Get();
  2209. MOZ_ASSERT(quotaManager);
  2210. MutexAutoLock lock(quotaManager->mQuotaMutex);
  2211. mQuotaCheckDisabled = false;
  2212. }
  2213. /*******************************************************************************
  2214. * Quota manager
  2215. ******************************************************************************/
  2216. QuotaManager::QuotaManager()
  2217. : mQuotaMutex("QuotaManager.mQuotaMutex"),
  2218. mTemporaryStorageLimit(0),
  2219. mTemporaryStorageUsage(0),
  2220. mTemporaryStorageInitialized(false),
  2221. mStorageInitialized(false)
  2222. {
  2223. AssertIsOnOwningThread();
  2224. MOZ_ASSERT(!gInstance);
  2225. }
  2226. QuotaManager::~QuotaManager()
  2227. {
  2228. AssertIsOnOwningThread();
  2229. MOZ_ASSERT(!gInstance || gInstance == this);
  2230. }
  2231. void
  2232. QuotaManager::GetOrCreate(nsIRunnable* aCallback)
  2233. {
  2234. AssertIsOnBackgroundThread();
  2235. if (IsShuttingDown()) {
  2236. MOZ_ASSERT(false, "Calling GetOrCreate() after shutdown!");
  2237. return;
  2238. }
  2239. if (gInstance || gCreateFailed) {
  2240. MOZ_ASSERT(!gCreateRunnable);
  2241. MOZ_ASSERT_IF(gCreateFailed, !gInstance);
  2242. MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(aCallback));
  2243. } else {
  2244. if (!gCreateRunnable) {
  2245. gCreateRunnable = new CreateRunnable();
  2246. MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(gCreateRunnable));
  2247. }
  2248. gCreateRunnable->AddCallback(aCallback);
  2249. }
  2250. }
  2251. // static
  2252. QuotaManager*
  2253. QuotaManager::Get()
  2254. {
  2255. // Does not return an owning reference.
  2256. return gInstance;
  2257. }
  2258. // static
  2259. bool
  2260. QuotaManager::IsShuttingDown()
  2261. {
  2262. return gShutdown;
  2263. }
  2264. auto
  2265. QuotaManager::CreateDirectoryLock(Nullable<PersistenceType> aPersistenceType,
  2266. const nsACString& aGroup,
  2267. const OriginScope& aOriginScope,
  2268. Nullable<bool> aIsApp,
  2269. Nullable<Client::Type> aClientType,
  2270. bool aExclusive,
  2271. bool aInternal,
  2272. OpenDirectoryListener* aOpenListener)
  2273. -> already_AddRefed<DirectoryLockImpl>
  2274. {
  2275. AssertIsOnOwningThread();
  2276. MOZ_ASSERT_IF(aOriginScope.IsOrigin(), !aOriginScope.GetOrigin().IsEmpty());
  2277. MOZ_ASSERT_IF(!aInternal, !aPersistenceType.IsNull());
  2278. MOZ_ASSERT_IF(!aInternal,
  2279. aPersistenceType.Value() != PERSISTENCE_TYPE_INVALID);
  2280. MOZ_ASSERT_IF(!aInternal, !aGroup.IsEmpty());
  2281. MOZ_ASSERT_IF(!aInternal, aOriginScope.IsOrigin());
  2282. MOZ_ASSERT_IF(!aInternal, !aIsApp.IsNull());
  2283. MOZ_ASSERT_IF(!aInternal, !aClientType.IsNull());
  2284. MOZ_ASSERT_IF(!aInternal, aClientType.Value() != Client::TYPE_MAX);
  2285. MOZ_ASSERT_IF(!aInternal, aOpenListener);
  2286. RefPtr<DirectoryLockImpl> lock = new DirectoryLockImpl(this,
  2287. aPersistenceType,
  2288. aGroup,
  2289. aOriginScope,
  2290. aIsApp,
  2291. aClientType,
  2292. aExclusive,
  2293. aInternal,
  2294. aOpenListener);
  2295. mPendingDirectoryLocks.AppendElement(lock);
  2296. // See if this lock needs to wait.
  2297. bool blocked = false;
  2298. for (uint32_t index = mDirectoryLocks.Length(); index > 0; index--) {
  2299. DirectoryLockImpl* existingLock = mDirectoryLocks[index - 1];
  2300. if (lock->MustWaitFor(*existingLock)) {
  2301. existingLock->AddBlockingLock(lock);
  2302. lock->AddBlockedOnLock(existingLock);
  2303. blocked = true;
  2304. }
  2305. }
  2306. RegisterDirectoryLock(lock);
  2307. // Otherwise, notify the open listener immediately.
  2308. if (!blocked) {
  2309. lock->NotifyOpenListener();
  2310. }
  2311. return lock.forget();
  2312. }
  2313. auto
  2314. QuotaManager::CreateDirectoryLockForEviction(PersistenceType aPersistenceType,
  2315. const nsACString& aGroup,
  2316. const nsACString& aOrigin,
  2317. bool aIsApp)
  2318. -> already_AddRefed<DirectoryLockImpl>
  2319. {
  2320. AssertIsOnOwningThread();
  2321. MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_INVALID);
  2322. MOZ_ASSERT(!aOrigin.IsEmpty());
  2323. RefPtr<DirectoryLockImpl> lock =
  2324. new DirectoryLockImpl(this,
  2325. Nullable<PersistenceType>(aPersistenceType),
  2326. aGroup,
  2327. OriginScope::FromOrigin(aOrigin),
  2328. Nullable<bool>(aIsApp),
  2329. Nullable<Client::Type>(),
  2330. /* aExclusive */ true,
  2331. /* aInternal */ true,
  2332. nullptr);
  2333. #ifdef DEBUG
  2334. for (uint32_t index = mDirectoryLocks.Length(); index > 0; index--) {
  2335. DirectoryLockImpl* existingLock = mDirectoryLocks[index - 1];
  2336. MOZ_ASSERT(!lock->MustWaitFor(*existingLock));
  2337. }
  2338. #endif
  2339. RegisterDirectoryLock(lock);
  2340. return lock.forget();
  2341. }
  2342. void
  2343. QuotaManager::RegisterDirectoryLock(DirectoryLockImpl* aLock)
  2344. {
  2345. AssertIsOnOwningThread();
  2346. MOZ_ASSERT(aLock);
  2347. mDirectoryLocks.AppendElement(aLock);
  2348. if (aLock->ShouldUpdateLockTable()) {
  2349. const Nullable<PersistenceType>& persistenceType =
  2350. aLock->GetPersistenceType();
  2351. const OriginScope& originScope = aLock->GetOriginScope();
  2352. MOZ_ASSERT(!persistenceType.IsNull());
  2353. MOZ_ASSERT(!aLock->GetGroup().IsEmpty());
  2354. MOZ_ASSERT(originScope.IsOrigin());
  2355. MOZ_ASSERT(!originScope.GetOrigin().IsEmpty());
  2356. DirectoryLockTable& directoryLockTable =
  2357. GetDirectoryLockTable(persistenceType.Value());
  2358. nsTArray<DirectoryLockImpl*>* array;
  2359. if (!directoryLockTable.Get(originScope.GetOrigin(), &array)) {
  2360. array = new nsTArray<DirectoryLockImpl*>();
  2361. directoryLockTable.Put(originScope.GetOrigin(), array);
  2362. if (!IsShuttingDown()) {
  2363. UpdateOriginAccessTime(persistenceType.Value(),
  2364. aLock->GetGroup(),
  2365. originScope.GetOrigin());
  2366. }
  2367. }
  2368. array->AppendElement(aLock);
  2369. }
  2370. }
  2371. void
  2372. QuotaManager::UnregisterDirectoryLock(DirectoryLockImpl* aLock)
  2373. {
  2374. AssertIsOnOwningThread();
  2375. MOZ_ALWAYS_TRUE(mDirectoryLocks.RemoveElement(aLock));
  2376. if (aLock->ShouldUpdateLockTable()) {
  2377. const Nullable<PersistenceType>& persistenceType =
  2378. aLock->GetPersistenceType();
  2379. const OriginScope& originScope = aLock->GetOriginScope();
  2380. MOZ_ASSERT(!persistenceType.IsNull());
  2381. MOZ_ASSERT(!aLock->GetGroup().IsEmpty());
  2382. MOZ_ASSERT(originScope.IsOrigin());
  2383. MOZ_ASSERT(!originScope.GetOrigin().IsEmpty());
  2384. DirectoryLockTable& directoryLockTable =
  2385. GetDirectoryLockTable(persistenceType.Value());
  2386. nsTArray<DirectoryLockImpl*>* array;
  2387. MOZ_ALWAYS_TRUE(directoryLockTable.Get(originScope.GetOrigin(), &array));
  2388. MOZ_ALWAYS_TRUE(array->RemoveElement(aLock));
  2389. if (array->IsEmpty()) {
  2390. directoryLockTable.Remove(originScope.GetOrigin());
  2391. if (!IsShuttingDown()) {
  2392. UpdateOriginAccessTime(persistenceType.Value(),
  2393. aLock->GetGroup(),
  2394. originScope.GetOrigin());
  2395. }
  2396. }
  2397. }
  2398. }
  2399. void
  2400. QuotaManager::RemovePendingDirectoryLock(DirectoryLockImpl* aLock)
  2401. {
  2402. AssertIsOnOwningThread();
  2403. MOZ_ASSERT(aLock);
  2404. MOZ_ALWAYS_TRUE(mPendingDirectoryLocks.RemoveElement(aLock));
  2405. }
  2406. uint64_t
  2407. QuotaManager::CollectOriginsForEviction(
  2408. uint64_t aMinSizeToBeFreed,
  2409. nsTArray<RefPtr<DirectoryLockImpl>>& aLocks)
  2410. {
  2411. AssertIsOnOwningThread();
  2412. MOZ_ASSERT(aLocks.IsEmpty());
  2413. struct MOZ_STACK_CLASS Helper final
  2414. {
  2415. static void
  2416. GetInactiveOriginInfos(nsTArray<RefPtr<OriginInfo>>& aOriginInfos,
  2417. nsTArray<DirectoryLockImpl*>& aLocks,
  2418. nsTArray<OriginInfo*>& aInactiveOriginInfos)
  2419. {
  2420. for (OriginInfo* originInfo : aOriginInfos) {
  2421. MOZ_ASSERT(IsTreatedAsTemporary(originInfo->mGroupInfo->mPersistenceType,
  2422. originInfo->mIsApp));
  2423. OriginScope originScope = OriginScope::FromOrigin(originInfo->mOrigin);
  2424. bool match = false;
  2425. for (uint32_t j = aLocks.Length(); j > 0; j--) {
  2426. DirectoryLockImpl* lock = aLocks[j - 1];
  2427. if (originScope.Matches(lock->GetOriginScope())) {
  2428. match = true;
  2429. break;
  2430. }
  2431. }
  2432. if (!match) {
  2433. MOZ_ASSERT(!originInfo->mQuotaObjects.Count(),
  2434. "Inactive origin shouldn't have open files!");
  2435. aInactiveOriginInfos.InsertElementSorted(originInfo,
  2436. OriginInfoLRUComparator());
  2437. }
  2438. }
  2439. }
  2440. };
  2441. // Split locks into separate arrays and filter out locks for persistent
  2442. // storage, they can't block us.
  2443. nsTArray<DirectoryLockImpl*> temporaryStorageLocks;
  2444. nsTArray<DirectoryLockImpl*> defaultStorageLocks;
  2445. for (DirectoryLockImpl* lock : mDirectoryLocks) {
  2446. const Nullable<PersistenceType>& persistenceType =
  2447. lock->GetPersistenceType();
  2448. if (persistenceType.IsNull()) {
  2449. temporaryStorageLocks.AppendElement(lock);
  2450. defaultStorageLocks.AppendElement(lock);
  2451. } else if (persistenceType.Value() == PERSISTENCE_TYPE_TEMPORARY) {
  2452. temporaryStorageLocks.AppendElement(lock);
  2453. } else if (persistenceType.Value() == PERSISTENCE_TYPE_DEFAULT) {
  2454. defaultStorageLocks.AppendElement(lock);
  2455. } else {
  2456. MOZ_ASSERT(persistenceType.Value() == PERSISTENCE_TYPE_PERSISTENT);
  2457. // Do nothing here, persistent origins don't need to be collected ever.
  2458. }
  2459. }
  2460. nsTArray<OriginInfo*> inactiveOrigins;
  2461. // Enumerate and process inactive origins. This must be protected by the
  2462. // mutex.
  2463. MutexAutoLock lock(mQuotaMutex);
  2464. for (auto iter = mGroupInfoPairs.Iter(); !iter.Done(); iter.Next()) {
  2465. GroupInfoPair* pair = iter.UserData();
  2466. MOZ_ASSERT(!iter.Key().IsEmpty());
  2467. MOZ_ASSERT(pair);
  2468. RefPtr<GroupInfo> groupInfo =
  2469. pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
  2470. if (groupInfo) {
  2471. Helper::GetInactiveOriginInfos(groupInfo->mOriginInfos,
  2472. temporaryStorageLocks,
  2473. inactiveOrigins);
  2474. }
  2475. groupInfo = pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
  2476. if (groupInfo) {
  2477. Helper::GetInactiveOriginInfos(groupInfo->mOriginInfos,
  2478. defaultStorageLocks,
  2479. inactiveOrigins);
  2480. }
  2481. }
  2482. #ifdef DEBUG
  2483. // Make sure the array is sorted correctly.
  2484. for (uint32_t index = inactiveOrigins.Length(); index > 1; index--) {
  2485. MOZ_ASSERT(inactiveOrigins[index - 1]->mAccessTime >=
  2486. inactiveOrigins[index - 2]->mAccessTime);
  2487. }
  2488. #endif
  2489. // Create a list of inactive and the least recently used origins
  2490. // whose aggregate size is greater or equals the minimal size to be freed.
  2491. uint64_t sizeToBeFreed = 0;
  2492. for(uint32_t count = inactiveOrigins.Length(), index = 0;
  2493. index < count;
  2494. index++) {
  2495. if (sizeToBeFreed >= aMinSizeToBeFreed) {
  2496. inactiveOrigins.TruncateLength(index);
  2497. break;
  2498. }
  2499. sizeToBeFreed += inactiveOrigins[index]->mUsage;
  2500. }
  2501. if (sizeToBeFreed >= aMinSizeToBeFreed) {
  2502. // Success, add directory locks for these origins, so any other
  2503. // operations for them will be delayed (until origin eviction is finalized).
  2504. for (OriginInfo* originInfo : inactiveOrigins) {
  2505. RefPtr<DirectoryLockImpl> lock =
  2506. CreateDirectoryLockForEviction(originInfo->mGroupInfo->mPersistenceType,
  2507. originInfo->mGroupInfo->mGroup,
  2508. originInfo->mOrigin,
  2509. originInfo->mIsApp);
  2510. aLocks.AppendElement(lock.forget());
  2511. }
  2512. return sizeToBeFreed;
  2513. }
  2514. return 0;
  2515. }
  2516. nsresult
  2517. QuotaManager::Init(const nsAString& aBasePath)
  2518. {
  2519. nsresult rv;
  2520. mBasePath = aBasePath;
  2521. nsCOMPtr<nsIFile> baseDir = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  2522. if (NS_WARN_IF(NS_FAILED(rv))) {
  2523. return rv;
  2524. }
  2525. rv = baseDir->InitWithPath(aBasePath);
  2526. if (NS_WARN_IF(NS_FAILED(rv))) {
  2527. return rv;
  2528. }
  2529. rv = CloneStoragePath(baseDir,
  2530. NS_LITERAL_STRING(INDEXEDDB_DIRECTORY_NAME),
  2531. mIndexedDBPath);
  2532. if (NS_WARN_IF(NS_FAILED(rv))) {
  2533. return rv;
  2534. }
  2535. rv = baseDir->Append(NS_LITERAL_STRING(STORAGE_DIRECTORY_NAME));
  2536. if (NS_WARN_IF(NS_FAILED(rv))) {
  2537. return rv;
  2538. }
  2539. rv = baseDir->GetPath(mStoragePath);
  2540. if (NS_WARN_IF(NS_FAILED(rv))) {
  2541. return rv;
  2542. }
  2543. rv = CloneStoragePath(baseDir,
  2544. NS_LITERAL_STRING(PERMANENT_DIRECTORY_NAME),
  2545. mPermanentStoragePath);
  2546. if (NS_WARN_IF(NS_FAILED(rv))) {
  2547. return rv;
  2548. }
  2549. rv = CloneStoragePath(baseDir,
  2550. NS_LITERAL_STRING(TEMPORARY_DIRECTORY_NAME),
  2551. mTemporaryStoragePath);
  2552. if (NS_WARN_IF(NS_FAILED(rv))) {
  2553. return rv;
  2554. }
  2555. rv = CloneStoragePath(baseDir,
  2556. NS_LITERAL_STRING(DEFAULT_DIRECTORY_NAME),
  2557. mDefaultStoragePath);
  2558. if (NS_WARN_IF(NS_FAILED(rv))) {
  2559. return rv;
  2560. }
  2561. // Make a lazy thread for any IO we need (like clearing or enumerating the
  2562. // contents of storage directories).
  2563. mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
  2564. NS_LITERAL_CSTRING("Storage I/O"),
  2565. LazyIdleThread::ManualShutdown);
  2566. // Make a timer here to avoid potential failures later. We don't actually
  2567. // initialize the timer until shutdown.
  2568. mShutdownTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
  2569. if (NS_WARN_IF(!mShutdownTimer)) {
  2570. return NS_ERROR_FAILURE;
  2571. }
  2572. static_assert(Client::IDB == 0 && Client::ASMJS == 1 && Client::DOMCACHE == 2 &&
  2573. Client::TYPE_MAX == 3, "Fix the registration!");
  2574. MOZ_ASSERT(mClients.Capacity() == Client::TYPE_MAX,
  2575. "Should be using an auto array with correct capacity!");
  2576. // Register clients.
  2577. mClients.AppendElement(indexedDB::CreateQuotaClient());
  2578. mClients.AppendElement(asmjscache::CreateClient());
  2579. mClients.AppendElement(cache::CreateQuotaClient());
  2580. return NS_OK;
  2581. }
  2582. void
  2583. QuotaManager::Shutdown()
  2584. {
  2585. AssertIsOnOwningThread();
  2586. // Setting this flag prevents the service from being recreated and prevents
  2587. // further storagess from being created.
  2588. if (gShutdown.exchange(true)) {
  2589. NS_ERROR("Shutdown more than once?!");
  2590. }
  2591. StopIdleMaintenance();
  2592. // Kick off the shutdown timer.
  2593. MOZ_ALWAYS_SUCCEEDS(
  2594. mShutdownTimer->InitWithFuncCallback(&ShutdownTimerCallback,
  2595. this,
  2596. DEFAULT_SHUTDOWN_TIMER_MS,
  2597. nsITimer::TYPE_ONE_SHOT));
  2598. // Each client will spin the event loop while we wait on all the threads
  2599. // to close. Our timer may fire during that loop.
  2600. for (uint32_t index = 0; index < Client::TYPE_MAX; index++) {
  2601. mClients[index]->ShutdownWorkThreads();
  2602. }
  2603. // Cancel the timer regardless of whether it actually fired.
  2604. if (NS_FAILED(mShutdownTimer->Cancel())) {
  2605. NS_WARNING("Failed to cancel shutdown timer!");
  2606. }
  2607. // NB: It's very important that runnable is destroyed on this thread
  2608. // (i.e. after we join the IO thread) because we can't release the
  2609. // QuotaManager on the IO thread. This should probably use
  2610. // NewNonOwningRunnableMethod ...
  2611. RefPtr<Runnable> runnable =
  2612. NewRunnableMethod(this, &QuotaManager::ReleaseIOThreadObjects);
  2613. MOZ_ASSERT(runnable);
  2614. // Give clients a chance to cleanup IO thread only objects.
  2615. if (NS_FAILED(mIOThread->Dispatch(runnable, NS_DISPATCH_NORMAL))) {
  2616. NS_WARNING("Failed to dispatch runnable!");
  2617. }
  2618. // Make sure to join with our IO thread.
  2619. if (NS_FAILED(mIOThread->Shutdown())) {
  2620. NS_WARNING("Failed to shutdown IO thread!");
  2621. }
  2622. for (RefPtr<DirectoryLockImpl>& lock : mPendingDirectoryLocks) {
  2623. lock->Invalidate();
  2624. }
  2625. }
  2626. void
  2627. QuotaManager::InitQuotaForOrigin(PersistenceType aPersistenceType,
  2628. const nsACString& aGroup,
  2629. const nsACString& aOrigin,
  2630. bool aIsApp,
  2631. uint64_t aUsageBytes,
  2632. int64_t aAccessTime)
  2633. {
  2634. AssertIsOnIOThread();
  2635. MOZ_ASSERT(IsTreatedAsTemporary(aPersistenceType, aIsApp));
  2636. MutexAutoLock lock(mQuotaMutex);
  2637. GroupInfoPair* pair;
  2638. if (!mGroupInfoPairs.Get(aGroup, &pair)) {
  2639. pair = new GroupInfoPair();
  2640. mGroupInfoPairs.Put(aGroup, pair);
  2641. // The hashtable is now responsible to delete the GroupInfoPair.
  2642. }
  2643. RefPtr<GroupInfo> groupInfo = pair->LockedGetGroupInfo(aPersistenceType);
  2644. if (!groupInfo) {
  2645. groupInfo = new GroupInfo(pair, aPersistenceType, aGroup);
  2646. pair->LockedSetGroupInfo(aPersistenceType, groupInfo);
  2647. }
  2648. RefPtr<OriginInfo> originInfo =
  2649. new OriginInfo(groupInfo, aOrigin, aIsApp, aUsageBytes, aAccessTime);
  2650. groupInfo->LockedAddOriginInfo(originInfo);
  2651. }
  2652. void
  2653. QuotaManager::DecreaseUsageForOrigin(PersistenceType aPersistenceType,
  2654. const nsACString& aGroup,
  2655. const nsACString& aOrigin,
  2656. int64_t aSize)
  2657. {
  2658. MOZ_ASSERT(!NS_IsMainThread());
  2659. MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
  2660. MutexAutoLock lock(mQuotaMutex);
  2661. GroupInfoPair* pair;
  2662. if (!mGroupInfoPairs.Get(aGroup, &pair)) {
  2663. return;
  2664. }
  2665. RefPtr<GroupInfo> groupInfo = pair->LockedGetGroupInfo(aPersistenceType);
  2666. if (!groupInfo) {
  2667. return;
  2668. }
  2669. RefPtr<OriginInfo> originInfo = groupInfo->LockedGetOriginInfo(aOrigin);
  2670. if (originInfo) {
  2671. originInfo->LockedDecreaseUsage(aSize);
  2672. }
  2673. }
  2674. void
  2675. QuotaManager::UpdateOriginAccessTime(PersistenceType aPersistenceType,
  2676. const nsACString& aGroup,
  2677. const nsACString& aOrigin)
  2678. {
  2679. AssertIsOnOwningThread();
  2680. MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
  2681. MutexAutoLock lock(mQuotaMutex);
  2682. GroupInfoPair* pair;
  2683. if (!mGroupInfoPairs.Get(aGroup, &pair)) {
  2684. return;
  2685. }
  2686. RefPtr<GroupInfo> groupInfo = pair->LockedGetGroupInfo(aPersistenceType);
  2687. if (!groupInfo) {
  2688. return;
  2689. }
  2690. RefPtr<OriginInfo> originInfo = groupInfo->LockedGetOriginInfo(aOrigin);
  2691. if (originInfo) {
  2692. int64_t timestamp = PR_Now();
  2693. originInfo->LockedUpdateAccessTime(timestamp);
  2694. MutexAutoUnlock autoUnlock(mQuotaMutex);
  2695. RefPtr<SaveOriginAccessTimeOp> op =
  2696. new SaveOriginAccessTimeOp(aPersistenceType, aOrigin, timestamp);
  2697. op->RunImmediately();
  2698. }
  2699. }
  2700. void
  2701. QuotaManager::RemoveQuota()
  2702. {
  2703. MutexAutoLock lock(mQuotaMutex);
  2704. for (auto iter = mGroupInfoPairs.Iter(); !iter.Done(); iter.Next()) {
  2705. nsAutoPtr<GroupInfoPair>& pair = iter.Data();
  2706. MOZ_ASSERT(!iter.Key().IsEmpty(), "Empty key!");
  2707. MOZ_ASSERT(pair, "Null pointer!");
  2708. RefPtr<GroupInfo> groupInfo =
  2709. pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
  2710. if (groupInfo) {
  2711. groupInfo->LockedRemoveOriginInfos();
  2712. }
  2713. groupInfo = pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
  2714. if (groupInfo) {
  2715. groupInfo->LockedRemoveOriginInfos();
  2716. }
  2717. iter.Remove();
  2718. }
  2719. NS_ASSERTION(mTemporaryStorageUsage == 0, "Should be zero!");
  2720. }
  2721. already_AddRefed<QuotaObject>
  2722. QuotaManager::GetQuotaObject(PersistenceType aPersistenceType,
  2723. const nsACString& aGroup,
  2724. const nsACString& aOrigin,
  2725. nsIFile* aFile)
  2726. {
  2727. NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
  2728. if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) {
  2729. return nullptr;
  2730. }
  2731. nsString path;
  2732. nsresult rv = aFile->GetPath(path);
  2733. NS_ENSURE_SUCCESS(rv, nullptr);
  2734. int64_t fileSize;
  2735. bool exists;
  2736. rv = aFile->Exists(&exists);
  2737. NS_ENSURE_SUCCESS(rv, nullptr);
  2738. if (exists) {
  2739. rv = aFile->GetFileSize(&fileSize);
  2740. NS_ENSURE_SUCCESS(rv, nullptr);
  2741. }
  2742. else {
  2743. fileSize = 0;
  2744. }
  2745. // Re-escape our parameters above to make sure we get the right quota group.
  2746. nsAutoCString group;
  2747. rv = NS_EscapeURL(aGroup, esc_Query, group, fallible);
  2748. NS_ENSURE_SUCCESS(rv, nullptr);
  2749. nsAutoCString origin;
  2750. rv = NS_EscapeURL(aOrigin, esc_Query, origin, fallible);
  2751. NS_ENSURE_SUCCESS(rv, nullptr);
  2752. RefPtr<QuotaObject> result;
  2753. {
  2754. MutexAutoLock lock(mQuotaMutex);
  2755. GroupInfoPair* pair;
  2756. if (!mGroupInfoPairs.Get(group, &pair)) {
  2757. return nullptr;
  2758. }
  2759. RefPtr<GroupInfo> groupInfo =
  2760. pair->LockedGetGroupInfo(aPersistenceType);
  2761. if (!groupInfo) {
  2762. return nullptr;
  2763. }
  2764. RefPtr<OriginInfo> originInfo = groupInfo->LockedGetOriginInfo(origin);
  2765. if (!originInfo) {
  2766. return nullptr;
  2767. }
  2768. // We need this extra raw pointer because we can't assign to the smart
  2769. // pointer directly since QuotaObject::AddRef would try to acquire the same
  2770. // mutex.
  2771. QuotaObject* quotaObject;
  2772. if (!originInfo->mQuotaObjects.Get(path, &quotaObject)) {
  2773. // Create a new QuotaObject.
  2774. quotaObject = new QuotaObject(originInfo, path, fileSize);
  2775. // Put it to the hashtable. The hashtable is not responsible to delete
  2776. // the QuotaObject.
  2777. originInfo->mQuotaObjects.Put(path, quotaObject);
  2778. }
  2779. // Addref the QuotaObject and move the ownership to the result. This must
  2780. // happen before we unlock!
  2781. result = quotaObject->LockedAddRef();
  2782. }
  2783. // The caller becomes the owner of the QuotaObject, that is, the caller is
  2784. // is responsible to delete it when the last reference is removed.
  2785. return result.forget();
  2786. }
  2787. already_AddRefed<QuotaObject>
  2788. QuotaManager::GetQuotaObject(PersistenceType aPersistenceType,
  2789. const nsACString& aGroup,
  2790. const nsACString& aOrigin,
  2791. const nsAString& aPath)
  2792. {
  2793. nsresult rv;
  2794. nsCOMPtr<nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  2795. NS_ENSURE_SUCCESS(rv, nullptr);
  2796. rv = file->InitWithPath(aPath);
  2797. NS_ENSURE_SUCCESS(rv, nullptr);
  2798. return GetQuotaObject(aPersistenceType, aGroup, aOrigin, file);
  2799. }
  2800. void
  2801. QuotaManager::AbortOperationsForProcess(ContentParentId aContentParentId)
  2802. {
  2803. AssertIsOnOwningThread();
  2804. for (RefPtr<Client>& client : mClients) {
  2805. client->AbortOperationsForProcess(aContentParentId);
  2806. }
  2807. }
  2808. nsresult
  2809. QuotaManager::GetDirectoryForOrigin(PersistenceType aPersistenceType,
  2810. const nsACString& aASCIIOrigin,
  2811. nsIFile** aDirectory) const
  2812. {
  2813. nsresult rv;
  2814. nsCOMPtr<nsIFile> directory =
  2815. do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  2816. NS_ENSURE_SUCCESS(rv, rv);
  2817. rv = directory->InitWithPath(GetStoragePath(aPersistenceType));
  2818. NS_ENSURE_SUCCESS(rv, rv);
  2819. nsAutoCString originSanitized(aASCIIOrigin);
  2820. SanitizeOriginString(originSanitized);
  2821. rv = directory->Append(NS_ConvertASCIItoUTF16(originSanitized));
  2822. NS_ENSURE_SUCCESS(rv, rv);
  2823. directory.forget(aDirectory);
  2824. return NS_OK;
  2825. }
  2826. nsresult
  2827. QuotaManager::RestoreDirectoryMetadata2(nsIFile* aDirectory, bool aPersistent)
  2828. {
  2829. AssertIsOnIOThread();
  2830. MOZ_ASSERT(aDirectory);
  2831. MOZ_ASSERT(mStorageInitialized);
  2832. RefPtr<RestoreDirectoryMetadata2Helper> helper =
  2833. new RestoreDirectoryMetadata2Helper(aDirectory, aPersistent);
  2834. nsresult rv = helper->RestoreMetadata2File();
  2835. if (NS_WARN_IF(NS_FAILED(rv))) {
  2836. return rv;
  2837. }
  2838. return NS_OK;
  2839. }
  2840. nsresult
  2841. QuotaManager::GetDirectoryMetadata2(nsIFile* aDirectory,
  2842. int64_t* aTimestamp,
  2843. nsACString& aSuffix,
  2844. nsACString& aGroup,
  2845. nsACString& aOrigin,
  2846. bool* aIsApp)
  2847. {
  2848. MOZ_ASSERT(!NS_IsMainThread());
  2849. MOZ_ASSERT(aDirectory);
  2850. MOZ_ASSERT(aTimestamp);
  2851. MOZ_ASSERT(aIsApp);
  2852. MOZ_ASSERT(mStorageInitialized);
  2853. nsCOMPtr<nsIBinaryInputStream> binaryStream;
  2854. nsresult rv = GetBinaryInputStream(aDirectory,
  2855. NS_LITERAL_STRING(METADATA_V2_FILE_NAME),
  2856. getter_AddRefs(binaryStream));
  2857. NS_ENSURE_SUCCESS(rv, rv);
  2858. uint64_t timestamp;
  2859. rv = binaryStream->Read64(&timestamp);
  2860. NS_ENSURE_SUCCESS(rv, rv);
  2861. bool persisted;
  2862. rv = binaryStream->ReadBoolean(&persisted);
  2863. if (NS_WARN_IF(NS_FAILED(rv))) {
  2864. return rv;
  2865. }
  2866. uint32_t reservedData1;
  2867. rv = binaryStream->Read32(&reservedData1);
  2868. if (NS_WARN_IF(NS_FAILED(rv))) {
  2869. return rv;
  2870. }
  2871. uint32_t reservedData2;
  2872. rv = binaryStream->Read32(&reservedData2);
  2873. if (NS_WARN_IF(NS_FAILED(rv))) {
  2874. return rv;
  2875. }
  2876. nsCString suffix;
  2877. rv = binaryStream->ReadCString(suffix);
  2878. if (NS_WARN_IF(NS_FAILED(rv))) {
  2879. return rv;
  2880. }
  2881. nsCString group;
  2882. rv = binaryStream->ReadCString(group);
  2883. NS_ENSURE_SUCCESS(rv, rv);
  2884. nsCString origin;
  2885. rv = binaryStream->ReadCString(origin);
  2886. NS_ENSURE_SUCCESS(rv, rv);
  2887. bool isApp;
  2888. rv = binaryStream->ReadBoolean(&isApp);
  2889. if (NS_WARN_IF(NS_FAILED(rv))) {
  2890. return rv;
  2891. }
  2892. *aTimestamp = timestamp;
  2893. aSuffix = suffix;
  2894. aGroup = group;
  2895. aOrigin = origin;
  2896. *aIsApp = isApp;
  2897. return NS_OK;
  2898. }
  2899. nsresult
  2900. QuotaManager::GetDirectoryMetadata2WithRestore(nsIFile* aDirectory,
  2901. bool aPersistent,
  2902. int64_t* aTimestamp,
  2903. nsACString& aSuffix,
  2904. nsACString& aGroup,
  2905. nsACString& aOrigin,
  2906. bool* aIsApp)
  2907. {
  2908. nsresult rv = GetDirectoryMetadata2(aDirectory,
  2909. aTimestamp,
  2910. aSuffix,
  2911. aGroup,
  2912. aOrigin,
  2913. aIsApp);
  2914. if (NS_WARN_IF(NS_FAILED(rv))) {
  2915. rv = RestoreDirectoryMetadata2(aDirectory, aPersistent);
  2916. if (NS_WARN_IF(NS_FAILED(rv))) {
  2917. return rv;
  2918. }
  2919. rv = GetDirectoryMetadata2(aDirectory,
  2920. aTimestamp,
  2921. aSuffix,
  2922. aGroup,
  2923. aOrigin,
  2924. aIsApp);
  2925. if (NS_WARN_IF(NS_FAILED(rv))) {
  2926. return rv;
  2927. }
  2928. }
  2929. return NS_OK;
  2930. }
  2931. nsresult
  2932. QuotaManager::GetDirectoryMetadata2(nsIFile* aDirectory, int64_t* aTimestamp)
  2933. {
  2934. AssertIsOnIOThread();
  2935. MOZ_ASSERT(aDirectory);
  2936. MOZ_ASSERT(aTimestamp);
  2937. MOZ_ASSERT(mStorageInitialized);
  2938. nsCOMPtr<nsIBinaryInputStream> binaryStream;
  2939. nsresult rv = GetBinaryInputStream(aDirectory,
  2940. NS_LITERAL_STRING(METADATA_V2_FILE_NAME),
  2941. getter_AddRefs(binaryStream));
  2942. if (NS_WARN_IF(NS_FAILED(rv))) {
  2943. return rv;
  2944. }
  2945. uint64_t timestamp;
  2946. rv = binaryStream->Read64(&timestamp);
  2947. if (NS_WARN_IF(NS_FAILED(rv))) {
  2948. return rv;
  2949. }
  2950. *aTimestamp = timestamp;
  2951. return NS_OK;
  2952. }
  2953. nsresult
  2954. QuotaManager::GetDirectoryMetadata2WithRestore(nsIFile* aDirectory,
  2955. bool aPersistent,
  2956. int64_t* aTimestamp)
  2957. {
  2958. nsresult rv = GetDirectoryMetadata2(aDirectory, aTimestamp);
  2959. if (NS_WARN_IF(NS_FAILED(rv))) {
  2960. rv = RestoreDirectoryMetadata2(aDirectory, aPersistent);
  2961. if (NS_WARN_IF(NS_FAILED(rv))) {
  2962. return rv;
  2963. }
  2964. rv = GetDirectoryMetadata2(aDirectory, aTimestamp);
  2965. if (NS_WARN_IF(NS_FAILED(rv))) {
  2966. return rv;
  2967. }
  2968. }
  2969. return NS_OK;
  2970. }
  2971. nsresult
  2972. QuotaManager::InitializeRepository(PersistenceType aPersistenceType)
  2973. {
  2974. MOZ_ASSERT(aPersistenceType == PERSISTENCE_TYPE_TEMPORARY ||
  2975. aPersistenceType == PERSISTENCE_TYPE_DEFAULT);
  2976. nsresult rv;
  2977. nsCOMPtr<nsIFile> directory =
  2978. do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  2979. if (NS_WARN_IF(NS_FAILED(rv))) {
  2980. return rv;
  2981. }
  2982. rv = directory->InitWithPath(GetStoragePath(aPersistenceType));
  2983. if (NS_WARN_IF(NS_FAILED(rv))) {
  2984. return rv;
  2985. }
  2986. bool created;
  2987. rv = EnsureDirectory(directory, &created);
  2988. if (NS_WARN_IF(NS_FAILED(rv))) {
  2989. return rv;
  2990. }
  2991. nsCOMPtr<nsISimpleEnumerator> entries;
  2992. rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
  2993. if (NS_WARN_IF(NS_FAILED(rv))) {
  2994. return rv;
  2995. }
  2996. bool hasMore;
  2997. while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
  2998. nsCOMPtr<nsISupports> entry;
  2999. rv = entries->GetNext(getter_AddRefs(entry));
  3000. if (NS_WARN_IF(NS_FAILED(rv))) {
  3001. return rv;
  3002. }
  3003. nsCOMPtr<nsIFile> childDirectory = do_QueryInterface(entry);
  3004. MOZ_ASSERT(childDirectory);
  3005. bool isDirectory;
  3006. rv = childDirectory->IsDirectory(&isDirectory);
  3007. if (NS_WARN_IF(NS_FAILED(rv))) {
  3008. return rv;
  3009. }
  3010. if (!isDirectory) {
  3011. nsString leafName;
  3012. rv = childDirectory->GetLeafName(leafName);
  3013. if (NS_WARN_IF(NS_FAILED(rv))) {
  3014. return rv;
  3015. }
  3016. if (leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
  3017. continue;
  3018. }
  3019. QM_WARNING("Something (%s) in the repository that doesn't belong!",
  3020. NS_ConvertUTF16toUTF8(leafName).get());
  3021. return NS_ERROR_UNEXPECTED;
  3022. }
  3023. int64_t timestamp;
  3024. nsCString suffix;
  3025. nsCString group;
  3026. nsCString origin;
  3027. bool isApp;
  3028. rv = GetDirectoryMetadata2WithRestore(childDirectory,
  3029. /* aPersistent */ false,
  3030. &timestamp,
  3031. suffix,
  3032. group,
  3033. origin,
  3034. &isApp);
  3035. if (NS_WARN_IF(NS_FAILED(rv))) {
  3036. return rv;
  3037. }
  3038. if (IsTreatedAsPersistent(aPersistenceType, isApp)) {
  3039. continue;
  3040. }
  3041. rv = InitializeOrigin(aPersistenceType, group, origin, isApp, timestamp,
  3042. childDirectory);
  3043. if (NS_WARN_IF(NS_FAILED(rv))) {
  3044. return rv;
  3045. }
  3046. }
  3047. if (NS_WARN_IF(NS_FAILED(rv))) {
  3048. return rv;
  3049. }
  3050. return NS_OK;
  3051. }
  3052. namespace {
  3053. // The Cache API was creating top level morgue directories by accident for
  3054. // a short time in nightly. This unfortunately prevents all storage from
  3055. // working. So recover these profiles by removing these corrupt directories.
  3056. // This should be removed at some point in the future.
  3057. bool
  3058. MaybeRemoveCorruptDirectory(const nsAString& aLeafName, nsIFile* aDir)
  3059. {
  3060. #ifdef NIGHTLY_BUILD
  3061. MOZ_ASSERT(aDir);
  3062. if (aLeafName != NS_LITERAL_STRING("morgue")) {
  3063. return false;
  3064. }
  3065. NS_WARNING("QuotaManager removing corrupt morgue directory!");
  3066. nsresult rv = aDir->Remove(true /* recursive */);
  3067. if (NS_WARN_IF(NS_FAILED(rv))) {
  3068. return false;
  3069. }
  3070. return true;
  3071. #else
  3072. return false;
  3073. #endif // NIGHTLY_BUILD
  3074. }
  3075. } // namespace
  3076. nsresult
  3077. QuotaManager::InitializeOrigin(PersistenceType aPersistenceType,
  3078. const nsACString& aGroup,
  3079. const nsACString& aOrigin,
  3080. bool aIsApp,
  3081. int64_t aAccessTime,
  3082. nsIFile* aDirectory)
  3083. {
  3084. AssertIsOnIOThread();
  3085. nsresult rv;
  3086. bool trackQuota = IsQuotaEnforced(aPersistenceType, aOrigin, aIsApp);
  3087. // We need to initialize directories of all clients if they exists and also
  3088. // get the total usage to initialize the quota.
  3089. nsAutoPtr<UsageInfo> usageInfo;
  3090. if (trackQuota) {
  3091. usageInfo = new UsageInfo();
  3092. }
  3093. nsCOMPtr<nsISimpleEnumerator> entries;
  3094. rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
  3095. NS_ENSURE_SUCCESS(rv, rv);
  3096. bool hasMore;
  3097. while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
  3098. nsCOMPtr<nsISupports> entry;
  3099. rv = entries->GetNext(getter_AddRefs(entry));
  3100. NS_ENSURE_SUCCESS(rv, rv);
  3101. nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
  3102. NS_ENSURE_TRUE(file, NS_NOINTERFACE);
  3103. nsString leafName;
  3104. rv = file->GetLeafName(leafName);
  3105. NS_ENSURE_SUCCESS(rv, rv);
  3106. if (leafName.EqualsLiteral(METADATA_FILE_NAME) ||
  3107. leafName.EqualsLiteral(METADATA_V2_FILE_NAME) ||
  3108. leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
  3109. continue;
  3110. }
  3111. bool isDirectory;
  3112. rv = file->IsDirectory(&isDirectory);
  3113. NS_ENSURE_SUCCESS(rv, rv);
  3114. if (!isDirectory) {
  3115. NS_WARNING("Unknown file found!");
  3116. return NS_ERROR_UNEXPECTED;
  3117. }
  3118. if (MaybeRemoveCorruptDirectory(leafName, file)) {
  3119. continue;
  3120. }
  3121. Client::Type clientType;
  3122. rv = Client::TypeFromText(leafName, clientType);
  3123. if (NS_FAILED(rv)) {
  3124. NS_WARNING("Unknown directory found!");
  3125. return NS_ERROR_UNEXPECTED;
  3126. }
  3127. Atomic<bool> dummy(false);
  3128. rv = mClients[clientType]->InitOrigin(aPersistenceType,
  3129. aGroup,
  3130. aOrigin,
  3131. /* aCanceled */ dummy,
  3132. usageInfo);
  3133. NS_ENSURE_SUCCESS(rv, rv);
  3134. }
  3135. if (trackQuota) {
  3136. InitQuotaForOrigin(aPersistenceType, aGroup, aOrigin, aIsApp,
  3137. usageInfo->TotalUsage(), aAccessTime);
  3138. }
  3139. return NS_OK;
  3140. }
  3141. nsresult
  3142. QuotaManager::MaybeUpgradeIndexedDBDirectory()
  3143. {
  3144. AssertIsOnIOThread();
  3145. nsresult rv;
  3146. nsCOMPtr<nsIFile> indexedDBDir =
  3147. do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  3148. NS_ENSURE_SUCCESS(rv, rv);
  3149. rv = indexedDBDir->InitWithPath(mIndexedDBPath);
  3150. NS_ENSURE_SUCCESS(rv, rv);
  3151. bool exists;
  3152. rv = indexedDBDir->Exists(&exists);
  3153. NS_ENSURE_SUCCESS(rv, rv);
  3154. if (!exists) {
  3155. // Nothing to upgrade.
  3156. return NS_OK;
  3157. }
  3158. bool isDirectory;
  3159. rv = indexedDBDir->IsDirectory(&isDirectory);
  3160. NS_ENSURE_SUCCESS(rv, rv);
  3161. if (!isDirectory) {
  3162. NS_WARNING("indexedDB entry is not a directory!");
  3163. return NS_OK;
  3164. }
  3165. nsCOMPtr<nsIFile> persistentStorageDir =
  3166. do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  3167. NS_ENSURE_SUCCESS(rv, rv);
  3168. rv = persistentStorageDir->InitWithPath(mStoragePath);
  3169. NS_ENSURE_SUCCESS(rv, rv);
  3170. rv = persistentStorageDir->Append(NS_LITERAL_STRING(PERSISTENT_DIRECTORY_NAME));
  3171. NS_ENSURE_SUCCESS(rv, rv);
  3172. rv = persistentStorageDir->Exists(&exists);
  3173. NS_ENSURE_SUCCESS(rv, rv);
  3174. if (exists) {
  3175. NS_WARNING("indexedDB directory shouldn't exist after the upgrade!");
  3176. return NS_OK;
  3177. }
  3178. nsCOMPtr<nsIFile> storageDir;
  3179. rv = persistentStorageDir->GetParent(getter_AddRefs(storageDir));
  3180. NS_ENSURE_SUCCESS(rv, rv);
  3181. // MoveTo() is atomic if the move happens on the same volume which should
  3182. // be our case, so even if we crash in the middle of the operation nothing
  3183. // breaks next time we try to initialize.
  3184. // However there's a theoretical possibility that the indexedDB directory
  3185. // is on different volume, but it should be rare enough that we don't have
  3186. // to worry about it.
  3187. rv = indexedDBDir->MoveTo(storageDir, NS_LITERAL_STRING(PERSISTENT_DIRECTORY_NAME));
  3188. NS_ENSURE_SUCCESS(rv, rv);
  3189. return NS_OK;
  3190. }
  3191. nsresult
  3192. QuotaManager::MaybeUpgradePersistentStorageDirectory()
  3193. {
  3194. AssertIsOnIOThread();
  3195. nsresult rv;
  3196. nsCOMPtr<nsIFile> persistentStorageDir =
  3197. do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  3198. if (NS_WARN_IF(NS_FAILED(rv))) {
  3199. return rv;
  3200. }
  3201. rv = persistentStorageDir->InitWithPath(mStoragePath);
  3202. if (NS_WARN_IF(NS_FAILED(rv))) {
  3203. return rv;
  3204. }
  3205. rv = persistentStorageDir->Append(NS_LITERAL_STRING(PERSISTENT_DIRECTORY_NAME));
  3206. if (NS_WARN_IF(NS_FAILED(rv))) {
  3207. return rv;
  3208. }
  3209. bool exists;
  3210. rv = persistentStorageDir->Exists(&exists);
  3211. if (NS_WARN_IF(NS_FAILED(rv))) {
  3212. return rv;
  3213. }
  3214. if (!exists) {
  3215. // Nothing to upgrade.
  3216. return NS_OK;
  3217. }
  3218. bool isDirectory;
  3219. rv = persistentStorageDir->IsDirectory(&isDirectory);
  3220. if (NS_WARN_IF(NS_FAILED(rv))) {
  3221. return rv;
  3222. }
  3223. if (!isDirectory) {
  3224. NS_WARNING("persistent entry is not a directory!");
  3225. return NS_OK;
  3226. }
  3227. nsCOMPtr<nsIFile> defaultStorageDir =
  3228. do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  3229. if (NS_WARN_IF(NS_FAILED(rv))) {
  3230. return rv;
  3231. }
  3232. rv = defaultStorageDir->InitWithPath(mDefaultStoragePath);
  3233. if (NS_WARN_IF(NS_FAILED(rv))) {
  3234. return rv;
  3235. }
  3236. rv = defaultStorageDir->Exists(&exists);
  3237. if (NS_WARN_IF(NS_FAILED(rv))) {
  3238. return rv;
  3239. }
  3240. if (exists) {
  3241. NS_WARNING("storage/persistent shouldn't exist after the upgrade!");
  3242. return NS_OK;
  3243. }
  3244. // Create real metadata files for origin directories in persistent storage.
  3245. RefPtr<CreateOrUpgradeDirectoryMetadataHelper> helper =
  3246. new CreateOrUpgradeDirectoryMetadataHelper(persistentStorageDir,
  3247. /* aPersistent */ true);
  3248. rv = helper->CreateOrUpgradeMetadataFiles();
  3249. if (NS_WARN_IF(NS_FAILED(rv))) {
  3250. return rv;
  3251. }
  3252. // Upgrade metadata files for origin directories in temporary storage.
  3253. nsCOMPtr<nsIFile> temporaryStorageDir =
  3254. do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  3255. if (NS_WARN_IF(NS_FAILED(rv))) {
  3256. return rv;
  3257. }
  3258. rv = temporaryStorageDir->InitWithPath(mTemporaryStoragePath);
  3259. if (NS_WARN_IF(NS_FAILED(rv))) {
  3260. return rv;
  3261. }
  3262. rv = temporaryStorageDir->Exists(&exists);
  3263. if (NS_WARN_IF(NS_FAILED(rv))) {
  3264. return rv;
  3265. }
  3266. if (exists) {
  3267. rv = temporaryStorageDir->IsDirectory(&isDirectory);
  3268. if (NS_WARN_IF(NS_FAILED(rv))) {
  3269. return rv;
  3270. }
  3271. if (!isDirectory) {
  3272. NS_WARNING("temporary entry is not a directory!");
  3273. return NS_OK;
  3274. }
  3275. helper =
  3276. new CreateOrUpgradeDirectoryMetadataHelper(temporaryStorageDir,
  3277. /* aPersistent */ false);
  3278. rv = helper->CreateOrUpgradeMetadataFiles();
  3279. if (NS_WARN_IF(NS_FAILED(rv))) {
  3280. return rv;
  3281. }
  3282. }
  3283. // And finally rename persistent to default.
  3284. rv = persistentStorageDir->RenameTo(nullptr, NS_LITERAL_STRING(DEFAULT_DIRECTORY_NAME));
  3285. if (NS_WARN_IF(NS_FAILED(rv))) {
  3286. return rv;
  3287. }
  3288. return NS_OK;
  3289. }
  3290. nsresult
  3291. QuotaManager::MaybeRemoveOldDirectories()
  3292. {
  3293. AssertIsOnIOThread();
  3294. nsresult rv;
  3295. nsCOMPtr<nsIFile> indexedDBDir =
  3296. do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  3297. if (NS_WARN_IF(NS_FAILED(rv))) {
  3298. return rv;
  3299. }
  3300. rv = indexedDBDir->InitWithPath(mIndexedDBPath);
  3301. if (NS_WARN_IF(NS_FAILED(rv))) {
  3302. return rv;
  3303. }
  3304. bool exists;
  3305. rv = indexedDBDir->Exists(&exists);
  3306. if (NS_WARN_IF(NS_FAILED(rv))) {
  3307. return rv;
  3308. }
  3309. if (exists) {
  3310. QM_WARNING("Deleting old <profile>/indexedDB directory!");
  3311. rv = indexedDBDir->Remove(/* aRecursive */ true);
  3312. if (NS_WARN_IF(NS_FAILED(rv))) {
  3313. return rv;
  3314. }
  3315. }
  3316. nsCOMPtr<nsIFile> persistentStorageDir =
  3317. do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  3318. if (NS_WARN_IF(NS_FAILED(rv))) {
  3319. return rv;
  3320. }
  3321. rv = persistentStorageDir->InitWithPath(mStoragePath);
  3322. if (NS_WARN_IF(NS_FAILED(rv))) {
  3323. return rv;
  3324. }
  3325. rv = persistentStorageDir->Append(NS_LITERAL_STRING(PERSISTENT_DIRECTORY_NAME));
  3326. if (NS_WARN_IF(NS_FAILED(rv))) {
  3327. return rv;
  3328. }
  3329. rv = persistentStorageDir->Exists(&exists);
  3330. if (NS_WARN_IF(NS_FAILED(rv))) {
  3331. return rv;
  3332. }
  3333. if (exists) {
  3334. QM_WARNING("Deleting old <profile>/storage/persistent directory!");
  3335. rv = persistentStorageDir->Remove(/* aRecursive */ true);
  3336. if (NS_WARN_IF(NS_FAILED(rv))) {
  3337. return rv;
  3338. }
  3339. }
  3340. return NS_OK;
  3341. }
  3342. nsresult
  3343. QuotaManager::UpgradeStorageFrom0ToCurrent(mozIStorageConnection* aConnection)
  3344. {
  3345. AssertIsOnIOThread();
  3346. MOZ_ASSERT(aConnection);
  3347. nsresult rv;
  3348. for (const PersistenceType persistenceType : kAllPersistenceTypes) {
  3349. nsCOMPtr<nsIFile> directory =
  3350. do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  3351. if (NS_WARN_IF(NS_FAILED(rv))) {
  3352. return rv;
  3353. }
  3354. rv = directory->InitWithPath(GetStoragePath(persistenceType));
  3355. if (NS_WARN_IF(NS_FAILED(rv))) {
  3356. return rv;
  3357. }
  3358. bool persistent = persistenceType == PERSISTENCE_TYPE_PERSISTENT;
  3359. RefPtr<UpgradeDirectoryMetadataFrom1To2Helper> helper =
  3360. new UpgradeDirectoryMetadataFrom1To2Helper(directory, persistent);
  3361. rv = helper->UpgradeMetadataFiles();
  3362. if (NS_WARN_IF(NS_FAILED(rv))) {
  3363. return rv;
  3364. }
  3365. }
  3366. #ifdef DEBUG
  3367. {
  3368. int32_t storageVersion;
  3369. rv = aConnection->GetSchemaVersion(&storageVersion);
  3370. if (NS_WARN_IF(NS_FAILED(rv))) {
  3371. return rv;
  3372. }
  3373. MOZ_ASSERT(storageVersion == 0);
  3374. }
  3375. #endif
  3376. rv = aConnection->SetSchemaVersion(kStorageVersion);
  3377. if (NS_WARN_IF(NS_FAILED(rv))) {
  3378. return rv;
  3379. }
  3380. return NS_OK;
  3381. }
  3382. #if 0
  3383. nsresult
  3384. QuotaManager::UpgradeStorageFrom1To2(mozIStorageConnection* aConnection)
  3385. {
  3386. AssertIsOnIOThread();
  3387. MOZ_ASSERT(aConnection);
  3388. nsresult rv = aConnection->SetSchemaVersion(MakeStorageVersion(2, 0));
  3389. if (NS_WARN_IF(NS_FAILED(rv))) {
  3390. return rv;
  3391. }
  3392. return NS_OK;
  3393. }
  3394. #endif
  3395. nsresult
  3396. QuotaManager::EnsureStorageIsInitialized()
  3397. {
  3398. AssertIsOnIOThread();
  3399. if (mStorageInitialized) {
  3400. return NS_OK;
  3401. }
  3402. nsresult rv;
  3403. nsCOMPtr<nsIFile> storageFile =
  3404. do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  3405. if (NS_WARN_IF(NS_FAILED(rv))) {
  3406. return rv;
  3407. }
  3408. rv = storageFile->InitWithPath(mBasePath);
  3409. if (NS_WARN_IF(NS_FAILED(rv))) {
  3410. return rv;
  3411. }
  3412. rv = storageFile->Append(NS_LITERAL_STRING(STORAGE_FILE_NAME));
  3413. if (NS_WARN_IF(NS_FAILED(rv))) {
  3414. return rv;
  3415. }
  3416. nsCOMPtr<mozIStorageService> ss =
  3417. do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv);
  3418. if (NS_WARN_IF(NS_FAILED(rv))) {
  3419. return rv;
  3420. }
  3421. nsCOMPtr<mozIStorageConnection> connection;
  3422. rv = ss->OpenUnsharedDatabase(storageFile, getter_AddRefs(connection));
  3423. if (rv == NS_ERROR_FILE_CORRUPTED) {
  3424. // Nuke the database file.
  3425. rv = storageFile->Remove(false);
  3426. if (NS_WARN_IF(NS_FAILED(rv))) {
  3427. return rv;
  3428. }
  3429. rv = ss->OpenUnsharedDatabase(storageFile, getter_AddRefs(connection));
  3430. }
  3431. if (NS_WARN_IF(NS_FAILED(rv))) {
  3432. return rv;
  3433. }
  3434. // We want extra durability for this important file.
  3435. rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
  3436. "PRAGMA synchronous = EXTRA;"
  3437. ));
  3438. if (NS_WARN_IF(NS_FAILED(rv))) {
  3439. return rv;
  3440. }
  3441. // Check to make sure that the storage version is correct.
  3442. int32_t storageVersion;
  3443. rv = connection->GetSchemaVersion(&storageVersion);
  3444. if (NS_WARN_IF(NS_FAILED(rv))) {
  3445. return rv;
  3446. }
  3447. if (GetMajorStorageVersion(storageVersion) > kMajorStorageVersion) {
  3448. NS_WARNING("Unable to initialize storage, version is too high!");
  3449. return NS_ERROR_FAILURE;
  3450. }
  3451. if (storageVersion < kStorageVersion) {
  3452. const bool newDatabase = !storageVersion;
  3453. if (newDatabase) {
  3454. // Set the page size first.
  3455. if (kSQLitePageSizeOverride) {
  3456. rv = connection->ExecuteSimpleSQL(
  3457. nsPrintfCString("PRAGMA page_size = %lu;", kSQLitePageSizeOverride)
  3458. );
  3459. if (NS_WARN_IF(NS_FAILED(rv))) {
  3460. return rv;
  3461. }
  3462. }
  3463. }
  3464. mozStorageTransaction transaction(connection, false,
  3465. mozIStorageConnection::TRANSACTION_IMMEDIATE);
  3466. if (newDatabase) {
  3467. rv = MaybeUpgradeIndexedDBDirectory();
  3468. if (NS_WARN_IF(NS_FAILED(rv))) {
  3469. return rv;
  3470. }
  3471. rv = MaybeUpgradePersistentStorageDirectory();
  3472. if (NS_WARN_IF(NS_FAILED(rv))) {
  3473. return rv;
  3474. }
  3475. rv = MaybeRemoveOldDirectories();
  3476. if (NS_WARN_IF(NS_FAILED(rv))) {
  3477. return rv;
  3478. }
  3479. rv = UpgradeStorageFrom0ToCurrent(connection);
  3480. if (NS_WARN_IF(NS_FAILED(rv))) {
  3481. return rv;
  3482. }
  3483. MOZ_ASSERT(NS_SUCCEEDED(connection->GetSchemaVersion(&storageVersion)));
  3484. MOZ_ASSERT(storageVersion == kStorageVersion);
  3485. } else {
  3486. // This logic needs to change next time we change the storage!
  3487. static_assert(kStorageVersion == int32_t((1 << 16) + 0),
  3488. "Upgrade function needed due to storage version increase.");
  3489. while (storageVersion != kStorageVersion) {
  3490. /* if (storageVersion == MakeStorageVersion(1, 0)) {
  3491. rv = UpgradeStorageFrom1To2(connection);
  3492. } else */ {
  3493. NS_WARNING("Unable to initialize storage, no upgrade path is "
  3494. "available!");
  3495. return NS_ERROR_FAILURE;
  3496. }
  3497. if (NS_WARN_IF(NS_FAILED(rv))) {
  3498. return rv;
  3499. }
  3500. rv = connection->GetSchemaVersion(&storageVersion);
  3501. if (NS_WARN_IF(NS_FAILED(rv))) {
  3502. return rv;
  3503. }
  3504. }
  3505. MOZ_ASSERT(storageVersion == kStorageVersion);
  3506. }
  3507. rv = transaction.Commit();
  3508. if (NS_WARN_IF(NS_FAILED(rv))) {
  3509. return rv;
  3510. }
  3511. }
  3512. mStorageInitialized = true;
  3513. return NS_OK;
  3514. }
  3515. void
  3516. QuotaManager::OpenDirectory(PersistenceType aPersistenceType,
  3517. const nsACString& aGroup,
  3518. const nsACString& aOrigin,
  3519. bool aIsApp,
  3520. Client::Type aClientType,
  3521. bool aExclusive,
  3522. OpenDirectoryListener* aOpenListener)
  3523. {
  3524. AssertIsOnOwningThread();
  3525. RefPtr<DirectoryLockImpl> lock =
  3526. CreateDirectoryLock(Nullable<PersistenceType>(aPersistenceType),
  3527. aGroup,
  3528. OriginScope::FromOrigin(aOrigin),
  3529. Nullable<bool>(aIsApp),
  3530. Nullable<Client::Type>(aClientType),
  3531. aExclusive,
  3532. false,
  3533. aOpenListener);
  3534. MOZ_ASSERT(lock);
  3535. }
  3536. void
  3537. QuotaManager::OpenDirectoryInternal(Nullable<PersistenceType> aPersistenceType,
  3538. const OriginScope& aOriginScope,
  3539. Nullable<Client::Type> aClientType,
  3540. bool aExclusive,
  3541. OpenDirectoryListener* aOpenListener)
  3542. {
  3543. AssertIsOnOwningThread();
  3544. RefPtr<DirectoryLockImpl> lock =
  3545. CreateDirectoryLock(aPersistenceType,
  3546. EmptyCString(),
  3547. aOriginScope,
  3548. Nullable<bool>(),
  3549. Nullable<Client::Type>(aClientType),
  3550. aExclusive,
  3551. true,
  3552. aOpenListener);
  3553. MOZ_ASSERT(lock);
  3554. if (!aExclusive) {
  3555. return;
  3556. }
  3557. // All the locks that block this new exclusive lock need to be invalidated.
  3558. // We also need to notify clients to abort operations for them.
  3559. AutoTArray<nsAutoPtr<nsTHashtable<nsCStringHashKey>>,
  3560. Client::TYPE_MAX> origins;
  3561. origins.SetLength(Client::TYPE_MAX);
  3562. const nsTArray<DirectoryLockImpl*>& blockedOnLocks =
  3563. lock->GetBlockedOnLocks();
  3564. for (DirectoryLockImpl* blockedOnLock : blockedOnLocks) {
  3565. blockedOnLock->Invalidate();
  3566. if (!blockedOnLock->IsInternal()) {
  3567. MOZ_ASSERT(!blockedOnLock->GetClientType().IsNull());
  3568. Client::Type clientType = blockedOnLock->GetClientType().Value();
  3569. MOZ_ASSERT(clientType < Client::TYPE_MAX);
  3570. const OriginScope& originScope = blockedOnLock->GetOriginScope();
  3571. MOZ_ASSERT(originScope.IsOrigin());
  3572. MOZ_ASSERT(!originScope.GetOrigin().IsEmpty());
  3573. nsAutoPtr<nsTHashtable<nsCStringHashKey>>& origin = origins[clientType];
  3574. if (!origin) {
  3575. origin = new nsTHashtable<nsCStringHashKey>();
  3576. }
  3577. origin->PutEntry(originScope.GetOrigin());
  3578. }
  3579. }
  3580. for (uint32_t index : MakeRange(uint32_t(Client::TYPE_MAX))) {
  3581. if (origins[index]) {
  3582. for (auto iter = origins[index]->Iter(); !iter.Done(); iter.Next()) {
  3583. MOZ_ASSERT(mClients[index]);
  3584. mClients[index]->AbortOperations(iter.Get()->GetKey());
  3585. }
  3586. }
  3587. }
  3588. }
  3589. nsresult
  3590. QuotaManager::EnsureOriginIsInitialized(PersistenceType aPersistenceType,
  3591. const nsACString& aSuffix,
  3592. const nsACString& aGroup,
  3593. const nsACString& aOrigin,
  3594. bool aIsApp,
  3595. nsIFile** aDirectory)
  3596. {
  3597. AssertIsOnIOThread();
  3598. nsresult rv = EnsureStorageIsInitialized();
  3599. NS_ENSURE_SUCCESS(rv, rv);
  3600. // Get directory for this origin and persistence type.
  3601. nsCOMPtr<nsIFile> directory;
  3602. rv = GetDirectoryForOrigin(aPersistenceType, aOrigin,
  3603. getter_AddRefs(directory));
  3604. NS_ENSURE_SUCCESS(rv, rv);
  3605. if (IsTreatedAsPersistent(aPersistenceType, aIsApp)) {
  3606. if (mInitializedOrigins.Contains(OriginKey(aPersistenceType, aOrigin))) {
  3607. directory.forget(aDirectory);
  3608. return NS_OK;
  3609. }
  3610. } else if (!mTemporaryStorageInitialized) {
  3611. rv = InitializeRepository(aPersistenceType);
  3612. if (NS_WARN_IF(NS_FAILED(rv))) {
  3613. // We have to cleanup partially initialized quota.
  3614. RemoveQuota();
  3615. return rv;
  3616. }
  3617. rv = InitializeRepository(ComplementaryPersistenceType(aPersistenceType));
  3618. if (NS_WARN_IF(NS_FAILED(rv))) {
  3619. // We have to cleanup partially initialized quota.
  3620. RemoveQuota();
  3621. return rv;
  3622. }
  3623. if (gFixedLimitKB >= 0) {
  3624. mTemporaryStorageLimit = static_cast<uint64_t>(gFixedLimitKB) * 1024;
  3625. }
  3626. else {
  3627. nsCOMPtr<nsIFile> storageDir =
  3628. do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  3629. if (NS_WARN_IF(NS_FAILED(rv))) {
  3630. return rv;
  3631. }
  3632. rv = storageDir->InitWithPath(GetStoragePath());
  3633. if (NS_WARN_IF(NS_FAILED(rv))) {
  3634. return rv;
  3635. }
  3636. rv = GetTemporaryStorageLimit(storageDir, mTemporaryStorageUsage,
  3637. &mTemporaryStorageLimit);
  3638. NS_ENSURE_SUCCESS(rv, rv);
  3639. }
  3640. mTemporaryStorageInitialized = true;
  3641. CheckTemporaryStorageLimits();
  3642. }
  3643. int64_t timestamp;
  3644. bool created;
  3645. rv = EnsureDirectory(directory, &created);
  3646. NS_ENSURE_SUCCESS(rv, rv);
  3647. if (IsTreatedAsPersistent(aPersistenceType, aIsApp)) {
  3648. if (created) {
  3649. timestamp = PR_Now();
  3650. rv = CreateDirectoryMetadata(directory,
  3651. timestamp,
  3652. aSuffix,
  3653. aGroup,
  3654. aOrigin,
  3655. aIsApp);
  3656. if (NS_WARN_IF(NS_FAILED(rv))) {
  3657. return rv;
  3658. }
  3659. rv = CreateDirectoryMetadata2(directory,
  3660. timestamp,
  3661. aSuffix,
  3662. aGroup,
  3663. aOrigin,
  3664. aIsApp);
  3665. NS_ENSURE_SUCCESS(rv, rv);
  3666. } else {
  3667. bool persistent = aPersistenceType == PERSISTENCE_TYPE_PERSISTENT;
  3668. rv = GetDirectoryMetadata2WithRestore(directory,
  3669. persistent,
  3670. &timestamp);
  3671. if (NS_WARN_IF(NS_FAILED(rv))) {
  3672. return rv;
  3673. }
  3674. MOZ_ASSERT(timestamp <= PR_Now());
  3675. }
  3676. rv = InitializeOrigin(aPersistenceType, aGroup, aOrigin, aIsApp, timestamp,
  3677. directory);
  3678. NS_ENSURE_SUCCESS(rv, rv);
  3679. mInitializedOrigins.AppendElement(OriginKey(aPersistenceType, aOrigin));
  3680. } else if (created) {
  3681. timestamp = PR_Now();
  3682. rv = CreateDirectoryMetadata(directory,
  3683. timestamp,
  3684. aSuffix,
  3685. aGroup,
  3686. aOrigin,
  3687. aIsApp);
  3688. if (NS_WARN_IF(NS_FAILED(rv))) {
  3689. return rv;
  3690. }
  3691. rv = CreateDirectoryMetadata2(directory,
  3692. timestamp,
  3693. aSuffix,
  3694. aGroup,
  3695. aOrigin,
  3696. aIsApp);
  3697. NS_ENSURE_SUCCESS(rv, rv);
  3698. rv = InitializeOrigin(aPersistenceType, aGroup, aOrigin, aIsApp, timestamp,
  3699. directory);
  3700. NS_ENSURE_SUCCESS(rv, rv);
  3701. }
  3702. directory.forget(aDirectory);
  3703. return NS_OK;
  3704. }
  3705. void
  3706. QuotaManager::OriginClearCompleted(PersistenceType aPersistenceType,
  3707. const nsACString& aOrigin,
  3708. bool aIsApp)
  3709. {
  3710. AssertIsOnIOThread();
  3711. if (IsTreatedAsPersistent(aPersistenceType, aIsApp)) {
  3712. mInitializedOrigins.RemoveElement(OriginKey(aPersistenceType, aOrigin));
  3713. }
  3714. for (uint32_t index = 0; index < Client::TYPE_MAX; index++) {
  3715. mClients[index]->OnOriginClearCompleted(aPersistenceType, aOrigin);
  3716. }
  3717. }
  3718. void
  3719. QuotaManager::ResetOrClearCompleted()
  3720. {
  3721. AssertIsOnIOThread();
  3722. mInitializedOrigins.Clear();
  3723. mTemporaryStorageInitialized = false;
  3724. mStorageInitialized = false;
  3725. ReleaseIOThreadObjects();
  3726. }
  3727. Client*
  3728. QuotaManager::GetClient(Client::Type aClientType)
  3729. {
  3730. MOZ_ASSERT(aClientType >= Client::IDB);
  3731. MOZ_ASSERT(aClientType < Client::TYPE_MAX);
  3732. return mClients.ElementAt(aClientType);
  3733. }
  3734. uint64_t
  3735. QuotaManager::GetGroupLimit() const
  3736. {
  3737. MOZ_ASSERT(mTemporaryStorageInitialized);
  3738. // To avoid one group evicting all the rest, limit the amount any one group
  3739. // can use to 20%. To prevent individual sites from using exorbitant amounts
  3740. // of storage where there is a lot of free space, cap the group limit to 2GB.
  3741. uint64_t x = std::min<uint64_t>(mTemporaryStorageLimit * .20, 2 GB);
  3742. // In low-storage situations, make an exception (while not exceeding the total
  3743. // storage limit).
  3744. return std::min<uint64_t>(mTemporaryStorageLimit,
  3745. std::max<uint64_t>(x, 10 MB));
  3746. }
  3747. void
  3748. QuotaManager::GetGroupUsageAndLimit(const nsACString& aGroup,
  3749. UsageInfo* aUsageInfo)
  3750. {
  3751. AssertIsOnIOThread();
  3752. MOZ_ASSERT(aUsageInfo);
  3753. {
  3754. MutexAutoLock lock(mQuotaMutex);
  3755. aUsageInfo->SetLimit(GetGroupLimit());
  3756. aUsageInfo->ResetUsage();
  3757. GroupInfoPair* pair;
  3758. if (!mGroupInfoPairs.Get(aGroup, &pair)) {
  3759. return;
  3760. }
  3761. // Calculate temporary group usage
  3762. RefPtr<GroupInfo> temporaryGroupInfo =
  3763. pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
  3764. if (temporaryGroupInfo) {
  3765. aUsageInfo->AppendToDatabaseUsage(temporaryGroupInfo->mUsage);
  3766. }
  3767. // Calculate default group usage
  3768. RefPtr<GroupInfo> defaultGroupInfo =
  3769. pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
  3770. if (defaultGroupInfo) {
  3771. aUsageInfo->AppendToDatabaseUsage(defaultGroupInfo->mUsage);
  3772. }
  3773. }
  3774. }
  3775. // static
  3776. void
  3777. QuotaManager::GetStorageId(PersistenceType aPersistenceType,
  3778. const nsACString& aOrigin,
  3779. Client::Type aClientType,
  3780. nsACString& aDatabaseId)
  3781. {
  3782. nsAutoCString str;
  3783. str.AppendInt(aPersistenceType);
  3784. str.Append('*');
  3785. str.Append(aOrigin);
  3786. str.Append('*');
  3787. str.AppendInt(aClientType);
  3788. aDatabaseId = str;
  3789. }
  3790. // static
  3791. nsresult
  3792. QuotaManager::GetInfoFromPrincipal(nsIPrincipal* aPrincipal,
  3793. nsACString* aSuffix,
  3794. nsACString* aGroup,
  3795. nsACString* aOrigin,
  3796. bool* aIsApp)
  3797. {
  3798. MOZ_ASSERT(NS_IsMainThread());
  3799. MOZ_ASSERT(aPrincipal);
  3800. if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
  3801. GetInfoForChrome(aSuffix, aGroup, aOrigin, aIsApp);
  3802. return NS_OK;
  3803. }
  3804. if (aPrincipal->GetIsNullPrincipal()) {
  3805. NS_WARNING("IndexedDB not supported from this principal!");
  3806. return NS_ERROR_FAILURE;
  3807. }
  3808. nsCString origin;
  3809. nsresult rv = aPrincipal->GetOrigin(origin);
  3810. NS_ENSURE_SUCCESS(rv, rv);
  3811. if (origin.EqualsLiteral(kChromeOrigin)) {
  3812. NS_WARNING("Non-chrome principal can't use chrome origin!");
  3813. return NS_ERROR_FAILURE;
  3814. }
  3815. nsCString suffix;
  3816. BasePrincipal::Cast(aPrincipal)->OriginAttributesRef().CreateSuffix(suffix);
  3817. if (aSuffix)
  3818. {
  3819. aSuffix->Assign(suffix);
  3820. }
  3821. if (aGroup) {
  3822. nsCString baseDomain;
  3823. rv = aPrincipal->GetBaseDomain(baseDomain);
  3824. if (NS_FAILED(rv)) {
  3825. // A hack for JetPack.
  3826. nsCOMPtr<nsIURI> uri;
  3827. rv = aPrincipal->GetURI(getter_AddRefs(uri));
  3828. NS_ENSURE_SUCCESS(rv, rv);
  3829. bool isIndexedDBURI = false;
  3830. rv = uri->SchemeIs("indexedDB", &isIndexedDBURI);
  3831. NS_ENSURE_SUCCESS(rv, rv);
  3832. if (isIndexedDBURI) {
  3833. rv = NS_OK;
  3834. }
  3835. }
  3836. NS_ENSURE_SUCCESS(rv, rv);
  3837. if (baseDomain.IsEmpty()) {
  3838. aGroup->Assign(origin);
  3839. } else {
  3840. aGroup->Assign(baseDomain + suffix);
  3841. }
  3842. }
  3843. if (aOrigin) {
  3844. aOrigin->Assign(origin);
  3845. }
  3846. if (aIsApp) {
  3847. *aIsApp = aPrincipal->GetAppStatus() !=
  3848. nsIPrincipal::APP_STATUS_NOT_INSTALLED;
  3849. }
  3850. return NS_OK;
  3851. }
  3852. // static
  3853. nsresult
  3854. QuotaManager::GetInfoFromWindow(nsPIDOMWindowOuter* aWindow,
  3855. nsACString* aSuffix,
  3856. nsACString* aGroup,
  3857. nsACString* aOrigin,
  3858. bool* aIsApp)
  3859. {
  3860. MOZ_ASSERT(NS_IsMainThread());
  3861. MOZ_ASSERT(aWindow);
  3862. nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(aWindow);
  3863. NS_ENSURE_TRUE(sop, NS_ERROR_FAILURE);
  3864. nsCOMPtr<nsIPrincipal> principal = sop->GetPrincipal();
  3865. NS_ENSURE_TRUE(principal, NS_ERROR_FAILURE);
  3866. nsresult rv =
  3867. GetInfoFromPrincipal(principal, aSuffix, aGroup, aOrigin, aIsApp);
  3868. NS_ENSURE_SUCCESS(rv, rv);
  3869. return NS_OK;
  3870. }
  3871. // static
  3872. void
  3873. QuotaManager::GetInfoForChrome(nsACString* aSuffix,
  3874. nsACString* aGroup,
  3875. nsACString* aOrigin,
  3876. bool* aIsApp)
  3877. {
  3878. MOZ_ASSERT(NS_IsMainThread());
  3879. MOZ_ASSERT(nsContentUtils::LegacyIsCallerChromeOrNativeCode());
  3880. if (aSuffix) {
  3881. aSuffix->Assign(EmptyCString());
  3882. }
  3883. if (aGroup) {
  3884. ChromeOrigin(*aGroup);
  3885. }
  3886. if (aOrigin) {
  3887. ChromeOrigin(*aOrigin);
  3888. }
  3889. if (aIsApp) {
  3890. *aIsApp = false;
  3891. }
  3892. }
  3893. // static
  3894. bool
  3895. QuotaManager::IsOriginInternal(const nsACString& aOrigin)
  3896. {
  3897. // The first prompt is not required for these origins.
  3898. if (aOrigin.EqualsLiteral(kChromeOrigin) ||
  3899. StringBeginsWith(aOrigin, nsDependentCString(kAboutHomeOriginPrefix)) ||
  3900. StringBeginsWith(aOrigin, nsDependentCString(kIndexedDBOriginPrefix)) ||
  3901. StringBeginsWith(aOrigin, nsDependentCString(kResourceOriginPrefix))) {
  3902. return true;
  3903. }
  3904. return false;
  3905. }
  3906. // static
  3907. bool
  3908. QuotaManager::IsFirstPromptRequired(PersistenceType aPersistenceType,
  3909. const nsACString& aOrigin,
  3910. bool aIsApp)
  3911. {
  3912. if (IsTreatedAsTemporary(aPersistenceType, aIsApp)) {
  3913. return false;
  3914. }
  3915. return !IsOriginInternal(aOrigin);
  3916. }
  3917. // static
  3918. bool
  3919. QuotaManager::IsQuotaEnforced(PersistenceType aPersistenceType,
  3920. const nsACString& aOrigin,
  3921. bool aIsApp)
  3922. {
  3923. return IsTreatedAsTemporary(aPersistenceType, aIsApp);
  3924. }
  3925. // static
  3926. void
  3927. QuotaManager::ChromeOrigin(nsACString& aOrigin)
  3928. {
  3929. aOrigin.AssignLiteral(kChromeOrigin);
  3930. }
  3931. uint64_t
  3932. QuotaManager::LockedCollectOriginsForEviction(
  3933. uint64_t aMinSizeToBeFreed,
  3934. nsTArray<RefPtr<DirectoryLockImpl>>& aLocks)
  3935. {
  3936. mQuotaMutex.AssertCurrentThreadOwns();
  3937. RefPtr<CollectOriginsHelper> helper =
  3938. new CollectOriginsHelper(mQuotaMutex, aMinSizeToBeFreed);
  3939. // Unlock while calling out to XPCOM (code behind the dispatch method needs
  3940. // to acquire its own lock which can potentially lead to a deadlock and it
  3941. // also calls an observer that can do various stuff like IO, so it's better
  3942. // to not hold our mutex while that happens).
  3943. {
  3944. MutexAutoUnlock autoUnlock(mQuotaMutex);
  3945. MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(helper, NS_DISPATCH_NORMAL));
  3946. }
  3947. return helper->BlockAndReturnOriginsForEviction(aLocks);
  3948. }
  3949. void
  3950. QuotaManager::LockedRemoveQuotaForOrigin(PersistenceType aPersistenceType,
  3951. const nsACString& aGroup,
  3952. const nsACString& aOrigin)
  3953. {
  3954. mQuotaMutex.AssertCurrentThreadOwns();
  3955. MOZ_ASSERT(aPersistenceType != PERSISTENCE_TYPE_PERSISTENT);
  3956. GroupInfoPair* pair;
  3957. mGroupInfoPairs.Get(aGroup, &pair);
  3958. if (!pair) {
  3959. return;
  3960. }
  3961. RefPtr<GroupInfo> groupInfo = pair->LockedGetGroupInfo(aPersistenceType);
  3962. if (groupInfo) {
  3963. groupInfo->LockedRemoveOriginInfo(aOrigin);
  3964. if (!groupInfo->LockedHasOriginInfos()) {
  3965. pair->LockedClearGroupInfo(aPersistenceType);
  3966. if (!pair->LockedHasGroupInfos()) {
  3967. mGroupInfoPairs.Remove(aGroup);
  3968. }
  3969. }
  3970. }
  3971. }
  3972. void
  3973. QuotaManager::CheckTemporaryStorageLimits()
  3974. {
  3975. AssertIsOnIOThread();
  3976. nsTArray<OriginInfo*> doomedOriginInfos;
  3977. {
  3978. MutexAutoLock lock(mQuotaMutex);
  3979. for (auto iter = mGroupInfoPairs.Iter(); !iter.Done(); iter.Next()) {
  3980. GroupInfoPair* pair = iter.UserData();
  3981. MOZ_ASSERT(!iter.Key().IsEmpty(), "Empty key!");
  3982. MOZ_ASSERT(pair, "Null pointer!");
  3983. uint64_t groupUsage = 0;
  3984. RefPtr<GroupInfo> temporaryGroupInfo =
  3985. pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
  3986. if (temporaryGroupInfo) {
  3987. groupUsage += temporaryGroupInfo->mUsage;
  3988. }
  3989. RefPtr<GroupInfo> defaultGroupInfo =
  3990. pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
  3991. if (defaultGroupInfo) {
  3992. groupUsage += defaultGroupInfo->mUsage;
  3993. }
  3994. if (groupUsage > 0) {
  3995. QuotaManager* quotaManager = QuotaManager::Get();
  3996. MOZ_ASSERT(quotaManager, "Shouldn't be null!");
  3997. if (groupUsage > quotaManager->GetGroupLimit()) {
  3998. nsTArray<OriginInfo*> originInfos;
  3999. if (temporaryGroupInfo) {
  4000. originInfos.AppendElements(temporaryGroupInfo->mOriginInfos);
  4001. }
  4002. if (defaultGroupInfo) {
  4003. originInfos.AppendElements(defaultGroupInfo->mOriginInfos);
  4004. }
  4005. originInfos.Sort(OriginInfoLRUComparator());
  4006. for (uint32_t i = 0; i < originInfos.Length(); i++) {
  4007. OriginInfo* originInfo = originInfos[i];
  4008. doomedOriginInfos.AppendElement(originInfo);
  4009. groupUsage -= originInfo->mUsage;
  4010. if (groupUsage <= quotaManager->GetGroupLimit()) {
  4011. break;
  4012. }
  4013. }
  4014. }
  4015. }
  4016. }
  4017. uint64_t usage = 0;
  4018. for (uint32_t index = 0; index < doomedOriginInfos.Length(); index++) {
  4019. usage += doomedOriginInfos[index]->mUsage;
  4020. }
  4021. if (mTemporaryStorageUsage - usage > mTemporaryStorageLimit) {
  4022. nsTArray<OriginInfo*> originInfos;
  4023. for (auto iter = mGroupInfoPairs.Iter(); !iter.Done(); iter.Next()) {
  4024. GroupInfoPair* pair = iter.UserData();
  4025. MOZ_ASSERT(!iter.Key().IsEmpty(), "Empty key!");
  4026. MOZ_ASSERT(pair, "Null pointer!");
  4027. RefPtr<GroupInfo> groupInfo =
  4028. pair->LockedGetGroupInfo(PERSISTENCE_TYPE_TEMPORARY);
  4029. if (groupInfo) {
  4030. originInfos.AppendElements(groupInfo->mOriginInfos);
  4031. }
  4032. groupInfo = pair->LockedGetGroupInfo(PERSISTENCE_TYPE_DEFAULT);
  4033. if (groupInfo) {
  4034. originInfos.AppendElements(groupInfo->mOriginInfos);
  4035. }
  4036. }
  4037. for (uint32_t index = originInfos.Length(); index > 0; index--) {
  4038. if (doomedOriginInfos.Contains(originInfos[index - 1])) {
  4039. originInfos.RemoveElementAt(index - 1);
  4040. }
  4041. }
  4042. originInfos.Sort(OriginInfoLRUComparator());
  4043. for (uint32_t i = 0; i < originInfos.Length(); i++) {
  4044. if (mTemporaryStorageUsage - usage <= mTemporaryStorageLimit) {
  4045. originInfos.TruncateLength(i);
  4046. break;
  4047. }
  4048. usage += originInfos[i]->mUsage;
  4049. }
  4050. doomedOriginInfos.AppendElements(originInfos);
  4051. }
  4052. }
  4053. for (uint32_t index = 0; index < doomedOriginInfos.Length(); index++) {
  4054. OriginInfo* doomedOriginInfo = doomedOriginInfos[index];
  4055. DeleteFilesForOrigin(doomedOriginInfo->mGroupInfo->mPersistenceType,
  4056. doomedOriginInfo->mOrigin);
  4057. }
  4058. nsTArray<OriginParams> doomedOrigins;
  4059. {
  4060. MutexAutoLock lock(mQuotaMutex);
  4061. for (uint32_t index = 0; index < doomedOriginInfos.Length(); index++) {
  4062. OriginInfo* doomedOriginInfo = doomedOriginInfos[index];
  4063. PersistenceType persistenceType =
  4064. doomedOriginInfo->mGroupInfo->mPersistenceType;
  4065. nsCString group = doomedOriginInfo->mGroupInfo->mGroup;
  4066. nsCString origin = doomedOriginInfo->mOrigin;
  4067. bool isApp = doomedOriginInfo->mIsApp;
  4068. LockedRemoveQuotaForOrigin(persistenceType, group, origin);
  4069. #ifdef DEBUG
  4070. doomedOriginInfos[index] = nullptr;
  4071. #endif
  4072. doomedOrigins.AppendElement(OriginParams(persistenceType, origin, isApp));
  4073. }
  4074. }
  4075. for (const OriginParams& doomedOrigin : doomedOrigins) {
  4076. OriginClearCompleted(doomedOrigin.mPersistenceType,
  4077. doomedOrigin.mOrigin,
  4078. doomedOrigin.mIsApp);
  4079. }
  4080. }
  4081. void
  4082. QuotaManager::DeleteFilesForOrigin(PersistenceType aPersistenceType,
  4083. const nsACString& aOrigin)
  4084. {
  4085. nsCOMPtr<nsIFile> directory;
  4086. nsresult rv = GetDirectoryForOrigin(aPersistenceType, aOrigin,
  4087. getter_AddRefs(directory));
  4088. NS_ENSURE_SUCCESS_VOID(rv);
  4089. rv = directory->Remove(true);
  4090. if (rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST &&
  4091. rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
  4092. // This should never fail if we've closed all storage connections
  4093. // correctly...
  4094. NS_ERROR("Failed to remove directory!");
  4095. }
  4096. }
  4097. void
  4098. QuotaManager::FinalizeOriginEviction(
  4099. nsTArray<RefPtr<DirectoryLockImpl>>& aLocks)
  4100. {
  4101. NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
  4102. RefPtr<FinalizeOriginEvictionOp> op =
  4103. new FinalizeOriginEvictionOp(mOwningThread, aLocks);
  4104. if (IsOnIOThread()) {
  4105. op->RunOnIOThreadImmediately();
  4106. } else {
  4107. op->Dispatch();
  4108. }
  4109. }
  4110. void
  4111. QuotaManager::ShutdownTimerCallback(nsITimer* aTimer, void* aClosure)
  4112. {
  4113. AssertIsOnBackgroundThread();
  4114. auto quotaManager = static_cast<QuotaManager*>(aClosure);
  4115. MOZ_ASSERT(quotaManager);
  4116. NS_WARNING("Some storage operations are taking longer than expected "
  4117. "during shutdown and will be aborted!");
  4118. // Abort all operations.
  4119. for (RefPtr<Client>& client : quotaManager->mClients) {
  4120. client->AbortOperations(NullCString());
  4121. }
  4122. }
  4123. auto
  4124. QuotaManager::GetDirectoryLockTable(PersistenceType aPersistenceType)
  4125. -> DirectoryLockTable&
  4126. {
  4127. switch (aPersistenceType) {
  4128. case PERSISTENCE_TYPE_TEMPORARY:
  4129. return mTemporaryDirectoryLockTable;
  4130. case PERSISTENCE_TYPE_DEFAULT:
  4131. return mDefaultDirectoryLockTable;
  4132. case PERSISTENCE_TYPE_PERSISTENT:
  4133. case PERSISTENCE_TYPE_INVALID:
  4134. default:
  4135. MOZ_CRASH("Bad persistence type value!");
  4136. }
  4137. }
  4138. /*******************************************************************************
  4139. * Local class implementations
  4140. ******************************************************************************/
  4141. void
  4142. OriginInfo::LockedDecreaseUsage(int64_t aSize)
  4143. {
  4144. AssertCurrentThreadOwnsQuotaMutex();
  4145. AssertNoUnderflow(mUsage, aSize);
  4146. mUsage -= aSize;
  4147. AssertNoUnderflow(mGroupInfo->mUsage, aSize);
  4148. mGroupInfo->mUsage -= aSize;
  4149. QuotaManager* quotaManager = QuotaManager::Get();
  4150. MOZ_ASSERT(quotaManager);
  4151. AssertNoUnderflow(quotaManager->mTemporaryStorageUsage, aSize);
  4152. quotaManager->mTemporaryStorageUsage -= aSize;
  4153. }
  4154. already_AddRefed<OriginInfo>
  4155. GroupInfo::LockedGetOriginInfo(const nsACString& aOrigin)
  4156. {
  4157. AssertCurrentThreadOwnsQuotaMutex();
  4158. for (RefPtr<OriginInfo>& originInfo : mOriginInfos) {
  4159. if (originInfo->mOrigin == aOrigin) {
  4160. RefPtr<OriginInfo> result = originInfo;
  4161. return result.forget();
  4162. }
  4163. }
  4164. return nullptr;
  4165. }
  4166. void
  4167. GroupInfo::LockedAddOriginInfo(OriginInfo* aOriginInfo)
  4168. {
  4169. AssertCurrentThreadOwnsQuotaMutex();
  4170. NS_ASSERTION(!mOriginInfos.Contains(aOriginInfo),
  4171. "Replacing an existing entry!");
  4172. mOriginInfos.AppendElement(aOriginInfo);
  4173. AssertNoOverflow(mUsage, aOriginInfo->mUsage);
  4174. mUsage += aOriginInfo->mUsage;
  4175. QuotaManager* quotaManager = QuotaManager::Get();
  4176. MOZ_ASSERT(quotaManager);
  4177. AssertNoOverflow(quotaManager->mTemporaryStorageUsage, aOriginInfo->mUsage);
  4178. quotaManager->mTemporaryStorageUsage += aOriginInfo->mUsage;
  4179. }
  4180. void
  4181. GroupInfo::LockedRemoveOriginInfo(const nsACString& aOrigin)
  4182. {
  4183. AssertCurrentThreadOwnsQuotaMutex();
  4184. for (uint32_t index = 0; index < mOriginInfos.Length(); index++) {
  4185. if (mOriginInfos[index]->mOrigin == aOrigin) {
  4186. AssertNoUnderflow(mUsage, mOriginInfos[index]->mUsage);
  4187. mUsage -= mOriginInfos[index]->mUsage;
  4188. QuotaManager* quotaManager = QuotaManager::Get();
  4189. MOZ_ASSERT(quotaManager);
  4190. AssertNoUnderflow(quotaManager->mTemporaryStorageUsage,
  4191. mOriginInfos[index]->mUsage);
  4192. quotaManager->mTemporaryStorageUsage -= mOriginInfos[index]->mUsage;
  4193. mOriginInfos.RemoveElementAt(index);
  4194. return;
  4195. }
  4196. }
  4197. }
  4198. void
  4199. GroupInfo::LockedRemoveOriginInfos()
  4200. {
  4201. AssertCurrentThreadOwnsQuotaMutex();
  4202. QuotaManager* quotaManager = QuotaManager::Get();
  4203. MOZ_ASSERT(quotaManager);
  4204. for (uint32_t index = mOriginInfos.Length(); index > 0; index--) {
  4205. OriginInfo* originInfo = mOriginInfos[index - 1];
  4206. AssertNoUnderflow(mUsage, originInfo->mUsage);
  4207. mUsage -= originInfo->mUsage;
  4208. AssertNoUnderflow(quotaManager->mTemporaryStorageUsage, originInfo->mUsage);
  4209. quotaManager->mTemporaryStorageUsage -= originInfo->mUsage;
  4210. mOriginInfos.RemoveElementAt(index - 1);
  4211. }
  4212. }
  4213. RefPtr<GroupInfo>&
  4214. GroupInfoPair::GetGroupInfoForPersistenceType(PersistenceType aPersistenceType)
  4215. {
  4216. switch (aPersistenceType) {
  4217. case PERSISTENCE_TYPE_TEMPORARY:
  4218. return mTemporaryStorageGroupInfo;
  4219. case PERSISTENCE_TYPE_DEFAULT:
  4220. return mDefaultStorageGroupInfo;
  4221. case PERSISTENCE_TYPE_PERSISTENT:
  4222. case PERSISTENCE_TYPE_INVALID:
  4223. default:
  4224. MOZ_CRASH("Bad persistence type value!");
  4225. }
  4226. }
  4227. CollectOriginsHelper::CollectOriginsHelper(mozilla::Mutex& aMutex,
  4228. uint64_t aMinSizeToBeFreed)
  4229. : mMinSizeToBeFreed(aMinSizeToBeFreed),
  4230. mMutex(aMutex),
  4231. mCondVar(aMutex, "CollectOriginsHelper::mCondVar"),
  4232. mSizeToBeFreed(0),
  4233. mWaiting(true)
  4234. {
  4235. MOZ_ASSERT(!NS_IsMainThread(), "Wrong thread!");
  4236. mMutex.AssertCurrentThreadOwns();
  4237. }
  4238. int64_t
  4239. CollectOriginsHelper::BlockAndReturnOriginsForEviction(
  4240. nsTArray<RefPtr<DirectoryLockImpl>>& aLocks)
  4241. {
  4242. MOZ_ASSERT(!NS_IsMainThread(), "Wrong thread!");
  4243. mMutex.AssertCurrentThreadOwns();
  4244. while (mWaiting) {
  4245. mCondVar.Wait();
  4246. }
  4247. mLocks.SwapElements(aLocks);
  4248. return mSizeToBeFreed;
  4249. }
  4250. NS_IMETHODIMP
  4251. CollectOriginsHelper::Run()
  4252. {
  4253. AssertIsOnBackgroundThread();
  4254. QuotaManager* quotaManager = QuotaManager::Get();
  4255. NS_ASSERTION(quotaManager, "Shouldn't be null!");
  4256. // We use extra stack vars here to avoid race detector warnings (the same
  4257. // memory accessed with and without the lock held).
  4258. nsTArray<RefPtr<DirectoryLockImpl>> locks;
  4259. uint64_t sizeToBeFreed =
  4260. quotaManager->CollectOriginsForEviction(mMinSizeToBeFreed, locks);
  4261. MutexAutoLock lock(mMutex);
  4262. NS_ASSERTION(mWaiting, "Huh?!");
  4263. mLocks.SwapElements(locks);
  4264. mSizeToBeFreed = sizeToBeFreed;
  4265. mWaiting = false;
  4266. mCondVar.Notify();
  4267. return NS_OK;
  4268. }
  4269. /*******************************************************************************
  4270. * OriginOperationBase
  4271. ******************************************************************************/
  4272. NS_IMETHODIMP
  4273. OriginOperationBase::Run()
  4274. {
  4275. nsresult rv;
  4276. switch (mState) {
  4277. case State_Initial: {
  4278. rv = Init();
  4279. break;
  4280. }
  4281. case State_Initializing: {
  4282. rv = InitOnMainThread();
  4283. break;
  4284. }
  4285. case State_FinishingInit: {
  4286. rv = FinishInit();
  4287. break;
  4288. }
  4289. case State_CreatingQuotaManager: {
  4290. rv = QuotaManagerOpen();
  4291. break;
  4292. }
  4293. case State_DirectoryOpenPending: {
  4294. rv = DirectoryOpen();
  4295. break;
  4296. }
  4297. case State_DirectoryWorkOpen: {
  4298. rv = DirectoryWork();
  4299. break;
  4300. }
  4301. case State_UnblockingOpen: {
  4302. UnblockOpen();
  4303. return NS_OK;
  4304. }
  4305. default:
  4306. MOZ_CRASH("Bad state!");
  4307. }
  4308. if (NS_WARN_IF(NS_FAILED(rv)) && mState != State_UnblockingOpen) {
  4309. Finish(rv);
  4310. }
  4311. return NS_OK;
  4312. }
  4313. nsresult
  4314. OriginOperationBase::DirectoryOpen()
  4315. {
  4316. AssertIsOnOwningThread();
  4317. MOZ_ASSERT(mState == State_DirectoryOpenPending);
  4318. QuotaManager* quotaManager = QuotaManager::Get();
  4319. if (NS_WARN_IF(!quotaManager)) {
  4320. return NS_ERROR_FAILURE;
  4321. }
  4322. // Must set this before dispatching otherwise we will race with the IO thread.
  4323. AdvanceState();
  4324. nsresult rv = quotaManager->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL);
  4325. if (NS_WARN_IF(NS_FAILED(rv))) {
  4326. return NS_ERROR_FAILURE;
  4327. }
  4328. return NS_OK;
  4329. }
  4330. void
  4331. OriginOperationBase::Finish(nsresult aResult)
  4332. {
  4333. if (NS_SUCCEEDED(mResultCode)) {
  4334. mResultCode = aResult;
  4335. }
  4336. // Must set mState before dispatching otherwise we will race with the main
  4337. // thread.
  4338. mState = State_UnblockingOpen;
  4339. MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(this, NS_DISPATCH_NORMAL));
  4340. }
  4341. nsresult
  4342. OriginOperationBase::Init()
  4343. {
  4344. AssertIsOnOwningThread();
  4345. MOZ_ASSERT(mState == State_Initial);
  4346. AdvanceState();
  4347. if (mNeedsMainThreadInit) {
  4348. MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
  4349. } else {
  4350. AdvanceState();
  4351. MOZ_ALWAYS_SUCCEEDS(Run());
  4352. }
  4353. return NS_OK;
  4354. }
  4355. nsresult
  4356. OriginOperationBase::InitOnMainThread()
  4357. {
  4358. MOZ_ASSERT(NS_IsMainThread());
  4359. MOZ_ASSERT(mState == State_Initializing);
  4360. nsresult rv = DoInitOnMainThread();
  4361. if (NS_WARN_IF(NS_FAILED(rv))) {
  4362. return rv;
  4363. }
  4364. AdvanceState();
  4365. MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(this, NS_DISPATCH_NORMAL));
  4366. return NS_OK;
  4367. }
  4368. nsresult
  4369. OriginOperationBase::FinishInit()
  4370. {
  4371. AssertIsOnOwningThread();
  4372. MOZ_ASSERT(mState == State_FinishingInit);
  4373. if (QuotaManager::IsShuttingDown()) {
  4374. return NS_ERROR_FAILURE;
  4375. }
  4376. AdvanceState();
  4377. if (mNeedsQuotaManagerInit && !QuotaManager::Get()) {
  4378. QuotaManager::GetOrCreate(this);
  4379. } else {
  4380. Open();
  4381. }
  4382. return NS_OK;
  4383. }
  4384. nsresult
  4385. OriginOperationBase::QuotaManagerOpen()
  4386. {
  4387. AssertIsOnOwningThread();
  4388. MOZ_ASSERT(mState == State_CreatingQuotaManager);
  4389. if (NS_WARN_IF(!QuotaManager::Get())) {
  4390. return NS_ERROR_FAILURE;
  4391. }
  4392. Open();
  4393. return NS_OK;
  4394. }
  4395. nsresult
  4396. OriginOperationBase::DirectoryWork()
  4397. {
  4398. AssertIsOnIOThread();
  4399. MOZ_ASSERT(mState == State_DirectoryWorkOpen);
  4400. QuotaManager* quotaManager = QuotaManager::Get();
  4401. if (NS_WARN_IF(!quotaManager)) {
  4402. return NS_ERROR_FAILURE;
  4403. }
  4404. nsresult rv;
  4405. if (mNeedsQuotaManagerInit) {
  4406. rv = quotaManager->EnsureStorageIsInitialized();
  4407. if (NS_WARN_IF(NS_FAILED(rv))) {
  4408. return rv;
  4409. }
  4410. }
  4411. rv = DoDirectoryWork(quotaManager);
  4412. if (NS_WARN_IF(NS_FAILED(rv))) {
  4413. return rv;
  4414. }
  4415. // Must set mState before dispatching otherwise we will race with the owning
  4416. // thread.
  4417. AdvanceState();
  4418. MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(this, NS_DISPATCH_NORMAL));
  4419. return NS_OK;
  4420. }
  4421. void
  4422. FinalizeOriginEvictionOp::Dispatch()
  4423. {
  4424. MOZ_ASSERT(!NS_IsMainThread());
  4425. MOZ_ASSERT(GetState() == State_Initial);
  4426. SetState(State_DirectoryOpenPending);
  4427. MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(this, NS_DISPATCH_NORMAL));
  4428. }
  4429. void
  4430. FinalizeOriginEvictionOp::RunOnIOThreadImmediately()
  4431. {
  4432. AssertIsOnIOThread();
  4433. MOZ_ASSERT(GetState() == State_Initial);
  4434. SetState(State_DirectoryWorkOpen);
  4435. MOZ_ALWAYS_SUCCEEDS(this->Run());
  4436. }
  4437. void
  4438. FinalizeOriginEvictionOp::Open()
  4439. {
  4440. MOZ_CRASH("Shouldn't get here!");
  4441. }
  4442. nsresult
  4443. FinalizeOriginEvictionOp::DoDirectoryWork(QuotaManager* aQuotaManager)
  4444. {
  4445. AssertIsOnIOThread();
  4446. PROFILER_LABEL("Quota", "FinalizeOriginEvictionOp::DoDirectoryWork",
  4447. js::ProfileEntry::Category::OTHER);
  4448. for (RefPtr<DirectoryLockImpl>& lock : mLocks) {
  4449. aQuotaManager->OriginClearCompleted(lock->GetPersistenceType().Value(),
  4450. lock->GetOriginScope().GetOrigin(),
  4451. lock->GetIsApp().Value());
  4452. }
  4453. return NS_OK;
  4454. }
  4455. void
  4456. FinalizeOriginEvictionOp::UnblockOpen()
  4457. {
  4458. AssertIsOnOwningThread();
  4459. MOZ_ASSERT(GetState() == State_UnblockingOpen);
  4460. #ifdef DEBUG
  4461. NoteActorDestroyed();
  4462. #endif
  4463. mLocks.Clear();
  4464. AdvanceState();
  4465. }
  4466. NS_IMPL_ISUPPORTS_INHERITED0(NormalOriginOperationBase, Runnable)
  4467. void
  4468. NormalOriginOperationBase::Open()
  4469. {
  4470. AssertIsOnOwningThread();
  4471. MOZ_ASSERT(GetState() == State_CreatingQuotaManager);
  4472. MOZ_ASSERT(QuotaManager::Get());
  4473. AdvanceState();
  4474. QuotaManager::Get()->OpenDirectoryInternal(mPersistenceType,
  4475. mOriginScope,
  4476. Nullable<Client::Type>(),
  4477. mExclusive,
  4478. this);
  4479. }
  4480. void
  4481. NormalOriginOperationBase::UnblockOpen()
  4482. {
  4483. AssertIsOnOwningThread();
  4484. MOZ_ASSERT(GetState() == State_UnblockingOpen);
  4485. SendResults();
  4486. mDirectoryLock = nullptr;
  4487. AdvanceState();
  4488. }
  4489. void
  4490. NormalOriginOperationBase::DirectoryLockAcquired(DirectoryLock* aLock)
  4491. {
  4492. AssertIsOnOwningThread();
  4493. MOZ_ASSERT(aLock);
  4494. MOZ_ASSERT(GetState() == State_DirectoryOpenPending);
  4495. MOZ_ASSERT(!mDirectoryLock);
  4496. mDirectoryLock = aLock;
  4497. nsresult rv = DirectoryOpen();
  4498. if (NS_WARN_IF(NS_FAILED(rv))) {
  4499. Finish(rv);
  4500. return;
  4501. }
  4502. }
  4503. void
  4504. NormalOriginOperationBase::DirectoryLockFailed()
  4505. {
  4506. AssertIsOnOwningThread();
  4507. MOZ_ASSERT(GetState() == State_DirectoryOpenPending);
  4508. MOZ_ASSERT(!mDirectoryLock);
  4509. Finish(NS_ERROR_FAILURE);
  4510. }
  4511. nsresult
  4512. SaveOriginAccessTimeOp::DoDirectoryWork(QuotaManager* aQuotaManager)
  4513. {
  4514. AssertIsOnIOThread();
  4515. MOZ_ASSERT(!mPersistenceType.IsNull());
  4516. MOZ_ASSERT(mOriginScope.IsOrigin());
  4517. PROFILER_LABEL("Quota", "SaveOriginAccessTimeOp::DoDirectoryWork",
  4518. js::ProfileEntry::Category::OTHER);
  4519. nsCOMPtr<nsIFile> directory;
  4520. nsresult rv =
  4521. aQuotaManager->GetDirectoryForOrigin(mPersistenceType.Value(),
  4522. mOriginScope.GetOrigin(),
  4523. getter_AddRefs(directory));
  4524. if (NS_WARN_IF(NS_FAILED(rv))) {
  4525. return rv;
  4526. }
  4527. nsCOMPtr<nsIBinaryOutputStream> stream;
  4528. rv = GetBinaryOutputStream(directory,
  4529. NS_LITERAL_STRING(METADATA_V2_FILE_NAME),
  4530. kUpdateFileFlag,
  4531. getter_AddRefs(stream));
  4532. if (NS_WARN_IF(NS_FAILED(rv))) {
  4533. return rv;
  4534. }
  4535. // The origin directory may not exist anymore.
  4536. if (stream) {
  4537. rv = stream->Write64(mTimestamp);
  4538. if (NS_WARN_IF(NS_FAILED(rv))) {
  4539. return rv;
  4540. }
  4541. }
  4542. return NS_OK;
  4543. }
  4544. void
  4545. SaveOriginAccessTimeOp::SendResults()
  4546. {
  4547. #ifdef DEBUG
  4548. NoteActorDestroyed();
  4549. #endif
  4550. }
  4551. /*******************************************************************************
  4552. * Quota
  4553. ******************************************************************************/
  4554. Quota::Quota()
  4555. #ifdef DEBUG
  4556. : mActorDestroyed(false)
  4557. #endif
  4558. {
  4559. }
  4560. Quota::~Quota()
  4561. {
  4562. MOZ_ASSERT(mActorDestroyed);
  4563. }
  4564. void
  4565. Quota::StartIdleMaintenance()
  4566. {
  4567. AssertIsOnBackgroundThread();
  4568. MOZ_ASSERT(!QuotaManager::IsShuttingDown());
  4569. QuotaManager* quotaManager = QuotaManager::Get();
  4570. if (NS_WARN_IF(!quotaManager)) {
  4571. return;
  4572. }
  4573. quotaManager->StartIdleMaintenance();
  4574. }
  4575. void
  4576. Quota::ActorDestroy(ActorDestroyReason aWhy)
  4577. {
  4578. AssertIsOnBackgroundThread();
  4579. #ifdef DEBUG
  4580. MOZ_ASSERT(!mActorDestroyed);
  4581. mActorDestroyed = true;
  4582. #endif
  4583. }
  4584. PQuotaUsageRequestParent*
  4585. Quota::AllocPQuotaUsageRequestParent(const UsageRequestParams& aParams)
  4586. {
  4587. AssertIsOnBackgroundThread();
  4588. MOZ_ASSERT(aParams.type() != UsageRequestParams::T__None);
  4589. RefPtr<QuotaUsageRequestBase> actor;
  4590. switch (aParams.type()) {
  4591. case UsageRequestParams::TAllUsageParams:
  4592. actor = new GetUsageOp(aParams);
  4593. break;
  4594. case UsageRequestParams::TOriginUsageParams:
  4595. actor = new GetOriginUsageOp(aParams);
  4596. break;
  4597. default:
  4598. MOZ_CRASH("Should never get here!");
  4599. }
  4600. MOZ_ASSERT(actor);
  4601. // Transfer ownership to IPDL.
  4602. return actor.forget().take();
  4603. }
  4604. bool
  4605. Quota::RecvPQuotaUsageRequestConstructor(PQuotaUsageRequestParent* aActor,
  4606. const UsageRequestParams& aParams)
  4607. {
  4608. AssertIsOnBackgroundThread();
  4609. MOZ_ASSERT(aActor);
  4610. MOZ_ASSERT(aParams.type() != UsageRequestParams::T__None);
  4611. auto* op = static_cast<QuotaUsageRequestBase*>(aActor);
  4612. if (NS_WARN_IF(!op->Init(this))) {
  4613. return false;
  4614. }
  4615. op->RunImmediately();
  4616. return true;
  4617. }
  4618. bool
  4619. Quota::DeallocPQuotaUsageRequestParent(PQuotaUsageRequestParent* aActor)
  4620. {
  4621. AssertIsOnBackgroundThread();
  4622. MOZ_ASSERT(aActor);
  4623. // Transfer ownership back from IPDL.
  4624. RefPtr<QuotaUsageRequestBase> actor =
  4625. dont_AddRef(static_cast<QuotaUsageRequestBase*>(aActor));
  4626. return true;
  4627. }
  4628. PQuotaRequestParent*
  4629. Quota::AllocPQuotaRequestParent(const RequestParams& aParams)
  4630. {
  4631. AssertIsOnBackgroundThread();
  4632. MOZ_ASSERT(aParams.type() != RequestParams::T__None);
  4633. if (aParams.type() == RequestParams::TClearOriginsParams) {
  4634. PBackgroundParent* actor = Manager();
  4635. MOZ_ASSERT(actor);
  4636. if (BackgroundParent::IsOtherProcessActor(actor)) {
  4637. ASSERT_UNLESS_FUZZING();
  4638. return nullptr;
  4639. }
  4640. }
  4641. RefPtr<QuotaRequestBase> actor;
  4642. switch (aParams.type()) {
  4643. case RequestParams::TClearOriginParams:
  4644. case RequestParams::TClearOriginsParams:
  4645. actor = new OriginClearOp(aParams);
  4646. break;
  4647. case RequestParams::TClearAllParams:
  4648. actor = new ResetOrClearOp(/* aClear */ true);
  4649. break;
  4650. case RequestParams::TResetAllParams:
  4651. actor = new ResetOrClearOp(/* aClear */ false);
  4652. break;
  4653. default:
  4654. MOZ_CRASH("Should never get here!");
  4655. }
  4656. MOZ_ASSERT(actor);
  4657. // Transfer ownership to IPDL.
  4658. return actor.forget().take();
  4659. }
  4660. bool
  4661. Quota::RecvPQuotaRequestConstructor(PQuotaRequestParent* aActor,
  4662. const RequestParams& aParams)
  4663. {
  4664. AssertIsOnBackgroundThread();
  4665. MOZ_ASSERT(aActor);
  4666. MOZ_ASSERT(aParams.type() != RequestParams::T__None);
  4667. auto* op = static_cast<QuotaRequestBase*>(aActor);
  4668. if (NS_WARN_IF(!op->Init(this))) {
  4669. return false;
  4670. }
  4671. op->RunImmediately();
  4672. return true;
  4673. }
  4674. bool
  4675. Quota::DeallocPQuotaRequestParent(PQuotaRequestParent* aActor)
  4676. {
  4677. AssertIsOnBackgroundThread();
  4678. MOZ_ASSERT(aActor);
  4679. // Transfer ownership back from IPDL.
  4680. RefPtr<QuotaRequestBase> actor =
  4681. dont_AddRef(static_cast<QuotaRequestBase*>(aActor));
  4682. return true;
  4683. }
  4684. bool
  4685. Quota::RecvStartIdleMaintenance()
  4686. {
  4687. AssertIsOnBackgroundThread();
  4688. PBackgroundParent* actor = Manager();
  4689. MOZ_ASSERT(actor);
  4690. if (BackgroundParent::IsOtherProcessActor(actor)) {
  4691. ASSERT_UNLESS_FUZZING();
  4692. return false;
  4693. }
  4694. if (QuotaManager::IsShuttingDown()) {
  4695. return true;
  4696. }
  4697. QuotaManager* quotaManager = QuotaManager::Get();
  4698. if (!quotaManager) {
  4699. nsCOMPtr<nsIRunnable> callback =
  4700. NewRunnableMethod(this, &Quota::StartIdleMaintenance);
  4701. QuotaManager::GetOrCreate(callback);
  4702. return true;
  4703. }
  4704. quotaManager->StartIdleMaintenance();
  4705. return true;
  4706. }
  4707. bool
  4708. Quota::RecvStopIdleMaintenance()
  4709. {
  4710. AssertIsOnBackgroundThread();
  4711. PBackgroundParent* actor = Manager();
  4712. MOZ_ASSERT(actor);
  4713. if (BackgroundParent::IsOtherProcessActor(actor)) {
  4714. ASSERT_UNLESS_FUZZING();
  4715. return false;
  4716. }
  4717. if (QuotaManager::IsShuttingDown()) {
  4718. return true;
  4719. }
  4720. QuotaManager* quotaManager = QuotaManager::Get();
  4721. if (!quotaManager) {
  4722. return true;
  4723. }
  4724. quotaManager->StopIdleMaintenance();
  4725. return true;
  4726. }
  4727. bool
  4728. QuotaUsageRequestBase::Init(Quota* aQuota)
  4729. {
  4730. AssertIsOnOwningThread();
  4731. MOZ_ASSERT(aQuota);
  4732. mNeedsQuotaManagerInit = true;
  4733. return true;
  4734. }
  4735. nsresult
  4736. QuotaUsageRequestBase::GetUsageForOrigin(QuotaManager* aQuotaManager,
  4737. PersistenceType aPersistenceType,
  4738. const nsACString& aGroup,
  4739. const nsACString& aOrigin,
  4740. bool aIsApp,
  4741. UsageInfo* aUsageInfo)
  4742. {
  4743. AssertIsOnIOThread();
  4744. MOZ_ASSERT(aQuotaManager);
  4745. MOZ_ASSERT(aUsageInfo);
  4746. MOZ_ASSERT(aUsageInfo->TotalUsage() == 0);
  4747. nsCOMPtr<nsIFile> directory;
  4748. nsresult rv = aQuotaManager->GetDirectoryForOrigin(aPersistenceType,
  4749. aOrigin,
  4750. getter_AddRefs(directory));
  4751. NS_ENSURE_SUCCESS(rv, rv);
  4752. bool exists;
  4753. rv = directory->Exists(&exists);
  4754. NS_ENSURE_SUCCESS(rv, rv);
  4755. // If the directory exists then enumerate all the files inside, adding up
  4756. // the sizes to get the final usage statistic.
  4757. if (exists && !mCanceled) {
  4758. bool initialized;
  4759. if (IsTreatedAsPersistent(aPersistenceType, aIsApp)) {
  4760. nsCString originKey = OriginKey(aPersistenceType, aOrigin);
  4761. initialized = aQuotaManager->IsOriginInitialized(originKey);
  4762. } else {
  4763. initialized = aQuotaManager->IsTemporaryStorageInitialized();
  4764. }
  4765. nsCOMPtr<nsISimpleEnumerator> entries;
  4766. rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
  4767. NS_ENSURE_SUCCESS(rv, rv);
  4768. bool hasMore;
  4769. while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
  4770. hasMore && !mCanceled) {
  4771. nsCOMPtr<nsISupports> entry;
  4772. rv = entries->GetNext(getter_AddRefs(entry));
  4773. NS_ENSURE_SUCCESS(rv, rv);
  4774. nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
  4775. NS_ENSURE_TRUE(file, NS_NOINTERFACE);
  4776. nsString leafName;
  4777. rv = file->GetLeafName(leafName);
  4778. NS_ENSURE_SUCCESS(rv, rv);
  4779. if (leafName.EqualsLiteral(METADATA_FILE_NAME) ||
  4780. leafName.EqualsLiteral(METADATA_V2_FILE_NAME) ||
  4781. leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
  4782. continue;
  4783. }
  4784. if (!initialized) {
  4785. bool isDirectory;
  4786. rv = file->IsDirectory(&isDirectory);
  4787. NS_ENSURE_SUCCESS(rv, rv);
  4788. if (!isDirectory) {
  4789. NS_WARNING("Unknown file found!");
  4790. return NS_ERROR_UNEXPECTED;
  4791. }
  4792. }
  4793. if (MaybeRemoveCorruptDirectory(leafName, file)) {
  4794. continue;
  4795. }
  4796. Client::Type clientType;
  4797. rv = Client::TypeFromText(leafName, clientType);
  4798. if (NS_FAILED(rv)) {
  4799. NS_WARNING("Unknown directory found!");
  4800. if (!initialized) {
  4801. return NS_ERROR_UNEXPECTED;
  4802. }
  4803. continue;
  4804. }
  4805. Client* client = aQuotaManager->GetClient(clientType);
  4806. MOZ_ASSERT(client);
  4807. if (initialized) {
  4808. rv = client->GetUsageForOrigin(aPersistenceType,
  4809. aGroup,
  4810. aOrigin,
  4811. mCanceled,
  4812. aUsageInfo);
  4813. }
  4814. else {
  4815. rv = client->InitOrigin(aPersistenceType,
  4816. aGroup,
  4817. aOrigin,
  4818. mCanceled,
  4819. aUsageInfo);
  4820. }
  4821. NS_ENSURE_SUCCESS(rv, rv);
  4822. }
  4823. }
  4824. return NS_OK;
  4825. }
  4826. void
  4827. QuotaUsageRequestBase::SendResults()
  4828. {
  4829. AssertIsOnOwningThread();
  4830. if (IsActorDestroyed()) {
  4831. if (NS_SUCCEEDED(mResultCode)) {
  4832. mResultCode = NS_ERROR_FAILURE;
  4833. }
  4834. } else {
  4835. if (mCanceled) {
  4836. mResultCode = NS_ERROR_FAILURE;
  4837. }
  4838. UsageRequestResponse response;
  4839. if (NS_SUCCEEDED(mResultCode)) {
  4840. GetResponse(response);
  4841. } else {
  4842. response = mResultCode;
  4843. }
  4844. Unused << PQuotaUsageRequestParent::Send__delete__(this, response);
  4845. }
  4846. }
  4847. void
  4848. QuotaUsageRequestBase::ActorDestroy(ActorDestroyReason aWhy)
  4849. {
  4850. AssertIsOnOwningThread();
  4851. NoteActorDestroyed();
  4852. }
  4853. bool
  4854. QuotaUsageRequestBase::RecvCancel()
  4855. {
  4856. AssertIsOnOwningThread();
  4857. if (mCanceled.exchange(true)) {
  4858. NS_WARNING("Canceled more than once?!");
  4859. return false;
  4860. }
  4861. return true;
  4862. }
  4863. GetUsageOp::GetUsageOp(const UsageRequestParams& aParams)
  4864. : mGetAll(aParams.get_AllUsageParams().getAll())
  4865. {
  4866. AssertIsOnOwningThread();
  4867. MOZ_ASSERT(aParams.type() == UsageRequestParams::TAllUsageParams);
  4868. }
  4869. nsresult
  4870. GetUsageOp::TraverseRepository(QuotaManager* aQuotaManager,
  4871. PersistenceType aPersistenceType)
  4872. {
  4873. AssertIsOnIOThread();
  4874. MOZ_ASSERT(aQuotaManager);
  4875. nsresult rv;
  4876. nsCOMPtr<nsIFile> directory =
  4877. do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  4878. if (NS_WARN_IF(NS_FAILED(rv))) {
  4879. return rv;
  4880. }
  4881. rv = directory->InitWithPath(aQuotaManager->GetStoragePath(aPersistenceType));
  4882. if (NS_WARN_IF(NS_FAILED(rv))) {
  4883. return rv;
  4884. }
  4885. bool exists;
  4886. rv = directory->Exists(&exists);
  4887. if (NS_WARN_IF(NS_FAILED(rv))) {
  4888. return rv;
  4889. }
  4890. if (!exists) {
  4891. return NS_OK;
  4892. }
  4893. nsCOMPtr<nsISimpleEnumerator> entries;
  4894. rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
  4895. if (NS_WARN_IF(NS_FAILED(rv))) {
  4896. return rv;
  4897. }
  4898. bool persistent = aPersistenceType == PERSISTENCE_TYPE_PERSISTENT;
  4899. bool hasMore;
  4900. while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
  4901. hasMore && !mCanceled) {
  4902. nsCOMPtr<nsISupports> entry;
  4903. rv = entries->GetNext(getter_AddRefs(entry));
  4904. if (NS_WARN_IF(NS_FAILED(rv))) {
  4905. return rv;
  4906. }
  4907. nsCOMPtr<nsIFile> originDir = do_QueryInterface(entry);
  4908. MOZ_ASSERT(originDir);
  4909. bool isDirectory;
  4910. rv = originDir->IsDirectory(&isDirectory);
  4911. if (NS_WARN_IF(NS_FAILED(rv))) {
  4912. return rv;
  4913. }
  4914. if (!isDirectory) {
  4915. nsString leafName;
  4916. rv = originDir->GetLeafName(leafName);
  4917. if (NS_WARN_IF(NS_FAILED(rv))) {
  4918. return rv;
  4919. }
  4920. if (!leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
  4921. QM_WARNING("Something (%s) in the repository that doesn't belong!",
  4922. NS_ConvertUTF16toUTF8(leafName).get());
  4923. }
  4924. continue;
  4925. }
  4926. int64_t timestamp;
  4927. nsCString suffix;
  4928. nsCString group;
  4929. nsCString origin;
  4930. bool isApp;
  4931. rv = aQuotaManager->GetDirectoryMetadata2WithRestore(originDir,
  4932. persistent,
  4933. &timestamp,
  4934. suffix,
  4935. group,
  4936. origin,
  4937. &isApp);
  4938. if (NS_WARN_IF(NS_FAILED(rv))) {
  4939. return rv;
  4940. }
  4941. if (!mGetAll && aQuotaManager->IsOriginInternal(origin)) {
  4942. continue;
  4943. }
  4944. OriginUsage* originUsage;
  4945. // We can't store pointers to OriginUsage objects in the hashtable
  4946. // since AppendElement() reallocates its internal array buffer as number
  4947. // of elements grows.
  4948. uint32_t index;
  4949. if (mOriginUsagesIndex.Get(origin, &index)) {
  4950. originUsage = &mOriginUsages[index];
  4951. } else {
  4952. index = mOriginUsages.Length();
  4953. originUsage = mOriginUsages.AppendElement();
  4954. originUsage->origin() = origin;
  4955. originUsage->persisted() = false;
  4956. originUsage->usage() = 0;
  4957. mOriginUsagesIndex.Put(origin, index);
  4958. }
  4959. UsageInfo usageInfo;
  4960. rv = GetUsageForOrigin(aQuotaManager,
  4961. aPersistenceType,
  4962. group,
  4963. origin,
  4964. isApp,
  4965. &usageInfo);
  4966. if (NS_WARN_IF(NS_FAILED(rv))) {
  4967. return rv;
  4968. }
  4969. originUsage->usage() = originUsage->usage() + usageInfo.TotalUsage();
  4970. }
  4971. if (NS_WARN_IF(NS_FAILED(rv))) {
  4972. return rv;
  4973. }
  4974. return NS_OK;
  4975. }
  4976. nsresult
  4977. GetUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager)
  4978. {
  4979. AssertIsOnIOThread();
  4980. PROFILER_LABEL("Quota", "GetUsageOp::DoDirectoryWork",
  4981. js::ProfileEntry::Category::OTHER);
  4982. nsresult rv;
  4983. for (const PersistenceType type : kAllPersistenceTypes) {
  4984. rv = TraverseRepository(aQuotaManager, type);
  4985. if (NS_WARN_IF(NS_FAILED(rv))) {
  4986. return rv;
  4987. }
  4988. }
  4989. return NS_OK;
  4990. }
  4991. void
  4992. GetUsageOp::GetResponse(UsageRequestResponse& aResponse)
  4993. {
  4994. AssertIsOnOwningThread();
  4995. aResponse = AllUsageResponse();
  4996. if (!mOriginUsages.IsEmpty()) {
  4997. nsTArray<OriginUsage>& originUsages =
  4998. aResponse.get_AllUsageResponse().originUsages();
  4999. mOriginUsages.SwapElements(originUsages);
  5000. }
  5001. }
  5002. GetOriginUsageOp::GetOriginUsageOp(const UsageRequestParams& aParams)
  5003. : mParams(aParams.get_OriginUsageParams())
  5004. , mGetGroupUsage(aParams.get_OriginUsageParams().getGroupUsage())
  5005. {
  5006. AssertIsOnOwningThread();
  5007. MOZ_ASSERT(aParams.type() == UsageRequestParams::TOriginUsageParams);
  5008. }
  5009. bool
  5010. GetOriginUsageOp::Init(Quota* aQuota)
  5011. {
  5012. AssertIsOnOwningThread();
  5013. MOZ_ASSERT(aQuota);
  5014. if (NS_WARN_IF(!QuotaUsageRequestBase::Init(aQuota))) {
  5015. return false;
  5016. }
  5017. mNeedsMainThreadInit = true;
  5018. return true;
  5019. }
  5020. nsresult
  5021. GetOriginUsageOp::DoInitOnMainThread()
  5022. {
  5023. MOZ_ASSERT(NS_IsMainThread());
  5024. MOZ_ASSERT(GetState() == State_Initializing);
  5025. MOZ_ASSERT(mNeedsMainThreadInit);
  5026. const PrincipalInfo& principalInfo = mParams.principalInfo();
  5027. nsresult rv;
  5028. nsCOMPtr<nsIPrincipal> principal =
  5029. PrincipalInfoToPrincipal(principalInfo, &rv);
  5030. if (NS_WARN_IF(NS_FAILED(rv))) {
  5031. return rv;
  5032. }
  5033. // Figure out which origin we're dealing with.
  5034. nsCString origin;
  5035. rv = QuotaManager::GetInfoFromPrincipal(principal, &mSuffix, &mGroup,
  5036. &origin, &mIsApp);
  5037. if (NS_WARN_IF(NS_FAILED(rv))) {
  5038. return rv;
  5039. }
  5040. mOriginScope.SetFromOrigin(origin);
  5041. return NS_OK;
  5042. }
  5043. nsresult
  5044. GetOriginUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager)
  5045. {
  5046. AssertIsOnIOThread();
  5047. MOZ_ASSERT(mUsageInfo.TotalUsage() == 0);
  5048. PROFILER_LABEL("Quota", "GetOriginUsageOp::DoDirectoryWork",
  5049. js::ProfileEntry::Category::OTHER);
  5050. nsresult rv;
  5051. if (mGetGroupUsage) {
  5052. nsCOMPtr<nsIFile> directory;
  5053. // Ensure origin is initialized first. It will initialize all origins for
  5054. // temporary storage including origins belonging to our group.
  5055. rv = aQuotaManager->EnsureOriginIsInitialized(PERSISTENCE_TYPE_TEMPORARY,
  5056. mSuffix, mGroup,
  5057. mOriginScope.GetOrigin(),
  5058. mIsApp,
  5059. getter_AddRefs(directory));
  5060. if (NS_WARN_IF(NS_FAILED(rv))) {
  5061. return rv;
  5062. }
  5063. // Get cached usage and limit (the method doesn't have to stat any files).
  5064. aQuotaManager->GetGroupUsageAndLimit(mGroup, &mUsageInfo);
  5065. return NS_OK;
  5066. }
  5067. // Add all the persistent/temporary/default storage files we care about.
  5068. for (const PersistenceType type : kAllPersistenceTypes) {
  5069. UsageInfo usageInfo;
  5070. rv = GetUsageForOrigin(aQuotaManager,
  5071. type,
  5072. mGroup,
  5073. mOriginScope.GetOrigin(),
  5074. mIsApp,
  5075. &usageInfo);
  5076. if (NS_WARN_IF(NS_FAILED(rv))) {
  5077. return rv;
  5078. }
  5079. mUsageInfo.Append(usageInfo);
  5080. }
  5081. return NS_OK;
  5082. }
  5083. void
  5084. GetOriginUsageOp::GetResponse(UsageRequestResponse& aResponse)
  5085. {
  5086. AssertIsOnOwningThread();
  5087. OriginUsageResponse usageResponse;
  5088. // We'll get the group usage when mGetGroupUsage is true and get the
  5089. // origin usage when mGetGroupUsage is false.
  5090. usageResponse.usage() = mUsageInfo.TotalUsage();
  5091. if (mGetGroupUsage) {
  5092. usageResponse.limit() = mUsageInfo.Limit();
  5093. } else {
  5094. usageResponse.fileUsage() = mUsageInfo.FileUsage();
  5095. }
  5096. aResponse = usageResponse;
  5097. }
  5098. bool
  5099. QuotaRequestBase::Init(Quota* aQuota)
  5100. {
  5101. AssertIsOnOwningThread();
  5102. MOZ_ASSERT(aQuota);
  5103. mNeedsQuotaManagerInit = true;
  5104. return true;
  5105. }
  5106. void
  5107. QuotaRequestBase::SendResults()
  5108. {
  5109. AssertIsOnOwningThread();
  5110. if (IsActorDestroyed()) {
  5111. if (NS_SUCCEEDED(mResultCode)) {
  5112. mResultCode = NS_ERROR_FAILURE;
  5113. }
  5114. } else {
  5115. RequestResponse response;
  5116. if (NS_SUCCEEDED(mResultCode)) {
  5117. GetResponse(response);
  5118. } else {
  5119. response = mResultCode;
  5120. }
  5121. Unused << PQuotaRequestParent::Send__delete__(this, response);
  5122. }
  5123. }
  5124. void
  5125. QuotaRequestBase::ActorDestroy(ActorDestroyReason aWhy)
  5126. {
  5127. AssertIsOnOwningThread();
  5128. NoteActorDestroyed();
  5129. }
  5130. void
  5131. ResetOrClearOp::DeleteFiles(QuotaManager* aQuotaManager)
  5132. {
  5133. AssertIsOnIOThread();
  5134. MOZ_ASSERT(aQuotaManager);
  5135. nsresult rv;
  5136. nsCOMPtr<nsIFile> directory =
  5137. do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  5138. if (NS_WARN_IF(NS_FAILED(rv))) {
  5139. return;
  5140. }
  5141. rv = directory->InitWithPath(aQuotaManager->GetStoragePath());
  5142. if (NS_WARN_IF(NS_FAILED(rv))) {
  5143. return;
  5144. }
  5145. rv = directory->Remove(true);
  5146. if (rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST &&
  5147. rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
  5148. // This should never fail if we've closed all storage connections
  5149. // correctly...
  5150. MOZ_ASSERT(false, "Failed to remove storage directory!");
  5151. }
  5152. nsCOMPtr<nsIFile> storageFile =
  5153. do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  5154. if (NS_WARN_IF(NS_FAILED(rv))) {
  5155. return;
  5156. }
  5157. rv = storageFile->InitWithPath(aQuotaManager->GetBasePath());
  5158. if (NS_WARN_IF(NS_FAILED(rv))) {
  5159. return;
  5160. }
  5161. rv = storageFile->Append(NS_LITERAL_STRING(STORAGE_FILE_NAME));
  5162. if (NS_WARN_IF(NS_FAILED(rv))) {
  5163. return;
  5164. }
  5165. rv = storageFile->Remove(true);
  5166. if (rv != NS_ERROR_FILE_TARGET_DOES_NOT_EXIST &&
  5167. rv != NS_ERROR_FILE_NOT_FOUND && NS_FAILED(rv)) {
  5168. // This should never fail if we've closed the storage connection
  5169. // correctly...
  5170. MOZ_ASSERT(false, "Failed to remove storage file!");
  5171. }
  5172. }
  5173. nsresult
  5174. ResetOrClearOp::DoDirectoryWork(QuotaManager* aQuotaManager)
  5175. {
  5176. AssertIsOnIOThread();
  5177. PROFILER_LABEL("Quota", "ResetOrClearOp::DoDirectoryWork",
  5178. js::ProfileEntry::Category::OTHER);
  5179. if (mClear) {
  5180. DeleteFiles(aQuotaManager);
  5181. }
  5182. aQuotaManager->RemoveQuota();
  5183. aQuotaManager->ResetOrClearCompleted();
  5184. return NS_OK;
  5185. }
  5186. void
  5187. ResetOrClearOp::GetResponse(RequestResponse& aResponse)
  5188. {
  5189. AssertIsOnOwningThread();
  5190. if (mClear) {
  5191. aResponse = ClearAllResponse();
  5192. } else {
  5193. aResponse = ResetAllResponse();
  5194. }
  5195. }
  5196. OriginClearOp::OriginClearOp(const RequestParams& aParams)
  5197. : QuotaRequestBase(/* aExclusive */ true)
  5198. , mParams(aParams)
  5199. , mMultiple(aParams.type() == RequestParams::TClearOriginsParams)
  5200. {
  5201. MOZ_ASSERT(aParams.type() == RequestParams::TClearOriginParams ||
  5202. aParams.type() == RequestParams::TClearOriginsParams);
  5203. }
  5204. bool
  5205. OriginClearOp::Init(Quota* aQuota)
  5206. {
  5207. AssertIsOnOwningThread();
  5208. MOZ_ASSERT(aQuota);
  5209. if (NS_WARN_IF(!QuotaRequestBase::Init(aQuota))) {
  5210. return false;
  5211. }
  5212. if (!mMultiple) {
  5213. const ClearOriginParams& params = mParams.get_ClearOriginParams();
  5214. if (params.persistenceTypeIsExplicit()) {
  5215. MOZ_ASSERT(params.persistenceType() != PERSISTENCE_TYPE_INVALID);
  5216. mPersistenceType.SetValue(params.persistenceType());
  5217. }
  5218. }
  5219. mNeedsMainThreadInit = true;
  5220. return true;
  5221. }
  5222. nsresult
  5223. OriginClearOp::DoInitOnMainThread()
  5224. {
  5225. MOZ_ASSERT(NS_IsMainThread());
  5226. MOZ_ASSERT(GetState() == State_Initializing);
  5227. MOZ_ASSERT(mNeedsMainThreadInit);
  5228. if (mMultiple) {
  5229. const ClearOriginsParams& params = mParams.get_ClearOriginsParams();
  5230. mOriginScope.SetFromJSONPattern(params.pattern());
  5231. } else {
  5232. const ClearOriginParams& params = mParams.get_ClearOriginParams();
  5233. const PrincipalInfo& principalInfo = params.principalInfo();
  5234. nsresult rv;
  5235. nsCOMPtr<nsIPrincipal> principal =
  5236. PrincipalInfoToPrincipal(principalInfo, &rv);
  5237. if (NS_WARN_IF(NS_FAILED(rv))) {
  5238. return rv;
  5239. }
  5240. // Figure out which origin we're dealing with.
  5241. nsCString origin;
  5242. rv = QuotaManager::GetInfoFromPrincipal(principal, nullptr, nullptr, &origin,
  5243. nullptr);
  5244. if (NS_WARN_IF(NS_FAILED(rv))) {
  5245. return rv;
  5246. }
  5247. if (params.clearAll()) {
  5248. mOriginScope.SetFromPrefix(origin);
  5249. } else {
  5250. mOriginScope.SetFromOrigin(origin);
  5251. }
  5252. }
  5253. return NS_OK;
  5254. }
  5255. void
  5256. OriginClearOp::DeleteFiles(QuotaManager* aQuotaManager,
  5257. PersistenceType aPersistenceType)
  5258. {
  5259. AssertIsOnIOThread();
  5260. MOZ_ASSERT(aQuotaManager);
  5261. nsresult rv;
  5262. nsCOMPtr<nsIFile> directory =
  5263. do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  5264. if (NS_WARN_IF(NS_FAILED(rv))) {
  5265. return;
  5266. }
  5267. rv = directory->InitWithPath(aQuotaManager->GetStoragePath(aPersistenceType));
  5268. if (NS_WARN_IF(NS_FAILED(rv))) {
  5269. return;
  5270. }
  5271. nsCOMPtr<nsISimpleEnumerator> entries;
  5272. if (NS_WARN_IF(NS_FAILED(
  5273. directory->GetDirectoryEntries(getter_AddRefs(entries)))) || !entries) {
  5274. return;
  5275. }
  5276. OriginScope originScope = mOriginScope.Clone();
  5277. if (originScope.IsOrigin()) {
  5278. nsCString originSanitized(originScope.GetOrigin());
  5279. SanitizeOriginString(originSanitized);
  5280. originScope.SetOrigin(originSanitized);
  5281. } else if (originScope.IsPrefix()) {
  5282. nsCString prefixSanitized(originScope.GetPrefix());
  5283. SanitizeOriginString(prefixSanitized);
  5284. originScope.SetPrefix(prefixSanitized);
  5285. }
  5286. bool hasMore;
  5287. while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
  5288. nsCOMPtr<nsISupports> entry;
  5289. rv = entries->GetNext(getter_AddRefs(entry));
  5290. if (NS_WARN_IF(NS_FAILED(rv))) {
  5291. return;
  5292. }
  5293. nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
  5294. MOZ_ASSERT(file);
  5295. bool isDirectory;
  5296. rv = file->IsDirectory(&isDirectory);
  5297. if (NS_WARN_IF(NS_FAILED(rv))) {
  5298. return;
  5299. }
  5300. nsString leafName;
  5301. rv = file->GetLeafName(leafName);
  5302. if (NS_WARN_IF(NS_FAILED(rv))) {
  5303. return;
  5304. }
  5305. if (!isDirectory) {
  5306. if (!leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
  5307. QM_WARNING("Something (%s) in the repository that doesn't belong!",
  5308. NS_ConvertUTF16toUTF8(leafName).get());
  5309. }
  5310. continue;
  5311. }
  5312. // Skip the origin directory if it doesn't match the pattern.
  5313. if (!originScope.MatchesOrigin(OriginScope::FromOrigin(
  5314. NS_ConvertUTF16toUTF8(leafName)))) {
  5315. continue;
  5316. }
  5317. bool persistent = aPersistenceType == PERSISTENCE_TYPE_PERSISTENT;
  5318. int64_t timestamp;
  5319. nsCString suffix;
  5320. nsCString group;
  5321. nsCString origin;
  5322. bool isApp;
  5323. rv = aQuotaManager->GetDirectoryMetadata2WithRestore(file,
  5324. persistent,
  5325. &timestamp,
  5326. suffix,
  5327. group,
  5328. origin,
  5329. &isApp);
  5330. if (NS_WARN_IF(NS_FAILED(rv))) {
  5331. return;
  5332. }
  5333. for (uint32_t index = 0; index < 10; index++) {
  5334. // We can't guarantee that this will always succeed on Windows...
  5335. if (NS_SUCCEEDED((rv = file->Remove(true)))) {
  5336. break;
  5337. }
  5338. NS_WARNING("Failed to remove directory, retrying after a short delay.");
  5339. PR_Sleep(PR_MillisecondsToInterval(200));
  5340. }
  5341. if (NS_FAILED(rv)) {
  5342. NS_WARNING("Failed to remove directory, giving up!");
  5343. }
  5344. if (aPersistenceType != PERSISTENCE_TYPE_PERSISTENT) {
  5345. aQuotaManager->RemoveQuotaForOrigin(aPersistenceType, group, origin);
  5346. }
  5347. aQuotaManager->OriginClearCompleted(aPersistenceType, origin, isApp);
  5348. }
  5349. }
  5350. nsresult
  5351. OriginClearOp::DoDirectoryWork(QuotaManager* aQuotaManager)
  5352. {
  5353. AssertIsOnIOThread();
  5354. PROFILER_LABEL("Quota", "OriginClearOp::DoDirectoryWork",
  5355. js::ProfileEntry::Category::OTHER);
  5356. if (mPersistenceType.IsNull()) {
  5357. for (const PersistenceType type : kAllPersistenceTypes) {
  5358. DeleteFiles(aQuotaManager, type);
  5359. }
  5360. } else {
  5361. DeleteFiles(aQuotaManager, mPersistenceType.Value());
  5362. }
  5363. return NS_OK;
  5364. }
  5365. void
  5366. OriginClearOp::GetResponse(RequestResponse& aResponse)
  5367. {
  5368. AssertIsOnOwningThread();
  5369. if (mMultiple) {
  5370. aResponse = ClearOriginsResponse();
  5371. } else {
  5372. aResponse = ClearOriginResponse();
  5373. }
  5374. }
  5375. nsresult
  5376. StorageDirectoryHelper::AddOriginDirectory(nsIFile* aDirectory,
  5377. OriginProps** aOriginProps)
  5378. {
  5379. AssertIsOnIOThread();
  5380. MOZ_ASSERT(aDirectory);
  5381. OriginProps* originProps;
  5382. nsString leafName;
  5383. nsresult rv = aDirectory->GetLeafName(leafName);
  5384. if (NS_WARN_IF(NS_FAILED(rv))) {
  5385. return rv;
  5386. }
  5387. if (leafName.EqualsLiteral(kChromeOrigin)) {
  5388. originProps = mOriginProps.AppendElement();
  5389. originProps->mDirectory = aDirectory;
  5390. originProps->mSpec = kChromeOrigin;
  5391. originProps->mType = OriginProps::eChrome;
  5392. } else {
  5393. nsCString spec;
  5394. PrincipalOriginAttributes attrs;
  5395. bool result = OriginParser::ParseOrigin(NS_ConvertUTF16toUTF8(leafName),
  5396. spec, &attrs);
  5397. if (NS_WARN_IF(!result)) {
  5398. return NS_ERROR_FAILURE;
  5399. }
  5400. originProps = mOriginProps.AppendElement();
  5401. originProps->mDirectory = aDirectory;
  5402. originProps->mSpec = spec;
  5403. originProps->mAttrs = attrs;
  5404. originProps->mType = OriginProps::eContent;
  5405. }
  5406. if (aOriginProps) {
  5407. *aOriginProps = originProps;
  5408. }
  5409. return NS_OK;
  5410. }
  5411. nsresult
  5412. StorageDirectoryHelper::ProcessOriginDirectories()
  5413. {
  5414. AssertIsOnIOThread();
  5415. MOZ_ASSERT(!mOriginProps.IsEmpty());
  5416. MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(this));
  5417. {
  5418. mozilla::MutexAutoLock autolock(mMutex);
  5419. while (mWaiting) {
  5420. mCondVar.Wait();
  5421. }
  5422. }
  5423. if (NS_WARN_IF(NS_FAILED(mMainThreadResultCode))) {
  5424. return mMainThreadResultCode;
  5425. }
  5426. // Verify that the bounce to the main thread didn't start the shutdown
  5427. // sequence.
  5428. if (NS_WARN_IF(QuotaManager::IsShuttingDown())) {
  5429. return NS_ERROR_FAILURE;
  5430. }
  5431. nsresult rv = DoProcessOriginDirectories();
  5432. if (NS_WARN_IF(NS_FAILED(rv))) {
  5433. return rv;
  5434. }
  5435. return NS_OK;
  5436. }
  5437. nsresult
  5438. StorageDirectoryHelper::RunOnMainThread()
  5439. {
  5440. MOZ_ASSERT(NS_IsMainThread());
  5441. MOZ_ASSERT(!mOriginProps.IsEmpty());
  5442. nsresult rv;
  5443. nsCOMPtr<nsIScriptSecurityManager> secMan =
  5444. do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
  5445. if (NS_WARN_IF(NS_FAILED(rv))) {
  5446. return rv;
  5447. }
  5448. for (uint32_t count = mOriginProps.Length(), index = 0;
  5449. index < count;
  5450. index++) {
  5451. OriginProps& originProps = mOriginProps[index];
  5452. switch (originProps.mType) {
  5453. case OriginProps::eChrome: {
  5454. QuotaManager::GetInfoForChrome(&originProps.mSuffix,
  5455. &originProps.mGroup,
  5456. &originProps.mOrigin,
  5457. &originProps.mIsApp);
  5458. break;
  5459. }
  5460. case OriginProps::eContent: {
  5461. nsCOMPtr<nsIURI> uri;
  5462. rv = NS_NewURI(getter_AddRefs(uri), originProps.mSpec);
  5463. if (NS_WARN_IF(NS_FAILED(rv))) {
  5464. return rv;
  5465. }
  5466. nsCOMPtr<nsIPrincipal> principal =
  5467. BasePrincipal::CreateCodebasePrincipal(uri, originProps.mAttrs);
  5468. if (NS_WARN_IF(!principal)) {
  5469. return NS_ERROR_FAILURE;
  5470. }
  5471. rv = QuotaManager::GetInfoFromPrincipal(principal,
  5472. &originProps.mSuffix,
  5473. &originProps.mGroup,
  5474. &originProps.mOrigin,
  5475. &originProps.mIsApp);
  5476. if (NS_WARN_IF(NS_FAILED(rv))) {
  5477. return rv;
  5478. }
  5479. break;
  5480. }
  5481. default:
  5482. MOZ_CRASH("Bad type!");
  5483. }
  5484. }
  5485. return NS_OK;
  5486. }
  5487. NS_IMETHODIMP
  5488. StorageDirectoryHelper::Run()
  5489. {
  5490. MOZ_ASSERT(NS_IsMainThread());
  5491. nsresult rv = RunOnMainThread();
  5492. if (NS_WARN_IF(NS_FAILED(rv))) {
  5493. mMainThreadResultCode = rv;
  5494. }
  5495. MutexAutoLock lock(mMutex);
  5496. MOZ_ASSERT(mWaiting);
  5497. mWaiting = false;
  5498. mCondVar.Notify();
  5499. return NS_OK;
  5500. }
  5501. // static
  5502. bool
  5503. OriginParser::ParseOrigin(const nsACString& aOrigin,
  5504. nsCString& aSpec,
  5505. PrincipalOriginAttributes* aAttrs)
  5506. {
  5507. MOZ_ASSERT(!aOrigin.IsEmpty());
  5508. MOZ_ASSERT(aAttrs);
  5509. PrincipalOriginAttributes originAttributes;
  5510. nsCString originNoSuffix;
  5511. bool ok = originAttributes.PopulateFromOrigin(aOrigin, originNoSuffix);
  5512. if (!ok) {
  5513. return false;
  5514. }
  5515. OriginParser parser(originNoSuffix, originAttributes);
  5516. return parser.Parse(aSpec, aAttrs);
  5517. }
  5518. bool
  5519. OriginParser::Parse(nsACString& aSpec, PrincipalOriginAttributes* aAttrs)
  5520. {
  5521. MOZ_ASSERT(aAttrs);
  5522. while (mTokenizer.hasMoreTokens()) {
  5523. const nsDependentCSubstring& token = mTokenizer.nextToken();
  5524. HandleToken(token);
  5525. if (mError) {
  5526. break;
  5527. }
  5528. if (!mHandledTokens.IsEmpty()) {
  5529. mHandledTokens.Append(NS_LITERAL_CSTRING(", "));
  5530. }
  5531. mHandledTokens.Append('\'');
  5532. mHandledTokens.Append(token);
  5533. mHandledTokens.Append('\'');
  5534. }
  5535. if (!mError && mTokenizer.separatorAfterCurrentToken()) {
  5536. HandleTrailingSeparator();
  5537. }
  5538. if (mError) {
  5539. QM_WARNING("Origin '%s' failed to parse, handled tokens: %s", mOrigin.get(),
  5540. mHandledTokens.get());
  5541. return false;
  5542. }
  5543. MOZ_ASSERT(mState == eComplete || mState == eHandledTrailingSeparator);
  5544. if (mAppId == kNoAppId) {
  5545. *aAttrs = mOriginAttributes;
  5546. } else {
  5547. MOZ_ASSERT(mOriginAttributes.mAppId == kNoAppId);
  5548. *aAttrs = PrincipalOriginAttributes(mAppId, mInIsolatedMozBrowser);
  5549. }
  5550. nsAutoCString spec(mSchema);
  5551. if (mSchemaType == eFile) {
  5552. spec.AppendLiteral("://");
  5553. for (uint32_t count = mPathnameComponents.Length(), index = 0;
  5554. index < count;
  5555. index++) {
  5556. spec.Append('/');
  5557. spec.Append(mPathnameComponents[index]);
  5558. }
  5559. aSpec = spec;
  5560. return true;
  5561. }
  5562. if (mSchemaType == eAbout) {
  5563. spec.Append(':');
  5564. } else {
  5565. spec.AppendLiteral("://");
  5566. }
  5567. spec.Append(mHost);
  5568. if (!mPort.IsNull()) {
  5569. spec.Append(':');
  5570. spec.AppendInt(mPort.Value());
  5571. }
  5572. aSpec = spec;
  5573. return true;
  5574. }
  5575. void
  5576. OriginParser::HandleSchema(const nsDependentCSubstring& aToken)
  5577. {
  5578. MOZ_ASSERT(!aToken.IsEmpty());
  5579. MOZ_ASSERT(mState == eExpectingAppIdOrSchema || mState == eExpectingSchema);
  5580. bool isAbout = false;
  5581. bool isFile = false;
  5582. if (aToken.EqualsLiteral("http") ||
  5583. aToken.EqualsLiteral("https") ||
  5584. (isAbout = aToken.EqualsLiteral("about") ||
  5585. aToken.EqualsLiteral("moz-safe-about")) ||
  5586. aToken.EqualsLiteral("indexeddb") ||
  5587. (isFile = aToken.EqualsLiteral("file")) ||
  5588. aToken.EqualsLiteral("app") ||
  5589. aToken.EqualsLiteral("resource")) {
  5590. mSchema = aToken;
  5591. if (isAbout) {
  5592. mSchemaType = eAbout;
  5593. mState = eExpectingHost;
  5594. } else {
  5595. if (isFile) {
  5596. mSchemaType = eFile;
  5597. }
  5598. mState = eExpectingEmptyToken1;
  5599. }
  5600. return;
  5601. }
  5602. QM_WARNING("'%s' is not a valid schema!", nsCString(aToken).get());
  5603. mError = true;
  5604. }
  5605. void
  5606. OriginParser::HandlePathnameComponent(const nsDependentCSubstring& aToken)
  5607. {
  5608. MOZ_ASSERT(!aToken.IsEmpty());
  5609. MOZ_ASSERT(mState == eExpectingEmptyTokenOrDriveLetterOrPathnameComponent ||
  5610. mState == eExpectingEmptyTokenOrPathnameComponent);
  5611. MOZ_ASSERT(mSchemaType == eFile);
  5612. mPathnameComponents.AppendElement(aToken);
  5613. mState = mTokenizer.hasMoreTokens() ? eExpectingEmptyTokenOrPathnameComponent
  5614. : eComplete;
  5615. }
  5616. void
  5617. OriginParser::HandleToken(const nsDependentCSubstring& aToken)
  5618. {
  5619. switch (mState) {
  5620. case eExpectingAppIdOrSchema: {
  5621. if (aToken.IsEmpty()) {
  5622. QM_WARNING("Expected an app id or schema (not an empty string)!");
  5623. mError = true;
  5624. return;
  5625. }
  5626. if (NS_IsAsciiDigit(aToken.First())) {
  5627. // nsDependentCSubstring doesn't provice ToInteger()
  5628. nsCString token(aToken);
  5629. nsresult rv;
  5630. uint32_t appId = token.ToInteger(&rv);
  5631. if (NS_SUCCEEDED(rv)) {
  5632. mAppId = appId;
  5633. mState = eExpectingInMozBrowser;
  5634. return;
  5635. }
  5636. }
  5637. HandleSchema(aToken);
  5638. return;
  5639. }
  5640. case eExpectingInMozBrowser: {
  5641. if (aToken.Length() != 1) {
  5642. QM_WARNING("'%d' is not a valid length for the inMozBrowser flag!",
  5643. aToken.Length());
  5644. mError = true;
  5645. return;
  5646. }
  5647. if (aToken.First() == 't') {
  5648. mInIsolatedMozBrowser = true;
  5649. } else if (aToken.First() == 'f') {
  5650. mInIsolatedMozBrowser = false;
  5651. } else {
  5652. QM_WARNING("'%s' is not a valid value for the inMozBrowser flag!",
  5653. nsCString(aToken).get());
  5654. mError = true;
  5655. return;
  5656. }
  5657. mState = eExpectingSchema;
  5658. return;
  5659. }
  5660. case eExpectingSchema: {
  5661. if (aToken.IsEmpty()) {
  5662. QM_WARNING("Expected a schema (not an empty string)!");
  5663. mError = true;
  5664. return;
  5665. }
  5666. HandleSchema(aToken);
  5667. return;
  5668. }
  5669. case eExpectingEmptyToken1: {
  5670. if (!aToken.IsEmpty()) {
  5671. QM_WARNING("Expected the first empty token!");
  5672. mError = true;
  5673. return;
  5674. }
  5675. mState = eExpectingEmptyToken2;
  5676. return;
  5677. }
  5678. case eExpectingEmptyToken2: {
  5679. if (!aToken.IsEmpty()) {
  5680. QM_WARNING("Expected the second empty token!");
  5681. mError = true;
  5682. return;
  5683. }
  5684. if (mSchemaType == eFile) {
  5685. mState = eExpectingEmptyToken3;
  5686. } else {
  5687. mState = eExpectingHost;
  5688. }
  5689. return;
  5690. }
  5691. case eExpectingEmptyToken3: {
  5692. MOZ_ASSERT(mSchemaType == eFile);
  5693. if (!aToken.IsEmpty()) {
  5694. QM_WARNING("Expected the third empty token!");
  5695. mError = true;
  5696. return;
  5697. }
  5698. mState = mTokenizer.hasMoreTokens()
  5699. ? eExpectingEmptyTokenOrDriveLetterOrPathnameComponent
  5700. : eComplete;
  5701. return;
  5702. }
  5703. case eExpectingHost: {
  5704. if (aToken.IsEmpty()) {
  5705. QM_WARNING("Expected a host (not an empty string)!");
  5706. mError = true;
  5707. return;
  5708. }
  5709. mHost = aToken;
  5710. mState = mTokenizer.hasMoreTokens() ? eExpectingPort : eComplete;
  5711. return;
  5712. }
  5713. case eExpectingPort: {
  5714. MOZ_ASSERT(mSchemaType == eNone);
  5715. if (aToken.IsEmpty()) {
  5716. QM_WARNING("Expected a port (not an empty string)!");
  5717. mError = true;
  5718. return;
  5719. }
  5720. // nsDependentCSubstring doesn't provice ToInteger()
  5721. nsCString token(aToken);
  5722. nsresult rv;
  5723. uint32_t port = token.ToInteger(&rv);
  5724. if (NS_SUCCEEDED(rv)) {
  5725. mPort.SetValue() = port;
  5726. } else {
  5727. QM_WARNING("'%s' is not a valid port number!", token.get());
  5728. mError = true;
  5729. return;
  5730. }
  5731. mState = eComplete;
  5732. return;
  5733. }
  5734. case eExpectingEmptyTokenOrDriveLetterOrPathnameComponent: {
  5735. MOZ_ASSERT(mSchemaType == eFile);
  5736. if (aToken.IsEmpty()) {
  5737. mPathnameComponents.AppendElement(EmptyCString());
  5738. mState =
  5739. mTokenizer.hasMoreTokens() ? eExpectingEmptyTokenOrPathnameComponent
  5740. : eComplete;
  5741. return;
  5742. }
  5743. if (aToken.Length() == 1 && NS_IsAsciiAlpha(aToken.First())) {
  5744. mMaybeDriveLetter = true;
  5745. mPathnameComponents.AppendElement(aToken);
  5746. mState =
  5747. mTokenizer.hasMoreTokens() ? eExpectingEmptyTokenOrPathnameComponent
  5748. : eComplete;
  5749. return;
  5750. }
  5751. HandlePathnameComponent(aToken);
  5752. return;
  5753. }
  5754. case eExpectingEmptyTokenOrPathnameComponent: {
  5755. MOZ_ASSERT(mSchemaType == eFile);
  5756. if (aToken.IsEmpty()) {
  5757. if (mMaybeDriveLetter) {
  5758. MOZ_ASSERT(mPathnameComponents.Length() == 1);
  5759. nsCString& pathnameComponent = mPathnameComponents[0];
  5760. pathnameComponent.Append(':');
  5761. mMaybeDriveLetter = false;
  5762. } else {
  5763. mPathnameComponents.AppendElement(EmptyCString());
  5764. }
  5765. mState =
  5766. mTokenizer.hasMoreTokens() ? eExpectingEmptyTokenOrPathnameComponent
  5767. : eComplete;
  5768. return;
  5769. }
  5770. HandlePathnameComponent(aToken);
  5771. return;
  5772. }
  5773. default:
  5774. MOZ_CRASH("Should never get here!");
  5775. }
  5776. }
  5777. void
  5778. OriginParser::HandleTrailingSeparator()
  5779. {
  5780. MOZ_ASSERT(mState == eComplete);
  5781. MOZ_ASSERT(mSchemaType == eFile);
  5782. mPathnameComponents.AppendElement(EmptyCString());
  5783. mState = eHandledTrailingSeparator;
  5784. }
  5785. nsresult
  5786. CreateOrUpgradeDirectoryMetadataHelper::CreateOrUpgradeMetadataFiles()
  5787. {
  5788. AssertIsOnIOThread();
  5789. bool exists;
  5790. nsresult rv = mDirectory->Exists(&exists);
  5791. if (NS_WARN_IF(NS_FAILED(rv))) {
  5792. return rv;
  5793. }
  5794. if (!exists) {
  5795. return NS_OK;
  5796. }
  5797. nsCOMPtr<nsISimpleEnumerator> entries;
  5798. rv = mDirectory->GetDirectoryEntries(getter_AddRefs(entries));
  5799. if (NS_WARN_IF(NS_FAILED(rv))) {
  5800. return rv;
  5801. }
  5802. bool hasMore;
  5803. while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
  5804. nsCOMPtr<nsISupports> entry;
  5805. rv = entries->GetNext(getter_AddRefs(entry));
  5806. if (NS_WARN_IF(NS_FAILED(rv))) {
  5807. return rv;
  5808. }
  5809. nsCOMPtr<nsIFile> originDir = do_QueryInterface(entry);
  5810. MOZ_ASSERT(originDir);
  5811. nsString leafName;
  5812. rv = originDir->GetLeafName(leafName);
  5813. if (NS_WARN_IF(NS_FAILED(rv))) {
  5814. return rv;
  5815. }
  5816. bool isDirectory;
  5817. rv = originDir->IsDirectory(&isDirectory);
  5818. if (NS_WARN_IF(NS_FAILED(rv))) {
  5819. return rv;
  5820. }
  5821. if (isDirectory) {
  5822. if (leafName.EqualsLiteral("moz-safe-about+++home")) {
  5823. // This directory was accidentally created by a buggy nightly and can
  5824. // be safely removed.
  5825. QM_WARNING("Deleting accidental moz-safe-about+++home directory!");
  5826. rv = originDir->Remove(/* aRecursive */ true);
  5827. if (NS_WARN_IF(NS_FAILED(rv))) {
  5828. return rv;
  5829. }
  5830. continue;
  5831. }
  5832. } else {
  5833. if (!leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
  5834. QM_WARNING("Something (%s) in the storage directory that doesn't belong!",
  5835. NS_ConvertUTF16toUTF8(leafName).get());
  5836. }
  5837. continue;
  5838. }
  5839. if (mPersistent) {
  5840. rv = MaybeUpgradeOriginDirectory(originDir);
  5841. if (NS_WARN_IF(NS_FAILED(rv))) {
  5842. return rv;
  5843. }
  5844. }
  5845. OriginProps* originProps;
  5846. rv = AddOriginDirectory(originDir, &originProps);
  5847. if (NS_WARN_IF(NS_FAILED(rv))) {
  5848. return rv;
  5849. }
  5850. if (!mPersistent) {
  5851. int64_t timestamp;
  5852. nsCString group;
  5853. nsCString origin;
  5854. bool hasIsApp;
  5855. rv = GetDirectoryMetadata(originDir,
  5856. &timestamp,
  5857. group,
  5858. origin,
  5859. &hasIsApp);
  5860. if (NS_FAILED(rv)) {
  5861. timestamp = INT64_MIN;
  5862. rv = GetLastModifiedTime(originDir, &timestamp);
  5863. if (NS_WARN_IF(NS_FAILED(rv))) {
  5864. return rv;
  5865. }
  5866. originProps->mTimestamp = timestamp;
  5867. originProps->mNeedsRestore = true;
  5868. } else if (hasIsApp) {
  5869. originProps->mIgnore = true;
  5870. }
  5871. }
  5872. else if (!QuotaManager::IsOriginInternal(originProps->mSpec)) {
  5873. int64_t timestamp = INT64_MIN;
  5874. rv = GetLastModifiedTime(originDir, &timestamp);
  5875. if (NS_WARN_IF(NS_FAILED(rv))) {
  5876. return rv;
  5877. }
  5878. originProps->mTimestamp = timestamp;
  5879. }
  5880. }
  5881. if (mOriginProps.IsEmpty()) {
  5882. return NS_OK;
  5883. }
  5884. rv = ProcessOriginDirectories();
  5885. if (NS_WARN_IF(NS_FAILED(rv))) {
  5886. return rv;
  5887. }
  5888. return NS_OK;
  5889. }
  5890. nsresult
  5891. CreateOrUpgradeDirectoryMetadataHelper::MaybeUpgradeOriginDirectory(
  5892. nsIFile* aDirectory)
  5893. {
  5894. AssertIsOnIOThread();
  5895. MOZ_ASSERT(aDirectory);
  5896. nsCOMPtr<nsIFile> metadataFile;
  5897. nsresult rv = aDirectory->Clone(getter_AddRefs(metadataFile));
  5898. if (NS_WARN_IF(NS_FAILED(rv))) {
  5899. return rv;
  5900. }
  5901. rv = metadataFile->Append(NS_LITERAL_STRING(METADATA_FILE_NAME));
  5902. if (NS_WARN_IF(NS_FAILED(rv))) {
  5903. return rv;
  5904. }
  5905. bool exists;
  5906. rv = metadataFile->Exists(&exists);
  5907. if (NS_WARN_IF(NS_FAILED(rv))) {
  5908. return rv;
  5909. }
  5910. if (!exists) {
  5911. // Directory structure upgrade needed.
  5912. // Move all files to IDB specific directory.
  5913. nsString idbDirectoryName;
  5914. rv = Client::TypeToText(Client::IDB, idbDirectoryName);
  5915. if (NS_WARN_IF(NS_FAILED(rv))) {
  5916. return rv;
  5917. }
  5918. nsCOMPtr<nsIFile> idbDirectory;
  5919. rv = aDirectory->Clone(getter_AddRefs(idbDirectory));
  5920. if (NS_WARN_IF(NS_FAILED(rv))) {
  5921. return rv;
  5922. }
  5923. rv = idbDirectory->Append(idbDirectoryName);
  5924. if (NS_WARN_IF(NS_FAILED(rv))) {
  5925. return rv;
  5926. }
  5927. rv = idbDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
  5928. if (rv == NS_ERROR_FILE_ALREADY_EXISTS) {
  5929. NS_WARNING("IDB directory already exists!");
  5930. bool isDirectory;
  5931. rv = idbDirectory->IsDirectory(&isDirectory);
  5932. if (NS_WARN_IF(NS_FAILED(rv))) {
  5933. return rv;
  5934. }
  5935. if (NS_WARN_IF(!isDirectory)) {
  5936. return NS_ERROR_UNEXPECTED;
  5937. }
  5938. }
  5939. else {
  5940. if (NS_WARN_IF(NS_FAILED(rv))) {
  5941. return rv;
  5942. }
  5943. }
  5944. nsCOMPtr<nsISimpleEnumerator> entries;
  5945. rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries));
  5946. if (NS_WARN_IF(NS_FAILED(rv))) {
  5947. return rv;
  5948. }
  5949. bool hasMore;
  5950. while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
  5951. nsCOMPtr<nsISupports> entry;
  5952. rv = entries->GetNext(getter_AddRefs(entry));
  5953. if (NS_WARN_IF(NS_FAILED(rv))) {
  5954. return rv;
  5955. }
  5956. nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
  5957. if (NS_WARN_IF(!file)) {
  5958. return rv;
  5959. }
  5960. nsString leafName;
  5961. rv = file->GetLeafName(leafName);
  5962. if (NS_WARN_IF(NS_FAILED(rv))) {
  5963. return rv;
  5964. }
  5965. if (!leafName.Equals(idbDirectoryName)) {
  5966. rv = file->MoveTo(idbDirectory, EmptyString());
  5967. if (NS_WARN_IF(NS_FAILED(rv))) {
  5968. return rv;
  5969. }
  5970. }
  5971. }
  5972. rv = metadataFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
  5973. if (NS_WARN_IF(NS_FAILED(rv))) {
  5974. return rv;
  5975. }
  5976. }
  5977. return NS_OK;
  5978. }
  5979. nsresult
  5980. CreateOrUpgradeDirectoryMetadataHelper::GetDirectoryMetadata(
  5981. nsIFile* aDirectory,
  5982. int64_t* aTimestamp,
  5983. nsACString& aGroup,
  5984. nsACString& aOrigin,
  5985. bool* aHasIsApp)
  5986. {
  5987. AssertIsOnIOThread();
  5988. MOZ_ASSERT(aDirectory);
  5989. MOZ_ASSERT(aTimestamp);
  5990. MOZ_ASSERT(aHasIsApp);
  5991. MOZ_ASSERT(!mPersistent);
  5992. nsCOMPtr<nsIBinaryInputStream> binaryStream;
  5993. nsresult rv = GetBinaryInputStream(aDirectory,
  5994. NS_LITERAL_STRING(METADATA_FILE_NAME),
  5995. getter_AddRefs(binaryStream));
  5996. if (NS_WARN_IF(NS_FAILED(rv))) {
  5997. return rv;
  5998. }
  5999. uint64_t timestamp;
  6000. rv = binaryStream->Read64(&timestamp);
  6001. if (NS_WARN_IF(NS_FAILED(rv))) {
  6002. return rv;
  6003. }
  6004. nsCString group;
  6005. rv = binaryStream->ReadCString(group);
  6006. if (NS_WARN_IF(NS_FAILED(rv))) {
  6007. return rv;
  6008. }
  6009. nsCString origin;
  6010. rv = binaryStream->ReadCString(origin);
  6011. if (NS_WARN_IF(NS_FAILED(rv))) {
  6012. return rv;
  6013. }
  6014. bool dummyIsApp;
  6015. bool hasIsApp = NS_SUCCEEDED(binaryStream->ReadBoolean(&dummyIsApp));
  6016. *aTimestamp = timestamp;
  6017. aGroup = group;
  6018. aOrigin = origin;
  6019. *aHasIsApp = hasIsApp;
  6020. return NS_OK;
  6021. }
  6022. nsresult
  6023. CreateOrUpgradeDirectoryMetadataHelper::DoProcessOriginDirectories()
  6024. {
  6025. AssertIsOnIOThread();
  6026. nsresult rv;
  6027. nsCOMPtr<nsIFile> permanentStorageDir;
  6028. for (uint32_t count = mOriginProps.Length(), index = 0;
  6029. index < count;
  6030. index++) {
  6031. OriginProps& originProps = mOriginProps[index];
  6032. if (mPersistent) {
  6033. rv = CreateDirectoryMetadata(originProps.mDirectory,
  6034. originProps.mTimestamp,
  6035. originProps.mSuffix,
  6036. originProps.mGroup,
  6037. originProps.mOrigin,
  6038. originProps.mIsApp);
  6039. if (NS_WARN_IF(NS_FAILED(rv))) {
  6040. return rv;
  6041. }
  6042. // Move internal origins to new persistent storage.
  6043. if (QuotaManager::IsOriginInternal(originProps.mSpec)) {
  6044. if (!permanentStorageDir) {
  6045. permanentStorageDir =
  6046. do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
  6047. if (NS_WARN_IF(NS_FAILED(rv))) {
  6048. return rv;
  6049. }
  6050. QuotaManager* quotaManager = QuotaManager::Get();
  6051. MOZ_ASSERT(quotaManager);
  6052. const nsString& permanentStoragePath =
  6053. quotaManager->GetStoragePath(PERSISTENCE_TYPE_PERSISTENT);
  6054. rv = permanentStorageDir->InitWithPath(permanentStoragePath);
  6055. if (NS_WARN_IF(NS_FAILED(rv))) {
  6056. return rv;
  6057. }
  6058. }
  6059. nsString leafName;
  6060. rv = originProps.mDirectory->GetLeafName(leafName);
  6061. if (NS_WARN_IF(NS_FAILED(rv))) {
  6062. return rv;
  6063. }
  6064. nsCOMPtr<nsIFile> newDirectory;
  6065. rv = permanentStorageDir->Clone(getter_AddRefs(newDirectory));
  6066. if (NS_WARN_IF(NS_FAILED(rv))) {
  6067. return rv;
  6068. }
  6069. rv = newDirectory->Append(leafName);
  6070. if (NS_WARN_IF(NS_FAILED(rv))) {
  6071. return rv;
  6072. }
  6073. bool exists;
  6074. rv = newDirectory->Exists(&exists);
  6075. if (NS_WARN_IF(NS_FAILED(rv))) {
  6076. return rv;
  6077. }
  6078. if (exists) {
  6079. QM_WARNING("Found %s in storage/persistent and storage/permanent !",
  6080. NS_ConvertUTF16toUTF8(leafName).get());
  6081. rv = originProps.mDirectory->Remove(/* recursive */ true);
  6082. } else {
  6083. rv = originProps.mDirectory->MoveTo(permanentStorageDir, EmptyString());
  6084. }
  6085. if (NS_WARN_IF(NS_FAILED(rv))) {
  6086. return rv;
  6087. }
  6088. }
  6089. } else if (originProps.mNeedsRestore) {
  6090. rv = CreateDirectoryMetadata(originProps.mDirectory,
  6091. originProps.mTimestamp,
  6092. originProps.mSuffix,
  6093. originProps.mGroup,
  6094. originProps.mOrigin,
  6095. originProps.mIsApp);
  6096. if (NS_WARN_IF(NS_FAILED(rv))) {
  6097. return rv;
  6098. }
  6099. } else if (!originProps.mIgnore) {
  6100. nsCOMPtr<nsIBinaryOutputStream> stream;
  6101. rv = GetBinaryOutputStream(originProps.mDirectory,
  6102. NS_LITERAL_STRING(METADATA_FILE_NAME),
  6103. kAppendFileFlag,
  6104. getter_AddRefs(stream));
  6105. if (NS_WARN_IF(NS_FAILED(rv))) {
  6106. return rv;
  6107. }
  6108. MOZ_ASSERT(stream);
  6109. rv = stream->WriteBoolean(originProps.mIsApp);
  6110. if (NS_WARN_IF(NS_FAILED(rv))) {
  6111. return rv;
  6112. }
  6113. }
  6114. }
  6115. return NS_OK;
  6116. }
  6117. nsresult
  6118. UpgradeDirectoryMetadataFrom1To2Helper::UpgradeMetadataFiles()
  6119. {
  6120. AssertIsOnIOThread();
  6121. bool exists;
  6122. nsresult rv = mDirectory->Exists(&exists);
  6123. if (NS_WARN_IF(NS_FAILED(rv))) {
  6124. return rv;
  6125. }
  6126. if (!exists) {
  6127. return NS_OK;
  6128. }
  6129. nsCOMPtr<nsISimpleEnumerator> entries;
  6130. rv = mDirectory->GetDirectoryEntries(getter_AddRefs(entries));
  6131. if (NS_WARN_IF(NS_FAILED(rv))) {
  6132. return rv;
  6133. }
  6134. bool hasMore;
  6135. while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
  6136. nsCOMPtr<nsISupports> entry;
  6137. rv = entries->GetNext(getter_AddRefs(entry));
  6138. if (NS_WARN_IF(NS_FAILED(rv))) {
  6139. return rv;
  6140. }
  6141. nsCOMPtr<nsIFile> originDir = do_QueryInterface(entry);
  6142. MOZ_ASSERT(originDir);
  6143. bool isDirectory;
  6144. rv = originDir->IsDirectory(&isDirectory);
  6145. if (NS_WARN_IF(NS_FAILED(rv))) {
  6146. return rv;
  6147. }
  6148. if (!isDirectory) {
  6149. nsString leafName;
  6150. rv = originDir->GetLeafName(leafName);
  6151. if (NS_WARN_IF(NS_FAILED(rv))) {
  6152. return rv;
  6153. }
  6154. if (!leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
  6155. QM_WARNING("Something (%s) in the storage directory that doesn't belong!",
  6156. NS_ConvertUTF16toUTF8(leafName).get());
  6157. }
  6158. continue;
  6159. }
  6160. OriginProps* originProps;
  6161. rv = AddOriginDirectory(originDir, &originProps);
  6162. if (NS_WARN_IF(NS_FAILED(rv))) {
  6163. return rv;
  6164. }
  6165. int64_t timestamp;
  6166. nsCString group;
  6167. nsCString origin;
  6168. bool isApp;
  6169. nsresult rv = GetDirectoryMetadata(originDir,
  6170. &timestamp,
  6171. group,
  6172. origin,
  6173. &isApp);
  6174. if (NS_FAILED(rv)) {
  6175. if (!mPersistent) {
  6176. rv = GetLastModifiedTime(originDir, &timestamp);
  6177. if (NS_WARN_IF(NS_FAILED(rv))) {
  6178. return rv;
  6179. }
  6180. originProps->mTimestamp = timestamp;
  6181. }
  6182. originProps->mNeedsRestore = true;
  6183. } else {
  6184. originProps->mTimestamp = timestamp;
  6185. }
  6186. }
  6187. if (mOriginProps.IsEmpty()) {
  6188. return NS_OK;
  6189. }
  6190. rv = ProcessOriginDirectories();
  6191. if (NS_WARN_IF(NS_FAILED(rv))) {
  6192. return rv;
  6193. }
  6194. return NS_OK;
  6195. }
  6196. nsresult
  6197. UpgradeDirectoryMetadataFrom1To2Helper::GetDirectoryMetadata(
  6198. nsIFile* aDirectory,
  6199. int64_t* aTimestamp,
  6200. nsACString& aGroup,
  6201. nsACString& aOrigin,
  6202. bool* aIsApp)
  6203. {
  6204. AssertIsOnIOThread();
  6205. MOZ_ASSERT(aDirectory);
  6206. MOZ_ASSERT(aTimestamp);
  6207. MOZ_ASSERT(aIsApp);
  6208. nsCOMPtr<nsIBinaryInputStream> binaryStream;
  6209. nsresult rv = GetBinaryInputStream(aDirectory,
  6210. NS_LITERAL_STRING(METADATA_FILE_NAME),
  6211. getter_AddRefs(binaryStream));
  6212. if (NS_WARN_IF(NS_FAILED(rv))) {
  6213. return rv;
  6214. }
  6215. uint64_t timestamp;
  6216. rv = binaryStream->Read64(&timestamp);
  6217. if (NS_WARN_IF(NS_FAILED(rv))) {
  6218. return rv;
  6219. }
  6220. nsCString group;
  6221. rv = binaryStream->ReadCString(group);
  6222. if (NS_WARN_IF(NS_FAILED(rv))) {
  6223. return rv;
  6224. }
  6225. nsCString origin;
  6226. rv = binaryStream->ReadCString(origin);
  6227. if (NS_WARN_IF(NS_FAILED(rv))) {
  6228. return rv;
  6229. }
  6230. bool isApp;
  6231. rv = binaryStream->ReadBoolean(&isApp);
  6232. if (NS_WARN_IF(NS_FAILED(rv))) {
  6233. return rv;
  6234. }
  6235. *aTimestamp = timestamp;
  6236. aGroup = group;
  6237. aOrigin = origin;
  6238. *aIsApp = isApp;
  6239. return NS_OK;
  6240. }
  6241. nsresult
  6242. UpgradeDirectoryMetadataFrom1To2Helper::DoProcessOriginDirectories()
  6243. {
  6244. AssertIsOnIOThread();
  6245. for (uint32_t count = mOriginProps.Length(), index = 0;
  6246. index < count;
  6247. index++) {
  6248. OriginProps& originProps = mOriginProps[index];
  6249. nsresult rv;
  6250. if (originProps.mNeedsRestore) {
  6251. rv = CreateDirectoryMetadata(originProps.mDirectory,
  6252. originProps.mTimestamp,
  6253. originProps.mSuffix,
  6254. originProps.mGroup,
  6255. originProps.mOrigin,
  6256. originProps.mIsApp);
  6257. if (NS_WARN_IF(NS_FAILED(rv))) {
  6258. return rv;
  6259. }
  6260. }
  6261. rv = CreateDirectoryMetadata2(originProps.mDirectory,
  6262. originProps.mTimestamp,
  6263. originProps.mSuffix,
  6264. originProps.mGroup,
  6265. originProps.mOrigin,
  6266. originProps.mIsApp);
  6267. if (NS_WARN_IF(NS_FAILED(rv))) {
  6268. return rv;
  6269. }
  6270. nsString oldName;
  6271. rv = originProps.mDirectory->GetLeafName(oldName);
  6272. if (NS_WARN_IF(NS_FAILED(rv))) {
  6273. return rv;
  6274. }
  6275. nsAutoCString originSanitized(originProps.mOrigin);
  6276. SanitizeOriginString(originSanitized);
  6277. NS_ConvertASCIItoUTF16 newName(originSanitized);
  6278. if (!oldName.Equals(newName)) {
  6279. rv = originProps.mDirectory->RenameTo(nullptr, newName);
  6280. if (NS_WARN_IF(NS_FAILED(rv))) {
  6281. return rv;
  6282. }
  6283. }
  6284. }
  6285. return NS_OK;
  6286. }
  6287. nsresult
  6288. RestoreDirectoryMetadata2Helper::RestoreMetadata2File()
  6289. {
  6290. AssertIsOnIOThread();
  6291. nsresult rv;
  6292. OriginProps* originProps;
  6293. rv = AddOriginDirectory(mDirectory, &originProps);
  6294. if (NS_WARN_IF(NS_FAILED(rv))) {
  6295. return rv;
  6296. }
  6297. if (!mPersistent) {
  6298. int64_t timestamp = INT64_MIN;
  6299. rv = GetLastModifiedTime(mDirectory, &timestamp);
  6300. if (NS_WARN_IF(NS_FAILED(rv))) {
  6301. return rv;
  6302. }
  6303. originProps->mTimestamp = timestamp;
  6304. }
  6305. rv = ProcessOriginDirectories();
  6306. if (NS_WARN_IF(NS_FAILED(rv))) {
  6307. return rv;
  6308. }
  6309. return NS_OK;
  6310. }
  6311. nsresult
  6312. RestoreDirectoryMetadata2Helper::DoProcessOriginDirectories()
  6313. {
  6314. AssertIsOnIOThread();
  6315. MOZ_ASSERT(mOriginProps.Length() == 1);
  6316. OriginProps& originProps = mOriginProps[0];
  6317. nsresult rv = CreateDirectoryMetadata2(originProps.mDirectory,
  6318. originProps.mTimestamp,
  6319. originProps.mSuffix,
  6320. originProps.mGroup,
  6321. originProps.mOrigin,
  6322. originProps.mIsApp);
  6323. if (NS_WARN_IF(NS_FAILED(rv))) {
  6324. return rv;
  6325. }
  6326. return NS_OK;
  6327. }
  6328. } // namespace quota
  6329. } // namespace dom
  6330. } // namespace mozilla