~ubuntu-branches/ubuntu/maverick/evolution-data-server/maverick-proposed

« back to all changes in this revision

Viewing changes to libdb/os_win32/os_map.c

  • Committer: Bazaar Package Importer
  • Author(s): Didier Roche
  • Date: 2010-05-17 17:02:06 UTC
  • mfrom: (1.1.79 upstream) (1.6.12 experimental)
  • Revision ID: james.westby@ubuntu.com-20100517170206-4ufr52vwrhh26yh0
Tags: 2.30.1-1ubuntu1
* Merge from debian experimental. Remaining change:
  (LP: #42199, #229669, #173703, #360344, #508494)
  + debian/control:
    - add Vcs-Bzr tag
    - don't use libgnome
    - Use Breaks instead of Conflicts against evolution 2.25 and earlier.
  + debian/evolution-data-server.install,
    debian/patches/45_libcamel_providers_version.patch:
    - use the upstream versioning, not a Debian-specific one 
  + debian/libedata-book1.2-dev.install, debian/libebackend-1.2-dev.install,
    debian/libcamel1.2-dev.install, debian/libedataserverui1.2-dev.install:
    - install html documentation
  + debian/rules:
    - don't build documentation it's shipped with the tarball

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*-
2
 
 * See the file LICENSE for redistribution information.
3
 
 *
4
 
 * Copyright (c) 1996-2002
5
 
 *      Sleepycat Software.  All rights reserved.
6
 
 */
7
 
 
8
 
#include "db_config.h"
9
 
 
10
 
#ifndef lint
11
 
static const char revid[] = "$Id$";
12
 
#endif /* not lint */
13
 
 
14
 
#include "db_int.h"
15
 
 
16
 
static int __os_map
17
 
  __P((DB_ENV *, char *, REGINFO *, DB_FH *, size_t, int, int, int, void **));
18
 
static int __os_unique_name __P((char *, HANDLE, char *, size_t));
19
 
 
20
 
/*
21
 
 * __os_r_sysattach --
22
 
 *      Create/join a shared memory region.
23
 
 */
24
 
int
25
 
__os_r_sysattach(dbenv, infop, rp)
26
 
        DB_ENV *dbenv;
27
 
        REGINFO *infop;
28
 
        REGION *rp;
29
 
{
30
 
        DB_FH fh;
31
 
        int is_system, ret;
32
 
 
33
 
        /*
34
 
         * Try to open/create the file.  We DO NOT need to ensure that multiple
35
 
         * threads/processes attempting to simultaneously create the region are
36
 
         * properly ordered, our caller has already taken care of that.
37
 
         */
38
 
        if ((ret = __os_open(dbenv, infop->name,
39
 
            DB_OSO_DIRECT |
40
 
            F_ISSET(infop, REGION_CREATE_OK) ? DB_OSO_CREATE: 0,
41
 
            infop->mode, &fh)) != 0) {
42
 
                __db_err(dbenv, "%s: %s", infop->name, db_strerror(ret));
43
 
                return (ret);
44
 
        }
45
 
 
46
 
        /*
47
 
         * On Windows/9X, files that are opened by multiple processes do not
48
 
         * share data correctly.  For this reason, the DB_SYSTEM_MEM flag is
49
 
         * implied for any application that does not specify the DB_PRIVATE
50
 
         * flag.
51
 
         */
52
 
        is_system = F_ISSET(dbenv, DB_ENV_SYSTEM_MEM) ||
53
 
            (!F_ISSET(dbenv, DB_ENV_PRIVATE) && __os_is_winnt() == 0);
54
 
 
55
 
        /*
56
 
         * Map the file in.  If we're creating an in-system-memory region,
57
 
         * specify a segment ID (which is never used again) so that the
58
 
         * calling code writes out the REGENV_REF structure to the primary
59
 
         * environment file.
60
 
         */
61
 
        ret = __os_map(dbenv, infop->name, infop, &fh, rp->size,
62
 
           1, is_system, 0, &infop->addr);
63
 
        if (ret == 0 && is_system == 1)
64
 
                rp->segid = 1;
65
 
 
66
 
        (void)__os_closehandle(dbenv, &fh);
67
 
 
68
 
        return (ret);
69
 
}
70
 
 
71
 
/*
72
 
 * __os_r_sysdetach --
73
 
 *      Detach from a shared memory region.
74
 
 */
75
 
int
76
 
__os_r_sysdetach(dbenv, infop, destroy)
77
 
        DB_ENV *dbenv;
78
 
        REGINFO *infop;
79
 
        int destroy;
80
 
{
81
 
        int ret, t_ret;
82
 
 
83
 
        if (infop->wnt_handle != NULL) {
84
 
                (void)CloseHandle(*((HANDLE*)(infop->wnt_handle)));
85
 
                __os_free(dbenv, infop->wnt_handle);
86
 
        }
87
 
 
88
 
        ret = !UnmapViewOfFile(infop->addr) ? __os_win32_errno() : 0;
89
 
        if (ret != 0)
90
 
                __db_err(dbenv, "UnmapViewOfFile: %s", strerror(ret));
91
 
 
92
 
        if (!F_ISSET(dbenv, DB_ENV_SYSTEM_MEM) && destroy) {
93
 
                if (F_ISSET(dbenv, DB_ENV_OVERWRITE))
94
 
                        (void)__db_overwrite(dbenv, infop->name);
95
 
                if ((t_ret = __os_unlink(dbenv, infop->name)) != 0 && ret == 0)
96
 
                        ret = t_ret;
97
 
        }
98
 
 
99
 
        return (ret);
100
 
}
101
 
 
102
 
/*
103
 
 * __os_mapfile --
104
 
 *      Map in a shared memory file.
105
 
 */
106
 
int
107
 
__os_mapfile(dbenv, path, fhp, len, is_rdonly, addr)
108
 
        DB_ENV *dbenv;
109
 
        char *path;
110
 
        DB_FH *fhp;
111
 
        int is_rdonly;
112
 
        size_t len;
113
 
        void **addr;
114
 
{
115
 
        /* If the user replaced the map call, call through their interface. */
116
 
        if (DB_GLOBAL(j_map) != NULL)
117
 
                return (DB_GLOBAL(j_map)(path, len, 0, is_rdonly, addr));
118
 
 
119
 
        return (__os_map(dbenv, path, NULL, fhp, len, 0, 0, is_rdonly, addr));
120
 
}
121
 
 
122
 
/*
123
 
 * __os_unmapfile --
124
 
 *      Unmap the shared memory file.
125
 
 */
126
 
int
127
 
__os_unmapfile(dbenv, addr, len)
128
 
        DB_ENV *dbenv;
129
 
        void *addr;
130
 
        size_t len;
131
 
{
132
 
        /* If the user replaced the map call, call through their interface. */
133
 
        if (DB_GLOBAL(j_unmap) != NULL)
134
 
                return (DB_GLOBAL(j_unmap)(addr, len));
135
 
 
136
 
        return (!UnmapViewOfFile(addr) ? __os_win32_errno() : 0);
137
 
}
138
 
 
139
 
/*
140
 
 * __os_unique_name --
141
 
 *      Create a unique identifying name from a pathname (may be absolute or
142
 
 *      relative) and/or a file descriptor.
143
 
 *
144
 
 *      The name returned must be unique (different files map to different
145
 
 *      names), and repeatable (same files, map to same names).  It's not
146
 
 *      so easy to do by name.  Should handle not only:
147
 
 *
148
 
 *              foo.bar  ==  ./foo.bar  ==  c:/whatever_path/foo.bar
149
 
 *
150
 
 *      but also understand that:
151
 
 *
152
 
 *              foo.bar  ==  Foo.Bar    (FAT file system)
153
 
 *              foo.bar  !=  Foo.Bar    (NTFS)
154
 
 *
155
 
 *      The best solution is to use the file index, found in the file
156
 
 *      information structure (similar to UNIX inode #).
157
 
 *
158
 
 *      When a file is deleted, its file index may be reused,
159
 
 *      but if the unique name has not gone from its namespace,
160
 
 *      we may get a conflict.  So to ensure some tie in to the
161
 
 *      original pathname, we also use the creation time and the
162
 
 *      file basename.  This is not a perfect system, but it
163
 
 *      should work for all but anamolous test cases.
164
 
 *
165
 
 */
166
 
static int
167
 
__os_unique_name(orig_path, hfile, result_path, result_path_len)
168
 
        char *orig_path, *result_path;
169
 
        HANDLE hfile;
170
 
        size_t result_path_len;
171
 
{
172
 
        BY_HANDLE_FILE_INFORMATION fileinfo;
173
 
        char *basename, *p;
174
 
 
175
 
        /*
176
 
         * In Windows, pathname components are delimited by '/' or '\', and
177
 
         * if neither is present, we need to strip off leading drive letter
178
 
         * (e.g. c:foo.txt).
179
 
         */
180
 
        basename = strrchr(orig_path, '/');
181
 
        p = strrchr(orig_path, '\\');
182
 
        if (basename == NULL || (p != NULL && p > basename))
183
 
                basename = p;
184
 
        if (basename == NULL)
185
 
                basename = strrchr(orig_path, ':');
186
 
 
187
 
        if (basename == NULL)
188
 
                basename = orig_path;
189
 
        else
190
 
                basename++;
191
 
 
192
 
        if (!GetFileInformationByHandle(hfile, &fileinfo))
193
 
                return (__os_win32_errno());
194
 
 
195
 
        (void)snprintf(result_path, result_path_len,
196
 
            "__db_shmem.%8.8lx.%8.8lx.%8.8lx.%8.8lx.%8.8lx.%s",
197
 
            fileinfo.dwVolumeSerialNumber,
198
 
            fileinfo.nFileIndexHigh,
199
 
            fileinfo.nFileIndexLow,
200
 
            fileinfo.ftCreationTime.dwHighDateTime,
201
 
            fileinfo.ftCreationTime.dwHighDateTime,
202
 
            basename);
203
 
 
204
 
        return (0);
205
 
}
206
 
 
207
 
/*
208
 
 * __os_map --
209
 
 *      The mmap(2) function for Windows.
210
 
 */
211
 
static int
212
 
__os_map(dbenv, path, infop, fhp, len, is_region, is_system, is_rdonly, addr)
213
 
        DB_ENV *dbenv;
214
 
        REGINFO *infop;
215
 
        char *path;
216
 
        DB_FH *fhp;
217
 
        int is_region, is_system, is_rdonly;
218
 
        size_t len;
219
 
        void **addr;
220
 
{
221
 
        HANDLE hMemory;
222
 
        REGENV *renv;
223
 
        int ret, use_pagefile;
224
 
        char shmem_name[MAXPATHLEN];
225
 
        void *pMemory;
226
 
 
227
 
        ret = 0;
228
 
        if (infop != NULL)
229
 
                infop->wnt_handle = NULL;
230
 
 
231
 
        use_pagefile = is_region && is_system;
232
 
 
233
 
        /*
234
 
         * If creating a region in system space, get a matching name in the
235
 
         * paging file namespace.
236
 
         */
237
 
        if (use_pagefile && (ret = __os_unique_name(
238
 
            path, fhp->handle, shmem_name, sizeof(shmem_name))) != 0)
239
 
                return (ret);
240
 
 
241
 
        /*
242
 
         * XXX
243
 
         * DB: We have not implemented copy-on-write here.
244
 
         *
245
 
         * XXX
246
 
         * DB: This code will fail if the library is ever compiled on a 64-bit
247
 
         * machine.
248
 
         *
249
 
         * XXX
250
 
         * If this is an region in system memory, let's try opening using the
251
 
         * OpenFileMapping() first.  Why, oh why are we doing this?
252
 
         *
253
 
         * Well, we might be asking the OS for a handle to a pre-existing
254
 
         * memory section, or we might be the first to get here and want the
255
 
         * section created. CreateFileMapping() sounds like it will do both
256
 
         * jobs. But, not so. It seems to mess up making the commit charge to
257
 
         * the process. It thinks, incorrectly, that when we want to join a
258
 
         * previously existing section, that it should make a commit charge
259
 
         * for the whole section.  In fact, there is no new committed memory
260
 
         * whatever.  The call can fail if there is insufficient memory free
261
 
         * to handle the erroneous commit charge.  So, we find that the bogus
262
 
         * commit is not made if we call OpenFileMapping().  So we do that
263
 
         * first, and only call CreateFileMapping() if we're really creating
264
 
         * the section.
265
 
         */
266
 
        hMemory = NULL;
267
 
        if (use_pagefile)
268
 
                hMemory = OpenFileMapping(
269
 
                    is_rdonly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
270
 
                    0,
271
 
                    shmem_name);
272
 
 
273
 
        if (hMemory == NULL)
274
 
                hMemory = CreateFileMapping(
275
 
                    use_pagefile ? (HANDLE)-1 : fhp->handle,
276
 
                    0,
277
 
                    is_rdonly ? PAGE_READONLY : PAGE_READWRITE,
278
 
                    0, (DWORD)len,
279
 
                    use_pagefile ? shmem_name : NULL);
280
 
        if (hMemory == NULL) {
281
 
                ret = __os_win32_errno();
282
 
                __db_err(dbenv, "OpenFileMapping: %s", strerror(ret));
283
 
                return (ret);
284
 
        }
285
 
 
286
 
        pMemory = MapViewOfFile(hMemory,
287
 
            (is_rdonly ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS), 0, 0, len);
288
 
        if (pMemory == NULL) {
289
 
                ret = __os_win32_errno();
290
 
                __db_err(dbenv, "MapViewOfFile: %s", strerror(ret));
291
 
                return (ret);
292
 
        }
293
 
 
294
 
        /*
295
 
         * XXX
296
 
         * It turns out that the kernel object underlying the named section
297
 
         * is reference counted, but that the call to MapViewOfFile() above
298
 
         * does NOT increment the reference count! So, if we close the handle
299
 
         * here, the kernel deletes the object from the kernel namespace.
300
 
         * When a second process comes along to join the region, the kernel
301
 
         * happily creates a new object with the same name, but completely
302
 
         * different identity. The two processes then have distinct isolated
303
 
         * mapped sections, not at all what was wanted. Not closing the handle
304
 
         * here fixes this problem.  We carry the handle around in the region
305
 
         * structure so we can close it when unmap is called.  Ignore malloc
306
 
         * errors, it just means we leak the memory.
307
 
         */
308
 
        if (use_pagefile && infop != NULL) {
309
 
                if (__os_malloc(dbenv,
310
 
                    sizeof(HANDLE), &infop->wnt_handle) == 0)
311
 
                        memcpy(infop->wnt_handle, &hMemory, sizeof(HANDLE));
312
 
        } else
313
 
                CloseHandle(hMemory);
314
 
 
315
 
        if (is_region) {
316
 
                /*
317
 
                 * XXX
318
 
                 * Windows/95 zeroes anonymous memory regions at last close.
319
 
                 * This means that the backing file can exist and reference
320
 
                 * the region, but the region itself is no longer initialized.
321
 
                 * If the caller is capable of creating the region, update
322
 
                 * the REGINFO structure so that they do so.
323
 
                 */
324
 
                renv = (REGENV *)pMemory;
325
 
                if (renv->magic == 0) {
326
 
                        if (F_ISSET(infop, REGION_CREATE_OK))
327
 
                                F_SET(infop, REGION_CREATE);
328
 
                        else {
329
 
                                (void)UnmapViewOfFile(pMemory);
330
 
                                pMemory = NULL;
331
 
                                ret = EAGAIN;
332
 
                        }
333
 
                }
334
 
        }
335
 
 
336
 
        *addr = pMemory;
337
 
        return (ret);
338
 
}