blob: dd35c10728b8a5e2482b434da6beb9ea43b0c04d [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{
Tim Peters5ebfd362001-11-13 23:11:19 +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
42 SYSTEM_INFO si;
43 GetSystemInfo(&si);
44 return si.dwAllocationGranularity;
45}
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{
Tim Peters5ebfd362001-11-13 23:11:19 +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{
82 ACCESS_DEFAULT,
83 ACCESS_READ,
84 ACCESS_WRITE,
85 ACCESS_COPY
86} access_mode;
87
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000088typedef struct {
Guido van Rossum09fdf072000-03-31 01:17:07 +000089 PyObject_HEAD
90 char * data;
91 size_t size;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +000092 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
Guido van Rossum09fdf072000-03-31 01:17:07 +000096 HANDLE map_handle;
Mark Hammond071864a2000-07-30 02:46:26 +000097 HANDLE file_handle;
Guido van Rossum09fdf072000-03-31 01:17:07 +000098 char * tagname;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +000099#endif
100
101#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000102 int fd;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000103#endif
Tim Peters5ebfd362001-11-13 23:11:19 +0000104
105 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
Mark Hammond2cbed002000-07-30 02:22:43 +0000113 if (m_obj->data != NULL)
114 UnmapViewOfFile (m_obj->data);
115 if (m_obj->map_handle != INVALID_HANDLE_VALUE)
116 CloseHandle (m_obj->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000117 if (m_obj->file_handle != INVALID_HANDLE_VALUE)
118 CloseHandle (m_obj->file_handle);
Mark Hammond2cbed002000-07-30 02:22:43 +0000119 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
Neal Norwitz6eac2002005-11-02 05:36:37 +0000124 if (m_obj->fd >= 0)
125 (void) close(m_obj->fd);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000126 if (m_obj->data!=NULL) {
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000127 msync(m_obj->data, m_obj->size, MS_SYNC);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000128 munmap(m_obj->data, m_obj->size);
129 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000130#endif /* UNIX */
131
Guido van Rossumb18618d2000-05-03 23:44:39 +0000132 PyObject_Del(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
Mark Hammond071864a2000-07-30 02:46:26 +0000139 /* For each resource we maintain, we need to check
Tim Petersec0a5f02006-02-16 23:47:20 +0000140 the value is valid, and if so, free the resource
Mark Hammond071864a2000-07-30 02:46:26 +0000141 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) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000147 UnmapViewOfFile(self->data);
Mark Hammond071864a2000-07-30 02:46:26 +0000148 self->data = NULL;
149 }
150 if (self->map_handle != INVALID_HANDLE_VALUE) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000151 CloseHandle(self->map_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000152 self->map_handle = INVALID_HANDLE_VALUE;
153 }
154 if (self->file_handle != INVALID_HANDLE_VALUE) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000155 CloseHandle(self->file_handle);
Mark Hammond071864a2000-07-30 02:46:26 +0000156 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
Neal Norwitz6eac2002005-11-02 05:36:37 +0000161 (void) close(self->fd);
162 self->fd = -1;
Neal Norwitze604c022003-01-10 20:52:16 +0000163 if (self->data != NULL) {
164 munmap(self->data, self->size);
165 self->data = NULL;
166 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000167#endif
168
Tim Peters8f9cc292006-02-17 00:00:20 +0000169 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000170 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000171}
172
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000173#ifdef MS_WINDOWS
Guido van Rossum09fdf072000-03-31 01:17:07 +0000174#define CHECK_VALID(err) \
175do { \
Guido van Rossum69c2b882003-04-09 19:31:02 +0000176 if (self->map_handle == INVALID_HANDLE_VALUE) { \
Tim Peters8f9cc292006-02-17 00:00:20 +0000177 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
Guido van Rossum09fdf072000-03-31 01:17:07 +0000178 return err; \
179 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000180} while (0)
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000181#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000182
183#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000184#define CHECK_VALID(err) \
185do { \
186 if (self->data == NULL) { \
Tim Peters8f9cc292006-02-17 00:00:20 +0000187 PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \
Guido van Rossum09fdf072000-03-31 01:17:07 +0000188 return err; \
189 } \
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000190} while (0)
191#endif /* UNIX */
192
193static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000194mmap_read_byte_method(mmap_object *self,
Georg Brandl96a8c392006-05-29 21:04:52 +0000195 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000196{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000197 CHECK_VALID(NULL);
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000198 if (self->pos < self->size) {
Tim Petersd6283b82001-05-09 18:48:26 +0000199 char value = self->data[self->pos];
Guido van Rossum09fdf072000-03-31 01:17:07 +0000200 self->pos += 1;
Tim Petersd6283b82001-05-09 18:48:26 +0000201 return Py_BuildValue("c", value);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000202 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000203 PyErr_SetString(PyExc_ValueError, "read byte out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000204 return NULL;
205 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000206}
207
208static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000209mmap_read_line_method(mmap_object *self,
Georg Brandl96a8c392006-05-29 21:04:52 +0000210 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000211{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000212 char *start = self->data+self->pos;
213 char *eof = self->data+self->size;
214 char *eol;
215 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000216
Guido van Rossum09fdf072000-03-31 01:17:07 +0000217 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000218
Fred Drake56a87a02000-04-04 18:17:35 +0000219 eol = memchr(start, '\n', self->size - self->pos);
220 if (!eol)
221 eol = eof;
222 else
223 ++eol; /* we're interested in the position after the
224 newline. */
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000225 result = PyString_FromStringAndSize(start, (eol - start));
Guido van Rossum09fdf072000-03-31 01:17:07 +0000226 self->pos += (eol - start);
Tim Peters23721ee2006-02-16 23:50:16 +0000227 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000228}
229
230static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000231mmap_read_method(mmap_object *self,
232 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000233{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000234 Py_ssize_t num_bytes;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000235 PyObject *result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000236
Guido van Rossum09fdf072000-03-31 01:17:07 +0000237 CHECK_VALID(NULL);
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000238 if (!PyArg_ParseTuple(args, "n:read", &num_bytes))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000239 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000240
Guido van Rossum09fdf072000-03-31 01:17:07 +0000241 /* silently 'adjust' out-of-range requests */
242 if ((self->pos + num_bytes) > self->size) {
243 num_bytes -= (self->pos+num_bytes) - self->size;
244 }
245 result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
Tim Petersec0a5f02006-02-16 23:47:20 +0000246 self->pos += num_bytes;
Tim Peters23721ee2006-02-16 23:50:16 +0000247 return result;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000248}
249
250static PyObject *
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000251mmap_gfind(mmap_object *self,
252 PyObject *args,
253 int reverse)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000254{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000255 Py_ssize_t start = self->pos;
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000256 Py_ssize_t end = self->size;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000257 char *needle;
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000258 Py_ssize_t len;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000259
Guido van Rossum09fdf072000-03-31 01:17:07 +0000260 CHECK_VALID(NULL);
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000261 if (!PyArg_ParseTuple(args, reverse ? "s#|nn:rfind" : "s#|nn:find",
262 &needle, &len, &start, &end)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000263 return NULL;
264 } else {
Greg Stein834f4dd2001-05-14 09:32:26 +0000265 char *p;
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000266 char sign = reverse ? -1 : 1;
Greg Stein834f4dd2001-05-14 09:32:26 +0000267
268 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000269 start += self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000270 if (start < 0)
Tim Peters5ebfd362001-11-13 23:11:19 +0000271 start = 0;
Tim Petersd401edd2001-05-14 23:19:12 +0000272 else if ((size_t)start > self->size)
Tim Peters5ebfd362001-11-13 23:11:19 +0000273 start = self->size;
Greg Stein834f4dd2001-05-14 09:32:26 +0000274
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000275 if (end < 0)
276 end += self->size;
277 if (end < 0)
278 end = 0;
279 else if ((size_t)end > self->size)
280 end = self->size;
281
282 start += (Py_ssize_t)self->data;
283 end += (Py_ssize_t)self->data;
284
285 for (p = (char *)(reverse ? end - len : start);
286 p >= (char *)start && p + len <= (char *)end; p+=sign) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000287 Py_ssize_t i;
Tim Petersc9ffa062002-03-08 05:43:32 +0000288 for (i = 0; i < len && needle[i] == p[i]; ++i)
289 /* nothing */;
290 if (i == len) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000291 return PyInt_FromSsize_t(p - self->data);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000292 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000293 }
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000294 return PyInt_FromLong(-1);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000295 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000296}
297
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000298static PyObject *
299mmap_find_method(mmap_object *self,
300 PyObject *args)
301{
302 return mmap_gfind(self, args, 0);
303}
304
305static PyObject *
306mmap_rfind_method(mmap_object *self,
307 PyObject *args)
308{
309 return mmap_gfind(self, args, 1);
310}
311
Tim Petersec0a5f02006-02-16 23:47:20 +0000312static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000313is_writeable(mmap_object *self)
314{
315 if (self->access != ACCESS_READ)
Tim Petersec0a5f02006-02-16 23:47:20 +0000316 return 1;
Tim Peters5ebfd362001-11-13 23:11:19 +0000317 PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
318 return 0;
319}
320
Tim Petersec0a5f02006-02-16 23:47:20 +0000321static int
Tim Peters5ebfd362001-11-13 23:11:19 +0000322is_resizeable(mmap_object *self)
323{
324 if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
Tim Petersec0a5f02006-02-16 23:47:20 +0000325 return 1;
326 PyErr_Format(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000327 "mmap can't resize a readonly or copy-on-write memory map.");
328 return 0;
329}
330
331
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000332static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000333mmap_write_method(mmap_object *self,
334 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000335{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000336 Py_ssize_t length;
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000337 char *data;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000338
Guido van Rossum09fdf072000-03-31 01:17:07 +0000339 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000340 if (!PyArg_ParseTuple(args, "s#:write", &data, &length))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000341 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000342
Tim Peters5ebfd362001-11-13 23:11:19 +0000343 if (!is_writeable(self))
344 return NULL;
345
Guido van Rossum09fdf072000-03-31 01:17:07 +0000346 if ((self->pos + length) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000347 PyErr_SetString(PyExc_ValueError, "data out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000348 return NULL;
349 }
Tim Peters8f9cc292006-02-17 00:00:20 +0000350 memcpy(self->data+self->pos, data, length);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000351 self->pos = self->pos+length;
Tim Peters8f9cc292006-02-17 00:00:20 +0000352 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000353 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000354}
355
356static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000357mmap_write_byte_method(mmap_object *self,
358 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000359{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000360 char value;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000361
Guido van Rossum09fdf072000-03-31 01:17:07 +0000362 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000363 if (!PyArg_ParseTuple(args, "c:write_byte", &value))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000364 return(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000365
Tim Peters5ebfd362001-11-13 23:11:19 +0000366 if (!is_writeable(self))
367 return NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000368 *(self->data+self->pos) = value;
369 self->pos += 1;
Tim Peters8f9cc292006-02-17 00:00:20 +0000370 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000371 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000372}
Tim Petersec0a5f02006-02-16 23:47:20 +0000373
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000374static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000375mmap_size_method(mmap_object *self,
Georg Brandl96a8c392006-05-29 21:04:52 +0000376 PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000377{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000378 CHECK_VALID(NULL);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000379
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000380#ifdef MS_WINDOWS
Mark Hammond071864a2000-07-30 02:46:26 +0000381 if (self->file_handle != INVALID_HANDLE_VALUE) {
Martin v. Löwis15186072006-02-18 12:38:35 +0000382 DWORD low,high;
383 PY_LONG_LONG size;
384 low = GetFileSize(self->file_handle, &high);
385 if (low == INVALID_FILE_SIZE) {
386 /* It might be that the function appears to have failed,
387 when indeed its size equals INVALID_FILE_SIZE */
388 DWORD error = GetLastError();
389 if (error != NO_ERROR)
390 return PyErr_SetFromWindowsErr(error);
391 }
392 if (!high && low < LONG_MAX)
393 return PyInt_FromLong((long)low);
394 size = (((PY_LONG_LONG)high)<<32) + low;
395 return PyLong_FromLongLong(size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000396 } else {
Martin v. Löwis15186072006-02-18 12:38:35 +0000397 return PyInt_FromSsize_t(self->size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000398 }
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000399#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000400
401#ifdef UNIX
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000402 {
403 struct stat buf;
404 if (-1 == fstat(self->fd, &buf)) {
405 PyErr_SetFromErrno(mmap_module_error);
406 return NULL;
407 }
Martin v. Löwis15186072006-02-18 12:38:35 +0000408 return PyInt_FromSsize_t(buf.st_size);
Andrew M. Kuchling7b9fb922000-06-17 22:41:22 +0000409 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000410#endif /* UNIX */
411}
412
413/* This assumes that you want the entire file mapped,
414 / and when recreating the map will make the new file
415 / have the new size
416 /
417 / Is this really necessary? This could easily be done
418 / from python by just closing and re-opening with the
419 / new size?
420 */
421
422static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000423mmap_resize_method(mmap_object *self,
424 PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000425{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000426 Py_ssize_t new_size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000427 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000428 if (!PyArg_ParseTuple(args, "n:resize", &new_size) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000429 !is_resizeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000430 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000431#ifdef MS_WINDOWS
Tim Petersec0a5f02006-02-16 23:47:20 +0000432 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000433 DWORD dwErrCode = 0;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +0000434 DWORD off_hi, off_lo, newSizeLow, newSizeHigh;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000435 /* First, unmap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000436 UnmapViewOfFile(self->data);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000437 /* Close the mapping object */
Tim Peters8f9cc292006-02-17 00:00:20 +0000438 CloseHandle(self->map_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000439 /* Move to the desired EOF position */
Martin v. Löwis15186072006-02-18 12:38:35 +0000440#if SIZEOF_SIZE_T > 4
Travis E. Oliphant8feafab2007-10-23 02:40:56 +0000441 newSizeHigh = (DWORD)((self->offset + new_size) >> 32);
442 newSizeLow = (DWORD)((self->offset + new_size) & 0xFFFFFFFF);
443 off_hi = (DWORD)(self->offset >> 32);
444 off_lo = (DWORD)(self->offset & 0xFFFFFFFF);
Martin v. Löwis15186072006-02-18 12:38:35 +0000445#else
446 newSizeHigh = 0;
Martin v. Löwis5bb8a152006-02-18 12:49:49 +0000447 newSizeLow = (DWORD)new_size;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +0000448 off_hi = 0;
449 off_lo = (DWORD)self->offset;
Martin v. Löwis15186072006-02-18 12:38:35 +0000450#endif
Tim Peters8f9cc292006-02-17 00:00:20 +0000451 SetFilePointer(self->file_handle,
Martin v. Löwis15186072006-02-18 12:38:35 +0000452 newSizeLow, &newSizeHigh, FILE_BEGIN);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000453 /* Change the size of the file */
Tim Peters8f9cc292006-02-17 00:00:20 +0000454 SetEndOfFile(self->file_handle);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000455 /* Create another mapping object and remap the file view */
Tim Peters8f9cc292006-02-17 00:00:20 +0000456 self->map_handle = CreateFileMapping(
Mark Hammond071864a2000-07-30 02:46:26 +0000457 self->file_handle,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000458 NULL,
459 PAGE_READWRITE,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +0000460 0,
461 0,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000462 self->tagname);
463 if (self->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000464 self->data = (char *) MapViewOfFile(self->map_handle,
465 FILE_MAP_WRITE,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +0000466 off_hi,
467 off_lo,
468 new_size);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000469 if (self->data != NULL) {
470 self->size = new_size;
Tim Peters8f9cc292006-02-17 00:00:20 +0000471 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000472 return Py_None;
473 } else {
474 dwErrCode = GetLastError();
475 }
476 } else {
477 dwErrCode = GetLastError();
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000478 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000479 PyErr_SetFromWindowsErr(dwErrCode);
Tim Peters23721ee2006-02-16 23:50:16 +0000480 return NULL;
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000481#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000482
483#ifdef UNIX
Tim Petersec0a5f02006-02-16 23:47:20 +0000484#ifndef HAVE_MREMAP
Tim Peters5ebfd362001-11-13 23:11:19 +0000485 } else {
486 PyErr_SetString(PyExc_SystemError,
487 "mmap: resizing not available--no mremap()");
488 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000489#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000490 } else {
Armin Rigo335ffe82005-09-20 19:04:02 +0000491 void *newmap;
492
Georg Brandl38387b82005-08-24 07:17:40 +0000493 if (ftruncate(self->fd, new_size) == -1) {
494 PyErr_SetFromErrno(mmap_module_error);
495 return NULL;
496 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000497
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000498#ifdef MREMAP_MAYMOVE
Tim Peters5ebfd362001-11-13 23:11:19 +0000499 newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000500#else
Tim Peters5ebfd362001-11-13 23:11:19 +0000501 newmap = mremap(self->data, self->size, new_size, 0);
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000502#endif
Tim Petersec0a5f02006-02-16 23:47:20 +0000503 if (newmap == (void *)-1)
Tim Peters5ebfd362001-11-13 23:11:19 +0000504 {
505 PyErr_SetFromErrno(mmap_module_error);
506 return NULL;
507 }
508 self->data = newmap;
509 self->size = new_size;
510 Py_INCREF(Py_None);
511 return Py_None;
Andrew M. Kuchling6fef30e2000-06-18 14:51:21 +0000512#endif /* HAVE_MREMAP */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000513#endif /* UNIX */
Tim Peters5ebfd362001-11-13 23:11:19 +0000514 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000515}
516
517static PyObject *
Georg Brandl96a8c392006-05-29 21:04:52 +0000518mmap_tell_method(mmap_object *self, PyObject *unused)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000519{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000520 CHECK_VALID(NULL);
Neal Norwitz670f8752006-08-22 13:56:56 +0000521 return PyInt_FromSize_t(self->pos);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000522}
523
524static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000525mmap_flush_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000526{
Martin v. Löwisad0a4622006-02-16 14:30:23 +0000527 Py_ssize_t offset = 0;
528 Py_ssize_t size = self->size;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000529 CHECK_VALID(NULL);
Tim Petersf2882952006-02-17 01:07:39 +0000530 if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000531 return NULL;
Tim Petersf2882952006-02-17 01:07:39 +0000532 if ((size_t)(offset + size) > self->size) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000533 PyErr_SetString(PyExc_ValueError, "flush values out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000534 return NULL;
535 } else {
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000536#ifdef MS_WINDOWS
Georg Brandl2cfaa342006-05-29 19:39:45 +0000537 return PyInt_FromLong((long)
Tim Peters23721ee2006-02-16 23:50:16 +0000538 FlushViewOfFile(self->data+offset, size));
Martin v. Löwis6238d2b2002-06-30 15:26:10 +0000539#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000540#ifdef UNIX
Guido van Rossum09fdf072000-03-31 01:17:07 +0000541 /* XXX semantics of return value? */
542 /* XXX flags for msync? */
543 if (-1 == msync(self->data + offset, size,
Andrew M. Kuchling9bc5f332000-06-18 04:25:08 +0000544 MS_SYNC))
Guido van Rossum09fdf072000-03-31 01:17:07 +0000545 {
546 PyErr_SetFromErrno(mmap_module_error);
547 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000548 }
Georg Brandl2cfaa342006-05-29 19:39:45 +0000549 return PyInt_FromLong(0);
Tim Petersec0a5f02006-02-16 23:47:20 +0000550#endif /* UNIX */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000551 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000552}
553
554static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000555mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000556{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000557 Py_ssize_t dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000558 int how=0;
559 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000560 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
Tim Peters8f9cc292006-02-17 00:00:20 +0000561 return NULL;
562 else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000563 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000564 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000565 case 0: /* relative to start */
566 if (dist < 0)
567 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000568 where = dist;
569 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000570 case 1: /* relative to current position */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000571 if ((Py_ssize_t)self->pos + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000572 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000573 where = self->pos + dist;
574 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000575 case 2: /* relative to end */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000576 if ((Py_ssize_t)self->size + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000577 goto onoutofrange;
578 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000579 break;
580 default:
Tim Peters8f9cc292006-02-17 00:00:20 +0000581 PyErr_SetString(PyExc_ValueError, "unknown seek type");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000582 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000583 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000584 if (where > self->size)
585 goto onoutofrange;
586 self->pos = where;
Tim Peters8f9cc292006-02-17 00:00:20 +0000587 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000588 return Py_None;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000589 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000590
Tim Peters5ebfd362001-11-13 23:11:19 +0000591 onoutofrange:
Tim Peters8f9cc292006-02-17 00:00:20 +0000592 PyErr_SetString(PyExc_ValueError, "seek out of range");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000593 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000594}
595
596static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000597mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000598{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000599 unsigned long dest, src, count;
600 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000601 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &count) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000602 !is_writeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000603 return NULL;
604 } else {
605 /* bounds check the values */
606 if (/* end of source after end of data?? */
607 ((src+count) > self->size)
608 /* dest will fit? */
609 || (dest+count > self->size)) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000610 PyErr_SetString(PyExc_ValueError,
611 "source or destination out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000612 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000613 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000614 memmove(self->data+dest, self->data+src, count);
615 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000616 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000617 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000618 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000619}
620
621static struct PyMethodDef mmap_object_methods[] = {
Georg Brandl96a8c392006-05-29 21:04:52 +0000622 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000623 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000624 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000625 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
626 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
627 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
Georg Brandl96a8c392006-05-29 21:04:52 +0000628 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
629 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000630 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
631 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
Georg Brandl96a8c392006-05-29 21:04:52 +0000632 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
633 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000634 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
635 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000636 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000637};
638
639/* Functions for treating an mmap'ed file as a buffer */
640
Martin v. Löwis18e16552006-02-15 17:27:45 +0000641static Py_ssize_t
642mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000643{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000644 CHECK_VALID(-1);
Tim Peters8f9cc292006-02-17 00:00:20 +0000645 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000646 PyErr_SetString(PyExc_SystemError,
647 "Accessing non-existent mmap segment");
648 return -1;
649 }
650 *ptr = self->data;
651 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000652}
653
Martin v. Löwis18e16552006-02-15 17:27:45 +0000654static Py_ssize_t
655mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Tim Petersec0a5f02006-02-16 23:47:20 +0000656{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000657 CHECK_VALID(-1);
Tim Peters8f9cc292006-02-17 00:00:20 +0000658 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000659 PyErr_SetString(PyExc_SystemError,
660 "Accessing non-existent mmap segment");
661 return -1;
662 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000663 if (!is_writeable(self))
664 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000665 *ptr = self->data;
666 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000667}
668
Martin v. Löwis18e16552006-02-15 17:27:45 +0000669static Py_ssize_t
670mmap_buffer_getsegcount(mmap_object *self, Py_ssize_t *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000671{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000672 CHECK_VALID(-1);
Tim Petersec0a5f02006-02-16 23:47:20 +0000673 if (lenp)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000674 *lenp = self->size;
675 return 1;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000676}
677
Martin v. Löwis18e16552006-02-15 17:27:45 +0000678static Py_ssize_t
679mmap_buffer_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000680{
Tim Peters8f9cc292006-02-17 00:00:20 +0000681 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000682 PyErr_SetString(PyExc_SystemError,
683 "accessing non-existent buffer segment");
684 return -1;
685 }
686 *ptr = (const char *)self->data;
687 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000688}
689
690static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000691mmap_object_getattr(mmap_object *self, char *name)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000692{
Tim Peters8f9cc292006-02-17 00:00:20 +0000693 return Py_FindMethod(mmap_object_methods, (PyObject *)self, name);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000694}
695
Martin v. Löwis18e16552006-02-15 17:27:45 +0000696static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000697mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000698{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000699 CHECK_VALID(-1);
700 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000701}
702
703static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000704mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000705{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000706 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000707 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000708 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
709 return NULL;
710 }
711 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000712}
713
714static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000715mmap_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000716{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000717 CHECK_VALID(NULL);
718 if (ilow < 0)
719 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000720 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000721 ilow = self->size;
722 if (ihigh < 0)
723 ihigh = 0;
724 if (ihigh < ilow)
725 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000726 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000727 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000728
Guido van Rossum09fdf072000-03-31 01:17:07 +0000729 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000730}
731
732static PyObject *
Thomas Wouters3ccec682007-08-28 15:28:19 +0000733mmap_subscript(mmap_object *self, PyObject *item)
734{
735 CHECK_VALID(NULL);
736 if (PyIndex_Check(item)) {
737 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
738 if (i == -1 && PyErr_Occurred())
739 return NULL;
740 if (i < 0)
741 i += self->size;
Neal Norwitz9c4382f2007-10-31 06:33:20 +0000742 if (i < 0 || (size_t)i > self->size) {
Thomas Wouters3ccec682007-08-28 15:28:19 +0000743 PyErr_SetString(PyExc_IndexError,
744 "mmap index out of range");
745 return NULL;
746 }
747 return PyString_FromStringAndSize(self->data + i, 1);
748 }
749 else if (PySlice_Check(item)) {
750 Py_ssize_t start, stop, step, slicelen;
751
752 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
753 &start, &stop, &step, &slicelen) < 0) {
754 return NULL;
755 }
756
757 if (slicelen <= 0)
758 return PyString_FromStringAndSize("", 0);
759 else if (step == 1)
760 return PyString_FromStringAndSize(self->data + start,
761 slicelen);
762 else {
763 char *result_buf = (char *)PyMem_Malloc(slicelen);
764 Py_ssize_t cur, i;
765 PyObject *result;
766
767 if (result_buf == NULL)
768 return PyErr_NoMemory();
769 for (cur = start, i = 0; i < slicelen;
770 cur += step, i++) {
771 result_buf[i] = self->data[cur];
772 }
773 result = PyString_FromStringAndSize(result_buf,
774 slicelen);
775 PyMem_Free(result_buf);
776 return result;
777 }
778 }
779 else {
780 PyErr_SetString(PyExc_TypeError,
781 "mmap indices must be integers");
782 return NULL;
783 }
784}
785
786static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000787mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000788{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000789 CHECK_VALID(NULL);
790 PyErr_SetString(PyExc_SystemError,
791 "mmaps don't support concatenation");
792 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000793}
794
795static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000796mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000797{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000798 CHECK_VALID(NULL);
799 PyErr_SetString(PyExc_SystemError,
800 "mmaps don't support repeat operation");
801 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000802}
803
804static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000805mmap_ass_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000806{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000807 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000808
Guido van Rossum09fdf072000-03-31 01:17:07 +0000809 CHECK_VALID(-1);
810 if (ilow < 0)
811 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000812 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000813 ilow = self->size;
814 if (ihigh < 0)
815 ihigh = 0;
816 if (ihigh < ilow)
817 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000818 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000819 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000820
Thomas Wouters1baac722001-07-16 15:47:36 +0000821 if (v == NULL) {
822 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000823 "mmap object doesn't support slice deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000824 return -1;
825 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000826 if (! (PyString_Check(v)) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000827 PyErr_SetString(PyExc_IndexError,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000828 "mmap slice assignment must be a string");
829 return -1;
830 }
Tim Peters8f9cc292006-02-17 00:00:20 +0000831 if (PyString_Size(v) != (ihigh - ilow)) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000832 PyErr_SetString(PyExc_IndexError,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000833 "mmap slice assignment is wrong size");
834 return -1;
835 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000836 if (!is_writeable(self))
837 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000838 buf = PyString_AsString(v);
839 memcpy(self->data + ilow, buf, ihigh-ilow);
840 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000841}
842
843static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000844mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000845{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000846 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000847
Guido van Rossum09fdf072000-03-31 01:17:07 +0000848 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000849 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000850 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
851 return -1;
852 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000853 if (v == NULL) {
854 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000855 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000856 return -1;
857 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000858 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000859 PyErr_SetString(PyExc_IndexError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000860 "mmap assignment must be single-character string");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000861 return -1;
862 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000863 if (!is_writeable(self))
864 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000865 buf = PyString_AsString(v);
866 self->data[i] = buf[0];
867 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000868}
869
Thomas Wouters3ccec682007-08-28 15:28:19 +0000870static int
871mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
872{
873 CHECK_VALID(-1);
874
875 if (PyIndex_Check(item)) {
876 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
877 const char *buf;
878
879 if (i == -1 && PyErr_Occurred())
880 return -1;
881 if (i < 0)
882 i += self->size;
Neal Norwitz9c4382f2007-10-31 06:33:20 +0000883 if (i < 0 || (size_t)i > self->size) {
Thomas Wouters3ccec682007-08-28 15:28:19 +0000884 PyErr_SetString(PyExc_IndexError,
885 "mmap index out of range");
886 return -1;
887 }
888 if (value == NULL) {
889 PyErr_SetString(PyExc_TypeError,
890 "mmap object doesn't support item deletion");
891 return -1;
892 }
893 if (!PyString_Check(value) || PyString_Size(value) != 1) {
894 PyErr_SetString(PyExc_IndexError,
895 "mmap assignment must be single-character string");
896 return -1;
897 }
898 if (!is_writeable(self))
899 return -1;
900 buf = PyString_AsString(value);
901 self->data[i] = buf[0];
902 return 0;
903 }
904 else if (PySlice_Check(item)) {
905 Py_ssize_t start, stop, step, slicelen;
906
907 if (PySlice_GetIndicesEx((PySliceObject *)item,
908 self->size, &start, &stop,
909 &step, &slicelen) < 0) {
910 return -1;
911 }
912 if (value == NULL) {
913 PyErr_SetString(PyExc_TypeError,
914 "mmap object doesn't support slice deletion");
915 return -1;
916 }
917 if (!PyString_Check(value)) {
918 PyErr_SetString(PyExc_IndexError,
919 "mmap slice assignment must be a string");
920 return -1;
921 }
922 if (PyString_Size(value) != slicelen) {
923 PyErr_SetString(PyExc_IndexError,
924 "mmap slice assignment is wrong size");
925 return -1;
926 }
927 if (!is_writeable(self))
928 return -1;
929
930 if (slicelen == 0)
931 return 0;
932 else if (step == 1) {
933 const char *buf = PyString_AsString(value);
934
935 if (buf == NULL)
936 return -1;
937 memcpy(self->data + start, buf, slicelen);
938 return 0;
939 }
940 else {
941 Py_ssize_t cur, i;
942 const char *buf = PyString_AsString(value);
943
944 if (buf == NULL)
945 return -1;
946 for (cur = start, i = 0; i < slicelen;
947 cur += step, i++) {
948 self->data[cur] = buf[i];
949 }
950 return 0;
951 }
952 }
953 else {
954 PyErr_SetString(PyExc_TypeError,
955 "mmap indices must be integer");
956 return -1;
957 }
958}
959
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000960static PySequenceMethods mmap_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000961 (lenfunc)mmap_length, /*sq_length*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000962 (binaryfunc)mmap_concat, /*sq_concat*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000963 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
964 (ssizeargfunc)mmap_item, /*sq_item*/
965 (ssizessizeargfunc)mmap_slice, /*sq_slice*/
966 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
967 (ssizessizeobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000968};
969
Thomas Wouters3ccec682007-08-28 15:28:19 +0000970static PyMappingMethods mmap_as_mapping = {
971 (lenfunc)mmap_length,
972 (binaryfunc)mmap_subscript,
973 (objobjargproc)mmap_ass_subscript,
974};
975
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000976static PyBufferProcs mmap_as_buffer = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000977 (readbufferproc)mmap_buffer_getreadbuf,
978 (writebufferproc)mmap_buffer_getwritebuf,
979 (segcountproc)mmap_buffer_getsegcount,
980 (charbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000981};
982
983static PyTypeObject mmap_object_type = {
Martin v. Löwis68192102007-07-21 06:55:02 +0000984 PyVarObject_HEAD_INIT(0, 0) /* patched in module init */
Guido van Rossum14648392001-12-08 18:02:58 +0000985 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +0000986 sizeof(mmap_object), /* tp_size */
987 0, /* tp_itemsize */
988 /* methods */
989 (destructor) mmap_object_dealloc, /* tp_dealloc */
990 0, /* tp_print */
991 (getattrfunc) mmap_object_getattr, /* tp_getattr */
992 0, /* tp_setattr */
993 0, /* tp_compare */
994 0, /* tp_repr */
995 0, /* tp_as_number */
996 &mmap_as_sequence, /*tp_as_sequence*/
Thomas Wouters3ccec682007-08-28 15:28:19 +0000997 &mmap_as_mapping, /*tp_as_mapping*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000998 0, /*tp_hash*/
999 0, /*tp_call*/
1000 0, /*tp_str*/
1001 0, /*tp_getattro*/
1002 0, /*tp_setattro*/
1003 &mmap_as_buffer, /*tp_as_buffer*/
1004 Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
1005 0, /*tp_doc*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001006};
1007
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001008
1009/* extract the map size from the given PyObject
1010
Thomas Wouters7e474022000-07-16 12:04:32 +00001011 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001012 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001013static Py_ssize_t
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001014_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001015{
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001016 if (o == NULL)
1017 return 0;
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001018 if (PyIndex_Check(o)) {
1019 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
Guido van Rossum38fff8c2006-03-07 18:50:55 +00001020 if (i==-1 && PyErr_Occurred())
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001021 return -1;
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001022 if (i < 0) {
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001023 PyErr_Format(PyExc_OverflowError,
1024 "memory mapped %s must be positive",
1025 param);
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001026 return -1;
1027 }
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001028 return i;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001029 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001030
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001031 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001032 return -1;
1033}
1034
Tim Petersec0a5f02006-02-16 23:47:20 +00001035#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001036static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001037new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001038{
Neal Norwitzb5673922002-09-05 21:48:07 +00001039#ifdef HAVE_FSTAT
1040 struct stat st;
1041#endif
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001042 mmap_object *m_obj;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001043 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1044 Py_ssize_t map_size, offset;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001045 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001046 int devzero = -1;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001047 int access = (int)ACCESS_DEFAULT;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001048 static char *keywords[] = {"fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001049 "flags", "prot",
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001050 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001051
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001052 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iiiO", keywords,
Jeremy Hyltonaf68c872005-12-10 18:50:16 +00001053 &fd, &map_size_obj, &flags, &prot,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001054 &access, &offset_obj))
Guido van Rossum09fdf072000-03-31 01:17:07 +00001055 return NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001056 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001057 if (map_size < 0)
1058 return NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001059 offset = _GetMapSize(offset_obj, "offset");
1060 if (offset < 0)
1061 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001062
Tim Petersec0a5f02006-02-16 23:47:20 +00001063 if ((access != (int)ACCESS_DEFAULT) &&
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001064 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
Tim Petersec0a5f02006-02-16 23:47:20 +00001065 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001066 "mmap can't specify both access and flags, prot.");
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001067 switch ((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001068 case ACCESS_READ:
1069 flags = MAP_SHARED;
1070 prot = PROT_READ;
1071 break;
1072 case ACCESS_WRITE:
1073 flags = MAP_SHARED;
1074 prot = PROT_READ | PROT_WRITE;
1075 break;
1076 case ACCESS_COPY:
1077 flags = MAP_PRIVATE;
1078 prot = PROT_READ | PROT_WRITE;
1079 break;
Tim Petersec0a5f02006-02-16 23:47:20 +00001080 case ACCESS_DEFAULT:
Tim Peters5ebfd362001-11-13 23:11:19 +00001081 /* use the specified or default values of flags and prot */
1082 break;
1083 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001084 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001085 "mmap invalid access parameter.");
1086 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001087
1088#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001089# ifdef __VMS
1090 /* on OpenVMS we must ensure that all bytes are written to the file */
Andrew M. Kuchling7c22ccc2008-01-10 13:37:12 +00001091 if (fd != -1) {
1092 fsync(fd);
1093 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001094# endif
Andrew M. Kuchling7c22ccc2008-01-10 13:37:12 +00001095 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001096 if (map_size == 0) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001097 map_size = st.st_size;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001098 } else if ((size_t)offset + (size_t)map_size > st.st_size) {
Tim Petersec0a5f02006-02-16 23:47:20 +00001099 PyErr_SetString(PyExc_ValueError,
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001100 "mmap length is greater than file size");
1101 return NULL;
1102 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001103 }
1104#endif
Tim Peters8f9cc292006-02-17 00:00:20 +00001105 m_obj = PyObject_New(mmap_object, &mmap_object_type);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001106 if (m_obj == NULL) {return NULL;}
Neal Norwitz3b4fff82006-01-11 08:54:45 +00001107 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001108 m_obj->size = (size_t) map_size;
1109 m_obj->pos = (size_t) 0;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001110 m_obj->offset = offset;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001111 if (fd == -1) {
1112 m_obj->fd = -1;
1113 /* Assume the caller wants to map anonymous memory.
1114 This is the same behaviour as Windows. mmap.mmap(-1, size)
1115 on both Windows and Unix map anonymous memory.
1116 */
1117#ifdef MAP_ANONYMOUS
1118 /* BSD way to map anonymous memory */
1119 flags |= MAP_ANONYMOUS;
1120#else
1121 /* SVR4 method to map anonymous memory is to open /dev/zero */
1122 fd = devzero = open("/dev/zero", O_RDWR);
1123 if (devzero == -1) {
1124 Py_DECREF(m_obj);
1125 PyErr_SetFromErrno(mmap_module_error);
1126 return NULL;
1127 }
1128#endif
1129 } else {
1130 m_obj->fd = dup(fd);
1131 if (m_obj->fd == -1) {
1132 Py_DECREF(m_obj);
1133 PyErr_SetFromErrno(mmap_module_error);
1134 return NULL;
1135 }
Georg Brandl38387b82005-08-24 07:17:40 +00001136 }
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001137
Tim Petersec0a5f02006-02-16 23:47:20 +00001138 m_obj->data = mmap(NULL, map_size,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001139 prot, flags,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001140 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001141
1142 if (devzero != -1) {
1143 close(devzero);
1144 }
1145
Tim Peters5ebfd362001-11-13 23:11:19 +00001146 if (m_obj->data == (char *)-1) {
Andrew M. Kuchling16581c82004-05-19 14:39:08 +00001147 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001148 Py_DECREF(m_obj);
1149 PyErr_SetFromErrno(mmap_module_error);
1150 return NULL;
1151 }
Neal Norwitz8856fb72005-12-18 03:34:22 +00001152 m_obj->access = (access_mode)access;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001153 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001154}
1155#endif /* UNIX */
1156
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001157#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001158static PyObject *
Tim Peters5ebfd362001-11-13 23:11:19 +00001159new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001160{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001161 mmap_object *m_obj;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001162 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1163 Py_ssize_t map_size, offset;
1164 DWORD off_hi; /* upper 32 bits of offset */
1165 DWORD off_lo; /* lower 32 bits of offset */
1166 DWORD size_hi; /* upper 32 bits of size */
1167 DWORD size_lo; /* lower 32 bits of size */
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001168 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +00001169 DWORD dwErr = 0;
1170 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +00001171 HANDLE fh = 0;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001172 int access = (access_mode)ACCESS_DEFAULT;
Tim Peters5ebfd362001-11-13 23:11:19 +00001173 DWORD flProtect, dwDesiredAccess;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001174 static char *keywords[] = { "fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001175 "tagname",
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001176 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001177
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001178 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
Tim Petersec0a5f02006-02-16 23:47:20 +00001179 &fileno, &map_size_obj,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001180 &tagname, &access, &offset_obj)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001181 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001182 }
1183
Neal Norwitz8856fb72005-12-18 03:34:22 +00001184 switch((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001185 case ACCESS_READ:
1186 flProtect = PAGE_READONLY;
1187 dwDesiredAccess = FILE_MAP_READ;
1188 break;
1189 case ACCESS_DEFAULT: case ACCESS_WRITE:
1190 flProtect = PAGE_READWRITE;
1191 dwDesiredAccess = FILE_MAP_WRITE;
1192 break;
1193 case ACCESS_COPY:
1194 flProtect = PAGE_WRITECOPY;
1195 dwDesiredAccess = FILE_MAP_COPY;
1196 break;
1197 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001198 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001199 "mmap invalid access parameter.");
1200 }
1201
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001202 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001203 if (map_size < 0)
1204 return NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001205 offset = _GetMapSize(offset_obj, "offset");
1206 if (offset < 0)
1207 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001208
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001209 /* assume -1 and 0 both mean invalid filedescriptor
1210 to 'anonymously' map memory.
1211 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1212 XXX: Should this code be added?
1213 if (fileno == 0)
1214 PyErr_Warn(PyExc_DeprecationWarning,
1215 "don't use 0 for anonymous memory");
1216 */
1217 if (fileno != -1 && fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +00001218 fh = (HANDLE)_get_osfhandle(fileno);
1219 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001220 PyErr_SetFromErrno(mmap_module_error);
1221 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001222 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +00001223 /* Win9x appears to need us seeked to zero */
Guido van Rossum69c2b882003-04-09 19:31:02 +00001224 lseek(fileno, 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001225 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001226
Tim Peters8f9cc292006-02-17 00:00:20 +00001227 m_obj = PyObject_New(mmap_object, &mmap_object_type);
1228 if (m_obj == NULL)
Mark Hammond2cbed002000-07-30 02:22:43 +00001229 return NULL;
1230 /* Set every field to an invalid marker, so we can safely
1231 destruct the object in the face of failure */
1232 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +00001233 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +00001234 m_obj->map_handle = INVALID_HANDLE_VALUE;
1235 m_obj->tagname = NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001236 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001237
Guido van Rossum09fdf072000-03-31 01:17:07 +00001238 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +00001239 /* It is necessary to duplicate the handle, so the
1240 Python code can close it on us */
1241 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +00001242 GetCurrentProcess(), /* source process handle */
1243 fh, /* handle to be duplicated */
1244 GetCurrentProcess(), /* target proc handle */
1245 (LPHANDLE)&m_obj->file_handle, /* result */
1246 0, /* access - ignored due to options value */
1247 FALSE, /* inherited by child processes? */
1248 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +00001249 dwErr = GetLastError();
1250 Py_DECREF(m_obj);
1251 PyErr_SetFromWindowsErr(dwErr);
1252 return NULL;
1253 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001254 if (!map_size) {
Martin v. Löwis15186072006-02-18 12:38:35 +00001255 DWORD low,high;
1256 low = GetFileSize(fh, &high);
1257 /* low might just happen to have the value INVALID_FILE_SIZE;
1258 so we need to check the last error also. */
1259 if (low == INVALID_FILE_SIZE &&
1260 (dwErr = GetLastError()) != NO_ERROR) {
1261 Py_DECREF(m_obj);
1262 return PyErr_SetFromWindowsErr(dwErr);
1263 }
1264
1265#if SIZEOF_SIZE_T > 4
1266 m_obj->size = (((size_t)high)<<32) + low;
1267#else
1268 if (high)
1269 /* File is too large to map completely */
1270 m_obj->size = (size_t)-1;
1271 else
1272 m_obj->size = low;
1273#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001274 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001275 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001276 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001277 }
1278 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001279 m_obj->size = map_size;
1280 }
1281
1282 /* set the initial position */
1283 m_obj->pos = (size_t) 0;
1284
Mark Hammond2cbed002000-07-30 02:22:43 +00001285 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001286 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001287 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1288 if (m_obj->tagname == NULL) {
1289 PyErr_NoMemory();
1290 Py_DECREF(m_obj);
1291 return NULL;
1292 }
1293 strcpy(m_obj->tagname, tagname);
1294 }
1295 else
1296 m_obj->tagname = NULL;
1297
Neal Norwitz8856fb72005-12-18 03:34:22 +00001298 m_obj->access = (access_mode)access;
Tim Peterse564e7f2006-02-16 23:46:01 +00001299 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
Thomas Wouters2c98a7b2006-02-17 09:59:00 +00001300 * more than 4 bytes, we need to break it apart. Else (size_t
Tim Peterse564e7f2006-02-16 23:46:01 +00001301 * consumes 4 bytes), C doesn't define what happens if we shift
1302 * right by 32, so we need different code.
1303 */
1304#if SIZEOF_SIZE_T > 4
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001305 size_hi = (DWORD)((offset + m_obj->size) >> 32);
1306 size_lo = (DWORD)((offset + m_obj->size) & 0xFFFFFFFF);
1307 off_hi = (DWORD)(offset >> 32);
1308 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Tim Peterse564e7f2006-02-16 23:46:01 +00001309#else
1310 size_hi = 0;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001311 size_lo = (DWORD)(offset + m_obj->size);
1312 off_hi = 0;
1313 off_lo = (DWORD)offset;
Tim Peterse564e7f2006-02-16 23:46:01 +00001314#endif
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001315 /* For files, it would be sufficient to pass 0 as size.
1316 For anonymous maps, we have to pass the size explicitly. */
Tim Peters8f9cc292006-02-17 00:00:20 +00001317 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1318 NULL,
1319 flProtect,
1320 size_hi,
1321 size_lo,
1322 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001323 if (m_obj->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +00001324 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1325 dwDesiredAccess,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001326 off_hi,
1327 off_lo,
Tim Peters8f9cc292006-02-17 00:00:20 +00001328 0);
Tim Peters23721ee2006-02-16 23:50:16 +00001329 if (m_obj->data != NULL)
1330 return (PyObject *)m_obj;
1331 else
Tim Peters5ebfd362001-11-13 23:11:19 +00001332 dwErr = GetLastError();
Tim Peters23721ee2006-02-16 23:50:16 +00001333 } else
Guido van Rossum09fdf072000-03-31 01:17:07 +00001334 dwErr = GetLastError();
Mark Hammond2cbed002000-07-30 02:22:43 +00001335 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001336 PyErr_SetFromWindowsErr(dwErr);
Tim Peters23721ee2006-02-16 23:50:16 +00001337 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001338}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001339#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001340
1341/* List of functions exported by this module */
1342static struct PyMethodDef mmap_functions[] = {
Tim Petersec0a5f02006-02-16 23:47:20 +00001343 {"mmap", (PyCFunction) new_mmap_object,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001344 METH_VARARGS|METH_KEYWORDS},
1345 {NULL, NULL} /* Sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001346};
1347
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001348static void
1349setint(PyObject *d, const char *name, long value)
1350{
1351 PyObject *o = PyInt_FromLong(value);
Neal Norwitz5ed49972006-08-13 18:41:15 +00001352 if (o && PyDict_SetItemString(d, name, o) == 0) {
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001353 Py_DECREF(o);
Neal Norwitz5ed49972006-08-13 18:41:15 +00001354 }
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001355}
1356
Mark Hammond62b1ab12002-07-23 06:31:15 +00001357PyMODINIT_FUNC
Tim Peters5ebfd362001-11-13 23:11:19 +00001358 initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001359{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001360 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001361
1362 /* Patch the object type */
Christian Heimese93237d2007-12-19 02:37:44 +00001363 Py_TYPE(&mmap_object_type) = &PyType_Type;
Tim Peters2caf8df2001-01-14 05:05:51 +00001364
Tim Peters8f9cc292006-02-17 00:00:20 +00001365 module = Py_InitModule("mmap", mmap_functions);
Neal Norwitz1ac754f2006-01-19 06:09:39 +00001366 if (module == NULL)
1367 return;
Tim Peters8f9cc292006-02-17 00:00:20 +00001368 dict = PyModule_GetDict(module);
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001369 if (!dict)
1370 return;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001371 mmap_module_error = PyExc_EnvironmentError;
Tim Peters8f9cc292006-02-17 00:00:20 +00001372 PyDict_SetItemString(dict, "error", mmap_module_error);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001373#ifdef PROT_EXEC
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001374 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001375#endif
1376#ifdef PROT_READ
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001377 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001378#endif
1379#ifdef PROT_WRITE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001380 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001381#endif
1382
1383#ifdef MAP_SHARED
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001384 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001385#endif
1386#ifdef MAP_PRIVATE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001387 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001388#endif
1389#ifdef MAP_DENYWRITE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001390 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001391#endif
1392#ifdef MAP_EXECUTABLE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001393 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001394#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001395#ifdef MAP_ANONYMOUS
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001396 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1397 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001398#endif
1399
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001400 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001401
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001402 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
1403
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001404 setint(dict, "ACCESS_READ", ACCESS_READ);
1405 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1406 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Tim Peters5ebfd362001-11-13 23:11:19 +00001407}