From 3eed6718b002ac435fda03c6e06897b69983f603 Mon Sep 17 00:00:00 2001
From: Konstantin Knizhnik <knizhnik@garret.ru>
Date: Mon, 1 Jul 2019 22:35:10 +0300
Subject: [PATCH] Add fio_dsconnect function

---
 src/utils/file.c | 40 +++++++++++++++++++++++++++++++++++-----
 src/utils/file.h |  1 +
 2 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/src/utils/file.c b/src/utils/file.c
index 71a62713..74f60375 100644
--- a/src/utils/file.c
+++ b/src/utils/file.c
@@ -333,6 +333,20 @@ int fio_open(char const* path, int mode, fio_location location)
 	return fd;
 }
 
+
+/* Close ssh session */
+void
+fio_disconnect(void)
+{
+	if (fio_stdin)
+	{
+		SYS_CHECK(close(fio_stdin));
+		SYS_CHECK(close(fio_stdout));
+		fio_stdin = 0;
+		fio_stdout = 0;
+	}
+}
+
 /* Open stdio file */
 FILE* fio_fopen(char const* path, char const* mode, fio_location location)
 {
@@ -340,14 +354,30 @@ FILE* fio_fopen(char const* path, char const* mode, fio_location location)
 
 	if (fio_is_remote(location))
 	{
-		int flags = O_RDWR|O_CREAT;
+		int flags = 0;
 		int fd;
 		if (strcmp(mode, PG_BINARY_W) == 0) {
-			flags |= O_TRUNC|PG_BINARY;
-		} else if (strncmp(mode, PG_BINARY_R, strlen(PG_BINARY_R)) == 0) {
-			flags |= PG_BINARY;
+			flags = O_TRUNC|PG_BINARY|O_RDWR|O_CREAT;
+		} else if (strcmp(mode, "w") == 0) {
+			flags = O_TRUNC|O_RDWR|O_CREAT;
+		} else if (strcmp(mode, PG_BINARY_R) == 0) {
+			flags = O_RDONLY|PG_BINARY;
+		} else if (strcmp(mode, "r") == 0) {
+			flags = O_RDONLY;
+		} else if (strcmp(mode, PG_BINARY_R "+") == 0) {
+			/* stdio fopen("rb+") actually doesn't create unexisted file, but probackup frequently
+			 * needs to open existed file or create new one if not exists.
+			 * In stdio it can be done using two fopen calls: fopen("r+") and if failed then fopen("w").
+			 * But to eliminate extra call which especially critical in case of remote connection
+			 * we change r+ semantic to create file if not exists.
+			 */
+			flags = O_RDWR|O_CREAT|PG_BINARY;
+		} else if (strcmp(mode, "r+") == 0) { /* see comment above */
+			flags |= O_RDWR|O_CREAT;
 		} else if (strcmp(mode, "a") == 0) {
-			flags |= O_APPEND;
+			flags |= O_CREAT|O_RDWR|O_APPEND;
+		} else {
+			Assert(false);
 		}
 		fd = fio_open(path, flags, location);
 		if (fd >= 0)
diff --git a/src/utils/file.h b/src/utils/file.h
index f168d6cb..bb610101 100644
--- a/src/utils/file.h
+++ b/src/utils/file.h
@@ -90,6 +90,7 @@ extern int     fio_seek(int fd, off_t offs);
 extern int     fio_fstat(int fd, struct stat* st);
 extern int     fio_truncate(int fd, off_t size);
 extern int     fio_close(int fd);
+extern void    fio_disconnect(void);
 
 extern int     fio_rename(char const* old_path, char const* new_path, fio_location location);
 extern int     fio_symlink(char const* target, char const* link_path, fio_location location);