Skip to content

Commit e9ff495

Browse files
committed
Merge branch 'issue-1983' of https://github.com/thomaslee/rust into issue-2090
This adds a new os::copy_file function, contributed by Thomas Lee. I added test cases.
1 parent 28a0e9c commit e9ff495

File tree

2 files changed

+106
-1
lines changed

2 files changed

+106
-1
lines changed

src/libcore/libc.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,6 +1155,9 @@ mod funcs {
11551155
fn CreateDirectoryW(lpPathName: LPCWSTR,
11561156
lpSecurityAttributes:
11571157
LPSECURITY_ATTRIBUTES) -> BOOL;
1158+
fn CopyFileW(lpExistingFileName: LPCWSTR,
1159+
lpNewFileName: LPCWSTR,
1160+
bFailIfExists: BOOL) -> BOOL;
11581161
fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL;
11591162
fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL;
11601163
fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL;

src/libcore/os.rs

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ export env, getenv, setenv, fdopen, pipe;
3030
export getcwd, dll_filename, self_exe_path;
3131
export exe_suffix, dll_suffix, sysname;
3232
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;
3435

3536
// FIXME: move these to str perhaps?
3637
export as_c_charp, fill_charp_buf;
@@ -534,13 +535,76 @@ fn change_dir(p: path) -> bool {
534535
}
535536
}
536537

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 == 0u {
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 == 0u {
573+
fclose(istream);
574+
ret false;
575+
}
576+
let mut buf : [mut u8] = [mut];
577+
let bufsize = 8192u;
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, 1u, bufsize, istream);
584+
if nread > 0 as size_t {
585+
if libc::fwrite(b as *c_void, 1u, 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+
537600
#[doc = "Deletes an existing file"]
538601
fn remove_file(p: path) -> bool {
539602
ret unlink(p);
540603

541604
#[cfg(target_os = "win32")]
542605
fn unlink(p: path) -> bool {
543606
// FIXME: remove imports when export globs work properly.
607+
// (similar to Issue #2006)
544608
import libc::funcs::extra::kernel32::*;
545609
import libc::types::os::arch::extra::*;
546610
import win32::*;
@@ -762,4 +826,42 @@ mod tests {
762826
assert (!os::path_exists("test/nonexistent-bogus-path"));
763827
}
764828

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) > 0u);
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 != 0u);
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, 1u, str::len(s) + 1u, ostream) ==
855+
buf.len())};
856+
assert (libc::fclose(ostream) == (0u 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+
}
765867
}

0 commit comments

Comments
 (0)