blob: 1ebccdfa82a5820655a61450fa268d274a8ec0c2 [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
Benjamin Petersond7a4f9e2015-08-02 12:15:30 -070026# ifdef HAVE_FCNTL_H
Victor Stinner112d48a2011-05-03 14:36:36 +020027# include <fcntl.h>
Benjamin Petersond7a4f9e2015-08-02 12:15:30 -070028# endif /* HAVE_FCNTL_H */
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
Serhiy Storchakacbee9722014-08-19 17:03:42 +0300652#ifdef MS_WINDOWS
653static PyObject *
654mmap__sizeof__method(mmap_object *self, void *unused)
655{
656 Py_ssize_t res;
657
Serhiy Storchakac06a6d02015-12-19 20:07:48 +0200658 res = _PyObject_SIZE(Py_TYPE(self));
Serhiy Storchakacbee9722014-08-19 17:03:42 +0300659 if (self->tagname)
660 res += strlen(self->tagname) + 1;
661 return PyLong_FromSsize_t(res);
662}
663#endif
664
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000665static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000666 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
667 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
668 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
669 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
670 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
671 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
672 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
673 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
674 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
675 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
676 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
677 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
678 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
679 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Serhiy Storchakacbee9722014-08-19 17:03:42 +0300680#ifdef MS_WINDOWS
681 {"__sizeof__", (PyCFunction) mmap__sizeof__method, METH_NOARGS},
682#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000683 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000684};
685
686/* Functions for treating an mmap'ed file as a buffer */
687
Martin v. Löwis18e16552006-02-15 17:27:45 +0000688static Py_ssize_t
689mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000690{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000691 CHECK_VALID(-1);
692 if (index != 0) {
693 PyErr_SetString(PyExc_SystemError,
694 "Accessing non-existent mmap segment");
695 return -1;
696 }
697 *ptr = self->data;
698 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000699}
700
Martin v. Löwis18e16552006-02-15 17:27:45 +0000701static Py_ssize_t
702mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Tim Petersec0a5f02006-02-16 23:47:20 +0000703{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000704 CHECK_VALID(-1);
705 if (index != 0) {
706 PyErr_SetString(PyExc_SystemError,
707 "Accessing non-existent mmap segment");
708 return -1;
709 }
710 if (!is_writeable(self))
711 return -1;
712 *ptr = self->data;
713 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000714}
715
Martin v. Löwis18e16552006-02-15 17:27:45 +0000716static Py_ssize_t
717mmap_buffer_getsegcount(mmap_object *self, Py_ssize_t *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000718{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000719 CHECK_VALID(-1);
720 if (lenp)
721 *lenp = self->size;
722 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000723}
724
Martin v. Löwis18e16552006-02-15 17:27:45 +0000725static Py_ssize_t
726mmap_buffer_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000727{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000728 if (index != 0) {
729 PyErr_SetString(PyExc_SystemError,
730 "accessing non-existent buffer segment");
731 return -1;
732 }
733 *ptr = (const char *)self->data;
734 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000735}
736
Martin v. Löwis18e16552006-02-15 17:27:45 +0000737static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000738mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000739{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000740 CHECK_VALID(-1);
741 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000742}
743
744static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000745mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000746{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000747 CHECK_VALID(NULL);
748 if (i < 0 || (size_t)i >= self->size) {
749 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
750 return NULL;
751 }
752 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000753}
754
755static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000756mmap_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000757{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000758 CHECK_VALID(NULL);
759 if (ilow < 0)
760 ilow = 0;
761 else if ((size_t)ilow > self->size)
762 ilow = self->size;
763 if (ihigh < 0)
764 ihigh = 0;
765 if (ihigh < ilow)
766 ihigh = ilow;
767 else if ((size_t)ihigh > self->size)
768 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000769
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000770 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000771}
772
773static PyObject *
Thomas Wouters3ccec682007-08-28 15:28:19 +0000774mmap_subscript(mmap_object *self, PyObject *item)
775{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000776 CHECK_VALID(NULL);
777 if (PyIndex_Check(item)) {
778 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
779 if (i == -1 && PyErr_Occurred())
780 return NULL;
781 if (i < 0)
782 i += self->size;
783 if (i < 0 || (size_t)i >= self->size) {
784 PyErr_SetString(PyExc_IndexError,
785 "mmap index out of range");
786 return NULL;
787 }
788 return PyString_FromStringAndSize(self->data + i, 1);
789 }
790 else if (PySlice_Check(item)) {
791 Py_ssize_t start, stop, step, slicelen;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000792
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000793 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
794 &start, &stop, &step, &slicelen) < 0) {
795 return NULL;
796 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000797
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000798 if (slicelen <= 0)
799 return PyString_FromStringAndSize("", 0);
800 else if (step == 1)
801 return PyString_FromStringAndSize(self->data + start,
802 slicelen);
803 else {
804 char *result_buf = (char *)PyMem_Malloc(slicelen);
805 Py_ssize_t cur, i;
806 PyObject *result;
807
808 if (result_buf == NULL)
809 return PyErr_NoMemory();
810 for (cur = start, i = 0; i < slicelen;
811 cur += step, i++) {
812 result_buf[i] = self->data[cur];
813 }
814 result = PyString_FromStringAndSize(result_buf,
815 slicelen);
816 PyMem_Free(result_buf);
817 return result;
818 }
819 }
820 else {
821 PyErr_SetString(PyExc_TypeError,
822 "mmap indices must be integers");
823 return NULL;
824 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000825}
826
827static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000828mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000829{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000830 CHECK_VALID(NULL);
831 PyErr_SetString(PyExc_SystemError,
832 "mmaps don't support concatenation");
833 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000834}
835
836static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000837mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000838{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000839 CHECK_VALID(NULL);
840 PyErr_SetString(PyExc_SystemError,
841 "mmaps don't support repeat operation");
842 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000843}
844
845static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000846mmap_ass_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000847{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000848 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000849
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000850 CHECK_VALID(-1);
851 if (ilow < 0)
852 ilow = 0;
853 else if ((size_t)ilow > self->size)
854 ilow = self->size;
855 if (ihigh < 0)
856 ihigh = 0;
857 if (ihigh < ilow)
858 ihigh = ilow;
859 else if ((size_t)ihigh > self->size)
860 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000861
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000862 if (v == NULL) {
863 PyErr_SetString(PyExc_TypeError,
864 "mmap object doesn't support slice deletion");
865 return -1;
866 }
867 if (! (PyString_Check(v)) ) {
868 PyErr_SetString(PyExc_IndexError,
869 "mmap slice assignment must be a string");
870 return -1;
871 }
872 if (PyString_Size(v) != (ihigh - ilow)) {
873 PyErr_SetString(PyExc_IndexError,
874 "mmap slice assignment is wrong size");
875 return -1;
876 }
877 if (!is_writeable(self))
878 return -1;
879 buf = PyString_AsString(v);
880 memcpy(self->data + ilow, buf, ihigh-ilow);
881 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000882}
883
884static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000885mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000886{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000887 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000888
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000889 CHECK_VALID(-1);
890 if (i < 0 || (size_t)i >= self->size) {
891 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
892 return -1;
893 }
894 if (v == NULL) {
895 PyErr_SetString(PyExc_TypeError,
896 "mmap object doesn't support item deletion");
897 return -1;
898 }
899 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
900 PyErr_SetString(PyExc_IndexError,
901 "mmap assignment must be single-character string");
902 return -1;
903 }
904 if (!is_writeable(self))
905 return -1;
906 buf = PyString_AsString(v);
907 self->data[i] = buf[0];
908 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000909}
910
Thomas Wouters3ccec682007-08-28 15:28:19 +0000911static int
912mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
913{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000914 CHECK_VALID(-1);
Thomas Wouters3ccec682007-08-28 15:28:19 +0000915
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000916 if (PyIndex_Check(item)) {
917 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
918 const char *buf;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000919
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000920 if (i == -1 && PyErr_Occurred())
921 return -1;
922 if (i < 0)
923 i += self->size;
924 if (i < 0 || (size_t)i >= self->size) {
925 PyErr_SetString(PyExc_IndexError,
926 "mmap index out of range");
927 return -1;
928 }
929 if (value == NULL) {
930 PyErr_SetString(PyExc_TypeError,
931 "mmap object doesn't support item deletion");
932 return -1;
933 }
934 if (!PyString_Check(value) || PyString_Size(value) != 1) {
935 PyErr_SetString(PyExc_IndexError,
936 "mmap assignment must be single-character string");
937 return -1;
938 }
939 if (!is_writeable(self))
940 return -1;
941 buf = PyString_AsString(value);
942 self->data[i] = buf[0];
943 return 0;
944 }
945 else if (PySlice_Check(item)) {
946 Py_ssize_t start, stop, step, slicelen;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000947
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000948 if (PySlice_GetIndicesEx((PySliceObject *)item,
949 self->size, &start, &stop,
950 &step, &slicelen) < 0) {
951 return -1;
952 }
953 if (value == NULL) {
954 PyErr_SetString(PyExc_TypeError,
955 "mmap object doesn't support slice deletion");
956 return -1;
957 }
958 if (!PyString_Check(value)) {
959 PyErr_SetString(PyExc_IndexError,
960 "mmap slice assignment must be a string");
961 return -1;
962 }
963 if (PyString_Size(value) != slicelen) {
964 PyErr_SetString(PyExc_IndexError,
965 "mmap slice assignment is wrong size");
966 return -1;
967 }
968 if (!is_writeable(self))
969 return -1;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000970
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000971 if (slicelen == 0)
972 return 0;
973 else if (step == 1) {
974 const char *buf = PyString_AsString(value);
975
976 if (buf == NULL)
977 return -1;
978 memcpy(self->data + start, buf, slicelen);
979 return 0;
980 }
981 else {
982 Py_ssize_t cur, i;
983 const char *buf = PyString_AsString(value);
984
985 if (buf == NULL)
986 return -1;
987 for (cur = start, i = 0; i < slicelen;
988 cur += step, i++) {
989 self->data[cur] = buf[i];
990 }
991 return 0;
992 }
993 }
994 else {
995 PyErr_SetString(PyExc_TypeError,
996 "mmap indices must be integer");
997 return -1;
998 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000999}
1000
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001001static PySequenceMethods mmap_as_sequence = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001002 (lenfunc)mmap_length, /*sq_length*/
1003 (binaryfunc)mmap_concat, /*sq_concat*/
1004 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
1005 (ssizeargfunc)mmap_item, /*sq_item*/
1006 (ssizessizeargfunc)mmap_slice, /*sq_slice*/
1007 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
1008 (ssizessizeobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001009};
1010
Thomas Wouters3ccec682007-08-28 15:28:19 +00001011static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001012 (lenfunc)mmap_length,
1013 (binaryfunc)mmap_subscript,
1014 (objobjargproc)mmap_ass_subscript,
Thomas Wouters3ccec682007-08-28 15:28:19 +00001015};
1016
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001017static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001018 (readbufferproc)mmap_buffer_getreadbuf,
1019 (writebufferproc)mmap_buffer_getwritebuf,
1020 (segcountproc)mmap_buffer_getsegcount,
1021 (charbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001022};
1023
Georg Brandl845c4032008-01-21 14:16:46 +00001024static PyObject *
1025new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
1026
Georg Brandlef928022008-01-20 14:50:05 +00001027PyDoc_STRVAR(mmap_doc,
1028"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
1029\n\
1030Maps length bytes from the file specified by the file handle fileno,\n\
1031and returns a mmap object. If length is larger than the current size\n\
1032of the file, the file is extended to contain length bytes. If length\n\
1033is 0, the maximum length of the map is the current size of the file,\n\
1034except that if the file is empty Windows raises an exception (you cannot\n\
1035create an empty mapping on Windows).\n\
1036\n\
1037Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
1038\n\
1039Maps length bytes from the file specified by the file descriptor fileno,\n\
1040and returns a mmap object. If length is 0, the maximum length of the map\n\
1041will be the current size of the file when mmap is called.\n\
1042flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1043private copy-on-write mapping, so changes to the contents of the mmap\n\
Thomas Heller66260992008-08-19 17:47:13 +00001044object will be private to this process, and MAP_SHARED creates a mapping\n\
Georg Brandlef928022008-01-20 14:50:05 +00001045that's shared with all other processes mapping the same areas of the file.\n\
1046The default value is MAP_SHARED.\n\
1047\n\
1048To map anonymous memory, pass -1 as the fileno (both versions).");
1049
1050
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001051static PyTypeObject mmap_object_type = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001052 PyVarObject_HEAD_INIT(NULL, 0)
1053 "mmap.mmap", /* tp_name */
1054 sizeof(mmap_object), /* tp_size */
1055 0, /* tp_itemsize */
1056 /* methods */
1057 (destructor) mmap_object_dealloc, /* tp_dealloc */
1058 0, /* tp_print */
1059 0, /* tp_getattr */
1060 0, /* tp_setattr */
1061 0, /* tp_compare */
1062 0, /* tp_repr */
1063 0, /* tp_as_number */
1064 &mmap_as_sequence, /*tp_as_sequence*/
1065 &mmap_as_mapping, /*tp_as_mapping*/
1066 0, /*tp_hash*/
1067 0, /*tp_call*/
1068 0, /*tp_str*/
1069 PyObject_GenericGetAttr, /*tp_getattro*/
1070 0, /*tp_setattro*/
1071 &mmap_as_buffer, /*tp_as_buffer*/
1072 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
1073 mmap_doc, /*tp_doc*/
1074 0, /* tp_traverse */
1075 0, /* tp_clear */
1076 0, /* tp_richcompare */
1077 0, /* tp_weaklistoffset */
1078 0, /* tp_iter */
1079 0, /* tp_iternext */
1080 mmap_object_methods, /* tp_methods */
1081 0, /* tp_members */
1082 0, /* tp_getset */
1083 0, /* tp_base */
1084 0, /* tp_dict */
1085 0, /* tp_descr_get */
1086 0, /* tp_descr_set */
1087 0, /* tp_dictoffset */
1088 0, /* tp_init */
1089 PyType_GenericAlloc, /* tp_alloc */
1090 new_mmap_object, /* tp_new */
1091 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001092};
1093
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001094
1095/* extract the map size from the given PyObject
1096
Thomas Wouters7e474022000-07-16 12:04:32 +00001097 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001098 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001099static Py_ssize_t
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001100_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001101{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001102 if (o == NULL)
1103 return 0;
1104 if (PyIndex_Check(o)) {
1105 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1106 if (i==-1 && PyErr_Occurred())
1107 return -1;
1108 if (i < 0) {
1109 PyErr_Format(PyExc_OverflowError,
1110 "memory mapped %s must be positive",
1111 param);
1112 return -1;
1113 }
1114 return i;
1115 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001116
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001117 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1118 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001119}
1120
Tim Petersec0a5f02006-02-16 23:47:20 +00001121#ifdef UNIX
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001122#ifdef HAVE_LARGEFILE_SUPPORT
1123#define _Py_PARSE_OFF_T "L"
1124#else
1125#define _Py_PARSE_OFF_T "l"
1126#endif
1127
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001128static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001129new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001130{
Neal Norwitzb5673922002-09-05 21:48:07 +00001131#ifdef HAVE_FSTAT
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001132 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001133#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001134 mmap_object *m_obj;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001135 PyObject *map_size_obj = NULL;
1136 Py_ssize_t map_size;
1137 off_t offset = 0;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001138 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1139 int devzero = -1;
1140 int access = (int)ACCESS_DEFAULT;
1141 static char *keywords[] = {"fileno", "length",
1142 "flags", "prot",
1143 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001144
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001145 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii" _Py_PARSE_OFF_T, keywords,
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001146 &fd, &map_size_obj, &flags, &prot,
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001147 &access, &offset))
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001148 return NULL;
1149 map_size = _GetMapSize(map_size_obj, "size");
1150 if (map_size < 0)
1151 return NULL;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001152 if (offset < 0) {
1153 PyErr_SetString(PyExc_OverflowError,
1154 "memory mapped offset must be positive");
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001155 return NULL;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001156 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001157
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001158 if ((access != (int)ACCESS_DEFAULT) &&
1159 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1160 return PyErr_Format(PyExc_ValueError,
1161 "mmap can't specify both access and flags, prot.");
1162 switch ((access_mode)access) {
1163 case ACCESS_READ:
1164 flags = MAP_SHARED;
1165 prot = PROT_READ;
1166 break;
1167 case ACCESS_WRITE:
1168 flags = MAP_SHARED;
1169 prot = PROT_READ | PROT_WRITE;
1170 break;
1171 case ACCESS_COPY:
1172 flags = MAP_PRIVATE;
1173 prot = PROT_READ | PROT_WRITE;
1174 break;
1175 case ACCESS_DEFAULT:
Antoine Pitroud6f3a3e2011-03-06 02:03:34 +01001176 /* map prot to access type */
1177 if ((prot & PROT_READ) && (prot & PROT_WRITE)) {
1178 /* ACCESS_DEFAULT */
1179 }
1180 else if (prot & PROT_WRITE) {
1181 access = ACCESS_WRITE;
1182 }
1183 else {
1184 access = ACCESS_READ;
1185 }
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001186 break;
1187 default:
1188 return PyErr_Format(PyExc_ValueError,
1189 "mmap invalid access parameter.");
1190 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001191
Victor Stinner112d48a2011-05-03 14:36:36 +02001192#ifdef __APPLE__
1193 /* Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
1194 fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug */
1195 if (fd != -1)
1196 (void)fcntl(fd, F_FULLFSYNC);
1197#endif
Neal Norwitzb5673922002-09-05 21:48:07 +00001198#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001199# ifdef __VMS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001200 /* on OpenVMS we must ensure that all bytes are written to the file */
1201 if (fd != -1) {
1202 fsync(fd);
1203 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001204# endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001205 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1206 if (map_size == 0) {
Jesus Cea8b54d6d2012-09-10 00:22:39 +02001207 if (st.st_size == 0) {
1208 PyErr_SetString(PyExc_ValueError,
1209 "cannot mmap an empty file");
1210 return NULL;
1211 }
Antoine Pitrou8a0eede2011-01-20 21:20:18 +00001212 if (offset >= st.st_size) {
1213 PyErr_SetString(PyExc_ValueError,
1214 "mmap offset is greater than file size");
1215 return NULL;
1216 }
Richard Oudkerk36b9d412013-02-13 12:05:14 +00001217 if (st.st_size - offset > PY_SSIZE_T_MAX) {
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001218 PyErr_SetString(PyExc_ValueError,
1219 "mmap length is too large");
Richard Oudkerk36b9d412013-02-13 12:05:14 +00001220 return NULL;
1221 }
1222 map_size = (Py_ssize_t) (st.st_size - offset);
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001223 } else if (offset + (size_t)map_size > st.st_size) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001224 PyErr_SetString(PyExc_ValueError,
1225 "mmap length is greater than file size");
1226 return NULL;
1227 }
1228 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001229#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001230 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1231 if (m_obj == NULL) {return NULL;}
1232 m_obj->data = NULL;
1233 m_obj->size = (size_t) map_size;
1234 m_obj->pos = (size_t) 0;
1235 m_obj->offset = offset;
1236 if (fd == -1) {
1237 m_obj->fd = -1;
1238 /* Assume the caller wants to map anonymous memory.
1239 This is the same behaviour as Windows. mmap.mmap(-1, size)
1240 on both Windows and Unix map anonymous memory.
1241 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001242#ifdef MAP_ANONYMOUS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001243 /* BSD way to map anonymous memory */
1244 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001245#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001246 /* SVR4 method to map anonymous memory is to open /dev/zero */
1247 fd = devzero = open("/dev/zero", O_RDWR);
1248 if (devzero == -1) {
1249 Py_DECREF(m_obj);
1250 PyErr_SetFromErrno(mmap_module_error);
1251 return NULL;
1252 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001253#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001254 } else {
1255 m_obj->fd = dup(fd);
1256 if (m_obj->fd == -1) {
1257 Py_DECREF(m_obj);
1258 PyErr_SetFromErrno(mmap_module_error);
1259 return NULL;
1260 }
1261 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001262
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001263 m_obj->data = mmap(NULL, map_size,
1264 prot, flags,
1265 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001266
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001267 if (devzero != -1) {
1268 close(devzero);
1269 }
1270
1271 if (m_obj->data == (char *)-1) {
1272 m_obj->data = NULL;
1273 Py_DECREF(m_obj);
1274 PyErr_SetFromErrno(mmap_module_error);
1275 return NULL;
1276 }
1277 m_obj->access = (access_mode)access;
1278 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001279}
1280#endif /* UNIX */
1281
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001282#ifdef MS_WINDOWS
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001283
1284/* A note on sizes and offsets: while the actual map size must hold in a
1285 Py_ssize_t, both the total file size and the start offset can be longer
1286 than a Py_ssize_t, so we use PY_LONG_LONG which is always 64-bit.
1287*/
1288
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001289static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001290new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001291{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001292 mmap_object *m_obj;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001293 PyObject *map_size_obj = NULL;
1294 Py_ssize_t map_size;
1295 PY_LONG_LONG offset = 0, size;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001296 DWORD off_hi; /* upper 32 bits of offset */
1297 DWORD off_lo; /* lower 32 bits of offset */
1298 DWORD size_hi; /* upper 32 bits of size */
1299 DWORD size_lo; /* lower 32 bits of size */
1300 char *tagname = "";
1301 DWORD dwErr = 0;
1302 int fileno;
1303 HANDLE fh = 0;
1304 int access = (access_mode)ACCESS_DEFAULT;
1305 DWORD flProtect, dwDesiredAccess;
1306 static char *keywords[] = { "fileno", "length",
1307 "tagname",
1308 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001309
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001310 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziL", keywords,
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001311 &fileno, &map_size_obj,
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001312 &tagname, &access, &offset)) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001313 return NULL;
1314 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001315
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001316 switch((access_mode)access) {
1317 case ACCESS_READ:
1318 flProtect = PAGE_READONLY;
1319 dwDesiredAccess = FILE_MAP_READ;
1320 break;
1321 case ACCESS_DEFAULT: case ACCESS_WRITE:
1322 flProtect = PAGE_READWRITE;
1323 dwDesiredAccess = FILE_MAP_WRITE;
1324 break;
1325 case ACCESS_COPY:
1326 flProtect = PAGE_WRITECOPY;
1327 dwDesiredAccess = FILE_MAP_COPY;
1328 break;
1329 default:
1330 return PyErr_Format(PyExc_ValueError,
1331 "mmap invalid access parameter.");
1332 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001333
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001334 map_size = _GetMapSize(map_size_obj, "size");
1335 if (map_size < 0)
1336 return NULL;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001337 if (offset < 0) {
1338 PyErr_SetString(PyExc_OverflowError,
1339 "memory mapped offset must be positive");
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001340 return NULL;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001341 }
Tim Petersec0a5f02006-02-16 23:47:20 +00001342
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001343 /* assume -1 and 0 both mean invalid filedescriptor
1344 to 'anonymously' map memory.
1345 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1346 XXX: Should this code be added?
1347 if (fileno == 0)
1348 PyErr_Warn(PyExc_DeprecationWarning,
1349 "don't use 0 for anonymous memory");
1350 */
1351 if (fileno != -1 && fileno != 0) {
Brian Curtinba6c08e2010-08-01 15:47:53 +00001352 /* Ensure that fileno is within the CRT's valid range */
1353 if (_PyVerify_fd(fileno) == 0) {
1354 PyErr_SetFromErrno(mmap_module_error);
1355 return NULL;
1356 }
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001357 fh = (HANDLE)_get_osfhandle(fileno);
1358 if (fh==(HANDLE)-1) {
1359 PyErr_SetFromErrno(mmap_module_error);
1360 return NULL;
1361 }
1362 /* Win9x appears to need us seeked to zero */
1363 lseek(fileno, 0, SEEK_SET);
1364 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001365
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001366 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1367 if (m_obj == NULL)
1368 return NULL;
1369 /* Set every field to an invalid marker, so we can safely
1370 destruct the object in the face of failure */
1371 m_obj->data = NULL;
1372 m_obj->file_handle = INVALID_HANDLE_VALUE;
1373 m_obj->map_handle = NULL;
1374 m_obj->tagname = NULL;
1375 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001376
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001377 if (fh) {
1378 /* It is necessary to duplicate the handle, so the
1379 Python code can close it on us */
1380 if (!DuplicateHandle(
1381 GetCurrentProcess(), /* source process handle */
1382 fh, /* handle to be duplicated */
1383 GetCurrentProcess(), /* target proc handle */
1384 (LPHANDLE)&m_obj->file_handle, /* result */
1385 0, /* access - ignored due to options value */
1386 FALSE, /* inherited by child processes? */
1387 DUPLICATE_SAME_ACCESS)) { /* options */
1388 dwErr = GetLastError();
1389 Py_DECREF(m_obj);
1390 PyErr_SetFromWindowsErr(dwErr);
1391 return NULL;
1392 }
1393 if (!map_size) {
1394 DWORD low,high;
1395 low = GetFileSize(fh, &high);
1396 /* low might just happen to have the value INVALID_FILE_SIZE;
1397 so we need to check the last error also. */
1398 if (low == INVALID_FILE_SIZE &&
1399 (dwErr = GetLastError()) != NO_ERROR) {
1400 Py_DECREF(m_obj);
1401 return PyErr_SetFromWindowsErr(dwErr);
1402 }
1403
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001404 size = (((PY_LONG_LONG) high) << 32) + low;
Jesus Cea20f0ea12012-09-10 22:45:47 +02001405 if (size == 0) {
1406 PyErr_SetString(PyExc_ValueError,
1407 "cannot mmap an empty file");
Jesus Cea8e03b4c2012-09-10 22:57:34 +02001408 Py_DECREF(m_obj);
Jesus Cea20f0ea12012-09-10 22:45:47 +02001409 return NULL;
1410 }
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001411 if (offset >= size) {
Antoine Pitrou8a0eede2011-01-20 21:20:18 +00001412 PyErr_SetString(PyExc_ValueError,
1413 "mmap offset is greater than file size");
1414 Py_DECREF(m_obj);
1415 return NULL;
1416 }
Richard Oudkerk36b9d412013-02-13 12:05:14 +00001417 if (size - offset > PY_SSIZE_T_MAX) {
1418 PyErr_SetString(PyExc_ValueError,
1419 "mmap length is too large");
1420 Py_DECREF(m_obj);
1421 return NULL;
1422 }
1423 m_obj->size = (Py_ssize_t) (size - offset);
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001424 } else {
1425 m_obj->size = map_size;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001426 size = offset + map_size;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001427 }
1428 }
1429 else {
1430 m_obj->size = map_size;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001431 size = offset + map_size;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001432 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001433
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001434 /* set the initial position */
1435 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001436
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001437 /* set the tag name */
1438 if (tagname != NULL && *tagname != '\0') {
1439 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1440 if (m_obj->tagname == NULL) {
1441 PyErr_NoMemory();
1442 Py_DECREF(m_obj);
1443 return NULL;
1444 }
1445 strcpy(m_obj->tagname, tagname);
1446 }
1447 else
1448 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001449
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001450 m_obj->access = (access_mode)access;
Antoine Pitrouf4d2b3d2011-02-21 23:59:20 +00001451 size_hi = (DWORD)(size >> 32);
1452 size_lo = (DWORD)(size & 0xFFFFFFFF);
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001453 off_hi = (DWORD)(offset >> 32);
1454 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001455 /* For files, it would be sufficient to pass 0 as size.
1456 For anonymous maps, we have to pass the size explicitly. */
1457 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1458 NULL,
1459 flProtect,
1460 size_hi,
1461 size_lo,
1462 m_obj->tagname);
1463 if (m_obj->map_handle != NULL) {
1464 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1465 dwDesiredAccess,
1466 off_hi,
1467 off_lo,
1468 m_obj->size);
1469 if (m_obj->data != NULL)
1470 return (PyObject *)m_obj;
1471 else {
1472 dwErr = GetLastError();
1473 CloseHandle(m_obj->map_handle);
1474 m_obj->map_handle = NULL;
1475 }
1476 } else
1477 dwErr = GetLastError();
1478 Py_DECREF(m_obj);
1479 PyErr_SetFromWindowsErr(dwErr);
1480 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001481}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001482#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001483
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001484static void
1485setint(PyObject *d, const char *name, long value)
1486{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001487 PyObject *o = PyInt_FromLong(value);
1488 if (o && PyDict_SetItemString(d, name, o) == 0) {
1489 Py_DECREF(o);
1490 }
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001491}
1492
Mark Hammond62b1ab12002-07-23 06:31:15 +00001493PyMODINIT_FUNC
Georg Brandl845c4032008-01-21 14:16:46 +00001494initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001495{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001496 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001497
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001498 if (PyType_Ready(&mmap_object_type) < 0)
1499 return;
Tim Peters2caf8df2001-01-14 05:05:51 +00001500
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001501 module = Py_InitModule("mmap", NULL);
1502 if (module == NULL)
1503 return;
1504 dict = PyModule_GetDict(module);
1505 if (!dict)
1506 return;
1507 mmap_module_error = PyErr_NewException("mmap.error",
1508 PyExc_EnvironmentError , NULL);
1509 if (mmap_module_error == NULL)
1510 return;
1511 PyDict_SetItemString(dict, "error", mmap_module_error);
1512 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001513#ifdef PROT_EXEC
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001514 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001515#endif
1516#ifdef PROT_READ
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001517 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001518#endif
1519#ifdef PROT_WRITE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001520 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001521#endif
1522
1523#ifdef MAP_SHARED
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001524 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001525#endif
1526#ifdef MAP_PRIVATE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001527 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001528#endif
1529#ifdef MAP_DENYWRITE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001530 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001531#endif
1532#ifdef MAP_EXECUTABLE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001533 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001534#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001535#ifdef MAP_ANONYMOUS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001536 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1537 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001538#endif
1539
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001540 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001541
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001542 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001543
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001544 setint(dict, "ACCESS_READ", ACCESS_READ);
1545 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1546 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Tim Peters5ebfd362001-11-13 23:11:19 +00001547}