@@ -7,14 +7,13 @@ use std::{env, fs};
7
7
8
8
use num_traits:: cast:: ToPrimitive ;
9
9
10
- use crate :: function:: PyFuncArgs ;
10
+ use crate :: function:: { IntoPyNativeFunc , PyFuncArgs } ;
11
11
use crate :: obj:: objbytes:: PyBytesRef ;
12
12
use crate :: obj:: objdict:: PyDictRef ;
13
- use crate :: obj:: objint;
14
- use crate :: obj:: objint:: PyIntRef ;
13
+ use crate :: obj:: objint:: { self , PyInt , PyIntRef } ;
15
14
use crate :: obj:: objiter;
16
- use crate :: obj:: objstr ;
17
- use crate :: obj:: objstr:: PyStringRef ;
15
+ use crate :: obj:: objset :: PySet ;
16
+ use crate :: obj:: objstr:: { self , PyString , PyStringRef } ;
18
17
use crate :: obj:: objtype:: PyClassRef ;
19
18
use crate :: pyobject:: {
20
19
ItemProtocol , PyClassImpl , PyObjectRef , PyRef , PyResult , PyValue , TryIntoRef ,
@@ -61,6 +60,14 @@ pub fn raw_file_number(handle: File) -> i64 {
61
60
unimplemented ! ( ) ;
62
61
}
63
62
63
+ fn make_path ( _vm : & VirtualMachine , path : PyStringRef , dir_fd : & DirFd ) -> PyStringRef {
64
+ if dir_fd. dir_fd . is_some ( ) {
65
+ unimplemented ! ( ) ;
66
+ } else {
67
+ path
68
+ }
69
+ }
70
+
64
71
pub fn os_close ( vm : & VirtualMachine , args : PyFuncArgs ) -> PyResult {
65
72
arg_check ! ( vm, args, required = [ ( fileno, Some ( vm. ctx. int_type( ) ) ) ] ) ;
66
73
@@ -81,10 +88,19 @@ pub fn os_open(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
81
88
required = [
82
89
( name, Some ( vm. ctx. str_type( ) ) ) ,
83
90
( mode, Some ( vm. ctx. int_type( ) ) )
84
- ]
91
+ ] ,
92
+ optional = [ ( dir_fd, Some ( vm. ctx. int_type( ) ) ) ]
85
93
) ;
86
94
87
- let fname = objstr:: get_value ( & name) ;
95
+ let name = name. clone ( ) . downcast :: < PyString > ( ) . unwrap ( ) ;
96
+ let dir_fd = if let Some ( obj) = dir_fd {
97
+ DirFd {
98
+ dir_fd : Some ( obj. clone ( ) . downcast :: < PyInt > ( ) . unwrap ( ) ) ,
99
+ }
100
+ } else {
101
+ DirFd :: default ( )
102
+ } ;
103
+ let fname = & make_path ( vm, name, & dir_fd) . value ;
88
104
89
105
let handle = match objint:: get_value ( mode) . to_u16 ( ) . unwrap ( ) {
90
106
0 => OpenOptions :: new ( ) . read ( true ) . open ( & fname) ,
@@ -159,19 +175,22 @@ fn os_write(fd: PyIntRef, data: PyBytesRef, vm: &VirtualMachine) -> PyResult {
159
175
Ok ( vm. ctx . new_int ( written) )
160
176
}
161
177
162
- fn os_remove ( path : PyStringRef , vm : & VirtualMachine ) -> PyResult < ( ) > {
178
+ fn os_remove ( path : PyStringRef , dir_fd : DirFd , vm : & VirtualMachine ) -> PyResult < ( ) > {
179
+ let path = make_path ( vm, path, & dir_fd) ;
163
180
fs:: remove_file ( & path. value ) . map_err ( |s| vm. new_os_error ( s. to_string ( ) ) )
164
181
}
165
182
166
- fn os_mkdir ( path : PyStringRef , vm : & VirtualMachine ) -> PyResult < ( ) > {
183
+ fn os_mkdir ( path : PyStringRef , dir_fd : DirFd , vm : & VirtualMachine ) -> PyResult < ( ) > {
184
+ let path = make_path ( vm, path, & dir_fd) ;
167
185
fs:: create_dir ( & path. value ) . map_err ( |s| vm. new_os_error ( s. to_string ( ) ) )
168
186
}
169
187
170
188
fn os_mkdirs ( path : PyStringRef , vm : & VirtualMachine ) -> PyResult < ( ) > {
171
189
fs:: create_dir_all ( & path. value ) . map_err ( |s| vm. new_os_error ( s. to_string ( ) ) )
172
190
}
173
191
174
- fn os_rmdir ( path : PyStringRef , vm : & VirtualMachine ) -> PyResult < ( ) > {
192
+ fn os_rmdir ( path : PyStringRef , dir_fd : DirFd , vm : & VirtualMachine ) -> PyResult < ( ) > {
193
+ let path = make_path ( vm, path, & dir_fd) ;
175
194
fs:: remove_dir ( & path. value ) . map_err ( |s| vm. new_os_error ( s. to_string ( ) ) )
176
195
}
177
196
@@ -219,6 +238,12 @@ impl PyValue for DirEntry {
219
238
}
220
239
}
221
240
241
+ #[ derive( FromArgs , Default ) ]
242
+ struct DirFd {
243
+ #[ pyarg( keyword_only, default = "None" ) ]
244
+ dir_fd : Option < PyIntRef > ,
245
+ }
246
+
222
247
#[ derive( FromArgs ) ]
223
248
struct FollowSymlinks {
224
249
#[ pyarg( keyword_only, default = "true" ) ]
@@ -272,8 +297,13 @@ impl DirEntryRef {
272
297
. is_symlink ( ) )
273
298
}
274
299
275
- fn stat ( self , follow_symlinks : FollowSymlinks , vm : & VirtualMachine ) -> PyResult < StatResult > {
276
- os_stat ( self . path ( vm) . try_into_ref ( vm) ?, follow_symlinks, vm)
300
+ fn stat (
301
+ self ,
302
+ dir_fd : DirFd ,
303
+ follow_symlinks : FollowSymlinks ,
304
+ vm : & VirtualMachine ,
305
+ ) -> PyResult < StatResult > {
306
+ os_stat ( self . path ( vm) . try_into_ref ( vm) ?, dir_fd, follow_symlinks, vm)
277
307
}
278
308
}
279
309
@@ -432,30 +462,36 @@ macro_rules! os_unix_stat_inner {
432
462
#[ cfg( target_os = "linux" ) ]
433
463
fn os_stat (
434
464
path : PyStringRef ,
465
+ dir_fd : DirFd ,
435
466
follow_symlinks : FollowSymlinks ,
436
467
vm : & VirtualMachine ,
437
468
) -> PyResult < StatResult > {
438
469
use std:: os:: linux:: fs:: MetadataExt ;
470
+ let path = make_path ( vm, path, & dir_fd) ;
439
471
os_unix_stat_inner ! ( path, follow_symlinks, vm)
440
472
}
441
473
442
474
#[ cfg( target_os = "macos" ) ]
443
475
fn os_stat (
444
476
path : PyStringRef ,
477
+ dir_fd : DirFd ,
445
478
follow_symlinks : FollowSymlinks ,
446
479
vm : & VirtualMachine ,
447
480
) -> PyResult < StatResult > {
448
481
use std:: os:: macos:: fs:: MetadataExt ;
482
+ let path = make_path ( vm, path, & dir_fd) ;
449
483
os_unix_stat_inner ! ( path, follow_symlinks, vm)
450
484
}
451
485
452
486
#[ cfg( target_os = "android" ) ]
453
487
fn os_stat (
454
488
path : PyStringRef ,
489
+ dir_fd : DirFd ,
455
490
follow_symlinks : FollowSymlinks ,
456
491
vm : & VirtualMachine ,
457
492
) -> PyResult < StatResult > {
458
493
use std:: os:: android:: fs:: MetadataExt ;
494
+ let path = make_path ( vm, path, & dir_fd) ;
459
495
os_unix_stat_inner ! ( path, follow_symlinks, vm)
460
496
}
461
497
@@ -483,6 +519,7 @@ fn attributes_to_mode(attr: u32) -> u32 {
483
519
#[ cfg( windows) ]
484
520
fn os_stat (
485
521
path : PyStringRef ,
522
+ _dir_fd : DirFd , // TODO: error
486
523
follow_symlinks : FollowSymlinks ,
487
524
vm : & VirtualMachine ,
488
525
) -> PyResult < StatResult > {
@@ -523,13 +560,24 @@ fn os_stat(path: PyStringRef, vm: &VirtualMachine) -> PyResult {
523
560
}
524
561
525
562
#[ cfg( unix) ]
526
- fn os_symlink ( src : PyStringRef , dst : PyStringRef , vm : & VirtualMachine ) -> PyResult < ( ) > {
563
+ fn os_symlink (
564
+ src : PyStringRef ,
565
+ dst : PyStringRef ,
566
+ dir_fd : DirFd ,
567
+ vm : & VirtualMachine ,
568
+ ) -> PyResult < ( ) > {
527
569
use std:: os:: unix:: fs as unix_fs;
570
+ let dst = make_path ( vm, dst, & dir_fd) ;
528
571
unix_fs:: symlink ( & src. value , & dst. value ) . map_err ( |s| vm. new_os_error ( s. to_string ( ) ) )
529
572
}
530
573
531
574
#[ cfg( windows) ]
532
- fn os_symlink ( src : PyStringRef , dst : PyStringRef , vm : & VirtualMachine ) -> PyResult < ( ) > {
575
+ fn os_symlink (
576
+ src : PyStringRef ,
577
+ dst : PyStringRef ,
578
+ _dir_fd : DirFd ,
579
+ vm : & VirtualMachine ,
580
+ ) -> PyResult < ( ) > {
533
581
use std:: os:: windows:: fs as win_fs;
534
582
let ret = match fs:: metadata ( & dst. value ) {
535
583
Ok ( meta) => {
@@ -547,7 +595,12 @@ fn os_symlink(src: PyStringRef, dst: PyStringRef, vm: &VirtualMachine) -> PyResu
547
595
}
548
596
549
597
#[ cfg( all( not( unix) , not( windows) ) ) ]
550
- fn os_symlink ( src : PyStringRef , dst : PyStringRef , vm : & VirtualMachine ) -> PyResult < ( ) > {
598
+ fn os_symlink (
599
+ src : PyStringRef ,
600
+ dst : PyStringRef ,
601
+ dir_fd : DirFd ,
602
+ vm : & VirtualMachine ,
603
+ ) -> PyResult < ( ) > {
551
604
unimplemented ! ( ) ;
552
605
}
553
606
@@ -600,36 +653,114 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
600
653
"st_mtime" => ctx. new_property( StatResultRef :: st_mtime) ,
601
654
} ) ;
602
655
603
- py_module ! ( vm, "_os" , {
604
- "open" => ctx. new_rustfunc( os_open) ,
656
+ struct SupportFunc < ' a > {
657
+ name : & ' a str ,
658
+ func_obj : PyObjectRef ,
659
+ fd : Option < bool > ,
660
+ dir_fd : Option < bool > ,
661
+ follow_symlinks : Option < bool > ,
662
+ } ;
663
+ impl < ' a > SupportFunc < ' a > {
664
+ fn new < F , T , R > (
665
+ vm : & VirtualMachine ,
666
+ name : & ' a str ,
667
+ func : F ,
668
+ fd : Option < bool > ,
669
+ dir_fd : Option < bool > ,
670
+ follow_symlinks : Option < bool > ,
671
+ ) -> Self
672
+ where
673
+ F : IntoPyNativeFunc < T , R > ,
674
+ {
675
+ Self {
676
+ name : name,
677
+ func_obj : vm. ctx . new_rustfunc ( func) ,
678
+ fd : fd,
679
+ dir_fd : dir_fd,
680
+ follow_symlinks : follow_symlinks,
681
+ }
682
+ }
683
+ }
684
+ let support_funcs = vec ! [
685
+ SupportFunc :: new( vm, "open" , os_open, None , Some ( false ) , None ) ,
686
+ // access Some Some None
687
+ SupportFunc :: new( vm, "chdir" , os_chdir, Some ( false ) , None , None ) ,
688
+ // chflags Some, None Some
689
+ // chmod Some Some Some
690
+ // chown Some Some Some
691
+ // chroot Some None None
692
+ SupportFunc :: new( vm, "listdir" , os_listdir, Some ( false ) , None , None ) ,
693
+ SupportFunc :: new( vm, "mkdir" , os_mkdir, Some ( false ) , Some ( false ) , None ) ,
694
+ // mkfifo Some Some None
695
+ // mknod Some Some None
696
+ // pathconf Some None None
697
+ // readlink Some Some None
698
+ SupportFunc :: new( vm, "remove" , os_remove, Some ( false ) , Some ( false ) , None ) ,
699
+ // rename Some Some None
700
+ // replace Some Some None
701
+ SupportFunc :: new( vm, "rmdir" , os_rmdir, Some ( false ) , Some ( false ) , None ) ,
702
+ SupportFunc :: new( vm, "scandir" , os_scandir, Some ( false ) , None , None ) ,
703
+ SupportFunc :: new( vm, "stat" , os_stat, Some ( false ) , Some ( false ) , Some ( false ) ) ,
704
+ SupportFunc :: new( vm, "symlink" , os_symlink, None , Some ( false ) , None ) ,
705
+ // truncate Some None None
706
+ SupportFunc :: new( vm, "unlink" , os_remove, Some ( false ) , Some ( false ) , None ) ,
707
+ // utime Some Some Some
708
+ ] ;
709
+ let supports_fd = PySet :: default ( ) . into_ref ( vm) ;
710
+ let supports_dir_fd = PySet :: default ( ) . into_ref ( vm) ;
711
+ let supports_follow_symlinks = PySet :: default ( ) . into_ref ( vm) ;
712
+
713
+ let module = py_module ! ( vm, "_os" , {
605
714
"close" => ctx. new_rustfunc( os_close) ,
606
715
"error" => ctx. new_rustfunc( os_error) ,
607
716
"fsync" => ctx. new_rustfunc( os_fsync) ,
608
717
"read" => ctx. new_rustfunc( os_read) ,
609
718
"write" => ctx. new_rustfunc( os_write) ,
610
- "remove" => ctx. new_rustfunc( os_remove) ,
611
- "unlink" => ctx. new_rustfunc( os_remove) ,
612
- "mkdir" => ctx. new_rustfunc( os_mkdir) ,
613
719
"mkdirs" => ctx. new_rustfunc( os_mkdirs) ,
614
- "rmdir" => ctx. new_rustfunc( os_rmdir) ,
615
- "listdir" => ctx. new_rustfunc( os_listdir) ,
616
720
"putenv" => ctx. new_rustfunc( os_putenv) ,
617
721
"unsetenv" => ctx. new_rustfunc( os_unsetenv) ,
618
722
"environ" => environ,
619
723
"name" => ctx. new_str( os_name) ,
620
- "scandir" => ctx. new_rustfunc( os_scandir) ,
621
724
"ScandirIter" => scandir_iter,
622
725
"DirEntry" => dir_entry,
623
726
"stat_result" => stat_result,
624
- "stat" => ctx. new_rustfunc( os_stat) ,
625
- "symlink" => ctx. new_rustfunc( os_symlink) ,
626
727
"getcwd" => ctx. new_rustfunc( os_getcwd) ,
627
- "chdir" => ctx. new_rustfunc( os_chdir) ,
628
728
"O_RDONLY" => ctx. new_int( 0 ) ,
629
729
"O_WRONLY" => ctx. new_int( 1 ) ,
630
730
"O_RDWR" => ctx. new_int( 2 ) ,
631
731
"O_NONBLOCK" => ctx. new_int( 4 ) ,
632
732
"O_APPEND" => ctx. new_int( 8 ) ,
633
733
"O_CREAT" => ctx. new_int( 512 )
634
- } )
734
+ } ) ;
735
+
736
+ for support in support_funcs {
737
+ if support. fd . unwrap_or ( false ) {
738
+ supports_fd
739
+ . clone ( )
740
+ . add ( support. func_obj . clone ( ) , vm)
741
+ . unwrap ( ) ;
742
+ }
743
+ if support. dir_fd . unwrap_or ( false ) {
744
+ supports_dir_fd
745
+ . clone ( )
746
+ . add ( support. func_obj . clone ( ) , vm)
747
+ . unwrap ( ) ;
748
+ }
749
+ if support. follow_symlinks . unwrap_or ( false ) {
750
+ supports_follow_symlinks
751
+ . clone ( )
752
+ . add ( support. func_obj . clone ( ) , vm)
753
+ . unwrap ( ) ;
754
+ }
755
+ vm. set_attr ( & module, support. name , support. func_obj )
756
+ . unwrap ( ) ;
757
+ }
758
+
759
+ extend_module ! ( vm, module, {
760
+ "supports_fd" => supports_fd. into_object( ) ,
761
+ "supports_dir_fd" => supports_dir_fd. into_object( ) ,
762
+ "supports_follow_symlinks" => supports_follow_symlinks. into_object( ) ,
763
+ } ) ;
764
+
765
+ module
635
766
}
0 commit comments