diff -Nrbu mc-4.6.1a/vfs/fish.c mc-4.6.1a-OK/vfs/fish.c --- mc-4.6.1a/vfs/fish.c 2005-10-19 15:34:57.000000000 +0400 +++ mc-4.6.1a-OK/vfs/fish.c 2006-03-29 15:27:29.000000000 +0400 @@ -509,7 +509,35 @@ close (h); ERRNOR (EIO, -1); } - /* Use this as stor: ( dd block ; dd smallblock ) | ( cat > file; cat > /dev/null ) */ + + /* First, try this as stor: + * + * ( head -c number ) | ( cat > file; cat >/dev/null ) + * + * If `head' is not present on the remote system, `dd' will be used. + * Unfortunately, we cannot trust most non-GNU `head' implementations + * even if `-c' options is supported. Therefore, we separate GNU head + * (and other modern heads?) using `-q' and `-' . This causes another + * implementations to fail (because of "incorrect options"). + * + * Fallback is: + * + * rest=<number> + * while [ $rest -gt 0 ] + * do + * cnt=`expr \( $rest + 255 \) / 256` + * n=`dd bs=256 count=$cnt | tee -a <target_file> | wc -c` + * rest=`expr $rest - $n` + * done + * + * `dd' was not designed for full filling of input buffers, + * and does not report exact number of bytes (not blocks). + * Therefore a more complex shell script is needed. + * + * On some systems non-GNU head writes "Usage:" error report to stdout + * instead of stderr. It makes impossible the use of "head || dd" + * algorithm for file appending case, therefore just "dd" is used for it. + */ print_vfs_message(_("fish: store %s: sending command..."), name ); quoted_name = name_quote (name, 0); @@ -518,26 +546,39 @@ if (!fh->u.fish.append) n = fish_command (me, super, WAIT_REPLY, "#STOR %lu /%s\n" - "> /%s\n" "echo '### 001'\n" + "res=`exec 3>&1\n" "(\n" - "dd bs=1 count=%lu\n" + "head -c %lu -q - || echo DD >&3\n" ") 2>/dev/null | (\n" "cat > /%s\n" "cat > /dev/null\n" - "); echo '### 200'\n", - (unsigned long) s.st_size, name, quoted_name, - (unsigned long) s.st_size, quoted_name); + ")`; [ \"$res\" = DD ] && {\n" + "> /%s\n" + "rest=%lu\n" + "while [ $rest -gt 0 ]\n" + "do\n" + " cnt=`expr \\( $rest + 255 \\) / 256`\n" + " n=`dd bs=256 count=$cnt | tee -a /%s | wc -c`\n" + " rest=`expr $rest - $n`\n" + "done\n" + "}; echo '### 200'\n", + (unsigned long) s.st_size, name, + (unsigned long) s.st_size, quoted_name, + quoted_name, (unsigned long) s.st_size, quoted_name); else n = fish_command (me, super, WAIT_REPLY, "#STOR %lu /%s\n" "echo '### 001'\n" - "(\n" - "dd bs=1 count=%lu\n" - ") 2>/dev/null | (\n" - "cat >> /%s\n" - "cat > /dev/null\n" - "); echo '### 200'\n", + "{\n" + "rest=%lu\n" + "while [ $rest -gt 0 ]\n" + "do\n" + " cnt=`expr \\( $rest + 255 \\) / 256`\n" + " n=`dd bs=256 count=$cnt | tee -a /%s | wc -c`\n" + " rest=`expr $rest - $n`\n" + "done\n" + "}; echo '### 200'\n", (unsigned long) s.st_size, name, (unsigned long) s.st_size, quoted_name);