blob: 67e4000b2560cea9f745f4ab55edfde354a23ab3 [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
Victor Stinner112d48a2011-05-03 14:36:36 +020026# ifdef __APPLE__
27# include <fcntl.h>
28# endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000029#endif
30
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000031#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000032#include <windows.h>
Fred Drake145f96e2000-10-01 17:50:46 +000033static int
34my_getpagesize(void)
35{
Antoine Pitrouc83ea132010-05-09 14:46:46 +000036 SYSTEM_INFO si;
37 GetSystemInfo(&si);
38 return si.dwPageSize;
Fred Drake145f96e2000-10-01 17:50:46 +000039}
Travis E. Oliphant8feafab2007-10-23 02:40:56 +000040
41static int
42my_getallocationgranularity (void)
43{
44
Antoine Pitrouc83ea132010-05-09 14:46:46 +000045 SYSTEM_INFO si;
46 GetSystemInfo(&si);
47 return si.dwAllocationGranularity;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +000048}
49
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000050#endif
51
52#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000053#include <sys/mman.h>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000054#include <sys/stat.h>
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000055
Fred Drake145f96e2000-10-01 17:50:46 +000056#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
57static int
58my_getpagesize(void)
59{
Antoine Pitrouc83ea132010-05-09 14:46:46 +000060 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000061}
Travis E. Oliphant8feafab2007-10-23 02:40:56 +000062
63#define my_getallocationgranularity my_getpagesize
Fred Drake145f96e2000-10-01 17:50:46 +000064#else
65#define my_getpagesize getpagesize
66#endif
67
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000068#endif /* UNIX */
69
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000070#include <string.h>
Martin v. Löwis0e8bd7e2006-06-10 12:23:46 +000071
72#ifdef HAVE_SYS_TYPES_H
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000073#include <sys/types.h>
Martin v. Löwis0e8bd7e2006-06-10 12:23:46 +000074#endif /* HAVE_SYS_TYPES_H */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000075
Neal Norwitz3eaf2b52006-02-16 08:08:54 +000076/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +000077#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
78# define MAP_ANONYMOUS MAP_ANON
79#endif
80
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000081static PyObject *mmap_module_error;
82
Tim Peters5ebfd362001-11-13 23:11:19 +000083typedef enum
84{
Antoine Pitrouc83ea132010-05-09 14:46:46 +000085 ACCESS_DEFAULT,
86 ACCESS_READ,
87 ACCESS_WRITE,
88 ACCESS_COPY
Tim Peters5ebfd362001-11-13 23:11:19 +000089} access_mode;
90
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000091typedef struct {
Antoine Pitrouc83ea132010-05-09 14:46:46 +000092 PyObject_HEAD
93 char * data;
94 size_t size;
95 size_t pos; /* relative to offset */
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +000096#ifdef MS_WINDOWS
97 PY_LONG_LONG offset;
98#else
99 off_t offset;
100#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000101
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000102#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000103 HANDLE map_handle;
104 HANDLE file_handle;
105 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000106#endif
107
108#ifdef UNIX
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000109 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000110#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000111
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000112 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000113} mmap_object;
114
Tim Peters5ebfd362001-11-13 23:11:19 +0000115
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000116static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000117mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000118{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000119#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000120 if (m_obj->data != NULL)
121 UnmapViewOfFile (m_obj->data);
122 if (m_obj->map_handle != NULL)
123 CloseHandle (m_obj->map_handle);
124 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
125 CloseHandle (m_obj->file_handle);
126 if (m_obj->tagname)
127 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000128#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000129
130#ifdef UNIX
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000131 if (m_obj->fd >= 0)
132 (void) close(m_obj->fd);
133 if (m_obj->data!=NULL) {
R. David Murray2a4b3fc2010-12-11 02:13:04 +0000134 if (m_obj->access != ACCESS_READ && m_obj->access != ACCESS_COPY)
135 msync(m_obj->data, m_obj->size, MS_SYNC);
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000136 munmap(m_obj->data, m_obj->size);
137 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000138#endif /* UNIX */
139
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000140 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000141}
142
143static PyObject *
Georg Brandl96a8c392006-05-29 21:04:52 +0000144mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000145{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000146#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000147 /* For each resource we maintain, we need to check
148 the value is valid, and if so, free the resource
149 and set the member value to an invalid value so
150 the dealloc does not attempt to resource clearing
151 again.
152 TODO - should we check for errors in the close operations???
153 */
154 if (self->data != NULL) {
155 UnmapViewOfFile(self->data);
156 self->data = NULL;
157 }
158 if (self->map_handle != NULL) {
159 CloseHandle(self->map_handle);
160 self->map_handle = NULL;
161 }
162 if (self->file_handle != INVALID_HANDLE_VALUE) {
163 CloseHandle(self->file_handle);
164 self->file_handle = INVALID_HANDLE_VALUE;
165 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000166#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000167
168#ifdef UNIX
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000169 if (0 <= self->fd)
170 (void) close(self->fd);
171 self->fd = -1;
172 if (self->data != NULL) {
173 munmap(self->data, self->size);
174 self->data = NULL;
175 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000176#endif
177
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000178 Py_INCREF(Py_None);
179 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000180}
181
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000182#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000183#define CHECK_VALID(err) \
184do { \
185 if (self->map_handle == NULL) { \
186 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
187 return err; \
188 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000189} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000190#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000191
192#ifdef UNIX
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000193#define CHECK_VALID(err) \
194do { \
195 if (self->data == NULL) { \
196 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
197 return err; \
198 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000199} while (0)
200#endif /* UNIX */
201
202static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000203mmap_read_byte_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000204 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000205{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000206 CHECK_VALID(NULL);
207 if (self->pos < self->size) {
208 char value = self->data[self->pos];
209 self->pos += 1;
210 return Py_BuildValue("c", value);
211 } else {
212 PyErr_SetString(PyExc_ValueError, "read byte out of range");
213 return NULL;
214 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000215}
216
217static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000218mmap_read_line_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000219 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000220{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000221 char *start = self->data+self->pos;
222 char *eof = self->data+self->size;
223 char *eol;
224 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000225
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000226 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000227
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000228 eol = memchr(start, '\n', self->size - self->pos);
229 if (!eol)
230 eol = eof;
231 else
232 ++eol; /* we're interested in the position after the
233 newline. */
234 result = PyString_FromStringAndSize(start, (eol - start));
235 self->pos += (eol - start);
236 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000237}
238
239static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000240mmap_read_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000241 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000242{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000243 Py_ssize_t num_bytes, n;
244 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000245
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000246 CHECK_VALID(NULL);
247 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
248 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000249
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000250 /* silently 'adjust' out-of-range requests */
251 assert(self->size >= self->pos);
252 n = self->size - self->pos;
253 /* The difference can overflow, only if self->size is greater than
254 * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed,
255 * because the mapped area and the returned string each need more
256 * than half of the addressable memory. So we clip the size, and let
257 * the code below raise MemoryError.
258 */
259 if (n < 0)
260 n = PY_SSIZE_T_MAX;
261 if (num_bytes < 0 || num_bytes > n) {
262 num_bytes = n;
263 }
264 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
265 self->pos += num_bytes;
266 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000267}
268
269static PyObject *
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000270mmap_gfind(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000271 PyObject *args,
272 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000273{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000274 Py_ssize_t start = self->pos;
275 Py_ssize_t end = self->size;
276 const char *needle;
277 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000278
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000279 CHECK_VALID(NULL);
280 if (!PyArg_ParseTuple(args, reverse ? "s#|nn:rfind" : "s#|nn:find",
281 &needle, &len, &start, &end)) {
282 return NULL;
283 } else {
284 const char *p, *start_p, *end_p;
285 int sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000286
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000287 if (start < 0)
288 start += self->size;
289 if (start < 0)
290 start = 0;
291 else if ((size_t)start > self->size)
292 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000293
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000294 if (end < 0)
295 end += self->size;
296 if (end < 0)
297 end = 0;
298 else if ((size_t)end > self->size)
299 end = self->size;
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000300
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000301 start_p = self->data + start;
302 end_p = self->data + end;
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000303
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000304 for (p = (reverse ? end_p - len : start_p);
305 (p >= start_p) && (p + len <= end_p); p += sign) {
306 Py_ssize_t i;
307 for (i = 0; i < len && needle[i] == p[i]; ++i)
308 /* nothing */;
309 if (i == len) {
310 return PyInt_FromSsize_t(p - self->data);
311 }
312 }
313 return PyInt_FromLong(-1);
314 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000315}
316
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000317static PyObject *
318mmap_find_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000319 PyObject *args)
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000320{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000321 return mmap_gfind(self, args, 0);
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000322}
323
324static PyObject *
325mmap_rfind_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000326 PyObject *args)
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000327{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000328 return mmap_gfind(self, args, 1);
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000329}
330
Tim Petersec0a5f02006-02-16 23:47:20 +0000331static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000332is_writeable(mmap_object *self)
333{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000334 if (self->access != ACCESS_READ)
335 return 1;
336 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
337 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000338}
339
Tim Petersec0a5f02006-02-16 23:47:20 +0000340static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000341is_resizeable(mmap_object *self)
342{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000343 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
344 return 1;
345 PyErr_Format(PyExc_TypeError,
346 "mmap can't resize a readonly or copy-on-write memory map.");
347 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000348}
349
350
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000351static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000352mmap_write_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000353 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000354{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000355 Py_ssize_t length;
356 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000357
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000358 CHECK_VALID(NULL);
359 if (!PyArg_ParseTuple(args, "s#:write", &data, &length))
360 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000361
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000362 if (!is_writeable(self))
363 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000364
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000365 if ((self->pos + length) > self->size) {
366 PyErr_SetString(PyExc_ValueError, "data out of range");
367 return NULL;
368 }
369 memcpy(self->data+self->pos, data, length);
370 self->pos = self->pos+length;
371 Py_INCREF(Py_None);
372 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000373}
374
375static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000376mmap_write_byte_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000377 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000378{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000379 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000380
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000381 CHECK_VALID(NULL);
382 if (!PyArg_ParseTuple(args, "c:write_byte", &value))
383 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000384
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000385 if (!is_writeable(self))
386 return NULL;
Hirokazu Yamamotof2dc8852009-02-28 10:31:54 +0000387
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000388 if (self->pos < self->size) {
389 *(self->data+self->pos) = value;
390 self->pos += 1;
391 Py_INCREF(Py_None);
392 return Py_None;
393 }
394 else {
395 PyErr_SetString(PyExc_ValueError, "write byte out of range");
396 return NULL;
397 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000398}
Tim Petersec0a5f02006-02-16 23:47:20 +0000399
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000400static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000401mmap_size_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000402 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000403{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000404 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000405
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000406#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000407 if (self->file_handle != INVALID_HANDLE_VALUE) {
408 DWORD low,high;
409 PY_LONG_LONG size;
410 low = GetFileSize(self->file_handle, &high);
411 if (low == INVALID_FILE_SIZE) {
412 /* It might be that the function appears to have failed,
413 when indeed its size equals INVALID_FILE_SIZE */
414 DWORD error = GetLastError();
415 if (error != NO_ERROR)
416 return PyErr_SetFromWindowsErr(error);
417 }
418 if (!high && low < LONG_MAX)
419 return PyInt_FromLong((long)low);
420 size = (((PY_LONG_LONG)high)<<32) + low;
421 return PyLong_FromLongLong(size);
422 } else {
423 return PyInt_FromSsize_t(self->size);
424 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000425#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000426
427#ifdef UNIX
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000428 {
429 struct stat buf;
430 if (-1 == fstat(self->fd, &buf)) {
431 PyErr_SetFromErrno(mmap_module_error);
432 return NULL;
433 }
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +0000434#ifdef HAVE_LARGEFILE_SUPPORT
435 return PyLong_FromLongLong(buf.st_size);
436#else
437 return PyInt_FromLong(buf.st_size);
438#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000439 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000440#endif /* UNIX */
441}
442
443/* This assumes that you want the entire file mapped,
444 / and when recreating the map will make the new file
445 / have the new size
446 /
447 / Is this really necessary? This could easily be done
448 / from python by just closing and re-opening with the
449 / new size?
450 */
451
452static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000453mmap_resize_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000454 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000455{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000456 Py_ssize_t new_size;
457 CHECK_VALID(NULL);
458 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
459 !is_resizeable(self)) {
460 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000461#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000462 } else {
463 DWORD dwErrCode = 0;
464 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
465 /* First, unmap the file view */
466 UnmapViewOfFile(self->data);
467 self->data = NULL;
468 /* Close the mapping object */
469 CloseHandle(self->map_handle);
470 self->map_handle = NULL;
471 /* Move to the desired EOF position */
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000472 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
473 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
474 off_hi = (DWORD)(self->offset >> 32);
475 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000476 SetFilePointer(self->file_handle,
477 newSizeLow, &newSizeHigh, FILE_BEGIN);
478 /* Change the size of the file */
479 SetEndOfFile(self->file_handle);
480 /* Create another mapping object and remap the file view */
481 self->map_handle = CreateFileMapping(
482 self->file_handle,
483 NULL,
484 PAGE_READWRITE,
485 0,
486 0,
487 self->tagname);
488 if (self->map_handle != NULL) {
489 self->data = (char *) MapViewOfFile(self->map_handle,
490 FILE_MAP_WRITE,
491 off_hi,
492 off_lo,
493 new_size);
494 if (self->data != NULL) {
495 self->size = new_size;
496 Py_INCREF(Py_None);
497 return Py_None;
498 } else {
499 dwErrCode = GetLastError();
500 CloseHandle(self->map_handle);
501 self->map_handle = NULL;
502 }
503 } else {
504 dwErrCode = GetLastError();
505 }
506 PyErr_SetFromWindowsErr(dwErrCode);
507 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000508#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000509
510#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000511#ifndef HAVE_MREMAP
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000512 } else {
513 PyErr_SetString(PyExc_SystemError,
514 "mmap: resizing not available--no mremap()");
515 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000516#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000517 } else {
518 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000519
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000520 if (ftruncate(self->fd, self->offset + new_size) == -1) {
521 PyErr_SetFromErrno(mmap_module_error);
522 return NULL;
523 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000524
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000525#ifdef MREMAP_MAYMOVE
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000526 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000527#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000528 #if defined(__NetBSD__)
529 newmap = mremap(self->data, self->size, self->data, new_size, 0);
530 #else
531 newmap = mremap(self->data, self->size, new_size, 0);
532 #endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000533#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000534 if (newmap == (void *)-1)
535 {
536 PyErr_SetFromErrno(mmap_module_error);
537 return NULL;
538 }
539 self->data = newmap;
540 self->size = new_size;
541 Py_INCREF(Py_None);
542 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000543#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000544#endif /* UNIX */
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000545 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000546}
547
548static PyObject *
Georg Brandl96a8c392006-05-29 21:04:52 +0000549mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000550{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000551 CHECK_VALID(NULL);
552 return PyInt_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000553}
554
555static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000556mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000557{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000558 Py_ssize_t offset = 0;
559 Py_ssize_t size = self->size;
560 CHECK_VALID(NULL);
561 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
562 return NULL;
563 if ((size_t)(offset + size) > self->size) {
564 PyErr_SetString(PyExc_ValueError, "flush values out of range");
565 return NULL;
566 }
R. David Murray2a4b3fc2010-12-11 02:13:04 +0000567
568 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
569 return PyLong_FromLong(0);
570
Neal Norwitz448654f2008-01-27 07:36:03 +0000571#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000572 return PyInt_FromLong((long) FlushViewOfFile(self->data+offset, size));
Neal Norwitz448654f2008-01-27 07:36:03 +0000573#elif defined(UNIX)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000574 /* XXX semantics of return value? */
575 /* XXX flags for msync? */
576 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
577 PyErr_SetFromErrno(mmap_module_error);
578 return NULL;
579 }
580 return PyInt_FromLong(0);
Neal Norwitz448654f2008-01-27 07:36:03 +0000581#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000582 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
583 return NULL;
Neal Norwitz448654f2008-01-27 07:36:03 +0000584#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000585}
586
587static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000588mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000589{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000590 Py_ssize_t dist;
591 int how=0;
592 CHECK_VALID(NULL);
593 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
594 return NULL;
595 else {
596 size_t where;
597 switch (how) {
598 case 0: /* relative to start */
599 if (dist < 0)
600 goto onoutofrange;
601 where = dist;
602 break;
603 case 1: /* relative to current position */
604 if ((Py_ssize_t)self->pos + dist < 0)
605 goto onoutofrange;
606 where = self->pos + dist;
607 break;
608 case 2: /* relative to end */
609 if ((Py_ssize_t)self->size + dist < 0)
610 goto onoutofrange;
611 where = self->size + dist;
612 break;
613 default:
614 PyErr_SetString(PyExc_ValueError, "unknown seek type");
615 return NULL;
616 }
617 if (where > self->size)
618 goto onoutofrange;
619 self->pos = where;
620 Py_INCREF(Py_None);
621 return Py_None;
622 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000623
Tim Peters5ebfd362001-11-13 23:11:19 +0000624 onoutofrange:
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000625 PyErr_SetString(PyExc_ValueError, "seek out of range");
626 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000627}
628
629static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000630mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000631{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000632 unsigned long dest, src, cnt;
633 CHECK_VALID(NULL);
634 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
635 !is_writeable(self)) {
636 return NULL;
637 } else {
638 /* bounds check the values */
639 if (cnt < 0 || (cnt + dest) < cnt || (cnt + src) < cnt ||
640 src < 0 || src > self->size || (src + cnt) > self->size ||
641 dest < 0 || dest > self->size || (dest + cnt) > self->size) {
642 PyErr_SetString(PyExc_ValueError,
643 "source, destination, or count out of range");
644 return NULL;
645 }
646 memmove(self->data+dest, self->data+src, cnt);
647 Py_INCREF(Py_None);
648 return Py_None;
649 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000650}
651
652static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000653 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
654 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
655 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
656 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
657 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
658 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
659 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
660 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
661 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
662 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
663 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
664 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
665 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
666 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
667 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000668};
669
670/* Functions for treating an mmap'ed file as a buffer */
671
Martin v. Löwis18e16552006-02-15 17:27:45 +0000672static Py_ssize_t
673mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000674{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000675 CHECK_VALID(-1);
676 if (index != 0) {
677 PyErr_SetString(PyExc_SystemError,
678 "Accessing non-existent mmap segment");
679 return -1;
680 }
681 *ptr = self->data;
682 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000683}
684
Martin v. Löwis18e16552006-02-15 17:27:45 +0000685static Py_ssize_t
686mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Tim Petersec0a5f02006-02-16 23:47:20 +0000687{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000688 CHECK_VALID(-1);
689 if (index != 0) {
690 PyErr_SetString(PyExc_SystemError,
691 "Accessing non-existent mmap segment");
692 return -1;
693 }
694 if (!is_writeable(self))
695 return -1;
696 *ptr = self->data;
697 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000698}
699
Martin v. Löwis18e16552006-02-15 17:27:45 +0000700static Py_ssize_t
701mmap_buffer_getsegcount(mmap_object *self, Py_ssize_t *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000702{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000703 CHECK_VALID(-1);
704 if (lenp)
705 *lenp = self->size;
706 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000707}
708
Martin v. Löwis18e16552006-02-15 17:27:45 +0000709static Py_ssize_t
710mmap_buffer_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000711{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000712 if (index != 0) {
713 PyErr_SetString(PyExc_SystemError,
714 "accessing non-existent buffer segment");
715 return -1;
716 }
717 *ptr = (const char *)self->data;
718 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000719}
720
Martin v. Löwis18e16552006-02-15 17:27:45 +0000721static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000722mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000723{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000724 CHECK_VALID(-1);
725 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000726}
727
728static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000729mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000730{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000731 CHECK_VALID(NULL);
732 if (i < 0 || (size_t)i >= self->size) {
733 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
734 return NULL;
735 }
736 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000737}
738
739static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000740mmap_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000741{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000742 CHECK_VALID(NULL);
743 if (ilow < 0)
744 ilow = 0;
745 else if ((size_t)ilow > self->size)
746 ilow = self->size;
747 if (ihigh < 0)
748 ihigh = 0;
749 if (ihigh < ilow)
750 ihigh = ilow;
751 else if ((size_t)ihigh > self->size)
752 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000753
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000754 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000755}
756
757static PyObject *
Thomas Wouters3ccec682007-08-28 15:28:19 +0000758mmap_subscript(mmap_object *self, PyObject *item)
759{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000760 CHECK_VALID(NULL);
761 if (PyIndex_Check(item)) {
762 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
763 if (i == -1 && PyErr_Occurred())
764 return NULL;
765 if (i < 0)
766 i += self->size;
767 if (i < 0 || (size_t)i >= self->size) {
768 PyErr_SetString(PyExc_IndexError,
769 "mmap index out of range");
770 return NULL;
771 }
772 return PyString_FromStringAndSize(self->data + i, 1);
773 }
774 else if (PySlice_Check(item)) {
775 Py_ssize_t start, stop, step, slicelen;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000776
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000777 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
778 &start, &stop, &step, &slicelen) < 0) {
779 return NULL;
780 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000781
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000782 if (slicelen <= 0)
783 return PyString_FromStringAndSize("", 0);
784 else if (step == 1)
785 return PyString_FromStringAndSize(self->data + start,
786 slicelen);
787 else {
788 char *result_buf = (char *)PyMem_Malloc(slicelen);
789 Py_ssize_t cur, i;
790 PyObject *result;
791
792 if (result_buf == NULL)
793 return PyErr_NoMemory();
794 for (cur = start, i = 0; i < slicelen;
795 cur += step, i++) {
796 result_buf[i] = self->data[cur];
797 }
798 result = PyString_FromStringAndSize(result_buf,
799 slicelen);
800 PyMem_Free(result_buf);
801 return result;
802 }
803 }
804 else {
805 PyErr_SetString(PyExc_TypeError,
806 "mmap indices must be integers");
807 return NULL;
808 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000809}
810
811static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000812mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000813{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000814 CHECK_VALID(NULL);
815 PyErr_SetString(PyExc_SystemError,
816 "mmaps don't support concatenation");
817 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000818}
819
820static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000821mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000822{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000823 CHECK_VALID(NULL);
824 PyErr_SetString(PyExc_SystemError,
825 "mmaps don't support repeat operation");
826 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000827}
828
829static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000830mmap_ass_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000831{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000832 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000833
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000834 CHECK_VALID(-1);
835 if (ilow < 0)
836 ilow = 0;
837 else if ((size_t)ilow > self->size)
838 ilow = self->size;
839 if (ihigh < 0)
840 ihigh = 0;
841 if (ihigh < ilow)
842 ihigh = ilow;
843 else if ((size_t)ihigh > self->size)
844 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000845
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000846 if (v == NULL) {
847 PyErr_SetString(PyExc_TypeError,
848 "mmap object doesn't support slice deletion");
849 return -1;
850 }
851 if (! (PyString_Check(v)) ) {
852 PyErr_SetString(PyExc_IndexError,
853 "mmap slice assignment must be a string");
854 return -1;
855 }
856 if (PyString_Size(v) != (ihigh - ilow)) {
857 PyErr_SetString(PyExc_IndexError,
858 "mmap slice assignment is wrong size");
859 return -1;
860 }
861 if (!is_writeable(self))
862 return -1;
863 buf = PyString_AsString(v);
864 memcpy(self->data + ilow, buf, ihigh-ilow);
865 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000866}
867
868static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000869mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000870{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000871 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000872
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000873 CHECK_VALID(-1);
874 if (i < 0 || (size_t)i >= self->size) {
875 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
876 return -1;
877 }
878 if (v == NULL) {
879 PyErr_SetString(PyExc_TypeError,
880 "mmap object doesn't support item deletion");
881 return -1;
882 }
883 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
884 PyErr_SetString(PyExc_IndexError,
885 "mmap assignment must be single-character string");
886 return -1;
887 }
888 if (!is_writeable(self))
889 return -1;
890 buf = PyString_AsString(v);
891 self->data[i] = buf[0];
892 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000893}
894
Thomas Wouters3ccec682007-08-28 15:28:19 +0000895static int
896mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
897{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000898 CHECK_VALID(-1);
Thomas Wouters3ccec682007-08-28 15:28:19 +0000899
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000900 if (PyIndex_Check(item)) {
901 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
902 const char *buf;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000903
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000904 if (i == -1 && PyErr_Occurred())
905 return -1;
906 if (i < 0)
907 i += self->size;
908 if (i < 0 || (size_t)i >= self->size) {
909 PyErr_SetString(PyExc_IndexError,
910 "mmap index out of range");
911 return -1;
912 }
913 if (value == NULL) {
914 PyErr_SetString(PyExc_TypeError,
915 "mmap object doesn't support item deletion");
916 return -1;
917 }
918 if (!PyString_Check(value) || PyString_Size(value) != 1) {
919 PyErr_SetString(PyExc_IndexError,
920 "mmap assignment must be single-character string");
921 return -1;
922 }
923 if (!is_writeable(self))
924 return -1;
925 buf = PyString_AsString(value);
926 self->data[i] = buf[0];
927 return 0;
928 }
929 else if (PySlice_Check(item)) {
930 Py_ssize_t start, stop, step, slicelen;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000931
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000932 if (PySlice_GetIndicesEx((PySliceObject *)item,
933 self->size, &start, &stop,
934 &step, &slicelen) < 0) {
935 return -1;
936 }
937 if (value == NULL) {
938 PyErr_SetString(PyExc_TypeError,
939 "mmap object doesn't support slice deletion");
940 return -1;
941 }
942 if (!PyString_Check(value)) {
943 PyErr_SetString(PyExc_IndexError,
944 "mmap slice assignment must be a string");
945 return -1;
946 }
947 if (PyString_Size(value) != slicelen) {
948 PyErr_SetString(PyExc_IndexError,
949 "mmap slice assignment is wrong size");
950 return -1;
951 }
952 if (!is_writeable(self))
953 return -1;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000954
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000955 if (slicelen == 0)
956 return 0;
957 else if (step == 1) {
958 const char *buf = PyString_AsString(value);
959
960 if (buf == NULL)
961 return -1;
962 memcpy(self->data + start, buf, slicelen);
963 return 0;
964 }
965 else {
966 Py_ssize_t cur, i;
967 const char *buf = PyString_AsString(value);
968
969 if (buf == NULL)
970 return -1;
971 for (cur = start, i = 0; i < slicelen;
972 cur += step, i++) {
973 self->data[cur] = buf[i];
974 }
975 return 0;
976 }
977 }
978 else {
979 PyErr_SetString(PyExc_TypeError,
980 "mmap indices must be integer");
981 return -1;
982 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000983}
984
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000985static PySequenceMethods mmap_as_sequence = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000986 (lenfunc)mmap_length, /*sq_length*/
987 (binaryfunc)mmap_concat, /*sq_concat*/
988 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
989 (ssizeargfunc)mmap_item, /*sq_item*/
990 (ssizessizeargfunc)mmap_slice, /*sq_slice*/
991 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
992 (ssizessizeobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000993};
994
Thomas Wouters3ccec682007-08-28 15:28:19 +0000995static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000996 (lenfunc)mmap_length,
997 (binaryfunc)mmap_subscript,
998 (objobjargproc)mmap_ass_subscript,
Thomas Wouters3ccec682007-08-28 15:28:19 +0000999};
1000
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001001static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001002 (readbufferproc)mmap_buffer_getreadbuf,
1003 (writebufferproc)mmap_buffer_getwritebuf,
1004 (segcountproc)mmap_buffer_getsegcount,
1005 (charbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001006};
1007
Georg Brandl845c4032008-01-21 14:16:46 +00001008static PyObject *
1009new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
1010
Georg Brandlef928022008-01-20 14:50:05 +00001011PyDoc_STRVAR(mmap_doc,
1012"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
1013\n\
1014Maps length bytes from the file specified by the file handle fileno,\n\
1015and returns a mmap object. If length is larger than the current size\n\
1016of the file, the file is extended to contain length bytes. If length\n\
1017is 0, the maximum length of the map is the current size of the file,\n\
1018except that if the file is empty Windows raises an exception (you cannot\n\
1019create an empty mapping on Windows).\n\
1020\n\
1021Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
1022\n\
1023Maps length bytes from the file specified by the file descriptor fileno,\n\
1024and returns a mmap object. If length is 0, the maximum length of the map\n\
1025will be the current size of the file when mmap is called.\n\
1026flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1027private copy-on-write mapping, so changes to the contents of the mmap\n\
Thomas Heller66260992008-08-19 17:47:13 +00001028object will be private to this process, and MAP_SHARED creates a mapping\n\
Georg Brandlef928022008-01-20 14:50:05 +00001029that's shared with all other processes mapping the same areas of the file.\n\
1030The default value is MAP_SHARED.\n\
1031\n\
1032To map anonymous memory, pass -1 as the fileno (both versions).");
1033
1034
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001035static PyTypeObject mmap_object_type = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001036 PyVarObject_HEAD_INIT(NULL, 0)
1037 "mmap.mmap", /* tp_name */
1038 sizeof(mmap_object), /* tp_size */
1039 0, /* tp_itemsize */
1040 /* methods */
1041 (destructor) mmap_object_dealloc, /* tp_dealloc */
1042 0, /* tp_print */
1043 0, /* tp_getattr */
1044 0, /* tp_setattr */
1045 0, /* tp_compare */
1046 0, /* tp_repr */
1047 0, /* tp_as_number */
1048 &mmap_as_sequence, /*tp_as_sequence*/
1049 &mmap_as_mapping, /*tp_as_mapping*/
1050 0, /*tp_hash*/
1051 0, /*tp_call*/
1052 0, /*tp_str*/
1053 PyObject_GenericGetAttr, /*tp_getattro*/
1054 0, /*tp_setattro*/
1055 &mmap_as_buffer, /*tp_as_buffer*/
1056 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
1057 mmap_doc, /*tp_doc*/
1058 0, /* tp_traverse */
1059 0, /* tp_clear */
1060 0, /* tp_richcompare */
1061 0, /* tp_weaklistoffset */
1062 0, /* tp_iter */
1063 0, /* tp_iternext */
1064 mmap_object_methods, /* tp_methods */
1065 0, /* tp_members */
1066 0, /* tp_getset */
1067 0, /* tp_base */
1068 0, /* tp_dict */
1069 0, /* tp_descr_get */
1070 0, /* tp_descr_set */
1071 0, /* tp_dictoffset */
1072 0, /* tp_init */
1073 PyType_GenericAlloc, /* tp_alloc */
1074 new_mmap_object, /* tp_new */
1075 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001076};
1077
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001078
1079/* extract the map size from the given PyObject
1080
Thomas Wouters7e474022000-07-16 12:04:32 +00001081 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001082 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001083static Py_ssize_t
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001084_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001085{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001086 if (o == NULL)
1087 return 0;
1088 if (PyIndex_Check(o)) {
1089 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1090 if (i==-1 && PyErr_Occurred())
1091 return -1;
1092 if (i < 0) {
1093 PyErr_Format(PyExc_OverflowError,
1094 "memory mapped %s must be positive",
1095 param);
1096 return -1;
1097 }
1098 return i;
1099 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001100
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001101 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1102 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001103}
1104
Tim Petersec0a5f02006-02-16 23:47:20 +00001105#ifdef UNIX
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001106#ifdef HAVE_LARGEFILE_SUPPORT
1107#define _Py_PARSE_OFF_T "L"
1108#else
1109#define _Py_PARSE_OFF_T "l"
1110#endif
1111
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001112static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001113new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001114{
Neal Norwitzb5673922002-09-05 21:48:07 +00001115#ifdef HAVE_FSTAT
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001116 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001117#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001118 mmap_object *m_obj;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001119 PyObject *map_size_obj = NULL;
1120 Py_ssize_t map_size;
1121 off_t offset = 0;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001122 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1123 int devzero = -1;
1124 int access = (int)ACCESS_DEFAULT;
1125 static char *keywords[] = {"fileno", "length",
1126 "flags", "prot",
1127 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001128
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001129 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords,
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001130 &fd, &map_size_obj, &flags, &prot,
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001131 &access, &offset))
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001132 return NULL;
1133 map_size = _GetMapSize(map_size_obj, "size");
1134 if (map_size < 0)
1135 return NULL;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001136 if (offset < 0) {
1137 PyErr_SetString(PyExc_OverflowError,
1138 "memory mapped offset must be positive");
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001139 return NULL;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001140 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001141
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001142 if ((access != (int)ACCESS_DEFAULT) &&
1143 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1144 return PyErr_Format(PyExc_ValueError,
1145 "mmap can't specify both access and flags, prot.");
1146 switch ((access_mode)access) {
1147 case ACCESS_READ:
1148 flags = MAP_SHARED;
1149 prot = PROT_READ;
1150 break;
1151 case ACCESS_WRITE:
1152 flags = MAP_SHARED;
1153 prot = PROT_READ | PROT_WRITE;
1154 break;
1155 case ACCESS_COPY:
1156 flags = MAP_PRIVATE;
1157 prot = PROT_READ | PROT_WRITE;
1158 break;
1159 case ACCESS_DEFAULT:
Antoine Pitroud6f3a3e2011-03-06 02:03:34 +01001160 /* map prot to access type */
1161 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1162 /* ACCESS_DEFAULT */
1163 }
1164 else if (prot & PROT_WRITE) {
1165 access = ACCESS_WRITE;
1166 }
1167 else {
1168 access = ACCESS_READ;
1169 }
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001170 break;
1171 default:
1172 return PyErr_Format(PyExc_ValueError,
1173 "mmap invalid access parameter.");
1174 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001175
Victor Stinner112d48a2011-05-03 14:36:36 +02001176#ifdef __APPLE__
1177 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1178 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1179 if (fd != -1)
1180 (void)fcntl(fd, F_FULLFSYNC);
1181#endif
Neal Norwitzb5673922002-09-05 21:48:07 +00001182#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001183# ifdef __VMS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001184 /* on OpenVMS we must ensure that all bytes are written to the file */
1185 if (fd != -1) {
1186 fsync(fd);
1187 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001188# endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001189 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1190 if (map_size == 0) {
Jesus Cea8b54d6d2012-09-10 00:22:39 +02001191 if (st.st_size == 0) {
1192 PyErr_SetString(PyExc_ValueError,
1193 "cannot mmap an empty file");
1194 return NULL;
1195 }
Antoine Pitrou8a0eede2011-01-20 21:20:18 +00001196 if (offset >= st.st_size) {
1197 PyErr_SetString(PyExc_ValueError,
1198 "mmap offset is greater than file size");
1199 return NULL;
1200 }
Richard Oudkerk36b9d412013-02-13 12:05:14 +00001201 if (st.st_size - offset > PY_SSIZE_T_MAX) {
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001202 PyErr_SetString(PyExc_ValueError,
1203 "mmap length is too large");
Richard Oudkerk36b9d412013-02-13 12:05:14 +00001204 return NULL;
1205 }
1206 map_size = (Py_ssize_t) (st.st_size - offset);
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001207 } else if (offset + (size_t)map_size > st.st_size) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001208 PyErr_SetString(PyExc_ValueError,
1209 "mmap length is greater than file size");
1210 return NULL;
1211 }
1212 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001213#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001214 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1215 if (m_obj == NULL) {return NULL;}
1216 m_obj->data = NULL;
1217 m_obj->size = (size_t) map_size;
1218 m_obj->pos = (size_t) 0;
1219 m_obj->offset = offset;
1220 if (fd == -1) {
1221 m_obj->fd = -1;
1222 /* Assume the caller wants to map anonymous memory.
1223 This is the same behaviour as Windows. mmap.mmap(-1, size)
1224 on both Windows and Unix map anonymous memory.
1225 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001226#ifdef MAP_ANONYMOUS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001227 /* BSD way to map anonymous memory */
1228 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001229#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001230 /* SVR4 method to map anonymous memory is to open /dev/zero */
1231 fd = devzero = open("/dev/zero", O_RDWR);
1232 if (devzero == -1) {
1233 Py_DECREF(m_obj);
1234 PyErr_SetFromErrno(mmap_module_error);
1235 return NULL;
1236 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001237#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001238 } else {
1239 m_obj->fd = dup(fd);
1240 if (m_obj->fd == -1) {
1241 Py_DECREF(m_obj);
1242 PyErr_SetFromErrno(mmap_module_error);
1243 return NULL;
1244 }
1245 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001246
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001247 m_obj->data = mmap(NULL, map_size,
1248 prot, flags,
1249 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001250
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001251 if (devzero != -1) {
1252 close(devzero);
1253 }
1254
1255 if (m_obj->data == (char *)-1) {
1256 m_obj->data = NULL;
1257 Py_DECREF(m_obj);
1258 PyErr_SetFromErrno(mmap_module_error);
1259 return NULL;
1260 }
1261 m_obj->access = (access_mode)access;
1262 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001263}
1264#endif /* UNIX */
1265
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001266#ifdef MS_WINDOWS
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001267
1268/* A note on sizes and offsets: while the actual map size must hold in a
1269 Py_ssize_t, both the total file size and the start offset can be longer
1270 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1271*/
1272
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001273static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001274new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001275{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001276 mmap_object *m_obj;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001277 PyObject *map_size_obj = NULL;
1278 Py_ssize_t map_size;
1279 PY_LONG_LONG offset = 0, size;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001280 DWORD off_hi; /* upper 32 bits of offset */
1281 DWORD off_lo; /* lower 32 bits of offset */
1282 DWORD size_hi; /* upper 32 bits of size */
1283 DWORD size_lo; /* lower 32 bits of size */
1284 char *tagname = "";
1285 DWORD dwErr = 0;
1286 int fileno;
1287 HANDLE fh = 0;
1288 int access = (access_mode)ACCESS_DEFAULT;
1289 DWORD flProtect, dwDesiredAccess;
1290 static char *keywords[] = { "fileno", "length",
1291 "tagname",
1292 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001293
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001294 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords,
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001295 &fileno, &map_size_obj,
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001296 &tagname, &access, &offset)) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001297 return NULL;
1298 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001299
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001300 switch((access_mode)access) {
1301 case ACCESS_READ:
1302 flProtect = PAGE_READONLY;
1303 dwDesiredAccess = FILE_MAP_READ;
1304 break;
1305 case ACCESS_DEFAULT: case ACCESS_WRITE:
1306 flProtect = PAGE_READWRITE;
1307 dwDesiredAccess = FILE_MAP_WRITE;
1308 break;
1309 case ACCESS_COPY:
1310 flProtect = PAGE_WRITECOPY;
1311 dwDesiredAccess = FILE_MAP_COPY;
1312 break;
1313 default:
1314 return PyErr_Format(PyExc_ValueError,
1315 "mmap invalid access parameter.");
1316 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001317
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001318 map_size = _GetMapSize(map_size_obj, "size");
1319 if (map_size < 0)
1320 return NULL;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001321 if (offset < 0) {
1322 PyErr_SetString(PyExc_OverflowError,
1323 "memory mapped offset must be positive");
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001324 return NULL;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001325 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001326
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001327 /* assume -1 and 0 both mean invalid filedescriptor
1328 to 'anonymously' map memory.
1329 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1330 XXX: Should this code be added?
1331 if (fileno == 0)
1332 PyErr_Warn(PyExc_DeprecationWarning,
1333 "don't use 0 for anonymous memory");
1334 */
1335 if (fileno != -1 && fileno != 0) {
Brian Curtinba6c08e2010-08-01 15:47:53 +00001336 /* Ensure that fileno is within the CRT's valid range */
1337 if (_PyVerify_fd(fileno) == 0) {
1338 PyErr_SetFromErrno(mmap_module_error);
1339 return NULL;
1340 }
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001341 fh = (HANDLE)_get_osfhandle(fileno);
1342 if (fh==(HANDLE)-1) {
1343 PyErr_SetFromErrno(mmap_module_error);
1344 return NULL;
1345 }
1346 /* Win9x appears to need us seeked to zero */
1347 lseek(fileno, 0, SEEK_SET);
1348 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001349
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001350 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1351 if (m_obj == NULL)
1352 return NULL;
1353 /* Set every field to an invalid marker, so we can safely
1354 destruct the object in the face of failure */
1355 m_obj->data = NULL;
1356 m_obj->file_handle = INVALID_HANDLE_VALUE;
1357 m_obj->map_handle = NULL;
1358 m_obj->tagname = NULL;
1359 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001360
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001361 if (fh) {
1362 /* It is necessary to duplicate the handle, so the
1363 Python code can close it on us */
1364 if (!DuplicateHandle(
1365 GetCurrentProcess(), /* source process handle */
1366 fh, /* handle to be duplicated */
1367 GetCurrentProcess(), /* target proc handle */
1368 (LPHANDLE)&m_obj->file_handle, /* result */
1369 0, /* access - ignored due to options value */
1370 FALSE, /* inherited by child processes? */
1371 DUPLICATE_SAME_ACCESS)) { /* options */
1372 dwErr = GetLastError();
1373 Py_DECREF(m_obj);
1374 PyErr_SetFromWindowsErr(dwErr);
1375 return NULL;
1376 }
1377 if (!map_size) {
1378 DWORD low,high;
1379 low = GetFileSize(fh, &high);
1380 /* low might just happen to have the value INVALID_FILE_SIZE;
1381 so we need to check the last error also. */
1382 if (low == INVALID_FILE_SIZE &&
1383 (dwErr = GetLastError()) != NO_ERROR) {
1384 Py_DECREF(m_obj);
1385 return PyErr_SetFromWindowsErr(dwErr);
1386 }
1387
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001388 size = (((PY_LONG_LONG) high) << 32) + low;
Jesus Cea20f0ea12012-09-10 22:45:47 +02001389 if (size == 0) {
1390 PyErr_SetString(PyExc_ValueError,
1391 "cannot mmap an empty file");
Jesus Cea8e03b4c2012-09-10 22:57:34 +02001392 Py_DECREF(m_obj);
Jesus Cea20f0ea12012-09-10 22:45:47 +02001393 return NULL;
1394 }
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001395 if (offset >= size) {
Antoine Pitrou8a0eede2011-01-20 21:20:18 +00001396 PyErr_SetString(PyExc_ValueError,
1397 "mmap offset is greater than file size");
1398 Py_DECREF(m_obj);
1399 return NULL;
1400 }
Richard Oudkerk36b9d412013-02-13 12:05:14 +00001401 if (size - offset > PY_SSIZE_T_MAX) {
1402 PyErr_SetString(PyExc_ValueError,
1403 "mmap length is too large");
1404 Py_DECREF(m_obj);
1405 return NULL;
1406 }
1407 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001408 } else {
1409 m_obj->size = map_size;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001410 size = offset + map_size;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001411 }
1412 }
1413 else {
1414 m_obj->size = map_size;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001415 size = offset + map_size;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001416 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001417
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001418 /* set the initial position */
1419 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001420
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001421 /* set the tag name */
1422 if (tagname != NULL && *tagname != '\0') {
1423 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1424 if (m_obj->tagname == NULL) {
1425 PyErr_NoMemory();
1426 Py_DECREF(m_obj);
1427 return NULL;
1428 }
1429 strcpy(m_obj->tagname, tagname);
1430 }
1431 else
1432 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001433
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001434 m_obj->access = (access_mode)access;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001435 size_hi = (DWORD)(size >> 32);
1436 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001437 off_hi = (DWORD)(offset >> 32);
1438 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001439 /* For files, it would be sufficient to pass 0 as size.
1440 For anonymous maps, we have to pass the size explicitly. */
1441 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1442 NULL,
1443 flProtect,
1444 size_hi,
1445 size_lo,
1446 m_obj->tagname);
1447 if (m_obj->map_handle != NULL) {
1448 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1449 dwDesiredAccess,
1450 off_hi,
1451 off_lo,
1452 m_obj->size);
1453 if (m_obj->data != NULL)
1454 return (PyObject *)m_obj;
1455 else {
1456 dwErr = GetLastError();
1457 CloseHandle(m_obj->map_handle);
1458 m_obj->map_handle = NULL;
1459 }
1460 } else
1461 dwErr = GetLastError();
1462 Py_DECREF(m_obj);
1463 PyErr_SetFromWindowsErr(dwErr);
1464 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001465}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001466#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001467
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001468static void
1469setint(PyObject *d, const char *name, long value)
1470{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001471 PyObject *o = PyInt_FromLong(value);
1472 if (o && PyDict_SetItemString(d, name, o) == 0) {
1473 Py_DECREF(o);
1474 }
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001475}
1476
Mark Hammond62b1ab12002-07-23 06:31:15 +00001477PyMODINIT_FUNC
Georg Brandl845c4032008-01-21 14:16:46 +00001478initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001479{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001480 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001481
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001482 if (PyType_Ready(&mmap_object_type) < 0)
1483 return;
Tim Peters2caf8df2001-01-14 05:05:51 +00001484
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001485 module = Py_InitModule("mmap", NULL);
1486 if (module == NULL)
1487 return;
1488 dict = PyModule_GetDict(module);
1489 if (!dict)
1490 return;
1491 mmap_module_error = PyErr_NewException("mmap.error",
1492 PyExc_EnvironmentError , NULL);
1493 if (mmap_module_error == NULL)
1494 return;
1495 PyDict_SetItemString(dict, "error", mmap_module_error);
1496 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001497#ifdef PROT_EXEC
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001498 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001499#endif
1500#ifdef PROT_READ
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001501 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001502#endif
1503#ifdef PROT_WRITE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001504 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001505#endif
1506
1507#ifdef MAP_SHARED
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001508 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001509#endif
1510#ifdef MAP_PRIVATE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001511 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001512#endif
1513#ifdef MAP_DENYWRITE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001514 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001515#endif
1516#ifdef MAP_EXECUTABLE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001517 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001518#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001519#ifdef MAP_ANONYMOUS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001520 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1521 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001522#endif
1523
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001524 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001525
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001526 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001527
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001528 setint(dict, "ACCESS_READ", ACCESS_READ);
1529 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1530 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Tim Peters5ebfd362001-11-13 23:11:19 +00001531}