blob: ab9eedca9667105c5fbe9619476f0490bfbac693 [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
Guido van Rossum8ce8a782007-11-01 19:42:39 +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}
Guido van Rossum8ce8a782007-11-01 19:42:39 +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}
Guido van Rossum8ce8a782007-11-01 19:42:39 +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>
Thomas Wouters0e3f5912006-08-11 14:57:12 +000068
69#ifdef HAVE_SYS_TYPES_H
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000070#include <sys/types.h>
Thomas Wouters0e3f5912006-08-11 14:57:12 +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;
Guido van Rossum8ce8a782007-11-01 19:42:39 +000092 size_t pos; /* relative to offset */
93 size_t offset;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +000094 int exports;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000095
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000096#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +000097 HANDLE map_handle;
Mark Hammond071864a2000-07-30 02:46:26 +000098 HANDLE file_handle;
Guido van Rossum09fdf072000-03-31 01:17:07 +000099 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000100#endif
101
102#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000103 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000104#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000105
106 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000107} mmap_object;
108
Tim Peters5ebfd362001-11-13 23:11:19 +0000109
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000110static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000111mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000112{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000113#ifdef MS_WINDOWS
Mark Hammond2cbed002000-07-30 02:22:43 +0000114 if (m_obj->data != NULL)
115 UnmapViewOfFile (m_obj->data);
116 if (m_obj->map_handle != INVALID_HANDLE_VALUE)
117 CloseHandle (m_obj->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000118 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
119 CloseHandle (m_obj->file_handle);
Mark Hammond2cbed002000-07-30 02:22:43 +0000120 if (m_obj->tagname)
121 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000122#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000123
124#ifdef UNIX
Neal Norwitz6eac2002005-11-02 05:36:37 +0000125 if (m_obj->fd >= 0)
126 (void) close(m_obj->fd);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000127 if (m_obj->data!=NULL) {
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000128 msync(m_obj->data, m_obj->size, MS_SYNC);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000129 munmap(m_obj->data, m_obj->size);
130 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000131#endif /* UNIX */
132
Guido van Rossumb18618d2000-05-03 23:44:39 +0000133 PyObject_Del(m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000134}
135
136static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000137mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000138{
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000139 if (self->exports > 0) {
140 PyErr_SetString(PyExc_BufferError, "cannot close "\
141 "exported pointers exist");
142 return NULL;
143 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000144#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000145 /* For each resource we maintain, we need to check
Tim Petersec0a5f02006-02-16 23:47:20 +0000146 the value is valid, and if so, free the resource
Mark Hammond071864a2000-07-30 02:46:26 +0000147 and set the member value to an invalid value so
148 the dealloc does not attempt to resource clearing
149 again.
150 TODO - should we check for errors in the close operations???
151 */
152 if (self->data != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000153 UnmapViewOfFile(self->data);
Mark Hammond071864a2000-07-30 02:46:26 +0000154 self->data = NULL;
155 }
156 if (self->map_handle != INVALID_HANDLE_VALUE) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000157 CloseHandle(self->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000158 self->map_handle = INVALID_HANDLE_VALUE;
159 }
160 if (self->file_handle != INVALID_HANDLE_VALUE) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000161 CloseHandle(self->file_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000162 self->file_handle = INVALID_HANDLE_VALUE;
163 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000164#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000165
166#ifdef UNIX
Neal Norwitz6eac2002005-11-02 05:36:37 +0000167 (void) close(self->fd);
168 self->fd = -1;
Neal Norwitze604c022003-01-10 20:52:16 +0000169 if (self->data != NULL) {
170 munmap(self->data, self->size);
171 self->data = NULL;
172 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000173#endif
174
Tim Peters8f9cc292006-02-17 00:00:20 +0000175 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000176 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000177}
178
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000179#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +0000180#define CHECK_VALID(err) \
181do { \
Guido van Rossum69c2b882003-04-09 19:31:02 +0000182 if (self->map_handle == INVALID_HANDLE_VALUE) { \
Tim Peters8f9cc292006-02-17 00:00:20 +0000183 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
Guido van Rossum09fdf072000-03-31 01:17:07 +0000184 return err; \
185 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000186} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000187#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000188
189#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000190#define CHECK_VALID(err) \
191do { \
192 if (self->data == NULL) { \
Tim Peters8f9cc292006-02-17 00:00:20 +0000193 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
Guido van Rossum09fdf072000-03-31 01:17:07 +0000194 return err; \
195 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000196} while (0)
197#endif /* UNIX */
198
199static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000200mmap_read_byte_method(mmap_object *self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000201 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000202{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000203 CHECK_VALID(NULL);
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000204 if (self->pos < self->size) {
Tim Petersd6283b82001-05-09 18:48:26 +0000205 char value = self->data[self->pos];
Guido van Rossum09fdf072000-03-31 01:17:07 +0000206 self->pos += 1;
Tim Petersd6283b82001-05-09 18:48:26 +0000207 return Py_BuildValue("c", value);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000208 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000209 PyErr_SetString(PyExc_ValueError, "read byte out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000210 return NULL;
211 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000212}
213
214static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000215mmap_read_line_method(mmap_object *self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000216 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000217{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000218 char *start = self->data+self->pos;
219 char *eof = self->data+self->size;
220 char *eol;
221 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000222
Guido van Rossum09fdf072000-03-31 01:17:07 +0000223 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000224
Fred Drake56a87a02000-04-04 18:17:35 +0000225 eol = memchr(start, '\n', self->size - self->pos);
226 if (!eol)
227 eol = eof;
228 else
229 ++eol; /* we're interested in the position after the
230 newline. */
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000231 result = PyBytes_FromStringAndSize(start, (eol - start));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000232 self->pos += (eol - start);
Tim Peters23721ee2006-02-16 23:50:16 +0000233 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000234}
235
236static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000237mmap_read_method(mmap_object *self,
238 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000239{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000240 Py_ssize_t num_bytes;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000241 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000242
Guido van Rossum09fdf072000-03-31 01:17:07 +0000243 CHECK_VALID(NULL);
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000244 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000245 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000246
Guido van Rossum09fdf072000-03-31 01:17:07 +0000247 /* silently 'adjust' out-of-range requests */
248 if ((self->pos + num_bytes) > self->size) {
249 num_bytes -= (self->pos+num_bytes) - self->size;
250 }
Guido van Rossume5aeaad2007-07-26 18:28:23 +0000251 result = PyBytes_FromStringAndSize(self->data+self->pos, num_bytes);
Tim Petersec0a5f02006-02-16 23:47:20 +0000252 self->pos += num_bytes;
Tim Peters23721ee2006-02-16 23:50:16 +0000253 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000254}
255
256static PyObject *
Georg Brandlfceab5a2008-01-19 20:08:23 +0000257mmap_gfind(mmap_object *self,
258 PyObject *args,
259 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000260{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000261 Py_ssize_t start = self->pos;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000262 Py_ssize_t end = self->size;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000263 char *needle;
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000264 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000265
Guido van Rossum09fdf072000-03-31 01:17:07 +0000266 CHECK_VALID(NULL);
Georg Brandlfceab5a2008-01-19 20:08:23 +0000267 if (!PyArg_ParseTuple(args, reverse ? "s#|nn:rfind" : "s#|nn:find",
268 &needle, &len, &start, &end)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000269 return NULL;
270 } else {
Greg Stein834f4dd2001-05-14 09:32:26 +0000271 char *p;
Georg Brandlfceab5a2008-01-19 20:08:23 +0000272 char sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000273
274 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000275 start += self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000276 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000277 start = 0;
Tim Petersd401edd2001-05-14 23:19:12 +0000278 else if ((size_t)start > self->size)
Tim Peters5ebfd362001-11-13 23:11:19 +0000279 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000280
Georg Brandlfceab5a2008-01-19 20:08:23 +0000281 if (end < 0)
282 end += self->size;
283 if (end < 0)
284 end = 0;
285 else if ((size_t)end > self->size)
286 end = self->size;
287
288 start += (Py_ssize_t)self->data;
289 end += (Py_ssize_t)self->data;
290
291 for (p = (char *)(reverse ? end - len : start);
292 p >= (char *)start && p + len <= (char *)end; p+=sign) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000293 Py_ssize_t i;
Tim Petersc9ffa062002-03-08 05:43:32 +0000294 for (i = 0; i < len && needle[i] == p[i]; ++i)
295 /* nothing */;
296 if (i == len) {
Christian Heimes217cfd12007-12-02 14:31:20 +0000297 return PyLong_FromSsize_t(p - self->data);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000298 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000299 }
Christian Heimes217cfd12007-12-02 14:31:20 +0000300 return PyLong_FromLong(-1);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000301 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000302}
303
Georg Brandlfceab5a2008-01-19 20:08:23 +0000304static PyObject *
305mmap_find_method(mmap_object *self,
306 PyObject *args)
307{
308 return mmap_gfind(self, args, 0);
309}
310
311static PyObject *
312mmap_rfind_method(mmap_object *self,
313 PyObject *args)
314{
315 return mmap_gfind(self, args, 1);
316}
317
Tim Petersec0a5f02006-02-16 23:47:20 +0000318static int
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000319is_writable(mmap_object *self)
Tim Peters5ebfd362001-11-13 23:11:19 +0000320{
321 if (self->access != ACCESS_READ)
Tim Petersec0a5f02006-02-16 23:47:20 +0000322 return 1;
Tim Peters5ebfd362001-11-13 23:11:19 +0000323 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
324 return 0;
325}
326
Tim Petersec0a5f02006-02-16 23:47:20 +0000327static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000328is_resizeable(mmap_object *self)
329{
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000330 if (self->exports > 0) {
331 PyErr_SetString(PyExc_BufferError,
332 "mmap can't resize with extant buffers exported.");
333 return 0;
334 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000335 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
Guido van Rossum98297ee2007-11-06 21:34:58 +0000336 return 1;
Tim Petersec0a5f02006-02-16 23:47:20 +0000337 PyErr_Format(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000338 "mmap can't resize a readonly or copy-on-write memory map.");
339 return 0;
340}
341
342
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000343static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000344mmap_write_method(mmap_object *self,
345 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000346{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000347 Py_ssize_t length;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000348 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000349
Guido van Rossum09fdf072000-03-31 01:17:07 +0000350 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000351 if (!PyArg_ParseTuple(args, "s#:write", &data, &length))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000352 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000353
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000354 if (!is_writable(self))
Tim Peters5ebfd362001-11-13 23:11:19 +0000355 return NULL;
356
Guido van Rossum09fdf072000-03-31 01:17:07 +0000357 if ((self->pos + length) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000358 PyErr_SetString(PyExc_ValueError, "data out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000359 return NULL;
360 }
Tim Peters8f9cc292006-02-17 00:00:20 +0000361 memcpy(self->data+self->pos, data, length);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000362 self->pos = self->pos+length;
Tim Peters8f9cc292006-02-17 00:00:20 +0000363 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000364 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000365}
366
367static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000368mmap_write_byte_method(mmap_object *self,
369 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000370{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000371 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000372
Guido van Rossum09fdf072000-03-31 01:17:07 +0000373 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000374 if (!PyArg_ParseTuple(args, "c:write_byte", &value))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000375 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000376
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000377 if (!is_writable(self))
Tim Peters5ebfd362001-11-13 23:11:19 +0000378 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000379 *(self->data+self->pos) = value;
380 self->pos += 1;
Tim Peters8f9cc292006-02-17 00:00:20 +0000381 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000382 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000383}
Tim Petersec0a5f02006-02-16 23:47:20 +0000384
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000385static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000386mmap_size_method(mmap_object *self,
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000387 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000388{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000389 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000390
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000391#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000392 if (self->file_handle != INVALID_HANDLE_VALUE) {
Martin v. Löwis15186072006-02-18 12:38:35 +0000393 DWORD low,high;
394 PY_LONG_LONG size;
395 low = GetFileSize(self->file_handle, &high);
396 if (low == INVALID_FILE_SIZE) {
397 /* It might be that the function appears to have failed,
398 when indeed its size equals INVALID_FILE_SIZE */
399 DWORD error = GetLastError();
400 if (error != NO_ERROR)
401 return PyErr_SetFromWindowsErr(error);
402 }
403 if (!high && low < LONG_MAX)
Christian Heimes217cfd12007-12-02 14:31:20 +0000404 return PyLong_FromLong((long)low);
Martin v. Löwis15186072006-02-18 12:38:35 +0000405 size = (((PY_LONG_LONG)high)<<32) + low;
406 return PyLong_FromLongLong(size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000407 } else {
Christian Heimes217cfd12007-12-02 14:31:20 +0000408 return PyLong_FromSsize_t(self->size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000409 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000410#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000411
412#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000413 {
414 struct stat buf;
415 if (-1 == fstat(self->fd, &buf)) {
416 PyErr_SetFromErrno(mmap_module_error);
417 return NULL;
418 }
Christian Heimes217cfd12007-12-02 14:31:20 +0000419 return PyLong_FromSsize_t(buf.st_size);
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000420 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000421#endif /* UNIX */
422}
423
424/* This assumes that you want the entire file mapped,
425 / and when recreating the map will make the new file
426 / have the new size
427 /
428 / Is this really necessary? This could easily be done
429 / from python by just closing and re-opening with the
430 / new size?
431 */
432
433static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000434mmap_resize_method(mmap_object *self,
435 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000436{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000437 Py_ssize_t new_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000438 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000439 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000440 !is_resizeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000441 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000442#ifdef MS_WINDOWS
Tim Petersec0a5f02006-02-16 23:47:20 +0000443 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000444 DWORD dwErrCode = 0;
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000445 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000446 /* First, unmap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000447 UnmapViewOfFile(self->data);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000448 /* Close the mapping object */
Tim Peters8f9cc292006-02-17 00:00:20 +0000449 CloseHandle(self->map_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000450 /* Move to the desired EOF position */
Martin v. Löwis15186072006-02-18 12:38:35 +0000451#if SIZEOF_SIZE_T > 4
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000452 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
453 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
454 off_hi = (DWORD)(self->offset >> 32);
455 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Martin v. Löwis15186072006-02-18 12:38:35 +0000456#else
457 newSizeHigh = 0;
Martin v. Löwis5bb8a152006-02-18 12:49:49 +0000458 newSizeLow = (DWORD)new_size;
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000459 off_hi = 0;
460 off_lo = (DWORD)self->offset;
Martin v. Löwis15186072006-02-18 12:38:35 +0000461#endif
Tim Peters8f9cc292006-02-17 00:00:20 +0000462 SetFilePointer(self->file_handle,
Martin v. Löwis15186072006-02-18 12:38:35 +0000463 newSizeLow, &newSizeHigh, FILE_BEGIN);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000464 /* Change the size of the file */
Tim Peters8f9cc292006-02-17 00:00:20 +0000465 SetEndOfFile(self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000466 /* Create another mapping object and remap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000467 self->map_handle = CreateFileMapping(
Mark Hammond071864a2000-07-30 02:46:26 +0000468 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000469 NULL,
470 PAGE_READWRITE,
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000471 0,
472 0,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000473 self->tagname);
474 if (self->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000475 self->data = (char *) MapViewOfFile(self->map_handle,
476 FILE_MAP_WRITE,
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000477 off_hi,
478 off_lo,
479 new_size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000480 if (self->data != NULL) {
481 self->size = new_size;
Tim Peters8f9cc292006-02-17 00:00:20 +0000482 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000483 return Py_None;
484 } else {
485 dwErrCode = GetLastError();
486 }
487 } else {
488 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000489 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000490 PyErr_SetFromWindowsErr(dwErrCode);
Tim Peters23721ee2006-02-16 23:50:16 +0000491 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000492#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000493
494#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000495#ifndef HAVE_MREMAP
Tim Peters5ebfd362001-11-13 23:11:19 +0000496 } else {
497 PyErr_SetString(PyExc_SystemError,
498 "mmap: resizing not available--no mremap()");
499 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000500#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000501 } else {
Armin Rigo335ffe82005-09-20 19:04:02 +0000502 void *newmap;
503
Georg Brandl38387b82005-08-24 07:17:40 +0000504 if (ftruncate(self->fd, new_size) == -1) {
505 PyErr_SetFromErrno(mmap_module_error);
506 return NULL;
507 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000508
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000509#ifdef MREMAP_MAYMOVE
Tim Peters5ebfd362001-11-13 23:11:19 +0000510 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000511#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000512 newmap = mremap(self->data, self->size, new_size, 0);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000513#endif
Tim Petersec0a5f02006-02-16 23:47:20 +0000514 if (newmap == (void *)-1)
Tim Peters5ebfd362001-11-13 23:11:19 +0000515 {
516 PyErr_SetFromErrno(mmap_module_error);
517 return NULL;
518 }
519 self->data = newmap;
520 self->size = new_size;
521 Py_INCREF(Py_None);
522 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000523#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000524#endif /* UNIX */
Tim Peters5ebfd362001-11-13 23:11:19 +0000525 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000526}
527
528static PyObject *
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000529mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000530{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000531 CHECK_VALID(NULL);
Christian Heimes217cfd12007-12-02 14:31:20 +0000532 return PyLong_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000533}
534
535static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000536mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000537{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000538 Py_ssize_t offset = 0;
539 Py_ssize_t size = self->size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000540 CHECK_VALID(NULL);
Tim Petersf2882952006-02-17 01:07:39 +0000541 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000542 return NULL;
Tim Petersf2882952006-02-17 01:07:39 +0000543 if ((size_t)(offset + size) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000544 PyErr_SetString(PyExc_ValueError, "flush values out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000545 return NULL;
546 } else {
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000547#ifdef MS_WINDOWS
Christian Heimes217cfd12007-12-02 14:31:20 +0000548 return PyLong_FromLong((long)
Tim Peters23721ee2006-02-16 23:50:16 +0000549 FlushViewOfFile(self->data+offset, size));
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000550#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000551#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000552 /* XXX semantics of return value? */
553 /* XXX flags for msync? */
554 if (-1 == msync(self->data + offset, size,
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000555 MS_SYNC))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000556 {
557 PyErr_SetFromErrno(mmap_module_error);
558 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000559 }
Christian Heimes217cfd12007-12-02 14:31:20 +0000560 return PyLong_FromLong(0);
Tim Petersec0a5f02006-02-16 23:47:20 +0000561#endif /* UNIX */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000562 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000563}
564
565static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000566mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000567{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000568 Py_ssize_t dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000569 int how=0;
570 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000571 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
Tim Peters8f9cc292006-02-17 00:00:20 +0000572 return NULL;
573 else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000574 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000575 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000576 case 0: /* relative to start */
577 if (dist < 0)
578 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000579 where = dist;
580 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000581 case 1: /* relative to current position */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000582 if ((Py_ssize_t)self->pos + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000583 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000584 where = self->pos + dist;
585 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000586 case 2: /* relative to end */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000587 if ((Py_ssize_t)self->size + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000588 goto onoutofrange;
589 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000590 break;
591 default:
Tim Peters8f9cc292006-02-17 00:00:20 +0000592 PyErr_SetString(PyExc_ValueError, "unknown seek type");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000593 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000594 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000595 if (where > self->size)
596 goto onoutofrange;
597 self->pos = where;
Tim Peters8f9cc292006-02-17 00:00:20 +0000598 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000599 return Py_None;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000600 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000601
Tim Peters5ebfd362001-11-13 23:11:19 +0000602 onoutofrange:
Tim Peters8f9cc292006-02-17 00:00:20 +0000603 PyErr_SetString(PyExc_ValueError, "seek out of range");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000604 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000605}
606
607static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000608mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000609{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000610 unsigned long dest, src, count;
611 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000612 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &count) ||
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000613 !is_writable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000614 return NULL;
615 } else {
616 /* bounds check the values */
617 if (/* end of source after end of data?? */
618 ((src+count) > self->size)
619 /* dest will fit? */
620 || (dest+count > self->size)) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000621 PyErr_SetString(PyExc_ValueError,
622 "source or destination out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000623 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000624 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000625 memmove(self->data+dest, self->data+src, count);
626 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000627 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000628 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000629 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000630}
631
632static struct PyMethodDef mmap_object_methods[] = {
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000633 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000634 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
Georg Brandlfceab5a2008-01-19 20:08:23 +0000635 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000636 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
637 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
638 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000639 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
640 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000641 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
642 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
Thomas Wouters4d70c3d2006-06-08 14:42:34 +0000643 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
644 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000645 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
646 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000647 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000648};
649
650/* Functions for treating an mmap'ed file as a buffer */
651
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000652static int
Guido van Rossum98297ee2007-11-06 21:34:58 +0000653mmap_buffer_getbuf(mmap_object *self, Py_buffer *view, int flags)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000654{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000655 CHECK_VALID(-1);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000656 if (PyBuffer_FillInfo(view, self->data, self->size,
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000657 (self->access == ACCESS_READ), flags) < 0)
658 return -1;
659 self->exports++;
660 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000661}
662
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000663static void
Travis E. Oliphant8ae62b62007-09-23 02:00:13 +0000664mmap_buffer_releasebuf(mmap_object *self, Py_buffer *view)
Tim Petersec0a5f02006-02-16 23:47:20 +0000665{
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000666 self->exports--;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000667}
668
669static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000670mmap_object_getattr(mmap_object *self, char *name)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000671{
Tim Peters8f9cc292006-02-17 00:00:20 +0000672 return Py_FindMethod(mmap_object_methods, (PyObject *)self, name);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000673}
674
Martin v. Löwis18e16552006-02-15 17:27:45 +0000675static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000676mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000677{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000678 CHECK_VALID(-1);
679 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000680}
681
682static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000683mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000684{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000685 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000686 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000687 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
688 return NULL;
689 }
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000690 return PyBytes_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000691}
692
693static PyObject *
Thomas Woutersed03b412007-08-28 21:37:11 +0000694mmap_subscript(mmap_object *self, PyObject *item)
695{
696 CHECK_VALID(NULL);
697 if (PyIndex_Check(item)) {
698 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
699 if (i == -1 && PyErr_Occurred())
700 return NULL;
701 if (i < 0)
702 i += self->size;
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000703 if (i < 0 || (size_t)i > self->size) {
Thomas Woutersed03b412007-08-28 21:37:11 +0000704 PyErr_SetString(PyExc_IndexError,
705 "mmap index out of range");
706 return NULL;
707 }
Christian Heimes217cfd12007-12-02 14:31:20 +0000708 return PyLong_FromLong(Py_CHARMASK(self->data[i]));
Thomas Woutersed03b412007-08-28 21:37:11 +0000709 }
710 else if (PySlice_Check(item)) {
711 Py_ssize_t start, stop, step, slicelen;
712
713 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
714 &start, &stop, &step, &slicelen) < 0) {
715 return NULL;
716 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000717
Thomas Woutersed03b412007-08-28 21:37:11 +0000718 if (slicelen <= 0)
Guido van Rossum98297ee2007-11-06 21:34:58 +0000719 return PyString_FromStringAndSize("", 0);
Thomas Woutersed03b412007-08-28 21:37:11 +0000720 else if (step == 1)
Guido van Rossum98297ee2007-11-06 21:34:58 +0000721 return PyString_FromStringAndSize(self->data + start,
722 slicelen);
Thomas Woutersed03b412007-08-28 21:37:11 +0000723 else {
724 char *result_buf = (char *)PyMem_Malloc(slicelen);
725 Py_ssize_t cur, i;
726 PyObject *result;
727
728 if (result_buf == NULL)
729 return PyErr_NoMemory();
730 for (cur = start, i = 0; i < slicelen;
731 cur += step, i++) {
732 result_buf[i] = self->data[cur];
733 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000734 result = PyString_FromStringAndSize(result_buf,
735 slicelen);
Thomas Woutersed03b412007-08-28 21:37:11 +0000736 PyMem_Free(result_buf);
737 return result;
738 }
739 }
740 else {
741 PyErr_SetString(PyExc_TypeError,
742 "mmap indices must be integers");
743 return NULL;
744 }
745}
746
747static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000748mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000749{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000750 CHECK_VALID(NULL);
751 PyErr_SetString(PyExc_SystemError,
752 "mmaps don't support concatenation");
753 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000754}
755
756static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000757mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000758{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000759 CHECK_VALID(NULL);
760 PyErr_SetString(PyExc_SystemError,
761 "mmaps don't support repeat operation");
762 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000763}
764
765static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000766mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000767{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000768 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000769
Guido van Rossum09fdf072000-03-31 01:17:07 +0000770 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000771 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000772 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
773 return -1;
774 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000775 if (v == NULL) {
776 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000777 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000778 return -1;
779 }
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000780 if (! (PyBytes_Check(v) && PyBytes_Size(v)==1) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000781 PyErr_SetString(PyExc_IndexError,
Thomas Woutersed03b412007-08-28 21:37:11 +0000782 "mmap assignment must be length-1 bytes()");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000783 return -1;
784 }
Sean Reifscheider54cf12b2007-09-17 17:55:36 +0000785 if (!is_writable(self))
Tim Peters5ebfd362001-11-13 23:11:19 +0000786 return -1;
Guido van Rossumb358a2c2007-07-16 19:29:02 +0000787 buf = PyBytes_AsString(v);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000788 self->data[i] = buf[0];
789 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000790}
791
Thomas Woutersed03b412007-08-28 21:37:11 +0000792static int
793mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
794{
795 CHECK_VALID(-1);
796
Guido van Rossum98297ee2007-11-06 21:34:58 +0000797 if (!is_writable(self))
798 return -1;
799
Thomas Woutersed03b412007-08-28 21:37:11 +0000800 if (PyIndex_Check(item)) {
801 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000802 Py_ssize_t v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000803
804 if (i == -1 && PyErr_Occurred())
805 return -1;
806 if (i < 0)
807 i += self->size;
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000808 if (i < 0 || (size_t)i > self->size) {
Thomas Woutersed03b412007-08-28 21:37:11 +0000809 PyErr_SetString(PyExc_IndexError,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000810 "mmap index out of range");
Thomas Woutersed03b412007-08-28 21:37:11 +0000811 return -1;
812 }
813 if (value == NULL) {
814 PyErr_SetString(PyExc_TypeError,
Guido van Rossum98297ee2007-11-06 21:34:58 +0000815 "mmap doesn't support item deletion");
Thomas Woutersed03b412007-08-28 21:37:11 +0000816 return -1;
817 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000818 if (!PyIndex_Check(value)) {
819 PyErr_SetString(PyExc_TypeError,
820 "mmap item value must be an int");
Thomas Woutersed03b412007-08-28 21:37:11 +0000821 return -1;
822 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000823 v = PyNumber_AsSsize_t(value, PyExc_TypeError);
824 if (v == -1 && PyErr_Occurred())
Thomas Woutersed03b412007-08-28 21:37:11 +0000825 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000826 if (v < 0 || v > 255) {
827 PyErr_SetString(PyExc_ValueError,
828 "mmap item value must be "
829 "in range(0, 256)");
830 return -1;
831 }
832 self->data[i] = v;
Thomas Woutersed03b412007-08-28 21:37:11 +0000833 return 0;
834 }
835 else if (PySlice_Check(item)) {
836 Py_ssize_t start, stop, step, slicelen;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000837 Py_buffer vbuf;
838
Thomas Woutersed03b412007-08-28 21:37:11 +0000839 if (PySlice_GetIndicesEx((PySliceObject *)item,
840 self->size, &start, &stop,
841 &step, &slicelen) < 0) {
842 return -1;
843 }
844 if (value == NULL) {
845 PyErr_SetString(PyExc_TypeError,
846 "mmap object doesn't support slice deletion");
847 return -1;
848 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000849 if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0)
Thomas Woutersed03b412007-08-28 21:37:11 +0000850 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000851 if (vbuf.len != slicelen) {
Thomas Woutersed03b412007-08-28 21:37:11 +0000852 PyErr_SetString(PyExc_IndexError,
853 "mmap slice assignment is wrong size");
Guido van Rossum98297ee2007-11-06 21:34:58 +0000854 PyObject_ReleaseBuffer(value, &vbuf);
Thomas Woutersed03b412007-08-28 21:37:11 +0000855 return -1;
856 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000857
Guido van Rossum98297ee2007-11-06 21:34:58 +0000858 if (slicelen == 0) {
859 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000860 else if (step == 1) {
Guido van Rossum98297ee2007-11-06 21:34:58 +0000861 memcpy(self->data + start, vbuf.buf, slicelen);
Thomas Woutersed03b412007-08-28 21:37:11 +0000862 }
863 else {
864 Py_ssize_t cur, i;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000865
866 for (cur = start, i = 0;
867 i < slicelen;
868 cur += step, i++)
869 {
870 self->data[cur] = ((char *)vbuf.buf)[i];
Thomas Woutersed03b412007-08-28 21:37:11 +0000871 }
Thomas Woutersed03b412007-08-28 21:37:11 +0000872 }
Guido van Rossum98297ee2007-11-06 21:34:58 +0000873 PyObject_ReleaseBuffer(value, &vbuf);
874 return 0;
Thomas Woutersed03b412007-08-28 21:37:11 +0000875 }
876 else {
877 PyErr_SetString(PyExc_TypeError,
878 "mmap indices must be integer");
879 return -1;
880 }
881}
882
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000883static PySequenceMethods mmap_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000884 (lenfunc)mmap_length, /*sq_length*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000885 (binaryfunc)mmap_concat, /*sq_concat*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000886 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
887 (ssizeargfunc)mmap_item, /*sq_item*/
Thomas Woutersd2cf20e2007-08-30 22:57:53 +0000888 0, /*sq_slice*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000889 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
Thomas Woutersd2cf20e2007-08-30 22:57:53 +0000890 0, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000891};
892
Thomas Woutersed03b412007-08-28 21:37:11 +0000893static PyMappingMethods mmap_as_mapping = {
894 (lenfunc)mmap_length,
895 (binaryfunc)mmap_subscript,
896 (objobjargproc)mmap_ass_subscript,
897};
898
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000899static PyBufferProcs mmap_as_buffer = {
Travis E. Oliphantb99f7622007-08-18 11:21:56 +0000900 (getbufferproc)mmap_buffer_getbuf,
901 (releasebufferproc)mmap_buffer_releasebuf,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000902};
903
904static PyTypeObject mmap_object_type = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000905 PyVarObject_HEAD_INIT(0, 0) /* patched in module init */
Guido van Rossum14648392001-12-08 18:02:58 +0000906 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000907 sizeof(mmap_object), /* tp_size */
908 0, /* tp_itemsize */
909 /* methods */
910 (destructor) mmap_object_dealloc, /* tp_dealloc */
911 0, /* tp_print */
912 (getattrfunc) mmap_object_getattr, /* tp_getattr */
913 0, /* tp_setattr */
914 0, /* tp_compare */
915 0, /* tp_repr */
916 0, /* tp_as_number */
917 &mmap_as_sequence, /*tp_as_sequence*/
Thomas Woutersed03b412007-08-28 21:37:11 +0000918 &mmap_as_mapping, /*tp_as_mapping*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000919 0, /*tp_hash*/
920 0, /*tp_call*/
921 0, /*tp_str*/
922 0, /*tp_getattro*/
923 0, /*tp_setattro*/
924 &mmap_as_buffer, /*tp_as_buffer*/
Guido van Rossum3cf5b1e2006-07-27 21:53:35 +0000925 Py_TPFLAGS_DEFAULT, /*tp_flags*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000926 0, /*tp_doc*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000927};
928
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000929
930/* extract the map size from the given PyObject
931
Thomas Wouters7e474022000-07-16 12:04:32 +0000932 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000933 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000934static Py_ssize_t
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000935_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000936{
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000937 if (o == NULL)
938 return 0;
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000939 if (PyIndex_Check(o)) {
940 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
Guido van Rossum98297ee2007-11-06 21:34:58 +0000941 if (i==-1 && PyErr_Occurred())
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000942 return -1;
Guido van Rossum98297ee2007-11-06 21:34:58 +0000943 if (i < 0) {
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000944 PyErr_Format(PyExc_OverflowError,
945 "memory mapped %s must be positive",
946 param);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000947 return -1;
948 }
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000949 return i;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000950 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000951
Thomas Wouters00ee7ba2006-08-21 19:07:27 +0000952 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000953 return -1;
954}
955
Tim Petersec0a5f02006-02-16 23:47:20 +0000956#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000957static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000958new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000959{
Neal Norwitzb5673922002-09-05 21:48:07 +0000960#ifdef HAVE_FSTAT
961 struct stat st;
962#endif
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000963 mmap_object *m_obj;
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000964 PyObject *map_size_obj = NULL, *offset_obj = NULL;
965 Py_ssize_t map_size, offset;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000966 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +0000967 int devzero = -1;
Neal Norwitz8856fb72005-12-18 03:34:22 +0000968 int access = (int)ACCESS_DEFAULT;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +0000969 static char *keywords[] = {"fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +0000970 "flags", "prot",
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000971 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000972
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000973 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iiiO", keywords,
Jeremy Hyltonaf68c872005-12-10 18:50:16 +0000974 &fd, &map_size_obj, &flags, &prot,
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000975 &access, &offset_obj))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000976 return NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000977 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000978 if (map_size < 0)
979 return NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +0000980 offset = _GetMapSize(offset_obj, "offset");
981 if (offset < 0)
982 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000983
Tim Petersec0a5f02006-02-16 23:47:20 +0000984 if ((access != (int)ACCESS_DEFAULT) &&
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +0000985 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
Tim Petersec0a5f02006-02-16 23:47:20 +0000986 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000987 "mmap can't specify both access and flags, prot.");
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +0000988 switch ((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +0000989 case ACCESS_READ:
990 flags = MAP_SHARED;
991 prot = PROT_READ;
992 break;
993 case ACCESS_WRITE:
994 flags = MAP_SHARED;
995 prot = PROT_READ | PROT_WRITE;
996 break;
997 case ACCESS_COPY:
998 flags = MAP_PRIVATE;
999 prot = PROT_READ | PROT_WRITE;
1000 break;
Tim Petersec0a5f02006-02-16 23:47:20 +00001001 case ACCESS_DEFAULT:
Tim Peters5ebfd362001-11-13 23:11:19 +00001002 /* use the specified or default values of flags and prot */
1003 break;
1004 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001005 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001006 "mmap invalid access parameter.");
1007 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001008
1009#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001010# ifdef __VMS
1011 /* on OpenVMS we must ensure that all bytes are written to the file */
Christian Heimes25bb7832008-01-11 16:17:00 +00001012 if (fd != -1) {
1013 fsync(fd);
1014 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001015# endif
Christian Heimes25bb7832008-01-11 16:17:00 +00001016 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001017 if (map_size == 0) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001018 map_size = st.st_size;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001019 } else if ((size_t)offset + (size_t)map_size > st.st_size) {
Tim Petersec0a5f02006-02-16 23:47:20 +00001020 PyErr_SetString(PyExc_ValueError,
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001021 "mmap length is greater than file size");
1022 return NULL;
1023 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001024 }
1025#endif
Tim Peters8f9cc292006-02-17 00:00:20 +00001026 m_obj = PyObject_New(mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001027 if (m_obj == NULL) {return NULL;}
Neal Norwitz3b4fff82006-01-11 08:54:45 +00001028 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001029 m_obj->size = (size_t) map_size;
1030 m_obj->pos = (size_t) 0;
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001031 m_obj->exports = 0;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001032 m_obj->offset = offset;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001033 if (fd == -1) {
1034 m_obj->fd = -1;
1035 /* Assume the caller wants to map anonymous memory.
1036 This is the same behaviour as Windows. mmap.mmap(-1, size)
1037 on both Windows and Unix map anonymous memory.
1038 */
1039#ifdef MAP_ANONYMOUS
1040 /* BSD way to map anonymous memory */
1041 flags |= MAP_ANONYMOUS;
1042#else
1043 /* SVR4 method to map anonymous memory is to open /dev/zero */
1044 fd = devzero = open("/dev/zero", O_RDWR);
1045 if (devzero == -1) {
1046 Py_DECREF(m_obj);
1047 PyErr_SetFromErrno(mmap_module_error);
1048 return NULL;
1049 }
1050#endif
1051 } else {
1052 m_obj->fd = dup(fd);
1053 if (m_obj->fd == -1) {
1054 Py_DECREF(m_obj);
1055 PyErr_SetFromErrno(mmap_module_error);
1056 return NULL;
1057 }
Georg Brandl38387b82005-08-24 07:17:40 +00001058 }
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001059
Tim Petersec0a5f02006-02-16 23:47:20 +00001060 m_obj->data = mmap(NULL, map_size,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001061 prot, flags,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001062 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001063
1064 if (devzero != -1) {
1065 close(devzero);
1066 }
1067
Tim Peters5ebfd362001-11-13 23:11:19 +00001068 if (m_obj->data == (char *)-1) {
Andrew M. Kuchling16581c82004-05-19 14:39:08 +00001069 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001070 Py_DECREF(m_obj);
1071 PyErr_SetFromErrno(mmap_module_error);
1072 return NULL;
1073 }
Neal Norwitz8856fb72005-12-18 03:34:22 +00001074 m_obj->access = (access_mode)access;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001075 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001076}
1077#endif /* UNIX */
1078
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001079#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001080static PyObject *
Tim Peters5ebfd362001-11-13 23:11:19 +00001081new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001082{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001083 mmap_object *m_obj;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001084 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1085 Py_ssize_t map_size, offset;
1086 DWORD off_hi; /* upper 32 bits of offset */
1087 DWORD off_lo; /* lower 32 bits of offset */
1088 DWORD size_hi; /* upper 32 bits of size */
1089 DWORD size_lo; /* lower 32 bits of size */
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001090 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +00001091 DWORD dwErr = 0;
1092 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +00001093 HANDLE fh = 0;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001094 int access = (access_mode)ACCESS_DEFAULT;
Tim Peters5ebfd362001-11-13 23:11:19 +00001095 DWORD flProtect, dwDesiredAccess;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001096 static char *keywords[] = { "fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001097 "tagname",
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001098 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001099
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001100 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
Tim Petersec0a5f02006-02-16 23:47:20 +00001101 &fileno, &map_size_obj,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001102 &tagname, &access, &offset_obj)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001103 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001104 }
1105
Neal Norwitz8856fb72005-12-18 03:34:22 +00001106 switch((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001107 case ACCESS_READ:
1108 flProtect = PAGE_READONLY;
1109 dwDesiredAccess = FILE_MAP_READ;
1110 break;
1111 case ACCESS_DEFAULT: case ACCESS_WRITE:
1112 flProtect = PAGE_READWRITE;
1113 dwDesiredAccess = FILE_MAP_WRITE;
1114 break;
1115 case ACCESS_COPY:
1116 flProtect = PAGE_WRITECOPY;
1117 dwDesiredAccess = FILE_MAP_COPY;
1118 break;
1119 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001120 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001121 "mmap invalid access parameter.");
1122 }
1123
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001124 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001125 if (map_size < 0)
1126 return NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001127 offset = _GetMapSize(offset_obj, "offset");
1128 if (offset < 0)
1129 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001130
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001131 /* assume -1 and 0 both mean invalid filedescriptor
1132 to 'anonymously' map memory.
1133 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1134 XXX: Should this code be added?
1135 if (fileno == 0)
Skip Montanaro46fc3372007-08-12 11:44:53 +00001136 PyErr_WarnEx(PyExc_DeprecationWarning,
1137 "don't use 0 for anonymous memory",
1138 1);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001139 */
1140 if (fileno != -1 && fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +00001141 fh = (HANDLE)_get_osfhandle(fileno);
1142 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001143 PyErr_SetFromErrno(mmap_module_error);
1144 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001145 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +00001146 /* Win9x appears to need us seeked to zero */
Guido van Rossum69c2b882003-04-09 19:31:02 +00001147 lseek(fileno, 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001148 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001149
Tim Peters8f9cc292006-02-17 00:00:20 +00001150 m_obj = PyObject_New(mmap_object, &mmap_object_type);
1151 if (m_obj == NULL)
Mark Hammond2cbed002000-07-30 02:22:43 +00001152 return NULL;
1153 /* Set every field to an invalid marker, so we can safely
1154 destruct the object in the face of failure */
1155 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +00001156 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +00001157 m_obj->map_handle = INVALID_HANDLE_VALUE;
1158 m_obj->tagname = NULL;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001159 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001160
Guido van Rossum09fdf072000-03-31 01:17:07 +00001161 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +00001162 /* It is necessary to duplicate the handle, so the
1163 Python code can close it on us */
1164 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +00001165 GetCurrentProcess(), /* source process handle */
1166 fh, /* handle to be duplicated */
1167 GetCurrentProcess(), /* target proc handle */
1168 (LPHANDLE)&m_obj->file_handle, /* result */
1169 0, /* access - ignored due to options value */
1170 FALSE, /* inherited by child processes? */
1171 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +00001172 dwErr = GetLastError();
1173 Py_DECREF(m_obj);
1174 PyErr_SetFromWindowsErr(dwErr);
1175 return NULL;
1176 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001177 if (!map_size) {
Martin v. Löwis15186072006-02-18 12:38:35 +00001178 DWORD low,high;
1179 low = GetFileSize(fh, &high);
1180 /* low might just happen to have the value INVALID_FILE_SIZE;
1181 so we need to check the last error also. */
1182 if (low == INVALID_FILE_SIZE &&
1183 (dwErr = GetLastError()) != NO_ERROR) {
1184 Py_DECREF(m_obj);
1185 return PyErr_SetFromWindowsErr(dwErr);
Guido van Rossum98297ee2007-11-06 21:34:58 +00001186 }
1187
Martin v. Löwis15186072006-02-18 12:38:35 +00001188#if SIZEOF_SIZE_T > 4
1189 m_obj->size = (((size_t)high)<<32) + low;
1190#else
1191 if (high)
1192 /* File is too large to map completely */
1193 m_obj->size = (size_t)-1;
1194 else
1195 m_obj->size = low;
1196#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001197 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001198 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001199 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001200 }
1201 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001202 m_obj->size = map_size;
1203 }
1204
1205 /* set the initial position */
1206 m_obj->pos = (size_t) 0;
1207
Travis E. Oliphantb99f7622007-08-18 11:21:56 +00001208 m_obj->exports = 0;
Mark Hammond2cbed002000-07-30 02:22:43 +00001209 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001210 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001211 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1212 if (m_obj->tagname == NULL) {
1213 PyErr_NoMemory();
1214 Py_DECREF(m_obj);
1215 return NULL;
1216 }
1217 strcpy(m_obj->tagname, tagname);
1218 }
1219 else
1220 m_obj->tagname = NULL;
1221
Neal Norwitz8856fb72005-12-18 03:34:22 +00001222 m_obj->access = (access_mode)access;
Tim Peterse564e7f2006-02-16 23:46:01 +00001223 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
Thomas Wouters2c98a7b2006-02-17 09:59:00 +00001224 * more than 4 bytes, we need to break it apart. Else (size_t
Tim Peterse564e7f2006-02-16 23:46:01 +00001225 * consumes 4 bytes), C doesn't define what happens if we shift
1226 * right by 32, so we need different code.
1227 */
1228#if SIZEOF_SIZE_T > 4
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001229 size_hi = (DWORD)((offset + m_obj->size) >> 32);
1230 size_lo = (DWORD)((offset + m_obj->size) & 0xFFFFFFFF);
1231 off_hi = (DWORD)(offset >> 32);
1232 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Tim Peterse564e7f2006-02-16 23:46:01 +00001233#else
1234 size_hi = 0;
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001235 size_lo = (DWORD)(offset + m_obj->size);
1236 off_hi = 0;
1237 off_lo = (DWORD)offset;
Tim Peterse564e7f2006-02-16 23:46:01 +00001238#endif
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001239 /* For files, it would be sufficient to pass 0 as size.
1240 For anonymous maps, we have to pass the size explicitly. */
Tim Peters8f9cc292006-02-17 00:00:20 +00001241 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1242 NULL,
1243 flProtect,
1244 size_hi,
1245 size_lo,
1246 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001247 if (m_obj->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +00001248 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1249 dwDesiredAccess,
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001250 off_hi,
1251 off_lo,
Tim Peters8f9cc292006-02-17 00:00:20 +00001252 0);
Tim Peters23721ee2006-02-16 23:50:16 +00001253 if (m_obj->data != NULL)
1254 return (PyObject *)m_obj;
1255 else
Tim Peters5ebfd362001-11-13 23:11:19 +00001256 dwErr = GetLastError();
Tim Peters23721ee2006-02-16 23:50:16 +00001257 } else
Guido van Rossum09fdf072000-03-31 01:17:07 +00001258 dwErr = GetLastError();
Mark Hammond2cbed002000-07-30 02:22:43 +00001259 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001260 PyErr_SetFromWindowsErr(dwErr);
Tim Peters23721ee2006-02-16 23:50:16 +00001261 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001262}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001263#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001264
1265/* List of functions exported by this module */
1266static struct PyMethodDef mmap_functions[] = {
Tim Petersec0a5f02006-02-16 23:47:20 +00001267 {"mmap", (PyCFunction) new_mmap_object,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001268 METH_VARARGS|METH_KEYWORDS},
1269 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001270};
1271
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001272static void
1273setint(PyObject *d, const char *name, long value)
1274{
Christian Heimes217cfd12007-12-02 14:31:20 +00001275 PyObject *o = PyLong_FromLong(value);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001276 if (o && PyDict_SetItemString(d, name, o) == 0) {
1277 Py_DECREF(o);
1278 }
1279}
1280
Mark Hammond62b1ab12002-07-23 06:31:15 +00001281PyMODINIT_FUNC
Tim Peters5ebfd362001-11-13 23:11:19 +00001282 initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001283{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001284 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001285
1286 /* Patch the object type */
Christian Heimes90aa7642007-12-19 02:45:37 +00001287 Py_TYPE(&mmap_object_type) = &PyType_Type;
Tim Peters2caf8df2001-01-14 05:05:51 +00001288
Tim Peters8f9cc292006-02-17 00:00:20 +00001289 module = Py_InitModule("mmap", mmap_functions);
Neal Norwitz1ac754f2006-01-19 06:09:39 +00001290 if (module == NULL)
1291 return;
Tim Peters8f9cc292006-02-17 00:00:20 +00001292 dict = PyModule_GetDict(module);
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001293 if (!dict)
1294 return;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001295 mmap_module_error = PyExc_EnvironmentError;
Tim Peters8f9cc292006-02-17 00:00:20 +00001296 PyDict_SetItemString(dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001297#ifdef PROT_EXEC
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001298 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001299#endif
1300#ifdef PROT_READ
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001301 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001302#endif
1303#ifdef PROT_WRITE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001304 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001305#endif
1306
1307#ifdef MAP_SHARED
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001308 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001309#endif
1310#ifdef MAP_PRIVATE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001311 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001312#endif
1313#ifdef MAP_DENYWRITE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001314 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001315#endif
1316#ifdef MAP_EXECUTABLE
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001317 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001318#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001319#ifdef MAP_ANONYMOUS
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001320 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1321 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001322#endif
1323
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001324 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001325
Guido van Rossum8ce8a782007-11-01 19:42:39 +00001326 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
1327
Thomas Wouters00ee7ba2006-08-21 19:07:27 +00001328 setint(dict, "ACCESS_READ", ACCESS_READ);
1329 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1330 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Tim Peters5ebfd362001-11-13 23:11:19 +00001331}