[apt-pkg/pkgcachegen.cc] remove the Ver == 0 and Desc == 0 from the last
[ntk/apt.git] / apt-pkg / contrib / mmap.cc
CommitLineData
578bfd0a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
0db4a45b 3// $Id: mmap.cc,v 1.22 2001/05/27 05:19:30 jgg Exp $
578bfd0a
AL
4/* ######################################################################
5
6 MMap Class - Provides 'real' mmap or a faked mmap using read().
7
8 MMap cover class.
9
10 Some broken versions of glibc2 (libc6) have a broken definition
11 of mmap that accepts a char * -- all other systems (and libc5) use
12 void *. We can't safely do anything here that would be portable, so
13 libc6 generates warnings -- which should be errors, g++ isn't properly
14 strict.
15
578bfd0a
AL
16 ##################################################################### */
17 /*}}}*/
18// Include Files /*{{{*/
19#define _BSD_SOURCE
094a497d
AL
20#include <apt-pkg/mmap.h>
21#include <apt-pkg/error.h>
578bfd0a 22
b2e465d6
AL
23#include <apti18n.h>
24
578bfd0a
AL
25#include <sys/mman.h>
26#include <sys/stat.h>
578bfd0a
AL
27#include <unistd.h>
28#include <fcntl.h>
13eb93fc 29#include <stdlib.h>
4f333a8b
MV
30
31#include <cstring>
578bfd0a
AL
32 /*}}}*/
33
34// MMap::MMap - Constructor /*{{{*/
35// ---------------------------------------------------------------------
36/* */
2d11135a 37MMap::MMap(FileFd &F,unsigned long Flags) : Flags(Flags), iSize(0),
578bfd0a
AL
38 Base(0)
39{
40 if ((Flags & NoImmMap) != NoImmMap)
2d11135a
AL
41 Map(F);
42}
43 /*}}}*/
44// MMap::MMap - Constructor /*{{{*/
45// ---------------------------------------------------------------------
46/* */
47MMap::MMap(unsigned long Flags) : Flags(Flags), iSize(0),
48 Base(0)
49{
578bfd0a
AL
50}
51 /*}}}*/
52// MMap::~MMap - Destructor /*{{{*/
53// ---------------------------------------------------------------------
54/* */
55MMap::~MMap()
56{
2d11135a 57 Close();
578bfd0a
AL
58}
59 /*}}}*/
60// MMap::Map - Perform the mapping /*{{{*/
61// ---------------------------------------------------------------------
62/* */
2d11135a 63bool MMap::Map(FileFd &Fd)
578bfd0a
AL
64{
65 iSize = Fd.Size();
66
67 // Set the permissions.
68 int Prot = PROT_READ;
69 int Map = MAP_SHARED;
70 if ((Flags & ReadOnly) != ReadOnly)
71 Prot |= PROT_WRITE;
72 if ((Flags & Public) != Public)
73 Map = MAP_PRIVATE;
74
b35d2f5f 75 if (iSize == 0)
b2e465d6 76 return _error->Error(_("Can't mmap an empty file"));
b35d2f5f 77
578bfd0a
AL
78 // Map it.
79 Base = mmap(0,iSize,Prot,Map,Fd.Fd(),0);
80 if (Base == (void *)-1)
b2e465d6 81 return _error->Errno("mmap",_("Couldn't make mmap of %lu bytes"),iSize);
578bfd0a
AL
82
83 return true;
84}
85 /*}}}*/
86// MMap::Close - Close the map /*{{{*/
87// ---------------------------------------------------------------------
88/* */
2d11135a 89bool MMap::Close(bool DoSync)
578bfd0a 90{
2d11135a 91 if ((Flags & UnMapped) == UnMapped || Base == 0 || iSize == 0)
578bfd0a 92 return true;
2d11135a 93
1164783d
AL
94 if (DoSync == true)
95 Sync();
578bfd0a
AL
96
97 if (munmap((char *)Base,iSize) != 0)
98 _error->Warning("Unable to munmap");
99
100 iSize = 0;
b2e465d6 101 Base = 0;
578bfd0a
AL
102 return true;
103}
104 /*}}}*/
105// MMap::Sync - Syncronize the map with the disk /*{{{*/
106// ---------------------------------------------------------------------
0149949b
AL
107/* This is done in syncronous mode - the docs indicate that this will
108 not return till all IO is complete */
578bfd0a
AL
109bool MMap::Sync()
110{
2d11135a
AL
111 if ((Flags & UnMapped) == UnMapped)
112 return true;
113
de3c15ea 114#ifdef _POSIX_SYNCHRONIZED_IO
1164783d 115 if ((Flags & ReadOnly) != ReadOnly)
e9fce64b 116 if (msync((char *)Base,iSize,MS_SYNC) < 0)
4b1b89c5 117 return _error->Errno("msync","Unable to write mmap");
de3c15ea 118#endif
578bfd0a
AL
119 return true;
120}
121 /*}}}*/
122// MMap::Sync - Syncronize a section of the file to disk /*{{{*/
123// ---------------------------------------------------------------------
124/* */
125bool MMap::Sync(unsigned long Start,unsigned long Stop)
126{
2d11135a
AL
127 if ((Flags & UnMapped) == UnMapped)
128 return true;
129
35c22def
AL
130#ifdef _POSIX_SYNCHRONIZED_IO
131 unsigned long PSize = sysconf(_SC_PAGESIZE);
1164783d 132 if ((Flags & ReadOnly) != ReadOnly)
e9fce64b 133 if (msync((char *)Base+(int)(Start/PSize)*PSize,Stop - Start,MS_SYNC) < 0)
4b1b89c5 134 return _error->Errno("msync","Unable to write mmap");
de3c15ea 135#endif
578bfd0a
AL
136 return true;
137}
138 /*}}}*/
139
13eb93fc 140 /*}}}*/
578bfd0a
AL
141// DynamicMMap::DynamicMMap - Constructor /*{{{*/
142// ---------------------------------------------------------------------
143/* */
c5f44afc 144DynamicMMap::DynamicMMap(FileFd &F,unsigned long Flags,unsigned long WorkSpace) :
2d11135a 145 MMap(F,Flags | NoImmMap), Fd(&F), WorkSpace(WorkSpace)
578bfd0a 146{
d38b7b3d
AL
147 if (_error->PendingError() == true)
148 return;
149
2d11135a 150 unsigned long EndOfFile = Fd->Size();
b2e465d6
AL
151 if (EndOfFile > WorkSpace)
152 WorkSpace = EndOfFile;
ea92d036 153 else if(WorkSpace > 0)
b2e465d6 154 {
ea92d036 155 Fd->Seek(WorkSpace - 1);
b2e465d6
AL
156 char C = 0;
157 Fd->Write(&C,sizeof(C));
158 }
159
2d11135a 160 Map(F);
578bfd0a
AL
161 iSize = EndOfFile;
162}
163 /*}}}*/
2d11135a
AL
164// DynamicMMap::DynamicMMap - Constructor for a non-file backed map /*{{{*/
165// ---------------------------------------------------------------------
f1c6a8ca
DK
166/* We try here to use mmap to reserve some space - this is much more
167 cooler than the fallback solution to simply allocate a char array
168 and could come in handy later than we are able to grow such an mmap */
2d11135a
AL
169DynamicMMap::DynamicMMap(unsigned long Flags,unsigned long WorkSpace) :
170 MMap(Flags | NoImmMap | UnMapped), Fd(0), WorkSpace(WorkSpace)
171{
172 if (_error->PendingError() == true)
173 return;
f1c6a8ca
DK
174
175#ifdef _POSIX_MAPPED_FILES
176 // use anonymous mmap() to get the memory
177 Base = (unsigned char*) mmap(0, WorkSpace, PROT_READ|PROT_WRITE,
178 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
179 if(Base != MAP_FAILED)
180 return;
181#endif
182 // fallback to a static allocated space
2d11135a 183 Base = new unsigned char[WorkSpace];
0db4a45b 184 memset(Base,0,WorkSpace);
2d11135a
AL
185 iSize = 0;
186}
187 /*}}}*/
578bfd0a
AL
188// DynamicMMap::~DynamicMMap - Destructor /*{{{*/
189// ---------------------------------------------------------------------
190/* We truncate the file to the size of the memory data set */
191DynamicMMap::~DynamicMMap()
192{
2d11135a
AL
193 if (Fd == 0)
194 {
f1c6a8ca
DK
195#ifdef _POSIX_MAPPED_FILES
196 munmap(Base, WorkSpace);
197#else
2d11135a 198 delete [] (unsigned char *)Base;
f1c6a8ca 199#endif
2d11135a
AL
200 return;
201 }
202
578bfd0a 203 unsigned long EndOfFile = iSize;
1164783d 204 iSize = WorkSpace;
2d11135a 205 Close(false);
3c8cda8b
MV
206 if(ftruncate(Fd->Fd(),EndOfFile) < 0)
207 _error->Errno("ftruncate", _("Failed to truncate file"));
578bfd0a
AL
208}
209 /*}}}*/
210// DynamicMMap::RawAllocate - Allocate a raw chunk of unaligned space /*{{{*/
211// ---------------------------------------------------------------------
f55a958f
AL
212/* This allocates a block of memory aligned to the given size */
213unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln)
578bfd0a
AL
214{
215 unsigned long Result = iSize;
f55a958f
AL
216 if (Aln != 0)
217 Result += Aln - (iSize%Aln);
c5f44afc 218
f55a958f 219 iSize = Result + Size;
c5f44afc 220
f1c6a8ca
DK
221 // try to grow the buffer
222 while(Result + Size > WorkSpace)
578bfd0a 223 {
f1c6a8ca
DK
224 if(!Grow())
225 {
226 _error->Error(_("Dynamic MMap ran out of room. Please increase the size "
227 "of APT::Cache-Limit. Current value: %lu. (man 5 apt.conf)"), WorkSpace);
228 return 0;
229 }
578bfd0a 230 }
578bfd0a
AL
231 return Result;
232}
233 /*}}}*/
234// DynamicMMap::Allocate - Pooled aligned allocation /*{{{*/
235// ---------------------------------------------------------------------
236/* This allocates an Item of size ItemSize so that it is aligned to its
237 size in the file. */
238unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
c5f44afc 239{
578bfd0a
AL
240 // Look for a matching pool entry
241 Pool *I;
242 Pool *Empty = 0;
243 for (I = Pools; I != Pools + PoolCount; I++)
244 {
245 if (I->ItemSize == 0)
246 Empty = I;
247 if (I->ItemSize == ItemSize)
248 break;
249 }
578bfd0a
AL
250 // No pool is allocated, use an unallocated one
251 if (I == Pools + PoolCount)
252 {
253 // Woops, we ran out, the calling code should allocate more.
254 if (Empty == 0)
255 {
256 _error->Error("Ran out of allocation pools");
257 return 0;
258 }
259
260 I = Empty;
261 I->ItemSize = ItemSize;
262 I->Count = 0;
263 }
c5f44afc
DK
264
265 unsigned long Result = 0;
578bfd0a
AL
266 // Out of space, allocate some more
267 if (I->Count == 0)
268 {
c5f44afc
DK
269 const unsigned long size = 20*1024;
270 I->Count = size/ItemSize;
271 Result = RawAllocate(size,ItemSize);
272 // Does the allocation failed ?
273 if (Result == 0 && _error->PendingError())
274 return 0;
275 I->Start = Result;
276 }
277 else
278 Result = I->Start;
f55a958f 279
578bfd0a 280 I->Count--;
c5f44afc 281 I->Start += ItemSize;
578bfd0a
AL
282 return Result/ItemSize;
283}
284 /*}}}*/
285// DynamicMMap::WriteString - Write a string to the file /*{{{*/
286// ---------------------------------------------------------------------
287/* Strings are not aligned to anything */
288unsigned long DynamicMMap::WriteString(const char *String,
289 unsigned long Len)
290{
6e52073f 291 if (Len == (unsigned long)-1)
578bfd0a 292 Len = strlen(String);
c5f44afc
DK
293
294 unsigned long Result = RawAllocate(Len+1,0);
295
296 if (Result == 0 && _error->PendingError())
297 return 0;
298
578bfd0a
AL
299 memcpy((char *)Base + Result,String,Len);
300 ((char *)Base)[Result + Len] = 0;
301 return Result;
302}
303 /*}}}*/
f1c6a8ca
DK
304// DynamicMMap::Grow - Grow the mmap /*{{{*/
305// ---------------------------------------------------------------------
306/* This method will try to grow the mmap we currently use. This doesn't
307 work most of the time because we can't move the mmap around in the
308 memory for now as this would require to adjust quite a lot of pointers
309 but why we should not at least try to grow it before we give up? */
310bool DynamicMMap::Grow()
311{
312#ifdef _POSIX_MAPPED_FILES
313 unsigned long newSize = WorkSpace + 1024*1024;
314
315 if(Fd != 0)
316 {
317 Fd->Seek(newSize - 1);
318 char C = 0;
319 Fd->Write(&C,sizeof(C));
320 }
321
322 Base = mremap(Base, WorkSpace, newSize, 0);
323 if(Base == MAP_FAILED)
324 return false;
325
326 WorkSpace = newSize;
327 return true;
328#else
329 return false;
330#endif
331}
332 /*}}}*/