arfile.cc 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: arfile.cc,v 1.6.2.1 2004/01/16 18:58:50 mdz Exp $
  4. /* ######################################################################
  5. AR File - Handle an 'AR' archive
  6. AR Archives have plain text headers at the start of each file
  7. section. The headers are aligned on a 2 byte boundry.
  8. Information about the structure of AR files can be found in ar(5)
  9. on a BSD system, or in the binutils source.
  10. ##################################################################### */
  11. /*}}}*/
  12. // Include Files /*{{{*/
  13. #include<config.h>
  14. #include <apt-pkg/arfile.h>
  15. #include <apt-pkg/strutl.h>
  16. #include <apt-pkg/error.h>
  17. #include <stdlib.h>
  18. #include <apti18n.h>
  19. /*}}}*/
  20. struct ARArchive::MemberHeader
  21. {
  22. char Name[16];
  23. char MTime[12];
  24. char UID[6];
  25. char GID[6];
  26. char Mode[8];
  27. char Size[10];
  28. char Magic[2];
  29. };
  30. // ARArchive::ARArchive - Constructor /*{{{*/
  31. // ---------------------------------------------------------------------
  32. /* */
  33. ARArchive::ARArchive(FileFd &File) : List(0), File(File)
  34. {
  35. LoadHeaders();
  36. }
  37. /*}}}*/
  38. // ARArchive::~ARArchive - Destructor /*{{{*/
  39. // ---------------------------------------------------------------------
  40. /* */
  41. ARArchive::~ARArchive()
  42. {
  43. while (List != 0)
  44. {
  45. Member *Tmp = List;
  46. List = List->Next;
  47. delete Tmp;
  48. }
  49. }
  50. /*}}}*/
  51. // ARArchive::LoadHeaders - Load the headers from each file /*{{{*/
  52. // ---------------------------------------------------------------------
  53. /* AR files are structured with a 8 byte magic string followed by a 60
  54. byte plain text header then the file data, another header, data, etc */
  55. bool ARArchive::LoadHeaders()
  56. {
  57. signed long Left = File.Size();
  58. // Check the magic byte
  59. char Magic[8];
  60. if (File.Read(Magic,sizeof(Magic)) == false)
  61. return false;
  62. if (memcmp(Magic,"!<arch>\012",sizeof(Magic)) != 0)
  63. return _error->Error(_("Invalid archive signature"));
  64. Left -= sizeof(Magic);
  65. // Read the member list
  66. while (Left > 0)
  67. {
  68. MemberHeader Head;
  69. if (File.Read(&Head,sizeof(Head)) == false)
  70. return _error->Error(_("Error reading archive member header"));
  71. Left -= sizeof(Head);
  72. // Convert all of the integer members
  73. Member *Memb = new Member();
  74. if (StrToNum(Head.MTime,Memb->MTime,sizeof(Head.MTime)) == false ||
  75. StrToNum(Head.UID,Memb->UID,sizeof(Head.UID)) == false ||
  76. StrToNum(Head.GID,Memb->GID,sizeof(Head.GID)) == false ||
  77. StrToNum(Head.Mode,Memb->Mode,sizeof(Head.Mode),8) == false ||
  78. StrToNum(Head.Size,Memb->Size,sizeof(Head.Size)) == false)
  79. {
  80. delete Memb;
  81. return _error->Error(_("Invalid archive member header %s"), Head.Name);
  82. }
  83. // Check for an extra long name string
  84. if (memcmp(Head.Name,"#1/",3) == 0)
  85. {
  86. char S[300];
  87. unsigned long Len;
  88. if (StrToNum(Head.Name+3,Len,sizeof(Head.Size)-3) == false ||
  89. Len >= sizeof(S))
  90. {
  91. delete Memb;
  92. return _error->Error(_("Invalid archive member header"));
  93. }
  94. if (File.Read(S,Len) == false)
  95. return false;
  96. S[Len] = 0;
  97. Memb->Name = S;
  98. Memb->Size -= Len;
  99. Left -= Len;
  100. }
  101. else
  102. {
  103. unsigned int I = sizeof(Head.Name) - 1;
  104. for (; Head.Name[I] == ' ' || Head.Name[I] == '/'; I--);
  105. Memb->Name = std::string(Head.Name,I+1);
  106. }
  107. // Account for the AR header alignment
  108. unsigned Skip = Memb->Size % 2;
  109. // Add it to the list
  110. Memb->Next = List;
  111. List = Memb;
  112. Memb->Start = File.Tell();
  113. if (File.Skip(Memb->Size + Skip) == false)
  114. return false;
  115. if (Left < (signed)(Memb->Size + Skip))
  116. return _error->Error(_("Archive is too short"));
  117. Left -= Memb->Size + Skip;
  118. }
  119. if (Left != 0)
  120. return _error->Error(_("Failed to read the archive headers"));
  121. return true;
  122. }
  123. /*}}}*/
  124. // ARArchive::FindMember - Find a name in the member list /*{{{*/
  125. // ---------------------------------------------------------------------
  126. /* Find a member with the given name */
  127. const ARArchive::Member *ARArchive::FindMember(const char *Name) const
  128. {
  129. const Member *Res = List;
  130. while (Res != 0)
  131. {
  132. if (Res->Name == Name)
  133. return Res;
  134. Res = Res->Next;
  135. }
  136. return 0;
  137. }
  138. /*}}}*/