blob: 219ddd22c95870276b46580755c39265bb628a86 [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:
1157 /* use the specified or default values of flags and prot */
1158 break;
1159 default:
1160 return PyErr_Format(PyExc_ValueError,
1161 "mmap invalid access parameter.");
1162 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001163
Christian Heimes7adfad82008-02-15 08:20:11 +00001164 if (prot == PROT_READ) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001165 access = ACCESS_READ;
Christian Heimes7adfad82008-02-15 08:20:11 +00001166 }
1167
Neal Norwitzb5673922002-09-05 21:48:07 +00001168#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001169# ifdef __VMS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001170 /* on OpenVMS we must ensure that all bytes are written to the file */
1171 if (fd != -1) {
1172 fsync(fd);
1173 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001174# endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001175 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1176 if (map_size == 0) {
Antoine Pitrou8a0eede2011-01-20 21:20:18 +00001177 if (offset >= st.st_size) {
1178 PyErr_SetString(PyExc_ValueError,
1179 "mmap offset is greater than file size");
1180 return NULL;
1181 }
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001182 off_t calc_size = st.st_size - offset;
1183 map_size = calc_size;
1184 if (map_size != calc_size) {
1185 PyErr_SetString(PyExc_ValueError,
1186 "mmap length is too large");
1187 return NULL;
1188 }
1189 } else if (offset + (size_t)map_size > st.st_size) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001190 PyErr_SetString(PyExc_ValueError,
1191 "mmap length is greater than file size");
1192 return NULL;
1193 }
1194 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001195#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001196 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1197 if (m_obj == NULL) {return NULL;}
1198 m_obj->data = NULL;
1199 m_obj->size = (size_t) map_size;
1200 m_obj->pos = (size_t) 0;
1201 m_obj->offset = offset;
1202 if (fd == -1) {
1203 m_obj->fd = -1;
1204 /* Assume the caller wants to map anonymous memory.
1205 This is the same behaviour as Windows. mmap.mmap(-1, size)
1206 on both Windows and Unix map anonymous memory.
1207 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001208#ifdef MAP_ANONYMOUS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001209 /* BSD way to map anonymous memory */
1210 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001211#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001212 /* SVR4 method to map anonymous memory is to open /dev/zero */
1213 fd = devzero = open("/dev/zero", O_RDWR);
1214 if (devzero == -1) {
1215 Py_DECREF(m_obj);
1216 PyErr_SetFromErrno(mmap_module_error);
1217 return NULL;
1218 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001219#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001220 } else {
1221 m_obj->fd = dup(fd);
1222 if (m_obj->fd == -1) {
1223 Py_DECREF(m_obj);
1224 PyErr_SetFromErrno(mmap_module_error);
1225 return NULL;
1226 }
1227 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001228
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001229 m_obj->data = mmap(NULL, map_size,
1230 prot, flags,
1231 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001232
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001233 if (devzero != -1) {
1234 close(devzero);
1235 }
1236
1237 if (m_obj->data == (char *)-1) {
1238 m_obj->data = NULL;
1239 Py_DECREF(m_obj);
1240 PyErr_SetFromErrno(mmap_module_error);
1241 return NULL;
1242 }
1243 m_obj->access = (access_mode)access;
1244 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001245}
1246#endif /* UNIX */
1247
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001248#ifdef MS_WINDOWS
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001249
1250/* A note on sizes and offsets: while the actual map size must hold in a
1251 Py_ssize_t, both the total file size and the start offset can be longer
1252 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1253*/
1254
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001255static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001256new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001257{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001258 mmap_object *m_obj;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001259 PyObject *map_size_obj = NULL;
1260 Py_ssize_t map_size;
1261 PY_LONG_LONG offset = 0, size;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001262 DWORD off_hi; /* upper 32 bits of offset */
1263 DWORD off_lo; /* lower 32 bits of offset */
1264 DWORD size_hi; /* upper 32 bits of size */
1265 DWORD size_lo; /* lower 32 bits of size */
1266 char *tagname = "";
1267 DWORD dwErr = 0;
1268 int fileno;
1269 HANDLE fh = 0;
1270 int access = (access_mode)ACCESS_DEFAULT;
1271 DWORD flProtect, dwDesiredAccess;
1272 static char *keywords[] = { "fileno", "length",
1273 "tagname",
1274 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001275
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001276 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords,
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001277 &fileno, &map_size_obj,
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001278 &tagname, &access, &offset)) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001279 return NULL;
1280 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001281
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001282 switch((access_mode)access) {
1283 case ACCESS_READ:
1284 flProtect = PAGE_READONLY;
1285 dwDesiredAccess = FILE_MAP_READ;
1286 break;
1287 case ACCESS_DEFAULT: case ACCESS_WRITE:
1288 flProtect = PAGE_READWRITE;
1289 dwDesiredAccess = FILE_MAP_WRITE;
1290 break;
1291 case ACCESS_COPY:
1292 flProtect = PAGE_WRITECOPY;
1293 dwDesiredAccess = FILE_MAP_COPY;
1294 break;
1295 default:
1296 return PyErr_Format(PyExc_ValueError,
1297 "mmap invalid access parameter.");
1298 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001299
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001300 map_size = _GetMapSize(map_size_obj, "size");
1301 if (map_size < 0)
1302 return NULL;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001303 if (offset < 0) {
1304 PyErr_SetString(PyExc_OverflowError,
1305 "memory mapped offset must be positive");
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001306 return NULL;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001307 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001308
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001309 /* assume -1 and 0 both mean invalid filedescriptor
1310 to 'anonymously' map memory.
1311 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1312 XXX: Should this code be added?
1313 if (fileno == 0)
1314 PyErr_Warn(PyExc_DeprecationWarning,
1315 "don't use 0 for anonymous memory");
1316 */
1317 if (fileno != -1 && fileno != 0) {
Brian Curtinba6c08e2010-08-01 15:47:53 +00001318 /* Ensure that fileno is within the CRT's valid range */
1319 if (_PyVerify_fd(fileno) == 0) {
1320 PyErr_SetFromErrno(mmap_module_error);
1321 return NULL;
1322 }
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001323 fh = (HANDLE)_get_osfhandle(fileno);
1324 if (fh==(HANDLE)-1) {
1325 PyErr_SetFromErrno(mmap_module_error);
1326 return NULL;
1327 }
1328 /* Win9x appears to need us seeked to zero */
1329 lseek(fileno, 0, SEEK_SET);
1330 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001331
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001332 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1333 if (m_obj == NULL)
1334 return NULL;
1335 /* Set every field to an invalid marker, so we can safely
1336 destruct the object in the face of failure */
1337 m_obj->data = NULL;
1338 m_obj->file_handle = INVALID_HANDLE_VALUE;
1339 m_obj->map_handle = NULL;
1340 m_obj->tagname = NULL;
1341 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001342
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001343 if (fh) {
1344 /* It is necessary to duplicate the handle, so the
1345 Python code can close it on us */
1346 if (!DuplicateHandle(
1347 GetCurrentProcess(), /* source process handle */
1348 fh, /* handle to be duplicated */
1349 GetCurrentProcess(), /* target proc handle */
1350 (LPHANDLE)&m_obj->file_handle, /* result */
1351 0, /* access - ignored due to options value */
1352 FALSE, /* inherited by child processes? */
1353 DUPLICATE_SAME_ACCESS)) { /* options */
1354 dwErr = GetLastError();
1355 Py_DECREF(m_obj);
1356 PyErr_SetFromWindowsErr(dwErr);
1357 return NULL;
1358 }
1359 if (!map_size) {
1360 DWORD low,high;
1361 low = GetFileSize(fh, &high);
1362 /* low might just happen to have the value INVALID_FILE_SIZE;
1363 so we need to check the last error also. */
1364 if (low == INVALID_FILE_SIZE &&
1365 (dwErr = GetLastError()) != NO_ERROR) {
1366 Py_DECREF(m_obj);
1367 return PyErr_SetFromWindowsErr(dwErr);
1368 }
1369
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001370 size = (((PY_LONG_LONG) high) << 32) + low;
1371 if (offset >= size) {
Antoine Pitrou8a0eede2011-01-20 21:20:18 +00001372 PyErr_SetString(PyExc_ValueError,
1373 "mmap offset is greater than file size");
1374 Py_DECREF(m_obj);
1375 return NULL;
1376 }
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001377 if (offset - size > PY_SSIZE_T_MAX)
1378 /* Map area too large to fit in memory */
1379 m_obj->size = (Py_ssize_t) -1;
1380 else
1381 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001382 } else {
1383 m_obj->size = map_size;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001384 size = offset + map_size;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001385 }
1386 }
1387 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 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001391
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001392 /* set the initial position */
1393 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001394
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001395 /* set the tag name */
1396 if (tagname != NULL && *tagname != '\0') {
1397 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1398 if (m_obj->tagname == NULL) {
1399 PyErr_NoMemory();
1400 Py_DECREF(m_obj);
1401 return NULL;
1402 }
1403 strcpy(m_obj->tagname, tagname);
1404 }
1405 else
1406 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001407
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001408 m_obj->access = (access_mode)access;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001409 size_hi = (DWORD)(size >> 32);
1410 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001411 off_hi = (DWORD)(offset >> 32);
1412 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001413 /* For files, it would be sufficient to pass 0 as size.
1414 For anonymous maps, we have to pass the size explicitly. */
1415 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1416 NULL,
1417 flProtect,
1418 size_hi,
1419 size_lo,
1420 m_obj->tagname);
1421 if (m_obj->map_handle != NULL) {
1422 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1423 dwDesiredAccess,
1424 off_hi,
1425 off_lo,
1426 m_obj->size);
1427 if (m_obj->data != NULL)
1428 return (PyObject *)m_obj;
1429 else {
1430 dwErr = GetLastError();
1431 CloseHandle(m_obj->map_handle);
1432 m_obj->map_handle = NULL;
1433 }
1434 } else
1435 dwErr = GetLastError();
1436 Py_DECREF(m_obj);
1437 PyErr_SetFromWindowsErr(dwErr);
1438 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001439}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001440#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001441
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001442static void
1443setint(PyObject *d, const char *name, long value)
1444{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001445 PyObject *o = PyInt_FromLong(value);
1446 if (o && PyDict_SetItemString(d, name, o) == 0) {
1447 Py_DECREF(o);
1448 }
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001449}
1450
Mark Hammond62b1ab12002-07-23 06:31:15 +00001451PyMODINIT_FUNC
Georg Brandl845c4032008-01-21 14:16:46 +00001452initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001453{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001454 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001455
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001456 if (PyType_Ready(&mmap_object_type) < 0)
1457 return;
Tim Peters2caf8df2001-01-14 05:05:51 +00001458
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001459 module = Py_InitModule("mmap", NULL);
1460 if (module == NULL)
1461 return;
1462 dict = PyModule_GetDict(module);
1463 if (!dict)
1464 return;
1465 mmap_module_error = PyErr_NewException("mmap.error",
1466 PyExc_EnvironmentError , NULL);
1467 if (mmap_module_error == NULL)
1468 return;
1469 PyDict_SetItemString(dict, "error", mmap_module_error);
1470 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001471#ifdef PROT_EXEC
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001472 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001473#endif
1474#ifdef PROT_READ
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001475 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001476#endif
1477#ifdef PROT_WRITE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001478 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001479#endif
1480
1481#ifdef MAP_SHARED
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001482 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001483#endif
1484#ifdef MAP_PRIVATE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001485 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001486#endif
1487#ifdef MAP_DENYWRITE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001488 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001489#endif
1490#ifdef MAP_EXECUTABLE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001491 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001492#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001493#ifdef MAP_ANONYMOUS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001494 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1495 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001496#endif
1497
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001498 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001499
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001500 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001501
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001502 setint(dict, "ACCESS_READ", ACCESS_READ);
1503 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1504 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Tim Peters5ebfd362001-11-13 23:11:19 +00001505}