2
0

TarHeader.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. // TarHeader.cs
  2. //
  3. // Copyright (C) 2001 Mike Krueger
  4. //
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18. //
  19. // Linking this library statically or dynamically with other modules is
  20. // making a combined work based on this library. Thus, the terms and
  21. // conditions of the GNU General Public License cover the whole
  22. // combination.
  23. //
  24. // As a special exception, the copyright holders of this library give you
  25. // permission to link this library with independent modules to produce an
  26. // executable, regardless of the license terms of these independent
  27. // modules, and to copy and distribute the resulting executable under
  28. // terms of your choice, provided that you also meet, for each linked
  29. // independent module, the terms and conditions of the license of that
  30. // module. An independent module is a module which is not derived from
  31. // or based on this library. If you modify this library, you may extend
  32. // this exception to your version of the library, but you are not
  33. // obligated to do so. If you do not wish to do so, delete this
  34. // exception statement from your version.
  35. /* The tar format and its POSIX successor PAX have a long history which makes for compatability
  36. issues when creating and reading files...
  37. This is the ustar (Posix 1003.1) header.
  38. struct header
  39. {
  40. char t_name[100]; // 0 Filename
  41. char t_mode[8]; // 100 Permissions
  42. char t_uid[8]; // 108 Numerical User ID
  43. char t_gid[8]; // 116 Numerical Group ID
  44. char t_size[12]; // 124 Filesize
  45. char t_mtime[12]; // 136 st_mtime
  46. char t_chksum[8]; // 148 Checksum
  47. char t_typeflag; // 156 Type of File
  48. char t_linkname[100]; // 157 Target of Links
  49. char t_magic[6]; // 257 "ustar"
  50. char t_version[2]; // 263 Version fixed to 00
  51. char t_uname[32]; // 265 User Name
  52. char t_gname[32]; // 297 Group Name
  53. char t_devmajor[8]; // 329 Major for devices
  54. char t_devminor[8]; // 337 Minor for devices
  55. char t_prefix[155]; // 345 Prefix for t_name
  56. // 500 End
  57. char t_mfill[12]; // 500 Filler up to 512
  58. };
  59. */
  60. using System;
  61. using System.Text;
  62. namespace ICSharpCode.SharpZipLib.Tar
  63. {
  64. /// <summary>
  65. /// This class encapsulates the Tar Entry Header used in Tar Archives.
  66. /// The class also holds a number of tar constants, used mostly in headers.
  67. /// </summary>
  68. public class TarHeader : ICloneable
  69. {
  70. /// <summary>
  71. /// The length of the name field in a header buffer.
  72. /// </summary>
  73. public readonly static int NAMELEN = 100;
  74. /// <summary>
  75. /// The length of the mode field in a header buffer.
  76. /// </summary>
  77. public readonly static int MODELEN = 8;
  78. /// <summary>
  79. /// The length of the user id field in a header buffer.
  80. /// </summary>
  81. public readonly static int UIDLEN = 8;
  82. /// <summary>
  83. /// The length of the group id field in a header buffer.
  84. /// </summary>
  85. public readonly static int GIDLEN = 8;
  86. /// <summary>
  87. /// The length of the checksum field in a header buffer.
  88. /// </summary>
  89. public readonly static int CHKSUMLEN = 8;
  90. /// <summary>
  91. /// The length of the size field in a header buffer.
  92. /// </summary>
  93. public readonly static int SIZELEN = 12;
  94. /// <summary>
  95. /// The length of the magic field in a header buffer.
  96. /// </summary>
  97. public readonly static int MAGICLEN = 6;
  98. /// <summary>
  99. /// The length of the version field in a header buffer.
  100. /// </summary>
  101. public readonly static int VERSIONLEN = 2;
  102. /// <summary>
  103. /// The length of the modification time field in a header buffer.
  104. /// </summary>
  105. public readonly static int MODTIMELEN = 12;
  106. /// <summary>
  107. /// The length of the user name field in a header buffer.
  108. /// </summary>
  109. public readonly static int UNAMELEN = 32;
  110. /// <summary>
  111. /// The length of the group name field in a header buffer.
  112. /// </summary>
  113. public readonly static int GNAMELEN = 32;
  114. /// <summary>
  115. /// The length of the devices field in a header buffer.
  116. /// </summary>
  117. public readonly static int DEVLEN = 8;
  118. /// <summary>
  119. /// LF_ constants represents the "type" of an entry
  120. /// </summary>
  121. ///
  122. /// <summary>
  123. /// This is the "old way" of indicating a normal file.
  124. /// </summary>
  125. public const byte LF_OLDNORM = 0;
  126. /// <summary>
  127. /// Normal file type.
  128. /// </summary>
  129. public const byte LF_NORMAL = (byte) '0';
  130. /// <summary>
  131. /// Link file type.
  132. /// </summary>
  133. public const byte LF_LINK = (byte) '1';
  134. /// <summary>
  135. /// Symbolic link file type.
  136. /// </summary>
  137. public const byte LF_SYMLINK = (byte) '2';
  138. /// <summary>
  139. /// Character device file type.
  140. /// </summary>
  141. public const byte LF_CHR = (byte) '3';
  142. /// <summary>
  143. /// Block device file type.
  144. /// </summary>
  145. public const byte LF_BLK = (byte) '4';
  146. /// <summary>
  147. /// Directory file type.
  148. /// </summary>
  149. public const byte LF_DIR = (byte) '5';
  150. /// <summary>
  151. /// FIFO (pipe) file type.
  152. /// </summary>
  153. public const byte LF_FIFO = (byte) '6';
  154. /// <summary>
  155. /// Contiguous file type.
  156. /// </summary>
  157. public const byte LF_CONTIG = (byte) '7';
  158. /// <summary>
  159. /// Posix.1 2001 global extended header
  160. /// </summary>
  161. ///
  162. public const byte LF_GHDR = (byte) 'g';
  163. /// <summary>
  164. /// Posix.1 2001 extended header
  165. /// </summary>
  166. public readonly static byte LF_XHDR = (byte) 'x';
  167. // POSIX allows for upper case ascii type as extensions
  168. // Solaris access control list
  169. public const byte LF_ACL = (byte) 'A';
  170. // This is a dir entry that contains the names of files that were in the
  171. // dir at the time the dump was made
  172. public const byte LF_GNU_DUMPDIR = (byte) 'D';
  173. // Solaris Extended Attribute File
  174. public const byte LF_EXTATTR = (byte) 'E' ;
  175. // Inode (metadata only) no file content
  176. public const byte LF_META = (byte) 'I';
  177. // Identifies the next file on the tape as having a long link name
  178. public const byte LF_GNU_LONGLINK = (byte) 'K';
  179. // Identifies the next file on the tape as having a long name
  180. public const byte LF_GNU_LONGNAME = (byte) 'L';
  181. // Continuation of a file that began on another volume
  182. public const byte LF_GNU_MULTIVOL = (byte) 'M';
  183. // For storing filenames that dont fit in the main header (old GNU)
  184. public const byte LF_GNU_NAMES = (byte) 'N';
  185. // Sparse file
  186. public const byte LF_GNU_SPARSE = (byte) 'S';
  187. // Tape/volume header ignore on extraction
  188. public const byte LF_GNU_VOLHDR = (byte) 'V';
  189. /// <summary>
  190. /// The magic tag representing a POSIX tar archive. (includes trailing NULL)
  191. /// </summary>
  192. public readonly static string TMAGIC = "ustar ";
  193. /// <summary>
  194. /// The magic tag representing an old GNU tar archive where version is included in magic and overwrites it
  195. /// </summary>
  196. public readonly static string GNU_TMAGIC = "ustar ";
  197. /// <summary>
  198. /// The entry's name.
  199. /// </summary>
  200. public StringBuilder name;
  201. /// <summary>
  202. /// The entry's permission mode.
  203. /// </summary>
  204. public int mode;
  205. /// <summary>
  206. /// The entry's user id.
  207. /// </summary>
  208. public int userId;
  209. /// <summary>
  210. /// The entry's group id.
  211. /// </summary>
  212. public int groupId;
  213. /// <summary>
  214. /// The entry's size.
  215. /// </summary>
  216. public long size;
  217. /// <summary>
  218. /// The entry's modification time.
  219. /// </summary>
  220. public DateTime modTime;
  221. /// <summary>
  222. /// The entry's checksum.
  223. /// </summary>
  224. public int checkSum;
  225. /// <summary>
  226. /// The entry's type flag.
  227. /// </summary>
  228. public byte typeFlag;
  229. /// <summary>
  230. /// The entry's link name.
  231. /// </summary>
  232. public StringBuilder linkName;
  233. /// <summary>
  234. /// The entry's magic tag.
  235. /// </summary>
  236. public StringBuilder magic;
  237. /// <summary>
  238. /// The entry's version.
  239. /// </summary>
  240. public StringBuilder version;
  241. /// <summary>
  242. /// The entry's user name.
  243. /// </summary>
  244. public StringBuilder userName;
  245. /// <summary>
  246. /// The entry's group name.
  247. /// </summary>
  248. public StringBuilder groupName;
  249. /// <summary>
  250. /// The entry's major device number.
  251. /// </summary>
  252. public int devMajor;
  253. /// <summary>
  254. /// The entry's minor device number.
  255. /// </summary>
  256. public int devMinor;
  257. public TarHeader()
  258. {
  259. this.magic = new StringBuilder(TarHeader.TMAGIC);
  260. this.version = new StringBuilder(" ");
  261. this.name = new StringBuilder();
  262. this.linkName = new StringBuilder();
  263. string user = Environment.UserName;
  264. // string user = "PocketPC";
  265. // string user = "Everyone";
  266. if (user.Length > 31) {
  267. user = user.Substring(0, 31);
  268. }
  269. this.userId = 1003; // -jr- was 0
  270. this.groupId = 513; // -jr- was 0
  271. this.userName = new StringBuilder(user);
  272. // -jr-
  273. // this.groupName = new StringBuilder(String.Empty);
  274. // this.groupName = new StringBuilder("Everyone"); Attempt2
  275. this.groupName = new StringBuilder("None"); // Gnu compatible
  276. this.size = 0;
  277. }
  278. /// <summary>
  279. /// TarHeaders can be cloned.
  280. /// </summary>
  281. public object Clone()
  282. {
  283. TarHeader hdr = new TarHeader();
  284. hdr.name = (this.name == null) ? null : new StringBuilder(this.name.ToString());
  285. hdr.mode = this.mode;
  286. hdr.userId = this.userId;
  287. hdr.groupId = this.groupId;
  288. hdr.size = this.size;
  289. hdr.modTime = this.modTime;
  290. hdr.checkSum = this.checkSum;
  291. hdr.typeFlag = this.typeFlag;
  292. hdr.linkName = (this.linkName == null) ? null : new StringBuilder(this.linkName.ToString());
  293. hdr.magic = (this.magic == null) ? null : new StringBuilder(this.magic.ToString());
  294. hdr.version = (this.version == null) ? null : new StringBuilder(this.version.ToString());
  295. hdr.userName = (this.userName == null) ? null : new StringBuilder(this.userName.ToString());
  296. hdr.groupName = (this.groupName == null) ? null : new StringBuilder(this.groupName.ToString());
  297. hdr.devMajor = this.devMajor;
  298. hdr.devMinor = this.devMinor;
  299. return hdr;
  300. }
  301. /// <summary>
  302. /// Get the name of this entry.
  303. /// </summary>
  304. /// <returns>
  305. /// The entry's name.
  306. /// </returns>
  307. public string GetName()
  308. {
  309. return this.name.ToString();
  310. }
  311. /// <summary>
  312. /// Parse an octal string from a header buffer. This is used for the
  313. /// file permission mode value.
  314. /// </summary>
  315. /// <param name = "header">
  316. /// The header buffer from which to parse.
  317. /// </param>
  318. /// <param name = "offset">
  319. /// The offset into the buffer from which to parse.
  320. /// </param>
  321. /// <param name = "length">
  322. /// The number of header bytes to parse.
  323. /// </param>
  324. /// <returns>
  325. /// The long value of the octal string.
  326. /// </returns>
  327. public static long ParseOctal(byte[] header, int offset, int length)
  328. {
  329. long result = 0;
  330. bool stillPadding = true;
  331. int end = offset + length;
  332. for (int i = offset; i < end ; ++i)
  333. {
  334. if (header[i] == 0)
  335. {
  336. break;
  337. }
  338. if (header[i] == (byte)' ' || header[i] == '0')
  339. {
  340. if (stillPadding)
  341. {
  342. continue;
  343. }
  344. if (header[i] == (byte)' ')
  345. {
  346. break;
  347. }
  348. }
  349. stillPadding = false;
  350. result = (result << 3) + (header[i] - '0');
  351. }
  352. return result;
  353. }
  354. /// <summary>
  355. /// Parse an entry name from a header buffer.
  356. /// </summary>
  357. /// <param name="header">
  358. /// The header buffer from which to parse.
  359. /// </param>
  360. /// <param name="offset">
  361. /// The offset into the buffer from which to parse.
  362. /// </param>
  363. /// <param name="length">
  364. /// The number of header bytes to parse.
  365. /// </param>
  366. /// <returns>
  367. /// The header's entry name.
  368. /// </returns>
  369. public static StringBuilder ParseName(byte[] header, int offset, int length)
  370. {
  371. StringBuilder result = new StringBuilder(length);
  372. for (int i = offset; i < offset + length; ++i)
  373. {
  374. if (header[i] == 0)
  375. {
  376. break;
  377. }
  378. result.Append((char)header[i]);
  379. }
  380. return result;
  381. }
  382. public static int GetNameBytes(StringBuilder name, int nameOffset, byte[] buf, int bufferOffset, int length)
  383. {
  384. int i;
  385. for (i = 0 ; i < length && nameOffset + i < name.Length; ++i)
  386. {
  387. buf[bufferOffset + i] = (byte)name[nameOffset + i];
  388. }
  389. for (; i < length ; ++i)
  390. {
  391. buf[bufferOffset + i] = 0;
  392. }
  393. return bufferOffset + length;
  394. }
  395. /// <summary>
  396. /// Determine the number of bytes in an entry name.
  397. /// </summary>
  398. /// <param name="name">
  399. /// </param>
  400. /// <param name="buf">
  401. /// The header buffer from which to parse.
  402. /// </param>
  403. /// <param name="offset">
  404. /// The offset into the buffer from which to parse.
  405. /// </param>
  406. /// <param name="length">
  407. /// The number of header bytes to parse.
  408. /// </param>
  409. /// <returns>
  410. /// The number of bytes in a header's entry name.
  411. /// </returns>
  412. public static int GetNameBytes(StringBuilder name, byte[] buf, int offset, int length)
  413. {
  414. return GetNameBytes(name, 0, buf, offset, length);
  415. }
  416. /// <summary>
  417. /// Parse an octal integer from a header buffer.
  418. /// </summary>
  419. /// <param name = "val">
  420. /// </param>
  421. /// <param name = "buf">
  422. /// The header buffer from which to parse.
  423. /// </param>
  424. /// <param name = "offset">
  425. /// The offset into the buffer from which to parse.
  426. /// </param>
  427. /// <param name = "length">
  428. /// The number of header bytes to parse.
  429. /// </param>
  430. /// <returns>
  431. /// The integer value of the octal bytes.
  432. /// </returns>
  433. public static int GetOctalBytes(long val, byte[] buf, int offset, int length)
  434. {
  435. // TODO check for values too large...
  436. int idx = length - 1;
  437. // Either a space or null is valid here. We use NULL as per GNUTar
  438. buf[offset + idx] = 0;
  439. --idx;
  440. if (val > 0)
  441. {
  442. for (long v = val; idx >= 0 && v > 0; --idx)
  443. {
  444. buf[offset + idx] = (byte)((byte)'0' + (byte)(v & 7));
  445. v >>= 3;
  446. }
  447. }
  448. for (; idx >= 0; --idx)
  449. {
  450. buf[offset + idx] = (byte)'0';
  451. }
  452. return offset + length;
  453. }
  454. /// <summary>
  455. /// Parse an octal long integer from a header buffer.
  456. /// </summary>
  457. /// <param name = "val">
  458. /// </param>
  459. /// <param name = "buf">
  460. /// The header buffer from which to parse.
  461. /// </param>
  462. /// <param name = "offset">
  463. /// The offset into the buffer from which to parse.
  464. /// </param>
  465. /// <param name = "length">
  466. /// The number of header bytes to parse.
  467. /// </param>
  468. /// <returns>
  469. /// The long value of the octal bytes.
  470. /// </returns>
  471. public static int GetLongOctalBytes(long val, byte[] buf, int offset, int length)
  472. {
  473. return GetOctalBytes(val, buf, offset, length);
  474. }
  475. /// <summary>
  476. /// Add the checksum octal integer to header buffer.
  477. /// </summary>
  478. /// <param name = "val">
  479. /// </param>
  480. /// <param name = "buf">
  481. /// The header buffer to set the checksum for
  482. /// </param>
  483. /// <param name = "offset">
  484. /// The offset into the buffer for the checksum
  485. /// </param>
  486. /// <param name = "length">
  487. /// The number of header bytes to update.
  488. /// It's formatted differently from the other fields: it has 6 digits, a
  489. /// null, then a space -- rather than digits, a space, then a null.
  490. /// The final space is already there, from checksumming
  491. /// </param>
  492. /// <returns>
  493. /// The modified buffer offset
  494. /// </returns>
  495. private static int GetCheckSumOctalBytes(long val, byte[] buf, int offset, int length)
  496. {
  497. TarHeader.GetOctalBytes(val, buf, offset, length - 1);
  498. // buf[offset + length - 1] = (byte)' '; -jr- 23-Jan-2004 this causes failure!!!
  499. // buf[offset + length - 2] = 0;
  500. return offset + length;
  501. }
  502. /// <summary>
  503. /// Compute the checksum for a tar entry header.
  504. /// The checksum field must be all spaces prior to this happening
  505. /// </summary>
  506. /// <param name = "buf">
  507. /// The tar entry's header buffer.
  508. /// </param>
  509. /// <returns>
  510. /// The computed checksum.
  511. /// </returns>
  512. private static long ComputeCheckSum(byte[] buf)
  513. {
  514. long sum = 0;
  515. for (int i = 0; i < buf.Length; ++i)
  516. {
  517. sum += buf[i];
  518. }
  519. return sum;
  520. }
  521. readonly static long timeConversionFactor = 10000000L; // -jr- 1 tick == 100 nanoseconds
  522. readonly static DateTime datetTime1970 = new DateTime(1970, 1, 1, 0, 0, 0, 0);
  523. // readonly static DateTime datetTime1970 = new DateTime(1970, 1, 1, 0, 0, 0, 0).ToUniversalTime(); // -jr- Should be UTC? doesnt match Gnutar if this is so though, why?
  524. static int GetCTime(System.DateTime dateTime)
  525. {
  526. return (int)((dateTime.Ticks - datetTime1970.Ticks) / timeConversionFactor);
  527. }
  528. static DateTime GetDateTimeFromCTime(long ticks)
  529. {
  530. return new DateTime(datetTime1970.Ticks + ticks * timeConversionFactor);
  531. }
  532. /// <summary>
  533. /// Parse TarHeader information from a header buffer.
  534. /// </summary>
  535. /// <param name = "header">
  536. /// The tar entry header buffer to get information from.
  537. /// </param>
  538. public void ParseBuffer(byte[] header)
  539. {
  540. int offset = 0;
  541. name = TarHeader.ParseName(header, offset, TarHeader.NAMELEN);
  542. offset += TarHeader.NAMELEN;
  543. mode = (int)TarHeader.ParseOctal(header, offset, TarHeader.MODELEN);
  544. offset += TarHeader.MODELEN;
  545. userId = (int)TarHeader.ParseOctal(header, offset, TarHeader.UIDLEN);
  546. offset += TarHeader.UIDLEN;
  547. groupId = (int)TarHeader.ParseOctal(header, offset, TarHeader.GIDLEN);
  548. offset += TarHeader.GIDLEN;
  549. size = TarHeader.ParseOctal(header, offset, TarHeader.SIZELEN);
  550. offset += TarHeader.SIZELEN;
  551. modTime = GetDateTimeFromCTime(TarHeader.ParseOctal(header, offset, TarHeader.MODTIMELEN));
  552. offset += TarHeader.MODTIMELEN;
  553. checkSum = (int)TarHeader.ParseOctal(header, offset, TarHeader.CHKSUMLEN);
  554. offset += TarHeader.CHKSUMLEN;
  555. typeFlag = header[ offset++ ];
  556. linkName = TarHeader.ParseName(header, offset, TarHeader.NAMELEN);
  557. offset += TarHeader.NAMELEN;
  558. magic = TarHeader.ParseName(header, offset, TarHeader.MAGICLEN);
  559. offset += TarHeader.MAGICLEN;
  560. version = TarHeader.ParseName(header, offset, TarHeader.VERSIONLEN);
  561. offset += TarHeader.VERSIONLEN;
  562. userName = TarHeader.ParseName(header, offset, TarHeader.UNAMELEN);
  563. offset += TarHeader.UNAMELEN;
  564. groupName = TarHeader.ParseName(header, offset, TarHeader.GNAMELEN);
  565. offset += TarHeader.GNAMELEN;
  566. devMajor = (int)TarHeader.ParseOctal(header, offset, TarHeader.DEVLEN);
  567. offset += TarHeader.DEVLEN;
  568. devMinor = (int)TarHeader.ParseOctal(header, offset, TarHeader.DEVLEN);
  569. // Fields past this point not currently parsed or used...
  570. }
  571. /// <summary>
  572. /// 'Write' header information to buffer provided
  573. /// </summary>
  574. /// <param name="outbuf">output buffer for header information</param>
  575. public void WriteHeader(byte[] outbuf)
  576. {
  577. int offset = 0;
  578. offset = GetNameBytes(this.name, outbuf, offset, TarHeader.NAMELEN);
  579. offset = GetOctalBytes(this.mode, outbuf, offset, TarHeader.MODELEN);
  580. offset = GetOctalBytes(this.userId, outbuf, offset, TarHeader.UIDLEN);
  581. offset = GetOctalBytes(this.groupId, outbuf, offset, TarHeader.GIDLEN);
  582. long size = this.size;
  583. offset = GetLongOctalBytes(size, outbuf, offset, TarHeader.SIZELEN);
  584. offset = GetLongOctalBytes(GetCTime(this.modTime), outbuf, offset, TarHeader.MODTIMELEN);
  585. int csOffset = offset;
  586. for (int c = 0; c < TarHeader.CHKSUMLEN; ++c)
  587. {
  588. outbuf[offset++] = (byte)' ';
  589. }
  590. outbuf[offset++] = this.typeFlag;
  591. offset = GetNameBytes(this.linkName, outbuf, offset, NAMELEN);
  592. offset = GetNameBytes(this.magic, outbuf, offset, MAGICLEN);
  593. offset = GetNameBytes(this.version, outbuf, offset, VERSIONLEN);
  594. offset = GetNameBytes(this.userName, outbuf, offset, UNAMELEN);
  595. offset = GetNameBytes(this.groupName, outbuf, offset, GNAMELEN);
  596. if (this.typeFlag == LF_CHR || this.typeFlag == LF_BLK)
  597. {
  598. offset = GetOctalBytes(this.devMajor, outbuf, offset, DEVLEN);
  599. offset = GetOctalBytes(this.devMinor, outbuf, offset, DEVLEN);
  600. }
  601. for ( ; offset < outbuf.Length; )
  602. {
  603. outbuf[offset++] = 0;
  604. }
  605. long checkSum = ComputeCheckSum(outbuf);
  606. GetCheckSumOctalBytes(checkSum, outbuf, csOffset, CHKSUMLEN);
  607. }
  608. }
  609. }
  610. /* The original Java file had this header:
  611. *
  612. ** Authored by Timothy Gerard Endres
  613. ** <mailto:[email protected]> <http://www.trustice.com>
  614. **
  615. ** This work has been placed into the public domain.
  616. ** You may use this work in any way and for any purpose you wish.
  617. **
  618. ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
  619. ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
  620. ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
  621. ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
  622. ** REDISTRIBUTION OF THIS SOFTWARE.
  623. **
  624. */