@@ -5,6 +5,7 @@ use std::io::{self, ErrorKind, Read, Write};
55use std:: time:: { Duration , SystemTime } ;
66use std:: { env, fs} ;
77
8+ use bitflags:: bitflags;
89use num_traits:: cast:: ToPrimitive ;
910
1011use crate :: function:: { IntoPyNativeFunc , PyFuncArgs } ;
@@ -81,13 +82,26 @@ pub fn os_close(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
8182 Ok ( vm. get_none ( ) )
8283}
8384
85+ bitflags ! {
86+ pub struct FileCreationFlags : u32 {
87+ // https://elixir.bootlin.com/linux/v4.8/source/include/uapi/asm-generic/fcntl.h
88+ const O_RDONLY = 0o0000_0000 ;
89+ const O_WRONLY = 0o0000_0001 ;
90+ const O_RDWR = 0o0000_0002 ;
91+ const O_CREAT = 0o0000_0100 ;
92+ const O_EXCL = 0o0000_0200 ;
93+ const O_APPEND = 0o0000_2000 ;
94+ const O_NONBLOCK = 0o0000_4000 ;
95+ }
96+ }
97+
8498pub fn os_open ( vm : & VirtualMachine , args : PyFuncArgs ) -> PyResult {
8599 arg_check ! (
86100 vm,
87101 args,
88102 required = [
89103 ( name, Some ( vm. ctx. str_type( ) ) ) ,
90- ( mode , Some ( vm. ctx. int_type( ) ) )
104+ ( flags , Some ( vm. ctx. int_type( ) ) )
91105 ] ,
92106 optional = [ ( dir_fd, Some ( vm. ctx. int_type( ) ) ) ]
93107 ) ;
@@ -102,14 +116,32 @@ pub fn os_open(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
102116 } ;
103117 let fname = & make_path ( vm, name, & dir_fd) . value ;
104118
105- let handle = match objint:: get_value ( mode) . to_u16 ( ) . unwrap ( ) {
106- 0 => OpenOptions :: new ( ) . read ( true ) . open ( & fname) ,
107- 1 => OpenOptions :: new ( ) . write ( true ) . open ( & fname) ,
108- 2 => OpenOptions :: new ( ) . read ( true ) . write ( true ) . open ( & fname) ,
109- 512 => OpenOptions :: new ( ) . write ( true ) . create ( true ) . open ( & fname) ,
110- _ => OpenOptions :: new ( ) . read ( true ) . open ( & fname) ,
119+ let flags = FileCreationFlags :: from_bits ( objint:: get_value ( flags) . to_u32 ( ) . unwrap ( ) )
120+ . ok_or ( vm. new_value_error ( "Unsupported flag" . to_string ( ) ) ) ?;
121+
122+ let mut options = & mut OpenOptions :: new ( ) ;
123+
124+ if flags. contains ( FileCreationFlags :: O_WRONLY ) {
125+ options = options. write ( true ) ;
126+ } else if flags. contains ( FileCreationFlags :: O_RDWR ) {
127+ options = options. read ( true ) . write ( true ) ;
128+ } else {
129+ options = options. read ( true ) ;
111130 }
112- . map_err ( |err| match err. kind ( ) {
131+
132+ if flags. contains ( FileCreationFlags :: O_APPEND ) {
133+ options = options. append ( true ) ;
134+ }
135+
136+ if flags. contains ( FileCreationFlags :: O_CREAT ) {
137+ if flags. contains ( FileCreationFlags :: O_EXCL ) {
138+ options = options. create_new ( true ) ;
139+ } else {
140+ options = options. create ( true ) ;
141+ }
142+ }
143+
144+ let handle = options. open ( & fname) . map_err ( |err| match err. kind ( ) {
113145 ErrorKind :: NotFound => {
114146 let exc_type = vm. ctx . exceptions . file_not_found_error . clone ( ) ;
115147 vm. new_exception ( exc_type, format ! ( "No such file or directory: {}" , & fname) )
@@ -118,6 +150,10 @@ pub fn os_open(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
118150 let exc_type = vm. ctx . exceptions . permission_error . clone ( ) ;
119151 vm. new_exception ( exc_type, format ! ( "Permission denied: {}" , & fname) )
120152 }
153+ ErrorKind :: AlreadyExists => {
154+ let exc_type = vm. ctx . exceptions . file_exists_error . clone ( ) ;
155+ vm. new_exception ( exc_type, format ! ( "File exists: {}" , & fname) )
156+ }
121157 _ => vm. new_value_error ( "Unhandled file IO error" . to_string ( ) ) ,
122158 } ) ?;
123159
@@ -743,12 +779,13 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
743779 "getcwd" => ctx. new_rustfunc( os_getcwd) ,
744780 "chdir" => ctx. new_rustfunc( os_chdir) ,
745781 "fspath" => ctx. new_rustfunc( os_fspath) ,
746- "O_RDONLY" => ctx. new_int( 0 ) ,
747- "O_WRONLY" => ctx. new_int( 1 ) ,
748- "O_RDWR" => ctx. new_int( 2 ) ,
749- "O_NONBLOCK" => ctx. new_int( 4 ) ,
750- "O_APPEND" => ctx. new_int( 8 ) ,
751- "O_CREAT" => ctx. new_int( 512 )
782+ "O_RDONLY" => ctx. new_int( FileCreationFlags :: O_RDONLY . bits( ) ) ,
783+ "O_WRONLY" => ctx. new_int( FileCreationFlags :: O_WRONLY . bits( ) ) ,
784+ "O_RDWR" => ctx. new_int( FileCreationFlags :: O_RDWR . bits( ) ) ,
785+ "O_NONBLOCK" => ctx. new_int( FileCreationFlags :: O_NONBLOCK . bits( ) ) ,
786+ "O_APPEND" => ctx. new_int( FileCreationFlags :: O_APPEND . bits( ) ) ,
787+ "O_EXCL" => ctx. new_int( FileCreationFlags :: O_EXCL . bits( ) ) ,
788+ "O_CREAT" => ctx. new_int( FileCreationFlags :: O_CREAT . bits( ) )
752789 } ) ;
753790
754791 for support in support_funcs {
0 commit comments