- dtucker@cvs.openbsd.org 2004/06/25 05:38:48
     [sftp-server.c]
     Fall back to stat+rename if filesystem doesn't doesn't support hard
     links.  bz#823, ok djm@
diff --git a/sftp-server.c b/sftp-server.c
index 8349c17..39a6bda 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -14,7 +14,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 #include "includes.h"
-RCSID("$OpenBSD: sftp-server.c,v 1.46 2004/06/21 17:36:31 avsm Exp $");
+RCSID("$OpenBSD: sftp-server.c,v 1.47 2004/06/25 05:38:48 dtucker Exp $");
 
 #include "buffer.h"
 #include "bufaux.h"
@@ -839,9 +839,25 @@
 		status = errno_to_portable(errno);
 	else if (S_ISREG(sb.st_mode)) {
 		/* Race-free rename of regular files */
-		if (link(oldpath, newpath) == -1)
-			status = errno_to_portable(errno);
-		else if (unlink(oldpath) == -1) {
+		if (link(oldpath, newpath) == -1) {
+			if (errno == EOPNOTSUPP) {
+				struct stat st;
+
+				/*
+				 * fs doesn't support links, so fall back to
+				 * stat+rename.  This is racy.
+				 */
+				if (stat(newpath, &st) == -1) {
+					if (rename(oldpath, newpath) == -1)
+						status =
+						    errno_to_portable(errno);
+					else
+						status = SSH2_FX_OK;
+				}
+			} else {
+				status = errno_to_portable(errno);
+			}
+		} else if (unlink(oldpath) == -1) {
 			status = errno_to_portable(errno);
 			/* clean spare link */
 			unlink(newpath);