blob: 8407c11b3be2ca719ff667b6a6b2d8a8b19fd2b2 [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;
Hirokazu Yamamotof2dc8852009-02-28 10:31:54 +0000368
369 if (self->pos < self->size) {
370 *(self->data+self->pos) = value;
371 self->pos += 1;
372 Py_INCREF(Py_None);
373 return Py_None;
374 }
375 else {
376 PyErr_SetString(PyExc_ValueError, "write byte out of range");
377 return NULL;
378 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000379}
Tim Petersec0a5f02006-02-16 23:47:20 +0000380
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000381static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000382mmap_size_method(mmap_object *self,
Georg Brandl96a8c392006-05-29 21:04:52 +0000383 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000384{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000385 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000386
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000387#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000388 if (self->file_handle != INVALID_HANDLE_VALUE) {
Martin v. Löwis15186072006-02-18 12:38:35 +0000389 DWORD low,high;
390 PY_LONG_LONG size;
391 low = GetFileSize(self->file_handle, &high);
392 if (low == INVALID_FILE_SIZE) {
393 /* It might be that the function appears to have failed,
394 when indeed its size equals INVALID_FILE_SIZE */
395 DWORD error = GetLastError();
396 if (error != NO_ERROR)
397 return PyErr_SetFromWindowsErr(error);
398 }
399 if (!high && low < LONG_MAX)
400 return PyInt_FromLong((long)low);
401 size = (((PY_LONG_LONG)high)<<32) + low;
402 return PyLong_FromLongLong(size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000403 } else {
Martin v. Löwis15186072006-02-18 12:38:35 +0000404 return PyInt_FromSsize_t(self->size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000405 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000406#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000407
408#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000409 {
410 struct stat buf;
411 if (-1 == fstat(self->fd, &buf)) {
412 PyErr_SetFromErrno(mmap_module_error);
413 return NULL;
414 }
Martin v. Löwis15186072006-02-18 12:38:35 +0000415 return PyInt_FromSsize_t(buf.st_size);
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000416 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000417#endif /* UNIX */
418}
419
420/* This assumes that you want the entire file mapped,
421 / and when recreating the map will make the new file
422 / have the new size
423 /
424 / Is this really necessary? This could easily be done
425 / from python by just closing and re-opening with the
426 / new size?
427 */
428
429static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000430mmap_resize_method(mmap_object *self,
431 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000432{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000433 Py_ssize_t new_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000434 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000435 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000436 !is_resizeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000437 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000438#ifdef MS_WINDOWS
Tim Petersec0a5f02006-02-16 23:47:20 +0000439 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000440 DWORD dwErrCode = 0;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +0000441 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000442 /* First, unmap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000443 UnmapViewOfFile(self->data);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000444 /* Close the mapping object */
Tim Peters8f9cc292006-02-17 00:00:20 +0000445 CloseHandle(self->map_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000446 /* Move to the desired EOF position */
Martin v. Löwis15186072006-02-18 12:38:35 +0000447#if SIZEOF_SIZE_T > 4
Travis E. Oliphant8feafab2007-10-23 02:40:56 +0000448 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
449 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
450 off_hi = (DWORD)(self->offset >> 32);
451 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Martin v. Löwis15186072006-02-18 12:38:35 +0000452#else
453 newSizeHigh = 0;
Hirokazu Yamamoto17a837e2009-02-17 13:17:26 +0000454 newSizeLow = (DWORD)(self->offset + new_size);
Travis E. Oliphant8feafab2007-10-23 02:40:56 +0000455 off_hi = 0;
456 off_lo = (DWORD)self->offset;
Martin v. Löwis15186072006-02-18 12:38:35 +0000457#endif
Tim Peters8f9cc292006-02-17 00:00:20 +0000458 SetFilePointer(self->file_handle,
Martin v. Löwis15186072006-02-18 12:38:35 +0000459 newSizeLow, &newSizeHigh, FILE_BEGIN);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000460 /* Change the size of the file */
Tim Peters8f9cc292006-02-17 00:00:20 +0000461 SetEndOfFile(self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000462 /* Create another mapping object and remap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000463 self->map_handle = CreateFileMapping(
Mark Hammond071864a2000-07-30 02:46:26 +0000464 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000465 NULL,
466 PAGE_READWRITE,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +0000467 0,
468 0,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000469 self->tagname);
470 if (self->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000471 self->data = (char *) MapViewOfFile(self->map_handle,
472 FILE_MAP_WRITE,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +0000473 off_hi,
474 off_lo,
475 new_size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000476 if (self->data != NULL) {
477 self->size = new_size;
Tim Peters8f9cc292006-02-17 00:00:20 +0000478 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000479 return Py_None;
480 } else {
481 dwErrCode = GetLastError();
482 }
483 } else {
484 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000485 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000486 PyErr_SetFromWindowsErr(dwErrCode);
Tim Peters23721ee2006-02-16 23:50:16 +0000487 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000488#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000489
490#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000491#ifndef HAVE_MREMAP
Tim Peters5ebfd362001-11-13 23:11:19 +0000492 } else {
493 PyErr_SetString(PyExc_SystemError,
494 "mmap: resizing not available--no mremap()");
495 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000496#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000497 } else {
Armin Rigo335ffe82005-09-20 19:04:02 +0000498 void *newmap;
499
Hirokazu Yamamoto17a837e2009-02-17 13:17:26 +0000500 if (ftruncate(self->fd, self->offset + new_size) == -1) {
Georg Brandl38387b82005-08-24 07:17:40 +0000501 PyErr_SetFromErrno(mmap_module_error);
502 return NULL;
503 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000504
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000505#ifdef MREMAP_MAYMOVE
Tim Peters5ebfd362001-11-13 23:11:19 +0000506 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000507#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000508 newmap = mremap(self->data, self->size, new_size, 0);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000509#endif
Tim Petersec0a5f02006-02-16 23:47:20 +0000510 if (newmap == (void *)-1)
Tim Peters5ebfd362001-11-13 23:11:19 +0000511 {
512 PyErr_SetFromErrno(mmap_module_error);
513 return NULL;
514 }
515 self->data = newmap;
516 self->size = new_size;
517 Py_INCREF(Py_None);
518 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000519#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000520#endif /* UNIX */
Tim Peters5ebfd362001-11-13 23:11:19 +0000521 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000522}
523
524static PyObject *
Georg Brandl96a8c392006-05-29 21:04:52 +0000525mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000526{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000527 CHECK_VALID(NULL);
Neal Norwitz670f8752006-08-22 13:56:56 +0000528 return PyInt_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000529}
530
531static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000532mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000533{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000534 Py_ssize_t offset = 0;
535 Py_ssize_t size = self->size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000536 CHECK_VALID(NULL);
Tim Petersf2882952006-02-17 01:07:39 +0000537 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000538 return NULL;
Tim Petersf2882952006-02-17 01:07:39 +0000539 if ((size_t)(offset + size) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000540 PyErr_SetString(PyExc_ValueError, "flush values out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000541 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000542 }
Neal Norwitz448654f2008-01-27 07:36:03 +0000543#ifdef MS_WINDOWS
544 return PyInt_FromLong((long) FlushViewOfFile(self->data+offset, size));
545#elif defined(UNIX)
546 /* XXX semantics of return value? */
547 /* XXX flags for msync? */
548 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
549 PyErr_SetFromErrno(mmap_module_error);
550 return NULL;
551 }
552 return PyInt_FromLong(0);
553#else
554 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
555 return NULL;
556#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000557}
558
559static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000560mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000561{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000562 Py_ssize_t dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000563 int how=0;
564 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000565 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
Tim Peters8f9cc292006-02-17 00:00:20 +0000566 return NULL;
567 else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000568 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000569 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000570 case 0: /* relative to start */
571 if (dist < 0)
572 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000573 where = dist;
574 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000575 case 1: /* relative to current position */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000576 if ((Py_ssize_t)self->pos + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000577 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000578 where = self->pos + dist;
579 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000580 case 2: /* relative to end */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000581 if ((Py_ssize_t)self->size + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000582 goto onoutofrange;
583 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000584 break;
585 default:
Tim Peters8f9cc292006-02-17 00:00:20 +0000586 PyErr_SetString(PyExc_ValueError, "unknown seek type");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000587 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000588 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000589 if (where > self->size)
590 goto onoutofrange;
591 self->pos = where;
Tim Peters8f9cc292006-02-17 00:00:20 +0000592 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000593 return Py_None;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000594 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000595
Tim Peters5ebfd362001-11-13 23:11:19 +0000596 onoutofrange:
Tim Peters8f9cc292006-02-17 00:00:20 +0000597 PyErr_SetString(PyExc_ValueError, "seek out of range");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000598 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000599}
600
601static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000602mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000603{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000604 unsigned long dest, src, count;
605 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000606 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &count) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000607 !is_writeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000608 return NULL;
609 } else {
610 /* bounds check the values */
611 if (/* end of source after end of data?? */
612 ((src+count) > self->size)
613 /* dest will fit? */
614 || (dest+count > self->size)) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000615 PyErr_SetString(PyExc_ValueError,
616 "source or destination out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000617 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000618 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000619 memmove(self->data+dest, self->data+src, count);
620 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000621 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000622 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000623 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000624}
625
626static struct PyMethodDef mmap_object_methods[] = {
Georg Brandl96a8c392006-05-29 21:04:52 +0000627 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000628 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000629 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000630 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
631 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
632 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
Georg Brandl96a8c392006-05-29 21:04:52 +0000633 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
634 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000635 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
636 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
Georg Brandl96a8c392006-05-29 21:04:52 +0000637 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
638 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000639 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
640 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000641 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000642};
643
644/* Functions for treating an mmap'ed file as a buffer */
645
Martin v. Löwis18e16552006-02-15 17:27:45 +0000646static Py_ssize_t
647mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000648{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000649 CHECK_VALID(-1);
Tim Peters8f9cc292006-02-17 00:00:20 +0000650 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000651 PyErr_SetString(PyExc_SystemError,
652 "Accessing non-existent mmap segment");
653 return -1;
654 }
655 *ptr = self->data;
656 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000657}
658
Martin v. Löwis18e16552006-02-15 17:27:45 +0000659static Py_ssize_t
660mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Tim Petersec0a5f02006-02-16 23:47:20 +0000661{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000662 CHECK_VALID(-1);
Tim Peters8f9cc292006-02-17 00:00:20 +0000663 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000664 PyErr_SetString(PyExc_SystemError,
665 "Accessing non-existent mmap segment");
666 return -1;
667 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000668 if (!is_writeable(self))
669 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000670 *ptr = self->data;
671 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000672}
673
Martin v. Löwis18e16552006-02-15 17:27:45 +0000674static Py_ssize_t
675mmap_buffer_getsegcount(mmap_object *self, Py_ssize_t *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000676{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000677 CHECK_VALID(-1);
Tim Petersec0a5f02006-02-16 23:47:20 +0000678 if (lenp)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000679 *lenp = self->size;
680 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000681}
682
Martin v. Löwis18e16552006-02-15 17:27:45 +0000683static Py_ssize_t
684mmap_buffer_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000685{
Tim Peters8f9cc292006-02-17 00:00:20 +0000686 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000687 PyErr_SetString(PyExc_SystemError,
688 "accessing non-existent buffer segment");
689 return -1;
690 }
691 *ptr = (const char *)self->data;
692 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000693}
694
Martin v. Löwis18e16552006-02-15 17:27:45 +0000695static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000696mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000697{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000698 CHECK_VALID(-1);
699 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000700}
701
702static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000703mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000704{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000705 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000706 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000707 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
708 return NULL;
709 }
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000710 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000711}
712
713static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000714mmap_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000715{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000716 CHECK_VALID(NULL);
717 if (ilow < 0)
718 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000719 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000720 ilow = self->size;
721 if (ihigh < 0)
722 ihigh = 0;
723 if (ihigh < ilow)
724 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000725 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000726 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000727
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000728 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000729}
730
731static PyObject *
Thomas Wouters3ccec682007-08-28 15:28:19 +0000732mmap_subscript(mmap_object *self, PyObject *item)
733{
734 CHECK_VALID(NULL);
735 if (PyIndex_Check(item)) {
736 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
737 if (i == -1 && PyErr_Occurred())
738 return NULL;
739 if (i < 0)
740 i += self->size;
Hirokazu Yamamotof6bbd0e2009-02-17 10:12:10 +0000741 if (i < 0 || (size_t)i >= self->size) {
Thomas Wouters3ccec682007-08-28 15:28:19 +0000742 PyErr_SetString(PyExc_IndexError,
743 "mmap index out of range");
744 return NULL;
745 }
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000746 return PyString_FromStringAndSize(self->data + i, 1);
Thomas Wouters3ccec682007-08-28 15:28:19 +0000747 }
748 else if (PySlice_Check(item)) {
749 Py_ssize_t start, stop, step, slicelen;
750
751 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
752 &start, &stop, &step, &slicelen) < 0) {
753 return NULL;
754 }
755
756 if (slicelen <= 0)
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000757 return PyString_FromStringAndSize("", 0);
Thomas Wouters3ccec682007-08-28 15:28:19 +0000758 else if (step == 1)
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000759 return PyString_FromStringAndSize(self->data + start,
Thomas Wouters3ccec682007-08-28 15:28:19 +0000760 slicelen);
761 else {
762 char *result_buf = (char *)PyMem_Malloc(slicelen);
763 Py_ssize_t cur, i;
764 PyObject *result;
765
766 if (result_buf == NULL)
767 return PyErr_NoMemory();
768 for (cur = start, i = 0; i < slicelen;
769 cur += step, i++) {
770 result_buf[i] = self->data[cur];
771 }
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000772 result = PyString_FromStringAndSize(result_buf,
Thomas Wouters3ccec682007-08-28 15:28:19 +0000773 slicelen);
774 PyMem_Free(result_buf);
775 return result;
776 }
777 }
778 else {
779 PyErr_SetString(PyExc_TypeError,
780 "mmap indices must be integers");
781 return NULL;
782 }
783}
784
785static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000786mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000787{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000788 CHECK_VALID(NULL);
789 PyErr_SetString(PyExc_SystemError,
790 "mmaps don't support concatenation");
791 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000792}
793
794static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000795mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000796{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000797 CHECK_VALID(NULL);
798 PyErr_SetString(PyExc_SystemError,
799 "mmaps don't support repeat operation");
800 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000801}
802
803static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000804mmap_ass_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000805{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000806 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000807
Guido van Rossum09fdf072000-03-31 01:17:07 +0000808 CHECK_VALID(-1);
809 if (ilow < 0)
810 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000811 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000812 ilow = self->size;
813 if (ihigh < 0)
814 ihigh = 0;
815 if (ihigh < ilow)
816 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000817 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000818 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000819
Thomas Wouters1baac722001-07-16 15:47:36 +0000820 if (v == NULL) {
821 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000822 "mmap object doesn't support slice deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000823 return -1;
824 }
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000825 if (! (PyString_Check(v)) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000826 PyErr_SetString(PyExc_IndexError,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000827 "mmap slice assignment must be a string");
828 return -1;
829 }
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000830 if (PyString_Size(v) != (ihigh - ilow)) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000831 PyErr_SetString(PyExc_IndexError,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000832 "mmap slice assignment is wrong size");
833 return -1;
834 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000835 if (!is_writeable(self))
836 return -1;
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000837 buf = PyString_AsString(v);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000838 memcpy(self->data + ilow, buf, ihigh-ilow);
839 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000840}
841
842static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000843mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000844{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000845 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000846
Guido van Rossum09fdf072000-03-31 01:17:07 +0000847 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000848 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000849 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
850 return -1;
851 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000852 if (v == NULL) {
853 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000854 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000855 return -1;
856 }
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000857 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000858 PyErr_SetString(PyExc_IndexError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000859 "mmap assignment must be single-character string");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000860 return -1;
861 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000862 if (!is_writeable(self))
863 return -1;
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000864 buf = PyString_AsString(v);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000865 self->data[i] = buf[0];
866 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000867}
868
Thomas Wouters3ccec682007-08-28 15:28:19 +0000869static int
870mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
871{
872 CHECK_VALID(-1);
873
874 if (PyIndex_Check(item)) {
875 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
876 const char *buf;
877
878 if (i == -1 && PyErr_Occurred())
879 return -1;
880 if (i < 0)
881 i += self->size;
Hirokazu Yamamotof6bbd0e2009-02-17 10:12:10 +0000882 if (i < 0 || (size_t)i >= self->size) {
Thomas Wouters3ccec682007-08-28 15:28:19 +0000883 PyErr_SetString(PyExc_IndexError,
884 "mmap index out of range");
885 return -1;
886 }
887 if (value == NULL) {
888 PyErr_SetString(PyExc_TypeError,
889 "mmap object doesn't support item deletion");
890 return -1;
891 }
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000892 if (!PyString_Check(value) || PyString_Size(value) != 1) {
Thomas Wouters3ccec682007-08-28 15:28:19 +0000893 PyErr_SetString(PyExc_IndexError,
894 "mmap assignment must be single-character string");
895 return -1;
896 }
897 if (!is_writeable(self))
898 return -1;
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000899 buf = PyString_AsString(value);
Thomas Wouters3ccec682007-08-28 15:28:19 +0000900 self->data[i] = buf[0];
901 return 0;
902 }
903 else if (PySlice_Check(item)) {
904 Py_ssize_t start, stop, step, slicelen;
905
906 if (PySlice_GetIndicesEx((PySliceObject *)item,
907 self->size, &start, &stop,
908 &step, &slicelen) < 0) {
909 return -1;
910 }
911 if (value == NULL) {
912 PyErr_SetString(PyExc_TypeError,
913 "mmap object doesn't support slice deletion");
914 return -1;
915 }
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000916 if (!PyString_Check(value)) {
Thomas Wouters3ccec682007-08-28 15:28:19 +0000917 PyErr_SetString(PyExc_IndexError,
918 "mmap slice assignment must be a string");
919 return -1;
920 }
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000921 if (PyString_Size(value) != slicelen) {
Thomas Wouters3ccec682007-08-28 15:28:19 +0000922 PyErr_SetString(PyExc_IndexError,
923 "mmap slice assignment is wrong size");
924 return -1;
925 }
926 if (!is_writeable(self))
927 return -1;
928
929 if (slicelen == 0)
930 return 0;
931 else if (step == 1) {
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000932 const char *buf = PyString_AsString(value);
Thomas Wouters3ccec682007-08-28 15:28:19 +0000933
934 if (buf == NULL)
935 return -1;
936 memcpy(self->data + start, buf, slicelen);
937 return 0;
938 }
939 else {
940 Py_ssize_t cur, i;
Gregory P. Smithdd96db62008-06-09 04:58:54 +0000941 const char *buf = PyString_AsString(value);
Thomas Wouters3ccec682007-08-28 15:28:19 +0000942
943 if (buf == NULL)
944 return -1;
945 for (cur = start, i = 0; i < slicelen;
946 cur += step, i++) {
947 self->data[cur] = buf[i];
948 }
949 return 0;
950 }
951 }
952 else {
953 PyErr_SetString(PyExc_TypeError,
954 "mmap indices must be integer");
955 return -1;
956 }
957}
958
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000959static PySequenceMethods mmap_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000960 (lenfunc)mmap_length, /*sq_length*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000961 (binaryfunc)mmap_concat, /*sq_concat*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000962 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
963 (ssizeargfunc)mmap_item, /*sq_item*/
964 (ssizessizeargfunc)mmap_slice, /*sq_slice*/
965 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
966 (ssizessizeobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000967};
968
Thomas Wouters3ccec682007-08-28 15:28:19 +0000969static PyMappingMethods mmap_as_mapping = {
970 (lenfunc)mmap_length,
971 (binaryfunc)mmap_subscript,
972 (objobjargproc)mmap_ass_subscript,
973};
974
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000975static PyBufferProcs mmap_as_buffer = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000976 (readbufferproc)mmap_buffer_getreadbuf,
977 (writebufferproc)mmap_buffer_getwritebuf,
978 (segcountproc)mmap_buffer_getsegcount,
979 (charbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000980};
981
Georg Brandl845c4032008-01-21 14:16:46 +0000982static PyObject *
983new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
984
Georg Brandlef928022008-01-20 14:50:05 +0000985PyDoc_STRVAR(mmap_doc,
986"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
987\n\
988Maps length bytes from the file specified by the file handle fileno,\n\
989and returns a mmap object. If length is larger than the current size\n\
990of the file, the file is extended to contain length bytes. If length\n\
991is 0, the maximum length of the map is the current size of the file,\n\
992except that if the file is empty Windows raises an exception (you cannot\n\
993create an empty mapping on Windows).\n\
994\n\
995Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
996\n\
997Maps length bytes from the file specified by the file descriptor fileno,\n\
998and returns a mmap object. If length is 0, the maximum length of the map\n\
999will be the current size of the file when mmap is called.\n\
1000flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1001private copy-on-write mapping, so changes to the contents of the mmap\n\
Thomas Heller66260992008-08-19 17:47:13 +00001002object will be private to this process, and MAP_SHARED creates a mapping\n\
Georg Brandlef928022008-01-20 14:50:05 +00001003that's shared with all other processes mapping the same areas of the file.\n\
1004The default value is MAP_SHARED.\n\
1005\n\
1006To map anonymous memory, pass -1 as the fileno (both versions).");
1007
1008
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001009static PyTypeObject mmap_object_type = {
Georg Brandl845c4032008-01-21 14:16:46 +00001010 PyVarObject_HEAD_INIT(NULL, 0)
Guido van Rossum14648392001-12-08 18:02:58 +00001011 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +00001012 sizeof(mmap_object), /* tp_size */
1013 0, /* tp_itemsize */
1014 /* methods */
1015 (destructor) mmap_object_dealloc, /* tp_dealloc */
1016 0, /* tp_print */
Georg Brandlef928022008-01-20 14:50:05 +00001017 0, /* tp_getattr */
Guido van Rossum09fdf072000-03-31 01:17:07 +00001018 0, /* tp_setattr */
1019 0, /* tp_compare */
1020 0, /* tp_repr */
1021 0, /* tp_as_number */
1022 &mmap_as_sequence, /*tp_as_sequence*/
Thomas Wouters3ccec682007-08-28 15:28:19 +00001023 &mmap_as_mapping, /*tp_as_mapping*/
Guido van Rossum09fdf072000-03-31 01:17:07 +00001024 0, /*tp_hash*/
1025 0, /*tp_call*/
1026 0, /*tp_str*/
Georg Brandlef928022008-01-20 14:50:05 +00001027 PyObject_GenericGetAttr, /*tp_getattro*/
Guido van Rossum09fdf072000-03-31 01:17:07 +00001028 0, /*tp_setattro*/
1029 &mmap_as_buffer, /*tp_as_buffer*/
Georg Brandl845c4032008-01-21 14:16:46 +00001030 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
Georg Brandlef928022008-01-20 14:50:05 +00001031 mmap_doc, /*tp_doc*/
1032 0, /* tp_traverse */
1033 0, /* tp_clear */
1034 0, /* tp_richcompare */
1035 0, /* tp_weaklistoffset */
Georg Brandl845c4032008-01-21 14:16:46 +00001036 0, /* tp_iter */
1037 0, /* tp_iternext */
Georg Brandlef928022008-01-20 14:50:05 +00001038 mmap_object_methods, /* tp_methods */
Georg Brandl845c4032008-01-21 14:16:46 +00001039 0, /* tp_members */
1040 0, /* tp_getset */
1041 0, /* tp_base */
1042 0, /* tp_dict */
1043 0, /* tp_descr_get */
1044 0, /* tp_descr_set */
1045 0, /* tp_dictoffset */
1046 0, /* tp_init */
1047 PyType_GenericAlloc, /* tp_alloc */
1048 new_mmap_object, /* tp_new */
1049 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001050};
1051
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001052
1053/* extract the map size from the given PyObject
1054
Thomas Wouters7e474022000-07-16 12:04:32 +00001055 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001056 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001057static Py_ssize_t
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001058_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001059{
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001060 if (o == NULL)
1061 return 0;
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001062 if (PyIndex_Check(o)) {
1063 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
Guido van Rossum38fff8c2006-03-07 18:50:55 +00001064 if (i==-1 && PyErr_Occurred())
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001065 return -1;
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001066 if (i < 0) {
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001067 PyErr_Format(PyExc_OverflowError,
1068 "memory mapped %s must be positive",
1069 param);
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001070 return -1;
1071 }
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001072 return i;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001073 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001074
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001075 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001076 return -1;
1077}
1078
Tim Petersec0a5f02006-02-16 23:47:20 +00001079#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001080static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001081new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001082{
Neal Norwitzb5673922002-09-05 21:48:07 +00001083#ifdef HAVE_FSTAT
1084 struct stat st;
1085#endif
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001086 mmap_object *m_obj;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001087 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1088 Py_ssize_t map_size, offset;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001089 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001090 int devzero = -1;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001091 int access = (int)ACCESS_DEFAULT;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001092 static char *keywords[] = {"fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001093 "flags", "prot",
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001094 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001095
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001096 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iiiO", keywords,
Jeremy Hyltonaf68c872005-12-10 18:50:16 +00001097 &fd, &map_size_obj, &flags, &prot,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001098 &access, &offset_obj))
Guido van Rossum09fdf072000-03-31 01:17:07 +00001099 return NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001100 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001101 if (map_size < 0)
1102 return NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001103 offset = _GetMapSize(offset_obj, "offset");
1104 if (offset < 0)
1105 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001106
Tim Petersec0a5f02006-02-16 23:47:20 +00001107 if ((access != (int)ACCESS_DEFAULT) &&
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001108 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
Tim Petersec0a5f02006-02-16 23:47:20 +00001109 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001110 "mmap can't specify both access and flags, prot.");
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001111 switch ((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001112 case ACCESS_READ:
1113 flags = MAP_SHARED;
1114 prot = PROT_READ;
1115 break;
1116 case ACCESS_WRITE:
1117 flags = MAP_SHARED;
1118 prot = PROT_READ | PROT_WRITE;
1119 break;
1120 case ACCESS_COPY:
1121 flags = MAP_PRIVATE;
1122 prot = PROT_READ | PROT_WRITE;
1123 break;
Tim Petersec0a5f02006-02-16 23:47:20 +00001124 case ACCESS_DEFAULT:
Tim Peters5ebfd362001-11-13 23:11:19 +00001125 /* use the specified or default values of flags and prot */
1126 break;
1127 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001128 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001129 "mmap invalid access parameter.");
1130 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001131
Christian Heimes7adfad82008-02-15 08:20:11 +00001132 if (prot == PROT_READ) {
1133 access = ACCESS_READ;
1134 }
1135
Neal Norwitzb5673922002-09-05 21:48:07 +00001136#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001137# ifdef __VMS
1138 /* on OpenVMS we must ensure that all bytes are written to the file */
Andrew M. Kuchling7c22ccc2008-01-10 13:37:12 +00001139 if (fd != -1) {
1140 fsync(fd);
1141 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001142# endif
Andrew M. Kuchling7c22ccc2008-01-10 13:37:12 +00001143 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001144 if (map_size == 0) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001145 map_size = st.st_size;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001146 } else if ((size_t)offset + (size_t)map_size > st.st_size) {
Tim Petersec0a5f02006-02-16 23:47:20 +00001147 PyErr_SetString(PyExc_ValueError,
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001148 "mmap length is greater than file size");
1149 return NULL;
1150 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001151 }
1152#endif
Georg Brandl845c4032008-01-21 14:16:46 +00001153 m_obj = (mmap_object *)type->tp_alloc(type, 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001154 if (m_obj == NULL) {return NULL;}
Neal Norwitz3b4fff82006-01-11 08:54:45 +00001155 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001156 m_obj->size = (size_t) map_size;
1157 m_obj->pos = (size_t) 0;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001158 m_obj->offset = offset;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001159 if (fd == -1) {
1160 m_obj->fd = -1;
1161 /* Assume the caller wants to map anonymous memory.
1162 This is the same behaviour as Windows. mmap.mmap(-1, size)
1163 on both Windows and Unix map anonymous memory.
1164 */
1165#ifdef MAP_ANONYMOUS
1166 /* BSD way to map anonymous memory */
1167 flags |= MAP_ANONYMOUS;
1168#else
1169 /* SVR4 method to map anonymous memory is to open /dev/zero */
1170 fd = devzero = open("/dev/zero", O_RDWR);
1171 if (devzero == -1) {
1172 Py_DECREF(m_obj);
1173 PyErr_SetFromErrno(mmap_module_error);
1174 return NULL;
1175 }
1176#endif
1177 } else {
1178 m_obj->fd = dup(fd);
1179 if (m_obj->fd == -1) {
1180 Py_DECREF(m_obj);
1181 PyErr_SetFromErrno(mmap_module_error);
1182 return NULL;
1183 }
Georg Brandl38387b82005-08-24 07:17:40 +00001184 }
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001185
Tim Petersec0a5f02006-02-16 23:47:20 +00001186 m_obj->data = mmap(NULL, map_size,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001187 prot, flags,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001188 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001189
1190 if (devzero != -1) {
1191 close(devzero);
1192 }
1193
Tim Peters5ebfd362001-11-13 23:11:19 +00001194 if (m_obj->data == (char *)-1) {
Andrew M. Kuchling16581c82004-05-19 14:39:08 +00001195 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001196 Py_DECREF(m_obj);
1197 PyErr_SetFromErrno(mmap_module_error);
1198 return NULL;
1199 }
Neal Norwitz8856fb72005-12-18 03:34:22 +00001200 m_obj->access = (access_mode)access;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001201 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001202}
1203#endif /* UNIX */
1204
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001205#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001206static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001207new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001208{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001209 mmap_object *m_obj;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001210 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1211 Py_ssize_t map_size, offset;
1212 DWORD off_hi; /* upper 32 bits of offset */
1213 DWORD off_lo; /* lower 32 bits of offset */
1214 DWORD size_hi; /* upper 32 bits of size */
1215 DWORD size_lo; /* lower 32 bits of size */
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001216 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +00001217 DWORD dwErr = 0;
1218 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +00001219 HANDLE fh = 0;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001220 int access = (access_mode)ACCESS_DEFAULT;
Tim Peters5ebfd362001-11-13 23:11:19 +00001221 DWORD flProtect, dwDesiredAccess;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001222 static char *keywords[] = { "fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001223 "tagname",
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001224 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001225
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001226 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
Tim Petersec0a5f02006-02-16 23:47:20 +00001227 &fileno, &map_size_obj,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001228 &tagname, &access, &offset_obj)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001229 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001230 }
1231
Neal Norwitz8856fb72005-12-18 03:34:22 +00001232 switch((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001233 case ACCESS_READ:
1234 flProtect = PAGE_READONLY;
1235 dwDesiredAccess = FILE_MAP_READ;
1236 break;
1237 case ACCESS_DEFAULT: case ACCESS_WRITE:
1238 flProtect = PAGE_READWRITE;
1239 dwDesiredAccess = FILE_MAP_WRITE;
1240 break;
1241 case ACCESS_COPY:
1242 flProtect = PAGE_WRITECOPY;
1243 dwDesiredAccess = FILE_MAP_COPY;
1244 break;
1245 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001246 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001247 "mmap invalid access parameter.");
1248 }
1249
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001250 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001251 if (map_size < 0)
1252 return NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001253 offset = _GetMapSize(offset_obj, "offset");
1254 if (offset < 0)
1255 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001256
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001257 /* assume -1 and 0 both mean invalid filedescriptor
1258 to 'anonymously' map memory.
1259 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1260 XXX: Should this code be added?
1261 if (fileno == 0)
1262 PyErr_Warn(PyExc_DeprecationWarning,
1263 "don't use 0 for anonymous memory");
1264 */
1265 if (fileno != -1 && fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +00001266 fh = (HANDLE)_get_osfhandle(fileno);
1267 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001268 PyErr_SetFromErrno(mmap_module_error);
1269 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001270 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +00001271 /* Win9x appears to need us seeked to zero */
Guido van Rossum69c2b882003-04-09 19:31:02 +00001272 lseek(fileno, 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001273 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001274
Georg Brandl845c4032008-01-21 14:16:46 +00001275 m_obj = (mmap_object *)type->tp_alloc(type, 0);
Tim Peters8f9cc292006-02-17 00:00:20 +00001276 if (m_obj == NULL)
Mark Hammond2cbed002000-07-30 02:22:43 +00001277 return NULL;
1278 /* Set every field to an invalid marker, so we can safely
1279 destruct the object in the face of failure */
1280 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +00001281 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +00001282 m_obj->map_handle = INVALID_HANDLE_VALUE;
1283 m_obj->tagname = NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001284 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001285
Guido van Rossum09fdf072000-03-31 01:17:07 +00001286 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +00001287 /* It is necessary to duplicate the handle, so the
1288 Python code can close it on us */
1289 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +00001290 GetCurrentProcess(), /* source process handle */
1291 fh, /* handle to be duplicated */
1292 GetCurrentProcess(), /* target proc handle */
1293 (LPHANDLE)&m_obj->file_handle, /* result */
1294 0, /* access - ignored due to options value */
1295 FALSE, /* inherited by child processes? */
1296 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +00001297 dwErr = GetLastError();
1298 Py_DECREF(m_obj);
1299 PyErr_SetFromWindowsErr(dwErr);
1300 return NULL;
1301 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001302 if (!map_size) {
Martin v. Löwis15186072006-02-18 12:38:35 +00001303 DWORD low,high;
1304 low = GetFileSize(fh, &high);
1305 /* low might just happen to have the value INVALID_FILE_SIZE;
1306 so we need to check the last error also. */
1307 if (low == INVALID_FILE_SIZE &&
1308 (dwErr = GetLastError()) != NO_ERROR) {
1309 Py_DECREF(m_obj);
1310 return PyErr_SetFromWindowsErr(dwErr);
1311 }
1312
1313#if SIZEOF_SIZE_T > 4
1314 m_obj->size = (((size_t)high)<<32) + low;
1315#else
1316 if (high)
1317 /* File is too large to map completely */
1318 m_obj->size = (size_t)-1;
1319 else
1320 m_obj->size = low;
1321#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001322 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001323 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001324 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001325 }
1326 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001327 m_obj->size = map_size;
1328 }
1329
1330 /* set the initial position */
1331 m_obj->pos = (size_t) 0;
1332
Mark Hammond2cbed002000-07-30 02:22:43 +00001333 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001334 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001335 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1336 if (m_obj->tagname == NULL) {
1337 PyErr_NoMemory();
1338 Py_DECREF(m_obj);
1339 return NULL;
1340 }
1341 strcpy(m_obj->tagname, tagname);
1342 }
1343 else
1344 m_obj->tagname = NULL;
1345
Neal Norwitz8856fb72005-12-18 03:34:22 +00001346 m_obj->access = (access_mode)access;
Tim Peterse564e7f2006-02-16 23:46:01 +00001347 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
Thomas Wouters2c98a7b2006-02-17 09:59:00 +00001348 * more than 4 bytes, we need to break it apart. Else (size_t
Tim Peterse564e7f2006-02-16 23:46:01 +00001349 * consumes 4 bytes), C doesn't define what happens if we shift
1350 * right by 32, so we need different code.
1351 */
1352#if SIZEOF_SIZE_T > 4
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001353 size_hi = (DWORD)((offset + m_obj->size) >> 32);
1354 size_lo = (DWORD)((offset + m_obj->size) & 0xFFFFFFFF);
1355 off_hi = (DWORD)(offset >> 32);
1356 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Tim Peterse564e7f2006-02-16 23:46:01 +00001357#else
1358 size_hi = 0;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001359 size_lo = (DWORD)(offset + m_obj->size);
1360 off_hi = 0;
1361 off_lo = (DWORD)offset;
Tim Peterse564e7f2006-02-16 23:46:01 +00001362#endif
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001363 /* For files, it would be sufficient to pass 0 as size.
1364 For anonymous maps, we have to pass the size explicitly. */
Tim Peters8f9cc292006-02-17 00:00:20 +00001365 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1366 NULL,
1367 flProtect,
1368 size_hi,
1369 size_lo,
1370 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001371 if (m_obj->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +00001372 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1373 dwDesiredAccess,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001374 off_hi,
1375 off_lo,
Tim Peters8f9cc292006-02-17 00:00:20 +00001376 0);
Tim Peters23721ee2006-02-16 23:50:16 +00001377 if (m_obj->data != NULL)
1378 return (PyObject *)m_obj;
1379 else
Tim Peters5ebfd362001-11-13 23:11:19 +00001380 dwErr = GetLastError();
Tim Peters23721ee2006-02-16 23:50:16 +00001381 } else
Guido van Rossum09fdf072000-03-31 01:17:07 +00001382 dwErr = GetLastError();
Mark Hammond2cbed002000-07-30 02:22:43 +00001383 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001384 PyErr_SetFromWindowsErr(dwErr);
Tim Peters23721ee2006-02-16 23:50:16 +00001385 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001386}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001387#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001388
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001389static void
1390setint(PyObject *d, const char *name, long value)
1391{
1392 PyObject *o = PyInt_FromLong(value);
Neal Norwitz5ed49972006-08-13 18:41:15 +00001393 if (o && PyDict_SetItemString(d, name, o) == 0) {
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001394 Py_DECREF(o);
Neal Norwitz5ed49972006-08-13 18:41:15 +00001395 }
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001396}
1397
Mark Hammond62b1ab12002-07-23 06:31:15 +00001398PyMODINIT_FUNC
Georg Brandl845c4032008-01-21 14:16:46 +00001399initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001400{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001401 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001402
Georg Brandl845c4032008-01-21 14:16:46 +00001403 if (PyType_Ready(&mmap_object_type) < 0)
1404 return;
Tim Peters2caf8df2001-01-14 05:05:51 +00001405
Georg Brandl845c4032008-01-21 14:16:46 +00001406 module = Py_InitModule("mmap", NULL);
Neal Norwitz1ac754f2006-01-19 06:09:39 +00001407 if (module == NULL)
1408 return;
Tim Peters8f9cc292006-02-17 00:00:20 +00001409 dict = PyModule_GetDict(module);
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001410 if (!dict)
1411 return;
Facundo Batistae1396882008-02-17 18:59:29 +00001412 mmap_module_error = PyErr_NewException("mmap.error",
1413 PyExc_EnvironmentError , NULL);
1414 if (mmap_module_error == NULL)
1415 return;
Tim Peters8f9cc292006-02-17 00:00:20 +00001416 PyDict_SetItemString(dict, "error", mmap_module_error);
Georg Brandl845c4032008-01-21 14:16:46 +00001417 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001418#ifdef PROT_EXEC
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001419 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001420#endif
1421#ifdef PROT_READ
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001422 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001423#endif
1424#ifdef PROT_WRITE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001425 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001426#endif
1427
1428#ifdef MAP_SHARED
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001429 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001430#endif
1431#ifdef MAP_PRIVATE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001432 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001433#endif
1434#ifdef MAP_DENYWRITE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001435 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001436#endif
1437#ifdef MAP_EXECUTABLE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001438 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001439#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001440#ifdef MAP_ANONYMOUS
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001441 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1442 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001443#endif
1444
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001445 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001446
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001447 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
1448
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001449 setint(dict, "ACCESS_READ", ACCESS_READ);
1450 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1451 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Tim Peters5ebfd362001-11-13 23:11:19 +00001452}