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