summaryrefslogtreecommitdiffstats
path: root/apt-inst/contrib/arfile.cc
blob: 6d4a1f158c16b932b3e1295f5e12d4849bdeda6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// -*- mode: cpp; mode: fold -*-
// Description								/*{{{*/
/* ######################################################################

   AR File - Handle an 'AR' archive
   
   AR Archives have plain text headers at the start of each file
   section. The headers are aligned on a 2 byte boundary.
   
   Information about the structure of AR files can be found in ar(5)
   on a BSD system, or in the binutils source.

   ##################################################################### */
									/*}}}*/
// Include Files							/*{{{*/
#include <config.h>

#include <apt-pkg/arfile.h>
#include <apt-pkg/error.h>
#include <apt-pkg/fileutl.h>
#include <apt-pkg/strutl.h>

#include <string>
#include <string.h>
#include <sys/types.h>

#include <apti18n.h>
									/*}}}*/

struct ARArchive::MemberHeader
{
   char Name[16];
   char MTime[12];
   char UID[6];
   char GID[6];
   char Mode[8];
   char Size[10];
   char Magic[2];
};

// ARArchive::ARArchive - Constructor					/*{{{*/
// ---------------------------------------------------------------------
/* */
ARArchive::ARArchive(FileFd &File) : List(0), File(File)
{
   LoadHeaders();
}
									/*}}}*/
// ARArchive::~ARArchive - Destructor					/*{{{*/
// ---------------------------------------------------------------------
/* */
ARArchive::~ARArchive()
{
   while (List != 0)
   {
      Member *Tmp = List;
      List = List->Next;
      delete Tmp;
   }   
}
									/*}}}*/
// ARArchive::LoadHeaders - Load the headers from each file		/*{{{*/
// ---------------------------------------------------------------------
/* AR files are structured with a 8 byte magic string followed by a 60
   byte plain text header then the file data, another header, data, etc */
bool ARArchive::LoadHeaders()
{
   off_t Left = File.Size();
   
   // Check the magic byte
   char Magic[8];
   if (File.Read(Magic,sizeof(Magic)) == false)
      return false;
   if (memcmp(Magic,"!<arch>\012",sizeof(Magic)) != 0)
      return _error->Error(_("Invalid archive signature"));
   Left -= sizeof(Magic);
   
   // Read the member list
   while (Left > 0)
   {
      MemberHeader Head;
      if (File.Read(&Head,sizeof(Head)) == false)
	 return _error->Error(_("Error reading archive member header"));
      Left -= sizeof(Head);

      // Convert all of the integer members
      Member *Memb = new Member();
      if (StrToNum(Head.MTime,Memb->MTime,sizeof(Head.MTime)) == false ||
	  StrToNum(Head.UID,Memb->UID,sizeof(Head.UID)) == false ||
	  StrToNum(Head.GID,Memb->GID,sizeof(Head.GID)) == false ||
	  StrToNum(Head.Mode,Memb->Mode,sizeof(Head.Mode),8) == false ||
	  StrToNum(Head.Size,Memb->Size,sizeof(Head.Size)) == false)
      {
	 delete Memb;
	 return _error->Error(_("Invalid archive member header"));
      }

      if (Left < 0 || Memb->Size > static_cast<unsigned long long>(Left))
      {
	 delete Memb;
	 return _error->Error(_("Invalid archive member header"));
      }
      // Check for an extra long name string
      if (memcmp(Head.Name,"#1/",3) == 0)
      {
	 char S[300];
	 unsigned long Len;
	 if (StrToNum(Head.Name+3,Len,sizeof(Head.Size)-3) == false ||
	     Len >= sizeof(S))
	 {
	    delete Memb;
	    return _error->Error(_("Invalid archive member header"));
	 }

	 if (Len > Memb->Size)
	 {
	    delete Memb;
	    return _error->Error(_("Invalid archive member header"));
	 }

	 if (File.Read(S,Len) == false)
	 {
	    delete Memb;
	    return false;
	 }
	 S[Len] = 0;
	 Memb->Name = S;
	 Memb->Size -= Len;
	 Left -= Len;
      }
      else
      {
	 unsigned int I = sizeof(Head.Name) - 1;
	 for (; Head.Name[I] == ' ' || Head.Name[I] == '/'; I--)
	 {
	    if (I == 0)
	    {
	       delete Memb;
	       return _error->Error(_("Invalid archive member header"));
	    }
	 }
	 Memb->Name = std::string(Head.Name,I+1);
      }

      // Account for the AR header alignment 
      off_t Skip = Memb->Size % 2;
      
      // Add it to the list
      Memb->Next = List;
      List = Memb;
      Memb->Start = File.Tell();
      if (File.Skip(Memb->Size + Skip) == false)
	 return false;
      if (Left < (off_t)(Memb->Size + Skip))
	 return _error->Error(_("Archive is too short"));
      Left -= Memb->Size + Skip;
   }   
   if (Left != 0)
      return _error->Error(_("Failed to read the archive headers"));
   
   return true;
}
									/*}}}*/
// ARArchive::FindMember - Find a name in the member list		/*{{{*/
// ---------------------------------------------------------------------
/* Find a member with the given name */
const ARArchive::Member *ARArchive::FindMember(const char *Name) const
{
   const Member *Res = List;
   while (Res != 0)
   {
      if (Res->Name == Name)
	 return Res;
      Res = Res->Next;
   }
   
   return 0;
}
									/*}}}*/