1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752 |
- /*
- Copyright (c) 1990-2009 Info-ZIP. All rights reserved.
- See the accompanying file LICENSE, version 2009-Jan-02 or later
- (the contents of which are also included in unzip.h) for terms of use.
- If, for some reason, all these files are missing, the Info-ZIP license
- also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
- */
- /*---------------------------------------------------------------------------
- vms.c Igor Mandrichenko and others
- This file contains routines to extract VMS file attributes from a zipfile
- extra field and create a file with these attributes. The code was almost
- entirely written by Igor, with a couple of routines by GRR and lots of
- modifications and fixes by Christian Spieler.
- Contains: check_format()
- open_outfile()
- find_vms_attrs()
- flush()
- close_outfile()
- defer_dir_attribs()
- set_direc_attribs()
- dos_to_unix_time() (TIMESTAMP only)
- stamp_file() (TIMESTAMP only)
- vms_msg_text()
- do_wild()
- mapattr()
- mapname()
- checkdir()
- check_for_newer()
- return_VMS
- screensize()
- screenlinewrap()
- version()
- ---------------------------------------------------------------------------*/
- #ifdef VMS /* VMS only! */
- #define UNZIP_INTERNAL
- #include "unzip.h"
- #include "crc32.h"
- #include "vms.h"
- #include "vmsdefs.h"
- #ifdef MORE
- # include <ttdef.h>
- #endif
- #include <unixlib.h>
- #include <dvidef.h>
- #include <ssdef.h>
- #include <stsdef.h>
- /* Workaround for broken header files of older DECC distributions
- * that are incompatible with the /NAMES=AS_IS qualifier. */
- #define lib$getdvi LIB$GETDVI
- #define lib$getsyi LIB$GETSYI
- #define lib$sys_getmsg LIB$SYS_GETMSG
- #include <lib$routines.h>
- #ifndef EEXIST
- # include <errno.h> /* For mkdir() status codes */
- #endif
- /* On VAX, define Goofy VAX Type-Cast to obviate /standard = vaxc.
- Otherwise, lame system headers on VAX cause compiler warnings.
- (GNU C may define vax but not __VAX.)
- */
- #ifdef vax
- # define __VAX 1
- #endif
- #ifdef __VAX
- # define GVTC (unsigned int)
- #else
- # define GVTC
- #endif
- /* With GNU C, some FAB bits may be declared only as masks, not as
- * structure bits.
- */
- #ifdef __GNUC__
- # define OLD_FABDEF 1
- #endif
- #define ASYNCH_QIO /* Use asynchronous PK-style QIO writes */
- /* buffer size for a single block write (using RMS or QIO WRITEVBLK),
- must be less than 64k and a multiple of 512 ! */
- #define BUFS512 (((OUTBUFSIZ>0xFFFF) ? 0xFFFF : OUTBUFSIZ) & (~511))
- /* buffer size for record output (RMS limit for max. record size) */
- #define BUFSMAXREC 32767
- /* allocation size for RMS and QIO output buffers */
- #define BUFSALLOC (BUFS512 * 2 > BUFSMAXREC ? BUFS512 * 2 : BUFSMAXREC)
- /* locbuf size */
- /* VMS success or warning status */
- #define OK(s) (((s) & STS$M_SUCCESS) != 0)
- #define STRICMP(s1, s2) STRNICMP(s1, s2, 2147483647)
- /* Interactive inquiry response codes for replace(). */
- #define REPL_NO_EXTRACT 0
- #define REPL_NEW_VERSION 1
- #define REPL_OVERWRITE 2
- #define REPL_ERRLV_WARN 256
- #define REPL_TASKMASK 255
- /* 2008-09-13 CS.
- * Note: In extract.c, there are similar strings "InvalidResponse" and
- * "AssumeNone" defined. However, as the UI functionality of the VMS
- * "version-aware" query is slightly different from the generic variant,
- * these strings are kept separate for now to allow independent
- * "fine tuning" without affecting the other variant of the
- * "overwrite or ..." user query.
- */
- ZCONST char Far InvalidResponse[] =
- "error: invalid response [%.1s]\n";
- ZCONST char Far AssumeNo[] =
- "\n(EOF or read error, treating as \"[N]o extract (all)\" ...)\n";
- #ifdef SET_DIR_ATTRIB
- /* Structure for holding directory attribute data for final processing
- * after all files are in place.
- */
- typedef struct vmsdirattr {
- struct vmsdirattr *next; /* link to next in (linked) list */
- char *fn; /* file (directory) name */
- /* Non-VMS attributes data */
- ulg mod_dos_datetime; /* G.lrec.last_mod_dos_datetime */
- unsigned perms; /* same as min_info.file_attr */
- unsigned xlen; /* G.lrec.extra_field_length */
- char buf[1]; /* data buffer (extra_field, fn) */
- } vmsdirattr;
- #define VmsAtt(d) ((vmsdirattr *)d) /* typecast shortcut */
- #endif /* SET_DIR_ATTRIB */
- /*
- * Local static storage
- */
- static struct FAB fileblk; /* File Access Block */
- static struct XABDAT dattim; /* date-time XAB */
- static struct XABRDT rdt; /* revision date-time XAB */
- static struct RAB rab; /* Record Access Block */
- static struct NAM_STRUCT nam; /* name block */
- static struct FAB *outfab = NULL;
- static struct RAB *outrab = NULL;
- static struct XABFHC *xabfhc = NULL; /* file header characteristics */
- static struct XABDAT *xabdat = NULL; /* date-time */
- static struct XABRDT *xabrdt = NULL; /* revision date-time */
- static struct XABPRO *xabpro = NULL; /* protection */
- static struct XABKEY *xabkey = NULL; /* key (indexed) */
- static struct XABALL *xaball = NULL; /* allocation */
- static struct XAB *first_xab = NULL, *last_xab = NULL;
- static int replace_code_all = -1; /* All-file response for replace(). */
- static uch rfm;
- static uch locbuf[BUFSALLOC]; /* Space for 2 buffers of BUFS512 */
- static unsigned loccnt = 0;
- static uch *locptr;
- static char got_eol = 0;
- struct bufdsc
- {
- struct bufdsc *next;
- uch *buf;
- unsigned bufcnt;
- };
- static struct bufdsc b1, b2, *curbuf; /* buffer ring for asynchronous I/O */
- static int _flush_blocks(__GPRO__ uch *rawbuf, unsigned size, int final_flag);
- static int _flush_stream(__GPRO__ uch *rawbuf, unsigned size, int final_flag);
- static int _flush_varlen(__GPRO__ uch *rawbuf, unsigned size, int final_flag);
- static int _flush_qio(__GPRO__ uch *rawbuf, unsigned size, int final_flag);
- static int _close_rms(__GPRO);
- static int _close_qio(__GPRO);
- #ifdef ASYNCH_QIO
- static int WriteQIO(__GPRO__ uch *buf, unsigned len);
- #endif
- static int WriteBuffer(__GPRO__ uch *buf, unsigned len);
- static int WriteRecord(__GPRO__ uch *rec, unsigned len);
- static int (*_flush_routine)(__GPRO__ uch *rawbuf, unsigned size,
- int final_flag);
- static int (*_close_routine)(__GPRO);
- #ifdef SYMLINKS
- static int _read_link_rms(__GPRO__ int byte_count, char *link_text_buf);
- #endif /* SYMLINKS */
- static void init_buf_ring(void);
- static void set_default_datetime_XABs(__GPRO);
- static int create_default_output(__GPRO);
- static int create_rms_output(__GPRO);
- static int create_qio_output(__GPRO);
- static int replace(__GPRO);
- static int replace_rms_newversion(__GPRO);
- static int replace_rms_overwrite(__GPRO);
- static int find_vms_attrs(__GPRO__ int set_date_time);
- static void free_up(void);
- #ifdef CHECK_VERSIONS
- static int get_vms_version(char *verbuf, int len);
- #endif /* CHECK_VERSIONS */
- static unsigned find_eol(ZCONST uch *p, unsigned n, unsigned *l);
- #ifdef SET_DIR_ATTRIB
- static char *vms_path_fixdown(ZCONST char *dir_spec, char *dir_file);
- #endif
- #ifdef TIMESTAMP
- static time_t mkgmtime(struct tm *tm);
- static void uxtime2vmstime(time_t utimeval, long int binval[2]);
- #endif /* TIMESTAMP */
- static int vms_msg_fetch(int status);
- static void vms_msg(__GPRO__ ZCONST char *string, int status);
- /*
- 2005-02-14 SMS.
- Added some ODS5 support:
- Use longer name structures in NAML, where available.
- Locate special characters mindful of "^" escapes.
- */
- /* Hex digit table. */
- char hex_digit[16] = {
- '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
- };
- /* Character property table for converting Zip file names to
- (simpler) ODS2 or (escaped) ODS5 extended file names.
- ODS2 valid characters: 0-9 A-Z a-z $ - _
- ODS5 Invalid characters:
- C0 control codes (0x00 to 0x1F inclusive)
- Asterisk (*)
- Question mark (?)
- ODS5 Invalid characters only in VMS V7.2 (which no one runs, right?):
- Double quotation marks (")
- Backslash (\)
- Colon (:)
- Left angle bracket (<)
- Right angle bracket (>)
- Slash (/)
- Vertical bar (|)
- Characters escaped by "^":
- SP ! " # % & ' ( ) + , . : ; =
- @ [ \ ] ^ ` { | } ~
- Either "^_" or "^ " is accepted as a space. Period (.) is a special
- case. Note that un-escaped < and > can also confuse a directory
- spec.
- Characters put out as ^xx:
- 7F (DEL)
- 80-9F (C1 control characters)
- A0 (nonbreaking space)
- FF (Latin small letter y diaeresis)
- Other cases:
- Unicode: "^Uxxxx", where "xxxx" is four hex digits.
- Property table values:
- Normal ODS2 1
- Lower-case ODS2 2
- Period 4
- Space 8
- ODS5 simple 16
- ODS5 1-char escape 32
- ODS5 hex-hex escape 64
- */
- unsigned char char_prop[256] = {
- /* NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US */
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* SP ! " # $ % & ' ( ) * + , - . / */
- 8, 32, 32, 32, 17, 32, 32, 32, 32, 32, 0, 32, 32, 17, 4, 0,
- /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 32, 32, 32, 32, 32, 32,
- /* @ A B C D E F G H I J K L M N O */
- 32, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
- /* P Q R S T U V W X Y Z [ \ ] ^ _ */
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 32, 32, 32, 32, 17,
- /* ` a b c d e f g h i j k l m n o */
- 32, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- /* p q r s t u v w x y z { | } ~ DEL */
- 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 32, 32, 32, 32, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 64
- };
- /* 2004-11-23 SMS.
- *
- * get_rms_defaults().
- *
- * Get user-specified values from (DCL) SET RMS_DEFAULT. FAB/RAB
- * items of particular interest are:
- *
- * fab$w_deq default extension quantity (blocks) (write).
- * rab$b_mbc multi-block count.
- * rab$b_mbf multi-buffer count (used with rah and wbh).
- */
- #define DIAG_FLAG (uO.vflag >= 3)
- /* Default RMS parameter values.
- * The default extend quantity (deq) should not matter much here, as the
- * initial allocation should always be set according to the known file
- * size, and no extension should be needed.
- */
- #define RMS_DEQ_DEFAULT 16384 /* About 1/4 the max (65535 blocks). */
- #define RMS_MBC_DEFAULT 127 /* The max, */
- #define RMS_MBF_DEFAULT 2 /* Enough to enable rah and wbh. */
- /* GETJPI item descriptor structure. */
- typedef struct
- {
- short buf_len;
- short itm_cod;
- void *buf;
- int *ret_len;
- } jpi_item_t;
- /* Durable storage */
- static int rms_defaults_known = 0;
- /* JPI item buffers. */
- static unsigned short rms_ext;
- static char rms_mbc;
- static unsigned char rms_mbf;
- /* Active RMS item values. */
- unsigned short rms_ext_active;
- char rms_mbc_active;
- unsigned char rms_mbf_active;
- /* GETJPI item lengths. */
- static int rms_ext_len; /* Should come back 2. */
- static int rms_mbc_len; /* Should come back 1. */
- static int rms_mbf_len; /* Should come back 1. */
- /* Desperation attempts to define unknown macros. Probably doomed.
- * If these get used, expect sys$getjpiw() to return %x00000014 =
- * %SYSTEM-F-BADPARAM, bad parameter value.
- * They keep compilers with old header files quiet, though.
- */
- #ifndef JPI$_RMS_EXTEND_SIZE
- # define JPI$_RMS_EXTEND_SIZE 542
- #endif /* ndef JPI$_RMS_EXTEND_SIZE */
- #ifndef JPI$_RMS_DFMBC
- # define JPI$_RMS_DFMBC 535
- #endif /* ndef JPI$_RMS_DFMBC */
- #ifndef JPI$_RMS_DFMBFSDK
- # define JPI$_RMS_DFMBFSDK 536
- #endif /* ndef JPI$_RMS_DFMBFSDK */
- /* GETJPI item descriptor set. */
- struct
- {
- jpi_item_t rms_ext_itm;
- jpi_item_t rms_mbc_itm;
- jpi_item_t rms_mbf_itm;
- int term;
- } jpi_itm_lst =
- { { 2, JPI$_RMS_EXTEND_SIZE, &rms_ext, &rms_ext_len },
- { 1, JPI$_RMS_DFMBC, &rms_mbc, &rms_mbc_len },
- { 1, JPI$_RMS_DFMBFSDK, &rms_mbf, &rms_mbf_len },
- 0
- };
- static int get_rms_defaults()
- {
- int sts;
- /* Get process RMS_DEFAULT values. */
- sts = sys$getjpiw(0, 0, 0, &jpi_itm_lst, 0, 0, 0);
- if ((sts & STS$M_SEVERITY) != STS$K_SUCCESS)
- {
- /* Failed. Don't try again. */
- rms_defaults_known = -1;
- }
- else
- {
- /* Fine, but don't come back. */
- rms_defaults_known = 1;
- }
- /* Limit the active values according to the RMS_DEFAULT values. */
- if (rms_defaults_known > 0)
- {
- /* Set the default values. */
- rms_ext_active = RMS_DEQ_DEFAULT;
- rms_mbc_active = RMS_MBC_DEFAULT;
- rms_mbf_active = RMS_MBF_DEFAULT;
- /* Default extend quantity. Use the user value, if set. */
- if (rms_ext > 0)
- {
- rms_ext_active = rms_ext;
- }
- /* Default multi-block count. Use the user value, if set. */
- if (rms_mbc > 0)
- {
- rms_mbc_active = rms_mbc;
- }
- /* Default multi-buffer count. Use the user value, if set. */
- if (rms_mbf > 0)
- {
- rms_mbf_active = rms_mbf;
- }
- }
- if (DIAG_FLAG)
- {
- fprintf(stderr, "Get RMS defaults. getjpi sts = %%x%08x.\n", sts);
- if (rms_defaults_known > 0)
- {
- fprintf(stderr,
- " Default: deq = %6d, mbc = %3d, mbf = %3d.\n",
- rms_ext, rms_mbc, rms_mbf);
- }
- }
- return sts;
- }
- int check_format(__G)
- __GDEF
- {
- int rtype;
- int sts;
- struct FAB fab;
- #ifdef NAML$C_MAXRSS
- struct NAML nam;
- #endif
- fab = cc$rms_fab; /* Initialize FAB. */
- #ifdef NAML$C_MAXRSS
- nam = cc$rms_naml; /* Initialize NAML. */
- fab.fab$l_naml = &nam; /* Point FAB to NAML. */
- fab.fab$l_dna = (char *) -1; /* Using NAML for default name. */
- fab.fab$l_fna = (char *) -1; /* Using NAML for file name. */
- #endif /* NAML$C_MAXRSS */
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_FNA = G.zipfn;
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_FNS = strlen(G.zipfn);
- if (ERR(sts = sys$open(&fab)))
- {
- Info(slide, 1, ((char *)slide, "\n\
- error: cannot open zipfile [ %s ].\n",
- FnFilter1(G.zipfn)));
- vms_msg(__G__ " sys$open() error: ", sts);
- return PK_ERR;
- }
- rtype = fab.fab$b_rfm;
- sys$close(&fab);
- if (rtype == FAB$C_VAR || rtype == FAB$C_VFC)
- {
- Info(slide, 1, ((char *)slide, "\n\
- Error: zipfile is in variable-length record format. Please\n\
- run \"bilf l %s\" to convert the zipfile to stream-LF\n\
- record format. (BILF is available at various VMS archives.)\n\n",
- FnFilter1(G.zipfn)));
- return PK_ERR;
- }
- return PK_COOL;
- }
- #define PRINTABLE_FORMAT(x) ( (x) == FAB$C_VAR \
- || (x) == FAB$C_STMLF \
- || (x) == FAB$C_STMCR \
- || (x) == FAB$C_STM )
- /* VMS extra field types */
- #define VAT_NONE 0
- #define VAT_IZ 1 /* old Info-ZIP format */
- #define VAT_PK 2 /* PKWARE format */
- /*
- * open_outfile() assignments:
- *
- * VMS attributes ? create_xxx _flush_xxx
- * ---------------- ---------- ----------
- * not found 'default' text mode ?
- * yes -> 'stream'
- * no -> 'block'
- *
- * yes, in IZ format 'rms' uO.cflag ?
- * yes -> switch (fab.rfm)
- * VAR -> 'varlen'
- * STM* -> 'stream'
- * default -> 'block'
- * no -> 'block'
- *
- * yes, in PK format 'qio' uO.cflag ?
- * yes -> switch (pka_rattr)
- * VAR -> 'varlen'
- * STM* -> 'stream'
- * default -> 'block'
- * no -> 'qio'
- *
- * "text mode" == G.pInfo->textmode || (uO.cflag && !uO.bflag)
- * (simplified, for complete expression see create_default_output() code)
- */
- /* The VMS version of open_outfile() supports special return codes:
- * OPENOUT_OK a file has been opened normally
- * OPENOUT_FAILED the file open process failed
- * OPENOUT_SKIPOK file open skipped at user request, err level OK
- * OPENOUT_SKIPWARN file open skipped at user request, err level WARN
- */
- int open_outfile(__G)
- __GDEF
- {
- /* Get process RMS_DEFAULT values, if not already done. */
- if (rms_defaults_known == 0)
- {
- get_rms_defaults();
- }
- switch (find_vms_attrs(__G__ (uO.D_flag <= 1)))
- {
- case VAT_NONE:
- default:
- return create_default_output(__G);
- case VAT_IZ:
- return create_rms_output(__G);
- case VAT_PK:
- return create_qio_output(__G);
- }
- }
- static void init_buf_ring()
- {
- locptr = &locbuf[0];
- loccnt = 0;
- b1.buf = &locbuf[0];
- b1.bufcnt = 0;
- b1.next = &b2;
- b2.buf = &locbuf[BUFS512];
- b2.bufcnt = 0;
- b2.next = &b1;
- curbuf = &b1;
- }
- /* Static data storage for time conversion: */
- /* string constants for month names */
- static ZCONST char *month[] =
- {"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
- "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
- /* buffer for time string */
- static char timbuf[24]; /* length = first entry in "date_str" + 1 */
- /* fixed-length string descriptor for timbuf: */
- static ZCONST struct dsc$descriptor date_str =
- {sizeof(timbuf)-1, DSC$K_DTYPE_T, DSC$K_CLASS_S, timbuf};
- static void set_default_datetime_XABs(__GPRO)
- {
- unsigned yr, mo, dy, hh, mm, ss;
- #ifdef USE_EF_UT_TIME
- iztimes z_utime;
- struct tm *t;
- if (G.extra_field &&
- #ifdef IZ_CHECK_TZ
- G.tz_is_valid &&
- #endif
- (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0,
- G.lrec.last_mod_dos_datetime, &z_utime, NULL)
- & EB_UT_FL_MTIME))
- t = localtime(&(z_utime.mtime));
- else
- t = (struct tm *)NULL;
- if (t != (struct tm *)NULL)
- {
- yr = t->tm_year + 1900;
- mo = t->tm_mon;
- dy = t->tm_mday;
- hh = t->tm_hour;
- mm = t->tm_min;
- ss = t->tm_sec;
- }
- else
- {
- yr = ((G.lrec.last_mod_dos_datetime >> 25) & 0x7f) + 1980;
- mo = ((G.lrec.last_mod_dos_datetime >> 21) & 0x0f) - 1;
- dy = (G.lrec.last_mod_dos_datetime >> 16) & 0x1f;
- hh = (G.lrec.last_mod_dos_datetime >> 11) & 0x1f;
- mm = (G.lrec.last_mod_dos_datetime >> 5) & 0x3f;
- ss = (G.lrec.last_mod_dos_datetime << 1) & 0x3e;
- }
- #else /* !USE_EF_UT_TIME */
- yr = ((G.lrec.last_mod_dos_datetime >> 25) & 0x7f) + 1980;
- mo = ((G.lrec.last_mod_dos_datetime >> 21) & 0x0f) - 1;
- dy = (G.lrec.last_mod_dos_datetime >> 16) & 0x1f;
- hh = (G.lrec.last_mod_dos_datetime >> 11) & 0x1f;
- mm = (G.lrec.last_mod_dos_datetime >> 5) & 0x3f;
- ss = (G.lrec.last_mod_dos_datetime << 1) & 0x1f;
- #endif /* ?USE_EF_UT_TIME */
- dattim = cc$rms_xabdat; /* fill XABs with default values */
- rdt = cc$rms_xabrdt;
- sprintf(timbuf, "%02u-%3s-%04u %02u:%02u:%02u.00",
- dy, month[mo], yr, hh, mm, ss);
- sys$bintim(&date_str, &dattim.xab$q_cdt);
- memcpy(&rdt.xab$q_rdt, &dattim.xab$q_cdt, sizeof(rdt.xab$q_rdt));
- }
- /* The following return codes are supported:
- * OPENOUT_OK a file has been opened normally
- * OPENOUT_FAILED the file open process failed
- * OPENOUT_SKIPOK file open skipped at user request, err level OK
- * OPENOUT_SKIPWARN file open skipped at user request, err level WARN
- */
- static int create_default_output(__GPRO)
- {
- int ierr;
- int text_output, bin_fixed;
- /* Extract the file in text format (Variable_length by default,
- * Stream_LF with "-S" (/TEXT = STMLF), when
- * a) explicitly requested by the user (through the -a option),
- * and it is not a symbolic link,
- * or
- * b) piping to SYS$OUTPUT, unless "binary" piping was requested
- * by the user (through the -b option).
- */
- text_output = (G.pInfo->textmode
- #ifdef SYMLINKS
- && !G.symlnk
- #endif
- ) ||
- (uO.cflag &&
- (!uO.bflag || (!(uO.bflag - 1) && G.pInfo->textfile)));
- /* Use fixed length 512 byte record format for disk file when
- * a) explicitly requested by the user (-b option),
- * and
- * b) it is not a symbolic link,
- * and
- * c) it is not extracted in text mode.
- */
- bin_fixed = !text_output &&
- #ifdef SYMLINKS
- !G.symlnk &&
- #endif
- (uO.bflag != 0) && ((uO.bflag != 1) || !G.pInfo->textfile);
- rfm = FAB$C_STMLF; /* Default, stream-LF format from VMS or UNIX */
- if (!uO.cflag) /* Redirect output */
- {
- rab = cc$rms_rab; /* Initialize RAB. */
- fileblk = cc$rms_fab; /* Initialize FAB. */
- fileblk.fab$l_xab = NULL; /* No XABs. */
- rab.rab$l_fab = &fileblk; /* Point RAB to FAB. */
- outfab = &fileblk; /* Set pointers used elsewhere. */
- outrab = &rab;
- if (text_output && (!uO.S_flag))
- { /* Default format for output `real' text file */
- fileblk.fab$b_rfm = FAB$C_VAR; /* variable length records */
- fileblk.fab$b_rat = FAB$M_CR; /* implied (CR) carriage ctrl */
- }
- else if (bin_fixed)
- { /* Default format for output `real' binary file */
- fileblk.fab$b_rfm = FAB$C_FIX; /* fixed length records */
- fileblk.fab$w_mrs = 512; /* record size 512 bytes */
- fileblk.fab$b_rat = 0; /* no carriage ctrl */
- }
- else
- { /* Default format for output misc (bin or text) file */
- fileblk.fab$b_rfm = FAB$C_STMLF; /* stream-LF record format */
- fileblk.fab$b_rat = FAB$M_CR; /* implied (CR) carriage ctrl */
- }
- #ifdef NAML$C_MAXRSS
- nam = CC_RMS_NAM; /* Initialize NAML. */
- fileblk.FAB_NAM = &nam; /* Point FAB to NAML. */
- fileblk.fab$l_dna = (char *) -1; /* Using NAML for default name. */
- fileblk.fab$l_fna = (char *) -1; /* Using NAML for file name. */
- #endif /* NAML$C_MAXRSS */
- FAB_OR_NAML(fileblk, nam).FAB_OR_NAML_FNA = G.filename;
- FAB_OR_NAML(fileblk, nam).FAB_OR_NAML_FNS = strlen(G.filename);
- /* Prepare date-time XABs, unless user requests not to. */
- if (uO.D_flag <= 1) {
- set_default_datetime_XABs(__G);
- dattim.xab$l_nxt = fileblk.fab$l_xab;
- fileblk.fab$l_xab = (void *) &dattim;
- }
- /* 2005-02-14 SMS. What does this mean? ----vvvvvvvvvvvvvvvvvvvvvvvvvvv */
- fileblk.fab$w_ifi = 0; /* Clear IFI. It may be nonzero after ZIP */
- fileblk.fab$b_fac = FAB$M_BRO | FAB$M_PUT; /* {block|record} output */
- #ifdef SYMLINKS
- if (G.symlnk)
- /* Symlink file is read back to retrieve the link text. */
- fileblk.fab$b_fac |= FAB$M_GET;
- #endif
- /* 2004-11-23 SMS.
- * If RMS_DEFAULT values have been determined, and have not been
- * set by the user, then set some FAB/RAB parameters for faster
- * output. User-specified RMS_DEFAULT values override the
- * built-in default values, so if the RMS_DEFAULT values could
- * not be determined, then these (possibly unwise) values could
- * not be overridden, and hence will not be set. Honestly,
- * this seems to be excessively cautious, but only old VMS
- * versions will be affected.
- */
- /* If RMS_DEFAULT (and adjusted active) values are available,
- * then set the FAB/RAB parameters. If RMS_DEFAULT values are
- * not available, then suffer with the default behavior.
- */
- if (rms_defaults_known > 0)
- {
- /* Set the FAB/RAB parameters accordingly. */
- fileblk.fab$w_deq = rms_ext_active;
- rab.rab$b_mbc = rms_mbc_active;
- rab.rab$b_mbf = rms_mbf_active;
- #ifdef OLD_FABDEF
- /* Truncate at EOF on close, as we may over-extend. */
- fileblk.fab$l_fop |= FAB$M_TEF ;
- /* If using multiple buffers, enable write-behind. */
- if (rms_mbf_active > 1)
- {
- rab.rab$l_rop |= RAB$M_WBH;
- }
- }
- /* Set the initial file allocation according to the file
- * size. Also set the "sequential access only" flag, as
- * otherwise, on a file system with highwater marking
- * enabled, allocating space for a large file may lock the
- * disk for a long time (minutes).
- */
- fileblk.fab$l_alq = (unsigned) (G.lrec.ucsize+ 511)/ 512;
- fileblk.fab$l_fop |= FAB$M_SQO;
- #else /* !OLD_FABDEF */
- /* Truncate at EOF on close, as we may over-extend. */
- fileblk.fab$v_tef = 1;
- /* If using multiple buffers, enable write-behind. */
- if (rms_mbf_active > 1)
- {
- rab.rab$v_wbh = 1;
- }
- }
- /* Set the initial file allocation according to the file
- * size. Also set the "sequential access only" flag, as
- * otherwise, on a file system with highwater marking
- * enabled, allocating space for a large file may lock the
- * disk for a long time (minutes).
- */
- fileblk.fab$l_alq = (unsigned) (G.lrec.ucsize+ 511)/ 512;
- fileblk.fab$v_sqo = 1;
- #endif /* ?OLD_FABDEF */
- ierr = sys$create(outfab);
- if (ierr == RMS$_FEX)
- {
- /* File exists.
- * Consider command-line options, or ask the user what to do.
- */
- ierr = replace(__G);
- switch (ierr & REPL_TASKMASK)
- {
- case REPL_NO_EXTRACT: /* No extract. */
- free_up();
- return ((ierr & REPL_ERRLV_WARN)
- ? OPENOUT_SKIPWARN : OPENOUT_SKIPOK);
- case REPL_NEW_VERSION: /* Create a new version. */
- ierr = replace_rms_newversion(__G);
- break;
- case REPL_OVERWRITE: /* Overwrite the existing file. */
- ierr = replace_rms_overwrite(__G);
- break;
- }
- }
- if (ERR(ierr))
- {
- char buf[NAM_MAXRSS + 128]; /* Name length + message length. */
- sprintf(buf, "[ Cannot create ($create) output file %s ]\n",
- G.filename);
- vms_msg(__G__ buf, ierr);
- if (fileblk.fab$l_stv != 0)
- {
- vms_msg(__G__ "", fileblk.fab$l_stv);
- }
- free_up();
- return OPENOUT_FAILED;
- }
- if (!text_output)
- {
- rab.rab$l_rop |= (RAB$M_BIO | RAB$M_ASY);
- }
- rab.rab$b_rac = RAB$C_SEQ;
- if ((ierr = sys$connect(&rab)) != RMS$_NORMAL)
- {
- #ifdef DEBUG
- vms_msg(__G__ "create_default_output: sys$connect failed.\n", ierr);
- if (fileblk.fab$l_stv != 0)
- {
- vms_msg(__G__ "", fileblk.fab$l_stv);
- }
- #endif
- Info(slide, 1, ((char *)slide,
- "Cannot create ($connect) output file: %s\n",
- FnFilter1(G.filename)));
- free_up();
- return OPENOUT_FAILED;
- }
- } /* end if (!uO.cflag) */
- init_buf_ring();
- _flush_routine = text_output ? got_eol=0,_flush_stream : _flush_blocks;
- _close_routine = _close_rms;
- return OPENOUT_OK;
- }
- /* The following return codes are supported:
- * OPENOUT_OK a file has been opened normally
- * OPENOUT_FAILED the file open process failed
- * OPENOUT_SKIPOK file open skipped at user request, err level OK
- * OPENOUT_SKIPWARN file open skipped at user request, err level WARN
- */
- static int create_rms_output(__GPRO)
- {
- int ierr;
- int text_output;
- /* extract the file in text (variable-length) format, when
- * piping to SYS$OUTPUT, unless "binary" piping was requested
- * by the user (through the -b option); the "-a" option is
- * ignored when extracting zip entries with VMS attributes saved
- */
- text_output = uO.cflag &&
- (!uO.bflag || (!(uO.bflag - 1) && G.pInfo->textfile));
- rfm = outfab->fab$b_rfm; /* Use record format from VMS extra field */
- if (uO.cflag) /* SYS$OUTPUT */
- {
- if (text_output && !PRINTABLE_FORMAT(rfm))
- {
- Info(slide, 1, ((char *)slide,
- "[ File %s has illegal record format to put to screen ]\n",
- FnFilter1(G.filename)));
- free_up();
- return OPENOUT_FAILED;
- }
- }
- else /* File output */
- {
- rab = cc$rms_rab; /* Initialize RAB. */
- /* The output FAB has already been initialized with the values
- * found in the Zip file's "VMS attributes" extra field.
- */
- #ifdef NAML$C_MAXRSS
- nam = CC_RMS_NAM; /* Initialize NAML. */
- outfab->FAB_NAM = &nam; /* Point FAB to NAML. */
- outfab->fab$l_dna = (char *) -1; /* Using NAML for default name. */
- outfab->fab$l_fna = (char *) -1; /* Using NAML for file name. */
- #endif /* NAML$C_MAXRSS */
- FAB_OR_NAML(*outfab, nam).FAB_OR_NAML_FNA = G.filename;
- FAB_OR_NAML(*outfab, nam).FAB_OR_NAML_FNS = strlen(G.filename);
- /* Prepare date-time XABs, unless user requests not to. */
- if (uO.D_flag <= 1) {
- /* If no XAB date/time, use attributes from non-VMS fields. */
- if (!(xabdat && xabrdt))
- {
- set_default_datetime_XABs(__G);
- if (xabdat == NULL)
- {
- dattim.xab$l_nxt = outfab->fab$l_xab;
- outfab->fab$l_xab = (void *) &dattim;
- }
- }
- }
- /* 2005-02-14 SMS. What does this mean? ----vvvvvvvvvvvvvvvvvvvvvvvvvvv */
- outfab->fab$w_ifi = 0; /* Clear IFI. It may be nonzero after ZIP */
- outfab->fab$b_fac = FAB$M_BIO | FAB$M_PUT; /* block-mode output */
- #ifdef SYMLINKS
- /* 2007-02-28 SMS.
- * VMS/RMS symlink properties will be restored naturally when
- * the link file is recreated this way, so there's no need to do
- * the deferred symlink post-processing step for this file.
- * Therefore, clear the pInfo->symlink flag here, and the symlink
- * "close file" processor will only display the link text.
- */
- if (G.symlnk) {
- G.pInfo->symlink = 0;
- if (QCOND2) {
- /* Symlink file is read back to display the link text. */
- outfab->fab$b_fac |= FAB$M_GET;
- }
- }
- #endif /* SYMLINKS */
- /* 2004-11-23 SMS.
- * Set the "sequential access only" flag, as otherwise, on a
- * file system with highwater marking enabled, allocating space
- * for a large file may lock the disk for a long time (minutes).
- */
- #ifdef OLD_FABDEF
- outfab-> fab$l_fop |= FAB$M_SQO;
- #else /* !OLD_FABDEF */
- outfab-> fab$v_sqo = 1;
- #endif /* ?OLD_FABDEF */
- ierr = sys$create(outfab);
- if (ierr == RMS$_FEX)
- {
- /* File exists.
- * Consider command-line options, or ask the user what to do.
- */
- ierr = replace(__G);
- switch (ierr & REPL_TASKMASK)
- {
- case REPL_NO_EXTRACT: /* No extract. */
- free_up();
- return ((ierr & REPL_ERRLV_WARN)
- ? OPENOUT_SKIPWARN : OPENOUT_SKIPOK);
- case REPL_NEW_VERSION: /* Create a new version. */
- ierr = replace_rms_newversion(__G);
- break;
- case REPL_OVERWRITE: /* Overwrite the existing file. */
- ierr = replace_rms_overwrite(__G);
- break;
- }
- }
- if (ERR(ierr))
- {
- char buf[NAM_MAXRSS + 128]; /* Name length + message length. */
- sprintf(buf, "[ Cannot create ($create) output file %s ]\n",
- G.filename);
- vms_msg(__G__ buf, ierr);
- if (outfab->fab$l_stv != 0)
- {
- vms_msg(__G__ "", outfab->fab$l_stv);
- }
- free_up();
- return OPENOUT_FAILED;
- }
- if (outfab->fab$b_org & (FAB$C_REL | FAB$C_IDX)) {
- /* relative and indexed files require explicit allocation */
- ierr = sys$extend(outfab);
- if (ERR(ierr))
- {
- char buf[NAM_MAXRSS + 128]; /* Name length + msg length. */
- sprintf(buf, "[ Cannot allocate space for %s ]\n", G.filename);
- vms_msg(__G__ buf, ierr);
- if (outfab->fab$l_stv != 0)
- {
- vms_msg(__G__ "", outfab->fab$l_stv);
- }
- free_up();
- return OPENOUT_FAILED;
- }
- }
- outrab = &rab;
- rab.rab$l_fab = outfab;
- {
- rab.rab$l_rop |= (RAB$M_BIO | RAB$M_ASY);
- }
- rab.rab$b_rac = RAB$C_SEQ;
- if ((ierr = sys$connect(outrab)) != RMS$_NORMAL)
- {
- #ifdef DEBUG
- vms_msg(__G__ "create_rms_output: sys$connect failed.\n", ierr);
- if (outfab->fab$l_stv != 0)
- {
- vms_msg(__G__ "", outfab->fab$l_stv);
- }
- #endif
- Info(slide, 1, ((char *)slide,
- "Cannot create ($connect) output file: %s\n",
- FnFilter1(G.filename)));
- free_up();
- return OPENOUT_FAILED;
- }
- } /* end if (!uO.cflag) */
- init_buf_ring();
- if ( text_output )
- switch (rfm)
- {
- case FAB$C_VAR:
- _flush_routine = _flush_varlen;
- break;
- case FAB$C_STM:
- case FAB$C_STMCR:
- case FAB$C_STMLF:
- _flush_routine = _flush_stream;
- got_eol = 0;
- break;
- default:
- _flush_routine = _flush_blocks;
- break;
- }
- else
- _flush_routine = _flush_blocks;
- _close_routine = _close_rms;
- return OPENOUT_OK;
- }
- static int pka_devchn;
- static int pka_io_pending;
- static unsigned pka_vbn;
- /* IOSB for QIO[W] read and write operations. */
- #if defined(__DECC) || defined(__DECCXX)
- #pragma __member_alignment __save
- #pragma __nomember_alignment
- #endif /* __DECC || __DECCXX */
- static struct
- {
- unsigned short status;
- unsigned int count; /* Unaligned ! */
- unsigned short dummy;
- } pka_io_iosb;
- #if defined(__DECC) || defined(__DECCXX)
- #pragma __member_alignment __restore
- #endif /* __DECC || __DECCXX */
- /* IOSB for QIO[W] miscellaneous ACP operations. */
- static struct
- {
- unsigned short status;
- unsigned short dummy;
- unsigned int count;
- } pka_acp_iosb;
- static struct fibdef pka_fib;
- static struct atrdef pka_atr[VMS_MAX_ATRCNT];
- static int pka_idx;
- static ulg pka_uchar;
- static struct fatdef pka_rattr;
- /* Directory attribute storage, descriptor (list). */
- static struct atrdef pka_recattr[2] =
- { { sizeof(pka_rattr), ATR$C_RECATTR, GVTC &pka_rattr}, /* RECATTR. */
- { 0, 0, 0 } /* List terminator. */
- };
- static struct dsc$descriptor pka_fibdsc =
- { sizeof(pka_fib), DSC$K_DTYPE_Z, DSC$K_CLASS_S, (void *) &pka_fib };
- static struct dsc$descriptor_s pka_devdsc =
- { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &nam.NAM_DVI[1] };
- static struct dsc$descriptor_s pka_fnam =
- { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
- /* Expanded and resultant name storage. */
- static char exp_nam[NAM_MAXRSS];
- static char res_nam[NAM_MAXRSS];
- /* Special ODS5-QIO-compatible name storage. */
- #ifdef NAML$C_MAXRSS
- static char sys_nam[NAML$C_MAXRSS]; /* Probably need less here. */
- #endif /* NAML$C_MAXRSS */
- #define PK_PRINTABLE_RECTYP(x) ( (x) == FAT$C_VARIABLE \
- || (x) == FAT$C_STREAMLF \
- || (x) == FAT$C_STREAMCR \
- || (x) == FAT$C_STREAM )
- /* The following return codes are supported:
- * OPENOUT_OK a file has been opened normally
- * OPENOUT_FAILED the file open process failed
- * OPENOUT_SKIPOK file open skipped at user request, err level OK
- * OPENOUT_SKIPWARN file open skipped at user request, err level WARN
- */
- static int create_qio_output(__GPRO)
- {
- int status;
- int i;
- int text_output;
- /* extract the file in text (variable-length) format, when
- * piping to SYS$OUTPUT, unless "binary" piping was requested
- * by the user (through the -b option); the "-a" option is
- * ignored when extracting zip entries with VMS attributes saved
- */
- text_output = uO.cflag &&
- (!uO.bflag || (!(uO.bflag - 1) && G.pInfo->textfile));
- if ( uO.cflag )
- {
- int rtype;
- if (text_output)
- {
- rtype = pka_rattr.fat$v_rtype;
- if (!PK_PRINTABLE_RECTYP(rtype))
- {
- Info(slide, 1, ((char *)slide,
- "[ File %s has illegal record format to put to screen ]\n",
- FnFilter1(G.filename)));
- return OPENOUT_FAILED;
- }
- }
- else
- /* force "block I/O" for binary piping mode */
- rtype = FAT$C_UNDEFINED;
- init_buf_ring();
- switch (rtype)
- {
- case FAT$C_VARIABLE:
- _flush_routine = _flush_varlen;
- break;
- case FAT$C_STREAM:
- case FAT$C_STREAMCR:
- case FAT$C_STREAMLF:
- _flush_routine = _flush_stream;
- got_eol = 0;
- break;
- default:
- _flush_routine = _flush_blocks;
- break;
- }
- _close_routine = _close_rms;
- }
- else /* !(uO.cflag) : redirect output */
- {
- fileblk = cc$rms_fab; /* Initialize FAB. */
- nam = CC_RMS_NAM; /* Initialize NAM[L]. */
- fileblk.FAB_NAM = &nam; /* Point FAB to NAM[L]. */
- #ifdef NAML$C_MAXRSS
- fileblk.fab$l_dna = (char *) -1; /* Using NAML for default name. */
- fileblk.fab$l_fna = (char *) -1; /* Using NAML for file name. */
- /* Special ODS5-QIO-compatible name storage. */
- nam.naml$l_filesys_name = sys_nam;
- nam.naml$l_filesys_name_alloc = sizeof(sys_nam);
- #endif /* NAML$C_MAXRSS */
- /* VMS-format file name, derived from archive. */
- FAB_OR_NAML(fileblk, nam).FAB_OR_NAML_FNA = G.filename;
- FAB_OR_NAML(fileblk, nam).FAB_OR_NAML_FNS = strlen(G.filename);
- /* Expanded and resultant name storage. */
- nam.NAM_ESA = exp_nam;
- nam.NAM_ESS = sizeof(exp_nam);
- nam.NAM_RSA = res_nam;
- nam.NAM_RSS = sizeof(res_nam);
- if ( ERR(status = sys$parse(&fileblk)) )
- {
- vms_msg(__G__ "create_qio_output: sys$parse failed.\n", status);
- return OPENOUT_FAILED;
- }
- pka_devdsc.dsc$w_length = (unsigned short)nam.NAM_DVI[0];
- if ( ERR(status = sys$assign(&pka_devdsc, &pka_devchn, 0, 0)) )
- {
- vms_msg(__G__ "create_qio_output: sys$assign failed.\n", status);
- return OPENOUT_FAILED;
- }
- #ifdef NAML$C_MAXRSS
- /* Enable fancy name characters. Note that "fancy" here does
- not include Unicode, for which there's no support elsewhere.
- */
- pka_fib.fib$v_names_8bit = 1;
- pka_fib.fib$b_name_format_in = FIB$C_ISL1;
- /* ODS5 Extended names used as input to QIO have peculiar
- encoding (perhaps to minimize storage?), so the special
- filesys_name result (typically containing fewer carets) must
- be used here.
- */
- pka_fnam.dsc$a_pointer = nam.naml$l_filesys_name;
- pka_fnam.dsc$w_length = nam.naml$l_filesys_name_size;
- #else /* !NAML$C_MAXRSS */
- /* Extract only the name.type;version.
- 2005-02-14 SMS.
- Note: In old code, the version in the name here was retained
- only if -V (uO.V_flag, so that there might be an explicit
- version number in the archive (or perhaps not)), but the
- version should already have been stripped before this in
- adj_file_name_odsX(), and sys$parse() here should always
- return a good version number which may be used as-is. If
- not, here's where to fix the (new) problem. Note that the
- ODS5-compatible code uses the whole thing in filesys_name,
- too, and that's critical for proper interpretation of funny
- names. (Omitting the ";" can cause trouble, so it should
- certainly be kept, even if the version digits are removed
- here.)
- */
- pka_fnam.dsc$a_pointer = nam.NAM_L_NAME;
- pka_fnam.dsc$w_length =
- nam.NAM_B_NAME + nam.NAM_B_TYPE + nam.NAM_B_VER;
- #if 0
- pka_fnam.dsc$w_length = nam.NAM_B_NAME + nam.NAM_B_TYPE;
- if ( uO.V_flag /* keep versions */ )
- pka_fnam.dsc$w_length += nam.NAM_B_VER;
- #endif /* 0 */
- #endif /* ?NAML$C_MAXRSS */
- /* Move the directory ID from the NAM[L] to the FIB.
- Clear the FID in the FIB, as we're using the name.
- */
- for (i = 0; i < 3; i++)
- {
- pka_fib.FIB$W_DID[i] = nam.NAM_DID[i];
- pka_fib.FIB$W_FID[i] = 0;
- }
- /* 2004-11-23 SMS.
- * Set the "sequential access only" flag, as otherwise, on a
- * file system with highwater marking enabled, allocating space
- * for a large file may lock the disk for a long time (minutes).
- * (The "no other readers" flag is also required, if you want
- * the "sequential access only" flag to have any effect.)
- */
- pka_fib.FIB$L_ACCTL = FIB$M_WRITE | FIB$M_SEQONLY | FIB$M_NOREAD;
- /* Allocate space for the file */
- pka_fib.FIB$W_EXCTL = FIB$M_EXTEND;
- if ( pka_uchar & FCH$M_CONTIG )
- pka_fib.FIB$W_EXCTL |= FIB$M_ALCON | FIB$M_FILCON;
- if ( pka_uchar & FCH$M_CONTIGB )
- pka_fib.FIB$W_EXCTL |= FIB$M_ALCONB;
- #define SWAPW(x) ( (((x)>>16)&0xFFFF) + ((x)<<16) )
- pka_fib.fib$l_exsz = SWAPW(pka_rattr.fat$l_hiblk);
- status = sys$qiow(0, /* event flag */
- pka_devchn, /* channel */
- IO$_CREATE|IO$M_CREATE|IO$M_ACCESS, /* funct */
- &pka_acp_iosb, /* IOSB */
- 0, /* AST address */
- 0, /* AST parameter */
- &pka_fibdsc, /* P1 = File Info Block */
- &pka_fnam, /* P2 = File name (descr) */
- 0, /* P3 (= Resulting name len) */
- 0, /* P4 (= Resulting name descr) */
- pka_atr, /* P5 = Attribute descr */
- 0); /* P6 (not used) */
- if ( !ERR(status) )
- status = pka_acp_iosb.status;
- if ( status == SS$_DUPFILENAME )
- {
- /* File exists. Prepare to ask user what to do. */
- /* Arrange to store the resultant file spec (with new
- * version?) where the message code will find it.
- */
- short res_nam_len;
- struct dsc$descriptor_s res_nam_dscr =
- { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
- res_nam_dscr.dsc$a_pointer = G.filename;
- res_nam_dscr.dsc$w_length = sizeof(G.filename);
- /* File exists.
- * Consider command-line options, or ask the user what to do.
- */
- status = replace(__G);
- switch (status & REPL_TASKMASK)
- {
- case REPL_NO_EXTRACT: /* No extract. */
- free_up();
- return ((status & REPL_ERRLV_WARN)
- ? OPENOUT_SKIPWARN : OPENOUT_SKIPOK);
- case REPL_NEW_VERSION: /* Create a new version. */
- pka_fib.FIB$W_NMCTL |= FIB$M_NEWVER;
- break;
- case REPL_OVERWRITE: /* Overwrite the existing file. */
- pka_fib.FIB$W_NMCTL |= FIB$M_SUPERSEDE;
- break;
- }
- /* Retry file creation with new (user-specified) policy. */
- status = sys$qiow(0, /* event flag */
- pka_devchn, /* channel */
- IO$_CREATE|IO$M_CREATE|IO$M_ACCESS, /* funct */
- &pka_acp_iosb, /* IOSB */
- 0, /* AST address */
- 0, /* AST parameter */
- &pka_fibdsc, /* P1 = File Info Block */
- &pka_fnam, /* P2 = File name (descr) */
- &res_nam_len, /* P3 = Resulting name len */
- &res_nam_dscr, /* P4 = Resulting name descr */
- pka_atr, /* P5 = Attribute descr */
- 0); /* P6 (not used) */
- if ( !ERR(status) )
- status = pka_acp_iosb.status;
- if (res_nam_len > 0)
- {
- /* NUL-terminate the resulting file spec. */
- G.filename[res_nam_len] = '\0';
- }
- /* Clear any user-specified version policy flags
- * (for the next file to be processed).
- */
- pka_fib.FIB$W_NMCTL &= (~(FIB$M_NEWVER| FIB$M_SUPERSEDE));
- }
- if ( ERR(status) )
- {
- char buf[NAM_MAXRSS + 128]; /* Name length + message length. */
- sprintf(buf, "[ Cannot create (QIO) output file %s ]\n",
- G.filename);
- vms_msg(__G__ buf, status);
- sys$dassgn(pka_devchn);
- return OPENOUT_FAILED;
- }
- #ifdef ASYNCH_QIO
- init_buf_ring();
- pka_io_pending = FALSE;
- #else
- locptr = locbuf;
- loccnt = 0;
- #endif
- pka_vbn = 1;
- _flush_routine = _flush_qio;
- _close_routine = _close_qio;
- } /* end if (!uO.cflag) */
- return OPENOUT_OK;
- }
- /* 2008-07-23 SMS.
- * Segregated user query function from file re-open functions/code.
- *
- * There was no code in create_qio_output() to deal with an
- * SS$_DUPFILENAME condition, leading to ugly run-time failures, and its
- * requirements differ from those of the RMS (non-QIO) functions,
- * create_default_output() and create_rms_output().
- *
- * Whether it makes sense to have a second layer of VMS-specific
- * querying after the generic UnZip query in extract.c:
- * extract_or_test_entrylist() is another question, but changing that
- * looks more scary than just getting the VMS-specific stuff to work
- * right (better?).
- */
- /* "File exists" handler(s). Ask user about further action. */
- /* RMS create new version. */
- static int replace_rms_newversion(__GPRO)
- {
- int ierr;
- struct NAM_STRUCT nam;
- nam = CC_RMS_NAM; /* Initialize local NAM[L] block. */
- outfab->FAB_NAM = &nam; /* Point FAB to local NAM[L]. */
- /* Arrange to store the resultant file spec (with new version), so
- * that we can extract the actual file version from it, for later
- * use in the "extracting:/inflating:/..." message (G.filename).
- */
- nam.NAM_RSA = res_nam;
- nam.NAM_RSS = sizeof(res_nam);
- #ifdef NAML$C_MAXRSS
- outfab->fab$l_dna = (char *) -1; /* Using NAML for default name. */
- outfab->fab$l_fna = (char *) -1; /* Using NAML for file name. */
- #endif /* NAML$C_MAXRSS */
- FAB_OR_NAML(*outfab, nam).FAB_OR_NAML_FNA = G.filename;
- FAB_OR_NAML(*outfab, nam).FAB_OR_NAML_FNS = strlen(G.filename);
- /* Maximize version number. */
- outfab->fab$l_fop |= FAB$M_MXV;
- /* Create the new-version file. */
- ierr = sys$create(outfab);
- if (nam.NAM_RSL > 0)
- {
- /* File spec version pointers.
- * Versions must exist, so a simple right-to-left search for ";"
- * should work, even on ODS5 extended file specs.
- */
- char *semi_col_orig;
- char *semi_col_res;
- /* NUL-terminate the (complete) resultant file spec. */
- res_nam[nam.NAM_RSL] = '\0';
- /* Find the versions (";") in the original and resultant file specs. */
- semi_col_orig = strrchr(G.filename, ';');
- semi_col_res = strrchr(res_nam, ';');
- if ((semi_col_orig != NULL) && (semi_col_res != NULL))
- {
- /* Transfer the resultant version to the original file spec. */
- strcpy((semi_col_orig + 1), (semi_col_res + 1));
- }
- }
- return ierr;
- }
- /* RMS overwrite original version. */
- static int replace_rms_overwrite(__GPRO)
- {
- /* Supersede existing file. */
- outfab->fab$l_fop |= FAB$M_SUP;
- /* Create (overwrite) the original-version file. */
- return sys$create(outfab);
- }
- /* Main query function to ask user how to handle an existing file
- * (unless command-line options already specify what to do).
- */
- static int replace(__GPRO)
- {
- char answ[10];
- int replace_code;
- if (replace_code_all >= 0)
- {
- /* Use the previous all-file response. */
- replace_code = replace_code_all;
- }
- else if (uO.overwrite_none)
- {
- /* "-n". Do not extract this (or any) file. */
- replace_code = replace_code_all = REPL_NO_EXTRACT;
- }
- else if (uO.overwrite_all == 1)
- {
- /* "-o". Create a new version of this (or any) file. */
- replace_code = replace_code_all = REPL_NEW_VERSION;
- }
- else if (uO.overwrite_all > 1)
- {
- /* "-oo". Overwrite (supersede) this (or any) existing file. */
- replace_code = replace_code_all = REPL_OVERWRITE;
- }
- else
- {
- replace_code = -1;
- do
- {
- /* Request, accept, and decode a response. */
- Info(slide, 0x81, ((char *)slide,
- "%s exists: new [v]ersion, [o]verwrite, or [n]o extract?\n\
- (Uppercase response [V,O,N] => Do same for all files): ",
- FnFilter1(G.filename)));
- fflush(stderr);
- if (fgets(answ, sizeof(answ), stdin) == (char *)NULL)
- {
- Info(slide, 1, ((char *)slide, AssumeNo));
- /* Handle the NULL answer as "N",
- * do not extract any existing files. */
- replace_code_all = REPL_NO_EXTRACT;
- /* Set a warning indicator. */
- replace_code = REPL_NO_EXTRACT | REPL_ERRLV_WARN;
- /* We are finished, break out of the query loop. */
- break;
- }
- /* Strip off a trailing newline, to avoid corrupt
- * complaints when displaying the answer.
- */
- if (answ[strlen(answ) - 1] == '\n')
- answ[strlen(answ) - 1] = '\0';
- /* Extra newline to avoid having the extracting:/inflating:/...:
- * message overwritten by the next query.
- */
- Info(slide, 1, ((char *)slide, "\n"));
- /* Interpret response. Store upper-case answer for future use. */
- switch (answ[0])
- {
- case 'N':
- replace_code_all = REPL_NO_EXTRACT;
- case 'n':
- /* Do not extract this file. */
- replace_code = REPL_NO_EXTRACT;
- break;
- case 'O':
- replace_code_all = REPL_OVERWRITE;
- case 'o':
- /* Overwrite (supersede) this existing file. */
- replace_code = REPL_OVERWRITE;
- break;
- case 'V':
- replace_code_all = REPL_NEW_VERSION;
- case 'v':
- /* Create a new version of this file. */
- replace_code = REPL_NEW_VERSION;
- break;
- default:
- /* Invalid response. Try again. */
- Info(slide, 1, ((char *)slide, InvalidResponse, answ));
- }
- } while (replace_code < 0);
- }
- return replace_code;
- }
- #define W(p) (*(unsigned short*)(p))
- #define L(p) (*(unsigned long*)(p))
- #define EQL_L(a, b) ( L(a) == L(b) )
- #define EQL_W(a, b) ( W(a) == W(b) )
- /*
- * Function find_vms_attrs() scans the ZIP entry extra field, if any,
- * and looks for VMS attribute records. Various date-time attributes
- * are ignored if set_date_time is FALSE (typically for a directory).
- *
- * For a set of IZ records, a FAB and various XABs are created and
- * chained together.
- *
- * For a PK record, the pka_atr[] attribute descriptor array is
- * populated.
- *
- * The return value is a VAT_* value, according to the type of extra
- * field attribute data found.
- */
- static int find_vms_attrs(__GPRO__ int set_date_time)
- {
- uch *scan = G.extra_field;
- struct EB_header *hdr;
- int len;
- int type=VAT_NONE;
- outfab = NULL;
- xabfhc = NULL;
- xabdat = NULL;
- xabrdt = NULL;
- xabpro = NULL;
- first_xab = last_xab = NULL;
- if (scan == NULL)
- return VAT_NONE;
- len = G.lrec.extra_field_length;
- #define LINK(p) {/* Link xaballs and xabkeys into chain */ \
- if ( first_xab == NULL ) \
- first_xab = (void *) p; \
- if ( last_xab != NULL ) \
- last_xab->xab$l_nxt = (void *) p; \
- last_xab = (void *) p; \
- p->xab$l_nxt = NULL; \
- }
- /* End of macro LINK */
- while (len > 0)
- {
- hdr = (struct EB_header *)scan;
- if (EQL_W(&hdr->tag, IZ_SIGNATURE))
- {
- /*
- * Info-ZIP-style extra block decoding.
- */
- uch *blk;
- unsigned siz;
- uch *block_id;
- type = VAT_IZ;
- siz = hdr->size;
- blk = (uch *)(&hdr->data[0]);
- block_id = (uch *)(&((struct IZ_block *)hdr)->bid);
- if (EQL_L(block_id, FABSIG)) {
- outfab = (struct FAB *)extract_izvms_block(__G__ blk,
- siz, NULL, (uch *)&cc$rms_fab, FABL);
- } else if (EQL_L(block_id, XALLSIG)) {
- xaball = (struct XABALL *)extract_izvms_block(__G__ blk,
- siz, NULL, (uch *)&cc$rms_xaball, XALLL);
- LINK(xaball);
- } else if (EQL_L(block_id, XKEYSIG)) {
- xabkey = (struct XABKEY *)extract_izvms_block(__G__ blk,
- siz, NULL, (uch *)&cc$rms_xabkey, XKEYL);
- LINK(xabkey);
- } else if (EQL_L(block_id, XFHCSIG)) {
- xabfhc = (struct XABFHC *) extract_izvms_block(__G__ blk,
- siz, NULL, (uch *)&cc$rms_xabfhc, XFHCL);
- } else if (EQL_L(block_id, XDATSIG)) {
- if (set_date_time) {
- xabdat = (struct XABDAT *) extract_izvms_block(__G__ blk,
- siz, NULL, (uch *)&cc$rms_xabdat, XDATL);
- }
- } else if (EQL_L(block_id, XRDTSIG)) {
- if (set_date_time) {
- xabrdt = (struct XABRDT *) extract_izvms_block(__G__ blk,
- siz, NULL, (uch *)&cc$rms_xabrdt, XRDTL);
- }
- } else if (EQL_L(block_id, XPROSIG)) {
- xabpro = (struct XABPRO *) extract_izvms_block(__G__ blk,
- siz, NULL, (uch *)&cc$rms_xabpro, XPROL);
- } else if (EQL_L(block_id, VERSIG)) {
- #ifdef CHECK_VERSIONS
- char verbuf[80];
- unsigned verlen = 0;
- uch *vers;
- char *m;
- get_vms_version(verbuf, sizeof(verbuf));
- vers = extract_izvms_block(__G__ blk, siz,
- &verlen, NULL, 0);
- if ((m = strrchr((char *) vers, '-')) != NULL)
- *m = '\0'; /* Cut out release number */
- if (strcmp(verbuf, (char *) vers) && uO.qflag < 2)
- {
- Info(slide, 0, ((char *)slide,
- "[ Warning: VMS version mismatch."));
- Info(slide, 0, ((char *)slide,
- " This version %s --", verbuf));
- strncpy(verbuf, (char *) vers, verlen);
- verbuf[verlen] = '\0';
- Info(slide, 0, ((char *)slide,
- " version made by %s ]\n", verbuf));
- }
- free(vers);
- #endif /* CHECK_VERSIONS */
- } else {
- Info(slide, 1, ((char *)slide,
- "[ Warning: Unknown block signature %s ]\n",
- block_id));
- }
- }
- else if (hdr->tag == PK_SIGNATURE)
- {
- /*
- * PKWARE-style extra block decoding.
- */
- struct PK_header *blk;
- register byte *scn;
- register int len;
- type = VAT_PK;
- blk = (struct PK_header *)hdr;
- len = blk->size - (PK_HEADER_SIZE - EB_HEADSIZE);
- scn = (byte *)(&blk->data);
- pka_idx = 0;
- if (blk->crc32 != crc32(CRCVAL_INITIAL, scn, (extent)len))
- {
- Info(slide, 1, ((char *)slide,
- "[ Warning: CRC error, discarding PKWARE extra field ]\n"));
- len = 0;
- type = VAT_NONE;
- }
- while (len > PK_FLDHDR_SIZE)
- {
- register struct PK_field *fld;
- int skip=0;
- fld = (struct PK_field *)scn;
- switch(fld->tag)
- {
- case ATR$C_UCHAR:
- pka_uchar = L(&fld->value);
- break;
- case ATR$C_RECATTR:
- pka_rattr = *(struct fatdef *)(&fld->value);
- break;
- case ATR$C_UIC:
- case ATR$C_ADDACLENT:
- skip = !uO.X_flag;
- break;
- case ATR$C_CREDATE:
- case ATR$C_REVDATE:
- case ATR$C_EXPDATE:
- case ATR$C_BAKDATE:
- case ATR$C_ASCDATES:
- skip = (set_date_time == FALSE);
- break;
- }
- if ( !skip )
- {
- pka_atr[pka_idx].atr$w_size = fld->size;
- pka_atr[pka_idx].atr$w_type = fld->tag;
- pka_atr[pka_idx].atr$l_addr = GVTC &fld->value;
- ++pka_idx;
- }
- len -= fld->size + PK_FLDHDR_SIZE;
- scn += fld->size + PK_FLDHDR_SIZE;
- }
- pka_atr[pka_idx].atr$w_size = 0; /* End of list */
- pka_atr[pka_idx].atr$w_type = 0;
- pka_atr[pka_idx].atr$l_addr = 0; /* NULL when DECC VAX gets fixed */
- }
- len -= hdr->size + EB_HEADSIZE;
- scan += hdr->size + EB_HEADSIZE;
- }
- if ( type == VAT_IZ )
- {
- if (outfab != NULL)
- {
- /* Do not link XABPRO or XABRDT now.
- * Leave them for sys$close() resp. set_direc_attribs().
- */
- outfab->fab$l_xab = NULL;
- if (xabfhc != NULL)
- {
- xabfhc->xab$l_nxt = outfab->fab$l_xab;
- outfab->fab$l_xab = (void *) xabfhc;
- }
- if (xabdat != NULL)
- {
- xabdat->xab$l_nxt = outfab->fab$l_xab;
- outfab->fab$l_xab = (void *) xabdat;
- }
- if (first_xab != NULL) /* Link xaball,xabkey subchain */
- {
- last_xab->xab$l_nxt = outfab->fab$l_xab;
- outfab->fab$l_xab = (void *) first_xab;
- }
- }
- else
- type = VAT_NONE;
- }
- return type;
- }
- static void free_up()
- {
- /*
- * Free up all allocated XABs.
- */
- if (xabdat != NULL) free(xabdat);
- if (xabpro != NULL) free(xabpro);
- if (xabrdt != NULL) free(xabrdt);
- if (xabfhc != NULL) free(xabfhc);
- while (first_xab != NULL)
- {
- struct XAB *x;
- x = (struct XAB *) first_xab->xab$l_nxt;
- free(first_xab);
- first_xab = x;
- }
- /* Free FAB storage, if not the static one. */
- if (outfab != NULL && outfab != &fileblk)
- free(outfab);
- }
- #ifdef CHECK_VERSIONS
- static int get_vms_version(verbuf, len)
- char *verbuf;
- int len;
- {
- int i = SYI$_VERSION;
- int verlen = 0;
- struct dsc$descriptor version;
- char *m;
- version.dsc$a_pointer = verbuf;
- version.dsc$w_length = len - 1;
- version.dsc$b_dtype = DSC$K_DTYPE_B;
- version.dsc$b_class = DSC$K_CLASS_S;
- if (ERR(lib$getsyi(&i, 0, &version, &verlen, 0, 0)) || verlen == 0)
- return 0;
- /* Cut out trailing spaces "V5.4-3 " -> "V5.4-3" */
- for (m = verbuf + verlen, i = verlen - 1; i > 0 && verbuf[i] == ' '; --i)
- --m;
- *m = '\0';
- /* Cut out release number "V5.4-3" -> "V5.4" */
- if ((m = strrchr(verbuf, '-')) != NULL)
- *m = '\0';
- return strlen(verbuf) + 1; /* Transmit ending '\0' too */
- }
- #endif /* CHECK_VERSIONS */
- /* flush contents of output buffer */
- int flush(__G__ rawbuf, size, unshrink) /* return PK-type error code */
- __GDEF
- uch *rawbuf;
- ulg size;
- int unshrink;
- {
- G.crc32val = crc32(G.crc32val, rawbuf, (extent)size);
- if (uO.tflag)
- return PK_COOL; /* Do not output. Update CRC only */
- else
- return (*_flush_routine)(__G__ rawbuf, size, 0);
- }
- static int _flush_blocks(__G__ rawbuf, size, final_flag)
- /* Asynchronous version */
- __GDEF
- uch *rawbuf;
- unsigned size;
- int final_flag; /* 1 if this is the final flushout */
- {
- int status;
- unsigned off = 0;
- while (size > 0)
- {
- if (curbuf->bufcnt < BUFS512)
- {
- unsigned ncpy;
- ncpy = size > (BUFS512 - curbuf->bufcnt) ?
- (BUFS512 - curbuf->bufcnt) : size;
- memcpy(curbuf->buf + curbuf->bufcnt, rawbuf + off, ncpy);
- size -= ncpy;
- curbuf->bufcnt += ncpy;
- off += ncpy;
- }
- if (curbuf->bufcnt == BUFS512)
- {
- status = WriteBuffer(__G__ curbuf->buf, curbuf->bufcnt);
- if (status)
- return status;
- curbuf = curbuf->next;
- curbuf->bufcnt = 0;
- }
- }
- return (final_flag && (curbuf->bufcnt > 0)) ?
- WriteBuffer(__G__ curbuf->buf, curbuf->bufcnt) :
- PK_COOL;
- }
- #ifdef ASYNCH_QIO
- static int WriteQIO(__G__ buf, len)
- __GDEF
- uch *buf;
- unsigned len;
- {
- int status;
- if (pka_io_pending) {
- status = sys$synch(0, &pka_io_iosb);
- if (!ERR(status))
- status = pka_io_iosb.status;
- if (ERR(status))
- {
- vms_msg(__G__ "[ WriteQIO: sys$synch found I/O failure ]\n",
- status);
- return PK_DISK;
- }
- pka_io_pending = FALSE;
- }
- /*
- * Put content of buffer as a single VB
- */
- status = sys$qio(0, pka_devchn, IO$_WRITEVBLK,
- &pka_io_iosb, 0, 0,
- buf, len, pka_vbn,
- 0, 0, 0);
- if (ERR(status))
- {
- vms_msg(__G__ "[ WriteQIO: sys$qio failed ]\n", status);
- return PK_DISK;
- }
- pka_io_pending = TRUE;
- pka_vbn += (len>>9);
- return PK_COOL;
- }
- /*
- 2004-10-01 SMS. Changed to clear the extra byte written out by qio()
- and sys$write() when an odd byte count is incremented to the next
- even value, either explicitly (qio), or implicitly (sys$write), on
- the theory that a reliable NUL beats left-over garbage. Alpha and
- VAX object files seem frequently to have even more than one byte of
- extra junk past EOF, so this may not help them.
- */
- static int _flush_qio(__G__ rawbuf, size, final_flag)
- /* Asynchronous version */
- __GDEF
- uch *rawbuf;
- unsigned size;
- int final_flag; /* 1 if this is the final flushout */
- {
- int status;
- unsigned off = 0;
- while (size > 0)
- {
- if (curbuf->bufcnt < BUFS512)
- {
- unsigned ncpy;
- ncpy = size > (BUFS512 - curbuf->bufcnt) ?
- (BUFS512 - curbuf->bufcnt) : size;
- memcpy(curbuf->buf + curbuf->bufcnt, rawbuf + off, ncpy);
- size -= ncpy;
- curbuf->bufcnt += ncpy;
- off += ncpy;
- }
- if (curbuf->bufcnt == BUFS512)
- {
- status = WriteQIO(__G__ curbuf->buf, curbuf->bufcnt);
- if (status)
- return status;
- curbuf = curbuf->next;
- curbuf->bufcnt = 0;
- }
- }
- if (final_flag && (curbuf->bufcnt > 0))
- {
- unsigned bufcnt_even;
- /* Round up to an even byte count. */
- bufcnt_even = (curbuf->bufcnt+1) & (~1);
- /* If there is one, clear the extra byte. */
- if (bufcnt_even > curbuf->bufcnt)
- curbuf->buf[curbuf->bufcnt] = '\0';
- return WriteQIO(curbuf->buf, bufcnt_even);
- }
- else
- {
- return PK_COOL;
- }
- }
- #else /* !ASYNCH_QIO */
- static int _flush_qio(__G__ rawbuf, size, final_flag)
- __GDEF
- uch *rawbuf;
- unsigned size;
- int final_flag; /* 1 if this is the final flushout */
- {
- int status;
- uch *out_ptr=rawbuf;
- if ( final_flag )
- {
- if ( loccnt > 0 )
- {
- unsigned loccnt_even;
- /* Round up to an even byte count. */
- loccnt_even = (loccnt+1) & (~1);
- /* If there is one, clear the extra byte. */
- if (loccnt_even > loccnt)
- locbuf[loccnt] = '\0';
- status = sys$qiow(0, pka_devchn, IO$_WRITEVBLK,
- &pka_io_iosb, 0, 0,
- locbuf,
- loccnt_even,
- pka_vbn,
- 0, 0, 0);
- if (!ERR(status))
- status = pka_io_iosb.status;
- if (ERR(status))
- {
- vms_msg(__G__ "[ Write QIO failed ]\n", status);
- return PK_DISK;
- }
- }
- return PK_COOL;
- }
- if ( loccnt > 0 )
- {
- /*
- * Fill local buffer upto 512 bytes then put it out
- */
- unsigned ncpy;
- ncpy = 512-loccnt;
- if ( ncpy > size )
- ncpy = size;
- memcpy(locptr, out_ptr, ncpy);
- locptr += ncpy;
- loccnt += ncpy;
- size -= ncpy;
- out_ptr += ncpy;
- if ( loccnt == 512 )
- {
- status = sys$qiow(0, pka_devchn, IO$_WRITEVBLK,
- &pka_io_iosb, 0, 0,
- locbuf, loccnt, pka_vbn,
- 0, 0, 0);
- if (!ERR(status))
- status = pka_io_iosb.status;
- if (ERR(status))
- {
- vms_msg(__G__ "[ Write QIO failed ]\n", status);
- return PK_DISK;
- }
- pka_vbn++;
- loccnt = 0;
- locptr = locbuf;
- }
- }
- if ( size >= 512 )
- {
- unsigned nblk, put_cnt;
- /*
- * Put rest of buffer as a single VB
- */
- put_cnt = (nblk = size>>9)<<9;
- status = sys$qiow(0, pka_devchn, IO$_WRITEVBLK,
- &pka_io_iosb, 0, 0,
- out_ptr, put_cnt, pka_vbn,
- 0, 0, 0);
- if (!ERR(status))
- status = pka_io_iosb.status;
- if (ERR(status))
- {
- vms_msg(__G__ "[ Write QIO failed ]\n", status);
- return PK_DISK;
- }
- pka_vbn += nblk;
- out_ptr += put_cnt;
- size -= put_cnt;
- }
- if ( size > 0 )
- {
- memcpy(locptr, out_ptr, size);
- loccnt += size;
- locptr += size;
- }
- return PK_COOL;
- }
- #endif /* ?ASYNCH_QIO */
- /*
- * The routine _flush_varlen() requires: "(size & 1) == 0"
- * (The variable-length record algorithm assumes an even byte-count!)
- */
- static int _flush_varlen(__G__ rawbuf, size, final_flag)
- __GDEF
- uch *rawbuf;
- unsigned size;
- int final_flag;
- {
- unsigned nneed;
- unsigned reclen;
- uch *inptr=rawbuf;
- /*
- * Flush local buffer
- */
- if ( loccnt > 0 ) /* incomplete record left from previous call */
- {
- reclen = *(ush*)locbuf;
- nneed = reclen + 2 - loccnt;
- if ( nneed > size )
- {
- if ( size+loccnt > BUFSMAXREC )
- {
- char buf[80];
- Info(buf, 1, (buf,
- "[ Record too long (%u bytes) ]\n", reclen));
- return PK_DISK;
- }
- memcpy(locbuf+loccnt, inptr, size);
- loccnt += size;
- size = 0;
- }
- else
- {
- memcpy(locbuf+loccnt, inptr, nneed);
- loccnt += nneed;
- size -= nneed;
- inptr += nneed;
- if ( reclen & 1 )
- {
- size--;
- inptr++;
- }
- if ( WriteRecord(__G__ locbuf+2, reclen) )
- return PK_DISK;
- loccnt = 0;
- }
- }
- /*
- * Flush incoming records
- */
- while (size > 0)
- {
- reclen = *(ush*)inptr;
- if ( reclen+2 <= size )
- {
- if (WriteRecord(__G__ inptr+2, reclen))
- return PK_DISK;
- size -= 2+reclen;
- inptr += 2+reclen;
- if ( reclen & 1 )
- {
- --size;
- ++inptr;
- }
- }
- else
- {
- memcpy(locbuf, inptr, size);
- loccnt = size;
- size = 0;
- }
- }
- /*
- * Final flush rest of local buffer
- */
- if ( final_flag && loccnt > 0 )
- {
- char buf[80];
- Info(buf, 1, (buf,
- "[ Warning, incomplete record of length %u ]\n",
- (unsigned)*(ush*)locbuf));
- if ( WriteRecord(__G__ locbuf+2, loccnt-2) )
- return PK_DISK;
- }
- return PK_COOL;
- }
- /*
- * Routine _flush_stream breaks decompressed stream into records
- * depending on format of the stream (fab->rfm, G.pInfo->textmode, etc.)
- * and puts out these records. It also handles CR LF sequences.
- * Should be used when extracting *text* files.
- */
- #define VT 0x0B
- #define FF 0x0C
- /* The file is from MSDOS/OS2/NT -> handle CRLF as record end, throw out ^Z */
- /* GRR NOTES: cannot depend on hostnum! May have "flip'd" file or re-zipped
- * a Unix file, etc. */
- #ifdef USE_ORIG_DOS
- # define ORG_DOS \
- (G.pInfo->hostnum==FS_FAT_ \
- || G.pInfo->hostnum==FS_HPFS_ \
- || G.pInfo->hostnum==FS_NTFS_)
- #else
- # define ORG_DOS 1
- #endif
- /* Record delimiters */
- #ifdef undef
- #define RECORD_END(c, f) \
- ( ( ORG_DOS || G.pInfo->textmode ) && c==CTRLZ \
- || ( f == FAB$C_STMLF && c==LF ) \
- || ( f == FAB$C_STMCR || ORG_DOS || G.pInfo->textmode ) && c==CR \
- || ( f == FAB$C_STM && (c==CR || c==LF || c==FF || c==VT) ) \
- )
- #else
- # define RECORD_END(c, f) ((c) == LF || (c) == (CR))
- #endif
- static unsigned find_eol(p, n, l)
- /*
- * Find first CR, LF, CR/LF or LF/CR in string 'p' of length 'n'.
- * Return offset of the sequence found or 'n' if not found.
- * If found, return in '*l' length of the sequence (1 or 2) or
- * zero if sequence end not seen, i.e. CR or LF is last char
- * in the buffer.
- */
- ZCONST uch *p;
- unsigned n;
- unsigned *l;
- {
- unsigned off = n;
- ZCONST uch *q;
- *l = 0;
- for (q=p ; n > 0 ; --n, ++q)
- if ( RECORD_END(*q, rfm) )
- {
- off = q-p;
- break;
- }
- if ( n > 1 )
- {
- *l = 1;
- if ( ( q[0] == CR && q[1] == LF ) || ( q[0] == LF && q[1] == CR ) )
- *l = 2;
- }
- return off;
- }
- /* Record delimiters that must be put out */
- #define PRINT_SPEC(c) ( (c)==FF || (c)==VT )
- static int _flush_stream(__G__ rawbuf, size, final_flag)
- __GDEF
- uch *rawbuf;
- unsigned size;
- int final_flag; /* 1 if this is the final flushout */
- {
- int rest;
- unsigned end = 0, start = 0;
- if (size == 0 && loccnt == 0)
- return PK_COOL; /* Nothing to do ... */
- if ( final_flag )
- {
- unsigned recsize;
- /*
- * This is flush only call. size must be zero now.
- * Just eject everything we have in locbuf.
- */
- recsize = loccnt - (got_eol ? 1 : 0);
- /*
- * If the last char of file was ^Z ( end-of-file in MSDOS ),
- * we will see it now.
- */
- if ( recsize==1 && locbuf[0] == CTRLZ )
- return PK_COOL;
- return WriteRecord(__G__ locbuf, recsize);
- }
- if ( loccnt > 0 )
- {
- /* Find end of record partially saved in locbuf */
- unsigned recsize;
- int complete=0;
- if ( got_eol )
- {
- recsize = loccnt - 1;
- complete = 1;
- if ( (got_eol == CR && rawbuf[0] == LF) ||
- (got_eol == LF && rawbuf[0] == CR) )
- end = 1;
- got_eol = 0;
- }
- else
- {
- unsigned eol_len;
- unsigned eol_off;
- eol_off = find_eol(rawbuf, size, &eol_len);
- if ( loccnt+eol_off > BUFSMAXREC )
- {
- /*
- * No room in locbuf. Dump it and clear
- */
- char buf[80]; /* CANNOT use slide for Info() */
- recsize = loccnt;
- start = 0;
- Info(buf, 1, (buf,
- "[ Warning: Record too long (%u) ]\n", loccnt+eol_off));
- complete = 1;
- end = 0;
- }
- else
- {
- if ( eol_off >= size )
- {
- end = size;
- complete = 0;
- }
- else if ( eol_len == 0 )
- {
- got_eol = rawbuf[eol_off];
- end = size;
- complete = 0;
- }
- else
- {
- memcpy(locptr, rawbuf, eol_off);
- recsize = loccnt + eol_off;
- locptr += eol_off;
- loccnt += eol_off;
- end = eol_off + eol_len;
- complete = 1;
- }
- }
- }
- if ( complete )
- {
- if (WriteRecord(__G__ locbuf, recsize))
- return PK_DISK;
- loccnt = 0;
- locptr = locbuf;
- }
- } /* end if ( loccnt ) */
- for (start = end; start < size && end < size; )
- {
- unsigned eol_off, eol_len;
- got_eol = 0;
- #ifdef undef
- if (uO.cflag)
- /* skip CR's at the beginning of record */
- while (start < size && rawbuf[start] == CR)
- ++start;
- #endif
- if ( start >= size )
- continue;
- /* Find record end */
- end = start+(eol_off = find_eol(rawbuf+start, size-start, &eol_len));
- if ( end >= size )
- continue;
- if ( eol_len > 0 )
- {
- if ( WriteRecord(__G__ rawbuf+start, end-start) )
- return PK_DISK;
- start = end + eol_len;
- }
- else
- {
- got_eol = rawbuf[end];
- end = size;
- continue;
- }
- }
- rest = size - start;
- if (rest > 0)
- {
- if ( rest > BUFSMAXREC )
- {
- unsigned recsize;
- char buf[80]; /* CANNOT use slide for Info() */
- recsize = rest - (got_eol ? 1 : 0 );
- Info(buf, 1, (buf,
- "[ Warning: Record too long (%u) ]\n", recsize));
- got_eol = 0;
- return WriteRecord(__G__ rawbuf+start, recsize);
- }
- else
- {
- memcpy(locptr, rawbuf + start, rest);
- locptr += rest;
- loccnt += rest;
- }
- }
- return PK_COOL;
- }
- static int WriteBuffer(__G__ buf, len)
- __GDEF
- uch *buf;
- unsigned len;
- {
- int status;
- if (uO.cflag)
- {
- (void)(*G.message)((zvoid *)&G, buf, len, 0);
- }
- else
- {
- status = sys$wait(outrab);
- if (ERR(status))
- {
- vms_msg(__G__ "[ WriteBuffer: sys$wait failed ]\n", status);
- if (outrab->rab$l_stv != 0)
- {
- vms_msg(__G__ "", outrab->rab$l_stv);
- }
- }
- /* If odd byte count, then this must be the final record.
- Clear the extra byte past EOF to help keep the file clean.
- */
- if (len & 1)
- buf[len] = '\0';
- outrab->rab$w_rsz = len;
- outrab->rab$l_rbf = (char *) buf;
- if (ERR(status = sys$write(outrab)))
- {
- vms_msg(__G__ "[ WriteBuffer: sys$write failed ]\n", status);
- if (outrab->rab$l_stv != 0)
- {
- vms_msg(__G__ "", outrab->rab$l_stv);
- }
- return PK_DISK;
- }
- }
- return PK_COOL;
- }
- static int WriteRecord(__G__ rec, len)
- __GDEF
- uch *rec;
- unsigned len;
- {
- int status;
- if (uO.cflag)
- {
- (void)(*G.message)((zvoid *)&G, rec, len, 0);
- (void)(*G.message)((zvoid *)&G, (uch *) ("\n"), 1, 0);
- }
- else
- {
- if (ERR(status = sys$wait(outrab)))
- {
- vms_msg(__G__ "[ WriteRecord: sys$wait failed ]\n", status);
- if (outrab->rab$l_stv != 0)
- {
- vms_msg(__G__ "", outrab->rab$l_stv);
- }
- }
- outrab->rab$w_rsz = len;
- outrab->rab$l_rbf = (char *) rec;
- if (ERR(status = sys$put(outrab)))
- {
- vms_msg(__G__ "[ WriteRecord: sys$put failed ]\n", status);
- if (outrab->rab$l_stv != 0)
- {
- vms_msg(__G__ "", outrab->rab$l_stv);
- }
- return PK_DISK;
- }
- }
- return PK_COOL;
- }
- #ifdef SYMLINKS
- /* Read symlink text from a still-open rms file. */
- static int _read_link_rms(int byte_count, char *link_text_buf)
- {
- /* Use RMS to read the link text into the user's buffer.
- * Rewind, then read byte count = byte_count.
- * NUL-terminate the link text.
- *
- * $WAIT may be pointless if not async, but $WAIT elsewhere seems
- * to be used unconditionally, so what do I know?
- */
- int sts;
- int bytes_read;
- /* Clear the bytes-read count. */
- bytes_read = 0;
- /* Wait for anything pending. */
- sts = sys$wait(outrab);
- {
- /* Rewind. */
- sts = sys$rewind(outrab);
- if (!ERR(sts))
- {
- /* Wait for $REWIND. */
- sts = sys$wait(outrab);
- if (!ERR(sts))
- {
- /* Read the link text. */
- outrab->rab$w_usz = byte_count;
- outrab->rab$l_ubf = link_text_buf;
- sts = sys$read(outrab);
- if (!ERR(sts))
- {
- /* Wait for $READ. */
- sts = sys$wait(outrab);
- if (!ERR(sts))
- /* Set the resultant byte count. */
- bytes_read = outrab->rab$w_rsz;
- }
- }
- }
- }
- /* NUL-terminate the link text. */
- link_text_buf[bytes_read] = '\0';
- return sts;
- }
- #endif /* SYMLINKS */
- void close_outfile(__G)
- __GDEF
- {
- int status;
- status = (*_flush_routine)(__G__ NULL, 0, 1);
- if (status)
- return /* PK_DISK */;
- if (uO.cflag)
- return /* PK_COOL */; /* Don't close stdout */
- /* return */ (*_close_routine)(__G);
- }
- static int _close_rms(__GPRO)
- {
- int status;
- struct XABPRO pro;
- int retcode = PK_OK;
- #ifdef SYMLINKS
- /*----------------------------------------------------------------------
- UNIX description:
- If symbolic links are supported, allocate storage for a symlink
- control structure, put the uncompressed "data" and other required
- info in it, and add the structure to the "deferred symlinks" chain.
- Since we know it's a symbolic link to start with, we shouldn't have
- to worry about overflowing unsigned ints with unsigned longs.
- ----------------------------------------------------------------------*/
- if (G.symlnk) {
- extent ucsize = (extent)G.lrec.ucsize;
- /* 2007-03-03 SMS.
- * If the symlink is already a symlink (restored with VMS/RMS
- * symlink attributes), then read the link text from the file,
- * and close the file (using the appropriate methods), and then
- * return.
- */
- if (G.pInfo->symlink == 0)
- {
- if (QCOND2)
- {
- /* Link text storage. */
- char* link_target = malloc(ucsize + 1);
- if (link_target == NULL)
- {
- Info(slide, 0x201, ((char *)slide,
- "warning: cannot show symlink (%s) target, no mem\n",
- FnFilter1(G.filename)));
- retcode = PK_MEM;
- }
- else
- {
- /* Read the link text. */
- status = _read_link_rms(ucsize, link_target);
- if (ERR(status))
- {
- Info(slide, 0x201, ((char *)slide,
- "warning: error reading symlink text: %s\n",
- strerror(EVMSERR, status)));
- retcode = PK_DISK;
- }
- else
- {
- Info(slide, 0, ((char *)slide, "-> %s ",
- FnFilter1(link_target)));
- }
- free(link_target);
- }
- }
- }
- else
- {
- extent slnk_entrysize;
- slinkentry *slnk_entry;
- /* It's a symlink in need of post-processing. */
- /* Size of the symlink entry is the sum of
- * (struct size (includes 1st '\0') + 1 additional trailing '\0'),
- * system specific attribute data size (might be 0),
- * and the lengths of name and link target.
- */
- slnk_entrysize = (sizeof(slinkentry) + 1) +
- ucsize + strlen(G.filename);
- if (slnk_entrysize < ucsize) {
- Info(slide, 0x201, ((char *)slide,
- "warning: symbolic link (%s) failed: mem alloc overflow\n",
- FnFilter1(G.filename)));
- retcode = PK_ERR;
- }
- else
- {
- if ((slnk_entry = (slinkentry *)malloc(slnk_entrysize))
- == NULL) {
- Info(slide, 0x201, ((char *)slide,
- "warning: symbolic link (%s) failed, no mem\n",
- FnFilter1(G.filename)));
- retcode = PK_MEM;
- }
- else
- {
- slnk_entry->next = NULL;
- slnk_entry->targetlen = ucsize;
- /* don't set attributes for symlinks */
- slnk_entry->attriblen = 0;
- slnk_entry->target = slnk_entry->buf;
- slnk_entry->fname = slnk_entry->target + ucsize + 1;
- strcpy(slnk_entry->fname, G.filename);
- /* Read the link text using the appropriate method. */
- status = _read_link_rms(ucsize, slnk_entry->target);
- if (ERR(status))
- {
- Info(slide, 0x201, ((char *)slide,
- "warning: error reading symlink text (rms): %s\n",
- strerror(EVMSERR, status)));
- free(slnk_entry);
- retcode = PK_DISK;
- }
- else
- {
- if (QCOND2)
- Info(slide, 0, ((char *)slide, "-> %s ",
- FnFilter1(slnk_entry->target)));
- /* Add this symlink record to the list of
- deferred symlinks. */
- if (G.slink_last != NULL)
- G.slink_last->next = slnk_entry;
- else
- G.slink_head = slnk_entry;
- G.slink_last = slnk_entry;
- }
- }
- }
- }
- }
- #endif /* SYMLINKS */
- /* Link XABRDT, XABDAT, and (optionally) XABPRO. */
- if (xabrdt != NULL)
- {
- xabrdt->xab$l_nxt = NULL;
- outfab->fab$l_xab = (void *) xabrdt;
- }
- else
- {
- rdt.xab$l_nxt = NULL;
- outfab->fab$l_xab = (void *) &rdt;
- }
- if (xabdat != NULL)
- {
- xabdat->xab$l_nxt = outfab->fab$l_xab;
- outfab->fab$l_xab = (void *)xabdat;
- }
- if (xabpro != NULL)
- {
- if ( !uO.X_flag )
- xabpro->xab$l_uic = 0; /* Use default (user's) uic */
- xabpro->xab$l_nxt = outfab->fab$l_xab;
- outfab->fab$l_xab = (void *) xabpro;
- }
- else
- {
- pro = cc$rms_xabpro;
- pro.xab$w_pro = G.pInfo->file_attr;
- pro.xab$l_nxt = outfab->fab$l_xab;
- outfab->fab$l_xab = (void *) &pro;
- }
- status = sys$wait(outrab);
- if (ERR(status))
- {
- vms_msg(__G__ "[ _close_rms: sys$wait failed ]\n", status);
- if (outrab->rab$l_stv != 0)
- {
- vms_msg(__G__ "", outrab->rab$l_stv);
- }
- }
- status = sys$close(outfab);
- #ifdef DEBUG
- if (ERR(status))
- {
- vms_msg(__G__
- "\r[ Warning: cannot set owner/protection/time attributes ]\n",
- status);
- if (outfab->fab$l_stv != 0)
- {
- vms_msg(__G__ "", outfab->fab$l_stv);
- }
- retcode = PK_WARN;
- }
- #endif
- free_up();
- return retcode;
- }
- static int _close_qio(__GPRO)
- {
- int status;
- pka_fib.FIB$L_ACCTL =
- FIB$M_WRITE | FIB$M_NOTRUNC ;
- pka_fib.FIB$W_EXCTL = 0;
- pka_fib.FIB$W_FID[0] =
- pka_fib.FIB$W_FID[1] =
- pka_fib.FIB$W_FID[2] =
- pka_fib.FIB$W_DID[0] =
- pka_fib.FIB$W_DID[1] =
- pka_fib.FIB$W_DID[2] = 0;
- #ifdef ASYNCH_QIO
- if (pka_io_pending) {
- status = sys$synch(0, &pka_io_iosb);
- if (!ERR(status))
- status = pka_io_iosb.status;
- if (ERR(status))
- {
- vms_msg(__G__ "[ _close_qio: sys$synch found I/O failure ]\n",
- status);
- }
- pka_io_pending = FALSE;
- }
- #endif /* ASYNCH_QIO */
- #ifdef SYMLINKS
- if (G.symlnk && QCOND2)
- {
- /* Read back the symlink target specification for display purpose. */
- extent ucsize = (extent)G.lrec.ucsize;
- char *link_target; /* Link text storage. */
- if ((link_target = malloc(ucsize + 1)) == NULL)
- {
- Info(slide, 0x201, ((char *)slide,
- "warning: cannot show symlink (%s) target, no mem\n",
- FnFilter1(G.filename)));
- }
- else
- {
- unsigned bytes_read = 0;
- status = sys$qiow(0, /* event flag */
- pka_devchn, /* channel */
- IO$_READVBLK, /* function */
- &pka_io_iosb, /* IOSB */
- 0, /* AST address */
- 0, /* AST parameter */
- link_target, /* P1 = buffer address */
- ucsize, /* P2 = requested byte count */
- 1, /* P3 = VBN (1 = first) */
- 0, /* P4 (not used) */
- 0, /* P5 (not used) */
- 0); /* P6 (not used) */
- if (!ERR(status))
- /* Final status. */
- status = pka_io_iosb.status;
- /* Set the resultant byte count. */
- if (!ERR(status))
- bytes_read = pka_io_iosb.count;
- /* NUL-terminate the link text. */
- link_target[bytes_read] = '\0';
- if (ERR(status))
- {
- Info(slide, 0x201, ((char *)slide,
- "warning: error reading symlink text (qio): %s\n",
- strerror(EVMSERR, status)));
- }
- else
- {
- Info(slide, 0, ((char *)slide, "-> %s ",
- FnFilter1(link_target)));
- }
- free(link_target);
- }
- }
- #endif /* SYMLINKS */
- status = sys$qiow(0, pka_devchn, IO$_DEACCESS, &pka_acp_iosb,
- 0, 0,
- &pka_fibdsc, 0, 0, 0,
- pka_atr, 0);
- sys$dassgn(pka_devchn);
- if ( !ERR(status) )
- status = pka_acp_iosb.status;
- if ( ERR(status) )
- {
- vms_msg(__G__ "[ Deaccess QIO failed ]\n", status);
- return PK_DISK;
- }
- return PK_COOL;
- }
- #ifdef SET_DIR_ATTRIB
- /*
- * 2006-10-04 SMS.
- * vms_path_fixdown().
- *
- * Convert VMS directory spec to VMS directory file name. That is,
- * change "dev:[a.b.c.e]" to "dev:[a.b.c]e.DIR;1". The result (always
- * larger than the source) is returned in the user's buffer.
- */
- #define DIR_TYPE_VER ".DIR;1"
- static char *vms_path_fixdown(ZCONST char *dir_spec, char *dir_file)
- {
- char dir_close;
- char dir_open;
- unsigned i;
- unsigned dir_spec_len;
- dir_spec_len = strlen(dir_spec);
- if (dir_spec_len == 0) return NULL;
- i = dir_spec_len - 1;
- dir_close = dir_spec[i];
- /* Identify the directory delimiters (which must exist). */
- if (dir_close == ']')
- {
- dir_open = '[';
- }
- else if (dir_close == '>')
- {
- dir_open = '<';
- }
- else
- {
- return NULL;
- }
- /* Find the beginning of the last directory name segment. */
- while ((i > 0) && ((dir_spec[i - 1] == '^') ||
- ((dir_spec[i] != '.') && (dir_spec[i] != dir_open))))
- {
- i--;
- }
- /* Form the directory file name from the pieces. */
- if (dir_spec[i] == dir_open)
- {
- /* Top-level directory. */
- sprintf(dir_file, "%.*s000000%c%.*s%s",
- /* "dev:[" "000000" "]" */
- (i + 1), dir_spec, dir_close,
- /* "a" ".DIR;1" */
- (dir_spec_len - i - 2), (dir_spec + i + 1), DIR_TYPE_VER);
- }
- else
- {
- /* Non-top-level directory. */
- sprintf(dir_file, "%.*s%c%.*s%s",
- /* "dev:[a.b.c" "]" */
- i, dir_spec, dir_close,
- /* "e" ".DIR;1" */
- (dir_spec_len - i - 2), (dir_spec + i + 1), DIR_TYPE_VER);
- }
- return dir_file;
- } /* end function vms_path_fixdown(). */
- /* Save directory attributes (as the archive's extra field). */
- /* 2006-12-13 SMS.
- * This could probably be made more efficient by analyzing the data
- * here, extracting the important data, and saving only what's needed.
- * Given the existing code, it seemed simpler to save them all here, and
- * deal with what's important in set_direc_attribs().
- */
- int defer_dir_attribs(__G__ pd)
- __GDEF
- direntry **pd;
- {
- vmsdirattr *d_entry;
- unsigned fnlen;
- unsigned xlen;
- /* Allocate space to save the file (directory) name, the extra
- * block, and all the other data needed by the extra-block data
- * scanner functions. If that works, save the data.
- */
- fnlen = strlen(G.filename);
- xlen = G.lrec.extra_field_length;
- d_entry = (vmsdirattr *) malloc(sizeof(vmsdirattr) + fnlen + xlen);
- *pd = (direntry *) d_entry;
- if (d_entry == (vmsdirattr *) NULL)
- {
- return PK_MEM;
- }
- /* Save extra block length and data. */
- d_entry->xlen = xlen;
- memcpy(d_entry->buf, G.extra_field, xlen);
- /* Set pointer to file (directory) name. */
- d_entry->fn = d_entry->buf + xlen;
- /* Save file (directory) name. */
- strcpy(d_entry->fn, G.filename);
- /* Strip the closing ']' char, to allow proper sorting. */
- d_entry->fn[fnlen - 1] = '\0';
- /* Save generic permission data from mapattr(). */
- d_entry->perms = G.pInfo->file_attr;
- /* Save G.lrec.last_mod_dos_datetime. */
- d_entry->mod_dos_datetime = G.lrec.last_mod_dos_datetime;
- return PK_OK;
- } /* end function defer_dir_attribs() */
- int set_direc_attribs(__G__ d)
- __GDEF
- direntry *d;
- {
- uch *sav_ef_ptr;
- int i;
- int status;
- int type;
- ush attr;
- struct XABPRO pro;
- char dir_name[NAM_MAXRSS + 1];
- char warnmsg[NAM_MAXRSS + 128]; /* Name length + message length. */
- int retcode = PK_OK;
- /* Re-append the closing ']' character which has been stripped in
- * defer_dir_attribs() for compatibility with generic sorting code.
- */
- strcat(VmsAtt(d)->fn, "]");
- /* Convert "[a.b.c]" form into "[a.b]c.DIR;1" */
- vms_path_fixdown(VmsAtt(d)->fn, dir_name);
- /* Dummy up critical global (G) data from the preserved directory
- * attribute data.
- */
- sav_ef_ptr = G.extra_field;
- G.extra_field = (uch *)((VmsAtt(d)->xlen > 0) ? VmsAtt(d)->buf : NULL);
- G.lrec.extra_field_length = VmsAtt(d)->xlen;
- /* Extract the VMS file attributes from the preserved attribute
- * data, if they exist, and restore the date-time stamps.
- */
- type = find_vms_attrs(__G__ (uO.D_flag <= 0));
- if (outfab == NULL)
- {
- /* Default and PK schemes need a FAB. (IZ supplies one.)
- * In a degenerate case, this could be the first use of fileblk,
- * so we assume that we need to initialize it.
- */
- fileblk = cc$rms_fab; /* Initialize FAB. */
- outfab = &fileblk; /* Set pointer used elsewhere. */
- }
- /* Arrange FAB-NAM[L] for file (directory) access. */
- if (type != VAT_NONE)
- {
- if (type == VAT_IZ)
- {
- /* Make an attribute descriptor list for the VMS creation and
- * revision dates (which were stored in the IZ XABs by
- * find_vms_attrs()).
- */
- pka_idx = 0;
- if (xabrdt != NULL)
- {
- /* Revision date-time from XABRDT. */
- pka_atr[pka_idx].atr$w_size = 8;
- pka_atr[pka_idx].atr$w_type = ATR$C_REVDATE;
- pka_atr[pka_idx].atr$l_addr = GVTC &xabrdt->xab$q_rdt;
- ++pka_idx;
- }
- if (xabdat != NULL)
- {
- /* Trust the XABRDT value for revision date. */
- if (xabrdt == NULL)
- {
- /* Revision date-time from XABDAT. */
- pka_atr[pka_idx].atr$w_size = 8;
- pka_atr[pka_idx].atr$w_type = ATR$C_REVDATE;
- pka_atr[pka_idx].atr$l_addr = GVTC &xabdat->xab$q_rdt;
- ++pka_idx;
- }
- /* Creation date-time from XABDAT. */
- pka_atr[pka_idx].atr$w_size = 8;
- pka_atr[pka_idx].atr$w_type = ATR$C_CREDATE;
- pka_atr[pka_idx].atr$l_addr = GVTC &xabdat->xab$q_cdt;
- ++pka_idx;
- }
- if (xabpro != NULL)
- {
- if ( uO.X_flag ) {
- pka_atr[pka_idx].atr$w_size = 4;
- pka_atr[pka_idx].atr$w_type = ATR$C_UIC;
- pka_atr[pka_idx].atr$l_addr = GVTC &xabpro->xab$l_uic;
- ++pka_idx;
- }
- attr = xabpro->xab$w_pro;
- }
- else
- {
- /* Revoke directory Delete permission for all. */
- attr = VmsAtt(d)->perms
- | (((1<< XAB$V_NODEL)<< XAB$V_SYS)|
- ((1<< XAB$V_NODEL)<< XAB$V_OWN)|
- ((1<< XAB$V_NODEL)<< XAB$V_GRP)|
- ((1<< XAB$V_NODEL)<< XAB$V_WLD));
- }
- pka_atr[pka_idx].atr$w_size = 2;
- pka_atr[pka_idx].atr$w_type = ATR$C_FPRO;
- pka_atr[pka_idx].atr$l_addr = GVTC &attr;
- ++pka_idx;
- }
- }
- else
- {
- /* No VMS attribute data were found. Prepare to assemble
- * non-VMS attribute data.
- */
- pka_idx = 0;
- /* Get the (already converted) non-VMS permissions. */
- attr = VmsAtt(d)->perms; /* Use right-sized prot storage. */
- /* Revoke directory Delete permission for all. */
- attr |= (((1<< XAB$V_NODEL)<< XAB$V_SYS)|
- ((1<< XAB$V_NODEL)<< XAB$V_OWN)|
- ((1<< XAB$V_NODEL)<< XAB$V_GRP)|
- ((1<< XAB$V_NODEL)<< XAB$V_WLD));
- pka_atr[pka_idx].atr$w_size = 2;
- pka_atr[pka_idx].atr$w_type = ATR$C_FPRO;
- pka_atr[pka_idx].atr$l_addr = GVTC &attr;
- ++pka_idx;
- /* Restore directory date-time if user requests it (-D). */
- if (uO.D_flag <= 0)
- {
- /* Set the directory date-time from the non-VMS data.
- * Dummy up the DOS-style modification date into global (G)
- * data from the preserved directory attribute data.
- */
- G.lrec.last_mod_dos_datetime = VmsAtt(d)->mod_dos_datetime;
- /* Extract date-time data from the normal attribute data. */
- set_default_datetime_XABs(__G);
- /* Make an attribute descriptor list for the VMS creation
- * and revision dates (which were stored in the XABs by
- * set_default_datetime_XABs()).
- */
- pka_atr[pka_idx].atr$w_size = 8;
- pka_atr[pka_idx].atr$w_type = ATR$C_CREDATE;
- pka_atr[pka_idx].atr$l_addr = GVTC &dattim.xab$q_cdt;
- ++pka_idx;
- pka_atr[pka_idx].atr$w_size = 8;
- pka_atr[pka_idx].atr$w_type = ATR$C_REVDATE;
- pka_atr[pka_idx].atr$l_addr = GVTC &rdt.xab$q_rdt;
- ++pka_idx;
- }
- /* Set the directory protection from the non-VMS data. */
- /* Terminate the attribute descriptor list. */
- pka_atr[pka_idx].atr$w_size = 0; /* End of list */
- pka_atr[pka_idx].atr$w_type = 0;
- pka_atr[pka_idx].atr$l_addr = 0; /* NULL when DECC VAX gets fixed. */
- }
- nam = CC_RMS_NAM; /* Initialize NAM[L]. */
- outfab->FAB_NAM = &nam; /* Point FAB to NAM[L]. */
- /* Point the FAB-NAM[L] to the VMS-format directory file name. */
- #ifdef NAML$C_MAXRSS
- outfab->fab$l_dna = (char *) -1; /* Using NAML for default name. */
- outfab->fab$l_fna = (char *) -1; /* Using NAML for file name. */
- /* Special ODS5-QIO-compatible name storage. */
- nam.naml$l_filesys_name = sys_nam;
- nam.naml$l_filesys_name_alloc = sizeof(sys_nam);
- #endif /* NAML$C_MAXRSS */
- FAB_OR_NAML(*outfab, nam).FAB_OR_NAML_FNA = dir_name;
- FAB_OR_NAML(*outfab, nam).FAB_OR_NAML_FNS = strlen(dir_name);
- /* Expanded and resultant name storage. */
- nam.NAM_ESA = exp_nam;
- nam.NAM_ESS = sizeof(exp_nam);
- nam.NAM_RSA = res_nam;
- nam.NAM_RSS = sizeof(res_nam);
- status = sys$parse(outfab);
- if ( ERR(status) )
- {
- sprintf(warnmsg,
- "warning: set-dir-attributes failed ($parse) for %s.\n",
- dir_name);
- vms_msg(__G__ warnmsg, status);
- retcode = PK_WARN;
- goto cleanup_exit;
- }
- /* Set the length in the device name descriptor. */
- pka_devdsc.dsc$w_length = (unsigned short) nam.NAM_DVI[0];
- /* Open a channel to the disk device. */
- status = sys$assign(&pka_devdsc, &pka_devchn, 0, 0);
- if ( ERR(status) )
- {
- sprintf(warnmsg,
- "warning: set-dir-attributes failed ($assign) for %s.\n",
- dir_name);
- vms_msg(__G__ warnmsg, status);
- retcode = PK_WARN;
- goto cleanup_exit;
- }
- /* Move the directory ID from the NAM[L] to the FIB.
- Clear the FID in the FIB, as we're using the name.
- */
- for (i = 0; i < 3; i++)
- {
- pka_fib.FIB$W_DID[i] = nam.NAM_DID[i];
- pka_fib.FIB$W_FID[i] = 0;
- }
- #ifdef NAML$C_MAXRSS
- /* Enable fancy name characters. Note that "fancy" here does
- not include Unicode, for which there's no support elsewhere.
- */
- pka_fib.fib$v_names_8bit = 1;
- pka_fib.fib$b_name_format_in = FIB$C_ISL1;
- /* ODS5 Extended names used as input to QIO have peculiar
- encoding (perhaps to minimize storage?), so the special
- filesys_name result (typically containing fewer carets) must
- be used here.
- */
- pka_fnam.dsc$a_pointer = nam.naml$l_filesys_name;
- pka_fnam.dsc$w_length = nam.naml$l_filesys_name_size;
- #else /* !NAML$C_MAXRSS */
- /* ODS2-only: Use the whole name. */
- pka_fnam.dsc$a_pointer = nam.NAM_L_NAME;
- pka_fnam.dsc$w_length = nam.NAM_B_NAME + nam.NAM_B_TYPE + nam.NAM_B_VER;
- #endif /* ?NAML$C_MAXRSS */
- /* 2007-07-13 SMS.
- * Our freshly created directory can easily contain fewer files than
- * the original archived directory (for example, if not all the
- * files in the original directory were included in the archive), so
- * its size may differ from that of the archived directory. Thus,
- * simply restoring the original RECATTR attributes structure, which
- * includes EFBLK (and so on) can cause "SYSTEM-W-BADIRECTORY, bad
- * directory file format" complaints. Instead, we overwrite
- * selected archived attributes with current attributes, to avoid
- * setting obsolete/inappropriate attributes on the newly created
- * directory file.
- *
- * First, see if there is a RECATTR structure about which we need to
- * worry.
- */
- for (i = 0; pka_atr[i].atr$w_type != 0; i++)
- {
- if (pka_atr[i].atr$w_type == ATR$C_RECATTR)
- {
- /* We found a RECATTR structure which (we must assume) needs
- * adjustment. Retrieve the RECATTR data for the existing
- * (newly created) directory file.
- */
- status = sys$qiow(0, /* event flag */
- pka_devchn, /* channel */
- IO$_ACCESS, /* function code */
- &pka_acp_iosb, /* IOSB */
- 0, /* AST address */
- 0, /* AST parameter */
- &pka_fibdsc, /* P1 = File Info Block */
- &pka_fnam, /* P2 = File name */
- 0, /* P3 = Rslt nm len */
- 0, /* P4 = Rslt nm str */
- pka_recattr, /* P5 = Attributes */
- 0); /* P6 (not used) */
- /* If initial success, then get the final status from the IOSB. */
- if ( !ERR(status) )
- status = pka_acp_iosb.status;
- if ( ERR(status) )
- {
- sprintf(warnmsg,
- "warning: set-dir-attributes failed ($qiow acc) for %s.\n",
- dir_name);
- vms_msg(__G__ warnmsg, status);
- retcode = PK_WARN;
- }
- else
- {
- /* We should have valid RECATTR data. Overwrite the
- * critical bits of the archive RECATTR structure with
- * the current bits. The book says that an attempt to
- * modify HIBLK will be ignored, and FFBYTE should
- * always be zero, but safety is cheap.
- */
- struct fatdef *ptr_recattr;
- ptr_recattr = (struct fatdef *) pka_atr[i].atr$l_addr;
- ptr_recattr->fat$l_hiblk = pka_rattr.fat$l_hiblk;
- ptr_recattr->fat$l_efblk = pka_rattr.fat$l_efblk;
- ptr_recattr->fat$w_ffbyte = pka_rattr.fat$w_ffbyte;
- }
- /* There should be only one RECATTR structure in the list, so
- * escape from the loop after the first/only one has been
- * processed.
- */
- break;
- }
- }
- /* Modify the file (directory) attributes. */
- status = sys$qiow(0, /* event flag */
- pka_devchn, /* channel */
- IO$_MODIFY, /* function code */
- &pka_acp_iosb, /* IOSB */
- 0, /* AST address */
- 0, /* AST parameter */
- &pka_fibdsc, /* P1 = File Info Block */
- &pka_fnam, /* P2 = File name */
- 0, /* P3 = Rslt nm len */
- 0, /* P4 = Rslt nm str */
- pka_atr, /* P5 = Attributes */
- 0); /* P6 (not used) */
- /* If initial success, then get the final status from the IOSB. */
- if ( !ERR(status) )
- status = pka_acp_iosb.status;
- if ( ERR(status) )
- {
- sprintf(warnmsg,
- "warning: set-dir-attributes failed ($qiow mod) for %s.\n",
- dir_name);
- vms_msg(__G__ warnmsg, status);
- retcode = PK_WARN;
- }
- sys$dassgn(pka_devchn);
- cleanup_exit:
- free_up(); /* Free FAB, XAB storage. */
- free(d); /* Free directory attribute storage. */
- G.extra_field = sav_ef_ptr; /* Restore original pointer. */
- return retcode;
- } /* end function set_direc_attribs() */
- #endif /* SET_DIR_ATTRIB */
- #ifdef TIMESTAMP
- /* Nonzero if `y' is a leap year, else zero. */
- #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
- /* Number of leap years from 1970 to `y' (not including `y' itself). */
- #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
- /* Accumulated number of days from 01-Jan up to start of current month. */
- static ZCONST short ydays[] = {
- 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
- };
- /***********************/
- /* Function mkgmtime() */
- /***********************/
- static time_t mkgmtime(tm)
- struct tm *tm;
- {
- time_t m_time;
- int yr, mo, dy, hh, mm, ss;
- unsigned days;
- yr = tm->tm_year - 70;
- mo = tm->tm_mon;
- dy = tm->tm_mday - 1;
- hh = tm->tm_hour;
- mm = tm->tm_min;
- ss = tm->tm_sec;
- /* calculate days from BASE to this year and add expired days this year */
- dy = (unsigned)dy + ((unsigned)yr * 365) + (unsigned)nleap(yr+1970) +
- (unsigned)ydays[mo] + ((mo > 1) && leap(yr+1970));
- /* convert date & time to seconds relative to 00:00:00, 01/01/1970 */
- return (time_t)((unsigned long)(unsigned)dy * 86400L +
- (unsigned long)hh * 3600L +
- (unsigned long)(mm * 60 + ss));
- } /* end function mkgmtime() */
- /*******************************/
- /* Function dos_to_unix_time() */ /* only used for timestamping of archives */
- /*******************************/
- time_t dos_to_unix_time(dosdatetime)
- ulg dosdatetime;
- {
- struct tm *ltm; /* Local time. */
- time_t loctime; /* The time_t value of local time. */
- time_t then; /* The time to return. */
- long tzoffset_adj; /* timezone-adjustment `remainder' */
- int bailout_cnt; /* counter of tries for tz correction */
- then = time(NULL);
- ltm = localtime(&then);
- /* dissect date */
- ltm->tm_year = ((int)(dosdatetime >> 25) & 0x7f) + 80;
- ltm->tm_mon = ((int)(dosdatetime >> 21) & 0x0f) - 1;
- ltm->tm_mday = ((int)(dosdatetime >> 16) & 0x1f);
- /* dissect time */
- ltm->tm_hour = (int)(dosdatetime >> 11) & 0x1f;
- ltm->tm_min = (int)(dosdatetime >> 5) & 0x3f;
- ltm->tm_sec = (int)(dosdatetime << 1) & 0x3e;
- loctime = mkgmtime(ltm);
- /* Correct for the timezone and any daylight savings time.
- The correction is verified and repeated when not correct, to
- take into account the rare case that a change to or from daylight
- savings time occurs between when it is the time in `tm' locally
- and when it is that time in Greenwich. After the second correction,
- the "timezone & daylight" offset should be correct in all cases. To
- be sure, we allow a third try, but then the loop is stopped. */
- bailout_cnt = 3;
- then = loctime;
- do {
- ltm = localtime(&then);
- tzoffset_adj = (ltm != NULL) ? (loctime - mkgmtime(ltm)) : 0L;
- if (tzoffset_adj == 0L)
- break;
- then += tzoffset_adj;
- } while (--bailout_cnt > 0);
- if ( (dosdatetime >= DOSTIME_2038_01_18) &&
- (then < (time_t)0x70000000L) )
- then = U_TIME_T_MAX; /* saturate in case of (unsigned) overflow */
- if (then < (time_t)0L) /* a converted DOS time cannot be negative */
- then = S_TIME_T_MAX; /* -> saturate at max signed time_t value */
- return then;
- } /* end function dos_to_unix_time() */
- /*******************************/
- /* Function uxtime2vmstime() */
- /*******************************/
- static void uxtime2vmstime( /* convert time_t value into 64 bit VMS bintime */
- time_t utimeval,
- long int binval[2] )
- {
- time_t m_time = utimeval;
- struct tm *t = localtime(&m_time);
- if (t == (struct tm *)NULL) {
- /* time conversion error; use current time instead, hoping
- that localtime() does not reject it as well! */
- m_time = time(NULL);
- t = localtime(&m_time);
- }
- sprintf(timbuf, "%02d-%3s-%04d %02d:%02d:%02d.00",
- t->tm_mday, month[t->tm_mon], t->tm_year + 1900,
- t->tm_hour, t->tm_min, t->tm_sec);
- sys$bintim(&date_str, binval);
- } /* end function uxtime2vmstime() */
- /***************************/
- /* Function stamp_file() */ /* adapted from VMSmunch...it just won't die! */
- /***************************/
- int stamp_file(fname, modtime)
- ZCONST char *fname;
- time_t modtime;
- {
- int status;
- int i;
- static long int Cdate[2], Rdate[2], Edate[2], Bdate[2];
- static short int revisions;
- #if defined(__DECC) || defined(__DECCXX)
- #pragma __member_alignment __save
- #pragma __nomember_alignment
- #endif /* __DECC || __DECCXX */
- static union {
- unsigned short int value;
- struct {
- unsigned system : 4;
- unsigned owner : 4;
- unsigned group : 4;
- unsigned world : 4;
- } bits;
- } prot;
- #if defined(__DECC) || defined(__DECCXX)
- #pragma __member_alignment __restore
- #endif /* __DECC || __DECCXX */
- static unsigned long uic;
- static struct fjndef jnl;
- static struct atrdef Atr[] = {
- {sizeof(pka_rattr), ATR$C_RECATTR, GVTC &pka_rattr},
- {sizeof(pka_uchar), ATR$C_UCHAR, GVTC &pka_uchar},
- {sizeof(Cdate), ATR$C_CREDATE, GVTC &Cdate[0]},
- {sizeof(Rdate), ATR$C_REVDATE, GVTC &Rdate[0]},
- {sizeof(Edate), ATR$C_EXPDATE, GVTC &Edate[0]},
- {sizeof(Bdate), ATR$C_BAKDATE, GVTC &Bdate[0]},
- {sizeof(revisions), ATR$C_ASCDATES, GVTC &revisions},
- {sizeof(prot), ATR$C_FPRO, GVTC &prot},
- {sizeof(uic), ATR$C_UIC, GVTC &uic},
- {sizeof(jnl), ATR$C_JOURNAL, GVTC &jnl},
- {0, 0, 0}
- };
- fileblk = cc$rms_fab; /* Initialize FAB. */
- nam = CC_RMS_NAM; /* Initialize NAM[L]. */
- fileblk.FAB_NAM = &nam; /* Point FAB to NAM[L]. */
- #ifdef NAML$C_MAXRSS
- fileblk.fab$l_dna = (char *) -1; /* Using NAML for default name. */
- fileblk.fab$l_fna = (char *) -1; /* Using NAML for file name. */
- /* Special ODS5-QIO-compatible name storage. */
- nam.naml$l_filesys_name = sys_nam;
- nam.naml$l_filesys_name_alloc = sizeof(sys_nam);
- #endif /* NAML$C_MAXRSS */
- FAB_OR_NAML(fileblk, nam).FAB_OR_NAML_FNA = (char *)fname;
- FAB_OR_NAML(fileblk, nam).FAB_OR_NAML_FNS = strlen(fname);
- nam.NAM_ESA = exp_nam;
- nam.NAM_ESS = sizeof(exp_nam);
- nam.NAM_RSA = res_nam;
- nam.NAM_RSS = sizeof(res_nam);
- if ( ERR(status = sys$parse(&fileblk)) )
- {
- vms_msg(__G__ "stamp_file: sys$parse failed.\n", status);
- return -1;
- }
- pka_devdsc.dsc$w_length = (unsigned short)nam.NAM_DVI[0];
- if ( ERR(status = sys$assign(&pka_devdsc, &pka_devchn, 0, 0)) )
- {
- vms_msg(__G__ "stamp_file: sys$assign failed.\n", status);
- return -1;
- }
- /* Load the descriptor with the appropriate name data: */
- #ifdef NAML$C_MAXRSS
- /* Enable fancy name characters. Note that "fancy" here does
- not include Unicode, for which there's no support elsewhere.
- */
- pka_fib.fib$v_names_8bit = 1;
- pka_fib.fib$b_name_format_in = FIB$C_ISL1;
- /* ODS5 Extended names used as input to QIO have peculiar
- encoding (perhaps to minimize storage?), so the special
- filesys_name result (typically containing fewer carets) must
- be used here.
- */
- pka_fnam.dsc$a_pointer = nam.naml$l_filesys_name;
- pka_fnam.dsc$w_length = nam.naml$l_filesys_name_size;
- #else /* !NAML$C_MAXRSS */
- /* Extract only the name.type;version. */
- pka_fnam.dsc$a_pointer = nam.NAM_L_NAME;
- pka_fnam.dsc$w_length = nam.NAM_B_NAME + nam.NAM_B_TYPE + nam.NAM_B_VER;
- #endif /* ?NAML$C_MAXRSS */
- /* Move the directory ID from the NAM[L] to the FIB.
- Clear the FID in the FIB, as we're using the name.
- */
- for (i = 0; i < 3; i++)
- {
- pka_fib.FIB$W_DID[i] = nam.NAM_DID[i];
- pka_fib.FIB$W_FID[i] = 0;
- }
- /* Use the IO$_ACCESS function to return info about the file.
- This way, the file is not opened, and the expiration and
- revision dates are not modified.
- */
- status = sys$qiow(0, pka_devchn, IO$_ACCESS,
- &pka_acp_iosb, 0, 0,
- &pka_fibdsc, &pka_fnam, 0, 0, Atr, 0);
- if ( !ERR(status) )
- status = pka_acp_iosb.status;
- if ( ERR(status) )
- {
- vms_msg(__G__ "[ Access file QIO failed. ]\n", status);
- sys$dassgn(pka_devchn);
- return -1;
- }
- uxtime2vmstime(modtime, Cdate);
- memcpy(Rdate, Cdate, sizeof(Cdate));
- /* Note: Part of the FIB was cleared by earlier QIOW, so reset it. */
- pka_fib.FIB$L_ACCTL = FIB$M_NORECORD;
- /* Move the directory ID from the NAM[L] to the FIB.
- Clear the FID in the FIB, as we're using the name.
- */
- for (i = 0; i < 3; i++)
- {
- pka_fib.FIB$W_DID[i] = nam.NAM_DID[i];
- pka_fib.FIB$W_FID[i] = 0;
- }
- /* Use the IO$_MODIFY function to change info about the file */
- /* Note, used this way, the file is not opened, however this would */
- /* normally cause the expiration and revision dates to be modified. */
- /* Using FIB$M_NORECORD prohibits this from happening. */
- status = sys$qiow(0, pka_devchn, IO$_MODIFY,
- &pka_acp_iosb, 0, 0,
- &pka_fibdsc, &pka_fnam, 0, 0, Atr, 0);
- if ( !ERR(status) )
- status = pka_acp_iosb.status;
- if ( ERR(status) )
- {
- vms_msg(__G__ "[ Modify file QIO failed. ]\n", status);
- sys$dassgn(pka_devchn);
- return -1;
- }
- if ( ERR(status = sys$dassgn(pka_devchn)) )
- {
- vms_msg(__G__ "stamp_file: sys$dassgn failed.\n", status);
- return -1;
- }
- return 0;
- } /* end function stamp_file() */
- #endif /* TIMESTAMP */
- #ifdef DEBUG
- #if 0 /* currently not used anywhere ! */
- void dump_rms_block(p)
- unsigned char *p;
- {
- unsigned char bid, len;
- int err;
- char *type;
- char buf[132];
- int i;
- err = 0;
- bid = p[0];
- len = p[1];
- switch (bid)
- {
- case FAB$C_BID:
- type = "FAB";
- break;
- case XAB$C_ALL:
- type = "xabALL";
- break;
- case XAB$C_KEY:
- type = "xabKEY";
- break;
- case XAB$C_DAT:
- type = "xabDAT";
- break;
- case XAB$C_RDT:
- type = "xabRDT";
- break;
- case XAB$C_FHC:
- type = "xabFHC";
- break;
- case XAB$C_PRO:
- type = "xabPRO";
- break;
- default:
- type = "Unknown";
- err = 1;
- break;
- }
- printf("Block @%08X of type %s (%d).", p, type, bid);
- if (err)
- {
- printf("\n");
- return;
- }
- printf(" Size = %d\n", len);
- printf(" Offset - Hex - Dec\n");
- for (i = 0; i < len; i += 8)
- {
- int j;
- printf("%3d - ", i);
- for (j = 0; j < 8; j++)
- if (i + j < len)
- printf("%02X ", p[i + j]);
- else
- printf(" ");
- printf(" - ");
- for (j = 0; j < 8; j++)
- if (i + j < len)
- printf("%03d ", p[i + j]);
- else
- printf(" ");
- printf("\n");
- }
- }
- #endif /* never */
- #endif /* DEBUG */
- static char vms_msgbuf[256]; /* VMS-specific error message. */
- static $DESCRIPTOR(vms_msgbuf_dscr, vms_msgbuf);
- char *vms_msg_text(void)
- {
- return vms_msgbuf;
- }
- static int vms_msg_fetch(int status)
- {
- int msglen = 0;
- int sts;
- sts = lib$sys_getmsg(&status, &msglen, &vms_msgbuf_dscr, 0, 0);
- vms_msgbuf[msglen] = '\0';
- return sts;
- }
- static void vms_msg(__GPRO__ ZCONST char *string, int status)
- {
- if (ERR(vms_msg_fetch(status)))
- Info(slide, 1, ((char *)slide,
- "%s[ VMS status = %d ]\n", string, status));
- else
- Info(slide, 1, ((char *)slide,
- "%s[ %s ]\n", string, vms_msgbuf));
- }
- #ifndef SFX
- /* 2004-11-23 SMS.
- * Changed to return the resulting file name even when sys$search()
- * fails. Before, if the user specified "fred.zip;4" and there was
- * none, the error message would complain:
- * cannot find either fred.zip;4 or fred.zip;4.zip.
- * when it wasn't really looking for "fred.zip;4.zip".
- */
- /* 2005-08-11 SPC.
- * The calling interface for the VMS version of do_wild() differs from all
- * other implementations in the way it returns status info.
- * There are three return states:
- * a) pointer to buffer with non-zero-length string
- * - canonical full filespec of existing file (search succeeded).
- * b) pointer to buffer with zero-length string
- * - initial file search has failed, extended VMS error info is available
- * through call to vms_msg_text().
- * c) NULL pointer
- * - repeated file search has failed, because
- * i) the list of matches for the pattern has been exhausted after at
- * least one successful attempt.
- * ii) a second attempt for a failed initial pattern (where do_wild()
- * has returned a zero-length string) was tried and failed again.
- */
- char *do_wild( __G__ wld )
- __GDEF
- ZCONST char *wld;
- {
- int status;
- static char filenam[NAM_MAXRSS + 1];
- static char efn[NAM_MAXRSS];
- static char last_wild[NAM_MAXRSS + 1];
- static struct FAB fab;
- static struct NAM_STRUCT nam;
- static int first_call = 1;
- static ZCONST char deflt[] = "[]*.ZIP";
- if ( first_call || strcmp(wld, last_wild) )
- { /* (Re)Initialize everything */
- strcpy( last_wild, wld );
- fab = cc$rms_fab; /* Initialize FAB. */
- nam = CC_RMS_NAM; /* Initialize NAM[L]. */
- fab.FAB_NAM = &nam; /* Point FAB to NAM[L]. */
- #ifdef NAML$C_MAXRSS
- fab.fab$l_dna = (char *) -1; /* Using NAML for default name. */
- fab.fab$l_fna = (char *) -1; /* Using NAML for file name. */
- #endif /* NAML$C_MAXRSS */
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_DNA = (char *) deflt;
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_DNS = sizeof(deflt) - 1;
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_FNA = last_wild;
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_FNS = strlen(last_wild);
- nam.NAM_ESA = efn;
- nam.NAM_ESS = sizeof(efn)-1;
- nam.NAM_RSA = filenam;
- nam.NAM_RSS = sizeof(filenam)-1;
- first_call = 0;
- /* 2005-08-08 SMS.
- * Parse the file spec. If sys$parse() fails, save the VMS
- * error message for later use, and return an empty string.
- */
- nam.NAM_NOP = NAM_M_SYNCHK; /* Syntax-only analysis. */
- if ( !OK(status = sys$parse(&fab)) )
- {
- vms_msg_fetch(status);
- filenam[0] = '\0'; /* Initialization failed */
- return filenam;
- }
- /* 2005-11-16 SMS.
- * If syntax-only parse worked, re-parse normally so that
- * sys$search() will work properly. Regardless of parse error,
- * leave filenam[] as-was.
- */
- nam.NAM_NOP = 0; /* Normal analysis. */
- if ( OK(status = sys$parse(&fab)) )
- {
- status = sys$search(&fab);
- }
- if ( !OK(status) )
- {
- /* Save the VMS error message for later use. */
- vms_msg_fetch(status);
- }
- }
- else
- {
- if ( !OK(sys$search(&fab)) )
- {
- first_call = 1; /* Reinitialize next time */
- return (char *)NULL;
- }
- }
- filenam[nam.NAM_RSL] = '\0'; /* Add the NUL terminator. */
- return filenam;
- } /* end function do_wild() */
- #endif /* !SFX */
- static ulg unix_to_vms[8]={ /* Map from UNIX rwx to VMS rwed */
- /* Note that unix w bit is mapped to VMS wd bits */
- /* no access */
- XAB$M_NOREAD | XAB$M_NOWRITE | XAB$M_NODEL | XAB$M_NOEXE, /* --- */
- XAB$M_NOREAD | XAB$M_NOWRITE | XAB$M_NODEL, /* --x */
- XAB$M_NOREAD | XAB$M_NOEXE, /* -w- */
- XAB$M_NOREAD, /* -wx */
- XAB$M_NOWRITE | XAB$M_NODEL | XAB$M_NOEXE, /* r-- */
- XAB$M_NOWRITE | XAB$M_NODEL, /* r-x */
- XAB$M_NOEXE, /* rw- */
- 0 /* rwx */
- /* full access */
- };
- #define SETDFPROT /* We are using undocumented VMS System Service */
- /* SYS$SETDFPROT here. If your version of VMS does */
- /* not have that service, undef SETDFPROT. */
- /* IM: Maybe it's better to put this to Makefile */
- /* and DESCRIP.MMS */
- #ifdef SETDFPROT
- extern int sys$setdfprot();
- #endif
- int mapattr(__G)
- __GDEF
- {
- ulg tmp = G.crec.external_file_attributes;
- ulg theprot;
- static ulg defprot = (ulg)-1L,
- sysdef, owndef, grpdef, wlddef; /* Default protection fields */
- /* IM: The only field of XABPRO we need to set here is */
- /* file protection, so we need not to change type */
- /* of G.pInfo->file_attr. WORD is quite enough. */
- if ( defprot == (ulg)-1L )
- {
- /*
- * First time here -- Get user default settings
- */
- #ifdef SETDFPROT /* Undef this if linker cat't resolve SYS$SETDFPROT */
- defprot = (ulg)0L;
- if ( !ERR(sys$setdfprot(0, &defprot)) )
- {
- sysdef = defprot & ( (1L<<XAB$S_SYS)-1 ) << XAB$V_SYS;
- owndef = defprot & ( (1L<<XAB$S_OWN)-1 ) << XAB$V_OWN;
- grpdef = defprot & ( (1L<<XAB$S_GRP)-1 ) << XAB$V_GRP;
- wlddef = defprot & ( (1L<<XAB$S_WLD)-1 ) << XAB$V_WLD;
- }
- else
- #endif /* SETDFPROT */
- {
- umask(defprot = umask(0));
- defprot = ~defprot;
- wlddef = unix_to_vms[defprot & 07] << XAB$V_WLD;
- grpdef = unix_to_vms[(defprot>>3) & 07] << XAB$V_GRP;
- owndef = unix_to_vms[(defprot>>6) & 07] << XAB$V_OWN;
- sysdef = owndef >> (XAB$V_OWN - XAB$V_SYS);
- defprot = sysdef | owndef | grpdef | wlddef;
- }
- }
- switch (G.pInfo->hostnum) {
- case AMIGA_:
- tmp = (unsigned)(tmp>>16 & 0x0f); /* Amiga RWED bits */
- G.pInfo->file_attr = (tmp << XAB$V_OWN) |
- grpdef | sysdef | wlddef;
- break;
- case THEOS_:
- tmp &= 0xF1FFFFFFL;
- if ((tmp & 0xF0000000L) != 0x40000000L)
- tmp &= 0x01FFFFFFL; /* not a dir, mask all ftype bits */
- else
- tmp &= 0x41FFFFFFL; /* leave directory bit as set */
- /* fall through! */
- case UNIX_:
- case VMS_: /*IM: ??? Does VMS Zip store protection in UNIX format ?*/
- /* GRR: Yup. Bad decision on my part... */
- case ACORN_:
- case ATARI_:
- case ATHEOS_:
- case BEOS_:
- case QDOS_:
- case TANDEM_:
- {
- int r = FALSE;
- unsigned uxattr = (unsigned)(tmp >> 16); /* drwxrwxrwx */
- if (uxattr == 0 && G.extra_field) {
- /* Some (non-Info-ZIP) implementations of Zip for Unix and
- * VMS (and probably others ??) leave 0 in the upper 16-bit
- * part of the external_file_attributes field. Instead, they
- * store file permission attributes in some e.f. block.
- * As a work-around, we search for the presence of one of
- * these extra fields and fall back to the MSDOS compatible
- * part of external_file_attributes if one of the known
- * e.f. types has been detected.
- * Later, we might implement extraction of the permission
- * bits from the VMS extra field. But for now, the work-around
- * should be sufficient to provide "readable" extracted files.
- * (For ASI Unix e.f., an experimental remap of the e.f.
- * mode value IS already provided!)
- */
- ush ebID;
- unsigned ebLen;
- uch *ef = G.extra_field;
- unsigned ef_len = G.crec.extra_field_length;
- while (!r && ef_len >= EB_HEADSIZE) {
- ebID = makeword(ef);
- ebLen = (unsigned)makeword(ef+EB_LEN);
- if (ebLen > (ef_len - EB_HEADSIZE))
- /* discoverd some e.f. inconsistency! */
- break;
- switch (ebID) {
- case EF_ASIUNIX:
- if (ebLen >= (EB_ASI_MODE+2)) {
- uxattr =
- (unsigned)makeword(ef+(EB_HEADSIZE+EB_ASI_MODE));
- /* force stop of loop: */
- ef_len = (ebLen + EB_HEADSIZE);
- break;
- }
- /* else: fall through! */
- case EF_PKVMS:
- /* "found nondecypherable e.f. with perm. attr" */
- r = TRUE;
- default:
- break;
- }
- ef_len -= (ebLen + EB_HEADSIZE);
- ef += (ebLen + EB_HEADSIZE);
- }
- }
- if (!r) {
- #ifdef SYMLINKS
- /* Check if the file is a (POSIX-compatible) symbolic link.
- * We restrict symlink support to those "made-by" hosts that
- * are known to support symbolic links.
- */
- G.pInfo->symlink = S_ISLNK(uxattr) &&
- SYMLINK_HOST(G.pInfo->hostnum);
- #endif
- theprot = (unix_to_vms[uxattr & 07] << XAB$V_WLD)
- | (unix_to_vms[(uxattr>>3) & 07] << XAB$V_GRP)
- | (unix_to_vms[(uxattr>>6) & 07] << XAB$V_OWN);
- if ( uxattr & 0x4000 )
- /* Directory -- set D bits */
- theprot |= (XAB$M_NODEL << XAB$V_SYS)
- | (XAB$M_NODEL << XAB$V_OWN)
- | (XAB$M_NODEL << XAB$V_GRP)
- | (XAB$M_NODEL << XAB$V_WLD);
- G.pInfo->file_attr = theprot;
- break;
- }
- }
- /* fall through! */
- /* all remaining cases: expand MSDOS read-only bit into write perms */
- case FS_FAT_:
- case FS_HPFS_:
- case FS_NTFS_:
- case MAC_:
- case TOPS20_:
- default:
- theprot = defprot;
- if ( tmp & 1 ) /* Test read-only bit */
- { /* Bit is set -- set bits in all fields */
- tmp = XAB$M_NOWRITE | XAB$M_NODEL;
- theprot |= (tmp << XAB$V_SYS) | (tmp << XAB$V_OWN) |
- (tmp << XAB$V_GRP) | (tmp << XAB$V_WLD);
- }
- G.pInfo->file_attr = theprot;
- break;
- } /* end switch (host-OS-created-by) */
- return 0;
- } /* end function mapattr() */
- #define PATH_DEFAULT "SYS$DISK:[]"
- /* dest_struct_level()
- Returns file system structure level for argument, negative on
- error.
- */
- int dest_struct_level(char *path)
- {
- int acp_code;
- #ifdef DVI$C_ACP_F11V5
- /* Should know about ODS5 file system. Do actual check.
- (This should be non-VAX with __CRTL_VER >= 70200000.)
- */
- int sts;
- struct FAB fab;
- struct NAM_STRUCT nam;
- char e_name[NAM_MAXRSS + 1];
- struct dsc$descriptor_s dev_descr =
- { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0 };
- fab = cc$rms_fab; /* Initialize FAB. */
- nam = CC_RMS_NAM; /* Initialize NAM[L]. */
- fab.FAB_NAM = &nam; /* Point FAB to NAM[L]. */
- #ifdef NAML$C_MAXRSS
- fab.fab$l_dna = (char *) -1; /* Using NAML for default name. */
- fab.fab$l_fna = (char *) -1; /* Using NAML for file name. */
- #endif /* NAML$C_MAXRSS */
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_DNA = PATH_DEFAULT;
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_DNS = strlen(PATH_DEFAULT);
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_FNA = path;
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_FNS = strlen(path);
- nam.NAM_ESA = e_name;
- nam.NAM_ESS = sizeof(e_name) - 1;
- nam.NAM_NOP = NAM_M_SYNCHK; /* Syntax-only analysis. */
- sts = sys$parse(&fab);
- if ((sts & STS$M_SUCCESS) == STS$K_SUCCESS)
- {
- /* Load resultant device name into device descriptor. */
- dev_descr.dsc$a_pointer = nam.NAM_L_DEV;
- dev_descr.dsc$w_length = nam.NAM_B_DEV;
- /* Get filesystem type code.
- (Text results for this item code have been unreliable.)
- */
- sts = lib$getdvi(&((int) DVI$_ACPTYPE),
- 0,
- &dev_descr,
- &acp_code,
- 0,
- 0);
- if ((sts & STS$M_SUCCESS) != STS$K_SUCCESS)
- {
- acp_code = -2;
- }
- }
- else
- {
- acp_code = -1;
- }
- #else /* !DVI$C_ACP_F11V5 */
- /* Too old for ODS5 file system. Return level 2. */
- acp_code = DVI$C_ACP_F11V2;
- #endif /* ?DVI$C_ACP_F11V5 */
- return acp_code;
- }
- /* 2005-02-12 SMS.
- Note that these name conversion functions do no length checking.
- Buffer overflows are possible.
- */
- static void adj_dir_name_ods2(char *dest, char *src, int src_len)
- {
- /* The source string (src) typically extends beyond the directory
- segment of interest, hence the confining src_len argument.
- */
- unsigned char uchr;
- unsigned char prop;
- char * src_last;
- for (src_last = src + src_len; src < src_last; src++)
- {
- prop = char_prop[uchr = *src]; /* Get source char, properties. */
- if ((prop & 2) != 0) /* Up-case lower case. */
- {
- uchr -= ('a' - 'A'); /* (Simple-fast is adequate.) */
- }
- else if ((prop & 1) == 0) /* Replace invalid char */
- {
- uchr = '_'; /* with "_". */
- }
- *dest++ = uchr; /* Store good char. */
- }
- *dest = '\0'; /* Terminate destination. */
- }
- static void adj_dir_name_ods5(char *dest, char *src, int src_len)
- {
- /* The source string (src) typically extends beyond the directory
- segment of interest, hence the confining src_len argument.
- */
- unsigned char uchr;
- unsigned char prop;
- char * src_last;
- for (src_last = src + src_len; src < src_last; src++)
- {
- prop = char_prop[uchr = *src]; /* Get source char, props. */
- prop = char_prop[uchr]; /* Get source char props. */
- if ((prop & (32+8+4)) != 0) /* Escape 1-char, including */
- { /* SP and dot. */
- *dest++ = '^'; /* Insert caret. */
- if ((prop & 8) != 0) /* Replace SP with "_". */
- {
- uchr = '_';
- }
- else if (uchr == '?')
- {
- uchr = '/'; /* Replace "?" with "/". */
- }
- }
- else if ((prop & 64) != 0) /* Escape hex-hex. */
- {
- *dest++ = '^'; /* Insert caret. */
- *dest++ = hex_digit[uchr >> 4]; /* First hex digit. */
- uchr = hex_digit[uchr & 15]; /* Second hex digit. */
- }
- else if ((prop & 16) == 0) /* Replace invalid with "_". */
- {
- uchr = '_';
- }
- *dest++ = uchr; /* Put good (or last) char. */
- }
- *dest = '\0'; /* Terminate destination. */
- }
- static void adj_file_name_ods2(char *dest, char *src)
- {
- unsigned char uchr;
- unsigned char prop;
- char *endp;
- char *versionp;
- char *last_dot;
- endp = src + strlen(src); /* Pointer to the NUL-terminator of src. */
- /* Starting at the end, find the last non-decimal-digit. */
- versionp = endp;
- while ((--versionp >= src) && isdigit(*versionp));
- /* Left-most non-digit of a valid version is ";" (or perhaps "."). */
- if ((*versionp != ';') && ((uO.Y_flag == 0) || (*versionp != '.')))
- {
- /* No valid version. The last dot is the last dot. */
- versionp = endp;
- }
- else
- { /* Some kind of valid version. */
- if (!uO.V_flag) /* Not -V, so cut off version. */
- {
- *versionp = '\0';
- }
- else if (*versionp == '.')
- {
- *versionp = ';'; /* Replace version dot with ";". */
- }
- }
- /* 2008-11-04 SMS.
- * Simplified the scheme here to escape all non-last dots. This
- * should work when Zip works correctly (Zip 3.1).
- * Note that if no last dot is found, the non-last-dot test below
- * will always fail, but that's not a problem.
- */
- /* Find the last dot (if any). */
- last_dot = versionp;
- while ((--last_dot >= src) && (*last_dot != '.'));
- /* Critical features having been located, transform the name. */
- while ((uchr = *src++) != '\0') /* Get source character. */
- {
- /* Note that "src" has been incremented, affecting "src <=". */
- prop = char_prop[uchr]; /* Get source char properties. */
- if ((prop & 2) != 0) /* Up-case lower case. */
- {
- uchr -= ('a' - 'A'); /* (Simple-fast is adequate.) */
- }
- else if ((prop & 4) != 0) /* Dot. */
- {
- if (src <= last_dot) /* Replace non-last dot */
- {
- uchr = '_'; /* with "_". */
- }
- }
- else if ((prop & 1) == 0) /* Replace SP or invalid char, */
- {
- if (src <= versionp) /* if not in version, */
- {
- uchr = '_'; /* with "_". */
- }
- }
- *dest++ = uchr; /* Store good char. */
- }
- *dest = '\0'; /* Terminate destination. */
- }
- static void adj_file_name_ods5(char *dest, char *src)
- {
- unsigned char uchr;
- unsigned char prop;
- char *endp;
- char *versionp;
- char *last_dot;
- endp = src + strlen(src); /* Pointer to the NUL-terminator of src. */
- /* Starting at the end, find the last non-decimal-digit. */
- versionp = endp;
- while ((--versionp >= src) && isdigit(*versionp));
- /* Left-most non-digit of a valid version is ";" (or perhaps "."). */
- if ((*versionp != ';') && ((uO.Y_flag == 0) || (*versionp != '.')))
- {
- /* No valid version. The last dot is the last dot. */
- versionp = endp;
- }
- else
- { /* Some kind of valid version. */
- if (!uO.V_flag) /* Not -V, so cut off version. */
- {
- *versionp = '\0';
- }
- else if (*versionp == '.')
- {
- *versionp = ';'; /* Replace version dot with ";". */
- }
- }
- /* 2008-11-04 SMS.
- * Simplified the scheme here to escape all non-last dots. This
- * should work when Zip works correctly (Zip 3.1).
- * Note that if no last dot is found, the non-last-dot test below
- * will always fail, but that's not a problem.
- */
- /* Find the last dot (if any). */
- last_dot = versionp;
- while ((--last_dot >= src) && (*last_dot != '.'));
- /* Critical features having been located, transform the name. */
- while ((uchr = *src++) != '\0') /* Get source character. */
- {
- /* Note that "src" has been incremented, affecting "src <=". */
- prop = char_prop[uchr]; /* Get source char props. */
- if ((prop & (32+8)) != 0) /* Escape 1-char, including */
- { /* SP (but not dot). */
- if (src <= versionp) /* No escapes for version. */
- {
- *dest++ = '^'; /* Insert caret. */
- if ((prop & 8) != 0) /* Replace SP with "_". */
- {
- uchr = '_';
- }
- else if (uchr == '?')
- {
- uchr = '/'; /* Replace "?" with "/". */
- }
- }
- }
- else if ((prop & 4) != 0) /* Dot. */
- {
- if (src <= last_dot) /* Escape non-last dot */
- {
- *dest++ = '^'; /* Insert caret. */
- }
- }
- else if ((prop & 64) != 0) /* Escape hex-hex. */
- {
- *dest++ = '^'; /* Insert caret. */
- *dest++ = hex_digit[uchr >> 4]; /* First hex digit. */
- uchr = hex_digit[uchr & 15]; /* Second hex digit. */
- }
- else if ((prop & 16) == 0) /* Replace invalid with "_". */
- {
- uchr = '_';
- }
- *dest++ = uchr; /* Put good (or last) char. */
- }
- *dest = '\0'; /* Terminate destination. */
- }
- # define FN_MASK 7
- # define USE_DEFAULT (FN_MASK+1)
- /*
- * Checkdir function codes:
- * ROOT - set root path from unzip qq d:[dir]
- * INIT - get ready for "filename"
- * APPEND_DIR - append pathcomp
- * APPEND_NAME - append filename
- * APPEND_NAME | USE_DEFAULT - expand filename using collected path
- * GETPATH - return resulting filespec
- * END - free dynamically allocated space prior to program exit
- */
- static int created_dir;
- static int dest_file_sys_level;
- static int ods2_names = -1;
- int mapname(__G__ renamed)
- /* returns: */
- /* MPN_OK if no error, */
- /* MPN_INF_TRUNC if caution (filename trunc), */
- /* MPN_INF_SKIP if warning (skip file, dir doesn't exist), */
- /* MPN_ERR_SKIP if error (skip file), */
- /* MPN_CREATED_DIR if has created directory, */
- /* MPN_VOL_LABEL if path was volume label (skip it) */
- /* MPN_NOMEM if no memory (skip file) */
- __GDEF
- int renamed;
- {
- char pathcomp[FILNAMSIZ]; /* Path-component buffer. */
- char *last_slash; /* Last slash in path. */
- char *next_slash; /* Next slash in path. */
- int dir_len; /* Length of a directory segment. */
- char *cp = (char *)NULL; /* character pointer */
- int killed_ddot = FALSE; /* Set when skipping "../" pathcomp. */
- int error = MPN_OK;
- if ( renamed )
- {
- if ( !(error = checkdir(__G__ pathcomp, APPEND_NAME | USE_DEFAULT)) )
- strcpy(G.filename, pathcomp);
- return error;
- }
- /*---------------------------------------------------------------------------
- Initialize various pointers and counters and stuff.
- ---------------------------------------------------------------------------*/
- if (G.pInfo->vollabel)
- return MPN_VOL_LABEL; /* can't set disk volume labels on VMS */
- /* can create path as long as not just freshening, or if user told us */
- G.create_dirs = !uO.fflag;
- created_dir = FALSE; /* not yet */
- /* If not yet known, determine the destination file system type
- (ODS2 or ODS5). (If the user specified a destination, we should
- already have this, so use the default destination.)
- */
- if (ods2_names < 0)
- {
- /* If user doesn't force ODS2, set flag according to destination. */
- if (uO.ods2_flag == 0)
- {
- ods2_names =
- (dest_struct_level(PATH_DEFAULT) <= DVI$C_ACP_F11V2);
- }
- else
- {
- ods2_names = 1; /* User demands ODS2 names. */
- }
- }
- /* GRR: for VMS, convert to internal format now or later? or never? */
- if (checkdir(__G__ pathcomp, INIT) == 10)
- return MPN_NOMEM; /* Initialize path buffer, unless no memory. */
- /* Locate and treat directory segments one at a time.
- When pointer exceeds last_slash, then directory segments are
- done, and only the name (with version?) remains.
- */
- *pathcomp = '\0'; /* Initialize translation buffer. */
- last_slash = strrchr(G.filename, '/'); /* Find last slash. */
- if (uO.jflag) /* If junking directories, */
- cp = last_slash; /* start at (will be after) the last slash. */
- if (cp == NULL) /* If no '/', or keeping directories, */
- cp = G.filename; /* start at the front of the pathname. */
- else /* Else, with directories to junk, */
- ++cp; /* start after the last slash. */
- /* Loop through the directory segments. */
- while (cp < last_slash)
- {
- next_slash = strchr(cp, '/'); /* Find the next slash. */
- dir_len = next_slash- cp;
- /* Filter out unacceptable directories. */
- if ((dir_len == 2) && (strncmp(cp, "..", 2) == 0))
- { /* Double dot. */
- if (!uO.ddotflag) /* Not allowed. Skip it. */
- {
- dir_len = 0;
- killed_ddot = TRUE; /* Record skipping double-dot. */
- }
- }
- else if ((dir_len == 1) && (strncmp(cp, ".", 1) == 0))
- { /* Single dot. No-op. Skip it. */
- dir_len = 0;
- }
- /* If non-null, acceptable directory, then process it. */
- if (dir_len > 0)
- {
- if (ods2_names) /* Make directory name ODS2-compliant. */
- {
- adj_dir_name_ods2(pathcomp, cp, dir_len);
- }
- else /* Make directory name ODS5-compliant. */
- {
- adj_dir_name_ods5(pathcomp, cp, dir_len);
- }
- if (((error = checkdir(__G__ pathcomp, APPEND_DIR))
- & MPN_MASK) > MPN_INF_TRUNC)
- return error;
- }
- cp = next_slash+ 1; /* Continue at the next name segment. */
- } /* end while loop */
- /* Show warning when stripping insecure "parent dir" path components */
- if (killed_ddot && QCOND2) {
- Info(slide, 0, ((char *)slide,
- "warning: skipped \"../\" path component(s) in %s\n",
- FnFilter1(G.filename)));
- if (!(error & ~MPN_MASK))
- error = (error & MPN_MASK) | PK_WARN;
- }
- /* If there is one, adjust the name.type;version segment. */
- if (strlen(cp) == 0)
- {
- /* Directory only, no file name. Create the directory, as needed.
- Report directory creation to user.
- */
- checkdir(__G__ "", APPEND_NAME); /* create directory, if not found */
- checkdir(__G__ G.filename, GETPATH);
- if (created_dir) {
- if (QCOND2) {
- Info(slide, 0, ((char *)slide, " creating: %s\n",
- FnFilter1(G.filename)));
- }
- /* set dir time (note trailing '/') */
- return (error & ~MPN_MASK) | MPN_CREATED_DIR;
- }
- /* dir existed already; don't look for data to extract */
- return (error & ~MPN_MASK) | MPN_INF_SKIP;
- }
- /* Process the file name. */
- if (ods2_names) /* Make file name ODS2-compliant. */
- {
- adj_file_name_ods2(pathcomp, cp);
- }
- else /* Make file name ODS5-compliant. */
- {
- adj_file_name_ods5(pathcomp, cp);
- }
- checkdir(__G__ pathcomp, APPEND_NAME); /* returns 1 if truncated: care? */
- checkdir(__G__ G.filename, GETPATH);
- return error;
- } /* end function mapname() */
- int checkdir(__G__ pathcomp, fcn)
- /*
- * returns:
- * MPN_OK - no problem detected
- * MPN_INF_TRUNC - (on APPEND_NAME) truncated filename
- * MPN_INF_SKIP - path doesn't exist, not allowed to create
- * MPN_ERR_SKIP - path doesn't exist, tried to create and failed; or path
- * exists and is not a directory, but is supposed to be
- * MPN_ERR_TOOLONG - path is too long
- * MPN_NOMEM - can't allocate memory for filename buffers
- */
- __GDEF
- char *pathcomp;
- int fcn;
- {
- int function=fcn & FN_MASK;
- static char pathbuf[FILNAMSIZ];
- /* previously created directory (initialized to impossible dir. spec.) */
- static char lastdir[FILNAMSIZ] = "\t";
- static char *pathptr = pathbuf; /* For debugger */
- static char *devptr, *dirptr;
- static int devlen, dirlen;
- static int root_dirlen;
- static char *end;
- static int first_comp, root_has_dir;
- static int rootlen=0;
- static char *rootend;
- static int mkdir_failed=0;
- int status;
- struct FAB fab;
- struct NAM_STRUCT nam;
- /************
- *** ROOT ***
- ************/
- #if (!defined(SFX) || defined(SFX_EXDIR))
- if (function == ROOT)
- { /* Assume VMS root spec */
- /* 2006-01-20 SMS.
- Changed to use sys$parse() instead of sys$filescan() for analysis
- of the user-specified destination directory. Previously, various
- values behaved badly, without complaint, e.g. "-d sys$scratch".
- */
- char *root_dest;
- /* If the root path has already been set, return immediately. */
- if (rootlen > 0)
- return MPN_OK;
- /* Initialization. */
- root_dest = PATH_DEFAULT; /* Default destination for ODSx sensing. */
- root_has_dir = 0; /* Root includes a directory. */
- fab = cc$rms_fab; /* Initialize FAB. */
- nam = CC_RMS_NAM; /* Initialize NAM[L]. */
- fab.FAB_NAM = &nam; /* Point FAB to NAM[L]. */
- #ifdef NAML$C_MAXRSS
- fab.fab$l_dna = (char *) -1; /* Using NAML for default name. */
- fab.fab$l_fna = (char *) -1; /* Using NAML for file name. */
- #endif /* NAML$C_MAXRSS */
- /* Specified file spec. */
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_FNA = pathcomp;
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_FNS = strlen(pathcomp);
- /* Default file spec. */
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_DNA = PATH_DEFAULT;
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_DNS = strlen(PATH_DEFAULT);
- /* Expanded file spec. */
- nam.NAM_ESA = pathbuf;
- nam.NAM_ESS = NAM_MAXRSS;
- status = sys$parse(&fab);
- /* OK so far, if OK or if directory not found. */
- if (((status & STS$M_SEVERITY) != STS$K_SUCCESS) &&
- (status != RMS$_DNF))
- {
- /* Invalid destination directory specified. */
- Info(slide, 1, ((char *)slide,
- "Invalid destination directory (parse error): %s\n",
- FnFilter1(pathcomp)));
- return MPN_ERR_SKIP;
- }
- /* Should be only a device:[directory], so name+type+version
- should have length 2 (".;").
- */
- if (nam.NAM_B_NAME + nam.NAM_B_TYPE + nam.NAM_B_VER > 2)
- {
- Info(slide, 1, ((char *)slide,
- "Invalid destination directory (includes file name): %s\n",
- FnFilter1(nam.NAM_ESA)));
- return MPN_ERR_SKIP;
- }
- /* Truncate at name, leaving only "dev:[dir]". */
- *nam.NAM_L_NAME = '\0';
- rootlen = nam.NAM_L_NAME - nam.NAM_ESA;
- /* Remove any trailing dots in directory. */
- if ((nam.NAM_ESA[rootlen-1] == ']') &&
- (nam.NAM_ESA[rootlen-2] != '^'))
- {
- root_has_dir = 1;
- rootlen -= 2;
- while ((nam.NAM_ESA[rootlen] == '.') &&
- (nam.NAM_ESA[rootlen-1] != '^'))
- {
- rootlen--;
- }
- nam.NAM_ESA[++rootlen] = ']';
- nam.NAM_ESA[++rootlen] = '\0';
- }
- devlen = nam.NAM_L_DIR - nam.NAM_ESA;
- /* If directory not found, then create it. */
- if (status == RMS$_DNF)
- {
- if (status = mkdir(nam.NAM_ESA, 0))
- {
- Info(slide, 1, ((char *)slide,
- "Can not create destination directory: %s\n",
- FnFilter1(nam.NAM_ESA)));
- /* path didn't exist, tried to create, and failed. */
- return MPN_ERR_SKIP;
- }
- }
- /* Save the (valid) device:[directory] spec. */
- strcpy(pathbuf, nam.NAM_ESA);
- root_dest = pathbuf;
- /* At this point, the true destination is known. If the user
- supplied an invalid destination directory, the default
- directory will be used. (This may be pointless, but should
- be safe.)
- */
- /* If not yet known, determine the destination (root_dest) file
- system type (ODS2 or ODS5).
- */
- if (ods2_names < 0)
- {
- /* If user doesn't force ODS2, set flag according to dest. */
- if (uO.ods2_flag == 0)
- {
- ods2_names = (dest_struct_level(root_dest) <= DVI$C_ACP_F11V2);
- }
- else
- {
- ods2_names = 1; /* User demands ODS2 names. */
- }
- }
- /* Replace trailing "]" with ".", for later appending. */
- if ((pathbuf[rootlen-1] == ']') || (pathbuf[rootlen-1] == '>'))
- {
- pathbuf[rootlen-1] = '.';
- }
- /* Set various pointers and lengths. */
- devptr = pathbuf;
- dirptr = pathbuf + (nam.NAM_L_DIR - nam.NAM_ESA);
- rootend = pathbuf + rootlen;
- *(end = rootend) = '\0';
- root_dirlen = dirlen = rootlen - devlen;
- first_comp = !root_has_dir;
- return MPN_OK;
- }
- #endif /* !SFX || SFX_EXDIR */
- /************
- *** INIT ***
- ************/
- if ( function == INIT )
- {
- if ( strlen(G.filename) + rootlen + 13 > NAM_MAXRSS )
- return MPN_ERR_TOOLONG;
- if ( rootlen == 0 ) /* No root given, reset everything. */
- {
- devptr = dirptr = rootend = pathbuf;
- devlen = dirlen = 0;
- }
- end = rootend;
- first_comp = !root_has_dir;
- if ( dirlen = root_dirlen )
- end[-1] = '.';
- *end = '\0';
- return MPN_OK;
- }
- /******************
- *** APPEND_DIR ***
- ******************/
- if ( function == APPEND_DIR )
- {
- int cmplen;
- cmplen = strlen(pathcomp);
- if ( first_comp )
- {
- *end++ = '[';
- if ( cmplen )
- *end++ = '.'; /* "dir/..." --> "[.dir...]" */
- /* else "/dir..." --> "[dir...]" */
- first_comp = 0;
- }
- if ( cmplen == 1 && *pathcomp == '.' )
- ; /* "..././..." -- ignore */
- else if ( cmplen == 2 && pathcomp[0] == '.' && pathcomp[1] == '.' )
- { /* ".../../..." -- convert to "...-..." */
- *end++ = '-';
- *end++ = '.';
- }
- else if ( cmplen + (end-pathptr) > NAM_MAXRSS )
- return MPN_ERR_TOOLONG;
- else
- {
- strcpy(end, pathcomp);
- *(end+=cmplen) = '.';
- ++end;
- }
- dirlen = end - dirptr;
- *end = '\0';
- return MPN_OK;
- }
- /*******************
- *** APPEND_NAME ***
- *******************/
- if ( function == APPEND_NAME )
- {
- if ( fcn & USE_DEFAULT )
- { /* Expand renamed filename using collected path, return
- * at pathcomp */
- fab = cc$rms_fab; /* Initialize FAB. */
- nam = CC_RMS_NAM; /* Initialize NAM[L]. */
- fab.FAB_NAM = &nam; /* Point FAB to NAM[L]. */
- #ifdef NAML$C_MAXRSS
- fab.fab$l_dna = (char *) -1; /* Using NAML for default name. */
- fab.fab$l_fna = (char *) -1; /* Using NAML for file name. */
- #endif /* NAML$C_MAXRSS */
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_DNA = pathptr;
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_DNS = end - pathptr;
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_FNA = G.filename;
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_FNS = strlen(G.filename);
- nam.NAM_ESA = pathcomp; /* (Great design. ---v. SMS.) */
- nam.NAM_ESS = NAM_MAXRSS; /* Assume large enough. */
- if (!OK(status = sys$parse(&fab)) && status == RMS$_DNF )
- /* Directory not found: */
- { /* ... try to create it */
- char save;
- char *dirend;
- int mkdir_failed;
- dirend = (char*)nam.NAM_L_DIR + nam.NAM_B_DIR;
- save = *dirend;
- *dirend = '\0';
- if ( (mkdir_failed = mkdir(nam.NAM_L_DEV, 0)) &&
- errno == EEXIST )
- mkdir_failed = 0;
- *dirend = save;
- if ( mkdir_failed )
- return 3;
- created_dir = TRUE;
- } /* if (sys$parse... */
- pathcomp[nam.NAM_ESL] = '\0';
- return MPN_OK;
- } /* if (USE_DEFAULT) */
- else
- {
- *end = '\0';
- if ( dirlen )
- {
- dirptr[dirlen-1] = ']'; /* Close directory */
- /*
- * Try to create the target directory.
- * Don't waste time creating directory that was created
- * last time.
- */
- if ( STRICMP(lastdir, pathbuf) )
- {
- mkdir_failed = 0;
- if ( mkdir(pathbuf, 0) )
- {
- if ( errno != EEXIST )
- mkdir_failed = 1; /* Mine for GETPATH */
- }
- else
- created_dir = TRUE;
- strcpy(lastdir, pathbuf);
- }
- }
- else
- { /*
- * Target directory unspecified.
- * Try to create "SYS$DISK:[]"
- */
- if ( strcmp(lastdir, PATH_DEFAULT) )
- {
- strcpy(lastdir, PATH_DEFAULT);
- mkdir_failed = 0;
- if ( mkdir(lastdir, 0) && errno != EEXIST )
- mkdir_failed = 1; /* Mine for GETPATH */
- }
- }
- if ( strlen(pathcomp) + (end-pathbuf) > 255 )
- return MPN_INF_TRUNC;
- strcpy(end, pathcomp);
- end += strlen(pathcomp);
- return MPN_OK;
- }
- }
- /***************
- *** GETPATH ***
- ***************/
- if ( function == GETPATH )
- {
- if ( mkdir_failed )
- return MPN_ERR_SKIP;
- *end = '\0'; /* To be safe */
- strcpy( pathcomp, pathbuf );
- return MPN_OK;
- }
- /***********
- *** END ***
- ***********/
- if ( function == END )
- {
- Trace((stderr, "checkdir(): nothing to free...\n"));
- rootlen = 0;
- return MPN_OK;
- }
- return MPN_INVALID; /* should never reach */
- }
- int check_for_newer(__G__ filenam) /* return 1 if existing file newer or */
- __GDEF /* equal; 0 if older; -1 if doesn't */
- char *filenam; /* exist yet */
- {
- #ifdef USE_EF_UT_TIME
- iztimes z_utime;
- struct tm *t;
- #endif
- char *filenam_stat;
- unsigned short timbuf[7];
- unsigned dy, mo, yr, hh, mm, ss, dy2, mo2, yr2, hh2, mm2, ss2;
- struct FAB fab;
- struct XABDAT xdat;
- #ifdef NAML$C_MAXRSS
- struct NAM_STRUCT nam;
- #endif
- /* 2008-07-12 SMS.
- * Special case for "." as a file name, not as the current directory.
- * Substitute ".;" to keep stat() from seeing a plain ".".
- */
- if (strcmp(filenam, ".") == 0)
- filenam_stat = ".;";
- else
- filenam_stat = filenam;
- if (stat(filenam_stat, &G.statbuf))
- return DOES_NOT_EXIST;
- fab = cc$rms_fab; /* Initialize FAB. */
- xdat = cc$rms_xabdat; /* Initialize XAB. */
- #ifdef NAML$C_MAXRSS
- nam = CC_RMS_NAM; /* Initialize NAM[L]. */
- fab.FAB_NAM = &nam; /* Point FAB to NAM[L]. */
- fab.fab$l_dna = (char *) -1; /* Using NAML for default name. */
- fab.fab$l_fna = (char *) -1; /* Using NAML for file name. */
- #endif /* NAML$C_MAXRSS */
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_FNA = filenam;
- FAB_OR_NAML(fab, nam).FAB_OR_NAML_FNS = strlen(filenam);
- fab.fab$l_xab = (char *) &xdat;
- fab.fab$l_fop = FAB$M_GET | FAB$M_UFO;
- if (ERR(sys$open(&fab))) /* open failure: report exists and */
- return EXISTS_AND_OLDER; /* older so new copy will be made */
- sys$numtim(&timbuf, &xdat.xab$q_cdt);
- fab.fab$l_xab = NULL;
- sys$dassgn(fab.fab$l_stv);
- sys$close(&fab); /* be sure file is closed and RMS knows about it */
- #ifdef USE_EF_UT_TIME
- if (G.extra_field &&
- #ifdef IZ_CHECK_TZ
- G.tz_is_valid &&
- #endif
- (ef_scan_for_izux(G.extra_field, G.lrec.extra_field_length, 0,
- G.lrec.last_mod_dos_datetime, &z_utime, NULL)
- & EB_UT_FL_MTIME))
- t = localtime(&(z_utime.mtime));
- else
- t = (struct tm *)NULL;
- if (t != (struct tm *)NULL)
- {
- yr2 = (unsigned)(t->tm_year) + 1900;
- mo2 = (unsigned)(t->tm_mon) + 1;
- dy2 = (unsigned)(t->tm_mday);
- hh2 = (unsigned)(t->tm_hour);
- mm2 = (unsigned)(t->tm_min);
- ss2 = (unsigned)(t->tm_sec);
- /* round to nearest sec--may become 60,
- but doesn't matter for compare */
- ss = (unsigned)((float)timbuf[5] + (float)timbuf[6]*.01 + 0.5);
- TTrace((stderr, "check_for_newer: using Unix extra field mtime\n"));
- }
- else
- #endif /* USE_EF_UT_TIME */
- {
- yr2 = ((G.lrec.last_mod_dos_datetime >> 25) & 0x7f) + 1980;
- mo2 = (G.lrec.last_mod_dos_datetime >> 21) & 0x0f;
- dy2 = (G.lrec.last_mod_dos_datetime >> 16) & 0x1f;
- hh2 = (G.lrec.last_mod_dos_datetime >> 11) & 0x1f;
- mm2 = (G.lrec.last_mod_dos_datetime >> 5) & 0x3f;
- ss2 = (G.lrec.last_mod_dos_datetime << 1) & 0x1f;
- /* round to nearest 2 secs--may become 60,
- but doesn't matter for compare */
- ss = (unsigned)((float)timbuf[5] + (float)timbuf[6]*.01 + 1.) & (~1);
- }
- yr = timbuf[0];
- mo = timbuf[1];
- dy = timbuf[2];
- hh = timbuf[3];
- mm = timbuf[4];
- if (yr > yr2)
- return EXISTS_AND_NEWER;
- else if (yr < yr2)
- return EXISTS_AND_OLDER;
- if (mo > mo2)
- return EXISTS_AND_NEWER;
- else if (mo < mo2)
- return EXISTS_AND_OLDER;
- if (dy > dy2)
- return EXISTS_AND_NEWER;
- else if (dy < dy2)
- return EXISTS_AND_OLDER;
- if (hh > hh2)
- return EXISTS_AND_NEWER;
- else if (hh < hh2)
- return EXISTS_AND_OLDER;
- if (mm > mm2)
- return EXISTS_AND_NEWER;
- else if (mm < mm2)
- return EXISTS_AND_OLDER;
- if (ss >= ss2)
- return EXISTS_AND_NEWER;
- return EXISTS_AND_OLDER;
- }
- #ifdef RETURN_CODES
- void return_VMS(__G__ err)
- __GDEF
- #else
- void return_VMS(err)
- #endif
- int err;
- {
- int severity;
- #ifdef RETURN_CODES
- /*---------------------------------------------------------------------------
- Do our own, explicit processing of error codes and print message, since
- VMS misinterprets return codes as rather obnoxious system errors ("access
- violation," for example).
- ---------------------------------------------------------------------------*/
- switch (err) {
- case PK_COOL:
- break; /* life is fine... */
- case PK_WARN:
- Info(slide, 1, ((char *)slide, "\n\
- [return-code %d: warning error \
- (e.g., failed CRC or unknown compression method)]\n", err));
- break;
- case PK_ERR:
- case PK_BADERR:
- Info(slide, 1, ((char *)slide, "\n\
- [return-code %d: error in zipfile \
- (e.g., cannot find local file header sig)]\n", err));
- break;
- case PK_MEM:
- case PK_MEM2:
- case PK_MEM3:
- case PK_MEM4:
- case PK_MEM5:
- Info(slide, 1, ((char *)slide,
- "\n[return-code %d: insufficient memory]\n", err));
- break;
- case PK_NOZIP:
- Info(slide, 1, ((char *)slide,
- "\n[return-code %d: zipfile not found]\n", err));
- break;
- case PK_PARAM: /* exit(PK_PARAM); gives "access violation" */
- Info(slide, 1, ((char *)slide, "\n\
- [return-code %d: bad or illegal parameters specified on command line]\n",
- err));
- break;
- case PK_FIND:
- Info(slide, 1, ((char *)slide,
- "\n[return-code %d: no files found to extract/view/etc.]\n",
- err));
- break;
- case PK_DISK:
- Info(slide, 1, ((char *)slide,
- "\n[return-code %d: disk full or other I/O error]\n", err));
- break;
- case PK_EOF:
- Info(slide, 1, ((char *)slide, "\n\
- [return-code %d: unexpected EOF in zipfile (i.e., truncated)]\n", err));
- break;
- case IZ_CTRLC:
- Info(slide, 1, ((char *)slide,
- "\n[return-code %d: you hit ctrl-C to terminate]\n", err));
- break;
- case IZ_UNSUP:
- Info(slide, 1, ((char *)slide, "\n\
- [return-code %d: unsupported compression or encryption for all files]\n",
- err));
- break;
- case IZ_BADPWD:
- Info(slide, 1, ((char *)slide,
- "\n[return-code %d: bad decryption password for all files]\n",
- err));
- break;
- #ifdef DO_SAFECHECK_2GB
- case IZ_ERRBF:
- Info(slide, 1, ((char *)slide,
- "\n[return-code %d: big-file archive, small-file program]\n",
- err));
- break;
- #endif /* DO_SAFECHECK_2GB */
- default:
- Info(slide, 1, ((char *)slide,
- "\n[return-code %d: unknown return-code (screw-up)]\n", err));
- break;
- }
- #endif /* RETURN_CODES */
- /*---------------------------------------------------------------------------
- * Return an intelligent status/severity level:
- *
- * 2007-01-29 SMS.
- *
- * VMS Status Code Summary (See STSDEF.H for details.)
- *
- * Bits: 31:28 27:16 15:3 2 1 0
- * Field: Control Facility Message Severity
- * -----
- * 0 0 0 0 Warning
- * 0 0 1 1 Success
- * 0 1 0 2 Error
- * 0 1 1 3 Information
- * 1 0 0 4 Severe (fatal) error
- *
- * In the Control field, bits 31:29 are reserved. Bit 28 inhibits
- * printing the message. In the Facility field, bit 27 means
- * customer-defined (not HP-assigned, like us). In the Message field,
- * bit 15 means facility-specific (which our messages are).
- *
- * Note that the C library translates exit(0) to a $STATUS value of 1
- * (i.e., exit is both silent and has a $SEVERITY of "success").
- *
- * Previous versions of Info-ZIP programs used a generic ("chosen (by
- * experimentation)") Control+Facility code of 0x7FFF, which included
- * some reserved control bits, the inhibit-printing bit, and the
- * customer-defined bit.
- *
- * HP has now assigned official Facility names and corresponding
- * Facility codes for the Info-ZIP products:
- *
- * Facility Name Facility Code
- * IZ_UNZIP 1954 = 0x7A2
- * IZ_ZIP 1955 = 0x7A3
- *
- * Now, unless the CTL_FAC_IZ_UZP macro is defined at build-time, we
- * will use the official Facility code.
- *
- ---------------------------------------------------------------------------*/
- /* Official HP-assigned Info-ZIP UnZip Facility code. */
- #define FAC_IZ_UZP 1954 /* 0x7A2 */
- #ifndef CTL_FAC_IZ_UZP
- /*
- * Default is inhibit-printing with the official Facility code.
- */
- # define CTL_FAC_IZ_UZP ((0x1 << 12) | FAC_IZ_UZP)
- # define MSG_FAC_SPEC 0x8000 /* Facility-specific code. */
- #else /* CTL_FAC_IZ_UZP */
- /* Use the user-supplied Control+Facility code for err or warn. */
- # ifndef MSG_FAC_SPEC /* Old default is not Facility-specific. */
- # define MSG_FAC_SPEC 0x0 /* Facility-specific code. Or 0x8000. */
- # endif /* !MSG_FAC_SPEC */
- #endif /* ?CTL_FAC_IZ_ZIP */
- #define VMS_UZ_FAC_BITS ((CTL_FAC_IZ_UZP << 16) | MSG_FAC_SPEC)
- severity = (err == PK_WARN) ? 0 : /* warn */
- (err == PK_ERR || /* error */
- (err >= PK_NOZIP && err <= PK_FIND) || /* ... */
- (err >= IZ_CTRLC && err <= IZ_BADPWD)) ? 2 : /* ... */
- 4; /* fatal */
- exit( /* $SEVERITY: */
- (err == PK_COOL) ? SS$_NORMAL : /* success */
- (VMS_UZ_FAC_BITS | (err << 4) | severity) /* warning, error, fatal */
- );
- } /* end function return_VMS() */
- #ifdef MORE
- static int scrnlines = -1;
- static int scrncolumns = -1;
- static int scrnwrap = -1;
- static int getscreeninfo(int *tt_rows, int *tt_cols, int *tt_wrap)
- {
- /*
- * For VMS v5.x:
- * IO$_SENSEMODE/SETMODE info: Programming, Vol. 7A, System Programming,
- * I/O User's: Part I, sec. 8.4.1.1, 8.4.3, 8.4.5, 8.6
- * sys$assign(), sys$qio() info: Programming, Vol. 4B, System Services,
- * System Services Reference Manual, pp. sys-23, sys-379
- * fixed-length descriptor info: Programming, Vol. 3, System Services,
- * Intro to System Routines, sec. 2.9.2
- * GRR, 15 Aug 91 / SPC, 07 Aug 1995, 14 Nov 1999
- */
- #ifndef OUTDEVICE_NAME
- #define OUTDEVICE_NAME "SYS$OUTPUT"
- #endif
- static ZCONST struct dsc$descriptor_s OutDevDesc =
- {(sizeof(OUTDEVICE_NAME) - 1), DSC$K_DTYPE_T, DSC$K_CLASS_S,
- OUTDEVICE_NAME};
- /* {dsc$w_length, dsc$b_dtype, dsc$b_class, dsc$a_pointer}; */
- short OutDevChan, iosb[4];
- long status;
- struct tt_characts
- {
- uch class, type;
- ush pagewidth;
- union {
- struct {
- uch ttcharsbits[3];
- uch pagelength;
- } ttdef_bits;
- unsigned ttcharflags;
- } ttdef_area;
- } ttmode; /* total length = 8 bytes */
- /* assign a channel to standard output */
- status = sys$assign(&OutDevDesc, &OutDevChan, 0, 0);
- if (OK(status))
- {
- /* use sys$qiow and the IO$_SENSEMODE function to determine
- * the current tty status.
- */
- status = sys$qiow(0, OutDevChan, IO$_SENSEMODE, &iosb, 0, 0,
- &ttmode, sizeof(ttmode), 0, 0, 0, 0);
- /* deassign the output channel by way of clean-up */
- (void) sys$dassgn(OutDevChan);
- }
- if ( OK(status) && OK(status = iosb[0]) ) {
- if (tt_rows != NULL)
- *tt_rows = ( (ttmode.ttdef_area.ttdef_bits.pagelength >= 5)
- ? (int) (ttmode.ttdef_area.ttdef_bits.pagelength)
- /* TT device value */
- : (24) ); /* VT 100 default */
- if (tt_cols != NULL)
- *tt_cols = ( (ttmode.pagewidth >= 10)
- ? (int) (ttmode.pagewidth) /* TT device value */
- : (80) ); /* VT 100 default */
- if (tt_wrap != NULL)
- *tt_wrap = ((ttmode.ttdef_area.ttcharflags & TT$M_WRAP) != 0);
- } else {
- /* VT 100 defaults */
- if (tt_rows != NULL)
- *tt_rows = 24;
- if (tt_cols != NULL)
- *tt_cols = 80;
- if (tt_wrap != NULL)
- *tt_wrap = FALSE;
- }
- return (OK(status));
- }
- int screensize(int *tt_rows, int *tt_cols)
- {
- if (scrnlines < 0 || scrncolumns < 0)
- getscreeninfo(&scrnlines, &scrncolumns, &scrnwrap);
- if (tt_rows != NULL) *tt_rows = scrnlines;
- if (tt_cols != NULL) *tt_cols = scrncolumns;
- return !(scrnlines > 0 && scrncolumns > 0);
- }
- int screenlinewrap()
- {
- if (scrnwrap == -1)
- getscreeninfo(&scrnlines, &scrncolumns, &scrnwrap);
- return (scrnwrap);
- }
- #endif /* MORE */
- #ifndef SFX
- /************************/
- /* Function version() */
- /************************/
- /* 2004-11-23 SMS.
- * Changed to include the "-x" part of the VMS version.
- * Added the IA64 system type name.
- * Prepared for VMS versions after 9. (We should live so long.)
- */
- void version(__G)
- __GDEF
- {
- int len;
- #ifdef VMS_VERSION
- char *chrp1;
- char *chrp2;
- char buf[40];
- char vms_vers[16];
- int ver_maj;
- #endif
- #ifdef __DECC_VER
- char buf2[40];
- int vtyp;
- #endif
- #ifdef VMS_VERSION
- /* Truncate the version string at the first (trailing) space. */
- strncpy(vms_vers, VMS_VERSION, sizeof(vms_vers));
- vms_vers[sizeof(vms_vers)-1] = '\0';
- chrp1 = strchr(vms_vers, ' ');
- if (chrp1 != NULL)
- *chrp1 = '\0';
- /* Determine the major version number. */
- ver_maj = 0;
- chrp1 = strchr(&vms_vers[1], '.');
- for (chrp2 = &vms_vers[1];
- chrp2 < chrp1;
- ver_maj = ver_maj * 10 + *(chrp2++) - '0');
- #endif /* VMS_VERSION */
- /* DEC C in ANSI mode does not like "#ifdef MACRO" inside another
- macro when MACRO is equated to a value (by "#define MACRO 1"). */
- len = sprintf((char *)slide, LoadFarString(CompiledWith),
- #ifdef __GNUC__
- "gcc ", __VERSION__,
- #else
- # if defined(DECC) || defined(__DECC) || defined (__DECC__)
- "DEC C",
- # ifdef __DECC_VER
- (sprintf(buf2, " %c%d.%d-%03d",
- ((vtyp = (__DECC_VER / 10000) % 10) == 6 ? 'T' :
- (vtyp == 8 ? 'S' : 'V')),
- __DECC_VER / 10000000,
- (__DECC_VER % 10000000) / 100000, __DECC_VER % 1000), buf2),
- # else
- "",
- # endif
- # else
- # ifdef VAXC
- "VAX C", "",
- # else
- "unknown compiler", "",
- # endif
- # endif
- #endif
- #ifdef VMS_VERSION
- # if defined(__alpha)
- "OpenVMS",
- (sprintf(buf, " (%s Alpha)", vms_vers), buf),
- # elif defined(__ia64)
- "OpenVMS",
- (sprintf(buf, " (%s IA64)", vms_vers), buf),
- # else /* VAX */
- (ver_maj >= 6) ? "OpenVMS" : "VMS",
- (sprintf(buf, " (%s VAX)", vms_vers), buf),
- # endif
- #else
- "VMS",
- "",
- #endif /* ?VMS_VERSION */
- #ifdef __DATE__
- " on ", __DATE__
- #else
- "", ""
- #endif
- );
- (*G.message)((zvoid *)&G, slide, (ulg)len, 0);
- } /* end function version() */
- #endif /* !SFX */
- #ifdef __DECC
- /* 2004-11-20 SMS.
- *
- * acc_cb(), access callback function for DEC C open().
- *
- * Set some RMS FAB/RAB items, with consideration of user-specified
- * values from (DCL) SET RMS_DEFAULT. Items of particular interest are:
- *
- * fab$w_deq default extension quantity (blocks) (write).
- * rab$b_mbc multi-block count.
- * rab$b_mbf multi-buffer count (used with rah and wbh).
- *
- * See also the OPEN* macros in VMSCFG.H. Currently, no notice is
- * taken of the caller-ID value, but options could be set differently
- * for read versus write access. (I assume that specifying fab$w_deq,
- * for example, for a read-only file has no ill effects.)
- */
- /* Global storage. */
- int openr_id = OPENR_ID; /* Callback id storage, read. */
- /* acc_cb() */
- int acc_cb(int *id_arg, struct FAB *fab, struct RAB *rab)
- {
- int sts;
- /* Get process RMS_DEFAULT values, if not already done. */
- if (rms_defaults_known == 0)
- {
- get_rms_defaults();
- }
- /* If RMS_DEFAULT (and adjusted active) values are available, then set
- * the FAB/RAB parameters. If RMS_DEFAULT values are not available,
- * suffer with the default parameters.
- */
- if (rms_defaults_known > 0)
- {
- /* Set the FAB/RAB parameters accordingly. */
- fab-> fab$w_deq = rms_ext_active;
- rab-> rab$b_mbc = rms_mbc_active;
- rab-> rab$b_mbf = rms_mbf_active;
- /* Truncate at EOF on close, as we'll probably over-extend. */
- fab-> fab$v_tef = 1;
- /* If using multiple buffers, enable read-ahead and write-behind. */
- if (rms_mbf_active > 1)
- {
- rab-> rab$v_rah = 1;
- rab-> rab$v_wbh = 1;
- }
- if (DIAG_FLAG)
- {
- fprintf(stderr,
- "Open callback. ID = %d, deq = %6d, mbc = %3d, mbf = %3d.\n",
- *id_arg, fab-> fab$w_deq, rab-> rab$b_mbc, rab-> rab$b_mbf);
- }
- }
- /* Declare success. */
- return 0;
- }
- /*
- * 2004-09-19 SMS.
- *
- *----------------------------------------------------------------------
- *
- * decc_init()
- *
- * On non-VAX systems, uses LIB$INITIALIZE to set a collection of C
- * RTL features without using the DECC$* logical name method.
- *
- *----------------------------------------------------------------------
- */
- #ifdef __CRTL_VER
- #if !defined(__VAX) && (__CRTL_VER >= 70301000)
- #include <unixlib.h>
- /*--------------------------------------------------------------------*/
- /* Global storage. */
- /* Flag to sense if decc_init() was called. */
- static int decc_init_done = -1;
- /*--------------------------------------------------------------------*/
- /* decc_init()
- Uses LIB$INITIALIZE to set a collection of C RTL features without
- requiring the user to define the corresponding logical names.
- */
- /* Structure to hold a DECC$* feature name and its desired value. */
- typedef struct
- {
- char *name;
- int value;
- } decc_feat_t;
- /* Array of DECC$* feature names and their desired values. */
- decc_feat_t decc_feat_array[] = {
- /* Preserve command-line case with SET PROCESS/PARSE_STYLE=EXTENDED */
- { "DECC$ARGV_PARSE_STYLE", 1 },
- /* Preserve case for file names on ODS5 disks. */
- { "DECC$EFS_CASE_PRESERVE", 1 },
- /* Enable multiple dots (and most characters) in ODS5 file names,
- while preserving VMS-ness of ";version". */
- { "DECC$EFS_CHARSET", 1 },
- /* List terminator. */
- { (char *)NULL, 0 } };
- /* LIB$INITIALIZE initialization function. */
- static void decc_init(void)
- {
- int feat_index;
- int feat_value;
- int feat_value_max;
- int feat_value_min;
- int i;
- int sts;
- /* Set the global flag to indicate that LIB$INITIALIZE worked. */
- decc_init_done = 1;
- /* Loop through all items in the decc_feat_array[]. */
- for (i = 0; decc_feat_array[i].name != NULL; i++)
- {
- /* Get the feature index. */
- feat_index = decc$feature_get_index(decc_feat_array[i].name);
- if (feat_index >= 0)
- {
- /* Valid item. Collect its properties. */
- feat_value = decc$feature_get_value(feat_index, 1);
- feat_value_min = decc$feature_get_value(feat_index, 2);
- feat_value_max = decc$feature_get_value(feat_index, 3);
- if ((decc_feat_array[i].value >= feat_value_min) &&
- (decc_feat_array[i].value <= feat_value_max))
- {
- /* Valid value. Set it if necessary. */
- if (feat_value != decc_feat_array[i].value)
- {
- sts = decc$feature_set_value(
- feat_index,
- 1,
- decc_feat_array[i].value);
- }
- }
- else
- {
- /* Invalid DECC feature value. */
- printf(" INVALID DECC FEATURE VALUE, %d: %d <= %s <= %d.\n",
- feat_value,
- feat_value_min, decc_feat_array[i].name, feat_value_max);
- }
- }
- else
- {
- /* Invalid DECC feature name. */
- printf(" UNKNOWN DECC FEATURE: %s.\n", decc_feat_array[i].name);
- }
- }
- }
- /* Get "decc_init()" into a valid, loaded LIB$INITIALIZE PSECT. */
- #pragma nostandard
- /* Establish the LIB$INITIALIZE PSECT, with proper alignment and
- attributes.
- */
- globaldef {"LIB$INITIALIZ"} readonly _align (LONGWORD)
- int spare[8] = { 0 };
- globaldef {"LIB$INITIALIZE"} readonly _align (LONGWORD)
- void (*x_decc_init)() = decc_init;
- /* Fake reference to ensure loading the LIB$INITIALIZE PSECT. */
- #pragma extern_model save
- /* The declaration for LIB$INITIALIZE() is missing in the VMS system header
- files. Addionally, the lowercase name "lib$initialize" is defined as a
- macro, so that this system routine can be reference in code using the
- traditional C-style lowercase convention of function names for readability.
- (VMS system functions declared in the VMS system headers are defined in a
- similar way to allow using lowercase names within the C code, whereas the
- "externally" visible names in the created object files are uppercase.)
- */
- #ifndef lib$initialize
- # define lib$initialize LIB$INITIALIZE
- #endif
- int lib$initialize(void);
- #pragma extern_model strict_refdef
- int dmy_lib$initialize = (int)lib$initialize;
- #pragma extern_model restore
- #pragma standard
- #endif /* !defined(__VAX) && (__CRTL_VER >= 70301000) */
- #endif /* __CRTL_VER */
- #endif /* __DECC */
- #endif /* VMS */
|