Revision bump, add upstream patches to support fstrim. Make sure everything is in...
authorPatrick McLean <chutzpah@gentoo.org>
Thu, 29 Jan 2015 08:20:19 +0000 (08:20 +0000)
committerPatrick McLean <chutzpah@gentoo.org>
Thu, 29 Jan 2015 08:20:19 +0000 (08:20 +0000)
Package-Manager: portage-2.2.15/cvs/Linux x86_64
Manifest-Sign-Key: 0xE3F69979BB4B8928DA78E3D17CBF44EF

sys-fs/ntfs3g/ChangeLog
sys-fs/ntfs3g/Manifest
sys-fs/ntfs3g/files/ntfs3g-2014.2.15-dont-put-things-in-root.patch [new file with mode: 0644]
sys-fs/ntfs3g/files/ntfs3g-2014.2.15-fix-fstrim-applied-to-partitons.patch [new file with mode: 0644]
sys-fs/ntfs3g/files/ntfs3g-2014.2.15-implement-fstrim.patch [new file with mode: 0644]
sys-fs/ntfs3g/files/ntfs3g-2014.2.15-update-fuse-lite-to-support-ioctls.patch [new file with mode: 0644]
sys-fs/ntfs3g/ntfs3g-2014.2.15-r1.ebuild [new file with mode: 0644]

index 2a18b7c18b2a45a0ce3847d6cad4f3fe4a88b32d..d05b20b9379f548630c392b6259d6ed1a9cb42b2 100644 (file)
@@ -1,6 +1,19 @@
 # ChangeLog for sys-fs/ntfs3g
-# Copyright 1999-2014 Gentoo Foundation; Distributed under the GPL v2
-# $Header: /var/cvsroot/gentoo-x86/sys-fs/ntfs3g/ChangeLog,v 1.159 2014/04/13 15:02:30 vapier Exp $
+# Copyright 1999-2015 Gentoo Foundation; Distributed under the GPL v2
+# $Header: /var/cvsroot/gentoo-x86/sys-fs/ntfs3g/ChangeLog,v 1.160 2015/01/29 08:20:05 chutzpah Exp $
+
+*ntfs3g-2014.2.15-r1 (29 Jan 2015)
+
+  29 Jan 2015; Patrick McLean <chutzpah@gentoo.org>
+  +ntfs3g-2014.2.15-r1.ebuild,
+  +files/ntfs3g-2014.2.15-dont-put-things-in-root.patch,
+  +files/ntfs3g-2014.2.15-fix-fstrim-applied-to-partitons.patch,
+  +files/ntfs3g-2014.2.15-implement-fstrim.patch,
+  +files/ntfs3g-2014.2.15-update-fuse-lite-to-support-ioctls.patch:
+  Revision bump, add upstream patches to support fstrim. Make sure everything
+  is in /usr/{s,}bin rather than making some symlinks in /{s,}bin. Set LD to
+  make sure to use the bfd linker, even when the system linker is set to gold
+  (bug #450024)
 
   13 Apr 2014; Mike Frysinger <vapier@gentoo.org>
   +files/ntfs3g-2014.2.15-no-split-usr.patch, ntfs3g-2014.2.15.ebuild:
index 105832df3b3135ceecbc8c5690017628578f465f..9a1f0c9c5d583420e9ed1c76ecfd76f8f83c636f 100644 (file)
@@ -2,27 +2,32 @@
 Hash: SHA256
 
 AUX 99-ntfs3g.rules 51 SHA256 912165f71bbcae4753cd10a74c78bfd98e49bd9adbf80b96c39fc6738b12d463 SHA512 9310dd1dceec9a6252d3e8b95a9a1002c84a6f077457892eefe1255c85557041defbd8dcf6acef86285b45abd8bbe85822dd59a9e4c307bba80dd2c17f971851 WHIRLPOOL 9a0439ceb3bb1f142ee1929c03dab22066fdb3dba85c216265f6f10f3e9e2416beb4f3a73c8965b621b8d7b34c467a81628b6656f59e4c51e9fd529007f7ca27
+AUX ntfs3g-2014.2.15-dont-put-things-in-root.patch 1603 SHA256 49533f7afc92b68194af50d026f5963dbe7065eb4d771b9d03eca9d5fe803ed4 SHA512 c5e501ed0b45f45013e15b2df6b345d8deaa8ba32e7792304aec2ff32fb0c799bfccfe951019708ae7681c4353d79c09fcc5925da8d9bfd008c4c01981be90dc WHIRLPOOL 91120648217506fb9cd15ed40e2569452c6e16cecd60f32a441817a9bbb33b96fdcba57206f55dfb54e428463b6773e91be7ced14408a9d8e5f71fc440992828
+AUX ntfs3g-2014.2.15-fix-fstrim-applied-to-partitons.patch 6124 SHA256 8ae05ab8729b5832776e753a89224d603be1b4d8c18578ff8f886d4814cd98aa SHA512 e85ff66757465b4090167c8f12d72b3ee4c003502de2f122c418987e6bdc0366288e9bc674625964dca5e17b4511fc9b89b0c2f8653401f490a1889d008946da WHIRLPOOL 444b6339dbe9b74138eaba7b10b4fde539068f7a3e7993c9001ada13ba8a8d4fee3f870692f3af41c9ff31244c1b3127efa38222eec32029352d7d6a60ff29e0
+AUX ntfs3g-2014.2.15-implement-fstrim.patch 18171 SHA256 fc9ff216641ffd43de9442b4341fa5f73ef2cfbc99b7495a7139b31c42b42f5a SHA512 8f8a3112c864b72540f4d581fab7e68c7c5b2fb5b11865e6c4ab2af80630891fe086480af15fdb820ac54e327e843b6f8a854da257ed5ac9291b530e83b981f3 WHIRLPOOL 8bdd4e315dfe09e62fa932a46055c5adb090042fd533013fe937f3486e87b657d39818580d38a2dbc22d7c4f9f76102ced6ae62d9c62216fe9718028831175cf
 AUX ntfs3g-2014.2.15-no-split-usr.patch 1322 SHA256 3fdd9b2947e1ded82258a86d55d481d641613d8ff916f6eeacc6c0e68042beb8 SHA512 232a1a7b84339c86758365564fce2058c3e652f833c6908245aa5f6f0e91d5c09cedcb978a1ebe62897c7288df4fe8671ba7085af403056742d897181e479e05 WHIRLPOOL 733bcf75833bcd57f90fc69e55e6b4698470d92c4494cc4a567ba8b4ea562437587d13a1278b766f77ff16097057e3a9a0abfbb131466957a5d14bac0f3f37c9
+AUX ntfs3g-2014.2.15-update-fuse-lite-to-support-ioctls.patch 17856 SHA256 a5d7eccf79410491670881c47a4ed55e64c2c3211aa128e96f2ace7b021e1d78 SHA512 8af8cee87f5effd1cf8133f7e6dc5213dc798177c4bfd73d1b618158d94b22cab6aaf12e7ed2faed8d6a29f9f85bbb09b83548d4da6ccecc6b1716c457c506e9 WHIRLPOOL a96eeea001e7ecfbeed0f498a35141a1b2757eca7f63b6203da56833daa99c6ea5978d094419755580448883459a2fe092faa3cbabefa740e0e37dfbc60cf3e5
 DIST ntfs-3g_ntfsprogs-2013.1.13.tgz 1176304 SHA256 4b383f0074a3ab7683339d1f18222b107aaeb4983db119292c43c2b275cefb27 SHA512 34cc930320a9a54df406d0fdd71154503bac1181b5642382fcb38fa8c51235fa252c74a5c1ab06019972a236bbd717b47d2acbc7581a747657e4f7a8f216d8bc WHIRLPOOL 7a1c8ec1d93741f564053a9eb8f1c0e5511b23079ab2db6f0dd328d2d49572db22903fc9f15aa1bd6d9faad510c908a59fe22eaaa465d3519318579a75d1e89a
 DIST ntfs-3g_ntfsprogs-2014.2.15.tgz 1143575 SHA256 4c3099400cb14b231a3c9d718b3a8d152d38555059341ce5fc6d02292a4a5b56 SHA512 7e4a5c9ac9d43dcf0d4b4085dea6703126fc4808cb9e1b7038884b20df2a8ab8f54c269d7204a279b62c5ba1127a966fd64226a8ed8f0c11667d9326c2f8fa7c WHIRLPOOL 33931d50ba548cf309849b07e22068106b19caebe9f66f8a8d59e19c75fdbf282c9683656042452ba54ad160b3ebc7d098e90b7ad991316e3e5ff0c27f1c6e83
 EBUILD ntfs3g-2013.1.13.ebuild 2434 SHA256 b8c975febe41bec165ebd20ae039053c399e9de96ea9797a30d50b9950f023dd SHA512 a77afdd789778b2fec5c1dcb43780c738ab0f2c329c829fa3d2b0c8daaaa104255e019e9c8dcf1e053ee98664b24f22355a0d636deb8af1cf1dff2df8c0353d1 WHIRLPOOL 9775e88ed92cbb6f946fc354c48d303825252b56bf3f19d1a814388131d2093f67cd148cc468c9fe3c4380b208b06b6e3c3662180f7b04c5648518203f754121
+EBUILD ntfs3g-2014.2.15-r1.ebuild 2292 SHA256 1e0cf3002e1489b72d8a0a2975febce794c000ca2476370e4fb6c75e9510060b SHA512 288227dfb5f25641386bf18cc8e72917b904df71692a77bf0a232b717d0a2b140960b17ddbff0568ceac6d7e8ae3823c3da86b949da824e67c989a2da9a6f090 WHIRLPOOL 976933ecd9b74acf6ad062f949f857e04341edc6329290f1879ddb78c51bf23b58ef1ae5c7893e093cc338d05d4f22894a2b449797814b1b6ab0f9fd929736ac
 EBUILD ntfs3g-2014.2.15.ebuild 2465 SHA256 c6907ae036d3d5b677679e65257f8565d24d0e67cd52161eea43e49480170fd0 SHA512 033c1a0d3c1451ec975d4bdf4545e65301b73fc63095d5f9f351e1496abe01742fde0395079a695c7f2c72067d72e1d835f2666929677c38a867a267a154e5e7 WHIRLPOOL fdec6680ef3ab770966a5590d24db6bbf153eb521c06b37d402eca307a0b11d55678da846ce1fad9f9fcd079800cab1aac292f8640791bd636e6473b62ab8645
-MISC ChangeLog 24932 SHA256 8010b7ed408a90a047def8cfceca7e969f001a5aaab9f3a474c4a950410a5306 SHA512 a0b3fb9595426b821b836ef720dc878944a07bc9b8537914ad211ec332997d16819a9c2b98be0de801735be7fd41f9fd3379355644c08b8db97255d8f6ac71a1 WHIRLPOOL 8286154616d1b2f90c08698cda3ddd4da5ea89180fc3b398c3de50c0e7ffb37af2cc7acc71c16e4b5df528b6e11ff2af33ecda1b81a7afdeb06c16ec21e4bcd4
+MISC ChangeLog 25543 SHA256 58c8244d07c3c932e4ebd291f1235eae80ba0ad69974b02f8c62cbfd4f1e7e15 SHA512 d1ea2d9df1fd77bba306c59980216af00c9eff1de1ab848a6e146c6363b9160f9b428e5b92bda89a3a8378928dfb1a5aef7b895dc5af5c31ee0220c136afa1a8 WHIRLPOOL e59542c5c2d5e3dde12385f51d627ead43b769012c1ad66aa5a9929e8fa18b213d72f2886caa43bf86d76eb574805bf3562d7b3fcd3b07ec0ac6081536b1f216
 MISC metadata.xml 1162 SHA256 45be03e4ef0502e7ea46ece5b46380736f480af8e84e93c87cb26b05c052207d SHA512 6f35bc78044bce54a53834b9c95a37861386b8071b8d7dcfb6576deacc5788077bebd9d7ff5578888ba9f1b6e7ae47a8d04ba970e2441624ec5c4bbafdb39312 WHIRLPOOL b12bcd6a0cc88b881aedd8df7694edd1c655661f6b7fb7d27579da1c2e047a491f11bd96f69caf07161aa1dbb521be1d258de7211fcb8f4315c618d740492ef1
 -----BEGIN PGP SIGNATURE-----
-Version: GnuPG v2.0.22 (GNU/Linux)
+Version: GnuPG v2
 
-iQIcBAEBCAAGBQJTSqcJAAoJEPGu1DbS6WIAGtAP/16kCowqGQDTU5mis0vY9tJ/
-T2pNM++fLagiB30jFwg5yT1Ct3qWVWmZroEEMROBhE65AYyIoSndUrMKE6V2CjMn
-K8sXHShgc54H10dBF5xIwOWVeoxWAZPnAbkBM16b/5ukkkbncW/4GLfqWqACkQ7a
-9DVy8h95XTvE9vCo1BjNr196hheIVI03Nl+/1lp6C7Ha9CiP6c49a2kt1yVVpDaL
-AZiu0Kblm9aSwwBD+qFALszCPLMow9QOoZcC/5J2Ev2pRDiJNb8EU4TGrtHHW3h3
-ssWHPswzR35SS1NIoK8gHgH6fUit+mNTrilip0/aCihaVNls1Awc6oUvIUhZq3xU
-nnU2Ufsj2LFC6oUc3LAkP0yUv21ZToY2860qfD5fv3vt5m+Bk2Ipmfv28tz/gqna
-BGIsOZLfZjJUfo6TQtUVmRGCER5iaiL7/Z7pSxMqRNazvc4CAfdUSyWytMhz0hgx
-hvUs519Ds4tiCvk/VavQDWkYtJ5wLcHfTC3Tel9wIWe86UaDXr9+x1gpDWXa7ojU
-SEYTr1PMOC18AQNC0F3VE1ubAamuWin7P44CvN3c9J/ybkUTJdPIL70FBGK4RHur
-sqxAlbkPg0guv5bAdHhdRLkEoOUjh3Lup7JnVjGeEkd19bMYaushNz6YgHSTYd8B
-R2jSe5+r/6frz94BCEfF
-=xhiT
+iQIcBAEBCAAGBQJUye0/AAoJEHy/RO9cNQiDNtUQAMTSP19+0jeGHf3djj48KSFl
+FW1zT8gWsxhgIxwd/mXNWHlpgWromP7jZKK9UoyQKx6EVcwXW+P2baE8aexh8w/b
+Jpy0yq/9ICxrVrmv9445ahwNaMMnyTo3wB9jght5s14p6STytNO65qqIPMPyizQu
+z1CItGPr+xLBoxJiH/bFokzt44z7LD+rs3cZjf4aLiYcxf3kkx/cx+O8X58tJ4Cy
+QkYSupNKcBUN7BbBJBPmB9DZYs9hwcDrhTYqdU9x0E+cHshjh030OrI3ChCjCmkW
+jhMldqZR9odnE7Cu1j+WKJ7ZWtCyyqnuIKIo7ie/qPTqw6V/Z5uU2QWWffrUcDko
+OvwbyloNhQiB443/rvju/9YHSpJaARdV5Lmq0gntwHvW4GPbFKGFzBPbB0mXTJDb
+tlp9dchOWqmaccwEB/6MIQ4PCCpU+zV/l3ONpUQ3gOpzU5gYZiP8tGSMbvOgtwJJ
+n0plEfzTgU+/yNGJaho35n1vHZ08nWl6QcK3A5XxcfsglClCqmSU1akwF4e2hv5K
+jY0uO9aMDPFnrBkUzPFQGXi+Cm9vOf1nRmPHUToeN/iQRAQcSdnsbaBjDaWJ9HjA
+M8SElJRiHVTR7RuoAQ8WWy+bAxt9OP3E1+IaCt+ZbMkZtPIhKzML39A7SsdfQXzN
+7rOsGUH46yWQYZVuJs9w
+=WOzY
 -----END PGP SIGNATURE-----
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 (file)
index 0000000..66551f1
--- /dev/null
@@ -0,0 +1,37 @@
+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,7 @@
+ # mkfs.ntfs[.8] hard link
+ 
+ install-exec-hook:
+-      $(INSTALL) -d $(DESTDIR)/sbin
+-      $(LN_S) -f $(sbindir)/mkntfs $(DESTDIR)/sbin/mkfs.ntfs
++      $(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,8 @@
+ 
+ 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"
++      $(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 (file)
index 0000000..b67cb71
--- /dev/null
@@ -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 (file)
index 0000000..467f5d6
--- /dev/null
@@ -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-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 (file)
index 0000000..0c9b7cc
--- /dev/null
@@ -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/ntfs3g-2014.2.15-r1.ebuild b/sys-fs/ntfs3g/ntfs3g-2014.2.15-r1.ebuild
new file mode 100644 (file)
index 0000000..eedfc1b
--- /dev/null
@@ -0,0 +1,86 @@
+# Copyright 1999-2015 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: /var/cvsroot/gentoo-x86/sys-fs/ntfs3g/ntfs3g-2014.2.15-r1.ebuild,v 1.1 2015/01/29 08:20:05 chutzpah Exp $
+
+EAPI=5
+inherit eutils linux-info udev autotools
+
+MY_PN=${PN/3g/-3g}
+MY_P=${MY_PN}_ntfsprogs-${PV}
+
+DESCRIPTION="Open source read-write NTFS driver that runs under FUSE"
+HOMEPAGE="http://www.tuxera.com/community/ntfs-3g-download/"
+SRC_URI="http://tuxera.com/opensource/${MY_P}.tgz"
+
+LICENSE="GPL-2"
+SLOT="0"
+KEYWORDS="~alpha ~amd64 ~arm ~ppc ~ppc64 ~sparc ~x86 ~amd64-linux ~arm-linux ~x86-linux"
+IUSE="acl debug +external-fuse ntfsdecrypt +ntfsprogs static-libs suid xattr"
+
+RDEPEND="!<sys-apps/util-linux-2.20.1-r2
+       !sys-fs/ntfsprogs
+       ntfsdecrypt? (
+               >=dev-libs/libgcrypt-1.2.2:0
+               >=net-libs/gnutls-1.4.4
+       )
+       external-fuse? ( >=sys-fs/fuse-2.8.0 )"
+DEPEND="${RDEPEND}
+       sys-apps/attr
+       virtual/pkgconfig"
+
+S="${WORKDIR}/${MY_P}"
+
+DOCS="AUTHORS ChangeLog CREDITS README"
+
+PATCHES=(
+       "${FILESDIR}"/${PN}-2014.2.15-no-split-usr.patch
+       "${FILESDIR}"/${PN}-2014.2.15-dont-put-things-in-root.patch
+       "${FILESDIR}"/${P}-update-fuse-lite-to-support-ioctls.patch
+       "${FILESDIR}"/${P}-implement-fstrim.patch
+       "${FILESDIR}"/${P}-fix-fstrim-applied-to-partitons.patch
+)
+
+pkg_setup() {
+       if use external-fuse && use kernel_linux; then
+               if kernel_is lt 2 6 9; then
+                       die "Your kernel is too old."
+               fi
+               CONFIG_CHECK="~FUSE_FS"
+               FUSE_FS_WARNING="You need to have FUSE module built to use ntfs-3g"
+               linux-info_pkg_setup
+       fi
+}
+
+src_prepare() {
+       epatch "${PATCHES[@]}"
+       eautoreconf
+       elibtoolize
+}
+
+src_configure() {
+       LD="$(tc-getLD).bfd" econf \
+               --prefix="${EPREFIX}"/usr \
+               --exec-prefix="${EPREFIX}"/usr \
+               --docdir="${EPREFIX}"/usr/share/doc/${PF} \
+               $(use_enable debug) \
+               --enable-ldscript \
+               --disable-ldconfig \
+               $(use_enable acl posix-acls) \
+               $(use_enable xattr xattr-mappings) \
+               $(use_enable ntfsdecrypt crypto) \
+               $(use_enable ntfsprogs) \
+               --without-uuid \
+               --enable-extras \
+               $(use_enable static-libs static) \
+               --with-fuse=$(usex external-fuse external internal)
+}
+
+src_install() {
+       default
+
+       use suid && fperms u+s /usr/bin/${MY_PN}
+       udev_dorules "${FILESDIR}"/99-ntfs3g.rules
+       prune_libtool_files
+
+       dosym mount.ntfs-3g /usr/sbin/mount.ntfs #374197
+}