cpio.ck 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034
  1. /*++
  2. Copyright (c) 2017 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. cpio.ck
  9. Abstract:
  10. This module implements support for working with CPIO archives.
  11. Author:
  12. Evan Green 7-Jun-2017
  13. Environment:
  14. Chalk
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. from iobase import IoError;
  20. from io import IO_SEEK_SET, IO_SEEK_CUR, IO_SEEK_END, open;
  21. import os;
  22. from time import Time;
  23. //
  24. // ---------------------------------------------------------------- Definitions
  25. //
  26. //
  27. // Define the CPIO mode bits, in octal.
  28. //
  29. var CPIO_MODE_TYPE_MASK = 0170000;
  30. var CPIO_MODE_TYPE_SOCKET = 0140000;
  31. var CPIO_MODE_TYPE_SYMLINK = 0120000;
  32. var CPIO_MODE_TYPE_FILE = 0100000;
  33. var CPIO_MODE_TYPE_BLOCKDEV = 0060000;
  34. var CPIO_MODE_TYPE_DIRECTORY = 0040000;
  35. var CPIO_MODE_TYPE_CHARDEV = 0020000;
  36. var CPIO_MODE_TYPE_FIFO = 0010000;
  37. var CPIO_MODE_SUID = 0004000;
  38. var CPIO_MODE_SGID = 0002000;
  39. var CPIO_MODE_STICKY = 0001000;
  40. var CPIO_MODE_PERMISSIONS = 00000777;
  41. //
  42. // ----------------------------------------------- Internal Function Prototypes
  43. //
  44. //
  45. // -------------------------------------------------------------------- Globals
  46. //
  47. //
  48. // Define a table that helps convert a mode integer into a ls-style mode string.
  49. //
  50. var _fileModeTable = [
  51. [
  52. [CPIO_MODE_TYPE_SOCKET, "s"],
  53. [CPIO_MODE_TYPE_SYMLINK, "l"],
  54. [CPIO_MODE_TYPE_FILE, "-"],
  55. [CPIO_MODE_TYPE_BLOCKDEV, "b"],
  56. [CPIO_MODE_TYPE_DIRECTORY, "d"],
  57. [CPIO_MODE_TYPE_CHARDEV, "c"],
  58. [CPIO_MODE_TYPE_FIFO, "p"]
  59. ],
  60. [[0400, "r"],],
  61. [[0200, "w"],],
  62. [
  63. [0100 | CPIO_MODE_SUID, "s"],
  64. [CPIO_MODE_SUID, "S"],
  65. [0100, "x"]
  66. ],
  67. [[0040, "r"],],
  68. [[0020, "w"],],
  69. [
  70. [0010 | CPIO_MODE_SGID, "s"],
  71. [CPIO_MODE_SGID, "S"],
  72. [0010, "x"]
  73. ],
  74. [[0004, "r"],],
  75. [[0002, "w"],],
  76. [
  77. [0001 | CPIO_MODE_STICKY, "t"],
  78. [CPIO_MODE_STICKY, "T"],
  79. [0001, "x"]
  80. ]
  81. ];
  82. //
  83. // Define a table that helps get between OS file types and CPIO file types.
  84. //
  85. var _osFileTypes = {
  86. os.S_IFREG: CPIO_MODE_TYPE_FILE,
  87. os.S_IFDIR: CPIO_MODE_TYPE_DIRECTORY,
  88. os.S_IFBLK: CPIO_MODE_TYPE_BLOCKDEV,
  89. os.S_IFCHR: CPIO_MODE_TYPE_CHARDEV,
  90. os.S_IFLNK: CPIO_MODE_TYPE_SYMLINK,
  91. os.S_IFIFO: CPIO_MODE_TYPE_FIFO,
  92. os.S_IFSOCK: CPIO_MODE_TYPE_SOCKET
  93. };
  94. //
  95. // ------------------------------------------------------------------ Functions
  96. //
  97. class CpioFormatError is Exception {}
  98. class CpioEofError is Exception {}
  99. //
  100. // Define the CPIO member class, which describes a single member of a CPIO
  101. // archive.
  102. //
  103. class CpioMember {
  104. static
  105. function
  106. fromFile (
  107. file
  108. )
  109. /*++
  110. Routine Description:
  111. This routine creates a new CpioMember objects from the input file.
  112. Arguments:
  113. file - Supplies a file-like object to read from.
  114. Return Value:
  115. Returns the initialized object.
  116. --*/
  117. {
  118. var format;
  119. var magic = file.read(2);
  120. var member = CpioMember();
  121. if (magic.length() == 0) {
  122. Core.raise(CpioEofError());
  123. }
  124. //
  125. // Look at the magic field to determine the format.
  126. //
  127. if (magic == "\xC7\x71") {
  128. format = "bin";
  129. } else if (magic == "07") {
  130. magic += file.read(4);
  131. if (magic.length() < 6) {
  132. Core.raise(CpioFormatError("Magic truncated"));
  133. }
  134. if (magic == "070707") {
  135. format = "odc";
  136. } else if (magic == "070701") {
  137. format = "newc";
  138. } else if (magic == "070702") {
  139. format = "crc";
  140. }
  141. }
  142. if (format == "bin") {
  143. member._readBinaryHeader(file, format);
  144. } else if ((format == "odc") || (format == "newc") ||
  145. (format == "crc")) {
  146. member._readAsciiHeader(file, format);
  147. } else {
  148. Core.raise(CpioFormatError("Invalid CPIO header magic: \"%s\"" %
  149. magic));
  150. }
  151. //
  152. // If it's a symbolic link, read the link target now. Attribute that
  153. // read data to the header so the caller knows where the current file
  154. // position is.
  155. //
  156. if (member.isLink()) {
  157. member.link = file.read(member.size);
  158. if (member.link.length() != member.size) {
  159. Core.raise(CpioFormatError("Data truncated"));
  160. }
  161. member.headerSize += member.size;
  162. }
  163. return member;
  164. }
  165. function
  166. __init (
  167. )
  168. /*++
  169. Routine Description:
  170. This routine instantiates a new CpioMember class with an empty file
  171. name.
  172. Arguments:
  173. None.
  174. Return Value:
  175. Returns the initialized object.
  176. --*/
  177. {
  178. return this.__init("");
  179. }
  180. function
  181. __init (
  182. name
  183. )
  184. /*++
  185. Routine Description:
  186. This routine instantiates a new CpioMember class with the given
  187. archive member name.
  188. Arguments:
  189. name - Supplies the path of the member within the archive.
  190. Return Value:
  191. Returns the initialized object.
  192. --*/
  193. {
  194. this.name = name;
  195. this.devMajor = 0;
  196. this.devMinor = 0;
  197. this.mode = CPIO_MODE_TYPE_FILE;
  198. this.uid = 0;
  199. this.gid = 0;
  200. this.nlink = 1;
  201. this.rdevMajor = 0;
  202. this.rdevMinor = 0;
  203. this.mtime = Time.now().timestamp();
  204. this.size = 0;
  205. this.check = -1;
  206. return this;
  207. }
  208. function
  209. ls (
  210. verbose
  211. )
  212. /*++
  213. Routine Description:
  214. This routine returns a string containing a listing of the archive
  215. member.
  216. Arguments:
  217. verbose - Supplies a boolean indicating whether to print just the
  218. name, or a more ls -l type listing.
  219. Return Value:
  220. Returns a string describing the object.
  221. --*/
  222. {
  223. var bit;
  224. var found;
  225. var mode = this.mode;
  226. var modeString = "";
  227. var result = "";
  228. var modificationTime = Time.fromTimestamp(this.mtime, 0, null);
  229. if (!verbose) {
  230. return this.name;
  231. }
  232. if (verbose > 1) {
  233. result = "%8d" % [this.inode];
  234. }
  235. for (table in _fileModeTable) {
  236. found = false;
  237. for (element in table) {
  238. bit = element[0];
  239. if ((bit & mode) == bit) {
  240. modeString += element[1];
  241. found = true;
  242. break;
  243. }
  244. }
  245. if (!found) {
  246. modeString += "-";
  247. }
  248. }
  249. result += modeString +
  250. " %2d %5d %5d " % [this.nlink, this.uid, this.gid];
  251. if (this.isChr() || this.isBlk()) {
  252. result += "%8s" % ("%d,%d" % [this.devMajor, this.devMinor]);
  253. } else {
  254. result += "%8d" % this.size;
  255. }
  256. result += modificationTime.strftime(" %F %T ");
  257. result += this.name;
  258. return result;
  259. }
  260. function
  261. isFile (
  262. )
  263. /*++
  264. Routine Description:
  265. This routine returns true if the given info object is a regular file.
  266. Arguments:
  267. None.
  268. Return Value:
  269. true if the object is a regular file.
  270. false if the object is not a regular file.
  271. --*/
  272. {
  273. if ((this.mode & CPIO_MODE_TYPE_MASK) == CPIO_MODE_TYPE_FILE) {
  274. return true;
  275. }
  276. return false;
  277. }
  278. function
  279. isDir (
  280. )
  281. /*++
  282. Routine Description:
  283. This routine returns true if the given info object is a directory.
  284. Arguments:
  285. None.
  286. Return Value:
  287. true if the object is a directory.
  288. false if the object is not a directory.
  289. --*/
  290. {
  291. if ((this.mode & CPIO_MODE_TYPE_MASK) == CPIO_MODE_TYPE_DIRECTORY) {
  292. return true;
  293. }
  294. return false;
  295. }
  296. function
  297. isLink (
  298. )
  299. /*++
  300. Routine Description:
  301. This routine returns true if the given info object is a symbolic link.
  302. Arguments:
  303. None.
  304. Return Value:
  305. true if the object is a symbolic link.
  306. false if the object is not a symbolic link.
  307. --*/
  308. {
  309. if ((this.mode & CPIO_MODE_TYPE_MASK) == CPIO_MODE_TYPE_SYMLINK) {
  310. return true;
  311. }
  312. return false;
  313. }
  314. function
  315. isChr (
  316. )
  317. /*++
  318. Routine Description:
  319. This routine returns true if the given info object is a character
  320. device.
  321. Arguments:
  322. None.
  323. Return Value:
  324. true if the object is a character device.
  325. false if the object is not a character device.
  326. --*/
  327. {
  328. if ((this.mode & CPIO_MODE_TYPE_MASK) == CPIO_MODE_TYPE_CHARDEV) {
  329. return true;
  330. }
  331. return false;
  332. }
  333. function
  334. isBlk (
  335. )
  336. /*++
  337. Routine Description:
  338. This routine returns true if the given info object is a block
  339. device.
  340. Arguments:
  341. None.
  342. Return Value:
  343. true if the object is a block device.
  344. false if the object is not a block device.
  345. --*/
  346. {
  347. if ((this.mode & CPIO_MODE_TYPE_MASK) == CPIO_MODE_TYPE_BLOCKDEV) {
  348. return true;
  349. }
  350. return false;
  351. }
  352. function
  353. isFifo (
  354. )
  355. /*++
  356. Routine Description:
  357. This routine returns true if the given info object is a FIFO.
  358. Arguments:
  359. None.
  360. Return Value:
  361. true if the object is a FIFO.
  362. false if the object is not a FIFO.
  363. --*/
  364. {
  365. if ((this.mode & CPIO_MODE_TYPE_MASK) == CPIO_MODE_TYPE_FIFO) {
  366. return true;
  367. }
  368. return false;
  369. }
  370. function
  371. isDev (
  372. )
  373. /*++
  374. Routine Description:
  375. This routine returns true if the given info object is a FIFO, block
  376. device, or character device.
  377. Arguments:
  378. None.
  379. Return Value:
  380. true if the object is a special device of some kind.
  381. false if the object is a regular file, directory, or symbolic link.
  382. --*/
  383. {
  384. var type = this.mode & CPIO_MODE_TYPE_MASK;
  385. if ((type == CPIO_MODE_TYPE_FIFO) ||
  386. (type == CPIO_MODE_TYPE_BLOCKDEV) ||
  387. (type == CPIO_MODE_TYPE_CHARDEV)) {
  388. return true;
  389. }
  390. return false;
  391. }
  392. function
  393. write (
  394. inFile,
  395. outFile
  396. )
  397. /*++
  398. Routine Description:
  399. This routine writes the given member out to an archive.
  400. Arguments:
  401. inFile - Supplies an optional file object to write out as the data
  402. contents. This only applies to regular files.
  403. outFile - Supplies the file object to write the data out to.
  404. Return Value:
  405. None on success.
  406. An exception is raised on error.
  407. --*/
  408. {
  409. var format = this.format;
  410. if (format == "bin") {
  411. this._writeBinaryMember(inFile, outFile);
  412. } else if (format == "odc") {
  413. this._writeOldAsciiMember(inFile, outFile);
  414. } else {
  415. this._writeNewAsciiMember(format, inFile, outFile);
  416. }
  417. return;
  418. }
  419. function
  420. _readBinaryHeader (
  421. file,
  422. format
  423. )
  424. /*++
  425. Routine Description:
  426. This routine instantiates the member with the values from a binary
  427. header.
  428. Arguments:
  429. file - Supplies the file object, positioned just after the magic field.
  430. format - Supplies the format, which should just be "bin".
  431. Return Value:
  432. None. The fields are set in the object.
  433. --*/
  434. {
  435. var bytes = [];
  436. var data = file.read(24);
  437. var nameSize;
  438. var totalSize;
  439. if (data.length() != 24) {
  440. Core.raise(CpioFormatError("Header truncated"));
  441. }
  442. //
  443. // Convert all the bytes to numbers.
  444. //
  445. for (index in 0..24) {
  446. bytes.append(data.byteAt(index));
  447. }
  448. this.format = format;
  449. this.devMajor = 0;
  450. this.devMinor = bytes[0] + (bytes[1] << 8);
  451. this.inode = bytes[2] + (bytes[3] << 8);
  452. this.mode = bytes[4] + (bytes[5] << 8);
  453. this.uid = bytes[6] + (bytes[7] << 8);
  454. this.gid = bytes[8] + (bytes[9] << 8);
  455. this.nlink = bytes[10] + (bytes[11] << 8);
  456. this.rdevMajor = 0;
  457. this.rdevMinor = bytes[12] + (bytes[13] << 8);
  458. //
  459. // For the modification time, the most significant 16 bits are stored
  460. // first. Each 16-bit word is stored in native endian order.
  461. //
  462. this.mtime = ((bytes[14] + (bytes[15] << 8)) << 16) +
  463. bytes[16] + (bytes[17] << 8);
  464. nameSize = bytes[18] + (bytes[19] << 8);
  465. this.size = ((bytes[20] + (bytes[21] << 8)) << 16) +
  466. bytes[22] + (bytes[23] << 8);
  467. //
  468. // The name size includes a null terminating byte. If the name size is
  469. // odd, an extra byte of padding is added.
  470. //
  471. this.headerSize = 26 + nameSize;
  472. this.name = file.read(nameSize)[0..-1];
  473. if ((nameSize & 0x1) != 0) {
  474. file.read(1);
  475. this.headerSize += 1;
  476. }
  477. totalSize = this.headerSize + this.size;
  478. if ((totalSize & 0x1) != 0) {
  479. totalSize += 1;
  480. }
  481. this.archiveSize = totalSize;
  482. this.check = -1;
  483. return;
  484. }
  485. function
  486. _readAsciiHeader (
  487. file,
  488. format
  489. )
  490. /*++
  491. Routine Description:
  492. This routine instantiates the member with the values from an ASCII
  493. header.
  494. Arguments:
  495. file - Supplies the file object, positioned just after the magic field.
  496. format - Supplies the format, which should just be either "odc", "newc",
  497. or "crc".
  498. Return Value:
  499. None. The fields are set in the object.
  500. --*/
  501. {
  502. var check;
  503. var devMajor = "0";
  504. var devMinor;
  505. var fileSize;
  506. var gid;
  507. var header;
  508. var headerSize;
  509. var inode;
  510. var mode;
  511. var mtime;
  512. var nameSize;
  513. var nlink;
  514. var prefix;
  515. var rdevMajor = "0";
  516. var rdevMinor;
  517. var remainder;
  518. var totalSize;
  519. var uid;
  520. if (format == "odc") {
  521. prefix = "0";
  522. headerSize = 76;
  523. header = file.read(70);
  524. if (header.length() != 70) {
  525. Core.raise(CpioFormatError("Header truncated"));
  526. }
  527. devMinor = header[0..6];
  528. inode = header[6..12];
  529. mode = header[12..18];
  530. uid = header[18..24];
  531. gid = header[24..30];
  532. nlink = header[30..36];
  533. rdevMinor = header[36..42];
  534. mtime = header[42..53];
  535. nameSize = header[53..59];
  536. fileSize = header[59..70];
  537. nameSize = Int.fromString(prefix + nameSize);
  538. headerSize += nameSize;
  539. //
  540. // The old format contains no padding.
  541. //
  542. remainder = 0;
  543. } else {
  544. prefix = "0x";
  545. headerSize = 110;
  546. header = file.read(104);
  547. if (header.length() != 104) {
  548. Core.raise(CpioFormatError("Header truncated"));
  549. }
  550. inode = header[0..8];
  551. mode = header[8..16];
  552. uid = header[16..24];
  553. gid = header[24..32];
  554. nlink = header[32..40];
  555. mtime = header[40..48];
  556. fileSize = header[48..56];
  557. devMajor = header[56..64];
  558. devMinor = header[64..72];
  559. rdevMajor = header[72..80];
  560. rdevMinor = header[80..88];
  561. nameSize = header[88..96];
  562. check = header[96..104];
  563. nameSize = Int.fromString(prefix + nameSize);
  564. headerSize += nameSize;
  565. //
  566. // The new ASCII format's name is padded with null bytes to reach
  567. // a multiple of 4.
  568. //
  569. remainder = headerSize % 4;
  570. }
  571. this.format = format;
  572. this.inode = Int.fromString(prefix + inode);
  573. this.mode = Int.fromString(prefix + mode);
  574. this.uid = Int.fromString(prefix + uid);
  575. this.gid = Int.fromString(prefix + gid);
  576. this.nlink = Int.fromString(prefix + nlink);
  577. this.mtime = Int.fromString(prefix + mtime);
  578. this.size = Int.fromString(prefix + fileSize);
  579. this.devMajor = Int.fromString(prefix + devMajor);
  580. this.devMinor = Int.fromString(prefix + devMinor);
  581. this.rdevMajor = Int.fromString(prefix + rdevMajor);
  582. this.rdevMinor = Int.fromString(prefix + rdevMinor);
  583. if ((check != null) && (format == "crc")) {
  584. this.check = Int.fromString(prefix + check);
  585. } else {
  586. this.check = -1;
  587. }
  588. this.name = file.read(nameSize)[0..-1];
  589. if (this.name.length() != nameSize - 1) {
  590. Core.raise(CpioFormatError("File name truncated"));
  591. }
  592. //
  593. // The archive is padded with null bytes such that the fixed header
  594. // plus the name size plus the padding bytes is a multiple of 4.
  595. //
  596. if (remainder != 0) {
  597. remainder = 4 - remainder;
  598. file.read(remainder);
  599. headerSize += remainder;
  600. }
  601. totalSize = headerSize + this.size;
  602. //
  603. // The new ASCII format's file data is also padded out to a multiple
  604. // of 4.
  605. //
  606. if (format != "odc") {
  607. if ((totalSize % 4) != 0) {
  608. totalSize += 4 - (totalSize % 4);
  609. }
  610. }
  611. this.headerSize = headerSize;
  612. this.archiveSize = totalSize;
  613. return;
  614. }
  615. function
  616. _writeBinaryMember (
  617. inFile,
  618. outFile
  619. )
  620. /*++
  621. Routine Description:
  622. This routine writes out a member in binary format.
  623. Arguments:
  624. inFile - Supplies the file to read from.
  625. outFile - Supplies the file to write out to.
  626. Return Value:
  627. Returns the binary header string corresponding to this instance.
  628. --*/
  629. {
  630. var link;
  631. var max = 0xFFFF;
  632. var max2 = 0xFFFFFFFF;
  633. var nameSize = this.name.length() + 1;
  634. var result;
  635. if ((this.devMajor != 0) ||
  636. (this.devMinor > max) ||
  637. (this.inode > max) || (this.mode > max) || (this.uid > max) ||
  638. (this.gid > max) || (this.nlink > max) || (this.rdevMajor != 0) ||
  639. (this.rdevMinor > max) || (this.mtime > max2) ||
  640. (nameSize > max) || (this.size > max2)) {
  641. Core.raise(CpioFormatError("Header value too big for format"));
  642. }
  643. result = ["\xC7",
  644. "\x71",
  645. String.fromByte(this.devMinor & 0xFF),
  646. String.fromByte((this.devMinor >> 8) & 0xFF),
  647. String.fromByte(this.inode & 0xFF),
  648. String.fromByte((this.inode >> 8) & 0xFF),
  649. String.fromByte(this.mode & 0xFF),
  650. String.fromByte((this.mode >> 8) & 0xFF),
  651. String.fromByte(this.uid & 0xFF),
  652. String.fromByte((this.uid >> 8) & 0xFF),
  653. String.fromByte(this.gid & 0xFF),
  654. String.fromByte((this.gid >> 8) & 0xFF),
  655. String.fromByte(this.nlink & 0xFF),
  656. String.fromByte((this.nlink >> 8) & 0xFF),
  657. String.fromByte(this.rdevMajor & 0xFF),
  658. String.fromByte((this.rdevMinor >> 8) & 0xFF),
  659. String.fromByte((this.mtime >> 16) & 0xFF),
  660. String.fromByte((this.mtime >> 24) & 0xFF),
  661. String.fromByte(this.mtime & 0xFF),
  662. String.fromByte((this.mtime >> 8) & 0xFF),
  663. String.fromByte(nameSize & 0xFF),
  664. String.fromByte((nameSize >> 8) & 0xFF),
  665. String.fromByte((this.size >> 16) & 0xFF),
  666. String.fromByte((this.size >> 24) & 0xFF),
  667. String.fromByte(this.size & 0xFF),
  668. String.fromByte((this.size >> 8) & 0xFF),
  669. this.name,
  670. "\0"];
  671. result = "".join(result);
  672. if ((result.length() & 0x1) != 0) {
  673. result += "\0";
  674. }
  675. this.headerSize = result.length();
  676. outFile.write(result);
  677. if ((this.mode & CPIO_MODE_TYPE_MASK) == CPIO_MODE_TYPE_SYMLINK) {
  678. link = this.link;
  679. if (link.length() != this.size) {
  680. Core.raise(CpioFormatError("Member length %d does not match "
  681. "size of link '%s'" %
  682. [this.size, link]));
  683. }
  684. outFile.write(link);
  685. this.headerSize += link.length();
  686. this.archiveSize = this.headerSize;
  687. } else if ((this.mode & CPIO_MODE_TYPE_MASK) == CPIO_MODE_TYPE_FILE) {
  688. this._writeFileContents(inFile, outFile, this.size);
  689. this.archiveSize = this.headerSize + this.size;
  690. } else {
  691. if (this.size != 0) {
  692. Core.raise(CpioFormatError("Special device has non-zero size"));
  693. }
  694. this.archiveSize = this.headerSize;
  695. }
  696. if ((this.size & 0x1) != 0) {
  697. outFile.write("\0");
  698. this.archiveSize += 1;
  699. }
  700. return;
  701. }
  702. function
  703. _writeOldAsciiMember (
  704. inFile,
  705. outFile
  706. )
  707. /*++
  708. Routine Description:
  709. This routine writes out a member in ODC format.
  710. Arguments:
  711. inFile - Supplies the file to read from.
  712. outFile - Supplies the file to write out to.
  713. Return Value:
  714. Returns the binary header string corresponding to this instance.
  715. --*/
  716. {
  717. var link;
  718. var max = 0777777;
  719. var max2 = 077777777777;
  720. var nameSize = this.name.length() + 1;
  721. var result;
  722. if ((this.devMajor != 0) || (this.devMinor > max) ||
  723. (this.inode > max) || (this.mode > max) || (this.uid > max) ||
  724. (this.gid > max) || (this.nlink > max) || (this.rdevMajor != 0) ||
  725. (this.rdevMinor > max) || (this.mtime > max2) ||
  726. (nameSize > max) || (this.size > max2)) {
  727. Core.raise(CpioFormatError("Header value too big for format"));
  728. }
  729. result = "%06o%06o%06o%06o%06o%06o%06o%06o%011o%06o%011o" % [
  730. 070707,
  731. this.devMinor,
  732. this.inode,
  733. this.mode,
  734. this.uid,
  735. this.gid,
  736. this.nlink,
  737. this.rdevMinor,
  738. this.mtime,
  739. nameSize,
  740. this.size];
  741. result += this.name + "\0";
  742. outFile.write(result);
  743. this.headerSize = result.length();
  744. if ((this.mode & CPIO_MODE_TYPE_MASK) == CPIO_MODE_TYPE_SYMLINK) {
  745. link = this.link;
  746. if (link.length() != this.size) {
  747. Core.raise(CpioFormatError("Member length %d does not match "
  748. "size of link '%s'" %
  749. [this.size, link]));
  750. }
  751. outFile.write(link);
  752. this.headerSize += link.length();
  753. this.archiveSize = this.headerSize;
  754. } else if ((this.mode & CPIO_MODE_TYPE_MASK) == CPIO_MODE_TYPE_FILE) {
  755. this._writeFileContents(inFile, outFile, this.size);
  756. this.archiveSize = this.headerSize + this.size;
  757. } else {
  758. if (this.size != 0) {
  759. Core.raise(CpioFormatError("Special device has non-zero size"));
  760. }
  761. this.archiveSize = this.headerSize;
  762. }
  763. return;
  764. }
  765. function
  766. _writeNewAsciiMember (
  767. format,
  768. inFile,
  769. outFile
  770. )
  771. /*++
  772. Routine Description:
  773. This routine writes out a member in newc or crc format.
  774. Arguments:
  775. format - Supplies the desired format. Valid values are "newc" and "crc".
  776. inFile - Supplies the file to read from.
  777. outFile - Supplies the file to write out to.
  778. Return Value:
  779. Returns the binary header string corresponding to this instance.
  780. --*/
  781. {
  782. var check = this.check;
  783. var link;
  784. var magic = 070701;
  785. var max = 0xFFFFFFFF;
  786. var nameSize = this.name.length() + 1;
  787. var result;
  788. var size;
  789. if (format == "crc") {
  790. magic = 070702;
  791. //
  792. // Compute the sum of the data bytes if needed.
  793. //
  794. if (this.check < 0) {
  795. check = 0;
  796. if ((this.mode & CPIO_MODE_TYPE_MASK) ==
  797. CPIO_MODE_TYPE_SYMLINK) {
  798. link = this.link;
  799. check = this._sumData(link);
  800. }
  801. if ((this.mode & CPIO_MODE_TYPE_MASK) == CPIO_MODE_TYPE_FILE) {
  802. check = this._sumFile(inFile, this.size);
  803. }
  804. check &= 0xFFFFFFFF;
  805. }
  806. } else if (format == "newc") {
  807. check = 0;
  808. } else {
  809. Core.raise(CpioFormatError("Unknown format %s" % format));
  810. }
  811. if ((this.devMajor > max) || (this.devMinor > max) ||
  812. (this.inode > max) || (this.mode > max) || (this.uid > max) ||
  813. (this.gid > max) || (this.nlink > max) || (this.rdevMajor > max) ||
  814. (this.rdevMinor > max) || (this.mtime > max) ||
  815. (nameSize > max) || (this.size > max) || (check > max)) {
  816. Core.raise(CpioFormatError("Header value too big for format"));
  817. }
  818. result = "%06o%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x" % [
  819. magic,
  820. this.inode,
  821. this.mode,
  822. this.uid,
  823. this.gid,
  824. this.nlink,
  825. this.mtime,
  826. this.size,
  827. this.devMajor,
  828. this.devMinor,
  829. this.rdevMajor,
  830. this.rdevMinor,
  831. nameSize,
  832. check];
  833. result += this.name + "\0";
  834. outFile.write(result);
  835. //
  836. // Align the header up to 4 bytes.
  837. //
  838. size = result.length();
  839. while ((size & 0x3) != 0) {
  840. outFile.write("\0");
  841. size += 1;
  842. }
  843. this.headerSize = size;
  844. //
  845. // Write out the data contents.
  846. //
  847. if ((this.mode & CPIO_MODE_TYPE_MASK) == CPIO_MODE_TYPE_SYMLINK) {
  848. link = this.link;
  849. if (link.length() != this.size) {
  850. Core.raise(CpioFormatError("Member length %d does not match "
  851. "size of link '%s'" %
  852. [this.size, link]));
  853. }
  854. outFile.write(link);
  855. this.headerSize += this.size;
  856. this.archiveSize = this.headerSize;
  857. } else if ((this.mode & CPIO_MODE_TYPE_MASK) == CPIO_MODE_TYPE_FILE) {
  858. this._writeFileContents(inFile, outFile, this.size);
  859. this.archiveSize = this.headerSize + this.size;
  860. } else {
  861. if (this.size != 0) {
  862. Core.raise(CpioFormatError("Special device has non-zero size"));
  863. }
  864. this.archiveSize = this.headerSize;
  865. }
  866. //
  867. // Align the data out to four.
  868. //
  869. size = this.size;
  870. while ((size & 0x3) != 0) {
  871. outFile.write("\0");
  872. size += 1;
  873. this.archiveSize += 1;
  874. }
  875. return;
  876. }
  877. function
  878. _writeFileContents (
  879. inFile,
  880. outFile,
  881. size
  882. )
  883. /*++
  884. Routine Description:
  885. This routine writes the file contents out to the archive.
  886. Arguments:
  887. inFile - Supplies the file object to read from..
  888. outFile - Supplies the file object to write the data out to.
  889. size - Supplies the number of bytes to write.
  890. Return Value:
  891. None on success.
  892. An exception is raised on error.
  893. --*/
  894. {
  895. var chunk;
  896. var chunkSize;
  897. var maxChunkSize = 131072;
  898. while (size != 0) {
  899. chunkSize = (size < maxChunkSize) ? size : maxChunkSize;
  900. chunk = inFile.read(chunkSize);
  901. if (chunk.length() != chunkSize) {
  902. Core.raise(CpioEofError("Input file ended early"));
  903. }
  904. outFile.write(chunk);
  905. size -= chunkSize;
  906. }
  907. return;
  908. }
  909. function
  910. _sumFile (
  911. file,
  912. size
  913. )
  914. /*++
  915. Routine Description:
  916. This routine returns the sum of all the bytes in the file. It will
  917. return the file position back to where it was.
  918. Arguments:
  919. file - Supplies the file object to sum.
  920. size - Supplies the number of bytes to read from the file object.
  921. Return Value:
  922. Returns the sum of all the bytes in the file.
  923. --*/
  924. {
  925. var chunk;
  926. var chunkSize;
  927. var maxChunkSize = 131072;
  928. var start = file.tell();
  929. var sum = 0;
  930. while (size != 0) {
  931. chunkSize = (size < maxChunkSize) ? size : maxChunkSize;
  932. chunk = file.read(chunkSize);
  933. if (chunk.length() != chunkSize) {
  934. Core.raise(CpioEofError("Input file ended early"));
  935. }
  936. sum += this._sumData(chunk);
  937. size -= chunkSize;
  938. }
  939. file.seek(start, IO_SEEK_SET);
  940. return sum;
  941. }
  942. function
  943. _sumData (
  944. data
  945. )
  946. /*++
  947. Routine Description:
  948. This routine returns the sum of all the bytes in the data.
  949. Arguments:
  950. data - Supplies the data to sum.
  951. Return Value:
  952. Returns the sum of all the bytes in the data.
  953. --*/
  954. {
  955. var sum = 0;
  956. for (index in 0..data.length()) {
  957. sum += data.byteAt(index);
  958. }
  959. return sum;
  960. }
  961. }
  962. //
  963. // This class implements a file-like object that comes from the archive.
  964. //
  965. class ArchiveMemberFile {
  966. var _archive;
  967. var _file;
  968. var _member;
  969. var _startOffset;
  970. var _endOffset;
  971. var _currentOffset;
  972. function
  973. __init (
  974. archive,
  975. file,
  976. member
  977. )
  978. /*++
  979. Routine Description:
  980. This routine creates a new archive member file instance.
  981. Arguments:
  982. archive - Supplies the archive this member belongs to.
  983. file - Supplies the archive's underlying file object.
  984. member - Supplies the member to create a file object for.
  985. Return Value:
  986. Returns the initialized object.
  987. --*/
  988. {
  989. _archive = archive;
  990. _file = file;
  991. _member = member;
  992. _startOffset = member.offset + member.headerSize;
  993. _endOffset = _startOffset + member.size;
  994. _currentOffset = _startOffset;
  995. this.mode = "r";
  996. this.name = member.name;
  997. this.closed = false;
  998. return this;
  999. }
  1000. function
  1001. close (
  1002. )
  1003. /*++
  1004. Routine Description:
  1005. This routine closes the file.
  1006. Arguments:
  1007. None.
  1008. Return Value:
  1009. 0 always.
  1010. --*/
  1011. {
  1012. _file = null;
  1013. this.closed = true;
  1014. return 0;
  1015. }
  1016. function
  1017. readall (
  1018. )
  1019. /*++
  1020. Routine Description:
  1021. This routine reads the entire contents of the archive member.
  1022. Arguments:
  1023. None.
  1024. Return Value:
  1025. Returns the read data.
  1026. --*/
  1027. {
  1028. this.seek(0, IO_SEEK_SET);
  1029. return this.read(-1);
  1030. }
  1031. function
  1032. read (
  1033. size
  1034. )
  1035. /*++
  1036. Routine Description:
  1037. This routine reads from the archive member.
  1038. Arguments:
  1039. size - Supplies the size to read. Supply -1 to read the rest of the
  1040. file.
  1041. Return Value:
  1042. Returns the read data, which may be shorter than requested.
  1043. Returns an empty string on EOF.
  1044. --*/
  1045. {
  1046. var result;
  1047. if (_file == null) {
  1048. Core.raise(IoError("I/O operation on closed file"));
  1049. }
  1050. if ((size < 0) ||
  1051. (size > _endOffset - _currentOffset)) {
  1052. size = _endOffset - _currentOffset;
  1053. }
  1054. if (size == 0) {
  1055. return "";
  1056. }
  1057. this._syncOffset();
  1058. result = _file.read(size);
  1059. if (result.length() < size) {
  1060. Core.raise(IoError("Read error"));
  1061. }
  1062. _currentOffset += result.length();
  1063. _archive._setCurrentOffset(_currentOffset);
  1064. return result;
  1065. }
  1066. function
  1067. readline (
  1068. size
  1069. )
  1070. /*++
  1071. Routine Description:
  1072. This routine reads a line from the archive.
  1073. Arguments:
  1074. size - Supplies the maximum number of bytes to read. Supply -1 to
  1075. read until the new line or end of file.
  1076. Return Value:
  1077. Returns the read data, which may be shorter than requested.
  1078. Returns an empty string on EOF.
  1079. --*/
  1080. {
  1081. var result;
  1082. if (_file == null) {
  1083. Core.raise(IoError("I/O operation on closed file"));
  1084. }
  1085. if ((size < 0) ||
  1086. (size > _endOffset - _currentOffset)) {
  1087. size = _endOffset - _currentOffset;
  1088. }
  1089. if (size == 0) {
  1090. return "";
  1091. }
  1092. this._syncOffset();
  1093. result = _file.readline(size);
  1094. _currentOffset += result.length();
  1095. _archive._setCurrentOffset(_currentOffset);
  1096. return result;
  1097. }
  1098. function
  1099. readlines (
  1100. limit
  1101. )
  1102. /*++
  1103. Routine Description:
  1104. This routine reads multiple lines from a stream.
  1105. Arguments:
  1106. limit - Supplies the maximum number of bytes to read. Supply -1 for no
  1107. limit.
  1108. Return Value:
  1109. Returns a list of lines read from the file.
  1110. --*/
  1111. {
  1112. var line;
  1113. var result = [];
  1114. var size = 0;
  1115. line = this.readline();
  1116. if (limit <= 0) {
  1117. while (line != "") {
  1118. result.append(line);
  1119. line = this.readline();
  1120. }
  1121. } else {
  1122. while ((line != "") && (size < limit)) {
  1123. result.append(line);
  1124. size += line.length();
  1125. line = this.readline();
  1126. }
  1127. }
  1128. return result;
  1129. }
  1130. function
  1131. tell (
  1132. )
  1133. /*++
  1134. Routine Description:
  1135. This routine returns the current position within the file.
  1136. Arguments:
  1137. None.
  1138. Return Value:
  1139. Returns the current byte offset within the file.
  1140. --*/
  1141. {
  1142. if (_file == null) {
  1143. Core.raise(IoError("I/O operation on closed file"));
  1144. }
  1145. return _currentOffset - _startOffset;
  1146. }
  1147. function
  1148. seek (
  1149. offset,
  1150. whence
  1151. )
  1152. /*++
  1153. Routine Description:
  1154. This routine seeks into the file.
  1155. Arguments:
  1156. offset - Supplies the desired offset to seek from or to.
  1157. whence - Supplies the anchor point for the seek. Supply IO_SEEK_SET to
  1158. seek from the beginning of the file, IO_SEEK_CUR to seek from the
  1159. current position, or IO_SEEK_END to seek from the end of the file.
  1160. Return Value:
  1161. Returns the new absolute position within the file.
  1162. --*/
  1163. {
  1164. var newOffset;
  1165. if (_file == null) {
  1166. Core.raise(IoError("I/O operation on closed file"));
  1167. }
  1168. if (whence == IO_SEEK_SET) {
  1169. newOffset = _startOffset + offset;
  1170. } else if (whence == IO_SEEK_CUR) {
  1171. newOffset = _currentOffset + offset;
  1172. } else if (whence == IO_SEEK_END) {
  1173. newOffset = _endOffset + offset;
  1174. } else {
  1175. Core.raise(
  1176. IoError("Invalid seek disposition: %s" % whence.__str()));
  1177. }
  1178. if (newOffset < _startOffset) {
  1179. newOffset = _startOffset;
  1180. } else if (newOffset > _endOffset) {
  1181. newOffset = _endOffset;
  1182. }
  1183. _currentOffset = newOffset;
  1184. this._syncOffset();
  1185. return _currentOffset - _startOffset;
  1186. }
  1187. function
  1188. iterate (
  1189. iterator
  1190. )
  1191. /*++
  1192. Routine Description:
  1193. This routine iterates over the lines in a file.
  1194. Arguments:
  1195. iterator - Supplies null initially, or the previous iterator
  1196. Return Value:
  1197. Returns the new absolute position within the file.
  1198. --*/
  1199. {
  1200. var value = this.readline();
  1201. if (value == "") {
  1202. return null;
  1203. }
  1204. return value;
  1205. }
  1206. function
  1207. iteratorValue (
  1208. iterator
  1209. )
  1210. /*++
  1211. Routine Description:
  1212. This routine returns the value for an iterator.
  1213. Arguments:
  1214. iterator - Supplies null initially, or the previous iterator
  1215. Return Value:
  1216. Returns the value corresponding with the iterator.
  1217. --*/
  1218. {
  1219. return iterator;
  1220. }
  1221. function
  1222. isReadable (
  1223. )
  1224. /*++
  1225. Routine Description:
  1226. This routine determines if the given stream can be read from.
  1227. Arguments:
  1228. None.
  1229. Return Value:
  1230. true if the stream was opened with read permissions.
  1231. false if the stream cannot be read from.
  1232. --*/
  1233. {
  1234. if (_file == null) {
  1235. Core.raise(IoError("I/O operation on closed file"));
  1236. }
  1237. return true;
  1238. }
  1239. function
  1240. isWritable (
  1241. )
  1242. /*++
  1243. Routine Description:
  1244. This routine determines if the given file can be written to.
  1245. Arguments:
  1246. None.
  1247. Return Value:
  1248. true if the file can be written to.
  1249. false if the file cannot be written to.
  1250. --*/
  1251. {
  1252. if (_file == null) {
  1253. Core.raise(IoError("I/O operation on closed file"));
  1254. }
  1255. return false;
  1256. }
  1257. function
  1258. isSeekable (
  1259. )
  1260. /*++
  1261. Routine Description:
  1262. This routine determines if the file backing the stream can be seeked on.
  1263. Arguments:
  1264. None.
  1265. Return Value:
  1266. true if the underlying file is seekable.
  1267. false if the underlying file is not seekable.
  1268. --*/
  1269. {
  1270. if (_file == null) {
  1271. Core.raise(IoError("I/O operation on closed file"));
  1272. }
  1273. return _file.isSeekable();
  1274. }
  1275. function
  1276. _syncOffset (
  1277. )
  1278. /*++
  1279. Routine Description:
  1280. This routine synchronizes the file offset with the archive offset.
  1281. Upon return, ensures that the underlying file object is at the
  1282. correct offset and that the archive knows about any adjustments made.
  1283. Arguments:
  1284. None.
  1285. Return Value:
  1286. None.
  1287. --*/
  1288. {
  1289. if (_archive._getCurrentOffset() == _currentOffset) {
  1290. return;
  1291. }
  1292. _archive._setCurrentOffset(_file.seek(_currentOffset, IO_SEEK_SET));
  1293. return;
  1294. }
  1295. }
  1296. class CpioArchive {
  1297. var _file;
  1298. var _shouldClose;
  1299. var _isReadable;
  1300. var _isWritable;
  1301. var _isSeekable;
  1302. var _startOffset;
  1303. var _currentOffset;
  1304. var _nextOffset;
  1305. var _members;
  1306. var _memberDict;
  1307. var _fullyEnumerated;
  1308. var _trailerFound;
  1309. var _trailerOffset;
  1310. var _writeTrailer;
  1311. var _nextInode;
  1312. function
  1313. __init (
  1314. )
  1315. /*++
  1316. Routine Description:
  1317. This routine instantiates a new CpioArchive class with null parameters.
  1318. Arguments:
  1319. None.
  1320. Return Value:
  1321. Returns the initialized object.
  1322. --*/
  1323. {
  1324. Core.raise(ValueError("Use the other constructor"));
  1325. return null;
  1326. }
  1327. function
  1328. __init (
  1329. file,
  1330. mode
  1331. )
  1332. /*++
  1333. Routine Description:
  1334. This routine instantiates a new CpioArchiive class with the given file.
  1335. Arguments:
  1336. file - Supplies either a string, indicating the path of an archive to
  1337. open, or a file object to be used directly.
  1338. mode - Supplies the mode to open the archive with. Valid values are
  1339. "r", "w", and "a".
  1340. Return Value:
  1341. Returns the initialized object.
  1342. --*/
  1343. {
  1344. if ((file is String) || (file is Int)) {
  1345. _file = open(file, mode + "b");
  1346. _shouldClose = true;
  1347. } else {
  1348. _file = file;
  1349. _shouldClose = false;
  1350. }
  1351. _isReadable = _file.isReadable();
  1352. _isWritable = _file.isWritable();
  1353. _isSeekable = _file.isSeekable();
  1354. _startOffset = 0;
  1355. if (_isSeekable) {
  1356. _startOffset = _file.tell();
  1357. }
  1358. _currentOffset = _startOffset;
  1359. _nextOffset = _currentOffset;
  1360. _members = [];
  1361. _memberDict = {};
  1362. _fullyEnumerated = false;
  1363. _trailerFound = false;
  1364. _trailerOffset = -1;
  1365. _writeTrailer = false;
  1366. _nextInode = 2;
  1367. return this;
  1368. }
  1369. function
  1370. close (
  1371. )
  1372. /*++
  1373. Routine Description:
  1374. This routine closes the given archive.
  1375. Arguments:
  1376. None.
  1377. Return Value:
  1378. None.
  1379. --*/
  1380. {
  1381. var trailer;
  1382. if (_file == null) {
  1383. return;
  1384. }
  1385. //
  1386. // Write out the trailer entry if one needs to be written.
  1387. //
  1388. if (_writeTrailer) {
  1389. if (_currentOffset != _trailerOffset) {
  1390. this._checkAccess("s");
  1391. _currentOffset = _file.seek(_trailerOffset, IO_SEEK_SET);
  1392. }
  1393. trailer = CpioMember("TRAILER!!!");
  1394. trailer.format = _members[-1].format;
  1395. trailer.inode = 0;
  1396. trailer.mode = 0;
  1397. trailer.write(null, _file);
  1398. _writeTrailer = false;
  1399. }
  1400. if (_shouldClose) {
  1401. _file.close();
  1402. }
  1403. _file = null;
  1404. return;
  1405. }
  1406. function
  1407. iterate (
  1408. context
  1409. )
  1410. /*++
  1411. Routine Description:
  1412. This routine iterates over the archive.
  1413. Arguments:
  1414. context - Supplies the iteration context. null initially.
  1415. Return Value:
  1416. Returns the new iteration context, or null open reaching the end.
  1417. --*/
  1418. {
  1419. var index = context;
  1420. if (context == null) {
  1421. index = -1;
  1422. }
  1423. if (index + 1 < _members.length()) {
  1424. return index + 1;
  1425. }
  1426. if (_fullyEnumerated) {
  1427. return null;
  1428. }
  1429. if (this.next() == null) {
  1430. return null;
  1431. }
  1432. return index + 1;
  1433. }
  1434. function
  1435. iteratorValue (
  1436. context
  1437. )
  1438. /*++
  1439. Routine Description:
  1440. This routine returns the value for the given iteration context.
  1441. Arguments:
  1442. context - Supplies the iteration context. In this case just an index
  1443. into the members.
  1444. Return Value:
  1445. Returns the member at this iteration.
  1446. --*/
  1447. {
  1448. return _members[context];
  1449. }
  1450. function
  1451. next (
  1452. )
  1453. /*++
  1454. Routine Description:
  1455. This routine returns the next CpioMember in the archive if the archive
  1456. is open for reading.
  1457. Arguments:
  1458. None.
  1459. Return Value:
  1460. Returns the next CpioMember on success.
  1461. null if there are no more members in the archive.
  1462. --*/
  1463. {
  1464. var member;
  1465. var offset;
  1466. if (_trailerFound) {
  1467. return null;
  1468. }
  1469. this._checkAccess("r");
  1470. //
  1471. // Get to the next archive member, as the file may be pointing at the
  1472. // previous archive's data.
  1473. //
  1474. if (_currentOffset != _nextOffset) {
  1475. if (_isSeekable) {
  1476. _currentOffset = _file.seek(_nextOffset, IO_SEEK_SET);
  1477. } else {
  1478. _currentOffset +=
  1479. _file.read(_nextOffset - _currentOffset).length();
  1480. }
  1481. if (_currentOffset != _nextOffset) {
  1482. Core.raise(IoError("Failed to seek to next archive member"));
  1483. }
  1484. }
  1485. offset = _currentOffset;
  1486. try {
  1487. member = CpioMember.fromFile(_file);
  1488. } except CpioEofError {
  1489. _fullyEnumerated = true;
  1490. return null;
  1491. }
  1492. member.offset = offset;
  1493. _nextOffset = offset + member.archiveSize;
  1494. _currentOffset = offset + member.headerSize;
  1495. if (member.inode >= _nextInode) {
  1496. _nextInode = member.inode + 1;
  1497. }
  1498. //
  1499. // If this is the ending trailer entry, then the end of the archive is
  1500. // found for sure.
  1501. //
  1502. if (((member.name == "TRAILER!!") || (member.name == "TRAILER!!!")) &&
  1503. (member.size == 0)) {
  1504. _trailerFound = true;
  1505. _trailerOffset = offset;
  1506. _fullyEnumerated = true;
  1507. return null;
  1508. }
  1509. _members.append(member);
  1510. _memberDict[member.name] = member;
  1511. return member;
  1512. }
  1513. function
  1514. getMember (
  1515. name
  1516. )
  1517. /*++
  1518. Routine Description:
  1519. This routine returns the archive member with the given name. If the
  1520. member occurs more than once in the archive, the last one is returned.
  1521. Arguments:
  1522. name - Supplies the archive member name.
  1523. Return Value:
  1524. Returns the CpioMember with the given name on success.
  1525. Raises a KeyError if no member with the given name could be found.
  1526. --*/
  1527. {
  1528. if (_isReadable) {
  1529. //
  1530. // Load everything up if it's not all been seen yet.
  1531. //
  1532. while (!_fullyEnumerated) {
  1533. this.next();
  1534. }
  1535. }
  1536. return _memberDict[name];
  1537. }
  1538. function
  1539. getMembers (
  1540. )
  1541. /*++
  1542. Routine Description:
  1543. This routine returns a list of archive members. The order is the same
  1544. as the order in the archive.
  1545. Arguments:
  1546. None.
  1547. Return Value:
  1548. Returns a list of CpioMembers.
  1549. --*/
  1550. {
  1551. if (_isReadable) {
  1552. while (!_fullyEnumerated) {
  1553. this.next();
  1554. }
  1555. }
  1556. return _members;
  1557. }
  1558. function
  1559. getNames (
  1560. )
  1561. /*++
  1562. Routine Description:
  1563. This routine returns a list of archive member names. The list will be
  1564. in the same order as the archive.
  1565. Arguments:
  1566. None.
  1567. Return Value:
  1568. Returns a list of strings containing the archive member names.
  1569. --*/
  1570. {
  1571. var result = [];
  1572. if (_isReadable) {
  1573. while (!_fullyEnumerated) {
  1574. this.next();
  1575. }
  1576. }
  1577. for (member in _members) {
  1578. result.append(member.name);
  1579. }
  1580. return result;
  1581. }
  1582. function
  1583. list (
  1584. members,
  1585. verbose
  1586. )
  1587. /*++
  1588. Routine Description:
  1589. This routine prints a table of contents of the archive.
  1590. Arguments:
  1591. members - Supplies an optional list of CpioMembers to print. If null
  1592. is supplied, then the full listing of the archive is printed.
  1593. verbose - Supplies a boolean indicating whether to print out more
  1594. information about each member (true) or just the names (false).
  1595. Return Value:
  1596. Prints the table of contents using Core.print.
  1597. --*/
  1598. {
  1599. if (members == null) {
  1600. members = this.getMembers();
  1601. }
  1602. for (member in members) {
  1603. Core.print(member.ls(verbose));
  1604. }
  1605. return;
  1606. }
  1607. function
  1608. extractAll (
  1609. members,
  1610. directoryPath,
  1611. uid,
  1612. gid,
  1613. setPermissions
  1614. )
  1615. /*++
  1616. Routine Description:
  1617. This routine extracts all members from the archive. Permissions are
  1618. only set at the very end.
  1619. Arguments:
  1620. members - Supplies an optional list of archive members to extract. The
  1621. list should consist only of members from this archive. If null,
  1622. all archive members will be extracted.
  1623. directoryPath - Supplies an optional directory path to extract to. If
  1624. null, contents will be extracted to the current directory.
  1625. uid - Supplies the user ID to set on the extracted object. Supply -1 to
  1626. use the user ID number in the archive.
  1627. gid - Supplies the group ID to set on the extracted object. Supply -1
  1628. to use the group ID number in the archive.
  1629. setPermissions - Supplies a boolean indicating whether to set the
  1630. permissions in the file. If false and uid/gid are -1, then
  1631. no special attributes will be set on the file (which will make it
  1632. be owned by the caller).
  1633. Return Value:
  1634. None. An exception will be raised on failure.
  1635. --*/
  1636. {
  1637. if (members == null) {
  1638. members = this;
  1639. }
  1640. for (member in members) {
  1641. this._extract(member, directoryPath);
  1642. }
  1643. if (setPermissions) {
  1644. for (member in members) {
  1645. this._setPermissions(member, directoryPath, uid, gid);
  1646. }
  1647. }
  1648. return 0;
  1649. }
  1650. function
  1651. extract (
  1652. member,
  1653. directoryPath,
  1654. uid,
  1655. gid,
  1656. setPermissions
  1657. )
  1658. /*++
  1659. Routine Description:
  1660. This routine extracts a member from the archive as a file object.
  1661. Arguments:
  1662. member - Supplies a pointer to the member to extract.
  1663. directoryPath - Supplies an optional directory path to extract to. If
  1664. null, contents will be extracted to the current directory.
  1665. uid - Supplies the user ID to set on the extracted object. Supply -1 to
  1666. use the user ID number in the archive.
  1667. gid - Supplies the group ID to set on the extracted object. Supply -1
  1668. to use the group ID number in the archive.
  1669. setPermissions - Supplies a boolean indicating whether to set the
  1670. permissions in the file. If false and uid/gid are -1, then
  1671. no special attributes will be set on the file (which will make it
  1672. be owned by the caller).
  1673. Return Value:
  1674. None. An exception will be raised on failure.
  1675. --*/
  1676. {
  1677. this._extract(member, directoryPath);
  1678. if (setPermissions) {
  1679. this._setPermissions(member, directoryPath, uid, gid);
  1680. }
  1681. return 0;
  1682. }
  1683. function
  1684. extractFile (
  1685. member
  1686. )
  1687. /*++
  1688. Routine Description:
  1689. This routine extracts a member from the archive as a file object.
  1690. Arguments:
  1691. member - Supplies a pointer to the member to extract.
  1692. Return Value:
  1693. Returns a readable file like object.
  1694. null if the archive member is not a regular file.
  1695. --*/
  1696. {
  1697. this._checkAccess("r");
  1698. if (!member.isFile()) {
  1699. return null;
  1700. }
  1701. return ArchiveMemberFile(this, _file, member);
  1702. }
  1703. function
  1704. add (
  1705. name,
  1706. archiveName,
  1707. recursive,
  1708. filter
  1709. )
  1710. /*++
  1711. Routine Description:
  1712. This routine adds one or more files to the archive.
  1713. Arguments:
  1714. name - Supplies the path name of the file to add.
  1715. archiveName - Supplies the name that should go in the archive. Supply
  1716. null to just use the same name as the source. Supply "" to add a
  1717. directory as the root of the archive.
  1718. recursive - Supplies a boolean indicating whether to include files
  1719. within a specified directory or not.
  1720. filter - Supplies an optional function that may modify or remove each
  1721. member being added to the archive. If the routine returns the
  1722. member, it is added (potentially modified). If it returns null,
  1723. the member is abandoned and not added to the archive.
  1724. Return Value:
  1725. None. The member will be appended to the archive on success.
  1726. An exception will be raised on failure.
  1727. --*/
  1728. {
  1729. var contents;
  1730. var member;
  1731. var file;
  1732. if (archiveName == null) {
  1733. archiveName = name;
  1734. }
  1735. if (archiveName != "") {
  1736. member = this.createMember(name, archiveName, null);
  1737. //
  1738. // See if the caller wants to filter this element.
  1739. //
  1740. if (filter) {
  1741. member = filter(name, member);
  1742. if (member == null) {
  1743. return;
  1744. }
  1745. }
  1746. if ((os.isfile)(name)) {
  1747. file = open(name, "rb");
  1748. }
  1749. this.addMember(member, file);
  1750. if (file) {
  1751. file.close();
  1752. }
  1753. }
  1754. if (recursive && (os.isdir)(name)) {
  1755. contents = (os.listdir)(name);
  1756. if (archiveName != "") {
  1757. archiveName += "/";
  1758. }
  1759. for (element in contents) {
  1760. this.add(name + "/" + element,
  1761. archiveName + element,
  1762. recursive,
  1763. filter);
  1764. }
  1765. }
  1766. return;
  1767. }
  1768. function
  1769. createMember (
  1770. file,
  1771. archivePath,
  1772. format
  1773. )
  1774. /*++
  1775. Routine Description:
  1776. This routine creates a new CpioMember structure based on the given
  1777. file.
  1778. Arguments:
  1779. file - Supplies either a string or a file object containing the file to
  1780. create a member for.
  1781. archivePath - Supplies an optional within the archive where the file
  1782. should be put. If null it will match the name of the file.
  1783. format - Supplies the format to create the member in.
  1784. Return Value:
  1785. Returns a new CpioMember instance. This member has not yet been added
  1786. to the archive, it can be modified by the caller before callind add.
  1787. --*/
  1788. {
  1789. var member;
  1790. var mode;
  1791. var size;
  1792. var sourcePath = file;
  1793. var stat;
  1794. var statMode;
  1795. if (file is String) {
  1796. stat = (os.lstat)(file);
  1797. if (!archivePath) {
  1798. archivePath = file;
  1799. }
  1800. } else {
  1801. stat = (os.fstat)(file.fileno());
  1802. if (!archivePath) {
  1803. archivePath = file.name;
  1804. }
  1805. sourcePath = file.name;
  1806. }
  1807. member = CpioMember(archivePath);
  1808. size = stat.st_size;
  1809. statMode = stat.st_mode;
  1810. mode = statMode & 0777;
  1811. if ((statMode & os.S_ISUID) != 0) {
  1812. mode |= CPIO_MODE_SUID;
  1813. }
  1814. if ((statMode & os.S_ISGID) != 0) {
  1815. mode |= CPIO_MODE_SGID;
  1816. }
  1817. if ((statMode & os.S_ISVTX) != 0) {
  1818. mode |= CPIO_MODE_STICKY;
  1819. }
  1820. if ((statMode & os.S_IFMT) == os.S_IFLNK) {
  1821. member.link = (os.readlink)(sourcePath);
  1822. size = member.link.length();
  1823. } else if ((statMode & os.S_IFMT) == os.S_IFDIR) {
  1824. size = 0;
  1825. }
  1826. mode |= _osFileTypes[statMode & os.S_IFMT];
  1827. if (format != null) {
  1828. member.format = format;
  1829. } else if (_members.length() != 0) {
  1830. member.format = _members[-1].format;
  1831. } else {
  1832. member.format = "newc";
  1833. }
  1834. member.mode = mode;
  1835. member.inode = stat.st_ino;
  1836. if (member.inode == 0) {
  1837. member.inode = _nextInode;
  1838. _nextInode += 1;
  1839. }
  1840. member.uid = stat.st_uid;
  1841. member.gid = stat.st_gid;
  1842. member.nlink = stat.st_nlink;
  1843. member.mtime = stat.st_mtime;
  1844. member.size = size;
  1845. member.devMinor = stat.st_dev;
  1846. member.devMajor = 0;
  1847. member.rdevMinor = stat.st_rdev;
  1848. member.rdevMajor = 0;
  1849. member.check = -1;
  1850. return member;
  1851. }
  1852. function
  1853. addMember (
  1854. member,
  1855. file
  1856. )
  1857. /*++
  1858. Routine Description:
  1859. This routine appends a member to the archive.
  1860. Arguments:
  1861. member - Supplies the member to add.
  1862. file - Supplies the file contents to add. The size should correspond to
  1863. the member size.
  1864. Return Value:
  1865. None. The member will be appended to the archive on success.
  1866. An exception will be raised on failure.
  1867. --*/
  1868. {
  1869. this._checkAccess("w");
  1870. //
  1871. // Load the rest of the archive if it's readable.
  1872. //
  1873. if (_isReadable) {
  1874. while (!_fullyEnumerated) {
  1875. this.next();
  1876. }
  1877. }
  1878. //
  1879. // If a trailer was found, back up over it.
  1880. //
  1881. if (_trailerFound) {
  1882. this._checkAccess("s");
  1883. _currentOffset = _file.seek(_trailerOffset, IO_SEEK_SET);
  1884. }
  1885. //
  1886. // Write out the member.
  1887. //
  1888. member.offset = _currentOffset;
  1889. member.write(file, _file);
  1890. _currentOffset += member.archiveSize;
  1891. _trailerOffset = _currentOffset;
  1892. _writeTrailer = true;
  1893. _members.append(member);
  1894. _memberDict[member.name] = member;
  1895. return 0;
  1896. }
  1897. function
  1898. _checkAccess (
  1899. mode
  1900. )
  1901. /*++
  1902. Routine Description:
  1903. This routine validates that the archive has the given access, or raises
  1904. an exception if it doesn't.
  1905. Arguments:
  1906. mode - Supplies the mode to check for.
  1907. Return Value:
  1908. None.
  1909. --*/
  1910. {
  1911. if (_file == null) {
  1912. Core.raise(IoError("File is closed"));
  1913. }
  1914. for (character in mode) {
  1915. if (character == "r") {
  1916. if (!_isReadable) {
  1917. Core.raise(IoError("File is not open for reading"));
  1918. }
  1919. } else if (character == "w") {
  1920. if (!_isWritable) {
  1921. Core.raise(IoError("File is not open for writing"));
  1922. }
  1923. } else if (character == "s") {
  1924. if (!_isSeekable) {
  1925. Core.raise(IoError("File is not seekable"));
  1926. }
  1927. }
  1928. }
  1929. return;
  1930. }
  1931. function
  1932. _getCurrentOffset (
  1933. )
  1934. /*++
  1935. Routine Description:
  1936. This routine returns the internal offset from within the archive. This
  1937. should not be called externally.
  1938. Arguments:
  1939. None.
  1940. Return Value:
  1941. Returns the current offset.
  1942. --*/
  1943. {
  1944. return _currentOffset;
  1945. }
  1946. function
  1947. _setCurrentOffset (
  1948. offset
  1949. )
  1950. /*++
  1951. Routine Description:
  1952. This routine sets the internal offset within the archive. This should
  1953. not be called externally.
  1954. Arguments:
  1955. offset - Supplies the new offset to set.
  1956. Return Value:
  1957. None.
  1958. --*/
  1959. {
  1960. _currentOffset = offset;
  1961. return;
  1962. }
  1963. function
  1964. _extract (
  1965. member,
  1966. directoryPath
  1967. )
  1968. /*++
  1969. Routine Description:
  1970. This routine extracts data from a member to the host file system. This
  1971. routine does not set final permissions on the file.
  1972. Arguments:
  1973. member - Supplies a pointer to the member to extract.
  1974. directoryPath - Supplies an optional directory path to extract to. If
  1975. null, contents will be extracted to the current directory.
  1976. Return Value:
  1977. None. An exception will be raised on failure.
  1978. --*/
  1979. {
  1980. var chunk;
  1981. var chunkSize = 131072;
  1982. var destination;
  1983. var memberMode = member.mode;
  1984. var mode;
  1985. var path;
  1986. var source;
  1987. if (!directoryPath) {
  1988. directoryPath = ".";
  1989. }
  1990. path = directoryPath + "/" + member.name;
  1991. //
  1992. // Special devices are currently not supported.
  1993. //
  1994. if (member.isDev()) {
  1995. return;
  1996. }
  1997. if (member.isDir()) {
  1998. try {
  1999. (os.mkdir)(path, 0777);
  2000. } except os.OsError as e {
  2001. if (e.errno != os.EEXIST) {
  2002. Core.raise(e);
  2003. }
  2004. }
  2005. } else if (member.isLink()) {
  2006. try {
  2007. (os.symlink)(member.link, path);
  2008. } except os.OsError as e {
  2009. if (e.errno == os.EEXIST) {
  2010. (os.unlink)(path);
  2011. (os.symlink)(member.link, path);
  2012. } else {
  2013. Core.raise(e);
  2014. }
  2015. }
  2016. } else {
  2017. source = this.extractFile(member);
  2018. destination = open(path, "wb");
  2019. try {
  2020. while (true) {
  2021. chunk = source.read(chunkSize);
  2022. if (chunk.length() == 0) {
  2023. break;
  2024. }
  2025. destination.write(chunk);
  2026. }
  2027. } except Exception as e {
  2028. Core.raise(e);
  2029. } finally {
  2030. source.close();
  2031. destination.close();
  2032. }
  2033. }
  2034. return;
  2035. }
  2036. function
  2037. _setPermissions (
  2038. member,
  2039. directoryPath,
  2040. uid,
  2041. gid
  2042. )
  2043. /*++
  2044. Routine Description:
  2045. This routine sets the final permissions for an extracted member.
  2046. Arguments:
  2047. member - Supplies a pointer to the member to extract.
  2048. directoryPath - Supplies an optional directory path to extract to. If
  2049. null, contents will be extracted to the current directory.
  2050. uid - Supplies the user ID to set on the extracted object. Supply -1 to
  2051. use the user ID number in the archive.
  2052. gid - Supplies the group ID to set on the extracted object. Supply -1
  2053. to use the group ID number in the archive.
  2054. Return Value:
  2055. None. An exception will be raised on failure.
  2056. --*/
  2057. {
  2058. var memberMode = member.mode;
  2059. var mode;
  2060. var path;
  2061. if (!directoryPath) {
  2062. directoryPath = ".";
  2063. }
  2064. path = directoryPath + "/" + member.name;
  2065. mode = memberMode & 0777;
  2066. if (memberMode & CPIO_MODE_SUID) {
  2067. mode |= os.S_ISUID;
  2068. }
  2069. if (memberMode & CPIO_MODE_SGID) {
  2070. mode |= os.S_ISGID;
  2071. }
  2072. if (memberMode & CPIO_MODE_STICKY) {
  2073. mode |= os.S_ISVTX;
  2074. }
  2075. if (uid < 0) {
  2076. uid = member.uid;
  2077. }
  2078. if (gid < 0) {
  2079. gid = member.gid;
  2080. }
  2081. (os.lutimes)(path, member.mtime, 0, member.mtime, 0);
  2082. try {
  2083. (os.lchown)(path, uid, gid);
  2084. } except os.OsError as e {
  2085. if (e.errno != os.ENOSYS) {
  2086. Core.raise(e);
  2087. }
  2088. }
  2089. if (!(os.islink)(path)) {
  2090. (os.chmod)(path, mode);
  2091. }
  2092. return;
  2093. }
  2094. }
  2095. //
  2096. // --------------------------------------------------------- Internal Functions
  2097. //