blob: e25ec97bb4132a4a335c9a3e2225112d8e581eee [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
6 / mmapmodule.cpp -- map a view of a file into memory
7 /
8 / todo: need permission flags, perhaps a 'chsize' analog
9 / not all functions check range yet!!!
10 /
11 /
Mark Hammond071864a2000-07-30 02:46:26 +000012 / This version of mmapmodule.c has been changed significantly
13 / from the original mmapfile.c on which it was based.
14 / The original version of mmapfile is maintained by Sam at
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000015 / ftp://squirl.nightmare.com/pub/python/python-ext.
16*/
17
Martin v. Löwiscfe7e092006-02-17 06:59:14 +000018#define PY_SSIZE_T_CLEAN
Guido van Rossum09fdf072000-03-31 01:17:07 +000019#include <Python.h>
20
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000021#ifndef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000022#define UNIX
23#endif
24
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000025#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000026#include <windows.h>
Fred Drake145f96e2000-10-01 17:50:46 +000027static int
28my_getpagesize(void)
29{
Tim Peters5ebfd362001-11-13 23:11:19 +000030 SYSTEM_INFO si;
31 GetSystemInfo(&si);
32 return si.dwPageSize;
Fred Drake145f96e2000-10-01 17:50:46 +000033}
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000034#endif
35
36#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000037#include <sys/mman.h>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000038#include <sys/stat.h>
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000039
Fred Drake145f96e2000-10-01 17:50:46 +000040#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
41static int
42my_getpagesize(void)
43{
Tim Peters5ebfd362001-11-13 23:11:19 +000044 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000045}
46#else
47#define my_getpagesize getpagesize
48#endif
49
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000050#endif /* UNIX */
51
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000052#include <string.h>
Martin v. Löwis0e8bd7e2006-06-10 12:23:46 +000053
54#ifdef HAVE_SYS_TYPES_H
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000055#include <sys/types.h>
Martin v. Löwis0e8bd7e2006-06-10 12:23:46 +000056#endif /* HAVE_SYS_TYPES_H */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000057
Neal Norwitz3eaf2b52006-02-16 08:08:54 +000058/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +000059#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
60# define MAP_ANONYMOUS MAP_ANON
61#endif
62
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000063static PyObject *mmap_module_error;
64
Tim Peters5ebfd362001-11-13 23:11:19 +000065typedef enum
66{
67 ACCESS_DEFAULT,
68 ACCESS_READ,
69 ACCESS_WRITE,
70 ACCESS_COPY
71} access_mode;
72
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000073typedef struct {
Guido van Rossum09fdf072000-03-31 01:17:07 +000074 PyObject_HEAD
75 char * data;
76 size_t size;
77 size_t pos;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000078
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000079#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +000080 HANDLE map_handle;
Mark Hammond071864a2000-07-30 02:46:26 +000081 HANDLE file_handle;
Guido van Rossum09fdf072000-03-31 01:17:07 +000082 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000083#endif
84
85#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000086 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000087#endif
Tim Peters5ebfd362001-11-13 23:11:19 +000088
89 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000090} mmap_object;
91
Tim Peters5ebfd362001-11-13 23:11:19 +000092
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000093static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +000094mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000095{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000096#ifdef MS_WINDOWS
Mark Hammond2cbed002000-07-30 02:22:43 +000097 if (m_obj->data != NULL)
98 UnmapViewOfFile (m_obj->data);
99 if (m_obj->map_handle != INVALID_HANDLE_VALUE)
100 CloseHandle (m_obj->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000101 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
102 CloseHandle (m_obj->file_handle);
Mark Hammond2cbed002000-07-30 02:22:43 +0000103 if (m_obj->tagname)
104 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000105#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000106
107#ifdef UNIX
Neal Norwitz6eac2002005-11-02 05:36:37 +0000108 if (m_obj->fd >= 0)
109 (void) close(m_obj->fd);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000110 if (m_obj->data!=NULL) {
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000111 msync(m_obj->data, m_obj->size, MS_SYNC);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000112 munmap(m_obj->data, m_obj->size);
113 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000114#endif /* UNIX */
115
Guido van Rossumb18618d2000-05-03 23:44:39 +0000116 PyObject_Del(m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000117}
118
119static PyObject *
Georg Brandl96a8c392006-05-29 21:04:52 +0000120mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000121{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000122#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000123 /* For each resource we maintain, we need to check
Tim Petersec0a5f02006-02-16 23:47:20 +0000124 the value is valid, and if so, free the resource
Mark Hammond071864a2000-07-30 02:46:26 +0000125 and set the member value to an invalid value so
126 the dealloc does not attempt to resource clearing
127 again.
128 TODO - should we check for errors in the close operations???
129 */
130 if (self->data != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000131 UnmapViewOfFile(self->data);
Mark Hammond071864a2000-07-30 02:46:26 +0000132 self->data = NULL;
133 }
134 if (self->map_handle != INVALID_HANDLE_VALUE) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000135 CloseHandle(self->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000136 self->map_handle = INVALID_HANDLE_VALUE;
137 }
138 if (self->file_handle != INVALID_HANDLE_VALUE) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000139 CloseHandle(self->file_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000140 self->file_handle = INVALID_HANDLE_VALUE;
141 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000142#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000143
144#ifdef UNIX
Neal Norwitz6eac2002005-11-02 05:36:37 +0000145 (void) close(self->fd);
146 self->fd = -1;
Neal Norwitze604c022003-01-10 20:52:16 +0000147 if (self->data != NULL) {
148 munmap(self->data, self->size);
149 self->data = NULL;
150 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000151#endif
152
Tim Peters8f9cc292006-02-17 00:00:20 +0000153 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000154 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000155}
156
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000157#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +0000158#define CHECK_VALID(err) \
159do { \
Guido van Rossum69c2b882003-04-09 19:31:02 +0000160 if (self->map_handle == INVALID_HANDLE_VALUE) { \
Tim Peters8f9cc292006-02-17 00:00:20 +0000161 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
Guido van Rossum09fdf072000-03-31 01:17:07 +0000162 return err; \
163 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000164} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000165#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000166
167#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000168#define CHECK_VALID(err) \
169do { \
170 if (self->data == NULL) { \
Tim Peters8f9cc292006-02-17 00:00:20 +0000171 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
Guido van Rossum09fdf072000-03-31 01:17:07 +0000172 return err; \
173 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000174} while (0)
175#endif /* UNIX */
176
177static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000178mmap_read_byte_method(mmap_object *self,
Georg Brandl96a8c392006-05-29 21:04:52 +0000179 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000180{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000181 CHECK_VALID(NULL);
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000182 if (self->pos < self->size) {
Tim Petersd6283b82001-05-09 18:48:26 +0000183 char value = self->data[self->pos];
Guido van Rossum09fdf072000-03-31 01:17:07 +0000184 self->pos += 1;
Tim Petersd6283b82001-05-09 18:48:26 +0000185 return Py_BuildValue("c", value);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000186 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000187 PyErr_SetString(PyExc_ValueError, "read byte out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000188 return NULL;
189 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000190}
191
192static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000193mmap_read_line_method(mmap_object *self,
Georg Brandl96a8c392006-05-29 21:04:52 +0000194 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000195{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000196 char *start = self->data+self->pos;
197 char *eof = self->data+self->size;
198 char *eol;
199 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000200
Guido van Rossum09fdf072000-03-31 01:17:07 +0000201 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000202
Fred Drake56a87a02000-04-04 18:17:35 +0000203 eol = memchr(start, '\n', self->size - self->pos);
204 if (!eol)
205 eol = eof;
206 else
207 ++eol; /* we're interested in the position after the
208 newline. */
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000209 result = PyString_FromStringAndSize(start, (eol - start));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000210 self->pos += (eol - start);
Tim Peters23721ee2006-02-16 23:50:16 +0000211 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000212}
213
214static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000215mmap_read_method(mmap_object *self,
216 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000217{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000218 Py_ssize_t num_bytes;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000219 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000220
Guido van Rossum09fdf072000-03-31 01:17:07 +0000221 CHECK_VALID(NULL);
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000222 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000223 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000224
Guido van Rossum09fdf072000-03-31 01:17:07 +0000225 /* silently 'adjust' out-of-range requests */
226 if ((self->pos + num_bytes) > self->size) {
227 num_bytes -= (self->pos+num_bytes) - self->size;
228 }
229 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
Tim Petersec0a5f02006-02-16 23:47:20 +0000230 self->pos += num_bytes;
Tim Peters23721ee2006-02-16 23:50:16 +0000231 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000232}
233
234static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000235mmap_find_method(mmap_object *self,
236 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000237{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000238 Py_ssize_t start = self->pos;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000239 char *needle;
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000240 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000241
Guido van Rossum09fdf072000-03-31 01:17:07 +0000242 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000243 if (!PyArg_ParseTuple(args, "s#|n:find", &needle, &len, &start)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000244 return NULL;
245 } else {
Greg Stein834f4dd2001-05-14 09:32:26 +0000246 char *p;
247 char *e = self->data + self->size;
248
249 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000250 start += self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000251 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000252 start = 0;
Tim Petersd401edd2001-05-14 23:19:12 +0000253 else if ((size_t)start > self->size)
Tim Peters5ebfd362001-11-13 23:11:19 +0000254 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000255
Tim Petersc9ffa062002-03-08 05:43:32 +0000256 for (p = self->data + start; p + len <= e; ++p) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000257 Py_ssize_t i;
Tim Petersc9ffa062002-03-08 05:43:32 +0000258 for (i = 0; i < len && needle[i] == p[i]; ++i)
259 /* nothing */;
260 if (i == len) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000261 return PyInt_FromSsize_t(p - self->data);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000262 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000263 }
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000264 return PyInt_FromLong(-1);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000265 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000266}
267
Tim Petersec0a5f02006-02-16 23:47:20 +0000268static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000269is_writeable(mmap_object *self)
270{
271 if (self->access != ACCESS_READ)
Tim Petersec0a5f02006-02-16 23:47:20 +0000272 return 1;
Tim Peters5ebfd362001-11-13 23:11:19 +0000273 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
274 return 0;
275}
276
Tim Petersec0a5f02006-02-16 23:47:20 +0000277static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000278is_resizeable(mmap_object *self)
279{
280 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
Tim Petersec0a5f02006-02-16 23:47:20 +0000281 return 1;
282 PyErr_Format(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000283 "mmap can't resize a readonly or copy-on-write memory map.");
284 return 0;
285}
286
287
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000288static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000289mmap_write_method(mmap_object *self,
290 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000291{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000292 Py_ssize_t length;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000293 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000294
Guido van Rossum09fdf072000-03-31 01:17:07 +0000295 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000296 if (!PyArg_ParseTuple(args, "s#:write", &data, &length))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000297 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000298
Tim Peters5ebfd362001-11-13 23:11:19 +0000299 if (!is_writeable(self))
300 return NULL;
301
Guido van Rossum09fdf072000-03-31 01:17:07 +0000302 if ((self->pos + length) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000303 PyErr_SetString(PyExc_ValueError, "data out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000304 return NULL;
305 }
Tim Peters8f9cc292006-02-17 00:00:20 +0000306 memcpy(self->data+self->pos, data, length);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000307 self->pos = self->pos+length;
Tim Peters8f9cc292006-02-17 00:00:20 +0000308 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000309 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000310}
311
312static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000313mmap_write_byte_method(mmap_object *self,
314 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000315{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000316 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000317
Guido van Rossum09fdf072000-03-31 01:17:07 +0000318 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000319 if (!PyArg_ParseTuple(args, "c:write_byte", &value))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000320 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000321
Tim Peters5ebfd362001-11-13 23:11:19 +0000322 if (!is_writeable(self))
323 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000324 *(self->data+self->pos) = value;
325 self->pos += 1;
Tim Peters8f9cc292006-02-17 00:00:20 +0000326 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000327 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000328}
Tim Petersec0a5f02006-02-16 23:47:20 +0000329
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000330static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000331mmap_size_method(mmap_object *self,
Georg Brandl96a8c392006-05-29 21:04:52 +0000332 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000333{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000334 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000335
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000336#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000337 if (self->file_handle != INVALID_HANDLE_VALUE) {
Martin v. Löwis15186072006-02-18 12:38:35 +0000338 DWORD low,high;
339 PY_LONG_LONG size;
340 low = GetFileSize(self->file_handle, &high);
341 if (low == INVALID_FILE_SIZE) {
342 /* It might be that the function appears to have failed,
343 when indeed its size equals INVALID_FILE_SIZE */
344 DWORD error = GetLastError();
345 if (error != NO_ERROR)
346 return PyErr_SetFromWindowsErr(error);
347 }
348 if (!high && low < LONG_MAX)
349 return PyInt_FromLong((long)low);
350 size = (((PY_LONG_LONG)high)<<32) + low;
351 return PyLong_FromLongLong(size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000352 } else {
Martin v. Löwis15186072006-02-18 12:38:35 +0000353 return PyInt_FromSsize_t(self->size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000354 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000355#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000356
357#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000358 {
359 struct stat buf;
360 if (-1 == fstat(self->fd, &buf)) {
361 PyErr_SetFromErrno(mmap_module_error);
362 return NULL;
363 }
Martin v. Löwis15186072006-02-18 12:38:35 +0000364 return PyInt_FromSsize_t(buf.st_size);
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000365 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000366#endif /* UNIX */
367}
368
369/* This assumes that you want the entire file mapped,
370 / and when recreating the map will make the new file
371 / have the new size
372 /
373 / Is this really necessary? This could easily be done
374 / from python by just closing and re-opening with the
375 / new size?
376 */
377
378static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000379mmap_resize_method(mmap_object *self,
380 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000381{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000382 Py_ssize_t new_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000383 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000384 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000385 !is_resizeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000386 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000387#ifdef MS_WINDOWS
Tim Petersec0a5f02006-02-16 23:47:20 +0000388 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000389 DWORD dwErrCode = 0;
Martin v. Löwis15186072006-02-18 12:38:35 +0000390 DWORD newSizeLow, newSizeHigh;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000391 /* First, unmap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000392 UnmapViewOfFile(self->data);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000393 /* Close the mapping object */
Tim Peters8f9cc292006-02-17 00:00:20 +0000394 CloseHandle(self->map_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000395 /* Move to the desired EOF position */
Martin v. Löwis15186072006-02-18 12:38:35 +0000396#if SIZEOF_SIZE_T > 4
397 newSizeHigh = (DWORD)(new_size >> 32);
398 newSizeLow = (DWORD)(new_size & 0xFFFFFFFF);
399#else
400 newSizeHigh = 0;
Martin v. Löwis5bb8a152006-02-18 12:49:49 +0000401 newSizeLow = (DWORD)new_size;
Martin v. Löwis15186072006-02-18 12:38:35 +0000402#endif
Tim Peters8f9cc292006-02-17 00:00:20 +0000403 SetFilePointer(self->file_handle,
Martin v. Löwis15186072006-02-18 12:38:35 +0000404 newSizeLow, &newSizeHigh, FILE_BEGIN);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000405 /* Change the size of the file */
Tim Peters8f9cc292006-02-17 00:00:20 +0000406 SetEndOfFile(self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000407 /* Create another mapping object and remap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000408 self->map_handle = CreateFileMapping(
Mark Hammond071864a2000-07-30 02:46:26 +0000409 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000410 NULL,
411 PAGE_READWRITE,
Martin v. Löwis15186072006-02-18 12:38:35 +0000412 newSizeHigh,
413 newSizeLow,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000414 self->tagname);
415 if (self->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000416 self->data = (char *) MapViewOfFile(self->map_handle,
417 FILE_MAP_WRITE,
418 0,
419 0,
420 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000421 if (self->data != NULL) {
422 self->size = new_size;
Tim Peters8f9cc292006-02-17 00:00:20 +0000423 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000424 return Py_None;
425 } else {
426 dwErrCode = GetLastError();
427 }
428 } else {
429 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000430 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000431 PyErr_SetFromWindowsErr(dwErrCode);
Tim Peters23721ee2006-02-16 23:50:16 +0000432 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000433#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000434
435#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000436#ifndef HAVE_MREMAP
Tim Peters5ebfd362001-11-13 23:11:19 +0000437 } else {
438 PyErr_SetString(PyExc_SystemError,
439 "mmap: resizing not available--no mremap()");
440 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000441#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000442 } else {
Armin Rigo335ffe82005-09-20 19:04:02 +0000443 void *newmap;
444
Georg Brandl38387b82005-08-24 07:17:40 +0000445 if (ftruncate(self->fd, new_size) == -1) {
446 PyErr_SetFromErrno(mmap_module_error);
447 return NULL;
448 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000449
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000450#ifdef MREMAP_MAYMOVE
Tim Peters5ebfd362001-11-13 23:11:19 +0000451 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000452#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000453 newmap = mremap(self->data, self->size, new_size, 0);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000454#endif
Tim Petersec0a5f02006-02-16 23:47:20 +0000455 if (newmap == (void *)-1)
Tim Peters5ebfd362001-11-13 23:11:19 +0000456 {
457 PyErr_SetFromErrno(mmap_module_error);
458 return NULL;
459 }
460 self->data = newmap;
461 self->size = new_size;
462 Py_INCREF(Py_None);
463 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000464#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000465#endif /* UNIX */
Tim Peters5ebfd362001-11-13 23:11:19 +0000466 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000467}
468
469static PyObject *
Georg Brandl96a8c392006-05-29 21:04:52 +0000470mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000471{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000472 CHECK_VALID(NULL);
Georg Brandl2cfaa342006-05-29 19:39:45 +0000473 return PyInt_FromLong((long) self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000474}
475
476static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000477mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000478{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000479 Py_ssize_t offset = 0;
480 Py_ssize_t size = self->size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000481 CHECK_VALID(NULL);
Tim Petersf2882952006-02-17 01:07:39 +0000482 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000483 return NULL;
Tim Petersf2882952006-02-17 01:07:39 +0000484 if ((size_t)(offset + size) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000485 PyErr_SetString(PyExc_ValueError, "flush values out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000486 return NULL;
487 } else {
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000488#ifdef MS_WINDOWS
Georg Brandl2cfaa342006-05-29 19:39:45 +0000489 return PyInt_FromLong((long)
Tim Peters23721ee2006-02-16 23:50:16 +0000490 FlushViewOfFile(self->data+offset, size));
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000491#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000492#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000493 /* XXX semantics of return value? */
494 /* XXX flags for msync? */
495 if (-1 == msync(self->data + offset, size,
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000496 MS_SYNC))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000497 {
498 PyErr_SetFromErrno(mmap_module_error);
499 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000500 }
Georg Brandl2cfaa342006-05-29 19:39:45 +0000501 return PyInt_FromLong(0);
Tim Petersec0a5f02006-02-16 23:47:20 +0000502#endif /* UNIX */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000503 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000504}
505
506static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000507mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000508{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000509 Py_ssize_t dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000510 int how=0;
511 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000512 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
Tim Peters8f9cc292006-02-17 00:00:20 +0000513 return NULL;
514 else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000515 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000516 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000517 case 0: /* relative to start */
518 if (dist < 0)
519 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000520 where = dist;
521 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000522 case 1: /* relative to current position */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000523 if ((Py_ssize_t)self->pos + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000524 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000525 where = self->pos + dist;
526 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000527 case 2: /* relative to end */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000528 if ((Py_ssize_t)self->size + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000529 goto onoutofrange;
530 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000531 break;
532 default:
Tim Peters8f9cc292006-02-17 00:00:20 +0000533 PyErr_SetString(PyExc_ValueError, "unknown seek type");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000534 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000535 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000536 if (where > self->size)
537 goto onoutofrange;
538 self->pos = where;
Tim Peters8f9cc292006-02-17 00:00:20 +0000539 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000540 return Py_None;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000541 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000542
Tim Peters5ebfd362001-11-13 23:11:19 +0000543 onoutofrange:
Tim Peters8f9cc292006-02-17 00:00:20 +0000544 PyErr_SetString(PyExc_ValueError, "seek out of range");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000545 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000546}
547
548static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000549mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000550{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000551 unsigned long dest, src, count;
552 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000553 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &count) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000554 !is_writeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000555 return NULL;
556 } else {
557 /* bounds check the values */
558 if (/* end of source after end of data?? */
559 ((src+count) > self->size)
560 /* dest will fit? */
561 || (dest+count > self->size)) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000562 PyErr_SetString(PyExc_ValueError,
563 "source or destination out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000564 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000565 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000566 memmove(self->data+dest, self->data+src, count);
567 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000568 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000569 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000570 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000571}
572
573static struct PyMethodDef mmap_object_methods[] = {
Georg Brandl96a8c392006-05-29 21:04:52 +0000574 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000575 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
576 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
577 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
578 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
Georg Brandl96a8c392006-05-29 21:04:52 +0000579 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
580 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000581 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
582 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
Georg Brandl96a8c392006-05-29 21:04:52 +0000583 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
584 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000585 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
586 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000587 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000588};
589
590/* Functions for treating an mmap'ed file as a buffer */
591
Martin v. Löwis18e16552006-02-15 17:27:45 +0000592static Py_ssize_t
593mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000594{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000595 CHECK_VALID(-1);
Tim Peters8f9cc292006-02-17 00:00:20 +0000596 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000597 PyErr_SetString(PyExc_SystemError,
598 "Accessing non-existent mmap segment");
599 return -1;
600 }
601 *ptr = self->data;
602 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000603}
604
Martin v. Löwis18e16552006-02-15 17:27:45 +0000605static Py_ssize_t
606mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Tim Petersec0a5f02006-02-16 23:47:20 +0000607{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000608 CHECK_VALID(-1);
Tim Peters8f9cc292006-02-17 00:00:20 +0000609 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000610 PyErr_SetString(PyExc_SystemError,
611 "Accessing non-existent mmap segment");
612 return -1;
613 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000614 if (!is_writeable(self))
615 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000616 *ptr = self->data;
617 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000618}
619
Martin v. Löwis18e16552006-02-15 17:27:45 +0000620static Py_ssize_t
621mmap_buffer_getsegcount(mmap_object *self, Py_ssize_t *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000622{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000623 CHECK_VALID(-1);
Tim Petersec0a5f02006-02-16 23:47:20 +0000624 if (lenp)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000625 *lenp = self->size;
626 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000627}
628
Martin v. Löwis18e16552006-02-15 17:27:45 +0000629static Py_ssize_t
630mmap_buffer_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000631{
Tim Peters8f9cc292006-02-17 00:00:20 +0000632 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000633 PyErr_SetString(PyExc_SystemError,
634 "accessing non-existent buffer segment");
635 return -1;
636 }
637 *ptr = (const char *)self->data;
638 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000639}
640
641static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000642mmap_object_getattr(mmap_object *self, char *name)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000643{
Tim Peters8f9cc292006-02-17 00:00:20 +0000644 return Py_FindMethod(mmap_object_methods, (PyObject *)self, name);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000645}
646
Martin v. Löwis18e16552006-02-15 17:27:45 +0000647static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000648mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000649{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000650 CHECK_VALID(-1);
651 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000652}
653
654static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000655mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000656{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000657 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000658 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000659 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
660 return NULL;
661 }
662 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000663}
664
665static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000666mmap_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000667{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000668 CHECK_VALID(NULL);
669 if (ilow < 0)
670 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000671 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000672 ilow = self->size;
673 if (ihigh < 0)
674 ihigh = 0;
675 if (ihigh < ilow)
676 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000677 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000678 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000679
Guido van Rossum09fdf072000-03-31 01:17:07 +0000680 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000681}
682
683static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000684mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000685{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000686 CHECK_VALID(NULL);
687 PyErr_SetString(PyExc_SystemError,
688 "mmaps don't support concatenation");
689 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000690}
691
692static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000693mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000694{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000695 CHECK_VALID(NULL);
696 PyErr_SetString(PyExc_SystemError,
697 "mmaps don't support repeat operation");
698 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000699}
700
701static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000702mmap_ass_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000703{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000704 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000705
Guido van Rossum09fdf072000-03-31 01:17:07 +0000706 CHECK_VALID(-1);
707 if (ilow < 0)
708 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000709 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000710 ilow = self->size;
711 if (ihigh < 0)
712 ihigh = 0;
713 if (ihigh < ilow)
714 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000715 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000716 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000717
Thomas Wouters1baac722001-07-16 15:47:36 +0000718 if (v == NULL) {
719 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000720 "mmap object doesn't support slice deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000721 return -1;
722 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000723 if (! (PyString_Check(v)) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000724 PyErr_SetString(PyExc_IndexError,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000725 "mmap slice assignment must be a string");
726 return -1;
727 }
Tim Peters8f9cc292006-02-17 00:00:20 +0000728 if (PyString_Size(v) != (ihigh - ilow)) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000729 PyErr_SetString(PyExc_IndexError,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000730 "mmap slice assignment is wrong size");
731 return -1;
732 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000733 if (!is_writeable(self))
734 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000735 buf = PyString_AsString(v);
736 memcpy(self->data + ilow, buf, ihigh-ilow);
737 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000738}
739
740static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000741mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000742{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000743 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000744
Guido van Rossum09fdf072000-03-31 01:17:07 +0000745 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000746 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000747 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
748 return -1;
749 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000750 if (v == NULL) {
751 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000752 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000753 return -1;
754 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000755 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000756 PyErr_SetString(PyExc_IndexError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000757 "mmap assignment must be single-character string");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000758 return -1;
759 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000760 if (!is_writeable(self))
761 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000762 buf = PyString_AsString(v);
763 self->data[i] = buf[0];
764 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000765}
766
767static PySequenceMethods mmap_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000768 (lenfunc)mmap_length, /*sq_length*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000769 (binaryfunc)mmap_concat, /*sq_concat*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000770 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
771 (ssizeargfunc)mmap_item, /*sq_item*/
772 (ssizessizeargfunc)mmap_slice, /*sq_slice*/
773 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
774 (ssizessizeobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000775};
776
777static PyBufferProcs mmap_as_buffer = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000778 (readbufferproc)mmap_buffer_getreadbuf,
779 (writebufferproc)mmap_buffer_getwritebuf,
780 (segcountproc)mmap_buffer_getsegcount,
781 (charbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000782};
783
784static PyTypeObject mmap_object_type = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000785 PyObject_HEAD_INIT(0) /* patched in module init */
786 0, /* ob_size */
Guido van Rossum14648392001-12-08 18:02:58 +0000787 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000788 sizeof(mmap_object), /* tp_size */
789 0, /* tp_itemsize */
790 /* methods */
791 (destructor) mmap_object_dealloc, /* tp_dealloc */
792 0, /* tp_print */
793 (getattrfunc) mmap_object_getattr, /* tp_getattr */
794 0, /* tp_setattr */
795 0, /* tp_compare */
796 0, /* tp_repr */
797 0, /* tp_as_number */
798 &mmap_as_sequence, /*tp_as_sequence*/
799 0, /*tp_as_mapping*/
800 0, /*tp_hash*/
801 0, /*tp_call*/
802 0, /*tp_str*/
803 0, /*tp_getattro*/
804 0, /*tp_setattro*/
805 &mmap_as_buffer, /*tp_as_buffer*/
806 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
807 0, /*tp_doc*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000808};
809
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000810
811/* extract the map size from the given PyObject
812
Thomas Wouters7e474022000-07-16 12:04:32 +0000813 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000814 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000815static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000816_GetMapSize(PyObject *o)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000817{
Neal Norwitz8a87f5d2006-08-12 17:03:09 +0000818 if (PyIndex_Check(o)) {
819 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
Guido van Rossum38fff8c2006-03-07 18:50:55 +0000820 if (i==-1 && PyErr_Occurred())
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000821 return -1;
Neal Norwitz8a87f5d2006-08-12 17:03:09 +0000822 if (i < 0) {
823 PyErr_SetString(PyExc_OverflowError,
824 "memory mapped size must be positive");
825 return -1;
826 }
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000827 return i;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000828 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000829
Neal Norwitz8a87f5d2006-08-12 17:03:09 +0000830 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000831 return -1;
832}
833
Tim Petersec0a5f02006-02-16 23:47:20 +0000834#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000835static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000836new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000837{
Neal Norwitzb5673922002-09-05 21:48:07 +0000838#ifdef HAVE_FSTAT
839 struct stat st;
840#endif
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000841 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000842 PyObject *map_size_obj = NULL;
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000843 Py_ssize_t map_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000844 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +0000845 int devzero = -1;
Neal Norwitz8856fb72005-12-18 03:34:22 +0000846 int access = (int)ACCESS_DEFAULT;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +0000847 static char *keywords[] = {"fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +0000848 "flags", "prot",
Jeremy Hyltonaf68c872005-12-10 18:50:16 +0000849 "access", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000850
Tim Petersec0a5f02006-02-16 23:47:20 +0000851 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii", keywords,
Jeremy Hyltonaf68c872005-12-10 18:50:16 +0000852 &fd, &map_size_obj, &flags, &prot,
853 &access))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000854 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000855 map_size = _GetMapSize(map_size_obj);
856 if (map_size < 0)
857 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000858
Tim Petersec0a5f02006-02-16 23:47:20 +0000859 if ((access != (int)ACCESS_DEFAULT) &&
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +0000860 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
Tim Petersec0a5f02006-02-16 23:47:20 +0000861 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000862 "mmap can't specify both access and flags, prot.");
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +0000863 switch ((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +0000864 case ACCESS_READ:
865 flags = MAP_SHARED;
866 prot = PROT_READ;
867 break;
868 case ACCESS_WRITE:
869 flags = MAP_SHARED;
870 prot = PROT_READ | PROT_WRITE;
871 break;
872 case ACCESS_COPY:
873 flags = MAP_PRIVATE;
874 prot = PROT_READ | PROT_WRITE;
875 break;
Tim Petersec0a5f02006-02-16 23:47:20 +0000876 case ACCESS_DEFAULT:
Tim Peters5ebfd362001-11-13 23:11:19 +0000877 /* use the specified or default values of flags and prot */
878 break;
879 default:
Tim Petersec0a5f02006-02-16 23:47:20 +0000880 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000881 "mmap invalid access parameter.");
882 }
Neal Norwitzb5673922002-09-05 21:48:07 +0000883
884#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +0000885# ifdef __VMS
886 /* on OpenVMS we must ensure that all bytes are written to the file */
887 fsync(fd);
888# endif
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000889 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
890 if (map_size == 0) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000891 map_size = st.st_size;
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000892 } else if ((size_t)map_size > st.st_size) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000893 PyErr_SetString(PyExc_ValueError,
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000894 "mmap length is greater than file size");
895 return NULL;
896 }
Neal Norwitzb5673922002-09-05 21:48:07 +0000897 }
898#endif
Tim Peters8f9cc292006-02-17 00:00:20 +0000899 m_obj = PyObject_New(mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000900 if (m_obj == NULL) {return NULL;}
Neal Norwitz3b4fff82006-01-11 08:54:45 +0000901 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000902 m_obj->size = (size_t) map_size;
903 m_obj->pos = (size_t) 0;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +0000904 if (fd == -1) {
905 m_obj->fd = -1;
906 /* Assume the caller wants to map anonymous memory.
907 This is the same behaviour as Windows. mmap.mmap(-1, size)
908 on both Windows and Unix map anonymous memory.
909 */
910#ifdef MAP_ANONYMOUS
911 /* BSD way to map anonymous memory */
912 flags |= MAP_ANONYMOUS;
913#else
914 /* SVR4 method to map anonymous memory is to open /dev/zero */
915 fd = devzero = open("/dev/zero", O_RDWR);
916 if (devzero == -1) {
917 Py_DECREF(m_obj);
918 PyErr_SetFromErrno(mmap_module_error);
919 return NULL;
920 }
921#endif
922 } else {
923 m_obj->fd = dup(fd);
924 if (m_obj->fd == -1) {
925 Py_DECREF(m_obj);
926 PyErr_SetFromErrno(mmap_module_error);
927 return NULL;
928 }
Georg Brandl38387b82005-08-24 07:17:40 +0000929 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +0000930
Tim Petersec0a5f02006-02-16 23:47:20 +0000931 m_obj->data = mmap(NULL, map_size,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000932 prot, flags,
933 fd, 0);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +0000934
935 if (devzero != -1) {
936 close(devzero);
937 }
938
Tim Peters5ebfd362001-11-13 23:11:19 +0000939 if (m_obj->data == (char *)-1) {
Andrew M. Kuchling16581c82004-05-19 14:39:08 +0000940 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000941 Py_DECREF(m_obj);
942 PyErr_SetFromErrno(mmap_module_error);
943 return NULL;
944 }
Neal Norwitz8856fb72005-12-18 03:34:22 +0000945 m_obj->access = (access_mode)access;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000946 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000947}
948#endif /* UNIX */
949
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000950#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000951static PyObject *
Tim Peters5ebfd362001-11-13 23:11:19 +0000952new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000953{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000954 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000955 PyObject *map_size_obj = NULL;
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000956 Py_ssize_t map_size;
Tim Peterse564e7f2006-02-16 23:46:01 +0000957 DWORD size_hi; /* upper 32 bits of m_obj->size */
958 DWORD size_lo; /* lower 32 bits of m_obj->size */
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000959 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +0000960 DWORD dwErr = 0;
961 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +0000962 HANDLE fh = 0;
Neal Norwitz8856fb72005-12-18 03:34:22 +0000963 int access = (access_mode)ACCESS_DEFAULT;
Tim Peters5ebfd362001-11-13 23:11:19 +0000964 DWORD flProtect, dwDesiredAccess;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +0000965 static char *keywords[] = { "fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +0000966 "tagname",
Jeremy Hyltonaf68c872005-12-10 18:50:16 +0000967 "access", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000968
Tim Peters5ebfd362001-11-13 23:11:19 +0000969 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|zi", keywords,
Tim Petersec0a5f02006-02-16 23:47:20 +0000970 &fileno, &map_size_obj,
Tim Peters5ebfd362001-11-13 23:11:19 +0000971 &tagname, &access)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000972 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000973 }
974
Neal Norwitz8856fb72005-12-18 03:34:22 +0000975 switch((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +0000976 case ACCESS_READ:
977 flProtect = PAGE_READONLY;
978 dwDesiredAccess = FILE_MAP_READ;
979 break;
980 case ACCESS_DEFAULT: case ACCESS_WRITE:
981 flProtect = PAGE_READWRITE;
982 dwDesiredAccess = FILE_MAP_WRITE;
983 break;
984 case ACCESS_COPY:
985 flProtect = PAGE_WRITECOPY;
986 dwDesiredAccess = FILE_MAP_COPY;
987 break;
988 default:
Tim Petersec0a5f02006-02-16 23:47:20 +0000989 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000990 "mmap invalid access parameter.");
991 }
992
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000993 map_size = _GetMapSize(map_size_obj);
994 if (map_size < 0)
995 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +0000996
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +0000997 /* assume -1 and 0 both mean invalid filedescriptor
998 to 'anonymously' map memory.
999 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1000 XXX: Should this code be added?
1001 if (fileno == 0)
1002 PyErr_Warn(PyExc_DeprecationWarning,
1003 "don't use 0 for anonymous memory");
1004 */
1005 if (fileno != -1 && fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +00001006 fh = (HANDLE)_get_osfhandle(fileno);
1007 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001008 PyErr_SetFromErrno(mmap_module_error);
1009 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001010 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +00001011 /* Win9x appears to need us seeked to zero */
Guido van Rossum69c2b882003-04-09 19:31:02 +00001012 lseek(fileno, 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001013 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001014
Tim Peters8f9cc292006-02-17 00:00:20 +00001015 m_obj = PyObject_New(mmap_object, &mmap_object_type);
1016 if (m_obj == NULL)
Mark Hammond2cbed002000-07-30 02:22:43 +00001017 return NULL;
1018 /* Set every field to an invalid marker, so we can safely
1019 destruct the object in the face of failure */
1020 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +00001021 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +00001022 m_obj->map_handle = INVALID_HANDLE_VALUE;
1023 m_obj->tagname = NULL;
1024
Guido van Rossum09fdf072000-03-31 01:17:07 +00001025 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +00001026 /* It is necessary to duplicate the handle, so the
1027 Python code can close it on us */
1028 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +00001029 GetCurrentProcess(), /* source process handle */
1030 fh, /* handle to be duplicated */
1031 GetCurrentProcess(), /* target proc handle */
1032 (LPHANDLE)&m_obj->file_handle, /* result */
1033 0, /* access - ignored due to options value */
1034 FALSE, /* inherited by child processes? */
1035 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +00001036 dwErr = GetLastError();
1037 Py_DECREF(m_obj);
1038 PyErr_SetFromWindowsErr(dwErr);
1039 return NULL;
1040 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001041 if (!map_size) {
Martin v. Löwis15186072006-02-18 12:38:35 +00001042 DWORD low,high;
1043 low = GetFileSize(fh, &high);
1044 /* low might just happen to have the value INVALID_FILE_SIZE;
1045 so we need to check the last error also. */
1046 if (low == INVALID_FILE_SIZE &&
1047 (dwErr = GetLastError()) != NO_ERROR) {
1048 Py_DECREF(m_obj);
1049 return PyErr_SetFromWindowsErr(dwErr);
1050 }
1051
1052#if SIZEOF_SIZE_T > 4
1053 m_obj->size = (((size_t)high)<<32) + low;
1054#else
1055 if (high)
1056 /* File is too large to map completely */
1057 m_obj->size = (size_t)-1;
1058 else
1059 m_obj->size = low;
1060#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001061 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001062 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001063 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001064 }
1065 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001066 m_obj->size = map_size;
1067 }
1068
1069 /* set the initial position */
1070 m_obj->pos = (size_t) 0;
1071
Mark Hammond2cbed002000-07-30 02:22:43 +00001072 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001073 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001074 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1075 if (m_obj->tagname == NULL) {
1076 PyErr_NoMemory();
1077 Py_DECREF(m_obj);
1078 return NULL;
1079 }
1080 strcpy(m_obj->tagname, tagname);
1081 }
1082 else
1083 m_obj->tagname = NULL;
1084
Neal Norwitz8856fb72005-12-18 03:34:22 +00001085 m_obj->access = (access_mode)access;
Tim Peterse564e7f2006-02-16 23:46:01 +00001086 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
Thomas Wouters2c98a7b2006-02-17 09:59:00 +00001087 * more than 4 bytes, we need to break it apart. Else (size_t
Tim Peterse564e7f2006-02-16 23:46:01 +00001088 * consumes 4 bytes), C doesn't define what happens if we shift
1089 * right by 32, so we need different code.
1090 */
1091#if SIZEOF_SIZE_T > 4
1092 size_hi = (DWORD)(m_obj->size >> 32);
1093 size_lo = (DWORD)(m_obj->size & 0xFFFFFFFF);
1094#else
1095 size_hi = 0;
1096 size_lo = (DWORD)m_obj->size;
1097#endif
Tim Peters8f9cc292006-02-17 00:00:20 +00001098 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1099 NULL,
1100 flProtect,
1101 size_hi,
1102 size_lo,
1103 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001104 if (m_obj->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +00001105 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1106 dwDesiredAccess,
1107 0,
1108 0,
1109 0);
Tim Peters23721ee2006-02-16 23:50:16 +00001110 if (m_obj->data != NULL)
1111 return (PyObject *)m_obj;
1112 else
Tim Peters5ebfd362001-11-13 23:11:19 +00001113 dwErr = GetLastError();
Tim Peters23721ee2006-02-16 23:50:16 +00001114 } else
Guido van Rossum09fdf072000-03-31 01:17:07 +00001115 dwErr = GetLastError();
Mark Hammond2cbed002000-07-30 02:22:43 +00001116 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001117 PyErr_SetFromWindowsErr(dwErr);
Tim Peters23721ee2006-02-16 23:50:16 +00001118 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001119}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001120#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001121
1122/* List of functions exported by this module */
1123static struct PyMethodDef mmap_functions[] = {
Tim Petersec0a5f02006-02-16 23:47:20 +00001124 {"mmap", (PyCFunction) new_mmap_object,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001125 METH_VARARGS|METH_KEYWORDS},
1126 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001127};
1128
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001129static void
1130setint(PyObject *d, const char *name, long value)
1131{
1132 PyObject *o = PyInt_FromLong(value);
1133 if (o)
1134 if (PyDict_SetItemString(d, name, o) == 0)
1135 Py_DECREF(o);
1136}
1137
Mark Hammond62b1ab12002-07-23 06:31:15 +00001138PyMODINIT_FUNC
Tim Peters5ebfd362001-11-13 23:11:19 +00001139 initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001140{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001141 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001142
1143 /* Patch the object type */
1144 mmap_object_type.ob_type = &PyType_Type;
1145
Tim Peters8f9cc292006-02-17 00:00:20 +00001146 module = Py_InitModule("mmap", mmap_functions);
Neal Norwitz1ac754f2006-01-19 06:09:39 +00001147 if (module == NULL)
1148 return;
Tim Peters8f9cc292006-02-17 00:00:20 +00001149 dict = PyModule_GetDict(module);
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001150 if (!dict)
1151 return;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001152 mmap_module_error = PyExc_EnvironmentError;
Tim Peters8f9cc292006-02-17 00:00:20 +00001153 PyDict_SetItemString(dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001154#ifdef PROT_EXEC
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001155 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001156#endif
1157#ifdef PROT_READ
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001158 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001159#endif
1160#ifdef PROT_WRITE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001161 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001162#endif
1163
1164#ifdef MAP_SHARED
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001165 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001166#endif
1167#ifdef MAP_PRIVATE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001168 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001169#endif
1170#ifdef MAP_DENYWRITE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001171 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001172#endif
1173#ifdef MAP_EXECUTABLE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001174 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001175#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001176#ifdef MAP_ANONYMOUS
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001177 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1178 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001179#endif
1180
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001181 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001182
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001183 setint(dict, "ACCESS_READ", ACCESS_READ);
1184 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1185 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Tim Peters5ebfd362001-11-13 23:11:19 +00001186}