PageRenderTime 46ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/SourseRestore/zip/Tar/TarEntry.cs

#
C# | 571 lines | 262 code | 54 blank | 255 comment | 20 complexity | e79fc18c07a7b4265b4e10dce3cf8990 MD5 | raw file
  1. // TarEntry.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. using System;
  36. using System.IO;
  37. using System.Text;
  38. namespace ICSharpCode.SharpZipLib.Tar
  39. {
  40. /// <summary>
  41. /// This class represents an entry in a Tar archive. It consists
  42. /// of the entry's header, as well as the entry's File. Entries
  43. /// can be instantiated in one of three ways, depending on how
  44. /// they are to be used.
  45. /// <p>
  46. /// TarEntries that are created from the header bytes read from
  47. /// an archive are instantiated with the TarEntry( byte[] )
  48. /// constructor. These entries will be used when extracting from
  49. /// or listing the contents of an archive. These entries have their
  50. /// header filled in using the header bytes. They also set the File
  51. /// to null, since they reference an archive entry not a file.</p>
  52. /// <p>
  53. /// TarEntries that are created from files that are to be written
  54. /// into an archive are instantiated with the CreateEntryFromFile(string)
  55. /// pseudo constructor. These entries have their header filled in using
  56. /// the File's information. They also keep a reference to the File
  57. /// for convenience when writing entries.</p>
  58. /// <p>
  59. /// Finally, TarEntries can be constructed from nothing but a name.
  60. /// This allows the programmer to construct the entry by hand, for
  61. /// instance when only an InputStream is available for writing to
  62. /// the archive, and the header information is constructed from
  63. /// other information. In this case the header fields are set to
  64. /// defaults and the File is set to null.</p>
  65. ///
  66. /// <see cref="TarHeader"/>
  67. /// </summary>
  68. public class TarEntry : ICloneable
  69. {
  70. /// <summary>
  71. /// The name of the file this entry represents or null if the entry is not based on a file.
  72. /// </summary>
  73. string file;
  74. /// <summary>
  75. /// The entry's header information.
  76. /// </summary>
  77. TarHeader header;
  78. /// <summary>
  79. /// Only allow creation of Entries with the static CreateXYZ factory methods.
  80. /// </summary>
  81. private TarEntry()
  82. {
  83. }
  84. /// <summary>
  85. /// Construct an entry from an archive's header bytes. File is set
  86. /// to null.
  87. /// </summary>
  88. /// <param name = "headerBuf">
  89. /// The header bytes from a tar archive entry.
  90. /// </param>
  91. public TarEntry(byte[] headerBuf)
  92. {
  93. this.Initialize();
  94. this.header.ParseBuffer(headerBuf);
  95. }
  96. /// <summary>
  97. /// Construct a TarEntry using the <paramref name="header">header</paramref> provided
  98. /// </summary>
  99. /// <param name="header">Header details for entry</param>
  100. public TarEntry(TarHeader header)
  101. {
  102. file = null;
  103. this.header = header;
  104. }
  105. /// <summary>
  106. /// Clone this tar entry.
  107. /// </summary>
  108. /// <returns>Returns a clone of this entry.</returns>
  109. public object Clone()
  110. {
  111. TarEntry entry = new TarEntry();
  112. entry.file = this.file;
  113. entry.header = (TarHeader)this.header.Clone();
  114. entry.Name = this.Name;
  115. return entry;
  116. }
  117. /// <summary>
  118. /// Construct an entry with only a <paramref name="name"></paramref>.
  119. /// This allows the programmer to construct the entry's header "by hand".
  120. /// </summary>
  121. public static TarEntry CreateTarEntry(string name)
  122. {
  123. TarEntry entry = new TarEntry();
  124. entry.Initialize();
  125. entry.NameTarHeader(entry.header, name);
  126. return entry;
  127. }
  128. /// <summary>
  129. /// Construct an entry for a file. File is set to file, and the
  130. /// header is constructed from information from the file.
  131. /// </summary>
  132. /// <param name = "fileName">
  133. /// The file that the entry represents.
  134. /// </param>
  135. public static TarEntry CreateEntryFromFile(string fileName)
  136. {
  137. TarEntry entry = new TarEntry();
  138. entry.Initialize();
  139. entry.GetFileTarHeader(entry.header, fileName);
  140. return entry;
  141. }
  142. /// <summary>
  143. /// Initialization code common to all pseudo constructors.
  144. /// </summary>
  145. void Initialize()
  146. {
  147. this.file = null;
  148. this.header = new TarHeader();
  149. }
  150. /// <summary>
  151. /// Determine if the two entries are equal. Equality is determined
  152. /// by the header names being equal.
  153. /// </summary>
  154. /// <returns>
  155. /// True if the entries are equal.
  156. /// </returns>
  157. public override bool Equals(object it)
  158. {
  159. if (!(it is TarEntry))
  160. {
  161. return false;
  162. }
  163. return this.Name.Equals(((TarEntry)it).Name);
  164. }
  165. /// <summary>
  166. /// Must be overridden when you override Equals.
  167. /// </summary>
  168. public override int GetHashCode()
  169. {
  170. return Name.GetHashCode();
  171. }
  172. /// <summary>
  173. /// Determine if the given entry is a descendant of this entry.
  174. /// Descendancy is determined by the name of the descendant
  175. /// starting with this entry's name.
  176. /// </summary>
  177. /// <param name = "desc">
  178. /// Entry to be checked as a descendent of this.
  179. /// </param>
  180. /// <returns>
  181. /// True if entry is a descendant of this.
  182. /// </returns>
  183. public bool IsDescendent(TarEntry desc)
  184. {
  185. return desc.Name.StartsWith(Name);
  186. }
  187. /// <summary>
  188. /// Get this entry's header.
  189. /// </summary>
  190. /// <returns>
  191. /// This entry's TarHeader.
  192. /// </returns>
  193. public TarHeader TarHeader
  194. {
  195. get
  196. {
  197. return this.header;
  198. }
  199. }
  200. /// <summary>
  201. /// Get/Set this entry's name.
  202. /// </summary>
  203. public string Name
  204. {
  205. get
  206. {
  207. return header.Name;
  208. }
  209. set
  210. {
  211. header.Name = value;
  212. }
  213. }
  214. /// <summary>
  215. /// Get/set this entry's user id.
  216. /// </summary>
  217. public int UserId
  218. {
  219. get
  220. {
  221. return header.UserId;
  222. }
  223. set
  224. {
  225. header.UserId = value;
  226. }
  227. }
  228. /// <summary>
  229. /// Get/set this entry's group id.
  230. /// </summary>
  231. public int GroupId
  232. {
  233. get
  234. {
  235. return this.header.GroupId;
  236. }
  237. set
  238. {
  239. this.header.GroupId = value;
  240. }
  241. }
  242. /// <summary>
  243. /// Get/set this entry's user name.
  244. /// </summary>
  245. public string UserName
  246. {
  247. get
  248. {
  249. return this.header.UserName;
  250. }
  251. set
  252. {
  253. this.header.UserName = value;
  254. }
  255. }
  256. /// <summary>
  257. /// Get/set this entry's group name.
  258. /// </summary>
  259. public string GroupName
  260. {
  261. get
  262. {
  263. return this.header.GroupName;
  264. }
  265. set
  266. {
  267. this.header.GroupName = value;
  268. }
  269. }
  270. /// <summary>
  271. /// Convenience method to set this entry's group and user ids.
  272. /// </summary>
  273. /// <param name="userId">
  274. /// This entry's new user id.
  275. /// </param>
  276. /// <param name="groupId">
  277. /// This entry's new group id.
  278. /// </param>
  279. public void SetIds(int userId, int groupId)
  280. {
  281. UserId = userId;
  282. GroupId = groupId;
  283. }
  284. /// <summary>
  285. /// Convenience method to set this entry's group and user names.
  286. /// </summary>
  287. /// <param name="userName">
  288. /// This entry's new user name.
  289. /// </param>
  290. /// <param name="groupName">
  291. /// This entry's new group name.
  292. /// </param>
  293. public void SetNames(string userName, string groupName)
  294. {
  295. UserName = userName;
  296. GroupName = groupName;
  297. }
  298. /// <summary>
  299. /// Get/Set the modification time for this entry
  300. /// </summary>
  301. public DateTime ModTime
  302. {
  303. get
  304. {
  305. return this.header.ModTime;
  306. }
  307. set
  308. {
  309. this.header.ModTime = value;
  310. }
  311. }
  312. /// <summary>
  313. /// Get this entry's file.
  314. /// </summary>
  315. /// <returns>
  316. /// This entry's file.
  317. /// </returns>
  318. public string File
  319. {
  320. get
  321. {
  322. return this.file;
  323. }
  324. }
  325. /// <summary>
  326. /// Get/set this entry's recorded file size.
  327. /// </summary>
  328. public long Size
  329. {
  330. get
  331. {
  332. return this.header.Size;
  333. }
  334. set
  335. {
  336. this.header.Size = value;
  337. }
  338. }
  339. /// <summary>
  340. /// Convenience method that will modify an entry's name directly
  341. /// in place in an entry header buffer byte array.
  342. /// </summary>
  343. /// <param name="outbuf">
  344. /// The buffer containing the entry header to modify.
  345. /// </param>
  346. /// <param name="newName">
  347. /// The new name to place into the header buffer.
  348. /// </param>
  349. public void AdjustEntryName(byte[] outbuf, string newName)
  350. {
  351. int offset = 0;
  352. TarHeader.GetNameBytes(newName, outbuf, offset, TarHeader.NAMELEN);
  353. }
  354. /// <summary>
  355. /// Return true if this entry represents a directory, false otherwise
  356. /// </summary>
  357. /// <returns>
  358. /// True if this entry is a directory.
  359. /// </returns>
  360. public bool IsDirectory
  361. {
  362. get
  363. {
  364. if (this.file != null)
  365. {
  366. return Directory.Exists(file);
  367. }
  368. if (this.header != null)
  369. {
  370. if (this.header.TypeFlag == TarHeader.LF_DIR || Name.EndsWith("/"))
  371. {
  372. return true;
  373. }
  374. }
  375. return false;
  376. }
  377. }
  378. /// <summary>
  379. /// Fill in a TarHeader with information from a File.
  380. /// </summary>
  381. /// <param name="hdr">
  382. /// The TarHeader to fill in.
  383. /// </param>
  384. /// <param name="file">
  385. /// The file from which to get the header information.
  386. /// </param>
  387. public void GetFileTarHeader(TarHeader hdr, string file)
  388. {
  389. this.file = file;
  390. // bugfix from torhovl from #D forum:
  391. string name = file;
  392. #if !COMPACT_FRAMEWORK
  393. // 23-Jan-2004 GnuTar allows device names in path where the name is not local to the current directory
  394. if (name.IndexOf(Environment.CurrentDirectory) == 0)
  395. {
  396. name = name.Substring(Environment.CurrentDirectory.Length);
  397. }
  398. #endif
  399. /*
  400. if (Path.DirectorySeparatorChar == '\\')
  401. { // check if the OS is Windows
  402. // Strip off drive letters!
  403. if (name.Length > 2)
  404. {
  405. char ch1 = name[0];
  406. char ch2 = name[1];
  407. if (ch2 == ':' && Char.IsLetter(ch1))
  408. {
  409. name = name.Substring(2);
  410. }
  411. }
  412. }
  413. */
  414. name = name.Replace(Path.DirectorySeparatorChar, '/');
  415. // No absolute pathnames
  416. // Windows (and Posix?) paths can start with UNC style "\\NetworkDrive\",
  417. // so we loop on starting /'s.
  418. while (name.StartsWith("/"))
  419. {
  420. name = name.Substring(1);
  421. }
  422. hdr.LinkName = String.Empty;
  423. hdr.Name = name;
  424. if (Directory.Exists(file))
  425. {
  426. hdr.Mode = 1003; // Magic number for security access for a UNIX filesystem
  427. hdr.TypeFlag = TarHeader.LF_DIR;
  428. if (hdr.Name.Length == 0 || hdr.Name[hdr.Name.Length - 1] != '/')
  429. {
  430. hdr.Name = hdr.Name + "/";
  431. }
  432. hdr.Size = 0;
  433. }
  434. else
  435. {
  436. hdr.Mode = 33216; // Magic number for security access for a UNIX filesystem
  437. hdr.TypeFlag = TarHeader.LF_NORMAL;
  438. hdr.Size = new FileInfo(file.Replace('/', Path.DirectorySeparatorChar)).Length;
  439. }
  440. hdr.ModTime = System.IO.File.GetLastWriteTime(file.Replace('/', Path.DirectorySeparatorChar)).ToUniversalTime();
  441. hdr.DevMajor = 0;
  442. hdr.DevMinor = 0;
  443. }
  444. /// <summary>
  445. /// Get entries for all files present in this entries directory.
  446. /// If this entry doesnt represent a directory zero entries are returned.
  447. /// </summary>
  448. /// <returns>
  449. /// An array of TarEntry's for this entry's children.
  450. /// </returns>
  451. public TarEntry[] GetDirectoryEntries()
  452. {
  453. if (this.file == null || !Directory.Exists(this.file))
  454. {
  455. return new TarEntry[0];
  456. }
  457. string[] list = Directory.GetFileSystemEntries(this.file);
  458. TarEntry[] result = new TarEntry[list.Length];
  459. for (int i = 0; i < list.Length; ++i)
  460. {
  461. result[i] = TarEntry.CreateEntryFromFile(list[i]);
  462. }
  463. return result;
  464. }
  465. /// <summary>
  466. /// Write an entry's header information to a header buffer.
  467. /// </summary>
  468. /// <param name = "outbuf">
  469. /// The tar entry header buffer to fill in.
  470. /// </param>
  471. public void WriteEntryHeader(byte[] outbuf)
  472. {
  473. this.header.WriteHeader(outbuf);
  474. }
  475. /// <summary>
  476. /// Fill in a TarHeader given only the entry's name.
  477. /// </summary>
  478. /// <param name="hdr">
  479. /// The TarHeader to fill in.
  480. /// </param>
  481. /// <param name="name">
  482. /// The tar entry name.
  483. /// </param>
  484. public void NameTarHeader(TarHeader hdr, string name)
  485. {
  486. bool isDir = name.EndsWith("/");
  487. hdr.Name = name;
  488. hdr.Mode = isDir ? 1003 : 33216;
  489. hdr.UserId = 0;
  490. hdr.GroupId = 0;
  491. hdr.Size = 0;
  492. hdr.ModTime = DateTime.UtcNow;
  493. hdr.TypeFlag = isDir ? TarHeader.LF_DIR : TarHeader.LF_NORMAL;
  494. hdr.LinkName = String.Empty;
  495. hdr.UserName = String.Empty;
  496. hdr.GroupName = String.Empty;
  497. hdr.DevMajor = 0;
  498. hdr.DevMinor = 0;
  499. }
  500. }
  501. }
  502. /* The original Java file had this header:
  503. *
  504. ** Authored by Timothy Gerard Endres
  505. ** <mailto:time@gjt.org> <http://www.trustice.com>
  506. **
  507. ** This work has been placed into the public domain.
  508. ** You may use this work in any way and for any purpose you wish.
  509. **
  510. ** THIS SOFTWARE IS PROVIDED AS-IS WITHOUT WARRANTY OF ANY KIND,
  511. ** NOT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY. THE AUTHOR
  512. ** OF THIS SOFTWARE, ASSUMES _NO_ RESPONSIBILITY FOR ANY
  513. ** CONSEQUENCE RESULTING FROM THE USE, MODIFICATION, OR
  514. ** REDISTRIBUTION OF THIS SOFTWARE.
  515. **
  516. */