@@ -30,7 +30,8 @@ export env, getenv, setenv, fdopen, pipe;
30
30
export getcwd, dll_filename, self_exe_path;
31
31
export exe_suffix, dll_suffix, sysname;
32
32
export homedir, list_dir, list_dir_path, path_is_dir, path_exists,
33
- make_absolute, make_dir, remove_dir, change_dir, remove_file;
33
+ make_absolute, make_dir, remove_dir, change_dir, remove_file,
34
+ copy_file;
34
35
35
36
// FIXME: move these to str perhaps?
36
37
export as_c_charp, fill_charp_buf;
@@ -534,13 +535,76 @@ fn change_dir(p: path) -> bool {
534
535
}
535
536
}
536
537
538
+ #[ doc = "Copies a file from one location to another" ]
539
+ fn copy_file ( from : path , to : path ) -> bool {
540
+ ret do_copy_file ( from, to) ;
541
+
542
+ #[ cfg( target_os = "win32" ) ]
543
+ fn do_copy_file ( from : path , to : path ) -> bool {
544
+ // FIXME: remove imports when export globs work properly.
545
+ import libc:: funcs:: extra:: kernel32:: * ;
546
+ import libc:: types:: os:: arch:: extra:: * ;
547
+ import win32:: * ;
548
+ ret as_utf16_p ( from) { |fromp|
549
+ as_utf16_p ( to) { |top|
550
+ CopyFileW ( fromp, top, ( 0 as BOOL ) ) != ( 0 as BOOL )
551
+ }
552
+ }
553
+ }
554
+
555
+ #[ cfg( target_os = "linux" ) ]
556
+ #[ cfg( target_os = "macos" ) ]
557
+ #[ cfg( target_os = "freebsd" ) ]
558
+ fn do_copy_file ( from : path , to : path ) -> bool unsafe {
559
+ let istream = as_c_charp ( from) { |fromp|
560
+ as_c_charp ( "rb" ) { |modebuf|
561
+ libc:: fopen ( fromp, modebuf)
562
+ }
563
+ } ;
564
+ if istream as uint == 0 u {
565
+ ret false ;
566
+ }
567
+ let ostream = as_c_charp ( to) { |top|
568
+ as_c_charp ( "w+b" ) { |modebuf|
569
+ libc:: fopen ( top, modebuf)
570
+ }
571
+ } ;
572
+ if ostream as uint == 0 u {
573
+ fclose ( istream) ;
574
+ ret false;
575
+ }
576
+ let mut buf : [ mut u8] = [ mut] ;
577
+ let bufsize = 8192 u;
578
+ vec:: reserve ( buf, bufsize) ;
579
+ let mut done = false ;
580
+ let mut ok = true ;
581
+ while !done {
582
+ vec:: as_mut_buf ( buf) { |b|
583
+ let nread = libc:: fread ( b as * mut c_void , 1 u, bufsize, istream) ;
584
+ if nread > 0 as size_t {
585
+ if libc:: fwrite ( b as * c_void , 1 u, nread, ostream) != nread {
586
+ ok = false ;
587
+ done = true ;
588
+ }
589
+ } else {
590
+ done = true ;
591
+ }
592
+ }
593
+ }
594
+ fclose ( istream) ;
595
+ fclose ( ostream) ;
596
+ ret ok;
597
+ }
598
+ }
599
+
537
600
#[ doc = "Deletes an existing file" ]
538
601
fn remove_file ( p : path ) -> bool {
539
602
ret unlink ( p) ;
540
603
541
604
#[ cfg( target_os = "win32" ) ]
542
605
fn unlink ( p : path ) -> bool {
543
606
// FIXME: remove imports when export globs work properly.
607
+ // (similar to Issue #2006)
544
608
import libc:: funcs:: extra:: kernel32:: * ;
545
609
import libc:: types:: os:: arch:: extra:: * ;
546
610
import win32:: * ;
@@ -762,4 +826,42 @@ mod tests {
762
826
assert ( !os:: path_exists ( "test/nonexistent-bogus-path" ) ) ;
763
827
}
764
828
829
+ #[ test]
830
+ fn copy_file_does_not_exist ( ) {
831
+ assert !os:: copy_file ( "test/nonexistent-bogus-path" ,
832
+ "test/other-bogus-path" ) ;
833
+ assert !os:: path_exists ( "test/other-bogus-path" ) ;
834
+ }
835
+
836
+ #[ test]
837
+ fn copy_file_ok ( ) {
838
+ let tempdir = getcwd ( ) ; // would like to use $TMPDIR,
839
+ // doesn't seem to work on Linux
840
+ assert ( str:: len ( tempdir) > 0 u) ;
841
+ let in = tempdir + path:: path_sep ( ) + "in.txt" ;
842
+ let out = tempdir + path:: path_sep ( ) + "out.txt" ;
843
+
844
+ /* Write the temp input file */
845
+ let ostream = as_c_charp ( in) { |fromp|
846
+ as_c_charp ( "w+b" ) { |modebuf|
847
+ libc:: fopen ( fromp, modebuf)
848
+ }
849
+ } ;
850
+ assert ( ostream as uint != 0 u) ;
851
+ let s = "hello" ;
852
+ let mut buf = str:: bytes ( s) + [ 0 as u8 ] ;
853
+ vec:: as_mut_buf( buf) { |b|
854
+ assert ( libc:: fwrite( b as * c_void, 1 u, str:: len( s) + 1 u, ostream) ==
855
+ buf. len( ) ) } ;
856
+ assert ( libc:: fclose ( ostream) == ( 0 u as c_int ) ) ;
857
+ let rs = os:: copy_file ( in, out) ;
858
+ if ( !os:: path_exists ( in) ) {
859
+ fail ( #fmt ( "%s doesn't exist" , in) ) ;
860
+ }
861
+ assert ( rs) ;
862
+ let rslt = run:: run_program ( "diff" , [ in, out] ) ;
863
+ assert ( rslt == 0 ) ;
864
+ assert ( remove_file ( in) ) ;
865
+ assert ( remove_file ( out) ) ;
866
+ }
765
867
}
0 commit comments