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