blob: 7c3c3e4e2d4f97f37832d1d2d819cf637ee59e2c [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>
53#include <sys/types.h>
54
Neal Norwitz3eaf2b52006-02-16 08:08:54 +000055/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +000056#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
57# define MAP_ANONYMOUS MAP_ANON
58#endif
59
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000060static PyObject *mmap_module_error;
61
Tim Peters5ebfd362001-11-13 23:11:19 +000062typedef enum
63{
64 ACCESS_DEFAULT,
65 ACCESS_READ,
66 ACCESS_WRITE,
67 ACCESS_COPY
68} access_mode;
69
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000070typedef struct {
Guido van Rossum09fdf072000-03-31 01:17:07 +000071 PyObject_HEAD
72 char * data;
73 size_t size;
74 size_t pos;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000075
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000076#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +000077 HANDLE map_handle;
Mark Hammond071864a2000-07-30 02:46:26 +000078 HANDLE file_handle;
Guido van Rossum09fdf072000-03-31 01:17:07 +000079 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000080#endif
81
82#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000083 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000084#endif
Tim Peters5ebfd362001-11-13 23:11:19 +000085
86 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000087} mmap_object;
88
Tim Peters5ebfd362001-11-13 23:11:19 +000089
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000090static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +000091mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000092{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000093#ifdef MS_WINDOWS
Mark Hammond2cbed002000-07-30 02:22:43 +000094 if (m_obj->data != NULL)
95 UnmapViewOfFile (m_obj->data);
96 if (m_obj->map_handle != INVALID_HANDLE_VALUE)
97 CloseHandle (m_obj->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +000098 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
99 CloseHandle (m_obj->file_handle);
Mark Hammond2cbed002000-07-30 02:22:43 +0000100 if (m_obj->tagname)
101 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000102#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000103
104#ifdef UNIX
Neal Norwitz6eac2002005-11-02 05:36:37 +0000105 if (m_obj->fd >= 0)
106 (void) close(m_obj->fd);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000107 if (m_obj->data!=NULL) {
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000108 msync(m_obj->data, m_obj->size, MS_SYNC);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000109 munmap(m_obj->data, m_obj->size);
110 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000111#endif /* UNIX */
112
Guido van Rossumb18618d2000-05-03 23:44:39 +0000113 PyObject_Del(m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000114}
115
116static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000117mmap_close_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000118{
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000119 if (!PyArg_ParseTuple(args, ":close"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000120 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000121#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000122 /* For each resource we maintain, we need to check
Tim Petersec0a5f02006-02-16 23:47:20 +0000123 the value is valid, and if so, free the resource
Mark Hammond071864a2000-07-30 02:46:26 +0000124 and set the member value to an invalid value so
125 the dealloc does not attempt to resource clearing
126 again.
127 TODO - should we check for errors in the close operations???
128 */
129 if (self->data != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000130 UnmapViewOfFile(self->data);
Mark Hammond071864a2000-07-30 02:46:26 +0000131 self->data = NULL;
132 }
133 if (self->map_handle != INVALID_HANDLE_VALUE) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000134 CloseHandle(self->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000135 self->map_handle = INVALID_HANDLE_VALUE;
136 }
137 if (self->file_handle != INVALID_HANDLE_VALUE) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000138 CloseHandle(self->file_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000139 self->file_handle = INVALID_HANDLE_VALUE;
140 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000141#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000142
143#ifdef UNIX
Neal Norwitz6eac2002005-11-02 05:36:37 +0000144 (void) close(self->fd);
145 self->fd = -1;
Neal Norwitze604c022003-01-10 20:52:16 +0000146 if (self->data != NULL) {
147 munmap(self->data, self->size);
148 self->data = NULL;
149 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000150#endif
151
Tim Peters8f9cc292006-02-17 00:00:20 +0000152 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000153 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000154}
155
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000156#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +0000157#define CHECK_VALID(err) \
158do { \
Guido van Rossum69c2b882003-04-09 19:31:02 +0000159 if (self->map_handle == INVALID_HANDLE_VALUE) { \
Tim Peters8f9cc292006-02-17 00:00:20 +0000160 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
Guido van Rossum09fdf072000-03-31 01:17:07 +0000161 return err; \
162 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000163} while (0)
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
Guido van Rossum09fdf072000-03-31 01:17:07 +0000167#define CHECK_VALID(err) \
168do { \
169 if (self->data == NULL) { \
Tim Peters8f9cc292006-02-17 00:00:20 +0000170 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
Guido van Rossum09fdf072000-03-31 01:17:07 +0000171 return err; \
172 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000173} while (0)
174#endif /* UNIX */
175
176static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000177mmap_read_byte_method(mmap_object *self,
178 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000179{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000180 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000181 if (!PyArg_ParseTuple(args, ":read_byte"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000182 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000183 if (self->pos < self->size) {
Tim Petersd6283b82001-05-09 18:48:26 +0000184 char value = self->data[self->pos];
Guido van Rossum09fdf072000-03-31 01:17:07 +0000185 self->pos += 1;
Tim Petersd6283b82001-05-09 18:48:26 +0000186 return Py_BuildValue("c", value);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000187 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000188 PyErr_SetString(PyExc_ValueError, "read byte out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000189 return NULL;
190 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000191}
192
193static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000194mmap_read_line_method(mmap_object *self,
Tim Peters5ebfd362001-11-13 23:11:19 +0000195 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000196{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000197 char *start = self->data+self->pos;
198 char *eof = self->data+self->size;
199 char *eol;
200 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000201
Guido van Rossum09fdf072000-03-31 01:17:07 +0000202 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000203 if (!PyArg_ParseTuple(args, ":readline"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000204 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000205
Fred Drake56a87a02000-04-04 18:17:35 +0000206 eol = memchr(start, '\n', self->size - self->pos);
207 if (!eol)
208 eol = eof;
209 else
210 ++eol; /* we're interested in the position after the
211 newline. */
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000212 result = PyString_FromStringAndSize(start, (eol - start));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000213 self->pos += (eol - start);
Tim Peters23721ee2006-02-16 23:50:16 +0000214 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000215}
216
217static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000218mmap_read_method(mmap_object *self,
219 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000220{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000221 Py_ssize_t num_bytes;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000222 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000223
Guido van Rossum09fdf072000-03-31 01:17:07 +0000224 CHECK_VALID(NULL);
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000225 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000226 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000227
Guido van Rossum09fdf072000-03-31 01:17:07 +0000228 /* silently 'adjust' out-of-range requests */
229 if ((self->pos + num_bytes) > self->size) {
230 num_bytes -= (self->pos+num_bytes) - self->size;
231 }
232 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
Tim Petersec0a5f02006-02-16 23:47:20 +0000233 self->pos += num_bytes;
Tim Peters23721ee2006-02-16 23:50:16 +0000234 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000235}
236
237static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000238mmap_find_method(mmap_object *self,
239 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000240{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000241 Py_ssize_t start = self->pos;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000242 char *needle;
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000243 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000244
Guido van Rossum09fdf072000-03-31 01:17:07 +0000245 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000246 if (!PyArg_ParseTuple(args, "s#|n:find", &needle, &len, &start)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000247 return NULL;
248 } else {
Greg Stein834f4dd2001-05-14 09:32:26 +0000249 char *p;
250 char *e = self->data + self->size;
251
252 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000253 start += self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000254 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000255 start = 0;
Tim Petersd401edd2001-05-14 23:19:12 +0000256 else if ((size_t)start > self->size)
Tim Peters5ebfd362001-11-13 23:11:19 +0000257 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000258
Tim Petersc9ffa062002-03-08 05:43:32 +0000259 for (p = self->data + start; p + len <= e; ++p) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000260 Py_ssize_t i;
Tim Petersc9ffa062002-03-08 05:43:32 +0000261 for (i = 0; i < len && needle[i] == p[i]; ++i)
262 /* nothing */;
263 if (i == len) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000264 return PyInt_FromSsize_t(p - self->data);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000265 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000266 }
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000267 return PyInt_FromLong(-1);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000268 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000269}
270
Tim Petersec0a5f02006-02-16 23:47:20 +0000271static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000272is_writeable(mmap_object *self)
273{
274 if (self->access != ACCESS_READ)
Tim Petersec0a5f02006-02-16 23:47:20 +0000275 return 1;
Tim Peters5ebfd362001-11-13 23:11:19 +0000276 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
277 return 0;
278}
279
Tim Petersec0a5f02006-02-16 23:47:20 +0000280static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000281is_resizeable(mmap_object *self)
282{
283 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
Tim Petersec0a5f02006-02-16 23:47:20 +0000284 return 1;
285 PyErr_Format(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000286 "mmap can't resize a readonly or copy-on-write memory map.");
287 return 0;
288}
289
290
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000291static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000292mmap_write_method(mmap_object *self,
293 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000294{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000295 Py_ssize_t length;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000296 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000297
Guido van Rossum09fdf072000-03-31 01:17:07 +0000298 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000299 if (!PyArg_ParseTuple(args, "s#:write", &data, &length))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000300 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000301
Tim Peters5ebfd362001-11-13 23:11:19 +0000302 if (!is_writeable(self))
303 return NULL;
304
Guido van Rossum09fdf072000-03-31 01:17:07 +0000305 if ((self->pos + length) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000306 PyErr_SetString(PyExc_ValueError, "data out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000307 return NULL;
308 }
Tim Peters8f9cc292006-02-17 00:00:20 +0000309 memcpy(self->data+self->pos, data, length);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000310 self->pos = self->pos+length;
Tim Peters8f9cc292006-02-17 00:00:20 +0000311 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000312 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000313}
314
315static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000316mmap_write_byte_method(mmap_object *self,
317 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000318{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000319 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000320
Guido van Rossum09fdf072000-03-31 01:17:07 +0000321 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000322 if (!PyArg_ParseTuple(args, "c:write_byte", &value))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000323 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000324
Tim Peters5ebfd362001-11-13 23:11:19 +0000325 if (!is_writeable(self))
326 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000327 *(self->data+self->pos) = value;
328 self->pos += 1;
Tim Peters8f9cc292006-02-17 00:00:20 +0000329 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000330 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000331}
Tim Petersec0a5f02006-02-16 23:47:20 +0000332
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000333static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000334mmap_size_method(mmap_object *self,
335 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000336{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000337 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000338 if (!PyArg_ParseTuple(args, ":size"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000339 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000340
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000341#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000342 if (self->file_handle != INVALID_HANDLE_VALUE) {
Martin v. Löwis15186072006-02-18 12:38:35 +0000343 DWORD low,high;
344 PY_LONG_LONG size;
345 low = GetFileSize(self->file_handle, &high);
346 if (low == INVALID_FILE_SIZE) {
347 /* It might be that the function appears to have failed,
348 when indeed its size equals INVALID_FILE_SIZE */
349 DWORD error = GetLastError();
350 if (error != NO_ERROR)
351 return PyErr_SetFromWindowsErr(error);
352 }
353 if (!high && low < LONG_MAX)
354 return PyInt_FromLong((long)low);
355 size = (((PY_LONG_LONG)high)<<32) + low;
356 return PyLong_FromLongLong(size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000357 } else {
Martin v. Löwis15186072006-02-18 12:38:35 +0000358 return PyInt_FromSsize_t(self->size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000359 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000360#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000361
362#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000363 {
364 struct stat buf;
365 if (-1 == fstat(self->fd, &buf)) {
366 PyErr_SetFromErrno(mmap_module_error);
367 return NULL;
368 }
Martin v. Löwis15186072006-02-18 12:38:35 +0000369 return PyInt_FromSsize_t(buf.st_size);
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000370 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000371#endif /* UNIX */
372}
373
374/* This assumes that you want the entire file mapped,
375 / and when recreating the map will make the new file
376 / have the new size
377 /
378 / Is this really necessary? This could easily be done
379 / from python by just closing and re-opening with the
380 / new size?
381 */
382
383static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000384mmap_resize_method(mmap_object *self,
385 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000386{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000387 Py_ssize_t new_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000388 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000389 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000390 !is_resizeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000391 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000392#ifdef MS_WINDOWS
Tim Petersec0a5f02006-02-16 23:47:20 +0000393 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000394 DWORD dwErrCode = 0;
Martin v. Löwis15186072006-02-18 12:38:35 +0000395 DWORD newSizeLow, newSizeHigh;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000396 /* First, unmap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000397 UnmapViewOfFile(self->data);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000398 /* Close the mapping object */
Tim Peters8f9cc292006-02-17 00:00:20 +0000399 CloseHandle(self->map_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000400 /* Move to the desired EOF position */
Martin v. Löwis15186072006-02-18 12:38:35 +0000401#if SIZEOF_SIZE_T > 4
402 newSizeHigh = (DWORD)(new_size >> 32);
403 newSizeLow = (DWORD)(new_size & 0xFFFFFFFF);
404#else
405 newSizeHigh = 0;
Martin v. Löwis5bb8a152006-02-18 12:49:49 +0000406 newSizeLow = (DWORD)new_size;
Martin v. Löwis15186072006-02-18 12:38:35 +0000407#endif
Tim Peters8f9cc292006-02-17 00:00:20 +0000408 SetFilePointer(self->file_handle,
Martin v. Löwis15186072006-02-18 12:38:35 +0000409 newSizeLow, &newSizeHigh, FILE_BEGIN);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000410 /* Change the size of the file */
Tim Peters8f9cc292006-02-17 00:00:20 +0000411 SetEndOfFile(self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000412 /* Create another mapping object and remap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000413 self->map_handle = CreateFileMapping(
Mark Hammond071864a2000-07-30 02:46:26 +0000414 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000415 NULL,
416 PAGE_READWRITE,
Martin v. Löwis15186072006-02-18 12:38:35 +0000417 newSizeHigh,
418 newSizeLow,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000419 self->tagname);
420 if (self->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000421 self->data = (char *) MapViewOfFile(self->map_handle,
422 FILE_MAP_WRITE,
423 0,
424 0,
425 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000426 if (self->data != NULL) {
427 self->size = new_size;
Tim Peters8f9cc292006-02-17 00:00:20 +0000428 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000429 return Py_None;
430 } else {
431 dwErrCode = GetLastError();
432 }
433 } else {
434 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000435 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000436 PyErr_SetFromWindowsErr(dwErrCode);
Tim Peters23721ee2006-02-16 23:50:16 +0000437 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000438#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000439
440#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000441#ifndef HAVE_MREMAP
Tim Peters5ebfd362001-11-13 23:11:19 +0000442 } else {
443 PyErr_SetString(PyExc_SystemError,
444 "mmap: resizing not available--no mremap()");
445 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000446#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000447 } else {
Armin Rigo335ffe82005-09-20 19:04:02 +0000448 void *newmap;
449
Georg Brandl38387b82005-08-24 07:17:40 +0000450 if (ftruncate(self->fd, new_size) == -1) {
451 PyErr_SetFromErrno(mmap_module_error);
452 return NULL;
453 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000454
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000455#ifdef MREMAP_MAYMOVE
Tim Peters5ebfd362001-11-13 23:11:19 +0000456 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000457#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000458 newmap = mremap(self->data, self->size, new_size, 0);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000459#endif
Tim Petersec0a5f02006-02-16 23:47:20 +0000460 if (newmap == (void *)-1)
Tim Peters5ebfd362001-11-13 23:11:19 +0000461 {
462 PyErr_SetFromErrno(mmap_module_error);
463 return NULL;
464 }
465 self->data = newmap;
466 self->size = new_size;
467 Py_INCREF(Py_None);
468 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000469#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000470#endif /* UNIX */
Tim Peters5ebfd362001-11-13 23:11:19 +0000471 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000472}
473
474static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000475mmap_tell_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000476{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000477 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000478 if (!PyArg_ParseTuple(args, ":tell"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000479 return NULL;
Tim Peters8f9cc292006-02-17 00:00:20 +0000480 return Py_BuildValue("l", (long) self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000481}
482
483static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000484mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000485{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000486 Py_ssize_t offset = 0;
487 Py_ssize_t size = self->size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000488 CHECK_VALID(NULL);
Tim Petersf2882952006-02-17 01:07:39 +0000489 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000490 return NULL;
Tim Petersf2882952006-02-17 01:07:39 +0000491 if ((size_t)(offset + size) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000492 PyErr_SetString(PyExc_ValueError, "flush values out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000493 return NULL;
494 } else {
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000495#ifdef MS_WINDOWS
Tim Peters23721ee2006-02-16 23:50:16 +0000496 return Py_BuildValue("l", (long)
497 FlushViewOfFile(self->data+offset, size));
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000498#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000499#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000500 /* XXX semantics of return value? */
501 /* XXX flags for msync? */
502 if (-1 == msync(self->data + offset, size,
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000503 MS_SYNC))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000504 {
505 PyErr_SetFromErrno(mmap_module_error);
506 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000507 }
Tim Peters8f9cc292006-02-17 00:00:20 +0000508 return Py_BuildValue("l", (long) 0);
Tim Petersec0a5f02006-02-16 23:47:20 +0000509#endif /* UNIX */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000510 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000511}
512
513static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000514mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000515{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000516 Py_ssize_t dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000517 int how=0;
518 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000519 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
Tim Peters8f9cc292006-02-17 00:00:20 +0000520 return NULL;
521 else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000522 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000523 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000524 case 0: /* relative to start */
525 if (dist < 0)
526 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000527 where = dist;
528 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000529 case 1: /* relative to current position */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000530 if ((Py_ssize_t)self->pos + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000531 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000532 where = self->pos + dist;
533 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000534 case 2: /* relative to end */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000535 if ((Py_ssize_t)self->size + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000536 goto onoutofrange;
537 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000538 break;
539 default:
Tim Peters8f9cc292006-02-17 00:00:20 +0000540 PyErr_SetString(PyExc_ValueError, "unknown seek type");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000541 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000542 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000543 if (where > self->size)
544 goto onoutofrange;
545 self->pos = where;
Tim Peters8f9cc292006-02-17 00:00:20 +0000546 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000547 return Py_None;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000548 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000549
Tim Peters5ebfd362001-11-13 23:11:19 +0000550 onoutofrange:
Tim Peters8f9cc292006-02-17 00:00:20 +0000551 PyErr_SetString(PyExc_ValueError, "seek out of range");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000552 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000553}
554
555static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000556mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000557{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000558 unsigned long dest, src, count;
559 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000560 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &count) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000561 !is_writeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000562 return NULL;
563 } else {
564 /* bounds check the values */
565 if (/* end of source after end of data?? */
566 ((src+count) > self->size)
567 /* dest will fit? */
568 || (dest+count > self->size)) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000569 PyErr_SetString(PyExc_ValueError,
570 "source or destination out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000571 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000572 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000573 memmove(self->data+dest, self->data+src, count);
574 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000575 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000576 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000577 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000578}
579
580static struct PyMethodDef mmap_object_methods[] = {
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000581 {"close", (PyCFunction) mmap_close_method, METH_VARARGS},
582 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
583 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
584 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
585 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
586 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_VARARGS},
587 {"readline", (PyCFunction) mmap_read_line_method, METH_VARARGS},
588 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
589 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
590 {"size", (PyCFunction) mmap_size_method, METH_VARARGS},
591 {"tell", (PyCFunction) mmap_tell_method, METH_VARARGS},
592 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
593 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000594 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000595};
596
597/* Functions for treating an mmap'ed file as a buffer */
598
Martin v. Löwis18e16552006-02-15 17:27:45 +0000599static Py_ssize_t
600mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000601{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000602 CHECK_VALID(-1);
Tim Peters8f9cc292006-02-17 00:00:20 +0000603 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000604 PyErr_SetString(PyExc_SystemError,
605 "Accessing non-existent mmap segment");
606 return -1;
607 }
608 *ptr = self->data;
609 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000610}
611
Martin v. Löwis18e16552006-02-15 17:27:45 +0000612static Py_ssize_t
613mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Tim Petersec0a5f02006-02-16 23:47:20 +0000614{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000615 CHECK_VALID(-1);
Tim Peters8f9cc292006-02-17 00:00:20 +0000616 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000617 PyErr_SetString(PyExc_SystemError,
618 "Accessing non-existent mmap segment");
619 return -1;
620 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000621 if (!is_writeable(self))
622 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000623 *ptr = self->data;
624 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000625}
626
Martin v. Löwis18e16552006-02-15 17:27:45 +0000627static Py_ssize_t
628mmap_buffer_getsegcount(mmap_object *self, Py_ssize_t *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000629{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000630 CHECK_VALID(-1);
Tim Petersec0a5f02006-02-16 23:47:20 +0000631 if (lenp)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000632 *lenp = self->size;
633 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000634}
635
Martin v. Löwis18e16552006-02-15 17:27:45 +0000636static Py_ssize_t
637mmap_buffer_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000638{
Tim Peters8f9cc292006-02-17 00:00:20 +0000639 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000640 PyErr_SetString(PyExc_SystemError,
641 "accessing non-existent buffer segment");
642 return -1;
643 }
644 *ptr = (const char *)self->data;
645 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000646}
647
648static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000649mmap_object_getattr(mmap_object *self, char *name)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000650{
Tim Peters8f9cc292006-02-17 00:00:20 +0000651 return Py_FindMethod(mmap_object_methods, (PyObject *)self, name);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000652}
653
Martin v. Löwis18e16552006-02-15 17:27:45 +0000654static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000655mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000656{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000657 CHECK_VALID(-1);
658 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000659}
660
661static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000662mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000663{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000664 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000665 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000666 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
667 return NULL;
668 }
669 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000670}
671
672static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000673mmap_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000674{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000675 CHECK_VALID(NULL);
676 if (ilow < 0)
677 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000678 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000679 ilow = self->size;
680 if (ihigh < 0)
681 ihigh = 0;
682 if (ihigh < ilow)
683 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000684 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000685 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000686
Guido van Rossum09fdf072000-03-31 01:17:07 +0000687 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000688}
689
690static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000691mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000692{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000693 CHECK_VALID(NULL);
694 PyErr_SetString(PyExc_SystemError,
695 "mmaps don't support concatenation");
696 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000697}
698
699static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000700mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000701{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000702 CHECK_VALID(NULL);
703 PyErr_SetString(PyExc_SystemError,
704 "mmaps don't support repeat operation");
705 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000706}
707
708static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000709mmap_ass_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000710{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000711 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000712
Guido van Rossum09fdf072000-03-31 01:17:07 +0000713 CHECK_VALID(-1);
714 if (ilow < 0)
715 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000716 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000717 ilow = self->size;
718 if (ihigh < 0)
719 ihigh = 0;
720 if (ihigh < ilow)
721 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000722 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000723 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000724
Thomas Wouters1baac722001-07-16 15:47:36 +0000725 if (v == NULL) {
726 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000727 "mmap object doesn't support slice deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000728 return -1;
729 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000730 if (! (PyString_Check(v)) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000731 PyErr_SetString(PyExc_IndexError,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000732 "mmap slice assignment must be a string");
733 return -1;
734 }
Tim Peters8f9cc292006-02-17 00:00:20 +0000735 if (PyString_Size(v) != (ihigh - ilow)) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000736 PyErr_SetString(PyExc_IndexError,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000737 "mmap slice assignment is wrong size");
738 return -1;
739 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000740 if (!is_writeable(self))
741 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000742 buf = PyString_AsString(v);
743 memcpy(self->data + ilow, buf, ihigh-ilow);
744 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000745}
746
747static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000748mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000749{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000750 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000751
Guido van Rossum09fdf072000-03-31 01:17:07 +0000752 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000753 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000754 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
755 return -1;
756 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000757 if (v == NULL) {
758 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000759 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000760 return -1;
761 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000762 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000763 PyErr_SetString(PyExc_IndexError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000764 "mmap assignment must be single-character string");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000765 return -1;
766 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000767 if (!is_writeable(self))
768 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000769 buf = PyString_AsString(v);
770 self->data[i] = buf[0];
771 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000772}
773
774static PySequenceMethods mmap_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000775 (lenfunc)mmap_length, /*sq_length*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000776 (binaryfunc)mmap_concat, /*sq_concat*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000777 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
778 (ssizeargfunc)mmap_item, /*sq_item*/
779 (ssizessizeargfunc)mmap_slice, /*sq_slice*/
780 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
781 (ssizessizeobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000782};
783
784static PyBufferProcs mmap_as_buffer = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000785 (readbufferproc)mmap_buffer_getreadbuf,
786 (writebufferproc)mmap_buffer_getwritebuf,
787 (segcountproc)mmap_buffer_getsegcount,
788 (charbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000789};
790
791static PyTypeObject mmap_object_type = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000792 PyObject_HEAD_INIT(0) /* patched in module init */
793 0, /* ob_size */
Guido van Rossum14648392001-12-08 18:02:58 +0000794 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000795 sizeof(mmap_object), /* tp_size */
796 0, /* tp_itemsize */
797 /* methods */
798 (destructor) mmap_object_dealloc, /* tp_dealloc */
799 0, /* tp_print */
800 (getattrfunc) mmap_object_getattr, /* tp_getattr */
801 0, /* tp_setattr */
802 0, /* tp_compare */
803 0, /* tp_repr */
804 0, /* tp_as_number */
805 &mmap_as_sequence, /*tp_as_sequence*/
806 0, /*tp_as_mapping*/
807 0, /*tp_hash*/
808 0, /*tp_call*/
809 0, /*tp_str*/
810 0, /*tp_getattro*/
811 0, /*tp_setattro*/
812 &mmap_as_buffer, /*tp_as_buffer*/
813 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
814 0, /*tp_doc*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000815};
816
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000817
818/* extract the map size from the given PyObject
819
Thomas Wouters7e474022000-07-16 12:04:32 +0000820 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000821 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000822static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000823_GetMapSize(PyObject *o)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000824{
825 if (PyInt_Check(o)) {
826 long i = PyInt_AsLong(o);
827 if (PyErr_Occurred())
828 return -1;
829 if (i < 0)
830 goto onnegoverflow;
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000831 return i;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000832 }
833 else if (PyLong_Check(o)) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000834 Py_ssize_t i = PyInt_AsSsize_t(o);
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000835 if (PyErr_Occurred()) {
836 /* yes negative overflow is mistaken for positive overflow
837 but not worth the trouble to check sign of 'i' */
838 if (PyErr_ExceptionMatches(PyExc_OverflowError))
839 goto onposoverflow;
840 else
841 return -1;
842 }
843 if (i < 0)
844 goto onnegoverflow;
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000845 return i;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000846 }
847 else {
848 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000849 "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000850 return -1;
851 }
852
Tim Peters5ebfd362001-11-13 23:11:19 +0000853 onnegoverflow:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000854 PyErr_SetString(PyExc_OverflowError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000855 "memory mapped size must be positive");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000856 return -1;
857
Tim Peters5ebfd362001-11-13 23:11:19 +0000858 onposoverflow:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000859 PyErr_SetString(PyExc_OverflowError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000860 "memory mapped size is too large (limited by C int)");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000861 return -1;
862}
863
Tim Petersec0a5f02006-02-16 23:47:20 +0000864#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000865static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000866new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000867{
Neal Norwitzb5673922002-09-05 21:48:07 +0000868#ifdef HAVE_FSTAT
869 struct stat st;
870#endif
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000871 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000872 PyObject *map_size_obj = NULL;
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000873 Py_ssize_t map_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000874 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +0000875 int devzero = -1;
Neal Norwitz8856fb72005-12-18 03:34:22 +0000876 int access = (int)ACCESS_DEFAULT;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +0000877 static char *keywords[] = {"fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +0000878 "flags", "prot",
Jeremy Hyltonaf68c872005-12-10 18:50:16 +0000879 "access", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000880
Tim Petersec0a5f02006-02-16 23:47:20 +0000881 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii", keywords,
Jeremy Hyltonaf68c872005-12-10 18:50:16 +0000882 &fd, &map_size_obj, &flags, &prot,
883 &access))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000884 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000885 map_size = _GetMapSize(map_size_obj);
886 if (map_size < 0)
887 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000888
Tim Petersec0a5f02006-02-16 23:47:20 +0000889 if ((access != (int)ACCESS_DEFAULT) &&
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +0000890 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
Tim Petersec0a5f02006-02-16 23:47:20 +0000891 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000892 "mmap can't specify both access and flags, prot.");
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +0000893 switch ((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +0000894 case ACCESS_READ:
895 flags = MAP_SHARED;
896 prot = PROT_READ;
897 break;
898 case ACCESS_WRITE:
899 flags = MAP_SHARED;
900 prot = PROT_READ | PROT_WRITE;
901 break;
902 case ACCESS_COPY:
903 flags = MAP_PRIVATE;
904 prot = PROT_READ | PROT_WRITE;
905 break;
Tim Petersec0a5f02006-02-16 23:47:20 +0000906 case ACCESS_DEFAULT:
Tim Peters5ebfd362001-11-13 23:11:19 +0000907 /* use the specified or default values of flags and prot */
908 break;
909 default:
Tim Petersec0a5f02006-02-16 23:47:20 +0000910 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000911 "mmap invalid access parameter.");
912 }
Neal Norwitzb5673922002-09-05 21:48:07 +0000913
914#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +0000915# ifdef __VMS
916 /* on OpenVMS we must ensure that all bytes are written to the file */
917 fsync(fd);
918# endif
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000919 if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
920 if (map_size == 0) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000921 map_size = st.st_size;
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000922 } else if ((size_t)map_size > st.st_size) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000923 PyErr_SetString(PyExc_ValueError,
Martin v. Löwis7fe60c02005-03-03 11:22:44 +0000924 "mmap length is greater than file size");
925 return NULL;
926 }
Neal Norwitzb5673922002-09-05 21:48:07 +0000927 }
928#endif
Tim Peters8f9cc292006-02-17 00:00:20 +0000929 m_obj = PyObject_New(mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000930 if (m_obj == NULL) {return NULL;}
Neal Norwitz3b4fff82006-01-11 08:54:45 +0000931 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000932 m_obj->size = (size_t) map_size;
933 m_obj->pos = (size_t) 0;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +0000934 if (fd == -1) {
935 m_obj->fd = -1;
936 /* Assume the caller wants to map anonymous memory.
937 This is the same behaviour as Windows. mmap.mmap(-1, size)
938 on both Windows and Unix map anonymous memory.
939 */
940#ifdef MAP_ANONYMOUS
941 /* BSD way to map anonymous memory */
942 flags |= MAP_ANONYMOUS;
943#else
944 /* SVR4 method to map anonymous memory is to open /dev/zero */
945 fd = devzero = open("/dev/zero", O_RDWR);
946 if (devzero == -1) {
947 Py_DECREF(m_obj);
948 PyErr_SetFromErrno(mmap_module_error);
949 return NULL;
950 }
951#endif
952 } else {
953 m_obj->fd = dup(fd);
954 if (m_obj->fd == -1) {
955 Py_DECREF(m_obj);
956 PyErr_SetFromErrno(mmap_module_error);
957 return NULL;
958 }
Georg Brandl38387b82005-08-24 07:17:40 +0000959 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +0000960
Tim Petersec0a5f02006-02-16 23:47:20 +0000961 m_obj->data = mmap(NULL, map_size,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000962 prot, flags,
963 fd, 0);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +0000964
965 if (devzero != -1) {
966 close(devzero);
967 }
968
Tim Peters5ebfd362001-11-13 23:11:19 +0000969 if (m_obj->data == (char *)-1) {
Andrew M. Kuchling16581c82004-05-19 14:39:08 +0000970 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000971 Py_DECREF(m_obj);
972 PyErr_SetFromErrno(mmap_module_error);
973 return NULL;
974 }
Neal Norwitz8856fb72005-12-18 03:34:22 +0000975 m_obj->access = (access_mode)access;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000976 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000977}
978#endif /* UNIX */
979
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000980#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000981static PyObject *
Tim Peters5ebfd362001-11-13 23:11:19 +0000982new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000983{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000984 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000985 PyObject *map_size_obj = NULL;
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000986 Py_ssize_t map_size;
Tim Peterse564e7f2006-02-16 23:46:01 +0000987 DWORD size_hi; /* upper 32 bits of m_obj->size */
988 DWORD size_lo; /* lower 32 bits of m_obj->size */
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000989 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +0000990 DWORD dwErr = 0;
991 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +0000992 HANDLE fh = 0;
Neal Norwitz8856fb72005-12-18 03:34:22 +0000993 int access = (access_mode)ACCESS_DEFAULT;
Tim Peters5ebfd362001-11-13 23:11:19 +0000994 DWORD flProtect, dwDesiredAccess;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +0000995 static char *keywords[] = { "fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +0000996 "tagname",
Jeremy Hyltonaf68c872005-12-10 18:50:16 +0000997 "access", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000998
Tim Peters5ebfd362001-11-13 23:11:19 +0000999 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|zi", keywords,
Tim Petersec0a5f02006-02-16 23:47:20 +00001000 &fileno, &map_size_obj,
Tim Peters5ebfd362001-11-13 23:11:19 +00001001 &tagname, &access)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001002 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001003 }
1004
Neal Norwitz8856fb72005-12-18 03:34:22 +00001005 switch((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001006 case ACCESS_READ:
1007 flProtect = PAGE_READONLY;
1008 dwDesiredAccess = FILE_MAP_READ;
1009 break;
1010 case ACCESS_DEFAULT: case ACCESS_WRITE:
1011 flProtect = PAGE_READWRITE;
1012 dwDesiredAccess = FILE_MAP_WRITE;
1013 break;
1014 case ACCESS_COPY:
1015 flProtect = PAGE_WRITECOPY;
1016 dwDesiredAccess = FILE_MAP_COPY;
1017 break;
1018 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001019 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001020 "mmap invalid access parameter.");
1021 }
1022
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001023 map_size = _GetMapSize(map_size_obj);
1024 if (map_size < 0)
1025 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001026
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001027 /* assume -1 and 0 both mean invalid filedescriptor
1028 to 'anonymously' map memory.
1029 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1030 XXX: Should this code be added?
1031 if (fileno == 0)
1032 PyErr_Warn(PyExc_DeprecationWarning,
1033 "don't use 0 for anonymous memory");
1034 */
1035 if (fileno != -1 && fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +00001036 fh = (HANDLE)_get_osfhandle(fileno);
1037 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001038 PyErr_SetFromErrno(mmap_module_error);
1039 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001040 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +00001041 /* Win9x appears to need us seeked to zero */
Guido van Rossum69c2b882003-04-09 19:31:02 +00001042 lseek(fileno, 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001043 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001044
Tim Peters8f9cc292006-02-17 00:00:20 +00001045 m_obj = PyObject_New(mmap_object, &mmap_object_type);
1046 if (m_obj == NULL)
Mark Hammond2cbed002000-07-30 02:22:43 +00001047 return NULL;
1048 /* Set every field to an invalid marker, so we can safely
1049 destruct the object in the face of failure */
1050 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +00001051 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +00001052 m_obj->map_handle = INVALID_HANDLE_VALUE;
1053 m_obj->tagname = NULL;
1054
Guido van Rossum09fdf072000-03-31 01:17:07 +00001055 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +00001056 /* It is necessary to duplicate the handle, so the
1057 Python code can close it on us */
1058 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +00001059 GetCurrentProcess(), /* source process handle */
1060 fh, /* handle to be duplicated */
1061 GetCurrentProcess(), /* target proc handle */
1062 (LPHANDLE)&m_obj->file_handle, /* result */
1063 0, /* access - ignored due to options value */
1064 FALSE, /* inherited by child processes? */
1065 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +00001066 dwErr = GetLastError();
1067 Py_DECREF(m_obj);
1068 PyErr_SetFromWindowsErr(dwErr);
1069 return NULL;
1070 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001071 if (!map_size) {
Martin v. Löwis15186072006-02-18 12:38:35 +00001072 DWORD low,high;
1073 low = GetFileSize(fh, &high);
1074 /* low might just happen to have the value INVALID_FILE_SIZE;
1075 so we need to check the last error also. */
1076 if (low == INVALID_FILE_SIZE &&
1077 (dwErr = GetLastError()) != NO_ERROR) {
1078 Py_DECREF(m_obj);
1079 return PyErr_SetFromWindowsErr(dwErr);
1080 }
1081
1082#if SIZEOF_SIZE_T > 4
1083 m_obj->size = (((size_t)high)<<32) + low;
1084#else
1085 if (high)
1086 /* File is too large to map completely */
1087 m_obj->size = (size_t)-1;
1088 else
1089 m_obj->size = low;
1090#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001091 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001092 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001093 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001094 }
1095 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001096 m_obj->size = map_size;
1097 }
1098
1099 /* set the initial position */
1100 m_obj->pos = (size_t) 0;
1101
Mark Hammond2cbed002000-07-30 02:22:43 +00001102 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001103 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001104 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1105 if (m_obj->tagname == NULL) {
1106 PyErr_NoMemory();
1107 Py_DECREF(m_obj);
1108 return NULL;
1109 }
1110 strcpy(m_obj->tagname, tagname);
1111 }
1112 else
1113 m_obj->tagname = NULL;
1114
Neal Norwitz8856fb72005-12-18 03:34:22 +00001115 m_obj->access = (access_mode)access;
Tim Peterse564e7f2006-02-16 23:46:01 +00001116 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
Thomas Wouters2c98a7b2006-02-17 09:59:00 +00001117 * more than 4 bytes, we need to break it apart. Else (size_t
Tim Peterse564e7f2006-02-16 23:46:01 +00001118 * consumes 4 bytes), C doesn't define what happens if we shift
1119 * right by 32, so we need different code.
1120 */
1121#if SIZEOF_SIZE_T > 4
1122 size_hi = (DWORD)(m_obj->size >> 32);
1123 size_lo = (DWORD)(m_obj->size & 0xFFFFFFFF);
1124#else
1125 size_hi = 0;
1126 size_lo = (DWORD)m_obj->size;
1127#endif
Tim Peters8f9cc292006-02-17 00:00:20 +00001128 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1129 NULL,
1130 flProtect,
1131 size_hi,
1132 size_lo,
1133 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001134 if (m_obj->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +00001135 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1136 dwDesiredAccess,
1137 0,
1138 0,
1139 0);
Tim Peters23721ee2006-02-16 23:50:16 +00001140 if (m_obj->data != NULL)
1141 return (PyObject *)m_obj;
1142 else
Tim Peters5ebfd362001-11-13 23:11:19 +00001143 dwErr = GetLastError();
Tim Peters23721ee2006-02-16 23:50:16 +00001144 } else
Guido van Rossum09fdf072000-03-31 01:17:07 +00001145 dwErr = GetLastError();
Mark Hammond2cbed002000-07-30 02:22:43 +00001146 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001147 PyErr_SetFromWindowsErr(dwErr);
Tim Peters23721ee2006-02-16 23:50:16 +00001148 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001149}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001150#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001151
1152/* List of functions exported by this module */
1153static struct PyMethodDef mmap_functions[] = {
Tim Petersec0a5f02006-02-16 23:47:20 +00001154 {"mmap", (PyCFunction) new_mmap_object,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001155 METH_VARARGS|METH_KEYWORDS},
1156 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001157};
1158
Mark Hammond62b1ab12002-07-23 06:31:15 +00001159PyMODINIT_FUNC
Tim Peters5ebfd362001-11-13 23:11:19 +00001160 initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001161{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001162 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001163
1164 /* Patch the object type */
1165 mmap_object_type.ob_type = &PyType_Type;
1166
Tim Peters8f9cc292006-02-17 00:00:20 +00001167 module = Py_InitModule("mmap", mmap_functions);
Neal Norwitz1ac754f2006-01-19 06:09:39 +00001168 if (module == NULL)
1169 return;
Tim Peters8f9cc292006-02-17 00:00:20 +00001170 dict = PyModule_GetDict(module);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001171 mmap_module_error = PyExc_EnvironmentError;
1172 Py_INCREF(mmap_module_error);
Tim Peters8f9cc292006-02-17 00:00:20 +00001173 PyDict_SetItemString(dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001174#ifdef PROT_EXEC
Tim Peters8f9cc292006-02-17 00:00:20 +00001175 PyDict_SetItemString(dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001176#endif
1177#ifdef PROT_READ
Tim Peters8f9cc292006-02-17 00:00:20 +00001178 PyDict_SetItemString(dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001179#endif
1180#ifdef PROT_WRITE
Tim Peters8f9cc292006-02-17 00:00:20 +00001181 PyDict_SetItemString(dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001182#endif
1183
1184#ifdef MAP_SHARED
Tim Peters8f9cc292006-02-17 00:00:20 +00001185 PyDict_SetItemString(dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001186#endif
1187#ifdef MAP_PRIVATE
Tim Peters8f9cc292006-02-17 00:00:20 +00001188 PyDict_SetItemString(dict, "MAP_PRIVATE",
1189 PyInt_FromLong(MAP_PRIVATE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001190#endif
1191#ifdef MAP_DENYWRITE
Tim Peters8f9cc292006-02-17 00:00:20 +00001192 PyDict_SetItemString(dict, "MAP_DENYWRITE",
1193 PyInt_FromLong(MAP_DENYWRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001194#endif
1195#ifdef MAP_EXECUTABLE
Tim Peters8f9cc292006-02-17 00:00:20 +00001196 PyDict_SetItemString(dict, "MAP_EXECUTABLE",
1197 PyInt_FromLong(MAP_EXECUTABLE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001198#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001199#ifdef MAP_ANONYMOUS
Tim Peters8f9cc292006-02-17 00:00:20 +00001200 PyDict_SetItemString(dict, "MAP_ANON", PyInt_FromLong(MAP_ANONYMOUS) );
1201 PyDict_SetItemString(dict, "MAP_ANONYMOUS",
1202 PyInt_FromLong(MAP_ANONYMOUS) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001203#endif
1204
Tim Peters8f9cc292006-02-17 00:00:20 +00001205 PyDict_SetItemString(dict, "PAGESIZE",
1206 PyInt_FromLong((long)my_getpagesize()));
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001207
Tim Peters8f9cc292006-02-17 00:00:20 +00001208 PyDict_SetItemString(dict, "ACCESS_READ",
1209 PyInt_FromLong(ACCESS_READ));
1210 PyDict_SetItemString(dict, "ACCESS_WRITE",
1211 PyInt_FromLong(ACCESS_WRITE));
1212 PyDict_SetItemString(dict, "ACCESS_COPY",
1213 PyInt_FromLong(ACCESS_COPY));
Tim Peters5ebfd362001-11-13 23:11:19 +00001214}