blob: d6d16011c682e542cac0c15b988949f8b2d6ef1e [file] [log] [blame]
Guido van Rossum09fdf072000-03-31 01:17:07 +00001/*
2 / Author: Sam Rushing <rushing@nightmare.com>
Andrew M. Kuchling10f9c072001-11-05 21:25:42 +00003 / Hacked for Unix by AMK
Guido van Rossum09fdf072000-03-31 01:17:07 +00004 / $Id$
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00005
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00006 / Modified to support mmap with offset - to map a 'window' of a file
7 / Author: Yotam Medini yotamm@mellanox.co.il
8 /
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00009 / mmapmodule.cpp -- map a view of a file into memory
10 /
11 / todo: need permission flags, perhaps a 'chsize' analog
12 / not all functions check range yet!!!
13 /
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
Martin v. Löwiscfe7e092006-02-17 06:59:14 +000021#define PY_SSIZE_T_CLEAN
Guido van Rossum09fdf072000-03-31 01:17:07 +000022#include <Python.h>
23
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000024#ifndef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000025#define UNIX
26#endif
27
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000028#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000029#include <windows.h>
Fred Drake145f96e2000-10-01 17:50:46 +000030static int
31my_getpagesize(void)
32{
Antoine Pitrouc83ea132010-05-09 14:46:46 +000033 SYSTEM_INFO si;
34 GetSystemInfo(&si);
35 return si.dwPageSize;
Fred Drake145f96e2000-10-01 17:50:46 +000036}
Travis E. Oliphant8feafab2007-10-23 02:40:56 +000037
38static int
39my_getallocationgranularity (void)
40{
41
Antoine Pitrouc83ea132010-05-09 14:46:46 +000042 SYSTEM_INFO si;
43 GetSystemInfo(&si);
44 return si.dwAllocationGranularity;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +000045}
46
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000047#endif
48
49#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000050#include <sys/mman.h>
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +000051#include <sys/stat.h>
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000052
Fred Drake145f96e2000-10-01 17:50:46 +000053#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
54static int
55my_getpagesize(void)
56{
Antoine Pitrouc83ea132010-05-09 14:46:46 +000057 return sysconf(_SC_PAGESIZE);
Fred Drake145f96e2000-10-01 17:50:46 +000058}
Travis E. Oliphant8feafab2007-10-23 02:40:56 +000059
60#define my_getallocationgranularity my_getpagesize
Fred Drake145f96e2000-10-01 17:50:46 +000061#else
62#define my_getpagesize getpagesize
63#endif
64
Guido van Rossum4b36e6b2000-09-25 13:16:15 +000065#endif /* UNIX */
66
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000067#include <string.h>
Martin v. Löwis0e8bd7e2006-06-10 12:23:46 +000068
69#ifdef HAVE_SYS_TYPES_H
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000070#include <sys/types.h>
Martin v. Löwis0e8bd7e2006-06-10 12:23:46 +000071#endif /* HAVE_SYS_TYPES_H */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000072
Neal Norwitz3eaf2b52006-02-16 08:08:54 +000073/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +000074#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
75# define MAP_ANONYMOUS MAP_ANON
76#endif
77
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000078static PyObject *mmap_module_error;
79
Tim Peters5ebfd362001-11-13 23:11:19 +000080typedef enum
81{
Antoine Pitrouc83ea132010-05-09 14:46:46 +000082 ACCESS_DEFAULT,
83 ACCESS_READ,
84 ACCESS_WRITE,
85 ACCESS_COPY
Tim Peters5ebfd362001-11-13 23:11:19 +000086} access_mode;
87
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000088typedef struct {
Antoine Pitrouc83ea132010-05-09 14:46:46 +000089 PyObject_HEAD
90 char * data;
91 size_t size;
92 size_t pos; /* relative to offset */
93 size_t offset;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000094
Martin v. Löwis6238d2b2002-06-30 15:26:10 +000095#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +000096 HANDLE map_handle;
97 HANDLE file_handle;
98 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000099#endif
100
101#ifdef UNIX
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000102 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000103#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000104
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000105 access_mode access;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000106} mmap_object;
107
Tim Peters5ebfd362001-11-13 23:11:19 +0000108
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000109static void
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000110mmap_object_dealloc(mmap_object *m_obj)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000111{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000112#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000113 if (m_obj->data != NULL)
114 UnmapViewOfFile (m_obj->data);
115 if (m_obj->map_handle != NULL)
116 CloseHandle (m_obj->map_handle);
117 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
118 CloseHandle (m_obj->file_handle);
119 if (m_obj->tagname)
120 PyMem_Free(m_obj->tagname);
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000121#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000122
123#ifdef UNIX
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000124 if (m_obj->fd >= 0)
125 (void) close(m_obj->fd);
126 if (m_obj->data!=NULL) {
R. David Murray2a4b3fc2010-12-11 02:13:04 +0000127 if (m_obj->access != ACCESS_READ && m_obj->access != ACCESS_COPY)
128 msync(m_obj->data, m_obj->size, MS_SYNC);
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000129 munmap(m_obj->data, m_obj->size);
130 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000131#endif /* UNIX */
132
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000133 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000134}
135
136static PyObject *
Georg Brandl96a8c392006-05-29 21:04:52 +0000137mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000138{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000139#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000140 /* For each resource we maintain, we need to check
141 the value is valid, and if so, free the resource
142 and set the member value to an invalid value so
143 the dealloc does not attempt to resource clearing
144 again.
145 TODO - should we check for errors in the close operations???
146 */
147 if (self->data != NULL) {
148 UnmapViewOfFile(self->data);
149 self->data = NULL;
150 }
151 if (self->map_handle != NULL) {
152 CloseHandle(self->map_handle);
153 self->map_handle = NULL;
154 }
155 if (self->file_handle != INVALID_HANDLE_VALUE) {
156 CloseHandle(self->file_handle);
157 self->file_handle = INVALID_HANDLE_VALUE;
158 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000159#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000160
161#ifdef UNIX
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000162 if (0 <= self->fd)
163 (void) close(self->fd);
164 self->fd = -1;
165 if (self->data != NULL) {
166 munmap(self->data, self->size);
167 self->data = NULL;
168 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000169#endif
170
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000171 Py_INCREF(Py_None);
172 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000173}
174
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000175#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000176#define CHECK_VALID(err) \
177do { \
178 if (self->map_handle == NULL) { \
179 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
180 return err; \
181 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000182} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000183#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000184
185#ifdef UNIX
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000186#define CHECK_VALID(err) \
187do { \
188 if (self->data == NULL) { \
189 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
190 return err; \
191 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000192} while (0)
193#endif /* UNIX */
194
195static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000196mmap_read_byte_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000197 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000198{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000199 CHECK_VALID(NULL);
200 if (self->pos < self->size) {
201 char value = self->data[self->pos];
202 self->pos += 1;
203 return Py_BuildValue("c", value);
204 } else {
205 PyErr_SetString(PyExc_ValueError, "read byte out of range");
206 return NULL;
207 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000208}
209
210static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000211mmap_read_line_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000212 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000213{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000214 char *start = self->data+self->pos;
215 char *eof = self->data+self->size;
216 char *eol;
217 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000218
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000219 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000220
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000221 eol = memchr(start, '\n', self->size - self->pos);
222 if (!eol)
223 eol = eof;
224 else
225 ++eol; /* we're interested in the position after the
226 newline. */
227 result = PyString_FromStringAndSize(start, (eol - start));
228 self->pos += (eol - start);
229 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000230}
231
232static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000233mmap_read_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000234 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000235{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000236 Py_ssize_t num_bytes, n;
237 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000238
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000239 CHECK_VALID(NULL);
240 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
241 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000242
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000243 /* silently 'adjust' out-of-range requests */
244 assert(self->size >= self->pos);
245 n = self->size - self->pos;
246 /* The difference can overflow, only if self->size is greater than
247 * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed,
248 * because the mapped area and the returned string each need more
249 * than half of the addressable memory. So we clip the size, and let
250 * the code below raise MemoryError.
251 */
252 if (n < 0)
253 n = PY_SSIZE_T_MAX;
254 if (num_bytes < 0 || num_bytes > n) {
255 num_bytes = n;
256 }
257 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
258 self->pos += num_bytes;
259 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000260}
261
262static PyObject *
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000263mmap_gfind(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000264 PyObject *args,
265 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000266{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000267 Py_ssize_t start = self->pos;
268 Py_ssize_t end = self->size;
269 const char *needle;
270 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000271
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000272 CHECK_VALID(NULL);
273 if (!PyArg_ParseTuple(args, reverse ? "s#|nn:rfind" : "s#|nn:find",
274 &needle, &len, &start, &end)) {
275 return NULL;
276 } else {
277 const char *p, *start_p, *end_p;
278 int sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000279
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000280 if (start < 0)
281 start += self->size;
282 if (start < 0)
283 start = 0;
284 else if ((size_t)start > self->size)
285 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000286
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000287 if (end < 0)
288 end += self->size;
289 if (end < 0)
290 end = 0;
291 else if ((size_t)end > self->size)
292 end = self->size;
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000293
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000294 start_p = self->data + start;
295 end_p = self->data + end;
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000296
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000297 for (p = (reverse ? end_p - len : start_p);
298 (p >= start_p) && (p + len <= end_p); p += sign) {
299 Py_ssize_t i;
300 for (i = 0; i < len && needle[i] == p[i]; ++i)
301 /* nothing */;
302 if (i == len) {
303 return PyInt_FromSsize_t(p - self->data);
304 }
305 }
306 return PyInt_FromLong(-1);
307 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000308}
309
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000310static PyObject *
311mmap_find_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000312 PyObject *args)
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000313{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000314 return mmap_gfind(self, args, 0);
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000315}
316
317static PyObject *
318mmap_rfind_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000319 PyObject *args)
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000320{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000321 return mmap_gfind(self, args, 1);
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000322}
323
Tim Petersec0a5f02006-02-16 23:47:20 +0000324static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000325is_writeable(mmap_object *self)
326{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000327 if (self->access != ACCESS_READ)
328 return 1;
329 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
330 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000331}
332
Tim Petersec0a5f02006-02-16 23:47:20 +0000333static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000334is_resizeable(mmap_object *self)
335{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000336 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
337 return 1;
338 PyErr_Format(PyExc_TypeError,
339 "mmap can't resize a readonly or copy-on-write memory map.");
340 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000341}
342
343
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000344static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000345mmap_write_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000346 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000347{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000348 Py_ssize_t length;
349 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000350
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000351 CHECK_VALID(NULL);
352 if (!PyArg_ParseTuple(args, "s#:write", &data, &length))
353 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000354
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000355 if (!is_writeable(self))
356 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000357
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000358 if ((self->pos + length) > self->size) {
359 PyErr_SetString(PyExc_ValueError, "data out of range");
360 return NULL;
361 }
362 memcpy(self->data+self->pos, data, length);
363 self->pos = self->pos+length;
364 Py_INCREF(Py_None);
365 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000366}
367
368static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000369mmap_write_byte_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000370 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000371{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000372 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000373
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000374 CHECK_VALID(NULL);
375 if (!PyArg_ParseTuple(args, "c:write_byte", &value))
376 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000377
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000378 if (!is_writeable(self))
379 return NULL;
Hirokazu Yamamotof2dc8852009-02-28 10:31:54 +0000380
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000381 if (self->pos < self->size) {
382 *(self->data+self->pos) = value;
383 self->pos += 1;
384 Py_INCREF(Py_None);
385 return Py_None;
386 }
387 else {
388 PyErr_SetString(PyExc_ValueError, "write byte out of range");
389 return NULL;
390 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000391}
Tim Petersec0a5f02006-02-16 23:47:20 +0000392
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000393static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000394mmap_size_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000395 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000396{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000397 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000398
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000399#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000400 if (self->file_handle != INVALID_HANDLE_VALUE) {
401 DWORD low,high;
402 PY_LONG_LONG size;
403 low = GetFileSize(self->file_handle, &high);
404 if (low == INVALID_FILE_SIZE) {
405 /* It might be that the function appears to have failed,
406 when indeed its size equals INVALID_FILE_SIZE */
407 DWORD error = GetLastError();
408 if (error != NO_ERROR)
409 return PyErr_SetFromWindowsErr(error);
410 }
411 if (!high && low < LONG_MAX)
412 return PyInt_FromLong((long)low);
413 size = (((PY_LONG_LONG)high)<<32) + low;
414 return PyLong_FromLongLong(size);
415 } else {
416 return PyInt_FromSsize_t(self->size);
417 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000418#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000419
420#ifdef UNIX
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000421 {
422 struct stat buf;
423 if (-1 == fstat(self->fd, &buf)) {
424 PyErr_SetFromErrno(mmap_module_error);
425 return NULL;
426 }
427 return PyInt_FromSsize_t(buf.st_size);
428 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000429#endif /* UNIX */
430}
431
432/* This assumes that you want the entire file mapped,
433 / and when recreating the map will make the new file
434 / have the new size
435 /
436 / Is this really necessary? This could easily be done
437 / from python by just closing and re-opening with the
438 / new size?
439 */
440
441static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000442mmap_resize_method(mmap_object *self,
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000443 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000444{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000445 Py_ssize_t new_size;
446 CHECK_VALID(NULL);
447 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
448 !is_resizeable(self)) {
449 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000450#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000451 } else {
452 DWORD dwErrCode = 0;
453 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
454 /* First, unmap the file view */
455 UnmapViewOfFile(self->data);
456 self->data = NULL;
457 /* Close the mapping object */
458 CloseHandle(self->map_handle);
459 self->map_handle = NULL;
460 /* Move to the desired EOF position */
Martin v. Löwis15186072006-02-18 12:38:35 +0000461#if SIZEOF_SIZE_T > 4
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000462 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
463 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
464 off_hi = (DWORD)(self->offset >> 32);
465 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Martin v. Löwis15186072006-02-18 12:38:35 +0000466#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000467 newSizeHigh = 0;
468 newSizeLow = (DWORD)(self->offset + new_size);
469 off_hi = 0;
470 off_lo = (DWORD)self->offset;
Martin v. Löwis15186072006-02-18 12:38:35 +0000471#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000472 SetFilePointer(self->file_handle,
473 newSizeLow, &newSizeHigh, FILE_BEGIN);
474 /* Change the size of the file */
475 SetEndOfFile(self->file_handle);
476 /* Create another mapping object and remap the file view */
477 self->map_handle = CreateFileMapping(
478 self->file_handle,
479 NULL,
480 PAGE_READWRITE,
481 0,
482 0,
483 self->tagname);
484 if (self->map_handle != NULL) {
485 self->data = (char *) MapViewOfFile(self->map_handle,
486 FILE_MAP_WRITE,
487 off_hi,
488 off_lo,
489 new_size);
490 if (self->data != NULL) {
491 self->size = new_size;
492 Py_INCREF(Py_None);
493 return Py_None;
494 } else {
495 dwErrCode = GetLastError();
496 CloseHandle(self->map_handle);
497 self->map_handle = NULL;
498 }
499 } else {
500 dwErrCode = GetLastError();
501 }
502 PyErr_SetFromWindowsErr(dwErrCode);
503 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000504#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000505
506#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000507#ifndef HAVE_MREMAP
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000508 } else {
509 PyErr_SetString(PyExc_SystemError,
510 "mmap: resizing not available--no mremap()");
511 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000512#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000513 } else {
514 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000515
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000516 if (ftruncate(self->fd, self->offset + new_size) == -1) {
517 PyErr_SetFromErrno(mmap_module_error);
518 return NULL;
519 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000520
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000521#ifdef MREMAP_MAYMOVE
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000522 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000523#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000524 #if defined(__NetBSD__)
525 newmap = mremap(self->data, self->size, self->data, new_size, 0);
526 #else
527 newmap = mremap(self->data, self->size, new_size, 0);
528 #endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000529#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000530 if (newmap == (void *)-1)
531 {
532 PyErr_SetFromErrno(mmap_module_error);
533 return NULL;
534 }
535 self->data = newmap;
536 self->size = new_size;
537 Py_INCREF(Py_None);
538 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000539#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000540#endif /* UNIX */
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000541 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000542}
543
544static PyObject *
Georg Brandl96a8c392006-05-29 21:04:52 +0000545mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000546{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000547 CHECK_VALID(NULL);
548 return PyInt_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000549}
550
551static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000552mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000553{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000554 Py_ssize_t offset = 0;
555 Py_ssize_t size = self->size;
556 CHECK_VALID(NULL);
557 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
558 return NULL;
559 if ((size_t)(offset + size) > self->size) {
560 PyErr_SetString(PyExc_ValueError, "flush values out of range");
561 return NULL;
562 }
R. David Murray2a4b3fc2010-12-11 02:13:04 +0000563
564 if (self->access == ACCESS_READ || self->access == ACCESS_COPY)
565 return PyLong_FromLong(0);
566
Neal Norwitz448654f2008-01-27 07:36:03 +0000567#ifdef MS_WINDOWS
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000568 return PyInt_FromLong((long) FlushViewOfFile(self->data+offset, size));
Neal Norwitz448654f2008-01-27 07:36:03 +0000569#elif defined(UNIX)
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000570 /* XXX semantics of return value? */
571 /* XXX flags for msync? */
572 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
573 PyErr_SetFromErrno(mmap_module_error);
574 return NULL;
575 }
576 return PyInt_FromLong(0);
Neal Norwitz448654f2008-01-27 07:36:03 +0000577#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000578 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
579 return NULL;
Neal Norwitz448654f2008-01-27 07:36:03 +0000580#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000581}
582
583static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000584mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000585{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000586 Py_ssize_t dist;
587 int how=0;
588 CHECK_VALID(NULL);
589 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
590 return NULL;
591 else {
592 size_t where;
593 switch (how) {
594 case 0: /* relative to start */
595 if (dist < 0)
596 goto onoutofrange;
597 where = dist;
598 break;
599 case 1: /* relative to current position */
600 if ((Py_ssize_t)self->pos + dist < 0)
601 goto onoutofrange;
602 where = self->pos + dist;
603 break;
604 case 2: /* relative to end */
605 if ((Py_ssize_t)self->size + dist < 0)
606 goto onoutofrange;
607 where = self->size + dist;
608 break;
609 default:
610 PyErr_SetString(PyExc_ValueError, "unknown seek type");
611 return NULL;
612 }
613 if (where > self->size)
614 goto onoutofrange;
615 self->pos = where;
616 Py_INCREF(Py_None);
617 return Py_None;
618 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000619
Tim Peters5ebfd362001-11-13 23:11:19 +0000620 onoutofrange:
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000621 PyErr_SetString(PyExc_ValueError, "seek out of range");
622 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000623}
624
625static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000626mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000627{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000628 unsigned long dest, src, cnt;
629 CHECK_VALID(NULL);
630 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &cnt) ||
631 !is_writeable(self)) {
632 return NULL;
633 } else {
634 /* bounds check the values */
635 if (cnt < 0 || (cnt + dest) < cnt || (cnt + src) < cnt ||
636 src < 0 || src > self->size || (src + cnt) > self->size ||
637 dest < 0 || dest > self->size || (dest + cnt) > self->size) {
638 PyErr_SetString(PyExc_ValueError,
639 "source, destination, or count out of range");
640 return NULL;
641 }
642 memmove(self->data+dest, self->data+src, cnt);
643 Py_INCREF(Py_None);
644 return Py_None;
645 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000646}
647
648static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000649 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
650 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
651 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
652 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
653 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
654 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
655 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
656 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
657 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
658 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
659 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
660 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
661 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
662 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
663 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000664};
665
666/* Functions for treating an mmap'ed file as a buffer */
667
Martin v. Löwis18e16552006-02-15 17:27:45 +0000668static Py_ssize_t
669mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000670{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000671 CHECK_VALID(-1);
672 if (index != 0) {
673 PyErr_SetString(PyExc_SystemError,
674 "Accessing non-existent mmap segment");
675 return -1;
676 }
677 *ptr = self->data;
678 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000679}
680
Martin v. Löwis18e16552006-02-15 17:27:45 +0000681static Py_ssize_t
682mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Tim Petersec0a5f02006-02-16 23:47:20 +0000683{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000684 CHECK_VALID(-1);
685 if (index != 0) {
686 PyErr_SetString(PyExc_SystemError,
687 "Accessing non-existent mmap segment");
688 return -1;
689 }
690 if (!is_writeable(self))
691 return -1;
692 *ptr = self->data;
693 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000694}
695
Martin v. Löwis18e16552006-02-15 17:27:45 +0000696static Py_ssize_t
697mmap_buffer_getsegcount(mmap_object *self, Py_ssize_t *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000698{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000699 CHECK_VALID(-1);
700 if (lenp)
701 *lenp = self->size;
702 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000703}
704
Martin v. Löwis18e16552006-02-15 17:27:45 +0000705static Py_ssize_t
706mmap_buffer_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000707{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000708 if (index != 0) {
709 PyErr_SetString(PyExc_SystemError,
710 "accessing non-existent buffer segment");
711 return -1;
712 }
713 *ptr = (const char *)self->data;
714 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000715}
716
Martin v. Löwis18e16552006-02-15 17:27:45 +0000717static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000718mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000719{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000720 CHECK_VALID(-1);
721 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000722}
723
724static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000725mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000726{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000727 CHECK_VALID(NULL);
728 if (i < 0 || (size_t)i >= self->size) {
729 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
730 return NULL;
731 }
732 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000733}
734
735static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000736mmap_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000737{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000738 CHECK_VALID(NULL);
739 if (ilow < 0)
740 ilow = 0;
741 else if ((size_t)ilow > self->size)
742 ilow = self->size;
743 if (ihigh < 0)
744 ihigh = 0;
745 if (ihigh < ilow)
746 ihigh = ilow;
747 else if ((size_t)ihigh > self->size)
748 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000749
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000750 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000751}
752
753static PyObject *
Thomas Wouters3ccec682007-08-28 15:28:19 +0000754mmap_subscript(mmap_object *self, PyObject *item)
755{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000756 CHECK_VALID(NULL);
757 if (PyIndex_Check(item)) {
758 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
759 if (i == -1 && PyErr_Occurred())
760 return NULL;
761 if (i < 0)
762 i += self->size;
763 if (i < 0 || (size_t)i >= self->size) {
764 PyErr_SetString(PyExc_IndexError,
765 "mmap index out of range");
766 return NULL;
767 }
768 return PyString_FromStringAndSize(self->data + i, 1);
769 }
770 else if (PySlice_Check(item)) {
771 Py_ssize_t start, stop, step, slicelen;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000772
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000773 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
774 &start, &stop, &step, &slicelen) < 0) {
775 return NULL;
776 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000777
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000778 if (slicelen <= 0)
779 return PyString_FromStringAndSize("", 0);
780 else if (step == 1)
781 return PyString_FromStringAndSize(self->data + start,
782 slicelen);
783 else {
784 char *result_buf = (char *)PyMem_Malloc(slicelen);
785 Py_ssize_t cur, i;
786 PyObject *result;
787
788 if (result_buf == NULL)
789 return PyErr_NoMemory();
790 for (cur = start, i = 0; i < slicelen;
791 cur += step, i++) {
792 result_buf[i] = self->data[cur];
793 }
794 result = PyString_FromStringAndSize(result_buf,
795 slicelen);
796 PyMem_Free(result_buf);
797 return result;
798 }
799 }
800 else {
801 PyErr_SetString(PyExc_TypeError,
802 "mmap indices must be integers");
803 return NULL;
804 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000805}
806
807static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000808mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000809{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000810 CHECK_VALID(NULL);
811 PyErr_SetString(PyExc_SystemError,
812 "mmaps don't support concatenation");
813 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000814}
815
816static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000817mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000818{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000819 CHECK_VALID(NULL);
820 PyErr_SetString(PyExc_SystemError,
821 "mmaps don't support repeat operation");
822 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000823}
824
825static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000826mmap_ass_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000827{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000828 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000829
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000830 CHECK_VALID(-1);
831 if (ilow < 0)
832 ilow = 0;
833 else if ((size_t)ilow > self->size)
834 ilow = self->size;
835 if (ihigh < 0)
836 ihigh = 0;
837 if (ihigh < ilow)
838 ihigh = ilow;
839 else if ((size_t)ihigh > self->size)
840 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000841
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000842 if (v == NULL) {
843 PyErr_SetString(PyExc_TypeError,
844 "mmap object doesn't support slice deletion");
845 return -1;
846 }
847 if (! (PyString_Check(v)) ) {
848 PyErr_SetString(PyExc_IndexError,
849 "mmap slice assignment must be a string");
850 return -1;
851 }
852 if (PyString_Size(v) != (ihigh - ilow)) {
853 PyErr_SetString(PyExc_IndexError,
854 "mmap slice assignment is wrong size");
855 return -1;
856 }
857 if (!is_writeable(self))
858 return -1;
859 buf = PyString_AsString(v);
860 memcpy(self->data + ilow, buf, ihigh-ilow);
861 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000862}
863
864static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000865mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000866{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000867 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000868
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000869 CHECK_VALID(-1);
870 if (i < 0 || (size_t)i >= self->size) {
871 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
872 return -1;
873 }
874 if (v == NULL) {
875 PyErr_SetString(PyExc_TypeError,
876 "mmap object doesn't support item deletion");
877 return -1;
878 }
879 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
880 PyErr_SetString(PyExc_IndexError,
881 "mmap assignment must be single-character string");
882 return -1;
883 }
884 if (!is_writeable(self))
885 return -1;
886 buf = PyString_AsString(v);
887 self->data[i] = buf[0];
888 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000889}
890
Thomas Wouters3ccec682007-08-28 15:28:19 +0000891static int
892mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
893{
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000894 CHECK_VALID(-1);
Thomas Wouters3ccec682007-08-28 15:28:19 +0000895
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000896 if (PyIndex_Check(item)) {
897 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
898 const char *buf;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000899
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000900 if (i == -1 && PyErr_Occurred())
901 return -1;
902 if (i < 0)
903 i += self->size;
904 if (i < 0 || (size_t)i >= self->size) {
905 PyErr_SetString(PyExc_IndexError,
906 "mmap index out of range");
907 return -1;
908 }
909 if (value == NULL) {
910 PyErr_SetString(PyExc_TypeError,
911 "mmap object doesn't support item deletion");
912 return -1;
913 }
914 if (!PyString_Check(value) || PyString_Size(value) != 1) {
915 PyErr_SetString(PyExc_IndexError,
916 "mmap assignment must be single-character string");
917 return -1;
918 }
919 if (!is_writeable(self))
920 return -1;
921 buf = PyString_AsString(value);
922 self->data[i] = buf[0];
923 return 0;
924 }
925 else if (PySlice_Check(item)) {
926 Py_ssize_t start, stop, step, slicelen;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000927
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000928 if (PySlice_GetIndicesEx((PySliceObject *)item,
929 self->size, &start, &stop,
930 &step, &slicelen) < 0) {
931 return -1;
932 }
933 if (value == NULL) {
934 PyErr_SetString(PyExc_TypeError,
935 "mmap object doesn't support slice deletion");
936 return -1;
937 }
938 if (!PyString_Check(value)) {
939 PyErr_SetString(PyExc_IndexError,
940 "mmap slice assignment must be a string");
941 return -1;
942 }
943 if (PyString_Size(value) != slicelen) {
944 PyErr_SetString(PyExc_IndexError,
945 "mmap slice assignment is wrong size");
946 return -1;
947 }
948 if (!is_writeable(self))
949 return -1;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000950
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000951 if (slicelen == 0)
952 return 0;
953 else if (step == 1) {
954 const char *buf = PyString_AsString(value);
955
956 if (buf == NULL)
957 return -1;
958 memcpy(self->data + start, buf, slicelen);
959 return 0;
960 }
961 else {
962 Py_ssize_t cur, i;
963 const char *buf = PyString_AsString(value);
964
965 if (buf == NULL)
966 return -1;
967 for (cur = start, i = 0; i < slicelen;
968 cur += step, i++) {
969 self->data[cur] = buf[i];
970 }
971 return 0;
972 }
973 }
974 else {
975 PyErr_SetString(PyExc_TypeError,
976 "mmap indices must be integer");
977 return -1;
978 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000979}
980
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000981static PySequenceMethods mmap_as_sequence = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000982 (lenfunc)mmap_length, /*sq_length*/
983 (binaryfunc)mmap_concat, /*sq_concat*/
984 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
985 (ssizeargfunc)mmap_item, /*sq_item*/
986 (ssizessizeargfunc)mmap_slice, /*sq_slice*/
987 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
988 (ssizessizeobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000989};
990
Thomas Wouters3ccec682007-08-28 15:28:19 +0000991static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000992 (lenfunc)mmap_length,
993 (binaryfunc)mmap_subscript,
994 (objobjargproc)mmap_ass_subscript,
Thomas Wouters3ccec682007-08-28 15:28:19 +0000995};
996
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000997static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +0000998 (readbufferproc)mmap_buffer_getreadbuf,
999 (writebufferproc)mmap_buffer_getwritebuf,
1000 (segcountproc)mmap_buffer_getsegcount,
1001 (charbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001002};
1003
Georg Brandl845c4032008-01-21 14:16:46 +00001004static PyObject *
1005new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
1006
Georg Brandlef928022008-01-20 14:50:05 +00001007PyDoc_STRVAR(mmap_doc,
1008"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
1009\n\
1010Maps length bytes from the file specified by the file handle fileno,\n\
1011and returns a mmap object. If length is larger than the current size\n\
1012of the file, the file is extended to contain length bytes. If length\n\
1013is 0, the maximum length of the map is the current size of the file,\n\
1014except that if the file is empty Windows raises an exception (you cannot\n\
1015create an empty mapping on Windows).\n\
1016\n\
1017Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
1018\n\
1019Maps length bytes from the file specified by the file descriptor fileno,\n\
1020and returns a mmap object. If length is 0, the maximum length of the map\n\
1021will be the current size of the file when mmap is called.\n\
1022flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1023private copy-on-write mapping, so changes to the contents of the mmap\n\
Thomas Heller66260992008-08-19 17:47:13 +00001024object will be private to this process, and MAP_SHARED creates a mapping\n\
Georg Brandlef928022008-01-20 14:50:05 +00001025that's shared with all other processes mapping the same areas of the file.\n\
1026The default value is MAP_SHARED.\n\
1027\n\
1028To map anonymous memory, pass -1 as the fileno (both versions).");
1029
1030
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001031static PyTypeObject mmap_object_type = {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001032 PyVarObject_HEAD_INIT(NULL, 0)
1033 "mmap.mmap", /* tp_name */
1034 sizeof(mmap_object), /* tp_size */
1035 0, /* tp_itemsize */
1036 /* methods */
1037 (destructor) mmap_object_dealloc, /* tp_dealloc */
1038 0, /* tp_print */
1039 0, /* tp_getattr */
1040 0, /* tp_setattr */
1041 0, /* tp_compare */
1042 0, /* tp_repr */
1043 0, /* tp_as_number */
1044 &mmap_as_sequence, /*tp_as_sequence*/
1045 &mmap_as_mapping, /*tp_as_mapping*/
1046 0, /*tp_hash*/
1047 0, /*tp_call*/
1048 0, /*tp_str*/
1049 PyObject_GenericGetAttr, /*tp_getattro*/
1050 0, /*tp_setattro*/
1051 &mmap_as_buffer, /*tp_as_buffer*/
1052 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
1053 mmap_doc, /*tp_doc*/
1054 0, /* tp_traverse */
1055 0, /* tp_clear */
1056 0, /* tp_richcompare */
1057 0, /* tp_weaklistoffset */
1058 0, /* tp_iter */
1059 0, /* tp_iternext */
1060 mmap_object_methods, /* tp_methods */
1061 0, /* tp_members */
1062 0, /* tp_getset */
1063 0, /* tp_base */
1064 0, /* tp_dict */
1065 0, /* tp_descr_get */
1066 0, /* tp_descr_set */
1067 0, /* tp_dictoffset */
1068 0, /* tp_init */
1069 PyType_GenericAlloc, /* tp_alloc */
1070 new_mmap_object, /* tp_new */
1071 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001072};
1073
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001074
1075/* extract the map size from the given PyObject
1076
Thomas Wouters7e474022000-07-16 12:04:32 +00001077 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001078 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001079static Py_ssize_t
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001080_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001081{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001082 if (o == NULL)
1083 return 0;
1084 if (PyIndex_Check(o)) {
1085 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1086 if (i==-1 && PyErr_Occurred())
1087 return -1;
1088 if (i < 0) {
1089 PyErr_Format(PyExc_OverflowError,
1090 "memory mapped %s must be positive",
1091 param);
1092 return -1;
1093 }
1094 return i;
1095 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001096
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001097 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1098 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001099}
1100
Tim Petersec0a5f02006-02-16 23:47:20 +00001101#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001102static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001103new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001104{
Neal Norwitzb5673922002-09-05 21:48:07 +00001105#ifdef HAVE_FSTAT
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001106 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001107#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001108 mmap_object *m_obj;
1109 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1110 Py_ssize_t map_size, offset;
1111 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1112 int devzero = -1;
1113 int access = (int)ACCESS_DEFAULT;
1114 static char *keywords[] = {"fileno", "length",
1115 "flags", "prot",
1116 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001117
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001118 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iiiO", keywords,
1119 &fd, &map_size_obj, &flags, &prot,
1120 &access, &offset_obj))
1121 return NULL;
1122 map_size = _GetMapSize(map_size_obj, "size");
1123 if (map_size < 0)
1124 return NULL;
1125 offset = _GetMapSize(offset_obj, "offset");
1126 if (offset < 0)
1127 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001128
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001129 if ((access != (int)ACCESS_DEFAULT) &&
1130 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1131 return PyErr_Format(PyExc_ValueError,
1132 "mmap can't specify both access and flags, prot.");
1133 switch ((access_mode)access) {
1134 case ACCESS_READ:
1135 flags = MAP_SHARED;
1136 prot = PROT_READ;
1137 break;
1138 case ACCESS_WRITE:
1139 flags = MAP_SHARED;
1140 prot = PROT_READ | PROT_WRITE;
1141 break;
1142 case ACCESS_COPY:
1143 flags = MAP_PRIVATE;
1144 prot = PROT_READ | PROT_WRITE;
1145 break;
1146 case ACCESS_DEFAULT:
1147 /* use the specified or default values of flags and prot */
1148 break;
1149 default:
1150 return PyErr_Format(PyExc_ValueError,
1151 "mmap invalid access parameter.");
1152 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001153
Christian Heimes7adfad82008-02-15 08:20:11 +00001154 if (prot == PROT_READ) {
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001155 access = ACCESS_READ;
Christian Heimes7adfad82008-02-15 08:20:11 +00001156 }
1157
Neal Norwitzb5673922002-09-05 21:48:07 +00001158#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001159# ifdef __VMS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001160 /* on OpenVMS we must ensure that all bytes are written to the file */
1161 if (fd != -1) {
1162 fsync(fd);
1163 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001164# endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001165 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1166 if (map_size == 0) {
1167 map_size = st.st_size;
1168 } else if ((size_t)offset + (size_t)map_size > st.st_size) {
1169 PyErr_SetString(PyExc_ValueError,
1170 "mmap length is greater than file size");
1171 return NULL;
1172 }
1173 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001174#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001175 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1176 if (m_obj == NULL) {return NULL;}
1177 m_obj->data = NULL;
1178 m_obj->size = (size_t) map_size;
1179 m_obj->pos = (size_t) 0;
1180 m_obj->offset = offset;
1181 if (fd == -1) {
1182 m_obj->fd = -1;
1183 /* Assume the caller wants to map anonymous memory.
1184 This is the same behaviour as Windows. mmap.mmap(-1, size)
1185 on both Windows and Unix map anonymous memory.
1186 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001187#ifdef MAP_ANONYMOUS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001188 /* BSD way to map anonymous memory */
1189 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001190#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001191 /* SVR4 method to map anonymous memory is to open /dev/zero */
1192 fd = devzero = open("/dev/zero", O_RDWR);
1193 if (devzero == -1) {
1194 Py_DECREF(m_obj);
1195 PyErr_SetFromErrno(mmap_module_error);
1196 return NULL;
1197 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001198#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001199 } else {
1200 m_obj->fd = dup(fd);
1201 if (m_obj->fd == -1) {
1202 Py_DECREF(m_obj);
1203 PyErr_SetFromErrno(mmap_module_error);
1204 return NULL;
1205 }
1206 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001207
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001208 m_obj->data = mmap(NULL, map_size,
1209 prot, flags,
1210 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001211
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001212 if (devzero != -1) {
1213 close(devzero);
1214 }
1215
1216 if (m_obj->data == (char *)-1) {
1217 m_obj->data = NULL;
1218 Py_DECREF(m_obj);
1219 PyErr_SetFromErrno(mmap_module_error);
1220 return NULL;
1221 }
1222 m_obj->access = (access_mode)access;
1223 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001224}
1225#endif /* UNIX */
1226
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001227#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001228static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001229new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001230{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001231 mmap_object *m_obj;
1232 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1233 Py_ssize_t map_size, offset;
1234 DWORD off_hi; /* upper 32 bits of offset */
1235 DWORD off_lo; /* lower 32 bits of offset */
1236 DWORD size_hi; /* upper 32 bits of size */
1237 DWORD size_lo; /* lower 32 bits of size */
1238 char *tagname = "";
1239 DWORD dwErr = 0;
1240 int fileno;
1241 HANDLE fh = 0;
1242 int access = (access_mode)ACCESS_DEFAULT;
1243 DWORD flProtect, dwDesiredAccess;
1244 static char *keywords[] = { "fileno", "length",
1245 "tagname",
1246 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001247
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001248 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
1249 &fileno, &map_size_obj,
1250 &tagname, &access, &offset_obj)) {
1251 return NULL;
1252 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001253
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001254 switch((access_mode)access) {
1255 case ACCESS_READ:
1256 flProtect = PAGE_READONLY;
1257 dwDesiredAccess = FILE_MAP_READ;
1258 break;
1259 case ACCESS_DEFAULT: case ACCESS_WRITE:
1260 flProtect = PAGE_READWRITE;
1261 dwDesiredAccess = FILE_MAP_WRITE;
1262 break;
1263 case ACCESS_COPY:
1264 flProtect = PAGE_WRITECOPY;
1265 dwDesiredAccess = FILE_MAP_COPY;
1266 break;
1267 default:
1268 return PyErr_Format(PyExc_ValueError,
1269 "mmap invalid access parameter.");
1270 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001271
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001272 map_size = _GetMapSize(map_size_obj, "size");
1273 if (map_size < 0)
1274 return NULL;
1275 offset = _GetMapSize(offset_obj, "offset");
1276 if (offset < 0)
1277 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001278
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001279 /* assume -1 and 0 both mean invalid filedescriptor
1280 to 'anonymously' map memory.
1281 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1282 XXX: Should this code be added?
1283 if (fileno == 0)
1284 PyErr_Warn(PyExc_DeprecationWarning,
1285 "don't use 0 for anonymous memory");
1286 */
1287 if (fileno != -1 && fileno != 0) {
Brian Curtinba6c08e2010-08-01 15:47:53 +00001288 /* Ensure that fileno is within the CRT's valid range */
1289 if (_PyVerify_fd(fileno) == 0) {
1290 PyErr_SetFromErrno(mmap_module_error);
1291 return NULL;
1292 }
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001293 fh = (HANDLE)_get_osfhandle(fileno);
1294 if (fh==(HANDLE)-1) {
1295 PyErr_SetFromErrno(mmap_module_error);
1296 return NULL;
1297 }
1298 /* Win9x appears to need us seeked to zero */
1299 lseek(fileno, 0, SEEK_SET);
1300 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001301
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001302 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1303 if (m_obj == NULL)
1304 return NULL;
1305 /* Set every field to an invalid marker, so we can safely
1306 destruct the object in the face of failure */
1307 m_obj->data = NULL;
1308 m_obj->file_handle = INVALID_HANDLE_VALUE;
1309 m_obj->map_handle = NULL;
1310 m_obj->tagname = NULL;
1311 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001312
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001313 if (fh) {
1314 /* It is necessary to duplicate the handle, so the
1315 Python code can close it on us */
1316 if (!DuplicateHandle(
1317 GetCurrentProcess(), /* source process handle */
1318 fh, /* handle to be duplicated */
1319 GetCurrentProcess(), /* target proc handle */
1320 (LPHANDLE)&m_obj->file_handle, /* result */
1321 0, /* access - ignored due to options value */
1322 FALSE, /* inherited by child processes? */
1323 DUPLICATE_SAME_ACCESS)) { /* options */
1324 dwErr = GetLastError();
1325 Py_DECREF(m_obj);
1326 PyErr_SetFromWindowsErr(dwErr);
1327 return NULL;
1328 }
1329 if (!map_size) {
1330 DWORD low,high;
1331 low = GetFileSize(fh, &high);
1332 /* low might just happen to have the value INVALID_FILE_SIZE;
1333 so we need to check the last error also. */
1334 if (low == INVALID_FILE_SIZE &&
1335 (dwErr = GetLastError()) != NO_ERROR) {
1336 Py_DECREF(m_obj);
1337 return PyErr_SetFromWindowsErr(dwErr);
1338 }
1339
Martin v. Löwis15186072006-02-18 12:38:35 +00001340#if SIZEOF_SIZE_T > 4
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001341 m_obj->size = (((size_t)high)<<32) + low;
Martin v. Löwis15186072006-02-18 12:38:35 +00001342#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001343 if (high)
1344 /* File is too large to map completely */
1345 m_obj->size = (size_t)-1;
1346 else
1347 m_obj->size = low;
Martin v. Löwis15186072006-02-18 12:38:35 +00001348#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001349 } else {
1350 m_obj->size = map_size;
1351 }
1352 }
1353 else {
1354 m_obj->size = map_size;
1355 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001356
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001357 /* set the initial position */
1358 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001359
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001360 /* set the tag name */
1361 if (tagname != NULL && *tagname != '\0') {
1362 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1363 if (m_obj->tagname == NULL) {
1364 PyErr_NoMemory();
1365 Py_DECREF(m_obj);
1366 return NULL;
1367 }
1368 strcpy(m_obj->tagname, tagname);
1369 }
1370 else
1371 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001372
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001373 m_obj->access = (access_mode)access;
1374 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
1375 * more than 4 bytes, we need to break it apart. Else (size_t
1376 * consumes 4 bytes), C doesn't define what happens if we shift
1377 * right by 32, so we need different code.
1378 */
Tim Peterse564e7f2006-02-16 23:46:01 +00001379#if SIZEOF_SIZE_T > 4
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001380 size_hi = (DWORD)((offset + m_obj->size) >> 32);
1381 size_lo = (DWORD)((offset + m_obj->size) & 0xFFFFFFFF);
1382 off_hi = (DWORD)(offset >> 32);
1383 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Tim Peterse564e7f2006-02-16 23:46:01 +00001384#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001385 size_hi = 0;
1386 size_lo = (DWORD)(offset + m_obj->size);
1387 off_hi = 0;
1388 off_lo = (DWORD)offset;
Tim Peterse564e7f2006-02-16 23:46:01 +00001389#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001390 /* For files, it would be sufficient to pass 0 as size.
1391 For anonymous maps, we have to pass the size explicitly. */
1392 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1393 NULL,
1394 flProtect,
1395 size_hi,
1396 size_lo,
1397 m_obj->tagname);
1398 if (m_obj->map_handle != NULL) {
1399 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1400 dwDesiredAccess,
1401 off_hi,
1402 off_lo,
1403 m_obj->size);
1404 if (m_obj->data != NULL)
1405 return (PyObject *)m_obj;
1406 else {
1407 dwErr = GetLastError();
1408 CloseHandle(m_obj->map_handle);
1409 m_obj->map_handle = NULL;
1410 }
1411 } else
1412 dwErr = GetLastError();
1413 Py_DECREF(m_obj);
1414 PyErr_SetFromWindowsErr(dwErr);
1415 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001416}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001417#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001418
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001419static void
1420setint(PyObject *d, const char *name, long value)
1421{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001422 PyObject *o = PyInt_FromLong(value);
1423 if (o && PyDict_SetItemString(d, name, o) == 0) {
1424 Py_DECREF(o);
1425 }
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001426}
1427
Mark Hammond62b1ab12002-07-23 06:31:15 +00001428PyMODINIT_FUNC
Georg Brandl845c4032008-01-21 14:16:46 +00001429initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001430{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001431 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001432
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001433 if (PyType_Ready(&mmap_object_type) < 0)
1434 return;
Tim Peters2caf8df2001-01-14 05:05:51 +00001435
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001436 module = Py_InitModule("mmap", NULL);
1437 if (module == NULL)
1438 return;
1439 dict = PyModule_GetDict(module);
1440 if (!dict)
1441 return;
1442 mmap_module_error = PyErr_NewException("mmap.error",
1443 PyExc_EnvironmentError , NULL);
1444 if (mmap_module_error == NULL)
1445 return;
1446 PyDict_SetItemString(dict, "error", mmap_module_error);
1447 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001448#ifdef PROT_EXEC
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001449 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001450#endif
1451#ifdef PROT_READ
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001452 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001453#endif
1454#ifdef PROT_WRITE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001455 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001456#endif
1457
1458#ifdef MAP_SHARED
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001459 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001460#endif
1461#ifdef MAP_PRIVATE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001462 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001463#endif
1464#ifdef MAP_DENYWRITE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001465 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001466#endif
1467#ifdef MAP_EXECUTABLE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001468 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001469#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001470#ifdef MAP_ANONYMOUS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001471 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1472 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001473#endif
1474
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001475 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001476
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001477 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001478
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001479 setint(dict, "ACCESS_READ", ACCESS_READ);
1480 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1481 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Tim Peters5ebfd362001-11-13 23:11:19 +00001482}