blob: dd7ff6dcf66ed9ae2df23ed64feb5e8b7980ab0f [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{
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000227 int 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);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000232 if (!PyArg_ParseTuple (args, "s#|i:find", &needle, &len, &start)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000233 return NULL;
234 } else {
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000235 char *p = self->data+self->pos;
236 char *e = self->data+self->size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000237 while (p < e) {
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000238 char *s = p;
239 char *n = needle;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000240 while ((s<e) && (*n) && !(*s-*n)) {
241 s++, n++;
242 }
243 if (!*n) {
244 return Py_BuildValue (
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000245 "i",
246 (int) (p - (self->data + start)));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000247 }
248 p++;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000249 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000250 return Py_BuildValue ("l", (long) -1);
251 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000252}
253
254static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000255mmap_write_method(mmap_object *self,
256 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000257{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000258 long length;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000259 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000260
Guido van Rossum09fdf072000-03-31 01:17:07 +0000261 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000262 if (!PyArg_ParseTuple (args, "s#:write", &data, &length))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000263 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000264
Guido van Rossum09fdf072000-03-31 01:17:07 +0000265 if ((self->pos + length) > self->size) {
266 PyErr_SetString (PyExc_ValueError, "data out of range");
267 return NULL;
268 }
269 memcpy (self->data+self->pos, data, length);
270 self->pos = self->pos+length;
271 Py_INCREF (Py_None);
272 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000273}
274
275static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000276mmap_write_byte_method(mmap_object *self,
277 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000278{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000279 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000280
Guido van Rossum09fdf072000-03-31 01:17:07 +0000281 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000282 if (!PyArg_ParseTuple (args, "c:write_byte", &value))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000283 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000284
Guido van Rossum09fdf072000-03-31 01:17:07 +0000285 *(self->data+self->pos) = value;
286 self->pos += 1;
287 Py_INCREF (Py_None);
288 return (Py_None);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000289}
290
291static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000292mmap_size_method(mmap_object *self,
293 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000294{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000295 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000296 if (!PyArg_ParseTuple(args, ":size"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000297 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000298
299#ifdef MS_WIN32
Mark Hammond071864a2000-07-30 02:46:26 +0000300 if (self->file_handle != INVALID_HANDLE_VALUE) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000301 return (Py_BuildValue (
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000302 "l", (long)
Mark Hammond071864a2000-07-30 02:46:26 +0000303 GetFileSize (self->file_handle, NULL)));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000304 } else {
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000305 return (Py_BuildValue ("l", (long) self->size) );
Guido van Rossum09fdf072000-03-31 01:17:07 +0000306 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000307#endif /* MS_WIN32 */
308
309#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000310 {
311 struct stat buf;
312 if (-1 == fstat(self->fd, &buf)) {
313 PyErr_SetFromErrno(mmap_module_error);
314 return NULL;
315 }
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000316 return (Py_BuildValue ("l", (long) buf.st_size) );
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000317 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000318#endif /* UNIX */
319}
320
321/* This assumes that you want the entire file mapped,
322 / and when recreating the map will make the new file
323 / have the new size
324 /
325 / Is this really necessary? This could easily be done
326 / from python by just closing and re-opening with the
327 / new size?
328 */
329
330static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000331mmap_resize_method(mmap_object *self,
332 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000333{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000334 unsigned long new_size;
335 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000336 if (!PyArg_ParseTuple (args, "l:resize", &new_size)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000337 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000338#ifdef MS_WIN32
Guido van Rossum09fdf072000-03-31 01:17:07 +0000339 } else {
340 DWORD dwErrCode = 0;
341 /* First, unmap the file view */
342 UnmapViewOfFile (self->data);
343 /* Close the mapping object */
Mark Hammond071864a2000-07-30 02:46:26 +0000344 CloseHandle (self->map_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000345 /* Move to the desired EOF position */
Mark Hammond071864a2000-07-30 02:46:26 +0000346 SetFilePointer (self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000347 new_size, NULL, FILE_BEGIN);
348 /* Change the size of the file */
Mark Hammond071864a2000-07-30 02:46:26 +0000349 SetEndOfFile (self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000350 /* Create another mapping object and remap the file view */
351 self->map_handle = CreateFileMapping (
Mark Hammond071864a2000-07-30 02:46:26 +0000352 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000353 NULL,
354 PAGE_READWRITE,
355 0,
356 new_size,
357 self->tagname);
358 if (self->map_handle != NULL) {
359 self->data = (char *) MapViewOfFile (self->map_handle,
360 FILE_MAP_WRITE,
361 0,
362 0,
363 0);
364 if (self->data != NULL) {
365 self->size = new_size;
366 Py_INCREF (Py_None);
367 return Py_None;
368 } else {
369 dwErrCode = GetLastError();
370 }
371 } else {
372 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000373 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000374 PyErr_SetFromWindowsErr(dwErrCode);
375 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000376#endif /* MS_WIN32 */
377
378#ifdef UNIX
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000379#ifndef HAVE_MREMAP
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000380} else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000381 PyErr_SetString(PyExc_SystemError,
382 "mmap: resizing not available--no mremap()");
383 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000384#else
385} else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000386 void *newmap;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000387
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000388#ifdef MREMAP_MAYMOVE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000389 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000390#else
391 newmap = mremap(self->data, self->size, new_size, 0);
392#endif
Guido van Rossum09fdf072000-03-31 01:17:07 +0000393 if (newmap == (void *)-1)
394 {
395 PyErr_SetFromErrno(mmap_module_error);
396 return NULL;
397 }
398 self->data = newmap;
399 self->size = new_size;
400 Py_INCREF(Py_None);
401 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000402#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000403#endif /* UNIX */
404}
405}
406
407static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000408mmap_tell_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000409{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000410 CHECK_VALID(NULL);
Andrew M. Kuchling841b9fb2000-06-03 20:43:43 +0000411 if (!PyArg_ParseTuple(args, ":tell"))
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000412 return NULL;
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000413 return (Py_BuildValue ("l", (long) self->pos) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000414}
415
416static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000417mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000418{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000419 size_t offset = 0;
420 size_t size = self->size;
421 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000422 if (!PyArg_ParseTuple (args, "|ll:flush", &offset, &size)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000423 return NULL;
424 } else if ((offset + size) > self->size) {
425 PyErr_SetString (PyExc_ValueError,
426 "flush values out of range");
427 return NULL;
428 } else {
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000429#ifdef MS_WIN32
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000430 return (Py_BuildValue("l", (long)
431 FlushViewOfFile(self->data+offset, size)));
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000432#endif /* MS_WIN32 */
433#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000434 /* XXX semantics of return value? */
435 /* XXX flags for msync? */
436 if (-1 == msync(self->data + offset, size,
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000437 MS_SYNC))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000438 {
439 PyErr_SetFromErrno(mmap_module_error);
440 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000441 }
Fredrik Lundh5cccf502000-07-09 13:16:13 +0000442 return Py_BuildValue ("l", (long) 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000443#endif /* UNIX */
444 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000445}
446
447static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000448mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000449{
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000450 int dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000451 int how=0;
452 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000453 if (!PyArg_ParseTuple (args, "i|i:seek", &dist, &how)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000454 return(NULL);
455 } else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000456 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000457 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000458 case 0: /* relative to start */
459 if (dist < 0)
460 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000461 where = dist;
462 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000463 case 1: /* relative to current position */
464 if ((int)self->pos + dist < 0)
465 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000466 where = self->pos + dist;
467 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000468 case 2: /* relative to end */
469 if ((int)self->size + dist < 0)
470 goto onoutofrange;
471 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000472 break;
473 default:
474 PyErr_SetString (PyExc_ValueError,
475 "unknown seek type");
476 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000477 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000478 if (where > self->size)
479 goto onoutofrange;
480 self->pos = where;
481 Py_INCREF (Py_None);
482 return (Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000483 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000484
485onoutofrange:
486 PyErr_SetString (PyExc_ValueError, "seek out of range");
487 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000488}
489
490static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000491mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000492{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000493 unsigned long dest, src, count;
494 CHECK_VALID(NULL);
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000495 if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000496 return NULL;
497 } else {
498 /* bounds check the values */
499 if (/* end of source after end of data?? */
500 ((src+count) > self->size)
501 /* dest will fit? */
502 || (dest+count > self->size)) {
503 PyErr_SetString (PyExc_ValueError,
504 "source or destination out of range");
505 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000506 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000507 memmove (self->data+dest, self->data+src, count);
508 Py_INCREF (Py_None);
509 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000510 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000511 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000512}
513
514static struct PyMethodDef mmap_object_methods[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000515 {"close", (PyCFunction) mmap_close_method, 1},
516 {"find", (PyCFunction) mmap_find_method, 1},
517 {"flush", (PyCFunction) mmap_flush_method, 1},
518 {"move", (PyCFunction) mmap_move_method, 1},
519 {"read", (PyCFunction) mmap_read_method, 1},
520 {"read_byte", (PyCFunction) mmap_read_byte_method, 1},
521 {"readline", (PyCFunction) mmap_read_line_method, 1},
522 {"resize", (PyCFunction) mmap_resize_method, 1},
523 {"seek", (PyCFunction) mmap_seek_method, 1},
524 {"size", (PyCFunction) mmap_size_method, 1},
525 {"tell", (PyCFunction) mmap_tell_method, 1},
526 {"write", (PyCFunction) mmap_write_method, 1},
527 {"write_byte", (PyCFunction) mmap_write_byte_method, 1},
528 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000529};
530
531/* Functions for treating an mmap'ed file as a buffer */
532
533static int
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000534mmap_buffer_getreadbuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000535{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000536 CHECK_VALID(-1);
537 if ( index != 0 ) {
538 PyErr_SetString(PyExc_SystemError,
539 "Accessing non-existent mmap segment");
540 return -1;
541 }
542 *ptr = self->data;
543 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000544}
545
546static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000547mmap_buffer_getwritebuf(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000548{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000549 CHECK_VALID(-1);
550 if ( index != 0 ) {
551 PyErr_SetString(PyExc_SystemError,
552 "Accessing non-existent mmap segment");
553 return -1;
554 }
555 *ptr = self->data;
556 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000557}
558
559static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000560mmap_buffer_getsegcount(mmap_object *self, int *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000561{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000562 CHECK_VALID(-1);
563 if (lenp)
564 *lenp = self->size;
565 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000566}
567
568static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000569mmap_buffer_getcharbuffer(mmap_object *self, int index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000570{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000571 if ( index != 0 ) {
572 PyErr_SetString(PyExc_SystemError,
573 "accessing non-existent buffer segment");
574 return -1;
575 }
576 *ptr = (const char *)self->data;
577 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000578}
579
580static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000581mmap_object_getattr(mmap_object *self, char *name)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000582{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000583 return Py_FindMethod (mmap_object_methods, (PyObject *)self, name);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000584}
585
586static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000587mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000588{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000589 CHECK_VALID(-1);
590 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000591}
592
593static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000594mmap_item(mmap_object *self, int i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000595{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000596 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000597 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000598 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
599 return NULL;
600 }
601 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000602}
603
604static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000605mmap_slice(mmap_object *self, int ilow, int ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000606{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000607 CHECK_VALID(NULL);
608 if (ilow < 0)
609 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000610 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000611 ilow = self->size;
612 if (ihigh < 0)
613 ihigh = 0;
614 if (ihigh < ilow)
615 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000616 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000617 ihigh = self->size;
618
619 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000620}
621
622static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000623mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000624{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000625 CHECK_VALID(NULL);
626 PyErr_SetString(PyExc_SystemError,
627 "mmaps don't support concatenation");
628 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000629}
630
631static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000632mmap_repeat(mmap_object *self, int n)
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 repeat operation");
637 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000638}
639
640static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000641mmap_ass_slice(mmap_object *self, int ilow, int ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000642{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000643 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000644
Guido van Rossum09fdf072000-03-31 01:17:07 +0000645 CHECK_VALID(-1);
646 if (ilow < 0)
647 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000648 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000649 ilow = self->size;
650 if (ihigh < 0)
651 ihigh = 0;
652 if (ihigh < ilow)
653 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000654 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000655 ihigh = self->size;
656
657 if (! (PyString_Check(v)) ) {
658 PyErr_SetString(PyExc_IndexError,
659 "mmap slice assignment must be a string");
660 return -1;
661 }
662 if ( PyString_Size(v) != (ihigh - ilow) ) {
663 PyErr_SetString(PyExc_IndexError,
664 "mmap slice assignment is wrong size");
665 return -1;
666 }
667 buf = PyString_AsString(v);
668 memcpy(self->data + ilow, buf, ihigh-ilow);
669 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000670}
671
672static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000673mmap_ass_item(mmap_object *self, int i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000674{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000675 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000676
Guido van Rossum09fdf072000-03-31 01:17:07 +0000677 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000678 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000679 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
680 return -1;
681 }
682 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
683 PyErr_SetString(PyExc_IndexError,
684 "mmap assignment must be single-character string");
685 return -1;
686 }
687 buf = PyString_AsString(v);
688 self->data[i] = buf[0];
689 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000690}
691
692static PySequenceMethods mmap_as_sequence = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000693 (inquiry)mmap_length, /*sq_length*/
694 (binaryfunc)mmap_concat, /*sq_concat*/
695 (intargfunc)mmap_repeat, /*sq_repeat*/
696 (intargfunc)mmap_item, /*sq_item*/
697 (intintargfunc)mmap_slice, /*sq_slice*/
698 (intobjargproc)mmap_ass_item, /*sq_ass_item*/
699 (intintobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000700};
701
702static PyBufferProcs mmap_as_buffer = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000703 (getreadbufferproc)mmap_buffer_getreadbuf,
704 (getwritebufferproc)mmap_buffer_getwritebuf,
705 (getsegcountproc)mmap_buffer_getsegcount,
706 (getcharbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000707};
708
709static PyTypeObject mmap_object_type = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000710 PyObject_HEAD_INIT(0) /* patched in module init */
711 0, /* ob_size */
712 "mmap", /* tp_name */
713 sizeof(mmap_object), /* tp_size */
714 0, /* tp_itemsize */
715 /* methods */
716 (destructor) mmap_object_dealloc, /* tp_dealloc */
717 0, /* tp_print */
718 (getattrfunc) mmap_object_getattr, /* tp_getattr */
719 0, /* tp_setattr */
720 0, /* tp_compare */
721 0, /* tp_repr */
722 0, /* tp_as_number */
723 &mmap_as_sequence, /*tp_as_sequence*/
724 0, /*tp_as_mapping*/
725 0, /*tp_hash*/
726 0, /*tp_call*/
727 0, /*tp_str*/
728 0, /*tp_getattro*/
729 0, /*tp_setattro*/
730 &mmap_as_buffer, /*tp_as_buffer*/
731 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
732 0, /*tp_doc*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000733};
734
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000735
736/* extract the map size from the given PyObject
737
738 The map size is restricted to [0, INT_MAX] because this is the current
739 Python limitation on object sizes. Although the mmap object *could* handle
740 a larger map size, there is no point because all the useful operations
741 (len(), slicing(), sequence indexing) are limited by a C int.
742
Thomas Wouters7e474022000-07-16 12:04:32 +0000743 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000744 success, the map size is returned. */
745static int
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000746_GetMapSize(PyObject *o)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000747{
748 if (PyInt_Check(o)) {
749 long i = PyInt_AsLong(o);
750 if (PyErr_Occurred())
751 return -1;
752 if (i < 0)
753 goto onnegoverflow;
754 if (i > INT_MAX)
755 goto onposoverflow;
756 return (int)i;
757 }
758 else if (PyLong_Check(o)) {
759 long i = PyLong_AsLong(o);
760 if (PyErr_Occurred()) {
761 /* yes negative overflow is mistaken for positive overflow
762 but not worth the trouble to check sign of 'i' */
763 if (PyErr_ExceptionMatches(PyExc_OverflowError))
764 goto onposoverflow;
765 else
766 return -1;
767 }
768 if (i < 0)
769 goto onnegoverflow;
770 if (i > INT_MAX)
771 goto onposoverflow;
772 return (int)i;
773 }
774 else {
775 PyErr_SetString(PyExc_TypeError,
776 "map size must be an integral value");
777 return -1;
778 }
779
780onnegoverflow:
781 PyErr_SetString(PyExc_OverflowError,
782 "memory mapped size must be positive");
783 return -1;
784
785onposoverflow:
786 PyErr_SetString(PyExc_OverflowError,
787 "memory mapped size is too large (limited by C int)");
788 return -1;
789}
790
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000791#ifdef UNIX
792static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000793new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000794{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000795 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000796 PyObject *map_size_obj = NULL;
797 int map_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000798 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000799 char *keywords[] = {"file", "size", "flags", "prot", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000800
Guido van Rossum09fdf072000-03-31 01:17:07 +0000801 if (!PyArg_ParseTupleAndKeywords(args, kwdict,
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000802 "iO|ii", keywords,
803 &fd, &map_size_obj, &flags, &prot)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000804 )
805 return NULL;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000806 map_size = _GetMapSize(map_size_obj);
807 if (map_size < 0)
808 return NULL;
809
Guido van Rossumb18618d2000-05-03 23:44:39 +0000810 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000811 if (m_obj == NULL) {return NULL;}
812 m_obj->size = (size_t) map_size;
813 m_obj->pos = (size_t) 0;
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000814 m_obj->fd = fd;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000815 m_obj->data = mmap(NULL, map_size,
816 prot, flags,
817 fd, 0);
Tim Peterscf96de02001-04-21 02:46:11 +0000818 if (m_obj->data == (char *)-1)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000819 {
820 Py_DECREF(m_obj);
821 PyErr_SetFromErrno(mmap_module_error);
822 return NULL;
823 }
824 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000825}
826#endif /* UNIX */
827
828#ifdef MS_WIN32
829static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000830new_mmap_object(PyObject *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000831{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000832 mmap_object *m_obj;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000833 PyObject *map_size_obj = NULL;
834 int map_size;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000835 char *tagname = "";
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000836
Guido van Rossum09fdf072000-03-31 01:17:07 +0000837 DWORD dwErr = 0;
838 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +0000839 HANDLE fh = 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000840
Guido van Rossum09fdf072000-03-31 01:17:07 +0000841 if (!PyArg_ParseTuple(args,
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000842 "iO|z",
Guido van Rossum09fdf072000-03-31 01:17:07 +0000843 &fileno,
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000844 &map_size_obj,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000845 &tagname)
846 )
847 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000848
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000849 map_size = _GetMapSize(map_size_obj);
850 if (map_size < 0)
851 return NULL;
852
Guido van Rossum09fdf072000-03-31 01:17:07 +0000853 /* if an actual filename has been specified */
854 if (fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +0000855 fh = (HANDLE)_get_osfhandle(fileno);
856 if (fh==(HANDLE)-1) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000857 PyErr_SetFromErrno(mmap_module_error);
858 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000859 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +0000860 /* Win9x appears to need us seeked to zero */
861 fseek(&_iob[fileno], 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000862 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000863
Guido van Rossumb18618d2000-05-03 23:44:39 +0000864 m_obj = PyObject_New (mmap_object, &mmap_object_type);
Mark Hammond2cbed002000-07-30 02:22:43 +0000865 if (m_obj==NULL)
866 return NULL;
867 /* Set every field to an invalid marker, so we can safely
868 destruct the object in the face of failure */
869 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +0000870 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +0000871 m_obj->map_handle = INVALID_HANDLE_VALUE;
872 m_obj->tagname = NULL;
873
Guido van Rossum09fdf072000-03-31 01:17:07 +0000874 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +0000875 /* It is necessary to duplicate the handle, so the
876 Python code can close it on us */
877 if (!DuplicateHandle(
878 GetCurrentProcess(), /* source process handle */
Mark Hammond071864a2000-07-30 02:46:26 +0000879 fh, /* handle to be duplicated */
Mark Hammond2cbed002000-07-30 02:22:43 +0000880 GetCurrentProcess(), /* target proc handle */
881 (LPHANDLE)&m_obj->file_handle, /* result */
882 0, /* access - ignored due to options value */
883 FALSE, /* inherited by child processes? */
884 DUPLICATE_SAME_ACCESS)) { /* options */
885 dwErr = GetLastError();
886 Py_DECREF(m_obj);
887 PyErr_SetFromWindowsErr(dwErr);
888 return NULL;
889 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000890 if (!map_size) {
Mark Hammond071864a2000-07-30 02:46:26 +0000891 m_obj->size = GetFileSize (fh, NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000892 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000893 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000894 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000895 }
896 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000897 m_obj->size = map_size;
898 }
899
900 /* set the initial position */
901 m_obj->pos = (size_t) 0;
902
Mark Hammond2cbed002000-07-30 02:22:43 +0000903 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +0000904 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +0000905 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
906 if (m_obj->tagname == NULL) {
907 PyErr_NoMemory();
908 Py_DECREF(m_obj);
909 return NULL;
910 }
911 strcpy(m_obj->tagname, tagname);
912 }
913 else
914 m_obj->tagname = NULL;
915
Mark Hammond071864a2000-07-30 02:46:26 +0000916 m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000917 NULL,
918 PAGE_READWRITE,
919 0,
920 m_obj->size,
Tim Peters0d9f9dc2001-01-10 05:42:18 +0000921 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000922 if (m_obj->map_handle != NULL) {
923 m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
924 FILE_MAP_WRITE,
925 0,
926 0,
927 0);
928 if (m_obj->data != NULL) {
929 return ((PyObject *) m_obj);
930 } else {
931 dwErr = GetLastError();
932 }
933 } else {
934 dwErr = GetLastError();
935 }
Mark Hammond2cbed002000-07-30 02:22:43 +0000936 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000937 PyErr_SetFromWindowsErr(dwErr);
938 return (NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000939}
940#endif /* MS_WIN32 */
941
942/* List of functions exported by this module */
943static struct PyMethodDef mmap_functions[] = {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000944 {"mmap", (PyCFunction) new_mmap_object,
945 METH_VARARGS|METH_KEYWORDS},
946 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000947};
948
Guido van Rossum5a530192001-01-10 21:03:32 +0000949DL_EXPORT(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000950initmmap(void)
951{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000952 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +0000953
954 /* Patch the object type */
955 mmap_object_type.ob_type = &PyType_Type;
956
Guido van Rossum09fdf072000-03-31 01:17:07 +0000957 module = Py_InitModule ("mmap", mmap_functions);
958 dict = PyModule_GetDict (module);
959 mmap_module_error = PyExc_EnvironmentError;
960 Py_INCREF(mmap_module_error);
961 PyDict_SetItemString (dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000962#ifdef PROT_EXEC
Guido van Rossum09fdf072000-03-31 01:17:07 +0000963 PyDict_SetItemString (dict, "PROT_EXEC", PyInt_FromLong(PROT_EXEC) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000964#endif
965#ifdef PROT_READ
Guido van Rossum09fdf072000-03-31 01:17:07 +0000966 PyDict_SetItemString (dict, "PROT_READ", PyInt_FromLong(PROT_READ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000967#endif
968#ifdef PROT_WRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000969 PyDict_SetItemString (dict, "PROT_WRITE", PyInt_FromLong(PROT_WRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000970#endif
971
972#ifdef MAP_SHARED
Guido van Rossum09fdf072000-03-31 01:17:07 +0000973 PyDict_SetItemString (dict, "MAP_SHARED", PyInt_FromLong(MAP_SHARED) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000974#endif
975#ifdef MAP_PRIVATE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000976 PyDict_SetItemString (dict, "MAP_PRIVATE",
977 PyInt_FromLong(MAP_PRIVATE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000978#endif
979#ifdef MAP_DENYWRITE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000980 PyDict_SetItemString (dict, "MAP_DENYWRITE",
981 PyInt_FromLong(MAP_DENYWRITE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000982#endif
983#ifdef MAP_EXECUTABLE
Guido van Rossum09fdf072000-03-31 01:17:07 +0000984 PyDict_SetItemString (dict, "MAP_EXECUTABLE",
985 PyInt_FromLong(MAP_EXECUTABLE) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000986#endif
987#ifdef MAP_ANON
Guido van Rossum09fdf072000-03-31 01:17:07 +0000988 PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
989 PyDict_SetItemString (dict, "MAP_ANONYMOUS",
990 PyInt_FromLong(MAP_ANON) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000991#endif
992
Guido van Rossum09fdf072000-03-31 01:17:07 +0000993 PyDict_SetItemString (dict, "PAGESIZE",
Fred Drake145f96e2000-10-01 17:50:46 +0000994 PyInt_FromLong( (long)my_getpagesize() ) );
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000995}
Andrew M. Kuchling961fe172000-06-03 19:41:42 +0000996