blob: 49fe7f7c72c563461f0e35e3af2e86db8a73a3b9 [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
Christian Heimes501dbbf2008-01-23 14:00:25 +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
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;
Neal Norwitz739a3c42008-01-26 20:24:36 +0000256 Py_ssize_t end = self->size;
257 const 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 {
Neal Norwitz739a3c42008-01-26 20:24:36 +0000265 const char *p, *start_p, *end_p;
Neal Norwitze1027f92008-01-27 07:37:38 +0000266 int 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
Neal Norwitz739a3c42008-01-26 20:24:36 +0000282 start_p = self->data + start;
283 end_p = self->data + end;
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000284
Neal Norwitz739a3c42008-01-26 20:24:36 +0000285 for (p = (reverse ? end_p - len : start_p);
286 (p >= start_p) && (p + len <= end_p); 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;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000535 }
Neal Norwitz448654f2008-01-27 07:36:03 +0000536#ifdef MS_WINDOWS
537 return PyInt_FromLong((long) FlushViewOfFile(self->data+offset, size));
538#elif defined(UNIX)
539 /* XXX semantics of return value? */
540 /* XXX flags for msync? */
541 if (-1 == msync(self->data + offset, size, MS_SYNC)) {
542 PyErr_SetFromErrno(mmap_module_error);
543 return NULL;
544 }
545 return PyInt_FromLong(0);
546#else
547 PyErr_SetString(PyExc_ValueError, "flush not supported on this system");
548 return NULL;
549#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000550}
551
552static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000553mmap_seek_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000554{
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000555 Py_ssize_t dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000556 int how=0;
557 CHECK_VALID(NULL);
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000558 if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how))
Tim Peters8f9cc292006-02-17 00:00:20 +0000559 return NULL;
560 else {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000561 size_t where;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000562 switch (how) {
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000563 case 0: /* relative to start */
564 if (dist < 0)
565 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000566 where = dist;
567 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000568 case 1: /* relative to current position */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000569 if ((Py_ssize_t)self->pos + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000570 goto onoutofrange;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000571 where = self->pos + dist;
572 break;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000573 case 2: /* relative to end */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +0000574 if ((Py_ssize_t)self->size + dist < 0)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000575 goto onoutofrange;
576 where = self->size + dist;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000577 break;
578 default:
Tim Peters8f9cc292006-02-17 00:00:20 +0000579 PyErr_SetString(PyExc_ValueError, "unknown seek type");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000580 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000581 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000582 if (where > self->size)
583 goto onoutofrange;
584 self->pos = where;
Tim Peters8f9cc292006-02-17 00:00:20 +0000585 Py_INCREF(Py_None);
Tim Peters23721ee2006-02-16 23:50:16 +0000586 return Py_None;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000587 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000588
Tim Peters5ebfd362001-11-13 23:11:19 +0000589 onoutofrange:
Tim Peters8f9cc292006-02-17 00:00:20 +0000590 PyErr_SetString(PyExc_ValueError, "seek out of range");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +0000591 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000592}
593
594static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000595mmap_move_method(mmap_object *self, PyObject *args)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000596{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000597 unsigned long dest, src, count;
598 CHECK_VALID(NULL);
Tim Peters8f9cc292006-02-17 00:00:20 +0000599 if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &count) ||
Tim Peters5ebfd362001-11-13 23:11:19 +0000600 !is_writeable(self)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000601 return NULL;
602 } else {
603 /* bounds check the values */
604 if (/* end of source after end of data?? */
605 ((src+count) > self->size)
606 /* dest will fit? */
607 || (dest+count > self->size)) {
Tim Peters8f9cc292006-02-17 00:00:20 +0000608 PyErr_SetString(PyExc_ValueError,
609 "source or destination out of range");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000610 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000611 } else {
Tim Peters8f9cc292006-02-17 00:00:20 +0000612 memmove(self->data+dest, self->data+src, count);
613 Py_INCREF(Py_None);
Guido van Rossum09fdf072000-03-31 01:17:07 +0000614 return Py_None;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000615 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000616 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000617}
618
619static struct PyMethodDef mmap_object_methods[] = {
Georg Brandl96a8c392006-05-29 21:04:52 +0000620 {"close", (PyCFunction) mmap_close_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000621 {"find", (PyCFunction) mmap_find_method, METH_VARARGS},
Andrew M. Kuchling5c60bfc2008-01-19 18:18:41 +0000622 {"rfind", (PyCFunction) mmap_rfind_method, METH_VARARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000623 {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS},
624 {"move", (PyCFunction) mmap_move_method, METH_VARARGS},
625 {"read", (PyCFunction) mmap_read_method, METH_VARARGS},
Georg Brandl96a8c392006-05-29 21:04:52 +0000626 {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS},
627 {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000628 {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS},
629 {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS},
Georg Brandl96a8c392006-05-29 21:04:52 +0000630 {"size", (PyCFunction) mmap_size_method, METH_NOARGS},
631 {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS},
Martin v. Löwis43b936d2002-01-17 23:15:58 +0000632 {"write", (PyCFunction) mmap_write_method, METH_VARARGS},
633 {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS},
Guido van Rossum09fdf072000-03-31 01:17:07 +0000634 {NULL, NULL} /* sentinel */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000635};
636
637/* Functions for treating an mmap'ed file as a buffer */
638
Martin v. Löwis18e16552006-02-15 17:27:45 +0000639static Py_ssize_t
640mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000641{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000642 CHECK_VALID(-1);
Tim Peters8f9cc292006-02-17 00:00:20 +0000643 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000644 PyErr_SetString(PyExc_SystemError,
645 "Accessing non-existent mmap segment");
646 return -1;
647 }
648 *ptr = self->data;
649 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000650}
651
Martin v. Löwis18e16552006-02-15 17:27:45 +0000652static Py_ssize_t
653mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr)
Tim Petersec0a5f02006-02-16 23:47:20 +0000654{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000655 CHECK_VALID(-1);
Tim Peters8f9cc292006-02-17 00:00:20 +0000656 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000657 PyErr_SetString(PyExc_SystemError,
658 "Accessing non-existent mmap segment");
659 return -1;
660 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000661 if (!is_writeable(self))
662 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000663 *ptr = self->data;
664 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000665}
666
Martin v. Löwis18e16552006-02-15 17:27:45 +0000667static Py_ssize_t
668mmap_buffer_getsegcount(mmap_object *self, Py_ssize_t *lenp)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000669{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000670 CHECK_VALID(-1);
Tim Petersec0a5f02006-02-16 23:47:20 +0000671 if (lenp)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000672 *lenp = self->size;
673 return 1;
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_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000678{
Tim Peters8f9cc292006-02-17 00:00:20 +0000679 if (index != 0) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000680 PyErr_SetString(PyExc_SystemError,
681 "accessing non-existent buffer segment");
682 return -1;
683 }
684 *ptr = (const char *)self->data;
685 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000686}
687
Martin v. Löwis18e16552006-02-15 17:27:45 +0000688static Py_ssize_t
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000689mmap_length(mmap_object *self)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000690{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000691 CHECK_VALID(-1);
692 return self->size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000693}
694
695static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000696mmap_item(mmap_object *self, Py_ssize_t i)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000697{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000698 CHECK_VALID(NULL);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000699 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000700 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
701 return NULL;
702 }
703 return PyString_FromStringAndSize(self->data + i, 1);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000704}
705
706static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000707mmap_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000708{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000709 CHECK_VALID(NULL);
710 if (ilow < 0)
711 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000712 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000713 ilow = self->size;
714 if (ihigh < 0)
715 ihigh = 0;
716 if (ihigh < ilow)
717 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000718 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000719 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000720
Guido van Rossum09fdf072000-03-31 01:17:07 +0000721 return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000722}
723
724static PyObject *
Thomas Wouters3ccec682007-08-28 15:28:19 +0000725mmap_subscript(mmap_object *self, PyObject *item)
726{
727 CHECK_VALID(NULL);
728 if (PyIndex_Check(item)) {
729 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
730 if (i == -1 && PyErr_Occurred())
731 return NULL;
732 if (i < 0)
733 i += self->size;
Neal Norwitz9c4382f2007-10-31 06:33:20 +0000734 if (i < 0 || (size_t)i > self->size) {
Thomas Wouters3ccec682007-08-28 15:28:19 +0000735 PyErr_SetString(PyExc_IndexError,
736 "mmap index out of range");
737 return NULL;
738 }
739 return PyString_FromStringAndSize(self->data + i, 1);
740 }
741 else if (PySlice_Check(item)) {
742 Py_ssize_t start, stop, step, slicelen;
743
744 if (PySlice_GetIndicesEx((PySliceObject *)item, self->size,
745 &start, &stop, &step, &slicelen) < 0) {
746 return NULL;
747 }
748
749 if (slicelen <= 0)
750 return PyString_FromStringAndSize("", 0);
751 else if (step == 1)
752 return PyString_FromStringAndSize(self->data + start,
753 slicelen);
754 else {
755 char *result_buf = (char *)PyMem_Malloc(slicelen);
756 Py_ssize_t cur, i;
757 PyObject *result;
758
759 if (result_buf == NULL)
760 return PyErr_NoMemory();
761 for (cur = start, i = 0; i < slicelen;
762 cur += step, i++) {
763 result_buf[i] = self->data[cur];
764 }
765 result = PyString_FromStringAndSize(result_buf,
766 slicelen);
767 PyMem_Free(result_buf);
768 return result;
769 }
770 }
771 else {
772 PyErr_SetString(PyExc_TypeError,
773 "mmap indices must be integers");
774 return NULL;
775 }
776}
777
778static PyObject *
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +0000779mmap_concat(mmap_object *self, PyObject *bb)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000780{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000781 CHECK_VALID(NULL);
782 PyErr_SetString(PyExc_SystemError,
783 "mmaps don't support concatenation");
784 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000785}
786
787static PyObject *
Martin v. Löwis18e16552006-02-15 17:27:45 +0000788mmap_repeat(mmap_object *self, Py_ssize_t n)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000789{
Guido van Rossum09fdf072000-03-31 01:17:07 +0000790 CHECK_VALID(NULL);
791 PyErr_SetString(PyExc_SystemError,
792 "mmaps don't support repeat operation");
793 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000794}
795
796static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000797mmap_ass_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000798{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000799 const char *buf;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000800
Guido van Rossum09fdf072000-03-31 01:17:07 +0000801 CHECK_VALID(-1);
802 if (ilow < 0)
803 ilow = 0;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000804 else if ((size_t)ilow > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000805 ilow = self->size;
806 if (ihigh < 0)
807 ihigh = 0;
808 if (ihigh < ilow)
809 ihigh = ilow;
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000810 else if ((size_t)ihigh > self->size)
Guido van Rossum09fdf072000-03-31 01:17:07 +0000811 ihigh = self->size;
Tim Petersec0a5f02006-02-16 23:47:20 +0000812
Thomas Wouters1baac722001-07-16 15:47:36 +0000813 if (v == NULL) {
814 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000815 "mmap object doesn't support slice deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000816 return -1;
817 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000818 if (! (PyString_Check(v)) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000819 PyErr_SetString(PyExc_IndexError,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000820 "mmap slice assignment must be a string");
821 return -1;
822 }
Tim Peters8f9cc292006-02-17 00:00:20 +0000823 if (PyString_Size(v) != (ihigh - ilow)) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000824 PyErr_SetString(PyExc_IndexError,
Guido van Rossum09fdf072000-03-31 01:17:07 +0000825 "mmap slice assignment is wrong size");
826 return -1;
827 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000828 if (!is_writeable(self))
829 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000830 buf = PyString_AsString(v);
831 memcpy(self->data + ilow, buf, ihigh-ilow);
832 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000833}
834
835static int
Martin v. Löwis18e16552006-02-15 17:27:45 +0000836mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000837{
Guido van Rossum36d4f8b2000-04-10 21:34:37 +0000838 const char *buf;
Tim Petersec0a5f02006-02-16 23:47:20 +0000839
Guido van Rossum09fdf072000-03-31 01:17:07 +0000840 CHECK_VALID(-1);
Guido van Rossumce8e1dc2000-07-01 00:51:51 +0000841 if (i < 0 || (size_t)i >= self->size) {
Guido van Rossum09fdf072000-03-31 01:17:07 +0000842 PyErr_SetString(PyExc_IndexError, "mmap index out of range");
843 return -1;
844 }
Thomas Wouters1baac722001-07-16 15:47:36 +0000845 if (v == NULL) {
846 PyErr_SetString(PyExc_TypeError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000847 "mmap object doesn't support item deletion");
Thomas Wouters1baac722001-07-16 15:47:36 +0000848 return -1;
849 }
Guido van Rossum09fdf072000-03-31 01:17:07 +0000850 if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
Tim Petersec0a5f02006-02-16 23:47:20 +0000851 PyErr_SetString(PyExc_IndexError,
Tim Peters5ebfd362001-11-13 23:11:19 +0000852 "mmap assignment must be single-character string");
Guido van Rossum09fdf072000-03-31 01:17:07 +0000853 return -1;
854 }
Tim Peters5ebfd362001-11-13 23:11:19 +0000855 if (!is_writeable(self))
856 return -1;
Guido van Rossum09fdf072000-03-31 01:17:07 +0000857 buf = PyString_AsString(v);
858 self->data[i] = buf[0];
859 return 0;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000860}
861
Thomas Wouters3ccec682007-08-28 15:28:19 +0000862static int
863mmap_ass_subscript(mmap_object *self, PyObject *item, PyObject *value)
864{
865 CHECK_VALID(-1);
866
867 if (PyIndex_Check(item)) {
868 Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
869 const char *buf;
870
871 if (i == -1 && PyErr_Occurred())
872 return -1;
873 if (i < 0)
874 i += self->size;
Neal Norwitz9c4382f2007-10-31 06:33:20 +0000875 if (i < 0 || (size_t)i > self->size) {
Thomas Wouters3ccec682007-08-28 15:28:19 +0000876 PyErr_SetString(PyExc_IndexError,
877 "mmap index out of range");
878 return -1;
879 }
880 if (value == NULL) {
881 PyErr_SetString(PyExc_TypeError,
882 "mmap object doesn't support item deletion");
883 return -1;
884 }
885 if (!PyString_Check(value) || PyString_Size(value) != 1) {
886 PyErr_SetString(PyExc_IndexError,
887 "mmap assignment must be single-character string");
888 return -1;
889 }
890 if (!is_writeable(self))
891 return -1;
892 buf = PyString_AsString(value);
893 self->data[i] = buf[0];
894 return 0;
895 }
896 else if (PySlice_Check(item)) {
897 Py_ssize_t start, stop, step, slicelen;
898
899 if (PySlice_GetIndicesEx((PySliceObject *)item,
900 self->size, &start, &stop,
901 &step, &slicelen) < 0) {
902 return -1;
903 }
904 if (value == NULL) {
905 PyErr_SetString(PyExc_TypeError,
906 "mmap object doesn't support slice deletion");
907 return -1;
908 }
909 if (!PyString_Check(value)) {
910 PyErr_SetString(PyExc_IndexError,
911 "mmap slice assignment must be a string");
912 return -1;
913 }
914 if (PyString_Size(value) != slicelen) {
915 PyErr_SetString(PyExc_IndexError,
916 "mmap slice assignment is wrong size");
917 return -1;
918 }
919 if (!is_writeable(self))
920 return -1;
921
922 if (slicelen == 0)
923 return 0;
924 else if (step == 1) {
925 const char *buf = PyString_AsString(value);
926
927 if (buf == NULL)
928 return -1;
929 memcpy(self->data + start, buf, slicelen);
930 return 0;
931 }
932 else {
933 Py_ssize_t cur, i;
934 const char *buf = PyString_AsString(value);
935
936 if (buf == NULL)
937 return -1;
938 for (cur = start, i = 0; i < slicelen;
939 cur += step, i++) {
940 self->data[cur] = buf[i];
941 }
942 return 0;
943 }
944 }
945 else {
946 PyErr_SetString(PyExc_TypeError,
947 "mmap indices must be integer");
948 return -1;
949 }
950}
951
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000952static PySequenceMethods mmap_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000953 (lenfunc)mmap_length, /*sq_length*/
Guido van Rossum09fdf072000-03-31 01:17:07 +0000954 (binaryfunc)mmap_concat, /*sq_concat*/
Martin v. Löwis18e16552006-02-15 17:27:45 +0000955 (ssizeargfunc)mmap_repeat, /*sq_repeat*/
956 (ssizeargfunc)mmap_item, /*sq_item*/
957 (ssizessizeargfunc)mmap_slice, /*sq_slice*/
958 (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/
959 (ssizessizeobjargproc)mmap_ass_slice, /*sq_ass_slice*/
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000960};
961
Thomas Wouters3ccec682007-08-28 15:28:19 +0000962static PyMappingMethods mmap_as_mapping = {
963 (lenfunc)mmap_length,
964 (binaryfunc)mmap_subscript,
965 (objobjargproc)mmap_ass_subscript,
966};
967
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000968static PyBufferProcs mmap_as_buffer = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000969 (readbufferproc)mmap_buffer_getreadbuf,
970 (writebufferproc)mmap_buffer_getwritebuf,
971 (segcountproc)mmap_buffer_getsegcount,
972 (charbufferproc)mmap_buffer_getcharbuffer,
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +0000973};
974
Georg Brandl845c4032008-01-21 14:16:46 +0000975static PyObject *
976new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict);
977
Georg Brandlef928022008-01-20 14:50:05 +0000978PyDoc_STRVAR(mmap_doc,
979"Windows: mmap(fileno, length[, tagname[, access[, offset]]])\n\
980\n\
981Maps length bytes from the file specified by the file handle fileno,\n\
982and returns a mmap object. If length is larger than the current size\n\
983of the file, the file is extended to contain length bytes. If length\n\
984is 0, the maximum length of the map is the current size of the file,\n\
985except that if the file is empty Windows raises an exception (you cannot\n\
986create an empty mapping on Windows).\n\
987\n\
988Unix: mmap(fileno, length[, flags[, prot[, access[, offset]]]])\n\
989\n\
990Maps length bytes from the file specified by the file descriptor fileno,\n\
991and returns a mmap object. If length is 0, the maximum length of the map\n\
992will be the current size of the file when mmap is called.\n\
993flags specifies the nature of the mapping. MAP_PRIVATE creates a\n\
994private copy-on-write mapping, so changes to the contents of the mmap\n\
995object will be private to this process, and MAP_SHARED`creates a mapping\n\
996that's shared with all other processes mapping the same areas of the file.\n\
997The default value is MAP_SHARED.\n\
998\n\
999To map anonymous memory, pass -1 as the fileno (both versions).");
1000
1001
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001002static PyTypeObject mmap_object_type = {
Georg Brandl845c4032008-01-21 14:16:46 +00001003 PyVarObject_HEAD_INIT(NULL, 0)
Guido van Rossum14648392001-12-08 18:02:58 +00001004 "mmap.mmap", /* tp_name */
Guido van Rossum09fdf072000-03-31 01:17:07 +00001005 sizeof(mmap_object), /* tp_size */
1006 0, /* tp_itemsize */
1007 /* methods */
1008 (destructor) mmap_object_dealloc, /* tp_dealloc */
1009 0, /* tp_print */
Georg Brandlef928022008-01-20 14:50:05 +00001010 0, /* tp_getattr */
Guido van Rossum09fdf072000-03-31 01:17:07 +00001011 0, /* tp_setattr */
1012 0, /* tp_compare */
1013 0, /* tp_repr */
1014 0, /* tp_as_number */
1015 &mmap_as_sequence, /*tp_as_sequence*/
Thomas Wouters3ccec682007-08-28 15:28:19 +00001016 &mmap_as_mapping, /*tp_as_mapping*/
Guido van Rossum09fdf072000-03-31 01:17:07 +00001017 0, /*tp_hash*/
1018 0, /*tp_call*/
1019 0, /*tp_str*/
Georg Brandlef928022008-01-20 14:50:05 +00001020 PyObject_GenericGetAttr, /*tp_getattro*/
Guido van Rossum09fdf072000-03-31 01:17:07 +00001021 0, /*tp_setattro*/
1022 &mmap_as_buffer, /*tp_as_buffer*/
Georg Brandl845c4032008-01-21 14:16:46 +00001023 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/
Georg Brandlef928022008-01-20 14:50:05 +00001024 mmap_doc, /*tp_doc*/
1025 0, /* tp_traverse */
1026 0, /* tp_clear */
1027 0, /* tp_richcompare */
1028 0, /* tp_weaklistoffset */
Georg Brandl845c4032008-01-21 14:16:46 +00001029 0, /* tp_iter */
1030 0, /* tp_iternext */
Georg Brandlef928022008-01-20 14:50:05 +00001031 mmap_object_methods, /* tp_methods */
Georg Brandl845c4032008-01-21 14:16:46 +00001032 0, /* tp_members */
1033 0, /* tp_getset */
1034 0, /* tp_base */
1035 0, /* tp_dict */
1036 0, /* tp_descr_get */
1037 0, /* tp_descr_set */
1038 0, /* tp_dictoffset */
1039 0, /* tp_init */
1040 PyType_GenericAlloc, /* tp_alloc */
1041 new_mmap_object, /* tp_new */
1042 PyObject_Del, /* tp_free */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001043};
1044
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001045
1046/* extract the map size from the given PyObject
1047
Thomas Wouters7e474022000-07-16 12:04:32 +00001048 Returns -1 on error, with an appropriate Python exception raised. On
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001049 success, the map size is returned. */
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001050static Py_ssize_t
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001051_GetMapSize(PyObject *o, const char* param)
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001052{
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001053 if (o == NULL)
1054 return 0;
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001055 if (PyIndex_Check(o)) {
1056 Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
Guido van Rossum38fff8c2006-03-07 18:50:55 +00001057 if (i==-1 && PyErr_Occurred())
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001058 return -1;
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001059 if (i < 0) {
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001060 PyErr_Format(PyExc_OverflowError,
1061 "memory mapped %s must be positive",
1062 param);
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001063 return -1;
1064 }
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001065 return i;
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001066 }
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001067
Neal Norwitz8a87f5d2006-08-12 17:03:09 +00001068 PyErr_SetString(PyExc_TypeError, "map size must be an integral value");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001069 return -1;
1070}
1071
Tim Petersec0a5f02006-02-16 23:47:20 +00001072#ifdef UNIX
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001073static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001074new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001075{
Neal Norwitzb5673922002-09-05 21:48:07 +00001076#ifdef HAVE_FSTAT
1077 struct stat st;
1078#endif
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001079 mmap_object *m_obj;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001080 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1081 Py_ssize_t map_size, offset;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001082 int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001083 int devzero = -1;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001084 int access = (int)ACCESS_DEFAULT;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001085 static char *keywords[] = {"fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001086 "flags", "prot",
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001087 "access", "offset", NULL};
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001088
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001089 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iiiO", keywords,
Jeremy Hyltonaf68c872005-12-10 18:50:16 +00001090 &fd, &map_size_obj, &flags, &prot,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001091 &access, &offset_obj))
Guido van Rossum09fdf072000-03-31 01:17:07 +00001092 return NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001093 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001094 if (map_size < 0)
1095 return NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001096 offset = _GetMapSize(offset_obj, "offset");
1097 if (offset < 0)
1098 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001099
Tim Petersec0a5f02006-02-16 23:47:20 +00001100 if ((access != (int)ACCESS_DEFAULT) &&
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001101 ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ))))
Tim Petersec0a5f02006-02-16 23:47:20 +00001102 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001103 "mmap can't specify both access and flags, prot.");
Neal Norwitzd1cfc8a2006-02-05 03:36:57 +00001104 switch ((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001105 case ACCESS_READ:
1106 flags = MAP_SHARED;
1107 prot = PROT_READ;
1108 break;
1109 case ACCESS_WRITE:
1110 flags = MAP_SHARED;
1111 prot = PROT_READ | PROT_WRITE;
1112 break;
1113 case ACCESS_COPY:
1114 flags = MAP_PRIVATE;
1115 prot = PROT_READ | PROT_WRITE;
1116 break;
Tim Petersec0a5f02006-02-16 23:47:20 +00001117 case ACCESS_DEFAULT:
Tim Peters5ebfd362001-11-13 23:11:19 +00001118 /* use the specified or default values of flags and prot */
1119 break;
1120 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001121 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001122 "mmap invalid access parameter.");
1123 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001124
1125#ifdef HAVE_FSTAT
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001126# ifdef __VMS
1127 /* on OpenVMS we must ensure that all bytes are written to the file */
Andrew M. Kuchling7c22ccc2008-01-10 13:37:12 +00001128 if (fd != -1) {
1129 fsync(fd);
1130 }
Martin v. Löwisc16f3bd2003-05-03 09:14:54 +00001131# endif
Andrew M. Kuchling7c22ccc2008-01-10 13:37:12 +00001132 if (fd != -1 && fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) {
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001133 if (map_size == 0) {
Martin v. Löwiscfe7e092006-02-17 06:59:14 +00001134 map_size = st.st_size;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001135 } else if ((size_t)offset + (size_t)map_size > st.st_size) {
Tim Petersec0a5f02006-02-16 23:47:20 +00001136 PyErr_SetString(PyExc_ValueError,
Martin v. Löwis7fe60c02005-03-03 11:22:44 +00001137 "mmap length is greater than file size");
1138 return NULL;
1139 }
Neal Norwitzb5673922002-09-05 21:48:07 +00001140 }
1141#endif
Georg Brandl845c4032008-01-21 14:16:46 +00001142 m_obj = (mmap_object *)type->tp_alloc(type, 0);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001143 if (m_obj == NULL) {return NULL;}
Neal Norwitz3b4fff82006-01-11 08:54:45 +00001144 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001145 m_obj->size = (size_t) map_size;
1146 m_obj->pos = (size_t) 0;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001147 m_obj->offset = offset;
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001148 if (fd == -1) {
1149 m_obj->fd = -1;
1150 /* Assume the caller wants to map anonymous memory.
1151 This is the same behaviour as Windows. mmap.mmap(-1, size)
1152 on both Windows and Unix map anonymous memory.
1153 */
1154#ifdef MAP_ANONYMOUS
1155 /* BSD way to map anonymous memory */
1156 flags |= MAP_ANONYMOUS;
1157#else
1158 /* SVR4 method to map anonymous memory is to open /dev/zero */
1159 fd = devzero = open("/dev/zero", O_RDWR);
1160 if (devzero == -1) {
1161 Py_DECREF(m_obj);
1162 PyErr_SetFromErrno(mmap_module_error);
1163 return NULL;
1164 }
1165#endif
1166 } else {
1167 m_obj->fd = dup(fd);
1168 if (m_obj->fd == -1) {
1169 Py_DECREF(m_obj);
1170 PyErr_SetFromErrno(mmap_module_error);
1171 return NULL;
1172 }
Georg Brandl38387b82005-08-24 07:17:40 +00001173 }
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001174
Tim Petersec0a5f02006-02-16 23:47:20 +00001175 m_obj->data = mmap(NULL, map_size,
Guido van Rossum09fdf072000-03-31 01:17:07 +00001176 prot, flags,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001177 fd, offset);
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001178
1179 if (devzero != -1) {
1180 close(devzero);
1181 }
1182
Tim Peters5ebfd362001-11-13 23:11:19 +00001183 if (m_obj->data == (char *)-1) {
Andrew M. Kuchling16581c82004-05-19 14:39:08 +00001184 m_obj->data = NULL;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001185 Py_DECREF(m_obj);
1186 PyErr_SetFromErrno(mmap_module_error);
1187 return NULL;
1188 }
Neal Norwitz8856fb72005-12-18 03:34:22 +00001189 m_obj->access = (access_mode)access;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001190 return (PyObject *)m_obj;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001191}
1192#endif /* UNIX */
1193
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001194#ifdef MS_WINDOWS
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001195static PyObject *
Georg Brandl845c4032008-01-21 14:16:46 +00001196new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001197{
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001198 mmap_object *m_obj;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001199 PyObject *map_size_obj = NULL, *offset_obj = NULL;
1200 Py_ssize_t map_size, offset;
1201 DWORD off_hi; /* upper 32 bits of offset */
1202 DWORD off_lo; /* lower 32 bits of offset */
1203 DWORD size_hi; /* upper 32 bits of size */
1204 DWORD size_lo; /* lower 32 bits of size */
Fredrik Lundh54cf3dc2000-07-08 22:05:01 +00001205 char *tagname = "";
Guido van Rossum09fdf072000-03-31 01:17:07 +00001206 DWORD dwErr = 0;
1207 int fileno;
Mark Hammond071864a2000-07-30 02:46:26 +00001208 HANDLE fh = 0;
Neal Norwitz8856fb72005-12-18 03:34:22 +00001209 int access = (access_mode)ACCESS_DEFAULT;
Tim Peters5ebfd362001-11-13 23:11:19 +00001210 DWORD flProtect, dwDesiredAccess;
Martin v. Löwis02cbf4a2006-02-27 17:20:04 +00001211 static char *keywords[] = { "fileno", "length",
Tim Petersec0a5f02006-02-16 23:47:20 +00001212 "tagname",
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001213 "access", "offset", NULL };
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001214
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001215 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|ziO", keywords,
Tim Petersec0a5f02006-02-16 23:47:20 +00001216 &fileno, &map_size_obj,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001217 &tagname, &access, &offset_obj)) {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001218 return NULL;
Tim Peters5ebfd362001-11-13 23:11:19 +00001219 }
1220
Neal Norwitz8856fb72005-12-18 03:34:22 +00001221 switch((access_mode)access) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001222 case ACCESS_READ:
1223 flProtect = PAGE_READONLY;
1224 dwDesiredAccess = FILE_MAP_READ;
1225 break;
1226 case ACCESS_DEFAULT: case ACCESS_WRITE:
1227 flProtect = PAGE_READWRITE;
1228 dwDesiredAccess = FILE_MAP_WRITE;
1229 break;
1230 case ACCESS_COPY:
1231 flProtect = PAGE_WRITECOPY;
1232 dwDesiredAccess = FILE_MAP_COPY;
1233 break;
1234 default:
Tim Petersec0a5f02006-02-16 23:47:20 +00001235 return PyErr_Format(PyExc_ValueError,
Tim Peters5ebfd362001-11-13 23:11:19 +00001236 "mmap invalid access parameter.");
1237 }
1238
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001239 map_size = _GetMapSize(map_size_obj, "size");
Andrew M. Kuchling70d27422000-06-18 04:45:14 +00001240 if (map_size < 0)
1241 return NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001242 offset = _GetMapSize(offset_obj, "offset");
1243 if (offset < 0)
1244 return NULL;
Tim Petersec0a5f02006-02-16 23:47:20 +00001245
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001246 /* assume -1 and 0 both mean invalid filedescriptor
1247 to 'anonymously' map memory.
1248 XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
1249 XXX: Should this code be added?
1250 if (fileno == 0)
1251 PyErr_Warn(PyExc_DeprecationWarning,
1252 "don't use 0 for anonymous memory");
1253 */
1254 if (fileno != -1 && fileno != 0) {
Mark Hammond071864a2000-07-30 02:46:26 +00001255 fh = (HANDLE)_get_osfhandle(fileno);
1256 if (fh==(HANDLE)-1) {
Tim Peters5ebfd362001-11-13 23:11:19 +00001257 PyErr_SetFromErrno(mmap_module_error);
1258 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001259 }
Fred Drake1ef4e2d2000-04-05 14:15:31 +00001260 /* Win9x appears to need us seeked to zero */
Guido van Rossum69c2b882003-04-09 19:31:02 +00001261 lseek(fileno, 0, SEEK_SET);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001262 }
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001263
Georg Brandl845c4032008-01-21 14:16:46 +00001264 m_obj = (mmap_object *)type->tp_alloc(type, 0);
Tim Peters8f9cc292006-02-17 00:00:20 +00001265 if (m_obj == NULL)
Mark Hammond2cbed002000-07-30 02:22:43 +00001266 return NULL;
1267 /* Set every field to an invalid marker, so we can safely
1268 destruct the object in the face of failure */
1269 m_obj->data = NULL;
Mark Hammond071864a2000-07-30 02:46:26 +00001270 m_obj->file_handle = INVALID_HANDLE_VALUE;
Mark Hammond2cbed002000-07-30 02:22:43 +00001271 m_obj->map_handle = INVALID_HANDLE_VALUE;
1272 m_obj->tagname = NULL;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001273 m_obj->offset = offset;
Mark Hammond2cbed002000-07-30 02:22:43 +00001274
Guido van Rossum09fdf072000-03-31 01:17:07 +00001275 if (fh) {
Mark Hammond2cbed002000-07-30 02:22:43 +00001276 /* It is necessary to duplicate the handle, so the
1277 Python code can close it on us */
1278 if (!DuplicateHandle(
Tim Peters5ebfd362001-11-13 23:11:19 +00001279 GetCurrentProcess(), /* source process handle */
1280 fh, /* handle to be duplicated */
1281 GetCurrentProcess(), /* target proc handle */
1282 (LPHANDLE)&m_obj->file_handle, /* result */
1283 0, /* access - ignored due to options value */
1284 FALSE, /* inherited by child processes? */
1285 DUPLICATE_SAME_ACCESS)) { /* options */
Mark Hammond2cbed002000-07-30 02:22:43 +00001286 dwErr = GetLastError();
1287 Py_DECREF(m_obj);
1288 PyErr_SetFromWindowsErr(dwErr);
1289 return NULL;
1290 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001291 if (!map_size) {
Martin v. Löwis15186072006-02-18 12:38:35 +00001292 DWORD low,high;
1293 low = GetFileSize(fh, &high);
1294 /* low might just happen to have the value INVALID_FILE_SIZE;
1295 so we need to check the last error also. */
1296 if (low == INVALID_FILE_SIZE &&
1297 (dwErr = GetLastError()) != NO_ERROR) {
1298 Py_DECREF(m_obj);
1299 return PyErr_SetFromWindowsErr(dwErr);
1300 }
1301
1302#if SIZEOF_SIZE_T > 4
1303 m_obj->size = (((size_t)high)<<32) + low;
1304#else
1305 if (high)
1306 /* File is too large to map completely */
1307 m_obj->size = (size_t)-1;
1308 else
1309 m_obj->size = low;
1310#endif
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001311 } else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001312 m_obj->size = map_size;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001313 }
Guido van Rossum09fdf072000-03-31 01:17:07 +00001314 }
1315 else {
Guido van Rossum09fdf072000-03-31 01:17:07 +00001316 m_obj->size = map_size;
1317 }
1318
1319 /* set the initial position */
1320 m_obj->pos = (size_t) 0;
1321
Mark Hammond2cbed002000-07-30 02:22:43 +00001322 /* set the tag name */
Tim Peters0d9f9dc2001-01-10 05:42:18 +00001323 if (tagname != NULL && *tagname != '\0') {
Mark Hammond2cbed002000-07-30 02:22:43 +00001324 m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1325 if (m_obj->tagname == NULL) {
1326 PyErr_NoMemory();
1327 Py_DECREF(m_obj);
1328 return NULL;
1329 }
1330 strcpy(m_obj->tagname, tagname);
1331 }
1332 else
1333 m_obj->tagname = NULL;
1334
Neal Norwitz8856fb72005-12-18 03:34:22 +00001335 m_obj->access = (access_mode)access;
Tim Peterse564e7f2006-02-16 23:46:01 +00001336 /* DWORD is a 4-byte int. If we're on a box where size_t consumes
Thomas Wouters2c98a7b2006-02-17 09:59:00 +00001337 * more than 4 bytes, we need to break it apart. Else (size_t
Tim Peterse564e7f2006-02-16 23:46:01 +00001338 * consumes 4 bytes), C doesn't define what happens if we shift
1339 * right by 32, so we need different code.
1340 */
1341#if SIZEOF_SIZE_T > 4
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001342 size_hi = (DWORD)((offset + m_obj->size) >> 32);
1343 size_lo = (DWORD)((offset + m_obj->size) & 0xFFFFFFFF);
1344 off_hi = (DWORD)(offset >> 32);
1345 off_lo = (DWORD)(offset & 0xFFFFFFFF);
Tim Peterse564e7f2006-02-16 23:46:01 +00001346#else
1347 size_hi = 0;
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001348 size_lo = (DWORD)(offset + m_obj->size);
1349 off_hi = 0;
1350 off_lo = (DWORD)offset;
Tim Peterse564e7f2006-02-16 23:46:01 +00001351#endif
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001352 /* For files, it would be sufficient to pass 0 as size.
1353 For anonymous maps, we have to pass the size explicitly. */
Tim Peters8f9cc292006-02-17 00:00:20 +00001354 m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1355 NULL,
1356 flProtect,
1357 size_hi,
1358 size_lo,
1359 m_obj->tagname);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001360 if (m_obj->map_handle != NULL) {
Tim Peters8f9cc292006-02-17 00:00:20 +00001361 m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
1362 dwDesiredAccess,
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001363 off_hi,
1364 off_lo,
Tim Peters8f9cc292006-02-17 00:00:20 +00001365 0);
Tim Peters23721ee2006-02-16 23:50:16 +00001366 if (m_obj->data != NULL)
1367 return (PyObject *)m_obj;
1368 else
Tim Peters5ebfd362001-11-13 23:11:19 +00001369 dwErr = GetLastError();
Tim Peters23721ee2006-02-16 23:50:16 +00001370 } else
Guido van Rossum09fdf072000-03-31 01:17:07 +00001371 dwErr = GetLastError();
Mark Hammond2cbed002000-07-30 02:22:43 +00001372 Py_DECREF(m_obj);
Guido van Rossum09fdf072000-03-31 01:17:07 +00001373 PyErr_SetFromWindowsErr(dwErr);
Tim Peters23721ee2006-02-16 23:50:16 +00001374 return NULL;
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001375}
Martin v. Löwis6238d2b2002-06-30 15:26:10 +00001376#endif /* MS_WINDOWS */
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001377
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001378static void
1379setint(PyObject *d, const char *name, long value)
1380{
1381 PyObject *o = PyInt_FromLong(value);
Neal Norwitz5ed49972006-08-13 18:41:15 +00001382 if (o && PyDict_SetItemString(d, name, o) == 0) {
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001383 Py_DECREF(o);
Neal Norwitz5ed49972006-08-13 18:41:15 +00001384 }
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001385}
1386
Mark Hammond62b1ab12002-07-23 06:31:15 +00001387PyMODINIT_FUNC
Georg Brandl845c4032008-01-21 14:16:46 +00001388initmmap(void)
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001389{
Guido van Rossum09fdf072000-03-31 01:17:07 +00001390 PyObject *dict, *module;
Tim Peters2caf8df2001-01-14 05:05:51 +00001391
Georg Brandl845c4032008-01-21 14:16:46 +00001392 if (PyType_Ready(&mmap_object_type) < 0)
1393 return;
Tim Peters2caf8df2001-01-14 05:05:51 +00001394
Georg Brandl845c4032008-01-21 14:16:46 +00001395 module = Py_InitModule("mmap", NULL);
Neal Norwitz1ac754f2006-01-19 06:09:39 +00001396 if (module == NULL)
1397 return;
Tim Peters8f9cc292006-02-17 00:00:20 +00001398 dict = PyModule_GetDict(module);
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001399 if (!dict)
1400 return;
Guido van Rossum09fdf072000-03-31 01:17:07 +00001401 mmap_module_error = PyExc_EnvironmentError;
Tim Peters8f9cc292006-02-17 00:00:20 +00001402 PyDict_SetItemString(dict, "error", mmap_module_error);
Georg Brandl845c4032008-01-21 14:16:46 +00001403 PyDict_SetItemString(dict, "mmap", (PyObject*) &mmap_object_type);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001404#ifdef PROT_EXEC
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001405 setint(dict, "PROT_EXEC", PROT_EXEC);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001406#endif
1407#ifdef PROT_READ
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001408 setint(dict, "PROT_READ", PROT_READ);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001409#endif
1410#ifdef PROT_WRITE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001411 setint(dict, "PROT_WRITE", PROT_WRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001412#endif
1413
1414#ifdef MAP_SHARED
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001415 setint(dict, "MAP_SHARED", MAP_SHARED);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001416#endif
1417#ifdef MAP_PRIVATE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001418 setint(dict, "MAP_PRIVATE", MAP_PRIVATE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001419#endif
1420#ifdef MAP_DENYWRITE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001421 setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001422#endif
1423#ifdef MAP_EXECUTABLE
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001424 setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001425#endif
Neal Norwitz0e6bc8c2006-02-05 05:45:43 +00001426#ifdef MAP_ANONYMOUS
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001427 setint(dict, "MAP_ANON", MAP_ANONYMOUS);
1428 setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS);
Andrew M. Kuchling1ed7d2d2000-03-30 21:14:30 +00001429#endif
1430
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001431 setint(dict, "PAGESIZE", (long)my_getpagesize());
Andrew M. Kuchling961fe172000-06-03 19:41:42 +00001432
Travis E. Oliphant8feafab2007-10-23 02:40:56 +00001433 setint(dict, "ALLOCATIONGRANULARITY", (long)my_getallocationgranularity());
1434
Neal Norwitze9ac0bb2006-08-13 18:11:27 +00001435 setint(dict, "ACCESS_READ", ACCESS_READ);
1436 setint(dict, "ACCESS_WRITE", ACCESS_WRITE);
1437 setint(dict, "ACCESS_COPY", ACCESS_COPY);
Tim Peters5ebfd362001-11-13 23:11:19 +00001438}