CVS patch #477161: New "access" keyword for mmap, from Jay T Miller.
This gives mmap() on Windows the ability to create read-only, write- through and copy-on-write mmaps. A new keyword argument is introduced because the mmap() signatures diverged between Windows and Unix, so while they (now) both support this functionality, there wasn't a way to spell it in a common way without introducing a new spelling gimmick. The old spellings are still accepted, so there isn't a backward- compatibility issue here.
This commit is contained in:
parent
afeb2a4d89
commit
5ebfd36afa
|
@ -1,5 +1,5 @@
|
||||||
\section{\module{mmap} ---
|
\section{\module{mmap} ---
|
||||||
Memory-mapped file support}
|
Memory-mapped file support}
|
||||||
|
|
||||||
\declaremodule{builtin}{mmap}
|
\declaremodule{builtin}{mmap}
|
||||||
\modulesynopsis{Interface to memory-mapped files for Unix and Windows.}
|
\modulesynopsis{Interface to memory-mapped files for Unix and Windows.}
|
||||||
|
@ -23,36 +23,67 @@ If you wish to map an existing Python file object, use its
|
||||||
\function{os.open()} function, which returns a file descriptor
|
\function{os.open()} function, which returns a file descriptor
|
||||||
directly (the file still needs to be closed when done).
|
directly (the file still needs to be closed when done).
|
||||||
|
|
||||||
\begin{funcdesc}{mmap}{fileno, length\optional{, tagname}}
|
\begin{funcdesc}{mmap}{fileno, length\optional{, tagname\optional{, access}}}
|
||||||
\strong{(Windows version)} Maps \var{length} bytes from the file
|
\strong{(Windows version)} Maps \var{length} bytes from the file
|
||||||
specified by the file handle \var{fileno}, and returns a mmap object.
|
specified by the file handle \var{fileno}, and returns a mmap
|
||||||
If \var{length} is \code{0}, the maximum length of the map will be the
|
object. If \var{length} is \code{0}, the maximum length of the map
|
||||||
current size of the file when \function{mmap()} is called.
|
will be the current size of the file when \function{mmap()} is
|
||||||
|
called.
|
||||||
\var{tagname}, if specified and not \code{None}, is a string giving a
|
|
||||||
tag name for the mapping. Windows allows you to have many different
|
\var{tagname}, if specified and not \code{None}, is a string giving
|
||||||
mappings against the same file. If you specify the name of an
|
a tag name for the mapping. Windows allows you to have many
|
||||||
existing tag, that tag is opened, otherwise a new tag of this name is
|
different mappings against the same file. If you specify the name
|
||||||
created. If this parameter is omitted or \code{None}, the mapping is
|
of an existing tag, that tag is opened, otherwise a new tag of this
|
||||||
created without a name. Avoiding the use of the tag parameter will
|
name is created. If this parameter is omitted or \code{None}, the
|
||||||
assist in keeping your code portable between \UNIX{} and Windows.
|
mapping is created without a name. Avoiding the use of the tag
|
||||||
|
parameter will assist in keeping your code portable between \UNIX{}
|
||||||
|
and Windows.
|
||||||
|
|
||||||
|
\var{access} may be specified as an optional keyword parameter.
|
||||||
|
\var{access} accepts one of three values: \constant{ACCESS_READ},
|
||||||
|
\constant{ACCESS_WRITE}, or \constant{ACCESS_COPY} to specify
|
||||||
|
readonly, write-through or copy-on-write memory respectively.
|
||||||
|
\var{access} can be used on both \UNIX{} and Windows. If
|
||||||
|
\var{access} is not specified, Windows mmap returns a write-through
|
||||||
|
mapping. The initial memory values for all three access types are
|
||||||
|
taken from the specified file. Assignment to an
|
||||||
|
\constant{ACCESS_READ} memory map raises a \exception{TypeError}
|
||||||
|
exception. Assignment to an \constant{ACCESS_WRITE} memory map
|
||||||
|
affects both memory and the underlying file. Assigment to an
|
||||||
|
\constant{ACCESS_COPY} memory map affects memory but does not update
|
||||||
|
the underlying file.
|
||||||
\end{funcdesc}
|
\end{funcdesc}
|
||||||
|
|
||||||
\begin{funcdesc}{mmap}{fileno, length\optional{, flags\optional{, prot}}}
|
\begin{funcdesc}{mmap}{fileno, length\optional{, flags\optional{, prot\optional{, access}}}}
|
||||||
\strong{(\UNIX{} version)} Maps \var{length} bytes from the file
|
\strong{(\UNIX{} version)} Maps \var{length} bytes from the file
|
||||||
specified by the file descriptor \var{fileno}, and returns a mmap object.
|
specified by the file descriptor \var{fileno}, and returns a mmap
|
||||||
|
object.
|
||||||
\var{flags} specifies the nature of the mapping.
|
|
||||||
\constant{MAP_PRIVATE} creates a private copy-on-write mapping, so
|
\var{flags} specifies the nature of the mapping.
|
||||||
changes to the contents of the mmap object will be private to this
|
\constant{MAP_PRIVATE} creates a private copy-on-write mapping, so
|
||||||
process, and \constant{MAP_SHARED} creates a mapping that's shared
|
changes to the contents of the mmap object will be private to this
|
||||||
with all other processes mapping the same areas of the file.
|
process, and \constant{MAP_SHARED} creates a mapping that's shared
|
||||||
The default value is \constant{MAP_SHARED}.
|
with all other processes mapping the same areas of the file. The
|
||||||
|
default value is \constant{MAP_SHARED}.
|
||||||
\var{prot}, if specified, gives the desired memory protection; the two
|
|
||||||
most useful values are \constant{PROT_READ} and \constant{PROT_WRITE},
|
\var{prot}, if specified, gives the desired memory protection; the
|
||||||
to specify that the pages may be read or written.
|
two most useful values are \constant{PROT_READ} and
|
||||||
\var{prot} defaults to \constant{PROT_READ | PROT_WRITE}.
|
\constant{PROT_WRITE}, to specify that the pages may be read or
|
||||||
|
written. \var{prot} defaults to \constant{PROT_READ | PROT_WRITE}.
|
||||||
|
|
||||||
|
\var{access} may be specified in lieu of \var{flags} and \var{prot}
|
||||||
|
as an optional keyword parameter. \var{access} accepts one of three
|
||||||
|
values: \constant{ACCESS_READ}, \constant{ACCESS_WRITE}, or
|
||||||
|
\constant{ACCESS_COPY} to specify readonly, write-through, or
|
||||||
|
copy-on-write memory respectively. \var{access} can be used on both
|
||||||
|
\UNIX{} and Windows. It is an error to specify both \var{flags},
|
||||||
|
\var{prot} and \var{access}. The initial memory values for all
|
||||||
|
three access types are taken from the specified file. Assignment to
|
||||||
|
an \constant{ACCESS_READ} memory map raises a \exception{TypeError}
|
||||||
|
exception. Assignment to an \constant{ACCESS_WRITE} memory map
|
||||||
|
affects both memory and the underlying file. Assigment to an
|
||||||
|
\constant{ACCESS_COPY} memory map affects memory but does not update
|
||||||
|
the underlying file.
|
||||||
\end{funcdesc}
|
\end{funcdesc}
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,73 +91,80 @@ Memory-mapped file objects support the following methods:
|
||||||
|
|
||||||
|
|
||||||
\begin{methoddesc}{close}{}
|
\begin{methoddesc}{close}{}
|
||||||
Close the file. Subsequent calls to other methods of the object
|
Close the file. Subsequent calls to other methods of the object
|
||||||
will result in an exception being raised.
|
will result in an exception being raised.
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
||||||
\begin{methoddesc}{find}{string\optional{, start}}
|
\begin{methoddesc}{find}{string\optional{, start}}
|
||||||
Returns the lowest index in the object where the substring
|
Returns the lowest index in the object where the substring
|
||||||
\var{string} is found. Returns \code{-1} on failure. \var{start} is
|
\var{string} is found. Returns \code{-1} on failure. \var{start}
|
||||||
the index at which the search begins, and defaults to zero.
|
is the index at which the search begins, and defaults to zero.
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
||||||
\begin{methoddesc}{flush}{\optional{offset, size}}
|
\begin{methoddesc}{flush}{\optional{offset, size}}
|
||||||
Flushes changes made to the in-memory copy of a file back to disk.
|
Flushes changes made to the in-memory copy of a file back to disk.
|
||||||
Without use of this call there is no guarantee that changes are
|
Without use of this call there is no guarantee that changes are
|
||||||
written back before the object is destroyed. If \var{offset} and
|
written back before the object is destroyed. If \var{offset} and
|
||||||
\var{size} are specified, only changes to the given range of bytes
|
\var{size} are specified, only changes to the given range of bytes
|
||||||
will be flushed to disk; otherwise, the whole extent of the mapping is
|
will be flushed to disk; otherwise, the whole extent of the mapping
|
||||||
flushed.
|
is flushed.
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
||||||
\begin{methoddesc}{move}{\var{dest}, \var{src}, \var{count}}
|
\begin{methoddesc}{move}{\var{dest}, \var{src}, \var{count}}
|
||||||
Copy the \var{count} bytes starting at offset \var{src}
|
Copy the \var{count} bytes starting at offset \var{src} to the
|
||||||
to the destination index \var{dest}.
|
destination index \var{dest}. If the mmap was created with
|
||||||
|
\constant{ACCESS_READ}, then calls to move will throw a
|
||||||
|
\exception{TypeError} exception.
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
||||||
\begin{methoddesc}{read}{\var{num}}
|
\begin{methoddesc}{read}{\var{num}}
|
||||||
Return a string containing up to \var{num} bytes starting from the
|
Return a string containing up to \var{num} bytes starting from the
|
||||||
current file position; the file position is updated to point after the
|
current file position; the file position is updated to point after the
|
||||||
bytes that were returned.
|
bytes that were returned.
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
||||||
\begin{methoddesc}{read_byte}{}
|
\begin{methoddesc}{read_byte}{}
|
||||||
Returns a string of length 1 containing the character at the current
|
Returns a string of length 1 containing the character at the current
|
||||||
file position, and advances the file position by 1.
|
file position, and advances the file position by 1.
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
||||||
\begin{methoddesc}{readline}{}
|
\begin{methoddesc}{readline}{}
|
||||||
Returns a single line, starting at the current file position and up to
|
Returns a single line, starting at the current file position and up to
|
||||||
the next newline.
|
the next newline.
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
||||||
\begin{methoddesc}{resize}{\var{newsize}}
|
\begin{methoddesc}{resize}{\var{newsize}}
|
||||||
|
If the mmap was created with \constant{ACCESS_READ} or
|
||||||
|
\constant{ACCESS_COPY}, resizing the map will throw a \exception{TypeError} exception.
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
||||||
\begin{methoddesc}{seek}{pos\optional{, whence}}
|
\begin{methoddesc}{seek}{pos\optional{, whence}}
|
||||||
Set the file's current position.
|
Set the file's current position. \var{whence} argument is optional
|
||||||
\var{whence} argument is optional and defaults to \code{0} (absolute
|
and defaults to \code{0} (absolute file positioning); other values
|
||||||
file positioning); other values are \code{1} (seek relative to the
|
are \code{1} (seek relative to the current position) and \code{2}
|
||||||
current position) and \code{2} (seek relative to the file's end).
|
(seek relative to the file's end).
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
||||||
\begin{methoddesc}{size}{}
|
\begin{methoddesc}{size}{}
|
||||||
Return the length of the file, which can be larger than the size
|
Return the length of the file, which can be larger than the size of
|
||||||
of the memory-mapped area.
|
the memory-mapped area.
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
||||||
\begin{methoddesc}{tell}{}
|
\begin{methoddesc}{tell}{}
|
||||||
Returns the current position of the file pointer.
|
Returns the current position of the file pointer.
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
||||||
\begin{methoddesc}{write}{\var{string}}
|
\begin{methoddesc}{write}{\var{string}}
|
||||||
Write the bytes in \var{string} into memory at the current position of
|
Write the bytes in \var{string} into memory at the current position
|
||||||
the file pointer; the file position is updated to point after the
|
of the file pointer; the file position is updated to point after the
|
||||||
bytes that were written.
|
bytes that were written. If the mmap was created with
|
||||||
|
\constant{ACCESS_READ}, then writing to it will throw a
|
||||||
|
\exception{TypeError} exception.
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
||||||
\begin{methoddesc}{write_byte}{\var{byte}}
|
\begin{methoddesc}{write_byte}{\var{byte}}
|
||||||
Write the single-character string \var{byte} into memory at the
|
Write the single-character string \var{byte} into memory at the
|
||||||
current position of the file pointer; the file position is advanced by
|
current position of the file pointer; the file position is advanced
|
||||||
\code{1}.
|
by \code{1}.If the mmap was created with \constant{ACCESS_READ},
|
||||||
|
then writing to it will throw a \exception{TypeError} exception.
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
|
@ -17,4 +17,17 @@ test_mmap
|
||||||
Try to seek beyond end of mmap...
|
Try to seek beyond end of mmap...
|
||||||
Try to seek to negative position...
|
Try to seek to negative position...
|
||||||
Attempting resize()
|
Attempting resize()
|
||||||
|
Creating 10 byte test data file.
|
||||||
|
Opening mmap with access=ACCESS_READ
|
||||||
|
Ensuring that readonly mmap can't be slice assigned.
|
||||||
|
Ensuring that readonly mmap can't be item assigned.
|
||||||
|
Ensuring that readonly mmap can't be write() to.
|
||||||
|
Ensuring that readonly mmap can't be write_byte() to.
|
||||||
|
Ensuring that readonly mmap can't be resized.
|
||||||
|
Opening mmap with access=ACCESS_WRITE
|
||||||
|
Modifying write-through memory map.
|
||||||
|
Opening mmap with access=ACCESS_COPY
|
||||||
|
Modifying copy-on-write memory map.
|
||||||
|
Ensuring copy-on-write maps cannot be resized.
|
||||||
|
Ensuring invalid access parameter raises exception.
|
||||||
Test passed
|
Test passed
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from test_support import verify, TESTFN
|
from test_support import verify, vereq, TESTFN
|
||||||
import mmap
|
import mmap
|
||||||
import os, re
|
import os, re
|
||||||
|
|
||||||
|
@ -25,15 +25,15 @@ def test_both():
|
||||||
|
|
||||||
print type(m) # SF bug 128713: segfaulted on Linux
|
print type(m) # SF bug 128713: segfaulted on Linux
|
||||||
print ' Position of foo:', m.find('foo') / float(PAGESIZE), 'pages'
|
print ' Position of foo:', m.find('foo') / float(PAGESIZE), 'pages'
|
||||||
verify(m.find('foo') == PAGESIZE)
|
vereq(m.find('foo'), PAGESIZE)
|
||||||
|
|
||||||
print ' Length of file:', len(m) / float(PAGESIZE), 'pages'
|
print ' Length of file:', len(m) / float(PAGESIZE), 'pages'
|
||||||
verify(len(m) == 2*PAGESIZE)
|
vereq(len(m), 2*PAGESIZE)
|
||||||
|
|
||||||
print ' Contents of byte 0:', repr(m[0])
|
print ' Contents of byte 0:', repr(m[0])
|
||||||
verify(m[0] == '\0')
|
vereq(m[0], '\0')
|
||||||
print ' Contents of first 3 bytes:', repr(m[0:3])
|
print ' Contents of first 3 bytes:', repr(m[0:3])
|
||||||
verify(m[0:3] == '\0\0\0')
|
vereq(m[0:3], '\0\0\0')
|
||||||
|
|
||||||
# Modify the file's content
|
# Modify the file's content
|
||||||
print "\n Modifying file's content..."
|
print "\n Modifying file's content..."
|
||||||
|
@ -42,11 +42,11 @@ def test_both():
|
||||||
|
|
||||||
# Check that the modification worked
|
# Check that the modification worked
|
||||||
print ' Contents of byte 0:', repr(m[0])
|
print ' Contents of byte 0:', repr(m[0])
|
||||||
verify(m[0] == '3')
|
vereq(m[0], '3')
|
||||||
print ' Contents of first 3 bytes:', repr(m[0:3])
|
print ' Contents of first 3 bytes:', repr(m[0:3])
|
||||||
verify(m[0:3] == '3\0\0')
|
vereq(m[0:3], '3\0\0')
|
||||||
print ' Contents of second page:', repr(m[PAGESIZE-1 : PAGESIZE + 7])
|
print ' Contents of second page:', repr(m[PAGESIZE-1 : PAGESIZE + 7])
|
||||||
verify(m[PAGESIZE-1 : PAGESIZE + 7] == '\0foobar\0')
|
vereq(m[PAGESIZE-1 : PAGESIZE + 7], '\0foobar\0')
|
||||||
|
|
||||||
m.flush()
|
m.flush()
|
||||||
|
|
||||||
|
@ -61,19 +61,19 @@ def test_both():
|
||||||
print ' Regex match on mmap (page start, length of match):',
|
print ' Regex match on mmap (page start, length of match):',
|
||||||
print start / float(PAGESIZE), length
|
print start / float(PAGESIZE), length
|
||||||
|
|
||||||
verify(start == PAGESIZE)
|
vereq(start, PAGESIZE)
|
||||||
verify(end == PAGESIZE + 6)
|
vereq(end, PAGESIZE + 6)
|
||||||
|
|
||||||
# test seeking around (try to overflow the seek implementation)
|
# test seeking around (try to overflow the seek implementation)
|
||||||
m.seek(0,0)
|
m.seek(0,0)
|
||||||
print ' Seek to zeroth byte'
|
print ' Seek to zeroth byte'
|
||||||
verify(m.tell() == 0)
|
vereq(m.tell(), 0)
|
||||||
m.seek(42,1)
|
m.seek(42,1)
|
||||||
print ' Seek to 42nd byte'
|
print ' Seek to 42nd byte'
|
||||||
verify(m.tell() == 42)
|
vereq(m.tell(), 42)
|
||||||
m.seek(0,2)
|
m.seek(0,2)
|
||||||
print ' Seek to last byte'
|
print ' Seek to last byte'
|
||||||
verify(m.tell() == len(m))
|
vereq(m.tell(), len(m))
|
||||||
|
|
||||||
print ' Try to seek to negative position...'
|
print ' Try to seek to negative position...'
|
||||||
try:
|
try:
|
||||||
|
@ -132,6 +132,118 @@ def test_both():
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Test for "access" keyword parameter
|
||||||
|
try:
|
||||||
|
mapsize = 10
|
||||||
|
print " Creating", mapsize, "byte test data file."
|
||||||
|
open(TESTFN, "wb").write("a"*mapsize)
|
||||||
|
print " Opening mmap with access=ACCESS_READ"
|
||||||
|
f = open(TESTFN, "rb")
|
||||||
|
m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_READ)
|
||||||
|
verify(m[:] == 'a'*mapsize, "Readonly memory map data incorrect.")
|
||||||
|
|
||||||
|
print " Ensuring that readonly mmap can't be slice assigned."
|
||||||
|
try:
|
||||||
|
m[:] = 'b'*mapsize
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "Able to write to readonly memory map")
|
||||||
|
|
||||||
|
print " Ensuring that readonly mmap can't be item assigned."
|
||||||
|
try:
|
||||||
|
m[0] = 'b'
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "Able to write to readonly memory map")
|
||||||
|
|
||||||
|
print " Ensuring that readonly mmap can't be write() to."
|
||||||
|
try:
|
||||||
|
m.seek(0,0)
|
||||||
|
m.write('abc')
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "Able to write to readonly memory map")
|
||||||
|
|
||||||
|
print " Ensuring that readonly mmap can't be write_byte() to."
|
||||||
|
try:
|
||||||
|
m.seek(0,0)
|
||||||
|
m.write_byte('d')
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "Able to write to readonly memory map")
|
||||||
|
|
||||||
|
print " Ensuring that readonly mmap can't be resized."
|
||||||
|
try:
|
||||||
|
m.resize(2*mapsize)
|
||||||
|
except SystemError: # resize is not universally supported
|
||||||
|
pass
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "Able to resize readonly memory map")
|
||||||
|
del m, f
|
||||||
|
verify(open(TESTFN, "rb").read() == 'a'*mapsize,
|
||||||
|
"Readonly memory map data file was modified")
|
||||||
|
|
||||||
|
print " Opening mmap with access=ACCESS_WRITE"
|
||||||
|
f = open(TESTFN, "r+b")
|
||||||
|
m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_WRITE)
|
||||||
|
print " Modifying write-through memory map."
|
||||||
|
m[:] = 'c'*mapsize
|
||||||
|
verify(m[:] == 'c'*mapsize,
|
||||||
|
"Write-through memory map memory not updated properly.")
|
||||||
|
m.flush()
|
||||||
|
del m, f
|
||||||
|
verify(open(TESTFN).read() == 'c'*mapsize,
|
||||||
|
"Write-through memory map data file not updated properly.")
|
||||||
|
|
||||||
|
print " Opening mmap with access=ACCESS_COPY"
|
||||||
|
f = open(TESTFN, "r+b")
|
||||||
|
m = mmap.mmap(f.fileno(), mapsize, access=mmap.ACCESS_COPY)
|
||||||
|
print " Modifying copy-on-write memory map."
|
||||||
|
m[:] = 'd'*mapsize
|
||||||
|
verify(m[:] == 'd' * mapsize,
|
||||||
|
"Copy-on-write memory map data not written correctly.")
|
||||||
|
m.flush()
|
||||||
|
verify(open(TESTFN, "rb").read() == 'c'*mapsize,
|
||||||
|
"Copy-on-write test data file should not be modified.")
|
||||||
|
try:
|
||||||
|
print " Ensuring copy-on-write maps cannot be resized."
|
||||||
|
m.resize(2*mapsize)
|
||||||
|
except TypeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "Copy-on-write mmap resize did not raise exception.")
|
||||||
|
del m, f
|
||||||
|
try:
|
||||||
|
print " Ensuring invalid access parameter raises exception."
|
||||||
|
f = open(TESTFN, "r+b")
|
||||||
|
m = mmap.mmap(f.fileno(), mapsize, access=4)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "Invalid access code should have raised exception.")
|
||||||
|
|
||||||
|
if os.name == "posix":
|
||||||
|
print " Trying incompatible flags, prot and access parameters."
|
||||||
|
f=open(TESTFN, "r+b")
|
||||||
|
try:
|
||||||
|
m = mmap.mmap(f.fileno(), mapsize, flags=mmap.MAP_PRIVATE,
|
||||||
|
prot=mmap.PROT_READ, access=mmap.ACCESS_WRITE)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
verify(0, "Incompatible parameters should raise ValueError.")
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
os.unlink(TESTFN)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
print ' Test passed'
|
print ' Test passed'
|
||||||
|
|
||||||
test_both()
|
test_both()
|
||||||
|
|
|
@ -36,6 +36,13 @@ Core and builtins
|
||||||
|
|
||||||
Extension modules
|
Extension modules
|
||||||
|
|
||||||
|
- mmap has a new keyword argument, "access", allowing a uniform way for
|
||||||
|
both Windows and Unix users to create read-only, write-through and
|
||||||
|
copy-on-write memory mappings. This was previously possible only on
|
||||||
|
Unix. A new keyword argument was required to support this in a
|
||||||
|
uniform way because the mmap() signuatures had diverged across
|
||||||
|
platforms. Thanks to Jay T Miller for repairing this!
|
||||||
|
|
||||||
- By default, the gc.garbage list now contains only those instances in
|
- By default, the gc.garbage list now contains only those instances in
|
||||||
unreachable cycles that have __del__ methods; in 2.1 it contained all
|
unreachable cycles that have __del__ methods; in 2.1 it contained all
|
||||||
instances in unreachable cycles. "Instances" here has been generalized
|
instances in unreachable cycles. "Instances" here has been generalized
|
||||||
|
@ -55,7 +62,7 @@ Extension modules
|
||||||
|
|
||||||
Library
|
Library
|
||||||
|
|
||||||
- tkFileDialog exposes a Directory class and askdirectory
|
- tkFileDialog exposes a Directory class and askdirectory
|
||||||
convenience function.
|
convenience function.
|
||||||
|
|
||||||
- Symbolic group names in regular expressions must be unique. For
|
- Symbolic group names in regular expressions must be unique. For
|
||||||
|
|
|
@ -29,9 +29,9 @@
|
||||||
static int
|
static int
|
||||||
my_getpagesize(void)
|
my_getpagesize(void)
|
||||||
{
|
{
|
||||||
SYSTEM_INFO si;
|
SYSTEM_INFO si;
|
||||||
GetSystemInfo(&si);
|
GetSystemInfo(&si);
|
||||||
return si.dwPageSize;
|
return si.dwPageSize;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ my_getpagesize(void)
|
||||||
static int
|
static int
|
||||||
my_getpagesize(void)
|
my_getpagesize(void)
|
||||||
{
|
{
|
||||||
return sysconf(_SC_PAGESIZE);
|
return sysconf(_SC_PAGESIZE);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define my_getpagesize getpagesize
|
#define my_getpagesize getpagesize
|
||||||
|
@ -62,6 +62,14 @@ my_getpagesize(void)
|
||||||
|
|
||||||
static PyObject *mmap_module_error;
|
static PyObject *mmap_module_error;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
ACCESS_DEFAULT,
|
||||||
|
ACCESS_READ,
|
||||||
|
ACCESS_WRITE,
|
||||||
|
ACCESS_COPY
|
||||||
|
} access_mode;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
char * data;
|
char * data;
|
||||||
|
@ -77,8 +85,11 @@ typedef struct {
|
||||||
#ifdef UNIX
|
#ifdef UNIX
|
||||||
int fd;
|
int fd;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
access_mode access;
|
||||||
} mmap_object;
|
} mmap_object;
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mmap_object_dealloc(mmap_object *m_obj)
|
mmap_object_dealloc(mmap_object *m_obj)
|
||||||
{
|
{
|
||||||
|
@ -178,7 +189,7 @@ mmap_read_byte_method(mmap_object *self,
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
mmap_read_line_method(mmap_object *self,
|
mmap_read_line_method(mmap_object *self,
|
||||||
PyObject *args)
|
PyObject *args)
|
||||||
{
|
{
|
||||||
char *start = self->data+self->pos;
|
char *start = self->data+self->pos;
|
||||||
char *eof = self->data+self->size;
|
char *eof = self->data+self->size;
|
||||||
|
@ -236,11 +247,11 @@ mmap_find_method(mmap_object *self,
|
||||||
char *e = self->data + self->size;
|
char *e = self->data + self->size;
|
||||||
|
|
||||||
if (start < 0)
|
if (start < 0)
|
||||||
start += self->size;
|
start += self->size;
|
||||||
if (start < 0)
|
if (start < 0)
|
||||||
start = 0;
|
start = 0;
|
||||||
else if ((size_t)start > self->size)
|
else if ((size_t)start > self->size)
|
||||||
start = self->size;
|
start = self->size;
|
||||||
p = self->data + start;
|
p = self->data + start;
|
||||||
|
|
||||||
while (p < e) {
|
while (p < e) {
|
||||||
|
@ -260,6 +271,26 @@ mmap_find_method(mmap_object *self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
is_writeable(mmap_object *self)
|
||||||
|
{
|
||||||
|
if (self->access != ACCESS_READ)
|
||||||
|
return 1;
|
||||||
|
PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
is_resizeable(mmap_object *self)
|
||||||
|
{
|
||||||
|
if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
|
||||||
|
return 1;
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"mmap can't resize a readonly or copy-on-write memory map.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
mmap_write_method(mmap_object *self,
|
mmap_write_method(mmap_object *self,
|
||||||
PyObject *args)
|
PyObject *args)
|
||||||
|
@ -271,6 +302,9 @@ mmap_write_method(mmap_object *self,
|
||||||
if (!PyArg_ParseTuple (args, "s#:write", &data, &length))
|
if (!PyArg_ParseTuple (args, "s#:write", &data, &length))
|
||||||
return(NULL);
|
return(NULL);
|
||||||
|
|
||||||
|
if (!is_writeable(self))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if ((self->pos + length) > self->size) {
|
if ((self->pos + length) > self->size) {
|
||||||
PyErr_SetString (PyExc_ValueError, "data out of range");
|
PyErr_SetString (PyExc_ValueError, "data out of range");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -291,12 +325,14 @@ mmap_write_byte_method(mmap_object *self,
|
||||||
if (!PyArg_ParseTuple (args, "c:write_byte", &value))
|
if (!PyArg_ParseTuple (args, "c:write_byte", &value))
|
||||||
return(NULL);
|
return(NULL);
|
||||||
|
|
||||||
|
if (!is_writeable(self))
|
||||||
|
return NULL;
|
||||||
*(self->data+self->pos) = value;
|
*(self->data+self->pos) = value;
|
||||||
self->pos += 1;
|
self->pos += 1;
|
||||||
Py_INCREF (Py_None);
|
Py_INCREF (Py_None);
|
||||||
return (Py_None);
|
return (Py_None);
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
mmap_size_method(mmap_object *self,
|
mmap_size_method(mmap_object *self,
|
||||||
PyObject *args)
|
PyObject *args)
|
||||||
|
@ -342,7 +378,8 @@ mmap_resize_method(mmap_object *self,
|
||||||
{
|
{
|
||||||
unsigned long new_size;
|
unsigned long new_size;
|
||||||
CHECK_VALID(NULL);
|
CHECK_VALID(NULL);
|
||||||
if (!PyArg_ParseTuple (args, "l:resize", &new_size)) {
|
if (!PyArg_ParseTuple (args, "l:resize", &new_size) ||
|
||||||
|
!is_resizeable(self)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
#ifdef MS_WIN32
|
#ifdef MS_WIN32
|
||||||
} else {
|
} else {
|
||||||
|
@ -386,31 +423,31 @@ mmap_resize_method(mmap_object *self,
|
||||||
|
|
||||||
#ifdef UNIX
|
#ifdef UNIX
|
||||||
#ifndef HAVE_MREMAP
|
#ifndef HAVE_MREMAP
|
||||||
} else {
|
} else {
|
||||||
PyErr_SetString(PyExc_SystemError,
|
PyErr_SetString(PyExc_SystemError,
|
||||||
"mmap: resizing not available--no mremap()");
|
"mmap: resizing not available--no mremap()");
|
||||||
return NULL;
|
return NULL;
|
||||||
#else
|
#else
|
||||||
} else {
|
} else {
|
||||||
void *newmap;
|
void *newmap;
|
||||||
|
|
||||||
#ifdef MREMAP_MAYMOVE
|
#ifdef MREMAP_MAYMOVE
|
||||||
newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
|
newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
|
||||||
#else
|
#else
|
||||||
newmap = mremap(self->data, self->size, new_size, 0);
|
newmap = mremap(self->data, self->size, new_size, 0);
|
||||||
#endif
|
#endif
|
||||||
if (newmap == (void *)-1)
|
if (newmap == (void *)-1)
|
||||||
{
|
{
|
||||||
PyErr_SetFromErrno(mmap_module_error);
|
PyErr_SetFromErrno(mmap_module_error);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
self->data = newmap;
|
self->data = newmap;
|
||||||
self->size = new_size;
|
self->size = new_size;
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
return Py_None;
|
return Py_None;
|
||||||
#endif /* HAVE_MREMAP */
|
#endif /* HAVE_MREMAP */
|
||||||
#endif /* UNIX */
|
#endif /* UNIX */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -491,7 +528,7 @@ mmap_seek_method(mmap_object *self, PyObject *args)
|
||||||
return (Py_None);
|
return (Py_None);
|
||||||
}
|
}
|
||||||
|
|
||||||
onoutofrange:
|
onoutofrange:
|
||||||
PyErr_SetString (PyExc_ValueError, "seek out of range");
|
PyErr_SetString (PyExc_ValueError, "seek out of range");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -501,7 +538,8 @@ mmap_move_method(mmap_object *self, PyObject *args)
|
||||||
{
|
{
|
||||||
unsigned long dest, src, count;
|
unsigned long dest, src, count;
|
||||||
CHECK_VALID(NULL);
|
CHECK_VALID(NULL);
|
||||||
if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count)) {
|
if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count) ||
|
||||||
|
!is_writeable(self)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
} else {
|
} else {
|
||||||
/* bounds check the values */
|
/* bounds check the values */
|
||||||
|
@ -561,6 +599,8 @@ mmap_buffer_getwritebuf(mmap_object *self, int index, const void **ptr)
|
||||||
"Accessing non-existent mmap segment");
|
"Accessing non-existent mmap segment");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (!is_writeable(self))
|
||||||
|
return -1;
|
||||||
*ptr = self->data;
|
*ptr = self->data;
|
||||||
return self->size;
|
return self->size;
|
||||||
}
|
}
|
||||||
|
@ -665,7 +705,7 @@ mmap_ass_slice(mmap_object *self, int ilow, int ihigh, PyObject *v)
|
||||||
|
|
||||||
if (v == NULL) {
|
if (v == NULL) {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"mmap object doesn't support slice deletion");
|
"mmap object doesn't support slice deletion");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (! (PyString_Check(v)) ) {
|
if (! (PyString_Check(v)) ) {
|
||||||
|
@ -678,6 +718,8 @@ mmap_ass_slice(mmap_object *self, int ilow, int ihigh, PyObject *v)
|
||||||
"mmap slice assignment is wrong size");
|
"mmap slice assignment is wrong size");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (!is_writeable(self))
|
||||||
|
return -1;
|
||||||
buf = PyString_AsString(v);
|
buf = PyString_AsString(v);
|
||||||
memcpy(self->data + ilow, buf, ihigh-ilow);
|
memcpy(self->data + ilow, buf, ihigh-ilow);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -695,14 +737,16 @@ mmap_ass_item(mmap_object *self, int i, PyObject *v)
|
||||||
}
|
}
|
||||||
if (v == NULL) {
|
if (v == NULL) {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"mmap object doesn't support item deletion");
|
"mmap object doesn't support item deletion");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
|
if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
|
||||||
PyErr_SetString(PyExc_IndexError,
|
PyErr_SetString(PyExc_IndexError,
|
||||||
"mmap assignment must be single-character string");
|
"mmap assignment must be single-character string");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (!is_writeable(self))
|
||||||
|
return -1;
|
||||||
buf = PyString_AsString(v);
|
buf = PyString_AsString(v);
|
||||||
self->data[i] = buf[0];
|
self->data[i] = buf[0];
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -792,18 +836,18 @@ _GetMapSize(PyObject *o)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"map size must be an integral value");
|
"map size must be an integral value");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
onnegoverflow:
|
onnegoverflow:
|
||||||
PyErr_SetString(PyExc_OverflowError,
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
"memory mapped size must be positive");
|
"memory mapped size must be positive");
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
onposoverflow:
|
onposoverflow:
|
||||||
PyErr_SetString(PyExc_OverflowError,
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
"memory mapped size is too large (limited by C int)");
|
"memory mapped size is too large (limited by C int)");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -815,16 +859,42 @@ new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
|
||||||
PyObject *map_size_obj = NULL;
|
PyObject *map_size_obj = NULL;
|
||||||
int map_size;
|
int map_size;
|
||||||
int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
|
int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
|
||||||
char *keywords[] = {"file", "size", "flags", "prot", NULL};
|
access_mode access = ACCESS_DEFAULT;
|
||||||
|
char *keywords[] = {"fileno", "length",
|
||||||
|
"flags", "prot",
|
||||||
|
"access", NULL};
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwdict,
|
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii", keywords,
|
||||||
"iO|ii", keywords,
|
&fd, &map_size_obj, &flags, &prot, &access))
|
||||||
&fd, &map_size_obj, &flags, &prot)
|
|
||||||
)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
map_size = _GetMapSize(map_size_obj);
|
map_size = _GetMapSize(map_size_obj);
|
||||||
if (map_size < 0)
|
if (map_size < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if ((access != ACCESS_DEFAULT) &&
|
||||||
|
((flags != MAP_SHARED) || ( prot != (PROT_WRITE | PROT_READ))))
|
||||||
|
return PyErr_Format(PyExc_ValueError,
|
||||||
|
"mmap can't specify both access and flags, prot.");
|
||||||
|
switch(access) {
|
||||||
|
case ACCESS_READ:
|
||||||
|
flags = MAP_SHARED;
|
||||||
|
prot = PROT_READ;
|
||||||
|
break;
|
||||||
|
case ACCESS_WRITE:
|
||||||
|
flags = MAP_SHARED;
|
||||||
|
prot = PROT_READ | PROT_WRITE;
|
||||||
|
break;
|
||||||
|
case ACCESS_COPY:
|
||||||
|
flags = MAP_PRIVATE;
|
||||||
|
prot = PROT_READ | PROT_WRITE;
|
||||||
|
break;
|
||||||
|
case ACCESS_DEFAULT:
|
||||||
|
/* use the specified or default values of flags and prot */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return PyErr_Format(PyExc_ValueError,
|
||||||
|
"mmap invalid access parameter.");
|
||||||
|
}
|
||||||
|
|
||||||
m_obj = PyObject_New (mmap_object, &mmap_object_type);
|
m_obj = PyObject_New (mmap_object, &mmap_object_type);
|
||||||
if (m_obj == NULL) {return NULL;}
|
if (m_obj == NULL) {return NULL;}
|
||||||
|
@ -834,37 +904,57 @@ new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
|
||||||
m_obj->data = mmap(NULL, map_size,
|
m_obj->data = mmap(NULL, map_size,
|
||||||
prot, flags,
|
prot, flags,
|
||||||
fd, 0);
|
fd, 0);
|
||||||
if (m_obj->data == (char *)-1)
|
if (m_obj->data == (char *)-1) {
|
||||||
{
|
|
||||||
Py_DECREF(m_obj);
|
Py_DECREF(m_obj);
|
||||||
PyErr_SetFromErrno(mmap_module_error);
|
PyErr_SetFromErrno(mmap_module_error);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
m_obj->access = access;
|
||||||
return (PyObject *)m_obj;
|
return (PyObject *)m_obj;
|
||||||
}
|
}
|
||||||
#endif /* UNIX */
|
#endif /* UNIX */
|
||||||
|
|
||||||
#ifdef MS_WIN32
|
#ifdef MS_WIN32
|
||||||
static PyObject *
|
static PyObject *
|
||||||
new_mmap_object(PyObject *self, PyObject *args)
|
new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
|
||||||
{
|
{
|
||||||
mmap_object *m_obj;
|
mmap_object *m_obj;
|
||||||
PyObject *map_size_obj = NULL;
|
PyObject *map_size_obj = NULL;
|
||||||
int map_size;
|
int map_size;
|
||||||
char *tagname = "";
|
char *tagname = "";
|
||||||
|
|
||||||
DWORD dwErr = 0;
|
DWORD dwErr = 0;
|
||||||
int fileno;
|
int fileno;
|
||||||
HANDLE fh = 0;
|
HANDLE fh = 0;
|
||||||
|
access_mode access = ACCESS_DEFAULT;
|
||||||
|
DWORD flProtect, dwDesiredAccess;
|
||||||
|
char *keywords[] = { "fileno", "length",
|
||||||
|
"tagname",
|
||||||
|
"access", NULL };
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args,
|
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|zi", keywords,
|
||||||
"iO|z",
|
&fileno, &map_size_obj,
|
||||||
&fileno,
|
&tagname, &access)) {
|
||||||
&map_size_obj,
|
|
||||||
&tagname)
|
|
||||||
)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(access) {
|
||||||
|
case ACCESS_READ:
|
||||||
|
flProtect = PAGE_READONLY;
|
||||||
|
dwDesiredAccess = FILE_MAP_READ;
|
||||||
|
break;
|
||||||
|
case ACCESS_DEFAULT: case ACCESS_WRITE:
|
||||||
|
flProtect = PAGE_READWRITE;
|
||||||
|
dwDesiredAccess = FILE_MAP_WRITE;
|
||||||
|
break;
|
||||||
|
case ACCESS_COPY:
|
||||||
|
flProtect = PAGE_WRITECOPY;
|
||||||
|
dwDesiredAccess = FILE_MAP_COPY;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return PyErr_Format(PyExc_ValueError,
|
||||||
|
"mmap invalid access parameter.");
|
||||||
|
}
|
||||||
|
|
||||||
map_size = _GetMapSize(map_size_obj);
|
map_size = _GetMapSize(map_size_obj);
|
||||||
if (map_size < 0)
|
if (map_size < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -873,8 +963,8 @@ new_mmap_object(PyObject *self, PyObject *args)
|
||||||
if (fileno != 0) {
|
if (fileno != 0) {
|
||||||
fh = (HANDLE)_get_osfhandle(fileno);
|
fh = (HANDLE)_get_osfhandle(fileno);
|
||||||
if (fh==(HANDLE)-1) {
|
if (fh==(HANDLE)-1) {
|
||||||
PyErr_SetFromErrno(mmap_module_error);
|
PyErr_SetFromErrno(mmap_module_error);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/* Win9x appears to need us seeked to zero */
|
/* Win9x appears to need us seeked to zero */
|
||||||
fseek(&_iob[fileno], 0, SEEK_SET);
|
fseek(&_iob[fileno], 0, SEEK_SET);
|
||||||
|
@ -894,13 +984,13 @@ new_mmap_object(PyObject *self, PyObject *args)
|
||||||
/* It is necessary to duplicate the handle, so the
|
/* It is necessary to duplicate the handle, so the
|
||||||
Python code can close it on us */
|
Python code can close it on us */
|
||||||
if (!DuplicateHandle(
|
if (!DuplicateHandle(
|
||||||
GetCurrentProcess(), /* source process handle */
|
GetCurrentProcess(), /* source process handle */
|
||||||
fh, /* handle to be duplicated */
|
fh, /* handle to be duplicated */
|
||||||
GetCurrentProcess(), /* target proc handle */
|
GetCurrentProcess(), /* target proc handle */
|
||||||
(LPHANDLE)&m_obj->file_handle, /* result */
|
(LPHANDLE)&m_obj->file_handle, /* result */
|
||||||
0, /* access - ignored due to options value */
|
0, /* access - ignored due to options value */
|
||||||
FALSE, /* inherited by child processes? */
|
FALSE, /* inherited by child processes? */
|
||||||
DUPLICATE_SAME_ACCESS)) { /* options */
|
DUPLICATE_SAME_ACCESS)) { /* options */
|
||||||
dwErr = GetLastError();
|
dwErr = GetLastError();
|
||||||
Py_DECREF(m_obj);
|
Py_DECREF(m_obj);
|
||||||
PyErr_SetFromWindowsErr(dwErr);
|
PyErr_SetFromWindowsErr(dwErr);
|
||||||
|
@ -932,22 +1022,23 @@ new_mmap_object(PyObject *self, PyObject *args)
|
||||||
else
|
else
|
||||||
m_obj->tagname = NULL;
|
m_obj->tagname = NULL;
|
||||||
|
|
||||||
|
m_obj->access = access;
|
||||||
m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
|
m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
|
||||||
NULL,
|
NULL,
|
||||||
PAGE_READWRITE,
|
flProtect,
|
||||||
0,
|
0,
|
||||||
m_obj->size,
|
m_obj->size,
|
||||||
m_obj->tagname);
|
m_obj->tagname);
|
||||||
if (m_obj->map_handle != NULL) {
|
if (m_obj->map_handle != NULL) {
|
||||||
m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
|
m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
|
||||||
FILE_MAP_WRITE,
|
dwDesiredAccess,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0);
|
0);
|
||||||
if (m_obj->data != NULL) {
|
if (m_obj->data != NULL) {
|
||||||
return ((PyObject *) m_obj);
|
return ((PyObject *) m_obj);
|
||||||
} else {
|
} else {
|
||||||
dwErr = GetLastError();
|
dwErr = GetLastError();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dwErr = GetLastError();
|
dwErr = GetLastError();
|
||||||
|
@ -966,7 +1057,7 @@ static struct PyMethodDef mmap_functions[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
DL_EXPORT(void)
|
DL_EXPORT(void)
|
||||||
initmmap(void)
|
initmmap(void)
|
||||||
{
|
{
|
||||||
PyObject *dict, *module;
|
PyObject *dict, *module;
|
||||||
|
|
||||||
|
@ -1011,5 +1102,11 @@ initmmap(void)
|
||||||
|
|
||||||
PyDict_SetItemString (dict, "PAGESIZE",
|
PyDict_SetItemString (dict, "PAGESIZE",
|
||||||
PyInt_FromLong( (long)my_getpagesize() ) );
|
PyInt_FromLong( (long)my_getpagesize() ) );
|
||||||
}
|
|
||||||
|
|
||||||
|
PyDict_SetItemString (dict, "ACCESS_READ",
|
||||||
|
PyInt_FromLong(ACCESS_READ));
|
||||||
|
PyDict_SetItemString (dict, "ACCESS_WRITE",
|
||||||
|
PyInt_FromLong(ACCESS_WRITE));
|
||||||
|
PyDict_SetItemString (dict, "ACCESS_COPY",
|
||||||
|
PyInt_FromLong(ACCESS_COPY));
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue