]>
git.saurik.com Git - apt.git/blob - ftparchive/contents.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: contents.cc,v 1.4 2003/02/10 07:34:41 doogie Exp $
4 /* ######################################################################
6 contents - Archive contents generator
8 The GenContents class is a back end for an archive contents generator.
9 It takes a list of per-deb file name and merges it into a memory
10 database of all previous output. This database is stored as a set
11 of binary trees linked across directories to form a tree of all files+dirs
12 given to it. The tree will also be sorted as it is built up thus
13 removing the massive sort time overhead.
15 By breaking all the pathnames into components and storing them
16 separately a space saving is realized by not duplicating the string
17 over and over again. Ultimately this saving is sacrificed to storage of
18 the tree structure itself but the tree structure yields a speed gain
19 in the sorting and processing. Ultimately it takes about 5 seconds to
20 do 141000 nodes and about 5 meg of ram.
22 The tree looks something like:
30 The ---> is the DirDown link
33 ##################################################################### */
35 // Include Files /*{{{*/
38 #include <apt-pkg/debfile.h>
39 #include <apt-pkg/dirstream.h>
40 #include <apt-pkg/error.h>
41 #include <apt-pkg/fileutl.h>
52 // GenContents::~GenContents - Free allocated memory /*{{{*/
53 // ---------------------------------------------------------------------
54 /* Since all our allocations are static big-block allocations all that is
55 needed is to free all of them. */
56 GenContents::~GenContents()
58 while (BlockList
!= 0)
60 BigBlock
*Old
= BlockList
;
61 BlockList
= Old
->Next
;
67 // GenContents::Mystrdup - Custom strdup /*{{{*/
68 // ---------------------------------------------------------------------
69 /* This strdup also uses a large block allocator to eliminate glibc
71 char *GenContents::Mystrdup(const char *From
)
73 unsigned int Len
= strlen(From
) + 1;
77 StrPool
= (char *)malloc(StrLeft
);
79 BigBlock
*Block
= new BigBlock
;
80 Block
->Block
= StrPool
;
81 Block
->Next
= BlockList
;
85 memcpy(StrPool
,From
,Len
);
93 // GenContents::Node::operator new - Big block allocator /*{{{*/
94 // ---------------------------------------------------------------------
95 /* This eliminates glibc's malloc overhead by allocating large blocks and
96 having a continuous set of Nodes. This takes about 8 bytes off each nodes
97 space needs. Freeing is not supported. */
98 void *GenContents::Node::operator new(size_t Amount
,GenContents
*Owner
)
100 if (Owner
->NodeLeft
== 0)
102 Owner
->NodeLeft
= 10000;
103 Owner
->NodePool
= static_cast<Node
*>(malloc(Amount
*Owner
->NodeLeft
));
104 BigBlock
*Block
= new BigBlock
;
105 Block
->Block
= Owner
->NodePool
;
106 Block
->Next
= Owner
->BlockList
;
107 Owner
->BlockList
= Block
;
111 return Owner
->NodePool
++;
114 // GenContents::Grab - Grab a new node representing Name under Top /*{{{*/
115 // ---------------------------------------------------------------------
116 /* This grabs a new node representing the pathname component Name under
117 the node Top. The node is given the name Package. It is assumed that Name
118 is inside of top. If a duplicate already entered name is found then
119 a note is made on the Dup list and the previous in-tree node is returned. */
120 GenContents::Node
*GenContents::Grab(GenContents::Node
*Top
,const char *Name
,
123 /* We drop down to the next dir level each call. This simplifies
124 the calling routine */
125 if (Top
->DirDown
== 0)
127 Node
*Item
= new(this) Node
;
128 Item
->Path
= Mystrdup(Name
);
129 Item
->Package
= Package
;
138 Res
= strcmp(Name
,Top
->Path
);
143 // See if this the the same package (multi-version dup)
144 if (Top
->Package
== Package
||
145 strcasecmp(Top
->Package
,Package
) == 0)
148 // Look for an already existing Dup
149 for (Node
*I
= Top
->Dups
; I
!= 0; I
= I
->Dups
)
150 if (I
->Package
== Package
||
151 strcasecmp(I
->Package
,Package
) == 0)
155 Node
*Item
= new(this) Node
;
156 Item
->Path
= Top
->Path
;
157 Item
->Package
= Package
;
158 Item
->Dups
= Top
->Dups
;
163 // Continue to traverse the tree
166 if (Top
->BTreeLeft
== 0)
168 Top
= Top
->BTreeLeft
;
172 if (Top
->BTreeRight
== 0)
174 Top
= Top
->BTreeRight
;
178 // The item was not found in the tree
179 Node
*Item
= new(this) Node
;
180 Item
->Path
= Mystrdup(Name
);
181 Item
->Package
= Package
;
183 // Link it into the tree
186 Item
->BTreeLeft
= Top
->BTreeLeft
;
187 Top
->BTreeLeft
= Item
;
191 Item
->BTreeRight
= Top
->BTreeRight
;
192 Top
->BTreeRight
= Item
;
198 // GenContents::Add - Add a path to the tree /*{{{*/
199 // ---------------------------------------------------------------------
200 /* This takes a full pathname and adds it into the tree. We split the
201 pathname into directory fragments adding each one as we go. Technically
202 in output from tar this should result in hitting previous items. */
203 void GenContents::Add(const char *Dir
,const char *Package
)
205 Node
*Root
= &this->Root
;
207 // Drop leading slashes
208 while (*Dir
== '/' && *Dir
!= 0)
211 // Run over the string and grab out each bit up to and including a /
212 const char *Start
= Dir
;
216 if (*I
!= '/' || I
- Start
<= 1)
223 // Copy the path fragment over
225 strncpy(Tmp
,Start
,I
- Start
);
228 // Grab a node for it
229 Root
= Grab(Root
,Tmp
,Package
);
234 // The final component if it does not have a trailing /
236 Grab(Root
,Start
,Package
);
239 // GenContents::WriteSpace - Write a given number of white space chars /*{{{*/
240 // ---------------------------------------------------------------------
241 /* We mod 8 it and write tabs where possible. */
242 void GenContents::WriteSpace(std::string
&out
, size_t Current
, size_t Target
)
244 if (Target
<= Current
)
245 Target
= Current
+ 1;
247 /* Now we write tabs so long as the next tab stop would not pass
249 for (; (Current
/8 + 1)*8 < Target
; Current
= (Current
/8 + 1)*8)
252 // Fill the last bit with spaces
253 for (; Current
< Target
; Current
++)
257 // GenContents::Print - Display the tree /*{{{*/
258 // ---------------------------------------------------------------------
259 /* This is the final result function. It takes the tree and recursively
260 calls itself and runs over each section of the tree printing out
261 the pathname and the hit packages. We use Buf to build the pathname
262 summed over all the directory parents of this node. */
263 void GenContents::Print(FileFd
&Out
)
267 DoPrint(Out
,&Root
,Buffer
);
269 void GenContents::DoPrint(FileFd
&Out
,GenContents::Node
*Top
, char *Buf
)
275 DoPrint(Out
,Top
->BTreeLeft
,Buf
);
277 // Print the current dir location and then descend to lower dirs
278 char *OldEnd
= Buf
+ strlen(Buf
);
281 strcat(Buf
,Top
->Path
);
283 // Do not show the item if it is a directory with dups
284 if (Top
->Path
[strlen(Top
->Path
)-1] != '/' /*|| Top->Dups == 0*/)
286 std::string out
= Buf
;
287 WriteSpace(out
, out
.length(), 60);
288 for (Node
*I
= Top
; I
!= 0; I
= I
->Dups
)
292 out
.append(I
->Package
);
295 Out
.Write(out
.c_str(), out
.length());
299 // Go along the directory link
300 DoPrint(Out
,Top
->DirDown
,Buf
);
304 DoPrint(Out
,Top
->BTreeRight
,Buf
);
307 // ContentsExtract Constructor /*{{{*/
308 ContentsExtract::ContentsExtract()
309 : Data(0), MaxSize(0), CurSize(0)
313 // ContentsExtract Destructor /*{{{*/
314 ContentsExtract::~ContentsExtract()
319 // ContentsExtract::Read - Read the archive /*{{{*/
320 // ---------------------------------------------------------------------
322 bool ContentsExtract::Read(debDebFile
&Deb
)
325 return Deb
.ExtractArchive(*this);
328 // ContentsExtract::DoItem - Extract an item /*{{{*/
329 // ---------------------------------------------------------------------
330 /* This just tacks the name onto the end of our memory buffer */
331 bool ContentsExtract::DoItem(Item
&Itm
, int &/*Fd*/)
333 unsigned long Len
= strlen(Itm
.Name
);
335 // Strip leading ./'s
336 if (Itm
.Name
[0] == '.' && Itm
.Name
[1] == '/')
346 // Allocate more storage for the string list
347 if (CurSize
+ Len
+ 2 >= MaxSize
|| Data
== 0)
350 MaxSize
= 512*1024/2;
351 char *NewData
= (char *)realloc(Data
,MaxSize
*2);
353 return _error
->Error(_("realloc - Failed to allocate memory"));
358 strcpy(Data
+CurSize
,Itm
.Name
);
363 // ContentsExtract::TakeContents - Load the contents data /*{{{*/
364 // ---------------------------------------------------------------------
366 bool ContentsExtract::TakeContents(const void *NewData
,unsigned long long Length
)
374 // Allocate more storage for the string list
375 if (Length
+ 2 >= MaxSize
|| Data
== 0)
378 MaxSize
= 512*1024/2;
379 while (MaxSize
*2 <= Length
)
382 char *NewData
= (char *)realloc(Data
,MaxSize
*2);
384 return _error
->Error(_("realloc - Failed to allocate memory"));
388 memcpy(Data
,NewData
,Length
);
391 return Data
[CurSize
-1] == 0;
394 // ContentsExtract::Add - Read the contents data into the sorter /*{{{*/
395 // ---------------------------------------------------------------------
397 void ContentsExtract::Add(GenContents
&Contents
,std::string
const &Package
)
399 const char *Start
= Data
;
400 char *Pkg
= Contents
.Mystrdup(Package
.c_str());
401 for (const char *I
= Data
; I
< Data
+ CurSize
; I
++)
405 Contents
.Add(Start
,Pkg
);