blob: cd1391453ce78e057898f100d9dd8a8afeea7a7f [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 p = self->data + start;
255
Guido van Rossum09fdf072000-03-31 01:17:07 +0000256 while (p < e) {
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000257 char *s = p;
258 char *n = needle;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000259 while ((s<e) && (*n) && !(*s-*n)) {
260 s++, n++;
261 }
262 if (!*n) {
263 return Py_BuildValue (
Tim Petersd401edd2001-05-14 23:19:12 +0000264 "l",
265 (long) (p - self->data));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000266 }
267 p++;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000268 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000269 return Py_BuildValue ("l", (long) -1);
270 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000271}
272
Tim Peters5ebfd362001-11-13 23:11:19 +0000273static int
274is_writeable(mmap_object *self)
275{
276 if (self->access != ACCESS_READ)
277 return 1;
278 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
279 return 0;
280}
281
282static int
283is_resizeable(mmap_object *self)
284{
285 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
286 return 1;
287 PyErr_Format(PyExc_TypeError,
288 "mmap can't resize a readonly or copy-on-write memory map.");
289 return 0;
290}
291
292
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000293static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000294mmap_write_method(mmap_object *self,
295 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000296{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000297 long length;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000298 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000299
Guido van Rossum09fdf072000-03-31 01:17:07 +0000300 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000301 if (!PyArg_ParseTuple (args, "s#:write", &data, &length))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000302 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000303
Tim Peters5ebfd362001-11-13 23:11:19 +0000304 if (!is_writeable(self))
305 return NULL;
306
Guido van Rossum09fdf072000-03-31 01:17:07 +0000307 if ((self->pos + length) > self->size) {
308 PyErr_SetString (PyExc_ValueError, "data out of range");
309 return NULL;
310 }
311 memcpy (self->data+self->pos, data, length);
312 self->pos = self->pos+length;
313 Py_INCREF (Py_None);
314 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000315}
316
317static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000318mmap_write_byte_method(mmap_object *self,
319 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000320{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000321 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000322
Guido van Rossum09fdf072000-03-31 01:17:07 +0000323 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000324 if (!PyArg_ParseTuple (args, "c:write_byte", &value))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000325 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000326
Tim Peters5ebfd362001-11-13 23:11:19 +0000327 if (!is_writeable(self))
328 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000329 *(self->data+self->pos) = value;
330 self->pos += 1;
331 Py_INCREF (Py_None);
332 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000333}
Tim Peters5ebfd362001-11-13 23:11:19 +0000334
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000335static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000336mmap_size_method(mmap_object *self,
337 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000338{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000339 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000340 if (!PyArg_ParseTuple(args, ":size"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000341 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000342
343#ifdef MS_WIN32
Mark Hammond071864a2000-07-30 02:46:26 +0000344 if (self->file_handle != INVALID_HANDLE_VALUE) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000345 return (Py_BuildValue (
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000346 "l", (long)
Mark Hammond071864a2000-07-30 02:46:26 +0000347 GetFileSize (self->file_handle, NULL)));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000348 } else {
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000349 return (Py_BuildValue ("l", (long) self->size) );
Guido van Rossum09fdf072000-03-31 01:17:07 +0000350 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000351#endif /* MS_WIN32 */
352
353#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000354 {
355 struct stat buf;
356 if (-1 == fstat(self->fd, &buf)) {
357 PyErr_SetFromErrno(mmap_module_error);
358 return NULL;
359 }
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000360 return (Py_BuildValue ("l", (long) buf.st_size) );
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000361 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000362#endif /* UNIX */
363}
364
365/* This assumes that you want the entire file mapped,
366 / and when recreating the map will make the new file
367 / have the new size
368 /
369 / Is this really necessary? This could easily be done
370 / from python by just closing and re-opening with the
371 / new size?
372 */
373
374static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000375mmap_resize_method(mmap_object *self,
376 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000377{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000378 unsigned long new_size;
379 CHECK_VALID(NULL);
Tim Peters5ebfd362001-11-13 23:11:19 +0000380 if (!PyArg_ParseTuple (args, "l:resize", &new_size) ||
381 !is_resizeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000382 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000383#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000384 } else {
385 DWORD dwErrCode = 0;
386 /* First, unmap the file view */
387 UnmapViewOfFile (self->data);
388 /* Close the mapping object */
Mark Hammond071864a2000-07-30 02:46:26 +0000389 CloseHandle (self->map_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000390 /* Move to the desired EOF position */
Mark Hammond071864a2000-07-30 02:46:26 +0000391 SetFilePointer (self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000392 new_size, NULL, FILE_BEGIN);
393 /* Change the size of the file */
Mark Hammond071864a2000-07-30 02:46:26 +0000394 SetEndOfFile (self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000395 /* Create another mapping object and remap the file view */
396 self->map_handle = CreateFileMapping (
Mark Hammond071864a2000-07-30 02:46:26 +0000397 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000398 NULL,
399 PAGE_READWRITE,
400 0,
401 new_size,
402 self->tagname);
403 if (self->map_handle != NULL) {
404 self->data = (char *) MapViewOfFile (self->map_handle,
405 FILE_MAP_WRITE,
406 0,
407 0,
408 0);
409 if (self->data != NULL) {
410 self->size = new_size;
411 Py_INCREF (Py_None);
412 return Py_None;
413 } else {
414 dwErrCode = GetLastError();
415 }
416 } else {
417 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000418 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000419 PyErr_SetFromWindowsErr(dwErrCode);
420 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000421#endif /* MS_WIN32 */
422
423#ifdef UNIX
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000424#ifndef HAVE_MREMAP
Tim Peters5ebfd362001-11-13 23:11:19 +0000425 } else {
426 PyErr_SetString(PyExc_SystemError,
427 "mmap: resizing not available--no mremap()");
428 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000429#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000430 } else {
431 void *newmap;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000432
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000433#ifdef MREMAP_MAYMOVE
Tim Peters5ebfd362001-11-13 23:11:19 +0000434 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000435#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000436 newmap = mremap(self->data, self->size, new_size, 0);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000437#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000438 if (newmap == (void *)-1)
439 {
440 PyErr_SetFromErrno(mmap_module_error);
441 return NULL;
442 }
443 self->data = newmap;
444 self->size = new_size;
445 Py_INCREF(Py_None);
446 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000447#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000448#endif /* UNIX */
Tim Peters5ebfd362001-11-13 23:11:19 +0000449 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000450}
451
452static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000453mmap_tell_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000454{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000455 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000456 if (!PyArg_ParseTuple(args, ":tell"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000457 return NULL;
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000458 return (Py_BuildValue ("l", (long) self->pos) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000459}
460
461static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000462mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000463{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000464 size_t offset = 0;
465 size_t size = self->size;
466 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000467 if (!PyArg_ParseTuple (args, "|ll:flush", &offset, &size)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000468 return NULL;
469 } else if ((offset + size) > self->size) {
470 PyErr_SetString (PyExc_ValueError,
471 "flush values out of range");
472 return NULL;
473 } else {
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000474#ifdef MS_WIN32
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000475 return (Py_BuildValue("l", (long)
476 FlushViewOfFile(self->data+offset, size)));
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000477#endif /* MS_WIN32 */
478#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000479 /* XXX semantics of return value? */
480 /* XXX flags for msync? */
481 if (-1 == msync(self->data + offset, size,
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000482 MS_SYNC))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000483 {
484 PyErr_SetFromErrno(mmap_module_error);
485 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000486 }
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000487 return Py_BuildValue ("l", (long) 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000488#endif /* UNIX */
489 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000490}
491
492static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000493mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000494{
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000495 int dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000496 int how=0;
497 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000498 if (!PyArg_ParseTuple (args, "i|i:seek", &dist, &how)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000499 return(NULL);
500 } else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000501 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000502 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000503 case 0: /* relative to start */
504 if (dist < 0)
505 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000506 where = dist;
507 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000508 case 1: /* relative to current position */
509 if ((int)self->pos + dist < 0)
510 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000511 where = self->pos + dist;
512 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000513 case 2: /* relative to end */
514 if ((int)self->size + dist < 0)
515 goto onoutofrange;
516 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000517 break;
518 default:
519 PyErr_SetString (PyExc_ValueError,
520 "unknown seek type");
521 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000522 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000523 if (where > self->size)
524 goto onoutofrange;
525 self->pos = where;
526 Py_INCREF (Py_None);
527 return (Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000528 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000529
Tim Peters5ebfd362001-11-13 23:11:19 +0000530 onoutofrange:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000531 PyErr_SetString (PyExc_ValueError, "seek out of range");
532 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000533}
534
535static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000536mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000537{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000538 unsigned long dest, src, count;
539 CHECK_VALID(NULL);
Tim Peters5ebfd362001-11-13 23:11:19 +0000540 if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count) ||
541 !is_writeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000542 return NULL;
543 } else {
544 /* bounds check the values */
545 if (/* end of source after end of data?? */
546 ((src+count) > self->size)
547 /* dest will fit? */
548 || (dest+count > self->size)) {
549 PyErr_SetString (PyExc_ValueError,
550 "source or destination out of range");
551 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000552 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000553 memmove (self->data+dest, self->data+src, count);
554 Py_INCREF (Py_None);
555 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000556 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000557 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000558}
559
560static struct PyMethodDef mmap_object_methods[] = {
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000561 {"close", (PyCFunction) mmap_close_method, METH_VARARGS},
562 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
563 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
564 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
565 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
566 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_VARARGS},
567 {"readline", (PyCFunction) mmap_read_line_method, METH_VARARGS},
568 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
569 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
570 {"size", (PyCFunction) mmap_size_method, METH_VARARGS},
571 {"tell", (PyCFunction) mmap_tell_method, METH_VARARGS},
572 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
573 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000574 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000575};
576
577/* Functions for treating an mmap'ed file as a buffer */
578
579static int
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000580mmap_buffer_getreadbuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000581{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000582 CHECK_VALID(-1);
583 if ( index != 0 ) {
584 PyErr_SetString(PyExc_SystemError,
585 "Accessing non-existent mmap segment");
586 return -1;
587 }
588 *ptr = self->data;
589 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000590}
591
592static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000593mmap_buffer_getwritebuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000594{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000595 CHECK_VALID(-1);
596 if ( index != 0 ) {
597 PyErr_SetString(PyExc_SystemError,
598 "Accessing non-existent mmap segment");
599 return -1;
600 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000601 if (!is_writeable(self))
602 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000603 *ptr = self->data;
604 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000605}
606
607static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000608mmap_buffer_getsegcount(mmap_object *self, int *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000609{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000610 CHECK_VALID(-1);
611 if (lenp)
612 *lenp = self->size;
613 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000614}
615
616static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000617mmap_buffer_getcharbuffer(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000618{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000619 if ( index != 0 ) {
620 PyErr_SetString(PyExc_SystemError,
621 "accessing non-existent buffer segment");
622 return -1;
623 }
624 *ptr = (const char *)self->data;
625 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000626}
627
628static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000629mmap_object_getattr(mmap_object *self, char *name)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000630{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000631 return Py_FindMethod (mmap_object_methods, (PyObject *)self, name);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000632}
633
634static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000635mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000636{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000637 CHECK_VALID(-1);
638 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000639}
640
641static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000642mmap_item(mmap_object *self, int i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000643{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000644 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000645 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000646 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
647 return NULL;
648 }
649 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000650}
651
652static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000653mmap_slice(mmap_object *self, int ilow, int ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000654{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000655 CHECK_VALID(NULL);
656 if (ilow < 0)
657 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000658 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000659 ilow = self->size;
660 if (ihigh < 0)
661 ihigh = 0;
662 if (ihigh < ilow)
663 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000664 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000665 ihigh = self->size;
666
667 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000668}
669
670static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000671mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000672{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000673 CHECK_VALID(NULL);
674 PyErr_SetString(PyExc_SystemError,
675 "mmaps don't support concatenation");
676 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000677}
678
679static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000680mmap_repeat(mmap_object *self, int n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000681{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000682 CHECK_VALID(NULL);
683 PyErr_SetString(PyExc_SystemError,
684 "mmaps don't support repeat operation");
685 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000686}
687
688static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000689mmap_ass_slice(mmap_object *self, int ilow, int ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000690{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000691 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000692
Guido van Rossum09fdf072000-03-31 01:17:07 +0000693 CHECK_VALID(-1);
694 if (ilow < 0)
695 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000696 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000697 ilow = self->size;
698 if (ihigh < 0)
699 ihigh = 0;
700 if (ihigh < ilow)
701 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000702 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000703 ihigh = self->size;
704
Thomas Wouters1baac722001-07-16 15:47:36 +0000705 if (v == NULL) {
706 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000707 "mmap object doesn't support slice deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000708 return -1;
709 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000710 if (! (PyString_Check(v)) ) {
711 PyErr_SetString(PyExc_IndexError,
712 "mmap slice assignment must be a string");
713 return -1;
714 }
715 if ( PyString_Size(v) != (ihigh - ilow) ) {
716 PyErr_SetString(PyExc_IndexError,
717 "mmap slice assignment is wrong size");
718 return -1;
719 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000720 if (!is_writeable(self))
721 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000722 buf = PyString_AsString(v);
723 memcpy(self->data + ilow, buf, ihigh-ilow);
724 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000725}
726
727static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000728mmap_ass_item(mmap_object *self, int i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000729{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000730 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000731
Guido van Rossum09fdf072000-03-31 01:17:07 +0000732 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000733 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000734 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
735 return -1;
736 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000737 if (v == NULL) {
738 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000739 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000740 return -1;
741 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000742 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
743 PyErr_SetString(PyExc_IndexError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000744 "mmap assignment must be single-character string");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000745 return -1;
746 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000747 if (!is_writeable(self))
748 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000749 buf = PyString_AsString(v);
750 self->data[i] = buf[0];
751 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000752}
753
754static PySequenceMethods mmap_as_sequence = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000755 (inquiry)mmap_length, /*sq_length*/
756 (binaryfunc)mmap_concat, /*sq_concat*/
757 (intargfunc)mmap_repeat, /*sq_repeat*/
758 (intargfunc)mmap_item, /*sq_item*/
759 (intintargfunc)mmap_slice, /*sq_slice*/
760 (intobjargproc)mmap_ass_item, /*sq_ass_item*/
761 (intintobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000762};
763
764static PyBufferProcs mmap_as_buffer = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000765 (getreadbufferproc)mmap_buffer_getreadbuf,
766 (getwritebufferproc)mmap_buffer_getwritebuf,
767 (getsegcountproc)mmap_buffer_getsegcount,
768 (getcharbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000769};
770
771static PyTypeObject mmap_object_type = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000772 PyObject_HEAD_INIT(0) /* patched in module init */
773 0, /* ob_size */
Guido van Rossum14648392001-12-08 18:02:58 +0000774 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000775 sizeof(mmap_object), /* tp_size */
776 0, /* tp_itemsize */
777 /* methods */
778 (destructor) mmap_object_dealloc, /* tp_dealloc */
779 0, /* tp_print */
780 (getattrfunc) mmap_object_getattr, /* tp_getattr */
781 0, /* tp_setattr */
782 0, /* tp_compare */
783 0, /* tp_repr */
784 0, /* tp_as_number */
785 &mmap_as_sequence, /*tp_as_sequence*/
786 0, /*tp_as_mapping*/
787 0, /*tp_hash*/
788 0, /*tp_call*/
789 0, /*tp_str*/
790 0, /*tp_getattro*/
791 0, /*tp_setattro*/
792 &mmap_as_buffer, /*tp_as_buffer*/
793 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
794 0, /*tp_doc*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000795};
796
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000797
798/* extract the map size from the given PyObject
799
800 The map size is restricted to [0, INT_MAX] because this is the current
801 Python limitation on object sizes. Although the mmap object *could* handle
802 a larger map size, there is no point because all the useful operations
803 (len(), slicing(), sequence indexing) are limited by a C int.
804
Thomas Wouters7e474022000-07-16 12:04:32 +0000805 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000806 success, the map size is returned. */
807static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000808_GetMapSize(PyObject *o)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000809{
810 if (PyInt_Check(o)) {
811 long i = PyInt_AsLong(o);
812 if (PyErr_Occurred())
813 return -1;
814 if (i < 0)
815 goto onnegoverflow;
816 if (i > INT_MAX)
817 goto onposoverflow;
818 return (int)i;
819 }
820 else if (PyLong_Check(o)) {
821 long i = PyLong_AsLong(o);
822 if (PyErr_Occurred()) {
823 /* yes negative overflow is mistaken for positive overflow
824 but not worth the trouble to check sign of 'i' */
825 if (PyErr_ExceptionMatches(PyExc_OverflowError))
826 goto onposoverflow;
827 else
828 return -1;
829 }
830 if (i < 0)
831 goto onnegoverflow;
832 if (i > INT_MAX)
833 goto onposoverflow;
834 return (int)i;
835 }
836 else {
837 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000838 "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000839 return -1;
840 }
841
Tim Peters5ebfd362001-11-13 23:11:19 +0000842 onnegoverflow:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000843 PyErr_SetString(PyExc_OverflowError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000844 "memory mapped size must be positive");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000845 return -1;
846
Tim Peters5ebfd362001-11-13 23:11:19 +0000847 onposoverflow:
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000848 PyErr_SetString(PyExc_OverflowError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000849 "memory mapped size is too large (limited by C int)");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000850 return -1;
851}
852
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000853#ifdef UNIX
854static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000855new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000856{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000857 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000858 PyObject *map_size_obj = NULL;
859 int map_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000860 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Tim Peters5ebfd362001-11-13 23:11:19 +0000861 access_mode access = ACCESS_DEFAULT;
862 char *keywords[] = {"fileno", "length",
863 "flags", "prot",
864 "access", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000865
Tim Peters5ebfd362001-11-13 23:11:19 +0000866 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii", keywords,
867 &fd, &map_size_obj, &flags, &prot, &access))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000868 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000869 map_size = _GetMapSize(map_size_obj);
870 if (map_size < 0)
871 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000872
873 if ((access != ACCESS_DEFAULT) &&
874 ((flags != MAP_SHARED) || ( prot != (PROT_WRITE | PROT_READ))))
875 return PyErr_Format(PyExc_ValueError,
876 "mmap can't specify both access and flags, prot.");
877 switch(access) {
878 case ACCESS_READ:
879 flags = MAP_SHARED;
880 prot = PROT_READ;
881 break;
882 case ACCESS_WRITE:
883 flags = MAP_SHARED;
884 prot = PROT_READ | PROT_WRITE;
885 break;
886 case ACCESS_COPY:
887 flags = MAP_PRIVATE;
888 prot = PROT_READ | PROT_WRITE;
889 break;
890 case ACCESS_DEFAULT:
891 /* use the specified or default values of flags and prot */
892 break;
893 default:
894 return PyErr_Format(PyExc_ValueError,
895 "mmap invalid access parameter.");
896 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000897
Guido van Rossumb18618d2000-05-03 23:44:39 +0000898 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000899 if (m_obj == NULL) {return NULL;}
900 m_obj->size = (size_t) map_size;
901 m_obj->pos = (size_t) 0;
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000902 m_obj->fd = fd;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000903 m_obj->data = mmap(NULL, map_size,
904 prot, flags,
905 fd, 0);
Tim Peters5ebfd362001-11-13 23:11:19 +0000906 if (m_obj->data == (char *)-1) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000907 Py_DECREF(m_obj);
908 PyErr_SetFromErrno(mmap_module_error);
909 return NULL;
910 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000911 m_obj->access = access;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000912 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000913}
914#endif /* UNIX */
915
916#ifdef MS_WIN32
917static PyObject *
Tim Peters5ebfd362001-11-13 23:11:19 +0000918new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000919{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000920 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000921 PyObject *map_size_obj = NULL;
922 int map_size;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000923 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +0000924 DWORD dwErr = 0;
925 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +0000926 HANDLE fh = 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000927 access_mode access = ACCESS_DEFAULT;
928 DWORD flProtect, dwDesiredAccess;
929 char *keywords[] = { "fileno", "length",
930 "tagname",
931 "access", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000932
Tim Peters5ebfd362001-11-13 23:11:19 +0000933 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|zi", keywords,
934 &fileno, &map_size_obj,
935 &tagname, &access)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000936 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000937 }
938
939 switch(access) {
940 case ACCESS_READ:
941 flProtect = PAGE_READONLY;
942 dwDesiredAccess = FILE_MAP_READ;
943 break;
944 case ACCESS_DEFAULT: case ACCESS_WRITE:
945 flProtect = PAGE_READWRITE;
946 dwDesiredAccess = FILE_MAP_WRITE;
947 break;
948 case ACCESS_COPY:
949 flProtect = PAGE_WRITECOPY;
950 dwDesiredAccess = FILE_MAP_COPY;
951 break;
952 default:
953 return PyErr_Format(PyExc_ValueError,
954 "mmap invalid access parameter.");
955 }
956
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000957 map_size = _GetMapSize(map_size_obj);
958 if (map_size < 0)
959 return NULL;
960
Guido van Rossum09fdf072000-03-31 01:17:07 +0000961 /* if an actual filename has been specified */
962 if (fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +0000963 fh = (HANDLE)_get_osfhandle(fileno);
964 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +0000965 PyErr_SetFromErrno(mmap_module_error);
966 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000967 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +0000968 /* Win9x appears to need us seeked to zero */
969 fseek(&_iob[fileno], 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000970 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000971
Guido van Rossumb18618d2000-05-03 23:44:39 +0000972 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Mark Hammond2cbed002000-07-30 02:22:43 +0000973 if (m_obj==NULL)
974 return NULL;
975 /* Set every field to an invalid marker, so we can safely
976 destruct the object in the face of failure */
977 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +0000978 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +0000979 m_obj->map_handle = INVALID_HANDLE_VALUE;
980 m_obj->tagname = NULL;
981
Guido van Rossum09fdf072000-03-31 01:17:07 +0000982 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +0000983 /* It is necessary to duplicate the handle, so the
984 Python code can close it on us */
985 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +0000986 GetCurrentProcess(), /* source process handle */
987 fh, /* handle to be duplicated */
988 GetCurrentProcess(), /* target proc handle */
989 (LPHANDLE)&m_obj->file_handle, /* result */
990 0, /* access - ignored due to options value */
991 FALSE, /* inherited by child processes? */
992 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +0000993 dwErr = GetLastError();
994 Py_DECREF(m_obj);
995 PyErr_SetFromWindowsErr(dwErr);
996 return NULL;
997 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000998 if (!map_size) {
Mark Hammond071864a2000-07-30 02:46:26 +0000999 m_obj->size = GetFileSize (fh, NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001000 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001001 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001002 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001003 }
1004 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001005 m_obj->size = map_size;
1006 }
1007
1008 /* set the initial position */
1009 m_obj->pos = (size_t) 0;
1010
Mark Hammond2cbed002000-07-30 02:22:43 +00001011 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001012 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001013 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1014 if (m_obj->tagname == NULL) {
1015 PyErr_NoMemory();
1016 Py_DECREF(m_obj);
1017 return NULL;
1018 }
1019 strcpy(m_obj->tagname, tagname);
1020 }
1021 else
1022 m_obj->tagname = NULL;
1023
Tim Peters5ebfd362001-11-13 23:11:19 +00001024 m_obj->access = access;
Mark Hammond071864a2000-07-30 02:46:26 +00001025 m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001026 NULL,
Tim Peters5ebfd362001-11-13 23:11:19 +00001027 flProtect,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001028 0,
1029 m_obj->size,
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001030 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001031 if (m_obj->map_handle != NULL) {
1032 m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
Tim Peters5ebfd362001-11-13 23:11:19 +00001033 dwDesiredAccess,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001034 0,
1035 0,
1036 0);
1037 if (m_obj->data != NULL) {
1038 return ((PyObject *) m_obj);
1039 } else {
Tim Peters5ebfd362001-11-13 23:11:19 +00001040 dwErr = GetLastError();
Guido van Rossum09fdf072000-03-31 01:17:07 +00001041 }
1042 } else {
1043 dwErr = GetLastError();
1044 }
Mark Hammond2cbed002000-07-30 02:22:43 +00001045 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001046 PyErr_SetFromWindowsErr(dwErr);
1047 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001048}
1049#endif /* MS_WIN32 */
1050
1051/* List of functions exported by this module */
1052static struct PyMethodDef mmap_functions[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001053 {"mmap", (PyCFunction) new_mmap_object,
1054 METH_VARARGS|METH_KEYWORDS},
1055 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001056};
1057
Guido van Rossum5a530192001-01-10 21:03:32 +00001058DL_EXPORT(void)
Tim Peters5ebfd362001-11-13 23:11:19 +00001059 initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001060{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001061 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001062
1063 /* Patch the object type */
1064 mmap_object_type.ob_type = &PyType_Type;
1065
Guido van Rossum09fdf072000-03-31 01:17:07 +00001066 module = Py_InitModule ("mmap", mmap_functions);
1067 dict = PyModule_GetDict (module);
1068 mmap_module_error = PyExc_EnvironmentError;
1069 Py_INCREF(mmap_module_error);
1070 PyDict_SetItemString (dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001071#ifdef PROT_EXEC
Guido van Rossum09fdf072000-03-31 01:17:07 +00001072 PyDict_SetItemString (dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001073#endif
1074#ifdef PROT_READ
Guido van Rossum09fdf072000-03-31 01:17:07 +00001075 PyDict_SetItemString (dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001076#endif
1077#ifdef PROT_WRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001078 PyDict_SetItemString (dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001079#endif
1080
1081#ifdef MAP_SHARED
Guido van Rossum09fdf072000-03-31 01:17:07 +00001082 PyDict_SetItemString (dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001083#endif
1084#ifdef MAP_PRIVATE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001085 PyDict_SetItemString (dict, "MAP_PRIVATE",
1086 PyInt_FromLong(MAP_PRIVATE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001087#endif
1088#ifdef MAP_DENYWRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001089 PyDict_SetItemString (dict, "MAP_DENYWRITE",
1090 PyInt_FromLong(MAP_DENYWRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001091#endif
1092#ifdef MAP_EXECUTABLE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001093 PyDict_SetItemString (dict, "MAP_EXECUTABLE",
1094 PyInt_FromLong(MAP_EXECUTABLE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001095#endif
1096#ifdef MAP_ANON
Guido van Rossum09fdf072000-03-31 01:17:07 +00001097 PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
1098 PyDict_SetItemString (dict, "MAP_ANONYMOUS",
1099 PyInt_FromLong(MAP_ANON) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001100#endif
1101
Guido van Rossum09fdf072000-03-31 01:17:07 +00001102 PyDict_SetItemString (dict, "PAGESIZE",
Fred Drake145f96e2000-10-01 17:50:46 +00001103 PyInt_FromLong( (long)my_getpagesize() ) );
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001104
Tim Peters5ebfd362001-11-13 23:11:19 +00001105 PyDict_SetItemString (dict, "ACCESS_READ",
1106 PyInt_FromLong(ACCESS_READ));
1107 PyDict_SetItemString (dict, "ACCESS_WRITE",
1108 PyInt_FromLong(ACCESS_WRITE));
1109 PyDict_SetItemString (dict, "ACCESS_COPY",
1110 PyInt_FromLong(ACCESS_COPY));
1111}