@@ -6,7 +6,8 @@ mod mmap {
66 use crate :: common:: lock:: { PyMutex , PyMutexGuard } ;
77 use crate :: vm:: {
88 builtins:: { PyBytes , PyBytesRef , PyInt , PyIntRef , PyTypeRef } ,
9- function:: { FuncArgs , OptionalArg } ,
9+ byte:: value_from_object,
10+ function:: { ArgBytesLike , FuncArgs , OptionalArg } ,
1011 sliceable:: saturate_index,
1112 types:: Constructor ,
1213 AsObject , FromArgs , PyObject , PyObjectRef , PyPayload , PyRef , PyResult ,
@@ -16,7 +17,8 @@ mod mmap {
1617 use memmap2:: { Advice , Mmap , MmapMut , MmapOptions } ;
1718 use nix:: unistd;
1819 use std:: fs:: File ;
19- use std:: ops:: Deref ;
20+ use std:: io:: Write ;
21+ use std:: ops:: { Deref , DerefMut } ;
2022 #[ cfg( all( unix, not( target_os = "redox" ) ) ) ]
2123 use std:: os:: unix:: io:: { FromRawFd , IntoRawFd , RawFd } ;
2224
@@ -355,6 +357,24 @@ mod mmap {
355357 self . pos . store ( self . inner_pos ( ) + step) ;
356358 }
357359
360+ #[ inline]
361+ fn try_writable < R > (
362+ & self ,
363+ vm : & VirtualMachine ,
364+ f : impl FnOnce ( & mut MmapMut ) -> R ,
365+ ) -> PyResult < R > {
366+ if matches ! ( self . access, AccessMode :: Read ) {
367+ return Err (
368+ vm. new_type_error ( "mmap can't modify a readonly memory map." . to_owned ( ) )
369+ ) ;
370+ }
371+
372+ match self . check_valid ( vm) ?. deref_mut ( ) . as_mut ( ) . unwrap ( ) {
373+ MmapObj :: Write ( mmap) => Ok ( f ( mmap) ) ,
374+ _ => unreachable ! ( "already check" ) ,
375+ }
376+ }
377+
358378 fn check_valid ( & self , vm : & VirtualMachine ) -> PyResult < PyMutexGuard < Option < MmapObj > > > {
359379 let m = self . mmap . lock ( ) ;
360380
@@ -365,6 +385,24 @@ mod mmap {
365385 Ok ( m)
366386 }
367387
388+ /// TODO: impl resize
389+ #[ allow( dead_code) ]
390+ fn check_resizeable ( & self , vm : & VirtualMachine ) -> PyResult < ( ) > {
391+ if self . exports . load ( ) > 0 {
392+ return Err ( vm. new_buffer_error (
393+ "mmap can't resize with extant buffers exported." . to_owned ( ) ,
394+ ) ) ;
395+ }
396+
397+ if self . access == AccessMode :: Write || self . access == AccessMode :: Default {
398+ return Ok ( ( ) ) ;
399+ }
400+
401+ Err ( vm. new_type_error (
402+ "mmap can't resize a readonly or copy-on-write memory map." . to_owned ( ) ,
403+ ) )
404+ }
405+
368406 #[ pyproperty]
369407 fn closed ( & self ) -> bool {
370408 self . closed . load ( )
@@ -521,6 +559,30 @@ mod mmap {
521559 Ok ( ( ) )
522560 }
523561
562+ #[ pymethod( name = "move" ) ]
563+ fn move_ ( & self , dest : isize , src : isize , cnt : isize , vm : & VirtualMachine ) -> PyResult < ( ) > {
564+ let size = self . inner_size ( ) ;
565+ if dest < 0 || src < 0 || cnt < 0 || size - dest < cnt || size - src < cnt {
566+ return Err (
567+ vm. new_value_error ( "source, destination, or count out of range" . to_owned ( ) )
568+ ) ;
569+ }
570+
571+ let dest: usize = dest. try_into ( ) . unwrap ( ) ;
572+ let cnt: usize = cnt. try_into ( ) . unwrap ( ) ;
573+ let dest_end = dest + cnt;
574+ let src: usize = src. try_into ( ) . unwrap ( ) ;
575+ let src_end = src + cnt;
576+
577+ self . try_writable ( vm, |mmap| {
578+ let src_buf = mmap[ src..src_end] . to_vec ( ) ;
579+ ( & mut mmap[ dest..dest_end] )
580+ . write ( & src_buf)
581+ . map_err ( |e| vm. new_os_error ( e. to_string ( ) ) ) ?;
582+ Ok ( ( ) )
583+ } ) ?
584+ }
585+
524586 #[ pymethod]
525587 fn read ( & self , n : OptionalArg < PyObjectRef > , vm : & VirtualMachine ) -> PyResult < PyBytesRef > {
526588 let mut num_bytes = n
@@ -619,6 +681,54 @@ mod mmap {
619681 Ok ( result)
620682 }
621683
684+ //TODO: supports resize
685+ #[ pymethod]
686+ fn resize ( & self , _newsize : PyIntRef , vm : & VirtualMachine ) -> PyResult < ( ) > {
687+ self . check_resizeable ( vm) ?;
688+ Err ( vm. new_system_error ( "mmap: resizing not available--no mremap()" . to_owned ( ) ) )
689+ }
690+
691+ #[ pymethod]
692+ fn seek (
693+ & self ,
694+ pos : isize ,
695+ whence : OptionalArg < libc:: c_int > ,
696+ vm : & VirtualMachine ,
697+ ) -> PyResult < ( ) > {
698+ let dist = pos;
699+
700+ let how = whence. unwrap_or ( 0 ) ;
701+ let size = self . inner_size ( ) ;
702+
703+ let new_pos = match how {
704+ 0 => dist, // relative to start
705+ 1 => {
706+ // relative to current position
707+ let pos = self . inner_pos ( ) ;
708+ if isize:: MAX - pos < dist {
709+ return Err ( vm. new_value_error ( "seek out of range" . to_owned ( ) ) ) ;
710+ }
711+ pos + dist
712+ }
713+ 2 => {
714+ // relative to end
715+ if isize:: MAX - size < dist {
716+ return Err ( vm. new_value_error ( "seek out of range" . to_owned ( ) ) ) ;
717+ }
718+ size + dist
719+ }
720+ _ => return Err ( vm. new_value_error ( "unknown seek type" . to_owned ( ) ) ) ,
721+ } ;
722+
723+ if new_pos > size || new_pos < 0 {
724+ return Err ( vm. new_value_error ( "seek out of range" . to_owned ( ) ) ) ;
725+ }
726+
727+ self . pos . store ( new_pos) ;
728+
729+ Ok ( ( ) )
730+ }
731+
622732 #[ pymethod]
623733 fn size ( & self , vm : & VirtualMachine ) -> PyResult < PyIntRef > {
624734 let new_fd = unistd:: dup ( self . fd ) . map_err ( |e| vm. new_os_error ( e. to_string ( ) ) ) ?;
@@ -636,6 +746,49 @@ mod mmap {
636746 Ok ( self . inner_pos ( ) )
637747 }
638748
749+ #[ pymethod]
750+ fn write ( & self , bytes : ArgBytesLike , vm : & VirtualMachine ) -> PyResult < PyIntRef > {
751+ let pos = self . inner_pos ( ) ;
752+ let size = self . inner_size ( ) ;
753+
754+ let data = bytes. borrow_buf ( ) ;
755+
756+ if pos > size || size - pos < data. len ( ) as isize {
757+ return Err ( vm. new_value_error ( "data out of range" . to_owned ( ) ) ) ;
758+ }
759+
760+ let len = self . try_writable ( vm, |mmap| {
761+ ( & mut mmap[ pos as usize ..( pos as usize + data. len ( ) ) ] )
762+ . write ( & data)
763+ . map_err ( |e| vm. new_os_error ( e. to_string ( ) ) ) ?;
764+ Ok ( data. len ( ) )
765+ } ) ??;
766+
767+ self . advance_pos ( len as isize ) ;
768+
769+ Ok ( PyInt :: from ( len) . into_ref ( vm) )
770+ }
771+
772+ #[ pymethod]
773+ fn write_byte ( & self , byte : PyObjectRef , vm : & VirtualMachine ) -> PyResult < ( ) > {
774+ let b = value_from_object ( vm, & byte) ?;
775+
776+ let pos = self . inner_pos ( ) ;
777+ let size = self . inner_size ( ) ;
778+
779+ if pos >= size {
780+ return Err ( vm. new_value_error ( "write byte out of range" . to_owned ( ) ) ) ;
781+ }
782+
783+ self . try_writable ( vm, |mmap| {
784+ mmap[ pos as usize ] = b;
785+ } ) ?;
786+
787+ self . advance_pos ( 1 ) ;
788+
789+ Ok ( ( ) )
790+ }
791+
639792 #[ pymethod( magic) ]
640793 fn enter ( zelf : PyRef < Self > , vm : & VirtualMachine ) -> PyResult < PyRef < Self > > {
641794 let _m = zelf. check_valid ( vm) ?;
0 commit comments