blob: 24f78513dbed4ca4e266d921ad8c7f89a28f78c6 [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 Pitrouc7c96a92010-05-09 15:15:40 +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 Pitrouc7c96a92010-05-09 15:15:40 +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 Pitrouc7c96a92010-05-09 15:15:40 +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 Pitrouc7c96a92010-05-09 15:15:40 +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 Pitrouc7c96a92010-05-09 15:15:40 +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 Pitrouc7c96a92010-05-09 15:15:40 +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 Pitrouc7c96a92010-05-09 15:15:40 +0000102 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000103#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000104
Antoine Pitrouc7c96a92010-05-09 15:15:40 +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 Pitrouc7c96a92010-05-09 15:15:40 +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 Pitrouc7c96a92010-05-09 15:15:40 +0000124 if (m_obj->fd >= 0)
125 (void) close(m_obj->fd);
126 if (m_obj->data!=NULL) {
127 msync(m_obj->data, m_obj->size, MS_SYNC);
128 munmap(m_obj->data, m_obj->size);
129 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000130#endif /* UNIX */
131
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000132 Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000133}
134
135static PyObject *
Georg Brandl96a8c392006-05-29 21:04:52 +0000136mmap_close_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000137{
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000138#ifdef MS_WINDOWS
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000139 /* For each resource we maintain, we need to check
140 the value is valid, and if so, free the resource
141 and set the member value to an invalid value so
142 the dealloc does not attempt to resource clearing
143 again.
144 TODO - should we check for errors in the close operations???
145 */
146 if (self->data != NULL) {
147 UnmapViewOfFile(self->data);
148 self->data = NULL;
149 }
150 if (self->map_handle != NULL) {
151 CloseHandle(self->map_handle);
152 self->map_handle = NULL;
153 }
154 if (self->file_handle != INVALID_HANDLE_VALUE) {
155 CloseHandle(self->file_handle);
156 self->file_handle = INVALID_HANDLE_VALUE;
157 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000158#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000159
160#ifdef UNIX
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000161 if (0 <= self->fd)
162 (void) close(self->fd);
163 self->fd = -1;
164 if (self->data != NULL) {
165 munmap(self->data, self->size);
166 self->data = NULL;
167 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000168#endif
169
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000170 Py_INCREF(Py_None);
171 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000172}
173
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000174#ifdef MS_WINDOWS
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000175#define CHECK_VALID(err) \
176do { \
177 if (self->map_handle == NULL) { \
178 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
179 return err; \
180 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000181} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000182#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000183
184#ifdef UNIX
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000185#define CHECK_VALID(err) \
186do { \
187 if (self->data == NULL) { \
188 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
189 return err; \
190 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000191} while (0)
192#endif /* UNIX */
193
194static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000195mmap_read_byte_method(mmap_object *self,
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000196 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000197{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000198 CHECK_VALID(NULL);
199 if (self->pos < self->size) {
200 char value = self->data[self->pos];
201 self->pos += 1;
202 return Py_BuildValue("c", value);
203 } else {
204 PyErr_SetString(PyExc_ValueError, "read byte out of range");
205 return NULL;
206 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000207}
208
209static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000210mmap_read_line_method(mmap_object *self,
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000211 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000212{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000213 char *start = self->data+self->pos;
214 char *eof = self->data+self->size;
215 char *eol;
216 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000217
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000218 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000219
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000220 eol = memchr(start, '\n', self->size - self->pos);
221 if (!eol)
222 eol = eof;
223 else
224 ++eol; /* we're interested in the position after the
225 newline. */
226 result = PyString_FromStringAndSize(start, (eol - start));
227 self->pos += (eol - start);
228 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000229}
230
231static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000232mmap_read_method(mmap_object *self,
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000233 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000234{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000235 Py_ssize_t num_bytes, n;
236 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000237
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000238 CHECK_VALID(NULL);
239 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
240 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000241
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000242 /* silently 'adjust' out-of-range requests */
243 assert(self->size >= self->pos);
244 n = self->size - self->pos;
245 /* The difference can overflow, only if self->size is greater than
246 * PY_SSIZE_T_MAX. But then the operation cannot possibly succeed,
247 * because the mapped area and the returned string each need more
248 * than half of the addressable memory. So we clip the size, and let
249 * the code below raise MemoryError.
250 */
251 if (n < 0)
252 n = PY_SSIZE_T_MAX;
253 if (num_bytes < 0 || num_bytes > n) {
254 num_bytes = n;
255 }
256 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
257 self->pos += num_bytes;
258 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000259}
260
261static PyObject *
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000262mmap_gfind(mmap_object *self,
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000263 PyObject *args,
264 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000265{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000266 Py_ssize_t start = self->pos;
267 Py_ssize_t end = self->size;
268 const char *needle;
269 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000270
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000271 CHECK_VALID(NULL);
272 if (!PyArg_ParseTuple(args, reverse ? "s#|nn:rfind" : "s#|nn:find",
273 &needle, &len, &start, &end)) {
274 return NULL;
275 } else {
276 const char *p, *start_p, *end_p;
277 int sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000278
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000279 if (start < 0)
280 start += self->size;
281 if (start < 0)
282 start = 0;
283 else if ((size_t)start > self->size)
284 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000285
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000286 if (end < 0)
287 end += self->size;
288 if (end < 0)
289 end = 0;
290 else if ((size_t)end > self->size)
291 end = self->size;
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000292
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000293 start_p = self->data + start;
294 end_p = self->data + end;
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000295
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000296 for (p = (reverse ? end_p - len : start_p);
297 (p >= start_p) && (p + len <= end_p); p += sign) {
298 Py_ssize_t i;
299 for (i = 0; i < len && needle[i] == p[i]; ++i)
300 /* nothing */;
301 if (i == len) {
302 return PyInt_FromSsize_t(p - self->data);
303 }
304 }
305 return PyInt_FromLong(-1);
306 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000307}
308
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000309static PyObject *
310mmap_find_method(mmap_object *self,
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000311 PyObject *args)
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000312{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000313 return mmap_gfind(self, args, 0);
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000314}
315
316static PyObject *
317mmap_rfind_method(mmap_object *self,
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000318 PyObject *args)
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000319{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000320 return mmap_gfind(self, args, 1);
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000321}
322
Tim Petersec0a5f02006-02-16 23:47:20 +0000323static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000324is_writeable(mmap_object *self)
325{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000326 if (self->access != ACCESS_READ)
327 return 1;
328 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
329 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000330}
331
Tim Petersec0a5f02006-02-16 23:47:20 +0000332static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000333is_resizeable(mmap_object *self)
334{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000335 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
336 return 1;
337 PyErr_Format(PyExc_TypeError,
338 "mmap can't resize a readonly or copy-on-write memory map.");
339 return 0;
Tim Peters5ebfd362001-11-13 23:11:19 +0000340}
341
342
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000343static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000344mmap_write_method(mmap_object *self,
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000345 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000346{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000347 Py_ssize_t length;
348 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000349
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000350 CHECK_VALID(NULL);
351 if (!PyArg_ParseTuple(args, "s#:write", &data, &length))
352 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000353
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000354 if (!is_writeable(self))
355 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +0000356
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000357 if ((self->pos + length) > self->size) {
358 PyErr_SetString(PyExc_ValueError, "data out of range");
359 return NULL;
360 }
361 memcpy(self->data+self->pos, data, length);
362 self->pos = self->pos+length;
363 Py_INCREF(Py_None);
364 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000365}
366
367static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000368mmap_write_byte_method(mmap_object *self,
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000369 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000370{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000371 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000372
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000373 CHECK_VALID(NULL);
374 if (!PyArg_ParseTuple(args, "c:write_byte", &value))
375 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000376
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000377 if (!is_writeable(self))
378 return NULL;
Hirokazu Yamamotoe363fa02009-02-28 11:39:45 +0000379
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000380 if (self->pos < self->size) {
381 *(self->data+self->pos) = value;
382 self->pos += 1;
383 Py_INCREF(Py_None);
384 return Py_None;
385 }
386 else {
387 PyErr_SetString(PyExc_ValueError, "write byte out of range");
388 return NULL;
389 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000390}
Tim Petersec0a5f02006-02-16 23:47:20 +0000391
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000392static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000393mmap_size_method(mmap_object *self,
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000394 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000395{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000396 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000397
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000398#ifdef MS_WINDOWS
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000399 if (self->file_handle != INVALID_HANDLE_VALUE) {
400 DWORD low,high;
401 PY_LONG_LONG size;
402 low = GetFileSize(self->file_handle, &high);
403 if (low == INVALID_FILE_SIZE) {
404 /* It might be that the function appears to have failed,
405 when indeed its size equals INVALID_FILE_SIZE */
406 DWORD error = GetLastError();
407 if (error != NO_ERROR)
408 return PyErr_SetFromWindowsErr(error);
409 }
410 if (!high && low < LONG_MAX)
411 return PyInt_FromLong((long)low);
412 size = (((PY_LONG_LONG)high)<<32) + low;
413 return PyLong_FromLongLong(size);
414 } else {
415 return PyInt_FromSsize_t(self->size);
416 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000417#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000418
419#ifdef UNIX
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000420 {
421 struct stat buf;
422 if (-1 == fstat(self->fd, &buf)) {
423 PyErr_SetFromErrno(mmap_module_error);
424 return NULL;
425 }
426 return PyInt_FromSsize_t(buf.st_size);
427 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000428#endif /* UNIX */
429}
430
431/* This assumes that you want the entire file mapped,
432 / and when recreating the map will make the new file
433 / have the new size
434 /
435 / Is this really necessary? This could easily be done
436 / from python by just closing and re-opening with the
437 / new size?
438 */
439
440static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000441mmap_resize_method(mmap_object *self,
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000442 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000443{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000444 Py_ssize_t new_size;
445 CHECK_VALID(NULL);
446 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
447 !is_resizeable(self)) {
448 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000449#ifdef MS_WINDOWS
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000450 } else {
451 DWORD dwErrCode = 0;
452 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
453 /* First, unmap the file view */
454 UnmapViewOfFile(self->data);
455 self->data = NULL;
456 /* Close the mapping object */
457 CloseHandle(self->map_handle);
458 self->map_handle = NULL;
459 /* Move to the desired EOF position */
Martin v. Löwis15186072006-02-18 12:38:35 +0000460#if SIZEOF_SIZE_T > 4
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000461 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
462 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
463 off_hi = (DWORD)(self->offset >> 32);
464 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Martin v. Löwis15186072006-02-18 12:38:35 +0000465#else
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000466 newSizeHigh = 0;
467 newSizeLow = (DWORD)(self->offset + new_size);
468 off_hi = 0;
469 off_lo = (DWORD)self->offset;
Martin v. Löwis15186072006-02-18 12:38:35 +0000470#endif
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000471 SetFilePointer(self->file_handle,
472 newSizeLow, &newSizeHigh, FILE_BEGIN);
473 /* Change the size of the file */
474 SetEndOfFile(self->file_handle);
475 /* Create another mapping object and remap the file view */
476 self->map_handle = CreateFileMapping(
477 self->file_handle,
478 NULL,
479 PAGE_READWRITE,
480 0,
481 0,
482 self->tagname);
483 if (self->map_handle != NULL) {
484 self->data = (char *) MapViewOfFile(self->map_handle,
485 FILE_MAP_WRITE,
486 off_hi,
487 off_lo,
488 new_size);
489 if (self->data != NULL) {
490 self->size = new_size;
491 Py_INCREF(Py_None);
492 return Py_None;
493 } else {
494 dwErrCode = GetLastError();
495 CloseHandle(self->map_handle);
496 self->map_handle = NULL;
497 }
498 } else {
499 dwErrCode = GetLastError();
500 }
501 PyErr_SetFromWindowsErr(dwErrCode);
502 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000503#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000504
505#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000506#ifndef HAVE_MREMAP
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000507 } else {
508 PyErr_SetString(PyExc_SystemError,
509 "mmap: resizing not available--no mremap()");
510 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000511#else
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000512 } else {
513 void *newmap;
Armin Rigo335ffe82005-09-20 19:04:02 +0000514
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000515 if (ftruncate(self->fd, self->offset + new_size) == -1) {
516 PyErr_SetFromErrno(mmap_module_error);
517 return NULL;
518 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000519
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000520#ifdef MREMAP_MAYMOVE
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000521 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000522#else
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000523 #if defined(__NetBSD__)
524 newmap = mremap(self->data, self->size, self->data, new_size, 0);
525 #else
526 newmap = mremap(self->data, self->size, new_size, 0);
527 #endif /* __NetBSD__ */
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000528#endif
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000529 if (newmap == (void *)-1)
530 {
531 PyErr_SetFromErrno(mmap_module_error);
532 return NULL;
533 }
534 self->data = newmap;
535 self->size = new_size;
536 Py_INCREF(Py_None);
537 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000538#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000539#endif /* UNIX */
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000540 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000541}
542
543static PyObject *
Georg Brandl96a8c392006-05-29 21:04:52 +0000544mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000545{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000546 CHECK_VALID(NULL);
547 return PyInt_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000548}
549
550static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000551mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000552{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000553 Py_ssize_t offset = 0;
554 Py_ssize_t size = self->size;
555 CHECK_VALID(NULL);
556 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
557 return NULL;
558 if ((size_t)(offset + size) > self->size) {
559 PyErr_SetString(PyExc_ValueError, "flush values out of range");
560 return NULL;
561 }
Neal Norwitz448654f2008-01-27 07:36:03 +0000562#ifdef MS_WINDOWS
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000563 return PyInt_FromLong((long) FlushViewOfFile(self->data+offset, size));
Neal Norwitz448654f2008-01-27 07:36:03 +0000564#elif defined(UNIX)
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000565 /* XXX semantics of return value? */
566 /* XXX flags for msync? */
567 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
568 PyErr_SetFromErrno(mmap_module_error);
569 return NULL;
570 }
571 return PyInt_FromLong(0);
Neal Norwitz448654f2008-01-27 07:36:03 +0000572#else
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000573 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
574 return NULL;
Neal Norwitz448654f2008-01-27 07:36:03 +0000575#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000576}
577
578static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000579mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000580{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000581 Py_ssize_t dist;
582 int how=0;
583 CHECK_VALID(NULL);
584 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
585 return NULL;
586 else {
587 size_t where;
588 switch (how) {
589 case 0: /* relative to start */
590 if (dist < 0)
591 goto onoutofrange;
592 where = dist;
593 break;
594 case 1: /* relative to current position */
595 if ((Py_ssize_t)self->pos + dist < 0)
596 goto onoutofrange;
597 where = self->pos + dist;
598 break;
599 case 2: /* relative to end */
600 if ((Py_ssize_t)self->size + dist < 0)
601 goto onoutofrange;
602 where = self->size + dist;
603 break;
604 default:
605 PyErr_SetString(PyExc_ValueError, "unknown seek type");
606 return NULL;
607 }
608 if (where > self->size)
609 goto onoutofrange;
610 self->pos = where;
611 Py_INCREF(Py_None);
612 return Py_None;
613 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000614
Tim Peters5ebfd362001-11-13 23:11:19 +0000615 onoutofrange:
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000616 PyErr_SetString(PyExc_ValueError, "seek out of range");
617 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000618}
619
620static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000621mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000622{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000623 unsigned long dest, src, count;
624 CHECK_VALID(NULL);
625 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &count) ||
626 !is_writeable(self)) {
627 return NULL;
628 } else {
629 /* bounds check the values */
630 unsigned long pos = src > dest ? src : dest;
631 if (self->size < pos || count > self->size - pos) {
632 PyErr_SetString(PyExc_ValueError,
633 "source or destination out of range");
634 return NULL;
635 } else {
636 memmove(self->data+dest, self->data+src, count);
637 Py_INCREF(Py_None);
638 return Py_None;
639 }
640 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000641}
642
643static struct PyMethodDef mmap_object_methods[] = {
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000644 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
645 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
646 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
647 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
648 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
649 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
650 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
651 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
652 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
653 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
654 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
655 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
656 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
657 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
658 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000659};
660
661/* Functions for treating an mmap'ed file as a buffer */
662
Martin v. Löwis18e16552006-02-15 17:27:45 +0000663static Py_ssize_t
664mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000665{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000666 CHECK_VALID(-1);
667 if (index != 0) {
668 PyErr_SetString(PyExc_SystemError,
669 "Accessing non-existent mmap segment");
670 return -1;
671 }
672 *ptr = self->data;
673 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000674}
675
Martin v. Löwis18e16552006-02-15 17:27:45 +0000676static Py_ssize_t
677mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Tim Petersec0a5f02006-02-16 23:47:20 +0000678{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000679 CHECK_VALID(-1);
680 if (index != 0) {
681 PyErr_SetString(PyExc_SystemError,
682 "Accessing non-existent mmap segment");
683 return -1;
684 }
685 if (!is_writeable(self))
686 return -1;
687 *ptr = self->data;
688 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000689}
690
Martin v. Löwis18e16552006-02-15 17:27:45 +0000691static Py_ssize_t
692mmap_buffer_getsegcount(mmap_object *self, Py_ssize_t *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000693{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000694 CHECK_VALID(-1);
695 if (lenp)
696 *lenp = self->size;
697 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000698}
699
Martin v. Löwis18e16552006-02-15 17:27:45 +0000700static Py_ssize_t
701mmap_buffer_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000702{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000703 if (index != 0) {
704 PyErr_SetString(PyExc_SystemError,
705 "accessing non-existent buffer segment");
706 return -1;
707 }
708 *ptr = (const char *)self->data;
709 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000710}
711
Martin v. Löwis18e16552006-02-15 17:27:45 +0000712static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000713mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000714{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000715 CHECK_VALID(-1);
716 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000717}
718
719static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000720mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000721{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000722 CHECK_VALID(NULL);
723 if (i < 0 || (size_t)i >= self->size) {
724 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
725 return NULL;
726 }
727 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000728}
729
730static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000731mmap_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000732{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000733 CHECK_VALID(NULL);
734 if (ilow < 0)
735 ilow = 0;
736 else if ((size_t)ilow > self->size)
737 ilow = self->size;
738 if (ihigh < 0)
739 ihigh = 0;
740 if (ihigh < ilow)
741 ihigh = ilow;
742 else if ((size_t)ihigh > self->size)
743 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000744
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000745 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000746}
747
748static PyObject *
Thomas Wouters3ccec682007-08-28 15:28:19 +0000749mmap_subscript(mmap_object *self, PyObject *item)
750{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000751 CHECK_VALID(NULL);
752 if (PyIndex_Check(item)) {
753 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
754 if (i == -1 && PyErr_Occurred())
755 return NULL;
756 if (i < 0)
757 i += self->size;
758 if (i < 0 || (size_t)i >= self->size) {
759 PyErr_SetString(PyExc_IndexError,
760 "mmap index out of range");
761 return NULL;
762 }
763 return PyString_FromStringAndSize(self->data + i, 1);
764 }
765 else if (PySlice_Check(item)) {
766 Py_ssize_t start, stop, step, slicelen;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000767
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000768 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
769 &start, &stop, &step, &slicelen) < 0) {
770 return NULL;
771 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000772
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000773 if (slicelen <= 0)
774 return PyString_FromStringAndSize("", 0);
775 else if (step == 1)
776 return PyString_FromStringAndSize(self->data + start,
777 slicelen);
778 else {
779 char *result_buf = (char *)PyMem_Malloc(slicelen);
780 Py_ssize_t cur, i;
781 PyObject *result;
782
783 if (result_buf == NULL)
784 return PyErr_NoMemory();
785 for (cur = start, i = 0; i < slicelen;
786 cur += step, i++) {
787 result_buf[i] = self->data[cur];
788 }
789 result = PyString_FromStringAndSize(result_buf,
790 slicelen);
791 PyMem_Free(result_buf);
792 return result;
793 }
794 }
795 else {
796 PyErr_SetString(PyExc_TypeError,
797 "mmap indices must be integers");
798 return NULL;
799 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000800}
801
802static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000803mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000804{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000805 CHECK_VALID(NULL);
806 PyErr_SetString(PyExc_SystemError,
807 "mmaps don't support concatenation");
808 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000809}
810
811static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000812mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000813{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000814 CHECK_VALID(NULL);
815 PyErr_SetString(PyExc_SystemError,
816 "mmaps don't support repeat operation");
817 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000818}
819
820static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000821mmap_ass_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000822{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000823 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000824
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000825 CHECK_VALID(-1);
826 if (ilow < 0)
827 ilow = 0;
828 else if ((size_t)ilow > self->size)
829 ilow = self->size;
830 if (ihigh < 0)
831 ihigh = 0;
832 if (ihigh < ilow)
833 ihigh = ilow;
834 else if ((size_t)ihigh > self->size)
835 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000836
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000837 if (v == NULL) {
838 PyErr_SetString(PyExc_TypeError,
839 "mmap object doesn't support slice deletion");
840 return -1;
841 }
842 if (! (PyString_Check(v)) ) {
843 PyErr_SetString(PyExc_IndexError,
844 "mmap slice assignment must be a string");
845 return -1;
846 }
847 if (PyString_Size(v) != (ihigh - ilow)) {
848 PyErr_SetString(PyExc_IndexError,
849 "mmap slice assignment is wrong size");
850 return -1;
851 }
852 if (!is_writeable(self))
853 return -1;
854 buf = PyString_AsString(v);
855 memcpy(self->data + ilow, buf, ihigh-ilow);
856 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000857}
858
859static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000860mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000861{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000862 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000863
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000864 CHECK_VALID(-1);
865 if (i < 0 || (size_t)i >= self->size) {
866 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
867 return -1;
868 }
869 if (v == NULL) {
870 PyErr_SetString(PyExc_TypeError,
871 "mmap object doesn't support item deletion");
872 return -1;
873 }
874 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
875 PyErr_SetString(PyExc_IndexError,
876 "mmap assignment must be single-character string");
877 return -1;
878 }
879 if (!is_writeable(self))
880 return -1;
881 buf = PyString_AsString(v);
882 self->data[i] = buf[0];
883 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000884}
885
Thomas Wouters3ccec682007-08-28 15:28:19 +0000886static int
887mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
888{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000889 CHECK_VALID(-1);
Thomas Wouters3ccec682007-08-28 15:28:19 +0000890
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000891 if (PyIndex_Check(item)) {
892 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
893 const char *buf;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000894
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000895 if (i == -1 && PyErr_Occurred())
896 return -1;
897 if (i < 0)
898 i += self->size;
899 if (i < 0 || (size_t)i >= self->size) {
900 PyErr_SetString(PyExc_IndexError,
901 "mmap index out of range");
902 return -1;
903 }
904 if (value == NULL) {
905 PyErr_SetString(PyExc_TypeError,
906 "mmap object doesn't support item deletion");
907 return -1;
908 }
909 if (!PyString_Check(value) || PyString_Size(value) != 1) {
910 PyErr_SetString(PyExc_IndexError,
911 "mmap assignment must be single-character string");
912 return -1;
913 }
914 if (!is_writeable(self))
915 return -1;
916 buf = PyString_AsString(value);
917 self->data[i] = buf[0];
918 return 0;
919 }
920 else if (PySlice_Check(item)) {
921 Py_ssize_t start, stop, step, slicelen;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000922
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000923 if (PySlice_GetIndicesEx((PySliceObject *)item,
924 self->size, &start, &stop,
925 &step, &slicelen) < 0) {
926 return -1;
927 }
928 if (value == NULL) {
929 PyErr_SetString(PyExc_TypeError,
930 "mmap object doesn't support slice deletion");
931 return -1;
932 }
933 if (!PyString_Check(value)) {
934 PyErr_SetString(PyExc_IndexError,
935 "mmap slice assignment must be a string");
936 return -1;
937 }
938 if (PyString_Size(value) != slicelen) {
939 PyErr_SetString(PyExc_IndexError,
940 "mmap slice assignment is wrong size");
941 return -1;
942 }
943 if (!is_writeable(self))
944 return -1;
Thomas Wouters3ccec682007-08-28 15:28:19 +0000945
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000946 if (slicelen == 0)
947 return 0;
948 else if (step == 1) {
949 const char *buf = PyString_AsString(value);
950
951 if (buf == NULL)
952 return -1;
953 memcpy(self->data + start, buf, slicelen);
954 return 0;
955 }
956 else {
957 Py_ssize_t cur, i;
958 const char *buf = PyString_AsString(value);
959
960 if (buf == NULL)
961 return -1;
962 for (cur = start, i = 0; i < slicelen;
963 cur += step, i++) {
964 self->data[cur] = buf[i];
965 }
966 return 0;
967 }
968 }
969 else {
970 PyErr_SetString(PyExc_TypeError,
971 "mmap indices must be integer");
972 return -1;
973 }
Thomas Wouters3ccec682007-08-28 15:28:19 +0000974}
975
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000976static PySequenceMethods mmap_as_sequence = {
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000977 (lenfunc)mmap_length, /*sq_length*/
978 (binaryfunc)mmap_concat, /*sq_concat*/
979 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
980 (ssizeargfunc)mmap_item, /*sq_item*/
981 (ssizessizeargfunc)mmap_slice, /*sq_slice*/
982 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
983 (ssizessizeobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000984};
985
Thomas Wouters3ccec682007-08-28 15:28:19 +0000986static PyMappingMethods mmap_as_mapping = {
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000987 (lenfunc)mmap_length,
988 (binaryfunc)mmap_subscript,
989 (objobjargproc)mmap_ass_subscript,
Thomas Wouters3ccec682007-08-28 15:28:19 +0000990};
991
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000992static PyBufferProcs mmap_as_buffer = {
Antoine Pitrouc7c96a92010-05-09 15:15:40 +0000993 (readbufferproc)mmap_buffer_getreadbuf,
994 (writebufferproc)mmap_buffer_getwritebuf,
995 (segcountproc)mmap_buffer_getsegcount,
996 (charbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000997};
998
Georg Brandl845c4032008-01-21 14:16:46 +0000999static PyObject *
1000new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
1001
Georg Brandlef928022008-01-20 14:50:05 +00001002PyDoc_STRVAR(mmap_doc,
1003"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
1004\n\
1005Maps length bytes from the file specified by the file handle fileno,\n\
1006and returns a mmap object. If length is larger than the current size\n\
1007of the file, the file is extended to contain length bytes. If length\n\
1008is 0, the maximum length of the map is the current size of the file,\n\
1009except that if the file is empty Windows raises an exception (you cannot\n\
1010create an empty mapping on Windows).\n\
1011\n\
1012Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
1013\n\
1014Maps length bytes from the file specified by the file descriptor fileno,\n\
1015and returns a mmap object. If length is 0, the maximum length of the map\n\
1016will be the current size of the file when mmap is called.\n\
1017flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
1018private copy-on-write mapping, so changes to the contents of the mmap\n\
Thomas Heller66260992008-08-19 17:47:13 +00001019object will be private to this process, and MAP_SHARED creates a mapping\n\
Georg Brandlef928022008-01-20 14:50:05 +00001020that's shared with all other processes mapping the same areas of the file.\n\
1021The default value is MAP_SHARED.\n\
1022\n\
1023To map anonymous memory, pass -1 as the fileno (both versions).");
1024
1025
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001026static PyTypeObject mmap_object_type = {
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001027 PyVarObject_HEAD_INIT(NULL, 0)
1028 "mmap.mmap", /* tp_name */
1029 sizeof(mmap_object), /* tp_size */
1030 0, /* tp_itemsize */
1031 /* methods */
1032 (destructor) mmap_object_dealloc, /* tp_dealloc */
1033 0, /* tp_print */
1034 0, /* tp_getattr */
1035 0, /* tp_setattr */
1036 0, /* tp_compare */
1037 0, /* tp_repr */
1038 0, /* tp_as_number */
1039 &mmap_as_sequence, /*tp_as_sequence*/
1040 &mmap_as_mapping, /*tp_as_mapping*/
1041 0, /*tp_hash*/
1042 0, /*tp_call*/
1043 0, /*tp_str*/
1044 PyObject_GenericGetAttr, /*tp_getattro*/
1045 0, /*tp_setattro*/
1046 &mmap_as_buffer, /*tp_as_buffer*/
1047 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
1048 mmap_doc, /*tp_doc*/
1049 0, /* tp_traverse */
1050 0, /* tp_clear */
1051 0, /* tp_richcompare */
1052 0, /* tp_weaklistoffset */
1053 0, /* tp_iter */
1054 0, /* tp_iternext */
1055 mmap_object_methods, /* tp_methods */
1056 0, /* tp_members */
1057 0, /* tp_getset */
1058 0, /* tp_base */
1059 0, /* tp_dict */
1060 0, /* tp_descr_get */
1061 0, /* tp_descr_set */
1062 0, /* tp_dictoffset */
1063 0, /* tp_init */
1064 PyType_GenericAlloc, /* tp_alloc */
1065 new_mmap_object, /* tp_new */
1066 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001067};
1068
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001069
1070/* extract the map size from the given PyObject
1071
Thomas Wouters7e474022000-07-16 12:04:32 +00001072 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001073 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001074static Py_ssize_t
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001075_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001076{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001077 if (o == NULL)
1078 return 0;
1079 if (PyIndex_Check(o)) {
1080 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
1081 if (i==-1 && PyErr_Occurred())
1082 return -1;
1083 if (i < 0) {
1084 PyErr_Format(PyExc_OverflowError,
1085 "memory mapped %s must be positive",
1086 param);
1087 return -1;
1088 }
1089 return i;
1090 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001091
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001092 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
1093 return -1;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001094}
1095
Tim Petersec0a5f02006-02-16 23:47:20 +00001096#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001097static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001098new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001099{
Neal Norwitzb5673922002-09-05 21:48:07 +00001100#ifdef HAVE_FSTAT
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001101 struct stat st;
Neal Norwitzb5673922002-09-05 21:48:07 +00001102#endif
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001103 mmap_object *m_obj;
1104 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1105 Py_ssize_t map_size, offset;
1106 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
1107 int devzero = -1;
1108 int access = (int)ACCESS_DEFAULT;
1109 static char *keywords[] = {"fileno", "length",
1110 "flags", "prot",
1111 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001112
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001113 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iiiO", keywords,
1114 &fd, &map_size_obj, &flags, &prot,
1115 &access, &offset_obj))
1116 return NULL;
1117 map_size = _GetMapSize(map_size_obj, "size");
1118 if (map_size < 0)
1119 return NULL;
1120 offset = _GetMapSize(offset_obj, "offset");
1121 if (offset < 0)
1122 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001123
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001124 if ((access != (int)ACCESS_DEFAULT) &&
1125 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
1126 return PyErr_Format(PyExc_ValueError,
1127 "mmap can't specify both access and flags, prot.");
1128 switch ((access_mode)access) {
1129 case ACCESS_READ:
1130 flags = MAP_SHARED;
1131 prot = PROT_READ;
1132 break;
1133 case ACCESS_WRITE:
1134 flags = MAP_SHARED;
1135 prot = PROT_READ | PROT_WRITE;
1136 break;
1137 case ACCESS_COPY:
1138 flags = MAP_PRIVATE;
1139 prot = PROT_READ | PROT_WRITE;
1140 break;
1141 case ACCESS_DEFAULT:
1142 /* use the specified or default values of flags and prot */
1143 break;
1144 default:
1145 return PyErr_Format(PyExc_ValueError,
1146 "mmap invalid access parameter.");
1147 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001148
Christian Heimes7adfad82008-02-15 08:20:11 +00001149 if (prot == PROT_READ) {
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001150 access = ACCESS_READ;
Christian Heimes7adfad82008-02-15 08:20:11 +00001151 }
1152
Neal Norwitzb5673922002-09-05 21:48:07 +00001153#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001154# ifdef __VMS
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001155 /* on OpenVMS we must ensure that all bytes are written to the file */
1156 if (fd != -1) {
1157 fsync(fd);
1158 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001159# endif
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001160 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
1161 if (map_size == 0) {
1162 map_size = st.st_size;
1163 } else if ((size_t)offset + (size_t)map_size > st.st_size) {
1164 PyErr_SetString(PyExc_ValueError,
1165 "mmap length is greater than file size");
1166 return NULL;
1167 }
1168 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001169#endif
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001170 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1171 if (m_obj == NULL) {return NULL;}
1172 m_obj->data = NULL;
1173 m_obj->size = (size_t) map_size;
1174 m_obj->pos = (size_t) 0;
1175 m_obj->offset = offset;
1176 if (fd == -1) {
1177 m_obj->fd = -1;
1178 /* Assume the caller wants to map anonymous memory.
1179 This is the same behaviour as Windows. mmap.mmap(-1, size)
1180 on both Windows and Unix map anonymous memory.
1181 */
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001182#ifdef MAP_ANONYMOUS
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001183 /* BSD way to map anonymous memory */
1184 flags |= MAP_ANONYMOUS;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001185#else
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001186 /* SVR4 method to map anonymous memory is to open /dev/zero */
1187 fd = devzero = open("/dev/zero", O_RDWR);
1188 if (devzero == -1) {
1189 Py_DECREF(m_obj);
1190 PyErr_SetFromErrno(mmap_module_error);
1191 return NULL;
1192 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001193#endif
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001194 } else {
1195 m_obj->fd = dup(fd);
1196 if (m_obj->fd == -1) {
1197 Py_DECREF(m_obj);
1198 PyErr_SetFromErrno(mmap_module_error);
1199 return NULL;
1200 }
1201 }
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001202
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001203 m_obj->data = mmap(NULL, map_size,
1204 prot, flags,
1205 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001206
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001207 if (devzero != -1) {
1208 close(devzero);
1209 }
1210
1211 if (m_obj->data == (char *)-1) {
1212 m_obj->data = NULL;
1213 Py_DECREF(m_obj);
1214 PyErr_SetFromErrno(mmap_module_error);
1215 return NULL;
1216 }
1217 m_obj->access = (access_mode)access;
1218 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001219}
1220#endif /* UNIX */
1221
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001222#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001223static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001224new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001225{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001226 mmap_object *m_obj;
1227 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1228 Py_ssize_t map_size, offset;
1229 DWORD off_hi; /* upper 32 bits of offset */
1230 DWORD off_lo; /* lower 32 bits of offset */
1231 DWORD size_hi; /* upper 32 bits of size */
1232 DWORD size_lo; /* lower 32 bits of size */
1233 char *tagname = "";
1234 DWORD dwErr = 0;
1235 int fileno;
1236 HANDLE fh = 0;
1237 int access = (access_mode)ACCESS_DEFAULT;
1238 DWORD flProtect, dwDesiredAccess;
1239 static char *keywords[] = { "fileno", "length",
1240 "tagname",
1241 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001242
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001243 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
1244 &fileno, &map_size_obj,
1245 &tagname, &access, &offset_obj)) {
1246 return NULL;
1247 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001248
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001249 switch((access_mode)access) {
1250 case ACCESS_READ:
1251 flProtect = PAGE_READONLY;
1252 dwDesiredAccess = FILE_MAP_READ;
1253 break;
1254 case ACCESS_DEFAULT: case ACCESS_WRITE:
1255 flProtect = PAGE_READWRITE;
1256 dwDesiredAccess = FILE_MAP_WRITE;
1257 break;
1258 case ACCESS_COPY:
1259 flProtect = PAGE_WRITECOPY;
1260 dwDesiredAccess = FILE_MAP_COPY;
1261 break;
1262 default:
1263 return PyErr_Format(PyExc_ValueError,
1264 "mmap invalid access parameter.");
1265 }
Tim Peters5ebfd362001-11-13 23:11:19 +00001266
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001267 map_size = _GetMapSize(map_size_obj, "size");
1268 if (map_size < 0)
1269 return NULL;
1270 offset = _GetMapSize(offset_obj, "offset");
1271 if (offset < 0)
1272 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001273
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001274 /* assume -1 and 0 both mean invalid filedescriptor
1275 to 'anonymously' map memory.
1276 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1277 XXX: Should this code be added?
1278 if (fileno == 0)
1279 PyErr_Warn(PyExc_DeprecationWarning,
1280 "don't use 0 for anonymous memory");
1281 */
1282 if (fileno != -1 && fileno != 0) {
1283 fh = (HANDLE)_get_osfhandle(fileno);
1284 if (fh==(HANDLE)-1) {
1285 PyErr_SetFromErrno(mmap_module_error);
1286 return NULL;
1287 }
1288 /* Win9x appears to need us seeked to zero */
1289 lseek(fileno, 0, SEEK_SET);
1290 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001291
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001292 m_obj = (mmap_object *)type->tp_alloc(type, 0);
1293 if (m_obj == NULL)
1294 return NULL;
1295 /* Set every field to an invalid marker, so we can safely
1296 destruct the object in the face of failure */
1297 m_obj->data = NULL;
1298 m_obj->file_handle = INVALID_HANDLE_VALUE;
1299 m_obj->map_handle = NULL;
1300 m_obj->tagname = NULL;
1301 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001302
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001303 if (fh) {
1304 /* It is necessary to duplicate the handle, so the
1305 Python code can close it on us */
1306 if (!DuplicateHandle(
1307 GetCurrentProcess(), /* source process handle */
1308 fh, /* handle to be duplicated */
1309 GetCurrentProcess(), /* target proc handle */
1310 (LPHANDLE)&m_obj->file_handle, /* result */
1311 0, /* access - ignored due to options value */
1312 FALSE, /* inherited by child processes? */
1313 DUPLICATE_SAME_ACCESS)) { /* options */
1314 dwErr = GetLastError();
1315 Py_DECREF(m_obj);
1316 PyErr_SetFromWindowsErr(dwErr);
1317 return NULL;
1318 }
1319 if (!map_size) {
1320 DWORD low,high;
1321 low = GetFileSize(fh, &high);
1322 /* low might just happen to have the value INVALID_FILE_SIZE;
1323 so we need to check the last error also. */
1324 if (low == INVALID_FILE_SIZE &&
1325 (dwErr = GetLastError()) != NO_ERROR) {
1326 Py_DECREF(m_obj);
1327 return PyErr_SetFromWindowsErr(dwErr);
1328 }
1329
Martin v. Löwis15186072006-02-18 12:38:35 +00001330#if SIZEOF_SIZE_T > 4
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001331 m_obj->size = (((size_t)high)<<32) + low;
Martin v. Löwis15186072006-02-18 12:38:35 +00001332#else
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001333 if (high)
1334 /* File is too large to map completely */
1335 m_obj->size = (size_t)-1;
1336 else
1337 m_obj->size = low;
Martin v. Löwis15186072006-02-18 12:38:35 +00001338#endif
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001339 } else {
1340 m_obj->size = map_size;
1341 }
1342 }
1343 else {
1344 m_obj->size = map_size;
1345 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001346
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001347 /* set the initial position */
1348 m_obj->pos = (size_t) 0;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001349
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001350 /* set the tag name */
1351 if (tagname != NULL && *tagname != '\0') {
1352 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1353 if (m_obj->tagname == NULL) {
1354 PyErr_NoMemory();
1355 Py_DECREF(m_obj);
1356 return NULL;
1357 }
1358 strcpy(m_obj->tagname, tagname);
1359 }
1360 else
1361 m_obj->tagname = NULL;
Mark Hammond2cbed002000-07-30 02:22:43 +00001362
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001363 m_obj->access = (access_mode)access;
1364 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
1365 * more than 4 bytes, we need to break it apart. Else (size_t
1366 * consumes 4 bytes), C doesn't define what happens if we shift
1367 * right by 32, so we need different code.
1368 */
Tim Peterse564e7f2006-02-16 23:46:01 +00001369#if SIZEOF_SIZE_T > 4
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001370 size_hi = (DWORD)((offset + m_obj->size) >> 32);
1371 size_lo = (DWORD)((offset + m_obj->size) & 0xFFFFFFFF);
1372 off_hi = (DWORD)(offset >> 32);
1373 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Tim Peterse564e7f2006-02-16 23:46:01 +00001374#else
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001375 size_hi = 0;
1376 size_lo = (DWORD)(offset + m_obj->size);
1377 off_hi = 0;
1378 off_lo = (DWORD)offset;
Tim Peterse564e7f2006-02-16 23:46:01 +00001379#endif
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001380 /* For files, it would be sufficient to pass 0 as size.
1381 For anonymous maps, we have to pass the size explicitly. */
1382 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1383 NULL,
1384 flProtect,
1385 size_hi,
1386 size_lo,
1387 m_obj->tagname);
1388 if (m_obj->map_handle != NULL) {
1389 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1390 dwDesiredAccess,
1391 off_hi,
1392 off_lo,
1393 m_obj->size);
1394 if (m_obj->data != NULL)
1395 return (PyObject *)m_obj;
1396 else {
1397 dwErr = GetLastError();
1398 CloseHandle(m_obj->map_handle);
1399 m_obj->map_handle = NULL;
1400 }
1401 } else
1402 dwErr = GetLastError();
1403 Py_DECREF(m_obj);
1404 PyErr_SetFromWindowsErr(dwErr);
1405 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001406}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001407#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001408
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001409static void
1410setint(PyObject *d, const char *name, long value)
1411{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001412 PyObject *o = PyInt_FromLong(value);
1413 if (o && PyDict_SetItemString(d, name, o) == 0) {
1414 Py_DECREF(o);
1415 }
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001416}
1417
Mark Hammond62b1ab12002-07-23 06:31:15 +00001418PyMODINIT_FUNC
Georg Brandl845c4032008-01-21 14:16:46 +00001419initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001420{
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001421 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001422
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001423 if (PyType_Ready(&mmap_object_type) < 0)
1424 return;
Tim Peters2caf8df2001-01-14 05:05:51 +00001425
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001426 module = Py_InitModule("mmap", NULL);
1427 if (module == NULL)
1428 return;
1429 dict = PyModule_GetDict(module);
1430 if (!dict)
1431 return;
1432 mmap_module_error = PyErr_NewException("mmap.error",
1433 PyExc_EnvironmentError , NULL);
1434 if (mmap_module_error == NULL)
1435 return;
1436 PyDict_SetItemString(dict, "error", mmap_module_error);
1437 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001438#ifdef PROT_EXEC
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001439 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001440#endif
1441#ifdef PROT_READ
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001442 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001443#endif
1444#ifdef PROT_WRITE
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001445 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001446#endif
1447
1448#ifdef MAP_SHARED
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001449 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001450#endif
1451#ifdef MAP_PRIVATE
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001452 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001453#endif
1454#ifdef MAP_DENYWRITE
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001455 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001456#endif
1457#ifdef MAP_EXECUTABLE
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001458 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001459#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001460#ifdef MAP_ANONYMOUS
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001461 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1462 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001463#endif
1464
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001465 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001466
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001467 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001468
Antoine Pitrouc7c96a92010-05-09 15:15:40 +00001469 setint(dict, "ACCESS_READ", ACCESS_READ);
1470 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1471 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Tim Peters5ebfd362001-11-13 23:11:19 +00001472}