diff options
author | Andy Chu <andychu@google.com> | 2016-03-19 00:34:42 -0700 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2016-03-30 03:11:55 -0500 |
commit | 7a0186cc2abf6ef9af3f26416dba7e920d100b42 (patch) | |
tree | ab6df6eff64ef7952bf985f2e83bda7f58aa3a95 | |
parent | 9fcaca8434ece1afcc9982c18a86cf12ac9af508 (diff) | |
download | toybox-7a0186cc2abf6ef9af3f26416dba7e920d100b42.tar.gz |
Implement mv -n / cp -n (no clobber).
This fixes a failing test case in mv.test.
Test changes:
- Add coverage for -i (interactive).
- Better descriptions, better formatting, and removed some redundant
cases.
-rwxr-xr-x | tests/mv.test | 133 | ||||
-rw-r--r-- | toys/posix/cp.c | 17 |
2 files changed, 99 insertions, 51 deletions
diff --git a/tests/mv.test b/tests/mv.test index ab2ca5ed..b699d017 100755 --- a/tests/mv.test +++ b/tests/mv.test @@ -8,98 +8,145 @@ #testing "name" "command" "result" "infile" "stdin" touch file -testing "old_file to new_file" "mv file file1 && [ ! -e file -a -f file1 ] && - echo 'yes'" "yes\n" "" "" +testing "file to file" \ + "mv file file1 && [ ! -e file -a -f file1 ] && echo yes" \ + "yes\n" "" "" rm -f file* touch file mkdir dir -testing "file to a dir" "mv file dir && [ ! -e file -a -f dir/file ] && - echo 'yes'" "yes\n" "" "" +testing "file to dir" \ + "mv file dir && [ ! -e file -a -f dir/file ] && echo yes" \ + "yes\n" "" "" rm -rf file* dir* mkdir dir -testing "old_dir to new_dir" "mv dir dir1 && [ ! -e dir -a -d dir1 ] && - echo 'yes'" "yes\n" "" "" +testing "dir to dir" \ + "mv dir dir1 && [ ! -e dir -a -d dir1 ] && echo yes" \ + "yes\n" "" "" rm -rf dir* mkdir dir1 dir2 touch file1 file2 dir1/file3 ln -s file1 link1 -testing "multiple files/dir to a dir" "mv file1 file2 link1 dir1 dir2 && - [ ! -e file1 -a ! -e file2 -a ! -e link1 -a ! -e dir1 ] && - [ -f dir2/file1 -a -f dir2/file2 -a -L dir2/link1 -a -d dir2/dir1 ] && - [ -f dir2/dir1/file3 ] && readlink dir2/link1" "file1\n" "" "" +testing "multiple files/dirs to a dir" \ + "mv file1 file2 link1 dir1 dir2 && + [ ! -e file1 -a ! -e file2 -a ! -e link1 -a ! -e dir1 ] && + [ -f dir2/file1 -a -f dir2/file2 -a -L dir2/link1 -a -d dir2/dir1 ] && + [ -f dir2/dir1/file3 ] && readlink dir2/link1" \ + "file1\n" "" "" rm -rf file* link* dir* -touch file1 -testing "a empty file to new_file" "mv file1 file2 && - [ ! -e file1 -a -f file2 ] && stat -c %s file2" "0\n" "" "" -rm -rf file* - -mkdir dir1 -testing "enpty dir to new_dir" "mv dir1 dir2 && - [ ! -d dir1 -a -d dir2 ] && echo 'yes'" "yes\n" "" "" -rm -rf dir* - dd if=/dev/zero of=file1 seek=10k count=1 >/dev/null 2>&1 -testing "file new_file (random file)" "mv file1 file2 && - [ ! -e file1 -a -f file2 ] && stat -c %s file2" "5243392\n" "" "" +testing "random file to new file" \ + "mv file1 file2 && [ ! -e file1 -a -f file2 ] && stat -c %s file2" \ + "5243392\n" "" "" rm -f file* touch file1 ln -s file1 link1 -testing "link new_link (softlink)" "mv link1 link2 && - [ ! -e link1 -a -L link2 ] && readlink link2" "file1\n" "" "" +testing "symlink to new symlink" \ + "mv link1 link2 && [ ! -e link1 -a -L link2 ] && readlink link2" \ + "file1\n" "" "" unlink tLink2 &>/dev/null rm -f file* link* touch file1 ln file1 link1 -testing "link new_link (hardlink)" "mv link1 link2 && - [ ! -e link1 -a -f link2 -a file1 -ef link2 ] && echo 'yes'" "yes\n" "" "" +testing "hard link to new hardlink" \ + "mv link1 link2 && [ ! -e link1 -a -f link2 -a file1 -ef link2 ] && echo yes" \ + "yes\n" "" "" unlink link2 &>/dev/null rm -f file* link* touch file1 chmod a-r file1 -testing "file new_file (unreadable)" "mv file1 file2 && - [ ! -e file1 -a -f file2 ] && echo 'yes'" "yes\n" "" "" +testing "file to unreadable file" \ + "mv file1 file2 && [ ! -e file1 -a -f file2 ] && echo yes" \ + "yes\n" "" "" rm -f file* touch file1 ln file1 link1 mkdir dir1 -testing "file link dir (hardlink)" "mv file1 link1 dir1 && - [ ! -e file1 -a ! -e link1 -a -f dir1/file1 -a -f dir1/link1 ] && - [ dir1/file1 -ef dir1/link1 ] && echo 'yes'" "yes\n" "" "" +testing "file hardlink dir" \ + "mv file1 link1 dir1 && + [ ! -e file1 -a ! -e link1 -a -f dir1/file1 -a -f dir1/link1 ] && + [ dir1/file1 -ef dir1/link1 ] && echo yes" \ + "yes\n" "" "" rm -rf file* link* dir* mkdir -p dir1/dir2 dir3 touch dir1/dir2/file1 dir1/dir2/file2 -testing "dir1/dir2 dir3/new_dir" "mv dir1/dir2 dir3/dir4 && - [ ! -e dir1/dir2 -a -d dir3/dir4 -a -f dir3/dir4/file1 ] && - [ -f dir3/dir4/file2 ] && echo 'yes'" "yes\n" "" "" +testing "dir to new dir" \ + "mv dir1/dir2 dir3/new && + [ ! -e dir1/dir2 -a -d dir3/new -a -f dir3/new/file1 ] && + [ -f dir3/new/file2 ] && echo yes" \ + "yes\n" "" "" rm -rf file* dir* mkdir dir1 dir2 -testing "dir new_dir (already exist)" "mv dir1 dir2 && - [ ! -e dir1 -a -d dir2/dir1 ] && echo 'yes'" "yes\n" "" "" +testing "dir to existing dir" \ + "mv dir1 dir2 && [ ! -e dir1 -a -d dir2/dir1 ] && echo yes" \ + "yes\n" "" "" rm -rf dir* touch file1 file2 -testing "-f file new_file (exist)" "mv -f file1 file2 && - [ ! -e file1 -a -e file2 ] && echo 'yes'" "yes\n" "" "" +chmod 400 file1 file2 +testing "force over unwritable" \ + "mv -f file1 file2 && [ ! -e file1 -a -e file2 ] && echo yes" \ + "yes\n" "" "" +rm -f file* + +touch file1 file2 +testing "no clobber (dest exists)" \ + "mv -n file1 file2 && [ -e file1 -a -e file2 ] && echo yes"\ + "yes\n" "" "" +rm -f file* + +touch file1 +testing "no clobber (dest doesn't exist)" \ + "mv -n file1 new-dest && [ ! -e file1 -a -e new-dest ] && echo yes"\ + "yes\n" "" "" +rm -f file* + +# If there is stdin, it prompts. If no stdin, it moves anyway and file2 won't +# exist. +touch file1 file2 +chmod 400 file1 file2 +testing "mv over unwritable file: no stdin" \ + "mv file2 file1 && [ -e file1 -a ! -e file2 ] && echo yes" \ + "yes\n" "" "" rm -f file* touch file1 file2 -testing "-n file new_file (exist)" "mv -n file1 file2 && - [ -e file1 -a -e file2 ] && echo 'yes'" "yes\n" "" "" +chmod 400 file1 file2 +testing "mv over unwritable file: answered YES" \ + "mv file2 file1 && [ -e file1 -a ! -e file2 ] && echo yes" \ + "yes\n" "" "y\n" rm -f file* touch file1 file2 chmod 400 file1 file2 -testing "file over unwritable file with no stdin" \ - "</dev/null mv file2 file1 && [ -e file -a ! -e file2 ] && echo 'yes'" \ - "yes\n" "" "" +testing "mv over unwritable file: answered NO" \ + "mv file2 file1 && [ -e file1 -a -e file2 ] && echo yes" \ + "yes\n" "" "n\n" +rm -f file* + +touch file1 file2 +testing "interactive: no stdin" \ + "mv -i file2 file1 && [ -e file1 -a ! -e file2 ] && echo yes" \ + "yes\n" "" "" +rm -f file* + +touch file1 file2 +testing "interactive: answered YES" \ + "mv -i file2 file1 && [ -e file1 -a ! -e file2 ] && echo yes" \ + "yes\n" "" "y\n" +rm -f file* + +touch file1 file2 +testing "interactive: answered NO" \ + "mv -i file2 file1 && [ -e file1 -a -e file2 ] && echo yes" \ + "yes\n" "" "n\n" rm -f file* diff --git a/toys/posix/cp.c b/toys/posix/cp.c index d822b1e2..8bcb81e6 100644 --- a/toys/posix/cp.c +++ b/toys/posix/cp.c @@ -395,20 +395,21 @@ void cp_main(void) errno = EXDEV; if (CFG_MV && toys.which->name[0] == 'm') { - if (!(toys.optflags & FLAG_f)) { + int force = toys.optflags & FLAG_f, no_clobber = toys.optflags & FLAG_n; + if (!force || no_clobber) { struct stat st; - - // Technically "is writeable" is more complicated (022 is not writeable - // by the owner, just everybody _else_) but I don't care. - if (!stat(TT.destname, &st) - && ((toys.optflags & FLAG_i) || !(st.st_mode & 0222))) - { + int exists = !stat(TT.destname, &st); + // Prompt if -i or file isn't writable. Technically "is writable" is + // more complicated (022 is not writeable by the owner, just everybody + // _else_) but I don't care. + if (exists && ((toys.optflags & FLAG_i) || !(st.st_mode & 0222))) { fprintf(stderr, "%s: overwrite '%s'", toys.which->name, TT.destname); if (!yesno(1)) rc = 0; else unlink(TT.destname); } + // if -n and dest exists, don't try to rename() or copy + if (exists && no_clobber) rc = 0; } - if (rc) rc = rename(src, TT.destname); } |