summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin H. Johnson <robbat2@gentoo.org>2015-08-08 13:49:04 -0700
committerRobin H. Johnson <robbat2@gentoo.org>2015-08-08 17:38:18 -0700
commit56bd759df1d0c750a065b8c845e93d5dfa6b549d (patch)
tree3f91093cdb475e565ae857f1c5a7fd339e2d781e /sys-fs/ntfs3g/files
downloadgentoo-56bd759df1d0c750a065b8c845e93d5dfa6b549d.tar.gz
gentoo-56bd759df1d0c750a065b8c845e93d5dfa6b549d.tar.bz2
gentoo-56bd759df1d0c750a065b8c845e93d5dfa6b549d.zip
proj/gentoo: Initial commit
This commit represents a new era for Gentoo: Storing the gentoo-x86 tree in Git, as converted from CVS. This commit is the start of the NEW history. Any historical data is intended to be grafted onto this point. Creation process: 1. Take final CVS checkout snapshot 2. Remove ALL ChangeLog* files 3. Transform all Manifests to thin 4. Remove empty Manifests 5. Convert all stale $Header$/$Id$ CVS keywords to non-expanded Git $Id$ 5.1. Do not touch files with -kb/-ko keyword flags. Signed-off-by: Robin H. Johnson <robbat2@gentoo.org> X-Thanks: Alec Warner <antarus@gentoo.org> - did the GSoC 2006 migration tests X-Thanks: Robin H. Johnson <robbat2@gentoo.org> - infra guy, herding this project X-Thanks: Nguyen Thai Ngoc Duy <pclouds@gentoo.org> - Former Gentoo developer, wrote Git features for the migration X-Thanks: Brian Harring <ferringb@gentoo.org> - wrote much python to improve cvs2svn X-Thanks: Rich Freeman <rich0@gentoo.org> - validation scripts X-Thanks: Patrick Lauer <patrick@gentoo.org> - Gentoo dev, running new 2014 work in migration X-Thanks: Michał Górny <mgorny@gentoo.org> - scripts, QA, nagging X-Thanks: All of other Gentoo developers - many ideas and lots of paint on the bikeshed
Diffstat (limited to 'sys-fs/ntfs3g/files')
-rw-r--r--sys-fs/ntfs3g/files/99-ntfs3g.rules1
-rw-r--r--sys-fs/ntfs3g/files/ntfs3g-2014.2.15-dont-put-things-in-root.patch39
-rw-r--r--sys-fs/ntfs3g/files/ntfs3g-2014.2.15-fix-fstrim-applied-to-partitons.patch217
-rw-r--r--sys-fs/ntfs3g/files/ntfs3g-2014.2.15-implement-fstrim.patch648
-rw-r--r--sys-fs/ntfs3g/files/ntfs3g-2014.2.15-no-split-usr.patch25
-rw-r--r--sys-fs/ntfs3g/files/ntfs3g-2014.2.15-update-fuse-lite-to-support-ioctls.patch610
-rw-r--r--sys-fs/ntfs3g/files/ntfs3g-2015.3.14-dont-put-things-in-root.patch30
7 files changed, 1570 insertions, 0 deletions
diff --git a/sys-fs/ntfs3g/files/99-ntfs3g.rules b/sys-fs/ntfs3g/files/99-ntfs3g.rules
new file mode 100644
index 000000000000..52dca4064766
--- /dev/null
+++ b/sys-fs/ntfs3g/files/99-ntfs3g.rules
@@ -0,0 +1 @@
+ENV{ID_FS_TYPE}=="ntfs", ENV{ID_FS_TYPE}="ntfs-3g"
diff --git a/sys-fs/ntfs3g/files/ntfs3g-2014.2.15-dont-put-things-in-root.patch b/sys-fs/ntfs3g/files/ntfs3g-2014.2.15-dont-put-things-in-root.patch
new file mode 100644
index 000000000000..2444793480b5
--- /dev/null
+++ b/sys-fs/ntfs3g/files/ntfs3g-2014.2.15-dont-put-things-in-root.patch
@@ -0,0 +1,39 @@
+diff -ur ntfs-3g_ntfsprogs-2014.2.15.orig/ntfsprogs/Makefile.am ntfs-3g_ntfsprogs-2014.2.15/ntfsprogs/Makefile.am
+--- ntfs-3g_ntfsprogs-2014.2.15.orig/ntfsprogs/Makefile.am 2015-01-29 00:12:51.786936314 -0800
++++ ntfs-3g_ntfsprogs-2014.2.15/ntfsprogs/Makefile.am 2015-01-29 00:13:59.156442369 -0800
+@@ -140,8 +140,8 @@
+ # mkfs.ntfs[.8] hard link
+
+ install-exec-hook:
+- $(INSTALL) -d $(DESTDIR)/sbin
+- $(LN_S) -f $(sbindir)/mkntfs $(DESTDIR)/sbin/mkfs.ntfs
++ $(INSTALL) -d $(DESTDIR)/$(sbindir)
++ $(LN_S) -f mkntfs $(DESTDIR)/$(sbindir)/mkfs.ntfs
+
+ install-data-hook:
+ $(INSTALL) -d $(DESTDIR)$(man8dir)
+diff -ur ntfs-3g_ntfsprogs-2014.2.15.orig/src/Makefile.am ntfs-3g_ntfsprogs-2014.2.15/src/Makefile.am
+--- ntfs-3g_ntfsprogs-2014.2.15.orig/src/Makefile.am 2015-01-29 00:12:51.789936248 -0800
++++ ntfs-3g_ntfsprogs-2014.2.15/src/Makefile.am 2015-01-29 00:14:00.570411008 -0800
+@@ -68,9 +68,9 @@
+
+ if ENABLE_MOUNT_HELPER
+ install-exec-local: install-rootbinPROGRAMS
+- $(MKDIR_P) "$(DESTDIR)/sbin"
+- $(LN_S) -f "$(rootbindir)/ntfs-3g" "$(DESTDIR)/sbin/mount.ntfs-3g"
+- $(LN_S) -f "$(rootbindir)/lowntfs-3g" "$(DESTDIR)/sbin/mount.lowntfs-3g"
++ $(MKDIR_P) "$(DESTDIR)/$(sbindir)"
++ $(LN_S) -f "../bin/ntfs-3g" "$(DESTDIR)/$(sbindir)/mount.ntfs-3g"
++ $(LN_S) -f "../bin/lowntfs-3g" "$(DESTDIR)/$(sbindir)/mount.lowntfs-3g"
+ endif
+
+ install-data-local: install-man8
+@@ -80,7 +79,7 @@
+ uninstall-local:
+ $(RM) -f "$(DESTDIR)$(man8dir)/mount.ntfs-3g.8"
+ if ENABLE_MOUNT_HELPER
+- $(RM) -f "$(DESTDIR)/sbin/mount.ntfs-3g" "$(DESTDIR)/sbin/mount.lowntfs-3g"
++ $(RM) -f "$(DESTDIR)/$(sbindir)/mount.ntfs-3g" "$(DESTDIR)/$(sbindir)/mount.lowntfs-3g"
+ endif
+
+ endif # ENABLE_NTFS_3G
diff --git a/sys-fs/ntfs3g/files/ntfs3g-2014.2.15-fix-fstrim-applied-to-partitons.patch b/sys-fs/ntfs3g/files/ntfs3g-2014.2.15-fix-fstrim-applied-to-partitons.patch
new file mode 100644
index 000000000000..b67cb712ad51
--- /dev/null
+++ b/sys-fs/ntfs3g/files/ntfs3g-2014.2.15-fix-fstrim-applied-to-partitons.patch
@@ -0,0 +1,217 @@
+From c26a519da1ed182e7cfd67e7a353932dda53d811 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= <jpandre@users.sourceforge.net>
+Date: Mon, 4 Aug 2014 17:39:50 +0200
+Subject: [PATCH] Fixed fstrim(8) applied to partitions
+
+The new way goes via /sys/dev/block/MAJOR:MINOR to map partitions to
+devices and get discard parameters of the parent device. It also ensures
+that the partition is aligned to the discard block size.
+
+Contributed by Richard W.M. Jones
+---
+ libntfs-3g/ioctl.c | 140 ++++++++++++++++++++++++++---------------------------
+ 1 file changed, 68 insertions(+), 72 deletions(-)
+
+diff --git a/libntfs-3g/ioctl.c b/libntfs-3g/ioctl.c
+index bbbceb9..eb7c8e7 100644
+--- a/libntfs-3g/ioctl.c
++++ b/libntfs-3g/ioctl.c
+@@ -66,8 +66,6 @@
+ #include <linux/fs.h>
+ #endif
+
+-#include <dirent.h>
+-
+ #include "compat.h"
+ #include "debug.h"
+ #include "bitmap.h"
+@@ -135,17 +133,14 @@ static int read_u64(const char *path, u64 *n)
+ }
+
+ /* Find discard limits for current backing device.
+- * XXX Kernel makes this a pain in the neck.
+ */
+-static int fstrim_limits(ntfs_volume *vol, u64 *discard_granularity,
++static int fstrim_limits(ntfs_volume *vol,
++ u64 *discard_alignment,
++ u64 *discard_granularity,
+ u64 *discard_max_bytes)
+ {
+ struct stat statbuf;
+- DIR *dir;
+- struct dirent *d;
+- char path[80];
+- char line[64];
+- char dev[64];
++ char path1[80], path2[80];
+ int ret;
+
+ /* Stat the backing device. Caller has ensured it is a block device. */
+@@ -155,82 +150,78 @@ static int fstrim_limits(ntfs_volume *vol, u64 *discard_granularity,
+ return -errno;
+ }
+
+- /* Now look for a /sys/block/<dev>/dev file which contains
+- * "major:minor\n".
++ /* For whole devices,
++ * /sys/dev/block/MAJOR:MINOR/discard_alignment
++ * /sys/dev/block/MAJOR:MINOR/queue/discard_granularity
++ * /sys/dev/block/MAJOR:MINOR/queue/discard_max_bytes
++ * will exist.
++ * For partitions, we also need to check the parent device:
++ * /sys/dev/block/MAJOR:MINOR/../queue/discard_granularity
++ * /sys/dev/block/MAJOR:MINOR/../queue/discard_max_bytes
+ */
+- snprintf(dev, sizeof dev, "%d:%d\n",
++ snprintf(path1, sizeof path1, "/sys/dev/block/%d:%d",
+ major(statbuf.st_rdev), minor(statbuf.st_rdev));
+
+- dir = opendir("/sys/block");
+- if (dir == NULL) {
+- ntfs_log_debug("fstrim_limits: could not open /sys/block\n");
+- return -errno;
++ snprintf(path2, sizeof path2, "%s/discard_alignment", path1);
++ ret = read_u64(path2, discard_alignment);
++ if (ret) {
++ if (ret != -ENOENT)
++ return ret;
++ else
++ /* We would expect this file to exist on all
++ * modern kernels. But for the sake of very
++ * old kernels:
++ */
++ goto not_found;
+ }
+- for (;;) {
+- errno = 0;
+- d = readdir(dir);
+- if (!d) break;
+
+- snprintf(path, sizeof path, "/sys/block/%s/dev", d->d_name);
+- ret = read_line(path, line, sizeof line);
+- if (ret)
+- continue;
+- if (strcmp(line, dev) == 0)
+- goto found;
++ snprintf(path2, sizeof path2, "%s/queue/discard_granularity", path1);
++ ret = read_u64(path2, discard_granularity);
++ if (ret) {
++ if (ret != -ENOENT)
++ return ret;
++ else {
++ snprintf(path2, sizeof path2,
++ "%s/../queue/discard_granularity", path1);
++ ret = read_u64(path2, discard_granularity);
++ if (ret) {
++ if (ret != -ENOENT)
++ return ret;
++ else
++ goto not_found;
++ }
++ }
+ }
+
+- /* Check readdir didn't fail. */
+- if (errno != 0) {
+- ret = -errno;
+- ntfs_log_debug("fstrim_limits: readdir failed\n");
+- goto out;
++ snprintf(path2, sizeof path2, "%s/queue/discard_max_bytes", path1);
++ ret = read_u64(path2, discard_max_bytes);
++ if (ret) {
++ if (ret != -ENOENT)
++ return ret;
++ else {
++ snprintf(path2, sizeof path2,
++ "%s/../queue/discard_max_bytes", path1);
++ ret = read_u64(path2, discard_max_bytes);
++ if (ret) {
++ if (ret != -ENOENT)
++ return ret;
++ else
++ goto not_found;
++ }
++ }
+ }
+
++ return 0;
++
++not_found:
+ /* If we reach here then we didn't find the device. This is
+ * not an error, but set discard_max_bytes = 0 to indicate
+ * that discard is not available.
+ */
++ *discard_alignment = 0;
+ *discard_granularity = 0;
+ *discard_max_bytes = 0;
+- ntfs_log_debug("fstrim_limits: /sys/block entry corresponding to device %s not found\n",
+- vol->dev->d_name);
+- ret = 0;
+- goto out;
+-
+-found:
+- /* Found the device at /sys/block/ + d->d_name */
+- snprintf (path, sizeof path,
+- "/sys/block/%s/queue/discard_granularity",
+- d->d_name);
+- ret = read_u64(path, discard_granularity);
+- if (ret) {
+- ntfs_log_debug("fstrim_limits: could not read %s\n", path);
+- goto out;
+- }
+-
+- snprintf (path, sizeof path,
+- "/sys/block/%s/queue/discard_max_bytes",
+- d->d_name);
+- ret = read_u64(path, discard_max_bytes);
+- if (ret) {
+- ntfs_log_debug("fstrim_limits: could not read %s\n", path);
+- goto out;
+- }
+-
+- ntfs_log_debug("fstrim_limits: device %s discard granularity = %llu max_bytes = %llu\n",
+- d->d_name,
+- (unsigned long long) *discard_granularity,
+- (unsigned long long) *discard_max_bytes);
+-
+- ret = 0;
+-out:
+- if (closedir (dir) == -1) {
+- ret = -errno;
+- ntfs_log_debug("fstrim_limits: closedir failed\n");
+- return ret;
+- }
+-
+- return ret;
++ return 0;
+ }
+
+ #define FSTRIM_BUFSIZ 4096
+@@ -247,7 +238,7 @@ static int fstrim(ntfs_volume *vol, void *data)
+ u64 start = range->start;
+ u64 len = range->len;
+ u64 minlen = range->minlen;
+- u64 discard_granularity, discard_max_bytes;
++ u64 discard_alignment, discard_granularity, discard_max_bytes;
+ u8 *buf = NULL;
+ LCN start_buf;
+ int ret;
+@@ -279,9 +270,14 @@ static int fstrim(ntfs_volume *vol, void *data)
+ return -EOPNOTSUPP;
+ }
+
+- ret = fstrim_limits(vol, &discard_granularity, &discard_max_bytes);
++ ret = fstrim_limits(vol, &discard_alignment,
++ &discard_granularity, &discard_max_bytes);
+ 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");
+ return -EOPNOTSUPP;
+--
+1.9.3
+
diff --git a/sys-fs/ntfs3g/files/ntfs3g-2014.2.15-implement-fstrim.patch b/sys-fs/ntfs3g/files/ntfs3g-2014.2.15-implement-fstrim.patch
new file mode 100644
index 000000000000..467f5d67493a
--- /dev/null
+++ b/sys-fs/ntfs3g/files/ntfs3g-2014.2.15-implement-fstrim.patch
@@ -0,0 +1,648 @@
+diff -urN ntfs-3g_ntfsprogs-2014.2.15.old/configure.ac ntfs-3g_ntfsprogs-2014.2.15/configure.ac
+--- ntfs-3g_ntfsprogs-2014.2.15.old/configure.ac 2014-02-15 14:07:52.000000000 +0000
++++ ntfs-3g_ntfsprogs-2014.2.15/configure.ac 2014-07-31 13:51:24.425065808 +0100
+@@ -463,7 +463,8 @@
+ regex.h endian.h byteswap.h sys/byteorder.h sys/disk.h sys/endian.h \
+ sys/param.h sys/ioctl.h sys/mkdev.h sys/mount.h sys/stat.h sys/types.h \
+ sys/vfs.h sys/statvfs.h sys/sysmacros.h linux/major.h linux/fd.h \
+- linux/hdreg.h machine/endian.h windows.h syslog.h pwd.h malloc.h])
++ linux/fs.h inttypes.h linux/hdreg.h \
++ machine/endian.h windows.h syslog.h pwd.h malloc.h])
+
+ # Checks for typedefs, structures, and compiler characteristics.
+ AC_HEADER_STDBOOL
+diff -urN ntfs-3g_ntfsprogs-2014.2.15.old/include/ntfs-3g/ioctl.h ntfs-3g_ntfsprogs-2014.2.15/include/ntfs-3g/ioctl.h
+--- ntfs-3g_ntfsprogs-2014.2.15.old/include/ntfs-3g/ioctl.h 1970-01-01 01:00:00.000000000 +0100
++++ ntfs-3g_ntfsprogs-2014.2.15/include/ntfs-3g/ioctl.h 2014-07-31 13:51:24.426065810 +0100
+@@ -0,0 +1,30 @@
++/*
++ *
++ * Copyright (c) 2014 Jean-Pierre Andre
++ *
++ */
++
++/*
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program (in the main directory of the NTFS-3G
++ * distribution in the file COPYING); if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#ifndef IOCTL_H
++#define IOCTL_H
++
++int ntfs_ioctl(ntfs_inode *ni, int cmd, void *arg,
++ unsigned int flags, void *data);
++
++#endif /* IOCTL_H */
+diff -urN ntfs-3g_ntfsprogs-2014.2.15.old/include/ntfs-3g/volume.h ntfs-3g_ntfsprogs-2014.2.15/include/ntfs-3g/volume.h
+--- ntfs-3g_ntfsprogs-2014.2.15.old/include/ntfs-3g/volume.h 2014-02-15 14:07:52.000000000 +0000
++++ ntfs-3g_ntfsprogs-2014.2.15/include/ntfs-3g/volume.h 2014-07-31 13:51:24.426065810 +0100
+@@ -36,9 +36,7 @@
+ #ifdef HAVE_SYS_PARAM_H
+ #include <sys/param.h>
+ #endif
+-#ifdef HAVE_SYS_MOUNT_H
+-#include <sys/mount.h>
+-#endif
++ /* Do not #include <sys/mount.h> here : conflicts with <linux/fs.h> */
+ #ifdef HAVE_MNTENT_H
+ #include <mntent.h>
+ #endif
+diff -urN ntfs-3g_ntfsprogs-2014.2.15.old/libntfs-3g/ioctl.c ntfs-3g_ntfsprogs-2014.2.15/libntfs-3g/ioctl.c
+--- ntfs-3g_ntfsprogs-2014.2.15.old/libntfs-3g/ioctl.c 1970-01-01 01:00:00.000000000 +0100
++++ ntfs-3g_ntfsprogs-2014.2.15/libntfs-3g/ioctl.c 2014-07-31 13:51:24.427065813 +0100
+@@ -0,0 +1,382 @@
++/**
++ * ioctl.c - Processing of ioctls
++ *
++ * This module is part of ntfs-3g library
++ *
++ * Copyright (c) 2014 Jean-Pierre Andre
++ * Copyright (c) 2014 Red Hat, Inc.
++ *
++ * This program/include file is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as published
++ * by the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program/include file is distributed in the hope that it will be
++ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program (in the main directory of the NTFS-3G
++ * distribution in the file COPYING); if not, write to the Free Software
++ * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include "config.h"
++
++#ifdef HAVE_STDIO_H
++#include <stdio.h>
++#endif
++#ifdef HAVE_INTTYPES_H
++#include <inttypes.h>
++#endif
++#ifdef HAVE_STRING_H
++#include <string.h>
++#endif
++#ifdef HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#ifdef HAVE_FCNTL_H
++#include <fcntl.h>
++#endif
++#ifdef HAVE_UNISTD_H
++#include <unistd.h>
++#endif
++#ifdef HAVE_STDLIB_H
++#include <stdlib.h>
++#endif
++#ifdef HAVE_LIMITS_H
++#include <limits.h>
++#endif
++#include <syslog.h>
++
++#ifdef HAVE_SETXATTR
++#include <sys/xattr.h>
++#endif
++
++#ifdef HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++
++#ifdef HAVE_SYS_STAT_H
++#include <sys/stat.h>
++#endif
++
++#ifdef HAVE_LINUX_FS_H
++#include <linux/fs.h>
++#endif
++
++#include <dirent.h>
++
++#include "compat.h"
++#include "debug.h"
++#include "bitmap.h"
++#include "attrib.h"
++#include "inode.h"
++#include "layout.h"
++#include "volume.h"
++#include "index.h"
++#include "logging.h"
++#include "ntfstime.h"
++#include "unistr.h"
++#include "dir.h"
++#include "security.h"
++#include "ioctl.h"
++#include "misc.h"
++
++#if defined(FITRIM) && defined(BLKDISCARD)
++
++/* Issue a TRIM request to the underlying device for the given clusters. */
++static int fstrim_clusters(ntfs_volume *vol, LCN lcn, s64 length)
++{
++ struct ntfs_device *dev = vol->dev;
++ uint64_t range[2];
++
++ ntfs_log_debug("fstrim_clusters: %lld length %lld\n",
++ (long long) lcn, (long long) length);
++
++ range[0] = lcn << vol->cluster_size_bits;
++ range[1] = length << vol->cluster_size_bits;
++
++ if (dev->d_ops->ioctl(dev, BLKDISCARD, range) == -1) {
++ ntfs_log_debug("fstrim_one_cluster: ioctl failed: %m\n");
++ return -errno;
++ }
++ return 0;
++}
++
++static int read_line(const char *path, char *line, size_t max_bytes)
++{
++ FILE *fp;
++
++ fp = fopen(path, "r");
++ if (fp == NULL)
++ return -errno;
++ if (fgets(line, max_bytes, fp) == NULL) {
++ int ret = -EIO; /* fgets doesn't set errno */
++ fclose(fp);
++ return ret;
++ }
++ fclose (fp);
++ return 0;
++}
++
++static int read_u64(const char *path, u64 *n)
++{
++ char line[64];
++ int ret;
++
++ ret = read_line(path, line, sizeof line);
++ if (ret)
++ return ret;
++ if (sscanf(line, "%" SCNu64, n) != 1)
++ return -EINVAL;
++ return 0;
++}
++
++/* Find discard limits for current backing device.
++ * XXX Kernel makes this a pain in the neck.
++ */
++static int fstrim_limits(ntfs_volume *vol, u64 *discard_granularity,
++ u64 *discard_max_bytes)
++{
++ struct stat statbuf;
++ DIR *dir;
++ struct dirent *d;
++ char path[80];
++ char line[64];
++ char dev[64];
++ int ret;
++
++ /* Stat the backing device. Caller has ensured it is a block device. */
++ if (stat(vol->dev->d_name, &statbuf) == -1) {
++ ntfs_log_debug("fstrim_limits: could not stat %s\n",
++ vol->dev->d_name);
++ return -errno;
++ }
++
++ /* Now look for a /sys/block/<dev>/dev file which contains
++ * "major:minor\n".
++ */
++ snprintf(dev, sizeof dev, "%d:%d\n",
++ major(statbuf.st_rdev), minor(statbuf.st_rdev));
++
++ dir = opendir("/sys/block");
++ if (dir == NULL) {
++ ntfs_log_debug("fstrim_limits: could not open /sys/block\n");
++ return -errno;
++ }
++ for (;;) {
++ errno = 0;
++ d = readdir(dir);
++ if (!d) break;
++
++ snprintf(path, sizeof path, "/sys/block/%s/dev", d->d_name);
++ ret = read_line(path, line, sizeof line);
++ if (ret)
++ continue;
++ if (strcmp(line, dev) == 0)
++ goto found;
++ }
++
++ /* Check readdir didn't fail. */
++ if (errno != 0) {
++ ret = -errno;
++ ntfs_log_debug("fstrim_limits: readdir failed\n");
++ goto out;
++ }
++
++ /* If we reach here then we didn't find the device. This is
++ * not an error, but set discard_max_bytes = 0 to indicate
++ * that discard is not available.
++ */
++ *discard_granularity = 0;
++ *discard_max_bytes = 0;
++ ntfs_log_debug("fstrim_limits: /sys/block entry corresponding to device %s not found\n",
++ vol->dev->d_name);
++ ret = 0;
++ goto out;
++
++found:
++ /* Found the device at /sys/block/ + d->d_name */
++ snprintf (path, sizeof path,
++ "/sys/block/%s/queue/discard_granularity",
++ d->d_name);
++ ret = read_u64(path, discard_granularity);
++ if (ret) {
++ ntfs_log_debug("fstrim_limits: could not read %s\n", path);
++ goto out;
++ }
++
++ snprintf (path, sizeof path,
++ "/sys/block/%s/queue/discard_max_bytes",
++ d->d_name);
++ ret = read_u64(path, discard_max_bytes);
++ if (ret) {
++ ntfs_log_debug("fstrim_limits: could not read %s\n", path);
++ goto out;
++ }
++
++ ntfs_log_debug("fstrim_limits: device %s discard granularity = %llu max_bytes = %llu\n",
++ d->d_name,
++ (unsigned long long) *discard_granularity,
++ (unsigned long long) *discard_max_bytes);
++
++ ret = 0;
++out:
++ if (closedir (dir) == -1) {
++ ret = -errno;
++ ntfs_log_debug("fstrim_limits: closedir failed\n");
++ return ret;
++ }
++
++ return ret;
++}
++
++#define FSTRIM_BUFSIZ 4096
++
++/* Trim the filesystem.
++ *
++ * Free blocks between 'start' and 'start+len-1' (both byte offsets)
++ * are found and TRIM requests are sent to the block device. 'minlen'
++ * is the minimum continguous free range to discard.
++ */
++static int fstrim(ntfs_volume *vol, void *data)
++{
++ struct fstrim_range *range = data;
++ u64 start = range->start;
++ u64 len = range->len;
++ u64 minlen = range->minlen;
++ u64 discard_granularity, discard_max_bytes;
++ u8 *buf = NULL;
++ LCN start_buf;
++ int ret;
++
++ ntfs_log_debug("fstrim: start=%llu len=%llu minlen=%llu\n",
++ (unsigned long long) start,
++ (unsigned long long) len,
++ (unsigned long long) minlen);
++
++ /* Fail if user tries to use the fstrim -o/-l/-m options.
++ * 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");
++ return -EINVAL;
++ }
++ if (minlen > vol->cluster_size) {
++ ntfs_log_debug("fstrim: minlen > cluster size is not supported\n");
++ return -EINVAL;
++ }
++
++ /* Only block devices are supported. It would be possible to
++ * support backing files (ie. without using loop) but the
++ * ioctls used to punch holes in files are completely
++ * different.
++ */
++ if (!NDevBlock(vol->dev)) {
++ ntfs_log_debug("fstrim: not supported for non-block-device\n");
++ return -EOPNOTSUPP;
++ }
++
++ ret = fstrim_limits(vol, &discard_granularity, &discard_max_bytes);
++ if (ret)
++ return ret;
++ if (discard_granularity > vol->cluster_size) {
++ ntfs_log_debug("fstrim: discard granularity of backing device is larger than cluster size\n");
++ return -EOPNOTSUPP;
++ }
++ if (discard_max_bytes == 0) {
++ ntfs_log_debug("fstrim: backing device does not support discard (discard_max_bytes == 0)\n");
++ return -EOPNOTSUPP;
++ }
++
++ /* Sync the device before doing anything. */
++ ret = ntfs_device_sync(vol->dev);
++ if (ret)
++ return ret;
++
++ /* Read through the bitmap. */
++ buf = ntfs_malloc(FSTRIM_BUFSIZ);
++ if (buf == NULL)
++ return -errno;
++ for (start_buf = 0; start_buf < vol->nr_clusters;
++ start_buf += FSTRIM_BUFSIZ * 8) {
++ s64 count;
++ s64 br;
++ LCN end_buf, start_lcn;
++
++ /* start_buf is LCN of first cluster in the current buffer.
++ * end_buf is LCN of last cluster + 1 in the current buffer.
++ */
++ end_buf = start_buf + FSTRIM_BUFSIZ*8;
++ if (end_buf > vol->nr_clusters)
++ end_buf = vol->nr_clusters;
++ count = (end_buf - start_buf) / 8;
++
++ br = ntfs_attr_pread(vol->lcnbmp_na, start_buf/8, count, buf);
++ if (br != count) {
++ if (br >= 0)
++ ret = -EIO;
++ else
++ ret = -errno;
++ goto free_out;
++ }
++
++ /* Trim the clusters in large as possible blocks, but
++ * not larger than discard_max_bytes.
++ */
++ for (start_lcn = start_buf; start_lcn < end_buf; ++start_lcn) {
++ if (!ntfs_bit_get(buf, start_lcn-start_buf)) {
++ LCN end_lcn;
++
++ /* Cluster 'start_lcn' is not in use,
++ * find end of this run.
++ */
++ end_lcn = start_lcn+1;
++ while (end_lcn < end_buf &&
++ (u64) (end_lcn-start_lcn) << vol->cluster_size_bits
++ < discard_max_bytes &&
++ !ntfs_bit_get(buf, end_lcn-start_buf))
++ end_lcn++;
++
++ ret = fstrim_clusters(vol,
++ start_lcn, end_lcn-start_lcn);
++ if (ret)
++ goto free_out;
++
++ start_lcn = end_lcn-1;
++ }
++ }
++ }
++
++ ret = 0;
++free_out:
++ free(buf);
++ return ret;
++}
++
++#endif /* FITRIM && BLKDISCARD */
++
++int ntfs_ioctl(ntfs_inode *ni, int cmd, void *arg __attribute__((unused)),
++ unsigned int flags __attribute__((unused)), void *data)
++{
++ int ret = 0;
++
++ switch (cmd) {
++#if defined(FITRIM) && defined(BLKDISCARD)
++ case FITRIM:
++ if (!ni || !data)
++ ret = -EINVAL;
++ else
++ ret = fstrim(ni->vol, data);
++ break;
++#else
++#warning FITRIM or BLKDISCARD not defined
++#endif
++ default :
++ ret = -EINVAL;
++ break;
++ }
++ return (ret);
++}
+diff -urN ntfs-3g_ntfsprogs-2014.2.15.old/libntfs-3g/Makefile.am ntfs-3g_ntfsprogs-2014.2.15/libntfs-3g/Makefile.am
+--- ntfs-3g_ntfsprogs-2014.2.15.old/libntfs-3g/Makefile.am 2014-02-15 14:07:52.000000000 +0000
++++ ntfs-3g_ntfsprogs-2014.2.15/libntfs-3g/Makefile.am 2014-07-31 13:51:24.426065810 +0100
+@@ -30,6 +30,7 @@
+ efs.c \
+ index.c \
+ inode.c \
++ ioctl.c \
+ lcnalloc.c \
+ logfile.c \
+ logging.c \
+diff -urN ntfs-3g_ntfsprogs-2014.2.15.old/src/lowntfs-3g.c ntfs-3g_ntfsprogs-2014.2.15/src/lowntfs-3g.c
+--- ntfs-3g_ntfsprogs-2014.2.15.old/src/lowntfs-3g.c 2014-02-15 14:07:52.000000000 +0000
++++ ntfs-3g_ntfsprogs-2014.2.15/src/lowntfs-3g.c 2014-07-31 13:51:24.429065815 +0100
+@@ -81,7 +81,12 @@
+ #include <sys/dirent.h>
+ #endif /* defined(__APPLE__) || defined(__DARWIN__) */
+
++#ifdef HAVE_LINUX_FS_H
++#include <linux/fs.h>
++#endif
++
+ #include "compat.h"
++#include "bitmap.h"
+ #include "attrib.h"
+ #include "inode.h"
+ #include "volume.h"
+@@ -97,6 +102,7 @@
+ #include "logging.h"
+ #include "xattrs.h"
+ #include "misc.h"
++#include "ioctl.h"
+
+ #include "ntfs-3g_common.h"
+
+@@ -564,8 +570,6 @@
+ }
+ #endif /* defined(__APPLE__) || defined(__DARWIN__) */
+
+-#if defined(FUSE_CAP_DONT_MASK) || defined(FUSE_CAP_BIG_WRITES) \
+- || (defined(__APPLE__) || defined(__DARWIN__))
+ static void ntfs_init(void *userdata __attribute__((unused)),
+ struct fuse_conn_info *conn)
+ {
+@@ -582,8 +586,8 @@
+ >= SAFE_CAPACITY_FOR_BIG_WRITES))
+ conn->want |= FUSE_CAP_BIG_WRITES;
+ #endif
++ conn->want |= FUSE_CAP_IOCTL_DIR;
+ }
+-#endif /* defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__)) */
+
+ static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx,
+ ntfs_inode *ni, struct stat *stbuf)
+@@ -2573,6 +2577,48 @@
+ fuse_reply_err(req, 0);
+ }
+
++static void ntfs_fuse_ioctl(fuse_req_t req __attribute__((unused)),
++ fuse_ino_t ino __attribute__((unused)),
++ int cmd, void *arg,
++ struct fuse_file_info *fi __attribute__((unused)),
++ unsigned flags, const void *data,
++ size_t in_bufsz, size_t out_bufsz)
++{
++ ntfs_inode *ni;
++ char *buf = (char*)NULL;
++ int bufsz;
++ int ret = 0;
++
++ if (flags & FUSE_IOCTL_COMPAT) {
++ ret = -ENOSYS;
++ } else {
++ ni = ntfs_inode_open(ctx->vol, INODE(ino));
++ if (!ni) {
++ ret = -errno;
++ goto fail;
++ }
++ bufsz = (in_bufsz > out_bufsz ? in_bufsz : out_bufsz);
++ if (bufsz) {
++ buf = ntfs_malloc(bufsz);
++ if (!buf) {
++ ret = ENOMEM;
++ goto fail;
++ }
++ memcpy(buf, data, in_bufsz);
++ }
++ ret = ntfs_ioctl(ni, cmd, arg, flags, buf);
++ if (ntfs_inode_close (ni))
++ set_fuse_error(&ret);
++ }
++ if (ret)
++fail :
++ fuse_reply_err(req, -ret);
++ else
++ fuse_reply_ioctl(req, 0, buf, out_bufsz);
++ if (buf)
++ free(buf);
++}
++
+ static void ntfs_fuse_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
+ uint64_t vidx)
+ {
+@@ -3496,6 +3542,7 @@
+ .fsyncdir = ntfs_fuse_fsync,
+ .bmap = ntfs_fuse_bmap,
+ .destroy = ntfs_fuse_destroy2,
++ .ioctl = ntfs_fuse_ioctl,
+ #if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
+ .access = ntfs_fuse_access,
+ #endif
+@@ -3512,10 +3559,7 @@
+ .setbkuptime = ntfs_macfuse_setbkuptime,
+ .setchgtime = ntfs_macfuse_setchgtime,
+ #endif /* defined(__APPLE__) || defined(__DARWIN__) */
+-#if defined(FUSE_CAP_DONT_MASK) || defined(FUSE_CAP_BIG_WRITES) \
+- || (defined(__APPLE__) || defined(__DARWIN__))
+ .init = ntfs_init
+-#endif
+ };
+
+ static int ntfs_fuse_init(void)
+diff -urN ntfs-3g_ntfsprogs-2014.2.15.old/src/ntfs-3g.c ntfs-3g_ntfsprogs-2014.2.15/src/ntfs-3g.c
+--- ntfs-3g_ntfsprogs-2014.2.15.old/src/ntfs-3g.c 2014-02-15 14:07:52.000000000 +0000
++++ ntfs-3g_ntfsprogs-2014.2.15/src/ntfs-3g.c 2014-07-31 13:51:24.430065816 +0100
+@@ -96,6 +96,7 @@
+ #include "logging.h"
+ #include "xattrs.h"
+ #include "misc.h"
++#include "ioctl.h"
+
+ #include "ntfs-3g_common.h"
+
+@@ -636,8 +637,6 @@
+ }
+ #endif /* defined(__APPLE__) || defined(__DARWIN__) */
+
+-#if defined(FUSE_CAP_DONT_MASK) || defined(FUSE_CAP_BIG_WRITES) \
+- || (defined(__APPLE__) || defined(__DARWIN__))
+ static void *ntfs_init(struct fuse_conn_info *conn)
+ {
+ #if defined(__APPLE__) || defined(__DARWIN__)
+@@ -653,9 +652,9 @@
+ >= SAFE_CAPACITY_FOR_BIG_WRITES))
+ conn->want |= FUSE_CAP_BIG_WRITES;
+ #endif
++ conn->want |= FUSE_CAP_IOCTL_DIR;
+ return NULL;
+ }
+-#endif /* defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__)) */
+
+ static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf)
+ {
+@@ -2412,6 +2411,28 @@
+ return (ret);
+ }
+
++static int ntfs_fuse_ioctl(const char *path,
++ int cmd, void *arg,
++ struct fuse_file_info *fi __attribute__((unused)),
++ unsigned int flags, void *data)
++{
++ ntfs_inode *ni;
++ int ret;
++
++ if (flags & FUSE_IOCTL_COMPAT)
++ return -ENOSYS;
++
++ ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
++ if (!ni)
++ return -errno;
++
++ ret = ntfs_ioctl(ni, cmd, arg, flags, data);
++
++ if (ntfs_inode_close (ni))
++ set_fuse_error(&ret);
++ return ret;
++}
++
+ static int ntfs_fuse_bmap(const char *path, size_t blocksize, uint64_t *idx)
+ {
+ ntfs_inode *ni;
+@@ -3335,6 +3356,7 @@
+ .fsyncdir = ntfs_fuse_fsync,
+ .bmap = ntfs_fuse_bmap,
+ .destroy = ntfs_fuse_destroy2,
++ .ioctl = ntfs_fuse_ioctl,
+ #if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
+ .access = ntfs_fuse_access,
+ .opendir = ntfs_fuse_opendir,
+@@ -3352,10 +3374,7 @@
+ .setbkuptime = ntfs_macfuse_setbkuptime,
+ .setchgtime = ntfs_macfuse_setchgtime,
+ #endif /* defined(__APPLE__) || defined(__DARWIN__) */
+-#if defined(FUSE_CAP_DONT_MASK) || defined(FUSE_CAP_BIG_WRITES) \
+- || (defined(__APPLE__) || defined(__DARWIN__))
+ .init = ntfs_init
+-#endif
+ };
+
+ static int ntfs_fuse_init(void)
diff --git a/sys-fs/ntfs3g/files/ntfs3g-2014.2.15-no-split-usr.patch b/sys-fs/ntfs3g/files/ntfs3g-2014.2.15-no-split-usr.patch
new file mode 100644
index 000000000000..0228bfec330b
--- /dev/null
+++ b/sys-fs/ntfs3g/files/ntfs3g-2014.2.15-no-split-usr.patch
@@ -0,0 +1,25 @@
+we handle split /usr logic ourselves. this ends up breaking when building
+for an abi that doesn't exist in / (like cross-compiling) as the tests fail.
+
+--- a/libntfs-3g/Makefile.in
++++ b/libntfs-3g/Makefile.in
+@@ -912,19 +912,6 @@ uninstall-am: uninstall-libLTLIBRARIES uninstall-local \
+ uninstall-rootlibLTLIBRARIES
+
+
+-# We may need to move .so files to root
+-# And create ldscript or symbolic link from /usr
+-install-exec-hook: install-rootlibLTLIBRARIES
+-@INSTALL_LIBRARY_TRUE@ if [ ! "$(rootlibdir)" -ef "$(libdir)" ]; then \
+-@INSTALL_LIBRARY_TRUE@ $(MV) -f "$(DESTDIR)/$(libdir)"/libntfs-3g.so* "$(DESTDIR)/$(rootlibdir)"; \
+-@INSTALL_LIBRARY_TRUE@ fi
+-@GENERATE_LDSCRIPT_TRUE@@INSTALL_LIBRARY_TRUE@ if [ ! "$(rootlibdir)" -ef "$(libdir)" ]; then \
+-@GENERATE_LDSCRIPT_TRUE@@INSTALL_LIBRARY_TRUE@ $(install_sh_PROGRAM) "libntfs-3g.script.so" "$(DESTDIR)/$(libdir)/libntfs-3g.so"; \
+-@GENERATE_LDSCRIPT_TRUE@@INSTALL_LIBRARY_TRUE@ fi
+-@GENERATE_LDSCRIPT_FALSE@@INSTALL_LIBRARY_TRUE@ if [ ! "$(rootlibdir)" -ef "$(libdir)" ]; then \
+-@GENERATE_LDSCRIPT_FALSE@@INSTALL_LIBRARY_TRUE@ $(LN_S) "$(rootlibdir)/libntfs-3g.so" "$(DESTDIR)/$(libdir)/libntfs-3g.so"; \
+-@GENERATE_LDSCRIPT_FALSE@@INSTALL_LIBRARY_TRUE@ fi
+-
+ uninstall-local:
+ @INSTALL_LIBRARY_TRUE@ $(RM) -f "$(DESTDIR)/$(rootlibdir)"/libntfs-3g.so*
+
diff --git a/sys-fs/ntfs3g/files/ntfs3g-2014.2.15-update-fuse-lite-to-support-ioctls.patch b/sys-fs/ntfs3g/files/ntfs3g-2014.2.15-update-fuse-lite-to-support-ioctls.patch
new file mode 100644
index 000000000000..0c9b7cc97d3d
--- /dev/null
+++ b/sys-fs/ntfs3g/files/ntfs3g-2014.2.15-update-fuse-lite-to-support-ioctls.patch
@@ -0,0 +1,610 @@
+diff -ur ntfs-3g_ntfsprogs-2014.2.15/include/fuse-lite/fuse_common.h ntfs-3g_ntfsprogs-2014.2.15.new/include/fuse-lite/fuse_common.h
+--- ntfs-3g_ntfsprogs-2014.2.15/include/fuse-lite/fuse_common.h 2014-02-15 14:07:52.000000000 +0000
++++ ntfs-3g_ntfsprogs-2014.2.15.new/include/fuse-lite/fuse_common.h 2014-07-31 13:47:17.401904166 +0100
+@@ -49,6 +49,22 @@
+ #endif
+
+ #define FUSE_CAP_BIG_WRITES (1 << 5)
++#define FUSE_CAP_IOCTL_DIR (1 << 11)
++
++/**
++ * Ioctl flags
++ *
++ * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine
++ * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed
++ * FUSE_IOCTL_RETRY: retry with new iovecs
++ * FUSE_IOCTL_DIR: is a directory
++ */
++#define FUSE_IOCTL_COMPAT (1 << 0)
++#define FUSE_IOCTL_UNRESTRICTED (1 << 1)
++#define FUSE_IOCTL_RETRY (1 << 2)
++#define FUSE_IOCTL_DIR (1 << 4)
++
++#define FUSE_IOCTL_MAX_IOV 256
+
+ /**
+ * Information about open files
+diff -ur ntfs-3g_ntfsprogs-2014.2.15/include/fuse-lite/fuse.h ntfs-3g_ntfsprogs-2014.2.15.new/include/fuse-lite/fuse.h
+--- ntfs-3g_ntfsprogs-2014.2.15/include/fuse-lite/fuse.h 2014-02-15 14:07:52.000000000 +0000
++++ ntfs-3g_ntfsprogs-2014.2.15.new/include/fuse-lite/fuse.h 2014-07-31 13:47:17.401904166 +0100
+@@ -420,9 +420,27 @@
+ * Introduced in version 2.6
+ */
+ int (*bmap) (const char *, size_t blocksize, uint64_t *idx);
+- unsigned int flag_nullpath_ok : 1;
+
+ /**
++ * Ioctl
++ *
++ * flags will have FUSE_IOCTL_COMPAT set for 32bit ioctls in
++ * 64bit environment. The size and direction of data is
++ * determined by _IOC_*() decoding of cmd. For _IOC_NONE,
++ * data will be NULL, for _IOC_WRITE data is out area, for
++ * _IOC_READ in area and if both are set in/out area. In all
++ * non-NULL cases, the area is of _IOC_SIZE(cmd) bytes.
++ *
++ * Introduced in version 2.8
++ */
++ int (*ioctl) (const char *, int cmd, void *arg,
++ struct fuse_file_info *, unsigned int flags, void *data);
++
++ /*
++ * The flags below have been discarded, they should not be used
++ */
++ unsigned int flag_nullpath_ok : 1;
++ /**
+ * Reserved flags, don't set
+ */
+ unsigned int flag_reserved : 30;
+@@ -450,10 +468,8 @@
+ /** Private filesystem data */
+ void *private_data;
+
+-#ifdef POSIXACLS
+ /** Umask of the calling process (introduced in version 2.8) */
+ mode_t umask;
+-#endif
+ };
+
+ /* ----------------------------------------------------------- *
+@@ -601,6 +617,8 @@
+ const char *name);
+ int fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
+ uint64_t *idx);
++int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, int cmd, void *arg,
++ struct fuse_file_info *fi, unsigned int flags, void *data);
+ void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn);
+ void fuse_fs_destroy(struct fuse_fs *fs);
+
+diff -ur ntfs-3g_ntfsprogs-2014.2.15/include/fuse-lite/fuse_kernel.h ntfs-3g_ntfsprogs-2014.2.15.new/include/fuse-lite/fuse_kernel.h
+--- ntfs-3g_ntfsprogs-2014.2.15/include/fuse-lite/fuse_kernel.h 2014-02-15 14:07:52.000000000 +0000
++++ ntfs-3g_ntfsprogs-2014.2.15.new/include/fuse-lite/fuse_kernel.h 2014-07-31 13:47:17.401904166 +0100
+@@ -48,13 +48,19 @@
+ /** Version number of this interface */
+ #define FUSE_KERNEL_VERSION 7
+
+-/** Minor version number of this interface */
+-#ifdef POSIXACLS
+-#define FUSE_KERNEL_MINOR_VERSION 12
++/** Minor version number of this interface
++ * We introduce ourself as 7.18 (Posix ACLS : 7.12, IOCTL_DIR : 7.18)
++ * and we expect features features defined for 7.18, but not implemented
++ * here to not be triggered by ntfs-3g.
++ */
++#define FUSE_KERNEL_MINOR_VERSION 18
++
++/*
++ * For binary compatibility with old kernels we accept falling back to 7.8
++ */
++
++#define FUSE_KERNEL_MAJOR_FALLBACK 7
+ #define FUSE_KERNEL_MINOR_FALLBACK 8
+-#else
+-#define FUSE_KERNEL_MINOR_VERSION 8
+-#endif
+
+ /** The node ID of the root inode */
+ #define FUSE_ROOT_ID 1
+@@ -83,9 +89,7 @@
+ __u32 uid;
+ __u32 gid;
+ __u32 rdev;
+-#ifdef POSIXACLS
+ __u64 filling; /* JPA needed for minor >= 12, but meaning unknown */
+-#endif
+ };
+
+ struct fuse_kstatfs {
+@@ -132,11 +136,13 @@
+ * INIT request/reply flags
+ * FUSE_BIG_WRITES: allow big writes to be issued to the file system
+ * FUSE_DONT_MASK: don't apply umask to file mode on create operations
++ * FUSE_HAS_IOCTL_DIR: kernel supports ioctl on directories
+ */
+ #define FUSE_ASYNC_READ (1 << 0)
+ #define FUSE_POSIX_LOCKS (1 << 1)
+ #define FUSE_BIG_WRITES (1 << 5)
+ #define FUSE_DONT_MASK (1 << 6)
++#define FUSE_HAS_IOCTL_DIR (1 << 11)
+
+ /**
+ * Release flags
+@@ -180,6 +186,7 @@
+ FUSE_INTERRUPT = 36,
+ FUSE_BMAP = 37,
+ FUSE_DESTROY = 38,
++ FUSE_IOCTL = 39,
+ };
+
+ /* The read buffer is required to be at least 8k, but may be much larger */
+@@ -215,10 +222,8 @@
+ struct fuse_mknod_in {
+ __u32 mode;
+ __u32 rdev;
+-#ifdef POSIXACLS
+ __u32 umask;
+ __u32 padding;
+-#endif
+ };
+
+ struct fuse_mkdir_in {
+@@ -255,20 +260,14 @@
+
+ struct fuse_open_in {
+ __u32 flags;
+-#ifdef POSIXACLS
+- __u32 unused;
+-#else
+- __u32 mode;
+-#endif
++ __u32 mode; /* unused for protocol < 7.12 */
+ };
+
+ struct fuse_create_in {
+ __u32 flags;
+ __u32 mode;
+-#ifdef POSIXACLS
+ __u32 umask;
+ __u32 padding;
+-#endif
+ };
+
+ struct fuse_open_out {
+@@ -305,11 +304,9 @@
+ __u64 offset;
+ __u32 size;
+ __u32 write_flags;
+-#ifdef POSIXACLS
+ __u64 lock_owner; /* JPA */
+ __u32 flags; /* JPA */
+ __u32 padding; /* JPA */
+-#endif
+ };
+
+ struct fuse_write_out {
+@@ -389,6 +386,27 @@
+ __u64 block;
+ };
+
++struct fuse_ioctl_in {
++ __u64 fh;
++ __u32 flags;
++ __u32 cmd;
++ __u64 arg;
++ __u32 in_size;
++ __u32 out_size;
++};
++
++struct fuse_ioctl_iovec {
++ __u64 base;
++ __u64 len;
++};
++
++struct fuse_ioctl_out {
++ __s32 result;
++ __u32 flags;
++ __u32 in_iovs;
++ __u32 out_iovs;
++};
++
+ struct fuse_in_header {
+ __u32 len;
+ __u32 opcode;
+diff -ur ntfs-3g_ntfsprogs-2014.2.15/include/fuse-lite/fuse_lowlevel.h ntfs-3g_ntfsprogs-2014.2.15.new/include/fuse-lite/fuse_lowlevel.h
+--- ntfs-3g_ntfsprogs-2014.2.15/include/fuse-lite/fuse_lowlevel.h 2014-02-15 14:07:52.000000000 +0000
++++ ntfs-3g_ntfsprogs-2014.2.15.new/include/fuse-lite/fuse_lowlevel.h 2014-07-31 13:47:17.402904167 +0100
+@@ -101,10 +101,8 @@
+ /** Thread ID of the calling process */
+ pid_t pid;
+
+-#ifdef POSIXACLS
+ /** Umask of the calling process (introduced in version 2.8) */
+ mode_t umask;
+-#endif
+ };
+
+ /* 'to_set' flags in setattr */
+@@ -805,6 +803,37 @@
+ */
+ void (*bmap) (fuse_req_t req, fuse_ino_t ino, size_t blocksize,
+ uint64_t idx);
++ /**
++ * Ioctl
++ *
++ * Note: For unrestricted ioctls (not allowed for FUSE
++ * servers), data in and out areas can be discovered by giving
++ * iovs and setting FUSE_IOCTL_RETRY in @flags. For
++ * restricted ioctls, kernel prepares in/out data area
++ * according to the information encoded in cmd.
++ *
++ * Introduced in version 2.8
++ *
++ * Valid replies:
++ * fuse_reply_ioctl_retry
++ * fuse_reply_ioctl
++ * fuse_reply_ioctl_iov
++ * fuse_reply_err
++ *
++ * @param req request handle
++ * @param ino the inode number
++ * @param cmd ioctl command
++ * @param arg ioctl argument
++ * @param fi file information
++ * @param flags for FUSE_IOCTL_* flags
++ * @param in_buf data fetched from the caller
++ * @param in_bufsz number of fetched bytes
++ * @param out_bufsz maximum size of output data
++ */
++ void (*ioctl) (fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
++ struct fuse_file_info *fi, unsigned flags,
++ const void *in_buf, size_t in_bufsz, size_t out_bufsz);
++
+ };
+
+ /**
+@@ -1022,6 +1051,20 @@
+ const char *name, const struct stat *stbuf,
+ off_t off);
+
++/**
++ * Reply to finish ioctl
++ *
++ * Possible requests:
++ * ioctl
++ *
++ * @param req request handle
++ * @param result result to be passed to the caller
++ * @param buf buffer containing output data
++ * @param size length of output data
++ */
++int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size);
++
++
+ /* ----------------------------------------------------------- *
+ * Utility functions *
+ * ----------------------------------------------------------- */
+diff -ur ntfs-3g_ntfsprogs-2014.2.15/libfuse-lite/fuse.c ntfs-3g_ntfsprogs-2014.2.15.new/libfuse-lite/fuse.c
+--- ntfs-3g_ntfsprogs-2014.2.15/libfuse-lite/fuse.c 2014-02-15 14:07:52.000000000 +0000
++++ ntfs-3g_ntfsprogs-2014.2.15.new/libfuse-lite/fuse.c 2014-07-31 13:47:17.403904167 +0100
+@@ -1040,6 +1040,21 @@
+ return -ENOSYS;
+ }
+
++int fuse_fs_ioctl(struct fuse_fs *fs, const char *path, int cmd, void *arg,
++ struct fuse_file_info *fi, unsigned int flags, void *data)
++{
++ fuse_get_context()->private_data = fs->user_data;
++ if (fs->op.ioctl) {
++/*
++ if (fs->debug)
++ fprintf(stderr, "ioctl[%llu] 0x%x flags: 0x%x\n",
++ (unsigned long long) fi->fh, cmd, flags);
++*/
++ return fs->op.ioctl(path, cmd, arg, fi, flags, data);
++ } else
++ return -ENOSYS;
++}
++
+ static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
+ {
+ struct node *node;
+@@ -2716,6 +2731,60 @@
+ reply_err(req, err);
+ }
+
++static void fuse_lib_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
++ struct fuse_file_info *llfi, unsigned int flags,
++ const void *in_buf, size_t in_bufsz,
++ size_t out_bufsz)
++{
++ struct fuse *f = req_fuse_prepare(req);
++ struct fuse_intr_data d;
++ struct fuse_file_info fi;
++ char *path, *out_buf = NULL;
++ int err;
++
++ err = -EPERM;
++ if (flags & FUSE_IOCTL_UNRESTRICTED)
++ goto err;
++
++ if (flags & FUSE_IOCTL_DIR)
++ get_dirhandle(llfi, &fi);
++ else
++ fi = *llfi;
++
++ if (out_bufsz) {
++ err = -ENOMEM;
++ out_buf = malloc(out_bufsz);
++ if (!out_buf)
++ goto err;
++ }
++
++ assert(!in_bufsz || !out_bufsz || in_bufsz == out_bufsz);
++ if (out_buf)
++ memcpy(out_buf, in_buf, in_bufsz);
++
++ path = get_path(f, ino); /* Should be get_path_nullok() */
++ if (!path) {
++ err = ENOENT;
++ goto err;
++ }
++
++ fuse_prepare_interrupt(f, req, &d);
++
++ /* Note : const qualifier dropped */
++ err = fuse_fs_ioctl(f->fs, path, cmd, arg, &fi, flags,
++ out_buf ? (void*)out_buf : (void*)(uintptr_t)in_buf);
++
++ fuse_finish_interrupt(f, req, &d);
++ free(path);
++
++ fuse_reply_ioctl(req, err, out_buf, out_bufsz);
++ goto out;
++err:
++ reply_err(req, err);
++out:
++ free(out_buf);
++}
++
+ static struct fuse_lowlevel_ops fuse_path_ops = {
+ .init = fuse_lib_init,
+ .destroy = fuse_lib_destroy,
+@@ -2751,6 +2820,7 @@
+ .getlk = fuse_lib_getlk,
+ .setlk = fuse_lib_setlk,
+ .bmap = fuse_lib_bmap,
++ .ioctl = fuse_lib_ioctl,
+ };
+
+ struct fuse_session *fuse_get_session(struct fuse *f)
+diff -ur ntfs-3g_ntfsprogs-2014.2.15/libfuse-lite/fuse_lowlevel.c ntfs-3g_ntfsprogs-2014.2.15.new/libfuse-lite/fuse_lowlevel.c
+--- ntfs-3g_ntfsprogs-2014.2.15/libfuse-lite/fuse_lowlevel.c 2014-02-15 14:07:52.000000000 +0000
++++ ntfs-3g_ntfsprogs-2014.2.15.new/libfuse-lite/fuse_lowlevel.c 2014-07-31 13:47:17.403904167 +0100
+@@ -333,12 +333,8 @@
+
+ memset(&arg, 0, sizeof(arg));
+ fill_entry(&arg, e);
+-#ifdef POSIXACLS
+ return send_reply_ok(req, &arg, (req->f->conn.proto_minor >= 12
+ ? sizeof(arg) : FUSE_COMPAT_ENTRY_OUT_SIZE));
+-#else
+- return send_reply_ok(req, &arg, sizeof(arg));
+-#endif
+ }
+
+ int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
+@@ -351,7 +347,6 @@
+
+ memset(&arg, 0, sizeof(arg));
+ fill_entry(&arg.e, e);
+-#ifdef POSIXACLS
+ if (req->f->conn.proto_minor < 12) {
+ fill_open((struct fuse_open_out*)
+ ((char*)&arg + FUSE_COMPAT_ENTRY_OUT_SIZE), f);
+@@ -361,10 +356,6 @@
+ fill_open(&arg.o, f);
+ return send_reply_ok(req, &arg, sizeof(arg));
+ }
+-#else
+- fill_open(&arg.o, f);
+- return send_reply_ok(req, &arg, sizeof(arg));
+-#endif
+ }
+
+ int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
+@@ -377,12 +368,8 @@
+ arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
+ convert_stat(attr, &arg.attr);
+
+-#ifdef POSIXACLS
+ return send_reply_ok(req, &arg, (req->f->conn.proto_minor >= 12
+ ? sizeof(arg) : FUSE_COMPAT_FUSE_ATTR_OUT_SIZE));
+-#else
+- return send_reply_ok(req, &arg, sizeof(arg));
+-#endif
+ }
+
+ int fuse_reply_readlink(fuse_req_t req, const char *linkname)
+@@ -462,6 +449,28 @@
+ return send_reply_ok(req, &arg, sizeof(arg));
+ }
+
++int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
++{
++ struct fuse_ioctl_out arg;
++ struct iovec iov[3];
++ size_t count = 1;
++
++ memset(&arg, 0, sizeof(arg));
++ arg.result = result;
++ iov[count].iov_base = &arg;
++ iov[count].iov_len = sizeof(arg);
++ count++;
++
++ if (size) {
++ /* Note : const qualifier dropped */
++ iov[count].iov_base = (char *)(uintptr_t) buf;
++ iov[count].iov_len = size;
++ count++;
++ }
++
++ return send_reply_iov(req, 0, iov, count);
++}
++
+ static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+ const char *name = (const char *) inarg;
+@@ -538,11 +547,9 @@
+ const struct fuse_mknod_in *arg = (const struct fuse_mknod_in *) inarg;
+ const char *name = PARAM(arg);
+
+-#ifdef POSIXACLS
+ if (req->f->conn.proto_minor >= 12)
+ req->ctx.umask = arg->umask;
+ else
+-#endif
+ name = (const char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
+
+ if (req->f->op.mknod)
+@@ -555,10 +562,8 @@
+ {
+ const struct fuse_mkdir_in *arg = (const struct fuse_mkdir_in *) inarg;
+
+-#ifdef POSIXACLS
+ if (req->f->conn.proto_minor >= 12)
+ req->ctx.umask = arg->umask;
+-#endif
+
+ if (req->f->op.mkdir)
+ req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
+@@ -630,11 +635,9 @@
+ memset(&fi, 0, sizeof(fi));
+ fi.flags = arg->flags;
+
+-#ifdef POSIXACLS
+ if (req->f->conn.proto_minor >= 12)
+ req->ctx.umask = arg->umask;
+ else
+-#endif
+ name = (const char *) inarg + sizeof(struct fuse_open_in);
+
+ req->f->op.create(req, nodeid, name, arg->mode, &fi);
+@@ -682,7 +685,6 @@
+ fi.writepage = arg->write_flags & 1;
+
+ if (req->f->op.write) {
+-#ifdef POSIXACLS
+ const char *buf;
+
+ if (req->f->conn.proto_minor >= 12)
+@@ -690,9 +692,6 @@
+ else
+ buf = ((const char*)arg) + FUSE_COMPAT_WRITE_IN_SIZE;
+ req->f->op.write(req, nodeid, buf, arg->size, arg->offset, &fi);
+-#else
+- req->f->op.write(req, nodeid, PARAM(arg), arg->size, arg->offset, &fi);
+-#endif
+ } else
+ fuse_reply_err(req, ENOSYS);
+ }
+@@ -1011,6 +1010,39 @@
+ fuse_reply_err(req, ENOSYS);
+ }
+
++static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
++{
++ const struct fuse_ioctl_in *arg = (const struct fuse_ioctl_in *) inarg;
++ unsigned int flags = arg->flags;
++ const void *in_buf = arg->in_size ? PARAM(arg) : NULL;
++ struct fuse_file_info fi;
++
++ if (flags & FUSE_IOCTL_DIR &&
++ !(req->f->conn.want & FUSE_CAP_IOCTL_DIR)) {
++ fuse_reply_err(req, ENOTTY);
++ return;
++ }
++
++ memset(&fi, 0, sizeof(fi));
++ fi.fh = arg->fh;
++
++/* TODO JPA (need req->ioctl_64bit in obscure fuse_req_t)
++// probably a 64 bit ioctl on a 32-bit cpu
++// this is to forward a request from the kernel
++ if (sizeof(void *) == 4 && req->f->conn.proto_minor >= 16 &&
++ !(flags & FUSE_IOCTL_32BIT)) {
++ req->ioctl_64bit = 1;
++ }
++*/
++
++ if (req->f->op.ioctl)
++ req->f->op.ioctl(req, nodeid, arg->cmd,
++ (void *)(uintptr_t)arg->arg, &fi, flags,
++ in_buf, arg->in_size, arg->out_size);
++ else
++ fuse_reply_err(req, ENOSYS);
++}
++
+ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
+ {
+ const struct fuse_init_in *arg = (const struct fuse_init_in *) inarg;
+@@ -1047,6 +1079,8 @@
+ #endif
+ if (arg->flags & FUSE_BIG_WRITES)
+ f->conn.capable |= FUSE_CAP_BIG_WRITES;
++ if (arg->flags & FUSE_HAS_IOCTL_DIR)
++ f->conn.capable |= FUSE_CAP_IOCTL_DIR;
+ } else {
+ f->conn.async_read = 0;
+ f->conn.max_readahead = 0;
+@@ -1069,28 +1103,28 @@
+ memset(&outarg, 0, sizeof(outarg));
+ outarg.major = FUSE_KERNEL_VERSION;
+ /*
+- * if POSIXACLS is not set, protocol 7.8 provides a good
+- * compatibility with older kernel modules.
+- * if POSIXACLS is set, we try to use protocol 7.12 supposed
+- * to have the ability to process the umask conditionnally,
+- * but, when using an older kernel module, we fallback to 7.8
++ * Suggest using protocol 7.18 when available, and fallback
++ * to 7.8 when running on an old kernel.
++ * Protocol 7.12 has the ability to process the umask
++ * conditionnally (as needed if POSIXACLS is set)
++ * Protocol 7.18 has the ability to process the ioctls
+ */
+-#ifdef POSIXACLS
+- if (arg->major > 7 || (arg->major == 7 && arg->minor >= 12))
++ if (arg->major > 7 || (arg->major == 7 && arg->minor >= 18)) {
+ outarg.minor = FUSE_KERNEL_MINOR_VERSION;
+- else
+- outarg.minor = FUSE_KERNEL_MINOR_FALLBACK;
+-#else
+- outarg.minor = FUSE_KERNEL_MINOR_VERSION;
++ if (f->conn.want & FUSE_CAP_IOCTL_DIR)
++ outarg.flags |= FUSE_HAS_IOCTL_DIR;
++#ifdef POSIXACLS
++ if (f->conn.want & FUSE_CAP_DONT_MASK)
++ outarg.flags |= FUSE_DONT_MASK;
+ #endif
++ } else {
++ outarg.major = FUSE_KERNEL_MAJOR_FALLBACK;
++ outarg.minor = FUSE_KERNEL_MINOR_FALLBACK;
++ }
+ if (f->conn.async_read)
+ outarg.flags |= FUSE_ASYNC_READ;
+ if (f->op.getlk && f->op.setlk)
+ outarg.flags |= FUSE_POSIX_LOCKS;
+-#ifdef POSIXACLS
+- if (f->conn.want & FUSE_CAP_DONT_MASK)
+- outarg.flags |= FUSE_DONT_MASK;
+-#endif
+ if (f->conn.want & FUSE_CAP_BIG_WRITES)
+ outarg.flags |= FUSE_BIG_WRITES;
+ outarg.max_readahead = f->conn.max_readahead;
+@@ -1191,6 +1225,7 @@
+ [FUSE_CREATE] = { do_create, "CREATE" },
+ [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" },
+ [FUSE_BMAP] = { do_bmap, "BMAP" },
++ [FUSE_IOCTL] = { do_ioctl, "IOCTL" },
+ [FUSE_DESTROY] = { do_destroy, "DESTROY" },
+ };
+
diff --git a/sys-fs/ntfs3g/files/ntfs3g-2015.3.14-dont-put-things-in-root.patch b/sys-fs/ntfs3g/files/ntfs3g-2015.3.14-dont-put-things-in-root.patch
new file mode 100644
index 000000000000..e86d9defbaea
--- /dev/null
+++ b/sys-fs/ntfs3g/files/ntfs3g-2015.3.14-dont-put-things-in-root.patch
@@ -0,0 +1,30 @@
+install all files into the sbindir since there's no need to split between /sbin and /usr/sbin
+
+--- a/ntfsprogs/Makefile.in
++++ b/ntfsprogs/Makefile.in
+@@ -1348,8 +1348,8 @@ uninstall-man: uninstall-man8
+ # mkfs.ntfs[.8] hard link
+
+ @ENABLE_NTFSPROGS_TRUE@install-exec-hook:
+-@ENABLE_NTFSPROGS_TRUE@ $(INSTALL) -d $(DESTDIR)/sbin
+-@ENABLE_NTFSPROGS_TRUE@ $(LN_S) -f $(sbindir)/mkntfs $(DESTDIR)/sbin/mkfs.ntfs
++@ENABLE_NTFSPROGS_TRUE@ $(INSTALL) -d $(DESTDIR)/$(sbindir)
++@ENABLE_NTFSPROGS_TRUE@ $(LN_S) -f mkntfs $(DESTDIR)/$(sbindir)/mkfs.ntfs
+
+ @ENABLE_NTFSPROGS_TRUE@install-data-hook:
+ @ENABLE_NTFSPROGS_TRUE@ $(INSTALL) -d $(DESTDIR)$(man8dir)
+--- a/src/Makefile.in
++++ b/src/Makefile.in
+@@ -1040,9 +1040,9 @@ uninstall-man: uninstall-man8
+ @ENABLE_NTFS_3G_TRUE@@RUN_LDCONFIG_TRUE@ $(LDCONFIG)
+
+ @ENABLE_MOUNT_HELPER_TRUE@@ENABLE_NTFS_3G_TRUE@install-exec-local: install-rootbinPROGRAMS
+-@ENABLE_MOUNT_HELPER_TRUE@@ENABLE_NTFS_3G_TRUE@ $(MKDIR_P) "$(DESTDIR)/sbin"
+-@ENABLE_MOUNT_HELPER_TRUE@@ENABLE_NTFS_3G_TRUE@ $(LN_S) -f "$(rootbindir)/ntfs-3g" "$(DESTDIR)/sbin/mount.ntfs-3g"
+-@ENABLE_MOUNT_HELPER_TRUE@@ENABLE_NTFS_3G_TRUE@ $(LN_S) -f "$(rootbindir)/lowntfs-3g" "$(DESTDIR)/sbin/mount.lowntfs-3g"
++@ENABLE_MOUNT_HELPER_TRUE@@ENABLE_NTFS_3G_TRUE@ $(MKDIR_P) "$(DESTDIR)/$(sbindir)"
++@ENABLE_MOUNT_HELPER_TRUE@@ENABLE_NTFS_3G_TRUE@ $(LN_S) -f "../bin/ntfs-3g" "$(DESTDIR)/$(sbindir)/mount.ntfs-3g"
++@ENABLE_MOUNT_HELPER_TRUE@@ENABLE_NTFS_3G_TRUE@ $(LN_S) -f "../bin/lowntfs-3g" "$(DESTDIR)/$(sbindir)/mount.lowntfs-3g"
+
+ @ENABLE_NTFS_3G_TRUE@install-data-local: install-man8
+ @ENABLE_NTFS_3G_TRUE@ $(LN_S) -f ntfs-3g.8 "$(DESTDIR)$(man8dir)/mount.ntfs-3g.8"