blob: e93acda19f4b2e8c880ee7783aba2000e0614b30 [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
Travis E. Oliphant8feafab2007-10-23 02:40:56 +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 Pitrouc83ea132010-05-09 14:46:46 +000033 SYSTEM_INFO si;
34 GetSystemInfo(&si);
35 return si.dwPageSize;
Fred Drake145f96e2000-10-01 17:50:46 +000036}
Travis E. Oliphant8feafab2007-10-23 02:40:56 +000037
38static int
39my_getallocationgranularity (void)
40{
41
Antoine Pitrouc83ea132010-05-09 14:46:46 +000042 SYSTEM_INFO si;
43 GetSystemInfo(&si);
44 return si.dwAllocationGranularity;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +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 Pitrouc83ea132010-05-09 14:46:46 +000057 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000058}
Travis E. Oliphant8feafab2007-10-23 02:40:56 +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>
Martin v. Löwis0e8bd7e2006-06-10 12:23:46 +000068
69#ifdef HAVE_SYS_TYPES_H
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000070#include <sys/types.h>
Martin v. Löwis0e8bd7e2006-06-10 12:23:46 +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 Pitrouc83ea132010-05-09 14:46:46 +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 Pitrouc83ea132010-05-09 14:46:46 +000089 PyObject_HEAD
90 char * data;
91 size_t size;
92 size_t pos; /* relative to offset */
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +000093#ifdef MS_WINDOWS
94 PY_LONG_LONG offset;
95#else
96 off_t offset;
97#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000098
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000099#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000100 HANDLE map_handle;
101 HANDLE file_handle;
102 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000103#endif
104
105#ifdef UNIX
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000106 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000107#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000108
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000109 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000110} mmap_object;
111
Tim Peters5ebfd362001-11-13 23:11:19 +0000112
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000113static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000114mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000115{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000116#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000117 if (m_obj->data != NULL)
118 UnmapViewOfFile (m_obj->data);
119 if (m_obj->map_handle != NULL)
120 CloseHandle (m_obj->map_handle);
121 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
122 CloseHandle (m_obj->file_handle);
123 if (m_obj->tagname)
124 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000125#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000126
127#ifdef UNIX
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000128 if (m_obj->fd >= 0)
129 (void) close(m_obj->fd);
130 if (m_obj->data!=NULL) {
R. David Murray2a4b3fc2010-12-11 02:13:04 +0000131 if (m_obj->access != ACCESS_READ && m_obj->access != ACCESS_COPY)
132 msync(m_obj->data, m_obj->size, MS_SYNC);
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000133 munmap(m_obj->data, m_obj->size);
134 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000135#endif /* UNIX */
136
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000137 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000138}
139
140static PyObject *
Georg Brandl96a8c392006-05-29 21:04:52 +0000141mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000142{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000143#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000144 /* For each resource we maintain, we need to check
145 the value is valid, and if so, free the resource
146 and set the member value to an invalid value so
147 the dealloc does not attempt to resource clearing
148 again.
149 TODO - should we check for errors in the close operations???
150 */
151 if (self->data != NULL) {
152 UnmapViewOfFile(self->data);
153 self->data = NULL;
154 }
155 if (self->map_handle != NULL) {
156 CloseHandle(self->map_handle);
157 self->map_handle = NULL;
158 }
159 if (self->file_handle != INVALID_HANDLE_VALUE) {
160 CloseHandle(self->file_handle);
161 self->file_handle = INVALID_HANDLE_VALUE;
162 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000163#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000164
165#ifdef UNIX
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000166 if (0 <= self->fd)
167 (void) close(self->fd);
168 self->fd = -1;
169 if (self->data != NULL) {
170 munmap(self->data, self->size);
171 self->data = NULL;
172 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000173#endif
174
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000175 Py_INCREF(Py_None);
176 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000177}
178
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000179#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000180#define CHECK_VALID(err) \
181do { \
182 if (self->map_handle == NULL) { \
183 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
184 return err; \
185 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000186} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000187#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000188
189#ifdef UNIX
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000190#define CHECK_VALID(err) \
191do { \
192 if (self->data == NULL) { \
193 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
194 return err; \
195 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000196} while (0)
197#endif /* UNIX */
198
199static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000200mmap_read_byte_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000201 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000202{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000203 CHECK_VALID(NULL);
204 if (self->pos < self->size) {
205 char value = self->data[self->pos];
206 self->pos += 1;
207 return Py_BuildValue("c", value);
208 } else {
209 PyErr_SetString(PyExc_ValueError, "read byte out of range");
210 return NULL;
211 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000212}
213
214static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000215mmap_read_line_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000216 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000217{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000218 char *start = self->data+self->pos;
219 char *eof = self->data+self->size;
220 char *eol;
221 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000222
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000223 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000224
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000225 eol = memchr(start, '\n', self->size - self->pos);
226 if (!eol)
227 eol = eof;
228 else
229 ++eol; /* we're interested in the position after the
230 newline. */
231 result = PyString_FromStringAndSize(start, (eol - start));
232 self->pos += (eol - start);
233 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000234}
235
236static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000237mmap_read_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000238 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000239{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000240 Py_ssize_t num_bytes, n;
241 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000242
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000243 CHECK_VALID(NULL);
244 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
245 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000246
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000247 /* silently 'adjust' out-of-range requests */
248 assert(self->size >= self->pos);
249 n = self->size - self->pos;
250 /* The difference can overflow, only if self->size is greater than
251 * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed,
252 * because the mapped area and the returned string each need more
253 * than half of the addressable memory. So we clip the size, and let
254 * the code below raise MemoryError.
255 */
256 if (n < 0)
257 n = PY_SSIZE_T_MAX;
258 if (num_bytes < 0 || num_bytes > n) {
259 num_bytes = n;
260 }
261 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
262 self->pos += num_bytes;
263 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000264}
265
266static PyObject *
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000267mmap_gfind(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000268 PyObject *args,
269 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000270{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000271 Py_ssize_t start = self->pos;
272 Py_ssize_t end = self->size;
273 const char *needle;
274 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000275
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000276 CHECK_VALID(NULL);
277 if (!PyArg_ParseTuple(args, reverse ? "s#|nn:rfind" : "s#|nn:find",
278 &needle, &len, &start, &end)) {
279 return NULL;
280 } else {
281 const char *p, *start_p, *end_p;
282 int sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000283
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000284 if (start < 0)
285 start += self->size;
286 if (start < 0)
287 start = 0;
288 else if ((size_t)start > self->size)
289 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000290
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000291 if (end < 0)
292 end += self->size;
293 if (end < 0)
294 end = 0;
295 else if ((size_t)end > self->size)
296 end = self->size;
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000297
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000298 start_p = self->data + start;
299 end_p = self->data + end;
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000300
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000301 for (p = (reverse ? end_p - len : start_p);
302 (p >= start_p) && (p + len <= end_p); p += sign) {
303 Py_ssize_t i;
304 for (i = 0; i < len && needle[i] == p[i]; ++i)
305 /* nothing */;
306 if (i == len) {
307 return PyInt_FromSsize_t(p - self->data);
308 }
309 }
310 return PyInt_FromLong(-1);
311 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000312}
313
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000314static PyObject *
315mmap_find_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000316 PyObject *args)
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000317{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000318 return mmap_gfind(self, args, 0);
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000319}
320
321static PyObject *
322mmap_rfind_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000323 PyObject *args)
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000324{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000325 return mmap_gfind(self, args, 1);
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000326}
327
Tim Petersec0a5f02006-02-16 23:47:20 +0000328static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000329is_writeable(mmap_object *self)
330{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000331 if (self->access != ACCESS_READ)
332 return 1;
333 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
334 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000335}
336
Tim Petersec0a5f02006-02-16 23:47:20 +0000337static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000338is_resizeable(mmap_object *self)
339{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000340 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
341 return 1;
342 PyErr_Format(PyExc_TypeError,
343 "mmap can't resize a readonly or copy-on-write memory map.");
344 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000345}
346
347
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000348static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000349mmap_write_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000350 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000351{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000352 Py_ssize_t length;
353 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000354
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000355 CHECK_VALID(NULL);
356 if (!PyArg_ParseTuple(args, "s#:write", &data, &length))
357 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000358
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000359 if (!is_writeable(self))
360 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000361
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000362 if ((self->pos + length) > self->size) {
363 PyErr_SetString(PyExc_ValueError, "data out of range");
364 return NULL;
365 }
366 memcpy(self->data+self->pos, data, length);
367 self->pos = self->pos+length;
368 Py_INCREF(Py_None);
369 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000370}
371
372static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000373mmap_write_byte_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000374 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000375{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000376 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000377
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000378 CHECK_VALID(NULL);
379 if (!PyArg_ParseTuple(args, "c:write_byte", &value))
380 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000381
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000382 if (!is_writeable(self))
383 return NULL;
Hirokazu Yamamotof2dc8852009-02-28 10:31:54 +0000384
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000385 if (self->pos < self->size) {
386 *(self->data+self->pos) = value;
387 self->pos += 1;
388 Py_INCREF(Py_None);
389 return Py_None;
390 }
391 else {
392 PyErr_SetString(PyExc_ValueError, "write byte out of range");
393 return NULL;
394 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000395}
Tim Petersec0a5f02006-02-16 23:47:20 +0000396
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000397static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000398mmap_size_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000399 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000400{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000401 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000402
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000403#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000404 if (self->file_handle != INVALID_HANDLE_VALUE) {
405 DWORD low,high;
406 PY_LONG_LONG size;
407 low = GetFileSize(self->file_handle, &high);
408 if (low == INVALID_FILE_SIZE) {
409 /* It might be that the function appears to have failed,
410 when indeed its size equals INVALID_FILE_SIZE */
411 DWORD error = GetLastError();
412 if (error != NO_ERROR)
413 return PyErr_SetFromWindowsErr(error);
414 }
415 if (!high && low < LONG_MAX)
416 return PyInt_FromLong((long)low);
417 size = (((PY_LONG_LONG)high)<<32) + low;
418 return PyLong_FromLongLong(size);
419 } else {
420 return PyInt_FromSsize_t(self->size);
421 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000422#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000423
424#ifdef UNIX
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000425 {
426 struct stat buf;
427 if (-1 == fstat(self->fd, &buf)) {
428 PyErr_SetFromErrno(mmap_module_error);
429 return NULL;
430 }
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +0000431#ifdef HAVE_LARGEFILE_SUPPORT
432 return PyLong_FromLongLong(buf.st_size);
433#else
434 return PyInt_FromLong(buf.st_size);
435#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000436 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000437#endif /* UNIX */
438}
439
440/* This assumes that you want the entire file mapped,
441 / and when recreating the map will make the new file
442 / have the new size
443 /
444 / Is this really necessary? This could easily be done
445 / from python by just closing and re-opening with the
446 / new size?
447 */
448
449static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000450mmap_resize_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000451 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000452{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000453 Py_ssize_t new_size;
454 CHECK_VALID(NULL);
455 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
456 !is_resizeable(self)) {
457 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000458#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000459 } else {
460 DWORD dwErrCode = 0;
461 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
462 /* First, unmap the file view */
463 UnmapViewOfFile(self->data);
464 self->data = NULL;
465 /* Close the mapping object */
466 CloseHandle(self->map_handle);
467 self->map_handle = NULL;
468 /* Move to the desired EOF position */
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000469 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
470 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
471 off_hi = (DWORD)(self->offset >> 32);
472 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000473 SetFilePointer(self->file_handle,
474 newSizeLow, &newSizeHigh, FILE_BEGIN);
475 /* Change the size of the file */
476 SetEndOfFile(self->file_handle);
477 /* Create another mapping object and remap the file view */
478 self->map_handle = CreateFileMapping(
479 self->file_handle,
480 NULL,
481 PAGE_READWRITE,
482 0,
483 0,
484 self->tagname);
485 if (self->map_handle != NULL) {
486 self->data = (char *) MapViewOfFile(self->map_handle,
487 FILE_MAP_WRITE,
488 off_hi,
489 off_lo,
490 new_size);
491 if (self->data != NULL) {
492 self->size = new_size;
493 Py_INCREF(Py_None);
494 return Py_None;
495 } else {
496 dwErrCode = GetLastError();
497 CloseHandle(self->map_handle);
498 self->map_handle = NULL;
499 }
500 } else {
501 dwErrCode = GetLastError();
502 }
503 PyErr_SetFromWindowsErr(dwErrCode);
504 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000505#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000506
507#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000508#ifndef HAVE_MREMAP
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000509 } else {
510 PyErr_SetString(PyExc_SystemError,
511 "mmap: resizing not available--no mremap()");
512 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000513#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000514 } else {
515 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000516
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000517 if (ftruncate(self->fd, self->offset + new_size) == -1) {
518 PyErr_SetFromErrno(mmap_module_error);
519 return NULL;
520 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000521
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000522#ifdef MREMAP_MAYMOVE
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000523 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000524#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000525 #if defined(__NetBSD__)
526 newmap = mremap(self->data, self->size, self->data, new_size, 0);
527 #else
528 newmap = mremap(self->data, self->size, new_size, 0);
529 #endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000530#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000531 if (newmap == (void *)-1)
532 {
533 PyErr_SetFromErrno(mmap_module_error);
534 return NULL;
535 }
536 self->data = newmap;
537 self->size = new_size;
538 Py_INCREF(Py_None);
539 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000540#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000541#endif /* UNIX */
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000542 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000543}
544
545static PyObject *
Georg Brandl96a8c392006-05-29 21:04:52 +0000546mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000547{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000548 CHECK_VALID(NULL);
549 return PyInt_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000550}
551
552static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000553mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000554{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000555 Py_ssize_t offset = 0;
556 Py_ssize_t size = self->size;
557 CHECK_VALID(NULL);
558 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
559 return NULL;
560 if ((size_t)(offset + size) > self->size) {
561 PyErr_SetString(PyExc_ValueError, "flush values out of range");
562 return NULL;
563 }
R. David Murray2a4b3fc2010-12-11 02:13:04 +0000564
565 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
566 return PyLong_FromLong(0);
567
Neal Norwitz448654f2008-01-27 07:36:03 +0000568#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000569 return PyInt_FromLong((long) FlushViewOfFile(self->data+offset, size));
Neal Norwitz448654f2008-01-27 07:36:03 +0000570#elif defined(UNIX)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000571 /* XXX semantics of return value? */
572 /* XXX flags for msync? */
573 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
574 PyErr_SetFromErrno(mmap_module_error);
575 return NULL;
576 }
577 return PyInt_FromLong(0);
Neal Norwitz448654f2008-01-27 07:36:03 +0000578#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000579 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
580 return NULL;
Neal Norwitz448654f2008-01-27 07:36:03 +0000581#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000582}
583
584static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000585mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000586{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000587 Py_ssize_t dist;
588 int how=0;
589 CHECK_VALID(NULL);
590 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
591 return NULL;
592 else {
593 size_t where;
594 switch (how) {
595 case 0: /* relative to start */
596 if (dist < 0)
597 goto onoutofrange;
598 where = dist;
599 break;
600 case 1: /* relative to current position */
601 if ((Py_ssize_t)self->pos + dist < 0)
602 goto onoutofrange;
603 where = self->pos + dist;
604 break;
605 case 2: /* relative to end */
606 if ((Py_ssize_t)self->size + dist < 0)
607 goto onoutofrange;
608 where = self->size + dist;
609 break;
610 default:
611 PyErr_SetString(PyExc_ValueError, "unknown seek type");
612 return NULL;
613 }
614 if (where > self->size)
615 goto onoutofrange;
616 self->pos = where;
617 Py_INCREF(Py_None);
618 return Py_None;
619 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000620
Tim Peters5ebfd362001-11-13 23:11:19 +0000621 onoutofrange:
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000622 PyErr_SetString(PyExc_ValueError, "seek out of range");
623 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000624}
625
626static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000627mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000628{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000629 unsigned long dest, src, cnt;
630 CHECK_VALID(NULL);
631 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
632 !is_writeable(self)) {
633 return NULL;
634 } else {
635 /* bounds check the values */
636 if (cnt < 0 || (cnt + dest) < cnt || (cnt + src) < cnt ||
637 src < 0 || src > self->size || (src + cnt) > self->size ||
638 dest < 0 || dest > self->size || (dest + cnt) > self->size) {
639 PyErr_SetString(PyExc_ValueError,
640 "source, destination, or count out of range");
641 return NULL;
642 }
643 memmove(self->data+dest, self->data+src, cnt);
644 Py_INCREF(Py_None);
645 return Py_None;
646 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000647}
648
649static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000650 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
651 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
652 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
653 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
654 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
655 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
656 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
657 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
658 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
659 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
660 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
661 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
662 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
663 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
664 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000665};
666
667/* Functions for treating an mmap'ed file as a buffer */
668
Martin v. Löwis18e16552006-02-15 17:27:45 +0000669static Py_ssize_t
670mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000671{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000672 CHECK_VALID(-1);
673 if (index != 0) {
674 PyErr_SetString(PyExc_SystemError,
675 "Accessing non-existent mmap segment");
676 return -1;
677 }
678 *ptr = self->data;
679 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000680}
681
Martin v. Löwis18e16552006-02-15 17:27:45 +0000682static Py_ssize_t
683mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Tim Petersec0a5f02006-02-16 23:47:20 +0000684{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000685 CHECK_VALID(-1);
686 if (index != 0) {
687 PyErr_SetString(PyExc_SystemError,
688 "Accessing non-existent mmap segment");
689 return -1;
690 }
691 if (!is_writeable(self))
692 return -1;
693 *ptr = self->data;
694 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000695}
696
Martin v. Löwis18e16552006-02-15 17:27:45 +0000697static Py_ssize_t
698mmap_buffer_getsegcount(mmap_object *self, Py_ssize_t *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000699{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000700 CHECK_VALID(-1);
701 if (lenp)
702 *lenp = self->size;
703 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000704}
705
Martin v. Löwis18e16552006-02-15 17:27:45 +0000706static Py_ssize_t
707mmap_buffer_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000708{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000709 if (index != 0) {
710 PyErr_SetString(PyExc_SystemError,
711 "accessing non-existent buffer segment");
712 return -1;
713 }
714 *ptr = (const char *)self->data;
715 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000716}
717
Martin v. Löwis18e16552006-02-15 17:27:45 +0000718static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000719mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000720{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000721 CHECK_VALID(-1);
722 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000723}
724
725static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000726mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000727{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000728 CHECK_VALID(NULL);
729 if (i < 0 || (size_t)i >= self->size) {
730 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
731 return NULL;
732 }
733 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000734}
735
736static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000737mmap_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000738{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000739 CHECK_VALID(NULL);
740 if (ilow < 0)
741 ilow = 0;
742 else if ((size_t)ilow > self->size)
743 ilow = self->size;
744 if (ihigh < 0)
745 ihigh = 0;
746 if (ihigh < ilow)
747 ihigh = ilow;
748 else if ((size_t)ihigh > self->size)
749 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000750
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000751 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000752}
753
754static PyObject *
Thomas Wouters3ccec682007-08-28 15:28:19 +0000755mmap_subscript(mmap_object *self, PyObject *item)
756{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000757 CHECK_VALID(NULL);
758 if (PyIndex_Check(item)) {
759 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
760 if (i == -1 && PyErr_Occurred())
761 return NULL;
762 if (i < 0)
763 i += self->size;
764 if (i < 0 || (size_t)i >= self->size) {
765 PyErr_SetString(PyExc_IndexError,
766 "mmap index out of range");
767 return NULL;
768 }
769 return PyString_FromStringAndSize(self->data + i, 1);
770 }
771 else if (PySlice_Check(item)) {
772 Py_ssize_t start, stop, step, slicelen;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000773
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000774 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
775 &start, &stop, &step, &slicelen) < 0) {
776 return NULL;
777 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000778
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000779 if (slicelen <= 0)
780 return PyString_FromStringAndSize("", 0);
781 else if (step == 1)
782 return PyString_FromStringAndSize(self->data + start,
783 slicelen);
784 else {
785 char *result_buf = (char *)PyMem_Malloc(slicelen);
786 Py_ssize_t cur, i;
787 PyObject *result;
788
789 if (result_buf == NULL)
790 return PyErr_NoMemory();
791 for (cur = start, i = 0; i < slicelen;
792 cur += step, i++) {
793 result_buf[i] = self->data[cur];
794 }
795 result = PyString_FromStringAndSize(result_buf,
796 slicelen);
797 PyMem_Free(result_buf);
798 return result;
799 }
800 }
801 else {
802 PyErr_SetString(PyExc_TypeError,
803 "mmap indices must be integers");
804 return NULL;
805 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000806}
807
808static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000809mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000810{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000811 CHECK_VALID(NULL);
812 PyErr_SetString(PyExc_SystemError,
813 "mmaps don't support concatenation");
814 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000815}
816
817static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000818mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000819{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000820 CHECK_VALID(NULL);
821 PyErr_SetString(PyExc_SystemError,
822 "mmaps don't support repeat operation");
823 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000824}
825
826static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000827mmap_ass_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000828{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000829 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000830
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000831 CHECK_VALID(-1);
832 if (ilow < 0)
833 ilow = 0;
834 else if ((size_t)ilow > self->size)
835 ilow = self->size;
836 if (ihigh < 0)
837 ihigh = 0;
838 if (ihigh < ilow)
839 ihigh = ilow;
840 else if ((size_t)ihigh > self->size)
841 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000842
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000843 if (v == NULL) {
844 PyErr_SetString(PyExc_TypeError,
845 "mmap object doesn't support slice deletion");
846 return -1;
847 }
848 if (! (PyString_Check(v)) ) {
849 PyErr_SetString(PyExc_IndexError,
850 "mmap slice assignment must be a string");
851 return -1;
852 }
853 if (PyString_Size(v) != (ihigh - ilow)) {
854 PyErr_SetString(PyExc_IndexError,
855 "mmap slice assignment is wrong size");
856 return -1;
857 }
858 if (!is_writeable(self))
859 return -1;
860 buf = PyString_AsString(v);
861 memcpy(self->data + ilow, buf, ihigh-ilow);
862 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000863}
864
865static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000866mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000867{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000868 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000869
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000870 CHECK_VALID(-1);
871 if (i < 0 || (size_t)i >= self->size) {
872 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
873 return -1;
874 }
875 if (v == NULL) {
876 PyErr_SetString(PyExc_TypeError,
877 "mmap object doesn't support item deletion");
878 return -1;
879 }
880 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
881 PyErr_SetString(PyExc_IndexError,
882 "mmap assignment must be single-character string");
883 return -1;
884 }
885 if (!is_writeable(self))
886 return -1;
887 buf = PyString_AsString(v);
888 self->data[i] = buf[0];
889 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000890}
891
Thomas Wouters3ccec682007-08-28 15:28:19 +0000892static int
893mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
894{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000895 CHECK_VALID(-1);
Thomas Wouters3ccec682007-08-28 15:28:19 +0000896
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000897 if (PyIndex_Check(item)) {
898 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
899 const char *buf;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000900
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000901 if (i == -1 && PyErr_Occurred())
902 return -1;
903 if (i < 0)
904 i += self->size;
905 if (i < 0 || (size_t)i >= self->size) {
906 PyErr_SetString(PyExc_IndexError,
907 "mmap index out of range");
908 return -1;
909 }
910 if (value == NULL) {
911 PyErr_SetString(PyExc_TypeError,
912 "mmap object doesn't support item deletion");
913 return -1;
914 }
915 if (!PyString_Check(value) || PyString_Size(value) != 1) {
916 PyErr_SetString(PyExc_IndexError,
917 "mmap assignment must be single-character string");
918 return -1;
919 }
920 if (!is_writeable(self))
921 return -1;
922 buf = PyString_AsString(value);
923 self->data[i] = buf[0];
924 return 0;
925 }
926 else if (PySlice_Check(item)) {
927 Py_ssize_t start, stop, step, slicelen;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000928
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000929 if (PySlice_GetIndicesEx((PySliceObject *)item,
930 self->size, &start, &stop,
931 &step, &slicelen) < 0) {
932 return -1;
933 }
934 if (value == NULL) {
935 PyErr_SetString(PyExc_TypeError,
936 "mmap object doesn't support slice deletion");
937 return -1;
938 }
939 if (!PyString_Check(value)) {
940 PyErr_SetString(PyExc_IndexError,
941 "mmap slice assignment must be a string");
942 return -1;
943 }
944 if (PyString_Size(value) != slicelen) {
945 PyErr_SetString(PyExc_IndexError,
946 "mmap slice assignment is wrong size");
947 return -1;
948 }
949 if (!is_writeable(self))
950 return -1;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000951
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000952 if (slicelen == 0)
953 return 0;
954 else if (step == 1) {
955 const char *buf = PyString_AsString(value);
956
957 if (buf == NULL)
958 return -1;
959 memcpy(self->data + start, buf, slicelen);
960 return 0;
961 }
962 else {
963 Py_ssize_t cur, i;
964 const char *buf = PyString_AsString(value);
965
966 if (buf == NULL)
967 return -1;
968 for (cur = start, i = 0; i < slicelen;
969 cur += step, i++) {
970 self->data[cur] = buf[i];
971 }
972 return 0;
973 }
974 }
975 else {
976 PyErr_SetString(PyExc_TypeError,
977 "mmap indices must be integer");
978 return -1;
979 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000980}
981
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000982static PySequenceMethods mmap_as_sequence = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000983 (lenfunc)mmap_length, /*sq_length*/
984 (binaryfunc)mmap_concat, /*sq_concat*/
985 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
986 (ssizeargfunc)mmap_item, /*sq_item*/
987 (ssizessizeargfunc)mmap_slice, /*sq_slice*/
988 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
989 (ssizessizeobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000990};
991
Thomas Wouters3ccec682007-08-28 15:28:19 +0000992static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000993 (lenfunc)mmap_length,
994 (binaryfunc)mmap_subscript,
995 (objobjargproc)mmap_ass_subscript,
Thomas Wouters3ccec682007-08-28 15:28:19 +0000996};
997
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000998static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000999 (readbufferproc)mmap_buffer_getreadbuf,
1000 (writebufferproc)mmap_buffer_getwritebuf,
1001 (segcountproc)mmap_buffer_getsegcount,
1002 (charbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001003};
1004
Georg Brandl845c4032008-01-21 14:16:46 +00001005static PyObject *
1006new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
1007
Georg Brandlef928022008-01-20 14:50:05 +00001008PyDoc_STRVAR(mmap_doc,
1009"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
1010\n\
1011Maps length bytes from the file specified by the file handle fileno,\n\
1012and returns a mmap object. If length is larger than the current size\n\
1013of the file, the file is extended to contain length bytes. If length\n\
1014is 0, the maximum length of the map is the current size of the file,\n\
1015except that if the file is empty Windows raises an exception (you cannot\n\
1016create an empty mapping on Windows).\n\
1017\n\
1018Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
1019\n\
1020Maps length bytes from the file specified by the file descriptor fileno,\n\
1021and returns a mmap object. If length is 0, the maximum length of the map\n\
1022will be the current size of the file when mmap is called.\n\
1023flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1024private copy-on-write mapping, so changes to the contents of the mmap\n\
Thomas Heller66260992008-08-19 17:47:13 +00001025object will be private to this process, and MAP_SHARED creates a mapping\n\
Georg Brandlef928022008-01-20 14:50:05 +00001026that's shared with all other processes mapping the same areas of the file.\n\
1027The default value is MAP_SHARED.\n\
1028\n\
1029To map anonymous memory, pass -1 as the fileno (both versions).");
1030
1031
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001032static PyTypeObject mmap_object_type = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001033 PyVarObject_HEAD_INIT(NULL, 0)
1034 "mmap.mmap", /* tp_name */
1035 sizeof(mmap_object), /* tp_size */
1036 0, /* tp_itemsize */
1037 /* methods */
1038 (destructor) mmap_object_dealloc, /* tp_dealloc */
1039 0, /* tp_print */
1040 0, /* tp_getattr */
1041 0, /* tp_setattr */
1042 0, /* tp_compare */
1043 0, /* tp_repr */
1044 0, /* tp_as_number */
1045 &mmap_as_sequence, /*tp_as_sequence*/
1046 &mmap_as_mapping, /*tp_as_mapping*/
1047 0, /*tp_hash*/
1048 0, /*tp_call*/
1049 0, /*tp_str*/
1050 PyObject_GenericGetAttr, /*tp_getattro*/
1051 0, /*tp_setattro*/
1052 &mmap_as_buffer, /*tp_as_buffer*/
1053 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
1054 mmap_doc, /*tp_doc*/
1055 0, /* tp_traverse */
1056 0, /* tp_clear */
1057 0, /* tp_richcompare */
1058 0, /* tp_weaklistoffset */
1059 0, /* tp_iter */
1060 0, /* tp_iternext */
1061 mmap_object_methods, /* tp_methods */
1062 0, /* tp_members */
1063 0, /* tp_getset */
1064 0, /* tp_base */
1065 0, /* tp_dict */
1066 0, /* tp_descr_get */
1067 0, /* tp_descr_set */
1068 0, /* tp_dictoffset */
1069 0, /* tp_init */
1070 PyType_GenericAlloc, /* tp_alloc */
1071 new_mmap_object, /* tp_new */
1072 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001073};
1074
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001075
1076/* extract the map size from the given PyObject
1077
Thomas Wouters7e474022000-07-16 12:04:32 +00001078 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001079 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001080static Py_ssize_t
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001081_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001082{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001083 if (o == NULL)
1084 return 0;
1085 if (PyIndex_Check(o)) {
1086 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1087 if (i==-1 && PyErr_Occurred())
1088 return -1;
1089 if (i < 0) {
1090 PyErr_Format(PyExc_OverflowError,
1091 "memory mapped %s must be positive",
1092 param);
1093 return -1;
1094 }
1095 return i;
1096 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001097
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001098 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1099 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001100}
1101
Tim Petersec0a5f02006-02-16 23:47:20 +00001102#ifdef UNIX
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001103#ifdef HAVE_LARGEFILE_SUPPORT
1104#define _Py_PARSE_OFF_T "L"
1105#else
1106#define _Py_PARSE_OFF_T "l"
1107#endif
1108
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001109static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001110new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001111{
Neal Norwitzb5673922002-09-05 21:48:07 +00001112#ifdef HAVE_FSTAT
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001113 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001114#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001115 mmap_object *m_obj;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001116 PyObject *map_size_obj = NULL;
1117 Py_ssize_t map_size;
1118 off_t offset = 0;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001119 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1120 int devzero = -1;
1121 int access = (int)ACCESS_DEFAULT;
1122 static char *keywords[] = {"fileno", "length",
1123 "flags", "prot",
1124 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001125
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001126 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords,
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001127 &fd, &map_size_obj, &flags, &prot,
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001128 &access, &offset))
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001129 return NULL;
1130 map_size = _GetMapSize(map_size_obj, "size");
1131 if (map_size < 0)
1132 return NULL;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001133 if (offset < 0) {
1134 PyErr_SetString(PyExc_OverflowError,
1135 "memory mapped offset must be positive");
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001136 return NULL;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001137 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001138
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001139 if ((access != (int)ACCESS_DEFAULT) &&
1140 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1141 return PyErr_Format(PyExc_ValueError,
1142 "mmap can't specify both access and flags, prot.");
1143 switch ((access_mode)access) {
1144 case ACCESS_READ:
1145 flags = MAP_SHARED;
1146 prot = PROT_READ;
1147 break;
1148 case ACCESS_WRITE:
1149 flags = MAP_SHARED;
1150 prot = PROT_READ | PROT_WRITE;
1151 break;
1152 case ACCESS_COPY:
1153 flags = MAP_PRIVATE;
1154 prot = PROT_READ | PROT_WRITE;
1155 break;
1156 case ACCESS_DEFAULT:
Antoine Pitroud6f3a3e2011-03-06 02:03:34 +01001157 /* map prot to access type */
1158 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1159 /* ACCESS_DEFAULT */
1160 }
1161 else if (prot & PROT_WRITE) {
1162 access = ACCESS_WRITE;
1163 }
1164 else {
1165 access = ACCESS_READ;
1166 }
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001167 break;
1168 default:
1169 return PyErr_Format(PyExc_ValueError,
1170 "mmap invalid access parameter.");
1171 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001172
1173#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001174# ifdef __VMS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001175 /* on OpenVMS we must ensure that all bytes are written to the file */
1176 if (fd != -1) {
1177 fsync(fd);
1178 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001179# endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001180 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1181 if (map_size == 0) {
Antoine Pitrou8a0eede2011-01-20 21:20:18 +00001182 if (offset >= st.st_size) {
1183 PyErr_SetString(PyExc_ValueError,
1184 "mmap offset is greater than file size");
1185 return NULL;
1186 }
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001187 off_t calc_size = st.st_size - offset;
1188 map_size = calc_size;
1189 if (map_size != calc_size) {
1190 PyErr_SetString(PyExc_ValueError,
1191 "mmap length is too large");
1192 return NULL;
1193 }
1194 } else if (offset + (size_t)map_size > st.st_size) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001195 PyErr_SetString(PyExc_ValueError,
1196 "mmap length is greater than file size");
1197 return NULL;
1198 }
1199 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001200#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001201 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1202 if (m_obj == NULL) {return NULL;}
1203 m_obj->data = NULL;
1204 m_obj->size = (size_t) map_size;
1205 m_obj->pos = (size_t) 0;
1206 m_obj->offset = offset;
1207 if (fd == -1) {
1208 m_obj->fd = -1;
1209 /* Assume the caller wants to map anonymous memory.
1210 This is the same behaviour as Windows. mmap.mmap(-1, size)
1211 on both Windows and Unix map anonymous memory.
1212 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001213#ifdef MAP_ANONYMOUS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001214 /* BSD way to map anonymous memory */
1215 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001216#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001217 /* SVR4 method to map anonymous memory is to open /dev/zero */
1218 fd = devzero = open("/dev/zero", O_RDWR);
1219 if (devzero == -1) {
1220 Py_DECREF(m_obj);
1221 PyErr_SetFromErrno(mmap_module_error);
1222 return NULL;
1223 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001224#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001225 } else {
1226 m_obj->fd = dup(fd);
1227 if (m_obj->fd == -1) {
1228 Py_DECREF(m_obj);
1229 PyErr_SetFromErrno(mmap_module_error);
1230 return NULL;
1231 }
1232 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001233
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001234 m_obj->data = mmap(NULL, map_size,
1235 prot, flags,
1236 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001237
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001238 if (devzero != -1) {
1239 close(devzero);
1240 }
1241
1242 if (m_obj->data == (char *)-1) {
1243 m_obj->data = NULL;
1244 Py_DECREF(m_obj);
1245 PyErr_SetFromErrno(mmap_module_error);
1246 return NULL;
1247 }
1248 m_obj->access = (access_mode)access;
1249 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001250}
1251#endif /* UNIX */
1252
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001253#ifdef MS_WINDOWS
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001254
1255/* A note on sizes and offsets: while the actual map size must hold in a
1256 Py_ssize_t, both the total file size and the start offset can be longer
1257 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1258*/
1259
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001260static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001261new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001262{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001263 mmap_object *m_obj;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001264 PyObject *map_size_obj = NULL;
1265 Py_ssize_t map_size;
1266 PY_LONG_LONG offset = 0, size;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001267 DWORD off_hi; /* upper 32 bits of offset */
1268 DWORD off_lo; /* lower 32 bits of offset */
1269 DWORD size_hi; /* upper 32 bits of size */
1270 DWORD size_lo; /* lower 32 bits of size */
1271 char *tagname = "";
1272 DWORD dwErr = 0;
1273 int fileno;
1274 HANDLE fh = 0;
1275 int access = (access_mode)ACCESS_DEFAULT;
1276 DWORD flProtect, dwDesiredAccess;
1277 static char *keywords[] = { "fileno", "length",
1278 "tagname",
1279 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001280
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001281 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords,
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001282 &fileno, &map_size_obj,
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001283 &tagname, &access, &offset)) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001284 return NULL;
1285 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001286
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001287 switch((access_mode)access) {
1288 case ACCESS_READ:
1289 flProtect = PAGE_READONLY;
1290 dwDesiredAccess = FILE_MAP_READ;
1291 break;
1292 case ACCESS_DEFAULT: case ACCESS_WRITE:
1293 flProtect = PAGE_READWRITE;
1294 dwDesiredAccess = FILE_MAP_WRITE;
1295 break;
1296 case ACCESS_COPY:
1297 flProtect = PAGE_WRITECOPY;
1298 dwDesiredAccess = FILE_MAP_COPY;
1299 break;
1300 default:
1301 return PyErr_Format(PyExc_ValueError,
1302 "mmap invalid access parameter.");
1303 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001304
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001305 map_size = _GetMapSize(map_size_obj, "size");
1306 if (map_size < 0)
1307 return NULL;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001308 if (offset < 0) {
1309 PyErr_SetString(PyExc_OverflowError,
1310 "memory mapped offset must be positive");
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001311 return NULL;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001312 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001313
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001314 /* assume -1 and 0 both mean invalid filedescriptor
1315 to 'anonymously' map memory.
1316 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1317 XXX: Should this code be added?
1318 if (fileno == 0)
1319 PyErr_Warn(PyExc_DeprecationWarning,
1320 "don't use 0 for anonymous memory");
1321 */
1322 if (fileno != -1 && fileno != 0) {
Brian Curtinba6c08e2010-08-01 15:47:53 +00001323 /* Ensure that fileno is within the CRT's valid range */
1324 if (_PyVerify_fd(fileno) == 0) {
1325 PyErr_SetFromErrno(mmap_module_error);
1326 return NULL;
1327 }
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001328 fh = (HANDLE)_get_osfhandle(fileno);
1329 if (fh==(HANDLE)-1) {
1330 PyErr_SetFromErrno(mmap_module_error);
1331 return NULL;
1332 }
1333 /* Win9x appears to need us seeked to zero */
1334 lseek(fileno, 0, SEEK_SET);
1335 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001336
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001337 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1338 if (m_obj == NULL)
1339 return NULL;
1340 /* Set every field to an invalid marker, so we can safely
1341 destruct the object in the face of failure */
1342 m_obj->data = NULL;
1343 m_obj->file_handle = INVALID_HANDLE_VALUE;
1344 m_obj->map_handle = NULL;
1345 m_obj->tagname = NULL;
1346 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001347
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001348 if (fh) {
1349 /* It is necessary to duplicate the handle, so the
1350 Python code can close it on us */
1351 if (!DuplicateHandle(
1352 GetCurrentProcess(), /* source process handle */
1353 fh, /* handle to be duplicated */
1354 GetCurrentProcess(), /* target proc handle */
1355 (LPHANDLE)&m_obj->file_handle, /* result */
1356 0, /* access - ignored due to options value */
1357 FALSE, /* inherited by child processes? */
1358 DUPLICATE_SAME_ACCESS)) { /* options */
1359 dwErr = GetLastError();
1360 Py_DECREF(m_obj);
1361 PyErr_SetFromWindowsErr(dwErr);
1362 return NULL;
1363 }
1364 if (!map_size) {
1365 DWORD low,high;
1366 low = GetFileSize(fh, &high);
1367 /* low might just happen to have the value INVALID_FILE_SIZE;
1368 so we need to check the last error also. */
1369 if (low == INVALID_FILE_SIZE &&
1370 (dwErr = GetLastError()) != NO_ERROR) {
1371 Py_DECREF(m_obj);
1372 return PyErr_SetFromWindowsErr(dwErr);
1373 }
1374
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001375 size = (((PY_LONG_LONG) high) << 32) + low;
1376 if (offset >= size) {
Antoine Pitrou8a0eede2011-01-20 21:20:18 +00001377 PyErr_SetString(PyExc_ValueError,
1378 "mmap offset is greater than file size");
1379 Py_DECREF(m_obj);
1380 return NULL;
1381 }
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001382 if (offset - size > PY_SSIZE_T_MAX)
1383 /* Map area too large to fit in memory */
1384 m_obj->size = (Py_ssize_t) -1;
1385 else
1386 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001387 } else {
1388 m_obj->size = map_size;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001389 size = offset + map_size;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001390 }
1391 }
1392 else {
1393 m_obj->size = map_size;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001394 size = offset + map_size;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001395 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001396
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001397 /* set the initial position */
1398 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001399
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001400 /* set the tag name */
1401 if (tagname != NULL && *tagname != '\0') {
1402 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1403 if (m_obj->tagname == NULL) {
1404 PyErr_NoMemory();
1405 Py_DECREF(m_obj);
1406 return NULL;
1407 }
1408 strcpy(m_obj->tagname, tagname);
1409 }
1410 else
1411 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001412
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001413 m_obj->access = (access_mode)access;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001414 size_hi = (DWORD)(size >> 32);
1415 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001416 off_hi = (DWORD)(offset >> 32);
1417 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001418 /* For files, it would be sufficient to pass 0 as size.
1419 For anonymous maps, we have to pass the size explicitly. */
1420 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1421 NULL,
1422 flProtect,
1423 size_hi,
1424 size_lo,
1425 m_obj->tagname);
1426 if (m_obj->map_handle != NULL) {
1427 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1428 dwDesiredAccess,
1429 off_hi,
1430 off_lo,
1431 m_obj->size);
1432 if (m_obj->data != NULL)
1433 return (PyObject *)m_obj;
1434 else {
1435 dwErr = GetLastError();
1436 CloseHandle(m_obj->map_handle);
1437 m_obj->map_handle = NULL;
1438 }
1439 } else
1440 dwErr = GetLastError();
1441 Py_DECREF(m_obj);
1442 PyErr_SetFromWindowsErr(dwErr);
1443 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001444}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001445#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001446
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001447static void
1448setint(PyObject *d, const char *name, long value)
1449{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001450 PyObject *o = PyInt_FromLong(value);
1451 if (o && PyDict_SetItemString(d, name, o) == 0) {
1452 Py_DECREF(o);
1453 }
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001454}
1455
Mark Hammond62b1ab12002-07-23 06:31:15 +00001456PyMODINIT_FUNC
Georg Brandl845c4032008-01-21 14:16:46 +00001457initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001458{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001459 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001460
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001461 if (PyType_Ready(&mmap_object_type) < 0)
1462 return;
Tim Peters2caf8df2001-01-14 05:05:51 +00001463
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001464 module = Py_InitModule("mmap", NULL);
1465 if (module == NULL)
1466 return;
1467 dict = PyModule_GetDict(module);
1468 if (!dict)
1469 return;
1470 mmap_module_error = PyErr_NewException("mmap.error",
1471 PyExc_EnvironmentError , NULL);
1472 if (mmap_module_error == NULL)
1473 return;
1474 PyDict_SetItemString(dict, "error", mmap_module_error);
1475 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001476#ifdef PROT_EXEC
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001477 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001478#endif
1479#ifdef PROT_READ
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001480 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001481#endif
1482#ifdef PROT_WRITE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001483 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001484#endif
1485
1486#ifdef MAP_SHARED
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001487 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001488#endif
1489#ifdef MAP_PRIVATE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001490 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001491#endif
1492#ifdef MAP_DENYWRITE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001493 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001494#endif
1495#ifdef MAP_EXECUTABLE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001496 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001497#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001498#ifdef MAP_ANONYMOUS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001499 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1500 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001501#endif
1502
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001503 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001504
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001505 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001506
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001507 setint(dict, "ACCESS_READ", ACCESS_READ);
1508 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1509 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Tim Peters5ebfd362001-11-13 23:11:19 +00001510}