blob: c1cc013ed29f14ff329e2d55d17c8b951b8f49c3 [file] [log] [blame]
Guido van Rossum09fdf072000-03-31 01:17:07 +00001/*
2 / Author: Sam Rushing <rushing@nightmare.com>
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00003 / Hacked for Unix by A.M. Kuchling <amk1@bigfoot.com>
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{
32 SYSTEM_INFO si;
33 GetSystemInfo(&si);
34 return si.dwPageSize;
35}
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000036#endif
37
38#ifdef UNIX
39#include <unistd.h>
40#include <sys/mman.h>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000041#include <sys/stat.h>
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000042
43#ifndef MS_SYNC
44/* This is missing e.g. on SunOS 4.1.4 */
45#define MS_SYNC 0
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000046#endif
47
Fred Drake145f96e2000-10-01 17:50:46 +000048#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
49static int
50my_getpagesize(void)
51{
52 return sysconf(_SC_PAGESIZE);
53}
54#else
55#define my_getpagesize getpagesize
56#endif
57
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000058#endif /* UNIX */
59
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000060#include <string.h>
61#include <sys/types.h>
62
63static PyObject *mmap_module_error;
64
65typedef struct {
Guido van Rossum09fdf072000-03-31 01:17:07 +000066 PyObject_HEAD
67 char * data;
68 size_t size;
69 size_t pos;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000070
71#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +000072 HANDLE map_handle;
Mark Hammond071864a2000-07-30 02:46:26 +000073 HANDLE file_handle;
Guido van Rossum09fdf072000-03-31 01:17:07 +000074 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000075#endif
76
77#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000078 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000079#endif
80} mmap_object;
81
82static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +000083mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000084{
85#ifdef MS_WIN32
Mark Hammond2cbed002000-07-30 02:22:43 +000086 if (m_obj->data != NULL)
87 UnmapViewOfFile (m_obj->data);
88 if (m_obj->map_handle != INVALID_HANDLE_VALUE)
89 CloseHandle (m_obj->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +000090 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
91 CloseHandle (m_obj->file_handle);
Mark Hammond2cbed002000-07-30 02:22:43 +000092 if (m_obj->tagname)
93 PyMem_Free(m_obj->tagname);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000094#endif /* MS_WIN32 */
95
96#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +000097 if (m_obj->data!=NULL) {
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +000098 msync(m_obj->data, m_obj->size, MS_SYNC);
Guido van Rossum09fdf072000-03-31 01:17:07 +000099 munmap(m_obj->data, m_obj->size);
100 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000101#endif /* UNIX */
102
Guido van Rossumb18618d2000-05-03 23:44:39 +0000103 PyObject_Del(m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000104}
105
106static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000107mmap_close_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000108{
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000109 if (!PyArg_ParseTuple(args, ":close"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000110 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000111#ifdef MS_WIN32
Mark Hammond071864a2000-07-30 02:46:26 +0000112 /* For each resource we maintain, we need to check
113 the value is valid, and if so, free the resource
114 and set the member value to an invalid value so
115 the dealloc does not attempt to resource clearing
116 again.
117 TODO - should we check for errors in the close operations???
118 */
119 if (self->data != NULL) {
120 UnmapViewOfFile (self->data);
121 self->data = NULL;
122 }
123 if (self->map_handle != INVALID_HANDLE_VALUE) {
124 CloseHandle (self->map_handle);
125 self->map_handle = INVALID_HANDLE_VALUE;
126 }
127 if (self->file_handle != INVALID_HANDLE_VALUE) {
128 CloseHandle (self->file_handle);
129 self->file_handle = INVALID_HANDLE_VALUE;
130 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000131#endif /* MS_WIN32 */
132
133#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000134 munmap(self->data, self->size);
135 self->data = NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000136#endif
137
Guido van Rossum09fdf072000-03-31 01:17:07 +0000138 Py_INCREF (Py_None);
139 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000140}
141
142#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000143#define CHECK_VALID(err) \
144do { \
145 if (!self->map_handle) { \
146 PyErr_SetString (PyExc_ValueError, "mmap closed or invalid"); \
147 return err; \
148 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000149} while (0)
150#endif /* MS_WIN32 */
151
152#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000153#define CHECK_VALID(err) \
154do { \
155 if (self->data == NULL) { \
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 /* UNIX */
161
162static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000163mmap_read_byte_method(mmap_object *self,
164 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000165{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000166 char value;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000167 char *where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000168 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000169 if (!PyArg_ParseTuple(args, ":read_byte"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000170 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000171 if (self->pos < self->size) {
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000172 where = self->data + self->pos;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000173 value = (char) *(where);
174 self->pos += 1;
175 return Py_BuildValue("c", (char) *(where));
176 } else {
177 PyErr_SetString (PyExc_ValueError, "read byte out of range");
178 return NULL;
179 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000180}
181
182static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000183mmap_read_line_method(mmap_object *self,
184 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000185{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000186 char *start = self->data+self->pos;
187 char *eof = self->data+self->size;
188 char *eol;
189 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000190
Guido van Rossum09fdf072000-03-31 01:17:07 +0000191 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000192 if (!PyArg_ParseTuple(args, ":readline"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000193 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000194
Fred Drake56a87a02000-04-04 18:17:35 +0000195 eol = memchr(start, '\n', self->size - self->pos);
196 if (!eol)
197 eol = eof;
198 else
199 ++eol; /* we're interested in the position after the
200 newline. */
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000201 result = PyString_FromStringAndSize(start, (eol - start));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000202 self->pos += (eol - start);
203 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000204}
205
206static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000207mmap_read_method(mmap_object *self,
208 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000209{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000210 long num_bytes;
211 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000212
Guido van Rossum09fdf072000-03-31 01:17:07 +0000213 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000214 if (!PyArg_ParseTuple(args, "l:read", &num_bytes))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000215 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000216
Guido van Rossum09fdf072000-03-31 01:17:07 +0000217 /* silently 'adjust' out-of-range requests */
218 if ((self->pos + num_bytes) > self->size) {
219 num_bytes -= (self->pos+num_bytes) - self->size;
220 }
221 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
222 self->pos += num_bytes;
223 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000224}
225
226static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000227mmap_find_method(mmap_object *self,
228 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000229{
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000230 int start = self->pos;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000231 char *needle;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000232 int len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000233
Guido van Rossum09fdf072000-03-31 01:17:07 +0000234 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000235 if (!PyArg_ParseTuple (args, "s#|i:find", &needle, &len, &start)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000236 return NULL;
237 } else {
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000238 char *p = self->data+self->pos;
239 char *e = self->data+self->size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000240 while (p < e) {
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000241 char *s = p;
242 char *n = needle;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000243 while ((s<e) && (*n) && !(*s-*n)) {
244 s++, n++;
245 }
246 if (!*n) {
247 return Py_BuildValue (
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000248 "i",
249 (int) (p - (self->data + start)));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000250 }
251 p++;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000252 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000253 return Py_BuildValue ("l", (long) -1);
254 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000255}
256
257static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000258mmap_write_method(mmap_object *self,
259 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000260{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000261 long length;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000262 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000263
Guido van Rossum09fdf072000-03-31 01:17:07 +0000264 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000265 if (!PyArg_ParseTuple (args, "s#:write", &data, &length))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000266 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000267
Guido van Rossum09fdf072000-03-31 01:17:07 +0000268 if ((self->pos + length) > self->size) {
269 PyErr_SetString (PyExc_ValueError, "data out of range");
270 return NULL;
271 }
272 memcpy (self->data+self->pos, data, length);
273 self->pos = self->pos+length;
274 Py_INCREF (Py_None);
275 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000276}
277
278static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000279mmap_write_byte_method(mmap_object *self,
280 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000281{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000282 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000283
Guido van Rossum09fdf072000-03-31 01:17:07 +0000284 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000285 if (!PyArg_ParseTuple (args, "c:write_byte", &value))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000286 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000287
Guido van Rossum09fdf072000-03-31 01:17:07 +0000288 *(self->data+self->pos) = value;
289 self->pos += 1;
290 Py_INCREF (Py_None);
291 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000292}
293
294static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000295mmap_size_method(mmap_object *self,
296 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000297{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000298 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000299 if (!PyArg_ParseTuple(args, ":size"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000300 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000301
302#ifdef MS_WIN32
Mark Hammond071864a2000-07-30 02:46:26 +0000303 if (self->file_handle != INVALID_HANDLE_VALUE) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000304 return (Py_BuildValue (
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000305 "l", (long)
Mark Hammond071864a2000-07-30 02:46:26 +0000306 GetFileSize (self->file_handle, NULL)));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000307 } else {
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000308 return (Py_BuildValue ("l", (long) self->size) );
Guido van Rossum09fdf072000-03-31 01:17:07 +0000309 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000310#endif /* MS_WIN32 */
311
312#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000313 {
314 struct stat buf;
315 if (-1 == fstat(self->fd, &buf)) {
316 PyErr_SetFromErrno(mmap_module_error);
317 return NULL;
318 }
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000319 return (Py_BuildValue ("l", (long) buf.st_size) );
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000320 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000321#endif /* UNIX */
322}
323
324/* This assumes that you want the entire file mapped,
325 / and when recreating the map will make the new file
326 / have the new size
327 /
328 / Is this really necessary? This could easily be done
329 / from python by just closing and re-opening with the
330 / new size?
331 */
332
333static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000334mmap_resize_method(mmap_object *self,
335 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000336{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000337 unsigned long new_size;
338 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000339 if (!PyArg_ParseTuple (args, "l:resize", &new_size)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000340 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000341#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000342 } else {
343 DWORD dwErrCode = 0;
344 /* First, unmap the file view */
345 UnmapViewOfFile (self->data);
346 /* Close the mapping object */
Mark Hammond071864a2000-07-30 02:46:26 +0000347 CloseHandle (self->map_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000348 /* Move to the desired EOF position */
Mark Hammond071864a2000-07-30 02:46:26 +0000349 SetFilePointer (self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000350 new_size, NULL, FILE_BEGIN);
351 /* Change the size of the file */
Mark Hammond071864a2000-07-30 02:46:26 +0000352 SetEndOfFile (self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000353 /* Create another mapping object and remap the file view */
354 self->map_handle = CreateFileMapping (
Mark Hammond071864a2000-07-30 02:46:26 +0000355 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000356 NULL,
357 PAGE_READWRITE,
358 0,
359 new_size,
360 self->tagname);
361 if (self->map_handle != NULL) {
362 self->data = (char *) MapViewOfFile (self->map_handle,
363 FILE_MAP_WRITE,
364 0,
365 0,
366 0);
367 if (self->data != NULL) {
368 self->size = new_size;
369 Py_INCREF (Py_None);
370 return Py_None;
371 } else {
372 dwErrCode = GetLastError();
373 }
374 } else {
375 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000376 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000377 PyErr_SetFromWindowsErr(dwErrCode);
378 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000379#endif /* MS_WIN32 */
380
381#ifdef UNIX
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000382#ifndef HAVE_MREMAP
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000383} else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000384 PyErr_SetString(PyExc_SystemError,
385 "mmap: resizing not available--no mremap()");
386 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000387#else
388} else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000389 void *newmap;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000390
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000391#ifdef MREMAP_MAYMOVE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000392 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000393#else
394 newmap = mremap(self->data, self->size, new_size, 0);
395#endif
Guido van Rossum09fdf072000-03-31 01:17:07 +0000396 if (newmap == (void *)-1)
397 {
398 PyErr_SetFromErrno(mmap_module_error);
399 return NULL;
400 }
401 self->data = newmap;
402 self->size = new_size;
403 Py_INCREF(Py_None);
404 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000405#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000406#endif /* UNIX */
407}
408}
409
410static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000411mmap_tell_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000412{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000413 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000414 if (!PyArg_ParseTuple(args, ":tell"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000415 return NULL;
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000416 return (Py_BuildValue ("l", (long) self->pos) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000417}
418
419static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000420mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000421{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000422 size_t offset = 0;
423 size_t size = self->size;
424 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000425 if (!PyArg_ParseTuple (args, "|ll:flush", &offset, &size)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000426 return NULL;
427 } else if ((offset + size) > self->size) {
428 PyErr_SetString (PyExc_ValueError,
429 "flush values out of range");
430 return NULL;
431 } else {
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000432#ifdef MS_WIN32
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000433 return (Py_BuildValue("l", (long)
434 FlushViewOfFile(self->data+offset, size)));
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000435#endif /* MS_WIN32 */
436#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000437 /* XXX semantics of return value? */
438 /* XXX flags for msync? */
439 if (-1 == msync(self->data + offset, size,
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000440 MS_SYNC))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000441 {
442 PyErr_SetFromErrno(mmap_module_error);
443 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000444 }
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000445 return Py_BuildValue ("l", (long) 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000446#endif /* UNIX */
447 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000448}
449
450static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000451mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000452{
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000453 int dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000454 int how=0;
455 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000456 if (!PyArg_ParseTuple (args, "i|i:seek", &dist, &how)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000457 return(NULL);
458 } else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000459 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000460 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000461 case 0: /* relative to start */
462 if (dist < 0)
463 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000464 where = dist;
465 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000466 case 1: /* relative to current position */
467 if ((int)self->pos + dist < 0)
468 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000469 where = self->pos + dist;
470 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000471 case 2: /* relative to end */
472 if ((int)self->size + dist < 0)
473 goto onoutofrange;
474 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000475 break;
476 default:
477 PyErr_SetString (PyExc_ValueError,
478 "unknown seek type");
479 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000480 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000481 if (where > self->size)
482 goto onoutofrange;
483 self->pos = where;
484 Py_INCREF (Py_None);
485 return (Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000486 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000487
488onoutofrange:
489 PyErr_SetString (PyExc_ValueError, "seek out of range");
490 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000491}
492
493static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000494mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000495{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000496 unsigned long dest, src, count;
497 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000498 if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000499 return NULL;
500 } else {
501 /* bounds check the values */
502 if (/* end of source after end of data?? */
503 ((src+count) > self->size)
504 /* dest will fit? */
505 || (dest+count > self->size)) {
506 PyErr_SetString (PyExc_ValueError,
507 "source or destination out of range");
508 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000509 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000510 memmove (self->data+dest, self->data+src, count);
511 Py_INCREF (Py_None);
512 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000513 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000514 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000515}
516
517static struct PyMethodDef mmap_object_methods[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000518 {"close", (PyCFunction) mmap_close_method, 1},
519 {"find", (PyCFunction) mmap_find_method, 1},
520 {"flush", (PyCFunction) mmap_flush_method, 1},
521 {"move", (PyCFunction) mmap_move_method, 1},
522 {"read", (PyCFunction) mmap_read_method, 1},
523 {"read_byte", (PyCFunction) mmap_read_byte_method, 1},
524 {"readline", (PyCFunction) mmap_read_line_method, 1},
525 {"resize", (PyCFunction) mmap_resize_method, 1},
526 {"seek", (PyCFunction) mmap_seek_method, 1},
527 {"size", (PyCFunction) mmap_size_method, 1},
528 {"tell", (PyCFunction) mmap_tell_method, 1},
529 {"write", (PyCFunction) mmap_write_method, 1},
530 {"write_byte", (PyCFunction) mmap_write_byte_method, 1},
531 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000532};
533
534/* Functions for treating an mmap'ed file as a buffer */
535
536static int
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000537mmap_buffer_getreadbuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000538{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000539 CHECK_VALID(-1);
540 if ( index != 0 ) {
541 PyErr_SetString(PyExc_SystemError,
542 "Accessing non-existent mmap segment");
543 return -1;
544 }
545 *ptr = self->data;
546 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000547}
548
549static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000550mmap_buffer_getwritebuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000551{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000552 CHECK_VALID(-1);
553 if ( index != 0 ) {
554 PyErr_SetString(PyExc_SystemError,
555 "Accessing non-existent mmap segment");
556 return -1;
557 }
558 *ptr = self->data;
559 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000560}
561
562static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000563mmap_buffer_getsegcount(mmap_object *self, int *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000564{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000565 CHECK_VALID(-1);
566 if (lenp)
567 *lenp = self->size;
568 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000569}
570
571static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000572mmap_buffer_getcharbuffer(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000573{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000574 if ( index != 0 ) {
575 PyErr_SetString(PyExc_SystemError,
576 "accessing non-existent buffer segment");
577 return -1;
578 }
579 *ptr = (const char *)self->data;
580 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000581}
582
583static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000584mmap_object_getattr(mmap_object *self, char *name)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000585{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000586 return Py_FindMethod (mmap_object_methods, (PyObject *)self, name);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000587}
588
589static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000590mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000591{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000592 CHECK_VALID(-1);
593 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000594}
595
596static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000597mmap_item(mmap_object *self, int i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000598{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000599 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000600 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000601 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
602 return NULL;
603 }
604 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000605}
606
607static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000608mmap_slice(mmap_object *self, int ilow, int ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000609{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000610 CHECK_VALID(NULL);
611 if (ilow < 0)
612 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000613 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000614 ilow = self->size;
615 if (ihigh < 0)
616 ihigh = 0;
617 if (ihigh < ilow)
618 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000619 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000620 ihigh = self->size;
621
622 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000623}
624
625static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000626mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000627{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000628 CHECK_VALID(NULL);
629 PyErr_SetString(PyExc_SystemError,
630 "mmaps don't support concatenation");
631 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000632}
633
634static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000635mmap_repeat(mmap_object *self, int n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000636{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000637 CHECK_VALID(NULL);
638 PyErr_SetString(PyExc_SystemError,
639 "mmaps don't support repeat operation");
640 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000641}
642
643static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000644mmap_ass_slice(mmap_object *self, int ilow, int ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000645{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000646 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000647
Guido van Rossum09fdf072000-03-31 01:17:07 +0000648 CHECK_VALID(-1);
649 if (ilow < 0)
650 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000651 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000652 ilow = self->size;
653 if (ihigh < 0)
654 ihigh = 0;
655 if (ihigh < ilow)
656 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000657 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000658 ihigh = self->size;
659
660 if (! (PyString_Check(v)) ) {
661 PyErr_SetString(PyExc_IndexError,
662 "mmap slice assignment must be a string");
663 return -1;
664 }
665 if ( PyString_Size(v) != (ihigh - ilow) ) {
666 PyErr_SetString(PyExc_IndexError,
667 "mmap slice assignment is wrong size");
668 return -1;
669 }
670 buf = PyString_AsString(v);
671 memcpy(self->data + ilow, buf, ihigh-ilow);
672 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000673}
674
675static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000676mmap_ass_item(mmap_object *self, int i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000677{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000678 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000679
Guido van Rossum09fdf072000-03-31 01:17:07 +0000680 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000681 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000682 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
683 return -1;
684 }
685 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
686 PyErr_SetString(PyExc_IndexError,
687 "mmap assignment must be single-character string");
688 return -1;
689 }
690 buf = PyString_AsString(v);
691 self->data[i] = buf[0];
692 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000693}
694
695static PySequenceMethods mmap_as_sequence = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000696 (inquiry)mmap_length, /*sq_length*/
697 (binaryfunc)mmap_concat, /*sq_concat*/
698 (intargfunc)mmap_repeat, /*sq_repeat*/
699 (intargfunc)mmap_item, /*sq_item*/
700 (intintargfunc)mmap_slice, /*sq_slice*/
701 (intobjargproc)mmap_ass_item, /*sq_ass_item*/
702 (intintobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000703};
704
705static PyBufferProcs mmap_as_buffer = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000706 (getreadbufferproc)mmap_buffer_getreadbuf,
707 (getwritebufferproc)mmap_buffer_getwritebuf,
708 (getsegcountproc)mmap_buffer_getsegcount,
709 (getcharbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000710};
711
712static PyTypeObject mmap_object_type = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000713 PyObject_HEAD_INIT(0) /* patched in module init */
714 0, /* ob_size */
715 "mmap", /* tp_name */
716 sizeof(mmap_object), /* tp_size */
717 0, /* tp_itemsize */
718 /* methods */
719 (destructor) mmap_object_dealloc, /* tp_dealloc */
720 0, /* tp_print */
721 (getattrfunc) mmap_object_getattr, /* tp_getattr */
722 0, /* tp_setattr */
723 0, /* tp_compare */
724 0, /* tp_repr */
725 0, /* tp_as_number */
726 &mmap_as_sequence, /*tp_as_sequence*/
727 0, /*tp_as_mapping*/
728 0, /*tp_hash*/
729 0, /*tp_call*/
730 0, /*tp_str*/
731 0, /*tp_getattro*/
732 0, /*tp_setattro*/
733 &mmap_as_buffer, /*tp_as_buffer*/
734 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
735 0, /*tp_doc*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000736};
737
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000738
739/* extract the map size from the given PyObject
740
741 The map size is restricted to [0, INT_MAX] because this is the current
742 Python limitation on object sizes. Although the mmap object *could* handle
743 a larger map size, there is no point because all the useful operations
744 (len(), slicing(), sequence indexing) are limited by a C int.
745
Thomas Wouters7e474022000-07-16 12:04:32 +0000746 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000747 success, the map size is returned. */
748static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000749_GetMapSize(PyObject *o)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000750{
751 if (PyInt_Check(o)) {
752 long i = PyInt_AsLong(o);
753 if (PyErr_Occurred())
754 return -1;
755 if (i < 0)
756 goto onnegoverflow;
757 if (i > INT_MAX)
758 goto onposoverflow;
759 return (int)i;
760 }
761 else if (PyLong_Check(o)) {
762 long i = PyLong_AsLong(o);
763 if (PyErr_Occurred()) {
764 /* yes negative overflow is mistaken for positive overflow
765 but not worth the trouble to check sign of 'i' */
766 if (PyErr_ExceptionMatches(PyExc_OverflowError))
767 goto onposoverflow;
768 else
769 return -1;
770 }
771 if (i < 0)
772 goto onnegoverflow;
773 if (i > INT_MAX)
774 goto onposoverflow;
775 return (int)i;
776 }
777 else {
778 PyErr_SetString(PyExc_TypeError,
779 "map size must be an integral value");
780 return -1;
781 }
782
783onnegoverflow:
784 PyErr_SetString(PyExc_OverflowError,
785 "memory mapped size must be positive");
786 return -1;
787
788onposoverflow:
789 PyErr_SetString(PyExc_OverflowError,
790 "memory mapped size is too large (limited by C int)");
791 return -1;
792}
793
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000794#ifdef UNIX
795static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000796new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000797{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000798 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000799 PyObject *map_size_obj = NULL;
800 int map_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000801 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000802 char *keywords[] = {"file", "size", "flags", "prot", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000803
Guido van Rossum09fdf072000-03-31 01:17:07 +0000804 if (!PyArg_ParseTupleAndKeywords(args, kwdict,
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000805 "iO|ii", keywords,
806 &fd, &map_size_obj, &flags, &prot)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000807 )
808 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000809 map_size = _GetMapSize(map_size_obj);
810 if (map_size < 0)
811 return NULL;
812
Guido van Rossumb18618d2000-05-03 23:44:39 +0000813 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000814 if (m_obj == NULL) {return NULL;}
815 m_obj->size = (size_t) map_size;
816 m_obj->pos = (size_t) 0;
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000817 m_obj->fd = fd;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000818 m_obj->data = mmap(NULL, map_size,
819 prot, flags,
820 fd, 0);
821 if (m_obj->data == (void *)-1)
822 {
823 Py_DECREF(m_obj);
824 PyErr_SetFromErrno(mmap_module_error);
825 return NULL;
826 }
827 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000828}
829#endif /* UNIX */
830
831#ifdef MS_WIN32
832static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000833new_mmap_object(PyObject *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000834{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000835 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000836 PyObject *map_size_obj = NULL;
837 int map_size;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000838 char *tagname = "";
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000839
Guido van Rossum09fdf072000-03-31 01:17:07 +0000840 DWORD dwErr = 0;
841 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +0000842 HANDLE fh = 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000843
Guido van Rossum09fdf072000-03-31 01:17:07 +0000844 if (!PyArg_ParseTuple(args,
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000845 "iO|z",
Guido van Rossum09fdf072000-03-31 01:17:07 +0000846 &fileno,
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000847 &map_size_obj,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000848 &tagname)
849 )
850 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000851
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000852 map_size = _GetMapSize(map_size_obj);
853 if (map_size < 0)
854 return NULL;
855
Guido van Rossum09fdf072000-03-31 01:17:07 +0000856 /* if an actual filename has been specified */
857 if (fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +0000858 fh = (HANDLE)_get_osfhandle(fileno);
859 if (fh==(HANDLE)-1) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000860 PyErr_SetFromErrno(mmap_module_error);
861 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000862 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +0000863 /* Win9x appears to need us seeked to zero */
864 fseek(&_iob[fileno], 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000865 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000866
Guido van Rossumb18618d2000-05-03 23:44:39 +0000867 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Mark Hammond2cbed002000-07-30 02:22:43 +0000868 if (m_obj==NULL)
869 return NULL;
870 /* Set every field to an invalid marker, so we can safely
871 destruct the object in the face of failure */
872 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +0000873 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +0000874 m_obj->map_handle = INVALID_HANDLE_VALUE;
875 m_obj->tagname = NULL;
876
Guido van Rossum09fdf072000-03-31 01:17:07 +0000877 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +0000878 /* It is necessary to duplicate the handle, so the
879 Python code can close it on us */
880 if (!DuplicateHandle(
881 GetCurrentProcess(), /* source process handle */
Mark Hammond071864a2000-07-30 02:46:26 +0000882 fh, /* handle to be duplicated */
Mark Hammond2cbed002000-07-30 02:22:43 +0000883 GetCurrentProcess(), /* target proc handle */
884 (LPHANDLE)&m_obj->file_handle, /* result */
885 0, /* access - ignored due to options value */
886 FALSE, /* inherited by child processes? */
887 DUPLICATE_SAME_ACCESS)) { /* options */
888 dwErr = GetLastError();
889 Py_DECREF(m_obj);
890 PyErr_SetFromWindowsErr(dwErr);
891 return NULL;
892 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000893 if (!map_size) {
Mark Hammond071864a2000-07-30 02:46:26 +0000894 m_obj->size = GetFileSize (fh, NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000895 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000896 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000897 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000898 }
899 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000900 m_obj->size = map_size;
901 }
902
903 /* set the initial position */
904 m_obj->pos = (size_t) 0;
905
Mark Hammond2cbed002000-07-30 02:22:43 +0000906 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +0000907 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +0000908 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
909 if (m_obj->tagname == NULL) {
910 PyErr_NoMemory();
911 Py_DECREF(m_obj);
912 return NULL;
913 }
914 strcpy(m_obj->tagname, tagname);
915 }
916 else
917 m_obj->tagname = NULL;
918
Mark Hammond071864a2000-07-30 02:46:26 +0000919 m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000920 NULL,
921 PAGE_READWRITE,
922 0,
923 m_obj->size,
Tim Peters0d9f9dc2001-01-10 05:42:18 +0000924 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000925 if (m_obj->map_handle != NULL) {
926 m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
927 FILE_MAP_WRITE,
928 0,
929 0,
930 0);
931 if (m_obj->data != NULL) {
932 return ((PyObject *) m_obj);
933 } else {
934 dwErr = GetLastError();
935 }
936 } else {
937 dwErr = GetLastError();
938 }
Mark Hammond2cbed002000-07-30 02:22:43 +0000939 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000940 PyErr_SetFromWindowsErr(dwErr);
941 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000942}
943#endif /* MS_WIN32 */
944
945/* List of functions exported by this module */
946static struct PyMethodDef mmap_functions[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000947 {"mmap", (PyCFunction) new_mmap_object,
948 METH_VARARGS|METH_KEYWORDS},
949 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000950};
951
Guido van Rossum5a530192001-01-10 21:03:32 +0000952DL_EXPORT(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000953initmmap(void)
954{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000955 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +0000956
957 /* Patch the object type */
958 mmap_object_type.ob_type = &PyType_Type;
959
Guido van Rossum09fdf072000-03-31 01:17:07 +0000960 module = Py_InitModule ("mmap", mmap_functions);
961 dict = PyModule_GetDict (module);
962 mmap_module_error = PyExc_EnvironmentError;
963 Py_INCREF(mmap_module_error);
964 PyDict_SetItemString (dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000965#ifdef PROT_EXEC
Guido van Rossum09fdf072000-03-31 01:17:07 +0000966 PyDict_SetItemString (dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000967#endif
968#ifdef PROT_READ
Guido van Rossum09fdf072000-03-31 01:17:07 +0000969 PyDict_SetItemString (dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000970#endif
971#ifdef PROT_WRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000972 PyDict_SetItemString (dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000973#endif
974
975#ifdef MAP_SHARED
Guido van Rossum09fdf072000-03-31 01:17:07 +0000976 PyDict_SetItemString (dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000977#endif
978#ifdef MAP_PRIVATE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000979 PyDict_SetItemString (dict, "MAP_PRIVATE",
980 PyInt_FromLong(MAP_PRIVATE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000981#endif
982#ifdef MAP_DENYWRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000983 PyDict_SetItemString (dict, "MAP_DENYWRITE",
984 PyInt_FromLong(MAP_DENYWRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000985#endif
986#ifdef MAP_EXECUTABLE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000987 PyDict_SetItemString (dict, "MAP_EXECUTABLE",
988 PyInt_FromLong(MAP_EXECUTABLE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000989#endif
990#ifdef MAP_ANON
Guido van Rossum09fdf072000-03-31 01:17:07 +0000991 PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
992 PyDict_SetItemString (dict, "MAP_ANONYMOUS",
993 PyInt_FromLong(MAP_ANON) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000994#endif
995
Guido van Rossum09fdf072000-03-31 01:17:07 +0000996 PyDict_SetItemString (dict, "PAGESIZE",
Fred Drake145f96e2000-10-01 17:50:46 +0000997 PyInt_FromLong( (long)my_getpagesize() ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000998}
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000999