Hi Release Team,

There's a special case, I would like to get the newest ntfs-3g
(read/write NTFS driver for FUSE) to Buster.
Upstream is quite cautious with changes and do the following cycle:
development -> new stable release -> advanced bugfix release
(nicknamed as AR).
The latest AR release recently released and is in NEW at the moment
due to minor library bump. This mean it will need a small, tested
transition of partclone, testdisk and wimlib. As it builds an udeb, it
will need an ACK from KiBi as well.

Changelog is the following:
- Fixed reporting an error when failed to build the mountpoint
- Reverted accessing reparse directory through internal plugins
- Cleaned object ids beyond the updated part
- Fixed reacting to missing plugin
- Returned a low level error when an ioctl fails
- Truncated SSD trimming zones to granularity supported by the device

Diff of the code lines (not including noise like the internal version
number incrementation) is attached.

Hope this can be allowed for users to handle their data on NTFS
filesystems more safely.

Thanks for consideration,
Laszlo/GCS
diff -Nru ntfs-3g-2017.3.23AR.3/include/ntfs-3g/compat.h ntfs-3g-2017.3.23AR.4/include/ntfs-3g/compat.h
--- ntfs-3g-2017.3.23AR.3/include/ntfs-3g/compat.h	2017-03-23 09:42:44.000000000 +0000
+++ ntfs-3g-2017.3.23AR.4/include/ntfs-3g/compat.h	2019-03-01 08:10:14.000000000 +0000
@@ -41,6 +42,10 @@
 #define ELIBBAD ENOEXEC
 #endif
 
+#ifndef ELIBACC
+#define ELIBACC ENOENT
+#endif
+
 #ifndef PATH_MAX
 #define PATH_MAX 4096
 #endif
diff -Nru ntfs-3g-2017.3.23AR.3/libfuse-lite/fuse.c ntfs-3g-2017.3.23AR.4/libfuse-lite/fuse.c
--- ntfs-3g-2017.3.23AR.3/libfuse-lite/fuse.c	2018-09-01 06:39:24.000000000 +0000
+++ ntfs-3g-2017.3.23AR.4/libfuse-lite/fuse.c	2019-03-01 08:10:14.000000000 +0000
@@ -2781,8 +2781,10 @@
     fuse_finish_interrupt(f, req, &d);
     free(path);
 
-    fuse_reply_ioctl(req, err, out_buf, out_bufsz);
+    if (err >= 0) { /* not an error */
+        fuse_reply_ioctl(req, err, out_buf, out_bufsz);
 	goto out;
+    }
 err:
     reply_err(req, err);
 out:
diff -Nru ntfs-3g-2017.3.23AR.3/libntfs-3g/inode.c ntfs-3g-2017.3.23AR.4/libntfs-3g/inode.c
--- ntfs-3g-2017.3.23AR.3/libntfs-3g/inode.c	2018-09-01 06:39:23.000000000 +0000
+++ ntfs-3g-2017.3.23AR.4/libntfs-3g/inode.c	2019-03-01 08:10:14.000000000 +0000
@@ -1518,14 +1518,16 @@
 	ntfs_attr_search_ctx *ctx;
 	STANDARD_INFORMATION *std_info;
 	FILE_NAME_ATTR *fn;
-	const u64 *times;
+	u64 times[4];
 	ntfs_time now;
 	int cnt;
 	int ret;
 
 	ret = -1;
 	if ((size >= 8) && !(flags & XATTR_CREATE)) {
-		times = (const u64*)value;
+		/* Copy, to avoid alignment issue encountered on ARM */
+		memcpy(times, value,
+			(size < sizeof(times) ? size : sizeof(times)));
 		now = ntfs_current_time();
 			/* update the standard information attribute */
 		ctx = ntfs_attr_get_search_ctx(ni, NULL);
diff -Nru ntfs-3g-2017.3.23AR.3/libntfs-3g/ioctl.c ntfs-3g-2017.3.23AR.4/libntfs-3g/ioctl.c
--- ntfs-3g-2017.3.23AR.3/libntfs-3g/ioctl.c	2017-03-23 09:42:44.000000000 +0000
+++ ntfs-3g-2017.3.23AR.4/libntfs-3g/ioctl.c	2019-03-01 08:10:14.000000000 +0000
@@ -225,6 +225,24 @@
 	return 0;
 }
 
+static inline LCN align_up(ntfs_volume *vol, LCN lcn, u64 granularity)
+{
+	u64 aligned;
+
+	aligned = (lcn << vol->cluster_size_bits) + granularity - 1;
+	aligned -= aligned % granularity;
+	return (aligned >> vol->cluster_size_bits);
+}
+
+static inline u64 align_down(ntfs_volume *vol, u64 count, u64 granularity)
+{
+	u64 aligned;
+
+	aligned = count << vol->cluster_size_bits;
+	aligned -= aligned % granularity;
+	return (aligned >> vol->cluster_size_bits);
+}
+
 #define FSTRIM_BUFSIZ 4096
 
 /* Trim the filesystem.
@@ -255,11 +273,11 @@
 	 * XXX We could fix these limitations in future.
 	 */
 	if (start != 0 || len != (uint64_t)-1) {
-		ntfs_log_debug("fstrim: setting start or length is not supported\n");
+		ntfs_log_error("fstrim: setting start or length is not supported\n");
 		return -EINVAL;
 	}
 	if (minlen > vol->cluster_size) {
-		ntfs_log_debug("fstrim: minlen > cluster size is not supported\n");
+		ntfs_log_error("fstrim: minlen > cluster size is not supported\n");
 		return -EINVAL;
 	}
 
@@ -269,7 +287,7 @@
 	 * different.
 	 */
 	if (!NDevBlock(vol->dev)) {
-		ntfs_log_debug("fstrim: not supported for non-block-device\n");
+		ntfs_log_error("fstrim: not supported for non-block-device\n");
 		return -EOPNOTSUPP;
 	}
 
@@ -278,15 +296,12 @@
 	if (ret)
 		return ret;
 	if (discard_alignment != 0) {
-		ntfs_log_debug("fstrim: backing device is not aligned for discards\n");
-		return -EOPNOTSUPP;
-	}
-	if (discard_granularity > vol->cluster_size) {
-		ntfs_log_debug("fstrim: discard granularity of backing device is larger than cluster size\n");
+		ntfs_log_error("fstrim: backing device is not aligned for discards\n");
 		return -EOPNOTSUPP;
 	}
+
 	if (discard_max_bytes == 0) {
-		ntfs_log_debug("fstrim: backing device does not support discard (discard_max_bytes == 0)\n");
+		ntfs_log_error("fstrim: backing device does not support discard (discard_max_bytes == 0)\n");
 		return -EOPNOTSUPP;
 	}
 
@@ -323,11 +338,14 @@
 		}
 
 		/* Trim the clusters in large as possible blocks, but
-		 * not larger than discard_max_bytes.
+		 * not larger than discard_max_bytes, and compatible
+		 * with the supported trim granularity.
 		 */
 		for (start_lcn = start_buf; start_lcn < end_buf; ++start_lcn) {
 			if (!ntfs_bit_get(buf, start_lcn-start_buf)) {
 				LCN end_lcn;
+				LCN aligned_lcn;
+				u64 aligned_count;
 
 				/* Cluster 'start_lcn' is not in use,
 				 * find end of this run.
@@ -338,14 +356,25 @@
 					  < discard_max_bytes &&
 					!ntfs_bit_get(buf, end_lcn-start_buf))
 					end_lcn++;
+				aligned_lcn = align_up(vol, start_lcn,
+						discard_granularity);
+				if (aligned_lcn >= end_lcn)
+					aligned_count = 0;
+				else {
+					aligned_count = 
+						align_down(vol,
+							end_lcn - aligned_lcn,
+							discard_granularity);
+				}
+				if (aligned_count) {
+					ret = fstrim_clusters(vol,
+						aligned_lcn, aligned_count);
+					if (ret)
+						goto free_out;
 
-				ret = fstrim_clusters(vol,
-						start_lcn, end_lcn-start_lcn);
-				if (ret)
-					goto free_out;
-
-				*trimmed += (end_lcn - start_lcn)
+					*trimmed += aligned_count
 						<< vol->cluster_size_bits;
+				}
 				start_lcn = end_lcn-1;
 			}
 		}
diff -Nru ntfs-3g-2017.3.23AR.3/libntfs-3g/object_id.c ntfs-3g-2017.3.23AR.4/libntfs-3g/object_id.c
--- ntfs-3g-2017.3.23AR.3/libntfs-3g/object_id.c	2018-09-01 06:39:23.000000000 +0000
+++ ntfs-3g-2017.3.23AR.4/libntfs-3g/object_id.c	2019-03-01 08:10:14.000000000 +0000
@@ -333,7 +333,7 @@
 
 	na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED, 0);
 	if (na) {
-
+		memset(&old_attr, 0, sizeof(OBJECT_ID_ATTR));
 			/* remove the existing index entry */
 		oldsize = remove_object_id_index(na,xo,&old_attr);
 		if (oldsize < 0)
diff -Nru ntfs-3g-2017.3.23AR.3/ntfsprogs/ntfscp.c ntfs-3g-2017.3.23AR.4/ntfsprogs/ntfscp.c
--- ntfs-3g-2017.3.23AR.3/ntfsprogs/ntfscp.c	2018-09-01 06:39:24.000000000 +0000
+++ ntfs-3g-2017.3.23AR.4/ntfsprogs/ntfscp.c	2019-03-01 08:10:14.000000000 +0000
@@ -1153,8 +1153,9 @@
 	ntfs_attr_close(na);
 	if (opts.timestamp) {
 		if (!fstat(fileno(in),&st)) {
-			out->last_data_change_time = st.st_mtime*10000000LL
+			s64 change_time = st.st_mtime*10000000LL
 					+ NTFS_TIME_OFFSET;
+			out->last_data_change_time = cpu_to_le64(change_time);
 			ntfs_inode_update_times(out, 0);
 		} else {
 			ntfs_log_error("Failed to get the time stamp.\n");
diff -Nru ntfs-3g-2017.3.23AR.3/src/lowntfs-3g.c ntfs-3g-2017.3.23AR.4/src/lowntfs-3g.c
--- ntfs-3g-2017.3.23AR.3/src/lowntfs-3g.c	2018-09-01 06:39:23.000000000 +0000
+++ ntfs-3g-2017.3.23AR.4/src/lowntfs-3g.c	2019-03-01 08:10:14.000000000 +0000
@@ -1011,10 +1011,9 @@
 		REPARSE_POINT *reparse;
 
 		res = CALL_REPARSE_PLUGIN(ni, readlink, &buf);
-		if (res) {
+		if (res || !buf) {
 			buf = strdup(ntfs_bad_reparse);
-			if (!buf)
-				res = -errno;
+			res = (buf ? 0 : -errno);
 		}
 #else /* DISABLE_PLUGINS */
 		errno = 0;
@@ -3360,7 +3359,7 @@
 		|| !(ctx->secure_flags & (1 << SECURITY_ACL))
 		|| (setting && ctx->inherit))
 	    && foracl) {
-		if (ctx->silent)
+		if (ctx->silent && !ctx->security.mapping[MAPUSERS])
 			errno = 0;
 		else
 			errno = EOPNOTSUPP;
@@ -4617,7 +4616,8 @@
 	else {
 		ctx->abs_mnt_point = (char*)ntfs_malloc(PATH_MAX);
 		if (ctx->abs_mnt_point) {
-			if (getcwd(ctx->abs_mnt_point,
+			if ((strlen(opts.mnt_point) < PATH_MAX)
+			    && getcwd(ctx->abs_mnt_point,
 				     PATH_MAX - strlen(opts.mnt_point) - 1)) {
 				strcat(ctx->abs_mnt_point, "/");
 				strcat(ctx->abs_mnt_point, opts.mnt_point);
@@ -4625,6 +4625,9 @@
 			/* Solaris also wants the absolute mount point */
 				opts.mnt_point = ctx->abs_mnt_point;
 #endif /* defined(__sun) && defined (__SVR4) */
+			} else {
+				free(ctx->abs_mnt_point);
+				ctx->abs_mnt_point = (char*)NULL;
 			}
 		}
 	}
@@ -4774,7 +4777,6 @@
 
 #ifndef DISABLE_PLUGINS
 	register_internal_reparse_plugins();
-	register_directory_plugins(ctx);
 #endif /* DISABLE_PLUGINS */
 
 	se = mount_fuse(parsed_options);
diff -Nru ntfs-3g-2017.3.23AR.3/src/ntfs-3g.c ntfs-3g-2017.3.23AR.4/src/ntfs-3g.c
--- ntfs-3g-2017.3.23AR.3/src/ntfs-3g.c	2018-09-01 06:39:23.000000000 +0000
+++ ntfs-3g-2017.3.23AR.4/src/ntfs-3g.c	2019-03-01 08:10:14.000000000 +0000
@@ -2879,7 +2879,7 @@
 			|| !(ctx->secure_flags & (1 << SECURITY_ACL))
 			|| (setting && ctx->inherit))
 		    && foracl) {
-			if (ctx->silent)
+			if (ctx->silent && !ctx->security.mapping[MAPUSERS])
 				errno = 0;
 			else
 				errno = EOPNOTSUPP;
@@ -4148,7 +4148,8 @@
 	else {
 		ctx->abs_mnt_point = (char*)ntfs_malloc(PATH_MAX);
 		if (ctx->abs_mnt_point) {
-			if (getcwd(ctx->abs_mnt_point,
+			if ((strlen(opts.mnt_point) < PATH_MAX)
+			    && getcwd(ctx->abs_mnt_point,
 				     PATH_MAX - strlen(opts.mnt_point) - 1)) {
 				strcat(ctx->abs_mnt_point, "/");
 				strcat(ctx->abs_mnt_point, opts.mnt_point);
@@ -4156,6 +4157,9 @@
 			/* Solaris also wants the absolute mount point */
 				opts.mnt_point = ctx->abs_mnt_point;
 #endif /* defined(__sun) && defined (__SVR4) */
+			} else {
+				free(ctx->abs_mnt_point);
+				ctx->abs_mnt_point = (char*)NULL;
 			}
 		}
 	}
@@ -4304,7 +4308,6 @@
 
 #ifndef DISABLE_PLUGINS
 	register_internal_reparse_plugins();
-	register_directory_plugins(ctx);
 #endif /* DISABLE_PLUGINS */
 
 	fh = mount_fuse(parsed_options);
diff -Nru ntfs-3g-2017.3.23AR.3/src/ntfs-3g_common.c ntfs-3g-2017.3.23AR.4/src/ntfs-3g_common.c
--- ntfs-3g-2017.3.23AR.3/src/ntfs-3g_common.c	2018-09-01 06:39:23.000000000 +0000
+++ ntfs-3g-2017.3.23AR.4/src/ntfs-3g_common.c	2019-03-01 08:10:14.000000000 +0000
@@ -36,10 +36,6 @@
 #include <string.h>
 #endif
 
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-
 #ifdef HAVE_LIMITS_H
 #include <limits.h>
 #endif
@@ -770,108 +766,6 @@
 
 #ifndef DISABLE_PLUGINS
 
-/*
- *		Get attribute information for reparse directories
- *
- *	Reparse directories have a reparse tag which should be ignored.
- */
-
-static int directory_getattr(ntfs_inode *ni, const REPARSE_POINT *reparse,
-			      struct stat *stbuf)
-{
-	static ntfschar I30[] =
-		{ const_cpu_to_le16('$'), const_cpu_to_le16('I'),
-		  const_cpu_to_le16('3'), const_cpu_to_le16('0') };
-	ntfs_attr *na;
-	int res;
-
-	res = -EOPNOTSUPP;
-	if (ni && reparse && stbuf
-		&& ((reparse->reparse_tag == IO_REPARSE_TAG_WCI)
-		|| ((reparse->reparse_tag & IO_REPARSE_TAG_DIRECTORY)
-		    && !(reparse->reparse_tag & IO_REPARSE_TAG_IS_ALIAS)))
-	    && (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
-			/* Directory */
-		stbuf->st_mode = S_IFDIR | 0555;
-		/* get index size, if not known */
-		if (!test_nino_flag(ni, KnownSize)) {
-			na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, I30, 4);
-			if (na) {
-				ni->data_size = na->data_size;
-				ni->allocated_size = na->allocated_size;
-				set_nino_flag(ni, KnownSize);
-				ntfs_attr_close(na);
-			}
-		}
-		stbuf->st_size = ni->data_size;
-		stbuf->st_blocks = ni->allocated_size >> 9;
-		stbuf->st_nlink = 1;	/* Make find(1) work */
-		res = 0;
-	}
-	/* Not a directory, or another error occurred */
-	return (res);
-}
-
-/*
- *		Open a reparse directory for reading
- *
- *	Currently no reading context is created.
- */
-
-static int directory_opendir(ntfs_inode *ni, const REPARSE_POINT *reparse,
-			   struct fuse_file_info *fi)
-{
-	int res;
-
-	res = -EOPNOTSUPP;
-	if (ni && reparse && fi
-	    && ((reparse->reparse_tag == IO_REPARSE_TAG_WCI)
-		|| ((reparse->reparse_tag & IO_REPARSE_TAG_DIRECTORY)
-		    && !(reparse->reparse_tag & IO_REPARSE_TAG_IS_ALIAS)))
-	    && (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
-	    && ((fi->flags & O_ACCMODE) == O_RDONLY))
-		res = 0;
-	return (res);
-}
-
-/*
- *		Release a reparse directory
- *
- *	Should never be called, as no reading context was defined.
- */
-
-static int directory_release(ntfs_inode *ni __attribute__((unused)),
-			   const REPARSE_POINT *reparse __attribute__((unused)),
-			   struct fuse_file_info *fi __attribute__((unused)))
-{
-	return 0;
-}
-
-/*
- *		Read an open reparse directory
- *
- *	Returns 0 or a negative error code
- */
-
-static int directory_readdir(ntfs_inode *ni, const REPARSE_POINT *reparse,
-			s64 *pos, void *fillctx, ntfs_filldir_t filldir,
-			struct fuse_file_info *fi __attribute__((unused)))
-{
-	int res;
-
-	res = -EOPNOTSUPP;
-	if (ni && reparse && pos && fillctx && filldir
-	    && ((reparse->reparse_tag == IO_REPARSE_TAG_WCI)
-	        || ((reparse->reparse_tag & IO_REPARSE_TAG_DIRECTORY)
-	    	    && !(reparse->reparse_tag & IO_REPARSE_TAG_IS_ALIAS)))
-	    && (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
-		res = 0;
-		if (ntfs_readdir(ni, pos, fillctx, filldir))
-			res = -errno;
-	}
-	return (res);
-}
-
 int register_reparse_plugin(ntfs_fuse_context_t *ctx, le32 tag,
 				const plugin_operations_t *ops, void *handle)
 {
@@ -879,16 +773,14 @@
 	int res;
 
 	res = -1;
-	if (ctx) {
-		plugin = (plugin_list_t*)ntfs_malloc(sizeof(plugin_list_t));
-		if (plugin) {
-			plugin->tag = tag;
-			plugin->ops = ops;
-			plugin->handle = handle;
-			plugin->next = ctx->plugins;
-			ctx->plugins = plugin;
-			res = 0;
-		}
+	plugin = (plugin_list_t*)ntfs_malloc(sizeof(plugin_list_t));
+	if (plugin) {
+		plugin->tag = tag;
+		plugin->ops = ops;
+		plugin->handle = handle;
+		plugin->next = ctx->plugins;
+		ctx->plugins = plugin;
+		res = 0;
 	}
 	return (res);
 }
@@ -917,9 +809,7 @@
 	reparse = ntfs_get_reparse_point(ni);
 	if (reparse) {
 		tag = reparse->reparse_tag;
-		seltag = tag;
-		if (tag & IO_REPARSE_TAG_DIRECTORY)
-			seltag &= IO_REPARSE_TAG_DIRECTORY;
+		seltag = tag & IO_REPARSE_PLUGIN_SELECT;
 		for (plugin=ctx->plugins; plugin && (plugin->tag != seltag);
 						plugin = plugin->next) { }
 		if (plugin) {
@@ -951,6 +841,7 @@
 				if (!ops)
 					dlclose(handle);
 			} else {
+				errno = ELIBACC;
 				if (!(ctx->errors_logged & ERR_PLUGIN)) {
 					ntfs_log_perror(
 						"Could not load plugin %s",
@@ -981,23 +872,6 @@
 	}
 }
 
-void register_directory_plugins(ntfs_fuse_context_t *ctx)
-{
-	static const struct plugin_operations ops = {
-		.getattr = directory_getattr,
-		.release = directory_release,
-		.opendir = directory_opendir,
-		.readdir = directory_readdir,
-	} ;
-
-	if (ctx) {
-		register_reparse_plugin(ctx, IO_REPARSE_TAG_WCI,
-						&ops, (void*)NULL);
-		register_reparse_plugin(ctx, IO_REPARSE_TAG_DIRECTORY,
-						&ops, (void*)NULL);
-	}
-}
-
 #endif /* DISABLE_PLUGINS */
 
 #ifdef HAVE_SETXATTR
diff -Nru ntfs-3g-2017.3.23AR.3/src/ntfs-3g_common.h ntfs-3g-2017.3.23AR.4/src/ntfs-3g_common.h
--- ntfs-3g-2017.3.23AR.3/src/ntfs-3g_common.h	2018-09-01 06:39:23.000000000 +0000
+++ ntfs-3g-2017.3.23AR.4/src/ntfs-3g_common.h	2019-03-01 08:10:14.000000000 +0000
@@ -211,7 +211,7 @@
 				ntfs_inode *ni, REPARSE_POINT **reparse);
 int register_reparse_plugin(ntfs_fuse_context_t *ctx, le32 tag,
                                 const plugin_operations_t *ops, void *handle);
-void register_directory_plugins(ntfs_fuse_context_t *ctx);
+
 #endif /* DISABLE_PLUGINS */
 
 #endif /* _NTFS_3G_COMMON_H */

Reply via email to