~ubuntu-branches/debian/experimental/apt/experimental

« back to all changes in this revision

Viewing changes to apt-pkg/contrib/mmap.cc

  • Committer: Bazaar Package Importer
  • Author(s): Michael Vogt
  • Date: 2010-02-18 22:07:23 UTC
  • mfrom: (9.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20100218220723-zb7zdh6fmsmp30tr
Tags: 0.7.26~exp2
fix crash when LANGUAGE is not set

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
   libc6 generates warnings -- which should be errors, g++ isn't properly
14
14
   strict.
15
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
16
   ##################################################################### */
22
17
                                                                        /*}}}*/
23
18
// Include Files                                                        /*{{{*/
24
19
#define _BSD_SOURCE
25
 
#include <apt-pkg/contrib/mmap.h>
26
 
#include <apt-pkg/contrib/error.h>
 
20
#include <apt-pkg/mmap.h>
 
21
#include <apt-pkg/error.h>
27
22
 
28
23
#include <apti18n.h>
29
24
 
31
26
#include <sys/stat.h>
32
27
#include <unistd.h>
33
28
#include <fcntl.h>
 
29
#include <stdlib.h>
34
30
 
35
31
#include <cstring>
36
32
                                                                        /*}}}*/
144
140
// DynamicMMap::DynamicMMap - Constructor                               /*{{{*/
145
141
// ---------------------------------------------------------------------
146
142
/* */
147
 
DynamicMMap::DynamicMMap(FileFd &F,unsigned long Flags,unsigned long WorkSpace) : 
148
 
             MMap(F,Flags | NoImmMap), Fd(&F), WorkSpace(WorkSpace)
 
143
DynamicMMap::DynamicMMap(FileFd &F,unsigned long Flags,unsigned long const &Workspace,
 
144
                         unsigned long const &Grow, unsigned long const &Limit) :
 
145
                MMap(F,Flags | NoImmMap), Fd(&F), WorkSpace(Workspace),
 
146
                GrowFactor(Grow), Limit(Limit)
149
147
{
150
148
   if (_error->PendingError() == true)
151
149
      return;
166
164
                                                                        /*}}}*/
167
165
// DynamicMMap::DynamicMMap - Constructor for a non-file backed map     /*{{{*/
168
166
// ---------------------------------------------------------------------
169
 
/* This is just a fancy malloc really.. */
170
 
DynamicMMap::DynamicMMap(unsigned long Flags,unsigned long WorkSpace) :
171
 
             MMap(Flags | NoImmMap | UnMapped), Fd(0), WorkSpace(WorkSpace)
 
167
/* We try here to use mmap to reserve some space - this is much more
 
168
   cooler than the fallback solution to simply allocate a char array
 
169
   and could come in handy later than we are able to grow such an mmap */
 
170
DynamicMMap::DynamicMMap(unsigned long Flags,unsigned long const &WorkSpace,
 
171
                         unsigned long const &Grow, unsigned long const &Limit) :
 
172
                MMap(Flags | NoImmMap | UnMapped), Fd(0), WorkSpace(WorkSpace),
 
173
                GrowFactor(Grow), Limit(Limit)
172
174
{
173
 
   if (_error->PendingError() == true)
174
 
      return;
175
 
   
176
 
   Base = new unsigned char[WorkSpace];
177
 
   memset(Base,0,WorkSpace);
178
 
   iSize = 0;
 
175
        if (_error->PendingError() == true)
 
176
                return;
 
177
 
 
178
        // disable Moveable if we don't grow
 
179
        if (Grow == 0)
 
180
                Flags &= ~Moveable;
 
181
 
 
182
#ifndef __linux__
 
183
        // kfreebsd doesn't have mremap, so we use the fallback
 
184
        if ((Flags & Moveable) == Moveable)
 
185
                Flags |= Fallback;
 
186
#endif
 
187
 
 
188
#ifdef _POSIX_MAPPED_FILES
 
189
        if ((Flags & Fallback) != Fallback) {
 
190
                // Set the permissions.
 
191
                int Prot = PROT_READ;
 
192
                int Map = MAP_PRIVATE | MAP_ANONYMOUS;
 
193
                if ((Flags & ReadOnly) != ReadOnly)
 
194
                        Prot |= PROT_WRITE;
 
195
                if ((Flags & Public) == Public)
 
196
                        Map = MAP_SHARED | MAP_ANONYMOUS;
 
197
 
 
198
                // use anonymous mmap() to get the memory
 
199
                Base = (unsigned char*) mmap(0, WorkSpace, Prot, Map, -1, 0);
 
200
 
 
201
                if(Base == MAP_FAILED)
 
202
                        _error->Errno("DynamicMMap",_("Couldn't make mmap of %lu bytes"),WorkSpace);
 
203
 
 
204
                iSize = 0;
 
205
                return;
 
206
        }
 
207
#endif
 
208
        // fallback to a static allocated space
 
209
        Base = new unsigned char[WorkSpace];
 
210
        memset(Base,0,WorkSpace);
 
211
        iSize = 0;
179
212
}
180
213
                                                                        /*}}}*/
181
214
// DynamicMMap::~DynamicMMap - Destructor                               /*{{{*/
185
218
{
186
219
   if (Fd == 0)
187
220
   {
 
221
#ifdef _POSIX_MAPPED_FILES
 
222
      munmap(Base, WorkSpace);
 
223
#else
188
224
      delete [] (unsigned char *)Base;
 
225
#endif
189
226
      return;
190
227
   }
191
228
   
204
241
   unsigned long Result = iSize;
205
242
   if (Aln != 0)
206
243
      Result += Aln - (iSize%Aln);
207
 
   
 
244
 
208
245
   iSize = Result + Size;
209
 
   
210
 
   // Just in case error check
211
 
   if (Result + Size > WorkSpace)
 
246
 
 
247
   // try to grow the buffer
 
248
   while(Result + Size > WorkSpace)
212
249
   {
213
 
          _error->Error(_("Dynamic MMap ran out of room. Please increase the size "
214
 
                                  "of APT::Cache-Limit. Current value: %lu. (man 5 apt.conf)"), WorkSpace);
215
 
      return 0;
 
250
      if(!Grow())
 
251
      {
 
252
         _error->Error(_("Dynamic MMap ran out of room. Please increase the size "
 
253
                         "of APT::Cache-Limit. Current value: %lu. (man 5 apt.conf)"), WorkSpace);
 
254
         return 0;
 
255
      }
216
256
   }
217
 
 
218
257
   return Result;
219
258
}
220
259
                                                                        /*}}}*/
223
262
/* This allocates an Item of size ItemSize so that it is aligned to its
224
263
   size in the file. */
225
264
unsigned long DynamicMMap::Allocate(unsigned long ItemSize)
226
 
{   
 
265
{
227
266
   // Look for a matching pool entry
228
267
   Pool *I;
229
268
   Pool *Empty = 0;
234
273
      if (I->ItemSize == ItemSize)
235
274
         break;
236
275
   }
237
 
 
238
276
   // No pool is allocated, use an unallocated one
239
277
   if (I == Pools + PoolCount)
240
278
   {
249
287
      I->ItemSize = ItemSize;
250
288
      I->Count = 0;
251
289
   }
252
 
   
 
290
 
 
291
   unsigned long Result = 0;
253
292
   // Out of space, allocate some more
254
293
   if (I->Count == 0)
255
294
   {
256
 
      I->Count = 20*1024/ItemSize;
257
 
      I->Start = RawAllocate(I->Count*ItemSize,ItemSize);
258
 
   }   
 
295
      const unsigned long size = 20*1024;
 
296
      I->Count = size/ItemSize;
 
297
      Result = RawAllocate(size,ItemSize);
 
298
      // Does the allocation failed ?
 
299
      if (Result == 0 && _error->PendingError())
 
300
         return 0;
 
301
      I->Start = Result;
 
302
   }
 
303
   else
 
304
      Result = I->Start;
259
305
 
260
306
   I->Count--;
261
 
   unsigned long Result = I->Start;
262
 
   I->Start += ItemSize;  
 
307
   I->Start += ItemSize;
263
308
   return Result/ItemSize;
264
309
}
265
310
                                                                        /*}}}*/
269
314
unsigned long DynamicMMap::WriteString(const char *String,
270
315
                                       unsigned long Len)
271
316
{
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. Please increase the size "
277
 
                                  "of APT::Cache-Limit. Current value: %lu. (man 5 apt.conf)"), WorkSpace);
278
 
      return 0;
279
 
   }   
280
 
   
281
317
   if (Len == (unsigned long)-1)
282
318
      Len = strlen(String);
283
 
   iSize += Len + 1;
 
319
 
 
320
   unsigned long Result = RawAllocate(Len+1,0);
 
321
 
 
322
   if (Result == 0 && _error->PendingError())
 
323
      return 0;
 
324
 
284
325
   memcpy((char *)Base + Result,String,Len);
285
326
   ((char *)Base)[Result + Len] = 0;
286
327
   return Result;
287
328
}
288
329
                                                                        /*}}}*/
 
330
// DynamicMMap::Grow - Grow the mmap                                    /*{{{*/
 
331
// ---------------------------------------------------------------------
 
332
/* This method is a wrapper around different methods to (try to) grow
 
333
   a mmap (or our char[]-fallback). Encounterable environments:
 
334
   1. Moveable + !Fallback + linux -> mremap with MREMAP_MAYMOVE
 
335
   2. Moveable + !Fallback + !linux -> not possible (forbidden by constructor)
 
336
   3. Moveable + Fallback -> realloc
 
337
   4. !Moveable + !Fallback + linux -> mremap alone - which will fail in 99,9%
 
338
   5. !Moveable + !Fallback + !linux -> not possible (forbidden by constructor)
 
339
   6. !Moveable + Fallback -> not possible
 
340
   [ While Moveable and Fallback stands for the equally named flags and
 
341
     "linux" indicates a linux kernel instead of a freebsd kernel. ]
 
342
   So what you can see here is, that a MMAP which want to be growable need
 
343
   to be moveable to have a real chance but that this method will at least try
 
344
   the nearly impossible 4 to grow it before it finally give up: Never say never. */
 
345
bool DynamicMMap::Grow() {
 
346
        if (Limit != 0 && WorkSpace >= Limit)
 
347
                return _error->Error(_("The size of a MMap has already reached the defined limit of %lu bytes,"
 
348
                                       "abort the try to grow the MMap."), Limit);
 
349
 
 
350
        unsigned long const newSize = WorkSpace + 1024*1024;
 
351
 
 
352
        if(Fd != 0) {
 
353
                Fd->Seek(newSize - 1);
 
354
                char C = 0;
 
355
                Fd->Write(&C,sizeof(C));
 
356
        }
 
357
        if ((Flags & Fallback) != Fallback) {
 
358
#if defined(_POSIX_MAPPED_FILES) && defined(__linux__)
 
359
   #ifdef MREMAP_MAYMOVE
 
360
                if ((Flags & Moveable) == Moveable)
 
361
                        Base = mremap(Base, WorkSpace, newSize, MREMAP_MAYMOVE);
 
362
                else
 
363
   #endif
 
364
                        Base = mremap(Base, WorkSpace, newSize, 0);
 
365
 
 
366
                if(Base == MAP_FAILED)
 
367
                        return false;
 
368
#else
 
369
                return false;
 
370
#endif
 
371
        } else {
 
372
                if ((Flags & Moveable) != Moveable)
 
373
                        return false;
 
374
 
 
375
                Base = realloc(Base, newSize);
 
376
                if (Base == NULL)
 
377
                        return false;
 
378
        }
 
379
 
 
380
        WorkSpace = newSize;
 
381
        return true;
 
382
}
 
383
                                                                        /*}}}*/