blob: e47e41cea0b3d4872835b0c57ef4480eae363a07 [file] [log] [blame]
Guido van Rossum09fdf072000-03-31 01:17:07 +00001/*
2 / Author: Sam Rushing <rushing@nightmare.com>
Andrew M. Kuchling10f9c072001-11-05 21:25:42 +00003 / Hacked for Unix by AMK
Guido van Rossum09fdf072000-03-31 01:17:07 +00004 / $Id$
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00005
Guido van Rossum8ce8a782007-11-01 19:42:39 +00006 / Modified to support mmap with offset - to map a 'window' of a file
7 / Author: Yotam Medini yotamm@mellanox.co.il
8 /
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00009 / mmapmodule.cpp -- map a view of a file into memory
10 /
11 / todo: need permission flags, perhaps a 'chsize' analog
12 / not all functions check range yet!!!
13 /
14 /
Mark Hammond071864a2000-07-30 02:46:26 +000015 / This version of mmapmodule.c has been changed significantly
16 / from the original mmapfile.c on which it was based.
17 / The original version of mmapfile is maintained by Sam at
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000018 / ftp://squirl.nightmare.com/pub/python/python-ext.
19*/
20
Martin v. Löwiscfe7e092006-02-17 06:59:14 +000021#define PY_SSIZE_T_CLEAN
Guido van Rossum09fdf072000-03-31 01:17:07 +000022#include <Python.h>
23
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000024#ifndef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000025#define UNIX
26#endif
27
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000028#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000029#include <windows.h>
Fred Drake145f96e2000-10-01 17:50:46 +000030static int
31my_getpagesize(void)
32{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000033 SYSTEM_INFO si;
34 GetSystemInfo(&si);
35 return si.dwPageSize;
Fred Drake145f96e2000-10-01 17:50:46 +000036}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000037
38static int
39my_getallocationgranularity (void)
40{
41
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000042 SYSTEM_INFO si;
43 GetSystemInfo(&si);
44 return si.dwAllocationGranularity;
Guido van Rossum8ce8a782007-11-01 19:42:39 +000045}
46
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000047#endif
48
49#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000050#include <sys/mman.h>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000051#include <sys/stat.h>
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000052
Fred Drake145f96e2000-10-01 17:50:46 +000053#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
54static int
55my_getpagesize(void)
56{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000057 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000058}
Guido van Rossum8ce8a782007-11-01 19:42:39 +000059
60#define my_getallocationgranularity my_getpagesize
Fred Drake145f96e2000-10-01 17:50:46 +000061#else
62#define my_getpagesize getpagesize
63#endif
64
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000065#endif /* UNIX */
66
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000067#include <string.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000068
69#ifdef HAVE_SYS_TYPES_H
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000070#include <sys/types.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000071#endif /* HAVE_SYS_TYPES_H */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000072
Neal Norwitz3eaf2b52006-02-16 08:08:54 +000073/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +000074#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
75# define MAP_ANONYMOUS MAP_ANON
76#endif
77
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000078static PyObject *mmap_module_error;
79
Tim Peters5ebfd362001-11-13 23:11:19 +000080typedef enum
81{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000082 ACCESS_DEFAULT,
83 ACCESS_READ,
84 ACCESS_WRITE,
85 ACCESS_COPY
Tim Peters5ebfd362001-11-13 23:11:19 +000086} access_mode;
87
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000088typedef struct {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000089 PyObject_HEAD
90 char * data;
91 size_t size;
92 size_t pos; /* relative to offset */
93 size_t offset;
94 int exports;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000095
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000096#ifdef MS_WINDOWS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000097 HANDLE map_handle;
98 HANDLE file_handle;
99 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000100#endif
101
102#ifdef UNIX
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000103 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000104#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000105
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000106 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000107} mmap_object;
108
Tim Peters5ebfd362001-11-13 23:11:19 +0000109
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000110static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000111mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000112{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000113#ifdef MS_WINDOWS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000114 if (m_obj->data != NULL)
115 UnmapViewOfFile (m_obj->data);
116 if (m_obj->map_handle != NULL)
117 CloseHandle (m_obj->map_handle);
118 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
119 CloseHandle (m_obj->file_handle);
120 if (m_obj->tagname)
121 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000122#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000123
124#ifdef UNIX
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000125 if (m_obj->fd >= 0)
126 (void) close(m_obj->fd);
127 if (m_obj->data!=NULL) {
R. David Murray07c1bd72010-12-11 02:05:32 +0000128 if (m_obj->access != ACCESS_READ && m_obj->access != ACCESS_COPY)
129 msync(m_obj->data, m_obj->size, MS_SYNC);
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000130 munmap(m_obj->data, m_obj->size);
131 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000132#endif /* UNIX */
133
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000134 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000135}
136
137static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000138mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000139{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000140 if (self->exports > 0) {
141 PyErr_SetString(PyExc_BufferError, "cannot close "\
142 "exported pointers exist");
143 return NULL;
144 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000145#ifdef MS_WINDOWS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000146 /* For each resource we maintain, we need to check
147 the value is valid, and if so, free the resource
148 and set the member value to an invalid value so
149 the dealloc does not attempt to resource clearing
150 again.
151 TODO - should we check for errors in the close operations???
152 */
153 if (self->data != NULL) {
154 UnmapViewOfFile(self->data);
155 self->data = NULL;
156 }
157 if (self->map_handle != NULL) {
158 CloseHandle(self->map_handle);
159 self->map_handle = NULL;
160 }
161 if (self->file_handle != INVALID_HANDLE_VALUE) {
162 CloseHandle(self->file_handle);
163 self->file_handle = INVALID_HANDLE_VALUE;
164 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000165#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000166
167#ifdef UNIX
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000168 if (0 <= self->fd)
169 (void) close(self->fd);
170 self->fd = -1;
171 if (self->data != NULL) {
172 munmap(self->data, self->size);
173 self->data = NULL;
174 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000175#endif
176
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000177 Py_INCREF(Py_None);
178 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000179}
180
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000181#ifdef MS_WINDOWS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000182#define CHECK_VALID(err) \
183do { \
184 if (self->map_handle == NULL) { \
185 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
186 return err; \
187 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000188} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000189#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000190
191#ifdef UNIX
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000192#define CHECK_VALID(err) \
193do { \
194 if (self->data == NULL) { \
195 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
196 return err; \
197 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000198} while (0)
199#endif /* UNIX */
200
201static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000202mmap_read_byte_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000203 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000204{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000205 CHECK_VALID(NULL);
206 if (self->pos < self->size) {
207 char value = self->data[self->pos];
208 self->pos += 1;
Hirokazu Yamamoto09ea7922010-11-04 12:35:21 +0000209 return Py_BuildValue("B", (unsigned char)value);
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000210 } else {
211 PyErr_SetString(PyExc_ValueError, "read byte out of range");
212 return NULL;
213 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000214}
215
216static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000217mmap_read_line_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000218 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000219{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000220 char *start = self->data+self->pos;
221 char *eof = self->data+self->size;
222 char *eol;
223 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000224
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000225 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000226
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000227 eol = memchr(start, '\n', self->size - self->pos);
228 if (!eol)
229 eol = eof;
230 else
231 ++eol; /* we're interested in the position after the
232 newline. */
233 result = PyBytes_FromStringAndSize(start, (eol - start));
234 self->pos += (eol - start);
235 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000236}
237
238static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000239mmap_read_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000240 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000241{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000242 Py_ssize_t num_bytes, n;
243 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000244
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000245 CHECK_VALID(NULL);
246 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
247 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000248
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000249 /* silently 'adjust' out-of-range requests */
250 assert(self->size >= self->pos);
251 n = self->size - self->pos;
252 /* The difference can overflow, only if self->size is greater than
253 * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed,
254 * because the mapped area and the returned string each need more
255 * than half of the addressable memory. So we clip the size, and let
256 * the code below raise MemoryError.
257 */
258 if (n < 0)
259 n = PY_SSIZE_T_MAX;
260 if (num_bytes < 0 || num_bytes > n) {
261 num_bytes = n;
262 }
263 result = PyBytes_FromStringAndSize(self->data+self->pos, num_bytes);
264 self->pos += num_bytes;
265 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000266}
267
268static PyObject *
Georg Brandlfceab5a2008-01-19 20:08:23 +0000269mmap_gfind(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000270 PyObject *args,
271 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000272{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000273 Py_ssize_t start = self->pos;
274 Py_ssize_t end = self->size;
275 const char *needle;
276 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000277
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000278 CHECK_VALID(NULL);
279 if (!PyArg_ParseTuple(args, reverse ? "y#|nn:rfind" : "y#|nn:find",
280 &needle, &len, &start, &end)) {
281 return NULL;
282 } else {
283 const char *p, *start_p, *end_p;
284 int sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000285
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000286 if (start < 0)
287 start += self->size;
288 if (start < 0)
289 start = 0;
290 else if ((size_t)start > self->size)
291 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000292
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000293 if (end < 0)
294 end += self->size;
295 if (end < 0)
296 end = 0;
297 else if ((size_t)end > self->size)
298 end = self->size;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000299
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000300 start_p = self->data + start;
301 end_p = self->data + end;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000302
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000303 for (p = (reverse ? end_p - len : start_p);
304 (p >= start_p) && (p + len <= end_p); p += sign) {
305 Py_ssize_t i;
306 for (i = 0; i < len && needle[i] == p[i]; ++i)
307 /* nothing */;
308 if (i == len) {
309 return PyLong_FromSsize_t(p - self->data);
310 }
311 }
312 return PyLong_FromLong(-1);
313 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000314}
315
Georg Brandlfceab5a2008-01-19 20:08:23 +0000316static PyObject *
317mmap_find_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000318 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000319{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000320 return mmap_gfind(self, args, 0);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000321}
322
323static PyObject *
324mmap_rfind_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000325 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000326{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000327 return mmap_gfind(self, args, 1);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000328}
329
Tim Petersec0a5f02006-02-16 23:47:20 +0000330static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000331is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000332{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000333 if (self->access != ACCESS_READ)
334 return 1;
335 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
336 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000337}
338
Tim Petersec0a5f02006-02-16 23:47:20 +0000339static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000340is_resizeable(mmap_object *self)
341{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000342 if (self->exports > 0) {
343 PyErr_SetString(PyExc_BufferError,
344 "mmap can't resize with extant buffers exported.");
345 return 0;
346 }
347 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
348 return 1;
349 PyErr_Format(PyExc_TypeError,
350 "mmap can't resize a readonly or copy-on-write memory map.");
351 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000352}
353
354
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000355static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000356mmap_write_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000357 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000358{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000359 Py_ssize_t length;
360 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000361
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000362 CHECK_VALID(NULL);
363 if (!PyArg_ParseTuple(args, "y#:write", &data, &length))
364 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000365
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000366 if (!is_writable(self))
367 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000368
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000369 if ((self->pos + length) > self->size) {
370 PyErr_SetString(PyExc_ValueError, "data out of range");
371 return NULL;
372 }
373 memcpy(self->data+self->pos, data, length);
374 self->pos = self->pos+length;
375 Py_INCREF(Py_None);
376 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000377}
378
379static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000380mmap_write_byte_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000381 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000382{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000383 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000384
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000385 CHECK_VALID(NULL);
386 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
387 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000388
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000389 if (!is_writable(self))
390 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000391
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000392 if (self->pos < self->size) {
393 *(self->data+self->pos) = value;
394 self->pos += 1;
395 Py_INCREF(Py_None);
396 return Py_None;
397 }
398 else {
399 PyErr_SetString(PyExc_ValueError, "write byte out of range");
400 return NULL;
401 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000402}
Tim Petersec0a5f02006-02-16 23:47:20 +0000403
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000404static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000405mmap_size_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000406 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000407{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000408 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000409
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000410#ifdef MS_WINDOWS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000411 if (self->file_handle != INVALID_HANDLE_VALUE) {
412 DWORD low,high;
413 PY_LONG_LONG size;
414 low = GetFileSize(self->file_handle, &high);
415 if (low == INVALID_FILE_SIZE) {
416 /* It might be that the function appears to have failed,
417 when indeed its size equals INVALID_FILE_SIZE */
418 DWORD error = GetLastError();
419 if (error != NO_ERROR)
420 return PyErr_SetFromWindowsErr(error);
421 }
422 if (!high && low < LONG_MAX)
423 return PyLong_FromLong((long)low);
424 size = (((PY_LONG_LONG)high)<<32) + low;
425 return PyLong_FromLongLong(size);
426 } else {
427 return PyLong_FromSsize_t(self->size);
428 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000429#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000430
431#ifdef UNIX
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000432 {
433 struct stat buf;
434 if (-1 == fstat(self->fd, &buf)) {
435 PyErr_SetFromErrno(mmap_module_error);
436 return NULL;
437 }
438 return PyLong_FromSsize_t(buf.st_size);
439 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000440#endif /* UNIX */
441}
442
443/* This assumes that you want the entire file mapped,
444 / and when recreating the map will make the new file
445 / have the new size
446 /
447 / Is this really necessary? This could easily be done
448 / from python by just closing and re-opening with the
449 / new size?
450 */
451
452static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000453mmap_resize_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000454 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000455{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000456 Py_ssize_t new_size;
457 CHECK_VALID(NULL);
458 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
459 !is_resizeable(self)) {
460 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000461#ifdef MS_WINDOWS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000462 } else {
463 DWORD dwErrCode = 0;
464 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
465 /* First, unmap the file view */
466 UnmapViewOfFile(self->data);
467 self->data = NULL;
468 /* Close the mapping object */
469 CloseHandle(self->map_handle);
470 self->map_handle = NULL;
471 /* Move to the desired EOF position */
Martin v. Löwis15186072006-02-18 12:38:35 +0000472#if SIZEOF_SIZE_T > 4
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000473 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
474 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
475 off_hi = (DWORD)(self->offset >> 32);
476 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Martin v. Löwis15186072006-02-18 12:38:35 +0000477#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000478 newSizeHigh = 0;
479 newSizeLow = (DWORD)(self->offset + new_size);
480 off_hi = 0;
481 off_lo = (DWORD)self->offset;
Martin v. Löwis15186072006-02-18 12:38:35 +0000482#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000483 SetFilePointer(self->file_handle,
484 newSizeLow, &newSizeHigh, FILE_BEGIN);
485 /* Change the size of the file */
486 SetEndOfFile(self->file_handle);
487 /* Create another mapping object and remap the file view */
488 self->map_handle = CreateFileMapping(
489 self->file_handle,
490 NULL,
491 PAGE_READWRITE,
492 0,
493 0,
494 self->tagname);
495 if (self->map_handle != NULL) {
496 self->data = (char *) MapViewOfFile(self->map_handle,
497 FILE_MAP_WRITE,
498 off_hi,
499 off_lo,
500 new_size);
501 if (self->data != NULL) {
502 self->size = new_size;
503 Py_INCREF(Py_None);
504 return Py_None;
505 } else {
506 dwErrCode = GetLastError();
507 CloseHandle(self->map_handle);
508 self->map_handle = NULL;
509 }
510 } else {
511 dwErrCode = GetLastError();
512 }
513 PyErr_SetFromWindowsErr(dwErrCode);
514 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000515#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000516
517#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000518#ifndef HAVE_MREMAP
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000519 } else {
520 PyErr_SetString(PyExc_SystemError,
521 "mmap: resizing not available--no mremap()");
522 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000523#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000524 } else {
525 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000526
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000527 if (ftruncate(self->fd, self->offset + new_size) == -1) {
528 PyErr_SetFromErrno(mmap_module_error);
529 return NULL;
530 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000531
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000532#ifdef MREMAP_MAYMOVE
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000533 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000534#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000535 #if defined(__NetBSD__)
536 newmap = mremap(self->data, self->size, self->data, new_size, 0);
537 #else
538 newmap = mremap(self->data, self->size, new_size, 0);
539 #endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000540#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000541 if (newmap == (void *)-1)
542 {
543 PyErr_SetFromErrno(mmap_module_error);
544 return NULL;
545 }
546 self->data = newmap;
547 self->size = new_size;
548 Py_INCREF(Py_None);
549 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000550#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000551#endif /* UNIX */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000552 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000553}
554
555static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000556mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000557{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000558 CHECK_VALID(NULL);
559 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000560}
561
562static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000563mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000564{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000565 Py_ssize_t offset = 0;
566 Py_ssize_t size = self->size;
567 CHECK_VALID(NULL);
568 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
569 return NULL;
570 if ((size_t)(offset + size) > self->size) {
571 PyErr_SetString(PyExc_ValueError, "flush values out of range");
572 return NULL;
573 }
R. David Murray07c1bd72010-12-11 02:05:32 +0000574
575 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
576 return PyLong_FromLong(0);
577
Christian Heimesaf98da12008-01-27 15:18:18 +0000578#ifdef MS_WINDOWS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000579 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
Christian Heimesaf98da12008-01-27 15:18:18 +0000580#elif defined(UNIX)
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000581 /* XXX semantics of return value? */
582 /* XXX flags for msync? */
583 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
584 PyErr_SetFromErrno(mmap_module_error);
585 return NULL;
586 }
587 return PyLong_FromLong(0);
Christian Heimesaf98da12008-01-27 15:18:18 +0000588#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000589 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
590 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000591#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000592}
593
594static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000595mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000596{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000597 Py_ssize_t dist;
598 int how=0;
599 CHECK_VALID(NULL);
600 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
601 return NULL;
602 else {
603 size_t where;
604 switch (how) {
605 case 0: /* relative to start */
606 if (dist < 0)
607 goto onoutofrange;
608 where = dist;
609 break;
610 case 1: /* relative to current position */
611 if ((Py_ssize_t)self->pos + dist < 0)
612 goto onoutofrange;
613 where = self->pos + dist;
614 break;
615 case 2: /* relative to end */
616 if ((Py_ssize_t)self->size + dist < 0)
617 goto onoutofrange;
618 where = self->size + dist;
619 break;
620 default:
621 PyErr_SetString(PyExc_ValueError, "unknown seek type");
622 return NULL;
623 }
624 if (where > self->size)
625 goto onoutofrange;
626 self->pos = where;
627 Py_INCREF(Py_None);
628 return Py_None;
629 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000630
Tim Peters5ebfd362001-11-13 23:11:19 +0000631 onoutofrange:
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000632 PyErr_SetString(PyExc_ValueError, "seek out of range");
633 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000634}
635
636static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000637mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000638{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000639 unsigned long dest, src, cnt;
640 CHECK_VALID(NULL);
641 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
642 !is_writable(self)) {
643 return NULL;
644 } else {
645 /* bounds check the values */
646 if (cnt < 0 || (cnt + dest) < cnt || (cnt + src) < cnt ||
647 src < 0 || src > self->size || (src + cnt) > self->size ||
648 dest < 0 || dest > self->size || (dest + cnt) > self->size) {
649 PyErr_SetString(PyExc_ValueError,
650 "source, destination, or count out of range");
651 return NULL;
652 }
653 memmove(self->data+dest, self->data+src, cnt);
654 Py_INCREF(Py_None);
655 return Py_None;
656 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000657}
658
659static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000660 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
661 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
662 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
663 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
664 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
665 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
666 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
667 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
668 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
669 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
670 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
671 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
672 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
673 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
674 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000675};
676
677/* Functions for treating an mmap'ed file as a buffer */
678
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000679static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000680mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000681{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000682 CHECK_VALID(-1);
683 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
684 (self->access == ACCESS_READ), flags) < 0)
685 return -1;
686 self->exports++;
687 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000688}
689
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000690static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000691mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000692{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000693 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000694}
695
Martin v. Löwis18e16552006-02-15 17:27:45 +0000696static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000697mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000698{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000699 CHECK_VALID(-1);
700 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000701}
702
703static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000704mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000705{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000706 CHECK_VALID(NULL);
707 if (i < 0 || (size_t)i >= self->size) {
708 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
709 return NULL;
710 }
711 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000712}
713
714static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000715mmap_subscript(mmap_object *self, PyObject *item)
716{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000717 CHECK_VALID(NULL);
718 if (PyIndex_Check(item)) {
719 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
720 if (i == -1 && PyErr_Occurred())
721 return NULL;
722 if (i < 0)
723 i += self->size;
724 if (i < 0 || (size_t)i >= self->size) {
725 PyErr_SetString(PyExc_IndexError,
726 "mmap index out of range");
727 return NULL;
728 }
729 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
730 }
731 else if (PySlice_Check(item)) {
732 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000733
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000734 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
735 &start, &stop, &step, &slicelen) < 0) {
736 return NULL;
737 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000738
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000739 if (slicelen <= 0)
740 return PyBytes_FromStringAndSize("", 0);
741 else if (step == 1)
742 return PyBytes_FromStringAndSize(self->data + start,
743 slicelen);
744 else {
745 char *result_buf = (char *)PyMem_Malloc(slicelen);
746 Py_ssize_t cur, i;
747 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000748
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000749 if (result_buf == NULL)
750 return PyErr_NoMemory();
751 for (cur = start, i = 0; i < slicelen;
752 cur += step, i++) {
753 result_buf[i] = self->data[cur];
754 }
755 result = PyBytes_FromStringAndSize(result_buf,
756 slicelen);
757 PyMem_Free(result_buf);
758 return result;
759 }
760 }
761 else {
762 PyErr_SetString(PyExc_TypeError,
763 "mmap indices must be integers");
764 return NULL;
765 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000766}
767
768static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000769mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000770{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000771 CHECK_VALID(NULL);
772 PyErr_SetString(PyExc_SystemError,
773 "mmaps don't support concatenation");
774 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000775}
776
777static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000778mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000779{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000780 CHECK_VALID(NULL);
781 PyErr_SetString(PyExc_SystemError,
782 "mmaps don't support repeat operation");
783 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000784}
785
786static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000787mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000788{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000789 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000790
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000791 CHECK_VALID(-1);
792 if (i < 0 || (size_t)i >= self->size) {
793 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
794 return -1;
795 }
796 if (v == NULL) {
797 PyErr_SetString(PyExc_TypeError,
798 "mmap object doesn't support item deletion");
799 return -1;
800 }
801 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
802 PyErr_SetString(PyExc_IndexError,
803 "mmap assignment must be length-1 bytes()");
804 return -1;
805 }
806 if (!is_writable(self))
807 return -1;
808 buf = PyBytes_AsString(v);
809 self->data[i] = buf[0];
810 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000811}
812
Thomas Woutersed03b412007-08-28 21:37:11 +0000813static int
814mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
815{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000816 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000817
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000818 if (!is_writable(self))
819 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000820
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000821 if (PyIndex_Check(item)) {
822 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
823 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000824
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000825 if (i == -1 && PyErr_Occurred())
826 return -1;
827 if (i < 0)
828 i += self->size;
829 if (i < 0 || (size_t)i >= self->size) {
830 PyErr_SetString(PyExc_IndexError,
831 "mmap index out of range");
832 return -1;
833 }
834 if (value == NULL) {
835 PyErr_SetString(PyExc_TypeError,
836 "mmap doesn't support item deletion");
837 return -1;
838 }
839 if (!PyIndex_Check(value)) {
840 PyErr_SetString(PyExc_TypeError,
841 "mmap item value must be an int");
842 return -1;
843 }
844 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
845 if (v == -1 && PyErr_Occurred())
846 return -1;
847 if (v < 0 || v > 255) {
848 PyErr_SetString(PyExc_ValueError,
849 "mmap item value must be "
850 "in range(0, 256)");
851 return -1;
852 }
Antoine Pitrou835b4452010-08-15 18:32:16 +0000853 self->data[i] = (char) v;
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000854 return 0;
855 }
856 else if (PySlice_Check(item)) {
857 Py_ssize_t start, stop, step, slicelen;
858 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000859
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000860 if (PySlice_GetIndicesEx((PySliceObject *)item,
861 self->size, &start, &stop,
862 &step, &slicelen) < 0) {
863 return -1;
864 }
865 if (value == NULL) {
866 PyErr_SetString(PyExc_TypeError,
867 "mmap object doesn't support slice deletion");
868 return -1;
869 }
870 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
871 return -1;
872 if (vbuf.len != slicelen) {
873 PyErr_SetString(PyExc_IndexError,
874 "mmap slice assignment is wrong size");
875 PyBuffer_Release(&vbuf);
876 return -1;
877 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000878
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000879 if (slicelen == 0) {
880 }
881 else if (step == 1) {
882 memcpy(self->data + start, vbuf.buf, slicelen);
883 }
884 else {
885 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000886
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000887 for (cur = start, i = 0;
888 i < slicelen;
889 cur += step, i++)
890 {
891 self->data[cur] = ((char *)vbuf.buf)[i];
892 }
893 }
894 PyBuffer_Release(&vbuf);
895 return 0;
896 }
897 else {
898 PyErr_SetString(PyExc_TypeError,
899 "mmap indices must be integer");
900 return -1;
901 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000902}
903
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000904static PySequenceMethods mmap_as_sequence = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000905 (lenfunc)mmap_length, /*sq_length*/
906 (binaryfunc)mmap_concat, /*sq_concat*/
907 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
908 (ssizeargfunc)mmap_item, /*sq_item*/
909 0, /*sq_slice*/
910 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
911 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000912};
913
Thomas Woutersed03b412007-08-28 21:37:11 +0000914static PyMappingMethods mmap_as_mapping = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000915 (lenfunc)mmap_length,
916 (binaryfunc)mmap_subscript,
917 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +0000918};
919
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000920static PyBufferProcs mmap_as_buffer = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000921 (getbufferproc)mmap_buffer_getbuf,
922 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000923};
924
Georg Brandl86def6c2008-01-21 20:36:10 +0000925static PyObject *
926new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
927
Christian Heimese1c98112008-01-21 11:20:28 +0000928PyDoc_STRVAR(mmap_doc,
929"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
930\n\
931Maps length bytes from the file specified by the file handle fileno,\n\
932and returns a mmap object. If length is larger than the current size\n\
933of the file, the file is extended to contain length bytes. If length\n\
934is 0, the maximum length of the map is the current size of the file,\n\
935except that if the file is empty Windows raises an exception (you cannot\n\
936create an empty mapping on Windows).\n\
937\n\
938Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
939\n\
940Maps length bytes from the file specified by the file descriptor fileno,\n\
941and returns a mmap object. If length is 0, the maximum length of the map\n\
942will be the current size of the file when mmap is called.\n\
943flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
944private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +0000945object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +0000946that's shared with all other processes mapping the same areas of the file.\n\
947The default value is MAP_SHARED.\n\
948\n\
949To map anonymous memory, pass -1 as the fileno (both versions).");
950
951
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000952static PyTypeObject mmap_object_type = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000953 PyVarObject_HEAD_INIT(NULL, 0)
954 "mmap.mmap", /* tp_name */
955 sizeof(mmap_object), /* tp_size */
956 0, /* tp_itemsize */
957 /* methods */
958 (destructor) mmap_object_dealloc, /* tp_dealloc */
959 0, /* tp_print */
960 0, /* tp_getattr */
961 0, /* tp_setattr */
962 0, /* tp_reserved */
963 0, /* tp_repr */
964 0, /* tp_as_number */
965 &mmap_as_sequence, /*tp_as_sequence*/
966 &mmap_as_mapping, /*tp_as_mapping*/
967 0, /*tp_hash*/
968 0, /*tp_call*/
969 0, /*tp_str*/
970 PyObject_GenericGetAttr, /*tp_getattro*/
971 0, /*tp_setattro*/
972 &mmap_as_buffer, /*tp_as_buffer*/
973 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
974 mmap_doc, /*tp_doc*/
975 0, /* tp_traverse */
976 0, /* tp_clear */
977 0, /* tp_richcompare */
978 0, /* tp_weaklistoffset */
979 0, /* tp_iter */
980 0, /* tp_iternext */
981 mmap_object_methods, /* tp_methods */
982 0, /* tp_members */
983 0, /* tp_getset */
984 0, /* tp_base */
985 0, /* tp_dict */
986 0, /* tp_descr_get */
987 0, /* tp_descr_set */
988 0, /* tp_dictoffset */
989 0, /* tp_init */
990 PyType_GenericAlloc, /* tp_alloc */
991 new_mmap_object, /* tp_new */
992 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000993};
994
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000995
996/* extract the map size from the given PyObject
997
Thomas Wouters7e474022000-07-16 12:04:32 +0000998 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000999 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001000static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001001_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001002{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001003 if (o == NULL)
1004 return 0;
1005 if (PyIndex_Check(o)) {
1006 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1007 if (i==-1 && PyErr_Occurred())
1008 return -1;
1009 if (i < 0) {
1010 PyErr_Format(PyExc_OverflowError,
1011 "memory mapped %s must be positive",
1012 param);
1013 return -1;
1014 }
1015 return i;
1016 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001017
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001018 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1019 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001020}
1021
Tim Petersec0a5f02006-02-16 23:47:20 +00001022#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001023static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001024new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001025{
Neal Norwitzb5673922002-09-05 21:48:07 +00001026#ifdef HAVE_FSTAT
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001027 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001028#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001029 mmap_object *m_obj;
1030 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1031 Py_ssize_t map_size, offset;
1032 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1033 int devzero = -1;
1034 int access = (int)ACCESS_DEFAULT;
1035 static char *keywords[] = {"fileno", "length",
1036 "flags", "prot",
1037 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001038
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001039 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iiiO", keywords,
1040 &fd, &map_size_obj, &flags, &prot,
1041 &access, &offset_obj))
1042 return NULL;
1043 map_size = _GetMapSize(map_size_obj, "size");
1044 if (map_size < 0)
1045 return NULL;
1046 offset = _GetMapSize(offset_obj, "offset");
1047 if (offset < 0)
1048 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001049
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001050 if ((access != (int)ACCESS_DEFAULT) &&
1051 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1052 return PyErr_Format(PyExc_ValueError,
1053 "mmap can't specify both access and flags, prot.");
1054 switch ((access_mode)access) {
1055 case ACCESS_READ:
1056 flags = MAP_SHARED;
1057 prot = PROT_READ;
1058 break;
1059 case ACCESS_WRITE:
1060 flags = MAP_SHARED;
1061 prot = PROT_READ | PROT_WRITE;
1062 break;
1063 case ACCESS_COPY:
1064 flags = MAP_PRIVATE;
1065 prot = PROT_READ | PROT_WRITE;
1066 break;
1067 case ACCESS_DEFAULT:
1068 /* use the specified or default values of flags and prot */
1069 break;
1070 default:
1071 return PyErr_Format(PyExc_ValueError,
1072 "mmap invalid access parameter.");
1073 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001074
Christian Heimesa156e092008-02-16 07:38:31 +00001075 if (prot == PROT_READ) {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001076 access = ACCESS_READ;
Christian Heimesa156e092008-02-16 07:38:31 +00001077 }
1078
Neal Norwitzb5673922002-09-05 21:48:07 +00001079#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001080# ifdef __VMS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001081 /* on OpenVMS we must ensure that all bytes are written to the file */
1082 if (fd != -1) {
1083 fsync(fd);
1084 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001085# endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001086 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1087 if (map_size == 0) {
Antoine Pitrou6107a4e2011-01-20 21:11:13 +00001088 if (offset >= st.st_size) {
1089 PyErr_SetString(PyExc_ValueError,
1090 "mmap offset is greater than file size");
1091 return NULL;
1092 }
Antoine Pitroufb7bc3d2011-01-15 16:18:37 +00001093 map_size = st.st_size - offset;
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001094 } else if ((size_t)offset + (size_t)map_size > st.st_size) {
1095 PyErr_SetString(PyExc_ValueError,
1096 "mmap length is greater than file size");
1097 return NULL;
1098 }
1099 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001100#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001101 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1102 if (m_obj == NULL) {return NULL;}
1103 m_obj->data = NULL;
1104 m_obj->size = (size_t) map_size;
1105 m_obj->pos = (size_t) 0;
1106 m_obj->exports = 0;
1107 m_obj->offset = offset;
1108 if (fd == -1) {
1109 m_obj->fd = -1;
1110 /* Assume the caller wants to map anonymous memory.
1111 This is the same behaviour as Windows. mmap.mmap(-1, size)
1112 on both Windows and Unix map anonymous memory.
1113 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001114#ifdef MAP_ANONYMOUS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001115 /* BSD way to map anonymous memory */
1116 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001117#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001118 /* SVR4 method to map anonymous memory is to open /dev/zero */
1119 fd = devzero = open("/dev/zero", O_RDWR);
1120 if (devzero == -1) {
1121 Py_DECREF(m_obj);
1122 PyErr_SetFromErrno(mmap_module_error);
1123 return NULL;
1124 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001125#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001126 } else {
1127 m_obj->fd = dup(fd);
1128 if (m_obj->fd == -1) {
1129 Py_DECREF(m_obj);
1130 PyErr_SetFromErrno(mmap_module_error);
1131 return NULL;
1132 }
1133 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001134
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001135 m_obj->data = mmap(NULL, map_size,
1136 prot, flags,
1137 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001138
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001139 if (devzero != -1) {
1140 close(devzero);
1141 }
1142
1143 if (m_obj->data == (char *)-1) {
1144 m_obj->data = NULL;
1145 Py_DECREF(m_obj);
1146 PyErr_SetFromErrno(mmap_module_error);
1147 return NULL;
1148 }
1149 m_obj->access = (access_mode)access;
1150 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001151}
1152#endif /* UNIX */
1153
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001154#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001155static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001156new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001157{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001158 mmap_object *m_obj;
1159 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1160 Py_ssize_t map_size, offset;
1161 DWORD off_hi; /* upper 32 bits of offset */
1162 DWORD off_lo; /* lower 32 bits of offset */
1163 DWORD size_hi; /* upper 32 bits of size */
1164 DWORD size_lo; /* lower 32 bits of size */
1165 char *tagname = "";
1166 DWORD dwErr = 0;
1167 int fileno;
1168 HANDLE fh = 0;
1169 int access = (access_mode)ACCESS_DEFAULT;
1170 DWORD flProtect, dwDesiredAccess;
1171 static char *keywords[] = { "fileno", "length",
1172 "tagname",
1173 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001174
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001175 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
1176 &fileno, &map_size_obj,
1177 &tagname, &access, &offset_obj)) {
1178 return NULL;
1179 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001180
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001181 switch((access_mode)access) {
1182 case ACCESS_READ:
1183 flProtect = PAGE_READONLY;
1184 dwDesiredAccess = FILE_MAP_READ;
1185 break;
1186 case ACCESS_DEFAULT: case ACCESS_WRITE:
1187 flProtect = PAGE_READWRITE;
1188 dwDesiredAccess = FILE_MAP_WRITE;
1189 break;
1190 case ACCESS_COPY:
1191 flProtect = PAGE_WRITECOPY;
1192 dwDesiredAccess = FILE_MAP_COPY;
1193 break;
1194 default:
1195 return PyErr_Format(PyExc_ValueError,
1196 "mmap invalid access parameter.");
1197 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001198
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001199 map_size = _GetMapSize(map_size_obj, "size");
1200 if (map_size < 0)
1201 return NULL;
1202 offset = _GetMapSize(offset_obj, "offset");
1203 if (offset < 0)
1204 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001205
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001206 /* assume -1 and 0 both mean invalid filedescriptor
1207 to 'anonymously' map memory.
1208 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1209 XXX: Should this code be added?
1210 if (fileno == 0)
1211 PyErr_WarnEx(PyExc_DeprecationWarning,
1212 "don't use 0 for anonymous memory",
1213 1);
1214 */
1215 if (fileno != -1 && fileno != 0) {
Brian Curtin686ee4f2010-08-01 15:44:11 +00001216 /* Ensure that fileno is within the CRT's valid range */
1217 if (_PyVerify_fd(fileno) == 0) {
1218 PyErr_SetFromErrno(mmap_module_error);
1219 return NULL;
1220 }
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001221 fh = (HANDLE)_get_osfhandle(fileno);
1222 if (fh==(HANDLE)-1) {
1223 PyErr_SetFromErrno(mmap_module_error);
1224 return NULL;
1225 }
1226 /* Win9x appears to need us seeked to zero */
1227 lseek(fileno, 0, SEEK_SET);
1228 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001229
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001230 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1231 if (m_obj == NULL)
1232 return NULL;
1233 /* Set every field to an invalid marker, so we can safely
1234 destruct the object in the face of failure */
1235 m_obj->data = NULL;
1236 m_obj->file_handle = INVALID_HANDLE_VALUE;
1237 m_obj->map_handle = NULL;
1238 m_obj->tagname = NULL;
1239 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001240
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001241 if (fh) {
1242 /* It is necessary to duplicate the handle, so the
1243 Python code can close it on us */
1244 if (!DuplicateHandle(
1245 GetCurrentProcess(), /* source process handle */
1246 fh, /* handle to be duplicated */
1247 GetCurrentProcess(), /* target proc handle */
1248 (LPHANDLE)&m_obj->file_handle, /* result */
1249 0, /* access - ignored due to options value */
1250 FALSE, /* inherited by child processes? */
1251 DUPLICATE_SAME_ACCESS)) { /* options */
1252 dwErr = GetLastError();
1253 Py_DECREF(m_obj);
1254 PyErr_SetFromWindowsErr(dwErr);
1255 return NULL;
1256 }
1257 if (!map_size) {
1258 DWORD low,high;
1259 low = GetFileSize(fh, &high);
1260 /* low might just happen to have the value INVALID_FILE_SIZE;
1261 so we need to check the last error also. */
1262 if (low == INVALID_FILE_SIZE &&
1263 (dwErr = GetLastError()) != NO_ERROR) {
1264 Py_DECREF(m_obj);
1265 return PyErr_SetFromWindowsErr(dwErr);
1266 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001267
Martin v. Löwis15186072006-02-18 12:38:35 +00001268#if SIZEOF_SIZE_T > 4
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001269 m_obj->size = (((size_t)high)<<32) + low;
Martin v. Löwis15186072006-02-18 12:38:35 +00001270#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001271 if (high)
1272 /* File is too large to map completely */
1273 m_obj->size = (size_t)-1;
1274 else
1275 m_obj->size = low;
Martin v. Löwis15186072006-02-18 12:38:35 +00001276#endif
Antoine Pitrou6107a4e2011-01-20 21:11:13 +00001277 if (offset >= m_obj->size) {
1278 PyErr_SetString(PyExc_ValueError,
1279 "mmap offset is greater than file size");
1280 Py_DECREF(m_obj);
1281 return NULL;
1282 }
Antoine Pitrou50dc65f2011-01-15 17:31:19 +00001283 m_obj->size -= offset;
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001284 } else {
1285 m_obj->size = map_size;
1286 }
1287 }
1288 else {
1289 m_obj->size = map_size;
1290 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001291
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001292 /* set the initial position */
1293 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001294
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001295 m_obj->exports = 0;
1296 /* set the tag name */
1297 if (tagname != NULL && *tagname != '\0') {
1298 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1299 if (m_obj->tagname == NULL) {
1300 PyErr_NoMemory();
1301 Py_DECREF(m_obj);
1302 return NULL;
1303 }
1304 strcpy(m_obj->tagname, tagname);
1305 }
1306 else
1307 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001308
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001309 m_obj->access = (access_mode)access;
1310 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
1311 * more than 4 bytes, we need to break it apart. Else (size_t
1312 * consumes 4 bytes), C doesn't define what happens if we shift
1313 * right by 32, so we need different code.
1314 */
Tim Peterse564e7f2006-02-16 23:46:01 +00001315#if SIZEOF_SIZE_T > 4
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001316 size_hi = (DWORD)((offset + m_obj->size) >> 32);
1317 size_lo = (DWORD)((offset + m_obj->size) & 0xFFFFFFFF);
1318 off_hi = (DWORD)(offset >> 32);
1319 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Tim Peterse564e7f2006-02-16 23:46:01 +00001320#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001321 size_hi = 0;
1322 size_lo = (DWORD)(offset + m_obj->size);
1323 off_hi = 0;
1324 off_lo = (DWORD)offset;
Tim Peterse564e7f2006-02-16 23:46:01 +00001325#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001326 /* For files, it would be sufficient to pass 0 as size.
1327 For anonymous maps, we have to pass the size explicitly. */
1328 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1329 NULL,
1330 flProtect,
1331 size_hi,
1332 size_lo,
1333 m_obj->tagname);
1334 if (m_obj->map_handle != NULL) {
1335 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1336 dwDesiredAccess,
1337 off_hi,
1338 off_lo,
1339 m_obj->size);
1340 if (m_obj->data != NULL)
1341 return (PyObject *)m_obj;
1342 else {
1343 dwErr = GetLastError();
1344 CloseHandle(m_obj->map_handle);
1345 m_obj->map_handle = NULL;
1346 }
1347 } else
1348 dwErr = GetLastError();
1349 Py_DECREF(m_obj);
1350 PyErr_SetFromWindowsErr(dwErr);
1351 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001352}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001353#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001354
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001355static void
1356setint(PyObject *d, const char *name, long value)
1357{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001358 PyObject *o = PyLong_FromLong(value);
1359 if (o && PyDict_SetItemString(d, name, o) == 0) {
1360 Py_DECREF(o);
1361 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001362}
1363
Martin v. Löwis1a214512008-06-11 05:26:20 +00001364
1365static struct PyModuleDef mmapmodule = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001366 PyModuleDef_HEAD_INIT,
1367 "mmap",
1368 NULL,
1369 -1,
1370 NULL,
1371 NULL,
1372 NULL,
1373 NULL,
1374 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001375};
1376
Mark Hammond62b1ab12002-07-23 06:31:15 +00001377PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001378PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001379{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001380 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001381
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001382 if (PyType_Ready(&mmap_object_type) < 0)
1383 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001384
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001385 module = PyModule_Create(&mmapmodule);
1386 if (module == NULL)
1387 return NULL;
1388 dict = PyModule_GetDict(module);
1389 if (!dict)
1390 return NULL;
1391 mmap_module_error = PyErr_NewException("mmap.error",
1392 PyExc_EnvironmentError , NULL);
1393 if (mmap_module_error == NULL)
1394 return NULL;
1395 PyDict_SetItemString(dict, "error", mmap_module_error);
1396 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001397#ifdef PROT_EXEC
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001398 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001399#endif
1400#ifdef PROT_READ
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001401 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001402#endif
1403#ifdef PROT_WRITE
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001404 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001405#endif
1406
1407#ifdef MAP_SHARED
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001408 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001409#endif
1410#ifdef MAP_PRIVATE
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001411 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001412#endif
1413#ifdef MAP_DENYWRITE
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001414 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001415#endif
1416#ifdef MAP_EXECUTABLE
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001417 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001418#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001419#ifdef MAP_ANONYMOUS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001420 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1421 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001422#endif
1423
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001424 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001425
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001426 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001427
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001428 setint(dict, "ACCESS_READ", ACCESS_READ);
1429 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1430 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1431 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001432}