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