blob: 3164a274076a71310c3079a11c298f2a2461bb87 [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 /
12 / Note: This module currently only deals with 32-bit file
13 / sizes.
14 /
Mark Hammond071864a2000-07-30 02:46:26 +000015 / This version of mmapmodule.c has been changed significantly
16 / from the original mmapfile.c on which it was based.
17 / The original version of mmapfile is maintained by Sam at
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000018 / ftp://squirl.nightmare.com/pub/python/python-ext.
19*/
20
Guido van Rossum09fdf072000-03-31 01:17:07 +000021#include <Python.h>
22
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000023#ifndef MS_WIN32
24#define UNIX
25#endif
26
27#ifdef MS_WIN32
28#include <windows.h>
Fred Drake145f96e2000-10-01 17:50:46 +000029static int
30my_getpagesize(void)
31{
Tim Peters5ebfd362001-11-13 23:11:19 +000032 SYSTEM_INFO si;
33 GetSystemInfo(&si);
34 return si.dwPageSize;
Fred Drake145f96e2000-10-01 17:50:46 +000035}
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000036#endif
37
38#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000039#include <sys/mman.h>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000040#include <sys/stat.h>
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000041
42#ifndef MS_SYNC
43/* This is missing e.g. on SunOS 4.1.4 */
44#define MS_SYNC 0
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000045#endif
46
Fred Drake145f96e2000-10-01 17:50:46 +000047#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
48static int
49my_getpagesize(void)
50{
Tim Peters5ebfd362001-11-13 23:11:19 +000051 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000052}
53#else
54#define my_getpagesize getpagesize
55#endif
56
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000057#endif /* UNIX */
58
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000059#include <string.h>
60#include <sys/types.h>
61
62static PyObject *mmap_module_error;
63
Tim Peters5ebfd362001-11-13 23:11:19 +000064typedef enum
65{
66 ACCESS_DEFAULT,
67 ACCESS_READ,
68 ACCESS_WRITE,
69 ACCESS_COPY
70} access_mode;
71
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000072typedef struct {
Guido van Rossum09fdf072000-03-31 01:17:07 +000073 PyObject_HEAD
74 char * data;
75 size_t size;
76 size_t pos;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000077
78#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +000079 HANDLE map_handle;
Mark Hammond071864a2000-07-30 02:46:26 +000080 HANDLE file_handle;
Guido van Rossum09fdf072000-03-31 01:17:07 +000081 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000082#endif
83
84#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000085 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000086#endif
Tim Peters5ebfd362001-11-13 23:11:19 +000087
88 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000089} mmap_object;
90
Tim Peters5ebfd362001-11-13 23:11:19 +000091
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000092static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +000093mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000094{
95#ifdef MS_WIN32
Mark Hammond2cbed002000-07-30 02:22:43 +000096 if (m_obj->data != NULL)
97 UnmapViewOfFile (m_obj->data);
98 if (m_obj->map_handle != INVALID_HANDLE_VALUE)
99 CloseHandle (m_obj->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000100 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
101 CloseHandle (m_obj->file_handle);
Mark Hammond2cbed002000-07-30 02:22:43 +0000102 if (m_obj->tagname)
103 PyMem_Free(m_obj->tagname);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000104#endif /* MS_WIN32 */
105
106#ifdef UNIX
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;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000121#ifdef MS_WIN32
Mark Hammond071864a2000-07-30 02:46:26 +0000122 /* For each resource we maintain, we need to check
123 the value is valid, and if so, free the resource
124 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) {
130 UnmapViewOfFile (self->data);
131 self->data = NULL;
132 }
133 if (self->map_handle != INVALID_HANDLE_VALUE) {
134 CloseHandle (self->map_handle);
135 self->map_handle = INVALID_HANDLE_VALUE;
136 }
137 if (self->file_handle != INVALID_HANDLE_VALUE) {
138 CloseHandle (self->file_handle);
139 self->file_handle = INVALID_HANDLE_VALUE;
140 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000141#endif /* MS_WIN32 */
142
143#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000144 munmap(self->data, self->size);
145 self->data = NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000146#endif
147
Guido van Rossum09fdf072000-03-31 01:17:07 +0000148 Py_INCREF (Py_None);
149 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000150}
151
152#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000153#define CHECK_VALID(err) \
154do { \
155 if (!self->map_handle) { \
156 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
157 return err; \
158 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000159} while (0)
160#endif /* MS_WIN32 */
161
162#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000163#define CHECK_VALID(err) \
164do { \
165 if (self->data == NULL) { \
166 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
167 return err; \
168 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000169} while (0)
170#endif /* UNIX */
171
172static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000173mmap_read_byte_method(mmap_object *self,
174 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000175{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000176 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000177 if (!PyArg_ParseTuple(args, ":read_byte"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000178 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000179 if (self->pos < self->size) {
Tim Petersd6283b82001-05-09 18:48:26 +0000180 char value = self->data[self->pos];
Guido van Rossum09fdf072000-03-31 01:17:07 +0000181 self->pos += 1;
Tim Petersd6283b82001-05-09 18:48:26 +0000182 return Py_BuildValue("c", value);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000183 } else {
184 PyErr_SetString (PyExc_ValueError, "read byte out of range");
185 return NULL;
186 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000187}
188
189static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000190mmap_read_line_method(mmap_object *self,
Tim Peters5ebfd362001-11-13 23:11:19 +0000191 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000192{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000193 char *start = self->data+self->pos;
194 char *eof = self->data+self->size;
195 char *eol;
196 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000197
Guido van Rossum09fdf072000-03-31 01:17:07 +0000198 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000199 if (!PyArg_ParseTuple(args, ":readline"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000200 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000201
Fred Drake56a87a02000-04-04 18:17:35 +0000202 eol = memchr(start, '\n', self->size - self->pos);
203 if (!eol)
204 eol = eof;
205 else
206 ++eol; /* we're interested in the position after the
207 newline. */
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000208 result = PyString_FromStringAndSize(start, (eol - start));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000209 self->pos += (eol - start);
210 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000211}
212
213static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000214mmap_read_method(mmap_object *self,
215 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000216{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000217 long num_bytes;
218 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000219
Guido van Rossum09fdf072000-03-31 01:17:07 +0000220 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000221 if (!PyArg_ParseTuple(args, "l:read", &num_bytes))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000222 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000223
Guido van Rossum09fdf072000-03-31 01:17:07 +0000224 /* silently 'adjust' out-of-range requests */
225 if ((self->pos + num_bytes) > self->size) {
226 num_bytes -= (self->pos+num_bytes) - self->size;
227 }
228 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
229 self->pos += num_bytes;
230 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000231}
232
233static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000234mmap_find_method(mmap_object *self,
235 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000236{
Tim Petersd401edd2001-05-14 23:19:12 +0000237 long start = self->pos;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000238 char *needle;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000239 int len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000240
Guido van Rossum09fdf072000-03-31 01:17:07 +0000241 CHECK_VALID(NULL);
Tim Petersd401edd2001-05-14 23:19:12 +0000242 if (!PyArg_ParseTuple (args, "s#|l:find", &needle, &len, &start)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000243 return NULL;
244 } else {
Greg Stein834f4dd2001-05-14 09:32:26 +0000245 char *p;
246 char *e = self->data + self->size;
247
248 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000249 start += self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000250 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000251 start = 0;
Tim Petersd401edd2001-05-14 23:19:12 +0000252 else if ((size_t)start > self->size)
Tim Peters5ebfd362001-11-13 23:11:19 +0000253 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000254
Tim Petersc9ffa062002-03-08 05:43:32 +0000255 for (p = self->data + start; p + len <= e; ++p) {
256 int i;
257 for (i = 0; i < len && needle[i] == p[i]; ++i)
258 /* nothing */;
259 if (i == len) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000260 return Py_BuildValue (
Tim Petersd401edd2001-05-14 23:19:12 +0000261 "l",
262 (long) (p - self->data));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000263 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000264 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000265 return Py_BuildValue ("l", (long) -1);
266 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000267}
268
Tim Peters5ebfd362001-11-13 23:11:19 +0000269static int
270is_writeable(mmap_object *self)
271{
272 if (self->access != ACCESS_READ)
273 return 1;
274 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
275 return 0;
276}
277
278static int
279is_resizeable(mmap_object *self)
280{
281 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
282 return 1;
283 PyErr_Format(PyExc_TypeError,
284 "mmap can't resize a readonly or copy-on-write memory map.");
285 return 0;
286}
287
288
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000289static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000290mmap_write_method(mmap_object *self,
291 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000292{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000293 long length;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000294 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000295
Guido van Rossum09fdf072000-03-31 01:17:07 +0000296 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000297 if (!PyArg_ParseTuple (args, "s#:write", &data, &length))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000298 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000299
Tim Peters5ebfd362001-11-13 23:11:19 +0000300 if (!is_writeable(self))
301 return NULL;
302
Guido van Rossum09fdf072000-03-31 01:17:07 +0000303 if ((self->pos + length) > self->size) {
304 PyErr_SetString (PyExc_ValueError, "data out of range");
305 return NULL;
306 }
307 memcpy (self->data+self->pos, data, length);
308 self->pos = self->pos+length;
309 Py_INCREF (Py_None);
310 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000311}
312
313static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000314mmap_write_byte_method(mmap_object *self,
315 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000316{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000317 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000318
Guido van Rossum09fdf072000-03-31 01:17:07 +0000319 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000320 if (!PyArg_ParseTuple (args, "c:write_byte", &value))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000321 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000322
Tim Peters5ebfd362001-11-13 23:11:19 +0000323 if (!is_writeable(self))
324 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000325 *(self->data+self->pos) = value;
326 self->pos += 1;
327 Py_INCREF (Py_None);
328 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000329}
Tim Peters5ebfd362001-11-13 23:11:19 +0000330
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000331static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000332mmap_size_method(mmap_object *self,
333 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000334{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000335 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000336 if (!PyArg_ParseTuple(args, ":size"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000337 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000338
339#ifdef MS_WIN32
Mark Hammond071864a2000-07-30 02:46:26 +0000340 if (self->file_handle != INVALID_HANDLE_VALUE) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000341 return (Py_BuildValue (
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000342 "l", (long)
Mark Hammond071864a2000-07-30 02:46:26 +0000343 GetFileSize (self->file_handle, NULL)));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000344 } else {
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000345 return (Py_BuildValue ("l", (long) self->size) );
Guido van Rossum09fdf072000-03-31 01:17:07 +0000346 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000347#endif /* MS_WIN32 */
348
349#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000350 {
351 struct stat buf;
352 if (-1 == fstat(self->fd, &buf)) {
353 PyErr_SetFromErrno(mmap_module_error);
354 return NULL;
355 }
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000356 return (Py_BuildValue ("l", (long) buf.st_size) );
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000357 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000358#endif /* UNIX */
359}
360
361/* This assumes that you want the entire file mapped,
362 / and when recreating the map will make the new file
363 / have the new size
364 /
365 / Is this really necessary? This could easily be done
366 / from python by just closing and re-opening with the
367 / new size?
368 */
369
370static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000371mmap_resize_method(mmap_object *self,
372 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000373{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000374 unsigned long new_size;
375 CHECK_VALID(NULL);
Tim Peters5ebfd362001-11-13 23:11:19 +0000376 if (!PyArg_ParseTuple (args, "l:resize", &new_size) ||
377 !is_resizeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000378 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000379#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000380 } else {
381 DWORD dwErrCode = 0;
382 /* First, unmap the file view */
383 UnmapViewOfFile (self->data);
384 /* Close the mapping object */
Mark Hammond071864a2000-07-30 02:46:26 +0000385 CloseHandle (self->map_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000386 /* Move to the desired EOF position */
Mark Hammond071864a2000-07-30 02:46:26 +0000387 SetFilePointer (self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000388 new_size, NULL, FILE_BEGIN);
389 /* Change the size of the file */
Mark Hammond071864a2000-07-30 02:46:26 +0000390 SetEndOfFile (self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000391 /* Create another mapping object and remap the file view */
392 self->map_handle = CreateFileMapping (
Mark Hammond071864a2000-07-30 02:46:26 +0000393 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000394 NULL,
395 PAGE_READWRITE,
396 0,
397 new_size,
398 self->tagname);
399 if (self->map_handle != NULL) {
400 self->data = (char *) MapViewOfFile (self->map_handle,
401 FILE_MAP_WRITE,
402 0,
403 0,
404 0);
405 if (self->data != NULL) {
406 self->size = new_size;
407 Py_INCREF (Py_None);
408 return Py_None;
409 } else {
410 dwErrCode = GetLastError();
411 }
412 } else {
413 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000414 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000415 PyErr_SetFromWindowsErr(dwErrCode);
416 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000417#endif /* MS_WIN32 */
418
419#ifdef UNIX
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000420#ifndef HAVE_MREMAP
Tim Peters5ebfd362001-11-13 23:11:19 +0000421 } else {
422 PyErr_SetString(PyExc_SystemError,
423 "mmap: resizing not available--no mremap()");
424 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000425#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000426 } else {
427 void *newmap;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000428
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000429#ifdef MREMAP_MAYMOVE
Tim Peters5ebfd362001-11-13 23:11:19 +0000430 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000431#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000432 newmap = mremap(self->data, self->size, new_size, 0);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000433#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000434 if (newmap == (void *)-1)
435 {
436 PyErr_SetFromErrno(mmap_module_error);
437 return NULL;
438 }
439 self->data = newmap;
440 self->size = new_size;
441 Py_INCREF(Py_None);
442 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000443#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000444#endif /* UNIX */
Tim Peters5ebfd362001-11-13 23:11:19 +0000445 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000446}
447
448static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000449mmap_tell_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000450{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000451 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000452 if (!PyArg_ParseTuple(args, ":tell"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000453 return NULL;
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000454 return (Py_BuildValue ("l", (long) self->pos) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000455}
456
457static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000458mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000459{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000460 size_t offset = 0;
461 size_t size = self->size;
462 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000463 if (!PyArg_ParseTuple (args, "|ll:flush", &offset, &size)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000464 return NULL;
465 } else if ((offset + size) > self->size) {
466 PyErr_SetString (PyExc_ValueError,
467 "flush values out of range");
468 return NULL;
469 } else {
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000470#ifdef MS_WIN32
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000471 return (Py_BuildValue("l", (long)
472 FlushViewOfFile(self->data+offset, size)));
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000473#endif /* MS_WIN32 */
474#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000475 /* XXX semantics of return value? */
476 /* XXX flags for msync? */
477 if (-1 == msync(self->data + offset, size,
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000478 MS_SYNC))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000479 {
480 PyErr_SetFromErrno(mmap_module_error);
481 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000482 }
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000483 return Py_BuildValue ("l", (long) 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000484#endif /* UNIX */
485 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000486}
487
488static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000489mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000490{
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000491 int dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000492 int how=0;
493 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000494 if (!PyArg_ParseTuple (args, "i|i:seek", &dist, &how)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000495 return(NULL);
496 } else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000497 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000498 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000499 case 0: /* relative to start */
500 if (dist < 0)
501 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000502 where = dist;
503 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000504 case 1: /* relative to current position */
505 if ((int)self->pos + dist < 0)
506 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000507 where = self->pos + dist;
508 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000509 case 2: /* relative to end */
510 if ((int)self->size + dist < 0)
511 goto onoutofrange;
512 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000513 break;
514 default:
515 PyErr_SetString (PyExc_ValueError,
516 "unknown seek type");
517 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000518 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000519 if (where > self->size)
520 goto onoutofrange;
521 self->pos = where;
522 Py_INCREF (Py_None);
523 return (Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000524 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000525
Tim Peters5ebfd362001-11-13 23:11:19 +0000526 onoutofrange:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000527 PyErr_SetString (PyExc_ValueError, "seek out of range");
528 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000529}
530
531static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000532mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000533{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000534 unsigned long dest, src, count;
535 CHECK_VALID(NULL);
Tim Peters5ebfd362001-11-13 23:11:19 +0000536 if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count) ||
537 !is_writeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000538 return NULL;
539 } else {
540 /* bounds check the values */
541 if (/* end of source after end of data?? */
542 ((src+count) > self->size)
543 /* dest will fit? */
544 || (dest+count > self->size)) {
545 PyErr_SetString (PyExc_ValueError,
546 "source or destination out of range");
547 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000548 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000549 memmove (self->data+dest, self->data+src, count);
550 Py_INCREF (Py_None);
551 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000552 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000553 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000554}
555
556static struct PyMethodDef mmap_object_methods[] = {
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000557 {"close", (PyCFunction) mmap_close_method, METH_VARARGS},
558 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
559 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
560 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
561 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
562 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_VARARGS},
563 {"readline", (PyCFunction) mmap_read_line_method, METH_VARARGS},
564 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
565 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
566 {"size", (PyCFunction) mmap_size_method, METH_VARARGS},
567 {"tell", (PyCFunction) mmap_tell_method, METH_VARARGS},
568 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
569 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000570 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000571};
572
573/* Functions for treating an mmap'ed file as a buffer */
574
575static int
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000576mmap_buffer_getreadbuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000577{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000578 CHECK_VALID(-1);
579 if ( index != 0 ) {
580 PyErr_SetString(PyExc_SystemError,
581 "Accessing non-existent mmap segment");
582 return -1;
583 }
584 *ptr = self->data;
585 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000586}
587
588static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000589mmap_buffer_getwritebuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000590{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000591 CHECK_VALID(-1);
592 if ( index != 0 ) {
593 PyErr_SetString(PyExc_SystemError,
594 "Accessing non-existent mmap segment");
595 return -1;
596 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000597 if (!is_writeable(self))
598 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000599 *ptr = self->data;
600 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000601}
602
603static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000604mmap_buffer_getsegcount(mmap_object *self, int *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000605{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000606 CHECK_VALID(-1);
607 if (lenp)
608 *lenp = self->size;
609 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000610}
611
612static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000613mmap_buffer_getcharbuffer(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000614{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000615 if ( index != 0 ) {
616 PyErr_SetString(PyExc_SystemError,
617 "accessing non-existent buffer segment");
618 return -1;
619 }
620 *ptr = (const char *)self->data;
621 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000622}
623
624static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000625mmap_object_getattr(mmap_object *self, char *name)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000626{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000627 return Py_FindMethod (mmap_object_methods, (PyObject *)self, name);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000628}
629
630static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000631mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000632{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000633 CHECK_VALID(-1);
634 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000635}
636
637static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000638mmap_item(mmap_object *self, int i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000639{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000640 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000641 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000642 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
643 return NULL;
644 }
645 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000646}
647
648static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000649mmap_slice(mmap_object *self, int ilow, int ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000650{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000651 CHECK_VALID(NULL);
652 if (ilow < 0)
653 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000654 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000655 ilow = self->size;
656 if (ihigh < 0)
657 ihigh = 0;
658 if (ihigh < ilow)
659 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000660 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000661 ihigh = self->size;
662
663 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000664}
665
666static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000667mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000668{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000669 CHECK_VALID(NULL);
670 PyErr_SetString(PyExc_SystemError,
671 "mmaps don't support concatenation");
672 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000673}
674
675static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000676mmap_repeat(mmap_object *self, int n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000677{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000678 CHECK_VALID(NULL);
679 PyErr_SetString(PyExc_SystemError,
680 "mmaps don't support repeat operation");
681 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000682}
683
684static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000685mmap_ass_slice(mmap_object *self, int ilow, int ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000686{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000687 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000688
Guido van Rossum09fdf072000-03-31 01:17:07 +0000689 CHECK_VALID(-1);
690 if (ilow < 0)
691 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000692 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000693 ilow = self->size;
694 if (ihigh < 0)
695 ihigh = 0;
696 if (ihigh < ilow)
697 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000698 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000699 ihigh = self->size;
700
Thomas Wouters1baac722001-07-16 15:47:36 +0000701 if (v == NULL) {
702 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000703 "mmap object doesn't support slice deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000704 return -1;
705 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000706 if (! (PyString_Check(v)) ) {
707 PyErr_SetString(PyExc_IndexError,
708 "mmap slice assignment must be a string");
709 return -1;
710 }
711 if ( PyString_Size(v) != (ihigh - ilow) ) {
712 PyErr_SetString(PyExc_IndexError,
713 "mmap slice assignment is wrong size");
714 return -1;
715 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000716 if (!is_writeable(self))
717 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000718 buf = PyString_AsString(v);
719 memcpy(self->data + ilow, buf, ihigh-ilow);
720 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000721}
722
723static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000724mmap_ass_item(mmap_object *self, int i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000725{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000726 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000727
Guido van Rossum09fdf072000-03-31 01:17:07 +0000728 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000729 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000730 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
731 return -1;
732 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000733 if (v == NULL) {
734 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000735 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000736 return -1;
737 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000738 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
739 PyErr_SetString(PyExc_IndexError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000740 "mmap assignment must be single-character string");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000741 return -1;
742 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000743 if (!is_writeable(self))
744 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000745 buf = PyString_AsString(v);
746 self->data[i] = buf[0];
747 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000748}
749
750static PySequenceMethods mmap_as_sequence = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000751 (inquiry)mmap_length, /*sq_length*/
752 (binaryfunc)mmap_concat, /*sq_concat*/
753 (intargfunc)mmap_repeat, /*sq_repeat*/
754 (intargfunc)mmap_item, /*sq_item*/
755 (intintargfunc)mmap_slice, /*sq_slice*/
756 (intobjargproc)mmap_ass_item, /*sq_ass_item*/
757 (intintobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000758};
759
760static PyBufferProcs mmap_as_buffer = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000761 (getreadbufferproc)mmap_buffer_getreadbuf,
762 (getwritebufferproc)mmap_buffer_getwritebuf,
763 (getsegcountproc)mmap_buffer_getsegcount,
764 (getcharbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000765};
766
767static PyTypeObject mmap_object_type = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000768 PyObject_HEAD_INIT(0) /* patched in module init */
769 0, /* ob_size */
Guido van Rossum14648392001-12-08 18:02:58 +0000770 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000771 sizeof(mmap_object), /* tp_size */
772 0, /* tp_itemsize */
773 /* methods */
774 (destructor) mmap_object_dealloc, /* tp_dealloc */
775 0, /* tp_print */
776 (getattrfunc) mmap_object_getattr, /* tp_getattr */
777 0, /* tp_setattr */
778 0, /* tp_compare */
779 0, /* tp_repr */
780 0, /* tp_as_number */
781 &mmap_as_sequence, /*tp_as_sequence*/
782 0, /*tp_as_mapping*/
783 0, /*tp_hash*/
784 0, /*tp_call*/
785 0, /*tp_str*/
786 0, /*tp_getattro*/
787 0, /*tp_setattro*/
788 &mmap_as_buffer, /*tp_as_buffer*/
789 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
790 0, /*tp_doc*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000791};
792
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000793
794/* extract the map size from the given PyObject
795
796 The map size is restricted to [0, INT_MAX] because this is the current
797 Python limitation on object sizes. Although the mmap object *could* handle
798 a larger map size, there is no point because all the useful operations
799 (len(), slicing(), sequence indexing) are limited by a C int.
800
Thomas Wouters7e474022000-07-16 12:04:32 +0000801 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000802 success, the map size is returned. */
803static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000804_GetMapSize(PyObject *o)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000805{
806 if (PyInt_Check(o)) {
807 long i = PyInt_AsLong(o);
808 if (PyErr_Occurred())
809 return -1;
810 if (i < 0)
811 goto onnegoverflow;
812 if (i > INT_MAX)
813 goto onposoverflow;
814 return (int)i;
815 }
816 else if (PyLong_Check(o)) {
817 long i = PyLong_AsLong(o);
818 if (PyErr_Occurred()) {
819 /* yes negative overflow is mistaken for positive overflow
820 but not worth the trouble to check sign of 'i' */
821 if (PyErr_ExceptionMatches(PyExc_OverflowError))
822 goto onposoverflow;
823 else
824 return -1;
825 }
826 if (i < 0)
827 goto onnegoverflow;
828 if (i > INT_MAX)
829 goto onposoverflow;
830 return (int)i;
831 }
832 else {
833 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000834 "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000835 return -1;
836 }
837
Tim Peters5ebfd362001-11-13 23:11:19 +0000838 onnegoverflow:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000839 PyErr_SetString(PyExc_OverflowError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000840 "memory mapped size must be positive");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000841 return -1;
842
Tim Peters5ebfd362001-11-13 23:11:19 +0000843 onposoverflow:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000844 PyErr_SetString(PyExc_OverflowError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000845 "memory mapped size is too large (limited by C int)");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000846 return -1;
847}
848
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000849#ifdef UNIX
850static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000851new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000852{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000853 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000854 PyObject *map_size_obj = NULL;
855 int map_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000856 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Tim Peters5ebfd362001-11-13 23:11:19 +0000857 access_mode access = ACCESS_DEFAULT;
858 char *keywords[] = {"fileno", "length",
859 "flags", "prot",
860 "access", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000861
Tim Peters5ebfd362001-11-13 23:11:19 +0000862 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii", keywords,
863 &fd, &map_size_obj, &flags, &prot, &access))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000864 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000865 map_size = _GetMapSize(map_size_obj);
866 if (map_size < 0)
867 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000868
869 if ((access != ACCESS_DEFAULT) &&
870 ((flags != MAP_SHARED) || ( prot != (PROT_WRITE | PROT_READ))))
871 return PyErr_Format(PyExc_ValueError,
872 "mmap can't specify both access and flags, prot.");
873 switch(access) {
874 case ACCESS_READ:
875 flags = MAP_SHARED;
876 prot = PROT_READ;
877 break;
878 case ACCESS_WRITE:
879 flags = MAP_SHARED;
880 prot = PROT_READ | PROT_WRITE;
881 break;
882 case ACCESS_COPY:
883 flags = MAP_PRIVATE;
884 prot = PROT_READ | PROT_WRITE;
885 break;
886 case ACCESS_DEFAULT:
887 /* use the specified or default values of flags and prot */
888 break;
889 default:
890 return PyErr_Format(PyExc_ValueError,
891 "mmap invalid access parameter.");
892 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000893
Guido van Rossumb18618d2000-05-03 23:44:39 +0000894 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000895 if (m_obj == NULL) {return NULL;}
896 m_obj->size = (size_t) map_size;
897 m_obj->pos = (size_t) 0;
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000898 m_obj->fd = fd;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000899 m_obj->data = mmap(NULL, map_size,
900 prot, flags,
901 fd, 0);
Tim Peters5ebfd362001-11-13 23:11:19 +0000902 if (m_obj->data == (char *)-1) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000903 Py_DECREF(m_obj);
904 PyErr_SetFromErrno(mmap_module_error);
905 return NULL;
906 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000907 m_obj->access = access;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000908 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000909}
910#endif /* UNIX */
911
912#ifdef MS_WIN32
913static PyObject *
Tim Peters5ebfd362001-11-13 23:11:19 +0000914new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000915{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000916 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000917 PyObject *map_size_obj = NULL;
918 int map_size;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000919 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +0000920 DWORD dwErr = 0;
921 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +0000922 HANDLE fh = 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000923 access_mode access = ACCESS_DEFAULT;
924 DWORD flProtect, dwDesiredAccess;
925 char *keywords[] = { "fileno", "length",
926 "tagname",
927 "access", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000928
Tim Peters5ebfd362001-11-13 23:11:19 +0000929 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|zi", keywords,
930 &fileno, &map_size_obj,
931 &tagname, &access)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000932 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000933 }
934
935 switch(access) {
936 case ACCESS_READ:
937 flProtect = PAGE_READONLY;
938 dwDesiredAccess = FILE_MAP_READ;
939 break;
940 case ACCESS_DEFAULT: case ACCESS_WRITE:
941 flProtect = PAGE_READWRITE;
942 dwDesiredAccess = FILE_MAP_WRITE;
943 break;
944 case ACCESS_COPY:
945 flProtect = PAGE_WRITECOPY;
946 dwDesiredAccess = FILE_MAP_COPY;
947 break;
948 default:
949 return PyErr_Format(PyExc_ValueError,
950 "mmap invalid access parameter.");
951 }
952
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000953 map_size = _GetMapSize(map_size_obj);
954 if (map_size < 0)
955 return NULL;
956
Guido van Rossum09fdf072000-03-31 01:17:07 +0000957 /* if an actual filename has been specified */
958 if (fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +0000959 fh = (HANDLE)_get_osfhandle(fileno);
960 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +0000961 PyErr_SetFromErrno(mmap_module_error);
962 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000963 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +0000964 /* Win9x appears to need us seeked to zero */
965 fseek(&_iob[fileno], 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000966 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000967
Guido van Rossumb18618d2000-05-03 23:44:39 +0000968 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Mark Hammond2cbed002000-07-30 02:22:43 +0000969 if (m_obj==NULL)
970 return NULL;
971 /* Set every field to an invalid marker, so we can safely
972 destruct the object in the face of failure */
973 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +0000974 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +0000975 m_obj->map_handle = INVALID_HANDLE_VALUE;
976 m_obj->tagname = NULL;
977
Guido van Rossum09fdf072000-03-31 01:17:07 +0000978 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +0000979 /* It is necessary to duplicate the handle, so the
980 Python code can close it on us */
981 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +0000982 GetCurrentProcess(), /* source process handle */
983 fh, /* handle to be duplicated */
984 GetCurrentProcess(), /* target proc handle */
985 (LPHANDLE)&m_obj->file_handle, /* result */
986 0, /* access - ignored due to options value */
987 FALSE, /* inherited by child processes? */
988 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +0000989 dwErr = GetLastError();
990 Py_DECREF(m_obj);
991 PyErr_SetFromWindowsErr(dwErr);
992 return NULL;
993 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000994 if (!map_size) {
Mark Hammond071864a2000-07-30 02:46:26 +0000995 m_obj->size = GetFileSize (fh, NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000996 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000997 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000998 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000999 }
1000 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001001 m_obj->size = map_size;
1002 }
1003
1004 /* set the initial position */
1005 m_obj->pos = (size_t) 0;
1006
Mark Hammond2cbed002000-07-30 02:22:43 +00001007 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001008 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001009 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1010 if (m_obj->tagname == NULL) {
1011 PyErr_NoMemory();
1012 Py_DECREF(m_obj);
1013 return NULL;
1014 }
1015 strcpy(m_obj->tagname, tagname);
1016 }
1017 else
1018 m_obj->tagname = NULL;
1019
Tim Peters5ebfd362001-11-13 23:11:19 +00001020 m_obj->access = access;
Mark Hammond071864a2000-07-30 02:46:26 +00001021 m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001022 NULL,
Tim Peters5ebfd362001-11-13 23:11:19 +00001023 flProtect,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001024 0,
1025 m_obj->size,
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001026 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001027 if (m_obj->map_handle != NULL) {
1028 m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
Tim Peters5ebfd362001-11-13 23:11:19 +00001029 dwDesiredAccess,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001030 0,
1031 0,
1032 0);
1033 if (m_obj->data != NULL) {
1034 return ((PyObject *) m_obj);
1035 } else {
Tim Peters5ebfd362001-11-13 23:11:19 +00001036 dwErr = GetLastError();
Guido van Rossum09fdf072000-03-31 01:17:07 +00001037 }
1038 } else {
1039 dwErr = GetLastError();
1040 }
Mark Hammond2cbed002000-07-30 02:22:43 +00001041 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001042 PyErr_SetFromWindowsErr(dwErr);
1043 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001044}
1045#endif /* MS_WIN32 */
1046
1047/* List of functions exported by this module */
1048static struct PyMethodDef mmap_functions[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001049 {"mmap", (PyCFunction) new_mmap_object,
1050 METH_VARARGS|METH_KEYWORDS},
1051 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001052};
1053
Guido van Rossum5a530192001-01-10 21:03:32 +00001054DL_EXPORT(void)
Tim Peters5ebfd362001-11-13 23:11:19 +00001055 initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001056{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001057 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001058
1059 /* Patch the object type */
1060 mmap_object_type.ob_type = &PyType_Type;
1061
Guido van Rossum09fdf072000-03-31 01:17:07 +00001062 module = Py_InitModule ("mmap", mmap_functions);
1063 dict = PyModule_GetDict (module);
1064 mmap_module_error = PyExc_EnvironmentError;
1065 Py_INCREF(mmap_module_error);
1066 PyDict_SetItemString (dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001067#ifdef PROT_EXEC
Guido van Rossum09fdf072000-03-31 01:17:07 +00001068 PyDict_SetItemString (dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001069#endif
1070#ifdef PROT_READ
Guido van Rossum09fdf072000-03-31 01:17:07 +00001071 PyDict_SetItemString (dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001072#endif
1073#ifdef PROT_WRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001074 PyDict_SetItemString (dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001075#endif
1076
1077#ifdef MAP_SHARED
Guido van Rossum09fdf072000-03-31 01:17:07 +00001078 PyDict_SetItemString (dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001079#endif
1080#ifdef MAP_PRIVATE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001081 PyDict_SetItemString (dict, "MAP_PRIVATE",
1082 PyInt_FromLong(MAP_PRIVATE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001083#endif
1084#ifdef MAP_DENYWRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001085 PyDict_SetItemString (dict, "MAP_DENYWRITE",
1086 PyInt_FromLong(MAP_DENYWRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001087#endif
1088#ifdef MAP_EXECUTABLE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001089 PyDict_SetItemString (dict, "MAP_EXECUTABLE",
1090 PyInt_FromLong(MAP_EXECUTABLE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001091#endif
1092#ifdef MAP_ANON
Guido van Rossum09fdf072000-03-31 01:17:07 +00001093 PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
1094 PyDict_SetItemString (dict, "MAP_ANONYMOUS",
1095 PyInt_FromLong(MAP_ANON) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001096#endif
1097
Guido van Rossum09fdf072000-03-31 01:17:07 +00001098 PyDict_SetItemString (dict, "PAGESIZE",
Fred Drake145f96e2000-10-01 17:50:46 +00001099 PyInt_FromLong( (long)my_getpagesize() ) );
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001100
Tim Peters5ebfd362001-11-13 23:11:19 +00001101 PyDict_SetItemString (dict, "ACCESS_READ",
1102 PyInt_FromLong(ACCESS_READ));
1103 PyDict_SetItemString (dict, "ACCESS_WRITE",
1104 PyInt_FromLong(ACCESS_WRITE));
1105 PyDict_SetItemString (dict, "ACCESS_COPY",
1106 PyInt_FromLong(ACCESS_COPY));
1107}