blob: d5bc89f309d55842a73714b6c4d729dafdd3859d [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 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000167 if (!PyArg_ParseTuple(args, ":read_byte"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000168 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000169 if (self->pos < self->size) {
Tim Petersd6283b82001-05-09 18:48:26 +0000170 char value = self->data[self->pos];
Guido van Rossum09fdf072000-03-31 01:17:07 +0000171 self->pos += 1;
Tim Petersd6283b82001-05-09 18:48:26 +0000172 return Py_BuildValue("c", value);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000173 } else {
174 PyErr_SetString (PyExc_ValueError, "read byte out of range");
175 return NULL;
176 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000177}
178
179static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000180mmap_read_line_method(mmap_object *self,
181 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000182{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000183 char *start = self->data+self->pos;
184 char *eof = self->data+self->size;
185 char *eol;
186 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000187
Guido van Rossum09fdf072000-03-31 01:17:07 +0000188 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000189 if (!PyArg_ParseTuple(args, ":readline"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000190 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000191
Fred Drake56a87a02000-04-04 18:17:35 +0000192 eol = memchr(start, '\n', self->size - self->pos);
193 if (!eol)
194 eol = eof;
195 else
196 ++eol; /* we're interested in the position after the
197 newline. */
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000198 result = PyString_FromStringAndSize(start, (eol - start));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000199 self->pos += (eol - start);
200 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000201}
202
203static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000204mmap_read_method(mmap_object *self,
205 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000206{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000207 long num_bytes;
208 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000209
Guido van Rossum09fdf072000-03-31 01:17:07 +0000210 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000211 if (!PyArg_ParseTuple(args, "l:read", &num_bytes))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000212 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000213
Guido van Rossum09fdf072000-03-31 01:17:07 +0000214 /* silently 'adjust' out-of-range requests */
215 if ((self->pos + num_bytes) > self->size) {
216 num_bytes -= (self->pos+num_bytes) - self->size;
217 }
218 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
219 self->pos += num_bytes;
220 return (result);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000221}
222
223static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000224mmap_find_method(mmap_object *self,
225 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000226{
Tim Petersd401edd2001-05-14 23:19:12 +0000227 long start = self->pos;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000228 char *needle;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000229 int len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000230
Guido van Rossum09fdf072000-03-31 01:17:07 +0000231 CHECK_VALID(NULL);
Tim Petersd401edd2001-05-14 23:19:12 +0000232 if (!PyArg_ParseTuple (args, "s#|l:find", &needle, &len, &start)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000233 return NULL;
234 } else {
Greg Stein834f4dd2001-05-14 09:32:26 +0000235 char *p;
236 char *e = self->data + self->size;
237
238 if (start < 0)
239 start += self->size;
240 if (start < 0)
241 start = 0;
Tim Petersd401edd2001-05-14 23:19:12 +0000242 else if ((size_t)start > self->size)
Greg Stein834f4dd2001-05-14 09:32:26 +0000243 start = self->size;
244 p = self->data + start;
245
Guido van Rossum09fdf072000-03-31 01:17:07 +0000246 while (p < e) {
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000247 char *s = p;
248 char *n = needle;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000249 while ((s<e) && (*n) && !(*s-*n)) {
250 s++, n++;
251 }
252 if (!*n) {
253 return Py_BuildValue (
Tim Petersd401edd2001-05-14 23:19:12 +0000254 "l",
255 (long) (p - self->data));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000256 }
257 p++;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000258 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000259 return Py_BuildValue ("l", (long) -1);
260 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000261}
262
263static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000264mmap_write_method(mmap_object *self,
265 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000266{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000267 long length;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000268 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000269
Guido van Rossum09fdf072000-03-31 01:17:07 +0000270 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000271 if (!PyArg_ParseTuple (args, "s#:write", &data, &length))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000272 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000273
Guido van Rossum09fdf072000-03-31 01:17:07 +0000274 if ((self->pos + length) > self->size) {
275 PyErr_SetString (PyExc_ValueError, "data out of range");
276 return NULL;
277 }
278 memcpy (self->data+self->pos, data, length);
279 self->pos = self->pos+length;
280 Py_INCREF (Py_None);
281 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000282}
283
284static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000285mmap_write_byte_method(mmap_object *self,
286 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000287{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000288 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000289
Guido van Rossum09fdf072000-03-31 01:17:07 +0000290 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000291 if (!PyArg_ParseTuple (args, "c:write_byte", &value))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000292 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000293
Guido van Rossum09fdf072000-03-31 01:17:07 +0000294 *(self->data+self->pos) = value;
295 self->pos += 1;
296 Py_INCREF (Py_None);
297 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000298}
299
300static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000301mmap_size_method(mmap_object *self,
302 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000303{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000304 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000305 if (!PyArg_ParseTuple(args, ":size"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000306 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000307
308#ifdef MS_WIN32
Mark Hammond071864a2000-07-30 02:46:26 +0000309 if (self->file_handle != INVALID_HANDLE_VALUE) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000310 return (Py_BuildValue (
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000311 "l", (long)
Mark Hammond071864a2000-07-30 02:46:26 +0000312 GetFileSize (self->file_handle, NULL)));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000313 } else {
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000314 return (Py_BuildValue ("l", (long) self->size) );
Guido van Rossum09fdf072000-03-31 01:17:07 +0000315 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000316#endif /* MS_WIN32 */
317
318#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000319 {
320 struct stat buf;
321 if (-1 == fstat(self->fd, &buf)) {
322 PyErr_SetFromErrno(mmap_module_error);
323 return NULL;
324 }
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000325 return (Py_BuildValue ("l", (long) buf.st_size) );
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000326 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000327#endif /* UNIX */
328}
329
330/* This assumes that you want the entire file mapped,
331 / and when recreating the map will make the new file
332 / have the new size
333 /
334 / Is this really necessary? This could easily be done
335 / from python by just closing and re-opening with the
336 / new size?
337 */
338
339static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000340mmap_resize_method(mmap_object *self,
341 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000342{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000343 unsigned long new_size;
344 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000345 if (!PyArg_ParseTuple (args, "l:resize", &new_size)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000346 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000347#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000348 } else {
349 DWORD dwErrCode = 0;
350 /* First, unmap the file view */
351 UnmapViewOfFile (self->data);
352 /* Close the mapping object */
Mark Hammond071864a2000-07-30 02:46:26 +0000353 CloseHandle (self->map_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000354 /* Move to the desired EOF position */
Mark Hammond071864a2000-07-30 02:46:26 +0000355 SetFilePointer (self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000356 new_size, NULL, FILE_BEGIN);
357 /* Change the size of the file */
Mark Hammond071864a2000-07-30 02:46:26 +0000358 SetEndOfFile (self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000359 /* Create another mapping object and remap the file view */
360 self->map_handle = CreateFileMapping (
Mark Hammond071864a2000-07-30 02:46:26 +0000361 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000362 NULL,
363 PAGE_READWRITE,
364 0,
365 new_size,
366 self->tagname);
367 if (self->map_handle != NULL) {
368 self->data = (char *) MapViewOfFile (self->map_handle,
369 FILE_MAP_WRITE,
370 0,
371 0,
372 0);
373 if (self->data != NULL) {
374 self->size = new_size;
375 Py_INCREF (Py_None);
376 return Py_None;
377 } else {
378 dwErrCode = GetLastError();
379 }
380 } else {
381 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000382 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000383 PyErr_SetFromWindowsErr(dwErrCode);
384 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000385#endif /* MS_WIN32 */
386
387#ifdef UNIX
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000388#ifndef HAVE_MREMAP
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000389} else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000390 PyErr_SetString(PyExc_SystemError,
391 "mmap: resizing not available--no mremap()");
392 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000393#else
394} else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000395 void *newmap;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000396
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000397#ifdef MREMAP_MAYMOVE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000398 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000399#else
400 newmap = mremap(self->data, self->size, new_size, 0);
401#endif
Guido van Rossum09fdf072000-03-31 01:17:07 +0000402 if (newmap == (void *)-1)
403 {
404 PyErr_SetFromErrno(mmap_module_error);
405 return NULL;
406 }
407 self->data = newmap;
408 self->size = new_size;
409 Py_INCREF(Py_None);
410 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000411#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000412#endif /* UNIX */
413}
414}
415
416static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000417mmap_tell_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000418{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000419 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000420 if (!PyArg_ParseTuple(args, ":tell"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000421 return NULL;
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000422 return (Py_BuildValue ("l", (long) self->pos) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000423}
424
425static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000426mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000427{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000428 size_t offset = 0;
429 size_t size = self->size;
430 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000431 if (!PyArg_ParseTuple (args, "|ll:flush", &offset, &size)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000432 return NULL;
433 } else if ((offset + size) > self->size) {
434 PyErr_SetString (PyExc_ValueError,
435 "flush values out of range");
436 return NULL;
437 } else {
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000438#ifdef MS_WIN32
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000439 return (Py_BuildValue("l", (long)
440 FlushViewOfFile(self->data+offset, size)));
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000441#endif /* MS_WIN32 */
442#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000443 /* XXX semantics of return value? */
444 /* XXX flags for msync? */
445 if (-1 == msync(self->data + offset, size,
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000446 MS_SYNC))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000447 {
448 PyErr_SetFromErrno(mmap_module_error);
449 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000450 }
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000451 return Py_BuildValue ("l", (long) 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000452#endif /* UNIX */
453 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000454}
455
456static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000457mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000458{
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000459 int dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000460 int how=0;
461 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000462 if (!PyArg_ParseTuple (args, "i|i:seek", &dist, &how)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000463 return(NULL);
464 } else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000465 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000466 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000467 case 0: /* relative to start */
468 if (dist < 0)
469 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000470 where = dist;
471 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000472 case 1: /* relative to current position */
473 if ((int)self->pos + dist < 0)
474 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000475 where = self->pos + dist;
476 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000477 case 2: /* relative to end */
478 if ((int)self->size + dist < 0)
479 goto onoutofrange;
480 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000481 break;
482 default:
483 PyErr_SetString (PyExc_ValueError,
484 "unknown seek type");
485 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000486 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000487 if (where > self->size)
488 goto onoutofrange;
489 self->pos = where;
490 Py_INCREF (Py_None);
491 return (Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000492 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000493
494onoutofrange:
495 PyErr_SetString (PyExc_ValueError, "seek out of range");
496 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000497}
498
499static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000500mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000501{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000502 unsigned long dest, src, count;
503 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000504 if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000505 return NULL;
506 } else {
507 /* bounds check the values */
508 if (/* end of source after end of data?? */
509 ((src+count) > self->size)
510 /* dest will fit? */
511 || (dest+count > self->size)) {
512 PyErr_SetString (PyExc_ValueError,
513 "source or destination out of range");
514 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000515 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000516 memmove (self->data+dest, self->data+src, count);
517 Py_INCREF (Py_None);
518 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000519 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000520 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000521}
522
523static struct PyMethodDef mmap_object_methods[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000524 {"close", (PyCFunction) mmap_close_method, 1},
525 {"find", (PyCFunction) mmap_find_method, 1},
526 {"flush", (PyCFunction) mmap_flush_method, 1},
527 {"move", (PyCFunction) mmap_move_method, 1},
528 {"read", (PyCFunction) mmap_read_method, 1},
529 {"read_byte", (PyCFunction) mmap_read_byte_method, 1},
530 {"readline", (PyCFunction) mmap_read_line_method, 1},
531 {"resize", (PyCFunction) mmap_resize_method, 1},
532 {"seek", (PyCFunction) mmap_seek_method, 1},
533 {"size", (PyCFunction) mmap_size_method, 1},
534 {"tell", (PyCFunction) mmap_tell_method, 1},
535 {"write", (PyCFunction) mmap_write_method, 1},
536 {"write_byte", (PyCFunction) mmap_write_byte_method, 1},
537 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000538};
539
540/* Functions for treating an mmap'ed file as a buffer */
541
542static int
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000543mmap_buffer_getreadbuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000544{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000545 CHECK_VALID(-1);
546 if ( index != 0 ) {
547 PyErr_SetString(PyExc_SystemError,
548 "Accessing non-existent mmap segment");
549 return -1;
550 }
551 *ptr = self->data;
552 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000553}
554
555static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000556mmap_buffer_getwritebuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000557{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000558 CHECK_VALID(-1);
559 if ( index != 0 ) {
560 PyErr_SetString(PyExc_SystemError,
561 "Accessing non-existent mmap segment");
562 return -1;
563 }
564 *ptr = self->data;
565 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000566}
567
568static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000569mmap_buffer_getsegcount(mmap_object *self, int *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000570{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000571 CHECK_VALID(-1);
572 if (lenp)
573 *lenp = self->size;
574 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000575}
576
577static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000578mmap_buffer_getcharbuffer(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000579{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000580 if ( index != 0 ) {
581 PyErr_SetString(PyExc_SystemError,
582 "accessing non-existent buffer segment");
583 return -1;
584 }
585 *ptr = (const char *)self->data;
586 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000587}
588
589static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000590mmap_object_getattr(mmap_object *self, char *name)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000591{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000592 return Py_FindMethod (mmap_object_methods, (PyObject *)self, name);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000593}
594
595static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000596mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000597{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000598 CHECK_VALID(-1);
599 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000600}
601
602static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000603mmap_item(mmap_object *self, int i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000604{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000605 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000606 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000607 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
608 return NULL;
609 }
610 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000611}
612
613static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000614mmap_slice(mmap_object *self, int ilow, int ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000615{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000616 CHECK_VALID(NULL);
617 if (ilow < 0)
618 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000619 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000620 ilow = self->size;
621 if (ihigh < 0)
622 ihigh = 0;
623 if (ihigh < ilow)
624 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000625 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000626 ihigh = self->size;
627
628 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000629}
630
631static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000632mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000633{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000634 CHECK_VALID(NULL);
635 PyErr_SetString(PyExc_SystemError,
636 "mmaps don't support concatenation");
637 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000638}
639
640static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000641mmap_repeat(mmap_object *self, int n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000642{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000643 CHECK_VALID(NULL);
644 PyErr_SetString(PyExc_SystemError,
645 "mmaps don't support repeat operation");
646 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000647}
648
649static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000650mmap_ass_slice(mmap_object *self, int ilow, int ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000651{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000652 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000653
Guido van Rossum09fdf072000-03-31 01:17:07 +0000654 CHECK_VALID(-1);
655 if (ilow < 0)
656 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000657 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000658 ilow = self->size;
659 if (ihigh < 0)
660 ihigh = 0;
661 if (ihigh < ilow)
662 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000663 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000664 ihigh = self->size;
665
Thomas Wouters1baac722001-07-16 15:47:36 +0000666 if (v == NULL) {
667 PyErr_SetString(PyExc_TypeError,
668 "mmap object doesn't support slice deletion");
669 return -1;
670 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000671 if (! (PyString_Check(v)) ) {
672 PyErr_SetString(PyExc_IndexError,
673 "mmap slice assignment must be a string");
674 return -1;
675 }
676 if ( PyString_Size(v) != (ihigh - ilow) ) {
677 PyErr_SetString(PyExc_IndexError,
678 "mmap slice assignment is wrong size");
679 return -1;
680 }
681 buf = PyString_AsString(v);
682 memcpy(self->data + ilow, buf, ihigh-ilow);
683 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000684}
685
686static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000687mmap_ass_item(mmap_object *self, int i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000688{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000689 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000690
Guido van Rossum09fdf072000-03-31 01:17:07 +0000691 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000692 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000693 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
694 return -1;
695 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000696 if (v == NULL) {
697 PyErr_SetString(PyExc_TypeError,
698 "mmap object doesn't support item deletion");
699 return -1;
700 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000701 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
702 PyErr_SetString(PyExc_IndexError,
703 "mmap assignment must be single-character string");
704 return -1;
705 }
706 buf = PyString_AsString(v);
707 self->data[i] = buf[0];
708 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000709}
710
711static PySequenceMethods mmap_as_sequence = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000712 (inquiry)mmap_length, /*sq_length*/
713 (binaryfunc)mmap_concat, /*sq_concat*/
714 (intargfunc)mmap_repeat, /*sq_repeat*/
715 (intargfunc)mmap_item, /*sq_item*/
716 (intintargfunc)mmap_slice, /*sq_slice*/
717 (intobjargproc)mmap_ass_item, /*sq_ass_item*/
718 (intintobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000719};
720
721static PyBufferProcs mmap_as_buffer = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000722 (getreadbufferproc)mmap_buffer_getreadbuf,
723 (getwritebufferproc)mmap_buffer_getwritebuf,
724 (getsegcountproc)mmap_buffer_getsegcount,
725 (getcharbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000726};
727
728static PyTypeObject mmap_object_type = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000729 PyObject_HEAD_INIT(0) /* patched in module init */
730 0, /* ob_size */
731 "mmap", /* tp_name */
732 sizeof(mmap_object), /* tp_size */
733 0, /* tp_itemsize */
734 /* methods */
735 (destructor) mmap_object_dealloc, /* tp_dealloc */
736 0, /* tp_print */
737 (getattrfunc) mmap_object_getattr, /* tp_getattr */
738 0, /* tp_setattr */
739 0, /* tp_compare */
740 0, /* tp_repr */
741 0, /* tp_as_number */
742 &mmap_as_sequence, /*tp_as_sequence*/
743 0, /*tp_as_mapping*/
744 0, /*tp_hash*/
745 0, /*tp_call*/
746 0, /*tp_str*/
747 0, /*tp_getattro*/
748 0, /*tp_setattro*/
749 &mmap_as_buffer, /*tp_as_buffer*/
750 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
751 0, /*tp_doc*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000752};
753
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000754
755/* extract the map size from the given PyObject
756
757 The map size is restricted to [0, INT_MAX] because this is the current
758 Python limitation on object sizes. Although the mmap object *could* handle
759 a larger map size, there is no point because all the useful operations
760 (len(), slicing(), sequence indexing) are limited by a C int.
761
Thomas Wouters7e474022000-07-16 12:04:32 +0000762 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000763 success, the map size is returned. */
764static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000765_GetMapSize(PyObject *o)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000766{
767 if (PyInt_Check(o)) {
768 long i = PyInt_AsLong(o);
769 if (PyErr_Occurred())
770 return -1;
771 if (i < 0)
772 goto onnegoverflow;
773 if (i > INT_MAX)
774 goto onposoverflow;
775 return (int)i;
776 }
777 else if (PyLong_Check(o)) {
778 long i = PyLong_AsLong(o);
779 if (PyErr_Occurred()) {
780 /* yes negative overflow is mistaken for positive overflow
781 but not worth the trouble to check sign of 'i' */
782 if (PyErr_ExceptionMatches(PyExc_OverflowError))
783 goto onposoverflow;
784 else
785 return -1;
786 }
787 if (i < 0)
788 goto onnegoverflow;
789 if (i > INT_MAX)
790 goto onposoverflow;
791 return (int)i;
792 }
793 else {
794 PyErr_SetString(PyExc_TypeError,
795 "map size must be an integral value");
796 return -1;
797 }
798
799onnegoverflow:
800 PyErr_SetString(PyExc_OverflowError,
801 "memory mapped size must be positive");
802 return -1;
803
804onposoverflow:
805 PyErr_SetString(PyExc_OverflowError,
806 "memory mapped size is too large (limited by C int)");
807 return -1;
808}
809
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000810#ifdef UNIX
811static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000812new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000813{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000814 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000815 PyObject *map_size_obj = NULL;
816 int map_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000817 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000818 char *keywords[] = {"file", "size", "flags", "prot", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000819
Guido van Rossum09fdf072000-03-31 01:17:07 +0000820 if (!PyArg_ParseTupleAndKeywords(args, kwdict,
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000821 "iO|ii", keywords,
822 &fd, &map_size_obj, &flags, &prot)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000823 )
824 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000825 map_size = _GetMapSize(map_size_obj);
826 if (map_size < 0)
827 return NULL;
828
Guido van Rossumb18618d2000-05-03 23:44:39 +0000829 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000830 if (m_obj == NULL) {return NULL;}
831 m_obj->size = (size_t) map_size;
832 m_obj->pos = (size_t) 0;
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000833 m_obj->fd = fd;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000834 m_obj->data = mmap(NULL, map_size,
835 prot, flags,
836 fd, 0);
Tim Peterscf96de02001-04-21 02:46:11 +0000837 if (m_obj->data == (char *)-1)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000838 {
839 Py_DECREF(m_obj);
840 PyErr_SetFromErrno(mmap_module_error);
841 return NULL;
842 }
843 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000844}
845#endif /* UNIX */
846
847#ifdef MS_WIN32
848static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000849new_mmap_object(PyObject *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000850{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000851 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000852 PyObject *map_size_obj = NULL;
853 int map_size;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000854 char *tagname = "";
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000855
Guido van Rossum09fdf072000-03-31 01:17:07 +0000856 DWORD dwErr = 0;
857 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +0000858 HANDLE fh = 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000859
Guido van Rossum09fdf072000-03-31 01:17:07 +0000860 if (!PyArg_ParseTuple(args,
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000861 "iO|z",
Guido van Rossum09fdf072000-03-31 01:17:07 +0000862 &fileno,
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000863 &map_size_obj,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000864 &tagname)
865 )
866 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000867
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000868 map_size = _GetMapSize(map_size_obj);
869 if (map_size < 0)
870 return NULL;
871
Guido van Rossum09fdf072000-03-31 01:17:07 +0000872 /* if an actual filename has been specified */
873 if (fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +0000874 fh = (HANDLE)_get_osfhandle(fileno);
875 if (fh==(HANDLE)-1) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000876 PyErr_SetFromErrno(mmap_module_error);
877 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000878 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +0000879 /* Win9x appears to need us seeked to zero */
880 fseek(&_iob[fileno], 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000881 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000882
Guido van Rossumb18618d2000-05-03 23:44:39 +0000883 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Mark Hammond2cbed002000-07-30 02:22:43 +0000884 if (m_obj==NULL)
885 return NULL;
886 /* Set every field to an invalid marker, so we can safely
887 destruct the object in the face of failure */
888 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +0000889 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +0000890 m_obj->map_handle = INVALID_HANDLE_VALUE;
891 m_obj->tagname = NULL;
892
Guido van Rossum09fdf072000-03-31 01:17:07 +0000893 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +0000894 /* It is necessary to duplicate the handle, so the
895 Python code can close it on us */
896 if (!DuplicateHandle(
897 GetCurrentProcess(), /* source process handle */
Mark Hammond071864a2000-07-30 02:46:26 +0000898 fh, /* handle to be duplicated */
Mark Hammond2cbed002000-07-30 02:22:43 +0000899 GetCurrentProcess(), /* target proc handle */
900 (LPHANDLE)&m_obj->file_handle, /* result */
901 0, /* access - ignored due to options value */
902 FALSE, /* inherited by child processes? */
903 DUPLICATE_SAME_ACCESS)) { /* options */
904 dwErr = GetLastError();
905 Py_DECREF(m_obj);
906 PyErr_SetFromWindowsErr(dwErr);
907 return NULL;
908 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000909 if (!map_size) {
Mark Hammond071864a2000-07-30 02:46:26 +0000910 m_obj->size = GetFileSize (fh, NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000911 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000912 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000913 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000914 }
915 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000916 m_obj->size = map_size;
917 }
918
919 /* set the initial position */
920 m_obj->pos = (size_t) 0;
921
Mark Hammond2cbed002000-07-30 02:22:43 +0000922 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +0000923 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +0000924 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
925 if (m_obj->tagname == NULL) {
926 PyErr_NoMemory();
927 Py_DECREF(m_obj);
928 return NULL;
929 }
930 strcpy(m_obj->tagname, tagname);
931 }
932 else
933 m_obj->tagname = NULL;
934
Mark Hammond071864a2000-07-30 02:46:26 +0000935 m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000936 NULL,
937 PAGE_READWRITE,
938 0,
939 m_obj->size,
Tim Peters0d9f9dc2001-01-10 05:42:18 +0000940 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000941 if (m_obj->map_handle != NULL) {
942 m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
943 FILE_MAP_WRITE,
944 0,
945 0,
946 0);
947 if (m_obj->data != NULL) {
948 return ((PyObject *) m_obj);
949 } else {
950 dwErr = GetLastError();
951 }
952 } else {
953 dwErr = GetLastError();
954 }
Mark Hammond2cbed002000-07-30 02:22:43 +0000955 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000956 PyErr_SetFromWindowsErr(dwErr);
957 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000958}
959#endif /* MS_WIN32 */
960
961/* List of functions exported by this module */
962static struct PyMethodDef mmap_functions[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000963 {"mmap", (PyCFunction) new_mmap_object,
964 METH_VARARGS|METH_KEYWORDS},
965 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000966};
967
Guido van Rossum5a530192001-01-10 21:03:32 +0000968DL_EXPORT(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000969initmmap(void)
970{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000971 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +0000972
973 /* Patch the object type */
974 mmap_object_type.ob_type = &PyType_Type;
975
Guido van Rossum09fdf072000-03-31 01:17:07 +0000976 module = Py_InitModule ("mmap", mmap_functions);
977 dict = PyModule_GetDict (module);
978 mmap_module_error = PyExc_EnvironmentError;
979 Py_INCREF(mmap_module_error);
980 PyDict_SetItemString (dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000981#ifdef PROT_EXEC
Guido van Rossum09fdf072000-03-31 01:17:07 +0000982 PyDict_SetItemString (dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000983#endif
984#ifdef PROT_READ
Guido van Rossum09fdf072000-03-31 01:17:07 +0000985 PyDict_SetItemString (dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000986#endif
987#ifdef PROT_WRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000988 PyDict_SetItemString (dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000989#endif
990
991#ifdef MAP_SHARED
Guido van Rossum09fdf072000-03-31 01:17:07 +0000992 PyDict_SetItemString (dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000993#endif
994#ifdef MAP_PRIVATE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000995 PyDict_SetItemString (dict, "MAP_PRIVATE",
996 PyInt_FromLong(MAP_PRIVATE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000997#endif
998#ifdef MAP_DENYWRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000999 PyDict_SetItemString (dict, "MAP_DENYWRITE",
1000 PyInt_FromLong(MAP_DENYWRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001001#endif
1002#ifdef MAP_EXECUTABLE
Guido van Rossum09fdf072000-03-31 01:17:07 +00001003 PyDict_SetItemString (dict, "MAP_EXECUTABLE",
1004 PyInt_FromLong(MAP_EXECUTABLE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001005#endif
1006#ifdef MAP_ANON
Guido van Rossum09fdf072000-03-31 01:17:07 +00001007 PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
1008 PyDict_SetItemString (dict, "MAP_ANONYMOUS",
1009 PyInt_FromLong(MAP_ANON) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001010#endif
1011
Guido van Rossum09fdf072000-03-31 01:17:07 +00001012 PyDict_SetItemString (dict, "PAGESIZE",
Fred Drake145f96e2000-10-01 17:50:46 +00001013 PyInt_FromLong( (long)my_getpagesize() ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001014}
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001015