- more size_t fixes (Ralf)
[apt.git] / apt-pkg / contrib / mmap.cc
1 // -*- mode: c++; 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(size_t Start,size_t Stop)
132 {
133    if ((Flags & UnMapped) == UnMapped)
134       return true;
135    
136 #ifdef _POSIX_SYNCHRONIZED_IO
137    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    off_t EndOfFile = iSize;
195    iSize = WorkSpace;
196    Close(false);
197    if (ftruncate(Fd->Fd(),EndOfFile) != 0)
198    {
199      _error->Errno("ftruncate", _("Failed to ftruncate"));
200      return;
201    }
202 }  
203                                                                         /*}}}*/
204 // DynamicMMap::RawAllocate - Allocate a raw chunk of unaligned space   /*{{{*/
205 // ---------------------------------------------------------------------
206 /* This allocates a block of memory aligned to the given size */
207 unsigned long DynamicMMap::RawAllocate(unsigned long Size,unsigned long Aln)
208 {
209    unsigned long Result = iSize;
210    if (Aln != 0)
211       Result += Aln - (iSize%Aln);
212    
213    iSize = Result + Size;
214    
215    // Just in case error check
216    if (Result + Size > WorkSpace)
217    {
218       _error->Error("Dynamic MMap ran out of room");
219       return 0;
220    }
221
222    return Result;
223 }
224                                                                         /*}}}*/
225 // DynamicMMap::Allocate - Pooled aligned allocation                    /*{{{*/
226 // ---------------------------------------------------------------------
227 /* This allocates an Item of size ItemSize so that it is aligned to its
228    size in the file. */
229 unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
230 {   
231    // Look for a matching pool entry
232    Pool *I;
233    Pool *Empty = 0;
234    for (I = Pools; I != Pools + PoolCount; I++)
235    {
236       if (I->ItemSize == 0)
237          Empty = I;
238       if (I->ItemSize == ItemSize)
239          break;
240    }
241
242    // No pool is allocated, use an unallocated one
243    if (I == Pools + PoolCount)
244    {
245       // Woops, we ran out, the calling code should allocate more.
246       if (Empty == 0)
247       {
248          _error->Error("Ran out of allocation pools");
249          return 0;
250       }
251       
252       I = Empty;
253       I->ItemSize = ItemSize;
254       I->Count = 0;
255    }
256    
257    // Out of space, allocate some more
258    if (I->Count == 0)
259    {
260       I->Count = 20*1024/ItemSize;
261       I->Start = RawAllocate(I->Count*ItemSize,ItemSize);
262    }   
263
264    I->Count--;
265    unsigned long Result = I->Start;
266    I->Start += ItemSize;  
267    return Result/ItemSize;
268 }
269                                                                         /*}}}*/
270 // DynamicMMap::WriteString - Write a string to the file                /*{{{*/
271 // ---------------------------------------------------------------------
272 /* Strings are not aligned to anything */
273 size_t DynamicMMap::WriteString(const char *String,
274                                        size_t Len)
275 {
276    size_t Result = iSize;
277    // Just in case error check
278    if (Result + Len > WorkSpace)
279    {
280       _error->Error("Dynamic MMap ran out of room");
281       return 0;
282    }   
283    
284    if (Len == (size_t)-1)
285       Len = strlen(String);
286    iSize += Len + 1;
287    memcpy((char *)Base + Result,String,Len);
288    ((char *)Base)[Result + Len] = 0;
289    return Result;
290 }
291                                                                         /*}}}*/