]> git.saurik.com Git - apt.git/blob - apt-inst/contrib/arfile.cc
don't change owner/perms/times through file:// symlinks
[apt.git] / apt-inst / contrib / arfile.cc
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
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 boundary.
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 #include<config.h>
18
19 #include <apt-pkg/arfile.h>
20 #include <apt-pkg/strutl.h>
21 #include <apt-pkg/fileutl.h>
22 #include <apt-pkg/error.h>
23
24 #include <string.h>
25 #include <sys/types.h>
26 #include <string>
27
28 #include <apti18n.h>
29 /*}}}*/
30
31 struct 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 /* */
45 ARArchive::ARArchive(FileFd &File) : List(0), File(File)
46 {
47 LoadHeaders();
48 }
49 /*}}}*/
50 // ARArchive::~ARArchive - Destructor /*{{{*/
51 // ---------------------------------------------------------------------
52 /* */
53 ARArchive::~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 */
67 bool ARArchive::LoadHeaders()
68 {
69 off_t Left = File.Size();
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)
76 return _error->Error(_("Invalid archive signature"));
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)
84 return _error->Error(_("Error reading archive member header"));
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;
96 return _error->Error(_("Invalid archive member header %s"), Head.Name);
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 ||
105 Len >= sizeof(S))
106 {
107 delete Memb;
108 return _error->Error(_("Invalid archive member header"));
109 }
110 if (File.Read(S,Len) == false)
111 {
112 delete Memb;
113 return false;
114 }
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;
123 for (; Head.Name[I] == ' ' || Head.Name[I] == '/'; I--);
124 Memb->Name = std::string(Head.Name,I+1);
125 }
126
127 // Account for the AR header alignment
128 off_t Skip = Memb->Size % 2;
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;
136 if (Left < (off_t)(Memb->Size + Skip))
137 return _error->Error(_("Archive is too short"));
138 Left -= Memb->Size + Skip;
139 }
140 if (Left != 0)
141 return _error->Error(_("Failed to read the archive headers"));
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 */
149 const 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 /*}}}*/