summaryrefslogtreecommitdiff
path: root/filesystems/ntfs/files
diff options
context:
space:
mode:
Diffstat (limited to 'filesystems/ntfs/files')
-rw-r--r--filesystems/ntfs/files/README.FreeBSD126
-rw-r--r--filesystems/ntfs/files/extra-patch-ublio27
-rw-r--r--filesystems/ntfs/files/patch-configure30
-rw-r--r--filesystems/ntfs/files/patch-libntfs-3g__unix_io.c623
-rw-r--r--filesystems/ntfs/files/patch-ntfsprogs_mkntfs.c18
-rw-r--r--filesystems/ntfs/files/pkg-message.in13
6 files changed, 837 insertions, 0 deletions
diff --git a/filesystems/ntfs/files/README.FreeBSD b/filesystems/ntfs/files/README.FreeBSD
new file mode 100644
index 000000000000..ffaedb7707c3
--- /dev/null
+++ b/filesystems/ntfs/files/README.FreeBSD
@@ -0,0 +1,126 @@
+==============================================================================
+NTFS-3G README for the FreeBSD port
+==============================================================================
+
+1. Introduction
+2. Port specific notes
+3. Mounting at startup with /etc/fstab
+4. Ublio configuration
+5. Known issues
+
+==============================================================================
+1. Introduction
+==============================================================================
+
+The NTFS-3G project provides a read/write filesystem driver for NTFS. It uses
+the FUSE library (an OS-independent library to create filesystem drivers) and
+FreeBSD fusefs(5) kernel module (port of the kernel-dependent part of FUSE).
+For more information see:
+
+NTFS-3G site: https://github.com/tuxera/ntfs-3g
+FUSE site: https://github.com/libfuse/libfuse
+
+==============================================================================
+2. Port specific notes
+==============================================================================
+
+The port has a patch to align read/write operations to the media block size
+(required on FreeBSD).
+
+The port has 2 options: LOCK (to prevent access to the device by external
+programs than NTFS-3G once mounted, default on Linux), and UBLIO (use a user
+space cache library, see devel/libublio, not required on Linux).
+
+The reason for using UBLIO is that FreeBSD removed support for block devices,
+being them now character devices. The former ones had a cache, and NTFS-3G was
+optimized for it (Linux still uses them). The same happens on Mac OS X (based
+on FreeBSD 5). So using UBLIO both improves performance (~10 times faster),
+and reduces disk load.
+
+==============================================================================
+3. Mounting at startup with /etc/fstab
+==============================================================================
+
+To mount at startup you need to have the following line in /boot/loader.conf:
+
+ fusefs_load="YES"
+
+or have "fusefs" added to the "kld_list" in the /etc/rc.conf.
+
+Then create the following symlink:
+
+$ ln -s `which ntfs-3g` /usr/sbin/mount_ntfs-3g
+
+And add the appropriate line to /etc/fstab: the filesystem should be "ntfs-3g"
+instead of "ntfs", and the additional "late" parameter is required. Example:
+
+/dev/ad4s1 /wxp ntfs-3g rw,late 0 0
+
+==============================================================================
+4. Ublio configuration
+==============================================================================
+
+The UBLIO layer is configured through environment variables, which are read
+when mounting the filesystem. The following are available:
+
+NTFS_USE_UBLIO - Enable the UBLIO cache.
+UBLIO_BLOCKSIZE - Actual reads/writes will be multiples of this quantity.
+UBLIO_ITEMS - Number of cache entries, each of UBLIO_BLOCKSIZE length.
+UBLIO_GRACE - Number of times a cache entry will refuse being recycled.
+UBLIO_SYNC_IO - If enabled, all writes will be immediately executed.
+
+To give an idea about tuning, here are the default values with some notes
+(they are only based on some simple benchmarks, and may be wrong):
+
+NTFS_USE_UBLIO - 1. Disabling it drastically decreases performance.
+UBLIO_BLOCKSIZE - 262144 (256KB). Larger improves reading/writing speed of
+ large files, and smaller makes filesystem operations
+ (creation, deletion, moving, find(1)) perform faster.
+ Try 2/4MB and 512/256KB for the different approaches. Note
+ that after that points performance decreases again.
+UBLIO_ITEMS - 64. Higher increases speed of filesystem operations. Try 128.
+UBLIO_GRACE - 32. Makes the cache items have more chances to be reused.
+UBLIO_SYNC_IO - 0. If enabled, highly decreases writing speed, but the data
+ is immediately written to the disk.
+
+For example (improves performance over large files, but read below):
+
+# env UBLIO_BLOCKSIZE=2097152 ntfs-3g /dev/ad0s1 /mnt
+
+Alternatively these variables could be set in the shell startup file. For
+example if you are using it in /etc/fstab add them to /etc/profile. If you use
+it as a user, instead, editing the shell startup in HOME is enough.
+
+Note that higher values for UBLIO_BLOCKSIZE and UBLIO_ITEMS increase the
+memory usage by their product in bytes. For example, if you set it to 1MB it
+would consume 64MB. To decrease it to 16MB you could set UBLIO_BLOCKSIZE to
+256KB (currently this is the default). Small values like 4096 can be used and
+also perform fine.
+
+It is also possible to enforce block aligned I/O on regular files by setting
+the FORCE_ALIGNED_IO variable (it will be set to 512 bytes), but this is only
+useful for testing purposes and in practice has no use.
+
+==============================================================================
+5. Known issues
+==============================================================================
+
+- For mkntfs(8) -F must be used to allow non-block device to be processed.
+
+- Current implementation does not properly work with partitions of size which
+is not a multiply of UBLIO_BLOCKSIZE (cannot read/write last cluster). For
+instance, you may not be able to create ntfs filesystem because of this with
+
+ Initializing device with zeroes: 99%Failed to complete writing to
+ /dev/ada0s1 after three retries.
+
+- When reading/writing the same file repeatedly while doing many simultaneous
+operations on different files sometimes the former one fails: read(2) returns
+-1 and sets errno to EAGAIN. This is because of a difference between the FUSE
+kernel implementation in Linux and FreeBSD, and is being worked on. An example
+scenario would be playing a song in XMMS, while building many ports, which
+could cause XMMS skip the song. Another observed problem is the current
+directory not being found, but entering again would work (Linux access is
+path-based while FreeBSD is vnode-based, which may be reused).
+
+==============================================================================
diff --git a/filesystems/ntfs/files/extra-patch-ublio b/filesystems/ntfs/files/extra-patch-ublio
new file mode 100644
index 000000000000..36f1bb32acc9
--- /dev/null
+++ b/filesystems/ntfs/files/extra-patch-ublio
@@ -0,0 +1,27 @@
+--- ./libntfs-3g/Makefile.in.orig 2012-08-29 19:51:35.000000000 -0500
++++ ./libntfs-3g/Makefile.in 2012-08-29 20:00:20.000000000 -0500
+@@ -251,6 +251,7 @@
+ @INSTALL_LIBRARY_FALSE@noinst_LTLIBRARIES = libntfs-3g.la
+ libntfs_3g_la_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/include/ntfs-3g
+ libntfs_3g_la_LDFLAGS = -version-info $(LIBNTFS_3G_VERSION) -no-undefined
++libntfs_3g_la_LIBADD = -lublio
+ libntfs_3g_la_SOURCES = acls.c attrib.c attrlist.c bitmap.c bootsect.c \
+ cache.c collate.c compat.c compress.c debug.c device.c dir.c \
+ efs.c index.c inode.c lcnalloc.c logfile.c logging.c mft.c \
+--- src/ntfs-3g.c.orig 2011-04-10 20:04:41.000000000 +0200
++++ src/ntfs-3g.c 2011-04-25 18:56:07.000000000 +0200
+@@ -3262,9 +3262,13 @@
+ #else
+ .utime = ntfs_fuse_utime,
+ #endif
++#ifndef __FreeBSD__
++ .bmap = ntfs_fuse_bmap,
++#else
++ .bmap = NULL,
++#endif
+ .fsync = ntfs_fuse_fsync,
+ .fsyncdir = ntfs_fuse_fsync,
+- .bmap = ntfs_fuse_bmap,
+ .destroy = ntfs_fuse_destroy2,
+ #if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
+ .access = ntfs_fuse_access,
diff --git a/filesystems/ntfs/files/patch-configure b/filesystems/ntfs/files/patch-configure
new file mode 100644
index 000000000000..cee7cc4a9090
--- /dev/null
+++ b/filesystems/ntfs/files/patch-configure
@@ -0,0 +1,30 @@
+--- configure.orig 2017-03-23 09:42:56 UTC
++++ configure
+@@ -12871,7 +12871,7 @@ $as_echo_n "checking fuse compatibility... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking fuse compatibility" >&5
+ $as_echo_n "checking fuse compatibility... " >&6; }
+ case "${target_os}" in
+- linux*|solaris*)
++ freebsd*|linux*|solaris*)
+
+ # Check whether --with-fuse was given.
+ if test "${with_fuse+set}" = set; then :
+@@ -12885,9 +12885,6 @@ fi
+ darwin*|netbsd*|kfreebsd*-gnu)
+ with_fuse="external"
+ ;;
+- freebsd*)
+- as_fn_error $? "Please see FreeBSD support at http://www.freshports.org/sysutils/fusefs-ntfs" "$LINENO" 5
+- ;;
+ *)
+ as_fn_error $? "ntfs-3g can be built for Linux, FreeBSD, Mac OS X, NetBSD, and Solaris only." "$LINENO" 5
+ ;;
+@@ -15177,7 +15174,7 @@ fi
+ fi
+
+ # Settings
+-pkgconfigdir="\$(libdir)/pkgconfig"
++pkgconfigdir="\$(prefix)/libdata/pkgconfig"
+ ntfs3gincludedir="\$(includedir)/ntfs-3g"
+ # Executables should be installed to the root filesystem, otherwise
+ # automounting NTFS volumes can fail during boot if the driver binaries
diff --git a/filesystems/ntfs/files/patch-libntfs-3g__unix_io.c b/filesystems/ntfs/files/patch-libntfs-3g__unix_io.c
new file mode 100644
index 000000000000..b3e4c3dad80a
--- /dev/null
+++ b/filesystems/ntfs/files/patch-libntfs-3g__unix_io.c
@@ -0,0 +1,623 @@
+--- libntfs-3g/unix_io.c.orig 2010-03-06 13:12:25.000000000 -0300
++++ libntfs-3g/unix_io.c 2010-10-04 15:17:18.000000000 -0300
+@@ -54,6 +54,22 @@
+ #include <linux/fd.h>
+ #endif
+
++/*
++ * The following build definitions are available:
++ * USE_ALIGNED_IO - All I/O is done by blocks.
++ * USE_UBLIO - Use the ublio user space cache library.
++ * USE_LOCK - Lock the device/file when mounted.
++ */
++
++#ifdef __FreeBSD__
++#include <sys/disk.h>
++#define USE_ALIGNED_IO 1
++#endif
++
++#if USE_UBLIO
++#include <sys/uio.h>
++#endif
++
+ #include "types.h"
+ #include "mst.h"
+ #include "debug.h"
+@@ -61,13 +77,90 @@
+ #include "logging.h"
+ #include "misc.h"
+
+-#define DEV_FD(dev) (*(int *)dev->d_private)
++#if USE_UBLIO
++#define UBLIO_USE_API 1
++#include "ublio.h"
++#define UBLIO_DEFAULT_ENABLE 1
++#define UBLIO_DEFAULT_BLOCKSIZE 262144
++#define UBLIO_DEFAULT_ITEMS 64
++#define UBLIO_DEFAULT_GRACE 32
++#define UBLIO_DEFAULT_SYNC_IO 0
++#endif
++
++#if USE_ALIGNED_IO
++#define RAW_IO_ALIGNED(dev, offset, count) \
++ (DEV_HANDLE(dev)->block_size == 0 || \
++ ((offset) % DEV_HANDLE(dev)->block_size == 0 && \
++ (count) % DEV_HANDLE(dev)->block_size == 0))
++#define RAW_IO_ALIGN(dev, offset) \
++ ((offset) / DEV_HANDLE(dev)->block_size * DEV_HANDLE(dev)->block_size)
++#define RAW_IO_MAX_SIZE (128 * 1024 * 1024)
++#endif
++
++struct unix_filehandle {
++ int fd;
++#if USE_ALIGNED_IO
++ s64 pos;
++ s32 block_size;
++ s64 media_size;
++#endif
++#if USE_UBLIO
++ ublio_filehandle_t ublio_fh;
++#endif
++};
++
++#define DEV_HANDLE(dev) ((struct unix_filehandle *)dev->d_private)
++#define DEV_FD(dev) (DEV_HANDLE(dev)->fd)
+
+ /* Define to nothing if not present on this system. */
+ #ifndef O_EXCL
+ # define O_EXCL 0
+ #endif
+
++#if USE_ALIGNED_IO
++/**
++ * Get block_size and media_size
++ */
++static int
++raw_io_get_size(struct ntfs_device *dev)
++{
++ int bs;
++ off_t ms;
++ struct stat sb;
++
++ if (fstat(DEV_FD(dev), &sb) < 0) {
++ ntfs_log_perror("Failed to stat '%s'", dev->d_name);
++ return -1;
++ }
++
++ if (S_ISREG(sb.st_mode)) {
++ DEV_HANDLE(dev)->media_size = sb.st_size;
++ ntfs_log_trace("%s: regular file (media_size %lld)\n",
++ dev->d_name, DEV_HANDLE(dev)->media_size);
++ if (getenv("FORCE_ALIGNED_IO"))
++ DEV_HANDLE(dev)->block_size = 512;
++ return 0;
++ }
++
++ if (ioctl(DEV_FD(dev), DIOCGSECTORSIZE, &bs) < 0) {
++ ntfs_log_perror("Failed to ioctl(DIOCGSECTORSIZE) '%s'",
++ dev->d_name);
++ return -1;
++ }
++ DEV_HANDLE(dev)->block_size = bs;
++ ntfs_log_trace("%s: block size %d\n", dev->d_name, bs);
++
++ if (ioctl(DEV_FD(dev), DIOCGMEDIASIZE, &ms) < 0) {
++ ntfs_log_perror("Failed to ioctl(DIOCGMEDIASIZE) '%s'",
++ dev->d_name);
++ return -1;
++ }
++ DEV_HANDLE(dev)->media_size = ms;
++ ntfs_log_trace("%s: media size %lld\n", dev->d_name, ms);
++ return 0;
++}
++#endif
++
+ /**
+ * fsync replacement which makes every effort to try to get the data down to
+ * disk, using different means for different operating systems. Specifically,
+@@ -113,9 +206,21 @@
+ */
+ static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags)
+ {
++#if USE_ALIGNED_IO
++ size_t sectsize;
++#endif
++#if USE_LOCK
+ struct flock flk;
++#endif
+ struct stat sbuf;
+- int err;
++ struct unix_filehandle *ufh;
++ int err = 0;
++ int is_special = 0;
++#if USE_UBLIO
++ struct ublio_param up;
++ int use_ublio = 0;
++ char *xenv, *xgarbage;
++#endif
+
+ if (NDevOpen(dev)) {
+ errno = EBUSY;
+@@ -125,20 +230,28 @@
+ ntfs_log_perror("Failed to access '%s'", dev->d_name);
+ return -1;
+ }
+- if (S_ISBLK(sbuf.st_mode))
+- NDevSetBlock(dev);
++ if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode))
++ is_special = 1;
+
+- dev->d_private = ntfs_malloc(sizeof(int));
+- if (!dev->d_private)
++ ufh = ntfs_malloc(sizeof(*ufh));
++ if (!ufh)
+ return -1;
++ dev->d_private = ufh;
++#if USE_ALIGNED_IO
++ ufh->fd = -1;
++ ufh->pos = 0;
++ ufh->block_size = 0;
++ ufh->media_size = 0;
++#endif
++
+ /*
+ * Open file for exclusive access if mounting r/w.
+ * Fuseblk takes care about block devices.
+ */
+- if (!NDevBlock(dev) && (flags & O_RDWR) == O_RDWR)
++ if (!is_special && (flags & O_RDWR) == O_RDWR)
+ flags |= O_EXCL;
+- *(int*)dev->d_private = open(dev->d_name, flags);
+- if (*(int*)dev->d_private == -1) {
++ ufh->fd = open(dev->d_name, flags);
++ if (ufh->fd == -1) {
+ err = errno;
+ goto err_out;
+ }
+@@ -146,6 +259,37 @@
+ if ((flags & O_RDWR) != O_RDWR)
+ NDevSetReadOnly(dev);
+
++#if USE_UBLIO
++ ufh->ublio_fh = NULL;
++ if ((xenv = getenv("NTFS_USE_UBLIO")) &&
++ (xenv[0] == '0' || xenv[0] == '1') && xenv[1] == '\0')
++ use_ublio = (xenv[0] == '1');
++ else
++ use_ublio = UBLIO_DEFAULT_ENABLE;
++ if ((xenv = getenv("UBLIO_BLOCKSIZE")))
++ up.up_blocksize = strtoul(xenv, &xgarbage, 10);
++ if (!xenv || *xgarbage != '\0')
++ up.up_blocksize = UBLIO_DEFAULT_BLOCKSIZE;
++ if ((xenv = getenv("UBLIO_ITEMS")))
++ up.up_items = strtoul(xenv, &xgarbage, 10);
++ if (!xenv || *xgarbage != '\0')
++ up.up_items = UBLIO_DEFAULT_ITEMS;
++ if ((xenv = getenv("UBLIO_GRACE")))
++ up.up_grace = strtoul(xenv, &xgarbage, 10);
++ if (!xenv || *xgarbage != '\0')
++ up.up_grace = UBLIO_DEFAULT_GRACE;
++ if ((xenv = getenv("UBLIO_SYNC_IO")) &&
++ (xenv[0] == '0' || xenv[0] == '1') && xenv[1] == '\0')
++ up.up_sync_io = (xenv[0] == '1');
++ else
++ up.up_sync_io = UBLIO_DEFAULT_SYNC_IO;
++ up.up_priv = &ufh->fd;
++ up.up_pread = NULL;
++ up.up_preadv = NULL;
++ up.up_pwrite = NULL;
++ up.up_pwritev = NULL;
++#endif
++#if USE_LOCK
+ memset(&flk, 0, sizeof(flk));
+ if (NDevReadOnly(dev))
+ flk.l_type = F_RDLCK;
+@@ -153,7 +297,21 @@
+ flk.l_type = F_WRLCK;
+ flk.l_whence = SEEK_SET;
+ flk.l_start = flk.l_len = 0LL;
+- if (fcntl(DEV_FD(dev), F_SETLK, &flk)) {
++#endif
++#if USE_ALIGNED_IO
++ if (raw_io_get_size(dev) < 0) {
++ err = errno;
++ close(DEV_FD(dev));
++ goto err_out;
++ }
++ if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode))
++ NDevSetBlock(dev);
++#else
++ if (S_ISBLK(sbuf.st_mode))
++ NDevSetBlock(dev);
++#endif /* USE_ALIGNED_IO */
++#if USE_LOCK
++ if (!NDevBlock(dev) && fcntl(DEV_FD(dev), F_SETLK, &flk)) {
+ err = errno;
+ ntfs_log_perror("Failed to %s lock '%s'", NDevReadOnly(dev) ?
+ "read" : "write", dev->d_name);
+@@ -161,7 +319,16 @@
+ ntfs_log_perror("Failed to close '%s'", dev->d_name);
+ goto err_out;
+ }
+-
++#endif
++#if USE_UBLIO
++ if (use_ublio) {
++ ufh->ublio_fh = ublio_open(&up);
++ if (!ufh->ublio_fh) {
++ close(DEV_FD(dev));
++ goto err_out;
++ }
++ }
++#endif
+ NDevSetOpen(dev);
+ return 0;
+ err_out:
+@@ -181,7 +348,10 @@
+ */
+ static int ntfs_device_unix_io_close(struct ntfs_device *dev)
+ {
++ /* XXX no error if fysnc, fcntl (ublio_close) fails? */
++#if USE_LOCK
+ struct flock flk;
++#endif
+
+ if (!NDevOpen(dev)) {
+ errno = EBADF;
+@@ -194,12 +364,18 @@
+ return -1;
+ }
+
++#if USE_LOCK
+ memset(&flk, 0, sizeof(flk));
+ flk.l_type = F_UNLCK;
+ flk.l_whence = SEEK_SET;
+ flk.l_start = flk.l_len = 0LL;
+- if (fcntl(DEV_FD(dev), F_SETLK, &flk))
++ if (!NDevBlock(dev) && fcntl(DEV_FD(dev), F_SETLK, &flk))
+ ntfs_log_perror("Could not unlock %s", dev->d_name);
++#endif
++#if USE_UBLIO
++ if (DEV_HANDLE(dev)->ublio_fh)
++ ublio_close(DEV_HANDLE(dev)->ublio_fh);
++#endif
+ if (close(DEV_FD(dev))) {
+ ntfs_log_perror("Failed to close device %s", dev->d_name);
+ return -1;
+@@ -223,9 +399,234 @@
+ static s64 ntfs_device_unix_io_seek(struct ntfs_device *dev, s64 offset,
+ int whence)
+ {
++#if USE_ALIGNED_IO
++ s64 abs_pos;
++
++ ntfs_log_trace("seek offset = 0x%llx, whence = %d.\n", offset, whence);
++ switch (whence) {
++ case SEEK_SET:
++ abs_pos = offset;
++ break;
++
++ case SEEK_CUR:
++ abs_pos = DEV_HANDLE(dev)->pos + offset;
++ break;
++
++ case SEEK_END:
++ abs_pos = DEV_HANDLE(dev)->media_size + offset;
++ break;
++
++ default:
++ ntfs_log_trace("Wrong mode %d.\n", whence);
++ errno = EINVAL;
++ return -1;
++ }
++
++ if (abs_pos < 0 || abs_pos > DEV_HANDLE(dev)->media_size) {
++ ntfs_log_trace("Seeking outsize seekable area.\n");
++ errno = EINVAL;
++ return -1;
++ }
++ DEV_HANDLE(dev)->pos = abs_pos;
++ return abs_pos;
++#else
+ return lseek(DEV_FD(dev), offset, whence);
++#endif
+ }
+
++#if USE_ALIGNED_IO
++
++#if USE_UBLIO
++#define pread_wrap(fd, buf, count, off) \
++ (DEV_HANDLE(fd)->ublio_fh ? \
++ ublio_pread(DEV_HANDLE(fd)->ublio_fh, buf, count, off) : \
++ pread(DEV_FD(fd), buf, count, off))
++#define pwrite_wrap(fd, buf, count, off) \
++ (DEV_HANDLE(fd)->ublio_fh ? \
++ ublio_pwrite(DEV_HANDLE(fd)->ublio_fh, buf, count, off) : \
++ pwrite(DEV_FD(fd), buf, count, off))
++#else
++#define pread_wrap(fd, buf, count, off) \
++ pread(DEV_FD(fd), buf, count, off)
++#define pwrite_wrap(fd, buf, count, off) \
++ pwrite(DEV_FD(fd), buf, count, off)
++#endif
++
++/**
++ * aligned_pread - Perform an aligned positioned read from the device
++ */
++static s64 aligned_pread(struct ntfs_device *dev, void *buf, s64 count, s64 offset)
++{
++ s64 start, start_aligned;
++ s64 end, end_aligned;
++ size_t count_aligned;
++ char *buf_aligned;
++ ssize_t nr;
++
++ /* short-circuit for regular files */
++ start = offset;
++ if (count > RAW_IO_MAX_SIZE)
++ count = RAW_IO_MAX_SIZE;
++ if (RAW_IO_ALIGNED(dev, start, count))
++ return pread_wrap(dev, buf, count, start);
++
++ /*
++ * +- start_aligned +- end_aligned
++ * | |
++ * | +- start +- end |
++ * v v v v
++ * |----------|----------|----------|
++ * ^ ^
++ * +----- count ------+
++ * ^ ^
++ * +-------- count_aligned ---------+
++ */
++ start_aligned = RAW_IO_ALIGN(dev, start);
++ end = start + count;
++ end_aligned = RAW_IO_ALIGN(dev, end) +
++ (RAW_IO_ALIGNED(dev, end, 0) ? 0 : DEV_HANDLE(dev)->block_size);
++ count_aligned = end_aligned - start_aligned;
++ ntfs_log_trace(
++ "%s: count = 0x%llx/0x%x, start = 0x%llx/0x%llx, end = 0x%llx/0x%llx\n",
++ dev->d_name, count, count_aligned,
++ start, start_aligned, end, end_aligned);
++
++ /* allocate buffer */
++ buf_aligned = ntfs_malloc(count_aligned);
++ if (buf_aligned == NULL) {
++ ntfs_log_trace("ntfs_malloc(%d) failed\n", count_aligned);
++ return -1;
++ }
++
++ /* read aligned data */
++ nr = pread_wrap(dev, buf_aligned, count_aligned, start_aligned);
++ if (nr == 0)
++ return 0;
++ if (nr < 0 || nr < start - start_aligned) {
++ free(buf_aligned);
++ return -1;
++ }
++
++ /* copy out */
++ memcpy(buf, buf_aligned + (start - start_aligned), count);
++ free(buf_aligned);
++
++ nr -= start - start_aligned;
++ if (nr > count)
++ nr = count;
++ return nr;
++}
++
++/**
++ * aligned_pwrite - Perform an aligned positioned write from the device
++ */
++static s64 aligned_pwrite(struct ntfs_device *dev, void *buf, s64 count, s64 offset)
++{
++ s64 start, start_aligned;
++ s64 end, end_aligned;
++ size_t count_aligned;
++ char *buf_aligned;
++ ssize_t nw;
++
++ if (NDevReadOnly(dev)) {
++ errno = EROFS;
++ return -1;
++ }
++ NDevSetDirty(dev);
++
++ /* short-circuit for regular files */
++ start = offset;
++ if (count > RAW_IO_MAX_SIZE)
++ count = RAW_IO_MAX_SIZE;
++ if (RAW_IO_ALIGNED(dev, start, count))
++ return pwrite_wrap(dev, buf, count, start);
++
++ /*
++ * +- start_aligned +- end_aligned
++ * | |
++ * | +- start +- end |
++ * v v v v
++ * |----------|----------|----------|
++ * ^ ^
++ * +----- count ------+
++ * ^ ^
++ * +-------- count_aligned ---------+
++ */
++ start_aligned = RAW_IO_ALIGN(dev, start);
++ end = start + count;
++ end_aligned = RAW_IO_ALIGN(dev, end) +
++ (RAW_IO_ALIGNED(dev, end, 0) ? 0 : DEV_HANDLE(dev)->block_size);
++ count_aligned = end_aligned - start_aligned;
++ ntfs_log_trace(
++ "%s: count = 0x%llx/0x%x, start = 0x%llx/0x%llx, end = 0x%llx/0x%llx\n",
++ dev->d_name, count, count_aligned,
++ start, start_aligned, end, end_aligned);
++
++ /* allocate buffer */
++ buf_aligned = ntfs_malloc(count_aligned);
++ if (buf_aligned == NULL) {
++ ntfs_log_trace("ntfs_malloc(%d) failed\n", count_aligned);
++ return -1;
++ }
++
++ /* read aligned lead-in */
++ if (pread_wrap(dev, buf_aligned, DEV_HANDLE(dev)->block_size, start_aligned) != DEV_HANDLE(dev)->block_size) {
++ ntfs_log_trace("read lead-in failed\n");
++ free(buf_aligned);
++ return -1;
++ }
++
++ /* read aligned lead-out */
++ if (end != end_aligned && count_aligned > DEV_HANDLE(dev)->block_size) {
++ if (pread_wrap(dev, buf_aligned + count_aligned - DEV_HANDLE(dev)->block_size, DEV_HANDLE(dev)->block_size, end_aligned - DEV_HANDLE(dev)->block_size) != DEV_HANDLE(dev)->block_size) {
++ ntfs_log_trace("read lead-out failed\n");
++ free(buf_aligned);
++ return -1;
++ }
++ }
++
++ /* copy data to write */
++ memcpy(buf_aligned + (start - start_aligned), buf, count);
++
++ /* write aligned data */
++ nw = pwrite_wrap(dev, buf_aligned, count_aligned, start_aligned);
++ free(buf_aligned);
++ if (nw < 0 || nw < start - start_aligned)
++ return -1;
++
++ nw -= start - start_aligned;
++ if (nw > count)
++ nw = count;
++ return nw;
++}
++
++/**
++ * aligned_read - Perform an aligned read from the device
++ */
++static s64 aligned_read(struct ntfs_device *dev, void *buf, s64 count)
++{
++ s64 nr = aligned_pread(dev, buf, count, DEV_HANDLE(dev)->pos);
++ if (nr > 0)
++ DEV_HANDLE(dev)->pos += nr;
++ return nr;
++}
++
++/**
++ * aligned_write - Perform an aligned read from the device
++ */
++static s64 aligned_write(struct ntfs_device *dev, void *buf, s64 count)
++{
++ s64 nw = aligned_pwrite(dev, buf, count, DEV_HANDLE(dev)->pos);
++ if (nw > 0)
++ DEV_HANDLE(dev)->pos += nw;
++ return nw;
++}
++
++#undef ublio_pwrite
++#undef ublio_pread
++
++#endif
++
+ /**
+ * ntfs_device_unix_io_read - Read from the device, from the current location
+ * @dev:
+@@ -239,6 +640,29 @@
+ static s64 ntfs_device_unix_io_read(struct ntfs_device *dev, void *buf,
+ s64 count)
+ {
++#if USE_ALIGNED_IO
++ return aligned_read(dev, buf, count);
++#elif USE_UBLIO
++ if (DEV_HANDLE(dev)->ublio_fh) {
++ off_t offset;
++ ssize_t res;
++
++ offset = lseek(DEV_FD(dev), 0, SEEK_CUR);
++ if (offset == -1)
++ return -1;
++
++ res = ublio_pread(DEV_HANDLE(dev)->ublio_fh, buf, count,
++ offset);
++ if (res == -1)
++ return -1;
++
++ if (lseek(DEV_FD(dev), res, SEEK_CUR) == -1)
++ return -1;
++
++ return res;
++ }
++#endif
++
+ return read(DEV_FD(dev), buf, count);
+ }
+
+@@ -260,6 +684,28 @@
+ return -1;
+ }
+ NDevSetDirty(dev);
++#if USE_ALIGNED_IO
++ return aligned_write(dev, buf, count);
++#elif USE_UBLIO
++ if (DEV_HANDLE(dev)->ublio_fh)
++ off_t offset;
++ ssize_t res;
++
++ offset = lseek(DEV_FD(dev), 0, SEEK_CUR);
++ if (offset == -1)
++ return -1;
++
++ res = ublio_pwrite(DEV_HANDLE(dev)->ublio_fh, (void *)buf,
++ count, offset);
++ if (res == -1)
++ return -1;
++
++ if (lseek(DEV_FD(dev), res, SEEK_CUR) == -1)
++ return -1;
++
++ return res;
++ }
++#endif
+ return write(DEV_FD(dev), buf, count);
+ }
+
+@@ -277,6 +723,13 @@
+ static s64 ntfs_device_unix_io_pread(struct ntfs_device *dev, void *buf,
+ s64 count, s64 offset)
+ {
++#if USE_ALIGNED_IO
++ return aligned_pread(dev, buf, count, offset);
++#elif USE_UBLIO
++ if (DEV_HANDLE(dev)->ublio_fh)
++ return ublio_pread(DEV_HANDLE(dev)->ublio_fh, buf, count,
++ offset);
++#endif
+ return pread(DEV_FD(dev), buf, count, offset);
+ }
+
+@@ -299,6 +752,13 @@
+ return -1;
+ }
+ NDevSetDirty(dev);
++#if USE_ALIGNED_IO
++ return aligned_pwrite(dev, buf, count, offset);
++#elif USE_UBLIO
++ if (DEV_HANDLE(dev)->ublio_fh)
++ return ublio_pwrite(DEV_HANDLE(dev)->ublio_fh, (void *)buf,
++ count, offset);
++#endif
+ return pwrite(DEV_FD(dev), buf, count, offset);
+ }
+
+@@ -315,7 +775,14 @@
+ int res = 0;
+
+ if (!NDevReadOnly(dev)) {
++#if USE_UBLIO
++ if (DEV_HANDLE(dev)->ublio_fh)
++ res = ublio_fsync(DEV_HANDLE(dev)->ublio_fh);
++ if (!DEV_HANDLE(dev)->ublio_fh || !res)
++ res = ntfs_fsync(DEV_FD(dev));
++#else
+ res = ntfs_fsync(DEV_FD(dev));
++#endif
+ if (res)
+ ntfs_log_perror("Failed to sync device %s", dev->d_name);
+ else
diff --git a/filesystems/ntfs/files/patch-ntfsprogs_mkntfs.c b/filesystems/ntfs/files/patch-ntfsprogs_mkntfs.c
new file mode 100644
index 000000000000..4338563b5e04
--- /dev/null
+++ b/filesystems/ntfs/files/patch-ntfsprogs_mkntfs.c
@@ -0,0 +1,18 @@
+--- ntfsprogs/mkntfs.c.orig 2015-03-14 14:10:12 UTC
++++ ntfsprogs/mkntfs.c
+@@ -3488,6 +3488,7 @@ static BOOL mkntfs_open_partition(ntfs_v
+ goto done;
+ }
+
++#ifndef __FreeBSD__
+ if (!S_ISBLK(sbuf.st_mode)) {
+ ntfs_log_error("%s is not a block device.\n", vol->dev->d_name);
+ if (!opts.force) {
+@@ -3526,6 +3527,7 @@ static BOOL mkntfs_open_partition(ntfs_v
+ ntfs_log_warning("mkntfs forced anyway.\n");
+ #endif
+ }
++#endif
+ /* Make sure the file system is not mounted. */
+ if (ntfs_check_if_mounted(vol->dev->d_name, &mnt_flags)) {
+ ntfs_log_perror("Failed to determine whether %s is mounted", vol->dev->d_name);
diff --git a/filesystems/ntfs/files/pkg-message.in b/filesystems/ntfs/files/pkg-message.in
new file mode 100644
index 000000000000..dad797469e8e
--- /dev/null
+++ b/filesystems/ntfs/files/pkg-message.in
@@ -0,0 +1,13 @@
+[
+{ type: install
+ message: <<EOM
+NTFS-3G has been installed. It requires fusefs(5) support to operate,
+so issue the ``kldload fusefs'' command or ``sysrc kld_list+=fusefs''
+to make it load automatically when the system starts.
+
+For further information, implementation details, and known issues see
+the FreeBSD README (%%DOCSDIR%%/README.FreeBSD) in
+addition to the official README (contains some Linux-specific parts).
+EOM
+}
+]