blob: bc153c96a6c03a0fd27af2fcba21bfa71965e8b0 [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. */
Andrew M. Kuchling70d27422000-06-18 04:45:14 +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 */
242 if ((self->pos + num_bytes) > self->size) {
243 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;
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000256 Py_ssize_t end = self->size;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000257 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 {
Greg Stein834f4dd2001-05-14 09:32:26 +0000265 char *p;
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000266 char 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
282 start += (Py_ssize_t)self->data;
283 end += (Py_ssize_t)self->data;
284
285 for (p = (char *)(reverse ? end - len : start);
286 p >= (char *)start && p + len <= (char *)end; 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;
535 } else {
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000536#ifdef MS_WINDOWS
Georg Brandl2cfaa342006-05-29 19:39:45 +0000537 return PyInt_FromLong((long)
Tim Peters23721ee2006-02-16 23:50:16 +0000538 FlushViewOfFile(self->data+offset, size));
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000539#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000540#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000541 /* XXX semantics of return value? */
542 /* XXX flags for msync? */
543 if (-1 == msync(self->data + offset, size,
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000544 MS_SYNC))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000545 {
546 PyErr_SetFromErrno(mmap_module_error);
547 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000548 }
Georg Brandl2cfaa342006-05-29 19:39:45 +0000549 return PyInt_FromLong(0);
Tim Petersec0a5f02006-02-16 23:47:20 +0000550#endif /* UNIX */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000551 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000552}
553
554static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000555mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000556{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000557 Py_ssize_t dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000558 int how=0;
559 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000560 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
Tim Peters8f9cc292006-02-17 00:00:20 +0000561 return NULL;
562 else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000563 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000564 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000565 case 0: /* relative to start */
566 if (dist < 0)
567 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000568 where = dist;
569 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000570 case 1: /* relative to current position */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000571 if ((Py_ssize_t)self->pos + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000572 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000573 where = self->pos + dist;
574 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000575 case 2: /* relative to end */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000576 if ((Py_ssize_t)self->size + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000577 goto onoutofrange;
578 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000579 break;
580 default:
Tim Peters8f9cc292006-02-17 00:00:20 +0000581 PyErr_SetString(PyExc_ValueError, "unknown seek type");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000582 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000583 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000584 if (where > self->size)
585 goto onoutofrange;
586 self->pos = where;
Tim Peters8f9cc292006-02-17 00:00:20 +0000587 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000588 return Py_None;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000589 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000590
Tim Peters5ebfd362001-11-13 23:11:19 +0000591 onoutofrange:
Tim Peters8f9cc292006-02-17 00:00:20 +0000592 PyErr_SetString(PyExc_ValueError, "seek out of range");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000593 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000594}
595
596static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000597mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000598{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000599 unsigned long dest, src, count;
600 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000601 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &count) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000602 !is_writeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000603 return NULL;
604 } else {
605 /* bounds check the values */
606 if (/* end of source after end of data?? */
607 ((src+count) > self->size)
608 /* dest will fit? */
609 || (dest+count > self->size)) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000610 PyErr_SetString(PyExc_ValueError,
611 "source or destination out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000612 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000613 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000614 memmove(self->data+dest, self->data+src, count);
615 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000616 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000617 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000618 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000619}
620
621static struct PyMethodDef mmap_object_methods[] = {
Georg Brandl96a8c392006-05-29 21:04:52 +0000622 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000623 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000624 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000625 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
626 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
627 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
Georg Brandl96a8c392006-05-29 21:04:52 +0000628 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
629 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000630 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
631 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
Georg Brandl96a8c392006-05-29 21:04:52 +0000632 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
633 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000634 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
635 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000636 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000637};
638
639/* Functions for treating an mmap'ed file as a buffer */
640
Martin v. Löwis18e16552006-02-15 17:27:45 +0000641static Py_ssize_t
642mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000643{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000644 CHECK_VALID(-1);
Tim Peters8f9cc292006-02-17 00:00:20 +0000645 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000646 PyErr_SetString(PyExc_SystemError,
647 "Accessing non-existent mmap segment");
648 return -1;
649 }
650 *ptr = self->data;
651 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000652}
653
Martin v. Löwis18e16552006-02-15 17:27:45 +0000654static Py_ssize_t
655mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Tim Petersec0a5f02006-02-16 23:47:20 +0000656{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000657 CHECK_VALID(-1);
Tim Peters8f9cc292006-02-17 00:00:20 +0000658 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000659 PyErr_SetString(PyExc_SystemError,
660 "Accessing non-existent mmap segment");
661 return -1;
662 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000663 if (!is_writeable(self))
664 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000665 *ptr = self->data;
666 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000667}
668
Martin v. Löwis18e16552006-02-15 17:27:45 +0000669static Py_ssize_t
670mmap_buffer_getsegcount(mmap_object *self, Py_ssize_t *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000671{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000672 CHECK_VALID(-1);
Tim Petersec0a5f02006-02-16 23:47:20 +0000673 if (lenp)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000674 *lenp = self->size;
675 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000676}
677
Martin v. Löwis18e16552006-02-15 17:27:45 +0000678static Py_ssize_t
679mmap_buffer_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000680{
Tim Peters8f9cc292006-02-17 00:00:20 +0000681 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000682 PyErr_SetString(PyExc_SystemError,
683 "accessing non-existent buffer segment");
684 return -1;
685 }
686 *ptr = (const char *)self->data;
687 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000688}
689
Martin v. Löwis18e16552006-02-15 17:27:45 +0000690static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000691mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000692{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000693 CHECK_VALID(-1);
694 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000695}
696
697static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000698mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000699{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000700 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000701 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000702 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
703 return NULL;
704 }
705 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000706}
707
708static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000709mmap_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000710{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000711 CHECK_VALID(NULL);
712 if (ilow < 0)
713 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000714 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000715 ilow = self->size;
716 if (ihigh < 0)
717 ihigh = 0;
718 if (ihigh < ilow)
719 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000720 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000721 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000722
Guido van Rossum09fdf072000-03-31 01:17:07 +0000723 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000724}
725
726static PyObject *
Thomas Wouters3ccec682007-08-28 15:28:19 +0000727mmap_subscript(mmap_object *self, PyObject *item)
728{
729 CHECK_VALID(NULL);
730 if (PyIndex_Check(item)) {
731 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
732 if (i == -1 && PyErr_Occurred())
733 return NULL;
734 if (i < 0)
735 i += self->size;
Neal Norwitz9c4382f2007-10-31 06:33:20 +0000736 if (i < 0 || (size_t)i > self->size) {
Thomas Wouters3ccec682007-08-28 15:28:19 +0000737 PyErr_SetString(PyExc_IndexError,
738 "mmap index out of range");
739 return NULL;
740 }
741 return PyString_FromStringAndSize(self->data + i, 1);
742 }
743 else if (PySlice_Check(item)) {
744 Py_ssize_t start, stop, step, slicelen;
745
746 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
747 &start, &stop, &step, &slicelen) < 0) {
748 return NULL;
749 }
750
751 if (slicelen <= 0)
752 return PyString_FromStringAndSize("", 0);
753 else if (step == 1)
754 return PyString_FromStringAndSize(self->data + start,
755 slicelen);
756 else {
757 char *result_buf = (char *)PyMem_Malloc(slicelen);
758 Py_ssize_t cur, i;
759 PyObject *result;
760
761 if (result_buf == NULL)
762 return PyErr_NoMemory();
763 for (cur = start, i = 0; i < slicelen;
764 cur += step, i++) {
765 result_buf[i] = self->data[cur];
766 }
767 result = PyString_FromStringAndSize(result_buf,
768 slicelen);
769 PyMem_Free(result_buf);
770 return result;
771 }
772 }
773 else {
774 PyErr_SetString(PyExc_TypeError,
775 "mmap indices must be integers");
776 return NULL;
777 }
778}
779
780static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000781mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000782{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000783 CHECK_VALID(NULL);
784 PyErr_SetString(PyExc_SystemError,
785 "mmaps don't support concatenation");
786 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000787}
788
789static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000790mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000791{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000792 CHECK_VALID(NULL);
793 PyErr_SetString(PyExc_SystemError,
794 "mmaps don't support repeat operation");
795 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000796}
797
798static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000799mmap_ass_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000800{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000801 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000802
Guido van Rossum09fdf072000-03-31 01:17:07 +0000803 CHECK_VALID(-1);
804 if (ilow < 0)
805 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000806 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000807 ilow = self->size;
808 if (ihigh < 0)
809 ihigh = 0;
810 if (ihigh < ilow)
811 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000812 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000813 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000814
Thomas Wouters1baac722001-07-16 15:47:36 +0000815 if (v == NULL) {
816 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000817 "mmap object doesn't support slice deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000818 return -1;
819 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000820 if (! (PyString_Check(v)) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000821 PyErr_SetString(PyExc_IndexError,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000822 "mmap slice assignment must be a string");
823 return -1;
824 }
Tim Peters8f9cc292006-02-17 00:00:20 +0000825 if (PyString_Size(v) != (ihigh - ilow)) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000826 PyErr_SetString(PyExc_IndexError,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000827 "mmap slice assignment is wrong size");
828 return -1;
829 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000830 if (!is_writeable(self))
831 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000832 buf = PyString_AsString(v);
833 memcpy(self->data + ilow, buf, ihigh-ilow);
834 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000835}
836
837static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000838mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000839{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000840 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000841
Guido van Rossum09fdf072000-03-31 01:17:07 +0000842 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000843 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000844 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
845 return -1;
846 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000847 if (v == NULL) {
848 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000849 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000850 return -1;
851 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000852 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000853 PyErr_SetString(PyExc_IndexError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000854 "mmap assignment must be single-character string");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000855 return -1;
856 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000857 if (!is_writeable(self))
858 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000859 buf = PyString_AsString(v);
860 self->data[i] = buf[0];
861 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000862}
863
Thomas Wouters3ccec682007-08-28 15:28:19 +0000864static int
865mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
866{
867 CHECK_VALID(-1);
868
869 if (PyIndex_Check(item)) {
870 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
871 const char *buf;
872
873 if (i == -1 && PyErr_Occurred())
874 return -1;
875 if (i < 0)
876 i += self->size;
Neal Norwitz9c4382f2007-10-31 06:33:20 +0000877 if (i < 0 || (size_t)i > self->size) {
Thomas Wouters3ccec682007-08-28 15:28:19 +0000878 PyErr_SetString(PyExc_IndexError,
879 "mmap index out of range");
880 return -1;
881 }
882 if (value == NULL) {
883 PyErr_SetString(PyExc_TypeError,
884 "mmap object doesn't support item deletion");
885 return -1;
886 }
887 if (!PyString_Check(value) || PyString_Size(value) != 1) {
888 PyErr_SetString(PyExc_IndexError,
889 "mmap assignment must be single-character string");
890 return -1;
891 }
892 if (!is_writeable(self))
893 return -1;
894 buf = PyString_AsString(value);
895 self->data[i] = buf[0];
896 return 0;
897 }
898 else if (PySlice_Check(item)) {
899 Py_ssize_t start, stop, step, slicelen;
900
901 if (PySlice_GetIndicesEx((PySliceObject *)item,
902 self->size, &start, &stop,
903 &step, &slicelen) < 0) {
904 return -1;
905 }
906 if (value == NULL) {
907 PyErr_SetString(PyExc_TypeError,
908 "mmap object doesn't support slice deletion");
909 return -1;
910 }
911 if (!PyString_Check(value)) {
912 PyErr_SetString(PyExc_IndexError,
913 "mmap slice assignment must be a string");
914 return -1;
915 }
916 if (PyString_Size(value) != slicelen) {
917 PyErr_SetString(PyExc_IndexError,
918 "mmap slice assignment is wrong size");
919 return -1;
920 }
921 if (!is_writeable(self))
922 return -1;
923
924 if (slicelen == 0)
925 return 0;
926 else if (step == 1) {
927 const char *buf = PyString_AsString(value);
928
929 if (buf == NULL)
930 return -1;
931 memcpy(self->data + start, buf, slicelen);
932 return 0;
933 }
934 else {
935 Py_ssize_t cur, i;
936 const char *buf = PyString_AsString(value);
937
938 if (buf == NULL)
939 return -1;
940 for (cur = start, i = 0; i < slicelen;
941 cur += step, i++) {
942 self->data[cur] = buf[i];
943 }
944 return 0;
945 }
946 }
947 else {
948 PyErr_SetString(PyExc_TypeError,
949 "mmap indices must be integer");
950 return -1;
951 }
952}
953
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000954static PySequenceMethods mmap_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000955 (lenfunc)mmap_length, /*sq_length*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000956 (binaryfunc)mmap_concat, /*sq_concat*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000957 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
958 (ssizeargfunc)mmap_item, /*sq_item*/
959 (ssizessizeargfunc)mmap_slice, /*sq_slice*/
960 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
961 (ssizessizeobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000962};
963
Thomas Wouters3ccec682007-08-28 15:28:19 +0000964static PyMappingMethods mmap_as_mapping = {
965 (lenfunc)mmap_length,
966 (binaryfunc)mmap_subscript,
967 (objobjargproc)mmap_ass_subscript,
968};
969
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000970static PyBufferProcs mmap_as_buffer = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000971 (readbufferproc)mmap_buffer_getreadbuf,
972 (writebufferproc)mmap_buffer_getwritebuf,
973 (segcountproc)mmap_buffer_getsegcount,
974 (charbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000975};
976
Georg Brandl845c4032008-01-21 14:16:46 +0000977static PyObject *
978new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
979
Georg Brandlef928022008-01-20 14:50:05 +0000980PyDoc_STRVAR(mmap_doc,
981"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
982\n\
983Maps length bytes from the file specified by the file handle fileno,\n\
984and returns a mmap object. If length is larger than the current size\n\
985of the file, the file is extended to contain length bytes. If length\n\
986is 0, the maximum length of the map is the current size of the file,\n\
987except that if the file is empty Windows raises an exception (you cannot\n\
988create an empty mapping on Windows).\n\
989\n\
990Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
991\n\
992Maps length bytes from the file specified by the file descriptor fileno,\n\
993and returns a mmap object. If length is 0, the maximum length of the map\n\
994will be the current size of the file when mmap is called.\n\
995flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
996private copy-on-write mapping, so changes to the contents of the mmap\n\
997object will be private to this process, and MAP_SHARED`creates a mapping\n\
998that's shared with all other processes mapping the same areas of the file.\n\
999The default value is MAP_SHARED.\n\
1000\n\
1001To map anonymous memory, pass -1 as the fileno (both versions).");
1002
1003
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001004static PyTypeObject mmap_object_type = {
Georg Brandl845c4032008-01-21 14:16:46 +00001005 PyVarObject_HEAD_INIT(NULL, 0)
Guido van Rossum14648392001-12-08 18:02:58 +00001006 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +00001007 sizeof(mmap_object), /* tp_size */
1008 0, /* tp_itemsize */
1009 /* methods */
1010 (destructor) mmap_object_dealloc, /* tp_dealloc */
1011 0, /* tp_print */
Georg Brandlef928022008-01-20 14:50:05 +00001012 0, /* tp_getattr */
Guido van Rossum09fdf072000-03-31 01:17:07 +00001013 0, /* tp_setattr */
1014 0, /* tp_compare */
1015 0, /* tp_repr */
1016 0, /* tp_as_number */
1017 &mmap_as_sequence, /*tp_as_sequence*/
Thomas Wouters3ccec682007-08-28 15:28:19 +00001018 &mmap_as_mapping, /*tp_as_mapping*/
Guido van Rossum09fdf072000-03-31 01:17:07 +00001019 0, /*tp_hash*/
1020 0, /*tp_call*/
1021 0, /*tp_str*/
Georg Brandlef928022008-01-20 14:50:05 +00001022 PyObject_GenericGetAttr, /*tp_getattro*/
Guido van Rossum09fdf072000-03-31 01:17:07 +00001023 0, /*tp_setattro*/
1024 &mmap_as_buffer, /*tp_as_buffer*/
Georg Brandl845c4032008-01-21 14:16:46 +00001025 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
Georg Brandlef928022008-01-20 14:50:05 +00001026 mmap_doc, /*tp_doc*/
1027 0, /* tp_traverse */
1028 0, /* tp_clear */
1029 0, /* tp_richcompare */
1030 0, /* tp_weaklistoffset */
Georg Brandl845c4032008-01-21 14:16:46 +00001031 0, /* tp_iter */
1032 0, /* tp_iternext */
Georg Brandlef928022008-01-20 14:50:05 +00001033 mmap_object_methods, /* tp_methods */
Georg Brandl845c4032008-01-21 14:16:46 +00001034 0, /* tp_members */
1035 0, /* tp_getset */
1036 0, /* tp_base */
1037 0, /* tp_dict */
1038 0, /* tp_descr_get */
1039 0, /* tp_descr_set */
1040 0, /* tp_dictoffset */
1041 0, /* tp_init */
1042 PyType_GenericAlloc, /* tp_alloc */
1043 new_mmap_object, /* tp_new */
1044 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001045};
1046
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001047
1048/* extract the map size from the given PyObject
1049
Thomas Wouters7e474022000-07-16 12:04:32 +00001050 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001051 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001052static Py_ssize_t
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001053_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001054{
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001055 if (o == NULL)
1056 return 0;
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001057 if (PyIndex_Check(o)) {
1058 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
Guido van Rossum38fff8c2006-03-07 18:50:55 +00001059 if (i==-1 && PyErr_Occurred())
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001060 return -1;
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001061 if (i < 0) {
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001062 PyErr_Format(PyExc_OverflowError,
1063 "memory mapped %s must be positive",
1064 param);
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001065 return -1;
1066 }
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001067 return i;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001068 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001069
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001070 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001071 return -1;
1072}
1073
Tim Petersec0a5f02006-02-16 23:47:20 +00001074#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001075static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001076new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001077{
Neal Norwitzb5673922002-09-05 21:48:07 +00001078#ifdef HAVE_FSTAT
1079 struct stat st;
1080#endif
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001081 mmap_object *m_obj;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001082 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1083 Py_ssize_t map_size, offset;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001084 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001085 int devzero = -1;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001086 int access = (int)ACCESS_DEFAULT;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001087 static char *keywords[] = {"fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001088 "flags", "prot",
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001089 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001090
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001091 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iiiO", keywords,
Jeremy Hyltonaf68c872005-12-10 18:50:16 +00001092 &fd, &map_size_obj, &flags, &prot,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001093 &access, &offset_obj))
Guido van Rossum09fdf072000-03-31 01:17:07 +00001094 return NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001095 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001096 if (map_size < 0)
1097 return NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001098 offset = _GetMapSize(offset_obj, "offset");
1099 if (offset < 0)
1100 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001101
Tim Petersec0a5f02006-02-16 23:47:20 +00001102 if ((access != (int)ACCESS_DEFAULT) &&
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001103 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
Tim Petersec0a5f02006-02-16 23:47:20 +00001104 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001105 "mmap can't specify both access and flags, prot.");
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001106 switch ((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001107 case ACCESS_READ:
1108 flags = MAP_SHARED;
1109 prot = PROT_READ;
1110 break;
1111 case ACCESS_WRITE:
1112 flags = MAP_SHARED;
1113 prot = PROT_READ | PROT_WRITE;
1114 break;
1115 case ACCESS_COPY:
1116 flags = MAP_PRIVATE;
1117 prot = PROT_READ | PROT_WRITE;
1118 break;
Tim Petersec0a5f02006-02-16 23:47:20 +00001119 case ACCESS_DEFAULT:
Tim Peters5ebfd362001-11-13 23:11:19 +00001120 /* use the specified or default values of flags and prot */
1121 break;
1122 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001123 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001124 "mmap invalid access parameter.");
1125 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001126
1127#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001128# ifdef __VMS
1129 /* on OpenVMS we must ensure that all bytes are written to the file */
Andrew M. Kuchling7c22ccc2008-01-10 13:37:12 +00001130 if (fd != -1) {
1131 fsync(fd);
1132 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001133# endif
Andrew M. Kuchling7c22ccc2008-01-10 13:37:12 +00001134 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001135 if (map_size == 0) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001136 map_size = st.st_size;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001137 } else if ((size_t)offset + (size_t)map_size > st.st_size) {
Tim Petersec0a5f02006-02-16 23:47:20 +00001138 PyErr_SetString(PyExc_ValueError,
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001139 "mmap length is greater than file size");
1140 return NULL;
1141 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001142 }
1143#endif
Georg Brandl845c4032008-01-21 14:16:46 +00001144 m_obj = (mmap_object *)type->tp_alloc(type, 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001145 if (m_obj == NULL) {return NULL;}
Neal Norwitz3b4fff82006-01-11 08:54:45 +00001146 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001147 m_obj->size = (size_t) map_size;
1148 m_obj->pos = (size_t) 0;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001149 m_obj->offset = offset;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001150 if (fd == -1) {
1151 m_obj->fd = -1;
1152 /* Assume the caller wants to map anonymous memory.
1153 This is the same behaviour as Windows. mmap.mmap(-1, size)
1154 on both Windows and Unix map anonymous memory.
1155 */
1156#ifdef MAP_ANONYMOUS
1157 /* BSD way to map anonymous memory */
1158 flags |= MAP_ANONYMOUS;
1159#else
1160 /* SVR4 method to map anonymous memory is to open /dev/zero */
1161 fd = devzero = open("/dev/zero", O_RDWR);
1162 if (devzero == -1) {
1163 Py_DECREF(m_obj);
1164 PyErr_SetFromErrno(mmap_module_error);
1165 return NULL;
1166 }
1167#endif
1168 } else {
1169 m_obj->fd = dup(fd);
1170 if (m_obj->fd == -1) {
1171 Py_DECREF(m_obj);
1172 PyErr_SetFromErrno(mmap_module_error);
1173 return NULL;
1174 }
Georg Brandl38387b82005-08-24 07:17:40 +00001175 }
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001176
Tim Petersec0a5f02006-02-16 23:47:20 +00001177 m_obj->data = mmap(NULL, map_size,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001178 prot, flags,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001179 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001180
1181 if (devzero != -1) {
1182 close(devzero);
1183 }
1184
Tim Peters5ebfd362001-11-13 23:11:19 +00001185 if (m_obj->data == (char *)-1) {
Andrew M. Kuchling16581c82004-05-19 14:39:08 +00001186 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001187 Py_DECREF(m_obj);
1188 PyErr_SetFromErrno(mmap_module_error);
1189 return NULL;
1190 }
Neal Norwitz8856fb72005-12-18 03:34:22 +00001191 m_obj->access = (access_mode)access;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001192 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001193}
1194#endif /* UNIX */
1195
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001196#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001197static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001198new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001199{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001200 mmap_object *m_obj;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001201 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1202 Py_ssize_t map_size, offset;
1203 DWORD off_hi; /* upper 32 bits of offset */
1204 DWORD off_lo; /* lower 32 bits of offset */
1205 DWORD size_hi; /* upper 32 bits of size */
1206 DWORD size_lo; /* lower 32 bits of size */
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001207 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +00001208 DWORD dwErr = 0;
1209 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +00001210 HANDLE fh = 0;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001211 int access = (access_mode)ACCESS_DEFAULT;
Tim Peters5ebfd362001-11-13 23:11:19 +00001212 DWORD flProtect, dwDesiredAccess;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001213 static char *keywords[] = { "fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001214 "tagname",
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001215 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001216
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001217 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
Tim Petersec0a5f02006-02-16 23:47:20 +00001218 &fileno, &map_size_obj,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001219 &tagname, &access, &offset_obj)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001220 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001221 }
1222
Neal Norwitz8856fb72005-12-18 03:34:22 +00001223 switch((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001224 case ACCESS_READ:
1225 flProtect = PAGE_READONLY;
1226 dwDesiredAccess = FILE_MAP_READ;
1227 break;
1228 case ACCESS_DEFAULT: case ACCESS_WRITE:
1229 flProtect = PAGE_READWRITE;
1230 dwDesiredAccess = FILE_MAP_WRITE;
1231 break;
1232 case ACCESS_COPY:
1233 flProtect = PAGE_WRITECOPY;
1234 dwDesiredAccess = FILE_MAP_COPY;
1235 break;
1236 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001237 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001238 "mmap invalid access parameter.");
1239 }
1240
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001241 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001242 if (map_size < 0)
1243 return NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001244 offset = _GetMapSize(offset_obj, "offset");
1245 if (offset < 0)
1246 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001247
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001248 /* assume -1 and 0 both mean invalid filedescriptor
1249 to 'anonymously' map memory.
1250 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1251 XXX: Should this code be added?
1252 if (fileno == 0)
1253 PyErr_Warn(PyExc_DeprecationWarning,
1254 "don't use 0 for anonymous memory");
1255 */
1256 if (fileno != -1 && fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +00001257 fh = (HANDLE)_get_osfhandle(fileno);
1258 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001259 PyErr_SetFromErrno(mmap_module_error);
1260 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001261 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +00001262 /* Win9x appears to need us seeked to zero */
Guido van Rossum69c2b882003-04-09 19:31:02 +00001263 lseek(fileno, 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001264 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001265
Georg Brandl845c4032008-01-21 14:16:46 +00001266 m_obj = (mmap_object *)type->tp_alloc(type, 0);
Tim Peters8f9cc292006-02-17 00:00:20 +00001267 if (m_obj == NULL)
Mark Hammond2cbed002000-07-30 02:22:43 +00001268 return NULL;
1269 /* Set every field to an invalid marker, so we can safely
1270 destruct the object in the face of failure */
1271 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +00001272 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +00001273 m_obj->map_handle = INVALID_HANDLE_VALUE;
1274 m_obj->tagname = NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001275 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001276
Guido van Rossum09fdf072000-03-31 01:17:07 +00001277 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +00001278 /* It is necessary to duplicate the handle, so the
1279 Python code can close it on us */
1280 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +00001281 GetCurrentProcess(), /* source process handle */
1282 fh, /* handle to be duplicated */
1283 GetCurrentProcess(), /* target proc handle */
1284 (LPHANDLE)&m_obj->file_handle, /* result */
1285 0, /* access - ignored due to options value */
1286 FALSE, /* inherited by child processes? */
1287 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +00001288 dwErr = GetLastError();
1289 Py_DECREF(m_obj);
1290 PyErr_SetFromWindowsErr(dwErr);
1291 return NULL;
1292 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001293 if (!map_size) {
Martin v. Löwis15186072006-02-18 12:38:35 +00001294 DWORD low,high;
1295 low = GetFileSize(fh, &high);
1296 /* low might just happen to have the value INVALID_FILE_SIZE;
1297 so we need to check the last error also. */
1298 if (low == INVALID_FILE_SIZE &&
1299 (dwErr = GetLastError()) != NO_ERROR) {
1300 Py_DECREF(m_obj);
1301 return PyErr_SetFromWindowsErr(dwErr);
1302 }
1303
1304#if SIZEOF_SIZE_T > 4
1305 m_obj->size = (((size_t)high)<<32) + low;
1306#else
1307 if (high)
1308 /* File is too large to map completely */
1309 m_obj->size = (size_t)-1;
1310 else
1311 m_obj->size = low;
1312#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001313 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001314 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001315 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001316 }
1317 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001318 m_obj->size = map_size;
1319 }
1320
1321 /* set the initial position */
1322 m_obj->pos = (size_t) 0;
1323
Mark Hammond2cbed002000-07-30 02:22:43 +00001324 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001325 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001326 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1327 if (m_obj->tagname == NULL) {
1328 PyErr_NoMemory();
1329 Py_DECREF(m_obj);
1330 return NULL;
1331 }
1332 strcpy(m_obj->tagname, tagname);
1333 }
1334 else
1335 m_obj->tagname = NULL;
1336
Neal Norwitz8856fb72005-12-18 03:34:22 +00001337 m_obj->access = (access_mode)access;
Tim Peterse564e7f2006-02-16 23:46:01 +00001338 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
Thomas Wouters2c98a7b2006-02-17 09:59:00 +00001339 * more than 4 bytes, we need to break it apart. Else (size_t
Tim Peterse564e7f2006-02-16 23:46:01 +00001340 * consumes 4 bytes), C doesn't define what happens if we shift
1341 * right by 32, so we need different code.
1342 */
1343#if SIZEOF_SIZE_T > 4
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001344 size_hi = (DWORD)((offset + m_obj->size) >> 32);
1345 size_lo = (DWORD)((offset + m_obj->size) & 0xFFFFFFFF);
1346 off_hi = (DWORD)(offset >> 32);
1347 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Tim Peterse564e7f2006-02-16 23:46:01 +00001348#else
1349 size_hi = 0;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001350 size_lo = (DWORD)(offset + m_obj->size);
1351 off_hi = 0;
1352 off_lo = (DWORD)offset;
Tim Peterse564e7f2006-02-16 23:46:01 +00001353#endif
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001354 /* For files, it would be sufficient to pass 0 as size.
1355 For anonymous maps, we have to pass the size explicitly. */
Tim Peters8f9cc292006-02-17 00:00:20 +00001356 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1357 NULL,
1358 flProtect,
1359 size_hi,
1360 size_lo,
1361 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001362 if (m_obj->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +00001363 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1364 dwDesiredAccess,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001365 off_hi,
1366 off_lo,
Tim Peters8f9cc292006-02-17 00:00:20 +00001367 0);
Tim Peters23721ee2006-02-16 23:50:16 +00001368 if (m_obj->data != NULL)
1369 return (PyObject *)m_obj;
1370 else
Tim Peters5ebfd362001-11-13 23:11:19 +00001371 dwErr = GetLastError();
Tim Peters23721ee2006-02-16 23:50:16 +00001372 } else
Guido van Rossum09fdf072000-03-31 01:17:07 +00001373 dwErr = GetLastError();
Mark Hammond2cbed002000-07-30 02:22:43 +00001374 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001375 PyErr_SetFromWindowsErr(dwErr);
Tim Peters23721ee2006-02-16 23:50:16 +00001376 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001377}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001378#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001379
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001380static void
1381setint(PyObject *d, const char *name, long value)
1382{
1383 PyObject *o = PyInt_FromLong(value);
Neal Norwitz5ed49972006-08-13 18:41:15 +00001384 if (o && PyDict_SetItemString(d, name, o) == 0) {
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001385 Py_DECREF(o);
Neal Norwitz5ed49972006-08-13 18:41:15 +00001386 }
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001387}
1388
Mark Hammond62b1ab12002-07-23 06:31:15 +00001389PyMODINIT_FUNC
Georg Brandl845c4032008-01-21 14:16:46 +00001390initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001391{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001392 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001393
Georg Brandl845c4032008-01-21 14:16:46 +00001394 if (PyType_Ready(&mmap_object_type) < 0)
1395 return;
Tim Peters2caf8df2001-01-14 05:05:51 +00001396
Georg Brandl845c4032008-01-21 14:16:46 +00001397 module = Py_InitModule("mmap", NULL);
Neal Norwitz1ac754f2006-01-19 06:09:39 +00001398 if (module == NULL)
1399 return;
Tim Peters8f9cc292006-02-17 00:00:20 +00001400 dict = PyModule_GetDict(module);
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001401 if (!dict)
1402 return;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001403 mmap_module_error = PyExc_EnvironmentError;
Tim Peters8f9cc292006-02-17 00:00:20 +00001404 PyDict_SetItemString(dict, "error", mmap_module_error);
Georg Brandl845c4032008-01-21 14:16:46 +00001405 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001406#ifdef PROT_EXEC
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001407 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001408#endif
1409#ifdef PROT_READ
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001410 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001411#endif
1412#ifdef PROT_WRITE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001413 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001414#endif
1415
1416#ifdef MAP_SHARED
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001417 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001418#endif
1419#ifdef MAP_PRIVATE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001420 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001421#endif
1422#ifdef MAP_DENYWRITE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001423 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001424#endif
1425#ifdef MAP_EXECUTABLE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001426 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001427#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001428#ifdef MAP_ANONYMOUS
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001429 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1430 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001431#endif
1432
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001433 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001434
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001435 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
1436
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001437 setint(dict, "ACCESS_READ", ACCESS_READ);
1438 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1439 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Tim Peters5ebfd362001-11-13 23:11:19 +00001440}