| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181 |
- /*-
- * 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 <cm3p/zlib.h>
- #endif
- #ifdef __clang_analyzer__
- #include <assert.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;
- unsigned 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".
- */
- unsigned 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 {
- unsigned int detect_magic:1;
- unsigned int making:1;
- unsigned 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_identifier(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));
- if (archive_string_ensure(&(iso9660->cur_dirstr), 1) == NULL) {
- free(iso9660);
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- 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_identifier(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
- strncpy(system_id, "Unknown", size-1);
- system_id[size-1] = '\0';
- #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 = "\0\0";
- 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_S
- localtime_s(tm, t);
- #elif HAVE_LOCALTIME_R
- tzset();
- localtime_r(t, tm);
- #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_identifier(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, (unsigned int)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_CTIME_S)
- ctime_s(buf, sizeof(buf), &(iso9660->birth_time));
- #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));
- if (archive_string_ensure(&(iso9660->cur_dirstr),
- archive_strlen(&(dent->file->parentdir)) +
- archive_strlen(&(dent->file->basename)) + 2) == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- _isoent_free(isoent);
- *isoentpp = NULL;
- return (ARCHIVE_FATAL);
- }
- 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 {
- #ifdef __clang_analyzer__
- /* Tell clang-analyzer that pathtbl[depth] is in bounds. */
- assert(depth < vdd->max_depth);
- #endif
- /* 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
- __LA_LIBC_CC
- _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
- __LA_LIBC_CC
- _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;
- unsigned int initialized:1;
- unsigned 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 */
|