]> git.saurik.com Git - apt.git/blame_incremental - apt-pkg/contrib/mmap.cc
* merged from dpkg-log
[apt.git] / apt-pkg / contrib / mmap.cc
... / ...
CommitLineData
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
16 The configure test notes that some OS's have broken private mmap's
17 so on those OS's we can't use mmap. This means we have to use
18 configure to test mmap and can't rely on the POSIX
19 _POSIX_MAPPED_FILES test.
20
21 ##################################################################### */
22 /*}}}*/
23// Include Files /*{{{*/
24#define _BSD_SOURCE
25#include <apt-pkg/mmap.h>
26#include <apt-pkg/error.h>
27
28#include <apti18n.h>
29
30#include <sys/mman.h>
31#include <sys/stat.h>
32#include <unistd.h>
33#include <fcntl.h>
34 /*}}}*/
35
36// MMap::MMap - Constructor /*{{{*/
37// ---------------------------------------------------------------------
38/* */
39MMap::MMap(FileFd &F,unsigned long Flags) : Flags(Flags), iSize(0),
40 Base(0)
41{
42 if ((Flags & NoImmMap) != NoImmMap)
43 Map(F);
44}
45 /*}}}*/
46// MMap::MMap - Constructor /*{{{*/
47// ---------------------------------------------------------------------
48/* */
49MMap::MMap(unsigned long Flags) : Flags(Flags), iSize(0),
50 Base(0)
51{
52}
53 /*}}}*/
54// MMap::~MMap - Destructor /*{{{*/
55// ---------------------------------------------------------------------
56/* */
57MMap::~MMap()
58{
59 Close();
60}
61 /*}}}*/
62// MMap::Map - Perform the mapping /*{{{*/
63// ---------------------------------------------------------------------
64/* */
65bool MMap::Map(FileFd &Fd)
66{
67 iSize = Fd.Size();
68
69 // Set the permissions.
70 int Prot = PROT_READ;
71 int Map = MAP_SHARED;
72 if ((Flags & ReadOnly) != ReadOnly)
73 Prot |= PROT_WRITE;
74 if ((Flags & Public) != Public)
75 Map = MAP_PRIVATE;
76
77 if (iSize == 0)
78 return _error->Error(_("Can't mmap an empty file"));
79
80 // Map it.
81 Base = mmap(0,iSize,Prot,Map,Fd.Fd(),0);
82 if (Base == (void *)-1)
83 return _error->Errno("mmap",_("Couldn't make mmap of %lu bytes"),iSize);
84
85 return true;
86}
87 /*}}}*/
88// MMap::Close - Close the map /*{{{*/
89// ---------------------------------------------------------------------
90/* */
91bool MMap::Close(bool DoSync)
92{
93 if ((Flags & UnMapped) == UnMapped || Base == 0 || iSize == 0)
94 return true;
95
96 if (DoSync == true)
97 Sync();
98
99 if (munmap((char *)Base,iSize) != 0)
100 _error->Warning("Unable to munmap");
101
102 iSize = 0;
103 Base = 0;
104 return true;
105}
106 /*}}}*/
107// MMap::Sync - Syncronize the map with the disk /*{{{*/
108// ---------------------------------------------------------------------
109/* This is done in syncronous mode - the docs indicate that this will
110 not return till all IO is complete */
111bool MMap::Sync()
112{
113 if ((Flags & UnMapped) == UnMapped)
114 return true;
115
116#ifdef _POSIX_SYNCHRONIZED_IO
117 if ((Flags & ReadOnly) != ReadOnly)
118 if (msync((char *)Base,iSize,MS_SYNC) != 0)
119 return _error->Errno("msync","Unable to write mmap");
120#endif
121 return true;
122}
123 /*}}}*/
124// MMap::Sync - Syncronize a section of the file to disk /*{{{*/
125// ---------------------------------------------------------------------
126/* */
127bool MMap::Sync(unsigned long Start,unsigned long Stop)
128{
129 if ((Flags & UnMapped) == UnMapped)
130 return true;
131
132#ifdef _POSIX_SYNCHRONIZED_IO
133 unsigned long PSize = sysconf(_SC_PAGESIZE);
134 if ((Flags & ReadOnly) != ReadOnly)
135 if (msync((char *)Base+(int)(Start/PSize)*PSize,Stop - Start,MS_SYNC) != 0)
136 return _error->Errno("msync","Unable to write mmap");
137#endif
138 return true;
139}
140 /*}}}*/
141
142// DynamicMMap::DynamicMMap - Constructor /*{{{*/
143// ---------------------------------------------------------------------
144/* */
145DynamicMMap::DynamicMMap(FileFd &F,unsigned long Flags,unsigned long WorkSpace) :
146 MMap(F,Flags | NoImmMap), Fd(&F), WorkSpace(WorkSpace)
147{
148 if (_error->PendingError() == true)
149 return;
150
151 unsigned long EndOfFile = Fd->Size();
152 if (EndOfFile > WorkSpace)
153 WorkSpace = EndOfFile;
154 else if(WorkSpace > 0)
155 {
156 Fd->Seek(WorkSpace - 1);
157 char C = 0;
158 Fd->Write(&C,sizeof(C));
159 }
160
161 Map(F);
162 iSize = EndOfFile;
163}
164 /*}}}*/
165// DynamicMMap::DynamicMMap - Constructor for a non-file backed map /*{{{*/
166// ---------------------------------------------------------------------
167/* This is just a fancy malloc really.. */
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;
173
174 Base = new unsigned char[WorkSpace];
175 memset(Base,0,WorkSpace);
176 iSize = 0;
177}
178 /*}}}*/
179// DynamicMMap::~DynamicMMap - Destructor /*{{{*/
180// ---------------------------------------------------------------------
181/* We truncate the file to the size of the memory data set */
182DynamicMMap::~DynamicMMap()
183{
184 if (Fd == 0)
185 {
186 delete [] (unsigned char *)Base;
187 return;
188 }
189
190 unsigned long EndOfFile = iSize;
191 iSize = WorkSpace;
192 Close(false);
193 ftruncate(Fd->Fd(),EndOfFile);
194}
195 /*}}}*/
196// DynamicMMap::RawAllocate - Allocate a raw chunk of unaligned space /*{{{*/
197// ---------------------------------------------------------------------
198/* This allocates a block of memory aligned to the given size */
199unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln)
200{
201 unsigned long Result = iSize;
202 if (Aln != 0)
203 Result += Aln - (iSize%Aln);
204
205 iSize = Result + Size;
206
207 // Just in case error check
208 if (Result + Size > WorkSpace)
209 {
210 _error->Error("Dynamic MMap ran out of room");
211 return 0;
212 }
213
214 return Result;
215}
216 /*}}}*/
217// DynamicMMap::Allocate - Pooled aligned allocation /*{{{*/
218// ---------------------------------------------------------------------
219/* This allocates an Item of size ItemSize so that it is aligned to its
220 size in the file. */
221unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
222{
223 // Look for a matching pool entry
224 Pool *I;
225 Pool *Empty = 0;
226 for (I = Pools; I != Pools + PoolCount; I++)
227 {
228 if (I->ItemSize == 0)
229 Empty = I;
230 if (I->ItemSize == ItemSize)
231 break;
232 }
233
234 // No pool is allocated, use an unallocated one
235 if (I == Pools + PoolCount)
236 {
237 // Woops, we ran out, the calling code should allocate more.
238 if (Empty == 0)
239 {
240 _error->Error("Ran out of allocation pools");
241 return 0;
242 }
243
244 I = Empty;
245 I->ItemSize = ItemSize;
246 I->Count = 0;
247 }
248
249 // Out of space, allocate some more
250 if (I->Count == 0)
251 {
252 I->Count = 20*1024/ItemSize;
253 I->Start = RawAllocate(I->Count*ItemSize,ItemSize);
254 }
255
256 I->Count--;
257 unsigned long Result = I->Start;
258 I->Start += ItemSize;
259 return Result/ItemSize;
260}
261 /*}}}*/
262// DynamicMMap::WriteString - Write a string to the file /*{{{*/
263// ---------------------------------------------------------------------
264/* Strings are not aligned to anything */
265unsigned long DynamicMMap::WriteString(const char *String,
266 unsigned long Len)
267{
268 unsigned long Result = iSize;
269 // Just in case error check
270 if (Result + Len > WorkSpace)
271 {
272 _error->Error("Dynamic MMap ran out of room");
273 return 0;
274 }
275
276 if (Len == (unsigned long)-1)
277 Len = strlen(String);
278 iSize += Len + 1;
279 memcpy((char *)Base + Result,String,Len);
280 ((char *)Base)[Result + Len] = 0;
281 return Result;
282}
283 /*}}}*/