blob: a03957cf6fa402bbceb4781a54b2e5708ca1dde3 [file] [log] [blame]
Guido van Rossum09fdf072000-03-31 01:17:07 +00001/*
2 / Author: Sam Rushing <rushing@nightmare.com>
Andrew M. Kuchling10f9c072001-11-05 21:25:42 +00003 / Hacked for Unix by AMK
Guido van Rossum09fdf072000-03-31 01:17:07 +00004 / $Id$
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00005
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00006 / Modified to support mmap with offset - to map a 'window' of a file
7 / Author: Yotam Medini yotamm@mellanox.co.il
8 /
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00009 / mmapmodule.cpp -- map a view of a file into memory
10 /
11 / todo: need permission flags, perhaps a 'chsize' analog
12 / not all functions check range yet!!!
13 /
14 /
Mark Hammond071864a2000-07-30 02:46:26 +000015 / This version of mmapmodule.c has been changed significantly
16 / from the original mmapfile.c on which it was based.
17 / The original version of mmapfile is maintained by Sam at
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000018 / ftp://squirl.nightmare.com/pub/python/python-ext.
19*/
20
Martin v. Löwiscfe7e092006-02-17 06:59:14 +000021#define PY_SSIZE_T_CLEAN
Guido van Rossum09fdf072000-03-31 01:17:07 +000022#include <Python.h>
23
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000024#ifndef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000025#define UNIX
26#endif
27
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000028#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000029#include <windows.h>
Fred Drake145f96e2000-10-01 17:50:46 +000030static int
31my_getpagesize(void)
32{
Tim Peters5ebfd362001-11-13 23:11:19 +000033 SYSTEM_INFO si;
34 GetSystemInfo(&si);
35 return si.dwPageSize;
Fred Drake145f96e2000-10-01 17:50:46 +000036}
Travis E. Oliphant8feafab2007-10-23 02:40:56 +000037
38static int
39my_getallocationgranularity (void)
40{
41
42 SYSTEM_INFO si;
43 GetSystemInfo(&si);
44 return si.dwAllocationGranularity;
45}
46
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000047#endif
48
49#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000050#include <sys/mman.h>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000051#include <sys/stat.h>
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000052
Fred Drake145f96e2000-10-01 17:50:46 +000053#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
54static int
55my_getpagesize(void)
56{
Tim Peters5ebfd362001-11-13 23:11:19 +000057 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000058}
Travis E. Oliphant8feafab2007-10-23 02:40:56 +000059
60#define my_getallocationgranularity my_getpagesize
Fred Drake145f96e2000-10-01 17:50:46 +000061#else
62#define my_getpagesize getpagesize
63#endif
64
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000065#endif /* UNIX */
66
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000067#include <string.h>
Martin v. Löwis0e8bd7e2006-06-10 12:23:46 +000068
69#ifdef HAVE_SYS_TYPES_H
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000070#include <sys/types.h>
Martin v. Löwis0e8bd7e2006-06-10 12:23:46 +000071#endif /* HAVE_SYS_TYPES_H */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000072
Neal Norwitz3eaf2b52006-02-16 08:08:54 +000073/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +000074#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
75# define MAP_ANONYMOUS MAP_ANON
76#endif
77
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000078static PyObject *mmap_module_error;
79
Tim Peters5ebfd362001-11-13 23:11:19 +000080typedef enum
81{
82 ACCESS_DEFAULT,
83 ACCESS_READ,
84 ACCESS_WRITE,
85 ACCESS_COPY
86} access_mode;
87
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000088typedef struct {
Guido van Rossum09fdf072000-03-31 01:17:07 +000089 PyObject_HEAD
90 char * data;
91 size_t size;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +000092 size_t pos; /* relative to offset */
93 size_t offset;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000094
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000095#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +000096 HANDLE map_handle;
Mark Hammond071864a2000-07-30 02:46:26 +000097 HANDLE file_handle;
Guido van Rossum09fdf072000-03-31 01:17:07 +000098 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000099#endif
100
101#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000102 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000103#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000104
105 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000106} mmap_object;
107
Tim Peters5ebfd362001-11-13 23:11:19 +0000108
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000109static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000110mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000111{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000112#ifdef MS_WINDOWS
Mark Hammond2cbed002000-07-30 02:22:43 +0000113 if (m_obj->data != NULL)
114 UnmapViewOfFile (m_obj->data);
115 if (m_obj->map_handle != INVALID_HANDLE_VALUE)
116 CloseHandle (m_obj->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000117 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
118 CloseHandle (m_obj->file_handle);
Mark Hammond2cbed002000-07-30 02:22:43 +0000119 if (m_obj->tagname)
120 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000121#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000122
123#ifdef UNIX
Neal Norwitz6eac2002005-11-02 05:36:37 +0000124 if (m_obj->fd >= 0)
125 (void) close(m_obj->fd);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000126 if (m_obj->data!=NULL) {
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000127 msync(m_obj->data, m_obj->size, MS_SYNC);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000128 munmap(m_obj->data, m_obj->size);
129 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000130#endif /* UNIX */
131
Christian Heimes501dbbf2008-01-23 14:00:25 +0000132 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000133}
134
135static PyObject *
Georg Brandl96a8c392006-05-29 21:04:52 +0000136mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000137{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000138#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000139 /* For each resource we maintain, we need to check
Tim Petersec0a5f02006-02-16 23:47:20 +0000140 the value is valid, and if so, free the resource
Mark Hammond071864a2000-07-30 02:46:26 +0000141 and set the member value to an invalid value so
142 the dealloc does not attempt to resource clearing
143 again.
144 TODO - should we check for errors in the close operations???
145 */
146 if (self->data != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000147 UnmapViewOfFile(self->data);
Mark Hammond071864a2000-07-30 02:46:26 +0000148 self->data = NULL;
149 }
150 if (self->map_handle != INVALID_HANDLE_VALUE) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000151 CloseHandle(self->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000152 self->map_handle = INVALID_HANDLE_VALUE;
153 }
154 if (self->file_handle != INVALID_HANDLE_VALUE) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000155 CloseHandle(self->file_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000156 self->file_handle = INVALID_HANDLE_VALUE;
157 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000158#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000159
160#ifdef UNIX
Neal Norwitz6eac2002005-11-02 05:36:37 +0000161 (void) close(self->fd);
162 self->fd = -1;
Neal Norwitze604c022003-01-10 20:52:16 +0000163 if (self->data != NULL) {
164 munmap(self->data, self->size);
165 self->data = NULL;
166 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000167#endif
168
Tim Peters8f9cc292006-02-17 00:00:20 +0000169 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000170 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000171}
172
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000173#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +0000174#define CHECK_VALID(err) \
175do { \
Guido van Rossum69c2b882003-04-09 19:31:02 +0000176 if (self->map_handle == INVALID_HANDLE_VALUE) { \
Tim Peters8f9cc292006-02-17 00:00:20 +0000177 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
Guido van Rossum09fdf072000-03-31 01:17:07 +0000178 return err; \
179 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000180} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000181#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000182
183#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000184#define CHECK_VALID(err) \
185do { \
186 if (self->data == NULL) { \
Tim Peters8f9cc292006-02-17 00:00:20 +0000187 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
Guido van Rossum09fdf072000-03-31 01:17:07 +0000188 return err; \
189 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000190} while (0)
191#endif /* UNIX */
192
193static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000194mmap_read_byte_method(mmap_object *self,
Georg Brandl96a8c392006-05-29 21:04:52 +0000195 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000196{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000197 CHECK_VALID(NULL);
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000198 if (self->pos < self->size) {
Tim Petersd6283b82001-05-09 18:48:26 +0000199 char value = self->data[self->pos];
Guido van Rossum09fdf072000-03-31 01:17:07 +0000200 self->pos += 1;
Tim Petersd6283b82001-05-09 18:48:26 +0000201 return Py_BuildValue("c", value);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000202 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000203 PyErr_SetString(PyExc_ValueError, "read byte out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000204 return NULL;
205 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000206}
207
208static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000209mmap_read_line_method(mmap_object *self,
Georg Brandl96a8c392006-05-29 21:04:52 +0000210 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000211{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000212 char *start = self->data+self->pos;
213 char *eof = self->data+self->size;
214 char *eol;
215 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000216
Guido van Rossum09fdf072000-03-31 01:17:07 +0000217 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000218
Fred Drake56a87a02000-04-04 18:17:35 +0000219 eol = memchr(start, '\n', self->size - self->pos);
220 if (!eol)
221 eol = eof;
222 else
223 ++eol; /* we're interested in the position after the
224 newline. */
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000225 result = PyString_FromStringAndSize(start, (eol - start));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000226 self->pos += (eol - start);
Tim Peters23721ee2006-02-16 23:50:16 +0000227 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000228}
229
230static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000231mmap_read_method(mmap_object *self,
232 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000233{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000234 Py_ssize_t num_bytes;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000235 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000236
Guido van Rossum09fdf072000-03-31 01:17:07 +0000237 CHECK_VALID(NULL);
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000238 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000239 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000240
Guido van Rossum09fdf072000-03-31 01:17:07 +0000241 /* silently 'adjust' out-of-range requests */
Neal Norwitze7d8be82008-07-31 17:17:14 +0000242 if (num_bytes > self->size - self->pos) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000243 num_bytes -= (self->pos+num_bytes) - self->size;
244 }
245 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
Tim Petersec0a5f02006-02-16 23:47:20 +0000246 self->pos += num_bytes;
Tim Peters23721ee2006-02-16 23:50:16 +0000247 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000248}
249
250static PyObject *
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000251mmap_gfind(mmap_object *self,
252 PyObject *args,
253 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000254{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000255 Py_ssize_t start = self->pos;
Neal Norwitz739a3c42008-01-26 20:24:36 +0000256 Py_ssize_t end = self->size;
257 const char *needle;
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000258 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000259
Guido van Rossum09fdf072000-03-31 01:17:07 +0000260 CHECK_VALID(NULL);
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000261 if (!PyArg_ParseTuple(args, reverse ? "s#|nn:rfind" : "s#|nn:find",
262 &needle, &len, &start, &end)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000263 return NULL;
264 } else {
Neal Norwitz739a3c42008-01-26 20:24:36 +0000265 const char *p, *start_p, *end_p;
Neal Norwitze1027f92008-01-27 07:37:38 +0000266 int sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000267
268 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000269 start += self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000270 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000271 start = 0;
Tim Petersd401edd2001-05-14 23:19:12 +0000272 else if ((size_t)start > self->size)
Tim Peters5ebfd362001-11-13 23:11:19 +0000273 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000274
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000275 if (end < 0)
276 end += self->size;
277 if (end < 0)
278 end = 0;
279 else if ((size_t)end > self->size)
280 end = self->size;
281
Neal Norwitz739a3c42008-01-26 20:24:36 +0000282 start_p = self->data + start;
283 end_p = self->data + end;
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000284
Neal Norwitz739a3c42008-01-26 20:24:36 +0000285 for (p = (reverse ? end_p - len : start_p);
286 (p >= start_p) && (p + len <= end_p); p += sign) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000287 Py_ssize_t i;
Tim Petersc9ffa062002-03-08 05:43:32 +0000288 for (i = 0; i < len && needle[i] == p[i]; ++i)
289 /* nothing */;
290 if (i == len) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000291 return PyInt_FromSsize_t(p - self->data);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000292 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000293 }
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000294 return PyInt_FromLong(-1);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000295 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000296}
297
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000298static PyObject *
299mmap_find_method(mmap_object *self,
300 PyObject *args)
301{
302 return mmap_gfind(self, args, 0);
303}
304
305static PyObject *
306mmap_rfind_method(mmap_object *self,
307 PyObject *args)
308{
309 return mmap_gfind(self, args, 1);
310}
311
Tim Petersec0a5f02006-02-16 23:47:20 +0000312static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000313is_writeable(mmap_object *self)
314{
315 if (self->access != ACCESS_READ)
Tim Petersec0a5f02006-02-16 23:47:20 +0000316 return 1;
Tim Peters5ebfd362001-11-13 23:11:19 +0000317 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
318 return 0;
319}
320
Tim Petersec0a5f02006-02-16 23:47:20 +0000321static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000322is_resizeable(mmap_object *self)
323{
324 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
Tim Petersec0a5f02006-02-16 23:47:20 +0000325 return 1;
326 PyErr_Format(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000327 "mmap can't resize a readonly or copy-on-write memory map.");
328 return 0;
329}
330
331
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000332static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000333mmap_write_method(mmap_object *self,
334 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000335{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000336 Py_ssize_t length;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000337 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000338
Guido van Rossum09fdf072000-03-31 01:17:07 +0000339 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000340 if (!PyArg_ParseTuple(args, "s#:write", &data, &length))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000341 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000342
Tim Peters5ebfd362001-11-13 23:11:19 +0000343 if (!is_writeable(self))
344 return NULL;
345
Guido van Rossum09fdf072000-03-31 01:17:07 +0000346 if ((self->pos + length) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000347 PyErr_SetString(PyExc_ValueError, "data out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000348 return NULL;
349 }
Tim Peters8f9cc292006-02-17 00:00:20 +0000350 memcpy(self->data+self->pos, data, length);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000351 self->pos = self->pos+length;
Tim Peters8f9cc292006-02-17 00:00:20 +0000352 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000353 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000354}
355
356static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000357mmap_write_byte_method(mmap_object *self,
358 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000359{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000360 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000361
Guido van Rossum09fdf072000-03-31 01:17:07 +0000362 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000363 if (!PyArg_ParseTuple(args, "c:write_byte", &value))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000364 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000365
Tim Peters5ebfd362001-11-13 23:11:19 +0000366 if (!is_writeable(self))
367 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000368 *(self->data+self->pos) = value;
369 self->pos += 1;
Tim Peters8f9cc292006-02-17 00:00:20 +0000370 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000371 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000372}
Tim Petersec0a5f02006-02-16 23:47:20 +0000373
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000374static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000375mmap_size_method(mmap_object *self,
Georg Brandl96a8c392006-05-29 21:04:52 +0000376 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000377{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000378 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000379
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000380#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000381 if (self->file_handle != INVALID_HANDLE_VALUE) {
Martin v. Löwis15186072006-02-18 12:38:35 +0000382 DWORD low,high;
383 PY_LONG_LONG size;
384 low = GetFileSize(self->file_handle, &high);
385 if (low == INVALID_FILE_SIZE) {
386 /* It might be that the function appears to have failed,
387 when indeed its size equals INVALID_FILE_SIZE */
388 DWORD error = GetLastError();
389 if (error != NO_ERROR)
390 return PyErr_SetFromWindowsErr(error);
391 }
392 if (!high && low < LONG_MAX)
393 return PyInt_FromLong((long)low);
394 size = (((PY_LONG_LONG)high)<<32) + low;
395 return PyLong_FromLongLong(size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000396 } else {
Martin v. Löwis15186072006-02-18 12:38:35 +0000397 return PyInt_FromSsize_t(self->size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000398 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000399#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000400
401#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000402 {
403 struct stat buf;
404 if (-1 == fstat(self->fd, &buf)) {
405 PyErr_SetFromErrno(mmap_module_error);
406 return NULL;
407 }
Martin v. Löwis15186072006-02-18 12:38:35 +0000408 return PyInt_FromSsize_t(buf.st_size);
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000409 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000410#endif /* UNIX */
411}
412
413/* This assumes that you want the entire file mapped,
414 / and when recreating the map will make the new file
415 / have the new size
416 /
417 / Is this really necessary? This could easily be done
418 / from python by just closing and re-opening with the
419 / new size?
420 */
421
422static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000423mmap_resize_method(mmap_object *self,
424 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000425{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000426 Py_ssize_t new_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000427 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000428 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000429 !is_resizeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000430 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000431#ifdef MS_WINDOWS
Tim Petersec0a5f02006-02-16 23:47:20 +0000432 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000433 DWORD dwErrCode = 0;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +0000434 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000435 /* First, unmap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000436 UnmapViewOfFile(self->data);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000437 /* Close the mapping object */
Tim Peters8f9cc292006-02-17 00:00:20 +0000438 CloseHandle(self->map_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000439 /* Move to the desired EOF position */
Martin v. Löwis15186072006-02-18 12:38:35 +0000440#if SIZEOF_SIZE_T > 4
Travis E. Oliphant8feafab2007-10-23 02:40:56 +0000441 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
442 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
443 off_hi = (DWORD)(self->offset >> 32);
444 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Martin v. Löwis15186072006-02-18 12:38:35 +0000445#else
446 newSizeHigh = 0;
Martin v. Löwis5bb8a152006-02-18 12:49:49 +0000447 newSizeLow = (DWORD)new_size;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +0000448 off_hi = 0;
449 off_lo = (DWORD)self->offset;
Martin v. Löwis15186072006-02-18 12:38:35 +0000450#endif
Tim Peters8f9cc292006-02-17 00:00:20 +0000451 SetFilePointer(self->file_handle,
Martin v. Löwis15186072006-02-18 12:38:35 +0000452 newSizeLow, &newSizeHigh, FILE_BEGIN);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000453 /* Change the size of the file */
Tim Peters8f9cc292006-02-17 00:00:20 +0000454 SetEndOfFile(self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000455 /* Create another mapping object and remap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000456 self->map_handle = CreateFileMapping(
Mark Hammond071864a2000-07-30 02:46:26 +0000457 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000458 NULL,
459 PAGE_READWRITE,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +0000460 0,
461 0,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000462 self->tagname);
463 if (self->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000464 self->data = (char *) MapViewOfFile(self->map_handle,
465 FILE_MAP_WRITE,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +0000466 off_hi,
467 off_lo,
468 new_size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000469 if (self->data != NULL) {
470 self->size = new_size;
Tim Peters8f9cc292006-02-17 00:00:20 +0000471 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000472 return Py_None;
473 } else {
474 dwErrCode = GetLastError();
475 }
476 } else {
477 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000478 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000479 PyErr_SetFromWindowsErr(dwErrCode);
Tim Peters23721ee2006-02-16 23:50:16 +0000480 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000481#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000482
483#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000484#ifndef HAVE_MREMAP
Tim Peters5ebfd362001-11-13 23:11:19 +0000485 } else {
486 PyErr_SetString(PyExc_SystemError,
487 "mmap: resizing not available--no mremap()");
488 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000489#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000490 } else {
Armin Rigo335ffe82005-09-20 19:04:02 +0000491 void *newmap;
492
Georg Brandl38387b82005-08-24 07:17:40 +0000493 if (ftruncate(self->fd, new_size) == -1) {
494 PyErr_SetFromErrno(mmap_module_error);
495 return NULL;
496 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000497
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000498#ifdef MREMAP_MAYMOVE
Tim Peters5ebfd362001-11-13 23:11:19 +0000499 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000500#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000501 newmap = mremap(self->data, self->size, new_size, 0);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000502#endif
Tim Petersec0a5f02006-02-16 23:47:20 +0000503 if (newmap == (void *)-1)
Tim Peters5ebfd362001-11-13 23:11:19 +0000504 {
505 PyErr_SetFromErrno(mmap_module_error);
506 return NULL;
507 }
508 self->data = newmap;
509 self->size = new_size;
510 Py_INCREF(Py_None);
511 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000512#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000513#endif /* UNIX */
Tim Peters5ebfd362001-11-13 23:11:19 +0000514 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000515}
516
517static PyObject *
Georg Brandl96a8c392006-05-29 21:04:52 +0000518mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000519{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000520 CHECK_VALID(NULL);
Neal Norwitz670f8752006-08-22 13:56:56 +0000521 return PyInt_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000522}
523
524static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000525mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000526{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000527 Py_ssize_t offset = 0;
528 Py_ssize_t size = self->size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000529 CHECK_VALID(NULL);
Tim Petersf2882952006-02-17 01:07:39 +0000530 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000531 return NULL;
Tim Petersf2882952006-02-17 01:07:39 +0000532 if ((size_t)(offset + size) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000533 PyErr_SetString(PyExc_ValueError, "flush values out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000534 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000535 }
Neal Norwitz448654f2008-01-27 07:36:03 +0000536#ifdef MS_WINDOWS
537 return PyInt_FromLong((long) FlushViewOfFile(self->data+offset, size));
538#elif defined(UNIX)
539 /* XXX semantics of return value? */
540 /* XXX flags for msync? */
541 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
542 PyErr_SetFromErrno(mmap_module_error);
543 return NULL;
544 }
545 return PyInt_FromLong(0);
546#else
547 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
548 return NULL;
549#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000550}
551
552static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000553mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000554{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000555 Py_ssize_t dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000556 int how=0;
557 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000558 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
Tim Peters8f9cc292006-02-17 00:00:20 +0000559 return NULL;
560 else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000561 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000562 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000563 case 0: /* relative to start */
564 if (dist < 0)
565 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000566 where = dist;
567 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000568 case 1: /* relative to current position */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000569 if ((Py_ssize_t)self->pos + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000570 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000571 where = self->pos + dist;
572 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000573 case 2: /* relative to end */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000574 if ((Py_ssize_t)self->size + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000575 goto onoutofrange;
576 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000577 break;
578 default:
Tim Peters8f9cc292006-02-17 00:00:20 +0000579 PyErr_SetString(PyExc_ValueError, "unknown seek type");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000580 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000581 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000582 if (where > self->size)
583 goto onoutofrange;
584 self->pos = where;
Tim Peters8f9cc292006-02-17 00:00:20 +0000585 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000586 return Py_None;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000587 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000588
Tim Peters5ebfd362001-11-13 23:11:19 +0000589 onoutofrange:
Tim Peters8f9cc292006-02-17 00:00:20 +0000590 PyErr_SetString(PyExc_ValueError, "seek out of range");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000591 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000592}
593
594static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000595mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000596{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000597 unsigned long dest, src, count;
598 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000599 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &count) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000600 !is_writeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000601 return NULL;
602 } else {
603 /* bounds check the values */
604 if (/* end of source after end of data?? */
605 ((src+count) > self->size)
606 /* dest will fit? */
607 || (dest+count > self->size)) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000608 PyErr_SetString(PyExc_ValueError,
609 "source or destination out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000610 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000611 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000612 memmove(self->data+dest, self->data+src, count);
613 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000614 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000615 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000616 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000617}
618
619static struct PyMethodDef mmap_object_methods[] = {
Georg Brandl96a8c392006-05-29 21:04:52 +0000620 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000621 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000622 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000623 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
624 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
625 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
Georg Brandl96a8c392006-05-29 21:04:52 +0000626 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
627 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000628 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
629 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
Georg Brandl96a8c392006-05-29 21:04:52 +0000630 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
631 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000632 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
633 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000634 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000635};
636
637/* Functions for treating an mmap'ed file as a buffer */
638
Martin v. Löwis18e16552006-02-15 17:27:45 +0000639static Py_ssize_t
640mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000641{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000642 CHECK_VALID(-1);
Tim Peters8f9cc292006-02-17 00:00:20 +0000643 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000644 PyErr_SetString(PyExc_SystemError,
645 "Accessing non-existent mmap segment");
646 return -1;
647 }
648 *ptr = self->data;
649 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000650}
651
Martin v. Löwis18e16552006-02-15 17:27:45 +0000652static Py_ssize_t
653mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Tim Petersec0a5f02006-02-16 23:47:20 +0000654{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000655 CHECK_VALID(-1);
Tim Peters8f9cc292006-02-17 00:00:20 +0000656 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000657 PyErr_SetString(PyExc_SystemError,
658 "Accessing non-existent mmap segment");
659 return -1;
660 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000661 if (!is_writeable(self))
662 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000663 *ptr = self->data;
664 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000665}
666
Martin v. Löwis18e16552006-02-15 17:27:45 +0000667static Py_ssize_t
668mmap_buffer_getsegcount(mmap_object *self, Py_ssize_t *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000669{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000670 CHECK_VALID(-1);
Tim Petersec0a5f02006-02-16 23:47:20 +0000671 if (lenp)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000672 *lenp = self->size;
673 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000674}
675
Martin v. Löwis18e16552006-02-15 17:27:45 +0000676static Py_ssize_t
677mmap_buffer_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000678{
Tim Peters8f9cc292006-02-17 00:00:20 +0000679 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000680 PyErr_SetString(PyExc_SystemError,
681 "accessing non-existent buffer segment");
682 return -1;
683 }
684 *ptr = (const char *)self->data;
685 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000686}
687
Martin v. Löwis18e16552006-02-15 17:27:45 +0000688static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000689mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000690{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000691 CHECK_VALID(-1);
692 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000693}
694
695static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000696mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000697{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000698 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000699 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000700 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
701 return NULL;
702 }
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000703 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000704}
705
706static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000707mmap_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000708{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000709 CHECK_VALID(NULL);
710 if (ilow < 0)
711 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000712 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000713 ilow = self->size;
714 if (ihigh < 0)
715 ihigh = 0;
716 if (ihigh < ilow)
717 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000718 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000719 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000720
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000721 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000722}
723
724static PyObject *
Thomas Wouters3ccec682007-08-28 15:28:19 +0000725mmap_subscript(mmap_object *self, PyObject *item)
726{
727 CHECK_VALID(NULL);
728 if (PyIndex_Check(item)) {
729 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
730 if (i == -1 && PyErr_Occurred())
731 return NULL;
732 if (i < 0)
733 i += self->size;
Neal Norwitz9c4382f2007-10-31 06:33:20 +0000734 if (i < 0 || (size_t)i > self->size) {
Thomas Wouters3ccec682007-08-28 15:28:19 +0000735 PyErr_SetString(PyExc_IndexError,
736 "mmap index out of range");
737 return NULL;
738 }
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000739 return PyString_FromStringAndSize(self->data + i, 1);
Thomas Wouters3ccec682007-08-28 15:28:19 +0000740 }
741 else if (PySlice_Check(item)) {
742 Py_ssize_t start, stop, step, slicelen;
743
744 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
745 &start, &stop, &step, &slicelen) < 0) {
746 return NULL;
747 }
748
749 if (slicelen <= 0)
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000750 return PyString_FromStringAndSize("", 0);
Thomas Wouters3ccec682007-08-28 15:28:19 +0000751 else if (step == 1)
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000752 return PyString_FromStringAndSize(self->data + start,
Thomas Wouters3ccec682007-08-28 15:28:19 +0000753 slicelen);
754 else {
755 char *result_buf = (char *)PyMem_Malloc(slicelen);
756 Py_ssize_t cur, i;
757 PyObject *result;
758
759 if (result_buf == NULL)
760 return PyErr_NoMemory();
761 for (cur = start, i = 0; i < slicelen;
762 cur += step, i++) {
763 result_buf[i] = self->data[cur];
764 }
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000765 result = PyString_FromStringAndSize(result_buf,
Thomas Wouters3ccec682007-08-28 15:28:19 +0000766 slicelen);
767 PyMem_Free(result_buf);
768 return result;
769 }
770 }
771 else {
772 PyErr_SetString(PyExc_TypeError,
773 "mmap indices must be integers");
774 return NULL;
775 }
776}
777
778static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000779mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000780{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000781 CHECK_VALID(NULL);
782 PyErr_SetString(PyExc_SystemError,
783 "mmaps don't support concatenation");
784 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000785}
786
787static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000788mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000789{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000790 CHECK_VALID(NULL);
791 PyErr_SetString(PyExc_SystemError,
792 "mmaps don't support repeat operation");
793 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000794}
795
796static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000797mmap_ass_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000798{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000799 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000800
Guido van Rossum09fdf072000-03-31 01:17:07 +0000801 CHECK_VALID(-1);
802 if (ilow < 0)
803 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000804 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000805 ilow = self->size;
806 if (ihigh < 0)
807 ihigh = 0;
808 if (ihigh < ilow)
809 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000810 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000811 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000812
Thomas Wouters1baac722001-07-16 15:47:36 +0000813 if (v == NULL) {
814 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000815 "mmap object doesn't support slice deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000816 return -1;
817 }
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000818 if (! (PyString_Check(v)) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000819 PyErr_SetString(PyExc_IndexError,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000820 "mmap slice assignment must be a string");
821 return -1;
822 }
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000823 if (PyString_Size(v) != (ihigh - ilow)) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000824 PyErr_SetString(PyExc_IndexError,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000825 "mmap slice assignment is wrong size");
826 return -1;
827 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000828 if (!is_writeable(self))
829 return -1;
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000830 buf = PyString_AsString(v);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000831 memcpy(self->data + ilow, buf, ihigh-ilow);
832 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000833}
834
835static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000836mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000837{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000838 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000839
Guido van Rossum09fdf072000-03-31 01:17:07 +0000840 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000841 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000842 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
843 return -1;
844 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000845 if (v == NULL) {
846 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000847 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000848 return -1;
849 }
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000850 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000851 PyErr_SetString(PyExc_IndexError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000852 "mmap assignment must be single-character string");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000853 return -1;
854 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000855 if (!is_writeable(self))
856 return -1;
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000857 buf = PyString_AsString(v);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000858 self->data[i] = buf[0];
859 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000860}
861
Thomas Wouters3ccec682007-08-28 15:28:19 +0000862static int
863mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
864{
865 CHECK_VALID(-1);
866
867 if (PyIndex_Check(item)) {
868 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
869 const char *buf;
870
871 if (i == -1 && PyErr_Occurred())
872 return -1;
873 if (i < 0)
874 i += self->size;
Neal Norwitz9c4382f2007-10-31 06:33:20 +0000875 if (i < 0 || (size_t)i > self->size) {
Thomas Wouters3ccec682007-08-28 15:28:19 +0000876 PyErr_SetString(PyExc_IndexError,
877 "mmap index out of range");
878 return -1;
879 }
880 if (value == NULL) {
881 PyErr_SetString(PyExc_TypeError,
882 "mmap object doesn't support item deletion");
883 return -1;
884 }
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000885 if (!PyString_Check(value) || PyString_Size(value) != 1) {
Thomas Wouters3ccec682007-08-28 15:28:19 +0000886 PyErr_SetString(PyExc_IndexError,
887 "mmap assignment must be single-character string");
888 return -1;
889 }
890 if (!is_writeable(self))
891 return -1;
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000892 buf = PyString_AsString(value);
Thomas Wouters3ccec682007-08-28 15:28:19 +0000893 self->data[i] = buf[0];
894 return 0;
895 }
896 else if (PySlice_Check(item)) {
897 Py_ssize_t start, stop, step, slicelen;
898
899 if (PySlice_GetIndicesEx((PySliceObject *)item,
900 self->size, &start, &stop,
901 &step, &slicelen) < 0) {
902 return -1;
903 }
904 if (value == NULL) {
905 PyErr_SetString(PyExc_TypeError,
906 "mmap object doesn't support slice deletion");
907 return -1;
908 }
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000909 if (!PyString_Check(value)) {
Thomas Wouters3ccec682007-08-28 15:28:19 +0000910 PyErr_SetString(PyExc_IndexError,
911 "mmap slice assignment must be a string");
912 return -1;
913 }
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000914 if (PyString_Size(value) != slicelen) {
Thomas Wouters3ccec682007-08-28 15:28:19 +0000915 PyErr_SetString(PyExc_IndexError,
916 "mmap slice assignment is wrong size");
917 return -1;
918 }
919 if (!is_writeable(self))
920 return -1;
921
922 if (slicelen == 0)
923 return 0;
924 else if (step == 1) {
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000925 const char *buf = PyString_AsString(value);
Thomas Wouters3ccec682007-08-28 15:28:19 +0000926
927 if (buf == NULL)
928 return -1;
929 memcpy(self->data + start, buf, slicelen);
930 return 0;
931 }
932 else {
933 Py_ssize_t cur, i;
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000934 const char *buf = PyString_AsString(value);
Thomas Wouters3ccec682007-08-28 15:28:19 +0000935
936 if (buf == NULL)
937 return -1;
938 for (cur = start, i = 0; i < slicelen;
939 cur += step, i++) {
940 self->data[cur] = buf[i];
941 }
942 return 0;
943 }
944 }
945 else {
946 PyErr_SetString(PyExc_TypeError,
947 "mmap indices must be integer");
948 return -1;
949 }
950}
951
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000952static PySequenceMethods mmap_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000953 (lenfunc)mmap_length, /*sq_length*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000954 (binaryfunc)mmap_concat, /*sq_concat*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000955 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
956 (ssizeargfunc)mmap_item, /*sq_item*/
957 (ssizessizeargfunc)mmap_slice, /*sq_slice*/
958 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
959 (ssizessizeobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000960};
961
Thomas Wouters3ccec682007-08-28 15:28:19 +0000962static PyMappingMethods mmap_as_mapping = {
963 (lenfunc)mmap_length,
964 (binaryfunc)mmap_subscript,
965 (objobjargproc)mmap_ass_subscript,
966};
967
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000968static PyBufferProcs mmap_as_buffer = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000969 (readbufferproc)mmap_buffer_getreadbuf,
970 (writebufferproc)mmap_buffer_getwritebuf,
971 (segcountproc)mmap_buffer_getsegcount,
972 (charbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000973};
974
Georg Brandl845c4032008-01-21 14:16:46 +0000975static PyObject *
976new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
977
Georg Brandlef928022008-01-20 14:50:05 +0000978PyDoc_STRVAR(mmap_doc,
979"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
980\n\
981Maps length bytes from the file specified by the file handle fileno,\n\
982and returns a mmap object. If length is larger than the current size\n\
983of the file, the file is extended to contain length bytes. If length\n\
984is 0, the maximum length of the map is the current size of the file,\n\
985except that if the file is empty Windows raises an exception (you cannot\n\
986create an empty mapping on Windows).\n\
987\n\
988Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
989\n\
990Maps length bytes from the file specified by the file descriptor fileno,\n\
991and returns a mmap object. If length is 0, the maximum length of the map\n\
992will be the current size of the file when mmap is called.\n\
993flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
994private copy-on-write mapping, so changes to the contents of the mmap\n\
Thomas Heller66260992008-08-19 17:47:13 +0000995object will be private to this process, and MAP_SHARED creates a mapping\n\
Georg Brandlef928022008-01-20 14:50:05 +0000996that's shared with all other processes mapping the same areas of the file.\n\
997The default value is MAP_SHARED.\n\
998\n\
999To map anonymous memory, pass -1 as the fileno (both versions).");
1000
1001
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001002static PyTypeObject mmap_object_type = {
Georg Brandl845c4032008-01-21 14:16:46 +00001003 PyVarObject_HEAD_INIT(NULL, 0)
Guido van Rossum14648392001-12-08 18:02:58 +00001004 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +00001005 sizeof(mmap_object), /* tp_size */
1006 0, /* tp_itemsize */
1007 /* methods */
1008 (destructor) mmap_object_dealloc, /* tp_dealloc */
1009 0, /* tp_print */
Georg Brandlef928022008-01-20 14:50:05 +00001010 0, /* tp_getattr */
Guido van Rossum09fdf072000-03-31 01:17:07 +00001011 0, /* tp_setattr */
1012 0, /* tp_compare */
1013 0, /* tp_repr */
1014 0, /* tp_as_number */
1015 &mmap_as_sequence, /*tp_as_sequence*/
Thomas Wouters3ccec682007-08-28 15:28:19 +00001016 &mmap_as_mapping, /*tp_as_mapping*/
Guido van Rossum09fdf072000-03-31 01:17:07 +00001017 0, /*tp_hash*/
1018 0, /*tp_call*/
1019 0, /*tp_str*/
Georg Brandlef928022008-01-20 14:50:05 +00001020 PyObject_GenericGetAttr, /*tp_getattro*/
Guido van Rossum09fdf072000-03-31 01:17:07 +00001021 0, /*tp_setattro*/
1022 &mmap_as_buffer, /*tp_as_buffer*/
Georg Brandl845c4032008-01-21 14:16:46 +00001023 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
Georg Brandlef928022008-01-20 14:50:05 +00001024 mmap_doc, /*tp_doc*/
1025 0, /* tp_traverse */
1026 0, /* tp_clear */
1027 0, /* tp_richcompare */
1028 0, /* tp_weaklistoffset */
Georg Brandl845c4032008-01-21 14:16:46 +00001029 0, /* tp_iter */
1030 0, /* tp_iternext */
Georg Brandlef928022008-01-20 14:50:05 +00001031 mmap_object_methods, /* tp_methods */
Georg Brandl845c4032008-01-21 14:16:46 +00001032 0, /* tp_members */
1033 0, /* tp_getset */
1034 0, /* tp_base */
1035 0, /* tp_dict */
1036 0, /* tp_descr_get */
1037 0, /* tp_descr_set */
1038 0, /* tp_dictoffset */
1039 0, /* tp_init */
1040 PyType_GenericAlloc, /* tp_alloc */
1041 new_mmap_object, /* tp_new */
1042 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001043};
1044
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001045
1046/* extract the map size from the given PyObject
1047
Thomas Wouters7e474022000-07-16 12:04:32 +00001048 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001049 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001050static Py_ssize_t
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001051_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001052{
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001053 if (o == NULL)
1054 return 0;
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001055 if (PyIndex_Check(o)) {
1056 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
Guido van Rossum38fff8c2006-03-07 18:50:55 +00001057 if (i==-1 && PyErr_Occurred())
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001058 return -1;
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001059 if (i < 0) {
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001060 PyErr_Format(PyExc_OverflowError,
1061 "memory mapped %s must be positive",
1062 param);
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001063 return -1;
1064 }
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001065 return i;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001066 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001067
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001068 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001069 return -1;
1070}
1071
Tim Petersec0a5f02006-02-16 23:47:20 +00001072#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001073static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001074new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001075{
Neal Norwitzb5673922002-09-05 21:48:07 +00001076#ifdef HAVE_FSTAT
1077 struct stat st;
1078#endif
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001079 mmap_object *m_obj;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001080 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1081 Py_ssize_t map_size, offset;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001082 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001083 int devzero = -1;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001084 int access = (int)ACCESS_DEFAULT;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001085 static char *keywords[] = {"fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001086 "flags", "prot",
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001087 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001088
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001089 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iiiO", keywords,
Jeremy Hyltonaf68c872005-12-10 18:50:16 +00001090 &fd, &map_size_obj, &flags, &prot,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001091 &access, &offset_obj))
Guido van Rossum09fdf072000-03-31 01:17:07 +00001092 return NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001093 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001094 if (map_size < 0)
1095 return NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001096 offset = _GetMapSize(offset_obj, "offset");
1097 if (offset < 0)
1098 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001099
Tim Petersec0a5f02006-02-16 23:47:20 +00001100 if ((access != (int)ACCESS_DEFAULT) &&
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001101 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
Tim Petersec0a5f02006-02-16 23:47:20 +00001102 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001103 "mmap can't specify both access and flags, prot.");
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001104 switch ((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001105 case ACCESS_READ:
1106 flags = MAP_SHARED;
1107 prot = PROT_READ;
1108 break;
1109 case ACCESS_WRITE:
1110 flags = MAP_SHARED;
1111 prot = PROT_READ | PROT_WRITE;
1112 break;
1113 case ACCESS_COPY:
1114 flags = MAP_PRIVATE;
1115 prot = PROT_READ | PROT_WRITE;
1116 break;
Tim Petersec0a5f02006-02-16 23:47:20 +00001117 case ACCESS_DEFAULT:
Tim Peters5ebfd362001-11-13 23:11:19 +00001118 /* use the specified or default values of flags and prot */
1119 break;
1120 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001121 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001122 "mmap invalid access parameter.");
1123 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001124
Christian Heimes7adfad82008-02-15 08:20:11 +00001125 if (prot == PROT_READ) {
1126 access = ACCESS_READ;
1127 }
1128
Neal Norwitzb5673922002-09-05 21:48:07 +00001129#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001130# ifdef __VMS
1131 /* on OpenVMS we must ensure that all bytes are written to the file */
Andrew M. Kuchling7c22ccc2008-01-10 13:37:12 +00001132 if (fd != -1) {
1133 fsync(fd);
1134 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001135# endif
Andrew M. Kuchling7c22ccc2008-01-10 13:37:12 +00001136 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001137 if (map_size == 0) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001138 map_size = st.st_size;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001139 } else if ((size_t)offset + (size_t)map_size > st.st_size) {
Tim Petersec0a5f02006-02-16 23:47:20 +00001140 PyErr_SetString(PyExc_ValueError,
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001141 "mmap length is greater than file size");
1142 return NULL;
1143 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001144 }
1145#endif
Georg Brandl845c4032008-01-21 14:16:46 +00001146 m_obj = (mmap_object *)type->tp_alloc(type, 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001147 if (m_obj == NULL) {return NULL;}
Neal Norwitz3b4fff82006-01-11 08:54:45 +00001148 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001149 m_obj->size = (size_t) map_size;
1150 m_obj->pos = (size_t) 0;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001151 m_obj->offset = offset;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001152 if (fd == -1) {
1153 m_obj->fd = -1;
1154 /* Assume the caller wants to map anonymous memory.
1155 This is the same behaviour as Windows. mmap.mmap(-1, size)
1156 on both Windows and Unix map anonymous memory.
1157 */
1158#ifdef MAP_ANONYMOUS
1159 /* BSD way to map anonymous memory */
1160 flags |= MAP_ANONYMOUS;
1161#else
1162 /* SVR4 method to map anonymous memory is to open /dev/zero */
1163 fd = devzero = open("/dev/zero", O_RDWR);
1164 if (devzero == -1) {
1165 Py_DECREF(m_obj);
1166 PyErr_SetFromErrno(mmap_module_error);
1167 return NULL;
1168 }
1169#endif
1170 } else {
1171 m_obj->fd = dup(fd);
1172 if (m_obj->fd == -1) {
1173 Py_DECREF(m_obj);
1174 PyErr_SetFromErrno(mmap_module_error);
1175 return NULL;
1176 }
Georg Brandl38387b82005-08-24 07:17:40 +00001177 }
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001178
Tim Petersec0a5f02006-02-16 23:47:20 +00001179 m_obj->data = mmap(NULL, map_size,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001180 prot, flags,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001181 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001182
1183 if (devzero != -1) {
1184 close(devzero);
1185 }
1186
Tim Peters5ebfd362001-11-13 23:11:19 +00001187 if (m_obj->data == (char *)-1) {
Andrew M. Kuchling16581c82004-05-19 14:39:08 +00001188 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001189 Py_DECREF(m_obj);
1190 PyErr_SetFromErrno(mmap_module_error);
1191 return NULL;
1192 }
Neal Norwitz8856fb72005-12-18 03:34:22 +00001193 m_obj->access = (access_mode)access;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001194 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001195}
1196#endif /* UNIX */
1197
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001198#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001199static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001200new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001201{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001202 mmap_object *m_obj;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001203 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1204 Py_ssize_t map_size, offset;
1205 DWORD off_hi; /* upper 32 bits of offset */
1206 DWORD off_lo; /* lower 32 bits of offset */
1207 DWORD size_hi; /* upper 32 bits of size */
1208 DWORD size_lo; /* lower 32 bits of size */
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001209 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +00001210 DWORD dwErr = 0;
1211 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +00001212 HANDLE fh = 0;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001213 int access = (access_mode)ACCESS_DEFAULT;
Tim Peters5ebfd362001-11-13 23:11:19 +00001214 DWORD flProtect, dwDesiredAccess;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001215 static char *keywords[] = { "fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001216 "tagname",
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001217 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001218
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001219 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
Tim Petersec0a5f02006-02-16 23:47:20 +00001220 &fileno, &map_size_obj,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001221 &tagname, &access, &offset_obj)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001222 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001223 }
1224
Neal Norwitz8856fb72005-12-18 03:34:22 +00001225 switch((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001226 case ACCESS_READ:
1227 flProtect = PAGE_READONLY;
1228 dwDesiredAccess = FILE_MAP_READ;
1229 break;
1230 case ACCESS_DEFAULT: case ACCESS_WRITE:
1231 flProtect = PAGE_READWRITE;
1232 dwDesiredAccess = FILE_MAP_WRITE;
1233 break;
1234 case ACCESS_COPY:
1235 flProtect = PAGE_WRITECOPY;
1236 dwDesiredAccess = FILE_MAP_COPY;
1237 break;
1238 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001239 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001240 "mmap invalid access parameter.");
1241 }
1242
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001243 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001244 if (map_size < 0)
1245 return NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001246 offset = _GetMapSize(offset_obj, "offset");
1247 if (offset < 0)
1248 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001249
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001250 /* assume -1 and 0 both mean invalid filedescriptor
1251 to 'anonymously' map memory.
1252 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1253 XXX: Should this code be added?
1254 if (fileno == 0)
1255 PyErr_Warn(PyExc_DeprecationWarning,
1256 "don't use 0 for anonymous memory");
1257 */
1258 if (fileno != -1 && fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +00001259 fh = (HANDLE)_get_osfhandle(fileno);
1260 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001261 PyErr_SetFromErrno(mmap_module_error);
1262 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001263 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +00001264 /* Win9x appears to need us seeked to zero */
Guido van Rossum69c2b882003-04-09 19:31:02 +00001265 lseek(fileno, 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001266 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001267
Georg Brandl845c4032008-01-21 14:16:46 +00001268 m_obj = (mmap_object *)type->tp_alloc(type, 0);
Tim Peters8f9cc292006-02-17 00:00:20 +00001269 if (m_obj == NULL)
Mark Hammond2cbed002000-07-30 02:22:43 +00001270 return NULL;
1271 /* Set every field to an invalid marker, so we can safely
1272 destruct the object in the face of failure */
1273 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +00001274 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +00001275 m_obj->map_handle = INVALID_HANDLE_VALUE;
1276 m_obj->tagname = NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001277 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001278
Guido van Rossum09fdf072000-03-31 01:17:07 +00001279 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +00001280 /* It is necessary to duplicate the handle, so the
1281 Python code can close it on us */
1282 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +00001283 GetCurrentProcess(), /* source process handle */
1284 fh, /* handle to be duplicated */
1285 GetCurrentProcess(), /* target proc handle */
1286 (LPHANDLE)&m_obj->file_handle, /* result */
1287 0, /* access - ignored due to options value */
1288 FALSE, /* inherited by child processes? */
1289 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +00001290 dwErr = GetLastError();
1291 Py_DECREF(m_obj);
1292 PyErr_SetFromWindowsErr(dwErr);
1293 return NULL;
1294 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001295 if (!map_size) {
Martin v. Löwis15186072006-02-18 12:38:35 +00001296 DWORD low,high;
1297 low = GetFileSize(fh, &high);
1298 /* low might just happen to have the value INVALID_FILE_SIZE;
1299 so we need to check the last error also. */
1300 if (low == INVALID_FILE_SIZE &&
1301 (dwErr = GetLastError()) != NO_ERROR) {
1302 Py_DECREF(m_obj);
1303 return PyErr_SetFromWindowsErr(dwErr);
1304 }
1305
1306#if SIZEOF_SIZE_T > 4
1307 m_obj->size = (((size_t)high)<<32) + low;
1308#else
1309 if (high)
1310 /* File is too large to map completely */
1311 m_obj->size = (size_t)-1;
1312 else
1313 m_obj->size = low;
1314#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001315 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001316 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001317 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001318 }
1319 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001320 m_obj->size = map_size;
1321 }
1322
1323 /* set the initial position */
1324 m_obj->pos = (size_t) 0;
1325
Mark Hammond2cbed002000-07-30 02:22:43 +00001326 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001327 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001328 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1329 if (m_obj->tagname == NULL) {
1330 PyErr_NoMemory();
1331 Py_DECREF(m_obj);
1332 return NULL;
1333 }
1334 strcpy(m_obj->tagname, tagname);
1335 }
1336 else
1337 m_obj->tagname = NULL;
1338
Neal Norwitz8856fb72005-12-18 03:34:22 +00001339 m_obj->access = (access_mode)access;
Tim Peterse564e7f2006-02-16 23:46:01 +00001340 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
Thomas Wouters2c98a7b2006-02-17 09:59:00 +00001341 * more than 4 bytes, we need to break it apart. Else (size_t
Tim Peterse564e7f2006-02-16 23:46:01 +00001342 * consumes 4 bytes), C doesn't define what happens if we shift
1343 * right by 32, so we need different code.
1344 */
1345#if SIZEOF_SIZE_T > 4
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001346 size_hi = (DWORD)((offset + m_obj->size) >> 32);
1347 size_lo = (DWORD)((offset + m_obj->size) & 0xFFFFFFFF);
1348 off_hi = (DWORD)(offset >> 32);
1349 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Tim Peterse564e7f2006-02-16 23:46:01 +00001350#else
1351 size_hi = 0;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001352 size_lo = (DWORD)(offset + m_obj->size);
1353 off_hi = 0;
1354 off_lo = (DWORD)offset;
Tim Peterse564e7f2006-02-16 23:46:01 +00001355#endif
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001356 /* For files, it would be sufficient to pass 0 as size.
1357 For anonymous maps, we have to pass the size explicitly. */
Tim Peters8f9cc292006-02-17 00:00:20 +00001358 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1359 NULL,
1360 flProtect,
1361 size_hi,
1362 size_lo,
1363 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001364 if (m_obj->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +00001365 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1366 dwDesiredAccess,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001367 off_hi,
1368 off_lo,
Tim Peters8f9cc292006-02-17 00:00:20 +00001369 0);
Tim Peters23721ee2006-02-16 23:50:16 +00001370 if (m_obj->data != NULL)
1371 return (PyObject *)m_obj;
1372 else
Tim Peters5ebfd362001-11-13 23:11:19 +00001373 dwErr = GetLastError();
Tim Peters23721ee2006-02-16 23:50:16 +00001374 } else
Guido van Rossum09fdf072000-03-31 01:17:07 +00001375 dwErr = GetLastError();
Mark Hammond2cbed002000-07-30 02:22:43 +00001376 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001377 PyErr_SetFromWindowsErr(dwErr);
Tim Peters23721ee2006-02-16 23:50:16 +00001378 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001379}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001380#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001381
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001382static void
1383setint(PyObject *d, const char *name, long value)
1384{
1385 PyObject *o = PyInt_FromLong(value);
Neal Norwitz5ed49972006-08-13 18:41:15 +00001386 if (o && PyDict_SetItemString(d, name, o) == 0) {
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001387 Py_DECREF(o);
Neal Norwitz5ed49972006-08-13 18:41:15 +00001388 }
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001389}
1390
Mark Hammond62b1ab12002-07-23 06:31:15 +00001391PyMODINIT_FUNC
Georg Brandl845c4032008-01-21 14:16:46 +00001392initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001393{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001394 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001395
Georg Brandl845c4032008-01-21 14:16:46 +00001396 if (PyType_Ready(&mmap_object_type) < 0)
1397 return;
Tim Peters2caf8df2001-01-14 05:05:51 +00001398
Georg Brandl845c4032008-01-21 14:16:46 +00001399 module = Py_InitModule("mmap", NULL);
Neal Norwitz1ac754f2006-01-19 06:09:39 +00001400 if (module == NULL)
1401 return;
Tim Peters8f9cc292006-02-17 00:00:20 +00001402 dict = PyModule_GetDict(module);
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001403 if (!dict)
1404 return;
Facundo Batistae1396882008-02-17 18:59:29 +00001405 mmap_module_error = PyErr_NewException("mmap.error",
1406 PyExc_EnvironmentError , NULL);
1407 if (mmap_module_error == NULL)
1408 return;
Tim Peters8f9cc292006-02-17 00:00:20 +00001409 PyDict_SetItemString(dict, "error", mmap_module_error);
Georg Brandl845c4032008-01-21 14:16:46 +00001410 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001411#ifdef PROT_EXEC
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001412 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001413#endif
1414#ifdef PROT_READ
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001415 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001416#endif
1417#ifdef PROT_WRITE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001418 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001419#endif
1420
1421#ifdef MAP_SHARED
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001422 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001423#endif
1424#ifdef MAP_PRIVATE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001425 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001426#endif
1427#ifdef MAP_DENYWRITE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001428 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001429#endif
1430#ifdef MAP_EXECUTABLE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001431 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001432#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001433#ifdef MAP_ANONYMOUS
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001434 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1435 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001436#endif
1437
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001438 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001439
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001440 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
1441
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001442 setint(dict, "ACCESS_READ", ACCESS_READ);
1443 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1444 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Tim Peters5ebfd362001-11-13 23:11:19 +00001445}