$NetBSD: patch-sshfs.c,v 1.3 2022/08/24 22:26:33 wiz Exp $

Impedance adjustment with librefuse which used to provide an old API
incompatible with FUSE 3.1. This patch can go away when NetBSD 9
reaches its EOL.

--- sshfs.c.orig	2022-05-26 13:23:35.000000000 +0000
+++ sshfs.c
@@ -980,7 +980,11 @@ static int buf_get_entries(struct buffer
 				    S_ISLNK(stbuf.st_mode)) {
 					stbuf.st_mode = 0;
 				}
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+				filler(dbuf, name, &stbuf, 0);
+#else
 				filler(dbuf, name, &stbuf, 0, 0);
+#endif
 			}
 		}
 		free(name);
@@ -1884,6 +1888,21 @@ static int start_processing_thread(struc
 	return 0;
 }
 
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+static void *sshfs_init(struct fuse_conn_info *conn __attribute__((__unused__)))
+{
+	sshfs.sync_read = 1;
+
+	/* Don't start the processing thread here. This is a
+	 * workaround for a broken op->init() handing: librefuse calls
+	 * it inside fuse_new(), before we start the main
+	 * loop. Already fixed in HEAD. */
+	//if (!sshfs.delay_connect)
+	//	start_processing_thread(&sshfs.conns[0]);
+
+	return NULL;
+}
+#else
 static void *sshfs_init(struct fuse_conn_info *conn,
                         struct fuse_config *cfg)
 {
@@ -1909,6 +1928,7 @@ static void *sshfs_init(struct fuse_conn
 
 	return NULL;
 }
+#endif
 
 static int sftp_request_wait(struct request *req, uint8_t type,
                              uint8_t expect_type, struct buffer *outbuf)
@@ -2069,7 +2089,11 @@ static int sshfs_access(const char *path
 	int err = 0;
 
 	if (mask & X_OK) {
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+		err = sshfs.op->getattr(path, &stbuf);
+#else
 		err = sshfs.op->getattr(path, &stbuf, NULL);
+#endif
 		if (!err) {
 			if (S_ISREG(stbuf.st_mode) &&
 			    !(stbuf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
@@ -2323,11 +2347,15 @@ static int sshfs_opendir(const char *pat
 	return err;
 }
 
-static int sshfs_readdir(const char *path, void *dbuf, fuse_fill_dir_t filler,
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+static int sshfs_readdir(const char *path __attribute__((__unused__)), void *dbuf, fuse_fill_dir_t filler,
+			 off_t offset, struct fuse_file_info *fi)
+#else
+static int sshfs_readdir(const char *path __attribute__((__unused__)), void *dbuf, fuse_fill_dir_t filler,
 			 off_t offset, struct fuse_file_info *fi,
-			 enum fuse_readdir_flags flags)
+			 enum fuse_readdir_flags flags __attribute__((__unused__)))
+#endif
 {
-	(void) path; (void) flags;
 	int err;
 	struct dir_handle *handle;
 
@@ -2491,13 +2519,19 @@ static void random_string(char *str, int
 	*str = '\0';
 }
 
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+static int sshfs_rename(const char *from, const char *to)
+#else
 static int sshfs_rename(const char *from, const char *to, unsigned int flags)
+#endif
 {
 	int err;
 	struct conntab_entry *ce;
 
+#if !defined(__NetBSD__) || FUSE_H_ >= 20211204
 	if(flags != 0)
 		return -EINVAL;
+#endif
 
 	if (sshfs.ext_posix_rename)
 		err = sshfs_ext_posix_rename(from, to);
@@ -2572,19 +2606,24 @@ static inline struct sshfs_file *get_ssh
 	return (struct sshfs_file *) (uintptr_t) fi->fh;
 }
 
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+static int sshfs_chmod(const char *path, mode_t mode)
+#else
 static int sshfs_chmod(const char *path, mode_t mode,
                        struct fuse_file_info *fi)
+#endif
 {
-	(void) fi;
 	int err;
 	struct buffer buf;
 	struct sshfs_file *sf = NULL;
 
+#if !defined(__NetBSD__) || FUSE_H_ >= 20211204
 	if (fi != NULL) {
 		sf = get_sshfs_file(fi);
 		if (!sshfs_file_is_conn(sf))
 			return -EIO;
 	}
+#endif
 
 	buf_init(&buf, 0);
 	if (sf == NULL)
@@ -2605,19 +2644,24 @@ static int sshfs_chmod(const char *path,
 	return err;
 }
 
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+static int sshfs_chown(const char *path, uid_t uid, gid_t gid)
+#else
 static int sshfs_chown(const char *path, uid_t uid, gid_t gid,
                        struct fuse_file_info *fi)
+#endif
 {
-	(void) fi;
 	int err;
 	struct buffer buf;
 	struct sshfs_file *sf = NULL;
 
+#if !defined(__NetBSD__) || FUSE_H_ >= 20211204
 	if (fi != NULL) {
 		sf = get_sshfs_file(fi);
 		if (!sshfs_file_is_conn(sf))
 			return -EIO;
 	}
+#endif
 
 	if (sshfs.remote_uid_detected) {
 		if (uid == sshfs.local_uid)
@@ -2650,8 +2694,12 @@ static int sshfs_chown(const char *path,
 	return err;
 }
 
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+static int sshfs_truncate_workaround(const char *path, off_t size);
+#else
 static int sshfs_truncate_workaround(const char *path, off_t size,
                                      struct fuse_file_info *fi);
+#endif
 
 static void sshfs_inc_modifver(void)
 {
@@ -2660,10 +2708,13 @@ static void sshfs_inc_modifver(void)
 	pthread_mutex_unlock(&sshfs.lock);
 }
 
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+static int sshfs_utimens(const char *path, const struct timespec tv[2])
+#else
 static int sshfs_utimens(const char *path, const struct timespec tv[2],
 			 struct fuse_file_info *fi)
+#endif
 {
-	(void) fi;
 	int err;
 	struct buffer buf;
 	struct sshfs_file *sf = NULL;
@@ -2676,11 +2727,13 @@ static int sshfs_utimens(const char *pat
 	if (msec == 0)
 		msec = now.tv_sec;
 
+#if !defined(__NetBSD__) || FUSE_H_ >= 20211204
 	if (fi != NULL) {
 		sf = get_sshfs_file(fi);
 		if (!sshfs_file_is_conn(sf))
 			return -EIO;
 	}
+#endif
 
 	buf_init(&buf, 0);
 	if (sf == NULL)
@@ -3338,22 +3391,32 @@ static int sshfs_create(const char *path
 	return sshfs_open_common(path, mode, fi);
 }
 
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+static int sshfs_truncate(const char *path, off_t size)
+#else
 static int sshfs_truncate(const char *path, off_t size,
 			  struct fuse_file_info *fi)
+#endif
 {
 	int err;
 	struct buffer buf;
 	struct sshfs_file *sf = NULL;
 
+#if !defined(__NetBSD__) || FUSE_H_ >= 20211204
 	if (fi != NULL) {
 		sf = get_sshfs_file(fi);
 		if (!sshfs_file_is_conn(sf))
 			return -EIO;
 	}
+#endif
 
 	sshfs_inc_modifver();
 	if (sshfs.truncate_workaround)
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+		return sshfs_truncate_workaround(path, size);
+#else
 		return sshfs_truncate_workaround(path, size, fi);
+#endif
 
 	buf_init(&buf, 0);
 
@@ -3372,19 +3435,37 @@ static int sshfs_truncate(const char *pa
 	return err;
 }
 
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+/* Workaround for an issue in the past versions of
+ * librefuse. fuse_mount() used to call fuse_operations::getattr()
+ * before we were ready for that. */
+static int sshfs_initialized = 0;
+#endif
+
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+static int sshfs_getattr(const char *path, struct stat *stbuf)
+#else
 static int sshfs_getattr(const char *path, struct stat *stbuf,
 			 struct fuse_file_info *fi)
+#endif
 {
 	int err;
 	struct buffer buf;
 	struct buffer outbuf;
 	struct sshfs_file *sf = NULL;
 
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+	if (!sshfs_initialized)
+		return -EIO;
+#endif
+
+#if !defined(__NetBSD__) || FUSE_H_ >= 20211204
 	if (fi != NULL && !sshfs.fstat_workaround) {
 		sf = get_sshfs_file(fi);
 		if (!sshfs_file_is_conn(sf))
 			return -EIO;
 	}
+#endif
 
 	buf_init(&buf, 0);
 	if(sf == NULL) {
@@ -3508,15 +3589,23 @@ static int sshfs_truncate_extend(const c
  * If new size is greater than current size, then write a zero byte to
  * the new end of the file.
  */
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+static int sshfs_truncate_workaround(const char *path, off_t size)
+#else
 static int sshfs_truncate_workaround(const char *path, off_t size,
                                      struct fuse_file_info *fi)
+#endif
 {
 	if (size == 0)
 		return sshfs_truncate_zero(path);
 	else {
 		struct stat stbuf;
 		int err;
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+		err = sshfs_getattr(path, &stbuf);
+#else
 		err = sshfs_getattr(path, &stbuf, fi);
+#endif
 		if (err)
 			return err;
 		if (stbuf.st_size == size)
@@ -3524,7 +3613,11 @@ static int sshfs_truncate_workaround(con
 		else if (stbuf.st_size > size)
 			return sshfs_truncate_shrink(path, size);
 		else
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+			return sshfs_truncate_extend(path, size, NULL);
+#else
 			return sshfs_truncate_extend(path, size, fi);
+#endif
 	}
 }
 
@@ -4156,7 +4249,9 @@ int main(int argc, char *argv[])
 	char *fsname;
 	const char *sftp_server;
 	struct fuse *fuse;
+#if !defined(__NetBSD__) || FUSE_H_ >= 20211204
 	struct fuse_session *se;
+#endif
 	int i;
 
 #ifdef __APPLE__
@@ -4216,7 +4311,11 @@ int main(int argc, char *argv[])
 
 	if (sshfs.show_version) {
 		printf("SSHFS version %s\n", PACKAGE_VERSION);
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+		printf("FUSE library version %d\n", fuse_version());
+#else
 		printf("FUSE library version %s\n", fuse_pkgversion());
+#endif
 #if !defined(__CYGWIN__)
 		fuse_lowlevel_version();
 #endif
@@ -4225,7 +4324,11 @@ int main(int argc, char *argv[])
 
 	if (sshfs.show_help) {
 		usage(args.argv[0]);
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+		fuse_cmdline_help();
+#else
 		fuse_lib_help(&args);
+#endif
 		exit(0);
 	} else if (!sshfs.host) {
 		fprintf(stderr, "missing host\n");
@@ -4359,20 +4462,16 @@ int main(int argc, char *argv[])
 			sizeof(struct fuse_operations), NULL);
 	if(fuse == NULL)
 		exit(1);
+#if !defined(__NetBSD__) || FUSE_H_ >= 20211204
 	se = fuse_get_session(fuse);
 	res = fuse_set_signal_handlers(se);
 	if (res != 0) {
 		fuse_destroy(fuse);
 		exit(1);
 	}
+#endif
 
-	res = fuse_mount(fuse, sshfs.mountpoint);
-	if (res != 0) {
-		fuse_destroy(fuse);
-		exit(1);
-	}
-
-#if !defined(__CYGWIN__)
+#if !defined(__CYGWIN__) && (!defined(__NetBSD__) || FUSE_H_ >= 20211204)
 	res = fcntl(fuse_session_fd(se), F_SETFD, FD_CLOEXEC);
 	if (res == -1)
 		perror("WARNING: failed to set FD_CLOEXEC on fuse device");
@@ -4384,29 +4483,58 @@ int main(int argc, char *argv[])
 	 */
 	res = ssh_connect();
 	if (res == -1) {
-		fuse_unmount(fuse);
 		fuse_destroy(fuse);
 		exit(1);
 	}
 
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+	if (!sshfs.foreground)
+		res = fuse_daemonize(fuse);
+#else
 	res = fuse_daemonize(sshfs.foreground);
+#endif
 	if (res == -1) {
-		fuse_unmount(fuse);
 		fuse_destroy(fuse);
 		exit(1);
 	}
 
+	/* NetBSD librefuse (actually libpuffs) used to require that user
+	 * code calls fuse_daemonize() before calling fuse_mount(),
+	 * otherwise the daemonizing parent process would deadlock. FUSE
+	 * on the other hand defines no specific order of calling these
+	 * two functions. pho@ thought puffs_daemon() waiting for the
+	 * completion of fuse_mount() was actually helpful and not a bug
+	 * to be fixed, but it should at least not deadlock. That is,
+	 * fuse_daemonize() should immediately kill the parent if the
+	 * filesystem is already mounted. The change has already been made
+	 * in HEAD. */
+	res = fuse_mount(fuse, sshfs.mountpoint);
+	if (res != 0) {
+		fuse_destroy(fuse);
+		exit(1);
+	}
+
+#if defined(__NetBSD__) && FUSE_H_ < 20211204
+	sshfs_initialized = 1;
+#endif
+
+#if !defined(__NetBSD__) || FUSE_H_ >= 20211204
 	if (sshfs.singlethread)
 		res = fuse_loop(fuse);
 	else
 		res = fuse_loop_mt(fuse, 0);
+#else
+	res = fuse_loop(fuse);
+#endif
 
 	if (res != 0)
 		res = 1;
 	else
 		res = 0;
 
+#if !defined(__NetBSD__) || FUSE_H_ >= 20211204
 	fuse_remove_signal_handlers(se);
+#endif
 	fuse_unmount(fuse);
 	fuse_destroy(fuse);
 
