blob: f484a7a75bce5a5687b6a012f625a8687e8323cd [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 */
Antoine Pitrou9e719b62011-02-28 23:48:16 +000093#ifdef MS_WINDOWS
94 PY_LONG_LONG offset;
95#else
96 off_t offset;
97#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +000098 int exports;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000099
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000100#ifdef MS_WINDOWS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000101 HANDLE map_handle;
102 HANDLE file_handle;
103 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000104#endif
105
106#ifdef UNIX
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000107 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000108#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000109
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000110 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000111} mmap_object;
112
Tim Peters5ebfd362001-11-13 23:11:19 +0000113
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000114static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000115mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000116{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000117#ifdef MS_WINDOWS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000118 if (m_obj->data != NULL)
119 UnmapViewOfFile (m_obj->data);
120 if (m_obj->map_handle != NULL)
121 CloseHandle (m_obj->map_handle);
122 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
123 CloseHandle (m_obj->file_handle);
124 if (m_obj->tagname)
125 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000126#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000127
128#ifdef UNIX
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000129 if (m_obj->fd >= 0)
130 (void) close(m_obj->fd);
131 if (m_obj->data!=NULL) {
R. David Murray07c1bd72010-12-11 02:05:32 +0000132 if (m_obj->access != ACCESS_READ && m_obj->access != ACCESS_COPY)
133 msync(m_obj->data, m_obj->size, MS_SYNC);
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000134 munmap(m_obj->data, m_obj->size);
135 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000136#endif /* UNIX */
137
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000138 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000139}
140
141static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000142mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000143{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000144 if (self->exports > 0) {
145 PyErr_SetString(PyExc_BufferError, "cannot close "\
146 "exported pointers exist");
147 return NULL;
148 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000149#ifdef MS_WINDOWS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000150 /* For each resource we maintain, we need to check
151 the value is valid, and if so, free the resource
152 and set the member value to an invalid value so
153 the dealloc does not attempt to resource clearing
154 again.
155 TODO - should we check for errors in the close operations???
156 */
157 if (self->data != NULL) {
158 UnmapViewOfFile(self->data);
159 self->data = NULL;
160 }
161 if (self->map_handle != NULL) {
162 CloseHandle(self->map_handle);
163 self->map_handle = NULL;
164 }
165 if (self->file_handle != INVALID_HANDLE_VALUE) {
166 CloseHandle(self->file_handle);
167 self->file_handle = INVALID_HANDLE_VALUE;
168 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000169#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000170
171#ifdef UNIX
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000172 if (0 <= self->fd)
173 (void) close(self->fd);
174 self->fd = -1;
175 if (self->data != NULL) {
176 munmap(self->data, self->size);
177 self->data = NULL;
178 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000179#endif
180
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000181 Py_INCREF(Py_None);
182 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000183}
184
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000185#ifdef MS_WINDOWS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000186#define CHECK_VALID(err) \
187do { \
188 if (self->map_handle == NULL) { \
189 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
190 return err; \
191 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000192} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000193#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000194
195#ifdef UNIX
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000196#define CHECK_VALID(err) \
197do { \
198 if (self->data == NULL) { \
199 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
200 return err; \
201 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000202} while (0)
203#endif /* UNIX */
204
205static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000206mmap_read_byte_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000207 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000208{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000209 CHECK_VALID(NULL);
210 if (self->pos < self->size) {
211 char value = self->data[self->pos];
212 self->pos += 1;
Hirokazu Yamamoto09ea7922010-11-04 12:35:21 +0000213 return Py_BuildValue("B", (unsigned char)value);
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000214 } else {
215 PyErr_SetString(PyExc_ValueError, "read byte out of range");
216 return NULL;
217 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000218}
219
220static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000221mmap_read_line_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000222 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000223{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000224 char *start = self->data+self->pos;
225 char *eof = self->data+self->size;
226 char *eol;
227 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000228
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000229 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000230
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000231 eol = memchr(start, '\n', self->size - self->pos);
232 if (!eol)
233 eol = eof;
234 else
235 ++eol; /* we're interested in the position after the
236 newline. */
237 result = PyBytes_FromStringAndSize(start, (eol - start));
238 self->pos += (eol - start);
239 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000240}
241
242static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000243mmap_read_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000244 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000245{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000246 Py_ssize_t num_bytes, n;
247 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000248
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000249 CHECK_VALID(NULL);
250 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
251 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000252
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000253 /* silently 'adjust' out-of-range requests */
254 assert(self->size >= self->pos);
255 n = self->size - self->pos;
256 /* The difference can overflow, only if self->size is greater than
257 * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed,
258 * because the mapped area and the returned string each need more
259 * than half of the addressable memory. So we clip the size, and let
260 * the code below raise MemoryError.
261 */
262 if (n < 0)
263 n = PY_SSIZE_T_MAX;
264 if (num_bytes < 0 || num_bytes > n) {
265 num_bytes = n;
266 }
267 result = PyBytes_FromStringAndSize(self->data+self->pos, num_bytes);
268 self->pos += num_bytes;
269 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000270}
271
272static PyObject *
Georg Brandlfceab5a2008-01-19 20:08:23 +0000273mmap_gfind(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000274 PyObject *args,
275 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000276{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000277 Py_ssize_t start = self->pos;
278 Py_ssize_t end = self->size;
279 const char *needle;
280 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000281
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000282 CHECK_VALID(NULL);
283 if (!PyArg_ParseTuple(args, reverse ? "y#|nn:rfind" : "y#|nn:find",
284 &needle, &len, &start, &end)) {
285 return NULL;
286 } else {
287 const char *p, *start_p, *end_p;
288 int sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000289
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000290 if (start < 0)
291 start += self->size;
292 if (start < 0)
293 start = 0;
294 else if ((size_t)start > self->size)
295 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000296
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000297 if (end < 0)
298 end += self->size;
299 if (end < 0)
300 end = 0;
301 else if ((size_t)end > self->size)
302 end = self->size;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000303
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000304 start_p = self->data + start;
305 end_p = self->data + end;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000306
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000307 for (p = (reverse ? end_p - len : start_p);
308 (p >= start_p) && (p + len <= end_p); p += sign) {
309 Py_ssize_t i;
310 for (i = 0; i < len && needle[i] == p[i]; ++i)
311 /* nothing */;
312 if (i == len) {
313 return PyLong_FromSsize_t(p - self->data);
314 }
315 }
316 return PyLong_FromLong(-1);
317 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000318}
319
Georg Brandlfceab5a2008-01-19 20:08:23 +0000320static PyObject *
321mmap_find_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000322 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000323{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000324 return mmap_gfind(self, args, 0);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000325}
326
327static PyObject *
328mmap_rfind_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000329 PyObject *args)
Georg Brandlfceab5a2008-01-19 20:08:23 +0000330{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000331 return mmap_gfind(self, args, 1);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000332}
333
Tim Petersec0a5f02006-02-16 23:47:20 +0000334static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000335is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000336{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000337 if (self->access != ACCESS_READ)
338 return 1;
339 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
340 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000341}
342
Tim Petersec0a5f02006-02-16 23:47:20 +0000343static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000344is_resizeable(mmap_object *self)
345{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000346 if (self->exports > 0) {
347 PyErr_SetString(PyExc_BufferError,
348 "mmap can't resize with extant buffers exported.");
349 return 0;
350 }
351 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
352 return 1;
353 PyErr_Format(PyExc_TypeError,
354 "mmap can't resize a readonly or copy-on-write memory map.");
355 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000356}
357
358
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000359static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000360mmap_write_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000361 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000362{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000363 Py_ssize_t length;
364 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000365
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000366 CHECK_VALID(NULL);
367 if (!PyArg_ParseTuple(args, "y#:write", &data, &length))
368 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000369
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000370 if (!is_writable(self))
371 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000372
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000373 if ((self->pos + length) > self->size) {
374 PyErr_SetString(PyExc_ValueError, "data out of range");
375 return NULL;
376 }
377 memcpy(self->data+self->pos, data, length);
378 self->pos = self->pos+length;
379 Py_INCREF(Py_None);
380 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000381}
382
383static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000384mmap_write_byte_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000385 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000386{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000387 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000388
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000389 CHECK_VALID(NULL);
390 if (!PyArg_ParseTuple(args, "b:write_byte", &value))
391 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000392
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000393 if (!is_writable(self))
394 return NULL;
Hirokazu Yamamoto39c6dea2009-02-28 10:56:50 +0000395
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000396 if (self->pos < self->size) {
397 *(self->data+self->pos) = value;
398 self->pos += 1;
399 Py_INCREF(Py_None);
400 return Py_None;
401 }
402 else {
403 PyErr_SetString(PyExc_ValueError, "write byte out of range");
404 return NULL;
405 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000406}
Tim Petersec0a5f02006-02-16 23:47:20 +0000407
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000408static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000409mmap_size_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000410 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000411{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000412 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000413
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000414#ifdef MS_WINDOWS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000415 if (self->file_handle != INVALID_HANDLE_VALUE) {
416 DWORD low,high;
417 PY_LONG_LONG size;
418 low = GetFileSize(self->file_handle, &high);
419 if (low == INVALID_FILE_SIZE) {
420 /* It might be that the function appears to have failed,
421 when indeed its size equals INVALID_FILE_SIZE */
422 DWORD error = GetLastError();
423 if (error != NO_ERROR)
424 return PyErr_SetFromWindowsErr(error);
425 }
426 if (!high && low < LONG_MAX)
427 return PyLong_FromLong((long)low);
428 size = (((PY_LONG_LONG)high)<<32) + low;
429 return PyLong_FromLongLong(size);
430 } else {
431 return PyLong_FromSsize_t(self->size);
432 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000433#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000434
435#ifdef UNIX
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000436 {
437 struct stat buf;
438 if (-1 == fstat(self->fd, &buf)) {
439 PyErr_SetFromErrno(mmap_module_error);
440 return NULL;
441 }
Antoine Pitrou9e719b62011-02-28 23:48:16 +0000442#ifdef HAVE_LARGEFILE_SUPPORT
443 return PyLong_FromLongLong(buf.st_size);
444#else
445 return PyLong_FromLong(buf.st_size);
446#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000447 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000448#endif /* UNIX */
449}
450
451/* This assumes that you want the entire file mapped,
452 / and when recreating the map will make the new file
453 / have the new size
454 /
455 / Is this really necessary? This could easily be done
456 / from python by just closing and re-opening with the
457 / new size?
458 */
459
460static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000461mmap_resize_method(mmap_object *self,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000462 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000463{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000464 Py_ssize_t new_size;
465 CHECK_VALID(NULL);
466 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
467 !is_resizeable(self)) {
468 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000469#ifdef MS_WINDOWS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000470 } else {
471 DWORD dwErrCode = 0;
472 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
473 /* First, unmap the file view */
474 UnmapViewOfFile(self->data);
475 self->data = NULL;
476 /* Close the mapping object */
477 CloseHandle(self->map_handle);
478 self->map_handle = NULL;
479 /* Move to the desired EOF position */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000480 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
481 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
482 off_hi = (DWORD)(self->offset >> 32);
483 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000484 SetFilePointer(self->file_handle,
485 newSizeLow, &newSizeHigh, FILE_BEGIN);
486 /* Change the size of the file */
487 SetEndOfFile(self->file_handle);
488 /* Create another mapping object and remap the file view */
489 self->map_handle = CreateFileMapping(
490 self->file_handle,
491 NULL,
492 PAGE_READWRITE,
493 0,
494 0,
495 self->tagname);
496 if (self->map_handle != NULL) {
497 self->data = (char *) MapViewOfFile(self->map_handle,
498 FILE_MAP_WRITE,
499 off_hi,
500 off_lo,
501 new_size);
502 if (self->data != NULL) {
503 self->size = new_size;
504 Py_INCREF(Py_None);
505 return Py_None;
506 } else {
507 dwErrCode = GetLastError();
508 CloseHandle(self->map_handle);
509 self->map_handle = NULL;
510 }
511 } else {
512 dwErrCode = GetLastError();
513 }
514 PyErr_SetFromWindowsErr(dwErrCode);
515 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000516#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000517
518#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000519#ifndef HAVE_MREMAP
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000520 } else {
521 PyErr_SetString(PyExc_SystemError,
522 "mmap: resizing not available--no mremap()");
523 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000524#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000525 } else {
526 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000527
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000528 if (ftruncate(self->fd, self->offset + new_size) == -1) {
529 PyErr_SetFromErrno(mmap_module_error);
530 return NULL;
531 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000532
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000533#ifdef MREMAP_MAYMOVE
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000534 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000535#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000536 #if defined(__NetBSD__)
537 newmap = mremap(self->data, self->size, self->data, new_size, 0);
538 #else
539 newmap = mremap(self->data, self->size, new_size, 0);
540 #endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000541#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000542 if (newmap == (void *)-1)
543 {
544 PyErr_SetFromErrno(mmap_module_error);
545 return NULL;
546 }
547 self->data = newmap;
548 self->size = new_size;
549 Py_INCREF(Py_None);
550 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000551#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000552#endif /* UNIX */
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000553 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000554}
555
556static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000557mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000558{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000559 CHECK_VALID(NULL);
560 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000561}
562
563static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000564mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000565{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000566 Py_ssize_t offset = 0;
567 Py_ssize_t size = self->size;
568 CHECK_VALID(NULL);
569 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
570 return NULL;
571 if ((size_t)(offset + size) > self->size) {
572 PyErr_SetString(PyExc_ValueError, "flush values out of range");
573 return NULL;
574 }
R. David Murray07c1bd72010-12-11 02:05:32 +0000575
576 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
577 return PyLong_FromLong(0);
578
Christian Heimesaf98da12008-01-27 15:18:18 +0000579#ifdef MS_WINDOWS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000580 return PyLong_FromLong((long) FlushViewOfFile(self->data+offset, size));
Christian Heimesaf98da12008-01-27 15:18:18 +0000581#elif defined(UNIX)
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000582 /* XXX semantics of return value? */
583 /* XXX flags for msync? */
584 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
585 PyErr_SetFromErrno(mmap_module_error);
586 return NULL;
587 }
588 return PyLong_FromLong(0);
Christian Heimesaf98da12008-01-27 15:18:18 +0000589#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000590 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
591 return NULL;
Christian Heimesaf98da12008-01-27 15:18:18 +0000592#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000593}
594
595static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000596mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000597{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000598 Py_ssize_t dist;
599 int how=0;
600 CHECK_VALID(NULL);
601 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
602 return NULL;
603 else {
604 size_t where;
605 switch (how) {
606 case 0: /* relative to start */
607 if (dist < 0)
608 goto onoutofrange;
609 where = dist;
610 break;
611 case 1: /* relative to current position */
612 if ((Py_ssize_t)self->pos + dist < 0)
613 goto onoutofrange;
614 where = self->pos + dist;
615 break;
616 case 2: /* relative to end */
617 if ((Py_ssize_t)self->size + dist < 0)
618 goto onoutofrange;
619 where = self->size + dist;
620 break;
621 default:
622 PyErr_SetString(PyExc_ValueError, "unknown seek type");
623 return NULL;
624 }
625 if (where > self->size)
626 goto onoutofrange;
627 self->pos = where;
628 Py_INCREF(Py_None);
629 return Py_None;
630 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000631
Tim Peters5ebfd362001-11-13 23:11:19 +0000632 onoutofrange:
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000633 PyErr_SetString(PyExc_ValueError, "seek out of range");
634 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000635}
636
637static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000638mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000639{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000640 unsigned long dest, src, cnt;
641 CHECK_VALID(NULL);
642 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
643 !is_writable(self)) {
644 return NULL;
645 } else {
646 /* bounds check the values */
647 if (cnt < 0 || (cnt + dest) < cnt || (cnt + src) < cnt ||
648 src < 0 || src > self->size || (src + cnt) > self->size ||
649 dest < 0 || dest > self->size || (dest + cnt) > self->size) {
650 PyErr_SetString(PyExc_ValueError,
651 "source, destination, or count out of range");
652 return NULL;
653 }
654 memmove(self->data+dest, self->data+src, cnt);
655 Py_INCREF(Py_None);
656 return Py_None;
657 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000658}
659
660static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000661 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
662 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
663 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
664 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
665 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
666 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
667 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
668 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
669 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
670 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
671 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
672 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
673 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
674 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
675 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000676};
677
678/* Functions for treating an mmap'ed file as a buffer */
679
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000680static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000681mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000682{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000683 CHECK_VALID(-1);
684 if (PyBuffer_FillInfo(view, (PyObject*)self, self->data, self->size,
685 (self->access == ACCESS_READ), flags) < 0)
686 return -1;
687 self->exports++;
688 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000689}
690
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000691static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000692mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000693{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000694 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000695}
696
Martin v. Löwis18e16552006-02-15 17:27:45 +0000697static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000698mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000699{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000700 CHECK_VALID(-1);
701 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000702}
703
704static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000705mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000706{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000707 CHECK_VALID(NULL);
708 if (i < 0 || (size_t)i >= self->size) {
709 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
710 return NULL;
711 }
712 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000713}
714
715static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000716mmap_subscript(mmap_object *self, PyObject *item)
717{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000718 CHECK_VALID(NULL);
719 if (PyIndex_Check(item)) {
720 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
721 if (i == -1 && PyErr_Occurred())
722 return NULL;
723 if (i < 0)
724 i += self->size;
725 if (i < 0 || (size_t)i >= self->size) {
726 PyErr_SetString(PyExc_IndexError,
727 "mmap index out of range");
728 return NULL;
729 }
730 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
731 }
732 else if (PySlice_Check(item)) {
733 Py_ssize_t start, stop, step, slicelen;
Thomas Woutersed03b412007-08-28 21:37:11 +0000734
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000735 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
736 &start, &stop, &step, &slicelen) < 0) {
737 return NULL;
738 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000739
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000740 if (slicelen <= 0)
741 return PyBytes_FromStringAndSize("", 0);
742 else if (step == 1)
743 return PyBytes_FromStringAndSize(self->data + start,
744 slicelen);
745 else {
746 char *result_buf = (char *)PyMem_Malloc(slicelen);
747 Py_ssize_t cur, i;
748 PyObject *result;
Thomas Woutersed03b412007-08-28 21:37:11 +0000749
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000750 if (result_buf == NULL)
751 return PyErr_NoMemory();
752 for (cur = start, i = 0; i < slicelen;
753 cur += step, i++) {
754 result_buf[i] = self->data[cur];
755 }
756 result = PyBytes_FromStringAndSize(result_buf,
757 slicelen);
758 PyMem_Free(result_buf);
759 return result;
760 }
761 }
762 else {
763 PyErr_SetString(PyExc_TypeError,
764 "mmap indices must be integers");
765 return NULL;
766 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000767}
768
769static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000770mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000771{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000772 CHECK_VALID(NULL);
773 PyErr_SetString(PyExc_SystemError,
774 "mmaps don't support concatenation");
775 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000776}
777
778static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000779mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000780{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000781 CHECK_VALID(NULL);
782 PyErr_SetString(PyExc_SystemError,
783 "mmaps don't support repeat operation");
784 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000785}
786
787static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000788mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000789{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000790 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000791
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000792 CHECK_VALID(-1);
793 if (i < 0 || (size_t)i >= self->size) {
794 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
795 return -1;
796 }
797 if (v == NULL) {
798 PyErr_SetString(PyExc_TypeError,
799 "mmap object doesn't support item deletion");
800 return -1;
801 }
802 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
803 PyErr_SetString(PyExc_IndexError,
804 "mmap assignment must be length-1 bytes()");
805 return -1;
806 }
807 if (!is_writable(self))
808 return -1;
809 buf = PyBytes_AsString(v);
810 self->data[i] = buf[0];
811 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000812}
813
Thomas Woutersed03b412007-08-28 21:37:11 +0000814static int
815mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
816{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000817 CHECK_VALID(-1);
Thomas Woutersed03b412007-08-28 21:37:11 +0000818
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000819 if (!is_writable(self))
820 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000821
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000822 if (PyIndex_Check(item)) {
823 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
824 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000825
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000826 if (i == -1 && PyErr_Occurred())
827 return -1;
828 if (i < 0)
829 i += self->size;
830 if (i < 0 || (size_t)i >= self->size) {
831 PyErr_SetString(PyExc_IndexError,
832 "mmap index out of range");
833 return -1;
834 }
835 if (value == NULL) {
836 PyErr_SetString(PyExc_TypeError,
837 "mmap doesn't support item deletion");
838 return -1;
839 }
840 if (!PyIndex_Check(value)) {
841 PyErr_SetString(PyExc_TypeError,
842 "mmap item value must be an int");
843 return -1;
844 }
845 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
846 if (v == -1 && PyErr_Occurred())
847 return -1;
848 if (v < 0 || v > 255) {
849 PyErr_SetString(PyExc_ValueError,
850 "mmap item value must be "
851 "in range(0, 256)");
852 return -1;
853 }
Antoine Pitrou835b4452010-08-15 18:32:16 +0000854 self->data[i] = (char) v;
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000855 return 0;
856 }
857 else if (PySlice_Check(item)) {
858 Py_ssize_t start, stop, step, slicelen;
859 Py_buffer vbuf;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000860
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000861 if (PySlice_GetIndicesEx((PySliceObject *)item,
862 self->size, &start, &stop,
863 &step, &slicelen) < 0) {
864 return -1;
865 }
866 if (value == NULL) {
867 PyErr_SetString(PyExc_TypeError,
868 "mmap object doesn't support slice deletion");
869 return -1;
870 }
871 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
872 return -1;
873 if (vbuf.len != slicelen) {
874 PyErr_SetString(PyExc_IndexError,
875 "mmap slice assignment is wrong size");
876 PyBuffer_Release(&vbuf);
877 return -1;
878 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000879
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000880 if (slicelen == 0) {
881 }
882 else if (step == 1) {
883 memcpy(self->data + start, vbuf.buf, slicelen);
884 }
885 else {
886 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000887
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000888 for (cur = start, i = 0;
889 i < slicelen;
890 cur += step, i++)
891 {
892 self->data[cur] = ((char *)vbuf.buf)[i];
893 }
894 }
895 PyBuffer_Release(&vbuf);
896 return 0;
897 }
898 else {
899 PyErr_SetString(PyExc_TypeError,
900 "mmap indices must be integer");
901 return -1;
902 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000903}
904
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000905static PySequenceMethods mmap_as_sequence = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000906 (lenfunc)mmap_length, /*sq_length*/
907 (binaryfunc)mmap_concat, /*sq_concat*/
908 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
909 (ssizeargfunc)mmap_item, /*sq_item*/
910 0, /*sq_slice*/
911 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
912 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000913};
914
Thomas Woutersed03b412007-08-28 21:37:11 +0000915static PyMappingMethods mmap_as_mapping = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000916 (lenfunc)mmap_length,
917 (binaryfunc)mmap_subscript,
918 (objobjargproc)mmap_ass_subscript,
Thomas Woutersed03b412007-08-28 21:37:11 +0000919};
920
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000921static PyBufferProcs mmap_as_buffer = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000922 (getbufferproc)mmap_buffer_getbuf,
923 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000924};
925
Georg Brandl86def6c2008-01-21 20:36:10 +0000926static PyObject *
927new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
928
Christian Heimese1c98112008-01-21 11:20:28 +0000929PyDoc_STRVAR(mmap_doc,
930"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
931\n\
932Maps length bytes from the file specified by the file handle fileno,\n\
933and returns a mmap object. If length is larger than the current size\n\
934of the file, the file is extended to contain length bytes. If length\n\
935is 0, the maximum length of the map is the current size of the file,\n\
936except that if the file is empty Windows raises an exception (you cannot\n\
937create an empty mapping on Windows).\n\
938\n\
939Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
940\n\
941Maps length bytes from the file specified by the file descriptor fileno,\n\
942and returns a mmap object. If length is 0, the maximum length of the map\n\
943will be the current size of the file when mmap is called.\n\
944flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
945private copy-on-write mapping, so changes to the contents of the mmap\n\
Benjamin Petersonc4fe6f32008-08-19 18:57:56 +0000946object will be private to this process, and MAP_SHARED creates a mapping\n\
Christian Heimese1c98112008-01-21 11:20:28 +0000947that's shared with all other processes mapping the same areas of the file.\n\
948The default value is MAP_SHARED.\n\
949\n\
950To map anonymous memory, pass -1 as the fileno (both versions).");
951
952
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000953static PyTypeObject mmap_object_type = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +0000954 PyVarObject_HEAD_INIT(NULL, 0)
955 "mmap.mmap", /* tp_name */
956 sizeof(mmap_object), /* tp_size */
957 0, /* tp_itemsize */
958 /* methods */
959 (destructor) mmap_object_dealloc, /* tp_dealloc */
960 0, /* tp_print */
961 0, /* tp_getattr */
962 0, /* tp_setattr */
963 0, /* tp_reserved */
964 0, /* tp_repr */
965 0, /* tp_as_number */
966 &mmap_as_sequence, /*tp_as_sequence*/
967 &mmap_as_mapping, /*tp_as_mapping*/
968 0, /*tp_hash*/
969 0, /*tp_call*/
970 0, /*tp_str*/
971 PyObject_GenericGetAttr, /*tp_getattro*/
972 0, /*tp_setattro*/
973 &mmap_as_buffer, /*tp_as_buffer*/
974 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
975 mmap_doc, /*tp_doc*/
976 0, /* tp_traverse */
977 0, /* tp_clear */
978 0, /* tp_richcompare */
979 0, /* tp_weaklistoffset */
980 0, /* tp_iter */
981 0, /* tp_iternext */
982 mmap_object_methods, /* tp_methods */
983 0, /* tp_members */
984 0, /* tp_getset */
985 0, /* tp_base */
986 0, /* tp_dict */
987 0, /* tp_descr_get */
988 0, /* tp_descr_set */
989 0, /* tp_dictoffset */
990 0, /* tp_init */
991 PyType_GenericAlloc, /* tp_alloc */
992 new_mmap_object, /* tp_new */
993 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000994};
995
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000996
997/* extract the map size from the given PyObject
998
Thomas Wouters7e474022000-07-16 12:04:32 +0000999 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001000 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001001static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001002_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001003{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001004 if (o == NULL)
1005 return 0;
1006 if (PyIndex_Check(o)) {
1007 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1008 if (i==-1 && PyErr_Occurred())
1009 return -1;
1010 if (i < 0) {
1011 PyErr_Format(PyExc_OverflowError,
1012 "memory mapped %s must be positive",
1013 param);
1014 return -1;
1015 }
1016 return i;
1017 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001018
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001019 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1020 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001021}
1022
Tim Petersec0a5f02006-02-16 23:47:20 +00001023#ifdef UNIX
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001024#ifdef HAVE_LARGEFILE_SUPPORT
1025#define _Py_PARSE_OFF_T "L"
1026#else
1027#define _Py_PARSE_OFF_T "l"
1028#endif
1029
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001030static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001031new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001032{
Neal Norwitzb5673922002-09-05 21:48:07 +00001033#ifdef HAVE_FSTAT
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001034 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001035#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001036 mmap_object *m_obj;
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001037 PyObject *map_size_obj = NULL;
1038 Py_ssize_t map_size;
1039 off_t offset = 0;
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001040 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1041 int devzero = -1;
1042 int access = (int)ACCESS_DEFAULT;
1043 static char *keywords[] = {"fileno", "length",
1044 "flags", "prot",
1045 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001046
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001047 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001048 &fd, &map_size_obj, &flags, &prot,
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001049 &access, &offset))
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001050 return NULL;
1051 map_size = _GetMapSize(map_size_obj, "size");
1052 if (map_size < 0)
1053 return NULL;
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001054 if (offset < 0) {
1055 PyErr_SetString(PyExc_OverflowError,
1056 "memory mapped offset must be positive");
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001057 return NULL;
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001058 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001059
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001060 if ((access != (int)ACCESS_DEFAULT) &&
1061 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1062 return PyErr_Format(PyExc_ValueError,
1063 "mmap can't specify both access and flags, prot.");
1064 switch ((access_mode)access) {
1065 case ACCESS_READ:
1066 flags = MAP_SHARED;
1067 prot = PROT_READ;
1068 break;
1069 case ACCESS_WRITE:
1070 flags = MAP_SHARED;
1071 prot = PROT_READ | PROT_WRITE;
1072 break;
1073 case ACCESS_COPY:
1074 flags = MAP_PRIVATE;
1075 prot = PROT_READ | PROT_WRITE;
1076 break;
1077 case ACCESS_DEFAULT:
Antoine Pitrou16a0a0b2011-03-06 01:11:03 +01001078 /* map prot to access type */
1079 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1080 /* ACCESS_DEFAULT */
1081 }
1082 else if (prot & PROT_WRITE) {
1083 access = ACCESS_WRITE;
1084 }
1085 else {
1086 access = ACCESS_READ;
1087 }
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001088 break;
1089 default:
1090 return PyErr_Format(PyExc_ValueError,
1091 "mmap invalid access parameter.");
1092 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001093
1094#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001095# ifdef __VMS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001096 /* on OpenVMS we must ensure that all bytes are written to the file */
1097 if (fd != -1) {
1098 fsync(fd);
1099 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001100# endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001101 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1102 if (map_size == 0) {
Antoine Pitrou6107a4e2011-01-20 21:11:13 +00001103 if (offset >= st.st_size) {
1104 PyErr_SetString(PyExc_ValueError,
1105 "mmap offset is greater than file size");
1106 return NULL;
1107 }
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001108 off_t calc_size = st.st_size - offset;
1109 map_size = calc_size;
1110 if (map_size != calc_size) {
1111 PyErr_SetString(PyExc_ValueError,
1112 "mmap length is too large");
1113 return NULL;
1114 }
1115 } else if (offset + (size_t)map_size > st.st_size) {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001116 PyErr_SetString(PyExc_ValueError,
1117 "mmap length is greater than file size");
1118 return NULL;
1119 }
1120 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001121#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001122 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1123 if (m_obj == NULL) {return NULL;}
1124 m_obj->data = NULL;
1125 m_obj->size = (size_t) map_size;
1126 m_obj->pos = (size_t) 0;
1127 m_obj->exports = 0;
1128 m_obj->offset = offset;
1129 if (fd == -1) {
1130 m_obj->fd = -1;
1131 /* Assume the caller wants to map anonymous memory.
1132 This is the same behaviour as Windows. mmap.mmap(-1, size)
1133 on both Windows and Unix map anonymous memory.
1134 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001135#ifdef MAP_ANONYMOUS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001136 /* BSD way to map anonymous memory */
1137 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001138#else
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001139 /* SVR4 method to map anonymous memory is to open /dev/zero */
1140 fd = devzero = open("/dev/zero", O_RDWR);
1141 if (devzero == -1) {
1142 Py_DECREF(m_obj);
1143 PyErr_SetFromErrno(mmap_module_error);
1144 return NULL;
1145 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001146#endif
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001147 } else {
1148 m_obj->fd = dup(fd);
1149 if (m_obj->fd == -1) {
1150 Py_DECREF(m_obj);
1151 PyErr_SetFromErrno(mmap_module_error);
1152 return NULL;
1153 }
1154 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001155
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001156 m_obj->data = mmap(NULL, map_size,
1157 prot, flags,
1158 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001159
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001160 if (devzero != -1) {
1161 close(devzero);
1162 }
1163
1164 if (m_obj->data == (char *)-1) {
1165 m_obj->data = NULL;
1166 Py_DECREF(m_obj);
1167 PyErr_SetFromErrno(mmap_module_error);
1168 return NULL;
1169 }
1170 m_obj->access = (access_mode)access;
1171 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001172}
1173#endif /* UNIX */
1174
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001175#ifdef MS_WINDOWS
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001176
1177/* A note on sizes and offsets: while the actual map size must hold in a
1178 Py_ssize_t, both the total file size and the start offset can be longer
1179 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1180*/
1181
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001182static PyObject *
Georg Brandl86def6c2008-01-21 20:36:10 +00001183new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001184{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001185 mmap_object *m_obj;
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001186 PyObject *map_size_obj = NULL;
1187 Py_ssize_t map_size;
1188 PY_LONG_LONG offset = 0, size;
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001189 DWORD off_hi; /* upper 32 bits of offset */
1190 DWORD off_lo; /* lower 32 bits of offset */
1191 DWORD size_hi; /* upper 32 bits of size */
1192 DWORD size_lo; /* lower 32 bits of size */
1193 char *tagname = "";
1194 DWORD dwErr = 0;
1195 int fileno;
1196 HANDLE fh = 0;
1197 int access = (access_mode)ACCESS_DEFAULT;
1198 DWORD flProtect, dwDesiredAccess;
1199 static char *keywords[] = { "fileno", "length",
1200 "tagname",
1201 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001202
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001203 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords,
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001204 &fileno, &map_size_obj,
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001205 &tagname, &access, &offset)) {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001206 return NULL;
1207 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001208
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001209 switch((access_mode)access) {
1210 case ACCESS_READ:
1211 flProtect = PAGE_READONLY;
1212 dwDesiredAccess = FILE_MAP_READ;
1213 break;
1214 case ACCESS_DEFAULT: case ACCESS_WRITE:
1215 flProtect = PAGE_READWRITE;
1216 dwDesiredAccess = FILE_MAP_WRITE;
1217 break;
1218 case ACCESS_COPY:
1219 flProtect = PAGE_WRITECOPY;
1220 dwDesiredAccess = FILE_MAP_COPY;
1221 break;
1222 default:
1223 return PyErr_Format(PyExc_ValueError,
1224 "mmap invalid access parameter.");
1225 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001226
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001227 map_size = _GetMapSize(map_size_obj, "size");
1228 if (map_size < 0)
1229 return NULL;
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001230 if (offset < 0) {
1231 PyErr_SetString(PyExc_OverflowError,
1232 "memory mapped offset must be positive");
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001233 return NULL;
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001234 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001235
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001236 /* assume -1 and 0 both mean invalid filedescriptor
1237 to 'anonymously' map memory.
1238 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1239 XXX: Should this code be added?
1240 if (fileno == 0)
1241 PyErr_WarnEx(PyExc_DeprecationWarning,
1242 "don't use 0 for anonymous memory",
1243 1);
1244 */
1245 if (fileno != -1 && fileno != 0) {
Brian Curtin686ee4f2010-08-01 15:44:11 +00001246 /* Ensure that fileno is within the CRT's valid range */
1247 if (_PyVerify_fd(fileno) == 0) {
1248 PyErr_SetFromErrno(mmap_module_error);
1249 return NULL;
1250 }
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001251 fh = (HANDLE)_get_osfhandle(fileno);
1252 if (fh==(HANDLE)-1) {
1253 PyErr_SetFromErrno(mmap_module_error);
1254 return NULL;
1255 }
1256 /* Win9x appears to need us seeked to zero */
1257 lseek(fileno, 0, SEEK_SET);
1258 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001259
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001260 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1261 if (m_obj == NULL)
1262 return NULL;
1263 /* Set every field to an invalid marker, so we can safely
1264 destruct the object in the face of failure */
1265 m_obj->data = NULL;
1266 m_obj->file_handle = INVALID_HANDLE_VALUE;
1267 m_obj->map_handle = NULL;
1268 m_obj->tagname = NULL;
1269 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001270
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001271 if (fh) {
1272 /* It is necessary to duplicate the handle, so the
1273 Python code can close it on us */
1274 if (!DuplicateHandle(
1275 GetCurrentProcess(), /* source process handle */
1276 fh, /* handle to be duplicated */
1277 GetCurrentProcess(), /* target proc handle */
1278 (LPHANDLE)&m_obj->file_handle, /* result */
1279 0, /* access - ignored due to options value */
1280 FALSE, /* inherited by child processes? */
1281 DUPLICATE_SAME_ACCESS)) { /* options */
1282 dwErr = GetLastError();
1283 Py_DECREF(m_obj);
1284 PyErr_SetFromWindowsErr(dwErr);
1285 return NULL;
1286 }
1287 if (!map_size) {
1288 DWORD low,high;
1289 low = GetFileSize(fh, &high);
1290 /* low might just happen to have the value INVALID_FILE_SIZE;
1291 so we need to check the last error also. */
1292 if (low == INVALID_FILE_SIZE &&
1293 (dwErr = GetLastError()) != NO_ERROR) {
1294 Py_DECREF(m_obj);
1295 return PyErr_SetFromWindowsErr(dwErr);
1296 }
Guido van Rossum98297ee2007-11-06 21:34:58 +00001297
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001298 size = (((PY_LONG_LONG) high) << 32) + low;
1299 if (offset >= size) {
Antoine Pitrou6107a4e2011-01-20 21:11:13 +00001300 PyErr_SetString(PyExc_ValueError,
1301 "mmap offset is greater than file size");
1302 Py_DECREF(m_obj);
1303 return NULL;
1304 }
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001305 if (offset - size > PY_SSIZE_T_MAX)
1306 /* Map area too large to fit in memory */
1307 m_obj->size = (Py_ssize_t) -1;
1308 else
1309 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001310 } else {
1311 m_obj->size = map_size;
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001312 size = offset + map_size;
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001313 }
1314 }
1315 else {
1316 m_obj->size = map_size;
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001317 size = offset + map_size;
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001318 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001319
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001320 /* set the initial position */
1321 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001322
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001323 m_obj->exports = 0;
1324 /* set the tag name */
1325 if (tagname != NULL && *tagname != '\0') {
1326 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1327 if (m_obj->tagname == NULL) {
1328 PyErr_NoMemory();
1329 Py_DECREF(m_obj);
1330 return NULL;
1331 }
1332 strcpy(m_obj->tagname, tagname);
1333 }
1334 else
1335 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001336
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001337 m_obj->access = (access_mode)access;
Antoine Pitrou9e719b62011-02-28 23:48:16 +00001338 size_hi = (DWORD)(size >> 32);
1339 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001340 off_hi = (DWORD)(offset >> 32);
1341 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001342 /* For files, it would be sufficient to pass 0 as size.
1343 For anonymous maps, we have to pass the size explicitly. */
1344 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1345 NULL,
1346 flProtect,
1347 size_hi,
1348 size_lo,
1349 m_obj->tagname);
1350 if (m_obj->map_handle != NULL) {
1351 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1352 dwDesiredAccess,
1353 off_hi,
1354 off_lo,
1355 m_obj->size);
1356 if (m_obj->data != NULL)
1357 return (PyObject *)m_obj;
1358 else {
1359 dwErr = GetLastError();
1360 CloseHandle(m_obj->map_handle);
1361 m_obj->map_handle = NULL;
1362 }
1363 } else
1364 dwErr = GetLastError();
1365 Py_DECREF(m_obj);
1366 PyErr_SetFromWindowsErr(dwErr);
1367 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001368}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001369#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001370
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001371static void
1372setint(PyObject *d, const char *name, long value)
1373{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001374 PyObject *o = PyLong_FromLong(value);
1375 if (o && PyDict_SetItemString(d, name, o) == 0) {
1376 Py_DECREF(o);
1377 }
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001378}
1379
Martin v. Löwis1a214512008-06-11 05:26:20 +00001380
1381static struct PyModuleDef mmapmodule = {
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001382 PyModuleDef_HEAD_INIT,
1383 "mmap",
1384 NULL,
1385 -1,
1386 NULL,
1387 NULL,
1388 NULL,
1389 NULL,
1390 NULL
Martin v. Löwis1a214512008-06-11 05:26:20 +00001391};
1392
Mark Hammond62b1ab12002-07-23 06:31:15 +00001393PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +00001394PyInit_mmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001395{
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001396 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001397
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001398 if (PyType_Ready(&mmap_object_type) < 0)
1399 return NULL;
Tim Peters2caf8df2001-01-14 05:05:51 +00001400
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001401 module = PyModule_Create(&mmapmodule);
1402 if (module == NULL)
1403 return NULL;
1404 dict = PyModule_GetDict(module);
1405 if (!dict)
1406 return NULL;
1407 mmap_module_error = PyErr_NewException("mmap.error",
1408 PyExc_EnvironmentError , NULL);
1409 if (mmap_module_error == NULL)
1410 return NULL;
1411 PyDict_SetItemString(dict, "error", mmap_module_error);
1412 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001413#ifdef PROT_EXEC
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001414 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001415#endif
1416#ifdef PROT_READ
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001417 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001418#endif
1419#ifdef PROT_WRITE
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001420 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001421#endif
1422
1423#ifdef MAP_SHARED
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001424 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001425#endif
1426#ifdef MAP_PRIVATE
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001427 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001428#endif
1429#ifdef MAP_DENYWRITE
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001430 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001431#endif
1432#ifdef MAP_EXECUTABLE
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001433 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001434#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001435#ifdef MAP_ANONYMOUS
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001436 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1437 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001438#endif
1439
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001440 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001441
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001442 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001443
Antoine Pitrou7f14f0d2010-05-09 16:14:21 +00001444 setint(dict, "ACCESS_READ", ACCESS_READ);
1445 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1446 setint(dict, "ACCESS_COPY", ACCESS_COPY);
1447 return module;
Tim Peters5ebfd362001-11-13 23:11:19 +00001448}