| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162 |
- /*-
- * Copyright (c) 2009-2012 Michihiro NAKAJIMA
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #include "archive_platform.h"
- #ifdef HAVE_SYS_TYPES_H
- #include <sys/types.h>
- #endif
- #ifdef HAVE_SYS_UTSNAME_H
- #include <sys/utsname.h>
- #endif
- #ifdef HAVE_ERRNO_H
- #include <errno.h>
- #endif
- #ifdef HAVE_LIMITS_H
- #include <limits.h>
- #endif
- #include <stdio.h>
- #include <stdarg.h>
- #ifdef HAVE_STDLIB_H
- #include <stdlib.h>
- #endif
- #include <time.h>
- #ifdef HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #ifdef HAVE_ZLIB_H
- #include <cm_zlib.h>
- #endif
- #include "archive.h"
- #include "archive_endian.h"
- #include "archive_entry.h"
- #include "archive_entry_locale.h"
- #include "archive_private.h"
- #include "archive_rb.h"
- #include "archive_write_private.h"
- #if defined(_WIN32) && !defined(__CYGWIN__)
- #define getuid() 0
- #define getgid() 0
- #endif
- /*#define DEBUG 1*/
- #ifdef DEBUG
- /* To compare to the ISO image file made by mkisofs. */
- #define COMPAT_MKISOFS 1
- #endif
- #define LOGICAL_BLOCK_BITS 11
- #define LOGICAL_BLOCK_SIZE 2048
- #define PATH_TABLE_BLOCK_SIZE 4096
- #define SYSTEM_AREA_BLOCK 16
- #define PRIMARY_VOLUME_DESCRIPTOR_BLOCK 1
- #define SUPPLEMENTARY_VOLUME_DESCRIPTOR_BLOCK 1
- #define BOOT_RECORD_DESCRIPTOR_BLOCK 1
- #define VOLUME_DESCRIPTOR_SET_TERMINATOR_BLOCK 1
- #define NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK 1
- #define RRIP_ER_BLOCK 1
- #define PADDING_BLOCK 150
- #define FD_1_2M_SIZE (1024 * 1200)
- #define FD_1_44M_SIZE (1024 * 1440)
- #define FD_2_88M_SIZE (1024 * 2880)
- #define MULTI_EXTENT_SIZE (ARCHIVE_LITERAL_LL(1) << 32) /* 4Gi bytes. */
- #define MAX_DEPTH 8
- #define RR_CE_SIZE 28 /* SUSP "CE" extension size */
- #define FILE_FLAG_EXISTENCE 0x01
- #define FILE_FLAG_DIRECTORY 0x02
- #define FILE_FLAG_ASSOCIATED 0x04
- #define FILE_FLAG_RECORD 0x08
- #define FILE_FLAG_PROTECTION 0x10
- #define FILE_FLAG_MULTI_EXTENT 0x80
- static const char rrip_identifier[] =
- "RRIP_1991A";
- static const char rrip_descriptor[] =
- "THE ROCK RIDGE INTERCHANGE PROTOCOL PROVIDES SUPPORT FOR "
- "POSIX FILE SYSTEM SEMANTICS";
- static const char rrip_source[] =
- "PLEASE CONTACT DISC PUBLISHER FOR SPECIFICATION SOURCE. "
- "SEE PUBLISHER IDENTIFIER IN PRIMARY VOLUME DESCRIPTOR FOR "
- "CONTACT INFORMATION.";
- #define RRIP_ER_ID_SIZE (sizeof(rrip_identifier)-1)
- #define RRIP_ER_DSC_SIZE (sizeof(rrip_descriptor)-1)
- #define RRIP_ER_SRC_SIZE (sizeof(rrip_source)-1)
- #define RRIP_ER_SIZE (8 + RRIP_ER_ID_SIZE + \
- RRIP_ER_DSC_SIZE + RRIP_ER_SRC_SIZE)
- static const unsigned char zisofs_magic[8] = {
- 0x37, 0xE4, 0x53, 0x96, 0xC9, 0xDB, 0xD6, 0x07
- };
- #define ZF_HEADER_SIZE 16 /* zisofs header size. */
- #define ZF_LOG2_BS 15 /* log2 block size; 32K bytes. */
- #define ZF_BLOCK_SIZE (1UL << ZF_LOG2_BS)
- /*
- * Manage extra records.
- */
- struct extr_rec {
- int location;
- int offset;
- unsigned char buf[LOGICAL_BLOCK_SIZE];
- struct extr_rec *next;
- };
- struct ctl_extr_rec {
- int use_extr;
- unsigned char *bp;
- struct isoent *isoent;
- unsigned char *ce_ptr;
- int cur_len;
- int dr_len;
- int limit;
- int extr_off;
- int extr_loc;
- };
- #define DR_SAFETY RR_CE_SIZE
- #define DR_LIMIT (254 - DR_SAFETY)
- /*
- * The relation of struct isofile and isoent and archive_entry.
- *
- * Primary volume tree --> struct isoent
- * |
- * v
- * struct isofile --> archive_entry
- * ^
- * |
- * Joliet volume tree --> struct isoent
- *
- * struct isoent has specific information for volume.
- */
- struct isofile {
- /* Used for managing struct isofile list. */
- struct isofile *allnext;
- struct isofile *datanext;
- /* Used for managing a hardlinked struct isofile list. */
- struct isofile *hlnext;
- struct isofile *hardlink_target;
- struct archive_entry *entry;
- /*
- * Used for making a directory tree.
- */
- struct archive_string parentdir;
- struct archive_string basename;
- struct archive_string basename_utf16;
- struct archive_string symlink;
- int dircnt; /* The number of elements of
- * its parent directory */
- /*
- * Used for a Directory Record.
- */
- struct content {
- int64_t offset_of_temp;
- int64_t size;
- int blocks;
- uint32_t location;
- /*
- * One extent equals one content.
- * If this entry has multi extent, `next' variable points
- * next content data.
- */
- struct content *next; /* next content */
- } content, *cur_content;
- int write_content;
- enum {
- NO = 0,
- BOOT_CATALOG,
- BOOT_IMAGE
- } boot;
- /*
- * Used for a zisofs.
- */
- struct {
- unsigned char header_size;
- unsigned char log2_bs;
- uint32_t uncompressed_size;
- } zisofs;
- };
- struct isoent {
- /* Keep `rbnode' at the first member of struct isoent. */
- struct archive_rb_node rbnode;
- struct isofile *file;
- struct isoent *parent;
- /* A list of children.(use chnext) */
- struct {
- struct isoent *first;
- struct isoent **last;
- int cnt;
- } children;
- struct archive_rb_tree rbtree;
- /* A list of sub directories.(use drnext) */
- struct {
- struct isoent *first;
- struct isoent **last;
- int cnt;
- } subdirs;
- /* A sorted list of sub directories. */
- struct isoent **children_sorted;
- /* Used for managing struct isoent list. */
- struct isoent *chnext;
- struct isoent *drnext;
- struct isoent *ptnext;
- /*
- * Used for making a Directory Record.
- */
- int dir_number;
- struct {
- int vd;
- int self;
- int parent;
- int normal;
- } dr_len;
- uint32_t dir_location;
- int dir_block;
- /*
- * Identifier:
- * on primary, ISO9660 file/directory name.
- * on joliet, UCS2 file/directory name.
- * ext_off : offset of identifier extension.
- * ext_len : length of identifier extension.
- * id_len : byte size of identifier.
- * on primary, this is ext_off + ext_len + version length.
- * on joliet, this is ext_off + ext_len.
- * mb_len : length of multibyte-character of identifier.
- * on primary, mb_len and id_len are always the same.
- * on joliet, mb_len and id_len are different.
- */
- char *identifier;
- int ext_off;
- int ext_len;
- int id_len;
- int mb_len;
- /*
- * Used for making a Rockridge extension.
- * This is a part of Directory Records.
- */
- struct isoent *rr_parent;
- struct isoent *rr_child;
- /* Extra Record.(which we call in this source file)
- * A maximum size of the Directory Record is 254.
- * so, if generated RRIP data of a file cannot into a Directory
- * Record because of its size, that surplus data relocate this
- * Extra Record.
- */
- struct {
- struct extr_rec *first;
- struct extr_rec **last;
- struct extr_rec *current;
- } extr_rec_list;
- signed int virtual:1;
- /* If set to one, this file type is a directory.
- * A convenience flag to be used as
- * "archive_entry_filetype(isoent->file->entry) == AE_IFDIR".
- */
- signed int dir:1;
- };
- struct hardlink {
- struct archive_rb_node rbnode;
- int nlink;
- struct {
- struct isofile *first;
- struct isofile **last;
- } file_list;
- };
- /*
- * ISO writer options
- */
- struct iso_option {
- /*
- * Usage : abstract-file=<value>
- * Type : string, max 37 bytes
- * Default: Not specified
- * COMPAT : mkisofs -abstract <value>
- *
- * Specifies Abstract Filename.
- * This file shall be described in the Root Directory
- * and containing a abstract statement.
- */
- unsigned int abstract_file:1;
- #define OPT_ABSTRACT_FILE_DEFAULT 0 /* Not specified */
- #define ABSTRACT_FILE_SIZE 37
- /*
- * Usage : application-id=<value>
- * Type : string, max 128 bytes
- * Default: Not specified
- * COMPAT : mkisofs -A/-appid <value>.
- *
- * Specifies Application Identifier.
- * If the first byte is set to '_'(5F), the remaining
- * bytes of this option shall specify an identifier
- * for a file containing the identification of the
- * application.
- * This file shall be described in the Root Directory.
- */
- unsigned int application_id:1;
- #define OPT_APPLICATION_ID_DEFAULT 0 /* Use default identifier */
- #define APPLICATION_IDENTIFIER_SIZE 128
- /*
- * Usage : !allow-vernum
- * Type : boolean
- * Default: Enabled
- * : Violates the ISO9660 standard if disable.
- * COMPAT: mkisofs -N
- *
- * Allow filenames to use version numbers.
- */
- unsigned int allow_vernum:1;
- #define OPT_ALLOW_VERNUM_DEFAULT 1 /* Enabled */
- /*
- * Usage : biblio-file=<value>
- * Type : string, max 37 bytes
- * Default: Not specified
- * COMPAT : mkisofs -biblio <value>
- *
- * Specifies Bibliographic Filename.
- * This file shall be described in the Root Directory
- * and containing bibliographic records.
- */
- unsigned int biblio_file:1;
- #define OPT_BIBLIO_FILE_DEFAULT 0 /* Not specified */
- #define BIBLIO_FILE_SIZE 37
- /*
- * Usage : boot=<value>
- * Type : string
- * Default: Not specified
- * COMPAT : mkisofs -b/-eltorito-boot <value>
- *
- * Specifies "El Torito" boot image file to make
- * a bootable CD.
- */
- unsigned int boot:1;
- #define OPT_BOOT_DEFAULT 0 /* Not specified */
- /*
- * Usage : boot-catalog=<value>
- * Type : string
- * Default: "boot.catalog"
- * COMPAT : mkisofs -c/-eltorito-catalog <value>
- *
- * Specifies a fullpath of El Torito boot catalog.
- */
- unsigned int boot_catalog:1;
- #define OPT_BOOT_CATALOG_DEFAULT 0 /* Not specified */
- /*
- * Usage : boot-info-table
- * Type : boolean
- * Default: Disabled
- * COMPAT : mkisofs -boot-info-table
- *
- * Modify the boot image file specified by `boot'
- * option; ISO writer stores boot file information
- * into the boot file in ISO image at offset 8
- * through offset 64.
- */
- unsigned int boot_info_table:1;
- #define OPT_BOOT_INFO_TABLE_DEFAULT 0 /* Disabled */
- /*
- * Usage : boot-load-seg=<value>
- * Type : hexadecimal
- * Default: Not specified
- * COMPAT : mkisofs -boot-load-seg <value>
- *
- * Specifies a load segment for boot image.
- * This is used with no-emulation mode.
- */
- unsigned int boot_load_seg:1;
- #define OPT_BOOT_LOAD_SEG_DEFAULT 0 /* Not specified */
- /*
- * Usage : boot-load-size=<value>
- * Type : decimal
- * Default: Not specified
- * COMPAT : mkisofs -boot-load-size <value>
- *
- * Specifies a sector count for boot image.
- * This is used with no-emulation mode.
- */
- unsigned int boot_load_size:1;
- #define OPT_BOOT_LOAD_SIZE_DEFAULT 0 /* Not specified */
- /*
- * Usage : boot-type=<boot-media-type>
- * : 'no-emulation' : 'no emulation' image
- * : 'fd' : floppy disk image
- * : 'hard-disk' : hard disk image
- * Type : string
- * Default: Auto detect
- * : We check a size of boot image;
- * : If the size is just 1.22M/1.44M/2.88M,
- * : we assume boot_type is 'fd';
- * : otherwise boot_type is 'no-emulation'.
- * COMPAT :
- * boot=no-emulation
- * mkisofs -no-emul-boot
- * boot=fd
- * This is a default on the mkisofs.
- * boot=hard-disk
- * mkisofs -hard-disk-boot
- *
- * Specifies a type of "El Torito" boot image.
- */
- unsigned int boot_type:2;
- #define OPT_BOOT_TYPE_AUTO 0 /* auto detect */
- #define OPT_BOOT_TYPE_NO_EMU 1 /* ``no emulation'' image */
- #define OPT_BOOT_TYPE_FD 2 /* floppy disk image */
- #define OPT_BOOT_TYPE_HARD_DISK 3 /* hard disk image */
- #define OPT_BOOT_TYPE_DEFAULT OPT_BOOT_TYPE_AUTO
- /*
- * Usage : compression-level=<value>
- * Type : decimal
- * Default: Not specified
- * COMPAT : NONE
- *
- * Specifies compression level for option zisofs=direct.
- */
- unsigned int compression_level:1;
- #define OPT_COMPRESSION_LEVEL_DEFAULT 0 /* Not specified */
- /*
- * Usage : copyright-file=<value>
- * Type : string, max 37 bytes
- * Default: Not specified
- * COMPAT : mkisofs -copyright <value>
- *
- * Specifies Copyright Filename.
- * This file shall be described in the Root Directory
- * and containing a copyright statement.
- */
- unsigned int copyright_file:1;
- #define OPT_COPYRIGHT_FILE_DEFAULT 0 /* Not specified */
- #define COPYRIGHT_FILE_SIZE 37
- /*
- * Usage : gid=<value>
- * Type : decimal
- * Default: Not specified
- * COMPAT : mkisofs -gid <value>
- *
- * Specifies a group id to rewrite the group id of all files.
- */
- unsigned int gid:1;
- #define OPT_GID_DEFAULT 0 /* Not specified */
- /*
- * Usage : iso-level=[1234]
- * Type : decimal
- * Default: 1
- * COMPAT : mkisofs -iso-level <value>
- *
- * Specifies ISO9600 Level.
- * Level 1: [DEFAULT]
- * - limits each file size less than 4Gi bytes;
- * - a File Name shall not contain more than eight
- * d-characters or eight d1-characters;
- * - a File Name Extension shall not contain more than
- * three d-characters or three d1-characters;
- * - a Directory Identifier shall not contain more
- * than eight d-characters or eight d1-characters.
- * Level 2:
- * - limits each file size less than 4Giga bytes;
- * - a File Name shall not contain more than thirty
- * d-characters or thirty d1-characters;
- * - a File Name Extension shall not contain more than
- * thirty d-characters or thirty d1-characters;
- * - a Directory Identifier shall not contain more
- * than thirty-one d-characters or thirty-one
- * d1-characters.
- * Level 3:
- * - no limit of file size; use multi extent.
- * Level 4:
- * - this level 4 simulates mkisofs option
- * '-iso-level 4';
- * - crate a enhanced volume as mkisofs doing;
- * - allow a File Name to have leading dot;
- * - allow a File Name to have all ASCII letters;
- * - allow a File Name to have multiple dots;
- * - allow more then 8 depths of directory trees;
- * - disable a version number to a File Name;
- * - disable a forced period to the tail of a File Name;
- * - the maximum length of files and directories is raised to 193.
- * if rockridge option is disabled, raised to 207.
- */
- unsigned int iso_level:3;
- #define OPT_ISO_LEVEL_DEFAULT 1 /* ISO Level 1 */
- /*
- * Usage : joliet[=long]
- * : !joliet
- * : Do not generate Joliet Volume and Records.
- * : joliet [DEFAULT]
- * : Generates Joliet Volume and Directory Records.
- * : [COMPAT: mkisofs -J/-joliet]
- * : joliet=long
- * : The joliet filenames are up to 103 Unicode
- * : characters.
- * : This option breaks the Joliet specification.
- * : [COMPAT: mkisofs -J -joliet-long]
- * Type : boolean/string
- * Default: Enabled
- * COMPAT : mkisofs -J / -joliet-long
- *
- * Generates Joliet Volume and Directory Records.
- */
- unsigned int joliet:2;
- #define OPT_JOLIET_DISABLE 0 /* Not generate Joliet Records. */
- #define OPT_JOLIET_ENABLE 1 /* Generate Joliet Records. */
- #define OPT_JOLIET_LONGNAME 2 /* Use long joliet filenames.*/
- #define OPT_JOLIET_DEFAULT OPT_JOLIET_ENABLE
- /*
- * Usage : !limit-depth
- * Type : boolean
- * Default: Enabled
- * : Violates the ISO9660 standard if disable.
- * COMPAT : mkisofs -D/-disable-deep-relocation
- *
- * The number of levels in hierarchy cannot exceed eight.
- */
- unsigned int limit_depth:1;
- #define OPT_LIMIT_DEPTH_DEFAULT 1 /* Enabled */
- /*
- * Usage : !limit-dirs
- * Type : boolean
- * Default: Enabled
- * : Violates the ISO9660 standard if disable.
- * COMPAT : mkisofs -no-limit-pathtables
- *
- * Limits the number of directories less than 65536 due
- * to the size of the Parent Directory Number of Path
- * Table.
- */
- unsigned int limit_dirs:1;
- #define OPT_LIMIT_DIRS_DEFAULT 1 /* Enabled */
- /*
- * Usage : !pad
- * Type : boolean
- * Default: Enabled
- * COMPAT : -pad/-no-pad
- *
- * Pads the end of the ISO image by null of 300Ki bytes.
- */
- unsigned int pad:1;
- #define OPT_PAD_DEFAULT 1 /* Enabled */
- /*
- * Usage : publisher=<value>
- * Type : string, max 128 bytes
- * Default: Not specified
- * COMPAT : mkisofs -publisher <value>
- *
- * Specifies Publisher Identifier.
- * If the first byte is set to '_'(5F), the remaining
- * bytes of this option shall specify an identifier
- * for a file containing the identification of the user.
- * This file shall be described in the Root Directory.
- */
- unsigned int publisher:1;
- #define OPT_PUBLISHER_DEFAULT 0 /* Not specified */
- #define PUBLISHER_IDENTIFIER_SIZE 128
- /*
- * Usage : rockridge
- * : !rockridge
- * : disable to generate SUSP and RR records.
- * : rockridge
- * : the same as 'rockridge=useful'.
- * : rockridge=strict
- * : generate SUSP and RR records.
- * : [COMPAT: mkisofs -R]
- * : rockridge=useful [DEFAULT]
- * : generate SUSP and RR records.
- * : [COMPAT: mkisofs -r]
- * : NOTE Our rockridge=useful option does not set a zero
- * : to uid and gid, you should use application
- * : option such as --gid,--gname,--uid and --uname
- * : bsdtar options instead.
- * Type : boolean/string
- * Default: Enabled as rockridge=useful
- * COMPAT : mkisofs -r / -R
- *
- * Generates SUSP and RR records.
- */
- unsigned int rr:2;
- #define OPT_RR_DISABLED 0
- #define OPT_RR_STRICT 1
- #define OPT_RR_USEFUL 2
- #define OPT_RR_DEFAULT OPT_RR_USEFUL
- /*
- * Usage : volume-id=<value>
- * Type : string, max 32 bytes
- * Default: Not specified
- * COMPAT : mkisofs -V <value>
- *
- * Specifies Volume Identifier.
- */
- unsigned int volume_id:1;
- #define OPT_VOLUME_ID_DEFAULT 0 /* Use default identifier */
- #define VOLUME_IDENTIFIER_SIZE 32
- /*
- * Usage : !zisofs [DEFAULT]
- * : Disable to generate RRIP 'ZF' extension.
- * : zisofs
- * : Make files zisofs file and generate RRIP 'ZF'
- * : extension. So you do not need mkzftree utility
- * : for making zisofs.
- * : When the file size is less than one Logical Block
- * : size, that file will not zisofs'ed since it does
- * : reduce an ISO-image size.
- * :
- * : When you specify option 'boot=<boot-image>', that
- * : 'boot-image' file won't be converted to zisofs file.
- * Type : boolean
- * Default: Disabled
- *
- * Generates RRIP 'ZF' System Use Entry.
- */
- unsigned int zisofs:1;
- #define OPT_ZISOFS_DISABLED 0
- #define OPT_ZISOFS_DIRECT 1
- #define OPT_ZISOFS_DEFAULT OPT_ZISOFS_DISABLED
- };
- struct iso9660 {
- /* The creation time of ISO image. */
- time_t birth_time;
- /* A file stream of a temporary file, which file contents
- * save to until ISO image can be created. */
- int temp_fd;
- struct isofile *cur_file;
- struct isoent *cur_dirent;
- struct archive_string cur_dirstr;
- uint64_t bytes_remaining;
- int need_multi_extent;
- /* Temporary string buffer for Joliet extension. */
- struct archive_string utf16be;
- struct archive_string mbs;
- struct archive_string_conv *sconv_to_utf16be;
- struct archive_string_conv *sconv_from_utf16be;
- /* A list of all of struct isofile entries. */
- struct {
- struct isofile *first;
- struct isofile **last;
- } all_file_list;
- /* A list of struct isofile entries which have its
- * contents and are not a directory, a hardlinked file
- * and a symlink file. */
- struct {
- struct isofile *first;
- struct isofile **last;
- } data_file_list;
- /* Used for managing to find hardlinking files. */
- struct archive_rb_tree hardlink_rbtree;
- /* Used for making the Path Table Record. */
- struct vdd {
- /* the root of entry tree. */
- struct isoent *rootent;
- enum vdd_type {
- VDD_PRIMARY,
- VDD_JOLIET,
- VDD_ENHANCED
- } vdd_type;
- struct path_table {
- struct isoent *first;
- struct isoent **last;
- struct isoent **sorted;
- int cnt;
- } *pathtbl;
- int max_depth;
- int path_table_block;
- int path_table_size;
- int location_type_L_path_table;
- int location_type_M_path_table;
- int total_dir_block;
- } primary, joliet;
- /* Used for making a Volume Descriptor. */
- int volume_space_size;
- int volume_sequence_number;
- int total_file_block;
- struct archive_string volume_identifier;
- struct archive_string publisher_identifier;
- struct archive_string data_preparer_identifier;
- struct archive_string application_identifier;
- struct archive_string copyright_file_identifier;
- struct archive_string abstract_file_identifier;
- struct archive_string bibliographic_file_identifier;
- /* Used for making rockridge extensions. */
- int location_rrip_er;
- /* Used for making zisofs. */
- struct {
- signed int detect_magic:1;
- signed int making:1;
- signed int allzero:1;
- unsigned char magic_buffer[64];
- int magic_cnt;
- #ifdef HAVE_ZLIB_H
- /*
- * Copy a compressed file to iso9660.zisofs.temp_fd
- * and also copy a uncompressed file(original file) to
- * iso9660.temp_fd . If the number of logical block
- * of the compressed file is less than the number of
- * logical block of the uncompressed file, use it and
- * remove the copy of the uncompressed file.
- * but if not, we use uncompressed file and remove
- * the copy of the compressed file.
- */
- uint32_t *block_pointers;
- size_t block_pointers_allocated;
- int block_pointers_cnt;
- int block_pointers_idx;
- int64_t total_size;
- int64_t block_offset;
- z_stream stream;
- int stream_valid;
- int64_t remaining;
- int compression_level;
- #endif
- } zisofs;
- struct isoent *directories_too_deep;
- int dircnt_max;
- /* Write buffer. */
- #define wb_buffmax() (LOGICAL_BLOCK_SIZE * 32)
- #define wb_remaining(a) (((struct iso9660 *)(a)->format_data)->wbuff_remaining)
- #define wb_offset(a) (((struct iso9660 *)(a)->format_data)->wbuff_offset \
- + wb_buffmax() - wb_remaining(a))
- unsigned char wbuff[LOGICAL_BLOCK_SIZE * 32];
- size_t wbuff_remaining;
- enum {
- WB_TO_STREAM,
- WB_TO_TEMP
- } wbuff_type;
- int64_t wbuff_offset;
- int64_t wbuff_written;
- int64_t wbuff_tail;
- /* 'El Torito' boot data. */
- struct {
- /* boot catalog file */
- struct archive_string catalog_filename;
- struct isoent *catalog;
- /* boot image file */
- struct archive_string boot_filename;
- struct isoent *boot;
- unsigned char platform_id;
- #define BOOT_PLATFORM_X86 0
- #define BOOT_PLATFORM_PPC 1
- #define BOOT_PLATFORM_MAC 2
- struct archive_string id;
- unsigned char media_type;
- #define BOOT_MEDIA_NO_EMULATION 0
- #define BOOT_MEDIA_1_2M_DISKETTE 1
- #define BOOT_MEDIA_1_44M_DISKETTE 2
- #define BOOT_MEDIA_2_88M_DISKETTE 3
- #define BOOT_MEDIA_HARD_DISK 4
- unsigned char system_type;
- uint16_t boot_load_seg;
- uint16_t boot_load_size;
- #define BOOT_LOAD_SIZE 4
- } el_torito;
- struct iso_option opt;
- };
- /*
- * Types of Volume Descriptor
- */
- enum VD_type {
- VDT_BOOT_RECORD=0, /* Boot Record Volume Descriptor */
- VDT_PRIMARY=1, /* Primary Volume Descriptor */
- VDT_SUPPLEMENTARY=2, /* Supplementary Volume Descriptor */
- VDT_TERMINATOR=255 /* Volume Descriptor Set Terminator */
- };
- /*
- * Types of Directory Record
- */
- enum dir_rec_type {
- DIR_REC_VD, /* Stored in Volume Descriptor. */
- DIR_REC_SELF, /* Stored as Current Directory. */
- DIR_REC_PARENT, /* Stored as Parent Directory. */
- DIR_REC_NORMAL /* Stored as Child. */
- };
- /*
- * Kinds of Volume Descriptor Character
- */
- enum vdc {
- VDC_STD,
- VDC_LOWERCASE,
- VDC_UCS2,
- VDC_UCS2_DIRECT
- };
- /*
- * IDentifier Resolver.
- * Used for resolving duplicated filenames.
- */
- struct idr {
- struct idrent {
- struct archive_rb_node rbnode;
- /* Used in wait_list. */
- struct idrent *wnext;
- struct idrent *avail;
- struct isoent *isoent;
- int weight;
- int noff;
- int rename_num;
- } *idrent_pool;
- struct archive_rb_tree rbtree;
- struct {
- struct idrent *first;
- struct idrent **last;
- } wait_list;
- int pool_size;
- int pool_idx;
- int num_size;
- int null_size;
- char char_map[0x80];
- };
- enum char_type {
- A_CHAR,
- D_CHAR
- };
- static int iso9660_options(struct archive_write *,
- const char *, const char *);
- static int iso9660_write_header(struct archive_write *,
- struct archive_entry *);
- static ssize_t iso9660_write_data(struct archive_write *,
- const void *, size_t);
- static int iso9660_finish_entry(struct archive_write *);
- static int iso9660_close(struct archive_write *);
- static int iso9660_free(struct archive_write *);
- static void get_system_identitier(char *, size_t);
- static void set_str(unsigned char *, const char *, size_t, char,
- const char *);
- static inline int joliet_allowed_char(unsigned char, unsigned char);
- static int set_str_utf16be(struct archive_write *, unsigned char *,
- const char *, size_t, uint16_t, enum vdc);
- static int set_str_a_characters_bp(struct archive_write *,
- unsigned char *, int, int, const char *, enum vdc);
- static int set_str_d_characters_bp(struct archive_write *,
- unsigned char *, int, int, const char *, enum vdc);
- static void set_VD_bp(unsigned char *, enum VD_type, unsigned char);
- static inline void set_unused_field_bp(unsigned char *, int, int);
- static unsigned char *extra_open_record(unsigned char *, int,
- struct isoent *, struct ctl_extr_rec *);
- static void extra_close_record(struct ctl_extr_rec *, int);
- static unsigned char * extra_next_record(struct ctl_extr_rec *, int);
- static unsigned char *extra_get_record(struct isoent *, int *, int *, int *);
- static void extra_tell_used_size(struct ctl_extr_rec *, int);
- static int extra_setup_location(struct isoent *, int);
- static int set_directory_record_rr(unsigned char *, int,
- struct isoent *, struct iso9660 *, enum dir_rec_type);
- static int set_directory_record(unsigned char *, size_t,
- struct isoent *, struct iso9660 *, enum dir_rec_type,
- enum vdd_type);
- static inline int get_dir_rec_size(struct iso9660 *, struct isoent *,
- enum dir_rec_type, enum vdd_type);
- static inline unsigned char *wb_buffptr(struct archive_write *);
- static int wb_write_out(struct archive_write *);
- static int wb_consume(struct archive_write *, size_t);
- #ifdef HAVE_ZLIB_H
- static int wb_set_offset(struct archive_write *, int64_t);
- #endif
- static int write_null(struct archive_write *, size_t);
- static int write_VD_terminator(struct archive_write *);
- static int set_file_identifier(unsigned char *, int, int, enum vdc,
- struct archive_write *, struct vdd *,
- struct archive_string *, const char *, int,
- enum char_type);
- static int write_VD(struct archive_write *, struct vdd *);
- static int write_VD_boot_record(struct archive_write *);
- static int write_information_block(struct archive_write *);
- static int write_path_table(struct archive_write *, int,
- struct vdd *);
- static int write_directory_descriptors(struct archive_write *,
- struct vdd *);
- static int write_file_descriptors(struct archive_write *);
- static int write_rr_ER(struct archive_write *);
- static void calculate_path_table_size(struct vdd *);
- static void isofile_init_entry_list(struct iso9660 *);
- static void isofile_add_entry(struct iso9660 *, struct isofile *);
- static void isofile_free_all_entries(struct iso9660 *);
- static void isofile_init_entry_data_file_list(struct iso9660 *);
- static void isofile_add_data_file(struct iso9660 *, struct isofile *);
- static struct isofile * isofile_new(struct archive_write *,
- struct archive_entry *);
- static void isofile_free(struct isofile *);
- static int isofile_gen_utility_names(struct archive_write *,
- struct isofile *);
- static int isofile_register_hardlink(struct archive_write *,
- struct isofile *);
- static void isofile_connect_hardlink_files(struct iso9660 *);
- static void isofile_init_hardlinks(struct iso9660 *);
- static void isofile_free_hardlinks(struct iso9660 *);
- static struct isoent *isoent_new(struct isofile *);
- static int isoent_clone_tree(struct archive_write *,
- struct isoent **, struct isoent *);
- static void _isoent_free(struct isoent *isoent);
- static void isoent_free_all(struct isoent *);
- static struct isoent * isoent_create_virtual_dir(struct archive_write *,
- struct iso9660 *, const char *);
- static int isoent_cmp_node(const struct archive_rb_node *,
- const struct archive_rb_node *);
- static int isoent_cmp_key(const struct archive_rb_node *,
- const void *);
- static int isoent_add_child_head(struct isoent *, struct isoent *);
- static int isoent_add_child_tail(struct isoent *, struct isoent *);
- static void isoent_remove_child(struct isoent *, struct isoent *);
- static void isoent_setup_directory_location(struct iso9660 *,
- int, struct vdd *);
- static void isoent_setup_file_location(struct iso9660 *, int);
- static int get_path_component(char *, size_t, const char *);
- static int isoent_tree(struct archive_write *, struct isoent **);
- static struct isoent *isoent_find_child(struct isoent *, const char *);
- static struct isoent *isoent_find_entry(struct isoent *, const char *);
- static void idr_relaxed_filenames(char *);
- static void idr_init(struct iso9660 *, struct vdd *, struct idr *);
- static void idr_cleanup(struct idr *);
- static int idr_ensure_poolsize(struct archive_write *, struct idr *,
- int);
- static int idr_start(struct archive_write *, struct idr *,
- int, int, int, int, const struct archive_rb_tree_ops *);
- static void idr_register(struct idr *, struct isoent *, int,
- int);
- static void idr_extend_identifier(struct idrent *, int, int);
- static void idr_resolve(struct idr *, void (*)(unsigned char *, int));
- static void idr_set_num(unsigned char *, int);
- static void idr_set_num_beutf16(unsigned char *, int);
- static int isoent_gen_iso9660_identifier(struct archive_write *,
- struct isoent *, struct idr *);
- static int isoent_gen_joliet_identifier(struct archive_write *,
- struct isoent *, struct idr *);
- static int isoent_cmp_iso9660_identifier(const struct isoent *,
- const struct isoent *);
- static int isoent_cmp_node_iso9660(const struct archive_rb_node *,
- const struct archive_rb_node *);
- static int isoent_cmp_key_iso9660(const struct archive_rb_node *,
- const void *);
- static int isoent_cmp_joliet_identifier(const struct isoent *,
- const struct isoent *);
- static int isoent_cmp_node_joliet(const struct archive_rb_node *,
- const struct archive_rb_node *);
- static int isoent_cmp_key_joliet(const struct archive_rb_node *,
- const void *);
- static inline void path_table_add_entry(struct path_table *, struct isoent *);
- static inline struct isoent * path_table_last_entry(struct path_table *);
- static int isoent_make_path_table(struct archive_write *);
- static int isoent_find_out_boot_file(struct archive_write *,
- struct isoent *);
- static int isoent_create_boot_catalog(struct archive_write *,
- struct isoent *);
- static size_t fd_boot_image_size(int);
- static int make_boot_catalog(struct archive_write *);
- static int setup_boot_information(struct archive_write *);
- static int zisofs_init(struct archive_write *, struct isofile *);
- static void zisofs_detect_magic(struct archive_write *,
- const void *, size_t);
- static int zisofs_write_to_temp(struct archive_write *,
- const void *, size_t);
- static int zisofs_finish_entry(struct archive_write *);
- static int zisofs_rewind_boot_file(struct archive_write *);
- static int zisofs_free(struct archive_write *);
- int
- archive_write_set_format_iso9660(struct archive *_a)
- {
- struct archive_write *a = (struct archive_write *)_a;
- struct iso9660 *iso9660;
- archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW, "archive_write_set_format_iso9660");
- /* If another format was already registered, unregister it. */
- if (a->format_free != NULL)
- (a->format_free)(a);
- iso9660 = calloc(1, sizeof(*iso9660));
- if (iso9660 == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate iso9660 data");
- return (ARCHIVE_FATAL);
- }
- iso9660->birth_time = 0;
- iso9660->temp_fd = -1;
- iso9660->cur_file = NULL;
- iso9660->primary.max_depth = 0;
- iso9660->primary.vdd_type = VDD_PRIMARY;
- iso9660->primary.pathtbl = NULL;
- iso9660->joliet.rootent = NULL;
- iso9660->joliet.max_depth = 0;
- iso9660->joliet.vdd_type = VDD_JOLIET;
- iso9660->joliet.pathtbl = NULL;
- isofile_init_entry_list(iso9660);
- isofile_init_entry_data_file_list(iso9660);
- isofile_init_hardlinks(iso9660);
- iso9660->directories_too_deep = NULL;
- iso9660->dircnt_max = 1;
- iso9660->wbuff_remaining = wb_buffmax();
- iso9660->wbuff_type = WB_TO_TEMP;
- iso9660->wbuff_offset = 0;
- iso9660->wbuff_written = 0;
- iso9660->wbuff_tail = 0;
- archive_string_init(&(iso9660->utf16be));
- archive_string_init(&(iso9660->mbs));
- /*
- * Init Identifiers used for PVD and SVD.
- */
- archive_string_init(&(iso9660->volume_identifier));
- archive_strcpy(&(iso9660->volume_identifier), "CDROM");
- archive_string_init(&(iso9660->publisher_identifier));
- archive_string_init(&(iso9660->data_preparer_identifier));
- archive_string_init(&(iso9660->application_identifier));
- archive_strcpy(&(iso9660->application_identifier),
- archive_version_string());
- archive_string_init(&(iso9660->copyright_file_identifier));
- archive_string_init(&(iso9660->abstract_file_identifier));
- archive_string_init(&(iso9660->bibliographic_file_identifier));
- /*
- * Init El Torito bootable CD variables.
- */
- archive_string_init(&(iso9660->el_torito.catalog_filename));
- iso9660->el_torito.catalog = NULL;
- /* Set default file name of boot catalog */
- archive_strcpy(&(iso9660->el_torito.catalog_filename),
- "boot.catalog");
- archive_string_init(&(iso9660->el_torito.boot_filename));
- iso9660->el_torito.boot = NULL;
- iso9660->el_torito.platform_id = BOOT_PLATFORM_X86;
- archive_string_init(&(iso9660->el_torito.id));
- iso9660->el_torito.boot_load_seg = 0;
- iso9660->el_torito.boot_load_size = BOOT_LOAD_SIZE;
- /*
- * Init zisofs variables.
- */
- #ifdef HAVE_ZLIB_H
- iso9660->zisofs.block_pointers = NULL;
- iso9660->zisofs.block_pointers_allocated = 0;
- iso9660->zisofs.stream_valid = 0;
- iso9660->zisofs.compression_level = 9;
- memset(&(iso9660->zisofs.stream), 0,
- sizeof(iso9660->zisofs.stream));
- #endif
- /*
- * Set default value of iso9660 options.
- */
- iso9660->opt.abstract_file = OPT_ABSTRACT_FILE_DEFAULT;
- iso9660->opt.application_id = OPT_APPLICATION_ID_DEFAULT;
- iso9660->opt.allow_vernum = OPT_ALLOW_VERNUM_DEFAULT;
- iso9660->opt.biblio_file = OPT_BIBLIO_FILE_DEFAULT;
- iso9660->opt.boot = OPT_BOOT_DEFAULT;
- iso9660->opt.boot_catalog = OPT_BOOT_CATALOG_DEFAULT;
- iso9660->opt.boot_info_table = OPT_BOOT_INFO_TABLE_DEFAULT;
- iso9660->opt.boot_load_seg = OPT_BOOT_LOAD_SEG_DEFAULT;
- iso9660->opt.boot_load_size = OPT_BOOT_LOAD_SIZE_DEFAULT;
- iso9660->opt.boot_type = OPT_BOOT_TYPE_DEFAULT;
- iso9660->opt.compression_level = OPT_COMPRESSION_LEVEL_DEFAULT;
- iso9660->opt.copyright_file = OPT_COPYRIGHT_FILE_DEFAULT;
- iso9660->opt.iso_level = OPT_ISO_LEVEL_DEFAULT;
- iso9660->opt.joliet = OPT_JOLIET_DEFAULT;
- iso9660->opt.limit_depth = OPT_LIMIT_DEPTH_DEFAULT;
- iso9660->opt.limit_dirs = OPT_LIMIT_DIRS_DEFAULT;
- iso9660->opt.pad = OPT_PAD_DEFAULT;
- iso9660->opt.publisher = OPT_PUBLISHER_DEFAULT;
- iso9660->opt.rr = OPT_RR_DEFAULT;
- iso9660->opt.volume_id = OPT_VOLUME_ID_DEFAULT;
- iso9660->opt.zisofs = OPT_ZISOFS_DEFAULT;
- /* Create the root directory. */
- iso9660->primary.rootent =
- isoent_create_virtual_dir(a, iso9660, "");
- if (iso9660->primary.rootent == NULL) {
- free(iso9660);
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- iso9660->primary.rootent->parent = iso9660->primary.rootent;
- iso9660->cur_dirent = iso9660->primary.rootent;
- archive_string_init(&(iso9660->cur_dirstr));
- archive_string_ensure(&(iso9660->cur_dirstr), 1);
- iso9660->cur_dirstr.s[0] = 0;
- iso9660->sconv_to_utf16be = NULL;
- iso9660->sconv_from_utf16be = NULL;
- a->format_data = iso9660;
- a->format_name = "iso9660";
- a->format_options = iso9660_options;
- a->format_write_header = iso9660_write_header;
- a->format_write_data = iso9660_write_data;
- a->format_finish_entry = iso9660_finish_entry;
- a->format_close = iso9660_close;
- a->format_free = iso9660_free;
- a->archive.archive_format = ARCHIVE_FORMAT_ISO9660;
- a->archive.archive_format_name = "ISO9660";
- return (ARCHIVE_OK);
- }
- static int
- get_str_opt(struct archive_write *a, struct archive_string *s,
- size_t maxsize, const char *key, const char *value)
- {
- if (strlen(value) > maxsize) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Value is longer than %zu characters "
- "for option ``%s''", maxsize, key);
- return (ARCHIVE_FATAL);
- }
- archive_strcpy(s, value);
- return (ARCHIVE_OK);
- }
- static int
- get_num_opt(struct archive_write *a, int *num, int high, int low,
- const char *key, const char *value)
- {
- const char *p = value;
- int data = 0;
- int neg = 0;
- if (p == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid value(empty) for option ``%s''", key);
- return (ARCHIVE_FATAL);
- }
- if (*p == '-') {
- neg = 1;
- p++;
- }
- while (*p) {
- if (*p >= '0' && *p <= '9')
- data = data * 10 + *p - '0';
- else {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid value for option ``%s''", key);
- return (ARCHIVE_FATAL);
- }
- if (data > high) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid value(over %d) for "
- "option ``%s''", high, key);
- return (ARCHIVE_FATAL);
- }
- if (data < low) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid value(under %d) for "
- "option ``%s''", low, key);
- return (ARCHIVE_FATAL);
- }
- p++;
- }
- if (neg)
- data *= -1;
- *num = data;
- return (ARCHIVE_OK);
- }
- static int
- iso9660_options(struct archive_write *a, const char *key, const char *value)
- {
- struct iso9660 *iso9660 = a->format_data;
- const char *p;
- int r;
- switch (key[0]) {
- case 'a':
- if (strcmp(key, "abstract-file") == 0) {
- r = get_str_opt(a,
- &(iso9660->abstract_file_identifier),
- ABSTRACT_FILE_SIZE, key, value);
- iso9660->opt.abstract_file = r == ARCHIVE_OK;
- return (r);
- }
- if (strcmp(key, "application-id") == 0) {
- r = get_str_opt(a,
- &(iso9660->application_identifier),
- APPLICATION_IDENTIFIER_SIZE, key, value);
- iso9660->opt.application_id = r == ARCHIVE_OK;
- return (r);
- }
- if (strcmp(key, "allow-vernum") == 0) {
- iso9660->opt.allow_vernum = value != NULL;
- return (ARCHIVE_OK);
- }
- break;
- case 'b':
- if (strcmp(key, "biblio-file") == 0) {
- r = get_str_opt(a,
- &(iso9660->bibliographic_file_identifier),
- BIBLIO_FILE_SIZE, key, value);
- iso9660->opt.biblio_file = r == ARCHIVE_OK;
- return (r);
- }
- if (strcmp(key, "boot") == 0) {
- if (value == NULL)
- iso9660->opt.boot = 0;
- else {
- iso9660->opt.boot = 1;
- archive_strcpy(
- &(iso9660->el_torito.boot_filename),
- value);
- }
- return (ARCHIVE_OK);
- }
- if (strcmp(key, "boot-catalog") == 0) {
- r = get_str_opt(a,
- &(iso9660->el_torito.catalog_filename),
- 1024, key, value);
- iso9660->opt.boot_catalog = r == ARCHIVE_OK;
- return (r);
- }
- if (strcmp(key, "boot-info-table") == 0) {
- iso9660->opt.boot_info_table = value != NULL;
- return (ARCHIVE_OK);
- }
- if (strcmp(key, "boot-load-seg") == 0) {
- uint32_t seg;
- iso9660->opt.boot_load_seg = 0;
- if (value == NULL)
- goto invalid_value;
- seg = 0;
- p = value;
- if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X'))
- p += 2;
- while (*p) {
- if (seg)
- seg <<= 4;
- if (*p >= 'A' && *p <= 'F')
- seg += *p - 'A' + 0x0a;
- else if (*p >= 'a' && *p <= 'f')
- seg += *p - 'a' + 0x0a;
- else if (*p >= '0' && *p <= '9')
- seg += *p - '0';
- else
- goto invalid_value;
- if (seg > 0xffff) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Invalid value(over 0xffff) for "
- "option ``%s''", key);
- return (ARCHIVE_FATAL);
- }
- p++;
- }
- iso9660->el_torito.boot_load_seg = (uint16_t)seg;
- iso9660->opt.boot_load_seg = 1;
- return (ARCHIVE_OK);
- }
- if (strcmp(key, "boot-load-size") == 0) {
- int num = 0;
- r = get_num_opt(a, &num, 0xffff, 1, key, value);
- iso9660->opt.boot_load_size = r == ARCHIVE_OK;
- if (r != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- iso9660->el_torito.boot_load_size = (uint16_t)num;
- return (ARCHIVE_OK);
- }
- if (strcmp(key, "boot-type") == 0) {
- if (value == NULL)
- goto invalid_value;
- if (strcmp(value, "no-emulation") == 0)
- iso9660->opt.boot_type = OPT_BOOT_TYPE_NO_EMU;
- else if (strcmp(value, "fd") == 0)
- iso9660->opt.boot_type = OPT_BOOT_TYPE_FD;
- else if (strcmp(value, "hard-disk") == 0)
- iso9660->opt.boot_type = OPT_BOOT_TYPE_HARD_DISK;
- else
- goto invalid_value;
- return (ARCHIVE_OK);
- }
- break;
- case 'c':
- if (strcmp(key, "compression-level") == 0) {
- #ifdef HAVE_ZLIB_H
- if (value == NULL ||
- !(value[0] >= '0' && value[0] <= '9') ||
- value[1] != '\0')
- goto invalid_value;
- iso9660->zisofs.compression_level = value[0] - '0';
- iso9660->opt.compression_level = 1;
- return (ARCHIVE_OK);
- #else
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Option ``%s'' "
- "is not supported on this platform.", key);
- return (ARCHIVE_FATAL);
- #endif
- }
- if (strcmp(key, "copyright-file") == 0) {
- r = get_str_opt(a,
- &(iso9660->copyright_file_identifier),
- COPYRIGHT_FILE_SIZE, key, value);
- iso9660->opt.copyright_file = r == ARCHIVE_OK;
- return (r);
- }
- #ifdef DEBUG
- /* Specifies Volume creation date and time;
- * year(4),month(2),day(2),hour(2),minute(2),second(2).
- * e.g. "20090929033757"
- */
- if (strcmp(key, "creation") == 0) {
- struct tm tm;
- char buf[5];
- p = value;
- if (p == NULL || strlen(p) < 14)
- goto invalid_value;
- memset(&tm, 0, sizeof(tm));
- memcpy(buf, p, 4); buf[4] = '\0'; p += 4;
- tm.tm_year = strtol(buf, NULL, 10) - 1900;
- memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
- tm.tm_mon = strtol(buf, NULL, 10) - 1;
- memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
- tm.tm_mday = strtol(buf, NULL, 10);
- memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
- tm.tm_hour = strtol(buf, NULL, 10);
- memcpy(buf, p, 2); buf[2] = '\0'; p += 2;
- tm.tm_min = strtol(buf, NULL, 10);
- memcpy(buf, p, 2); buf[2] = '\0';
- tm.tm_sec = strtol(buf, NULL, 10);
- iso9660->birth_time = mktime(&tm);
- return (ARCHIVE_OK);
- }
- #endif
- break;
- case 'i':
- if (strcmp(key, "iso-level") == 0) {
- if (value != NULL && value[1] == '\0' &&
- (value[0] >= '1' && value[0] <= '4')) {
- iso9660->opt.iso_level = value[0]-'0';
- return (ARCHIVE_OK);
- }
- goto invalid_value;
- }
- break;
- case 'j':
- if (strcmp(key, "joliet") == 0) {
- if (value == NULL)
- iso9660->opt.joliet = OPT_JOLIET_DISABLE;
- else if (strcmp(value, "1") == 0)
- iso9660->opt.joliet = OPT_JOLIET_ENABLE;
- else if (strcmp(value, "long") == 0)
- iso9660->opt.joliet = OPT_JOLIET_LONGNAME;
- else
- goto invalid_value;
- return (ARCHIVE_OK);
- }
- break;
- case 'l':
- if (strcmp(key, "limit-depth") == 0) {
- iso9660->opt.limit_depth = value != NULL;
- return (ARCHIVE_OK);
- }
- if (strcmp(key, "limit-dirs") == 0) {
- iso9660->opt.limit_dirs = value != NULL;
- return (ARCHIVE_OK);
- }
- break;
- case 'p':
- if (strcmp(key, "pad") == 0) {
- iso9660->opt.pad = value != NULL;
- return (ARCHIVE_OK);
- }
- if (strcmp(key, "publisher") == 0) {
- r = get_str_opt(a,
- &(iso9660->publisher_identifier),
- PUBLISHER_IDENTIFIER_SIZE, key, value);
- iso9660->opt.publisher = r == ARCHIVE_OK;
- return (r);
- }
- break;
- case 'r':
- if (strcmp(key, "rockridge") == 0 ||
- strcmp(key, "Rockridge") == 0) {
- if (value == NULL)
- iso9660->opt.rr = OPT_RR_DISABLED;
- else if (strcmp(value, "1") == 0)
- iso9660->opt.rr = OPT_RR_USEFUL;
- else if (strcmp(value, "strict") == 0)
- iso9660->opt.rr = OPT_RR_STRICT;
- else if (strcmp(value, "useful") == 0)
- iso9660->opt.rr = OPT_RR_USEFUL;
- else
- goto invalid_value;
- return (ARCHIVE_OK);
- }
- break;
- case 'v':
- if (strcmp(key, "volume-id") == 0) {
- r = get_str_opt(a, &(iso9660->volume_identifier),
- VOLUME_IDENTIFIER_SIZE, key, value);
- iso9660->opt.volume_id = r == ARCHIVE_OK;
- return (r);
- }
- break;
- case 'z':
- if (strcmp(key, "zisofs") == 0) {
- if (value == NULL)
- iso9660->opt.zisofs = OPT_ZISOFS_DISABLED;
- else {
- #ifdef HAVE_ZLIB_H
- iso9660->opt.zisofs = OPT_ZISOFS_DIRECT;
- #else
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "``zisofs'' "
- "is not supported on this platform.");
- return (ARCHIVE_FATAL);
- #endif
- }
- return (ARCHIVE_OK);
- }
- break;
- }
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
- invalid_value:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid value for option ``%s''", key);
- return (ARCHIVE_FAILED);
- }
- static int
- iso9660_write_header(struct archive_write *a, struct archive_entry *entry)
- {
- struct iso9660 *iso9660;
- struct isofile *file;
- struct isoent *isoent;
- int r, ret = ARCHIVE_OK;
- iso9660 = a->format_data;
- iso9660->cur_file = NULL;
- iso9660->bytes_remaining = 0;
- iso9660->need_multi_extent = 0;
- if (archive_entry_filetype(entry) == AE_IFLNK
- && iso9660->opt.rr == OPT_RR_DISABLED) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Ignore symlink file.");
- iso9660->cur_file = NULL;
- return (ARCHIVE_WARN);
- }
- if (archive_entry_filetype(entry) == AE_IFREG &&
- archive_entry_size(entry) >= MULTI_EXTENT_SIZE) {
- if (iso9660->opt.iso_level < 3) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Ignore over %lld bytes file. "
- "This file too large.",
- MULTI_EXTENT_SIZE);
- iso9660->cur_file = NULL;
- return (ARCHIVE_WARN);
- }
- iso9660->need_multi_extent = 1;
- }
- file = isofile_new(a, entry);
- if (file == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate data");
- return (ARCHIVE_FATAL);
- }
- r = isofile_gen_utility_names(a, file);
- if (r < ARCHIVE_WARN) {
- isofile_free(file);
- return (r);
- }
- else if (r < ret)
- ret = r;
- /*
- * Ignore a path which looks like the top of directory name
- * since we have already made the root directory of an ISO image.
- */
- if (archive_strlen(&(file->parentdir)) == 0 &&
- archive_strlen(&(file->basename)) == 0) {
- isofile_free(file);
- return (r);
- }
- isofile_add_entry(iso9660, file);
- isoent = isoent_new(file);
- if (isoent == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate data");
- return (ARCHIVE_FATAL);
- }
- if (isoent->file->dircnt > iso9660->dircnt_max)
- iso9660->dircnt_max = isoent->file->dircnt;
- /* Add the current file into tree */
- r = isoent_tree(a, &isoent);
- if (r != ARCHIVE_OK)
- return (r);
- /* If there is the same file in tree and
- * the current file is older than the file in tree.
- * So we don't need the current file data anymore. */
- if (isoent->file != file)
- return (ARCHIVE_OK);
- /* Non regular files contents are unneeded to be saved to
- * temporary files. */
- if (archive_entry_filetype(file->entry) != AE_IFREG)
- return (ret);
- /*
- * Set the current file to cur_file to read its contents.
- */
- iso9660->cur_file = file;
- if (archive_entry_nlink(file->entry) > 1) {
- r = isofile_register_hardlink(a, file);
- if (r != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
- /*
- * Prepare to save the contents of the file.
- */
- if (iso9660->temp_fd < 0) {
- iso9660->temp_fd = __archive_mktemp(NULL);
- if (iso9660->temp_fd < 0) {
- archive_set_error(&a->archive, errno,
- "Couldn't create temporary file");
- return (ARCHIVE_FATAL);
- }
- }
- /* Save an offset of current file in temporary file. */
- file->content.offset_of_temp = wb_offset(a);
- file->cur_content = &(file->content);
- r = zisofs_init(a, file);
- if (r < ret)
- ret = r;
- iso9660->bytes_remaining = archive_entry_size(file->entry);
- return (ret);
- }
- static int
- write_to_temp(struct archive_write *a, const void *buff, size_t s)
- {
- struct iso9660 *iso9660 = a->format_data;
- ssize_t written;
- const unsigned char *b;
- b = (const unsigned char *)buff;
- while (s) {
- written = write(iso9660->temp_fd, b, s);
- if (written < 0) {
- archive_set_error(&a->archive, errno,
- "Can't write to temporary file");
- return (ARCHIVE_FATAL);
- }
- s -= written;
- b += written;
- }
- return (ARCHIVE_OK);
- }
- static int
- wb_write_to_temp(struct archive_write *a, const void *buff, size_t s)
- {
- const char *xp = buff;
- size_t xs = s;
- /*
- * If a written data size is big enough to use system-call
- * and there is no waiting data, this calls write_to_temp() in
- * order to reduce a extra memory copy.
- */
- if (wb_remaining(a) == wb_buffmax() && s > (1024 * 16)) {
- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
- xs = s % LOGICAL_BLOCK_SIZE;
- iso9660->wbuff_offset += s - xs;
- if (write_to_temp(a, buff, s - xs) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- if (xs == 0)
- return (ARCHIVE_OK);
- xp += s - xs;
- }
- while (xs) {
- size_t size = xs;
- if (size > wb_remaining(a))
- size = wb_remaining(a);
- memcpy(wb_buffptr(a), xp, size);
- if (wb_consume(a, size) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- xs -= size;
- xp += size;
- }
- return (ARCHIVE_OK);
- }
- static int
- wb_write_padding_to_temp(struct archive_write *a, int64_t csize)
- {
- size_t ns;
- int ret;
- ns = (size_t)(csize % LOGICAL_BLOCK_SIZE);
- if (ns != 0)
- ret = write_null(a, LOGICAL_BLOCK_SIZE - ns);
- else
- ret = ARCHIVE_OK;
- return (ret);
- }
- static ssize_t
- write_iso9660_data(struct archive_write *a, const void *buff, size_t s)
- {
- struct iso9660 *iso9660 = a->format_data;
- size_t ws;
- if (iso9660->temp_fd < 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Couldn't create temporary file");
- return (ARCHIVE_FATAL);
- }
- ws = s;
- if (iso9660->need_multi_extent &&
- (iso9660->cur_file->cur_content->size + ws) >=
- (MULTI_EXTENT_SIZE - LOGICAL_BLOCK_SIZE)) {
- struct content *con;
- size_t ts;
- ts = (size_t)(MULTI_EXTENT_SIZE - LOGICAL_BLOCK_SIZE -
- iso9660->cur_file->cur_content->size);
- if (iso9660->zisofs.detect_magic)
- zisofs_detect_magic(a, buff, ts);
- if (iso9660->zisofs.making) {
- if (zisofs_write_to_temp(a, buff, ts) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- } else {
- if (wb_write_to_temp(a, buff, ts) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- iso9660->cur_file->cur_content->size += ts;
- }
- /* Write padding. */
- if (wb_write_padding_to_temp(a,
- iso9660->cur_file->cur_content->size) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- /* Compute the logical block number. */
- iso9660->cur_file->cur_content->blocks = (int)
- ((iso9660->cur_file->cur_content->size
- + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);
- /*
- * Make next extent.
- */
- ws -= ts;
- buff = (const void *)(((const unsigned char *)buff) + ts);
- /* Make a content for next extent. */
- con = calloc(1, sizeof(*con));
- if (con == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate content data");
- return (ARCHIVE_FATAL);
- }
- con->offset_of_temp = wb_offset(a);
- iso9660->cur_file->cur_content->next = con;
- iso9660->cur_file->cur_content = con;
- #ifdef HAVE_ZLIB_H
- iso9660->zisofs.block_offset = 0;
- #endif
- }
- if (iso9660->zisofs.detect_magic)
- zisofs_detect_magic(a, buff, ws);
- if (iso9660->zisofs.making) {
- if (zisofs_write_to_temp(a, buff, ws) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- } else {
- if (wb_write_to_temp(a, buff, ws) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- iso9660->cur_file->cur_content->size += ws;
- }
- return (s);
- }
- static ssize_t
- iso9660_write_data(struct archive_write *a, const void *buff, size_t s)
- {
- struct iso9660 *iso9660 = a->format_data;
- ssize_t r;
- if (iso9660->cur_file == NULL)
- return (0);
- if (archive_entry_filetype(iso9660->cur_file->entry) != AE_IFREG)
- return (0);
- if (s > iso9660->bytes_remaining)
- s = (size_t)iso9660->bytes_remaining;
- if (s == 0)
- return (0);
- r = write_iso9660_data(a, buff, s);
- if (r > 0)
- iso9660->bytes_remaining -= r;
- return (r);
- }
- static int
- iso9660_finish_entry(struct archive_write *a)
- {
- struct iso9660 *iso9660 = a->format_data;
- if (iso9660->cur_file == NULL)
- return (ARCHIVE_OK);
- if (archive_entry_filetype(iso9660->cur_file->entry) != AE_IFREG)
- return (ARCHIVE_OK);
- if (iso9660->cur_file->content.size == 0)
- return (ARCHIVE_OK);
- /* If there are unwritten data, write null data instead. */
- while (iso9660->bytes_remaining > 0) {
- size_t s;
- s = (iso9660->bytes_remaining > a->null_length)?
- a->null_length: (size_t)iso9660->bytes_remaining;
- if (write_iso9660_data(a, a->nulls, s) < 0)
- return (ARCHIVE_FATAL);
- iso9660->bytes_remaining -= s;
- }
- if (iso9660->zisofs.making && zisofs_finish_entry(a) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- /* Write padding. */
- if (wb_write_padding_to_temp(a, iso9660->cur_file->cur_content->size)
- != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- /* Compute the logical block number. */
- iso9660->cur_file->cur_content->blocks = (int)
- ((iso9660->cur_file->cur_content->size
- + LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);
- /* Add the current file to data file list. */
- isofile_add_data_file(iso9660, iso9660->cur_file);
- return (ARCHIVE_OK);
- }
- static int
- iso9660_close(struct archive_write *a)
- {
- struct iso9660 *iso9660;
- int ret, blocks;
- iso9660 = a->format_data;
- /*
- * Write remaining data out to the temporary file.
- */
- if (wb_remaining(a) > 0) {
- ret = wb_write_out(a);
- if (ret < 0)
- return (ret);
- }
- /*
- * Preparations...
- */
- #ifdef DEBUG
- if (iso9660->birth_time == 0)
- #endif
- time(&(iso9660->birth_time));
- /*
- * Prepare a bootable ISO image.
- */
- if (iso9660->opt.boot) {
- /* Find out the boot file entry. */
- ret = isoent_find_out_boot_file(a, iso9660->primary.rootent);
- if (ret < 0)
- return (ret);
- /* Reconvert the boot file from zisofs'ed form to
- * plain form. */
- ret = zisofs_rewind_boot_file(a);
- if (ret < 0)
- return (ret);
- /* Write remaining data out to the temporary file. */
- if (wb_remaining(a) > 0) {
- ret = wb_write_out(a);
- if (ret < 0)
- return (ret);
- }
- /* Create the boot catalog. */
- ret = isoent_create_boot_catalog(a, iso9660->primary.rootent);
- if (ret < 0)
- return (ret);
- }
- /*
- * Prepare joliet extensions.
- */
- if (iso9660->opt.joliet) {
- /* Make a new tree for joliet. */
- ret = isoent_clone_tree(a, &(iso9660->joliet.rootent),
- iso9660->primary.rootent);
- if (ret < 0)
- return (ret);
- /* Make sure we have UTF-16BE converters.
- * if there is no file entry, converters are still
- * uninitialized. */
- if (iso9660->sconv_to_utf16be == NULL) {
- iso9660->sconv_to_utf16be =
- archive_string_conversion_to_charset(
- &(a->archive), "UTF-16BE", 1);
- if (iso9660->sconv_to_utf16be == NULL)
- /* Couldn't allocate memory */
- return (ARCHIVE_FATAL);
- iso9660->sconv_from_utf16be =
- archive_string_conversion_from_charset(
- &(a->archive), "UTF-16BE", 1);
- if (iso9660->sconv_from_utf16be == NULL)
- /* Couldn't allocate memory */
- return (ARCHIVE_FATAL);
- }
- }
- /*
- * Make Path Tables.
- */
- ret = isoent_make_path_table(a);
- if (ret < 0)
- return (ret);
- /*
- * Calculate a total volume size and setup all locations of
- * contents of an iso9660 image.
- */
- blocks = SYSTEM_AREA_BLOCK
- + PRIMARY_VOLUME_DESCRIPTOR_BLOCK
- + VOLUME_DESCRIPTOR_SET_TERMINATOR_BLOCK
- + NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK;
- if (iso9660->opt.boot)
- blocks += BOOT_RECORD_DESCRIPTOR_BLOCK;
- if (iso9660->opt.joliet)
- blocks += SUPPLEMENTARY_VOLUME_DESCRIPTOR_BLOCK;
- if (iso9660->opt.iso_level == 4)
- blocks += SUPPLEMENTARY_VOLUME_DESCRIPTOR_BLOCK;
- /* Setup the locations of Path Table. */
- iso9660->primary.location_type_L_path_table = blocks;
- blocks += iso9660->primary.path_table_block;
- iso9660->primary.location_type_M_path_table = blocks;
- blocks += iso9660->primary.path_table_block;
- if (iso9660->opt.joliet) {
- iso9660->joliet.location_type_L_path_table = blocks;
- blocks += iso9660->joliet.path_table_block;
- iso9660->joliet.location_type_M_path_table = blocks;
- blocks += iso9660->joliet.path_table_block;
- }
- /* Setup the locations of directories. */
- isoent_setup_directory_location(iso9660, blocks,
- &(iso9660->primary));
- blocks += iso9660->primary.total_dir_block;
- if (iso9660->opt.joliet) {
- isoent_setup_directory_location(iso9660, blocks,
- &(iso9660->joliet));
- blocks += iso9660->joliet.total_dir_block;
- }
- if (iso9660->opt.rr) {
- iso9660->location_rrip_er = blocks;
- blocks += RRIP_ER_BLOCK;
- }
- /* Setup the locations of all file contents. */
- isoent_setup_file_location(iso9660, blocks);
- blocks += iso9660->total_file_block;
- if (iso9660->opt.boot && iso9660->opt.boot_info_table) {
- ret = setup_boot_information(a);
- if (ret < 0)
- return (ret);
- }
- /* Now we have a total volume size. */
- iso9660->volume_space_size = blocks;
- if (iso9660->opt.pad)
- iso9660->volume_space_size += PADDING_BLOCK;
- iso9660->volume_sequence_number = 1;
- /*
- * Write an ISO 9660 image.
- */
- /* Switch to start using wbuff as file buffer. */
- iso9660->wbuff_remaining = wb_buffmax();
- iso9660->wbuff_type = WB_TO_STREAM;
- iso9660->wbuff_offset = 0;
- iso9660->wbuff_written = 0;
- iso9660->wbuff_tail = 0;
- /* Write The System Area */
- ret = write_null(a, SYSTEM_AREA_BLOCK * LOGICAL_BLOCK_SIZE);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- /* Write Primary Volume Descriptor */
- ret = write_VD(a, &(iso9660->primary));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- if (iso9660->opt.boot) {
- /* Write Boot Record Volume Descriptor */
- ret = write_VD_boot_record(a);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
- if (iso9660->opt.iso_level == 4) {
- /* Write Enhanced Volume Descriptor */
- iso9660->primary.vdd_type = VDD_ENHANCED;
- ret = write_VD(a, &(iso9660->primary));
- iso9660->primary.vdd_type = VDD_PRIMARY;
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
- if (iso9660->opt.joliet) {
- ret = write_VD(a, &(iso9660->joliet));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
- /* Write Volume Descriptor Set Terminator */
- ret = write_VD_terminator(a);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- /* Write Non-ISO File System Information */
- ret = write_information_block(a);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- /* Write Type L Path Table */
- ret = write_path_table(a, 0, &(iso9660->primary));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- /* Write Type M Path Table */
- ret = write_path_table(a, 1, &(iso9660->primary));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- if (iso9660->opt.joliet) {
- /* Write Type L Path Table */
- ret = write_path_table(a, 0, &(iso9660->joliet));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- /* Write Type M Path Table */
- ret = write_path_table(a, 1, &(iso9660->joliet));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
- /* Write Directory Descriptors */
- ret = write_directory_descriptors(a, &(iso9660->primary));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- if (iso9660->opt.joliet) {
- ret = write_directory_descriptors(a, &(iso9660->joliet));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
- if (iso9660->opt.rr) {
- /* Write Rockridge ER(Extensions Reference) */
- ret = write_rr_ER(a);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
- /* Write File Descriptors */
- ret = write_file_descriptors(a);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- /* Write Padding */
- if (iso9660->opt.pad) {
- ret = write_null(a, PADDING_BLOCK * LOGICAL_BLOCK_SIZE);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
- if (iso9660->directories_too_deep != NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "%s: Directories too deep.",
- archive_entry_pathname(
- iso9660->directories_too_deep->file->entry));
- return (ARCHIVE_WARN);
- }
- /* Write remaining data out. */
- ret = wb_write_out(a);
- return (ret);
- }
- static int
- iso9660_free(struct archive_write *a)
- {
- struct iso9660 *iso9660;
- int i, ret;
- iso9660 = a->format_data;
- /* Close the temporary file. */
- if (iso9660->temp_fd >= 0)
- close(iso9660->temp_fd);
- /* Free some stuff for zisofs operations. */
- ret = zisofs_free(a);
- /* Remove directory entries in tree which includes file entries. */
- isoent_free_all(iso9660->primary.rootent);
- for (i = 0; i < iso9660->primary.max_depth; i++)
- free(iso9660->primary.pathtbl[i].sorted);
- free(iso9660->primary.pathtbl);
- if (iso9660->opt.joliet) {
- isoent_free_all(iso9660->joliet.rootent);
- for (i = 0; i < iso9660->joliet.max_depth; i++)
- free(iso9660->joliet.pathtbl[i].sorted);
- free(iso9660->joliet.pathtbl);
- }
- /* Remove isofile entries. */
- isofile_free_all_entries(iso9660);
- isofile_free_hardlinks(iso9660);
- archive_string_free(&(iso9660->cur_dirstr));
- archive_string_free(&(iso9660->volume_identifier));
- archive_string_free(&(iso9660->publisher_identifier));
- archive_string_free(&(iso9660->data_preparer_identifier));
- archive_string_free(&(iso9660->application_identifier));
- archive_string_free(&(iso9660->copyright_file_identifier));
- archive_string_free(&(iso9660->abstract_file_identifier));
- archive_string_free(&(iso9660->bibliographic_file_identifier));
- archive_string_free(&(iso9660->el_torito.catalog_filename));
- archive_string_free(&(iso9660->el_torito.boot_filename));
- archive_string_free(&(iso9660->el_torito.id));
- archive_string_free(&(iso9660->utf16be));
- archive_string_free(&(iso9660->mbs));
- free(iso9660);
- a->format_data = NULL;
- return (ret);
- }
- /*
- * Get the System Identifier
- */
- static void
- get_system_identitier(char *system_id, size_t size)
- {
- #if defined(HAVE_SYS_UTSNAME_H)
- struct utsname u;
- uname(&u);
- strncpy(system_id, u.sysname, size-1);
- system_id[size-1] = '\0';
- #elif defined(_WIN32) && !defined(__CYGWIN__)
- strncpy(system_id, "Windows", size-1);
- system_id[size-1] = '\0';
- #else
- #error no way to get the system identifier on your platform.
- #endif
- }
- static void
- set_str(unsigned char *p, const char *s, size_t l, char f, const char *map)
- {
- unsigned char c;
- if (s == NULL)
- s = "";
- while ((c = *s++) != 0 && l > 0) {
- if (c >= 0x80 || map[c] == 0)
- {
- /* illegal character */
- if (c >= 'a' && c <= 'z') {
- /* convert c from a-z to A-Z */
- c -= 0x20;
- } else
- c = 0x5f;
- }
- *p++ = c;
- l--;
- }
- /* If l isn't zero, fill p buffer by the character
- * which indicated by f. */
- if (l > 0)
- memset(p , f, l);
- }
- static inline int
- joliet_allowed_char(unsigned char high, unsigned char low)
- {
- int utf16 = (high << 8) | low;
- if (utf16 <= 0x001F)
- return (0);
- switch (utf16) {
- case 0x002A: /* '*' */
- case 0x002F: /* '/' */
- case 0x003A: /* ':' */
- case 0x003B: /* ';' */
- case 0x003F: /* '?' */
- case 0x005C: /* '\' */
- return (0);/* Not allowed. */
- }
- return (1);
- }
- static int
- set_str_utf16be(struct archive_write *a, unsigned char *p, const char *s,
- size_t l, uint16_t uf, enum vdc vdc)
- {
- size_t size, i;
- int onepad;
- if (s == NULL)
- s = "";
- if (l & 0x01) {
- onepad = 1;
- l &= ~1;
- } else
- onepad = 0;
- if (vdc == VDC_UCS2) {
- struct iso9660 *iso9660 = a->format_data;
- if (archive_strncpy_l(&iso9660->utf16be, s, strlen(s),
- iso9660->sconv_to_utf16be) != 0 && errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for UTF-16BE");
- return (ARCHIVE_FATAL);
- }
- size = iso9660->utf16be.length;
- if (size > l)
- size = l;
- memcpy(p, iso9660->utf16be.s, size);
- } else {
- const uint16_t *u16 = (const uint16_t *)s;
- size = 0;
- while (*u16++)
- size += 2;
- if (size > l)
- size = l;
- memcpy(p, s, size);
- }
- for (i = 0; i < size; i += 2, p += 2) {
- if (!joliet_allowed_char(p[0], p[1]))
- archive_be16enc(p, 0x005F);/* '_' */
- }
- l -= size;
- while (l > 0) {
- archive_be16enc(p, uf);
- p += 2;
- l -= 2;
- }
- if (onepad)
- *p = 0;
- return (ARCHIVE_OK);
- }
- static const char a_characters_map[0x80] = {
- /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
- 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20-2F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30-3F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 60-6F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 70-7F */
- };
- static const char a1_characters_map[0x80] = {
- /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
- 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20-2F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30-3F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60-6F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,/* 70-7F */
- };
- static const char d_characters_map[0x80] = {
- /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 20-2F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,/* 30-3F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 60-6F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 70-7F */
- };
- static const char d1_characters_map[0x80] = {
- /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 00-0F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 10-1F */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 20-2F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,/* 30-3F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40-4F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,/* 50-5F */
- 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60-6F */
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,/* 70-7F */
- };
- static int
- set_str_a_characters_bp(struct archive_write *a, unsigned char *bp,
- int from, int to, const char *s, enum vdc vdc)
- {
- int r;
- switch (vdc) {
- case VDC_STD:
- set_str(bp+from, s, to - from + 1, 0x20,
- a_characters_map);
- r = ARCHIVE_OK;
- break;
- case VDC_LOWERCASE:
- set_str(bp+from, s, to - from + 1, 0x20,
- a1_characters_map);
- r = ARCHIVE_OK;
- break;
- case VDC_UCS2:
- case VDC_UCS2_DIRECT:
- r = set_str_utf16be(a, bp+from, s, to - from + 1,
- 0x0020, vdc);
- break;
- default:
- r = ARCHIVE_FATAL;
- }
- return (r);
- }
- static int
- set_str_d_characters_bp(struct archive_write *a, unsigned char *bp,
- int from, int to, const char *s, enum vdc vdc)
- {
- int r;
- switch (vdc) {
- case VDC_STD:
- set_str(bp+from, s, to - from + 1, 0x20,
- d_characters_map);
- r = ARCHIVE_OK;
- break;
- case VDC_LOWERCASE:
- set_str(bp+from, s, to - from + 1, 0x20,
- d1_characters_map);
- r = ARCHIVE_OK;
- break;
- case VDC_UCS2:
- case VDC_UCS2_DIRECT:
- r = set_str_utf16be(a, bp+from, s, to - from + 1,
- 0x0020, vdc);
- break;
- default:
- r = ARCHIVE_FATAL;
- }
- return (r);
- }
- static void
- set_VD_bp(unsigned char *bp, enum VD_type type, unsigned char ver)
- {
- /* Volume Descriptor Type */
- bp[1] = (unsigned char)type;
- /* Standard Identifier */
- memcpy(bp + 2, "CD001", 5);
- /* Volume Descriptor Version */
- bp[7] = ver;
- }
- static inline void
- set_unused_field_bp(unsigned char *bp, int from, int to)
- {
- memset(bp + from, 0, to - from + 1);
- }
- /*
- * 8-bit unsigned numerical values.
- * ISO9660 Standard 7.1.1
- */
- static inline void
- set_num_711(unsigned char *p, unsigned char value)
- {
- *p = value;
- }
- /*
- * 8-bit signed numerical values.
- * ISO9660 Standard 7.1.2
- */
- static inline void
- set_num_712(unsigned char *p, char value)
- {
- *((char *)p) = value;
- }
- /*
- * Least significant byte first.
- * ISO9660 Standard 7.2.1
- */
- static inline void
- set_num_721(unsigned char *p, uint16_t value)
- {
- archive_le16enc(p, value);
- }
- /*
- * Most significant byte first.
- * ISO9660 Standard 7.2.2
- */
- static inline void
- set_num_722(unsigned char *p, uint16_t value)
- {
- archive_be16enc(p, value);
- }
- /*
- * Both-byte orders.
- * ISO9660 Standard 7.2.3
- */
- static void
- set_num_723(unsigned char *p, uint16_t value)
- {
- archive_le16enc(p, value);
- archive_be16enc(p+2, value);
- }
- /*
- * Least significant byte first.
- * ISO9660 Standard 7.3.1
- */
- static inline void
- set_num_731(unsigned char *p, uint32_t value)
- {
- archive_le32enc(p, value);
- }
- /*
- * Most significant byte first.
- * ISO9660 Standard 7.3.2
- */
- static inline void
- set_num_732(unsigned char *p, uint32_t value)
- {
- archive_be32enc(p, value);
- }
- /*
- * Both-byte orders.
- * ISO9660 Standard 7.3.3
- */
- static inline void
- set_num_733(unsigned char *p, uint32_t value)
- {
- archive_le32enc(p, value);
- archive_be32enc(p+4, value);
- }
- static void
- set_digit(unsigned char *p, size_t s, int value)
- {
- while (s--) {
- p[s] = '0' + (value % 10);
- value /= 10;
- }
- }
- #if defined(HAVE_STRUCT_TM_TM_GMTOFF)
- #define get_gmoffset(tm) ((tm)->tm_gmtoff)
- #elif defined(HAVE_STRUCT_TM___TM_GMTOFF)
- #define get_gmoffset(tm) ((tm)->__tm_gmtoff)
- #else
- static long
- get_gmoffset(struct tm *tm)
- {
- long offset;
- #if defined(HAVE__GET_TIMEZONE)
- _get_timezone(&offset);
- #elif defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
- offset = _timezone;
- #else
- offset = timezone;
- #endif
- offset *= -1;
- if (tm->tm_isdst)
- offset += 3600;
- return (offset);
- }
- #endif
- static void
- get_tmfromtime(struct tm *tm, time_t *t)
- {
- #if HAVE_LOCALTIME_R
- tzset();
- localtime_r(t, tm);
- #elif HAVE__LOCALTIME64_S
- __time64_t tmp_t = (__time64_t) *t; //time_t may be shorter than 64 bits
- _localtime64_s(tm, &tmp_t);
- #else
- memcpy(tm, localtime(t), sizeof(*tm));
- #endif
- }
- /*
- * Date and Time Format.
- * ISO9660 Standard 8.4.26.1
- */
- static void
- set_date_time(unsigned char *p, time_t t)
- {
- struct tm tm;
- get_tmfromtime(&tm, &t);
- set_digit(p, 4, tm.tm_year + 1900);
- set_digit(p+4, 2, tm.tm_mon + 1);
- set_digit(p+6, 2, tm.tm_mday);
- set_digit(p+8, 2, tm.tm_hour);
- set_digit(p+10, 2, tm.tm_min);
- set_digit(p+12, 2, tm.tm_sec);
- set_digit(p+14, 2, 0);
- set_num_712(p+16, (char)(get_gmoffset(&tm)/(60*15)));
- }
- static void
- set_date_time_null(unsigned char *p)
- {
- memset(p, (int)'0', 16);
- p[16] = 0;
- }
- static void
- set_time_915(unsigned char *p, time_t t)
- {
- struct tm tm;
- get_tmfromtime(&tm, &t);
- set_num_711(p+0, tm.tm_year);
- set_num_711(p+1, tm.tm_mon+1);
- set_num_711(p+2, tm.tm_mday);
- set_num_711(p+3, tm.tm_hour);
- set_num_711(p+4, tm.tm_min);
- set_num_711(p+5, tm.tm_sec);
- set_num_712(p+6, (char)(get_gmoffset(&tm)/(60*15)));
- }
- /*
- * Write SUSP "CE" System Use Entry.
- */
- static int
- set_SUSP_CE(unsigned char *p, int location, int offset, int size)
- {
- unsigned char *bp = p -1;
- /* Extend the System Use Area
- * "CE" Format:
- * len ver
- * +----+----+----+----+-----------+-----------+
- * | 'C'| 'E'| 1C | 01 | LOCATION1 | LOCATION2 |
- * +----+----+----+----+-----------+-----------+
- * 0 1 2 3 4 12 20
- * +-----------+
- * | LOCATION3 |
- * +-----------+
- * 20 28
- * LOCATION1 : Location of Continuation of System Use Area.
- * LOCATION2 : Offset to Start of Continuation.
- * LOCATION3 : Length of the Continuation.
- */
- bp[1] = 'C';
- bp[2] = 'E';
- bp[3] = RR_CE_SIZE; /* length */
- bp[4] = 1; /* version */
- set_num_733(bp+5, location);
- set_num_733(bp+13, offset);
- set_num_733(bp+21, size);
- return (RR_CE_SIZE);
- }
- /*
- * The functions, which names are beginning with extra_, are used to
- * control extra records.
- * The maximum size of a Directory Record is 254. When a filename is
- * very long, all of RRIP data of a file won't stored to the Directory
- * Record and so remaining RRIP data store to an extra record instead.
- */
- static unsigned char *
- extra_open_record(unsigned char *bp, int dr_len, struct isoent *isoent,
- struct ctl_extr_rec *ctl)
- {
- ctl->bp = bp;
- if (bp != NULL)
- bp += dr_len;
- ctl->use_extr = 0;
- ctl->isoent = isoent;
- ctl->ce_ptr = NULL;
- ctl->cur_len = ctl->dr_len = dr_len;
- ctl->limit = DR_LIMIT;
- return (bp);
- }
- static void
- extra_close_record(struct ctl_extr_rec *ctl, int ce_size)
- {
- int padding = 0;
- if (ce_size > 0)
- extra_tell_used_size(ctl, ce_size);
- /* Padding. */
- if (ctl->cur_len & 0x01) {
- ctl->cur_len++;
- if (ctl->bp != NULL)
- ctl->bp[ctl->cur_len] = 0;
- padding = 1;
- }
- if (ctl->use_extr) {
- if (ctl->ce_ptr != NULL)
- set_SUSP_CE(ctl->ce_ptr, ctl->extr_loc,
- ctl->extr_off, ctl->cur_len - padding);
- } else
- ctl->dr_len = ctl->cur_len;
- }
- #define extra_space(ctl) ((ctl)->limit - (ctl)->cur_len)
- static unsigned char *
- extra_next_record(struct ctl_extr_rec *ctl, int length)
- {
- int cur_len = ctl->cur_len;/* save cur_len */
- /* Close the current extra record or Directory Record. */
- extra_close_record(ctl, RR_CE_SIZE);
- /* Get a next extra record. */
- ctl->use_extr = 1;
- if (ctl->bp != NULL) {
- /* Storing data into an extra record. */
- unsigned char *p;
- /* Save the pointer where a CE extension will be
- * stored to. */
- ctl->ce_ptr = &ctl->bp[cur_len+1];
- p = extra_get_record(ctl->isoent,
- &ctl->limit, &ctl->extr_off, &ctl->extr_loc);
- ctl->bp = p - 1;/* the base of bp offset is 1. */
- } else
- /* Calculating the size of an extra record. */
- (void)extra_get_record(ctl->isoent,
- &ctl->limit, NULL, NULL);
- ctl->cur_len = 0;
- /* Check if an extra record is almost full.
- * If so, get a next one. */
- if (extra_space(ctl) < length)
- (void)extra_next_record(ctl, length);
- return (ctl->bp);
- }
- static inline struct extr_rec *
- extra_last_record(struct isoent *isoent)
- {
- if (isoent->extr_rec_list.first == NULL)
- return (NULL);
- return ((struct extr_rec *)(void *)
- ((char *)(isoent->extr_rec_list.last)
- - offsetof(struct extr_rec, next)));
- }
- static unsigned char *
- extra_get_record(struct isoent *isoent, int *space, int *off, int *loc)
- {
- struct extr_rec *rec;
- isoent = isoent->parent;
- if (off != NULL) {
- /* Storing data into an extra record. */
- rec = isoent->extr_rec_list.current;
- if (DR_SAFETY > LOGICAL_BLOCK_SIZE - rec->offset)
- rec = rec->next;
- } else {
- /* Calculating the size of an extra record. */
- rec = extra_last_record(isoent);
- if (rec == NULL ||
- DR_SAFETY > LOGICAL_BLOCK_SIZE - rec->offset) {
- rec = malloc(sizeof(*rec));
- if (rec == NULL)
- return (NULL);
- rec->location = 0;
- rec->offset = 0;
- /* Insert `rec` into the tail of isoent->extr_rec_list */
- rec->next = NULL;
- /*
- * Note: testing isoent->extr_rec_list.last == NULL
- * here is really unneeded since it has been already
- * initialized at isoent_new function but Clang Static
- * Analyzer claims that it is dereference of null
- * pointer.
- */
- if (isoent->extr_rec_list.last == NULL)
- isoent->extr_rec_list.last =
- &(isoent->extr_rec_list.first);
- *isoent->extr_rec_list.last = rec;
- isoent->extr_rec_list.last = &(rec->next);
- }
- }
- *space = LOGICAL_BLOCK_SIZE - rec->offset - DR_SAFETY;
- if (*space & 0x01)
- *space -= 1;/* Keep padding space. */
- if (off != NULL)
- *off = rec->offset;
- if (loc != NULL)
- *loc = rec->location;
- isoent->extr_rec_list.current = rec;
- return (&rec->buf[rec->offset]);
- }
- static void
- extra_tell_used_size(struct ctl_extr_rec *ctl, int size)
- {
- struct isoent *isoent;
- struct extr_rec *rec;
- if (ctl->use_extr) {
- isoent = ctl->isoent->parent;
- rec = isoent->extr_rec_list.current;
- if (rec != NULL)
- rec->offset += size;
- }
- ctl->cur_len += size;
- }
- static int
- extra_setup_location(struct isoent *isoent, int location)
- {
- struct extr_rec *rec;
- int cnt;
- cnt = 0;
- rec = isoent->extr_rec_list.first;
- isoent->extr_rec_list.current = rec;
- while (rec) {
- cnt++;
- rec->location = location++;
- rec->offset = 0;
- rec = rec->next;
- }
- return (cnt);
- }
- /*
- * Create the RRIP entries.
- */
- static int
- set_directory_record_rr(unsigned char *bp, int dr_len,
- struct isoent *isoent, struct iso9660 *iso9660, enum dir_rec_type t)
- {
- /* Flags(BP 5) of the Rockridge "RR" System Use Field */
- unsigned char rr_flag;
- #define RR_USE_PX 0x01
- #define RR_USE_PN 0x02
- #define RR_USE_SL 0x04
- #define RR_USE_NM 0x08
- #define RR_USE_CL 0x10
- #define RR_USE_PL 0x20
- #define RR_USE_RE 0x40
- #define RR_USE_TF 0x80
- int length;
- struct ctl_extr_rec ctl;
- struct isoent *rr_parent, *pxent;
- struct isofile *file;
- bp = extra_open_record(bp, dr_len, isoent, &ctl);
- if (t == DIR_REC_PARENT) {
- rr_parent = isoent->rr_parent;
- pxent = isoent->parent;
- if (rr_parent != NULL)
- isoent = rr_parent;
- else
- isoent = isoent->parent;
- } else {
- rr_parent = NULL;
- pxent = isoent;
- }
- file = isoent->file;
- if (t != DIR_REC_NORMAL) {
- rr_flag = RR_USE_PX | RR_USE_TF;
- if (rr_parent != NULL)
- rr_flag |= RR_USE_PL;
- } else {
- rr_flag = RR_USE_PX | RR_USE_NM | RR_USE_TF;
- if (archive_entry_filetype(file->entry) == AE_IFLNK)
- rr_flag |= RR_USE_SL;
- if (isoent->rr_parent != NULL)
- rr_flag |= RR_USE_RE;
- if (isoent->rr_child != NULL)
- rr_flag |= RR_USE_CL;
- if (archive_entry_filetype(file->entry) == AE_IFCHR ||
- archive_entry_filetype(file->entry) == AE_IFBLK)
- rr_flag |= RR_USE_PN;
- #ifdef COMPAT_MKISOFS
- /*
- * mkisofs 2.01.01a63 records "RE" extension to
- * the entry of "rr_moved" directory.
- * I don't understand this behavior.
- */
- if (isoent->virtual &&
- isoent->parent == iso9660->primary.rootent &&
- strcmp(isoent->file->basename.s, "rr_moved") == 0)
- rr_flag |= RR_USE_RE;
- #endif
- }
- /* Write "SP" System Use Entry. */
- if (t == DIR_REC_SELF && isoent == isoent->parent) {
- length = 7;
- if (bp != NULL) {
- bp[1] = 'S';
- bp[2] = 'P';
- bp[3] = length;
- bp[4] = 1; /* version */
- bp[5] = 0xBE; /* Check Byte */
- bp[6] = 0xEF; /* Check Byte */
- bp[7] = 0;
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- }
- /* Write "RR" System Use Entry. */
- length = 5;
- if (extra_space(&ctl) < length)
- bp = extra_next_record(&ctl, length);
- if (bp != NULL) {
- bp[1] = 'R';
- bp[2] = 'R';
- bp[3] = length;
- bp[4] = 1; /* version */
- bp[5] = rr_flag;
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- /* Write "NM" System Use Entry. */
- if (rr_flag & RR_USE_NM) {
- /*
- * "NM" Format:
- * e.g. a basename is 'foo'
- * len ver flg
- * +----+----+----+----+----+----+----+----+
- * | 'N'| 'M'| 08 | 01 | 00 | 'f'| 'o'| 'o'|
- * +----+----+----+----+----+----+----+----+
- * <----------------- len ----------------->
- */
- size_t nmlen = file->basename.length;
- const char *nm = file->basename.s;
- size_t nmmax;
- if (extra_space(&ctl) < 6)
- bp = extra_next_record(&ctl, 6);
- if (bp != NULL) {
- bp[1] = 'N';
- bp[2] = 'M';
- bp[4] = 1; /* version */
- }
- nmmax = extra_space(&ctl);
- if (nmmax > 0xff)
- nmmax = 0xff;
- while (nmlen + 5 > nmmax) {
- length = (int)nmmax;
- if (bp != NULL) {
- bp[3] = length;
- bp[5] = 0x01;/* Alternate Name continues
- * in next "NM" field */
- memcpy(bp+6, nm, length - 5);
- bp += length;
- }
- nmlen -= length - 5;
- nm += length - 5;
- extra_tell_used_size(&ctl, length);
- if (extra_space(&ctl) < 6) {
- bp = extra_next_record(&ctl, 6);
- nmmax = extra_space(&ctl);
- if (nmmax > 0xff)
- nmmax = 0xff;
- }
- if (bp != NULL) {
- bp[1] = 'N';
- bp[2] = 'M';
- bp[4] = 1; /* version */
- }
- }
- length = 5 + (int)nmlen;
- if (bp != NULL) {
- bp[3] = length;
- bp[5] = 0;
- memcpy(bp+6, nm, nmlen);
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- }
- /* Write "PX" System Use Entry. */
- if (rr_flag & RR_USE_PX) {
- /*
- * "PX" Format:
- * len ver
- * +----+----+----+----+-----------+-----------+
- * | 'P'| 'X'| 2C | 01 | FILE MODE | LINKS |
- * +----+----+----+----+-----------+-----------+
- * 0 1 2 3 4 12 20
- * +-----------+-----------+------------------+
- * | USER ID | GROUP ID |FILE SERIAL NUMBER|
- * +-----------+-----------+------------------+
- * 20 28 36 44
- */
- length = 44;
- if (extra_space(&ctl) < length)
- bp = extra_next_record(&ctl, length);
- if (bp != NULL) {
- mode_t mode;
- int64_t uid;
- int64_t gid;
- mode = archive_entry_mode(file->entry);
- uid = archive_entry_uid(file->entry);
- gid = archive_entry_gid(file->entry);
- if (iso9660->opt.rr == OPT_RR_USEFUL) {
- /*
- * This action is similar to mkisofs -r option
- * but our rockridge=useful option does not
- * set a zero to uid and gid.
- */
- /* set all read bit ON */
- mode |= 0444;
- #if !defined(_WIN32) && !defined(__CYGWIN__)
- if (mode & 0111)
- #endif
- /* set all exec bit ON */
- mode |= 0111;
- /* clear all write bits. */
- mode &= ~0222;
- /* clear setuid,setgid,sticky bits. */
- mode &= ~07000;
- }
- bp[1] = 'P';
- bp[2] = 'X';
- bp[3] = length;
- bp[4] = 1; /* version */
- /* file mode */
- set_num_733(bp+5, mode);
- /* file links (stat.st_nlink) */
- set_num_733(bp+13,
- archive_entry_nlink(file->entry));
- set_num_733(bp+21, (uint32_t)uid);
- set_num_733(bp+29, (uint32_t)gid);
- /* File Serial Number */
- if (pxent->dir)
- set_num_733(bp+37, pxent->dir_location);
- else if (file->hardlink_target != NULL)
- set_num_733(bp+37,
- file->hardlink_target->cur_content->location);
- else
- set_num_733(bp+37,
- file->cur_content->location);
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- }
- /* Write "SL" System Use Entry. */
- if (rr_flag & RR_USE_SL) {
- /*
- * "SL" Format:
- * e.g. a symbolic name is 'foo/bar'
- * len ver flg
- * +----+----+----+----+----+------------+
- * | 'S'| 'L'| 0F | 01 | 00 | components |
- * +----+----+----+----+----+-----+------+
- * 0 1 2 3 4 5 ...|... 15
- * <----------------- len --------+------>
- * components : |
- * cflg clen |
- * +----+----+----+----+----+ |
- * | 00 | 03 | 'f'| 'o'| 'o'| <---+
- * +----+----+----+----+----+ |
- * 5 6 7 8 9 10 |
- * cflg clen |
- * +----+----+----+----+----+ |
- * | 00 | 03 | 'b'| 'a'| 'r'| <---+
- * +----+----+----+----+----+
- * 10 11 12 13 14 15
- *
- * - cflg : flag of component
- * - clen : length of component
- */
- const char *sl;
- char sl_last;
- if (extra_space(&ctl) < 7)
- bp = extra_next_record(&ctl, 7);
- sl = file->symlink.s;
- sl_last = '\0';
- if (bp != NULL) {
- bp[1] = 'S';
- bp[2] = 'L';
- bp[4] = 1; /* version */
- }
- for (;;) {
- unsigned char *nc, *cf, *cl, cldmy = 0;
- int sllen, slmax;
- slmax = extra_space(&ctl);
- if (slmax > 0xff)
- slmax = 0xff;
- if (bp != NULL)
- nc = &bp[6];
- else
- nc = NULL;
- cf = cl = NULL;
- sllen = 0;
- while (*sl && sllen + 11 < slmax) {
- if (sl_last == '\0' && sl[0] == '/') {
- /*
- * flg len
- * +----+----+
- * | 08 | 00 | ROOT component.
- * +----+----+ ("/")
- *
- * Root component has to appear
- * at the first component only.
- */
- if (nc != NULL) {
- cf = nc++;
- *cf = 0x08; /* ROOT */
- *nc++ = 0;
- }
- sllen += 2;
- sl++;
- sl_last = '/';
- cl = NULL;
- continue;
- }
- if (((sl_last == '\0' || sl_last == '/') &&
- sl[0] == '.' && sl[1] == '.' &&
- (sl[2] == '/' || sl[2] == '\0')) ||
- (sl[0] == '/' &&
- sl[1] == '.' && sl[2] == '.' &&
- (sl[3] == '/' || sl[3] == '\0'))) {
- /*
- * flg len
- * +----+----+
- * | 04 | 00 | PARENT component.
- * +----+----+ ("..")
- */
- if (nc != NULL) {
- cf = nc++;
- *cf = 0x04; /* PARENT */
- *nc++ = 0;
- }
- sllen += 2;
- if (sl[0] == '/')
- sl += 3;/* skip "/.." */
- else
- sl += 2;/* skip ".." */
- sl_last = '.';
- cl = NULL;
- continue;
- }
- if (((sl_last == '\0' || sl_last == '/') &&
- sl[0] == '.' &&
- (sl[1] == '/' || sl[1] == '\0')) ||
- (sl[0] == '/' && sl[1] == '.' &&
- (sl[2] == '/' || sl[2] == '\0'))) {
- /*
- * flg len
- * +----+----+
- * | 02 | 00 | CURRENT component.
- * +----+----+ (".")
- */
- if (nc != NULL) {
- cf = nc++;
- *cf = 0x02; /* CURRENT */
- *nc++ = 0;
- }
- sllen += 2;
- if (sl[0] == '/')
- sl += 2;/* skip "/." */
- else
- sl ++; /* skip "." */
- sl_last = '.';
- cl = NULL;
- continue;
- }
- if (sl[0] == '/' || cl == NULL) {
- if (nc != NULL) {
- cf = nc++;
- *cf = 0;
- cl = nc++;
- *cl = 0;
- } else
- cl = &cldmy;
- sllen += 2;
- if (sl[0] == '/') {
- sl_last = *sl++;
- continue;
- }
- }
- sl_last = *sl++;
- if (nc != NULL) {
- *nc++ = sl_last;
- (*cl) ++;
- }
- sllen++;
- }
- if (*sl) {
- length = 5 + sllen;
- if (bp != NULL) {
- /*
- * Mark flg as CONTINUE component.
- */
- *cf |= 0x01;
- /*
- * len ver flg
- * +----+----+----+----+----+-
- * | 'S'| 'L'| XX | 01 | 01 |
- * +----+----+----+----+----+-
- * ^
- * continues in next "SL"
- */
- bp[3] = length;
- bp[5] = 0x01;/* This Symbolic Link
- * continues in next
- * "SL" field */
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- if (extra_space(&ctl) < 11)
- bp = extra_next_record(&ctl, 11);
- if (bp != NULL) {
- /* Next 'SL' */
- bp[1] = 'S';
- bp[2] = 'L';
- bp[4] = 1; /* version */
- }
- } else {
- length = 5 + sllen;
- if (bp != NULL) {
- bp[3] = length;
- bp[5] = 0;
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- break;
- }
- }
- }
- /* Write "TF" System Use Entry. */
- if (rr_flag & RR_USE_TF) {
- /*
- * "TF" Format:
- * len ver
- * +----+----+----+----+-----+-------------+
- * | 'T'| 'F'| XX | 01 |FLAGS| TIME STAMPS |
- * +----+----+----+----+-----+-------------+
- * 0 1 2 3 4 5 XX
- * TIME STAMPS : ISO 9660 Standard 9.1.5.
- * If TF_LONG_FORM FLAGS is set,
- * use ISO9660 Standard 8.4.26.1.
- */
- #define TF_CREATION 0x01 /* Creation time recorded */
- #define TF_MODIFY 0x02 /* Modification time recorded */
- #define TF_ACCESS 0x04 /* Last Access time recorded */
- #define TF_ATTRIBUTES 0x08 /* Last Attribute Change time recorded */
- #define TF_BACKUP 0x10 /* Last Backup time recorded */
- #define TF_EXPIRATION 0x20 /* Expiration time recorded */
- #define TF_EFFECTIVE 0x40 /* Effective time recorded */
- #define TF_LONG_FORM 0x80 /* ISO 9660 17-byte time format used */
- unsigned char tf_flags;
- length = 5;
- tf_flags = 0;
- #ifndef COMPAT_MKISOFS
- if (archive_entry_birthtime_is_set(file->entry) &&
- archive_entry_birthtime(file->entry) <=
- archive_entry_mtime(file->entry)) {
- length += 7;
- tf_flags |= TF_CREATION;
- }
- #endif
- if (archive_entry_mtime_is_set(file->entry)) {
- length += 7;
- tf_flags |= TF_MODIFY;
- }
- if (archive_entry_atime_is_set(file->entry)) {
- length += 7;
- tf_flags |= TF_ACCESS;
- }
- if (archive_entry_ctime_is_set(file->entry)) {
- length += 7;
- tf_flags |= TF_ATTRIBUTES;
- }
- if (extra_space(&ctl) < length)
- bp = extra_next_record(&ctl, length);
- if (bp != NULL) {
- bp[1] = 'T';
- bp[2] = 'F';
- bp[3] = length;
- bp[4] = 1; /* version */
- bp[5] = tf_flags;
- bp += 5;
- /* Creation time */
- if (tf_flags & TF_CREATION) {
- set_time_915(bp+1,
- archive_entry_birthtime(file->entry));
- bp += 7;
- }
- /* Modification time */
- if (tf_flags & TF_MODIFY) {
- set_time_915(bp+1,
- archive_entry_mtime(file->entry));
- bp += 7;
- }
- /* Last Access time */
- if (tf_flags & TF_ACCESS) {
- set_time_915(bp+1,
- archive_entry_atime(file->entry));
- bp += 7;
- }
- /* Last Attribute Change time */
- if (tf_flags & TF_ATTRIBUTES) {
- set_time_915(bp+1,
- archive_entry_ctime(file->entry));
- bp += 7;
- }
- }
- extra_tell_used_size(&ctl, length);
- }
- /* Write "RE" System Use Entry. */
- if (rr_flag & RR_USE_RE) {
- /*
- * "RE" Format:
- * len ver
- * +----+----+----+----+
- * | 'R'| 'E'| 04 | 01 |
- * +----+----+----+----+
- * 0 1 2 3 4
- */
- length = 4;
- if (extra_space(&ctl) < length)
- bp = extra_next_record(&ctl, length);
- if (bp != NULL) {
- bp[1] = 'R';
- bp[2] = 'E';
- bp[3] = length;
- bp[4] = 1; /* version */
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- }
- /* Write "PL" System Use Entry. */
- if (rr_flag & RR_USE_PL) {
- /*
- * "PL" Format:
- * len ver
- * +----+----+----+----+------------+
- * | 'P'| 'L'| 0C | 01 | *LOCATION |
- * +----+----+----+----+------------+
- * 0 1 2 3 4 12
- * *LOCATION: location of parent directory
- */
- length = 12;
- if (extra_space(&ctl) < length)
- bp = extra_next_record(&ctl, length);
- if (bp != NULL) {
- bp[1] = 'P';
- bp[2] = 'L';
- bp[3] = length;
- bp[4] = 1; /* version */
- set_num_733(bp + 5,
- rr_parent->dir_location);
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- }
- /* Write "CL" System Use Entry. */
- if (rr_flag & RR_USE_CL) {
- /*
- * "CL" Format:
- * len ver
- * +----+----+----+----+------------+
- * | 'C'| 'L'| 0C | 01 | *LOCATION |
- * +----+----+----+----+------------+
- * 0 1 2 3 4 12
- * *LOCATION: location of child directory
- */
- length = 12;
- if (extra_space(&ctl) < length)
- bp = extra_next_record(&ctl, length);
- if (bp != NULL) {
- bp[1] = 'C';
- bp[2] = 'L';
- bp[3] = length;
- bp[4] = 1; /* version */
- set_num_733(bp + 5,
- isoent->rr_child->dir_location);
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- }
- /* Write "PN" System Use Entry. */
- if (rr_flag & RR_USE_PN) {
- /*
- * "PN" Format:
- * len ver
- * +----+----+----+----+------------+------------+
- * | 'P'| 'N'| 14 | 01 | dev_t high | dev_t low |
- * +----+----+----+----+------------+------------+
- * 0 1 2 3 4 12 20
- */
- length = 20;
- if (extra_space(&ctl) < length)
- bp = extra_next_record(&ctl, length);
- if (bp != NULL) {
- uint64_t dev;
- bp[1] = 'P';
- bp[2] = 'N';
- bp[3] = length;
- bp[4] = 1; /* version */
- dev = (uint64_t)archive_entry_rdev(file->entry);
- set_num_733(bp + 5, (uint32_t)(dev >> 32));
- set_num_733(bp + 13, (uint32_t)(dev & 0xFFFFFFFF));
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- }
- /* Write "ZF" System Use Entry. */
- if (file->zisofs.header_size) {
- /*
- * "ZF" Format:
- * len ver
- * +----+----+----+----+----+----+-------------+
- * | 'Z'| 'F'| 10 | 01 | 'p'| 'z'| Header Size |
- * +----+----+----+----+----+----+-------------+
- * 0 1 2 3 4 5 6 7
- * +--------------------+-------------------+
- * | Log2 of block Size | Uncompressed Size |
- * +--------------------+-------------------+
- * 7 8 16
- */
- length = 16;
- if (extra_space(&ctl) < length)
- bp = extra_next_record(&ctl, length);
- if (bp != NULL) {
- bp[1] = 'Z';
- bp[2] = 'F';
- bp[3] = length;
- bp[4] = 1; /* version */
- bp[5] = 'p';
- bp[6] = 'z';
- bp[7] = file->zisofs.header_size;
- bp[8] = file->zisofs.log2_bs;
- set_num_733(bp + 9, file->zisofs.uncompressed_size);
- bp += length;
- }
- extra_tell_used_size(&ctl, length);
- }
- /* Write "CE" System Use Entry. */
- if (t == DIR_REC_SELF && isoent == isoent->parent) {
- length = RR_CE_SIZE;
- if (bp != NULL)
- set_SUSP_CE(bp+1, iso9660->location_rrip_er,
- 0, RRIP_ER_SIZE);
- extra_tell_used_size(&ctl, length);
- }
- extra_close_record(&ctl, 0);
- return (ctl.dr_len);
- }
- /*
- * Write data of a Directory Record or calculate writing bytes itself.
- * If parameter `p' is NULL, calculates the size of writing data, which
- * a Directory Record needs to write, then it saved and return
- * the calculated size.
- * Parameter `n' is a remaining size of buffer. when parameter `p' is
- * not NULL, check whether that `n' is not less than the saved size.
- * if that `n' is small, return zero.
- *
- * This format of the Directory Record is according to
- * ISO9660 Standard 9.1
- */
- static int
- set_directory_record(unsigned char *p, size_t n, struct isoent *isoent,
- struct iso9660 *iso9660, enum dir_rec_type t,
- enum vdd_type vdd_type)
- {
- unsigned char *bp;
- size_t dr_len;
- size_t fi_len;
- if (p != NULL) {
- /*
- * Check whether a write buffer size is less than the
- * saved size which is needed to write this Directory
- * Record.
- */
- switch (t) {
- case DIR_REC_VD:
- dr_len = isoent->dr_len.vd; break;
- case DIR_REC_SELF:
- dr_len = isoent->dr_len.self; break;
- case DIR_REC_PARENT:
- dr_len = isoent->dr_len.parent; break;
- case DIR_REC_NORMAL:
- default:
- dr_len = isoent->dr_len.normal; break;
- }
- if (dr_len > n)
- return (0);/* Needs more buffer size. */
- }
- if (t == DIR_REC_NORMAL && isoent->identifier != NULL)
- fi_len = isoent->id_len;
- else
- fi_len = 1;
- if (p != NULL) {
- struct isoent *xisoent;
- struct isofile *file;
- unsigned char flag;
- if (t == DIR_REC_PARENT)
- xisoent = isoent->parent;
- else
- xisoent = isoent;
- file = isoent->file;
- if (file->hardlink_target != NULL)
- file = file->hardlink_target;
- /* Make a file flag. */
- if (xisoent->dir)
- flag = FILE_FLAG_DIRECTORY;
- else {
- if (file->cur_content->next != NULL)
- flag = FILE_FLAG_MULTI_EXTENT;
- else
- flag = 0;
- }
- bp = p -1;
- /* Extended Attribute Record Length */
- set_num_711(bp+2, 0);
- /* Location of Extent */
- if (xisoent->dir)
- set_num_733(bp+3, xisoent->dir_location);
- else
- set_num_733(bp+3, file->cur_content->location);
- /* Data Length */
- if (xisoent->dir)
- set_num_733(bp+11,
- xisoent->dir_block * LOGICAL_BLOCK_SIZE);
- else
- set_num_733(bp+11, (uint32_t)file->cur_content->size);
- /* Recording Date and Time */
- /* NOTE:
- * If a file type is symbolic link, you are seeing this
- * field value is different from a value mkisofs makes.
- * libarchive uses lstat to get this one, but it
- * seems mkisofs uses stat to get.
- */
- set_time_915(bp+19,
- archive_entry_mtime(xisoent->file->entry));
- /* File Flags */
- bp[26] = flag;
- /* File Unit Size */
- set_num_711(bp+27, 0);
- /* Interleave Gap Size */
- set_num_711(bp+28, 0);
- /* Volume Sequence Number */
- set_num_723(bp+29, iso9660->volume_sequence_number);
- /* Length of File Identifier */
- set_num_711(bp+33, (unsigned char)fi_len);
- /* File Identifier */
- switch (t) {
- case DIR_REC_VD:
- case DIR_REC_SELF:
- set_num_711(bp+34, 0);
- break;
- case DIR_REC_PARENT:
- set_num_711(bp+34, 1);
- break;
- case DIR_REC_NORMAL:
- if (isoent->identifier != NULL)
- memcpy(bp+34, isoent->identifier, fi_len);
- else
- set_num_711(bp+34, 0);
- break;
- }
- } else
- bp = NULL;
- dr_len = 33 + fi_len;
- /* Padding Field */
- if (dr_len & 0x01) {
- dr_len ++;
- if (p != NULL)
- bp[dr_len] = 0;
- }
- /* Volume Descriptor does not record extension. */
- if (t == DIR_REC_VD) {
- if (p != NULL)
- /* Length of Directory Record */
- set_num_711(p, (unsigned char)dr_len);
- else
- isoent->dr_len.vd = (int)dr_len;
- return ((int)dr_len);
- }
- /* Rockridge */
- if (iso9660->opt.rr && vdd_type != VDD_JOLIET)
- dr_len = set_directory_record_rr(bp, (int)dr_len,
- isoent, iso9660, t);
- if (p != NULL)
- /* Length of Directory Record */
- set_num_711(p, (unsigned char)dr_len);
- else {
- /*
- * Save the size which is needed to write this
- * Directory Record.
- */
- switch (t) {
- case DIR_REC_VD:
- /* This case does not come, but compiler
- * complains that DIR_REC_VD not handled
- * in switch .... */
- break;
- case DIR_REC_SELF:
- isoent->dr_len.self = (int)dr_len; break;
- case DIR_REC_PARENT:
- isoent->dr_len.parent = (int)dr_len; break;
- case DIR_REC_NORMAL:
- isoent->dr_len.normal = (int)dr_len; break;
- }
- }
- return ((int)dr_len);
- }
- /*
- * Calculate the size of a directory record.
- */
- static inline int
- get_dir_rec_size(struct iso9660 *iso9660, struct isoent *isoent,
- enum dir_rec_type t, enum vdd_type vdd_type)
- {
- return (set_directory_record(NULL, SIZE_MAX,
- isoent, iso9660, t, vdd_type));
- }
- /*
- * Manage to write ISO-image data with wbuff to reduce calling
- * __archive_write_output() for performance.
- */
- static inline unsigned char *
- wb_buffptr(struct archive_write *a)
- {
- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
- return (&(iso9660->wbuff[sizeof(iso9660->wbuff)
- - iso9660->wbuff_remaining]));
- }
- static int
- wb_write_out(struct archive_write *a)
- {
- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
- size_t wsize, nw;
- int r;
- wsize = sizeof(iso9660->wbuff) - iso9660->wbuff_remaining;
- nw = wsize % LOGICAL_BLOCK_SIZE;
- if (iso9660->wbuff_type == WB_TO_STREAM)
- r = __archive_write_output(a, iso9660->wbuff, wsize - nw);
- else
- r = write_to_temp(a, iso9660->wbuff, wsize - nw);
- /* Increase the offset. */
- iso9660->wbuff_offset += wsize - nw;
- if (iso9660->wbuff_offset > iso9660->wbuff_written)
- iso9660->wbuff_written = iso9660->wbuff_offset;
- iso9660->wbuff_remaining = sizeof(iso9660->wbuff);
- if (nw) {
- iso9660->wbuff_remaining -= nw;
- memmove(iso9660->wbuff, iso9660->wbuff + wsize - nw, nw);
- }
- return (r);
- }
- static int
- wb_consume(struct archive_write *a, size_t size)
- {
- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
- if (size > iso9660->wbuff_remaining ||
- iso9660->wbuff_remaining == 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal Programming error: iso9660:wb_consume()"
- " size=%jd, wbuff_remaining=%jd",
- (intmax_t)size, (intmax_t)iso9660->wbuff_remaining);
- return (ARCHIVE_FATAL);
- }
- iso9660->wbuff_remaining -= size;
- if (iso9660->wbuff_remaining < LOGICAL_BLOCK_SIZE)
- return (wb_write_out(a));
- return (ARCHIVE_OK);
- }
- #ifdef HAVE_ZLIB_H
- static int
- wb_set_offset(struct archive_write *a, int64_t off)
- {
- struct iso9660 *iso9660 = (struct iso9660 *)a->format_data;
- int64_t used, ext_bytes;
- if (iso9660->wbuff_type != WB_TO_TEMP) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal Programming error: iso9660:wb_set_offset()");
- return (ARCHIVE_FATAL);
- }
- used = sizeof(iso9660->wbuff) - iso9660->wbuff_remaining;
- if (iso9660->wbuff_offset + used > iso9660->wbuff_tail)
- iso9660->wbuff_tail = iso9660->wbuff_offset + used;
- if (iso9660->wbuff_offset < iso9660->wbuff_written) {
- if (used > 0 &&
- write_to_temp(a, iso9660->wbuff, (size_t)used) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- iso9660->wbuff_offset = iso9660->wbuff_written;
- lseek(iso9660->temp_fd, iso9660->wbuff_offset, SEEK_SET);
- iso9660->wbuff_remaining = sizeof(iso9660->wbuff);
- used = 0;
- }
- if (off < iso9660->wbuff_offset) {
- /*
- * Write out waiting data.
- */
- if (used > 0) {
- if (wb_write_out(a) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
- lseek(iso9660->temp_fd, off, SEEK_SET);
- iso9660->wbuff_offset = off;
- iso9660->wbuff_remaining = sizeof(iso9660->wbuff);
- } else if (off <= iso9660->wbuff_tail) {
- iso9660->wbuff_remaining = (size_t)
- (sizeof(iso9660->wbuff) - (off - iso9660->wbuff_offset));
- } else {
- ext_bytes = off - iso9660->wbuff_tail;
- iso9660->wbuff_remaining = (size_t)(sizeof(iso9660->wbuff)
- - (iso9660->wbuff_tail - iso9660->wbuff_offset));
- while (ext_bytes >= (int64_t)iso9660->wbuff_remaining) {
- if (write_null(a, (size_t)iso9660->wbuff_remaining)
- != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- ext_bytes -= iso9660->wbuff_remaining;
- }
- if (ext_bytes > 0) {
- if (write_null(a, (size_t)ext_bytes) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- }
- }
- return (ARCHIVE_OK);
- }
- #endif /* HAVE_ZLIB_H */
- static int
- write_null(struct archive_write *a, size_t size)
- {
- size_t remaining;
- unsigned char *p, *old;
- int r;
- remaining = wb_remaining(a);
- p = wb_buffptr(a);
- if (size <= remaining) {
- memset(p, 0, size);
- return (wb_consume(a, size));
- }
- memset(p, 0, remaining);
- r = wb_consume(a, remaining);
- if (r != ARCHIVE_OK)
- return (r);
- size -= remaining;
- old = p;
- p = wb_buffptr(a);
- memset(p, 0, old - p);
- remaining = wb_remaining(a);
- while (size) {
- size_t wsize = size;
- if (wsize > remaining)
- wsize = remaining;
- r = wb_consume(a, wsize);
- if (r != ARCHIVE_OK)
- return (r);
- size -= wsize;
- }
- return (ARCHIVE_OK);
- }
- /*
- * Write Volume Descriptor Set Terminator
- */
- static int
- write_VD_terminator(struct archive_write *a)
- {
- unsigned char *bp;
- bp = wb_buffptr(a) -1;
- set_VD_bp(bp, VDT_TERMINATOR, 1);
- set_unused_field_bp(bp, 8, LOGICAL_BLOCK_SIZE);
- return (wb_consume(a, LOGICAL_BLOCK_SIZE));
- }
- static int
- set_file_identifier(unsigned char *bp, int from, int to, enum vdc vdc,
- struct archive_write *a, struct vdd *vdd, struct archive_string *id,
- const char *label, int leading_under, enum char_type char_type)
- {
- char identifier[256];
- struct isoent *isoent;
- const char *ids;
- size_t len;
- int r;
- if (id->length > 0 && leading_under && id->s[0] != '_') {
- if (char_type == A_CHAR)
- r = set_str_a_characters_bp(a, bp, from, to, id->s, vdc);
- else
- r = set_str_d_characters_bp(a, bp, from, to, id->s, vdc);
- } else if (id->length > 0) {
- ids = id->s;
- if (leading_under)
- ids++;
- isoent = isoent_find_entry(vdd->rootent, ids);
- if (isoent == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Not Found %s `%s'.",
- label, ids);
- return (ARCHIVE_FATAL);
- }
- len = isoent->ext_off + isoent->ext_len;
- if (vdd->vdd_type == VDD_JOLIET) {
- if (len > sizeof(identifier)-2)
- len = sizeof(identifier)-2;
- } else {
- if (len > sizeof(identifier)-1)
- len = sizeof(identifier)-1;
- }
- memcpy(identifier, isoent->identifier, len);
- identifier[len] = '\0';
- if (vdd->vdd_type == VDD_JOLIET) {
- identifier[len+1] = 0;
- vdc = VDC_UCS2_DIRECT;
- }
- if (char_type == A_CHAR)
- r = set_str_a_characters_bp(a, bp, from, to,
- identifier, vdc);
- else
- r = set_str_d_characters_bp(a, bp, from, to,
- identifier, vdc);
- } else {
- if (char_type == A_CHAR)
- r = set_str_a_characters_bp(a, bp, from, to, NULL, vdc);
- else
- r = set_str_d_characters_bp(a, bp, from, to, NULL, vdc);
- }
- return (r);
- }
- /*
- * Write Primary/Supplementary Volume Descriptor
- */
- static int
- write_VD(struct archive_write *a, struct vdd *vdd)
- {
- struct iso9660 *iso9660;
- unsigned char *bp;
- uint16_t volume_set_size = 1;
- char identifier[256];
- enum VD_type vdt;
- enum vdc vdc;
- unsigned char vd_ver, fst_ver;
- int r;
- iso9660 = a->format_data;
- switch (vdd->vdd_type) {
- case VDD_JOLIET:
- vdt = VDT_SUPPLEMENTARY;
- vd_ver = fst_ver = 1;
- vdc = VDC_UCS2;
- break;
- case VDD_ENHANCED:
- vdt = VDT_SUPPLEMENTARY;
- vd_ver = fst_ver = 2;
- vdc = VDC_LOWERCASE;
- break;
- case VDD_PRIMARY:
- default:
- vdt = VDT_PRIMARY;
- vd_ver = fst_ver = 1;
- #ifdef COMPAT_MKISOFS
- vdc = VDC_LOWERCASE;
- #else
- vdc = VDC_STD;
- #endif
- break;
- }
- bp = wb_buffptr(a) -1;
- /* Volume Descriptor Type */
- set_VD_bp(bp, vdt, vd_ver);
- /* Unused Field */
- set_unused_field_bp(bp, 8, 8);
- /* System Identifier */
- get_system_identitier(identifier, sizeof(identifier));
- r = set_str_a_characters_bp(a, bp, 9, 40, identifier, vdc);
- if (r != ARCHIVE_OK)
- return (r);
- /* Volume Identifier */
- r = set_str_d_characters_bp(a, bp, 41, 72,
- iso9660->volume_identifier.s, vdc);
- if (r != ARCHIVE_OK)
- return (r);
- /* Unused Field */
- set_unused_field_bp(bp, 73, 80);
- /* Volume Space Size */
- set_num_733(bp+81, iso9660->volume_space_size);
- if (vdd->vdd_type == VDD_JOLIET) {
- /* Escape Sequences */
- bp[89] = 0x25;/* UCS-2 Level 3 */
- bp[90] = 0x2F;
- bp[91] = 0x45;
- memset(bp + 92, 0, 120 - 92 + 1);
- } else {
- /* Unused Field */
- set_unused_field_bp(bp, 89, 120);
- }
- /* Volume Set Size */
- set_num_723(bp+121, volume_set_size);
- /* Volume Sequence Number */
- set_num_723(bp+125, iso9660->volume_sequence_number);
- /* Logical Block Size */
- set_num_723(bp+129, LOGICAL_BLOCK_SIZE);
- /* Path Table Size */
- set_num_733(bp+133, vdd->path_table_size);
- /* Location of Occurrence of Type L Path Table */
- set_num_731(bp+141, vdd->location_type_L_path_table);
- /* Location of Optional Occurrence of Type L Path Table */
- set_num_731(bp+145, 0);
- /* Location of Occurrence of Type M Path Table */
- set_num_732(bp+149, vdd->location_type_M_path_table);
- /* Location of Optional Occurrence of Type M Path Table */
- set_num_732(bp+153, 0);
- /* Directory Record for Root Directory(BP 157 to 190) */
- set_directory_record(bp+157, 190-157+1, vdd->rootent,
- iso9660, DIR_REC_VD, vdd->vdd_type);
- /* Volume Set Identifier */
- r = set_str_d_characters_bp(a, bp, 191, 318, "", vdc);
- if (r != ARCHIVE_OK)
- return (r);
- /* Publisher Identifier */
- r = set_file_identifier(bp, 319, 446, vdc, a, vdd,
- &(iso9660->publisher_identifier),
- "Publisher File", 1, A_CHAR);
- if (r != ARCHIVE_OK)
- return (r);
- /* Data Preparer Identifier */
- r = set_file_identifier(bp, 447, 574, vdc, a, vdd,
- &(iso9660->data_preparer_identifier),
- "Data Preparer File", 1, A_CHAR);
- if (r != ARCHIVE_OK)
- return (r);
- /* Application Identifier */
- r = set_file_identifier(bp, 575, 702, vdc, a, vdd,
- &(iso9660->application_identifier),
- "Application File", 1, A_CHAR);
- if (r != ARCHIVE_OK)
- return (r);
- /* Copyright File Identifier */
- r = set_file_identifier(bp, 703, 739, vdc, a, vdd,
- &(iso9660->copyright_file_identifier),
- "Copyright File", 0, D_CHAR);
- if (r != ARCHIVE_OK)
- return (r);
- /* Abstract File Identifier */
- r = set_file_identifier(bp, 740, 776, vdc, a, vdd,
- &(iso9660->abstract_file_identifier),
- "Abstract File", 0, D_CHAR);
- if (r != ARCHIVE_OK)
- return (r);
- /* Bibliographic File Identifier */
- r = set_file_identifier(bp, 777, 813, vdc, a, vdd,
- &(iso9660->bibliographic_file_identifier),
- "Bibliongraphic File", 0, D_CHAR);
- if (r != ARCHIVE_OK)
- return (r);
- /* Volume Creation Date and Time */
- set_date_time(bp+814, iso9660->birth_time);
- /* Volume Modification Date and Time */
- set_date_time(bp+831, iso9660->birth_time);
- /* Volume Expiration Date and Time(obsolete) */
- set_date_time_null(bp+848);
- /* Volume Effective Date and Time */
- set_date_time(bp+865, iso9660->birth_time);
- /* File Structure Version */
- bp[882] = fst_ver;
- /* Reserved */
- bp[883] = 0;
- /* Application Use */
- memset(bp + 884, 0x20, 1395 - 884 + 1);
- /* Reserved */
- set_unused_field_bp(bp, 1396, LOGICAL_BLOCK_SIZE);
- return (wb_consume(a, LOGICAL_BLOCK_SIZE));
- }
- /*
- * Write Boot Record Volume Descriptor
- */
- static int
- write_VD_boot_record(struct archive_write *a)
- {
- struct iso9660 *iso9660;
- unsigned char *bp;
- iso9660 = a->format_data;
- bp = wb_buffptr(a) -1;
- /* Volume Descriptor Type */
- set_VD_bp(bp, VDT_BOOT_RECORD, 1);
- /* Boot System Identifier */
- memcpy(bp+8, "EL TORITO SPECIFICATION", 23);
- set_unused_field_bp(bp, 8+23, 39);
- /* Unused */
- set_unused_field_bp(bp, 40, 71);
- /* Absolute pointer to first sector of Boot Catalog */
- set_num_731(bp+72,
- iso9660->el_torito.catalog->file->content.location);
- /* Unused */
- set_unused_field_bp(bp, 76, LOGICAL_BLOCK_SIZE);
- return (wb_consume(a, LOGICAL_BLOCK_SIZE));
- }
- enum keytype {
- KEY_FLG,
- KEY_STR,
- KEY_INT,
- KEY_HEX
- };
- static void
- set_option_info(struct archive_string *info, int *opt, const char *key,
- enum keytype type, ...)
- {
- va_list ap;
- char prefix;
- const char *s;
- int d;
- prefix = (*opt==0)? ' ':',';
- va_start(ap, type);
- switch (type) {
- case KEY_FLG:
- d = va_arg(ap, int);
- archive_string_sprintf(info, "%c%s%s",
- prefix, (d == 0)?"!":"", key);
- break;
- case KEY_STR:
- s = va_arg(ap, const char *);
- archive_string_sprintf(info, "%c%s=%s",
- prefix, key, s);
- break;
- case KEY_INT:
- d = va_arg(ap, int);
- archive_string_sprintf(info, "%c%s=%d",
- prefix, key, d);
- break;
- case KEY_HEX:
- d = va_arg(ap, int);
- archive_string_sprintf(info, "%c%s=%x",
- prefix, key, d);
- break;
- }
- va_end(ap);
- *opt = 1;
- }
- /*
- * Make Non-ISO File System Information
- */
- static int
- write_information_block(struct archive_write *a)
- {
- struct iso9660 *iso9660;
- char buf[128];
- const char *v;
- int opt, r;
- struct archive_string info;
- size_t info_size = LOGICAL_BLOCK_SIZE *
- NON_ISO_FILE_SYSTEM_INFORMATION_BLOCK;
- iso9660 = (struct iso9660 *)a->format_data;
- if (info_size > wb_remaining(a)) {
- r = wb_write_out(a);
- if (r != ARCHIVE_OK)
- return (r);
- }
- archive_string_init(&info);
- if (archive_string_ensure(&info, info_size) == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- memset(info.s, 0, info_size);
- opt = 0;
- #if defined(HAVE__CTIME64_S)
- {
- __time64_t iso9660_birth_time_tmp = (__time64_t) iso9660->birth_time; //time_t may be shorter than 64 bits
- _ctime64_s(buf, sizeof(buf), &(iso9660_birth_time_tmp));
- }
- #elif defined(HAVE_CTIME_R)
- ctime_r(&(iso9660->birth_time), buf);
- #else
- strncpy(buf, ctime(&(iso9660->birth_time)), sizeof(buf)-1);
- buf[sizeof(buf)-1] = '\0';
- #endif
- archive_string_sprintf(&info,
- "INFO %s%s", buf, archive_version_string());
- if (iso9660->opt.abstract_file != OPT_ABSTRACT_FILE_DEFAULT)
- set_option_info(&info, &opt, "abstract-file",
- KEY_STR, iso9660->abstract_file_identifier.s);
- if (iso9660->opt.application_id != OPT_APPLICATION_ID_DEFAULT)
- set_option_info(&info, &opt, "application-id",
- KEY_STR, iso9660->application_identifier.s);
- if (iso9660->opt.allow_vernum != OPT_ALLOW_VERNUM_DEFAULT)
- set_option_info(&info, &opt, "allow-vernum",
- KEY_FLG, iso9660->opt.allow_vernum);
- if (iso9660->opt.biblio_file != OPT_BIBLIO_FILE_DEFAULT)
- set_option_info(&info, &opt, "biblio-file",
- KEY_STR, iso9660->bibliographic_file_identifier.s);
- if (iso9660->opt.boot != OPT_BOOT_DEFAULT)
- set_option_info(&info, &opt, "boot",
- KEY_STR, iso9660->el_torito.boot_filename.s);
- if (iso9660->opt.boot_catalog != OPT_BOOT_CATALOG_DEFAULT)
- set_option_info(&info, &opt, "boot-catalog",
- KEY_STR, iso9660->el_torito.catalog_filename.s);
- if (iso9660->opt.boot_info_table != OPT_BOOT_INFO_TABLE_DEFAULT)
- set_option_info(&info, &opt, "boot-info-table",
- KEY_FLG, iso9660->opt.boot_info_table);
- if (iso9660->opt.boot_load_seg != OPT_BOOT_LOAD_SEG_DEFAULT)
- set_option_info(&info, &opt, "boot-load-seg",
- KEY_HEX, iso9660->el_torito.boot_load_seg);
- if (iso9660->opt.boot_load_size != OPT_BOOT_LOAD_SIZE_DEFAULT)
- set_option_info(&info, &opt, "boot-load-size",
- KEY_INT, iso9660->el_torito.boot_load_size);
- if (iso9660->opt.boot_type != OPT_BOOT_TYPE_DEFAULT) {
- v = "no-emulation";
- if (iso9660->opt.boot_type == OPT_BOOT_TYPE_FD)
- v = "fd";
- if (iso9660->opt.boot_type == OPT_BOOT_TYPE_HARD_DISK)
- v = "hard-disk";
- set_option_info(&info, &opt, "boot-type",
- KEY_STR, v);
- }
- #ifdef HAVE_ZLIB_H
- if (iso9660->opt.compression_level != OPT_COMPRESSION_LEVEL_DEFAULT)
- set_option_info(&info, &opt, "compression-level",
- KEY_INT, iso9660->zisofs.compression_level);
- #endif
- if (iso9660->opt.copyright_file != OPT_COPYRIGHT_FILE_DEFAULT)
- set_option_info(&info, &opt, "copyright-file",
- KEY_STR, iso9660->copyright_file_identifier.s);
- if (iso9660->opt.iso_level != OPT_ISO_LEVEL_DEFAULT)
- set_option_info(&info, &opt, "iso-level",
- KEY_INT, iso9660->opt.iso_level);
- if (iso9660->opt.joliet != OPT_JOLIET_DEFAULT) {
- if (iso9660->opt.joliet == OPT_JOLIET_LONGNAME)
- set_option_info(&info, &opt, "joliet",
- KEY_STR, "long");
- else
- set_option_info(&info, &opt, "joliet",
- KEY_FLG, iso9660->opt.joliet);
- }
- if (iso9660->opt.limit_depth != OPT_LIMIT_DEPTH_DEFAULT)
- set_option_info(&info, &opt, "limit-depth",
- KEY_FLG, iso9660->opt.limit_depth);
- if (iso9660->opt.limit_dirs != OPT_LIMIT_DIRS_DEFAULT)
- set_option_info(&info, &opt, "limit-dirs",
- KEY_FLG, iso9660->opt.limit_dirs);
- if (iso9660->opt.pad != OPT_PAD_DEFAULT)
- set_option_info(&info, &opt, "pad",
- KEY_FLG, iso9660->opt.pad);
- if (iso9660->opt.publisher != OPT_PUBLISHER_DEFAULT)
- set_option_info(&info, &opt, "publisher",
- KEY_STR, iso9660->publisher_identifier.s);
- if (iso9660->opt.rr != OPT_RR_DEFAULT) {
- if (iso9660->opt.rr == OPT_RR_DISABLED)
- set_option_info(&info, &opt, "rockridge",
- KEY_FLG, iso9660->opt.rr);
- else if (iso9660->opt.rr == OPT_RR_STRICT)
- set_option_info(&info, &opt, "rockridge",
- KEY_STR, "strict");
- else if (iso9660->opt.rr == OPT_RR_USEFUL)
- set_option_info(&info, &opt, "rockridge",
- KEY_STR, "useful");
- }
- if (iso9660->opt.volume_id != OPT_VOLUME_ID_DEFAULT)
- set_option_info(&info, &opt, "volume-id",
- KEY_STR, iso9660->volume_identifier.s);
- if (iso9660->opt.zisofs != OPT_ZISOFS_DEFAULT)
- set_option_info(&info, &opt, "zisofs",
- KEY_FLG, iso9660->opt.zisofs);
- memcpy(wb_buffptr(a), info.s, info_size);
- archive_string_free(&info);
- return (wb_consume(a, info_size));
- }
- static int
- write_rr_ER(struct archive_write *a)
- {
- unsigned char *p;
- p = wb_buffptr(a);
- memset(p, 0, LOGICAL_BLOCK_SIZE);
- p[0] = 'E';
- p[1] = 'R';
- p[3] = 0x01;
- p[2] = RRIP_ER_SIZE;
- p[4] = RRIP_ER_ID_SIZE;
- p[5] = RRIP_ER_DSC_SIZE;
- p[6] = RRIP_ER_SRC_SIZE;
- p[7] = 0x01;
- memcpy(&p[8], rrip_identifier, p[4]);
- memcpy(&p[8+p[4]], rrip_descriptor, p[5]);
- memcpy(&p[8+p[4]+p[5]], rrip_source, p[6]);
- return (wb_consume(a, LOGICAL_BLOCK_SIZE));
- }
- static void
- calculate_path_table_size(struct vdd *vdd)
- {
- int depth, size;
- struct path_table *pt;
- pt = vdd->pathtbl;
- size = 0;
- for (depth = 0; depth < vdd->max_depth; depth++) {
- struct isoent **ptbl;
- int i, cnt;
- if ((cnt = pt[depth].cnt) == 0)
- break;
- ptbl = pt[depth].sorted;
- for (i = 0; i < cnt; i++) {
- int len;
- if (ptbl[i]->identifier == NULL)
- len = 1; /* root directory */
- else
- len = ptbl[i]->id_len;
- if (len & 0x01)
- len++; /* Padding Field */
- size += 8 + len;
- }
- }
- vdd->path_table_size = size;
- vdd->path_table_block =
- ((size + PATH_TABLE_BLOCK_SIZE -1) /
- PATH_TABLE_BLOCK_SIZE) *
- (PATH_TABLE_BLOCK_SIZE / LOGICAL_BLOCK_SIZE);
- }
- static int
- _write_path_table(struct archive_write *a, int type_m, int depth,
- struct vdd *vdd)
- {
- unsigned char *bp, *wb;
- struct isoent **ptbl;
- size_t wbremaining;
- int i, r, wsize;
- if (vdd->pathtbl[depth].cnt == 0)
- return (0);
- wsize = 0;
- wb = wb_buffptr(a);
- wbremaining = wb_remaining(a);
- bp = wb - 1;
- ptbl = vdd->pathtbl[depth].sorted;
- for (i = 0; i < vdd->pathtbl[depth].cnt; i++) {
- struct isoent *np;
- size_t len;
- np = ptbl[i];
- if (np->identifier == NULL)
- len = 1; /* root directory */
- else
- len = np->id_len;
- if (wbremaining - ((bp+1) - wb) < (len + 1 + 8)) {
- r = wb_consume(a, (bp+1) - wb);
- if (r < 0)
- return (r);
- wb = wb_buffptr(a);
- wbremaining = wb_remaining(a);
- bp = wb -1;
- }
- /* Length of Directory Identifier */
- set_num_711(bp+1, (unsigned char)len);
- /* Extended Attribute Record Length */
- set_num_711(bp+2, 0);
- /* Location of Extent */
- if (type_m)
- set_num_732(bp+3, np->dir_location);
- else
- set_num_731(bp+3, np->dir_location);
- /* Parent Directory Number */
- if (type_m)
- set_num_722(bp+7, np->parent->dir_number);
- else
- set_num_721(bp+7, np->parent->dir_number);
- /* Directory Identifier */
- if (np->identifier == NULL)
- bp[9] = 0;
- else
- memcpy(&bp[9], np->identifier, len);
- if (len & 0x01) {
- /* Padding Field */
- bp[9+len] = 0;
- len++;
- }
- wsize += 8 + (int)len;
- bp += 8 + len;
- }
- if ((bp + 1) > wb) {
- r = wb_consume(a, (bp+1)-wb);
- if (r < 0)
- return (r);
- }
- return (wsize);
- }
- static int
- write_path_table(struct archive_write *a, int type_m, struct vdd *vdd)
- {
- int depth, r;
- size_t path_table_size;
- r = ARCHIVE_OK;
- path_table_size = 0;
- for (depth = 0; depth < vdd->max_depth; depth++) {
- r = _write_path_table(a, type_m, depth, vdd);
- if (r < 0)
- return (r);
- path_table_size += r;
- }
- /* Write padding data. */
- path_table_size = path_table_size % PATH_TABLE_BLOCK_SIZE;
- if (path_table_size > 0)
- r = write_null(a, PATH_TABLE_BLOCK_SIZE - path_table_size);
- return (r);
- }
- static int
- calculate_directory_descriptors(struct iso9660 *iso9660, struct vdd *vdd,
- struct isoent *isoent, int depth)
- {
- struct isoent **enttbl;
- int bs, block, i;
- block = 1;
- bs = get_dir_rec_size(iso9660, isoent, DIR_REC_SELF, vdd->vdd_type);
- bs += get_dir_rec_size(iso9660, isoent, DIR_REC_PARENT, vdd->vdd_type);
- if (isoent->children.cnt <= 0 || (vdd->vdd_type != VDD_JOLIET &&
- !iso9660->opt.rr && depth + 1 >= vdd->max_depth))
- return (block);
- enttbl = isoent->children_sorted;
- for (i = 0; i < isoent->children.cnt; i++) {
- struct isoent *np = enttbl[i];
- struct isofile *file;
- file = np->file;
- if (file->hardlink_target != NULL)
- file = file->hardlink_target;
- file->cur_content = &(file->content);
- do {
- int dr_l;
- dr_l = get_dir_rec_size(iso9660, np, DIR_REC_NORMAL,
- vdd->vdd_type);
- if ((bs + dr_l) > LOGICAL_BLOCK_SIZE) {
- block ++;
- bs = dr_l;
- } else
- bs += dr_l;
- file->cur_content = file->cur_content->next;
- } while (file->cur_content != NULL);
- }
- return (block);
- }
- static int
- _write_directory_descriptors(struct archive_write *a, struct vdd *vdd,
- struct isoent *isoent, int depth)
- {
- struct iso9660 *iso9660 = a->format_data;
- struct isoent **enttbl;
- unsigned char *p, *wb;
- int i, r;
- int dr_l;
- p = wb = wb_buffptr(a);
- #define WD_REMAINING (LOGICAL_BLOCK_SIZE - (p - wb))
- p += set_directory_record(p, WD_REMAINING, isoent,
- iso9660, DIR_REC_SELF, vdd->vdd_type);
- p += set_directory_record(p, WD_REMAINING, isoent,
- iso9660, DIR_REC_PARENT, vdd->vdd_type);
- if (isoent->children.cnt <= 0 || (vdd->vdd_type != VDD_JOLIET &&
- !iso9660->opt.rr && depth + 1 >= vdd->max_depth)) {
- memset(p, 0, WD_REMAINING);
- return (wb_consume(a, LOGICAL_BLOCK_SIZE));
- }
- enttbl = isoent->children_sorted;
- for (i = 0; i < isoent->children.cnt; i++) {
- struct isoent *np = enttbl[i];
- struct isofile *file = np->file;
- if (file->hardlink_target != NULL)
- file = file->hardlink_target;
- file->cur_content = &(file->content);
- do {
- dr_l = set_directory_record(p, WD_REMAINING,
- np, iso9660, DIR_REC_NORMAL,
- vdd->vdd_type);
- if (dr_l == 0) {
- memset(p, 0, WD_REMAINING);
- r = wb_consume(a, LOGICAL_BLOCK_SIZE);
- if (r < 0)
- return (r);
- p = wb = wb_buffptr(a);
- dr_l = set_directory_record(p,
- WD_REMAINING, np, iso9660,
- DIR_REC_NORMAL, vdd->vdd_type);
- }
- p += dr_l;
- file->cur_content = file->cur_content->next;
- } while (file->cur_content != NULL);
- }
- memset(p, 0, WD_REMAINING);
- return (wb_consume(a, LOGICAL_BLOCK_SIZE));
- }
- static int
- write_directory_descriptors(struct archive_write *a, struct vdd *vdd)
- {
- struct isoent *np;
- int depth, r;
- depth = 0;
- np = vdd->rootent;
- do {
- struct extr_rec *extr;
- r = _write_directory_descriptors(a, vdd, np, depth);
- if (r < 0)
- return (r);
- if (vdd->vdd_type != VDD_JOLIET) {
- /*
- * This extract record is used by SUSP,RRIP.
- * Not for joliet.
- */
- for (extr = np->extr_rec_list.first;
- extr != NULL;
- extr = extr->next) {
- unsigned char *wb;
- wb = wb_buffptr(a);
- memcpy(wb, extr->buf, extr->offset);
- memset(wb + extr->offset, 0,
- LOGICAL_BLOCK_SIZE - extr->offset);
- r = wb_consume(a, LOGICAL_BLOCK_SIZE);
- if (r < 0)
- return (r);
- }
- }
- if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {
- /* Enter to sub directories. */
- np = np->subdirs.first;
- depth++;
- continue;
- }
- while (np != np->parent) {
- if (np->drnext == NULL) {
- /* Return to the parent directory. */
- np = np->parent;
- depth--;
- } else {
- np = np->drnext;
- break;
- }
- }
- } while (np != np->parent);
- return (ARCHIVE_OK);
- }
- /*
- * Read file contents from the temporary file, and write it.
- */
- static int
- write_file_contents(struct archive_write *a, int64_t offset, int64_t size)
- {
- struct iso9660 *iso9660 = a->format_data;
- int r;
- lseek(iso9660->temp_fd, offset, SEEK_SET);
- while (size) {
- size_t rsize;
- ssize_t rs;
- unsigned char *wb;
- wb = wb_buffptr(a);
- rsize = wb_remaining(a);
- if (rsize > (size_t)size)
- rsize = (size_t)size;
- rs = read(iso9660->temp_fd, wb, rsize);
- if (rs <= 0) {
- archive_set_error(&a->archive, errno,
- "Can't read temporary file(%jd)", (intmax_t)rs);
- return (ARCHIVE_FATAL);
- }
- size -= rs;
- r = wb_consume(a, rs);
- if (r < 0)
- return (r);
- }
- return (ARCHIVE_OK);
- }
- static int
- write_file_descriptors(struct archive_write *a)
- {
- struct iso9660 *iso9660 = a->format_data;
- struct isofile *file;
- int64_t blocks, offset;
- int r;
- blocks = 0;
- offset = 0;
- /* Make the boot catalog contents, and write it. */
- if (iso9660->el_torito.catalog != NULL) {
- r = make_boot_catalog(a);
- if (r < 0)
- return (r);
- }
- /* Write the boot file contents. */
- if (iso9660->el_torito.boot != NULL) {
- file = iso9660->el_torito.boot->file;
- blocks = file->content.blocks;
- offset = file->content.offset_of_temp;
- if (offset != 0) {
- r = write_file_contents(a, offset,
- blocks << LOGICAL_BLOCK_BITS);
- if (r < 0)
- return (r);
- blocks = 0;
- offset = 0;
- }
- }
- /* Write out all file contents. */
- for (file = iso9660->data_file_list.first;
- file != NULL; file = file->datanext) {
- if (!file->write_content)
- continue;
- if ((offset + (blocks << LOGICAL_BLOCK_BITS)) <
- file->content.offset_of_temp) {
- if (blocks > 0) {
- r = write_file_contents(a, offset,
- blocks << LOGICAL_BLOCK_BITS);
- if (r < 0)
- return (r);
- }
- blocks = 0;
- offset = file->content.offset_of_temp;
- }
- file->cur_content = &(file->content);
- do {
- blocks += file->cur_content->blocks;
- /* Next fragment */
- file->cur_content = file->cur_content->next;
- } while (file->cur_content != NULL);
- }
- /* Flush out remaining blocks. */
- if (blocks > 0) {
- r = write_file_contents(a, offset,
- blocks << LOGICAL_BLOCK_BITS);
- if (r < 0)
- return (r);
- }
- return (ARCHIVE_OK);
- }
- static void
- isofile_init_entry_list(struct iso9660 *iso9660)
- {
- iso9660->all_file_list.first = NULL;
- iso9660->all_file_list.last = &(iso9660->all_file_list.first);
- }
- static void
- isofile_add_entry(struct iso9660 *iso9660, struct isofile *file)
- {
- file->allnext = NULL;
- *iso9660->all_file_list.last = file;
- iso9660->all_file_list.last = &(file->allnext);
- }
- static void
- isofile_free_all_entries(struct iso9660 *iso9660)
- {
- struct isofile *file, *file_next;
- file = iso9660->all_file_list.first;
- while (file != NULL) {
- file_next = file->allnext;
- isofile_free(file);
- file = file_next;
- }
- }
- static void
- isofile_init_entry_data_file_list(struct iso9660 *iso9660)
- {
- iso9660->data_file_list.first = NULL;
- iso9660->data_file_list.last = &(iso9660->data_file_list.first);
- }
- static void
- isofile_add_data_file(struct iso9660 *iso9660, struct isofile *file)
- {
- file->datanext = NULL;
- *iso9660->data_file_list.last = file;
- iso9660->data_file_list.last = &(file->datanext);
- }
- static struct isofile *
- isofile_new(struct archive_write *a, struct archive_entry *entry)
- {
- struct isofile *file;
- file = calloc(1, sizeof(*file));
- if (file == NULL)
- return (NULL);
- if (entry != NULL)
- file->entry = archive_entry_clone(entry);
- else
- file->entry = archive_entry_new2(&a->archive);
- if (file->entry == NULL) {
- free(file);
- return (NULL);
- }
- archive_string_init(&(file->parentdir));
- archive_string_init(&(file->basename));
- archive_string_init(&(file->basename_utf16));
- archive_string_init(&(file->symlink));
- file->cur_content = &(file->content);
- return (file);
- }
- static void
- isofile_free(struct isofile *file)
- {
- struct content *con, *tmp;
- con = file->content.next;
- while (con != NULL) {
- tmp = con;
- con = con->next;
- free(tmp);
- }
- archive_entry_free(file->entry);
- archive_string_free(&(file->parentdir));
- archive_string_free(&(file->basename));
- archive_string_free(&(file->basename_utf16));
- archive_string_free(&(file->symlink));
- free(file);
- }
- #if defined(_WIN32) || defined(__CYGWIN__)
- static int
- cleanup_backslash_1(char *p)
- {
- int mb, dos;
- mb = dos = 0;
- while (*p) {
- if (*(unsigned char *)p > 127)
- mb = 1;
- if (*p == '\\') {
- /* If we have not met any multi-byte characters,
- * we can replace '\' with '/'. */
- if (!mb)
- *p = '/';
- dos = 1;
- }
- p++;
- }
- if (!mb || !dos)
- return (0);
- return (-1);
- }
- static void
- cleanup_backslash_2(wchar_t *p)
- {
- /* Convert a path-separator from '\' to '/' */
- while (*p != L'\0') {
- if (*p == L'\\')
- *p = L'/';
- p++;
- }
- }
- #endif
- /*
- * Generate a parent directory name and a base name from a pathname.
- */
- static int
- isofile_gen_utility_names(struct archive_write *a, struct isofile *file)
- {
- struct iso9660 *iso9660;
- const char *pathname;
- char *p, *dirname, *slash;
- size_t len;
- int ret = ARCHIVE_OK;
- iso9660 = a->format_data;
- archive_string_empty(&(file->parentdir));
- archive_string_empty(&(file->basename));
- archive_string_empty(&(file->basename_utf16));
- archive_string_empty(&(file->symlink));
- pathname = archive_entry_pathname(file->entry);
- if (pathname == NULL || pathname[0] == '\0') {/* virtual root */
- file->dircnt = 0;
- return (ret);
- }
- /*
- * Make a UTF-16BE basename if Joliet extension enabled.
- */
- if (iso9660->opt.joliet) {
- const char *u16, *ulast;
- size_t u16len, ulen_last;
- if (iso9660->sconv_to_utf16be == NULL) {
- iso9660->sconv_to_utf16be =
- archive_string_conversion_to_charset(
- &(a->archive), "UTF-16BE", 1);
- if (iso9660->sconv_to_utf16be == NULL)
- /* Couldn't allocate memory */
- return (ARCHIVE_FATAL);
- iso9660->sconv_from_utf16be =
- archive_string_conversion_from_charset(
- &(a->archive), "UTF-16BE", 1);
- if (iso9660->sconv_from_utf16be == NULL)
- /* Couldn't allocate memory */
- return (ARCHIVE_FATAL);
- }
- /*
- * Convert a filename to UTF-16BE.
- */
- if (0 > archive_entry_pathname_l(file->entry, &u16, &u16len,
- iso9660->sconv_to_utf16be)) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for UTF-16BE");
- return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "A filename cannot be converted to UTF-16BE;"
- "You should disable making Joliet extension");
- ret = ARCHIVE_WARN;
- }
- /*
- * Make sure a path separator is not in the last;
- * Remove trailing '/'.
- */
- while (u16len >= 2) {
- #if defined(_WIN32) || defined(__CYGWIN__)
- if (u16[u16len-2] == 0 &&
- (u16[u16len-1] == '/' || u16[u16len-1] == '\\'))
- #else
- if (u16[u16len-2] == 0 && u16[u16len-1] == '/')
- #endif
- {
- u16len -= 2;
- } else
- break;
- }
- /*
- * Find a basename in UTF-16BE.
- */
- ulast = u16;
- u16len >>= 1;
- ulen_last = u16len;
- while (u16len > 0) {
- #if defined(_WIN32) || defined(__CYGWIN__)
- if (u16[0] == 0 && (u16[1] == '/' || u16[1] == '\\'))
- #else
- if (u16[0] == 0 && u16[1] == '/')
- #endif
- {
- ulast = u16 + 2;
- ulen_last = u16len -1;
- }
- u16 += 2;
- u16len --;
- }
- ulen_last <<= 1;
- if (archive_string_ensure(&(file->basename_utf16),
- ulen_last) == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for UTF-16BE");
- return (ARCHIVE_FATAL);
- }
- /*
- * Set UTF-16BE basename.
- */
- memcpy(file->basename_utf16.s, ulast, ulen_last);
- file->basename_utf16.length = ulen_last;
- }
- archive_strcpy(&(file->parentdir), pathname);
- #if defined(_WIN32) || defined(__CYGWIN__)
- /*
- * Convert a path-separator from '\' to '/'
- */
- if (cleanup_backslash_1(file->parentdir.s) != 0) {
- const wchar_t *wp = archive_entry_pathname_w(file->entry);
- struct archive_wstring ws;
- if (wp != NULL) {
- int r;
- archive_string_init(&ws);
- archive_wstrcpy(&ws, wp);
- cleanup_backslash_2(ws.s);
- archive_string_empty(&(file->parentdir));
- r = archive_string_append_from_wcs(&(file->parentdir),
- ws.s, ws.length);
- archive_wstring_free(&ws);
- if (r < 0 && errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- }
- }
- #endif
- len = file->parentdir.length;
- p = dirname = file->parentdir.s;
- /*
- * Remove leading '/', '../' and './' elements
- */
- while (*p) {
- if (p[0] == '/') {
- p++;
- len--;
- } else if (p[0] != '.')
- break;
- else if (p[1] == '.' && p[2] == '/') {
- p += 3;
- len -= 3;
- } else if (p[1] == '/' || (p[1] == '.' && p[2] == '\0')) {
- p += 2;
- len -= 2;
- } else if (p[1] == '\0') {
- p++;
- len--;
- } else
- break;
- }
- if (p != dirname) {
- memmove(dirname, p, len+1);
- p = dirname;
- }
- /*
- * Remove "/","/." and "/.." elements from tail.
- */
- while (len > 0) {
- size_t ll = len;
- if (len > 0 && p[len-1] == '/') {
- p[len-1] = '\0';
- len--;
- }
- if (len > 1 && p[len-2] == '/' && p[len-1] == '.') {
- p[len-2] = '\0';
- len -= 2;
- }
- if (len > 2 && p[len-3] == '/' && p[len-2] == '.' &&
- p[len-1] == '.') {
- p[len-3] = '\0';
- len -= 3;
- }
- if (ll == len)
- break;
- }
- while (*p) {
- if (p[0] == '/') {
- if (p[1] == '/')
- /* Convert '//' --> '/' */
- memmove(p, p+1, strlen(p+1) + 1);
- else if (p[1] == '.' && p[2] == '/')
- /* Convert '/./' --> '/' */
- memmove(p, p+2, strlen(p+2) + 1);
- else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {
- /* Convert 'dir/dir1/../dir2/'
- * --> 'dir/dir2/'
- */
- char *rp = p -1;
- while (rp >= dirname) {
- if (*rp == '/')
- break;
- --rp;
- }
- if (rp > dirname) {
- strcpy(rp, p+3);
- p = rp;
- } else {
- strcpy(dirname, p+4);
- p = dirname;
- }
- } else
- p++;
- } else
- p++;
- }
- p = dirname;
- len = strlen(p);
- if (archive_entry_filetype(file->entry) == AE_IFLNK) {
- /* Convert symlink name too. */
- pathname = archive_entry_symlink(file->entry);
- archive_strcpy(&(file->symlink), pathname);
- #if defined(_WIN32) || defined(__CYGWIN__)
- /*
- * Convert a path-separator from '\' to '/'
- */
- if (archive_strlen(&(file->symlink)) > 0 &&
- cleanup_backslash_1(file->symlink.s) != 0) {
- const wchar_t *wp =
- archive_entry_symlink_w(file->entry);
- struct archive_wstring ws;
- if (wp != NULL) {
- int r;
- archive_string_init(&ws);
- archive_wstrcpy(&ws, wp);
- cleanup_backslash_2(ws.s);
- archive_string_empty(&(file->symlink));
- r = archive_string_append_from_wcs(
- &(file->symlink),
- ws.s, ws.length);
- archive_wstring_free(&ws);
- if (r < 0 && errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- }
- }
- #endif
- }
- /*
- * - Count up directory elements.
- * - Find out the position which points the last position of
- * path separator('/').
- */
- slash = NULL;
- file->dircnt = 0;
- for (; *p != '\0'; p++)
- if (*p == '/') {
- slash = p;
- file->dircnt++;
- }
- if (slash == NULL) {
- /* The pathname doesn't have a parent directory. */
- file->parentdir.length = len;
- archive_string_copy(&(file->basename), &(file->parentdir));
- archive_string_empty(&(file->parentdir));
- *file->parentdir.s = '\0';
- return (ret);
- }
- /* Make a basename from dirname and slash */
- *slash = '\0';
- file->parentdir.length = slash - dirname;
- archive_strcpy(&(file->basename), slash + 1);
- if (archive_entry_filetype(file->entry) == AE_IFDIR)
- file->dircnt ++;
- return (ret);
- }
- /*
- * Register a entry to get a hardlink target.
- */
- static int
- isofile_register_hardlink(struct archive_write *a, struct isofile *file)
- {
- struct iso9660 *iso9660 = a->format_data;
- struct hardlink *hl;
- const char *pathname;
- archive_entry_set_nlink(file->entry, 1);
- pathname = archive_entry_hardlink(file->entry);
- if (pathname == NULL) {
- /* This `file` is a hardlink target. */
- hl = malloc(sizeof(*hl));
- if (hl == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- hl->nlink = 1;
- /* A hardlink target must be the first position. */
- file->hlnext = NULL;
- hl->file_list.first = file;
- hl->file_list.last = &(file->hlnext);
- __archive_rb_tree_insert_node(&(iso9660->hardlink_rbtree),
- (struct archive_rb_node *)hl);
- } else {
- hl = (struct hardlink *)__archive_rb_tree_find_node(
- &(iso9660->hardlink_rbtree), pathname);
- if (hl != NULL) {
- /* Insert `file` entry into the tail. */
- file->hlnext = NULL;
- *hl->file_list.last = file;
- hl->file_list.last = &(file->hlnext);
- hl->nlink++;
- }
- archive_entry_unset_size(file->entry);
- }
- return (ARCHIVE_OK);
- }
- /*
- * Hardlinked files have to have the same location of extent.
- * We have to find out hardlink target entries for the entries
- * which have a hardlink target name.
- */
- static void
- isofile_connect_hardlink_files(struct iso9660 *iso9660)
- {
- struct archive_rb_node *n;
- struct hardlink *hl;
- struct isofile *target, *nf;
- ARCHIVE_RB_TREE_FOREACH(n, &(iso9660->hardlink_rbtree)) {
- hl = (struct hardlink *)n;
- /* The first entry must be a hardlink target. */
- target = hl->file_list.first;
- archive_entry_set_nlink(target->entry, hl->nlink);
- /* Set a hardlink target to reference entries. */
- for (nf = target->hlnext;
- nf != NULL; nf = nf->hlnext) {
- nf->hardlink_target = target;
- archive_entry_set_nlink(nf->entry, hl->nlink);
- }
- }
- }
- static int
- isofile_hd_cmp_node(const struct archive_rb_node *n1,
- const struct archive_rb_node *n2)
- {
- const struct hardlink *h1 = (const struct hardlink *)n1;
- const struct hardlink *h2 = (const struct hardlink *)n2;
- return (strcmp(archive_entry_pathname(h1->file_list.first->entry),
- archive_entry_pathname(h2->file_list.first->entry)));
- }
- static int
- isofile_hd_cmp_key(const struct archive_rb_node *n, const void *key)
- {
- const struct hardlink *h = (const struct hardlink *)n;
- return (strcmp(archive_entry_pathname(h->file_list.first->entry),
- (const char *)key));
- }
- static void
- isofile_init_hardlinks(struct iso9660 *iso9660)
- {
- static const struct archive_rb_tree_ops rb_ops = {
- isofile_hd_cmp_node, isofile_hd_cmp_key,
- };
- __archive_rb_tree_init(&(iso9660->hardlink_rbtree), &rb_ops);
- }
- static void
- isofile_free_hardlinks(struct iso9660 *iso9660)
- {
- struct archive_rb_node *n, *tmp;
- ARCHIVE_RB_TREE_FOREACH_SAFE(n, &(iso9660->hardlink_rbtree), tmp) {
- __archive_rb_tree_remove_node(&(iso9660->hardlink_rbtree), n);
- free(n);
- }
- }
- static struct isoent *
- isoent_new(struct isofile *file)
- {
- struct isoent *isoent;
- static const struct archive_rb_tree_ops rb_ops = {
- isoent_cmp_node, isoent_cmp_key,
- };
- isoent = calloc(1, sizeof(*isoent));
- if (isoent == NULL)
- return (NULL);
- isoent->file = file;
- isoent->children.first = NULL;
- isoent->children.last = &(isoent->children.first);
- __archive_rb_tree_init(&(isoent->rbtree), &rb_ops);
- isoent->subdirs.first = NULL;
- isoent->subdirs.last = &(isoent->subdirs.first);
- isoent->extr_rec_list.first = NULL;
- isoent->extr_rec_list.last = &(isoent->extr_rec_list.first);
- isoent->extr_rec_list.current = NULL;
- if (archive_entry_filetype(file->entry) == AE_IFDIR)
- isoent->dir = 1;
- return (isoent);
- }
- static inline struct isoent *
- isoent_clone(struct isoent *src)
- {
- return (isoent_new(src->file));
- }
- static void
- _isoent_free(struct isoent *isoent)
- {
- struct extr_rec *er, *er_next;
- free(isoent->children_sorted);
- free(isoent->identifier);
- er = isoent->extr_rec_list.first;
- while (er != NULL) {
- er_next = er->next;
- free(er);
- er = er_next;
- }
- free(isoent);
- }
- static void
- isoent_free_all(struct isoent *isoent)
- {
- struct isoent *np, *np_temp;
- if (isoent == NULL)
- return;
- np = isoent;
- for (;;) {
- if (np->dir) {
- if (np->children.first != NULL) {
- /* Enter to sub directories. */
- np = np->children.first;
- continue;
- }
- }
- for (;;) {
- np_temp = np;
- if (np->chnext == NULL) {
- /* Return to the parent directory. */
- np = np->parent;
- _isoent_free(np_temp);
- if (np == np_temp)
- return;
- } else {
- np = np->chnext;
- _isoent_free(np_temp);
- break;
- }
- }
- }
- }
- static struct isoent *
- isoent_create_virtual_dir(struct archive_write *a, struct iso9660 *iso9660, const char *pathname)
- {
- struct isofile *file;
- struct isoent *isoent;
- file = isofile_new(a, NULL);
- if (file == NULL)
- return (NULL);
- archive_entry_set_pathname(file->entry, pathname);
- archive_entry_unset_mtime(file->entry);
- archive_entry_unset_atime(file->entry);
- archive_entry_unset_ctime(file->entry);
- archive_entry_set_uid(file->entry, getuid());
- archive_entry_set_gid(file->entry, getgid());
- archive_entry_set_mode(file->entry, 0555 | AE_IFDIR);
- archive_entry_set_nlink(file->entry, 2);
- if (isofile_gen_utility_names(a, file) < ARCHIVE_WARN) {
- isofile_free(file);
- return (NULL);
- }
- isofile_add_entry(iso9660, file);
- isoent = isoent_new(file);
- if (isoent == NULL)
- return (NULL);
- isoent->dir = 1;
- isoent->virtual = 1;
- return (isoent);
- }
- static int
- isoent_cmp_node(const struct archive_rb_node *n1,
- const struct archive_rb_node *n2)
- {
- const struct isoent *e1 = (const struct isoent *)n1;
- const struct isoent *e2 = (const struct isoent *)n2;
- return (strcmp(e1->file->basename.s, e2->file->basename.s));
- }
- static int
- isoent_cmp_key(const struct archive_rb_node *n, const void *key)
- {
- const struct isoent *e = (const struct isoent *)n;
- return (strcmp(e->file->basename.s, (const char *)key));
- }
- static int
- isoent_add_child_head(struct isoent *parent, struct isoent *child)
- {
- if (!__archive_rb_tree_insert_node(
- &(parent->rbtree), (struct archive_rb_node *)child))
- return (0);
- if ((child->chnext = parent->children.first) == NULL)
- parent->children.last = &(child->chnext);
- parent->children.first = child;
- parent->children.cnt++;
- child->parent = parent;
- /* Add a child to a sub-directory chain */
- if (child->dir) {
- if ((child->drnext = parent->subdirs.first) == NULL)
- parent->subdirs.last = &(child->drnext);
- parent->subdirs.first = child;
- parent->subdirs.cnt++;
- child->parent = parent;
- } else
- child->drnext = NULL;
- return (1);
- }
- static int
- isoent_add_child_tail(struct isoent *parent, struct isoent *child)
- {
- if (!__archive_rb_tree_insert_node(
- &(parent->rbtree), (struct archive_rb_node *)child))
- return (0);
- child->chnext = NULL;
- *parent->children.last = child;
- parent->children.last = &(child->chnext);
- parent->children.cnt++;
- child->parent = parent;
- /* Add a child to a sub-directory chain */
- child->drnext = NULL;
- if (child->dir) {
- *parent->subdirs.last = child;
- parent->subdirs.last = &(child->drnext);
- parent->subdirs.cnt++;
- child->parent = parent;
- }
- return (1);
- }
- static void
- isoent_remove_child(struct isoent *parent, struct isoent *child)
- {
- struct isoent *ent;
- /* Remove a child entry from children chain. */
- ent = parent->children.first;
- while (ent->chnext != child)
- ent = ent->chnext;
- if ((ent->chnext = ent->chnext->chnext) == NULL)
- parent->children.last = &(ent->chnext);
- parent->children.cnt--;
- if (child->dir) {
- /* Remove a child entry from sub-directory chain. */
- ent = parent->subdirs.first;
- while (ent->drnext != child)
- ent = ent->drnext;
- if ((ent->drnext = ent->drnext->drnext) == NULL)
- parent->subdirs.last = &(ent->drnext);
- parent->subdirs.cnt--;
- }
- __archive_rb_tree_remove_node(&(parent->rbtree),
- (struct archive_rb_node *)child);
- }
- static int
- isoent_clone_tree(struct archive_write *a, struct isoent **nroot,
- struct isoent *root)
- {
- struct isoent *np, *xroot, *newent;
- np = root;
- xroot = NULL;
- do {
- newent = isoent_clone(np);
- if (newent == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- if (xroot == NULL) {
- *nroot = xroot = newent;
- newent->parent = xroot;
- } else
- isoent_add_child_tail(xroot, newent);
- if (np->dir && np->children.first != NULL) {
- /* Enter to sub directories. */
- np = np->children.first;
- xroot = newent;
- continue;
- }
- while (np != np->parent) {
- if (np->chnext == NULL) {
- /* Return to the parent directory. */
- np = np->parent;
- xroot = xroot->parent;
- } else {
- np = np->chnext;
- break;
- }
- }
- } while (np != np->parent);
- return (ARCHIVE_OK);
- }
- /*
- * Setup directory locations.
- */
- static void
- isoent_setup_directory_location(struct iso9660 *iso9660, int location,
- struct vdd *vdd)
- {
- struct isoent *np;
- int depth;
- vdd->total_dir_block = 0;
- depth = 0;
- np = vdd->rootent;
- do {
- int block;
- np->dir_block = calculate_directory_descriptors(
- iso9660, vdd, np, depth);
- vdd->total_dir_block += np->dir_block;
- np->dir_location = location;
- location += np->dir_block;
- block = extra_setup_location(np, location);
- vdd->total_dir_block += block;
- location += block;
- if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {
- /* Enter to sub directories. */
- np = np->subdirs.first;
- depth++;
- continue;
- }
- while (np != np->parent) {
- if (np->drnext == NULL) {
- /* Return to the parent directory. */
- np = np->parent;
- depth--;
- } else {
- np = np->drnext;
- break;
- }
- }
- } while (np != np->parent);
- }
- static void
- _isoent_file_location(struct iso9660 *iso9660, struct isoent *isoent,
- int *symlocation)
- {
- struct isoent **children;
- int n;
- if (isoent->children.cnt == 0)
- return;
- children = isoent->children_sorted;
- for (n = 0; n < isoent->children.cnt; n++) {
- struct isoent *np;
- struct isofile *file;
- np = children[n];
- if (np->dir)
- continue;
- if (np == iso9660->el_torito.boot)
- continue;
- file = np->file;
- if (file->boot || file->hardlink_target != NULL)
- continue;
- if (archive_entry_filetype(file->entry) == AE_IFLNK ||
- file->content.size == 0) {
- /*
- * Do not point a valid location.
- * Make sure entry is not hardlink file.
- */
- file->content.location = (*symlocation)--;
- continue;
- }
- file->write_content = 1;
- }
- }
- /*
- * Setup file locations.
- */
- static void
- isoent_setup_file_location(struct iso9660 *iso9660, int location)
- {
- struct isoent *isoent;
- struct isoent *np;
- struct isofile *file;
- size_t size;
- int block;
- int depth;
- int joliet;
- int symlocation;
- int total_block;
- iso9660->total_file_block = 0;
- if ((isoent = iso9660->el_torito.catalog) != NULL) {
- isoent->file->content.location = location;
- block = (int)((archive_entry_size(isoent->file->entry) +
- LOGICAL_BLOCK_SIZE -1) >> LOGICAL_BLOCK_BITS);
- location += block;
- iso9660->total_file_block += block;
- }
- if ((isoent = iso9660->el_torito.boot) != NULL) {
- isoent->file->content.location = location;
- size = fd_boot_image_size(iso9660->el_torito.media_type);
- if (size == 0)
- size = (size_t)archive_entry_size(isoent->file->entry);
- block = ((int)size + LOGICAL_BLOCK_SIZE -1)
- >> LOGICAL_BLOCK_BITS;
- location += block;
- iso9660->total_file_block += block;
- isoent->file->content.blocks = block;
- }
- depth = 0;
- symlocation = -16;
- if (!iso9660->opt.rr && iso9660->opt.joliet) {
- joliet = 1;
- np = iso9660->joliet.rootent;
- } else {
- joliet = 0;
- np = iso9660->primary.rootent;
- }
- do {
- _isoent_file_location(iso9660, np, &symlocation);
- if (np->subdirs.first != NULL &&
- (joliet ||
- ((iso9660->opt.rr == OPT_RR_DISABLED &&
- depth + 2 < iso9660->primary.max_depth) ||
- (iso9660->opt.rr &&
- depth + 1 < iso9660->primary.max_depth)))) {
- /* Enter to sub directories. */
- np = np->subdirs.first;
- depth++;
- continue;
- }
- while (np != np->parent) {
- if (np->drnext == NULL) {
- /* Return to the parent directory. */
- np = np->parent;
- depth--;
- } else {
- np = np->drnext;
- break;
- }
- }
- } while (np != np->parent);
- total_block = 0;
- for (file = iso9660->data_file_list.first;
- file != NULL; file = file->datanext) {
- if (!file->write_content)
- continue;
- file->cur_content = &(file->content);
- do {
- file->cur_content->location = location;
- location += file->cur_content->blocks;
- total_block += file->cur_content->blocks;
- /* Next fragment */
- file->cur_content = file->cur_content->next;
- } while (file->cur_content != NULL);
- }
- iso9660->total_file_block += total_block;
- }
- static int
- get_path_component(char *name, size_t n, const char *fn)
- {
- char *p;
- size_t l;
- p = strchr(fn, '/');
- if (p == NULL) {
- if ((l = strlen(fn)) == 0)
- return (0);
- } else
- l = p - fn;
- if (l > n -1)
- return (-1);
- memcpy(name, fn, l);
- name[l] = '\0';
- return ((int)l);
- }
- /*
- * Add a new entry into the tree.
- */
- static int
- isoent_tree(struct archive_write *a, struct isoent **isoentpp)
- {
- #if defined(_WIN32) && !defined(__CYGWIN__)
- char name[_MAX_FNAME];/* Included null terminator size. */
- #elif defined(NAME_MAX) && NAME_MAX >= 255
- char name[NAME_MAX+1];
- #else
- char name[256];
- #endif
- struct iso9660 *iso9660 = a->format_data;
- struct isoent *dent, *isoent, *np;
- struct isofile *f1, *f2;
- const char *fn, *p;
- int l;
- isoent = *isoentpp;
- dent = iso9660->primary.rootent;
- if (isoent->file->parentdir.length > 0)
- fn = p = isoent->file->parentdir.s;
- else
- fn = p = "";
- /*
- * If the path of the parent directory of `isoent' entry is
- * the same as the path of `cur_dirent', add isoent to
- * `cur_dirent'.
- */
- if (archive_strlen(&(iso9660->cur_dirstr))
- == archive_strlen(&(isoent->file->parentdir)) &&
- strcmp(iso9660->cur_dirstr.s, fn) == 0) {
- if (!isoent_add_child_tail(iso9660->cur_dirent, isoent)) {
- np = (struct isoent *)__archive_rb_tree_find_node(
- &(iso9660->cur_dirent->rbtree),
- isoent->file->basename.s);
- goto same_entry;
- }
- return (ARCHIVE_OK);
- }
- for (;;) {
- l = get_path_component(name, sizeof(name), fn);
- if (l == 0) {
- np = NULL;
- break;
- }
- if (l < 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "A name buffer is too small");
- _isoent_free(isoent);
- return (ARCHIVE_FATAL);
- }
- np = isoent_find_child(dent, name);
- if (np == NULL || fn[0] == '\0')
- break;
- /* Find next subdirectory. */
- if (!np->dir) {
- /* NOT Directory! */
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "`%s' is not directory, we cannot insert `%s' ",
- archive_entry_pathname(np->file->entry),
- archive_entry_pathname(isoent->file->entry));
- _isoent_free(isoent);
- *isoentpp = NULL;
- return (ARCHIVE_FAILED);
- }
- fn += l;
- if (fn[0] == '/')
- fn++;
- dent = np;
- }
- if (np == NULL) {
- /*
- * Create virtual parent directories.
- */
- while (fn[0] != '\0') {
- struct isoent *vp;
- struct archive_string as;
- archive_string_init(&as);
- archive_strncat(&as, p, fn - p + l);
- if (as.s[as.length-1] == '/') {
- as.s[as.length-1] = '\0';
- as.length--;
- }
- vp = isoent_create_virtual_dir(a, iso9660, as.s);
- if (vp == NULL) {
- archive_string_free(&as);
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- _isoent_free(isoent);
- *isoentpp = NULL;
- return (ARCHIVE_FATAL);
- }
- archive_string_free(&as);
- if (vp->file->dircnt > iso9660->dircnt_max)
- iso9660->dircnt_max = vp->file->dircnt;
- isoent_add_child_tail(dent, vp);
- np = vp;
- fn += l;
- if (fn[0] == '/')
- fn++;
- l = get_path_component(name, sizeof(name), fn);
- if (l < 0) {
- archive_string_free(&as);
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "A name buffer is too small");
- _isoent_free(isoent);
- *isoentpp = NULL;
- return (ARCHIVE_FATAL);
- }
- dent = np;
- }
- /* Found out the parent directory where isoent can be
- * inserted. */
- iso9660->cur_dirent = dent;
- archive_string_empty(&(iso9660->cur_dirstr));
- archive_string_ensure(&(iso9660->cur_dirstr),
- archive_strlen(&(dent->file->parentdir)) +
- archive_strlen(&(dent->file->basename)) + 2);
- if (archive_strlen(&(dent->file->parentdir)) +
- archive_strlen(&(dent->file->basename)) == 0)
- iso9660->cur_dirstr.s[0] = 0;
- else {
- if (archive_strlen(&(dent->file->parentdir)) > 0) {
- archive_string_copy(&(iso9660->cur_dirstr),
- &(dent->file->parentdir));
- archive_strappend_char(&(iso9660->cur_dirstr), '/');
- }
- archive_string_concat(&(iso9660->cur_dirstr),
- &(dent->file->basename));
- }
- if (!isoent_add_child_tail(dent, isoent)) {
- np = (struct isoent *)__archive_rb_tree_find_node(
- &(dent->rbtree), isoent->file->basename.s);
- goto same_entry;
- }
- return (ARCHIVE_OK);
- }
- same_entry:
- /*
- * We have already has the entry the filename of which is
- * the same.
- */
- f1 = np->file;
- f2 = isoent->file;
- /* If the file type of entries is different,
- * we cannot handle it. */
- if (archive_entry_filetype(f1->entry) !=
- archive_entry_filetype(f2->entry)) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Found duplicate entries `%s' and its file type is "
- "different",
- archive_entry_pathname(f1->entry));
- _isoent_free(isoent);
- *isoentpp = NULL;
- return (ARCHIVE_FAILED);
- }
- /* Swap file entries. */
- np->file = f2;
- isoent->file = f1;
- np->virtual = 0;
- _isoent_free(isoent);
- *isoentpp = np;
- return (ARCHIVE_OK);
- }
- /*
- * Find a entry from `isoent'
- */
- static struct isoent *
- isoent_find_child(struct isoent *isoent, const char *child_name)
- {
- struct isoent *np;
- np = (struct isoent *)__archive_rb_tree_find_node(
- &(isoent->rbtree), child_name);
- return (np);
- }
- /*
- * Find a entry full-path of which is specified by `fn' parameter,
- * in the tree.
- */
- static struct isoent *
- isoent_find_entry(struct isoent *rootent, const char *fn)
- {
- #if defined(_WIN32) && !defined(__CYGWIN__)
- char name[_MAX_FNAME];/* Included null terminator size. */
- #elif defined(NAME_MAX) && NAME_MAX >= 255
- char name[NAME_MAX+1];
- #else
- char name[256];
- #endif
- struct isoent *isoent, *np;
- int l;
- isoent = rootent;
- np = NULL;
- for (;;) {
- l = get_path_component(name, sizeof(name), fn);
- if (l == 0)
- break;
- fn += l;
- if (fn[0] == '/')
- fn++;
- np = isoent_find_child(isoent, name);
- if (np == NULL)
- break;
- if (fn[0] == '\0')
- break;/* We found out the entry */
- /* Try sub directory. */
- isoent = np;
- np = NULL;
- if (!isoent->dir)
- break;/* Not directory */
- }
- return (np);
- }
- /*
- * Following idr_* functions are used for resolving duplicated filenames
- * and unreceivable filenames to generate ISO9660/Joliet Identifiers.
- */
- static void
- idr_relaxed_filenames(char *map)
- {
- int i;
- for (i = 0x21; i <= 0x2F; i++)
- map[i] = 1;
- for (i = 0x3A; i <= 0x41; i++)
- map[i] = 1;
- for (i = 0x5B; i <= 0x5E; i++)
- map[i] = 1;
- map[0x60] = 1;
- for (i = 0x7B; i <= 0x7E; i++)
- map[i] = 1;
- }
- static void
- idr_init(struct iso9660 *iso9660, struct vdd *vdd, struct idr *idr)
- {
- idr->idrent_pool = NULL;
- idr->pool_size = 0;
- if (vdd->vdd_type != VDD_JOLIET) {
- if (iso9660->opt.iso_level <= 3) {
- memcpy(idr->char_map, d_characters_map,
- sizeof(idr->char_map));
- } else {
- memcpy(idr->char_map, d1_characters_map,
- sizeof(idr->char_map));
- idr_relaxed_filenames(idr->char_map);
- }
- }
- }
- static void
- idr_cleanup(struct idr *idr)
- {
- free(idr->idrent_pool);
- }
- static int
- idr_ensure_poolsize(struct archive_write *a, struct idr *idr,
- int cnt)
- {
- if (idr->pool_size < cnt) {
- void *p;
- const int bk = (1 << 7) - 1;
- int psize;
- psize = (cnt + bk) & ~bk;
- p = realloc(idr->idrent_pool, sizeof(struct idrent) * psize);
- if (p == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- idr->idrent_pool = (struct idrent *)p;
- idr->pool_size = psize;
- }
- return (ARCHIVE_OK);
- }
- static int
- idr_start(struct archive_write *a, struct idr *idr, int cnt, int ffmax,
- int num_size, int null_size, const struct archive_rb_tree_ops *rbt_ops)
- {
- int r;
- (void)ffmax; /* UNUSED */
- r = idr_ensure_poolsize(a, idr, cnt);
- if (r != ARCHIVE_OK)
- return (r);
- __archive_rb_tree_init(&(idr->rbtree), rbt_ops);
- idr->wait_list.first = NULL;
- idr->wait_list.last = &(idr->wait_list.first);
- idr->pool_idx = 0;
- idr->num_size = num_size;
- idr->null_size = null_size;
- return (ARCHIVE_OK);
- }
- static void
- idr_register(struct idr *idr, struct isoent *isoent, int weight, int noff)
- {
- struct idrent *idrent, *n;
- idrent = &(idr->idrent_pool[idr->pool_idx++]);
- idrent->wnext = idrent->avail = NULL;
- idrent->isoent = isoent;
- idrent->weight = weight;
- idrent->noff = noff;
- idrent->rename_num = 0;
- if (!__archive_rb_tree_insert_node(&(idr->rbtree), &(idrent->rbnode))) {
- n = (struct idrent *)__archive_rb_tree_find_node(
- &(idr->rbtree), idrent->isoent);
- if (n != NULL) {
- /* this `idrent' needs to rename. */
- idrent->avail = n;
- *idr->wait_list.last = idrent;
- idr->wait_list.last = &(idrent->wnext);
- }
- }
- }
- static void
- idr_extend_identifier(struct idrent *wnp, int numsize, int nullsize)
- {
- unsigned char *p;
- int wnp_ext_off;
- wnp_ext_off = wnp->isoent->ext_off;
- if (wnp->noff + numsize != wnp_ext_off) {
- p = (unsigned char *)wnp->isoent->identifier;
- /* Extend the filename; foo.c --> foo___.c */
- memmove(p + wnp->noff + numsize, p + wnp_ext_off,
- wnp->isoent->ext_len + nullsize);
- wnp->isoent->ext_off = wnp_ext_off = wnp->noff + numsize;
- wnp->isoent->id_len = wnp_ext_off + wnp->isoent->ext_len;
- }
- }
- static void
- idr_resolve(struct idr *idr, void (*fsetnum)(unsigned char *p, int num))
- {
- struct idrent *n;
- unsigned char *p;
- for (n = idr->wait_list.first; n != NULL; n = n->wnext) {
- idr_extend_identifier(n, idr->num_size, idr->null_size);
- p = (unsigned char *)n->isoent->identifier + n->noff;
- do {
- fsetnum(p, n->avail->rename_num++);
- } while (!__archive_rb_tree_insert_node(
- &(idr->rbtree), &(n->rbnode)));
- }
- }
- static void
- idr_set_num(unsigned char *p, int num)
- {
- static const char xdig[] = {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
- 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
- 'U', 'V', 'W', 'X', 'Y', 'Z'
- };
- num %= sizeof(xdig) * sizeof(xdig) * sizeof(xdig);
- p[0] = xdig[(num / (sizeof(xdig) * sizeof(xdig)))];
- num %= sizeof(xdig) * sizeof(xdig);
- p[1] = xdig[ (num / sizeof(xdig))];
- num %= sizeof(xdig);
- p[2] = xdig[num];
- }
- static void
- idr_set_num_beutf16(unsigned char *p, int num)
- {
- static const uint16_t xdig[] = {
- 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035,
- 0x0036, 0x0037, 0x0038, 0x0039,
- 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046,
- 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C,
- 0x004D, 0x004E, 0x004F, 0x0050, 0x0051, 0x0052,
- 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058,
- 0x0059, 0x005A
- };
- #define XDIG_CNT (sizeof(xdig)/sizeof(xdig[0]))
- num %= XDIG_CNT * XDIG_CNT * XDIG_CNT;
- archive_be16enc(p, xdig[(num / (XDIG_CNT * XDIG_CNT))]);
- num %= XDIG_CNT * XDIG_CNT;
- archive_be16enc(p+2, xdig[ (num / XDIG_CNT)]);
- num %= XDIG_CNT;
- archive_be16enc(p+4, xdig[num]);
- }
- /*
- * Generate ISO9660 Identifier.
- */
- static int
- isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,
- struct idr *idr)
- {
- struct iso9660 *iso9660;
- struct isoent *np;
- char *p;
- int l, r;
- const char *char_map;
- char allow_ldots, allow_multidot, allow_period, allow_vernum;
- int fnmax, ffmax, dnmax;
- static const struct archive_rb_tree_ops rb_ops = {
- isoent_cmp_node_iso9660, isoent_cmp_key_iso9660
- };
- if (isoent->children.cnt == 0)
- return (0);
- iso9660 = a->format_data;
- char_map = idr->char_map;
- if (iso9660->opt.iso_level <= 3) {
- allow_ldots = 0;
- allow_multidot = 0;
- allow_period = 1;
- allow_vernum = iso9660->opt.allow_vernum;
- if (iso9660->opt.iso_level == 1) {
- fnmax = 8;
- ffmax = 12;/* fnmax + '.' + 3 */
- dnmax = 8;
- } else {
- fnmax = 30;
- ffmax = 31;
- dnmax = 31;
- }
- } else {
- allow_ldots = allow_multidot = 1;
- allow_period = allow_vernum = 0;
- if (iso9660->opt.rr)
- /*
- * MDR : The maximum size of Directory Record(254).
- * DRL : A Directory Record Length(33).
- * CE : A size of SUSP CE System Use Entry(28).
- * MDR - DRL - CE = 254 - 33 - 28 = 193.
- */
- fnmax = ffmax = dnmax = 193;
- else
- /*
- * XA : CD-ROM XA System Use Extension
- * Information(14).
- * MDR - DRL - XA = 254 - 33 -14 = 207.
- */
- fnmax = ffmax = dnmax = 207;
- }
- r = idr_start(a, idr, isoent->children.cnt, ffmax, 3, 1, &rb_ops);
- if (r < 0)
- return (r);
- for (np = isoent->children.first; np != NULL; np = np->chnext) {
- char *dot, *xdot;
- int ext_off, noff, weight;
- l = (int)np->file->basename.length;
- p = malloc(l+31+2+1);
- if (p == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- memcpy(p, np->file->basename.s, l);
- p[l] = '\0';
- np->identifier = p;
- dot = xdot = NULL;
- if (!allow_ldots) {
- /*
- * If there is a '.' character at the first byte,
- * it has to be replaced by '_' character.
- */
- if (*p == '.')
- *p++ = '_';
- }
- for (;*p; p++) {
- if (*p & 0x80) {
- *p = '_';
- continue;
- }
- if (char_map[(unsigned char)*p]) {
- /* if iso-level is '4', a character '.' is
- * allowed by char_map. */
- if (*p == '.') {
- xdot = dot;
- dot = p;
- }
- continue;
- }
- if (*p >= 'a' && *p <= 'z') {
- *p -= 'a' - 'A';
- continue;
- }
- if (*p == '.') {
- xdot = dot;
- dot = p;
- if (allow_multidot)
- continue;
- }
- *p = '_';
- }
- p = np->identifier;
- weight = -1;
- if (dot == NULL) {
- int nammax;
- if (np->dir)
- nammax = dnmax;
- else
- nammax = fnmax;
- if (l > nammax) {
- p[nammax] = '\0';
- weight = nammax;
- ext_off = nammax;
- } else
- ext_off = l;
- } else {
- *dot = '.';
- ext_off = (int)(dot - p);
- if (iso9660->opt.iso_level == 1) {
- if (dot - p <= 8) {
- if (strlen(dot) > 4) {
- /* A length of a file extension
- * must be less than 4 */
- dot[4] = '\0';
- weight = 0;
- }
- } else {
- p[8] = dot[0];
- p[9] = dot[1];
- p[10] = dot[2];
- p[11] = dot[3];
- p[12] = '\0';
- weight = 8;
- ext_off = 8;
- }
- } else if (np->dir) {
- if (l > dnmax) {
- p[dnmax] = '\0';
- weight = dnmax;
- if (ext_off > dnmax)
- ext_off = dnmax;
- }
- } else if (l > ffmax) {
- int extlen = (int)strlen(dot);
- int xdoff;
- if (xdot != NULL)
- xdoff = (int)(xdot - p);
- else
- xdoff = 0;
- if (extlen > 1 && xdoff < fnmax-1) {
- int off;
- if (extlen > ffmax)
- extlen = ffmax;
- off = ffmax - extlen;
- if (off == 0) {
- /* A dot('.') character
- * doesn't place to the first
- * byte of identifier. */
- off ++;
- extlen --;
- }
- memmove(p+off, dot, extlen);
- p[ffmax] = '\0';
- ext_off = off;
- weight = off;
- #ifdef COMPAT_MKISOFS
- } else if (xdoff >= fnmax-1) {
- /* Simulate a bug(?) of mkisofs. */
- p[fnmax-1] = '\0';
- ext_off = fnmax-1;
- weight = fnmax-1;
- #endif
- } else {
- p[fnmax] = '\0';
- ext_off = fnmax;
- weight = fnmax;
- }
- }
- }
- /* Save an offset of a file name extension to sort files. */
- np->ext_off = ext_off;
- np->ext_len = (int)strlen(&p[ext_off]);
- np->id_len = l = ext_off + np->ext_len;
- /* Make an offset of the number which is used to be set
- * hexadecimal number to avoid duplicate identifier. */
- if (iso9660->opt.iso_level == 1) {
- if (ext_off >= 5)
- noff = 5;
- else
- noff = ext_off;
- } else {
- if (l == ffmax)
- noff = ext_off - 3;
- else if (l == ffmax-1)
- noff = ext_off - 2;
- else if (l == ffmax-2)
- noff = ext_off - 1;
- else
- noff = ext_off;
- }
- /* Register entry to the identifier resolver. */
- idr_register(idr, np, weight, noff);
- }
- /* Resolve duplicate identifier. */
- idr_resolve(idr, idr_set_num);
- /* Add a period and a version number to identifiers. */
- for (np = isoent->children.first; np != NULL; np = np->chnext) {
- if (!np->dir && np->rr_child == NULL) {
- p = np->identifier + np->ext_off + np->ext_len;
- if (np->ext_len == 0 && allow_period) {
- *p++ = '.';
- np->ext_len = 1;
- }
- if (np->ext_len == 1 && !allow_period) {
- *--p = '\0';
- np->ext_len = 0;
- }
- np->id_len = np->ext_off + np->ext_len;
- if (allow_vernum) {
- *p++ = ';';
- *p++ = '1';
- np->id_len += 2;
- }
- *p = '\0';
- } else
- np->id_len = np->ext_off + np->ext_len;
- np->mb_len = np->id_len;
- }
- return (ARCHIVE_OK);
- }
- /*
- * Generate Joliet Identifier.
- */
- static int
- isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
- struct idr *idr)
- {
- struct iso9660 *iso9660;
- struct isoent *np;
- unsigned char *p;
- size_t l;
- int r;
- size_t ffmax, parent_len;
- static const struct archive_rb_tree_ops rb_ops = {
- isoent_cmp_node_joliet, isoent_cmp_key_joliet
- };
- if (isoent->children.cnt == 0)
- return (0);
- iso9660 = a->format_data;
- if (iso9660->opt.joliet == OPT_JOLIET_LONGNAME)
- ffmax = 206;
- else
- ffmax = 128;
- r = idr_start(a, idr, isoent->children.cnt, (int)ffmax, 6, 2, &rb_ops);
- if (r < 0)
- return (r);
- parent_len = 1;
- for (np = isoent; np->parent != np; np = np->parent)
- parent_len += np->mb_len + 1;
- for (np = isoent->children.first; np != NULL; np = np->chnext) {
- unsigned char *dot;
- int ext_off, noff, weight;
- size_t lt;
- if ((l = np->file->basename_utf16.length) > ffmax)
- l = ffmax;
- p = malloc((l+1)*2);
- if (p == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- memcpy(p, np->file->basename_utf16.s, l);
- p[l] = 0;
- p[l+1] = 0;
- np->identifier = (char *)p;
- lt = l;
- dot = p + l;
- weight = 0;
- while (lt > 0) {
- if (!joliet_allowed_char(p[0], p[1]))
- archive_be16enc(p, 0x005F); /* '_' */
- else if (p[0] == 0 && p[1] == 0x2E) /* '.' */
- dot = p;
- p += 2;
- lt -= 2;
- }
- ext_off = (int)(dot - (unsigned char *)np->identifier);
- np->ext_off = ext_off;
- np->ext_len = (int)l - ext_off;
- np->id_len = (int)l;
- /*
- * Get a length of MBS of a full-pathname.
- */
- if (np->file->basename_utf16.length > ffmax) {
- if (archive_strncpy_l(&iso9660->mbs,
- (const char *)np->identifier, l,
- iso9660->sconv_from_utf16be) != 0 &&
- errno == ENOMEM) {
- archive_set_error(&a->archive, errno,
- "No memory");
- return (ARCHIVE_FATAL);
- }
- np->mb_len = (int)iso9660->mbs.length;
- if (np->mb_len != (int)np->file->basename.length)
- weight = np->mb_len;
- } else
- np->mb_len = (int)np->file->basename.length;
- /* If a length of full-pathname is longer than 240 bytes,
- * it violates Joliet extensions regulation. */
- if (parent_len > 240
- || np->mb_len > 240
- || parent_len + np->mb_len > 240) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "The regulation of Joliet extensions;"
- " A length of a full-pathname of `%s' is "
- "longer than 240 bytes, (p=%d, b=%d)",
- archive_entry_pathname(np->file->entry),
- (int)parent_len, (int)np->mb_len);
- return (ARCHIVE_FATAL);
- }
- /* Make an offset of the number which is used to be set
- * hexadecimal number to avoid duplicate identifier. */
- if (l == ffmax)
- noff = ext_off - 6;
- else if (l == ffmax-2)
- noff = ext_off - 4;
- else if (l == ffmax-4)
- noff = ext_off - 2;
- else
- noff = ext_off;
- /* Register entry to the identifier resolver. */
- idr_register(idr, np, weight, noff);
- }
- /* Resolve duplicate identifier with Joliet Volume. */
- idr_resolve(idr, idr_set_num_beutf16);
- return (ARCHIVE_OK);
- }
- /*
- * This comparing rule is according to ISO9660 Standard 9.3
- */
- static int
- isoent_cmp_iso9660_identifier(const struct isoent *p1, const struct isoent *p2)
- {
- const char *s1, *s2;
- int cmp;
- int l;
- s1 = p1->identifier;
- s2 = p2->identifier;
- /* Compare File Name */
- l = p1->ext_off;
- if (l > p2->ext_off)
- l = p2->ext_off;
- cmp = memcmp(s1, s2, l);
- if (cmp != 0)
- return (cmp);
- if (p1->ext_off < p2->ext_off) {
- s2 += l;
- l = p2->ext_off - p1->ext_off;
- while (l--)
- if (0x20 != *s2++)
- return (0x20
- - *(const unsigned char *)(s2 - 1));
- } else if (p1->ext_off > p2->ext_off) {
- s1 += l;
- l = p1->ext_off - p2->ext_off;
- while (l--)
- if (0x20 != *s1++)
- return (*(const unsigned char *)(s1 - 1)
- - 0x20);
- }
- /* Compare File Name Extension */
- if (p1->ext_len == 0 && p2->ext_len == 0)
- return (0);
- if (p1->ext_len == 1 && p2->ext_len == 1)
- return (0);
- if (p1->ext_len <= 1)
- return (-1);
- if (p2->ext_len <= 1)
- return (1);
- l = p1->ext_len;
- if (l > p2->ext_len)
- l = p2->ext_len;
- s1 = p1->identifier + p1->ext_off;
- s2 = p2->identifier + p2->ext_off;
- if (l > 1) {
- cmp = memcmp(s1, s2, l);
- if (cmp != 0)
- return (cmp);
- }
- if (p1->ext_len < p2->ext_len) {
- s2 += l;
- l = p2->ext_len - p1->ext_len;
- while (l--)
- if (0x20 != *s2++)
- return (0x20
- - *(const unsigned char *)(s2 - 1));
- } else if (p1->ext_len > p2->ext_len) {
- s1 += l;
- l = p1->ext_len - p2->ext_len;
- while (l--)
- if (0x20 != *s1++)
- return (*(const unsigned char *)(s1 - 1)
- - 0x20);
- }
- /* Compare File Version Number */
- /* No operation. The File Version Number is always one. */
- return (cmp);
- }
- static int
- isoent_cmp_node_iso9660(const struct archive_rb_node *n1,
- const struct archive_rb_node *n2)
- {
- const struct idrent *e1 = (const struct idrent *)n1;
- const struct idrent *e2 = (const struct idrent *)n2;
- return (isoent_cmp_iso9660_identifier(e2->isoent, e1->isoent));
- }
- static int
- isoent_cmp_key_iso9660(const struct archive_rb_node *node, const void *key)
- {
- const struct isoent *isoent = (const struct isoent *)key;
- const struct idrent *idrent = (const struct idrent *)node;
- return (isoent_cmp_iso9660_identifier(isoent, idrent->isoent));
- }
- static int
- isoent_cmp_joliet_identifier(const struct isoent *p1, const struct isoent *p2)
- {
- const unsigned char *s1, *s2;
- int cmp;
- int l;
- s1 = (const unsigned char *)p1->identifier;
- s2 = (const unsigned char *)p2->identifier;
- /* Compare File Name */
- l = p1->ext_off;
- if (l > p2->ext_off)
- l = p2->ext_off;
- cmp = memcmp(s1, s2, l);
- if (cmp != 0)
- return (cmp);
- if (p1->ext_off < p2->ext_off) {
- s2 += l;
- l = p2->ext_off - p1->ext_off;
- while (l--)
- if (0 != *s2++)
- return (- *(const unsigned char *)(s2 - 1));
- } else if (p1->ext_off > p2->ext_off) {
- s1 += l;
- l = p1->ext_off - p2->ext_off;
- while (l--)
- if (0 != *s1++)
- return (*(const unsigned char *)(s1 - 1));
- }
- /* Compare File Name Extension */
- if (p1->ext_len == 0 && p2->ext_len == 0)
- return (0);
- if (p1->ext_len == 2 && p2->ext_len == 2)
- return (0);
- if (p1->ext_len <= 2)
- return (-1);
- if (p2->ext_len <= 2)
- return (1);
- l = p1->ext_len;
- if (l > p2->ext_len)
- l = p2->ext_len;
- s1 = (unsigned char *)(p1->identifier + p1->ext_off);
- s2 = (unsigned char *)(p2->identifier + p2->ext_off);
- if (l > 1) {
- cmp = memcmp(s1, s2, l);
- if (cmp != 0)
- return (cmp);
- }
- if (p1->ext_len < p2->ext_len) {
- s2 += l;
- l = p2->ext_len - p1->ext_len;
- while (l--)
- if (0 != *s2++)
- return (- *(const unsigned char *)(s2 - 1));
- } else if (p1->ext_len > p2->ext_len) {
- s1 += l;
- l = p1->ext_len - p2->ext_len;
- while (l--)
- if (0 != *s1++)
- return (*(const unsigned char *)(s1 - 1));
- }
- /* Compare File Version Number */
- /* No operation. The File Version Number is always one. */
- return (cmp);
- }
- static int
- isoent_cmp_node_joliet(const struct archive_rb_node *n1,
- const struct archive_rb_node *n2)
- {
- const struct idrent *e1 = (const struct idrent *)n1;
- const struct idrent *e2 = (const struct idrent *)n2;
- return (isoent_cmp_joliet_identifier(e2->isoent, e1->isoent));
- }
- static int
- isoent_cmp_key_joliet(const struct archive_rb_node *node, const void *key)
- {
- const struct isoent *isoent = (const struct isoent *)key;
- const struct idrent *idrent = (const struct idrent *)node;
- return (isoent_cmp_joliet_identifier(isoent, idrent->isoent));
- }
- static int
- isoent_make_sorted_files(struct archive_write *a, struct isoent *isoent,
- struct idr *idr)
- {
- struct archive_rb_node *rn;
- struct isoent **children;
- children = malloc(isoent->children.cnt * sizeof(struct isoent *));
- if (children == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- isoent->children_sorted = children;
- ARCHIVE_RB_TREE_FOREACH(rn, &(idr->rbtree)) {
- struct idrent *idrent = (struct idrent *)rn;
- *children ++ = idrent->isoent;
- }
- return (ARCHIVE_OK);
- }
- /*
- * - Generate ISO9660 and Joliet identifiers from basenames.
- * - Sort files by each directory.
- */
- static int
- isoent_traverse_tree(struct archive_write *a, struct vdd* vdd)
- {
- struct iso9660 *iso9660 = a->format_data;
- struct isoent *np;
- struct idr idr;
- int depth;
- int r;
- int (*genid)(struct archive_write *, struct isoent *, struct idr *);
- idr_init(iso9660, vdd, &idr);
- np = vdd->rootent;
- depth = 0;
- if (vdd->vdd_type == VDD_JOLIET)
- genid = isoent_gen_joliet_identifier;
- else
- genid = isoent_gen_iso9660_identifier;
- do {
- if (np->virtual &&
- !archive_entry_mtime_is_set(np->file->entry)) {
- /* Set properly times to virtual directory */
- archive_entry_set_mtime(np->file->entry,
- iso9660->birth_time, 0);
- archive_entry_set_atime(np->file->entry,
- iso9660->birth_time, 0);
- archive_entry_set_ctime(np->file->entry,
- iso9660->birth_time, 0);
- }
- if (np->children.first != NULL) {
- if (vdd->vdd_type != VDD_JOLIET &&
- !iso9660->opt.rr && depth + 1 >= vdd->max_depth) {
- if (np->children.cnt > 0)
- iso9660->directories_too_deep = np;
- } else {
- /* Generate Identifier */
- r = genid(a, np, &idr);
- if (r < 0)
- goto exit_traverse_tree;
- r = isoent_make_sorted_files(a, np, &idr);
- if (r < 0)
- goto exit_traverse_tree;
- if (np->subdirs.first != NULL &&
- depth + 1 < vdd->max_depth) {
- /* Enter to sub directories. */
- np = np->subdirs.first;
- depth++;
- continue;
- }
- }
- }
- while (np != np->parent) {
- if (np->drnext == NULL) {
- /* Return to the parent directory. */
- np = np->parent;
- depth--;
- } else {
- np = np->drnext;
- break;
- }
- }
- } while (np != np->parent);
- r = ARCHIVE_OK;
- exit_traverse_tree:
- idr_cleanup(&idr);
- return (r);
- }
- /*
- * Collect directory entries into path_table by a directory depth.
- */
- static int
- isoent_collect_dirs(struct vdd *vdd, struct isoent *rootent, int depth)
- {
- struct isoent *np;
- if (rootent == NULL)
- rootent = vdd->rootent;
- np = rootent;
- do {
- /* Register current directory to pathtable. */
- path_table_add_entry(&(vdd->pathtbl[depth]), np);
- if (np->subdirs.first != NULL && depth + 1 < vdd->max_depth) {
- /* Enter to sub directories. */
- np = np->subdirs.first;
- depth++;
- continue;
- }
- while (np != rootent) {
- if (np->drnext == NULL) {
- /* Return to the parent directory. */
- np = np->parent;
- depth--;
- } else {
- np = np->drnext;
- break;
- }
- }
- } while (np != rootent);
- return (ARCHIVE_OK);
- }
- /*
- * The entry whose number of levels in a directory hierarchy is
- * large than eight relocate to rr_move directory.
- */
- static int
- isoent_rr_move_dir(struct archive_write *a, struct isoent **rr_moved,
- struct isoent *curent, struct isoent **newent)
- {
- struct iso9660 *iso9660 = a->format_data;
- struct isoent *rrmoved, *mvent, *np;
- if ((rrmoved = *rr_moved) == NULL) {
- struct isoent *rootent = iso9660->primary.rootent;
- /* There isn't rr_move entry.
- * Create rr_move entry and insert it into the root entry.
- */
- rrmoved = isoent_create_virtual_dir(a, iso9660, "rr_moved");
- if (rrmoved == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- /* Add "rr_moved" entry to the root entry. */
- isoent_add_child_head(rootent, rrmoved);
- archive_entry_set_nlink(rootent->file->entry,
- archive_entry_nlink(rootent->file->entry) + 1);
- /* Register "rr_moved" entry to second level pathtable. */
- path_table_add_entry(&(iso9660->primary.pathtbl[1]), rrmoved);
- /* Save rr_moved. */
- *rr_moved = rrmoved;
- }
- /*
- * Make a clone of curent which is going to be relocated
- * to rr_moved.
- */
- mvent = isoent_clone(curent);
- if (mvent == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- /* linking.. and use for creating "CL", "PL" and "RE" */
- mvent->rr_parent = curent->parent;
- curent->rr_child = mvent;
- /*
- * Move subdirectories from the curent to mvent
- */
- if (curent->children.first != NULL) {
- *mvent->children.last = curent->children.first;
- mvent->children.last = curent->children.last;
- }
- for (np = mvent->children.first; np != NULL; np = np->chnext)
- np->parent = mvent;
- mvent->children.cnt = curent->children.cnt;
- curent->children.cnt = 0;
- curent->children.first = NULL;
- curent->children.last = &curent->children.first;
- if (curent->subdirs.first != NULL) {
- *mvent->subdirs.last = curent->subdirs.first;
- mvent->subdirs.last = curent->subdirs.last;
- }
- mvent->subdirs.cnt = curent->subdirs.cnt;
- curent->subdirs.cnt = 0;
- curent->subdirs.first = NULL;
- curent->subdirs.last = &curent->subdirs.first;
- /*
- * The mvent becomes a child of the rr_moved entry.
- */
- isoent_add_child_tail(rrmoved, mvent);
- archive_entry_set_nlink(rrmoved->file->entry,
- archive_entry_nlink(rrmoved->file->entry) + 1);
- /*
- * This entry which relocated to the rr_moved directory
- * has to set the flag as a file.
- * See also RRIP 4.1.5.1 Description of the "CL" System Use Entry.
- */
- curent->dir = 0;
- *newent = mvent;
- return (ARCHIVE_OK);
- }
- static int
- isoent_rr_move(struct archive_write *a)
- {
- struct iso9660 *iso9660 = a->format_data;
- struct path_table *pt;
- struct isoent *rootent, *rr_moved;
- struct isoent *np, *last;
- int r;
- pt = &(iso9660->primary.pathtbl[MAX_DEPTH-1]);
- /* There aren't level 8 directories reaching a deeper level. */
- if (pt->cnt == 0)
- return (ARCHIVE_OK);
- rootent = iso9660->primary.rootent;
- /* If "rr_moved" directory is already existing,
- * we have to use it. */
- rr_moved = isoent_find_child(rootent, "rr_moved");
- if (rr_moved != NULL &&
- rr_moved != rootent->children.first) {
- /*
- * It's necessary that rr_move is the first entry
- * of the root.
- */
- /* Remove "rr_moved" entry from children chain. */
- isoent_remove_child(rootent, rr_moved);
- /* Add "rr_moved" entry into the head of children chain. */
- isoent_add_child_head(rootent, rr_moved);
- }
- /*
- * Check level 8 path_table.
- * If find out sub directory entries, that entries move to rr_move.
- */
- np = pt->first;
- while (np != NULL) {
- last = path_table_last_entry(pt);
- for (; np != NULL; np = np->ptnext) {
- struct isoent *mvent;
- struct isoent *newent;
- if (!np->dir)
- continue;
- for (mvent = np->subdirs.first;
- mvent != NULL; mvent = mvent->drnext) {
- r = isoent_rr_move_dir(a, &rr_moved,
- mvent, &newent);
- if (r < 0)
- return (r);
- isoent_collect_dirs(&(iso9660->primary),
- newent, 2);
- }
- }
- /* If new entries are added to level 8 path_talbe,
- * its sub directory entries move to rr_move too.
- */
- np = last->ptnext;
- }
- return (ARCHIVE_OK);
- }
- /*
- * This comparing rule is according to ISO9660 Standard 6.9.1
- */
- static int
- _compare_path_table(const void *v1, const void *v2)
- {
- const struct isoent *p1, *p2;
- const char *s1, *s2;
- int cmp, l;
- p1 = *((const struct isoent **)(uintptr_t)v1);
- p2 = *((const struct isoent **)(uintptr_t)v2);
- /* Compare parent directory number */
- cmp = p1->parent->dir_number - p2->parent->dir_number;
- if (cmp != 0)
- return (cmp);
- /* Compare identifier */
- s1 = p1->identifier;
- s2 = p2->identifier;
- l = p1->ext_off;
- if (l > p2->ext_off)
- l = p2->ext_off;
- cmp = strncmp(s1, s2, l);
- if (cmp != 0)
- return (cmp);
- if (p1->ext_off < p2->ext_off) {
- s2 += l;
- l = p2->ext_off - p1->ext_off;
- while (l--)
- if (0x20 != *s2++)
- return (0x20
- - *(const unsigned char *)(s2 - 1));
- } else if (p1->ext_off > p2->ext_off) {
- s1 += l;
- l = p1->ext_off - p2->ext_off;
- while (l--)
- if (0x20 != *s1++)
- return (*(const unsigned char *)(s1 - 1)
- - 0x20);
- }
- return (0);
- }
- static int
- _compare_path_table_joliet(const void *v1, const void *v2)
- {
- const struct isoent *p1, *p2;
- const unsigned char *s1, *s2;
- int cmp, l;
- p1 = *((const struct isoent **)(uintptr_t)v1);
- p2 = *((const struct isoent **)(uintptr_t)v2);
- /* Compare parent directory number */
- cmp = p1->parent->dir_number - p2->parent->dir_number;
- if (cmp != 0)
- return (cmp);
- /* Compare identifier */
- s1 = (const unsigned char *)p1->identifier;
- s2 = (const unsigned char *)p2->identifier;
- l = p1->ext_off;
- if (l > p2->ext_off)
- l = p2->ext_off;
- cmp = memcmp(s1, s2, l);
- if (cmp != 0)
- return (cmp);
- if (p1->ext_off < p2->ext_off) {
- s2 += l;
- l = p2->ext_off - p1->ext_off;
- while (l--)
- if (0 != *s2++)
- return (- *(const unsigned char *)(s2 - 1));
- } else if (p1->ext_off > p2->ext_off) {
- s1 += l;
- l = p1->ext_off - p2->ext_off;
- while (l--)
- if (0 != *s1++)
- return (*(const unsigned char *)(s1 - 1));
- }
- return (0);
- }
- static inline void
- path_table_add_entry(struct path_table *pathtbl, struct isoent *ent)
- {
- ent->ptnext = NULL;
- *pathtbl->last = ent;
- pathtbl->last = &(ent->ptnext);
- pathtbl->cnt ++;
- }
- static inline struct isoent *
- path_table_last_entry(struct path_table *pathtbl)
- {
- if (pathtbl->first == NULL)
- return (NULL);
- return (((struct isoent *)(void *)
- ((char *)(pathtbl->last) - offsetof(struct isoent, ptnext))));
- }
- /*
- * Sort directory entries in path_table
- * and assign directory number to each entries.
- */
- static int
- isoent_make_path_table_2(struct archive_write *a, struct vdd *vdd,
- int depth, int *dir_number)
- {
- struct isoent *np;
- struct isoent **enttbl;
- struct path_table *pt;
- int i;
- pt = &vdd->pathtbl[depth];
- if (pt->cnt == 0) {
- pt->sorted = NULL;
- return (ARCHIVE_OK);
- }
- enttbl = malloc(pt->cnt * sizeof(struct isoent *));
- if (enttbl == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- pt->sorted = enttbl;
- for (np = pt->first; np != NULL; np = np->ptnext)
- *enttbl ++ = np;
- enttbl = pt->sorted;
- switch (vdd->vdd_type) {
- case VDD_PRIMARY:
- case VDD_ENHANCED:
- #ifdef __COMPAR_FN_T
- qsort(enttbl, pt->cnt, sizeof(struct isoent *),
- (__compar_fn_t)_compare_path_table);
- #else
- qsort(enttbl, pt->cnt, sizeof(struct isoent *),
- _compare_path_table);
- #endif
- break;
- case VDD_JOLIET:
- #ifdef __COMPAR_FN_T
- qsort(enttbl, pt->cnt, sizeof(struct isoent *),
- (__compar_fn_t)_compare_path_table_joliet);
- #else
- qsort(enttbl, pt->cnt, sizeof(struct isoent *),
- _compare_path_table_joliet);
- #endif
- break;
- }
- for (i = 0; i < pt->cnt; i++)
- enttbl[i]->dir_number = (*dir_number)++;
- return (ARCHIVE_OK);
- }
- static int
- isoent_alloc_path_table(struct archive_write *a, struct vdd *vdd,
- int max_depth)
- {
- int i;
- vdd->max_depth = max_depth;
- vdd->pathtbl = malloc(sizeof(*vdd->pathtbl) * vdd->max_depth);
- if (vdd->pathtbl == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- for (i = 0; i < vdd->max_depth; i++) {
- vdd->pathtbl[i].first = NULL;
- vdd->pathtbl[i].last = &(vdd->pathtbl[i].first);
- vdd->pathtbl[i].sorted = NULL;
- vdd->pathtbl[i].cnt = 0;
- }
- return (ARCHIVE_OK);
- }
- /*
- * Make Path Tables
- */
- static int
- isoent_make_path_table(struct archive_write *a)
- {
- struct iso9660 *iso9660 = a->format_data;
- int depth, r;
- int dir_number;
- /*
- * Init Path Table.
- */
- if (iso9660->dircnt_max >= MAX_DEPTH &&
- (!iso9660->opt.limit_depth || iso9660->opt.iso_level == 4))
- r = isoent_alloc_path_table(a, &(iso9660->primary),
- iso9660->dircnt_max + 1);
- else
- /* The number of levels in the hierarchy cannot exceed
- * eight. */
- r = isoent_alloc_path_table(a, &(iso9660->primary),
- MAX_DEPTH);
- if (r < 0)
- return (r);
- if (iso9660->opt.joliet) {
- r = isoent_alloc_path_table(a, &(iso9660->joliet),
- iso9660->dircnt_max + 1);
- if (r < 0)
- return (r);
- }
- /* Step 0.
- * - Collect directories for primary and joliet.
- */
- isoent_collect_dirs(&(iso9660->primary), NULL, 0);
- if (iso9660->opt.joliet)
- isoent_collect_dirs(&(iso9660->joliet), NULL, 0);
- /*
- * Rockridge; move deeper depth directories to rr_moved.
- */
- if (iso9660->opt.rr) {
- r = isoent_rr_move(a);
- if (r < 0)
- return (r);
- }
- /* Update nlink. */
- isofile_connect_hardlink_files(iso9660);
- /* Step 1.
- * - Renew a value of the depth of that directories.
- * - Resolve hardlinks.
- * - Convert pathnames to ISO9660 name or UCS2(joliet).
- * - Sort files by each directory.
- */
- r = isoent_traverse_tree(a, &(iso9660->primary));
- if (r < 0)
- return (r);
- if (iso9660->opt.joliet) {
- r = isoent_traverse_tree(a, &(iso9660->joliet));
- if (r < 0)
- return (r);
- }
- /* Step 2.
- * - Sort directories.
- * - Assign all directory number.
- */
- dir_number = 1;
- for (depth = 0; depth < iso9660->primary.max_depth; depth++) {
- r = isoent_make_path_table_2(a, &(iso9660->primary),
- depth, &dir_number);
- if (r < 0)
- return (r);
- }
- if (iso9660->opt.joliet) {
- dir_number = 1;
- for (depth = 0; depth < iso9660->joliet.max_depth; depth++) {
- r = isoent_make_path_table_2(a, &(iso9660->joliet),
- depth, &dir_number);
- if (r < 0)
- return (r);
- }
- }
- if (iso9660->opt.limit_dirs && dir_number > 0xffff) {
- /*
- * Maximum number of directories is 65535(0xffff)
- * doe to size(16bit) of Parent Directory Number of
- * the Path Table.
- * See also ISO9660 Standard 9.4.
- */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Too many directories(%d) over 65535.", dir_number);
- return (ARCHIVE_FATAL);
- }
- /* Get the size of the Path Table. */
- calculate_path_table_size(&(iso9660->primary));
- if (iso9660->opt.joliet)
- calculate_path_table_size(&(iso9660->joliet));
- return (ARCHIVE_OK);
- }
- static int
- isoent_find_out_boot_file(struct archive_write *a, struct isoent *rootent)
- {
- struct iso9660 *iso9660 = a->format_data;
- /* Find a isoent of the boot file. */
- iso9660->el_torito.boot = isoent_find_entry(rootent,
- iso9660->el_torito.boot_filename.s);
- if (iso9660->el_torito.boot == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Can't find the boot image file ``%s''",
- iso9660->el_torito.boot_filename.s);
- return (ARCHIVE_FATAL);
- }
- iso9660->el_torito.boot->file->boot = BOOT_IMAGE;
- return (ARCHIVE_OK);
- }
- static int
- isoent_create_boot_catalog(struct archive_write *a, struct isoent *rootent)
- {
- struct iso9660 *iso9660 = a->format_data;
- struct isofile *file;
- struct isoent *isoent;
- struct archive_entry *entry;
- (void)rootent; /* UNUSED */
- /*
- * Create the entry which is the "boot.catalog" file.
- */
- file = isofile_new(a, NULL);
- if (file == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- archive_entry_set_pathname(file->entry,
- iso9660->el_torito.catalog_filename.s);
- archive_entry_set_size(file->entry, LOGICAL_BLOCK_SIZE);
- archive_entry_set_mtime(file->entry, iso9660->birth_time, 0);
- archive_entry_set_atime(file->entry, iso9660->birth_time, 0);
- archive_entry_set_ctime(file->entry, iso9660->birth_time, 0);
- archive_entry_set_uid(file->entry, getuid());
- archive_entry_set_gid(file->entry, getgid());
- archive_entry_set_mode(file->entry, AE_IFREG | 0444);
- archive_entry_set_nlink(file->entry, 1);
- if (isofile_gen_utility_names(a, file) < ARCHIVE_WARN) {
- isofile_free(file);
- return (ARCHIVE_FATAL);
- }
- file->boot = BOOT_CATALOG;
- file->content.size = LOGICAL_BLOCK_SIZE;
- isofile_add_entry(iso9660, file);
- isoent = isoent_new(file);
- if (isoent == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- isoent->virtual = 1;
- /* Add the "boot.catalog" entry into tree */
- if (isoent_tree(a, &isoent) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- iso9660->el_torito.catalog = isoent;
- /*
- * Get a boot media type.
- */
- switch (iso9660->opt.boot_type) {
- default:
- case OPT_BOOT_TYPE_AUTO:
- /* Try detecting a media type of the boot image. */
- entry = iso9660->el_torito.boot->file->entry;
- if (archive_entry_size(entry) == FD_1_2M_SIZE)
- iso9660->el_torito.media_type =
- BOOT_MEDIA_1_2M_DISKETTE;
- else if (archive_entry_size(entry) == FD_1_44M_SIZE)
- iso9660->el_torito.media_type =
- BOOT_MEDIA_1_44M_DISKETTE;
- else if (archive_entry_size(entry) == FD_2_88M_SIZE)
- iso9660->el_torito.media_type =
- BOOT_MEDIA_2_88M_DISKETTE;
- else
- /* We cannot decide whether the boot image is
- * hard-disk. */
- iso9660->el_torito.media_type =
- BOOT_MEDIA_NO_EMULATION;
- break;
- case OPT_BOOT_TYPE_NO_EMU:
- iso9660->el_torito.media_type = BOOT_MEDIA_NO_EMULATION;
- break;
- case OPT_BOOT_TYPE_HARD_DISK:
- iso9660->el_torito.media_type = BOOT_MEDIA_HARD_DISK;
- break;
- case OPT_BOOT_TYPE_FD:
- entry = iso9660->el_torito.boot->file->entry;
- if (archive_entry_size(entry) <= FD_1_2M_SIZE)
- iso9660->el_torito.media_type =
- BOOT_MEDIA_1_2M_DISKETTE;
- else if (archive_entry_size(entry) <= FD_1_44M_SIZE)
- iso9660->el_torito.media_type =
- BOOT_MEDIA_1_44M_DISKETTE;
- else if (archive_entry_size(entry) <= FD_2_88M_SIZE)
- iso9660->el_torito.media_type =
- BOOT_MEDIA_2_88M_DISKETTE;
- else {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Boot image file(``%s'') size is too big "
- "for fd type.",
- iso9660->el_torito.boot_filename.s);
- return (ARCHIVE_FATAL);
- }
- break;
- }
- /*
- * Get a system type.
- * TODO: `El Torito' specification says "A copy of byte 5 from the
- * Partition Table found in the boot image".
- */
- iso9660->el_torito.system_type = 0;
- /*
- * Get an ID.
- */
- if (iso9660->opt.publisher)
- archive_string_copy(&(iso9660->el_torito.id),
- &(iso9660->publisher_identifier));
- return (ARCHIVE_OK);
- }
- /*
- * If a media type is floppy, return its image size.
- * otherwise return 0.
- */
- static size_t
- fd_boot_image_size(int media_type)
- {
- switch (media_type) {
- case BOOT_MEDIA_1_2M_DISKETTE:
- return (FD_1_2M_SIZE);
- case BOOT_MEDIA_1_44M_DISKETTE:
- return (FD_1_44M_SIZE);
- case BOOT_MEDIA_2_88M_DISKETTE:
- return (FD_2_88M_SIZE);
- default:
- return (0);
- }
- }
- /*
- * Make a boot catalog image data.
- */
- static int
- make_boot_catalog(struct archive_write *a)
- {
- struct iso9660 *iso9660 = a->format_data;
- unsigned char *block;
- unsigned char *p;
- uint16_t sum, *wp;
- block = wb_buffptr(a);
- memset(block, 0, LOGICAL_BLOCK_SIZE);
- p = block;
- /*
- * Validation Entry
- */
- /* Header ID */
- p[0] = 1;
- /* Platform ID */
- p[1] = iso9660->el_torito.platform_id;
- /* Reserved */
- p[2] = p[3] = 0;
- /* ID */
- if (archive_strlen(&(iso9660->el_torito.id)) > 0)
- strncpy((char *)p+4, iso9660->el_torito.id.s, 23);
- p[27] = 0;
- /* Checksum */
- p[28] = p[29] = 0;
- /* Key */
- p[30] = 0x55;
- p[31] = 0xAA;
- sum = 0;
- wp = (uint16_t *)block;
- while (wp < (uint16_t *)&block[32])
- sum += archive_le16dec(wp++);
- set_num_721(&block[28], (~sum) + 1);
- /*
- * Initial/Default Entry
- */
- p = &block[32];
- /* Boot Indicator */
- p[0] = 0x88;
- /* Boot media type */
- p[1] = iso9660->el_torito.media_type;
- /* Load Segment */
- if (iso9660->el_torito.media_type == BOOT_MEDIA_NO_EMULATION)
- set_num_721(&p[2], iso9660->el_torito.boot_load_seg);
- else
- set_num_721(&p[2], 0);
- /* System Type */
- p[4] = iso9660->el_torito.system_type;
- /* Unused */
- p[5] = 0;
- /* Sector Count */
- if (iso9660->el_torito.media_type == BOOT_MEDIA_NO_EMULATION)
- set_num_721(&p[6], iso9660->el_torito.boot_load_size);
- else
- set_num_721(&p[6], 1);
- /* Load RBA */
- set_num_731(&p[8],
- iso9660->el_torito.boot->file->content.location);
- /* Unused */
- memset(&p[12], 0, 20);
- return (wb_consume(a, LOGICAL_BLOCK_SIZE));
- }
- static int
- setup_boot_information(struct archive_write *a)
- {
- struct iso9660 *iso9660 = a->format_data;
- struct isoent *np;
- int64_t size;
- uint32_t sum;
- unsigned char buff[4096];
- np = iso9660->el_torito.boot;
- lseek(iso9660->temp_fd,
- np->file->content.offset_of_temp + 64, SEEK_SET);
- size = archive_entry_size(np->file->entry) - 64;
- if (size <= 0) {
- archive_set_error(&a->archive, errno,
- "Boot file(%jd) is too small", (intmax_t)size + 64);
- return (ARCHIVE_FATAL);
- }
- sum = 0;
- while (size > 0) {
- size_t rsize;
- ssize_t i, rs;
- if (size > (int64_t)sizeof(buff))
- rsize = sizeof(buff);
- else
- rsize = (size_t)size;
- rs = read(iso9660->temp_fd, buff, rsize);
- if (rs <= 0) {
- archive_set_error(&a->archive, errno,
- "Can't read temporary file(%jd)",
- (intmax_t)rs);
- return (ARCHIVE_FATAL);
- }
- for (i = 0; i < rs; i += 4)
- sum += archive_le32dec(buff + i);
- size -= rs;
- }
- /* Set the location of Primary Volume Descriptor. */
- set_num_731(buff, SYSTEM_AREA_BLOCK);
- /* Set the location of the boot file. */
- set_num_731(buff+4, np->file->content.location);
- /* Set the size of the boot file. */
- size = fd_boot_image_size(iso9660->el_torito.media_type);
- if (size == 0)
- size = archive_entry_size(np->file->entry);
- set_num_731(buff+8, (uint32_t)size);
- /* Set the sum of the boot file. */
- set_num_731(buff+12, sum);
- /* Clear reserved bytes. */
- memset(buff+16, 0, 40);
- /* Overwrite the boot file. */
- lseek(iso9660->temp_fd,
- np->file->content.offset_of_temp + 8, SEEK_SET);
- return (write_to_temp(a, buff, 56));
- }
- #ifdef HAVE_ZLIB_H
- static int
- zisofs_init_zstream(struct archive_write *a)
- {
- struct iso9660 *iso9660 = a->format_data;
- int r;
- iso9660->zisofs.stream.next_in = NULL;
- iso9660->zisofs.stream.avail_in = 0;
- iso9660->zisofs.stream.total_in = 0;
- iso9660->zisofs.stream.total_out = 0;
- if (iso9660->zisofs.stream_valid)
- r = deflateReset(&(iso9660->zisofs.stream));
- else {
- r = deflateInit(&(iso9660->zisofs.stream),
- iso9660->zisofs.compression_level);
- iso9660->zisofs.stream_valid = 1;
- }
- switch (r) {
- case Z_OK:
- break;
- default:
- case Z_STREAM_ERROR:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal error initializing "
- "compression library: invalid setup parameter");
- return (ARCHIVE_FATAL);
- case Z_MEM_ERROR:
- archive_set_error(&a->archive, ENOMEM,
- "Internal error initializing "
- "compression library");
- return (ARCHIVE_FATAL);
- case Z_VERSION_ERROR:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal error initializing "
- "compression library: invalid library version");
- return (ARCHIVE_FATAL);
- }
- return (ARCHIVE_OK);
- }
- #endif /* HAVE_ZLIB_H */
- static int
- zisofs_init(struct archive_write *a, struct isofile *file)
- {
- struct iso9660 *iso9660 = a->format_data;
- #ifdef HAVE_ZLIB_H
- uint64_t tsize;
- size_t _ceil, bpsize;
- int r;
- #endif
- iso9660->zisofs.detect_magic = 0;
- iso9660->zisofs.making = 0;
- if (!iso9660->opt.rr || !iso9660->opt.zisofs)
- return (ARCHIVE_OK);
- if (archive_entry_size(file->entry) >= 24 &&
- archive_entry_size(file->entry) < MULTI_EXTENT_SIZE) {
- /* Acceptable file size for zisofs. */
- iso9660->zisofs.detect_magic = 1;
- iso9660->zisofs.magic_cnt = 0;
- }
- if (!iso9660->zisofs.detect_magic)
- return (ARCHIVE_OK);
- #ifdef HAVE_ZLIB_H
- /* The number of Logical Blocks which uncompressed data
- * will use in iso-image file is the same as the number of
- * Logical Blocks which zisofs(compressed) data will use
- * in ISO-image file. It won't reduce iso-image file size. */
- if (archive_entry_size(file->entry) <= LOGICAL_BLOCK_SIZE)
- return (ARCHIVE_OK);
- /* Initialize compression library */
- r = zisofs_init_zstream(a);
- if (r != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- /* Mark file->zisofs to create RRIP 'ZF' Use Entry. */
- file->zisofs.header_size = ZF_HEADER_SIZE >> 2;
- file->zisofs.log2_bs = ZF_LOG2_BS;
- file->zisofs.uncompressed_size =
- (uint32_t)archive_entry_size(file->entry);
- /* Calculate a size of Block Pointers of zisofs. */
- _ceil = (file->zisofs.uncompressed_size + ZF_BLOCK_SIZE -1)
- >> file->zisofs.log2_bs;
- iso9660->zisofs.block_pointers_cnt = (int)_ceil + 1;
- iso9660->zisofs.block_pointers_idx = 0;
- /* Ensure a buffer size used for Block Pointers */
- bpsize = iso9660->zisofs.block_pointers_cnt *
- sizeof(iso9660->zisofs.block_pointers[0]);
- if (iso9660->zisofs.block_pointers_allocated < bpsize) {
- free(iso9660->zisofs.block_pointers);
- iso9660->zisofs.block_pointers = malloc(bpsize);
- if (iso9660->zisofs.block_pointers == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate data");
- return (ARCHIVE_FATAL);
- }
- iso9660->zisofs.block_pointers_allocated = bpsize;
- }
- /*
- * Skip zisofs header and Block Pointers, which we will write
- * after all compressed data of a file written to the temporary
- * file.
- */
- tsize = ZF_HEADER_SIZE + bpsize;
- if (write_null(a, (size_t)tsize) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- /*
- * Initialize some variables to make zisofs.
- */
- archive_le32enc(&(iso9660->zisofs.block_pointers[0]),
- (uint32_t)tsize);
- iso9660->zisofs.remaining = file->zisofs.uncompressed_size;
- iso9660->zisofs.making = 1;
- iso9660->zisofs.allzero = 1;
- iso9660->zisofs.block_offset = tsize;
- iso9660->zisofs.total_size = tsize;
- iso9660->cur_file->cur_content->size = tsize;
- #endif
- return (ARCHIVE_OK);
- }
- static void
- zisofs_detect_magic(struct archive_write *a, const void *buff, size_t s)
- {
- struct iso9660 *iso9660 = a->format_data;
- struct isofile *file = iso9660->cur_file;
- const unsigned char *p, *endp;
- const unsigned char *magic_buff;
- uint32_t uncompressed_size;
- unsigned char header_size;
- unsigned char log2_bs;
- size_t _ceil, doff;
- uint32_t bst, bed;
- int magic_max;
- int64_t entry_size;
- entry_size = archive_entry_size(file->entry);
- if ((int64_t)sizeof(iso9660->zisofs.magic_buffer) > entry_size)
- magic_max = (int)entry_size;
- else
- magic_max = sizeof(iso9660->zisofs.magic_buffer);
- if (iso9660->zisofs.magic_cnt == 0 && s >= (size_t)magic_max)
- /* It's unnecessary we copy buffer. */
- magic_buff = buff;
- else {
- if (iso9660->zisofs.magic_cnt < magic_max) {
- size_t l;
- l = sizeof(iso9660->zisofs.magic_buffer)
- - iso9660->zisofs.magic_cnt;
- if (l > s)
- l = s;
- memcpy(iso9660->zisofs.magic_buffer
- + iso9660->zisofs.magic_cnt, buff, l);
- iso9660->zisofs.magic_cnt += (int)l;
- if (iso9660->zisofs.magic_cnt < magic_max)
- return;
- }
- magic_buff = iso9660->zisofs.magic_buffer;
- }
- iso9660->zisofs.detect_magic = 0;
- p = magic_buff;
- /* Check the magic code of zisofs. */
- if (memcmp(p, zisofs_magic, sizeof(zisofs_magic)) != 0)
- /* This is not zisofs file which made by mkzftree. */
- return;
- p += sizeof(zisofs_magic);
- /* Read a zisofs header. */
- uncompressed_size = archive_le32dec(p);
- header_size = p[4];
- log2_bs = p[5];
- if (uncompressed_size < 24 || header_size != 4 ||
- log2_bs > 30 || log2_bs < 7)
- return;/* Invalid or not supported header. */
- /* Calculate a size of Block Pointers of zisofs. */
- _ceil = (uncompressed_size +
- (ARCHIVE_LITERAL_LL(1) << log2_bs) -1) >> log2_bs;
- doff = (_ceil + 1) * 4 + 16;
- if (entry_size < (int64_t)doff)
- return;/* Invalid data. */
- /* Check every Block Pointer has valid value. */
- p = magic_buff + 16;
- endp = magic_buff + magic_max;
- while (_ceil && p + 8 <= endp) {
- bst = archive_le32dec(p);
- if (bst != doff)
- return;/* Invalid data. */
- p += 4;
- bed = archive_le32dec(p);
- if (bed < bst || bed > entry_size)
- return;/* Invalid data. */
- doff += bed - bst;
- _ceil--;
- }
- file->zisofs.uncompressed_size = uncompressed_size;
- file->zisofs.header_size = header_size;
- file->zisofs.log2_bs = log2_bs;
- /* Disable making a zisofs image. */
- iso9660->zisofs.making = 0;
- }
- #ifdef HAVE_ZLIB_H
- /*
- * Compress data and write it to a temporary file.
- */
- static int
- zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s)
- {
- struct iso9660 *iso9660 = a->format_data;
- struct isofile *file = iso9660->cur_file;
- const unsigned char *b;
- z_stream *zstrm;
- size_t avail, csize;
- int flush, r;
- zstrm = &(iso9660->zisofs.stream);
- zstrm->next_out = wb_buffptr(a);
- zstrm->avail_out = (uInt)wb_remaining(a);
- b = (const unsigned char *)buff;
- do {
- avail = ZF_BLOCK_SIZE - zstrm->total_in;
- if (s < avail) {
- avail = s;
- flush = Z_NO_FLUSH;
- } else
- flush = Z_FINISH;
- iso9660->zisofs.remaining -= avail;
- if (iso9660->zisofs.remaining <= 0)
- flush = Z_FINISH;
- zstrm->next_in = (Bytef *)(uintptr_t)(const void *)b;
- zstrm->avail_in = (uInt)avail;
- /*
- * Check if current data block are all zero.
- */
- if (iso9660->zisofs.allzero) {
- const unsigned char *nonzero = b;
- const unsigned char *nonzeroend = b + avail;
- while (nonzero < nonzeroend)
- if (*nonzero++) {
- iso9660->zisofs.allzero = 0;
- break;
- }
- }
- b += avail;
- s -= avail;
- /*
- * If current data block are all zero, we do not use
- * compressed data.
- */
- if (flush == Z_FINISH && iso9660->zisofs.allzero &&
- avail + zstrm->total_in == ZF_BLOCK_SIZE) {
- if (iso9660->zisofs.block_offset !=
- file->cur_content->size) {
- int64_t diff;
- r = wb_set_offset(a,
- file->cur_content->offset_of_temp +
- iso9660->zisofs.block_offset);
- if (r != ARCHIVE_OK)
- return (r);
- diff = file->cur_content->size -
- iso9660->zisofs.block_offset;
- file->cur_content->size -= diff;
- iso9660->zisofs.total_size -= diff;
- }
- zstrm->avail_in = 0;
- }
- /*
- * Compress file data.
- */
- while (zstrm->avail_in > 0) {
- csize = zstrm->total_out;
- r = deflate(zstrm, flush);
- switch (r) {
- case Z_OK:
- case Z_STREAM_END:
- csize = zstrm->total_out - csize;
- if (wb_consume(a, csize) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- iso9660->zisofs.total_size += csize;
- iso9660->cur_file->cur_content->size += csize;
- zstrm->next_out = wb_buffptr(a);
- zstrm->avail_out = (uInt)wb_remaining(a);
- break;
- default:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Compression failed:"
- " deflate() call returned status %d",
- r);
- return (ARCHIVE_FATAL);
- }
- }
- if (flush == Z_FINISH) {
- /*
- * Save the information of one zisofs block.
- */
- iso9660->zisofs.block_pointers_idx ++;
- archive_le32enc(&(iso9660->zisofs.block_pointers[
- iso9660->zisofs.block_pointers_idx]),
- (uint32_t)iso9660->zisofs.total_size);
- r = zisofs_init_zstream(a);
- if (r != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- iso9660->zisofs.allzero = 1;
- iso9660->zisofs.block_offset = file->cur_content->size;
- }
- } while (s);
- return (ARCHIVE_OK);
- }
- static int
- zisofs_finish_entry(struct archive_write *a)
- {
- struct iso9660 *iso9660 = a->format_data;
- struct isofile *file = iso9660->cur_file;
- unsigned char buff[16];
- size_t s;
- int64_t tail;
- /* Direct temp file stream to zisofs temp file stream. */
- archive_entry_set_size(file->entry, iso9660->zisofs.total_size);
- /*
- * Save a file pointer which points the end of current zisofs data.
- */
- tail = wb_offset(a);
- /*
- * Make a header.
- *
- * +-----------------+----------------+-----------------+
- * | Header 16 bytes | Block Pointers | Compressed data |
- * +-----------------+----------------+-----------------+
- * 0 16 +X
- * Block Pointers :
- * 4 * (((Uncompressed file size + block_size -1) / block_size) + 1)
- *
- * Write zisofs header.
- * Magic number
- * +----+----+----+----+----+----+----+----+
- * | 37 | E4 | 53 | 96 | C9 | DB | D6 | 07 |
- * +----+----+----+----+----+----+----+----+
- * 0 1 2 3 4 5 6 7 8
- *
- * +------------------------+------------------+
- * | Uncompressed file size | header_size >> 2 |
- * +------------------------+------------------+
- * 8 12 13
- *
- * +-----------------+----------------+
- * | log2 block_size | Reserved(0000) |
- * +-----------------+----------------+
- * 13 14 16
- */
- memcpy(buff, zisofs_magic, 8);
- set_num_731(buff+8, file->zisofs.uncompressed_size);
- buff[12] = file->zisofs.header_size;
- buff[13] = file->zisofs.log2_bs;
- buff[14] = buff[15] = 0;/* Reserved */
- /* Move to the right position to write the header. */
- wb_set_offset(a, file->content.offset_of_temp);
- /* Write the header. */
- if (wb_write_to_temp(a, buff, 16) != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- /*
- * Write zisofs Block Pointers.
- */
- s = iso9660->zisofs.block_pointers_cnt *
- sizeof(iso9660->zisofs.block_pointers[0]);
- if (wb_write_to_temp(a, iso9660->zisofs.block_pointers, s)
- != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- /* Set a file pointer back to the end of the temporary file. */
- wb_set_offset(a, tail);
- return (ARCHIVE_OK);
- }
- static int
- zisofs_free(struct archive_write *a)
- {
- struct iso9660 *iso9660 = a->format_data;
- int ret = ARCHIVE_OK;
- free(iso9660->zisofs.block_pointers);
- if (iso9660->zisofs.stream_valid &&
- deflateEnd(&(iso9660->zisofs.stream)) != Z_OK) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Failed to clean up compressor");
- ret = ARCHIVE_FATAL;
- }
- iso9660->zisofs.block_pointers = NULL;
- iso9660->zisofs.stream_valid = 0;
- return (ret);
- }
- struct zisofs_extract {
- int pz_log2_bs; /* Log2 of block size */
- uint64_t pz_uncompressed_size;
- size_t uncompressed_buffer_size;
- signed int initialized:1;
- signed int header_passed:1;
- uint32_t pz_offset;
- unsigned char *block_pointers;
- size_t block_pointers_size;
- size_t block_pointers_avail;
- size_t block_off;
- uint32_t block_avail;
- z_stream stream;
- int stream_valid;
- };
- static ssize_t
- zisofs_extract_init(struct archive_write *a, struct zisofs_extract *zisofs,
- const unsigned char *p, size_t bytes)
- {
- size_t avail = bytes;
- size_t _ceil, xsize;
- /* Allocate block pointers buffer. */
- _ceil = (size_t)((zisofs->pz_uncompressed_size +
- (((int64_t)1) << zisofs->pz_log2_bs) - 1)
- >> zisofs->pz_log2_bs);
- xsize = (_ceil + 1) * 4;
- if (zisofs->block_pointers == NULL) {
- size_t alloc = ((xsize >> 10) + 1) << 10;
- zisofs->block_pointers = malloc(alloc);
- if (zisofs->block_pointers == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "No memory for zisofs decompression");
- return (ARCHIVE_FATAL);
- }
- }
- zisofs->block_pointers_size = xsize;
- /* Allocate uncompressed data buffer. */
- zisofs->uncompressed_buffer_size = (size_t)1UL << zisofs->pz_log2_bs;
- /*
- * Read the file header, and check the magic code of zisofs.
- */
- if (!zisofs->header_passed) {
- int err = 0;
- if (avail < 16) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Illegal zisofs file body");
- return (ARCHIVE_FATAL);
- }
- if (memcmp(p, zisofs_magic, sizeof(zisofs_magic)) != 0)
- err = 1;
- else if (archive_le32dec(p + 8) != zisofs->pz_uncompressed_size)
- err = 1;
- else if (p[12] != 4 || p[13] != zisofs->pz_log2_bs)
- err = 1;
- if (err) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Illegal zisofs file body");
- return (ARCHIVE_FATAL);
- }
- avail -= 16;
- p += 16;
- zisofs->header_passed = 1;
- }
- /*
- * Read block pointers.
- */
- if (zisofs->header_passed &&
- zisofs->block_pointers_avail < zisofs->block_pointers_size) {
- xsize = zisofs->block_pointers_size
- - zisofs->block_pointers_avail;
- if (avail < xsize)
- xsize = avail;
- memcpy(zisofs->block_pointers
- + zisofs->block_pointers_avail, p, xsize);
- zisofs->block_pointers_avail += xsize;
- avail -= xsize;
- if (zisofs->block_pointers_avail
- == zisofs->block_pointers_size) {
- /* We've got all block pointers and initialize
- * related variables. */
- zisofs->block_off = 0;
- zisofs->block_avail = 0;
- /* Complete a initialization */
- zisofs->initialized = 1;
- }
- }
- return ((ssize_t)avail);
- }
- static ssize_t
- zisofs_extract(struct archive_write *a, struct zisofs_extract *zisofs,
- const unsigned char *p, size_t bytes)
- {
- size_t avail;
- int r;
- if (!zisofs->initialized) {
- ssize_t rs = zisofs_extract_init(a, zisofs, p, bytes);
- if (rs < 0)
- return (rs);
- if (!zisofs->initialized) {
- /* We need more data. */
- zisofs->pz_offset += (uint32_t)bytes;
- return (bytes);
- }
- avail = rs;
- p += bytes - avail;
- } else
- avail = bytes;
- /*
- * Get block offsets from block pointers.
- */
- if (zisofs->block_avail == 0) {
- uint32_t bst, bed;
- if (zisofs->block_off + 4 >= zisofs->block_pointers_size) {
- /* There isn't a pair of offsets. */
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Illegal zisofs block pointers");
- return (ARCHIVE_FATAL);
- }
- bst = archive_le32dec(
- zisofs->block_pointers + zisofs->block_off);
- if (bst != zisofs->pz_offset + (bytes - avail)) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Illegal zisofs block pointers(cannot seek)");
- return (ARCHIVE_FATAL);
- }
- bed = archive_le32dec(
- zisofs->block_pointers + zisofs->block_off + 4);
- if (bed < bst) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Illegal zisofs block pointers");
- return (ARCHIVE_FATAL);
- }
- zisofs->block_avail = bed - bst;
- zisofs->block_off += 4;
- /* Initialize compression library for new block. */
- if (zisofs->stream_valid)
- r = inflateReset(&zisofs->stream);
- else
- r = inflateInit(&zisofs->stream);
- if (r != Z_OK) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Can't initialize zisofs decompression.");
- return (ARCHIVE_FATAL);
- }
- zisofs->stream_valid = 1;
- zisofs->stream.total_in = 0;
- zisofs->stream.total_out = 0;
- }
- /*
- * Make uncompressed data.
- */
- if (zisofs->block_avail == 0) {
- /*
- * It's basically 32K bytes NUL data.
- */
- unsigned char *wb;
- size_t size, wsize;
- size = zisofs->uncompressed_buffer_size;
- while (size) {
- wb = wb_buffptr(a);
- if (size > wb_remaining(a))
- wsize = wb_remaining(a);
- else
- wsize = size;
- memset(wb, 0, wsize);
- r = wb_consume(a, wsize);
- if (r < 0)
- return (r);
- size -= wsize;
- }
- } else {
- zisofs->stream.next_in = (Bytef *)(uintptr_t)(const void *)p;
- if (avail > zisofs->block_avail)
- zisofs->stream.avail_in = zisofs->block_avail;
- else
- zisofs->stream.avail_in = (uInt)avail;
- zisofs->stream.next_out = wb_buffptr(a);
- zisofs->stream.avail_out = (uInt)wb_remaining(a);
- r = inflate(&zisofs->stream, 0);
- switch (r) {
- case Z_OK: /* Decompressor made some progress.*/
- case Z_STREAM_END: /* Found end of stream. */
- break;
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "zisofs decompression failed (%d)", r);
- return (ARCHIVE_FATAL);
- }
- avail -= zisofs->stream.next_in - p;
- zisofs->block_avail -= (uint32_t)(zisofs->stream.next_in - p);
- r = wb_consume(a, wb_remaining(a) - zisofs->stream.avail_out);
- if (r < 0)
- return (r);
- }
- zisofs->pz_offset += (uint32_t)bytes;
- return (bytes - avail);
- }
- static int
- zisofs_rewind_boot_file(struct archive_write *a)
- {
- struct iso9660 *iso9660 = a->format_data;
- struct isofile *file;
- unsigned char *rbuff;
- ssize_t r;
- size_t remaining, rbuff_size;
- struct zisofs_extract zext;
- int64_t read_offset, write_offset, new_offset;
- int fd, ret = ARCHIVE_OK;
- file = iso9660->el_torito.boot->file;
- /*
- * There is nothing to do if this boot file does not have
- * zisofs header.
- */
- if (file->zisofs.header_size == 0)
- return (ARCHIVE_OK);
- /*
- * Uncompress the zisofs'ed file contents.
- */
- memset(&zext, 0, sizeof(zext));
- zext.pz_uncompressed_size = file->zisofs.uncompressed_size;
- zext.pz_log2_bs = file->zisofs.log2_bs;
- fd = iso9660->temp_fd;
- new_offset = wb_offset(a);
- read_offset = file->content.offset_of_temp;
- remaining = (size_t)file->content.size;
- if (remaining > 1024 * 32)
- rbuff_size = 1024 * 32;
- else
- rbuff_size = remaining;
- rbuff = malloc(rbuff_size);
- if (rbuff == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- while (remaining) {
- size_t rsize;
- ssize_t rs;
- /* Get the current file pointer. */
- write_offset = lseek(fd, 0, SEEK_CUR);
- /* Change the file pointer to read. */
- lseek(fd, read_offset, SEEK_SET);
- rsize = rbuff_size;
- if (rsize > remaining)
- rsize = remaining;
- rs = read(iso9660->temp_fd, rbuff, rsize);
- if (rs <= 0) {
- archive_set_error(&a->archive, errno,
- "Can't read temporary file(%jd)", (intmax_t)rs);
- ret = ARCHIVE_FATAL;
- break;
- }
- remaining -= rs;
- read_offset += rs;
- /* Put the file pointer back to write. */
- lseek(fd, write_offset, SEEK_SET);
- r = zisofs_extract(a, &zext, rbuff, rs);
- if (r < 0) {
- ret = (int)r;
- break;
- }
- }
- if (ret == ARCHIVE_OK) {
- /*
- * Change the boot file content from zisofs'ed data
- * to plain data.
- */
- file->content.offset_of_temp = new_offset;
- file->content.size = file->zisofs.uncompressed_size;
- archive_entry_set_size(file->entry, file->content.size);
- /* Set to be no zisofs. */
- file->zisofs.header_size = 0;
- file->zisofs.log2_bs = 0;
- file->zisofs.uncompressed_size = 0;
- r = wb_write_padding_to_temp(a, file->content.size);
- if (r < 0)
- ret = ARCHIVE_FATAL;
- }
- /*
- * Free the resource we used in this function only.
- */
- free(rbuff);
- free(zext.block_pointers);
- if (zext.stream_valid && inflateEnd(&(zext.stream)) != Z_OK) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Failed to clean up compressor");
- ret = ARCHIVE_FATAL;
- }
- return (ret);
- }
- #else
- static int
- zisofs_write_to_temp(struct archive_write *a, const void *buff, size_t s)
- {
- (void)buff; /* UNUSED */
- (void)s; /* UNUSED */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Programming error");
- return (ARCHIVE_FATAL);
- }
- static int
- zisofs_rewind_boot_file(struct archive_write *a)
- {
- struct iso9660 *iso9660 = a->format_data;
- if (iso9660->el_torito.boot->file->zisofs.header_size != 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "We cannot extract the zisofs imaged boot file;"
- " this may not boot in being zisofs imaged");
- return (ARCHIVE_FAILED);
- }
- return (ARCHIVE_OK);
- }
- static int
- zisofs_finish_entry(struct archive_write *a)
- {
- (void)a; /* UNUSED */
- return (ARCHIVE_OK);
- }
- static int
- zisofs_free(struct archive_write *a)
- {
- (void)a; /* UNUSED */
- return (ARCHIVE_OK);
- }
- #endif /* HAVE_ZLIB_H */
|