blob: 4b2a97112b0ec8a305eabc892e70dec718414993 [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) {
Antoine Pitrou8a0eede2011-01-20 21:20:18 +00001167 if (offset >= st.st_size) {
1168 PyErr_SetString(PyExc_ValueError,
1169 "mmap offset is greater than file size");
1170 return NULL;
1171 }
Antoine Pitrou9989d852011-01-15 16:18:57 +00001172 map_size = st.st_size - offset;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001173 } else if ((size_t)offset + (size_t)map_size > st.st_size) {
1174 PyErr_SetString(PyExc_ValueError,
1175 "mmap length is greater than file size");
1176 return NULL;
1177 }
1178 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001179#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001180 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1181 if (m_obj == NULL) {return NULL;}
1182 m_obj->data = NULL;
1183 m_obj->size = (size_t) map_size;
1184 m_obj->pos = (size_t) 0;
1185 m_obj->offset = offset;
1186 if (fd == -1) {
1187 m_obj->fd = -1;
1188 /* Assume the caller wants to map anonymous memory.
1189 This is the same behaviour as Windows. mmap.mmap(-1, size)
1190 on both Windows and Unix map anonymous memory.
1191 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001192#ifdef MAP_ANONYMOUS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001193 /* BSD way to map anonymous memory */
1194 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001195#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001196 /* SVR4 method to map anonymous memory is to open /dev/zero */
1197 fd = devzero = open("/dev/zero", O_RDWR);
1198 if (devzero == -1) {
1199 Py_DECREF(m_obj);
1200 PyErr_SetFromErrno(mmap_module_error);
1201 return NULL;
1202 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001203#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001204 } else {
1205 m_obj->fd = dup(fd);
1206 if (m_obj->fd == -1) {
1207 Py_DECREF(m_obj);
1208 PyErr_SetFromErrno(mmap_module_error);
1209 return NULL;
1210 }
1211 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001212
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001213 m_obj->data = mmap(NULL, map_size,
1214 prot, flags,
1215 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001216
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001217 if (devzero != -1) {
1218 close(devzero);
1219 }
1220
1221 if (m_obj->data == (char *)-1) {
1222 m_obj->data = NULL;
1223 Py_DECREF(m_obj);
1224 PyErr_SetFromErrno(mmap_module_error);
1225 return NULL;
1226 }
1227 m_obj->access = (access_mode)access;
1228 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001229}
1230#endif /* UNIX */
1231
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001232#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001233static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001234new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001235{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001236 mmap_object *m_obj;
1237 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1238 Py_ssize_t map_size, offset;
1239 DWORD off_hi; /* upper 32 bits of offset */
1240 DWORD off_lo; /* lower 32 bits of offset */
1241 DWORD size_hi; /* upper 32 bits of size */
1242 DWORD size_lo; /* lower 32 bits of size */
1243 char *tagname = "";
1244 DWORD dwErr = 0;
1245 int fileno;
1246 HANDLE fh = 0;
1247 int access = (access_mode)ACCESS_DEFAULT;
1248 DWORD flProtect, dwDesiredAccess;
1249 static char *keywords[] = { "fileno", "length",
1250 "tagname",
1251 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001252
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001253 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
1254 &fileno, &map_size_obj,
1255 &tagname, &access, &offset_obj)) {
1256 return NULL;
1257 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001258
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001259 switch((access_mode)access) {
1260 case ACCESS_READ:
1261 flProtect = PAGE_READONLY;
1262 dwDesiredAccess = FILE_MAP_READ;
1263 break;
1264 case ACCESS_DEFAULT: case ACCESS_WRITE:
1265 flProtect = PAGE_READWRITE;
1266 dwDesiredAccess = FILE_MAP_WRITE;
1267 break;
1268 case ACCESS_COPY:
1269 flProtect = PAGE_WRITECOPY;
1270 dwDesiredAccess = FILE_MAP_COPY;
1271 break;
1272 default:
1273 return PyErr_Format(PyExc_ValueError,
1274 "mmap invalid access parameter.");
1275 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001276
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001277 map_size = _GetMapSize(map_size_obj, "size");
1278 if (map_size < 0)
1279 return NULL;
1280 offset = _GetMapSize(offset_obj, "offset");
1281 if (offset < 0)
1282 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001283
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001284 /* assume -1 and 0 both mean invalid filedescriptor
1285 to 'anonymously' map memory.
1286 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1287 XXX: Should this code be added?
1288 if (fileno == 0)
1289 PyErr_Warn(PyExc_DeprecationWarning,
1290 "don't use 0 for anonymous memory");
1291 */
1292 if (fileno != -1 && fileno != 0) {
Brian Curtinba6c08e2010-08-01 15:47:53 +00001293 /* Ensure that fileno is within the CRT's valid range */
1294 if (_PyVerify_fd(fileno) == 0) {
1295 PyErr_SetFromErrno(mmap_module_error);
1296 return NULL;
1297 }
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001298 fh = (HANDLE)_get_osfhandle(fileno);
1299 if (fh==(HANDLE)-1) {
1300 PyErr_SetFromErrno(mmap_module_error);
1301 return NULL;
1302 }
1303 /* Win9x appears to need us seeked to zero */
1304 lseek(fileno, 0, SEEK_SET);
1305 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001306
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001307 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1308 if (m_obj == NULL)
1309 return NULL;
1310 /* Set every field to an invalid marker, so we can safely
1311 destruct the object in the face of failure */
1312 m_obj->data = NULL;
1313 m_obj->file_handle = INVALID_HANDLE_VALUE;
1314 m_obj->map_handle = NULL;
1315 m_obj->tagname = NULL;
1316 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001317
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001318 if (fh) {
1319 /* It is necessary to duplicate the handle, so the
1320 Python code can close it on us */
1321 if (!DuplicateHandle(
1322 GetCurrentProcess(), /* source process handle */
1323 fh, /* handle to be duplicated */
1324 GetCurrentProcess(), /* target proc handle */
1325 (LPHANDLE)&m_obj->file_handle, /* result */
1326 0, /* access - ignored due to options value */
1327 FALSE, /* inherited by child processes? */
1328 DUPLICATE_SAME_ACCESS)) { /* options */
1329 dwErr = GetLastError();
1330 Py_DECREF(m_obj);
1331 PyErr_SetFromWindowsErr(dwErr);
1332 return NULL;
1333 }
1334 if (!map_size) {
1335 DWORD low,high;
1336 low = GetFileSize(fh, &high);
1337 /* low might just happen to have the value INVALID_FILE_SIZE;
1338 so we need to check the last error also. */
1339 if (low == INVALID_FILE_SIZE &&
1340 (dwErr = GetLastError()) != NO_ERROR) {
1341 Py_DECREF(m_obj);
1342 return PyErr_SetFromWindowsErr(dwErr);
1343 }
1344
Martin v. Löwis15186072006-02-18 12:38:35 +00001345#if SIZEOF_SIZE_T > 4
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001346 m_obj->size = (((size_t)high)<<32) + low;
Martin v. Löwis15186072006-02-18 12:38:35 +00001347#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001348 if (high)
1349 /* File is too large to map completely */
1350 m_obj->size = (size_t)-1;
1351 else
1352 m_obj->size = low;
Martin v. Löwis15186072006-02-18 12:38:35 +00001353#endif
Antoine Pitrou8a0eede2011-01-20 21:20:18 +00001354 if (offset >= m_obj->size) {
1355 PyErr_SetString(PyExc_ValueError,
1356 "mmap offset is greater than file size");
1357 Py_DECREF(m_obj);
1358 return NULL;
1359 }
Antoine Pitrou533aa252011-01-15 17:40:00 +00001360 m_obj->size -= offset;
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001361 } else {
1362 m_obj->size = map_size;
1363 }
1364 }
1365 else {
1366 m_obj->size = map_size;
1367 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001368
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001369 /* set the initial position */
1370 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001371
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001372 /* set the tag name */
1373 if (tagname != NULL && *tagname != '\0') {
1374 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1375 if (m_obj->tagname == NULL) {
1376 PyErr_NoMemory();
1377 Py_DECREF(m_obj);
1378 return NULL;
1379 }
1380 strcpy(m_obj->tagname, tagname);
1381 }
1382 else
1383 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001384
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001385 m_obj->access = (access_mode)access;
1386 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
1387 * more than 4 bytes, we need to break it apart. Else (size_t
1388 * consumes 4 bytes), C doesn't define what happens if we shift
1389 * right by 32, so we need different code.
1390 */
Tim Peterse564e7f2006-02-16 23:46:01 +00001391#if SIZEOF_SIZE_T > 4
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001392 size_hi = (DWORD)((offset + m_obj->size) >> 32);
1393 size_lo = (DWORD)((offset + m_obj->size) & 0xFFFFFFFF);
1394 off_hi = (DWORD)(offset >> 32);
1395 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Tim Peterse564e7f2006-02-16 23:46:01 +00001396#else
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001397 size_hi = 0;
1398 size_lo = (DWORD)(offset + m_obj->size);
1399 off_hi = 0;
1400 off_lo = (DWORD)offset;
Tim Peterse564e7f2006-02-16 23:46:01 +00001401#endif
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001402 /* For files, it would be sufficient to pass 0 as size.
1403 For anonymous maps, we have to pass the size explicitly. */
1404 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1405 NULL,
1406 flProtect,
1407 size_hi,
1408 size_lo,
1409 m_obj->tagname);
1410 if (m_obj->map_handle != NULL) {
1411 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1412 dwDesiredAccess,
1413 off_hi,
1414 off_lo,
1415 m_obj->size);
1416 if (m_obj->data != NULL)
1417 return (PyObject *)m_obj;
1418 else {
1419 dwErr = GetLastError();
1420 CloseHandle(m_obj->map_handle);
1421 m_obj->map_handle = NULL;
1422 }
1423 } else
1424 dwErr = GetLastError();
1425 Py_DECREF(m_obj);
1426 PyErr_SetFromWindowsErr(dwErr);
1427 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001428}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001429#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001430
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001431static void
1432setint(PyObject *d, const char *name, long value)
1433{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001434 PyObject *o = PyInt_FromLong(value);
1435 if (o && PyDict_SetItemString(d, name, o) == 0) {
1436 Py_DECREF(o);
1437 }
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001438}
1439
Mark Hammond62b1ab12002-07-23 06:31:15 +00001440PyMODINIT_FUNC
Georg Brandl845c4032008-01-21 14:16:46 +00001441initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001442{
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001443 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001444
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001445 if (PyType_Ready(&mmap_object_type) < 0)
1446 return;
Tim Peters2caf8df2001-01-14 05:05:51 +00001447
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001448 module = Py_InitModule("mmap", NULL);
1449 if (module == NULL)
1450 return;
1451 dict = PyModule_GetDict(module);
1452 if (!dict)
1453 return;
1454 mmap_module_error = PyErr_NewException("mmap.error",
1455 PyExc_EnvironmentError , NULL);
1456 if (mmap_module_error == NULL)
1457 return;
1458 PyDict_SetItemString(dict, "error", mmap_module_error);
1459 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001460#ifdef PROT_EXEC
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001461 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001462#endif
1463#ifdef PROT_READ
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001464 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001465#endif
1466#ifdef PROT_WRITE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001467 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001468#endif
1469
1470#ifdef MAP_SHARED
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001471 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001472#endif
1473#ifdef MAP_PRIVATE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001474 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001475#endif
1476#ifdef MAP_DENYWRITE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001477 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001478#endif
1479#ifdef MAP_EXECUTABLE
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001480 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001481#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001482#ifdef MAP_ANONYMOUS
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001483 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1484 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001485#endif
1486
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001487 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001488
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001489 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001490
Antoine Pitrouc83ea132010-05-09 14:46:46 +00001491 setint(dict, "ACCESS_READ", ACCESS_READ);
1492 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1493 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Tim Peters5ebfd362001-11-13 23:11:19 +00001494}