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