[haiku-commits] haiku: hrev47115 - src/add-ons/kernel/file_systems/ntfs/libntfs

  • From: Gerasim Troeglazov <3deyes@xxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 14 Apr 2014 13:43:11 +0200 (CEST)

hrev47115 adds 1 changeset to branch 'master'
old head: 02cdea9f9d6d42aebb17dfa38c9140e837adbbe0
new head: d68289f7ae3caa4b0d2b87717966b539632b8146
overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=d68289f+%5E02cdea9

----------------------------------------------------------------------------

d68289f: NTFS: Update libntfs to 2014.2.15

                                   [ Gerasim Troeglazov <3dEyes@xxxxxxxxx> ]

----------------------------------------------------------------------------

Revision:    hrev47115
Commit:      d68289f7ae3caa4b0d2b87717966b539632b8146
URL:         http://cgit.haiku-os.org/haiku/commit/?id=d68289f
Author:      Gerasim Troeglazov <3dEyes@xxxxxxxxx>
Date:        Mon Apr 14 11:35:50 2014 UTC

----------------------------------------------------------------------------

14 files changed, 860 insertions(+), 139 deletions(-)
.../kernel/file_systems/ntfs/libntfs/acls.c      |   2 +-
.../kernel/file_systems/ntfs/libntfs/attrib.c    |  48 +-
.../kernel/file_systems/ntfs/libntfs/attrib.h    |   3 +-
.../kernel/file_systems/ntfs/libntfs/compress.c  |   9 +-
.../kernel/file_systems/ntfs/libntfs/device.c    | 174 ++++-
.../kernel/file_systems/ntfs/libntfs/device.h    |  12 +-
.../kernel/file_systems/ntfs/libntfs/device_io.h |  21 +-
.../kernel/file_systems/ntfs/libntfs/dir.c       |   3 +
.../kernel/file_systems/ntfs/libntfs/dir.h       |   6 +-
.../kernel/file_systems/ntfs/libntfs/logging.c   |   2 +
.../kernel/file_systems/ntfs/libntfs/reparse.c   |   6 +-
.../kernel/file_systems/ntfs/libntfs/security.c  |   2 +
.../kernel/file_systems/ntfs/libntfs/volume.c    |   3 +-
.../kernel/file_systems/ntfs/libntfs/win32_io.c  | 708 +++++++++++++++++--

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/ntfs/libntfs/acls.c 
b/src/add-ons/kernel/file_systems/ntfs/libntfs/acls.c
index fb6e877..76599b4 100644
--- a/src/add-ons/kernel/file_systems/ntfs/libntfs/acls.c
+++ b/src/add-ons/kernel/file_systems/ntfs/libntfs/acls.c
@@ -644,7 +644,7 @@ BOOL ntfs_valid_descr(const char *securattr, unsigned int 
attrsz)
                && ((offgroup + 2) < attrsz)
                && (!offdacl
                        || ((offdacl >= sizeof(SECURITY_DESCRIPTOR_RELATIVE))
-                           && (offdacl+sizeof(ACL) < attrsz)))
+                           && (offdacl+sizeof(ACL) <= attrsz)))
                && (!offsacl
                        || ((offsacl >= sizeof(SECURITY_DESCRIPTOR_RELATIVE))
                            && (offsacl+sizeof(ACL) <= attrsz)))
diff --git a/src/add-ons/kernel/file_systems/ntfs/libntfs/attrib.c 
b/src/add-ons/kernel/file_systems/ntfs/libntfs/attrib.c
index c116d9a..1a9ef37 100644
--- a/src/add-ons/kernel/file_systems/ntfs/libntfs/attrib.c
+++ b/src/add-ons/kernel/file_systems/ntfs/libntfs/attrib.c
@@ -5,7 +5,7 @@
  * Copyright (c) 2002-2005 Richard Russon
  * Copyright (c) 2002-2008 Szabolcs Szakacsits
  * Copyright (c) 2004-2007 Yura Pakhuchiy
- * Copyright (c) 2007-2011 Jean-Pierre Andre
+ * Copyright (c) 2007-2013 Jean-Pierre Andre
  * Copyright (c) 2010      Erik Larsson
  *
  * This program/include file is free software; you can redistribute it and/or
@@ -454,7 +454,8 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES 
type,
        if (type == AT_ATTRIBUTE_LIST)
                a->flags = 0;
 
-       if ((type == AT_DATA) && !a->initialized_size) {
+       if ((type == AT_DATA)
+          && (a->non_resident ? !a->initialized_size : !a->value_length)) {
                /*
                 * Define/redefine the compression state if stream is
                 * empty, based on the compression mark on parent
@@ -4928,7 +4929,7 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const 
s64 newsize);
  *     ENOSPC - There is no enough space in base mft to resize $ATTRIBUTE_LIST.
  */
 static int ntfs_resident_attr_resize_i(ntfs_attr *na, const s64 newsize,
-                       BOOL force_non_resident)
+                       hole_type holes)
 {
        ntfs_attr_search_ctx *ctx;
        ntfs_volume *vol;
@@ -4966,7 +4967,7 @@ static int ntfs_resident_attr_resize_i(ntfs_attr *na, 
const s64 newsize,
         * attribute non-resident if the attribute type supports it. If it is
         * smaller we can go ahead and attempt the resize.
         */
-       if ((newsize < vol->mft_record_size) && !force_non_resident) {
+       if ((newsize < vol->mft_record_size) && (holes != HOLES_NONRES)) {
                /* Perform the resize of the attribute record. */
                if (!(ret = ntfs_resident_attr_value_resize(ctx->mrec, 
ctx->attr,
                                newsize))) {
@@ -5011,7 +5012,7 @@ static int ntfs_resident_attr_resize_i(ntfs_attr *na, 
const s64 newsize,
                 * could cause the attribute to be made resident again,
                 * so size changes are not allowed.
                 */
-               if (force_non_resident) {
+               if (holes == HOLES_NONRES) {
                        ret = 0;
                        if (newsize != na->data_size) {
                                ntfs_log_error("Cannot change size when"
@@ -5022,7 +5023,7 @@ static int ntfs_resident_attr_resize_i(ntfs_attr *na, 
const s64 newsize,
                        return (ret);
                }
                /* Resize non-resident attribute */
-               return ntfs_attr_truncate_i(na, newsize, HOLES_OK);
+               return ntfs_attr_truncate_i(na, newsize, holes);
        } else if (errno != ENOSPC && errno != EPERM) {
                err = errno;
                ntfs_log_perror("Failed to make attribute non-resident");
@@ -5078,7 +5079,7 @@ static int ntfs_resident_attr_resize_i(ntfs_attr *na, 
const s64 newsize,
                ntfs_inode_mark_dirty(tna->ni);
                ntfs_attr_close(tna);
                ntfs_attr_put_search_ctx(ctx);
-               return ntfs_resident_attr_resize_i(na, newsize, 
force_non_resident);
+               return ntfs_resident_attr_resize_i(na, newsize, holes);
        }
        /* Check whether error occurred. */
        if (errno != ENOENT) {
@@ -5098,7 +5099,7 @@ static int ntfs_resident_attr_resize_i(ntfs_attr *na, 
const s64 newsize,
                        ntfs_log_perror("Could not free space in MFT record");
                        return -1;
                }
-               return ntfs_resident_attr_resize_i(na, newsize, 
force_non_resident);
+               return ntfs_resident_attr_resize_i(na, newsize, holes);
        }
 
        /*
@@ -5137,7 +5138,7 @@ static int ntfs_resident_attr_resize_i(ntfs_attr *na, 
const s64 newsize,
                ntfs_attr_put_search_ctx(ctx);
                if (ntfs_inode_add_attrlist(ni))
                        return -1;
-               return ntfs_resident_attr_resize_i(na, newsize, 
force_non_resident);
+               return ntfs_resident_attr_resize_i(na, newsize, holes);
        }
        /* Allocate new mft record. */
        ni = ntfs_mft_record_alloc(vol, ni);
@@ -5158,7 +5159,7 @@ static int ntfs_resident_attr_resize_i(ntfs_attr *na, 
const s64 newsize,
 
        ntfs_attr_put_search_ctx(ctx);
        /* Try to perform resize once again. */
-       return ntfs_resident_attr_resize_i(na, newsize, force_non_resident);
+       return ntfs_resident_attr_resize_i(na, newsize, holes);
 
 resize_done:
        /*
@@ -5179,7 +5180,7 @@ static int ntfs_resident_attr_resize(ntfs_attr *na, const 
s64 newsize)
        int ret; 
        
        ntfs_log_enter("Entering\n");
-       ret = ntfs_resident_attr_resize_i(na, newsize, FALSE);
+       ret = ntfs_resident_attr_resize_i(na, newsize, HOLES_OK);
        ntfs_log_leave("\n");
        return ret;
 }
@@ -5203,7 +5204,7 @@ int ntfs_attr_force_non_resident(ntfs_attr *na)
 {
        int res;
 
-       res = ntfs_resident_attr_resize_i(na, na->data_size, TRUE);
+       res = ntfs_resident_attr_resize_i(na, na->data_size, HOLES_NONRES);
        if (!res && !NAttrNonResident(na)) {
                res = -1;
                errno = EIO;
@@ -5566,7 +5567,7 @@ retry:
                BOOL changed;
 
                if (!(na->data_flags & ATTR_IS_SPARSE)) {
-                       int sparse;
+                       int sparse = 0;
                        runlist_element *xrl;
 
                                /*
@@ -5574,10 +5575,18 @@ retry:
                                 * have to check whether there is a hole
                                 * in the updated region.
                                 */
-                       xrl = na->rl;
-                       if (xrl->lcn == LCN_RL_NOT_MAPPED)
-                               xrl++;
-                       sparse = ntfs_rl_sparse(xrl);
+                       for (xrl = na->rl; xrl->length; xrl++) {
+                               if (xrl->lcn < 0) {
+                                       if (xrl->lcn == LCN_HOLE) {
+                                               sparse = 1;
+                                               break;
+                                       }
+                                       if (xrl->lcn != LCN_RL_NOT_MAPPED) {
+                                               sparse = -1;
+                                               break;
+                                       }
+                               }
+                       }
                        if (sparse < 0) {
                                ntfs_log_error("Could not check whether 
sparse\n");
                                errno = EIO;
@@ -6441,7 +6450,7 @@ static int ntfs_attr_truncate_i(ntfs_attr *na, const s64 
newsize,
                else
                        ret = ntfs_non_resident_attr_shrink(na, fullsize);
        } else
-               ret = ntfs_resident_attr_resize(na, newsize);
+               ret = ntfs_resident_attr_resize_i(na, newsize, holes);
 out:   
        ntfs_log_leave("Return status %d\n", ret);
        return ret;
@@ -6587,7 +6596,8 @@ void *ntfs_attr_readall(ntfs_inode *ni, const ATTR_TYPES 
type,
        
        na = ntfs_attr_open(ni, type, name, name_len);
        if (!na) {
-               ntfs_log_perror("ntfs_attr_open failed");
+               ntfs_log_perror("ntfs_attr_open failed, inode %lld attr 0x%lx",
+                               (long long)ni->mft_no,(long)le32_to_cpu(type));
                goto err_exit;
        }
        data = ntfs_malloc(na->data_size);
diff --git a/src/add-ons/kernel/file_systems/ntfs/libntfs/attrib.h 
b/src/add-ons/kernel/file_systems/ntfs/libntfs/attrib.h
index 1979ba6..a0bee26 100644
--- a/src/add-ons/kernel/file_systems/ntfs/libntfs/attrib.h
+++ b/src/add-ons/kernel/file_systems/ntfs/libntfs/attrib.h
@@ -61,7 +61,8 @@ typedef enum {
 typedef enum {                 /* ways of processing holes when expanding */
        HOLES_NO,
        HOLES_OK,
-       HOLES_DELAY
+       HOLES_DELAY,
+       HOLES_NONRES
 } hole_type;
 
 /**
diff --git a/src/add-ons/kernel/file_systems/ntfs/libntfs/compress.c 
b/src/add-ons/kernel/file_systems/ntfs/libntfs/compress.c
index aeb082d..69b39ed 100644
--- a/src/add-ons/kernel/file_systems/ntfs/libntfs/compress.c
+++ b/src/add-ons/kernel/file_systems/ntfs/libntfs/compress.c
@@ -5,7 +5,7 @@
  * Copyright (c) 2004-2005 Anton Altaparmakov
  * Copyright (c) 2004-2006 Szabolcs Szakacsits
  * Copyright (c)      2005 Yura Pakhuchiy
- * Copyright (c) 2009-2011 Jean-Pierre Andre
+ * Copyright (c) 2009-2013 Jean-Pierre Andre
  *
  * 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
@@ -734,6 +734,7 @@ do_next_cb:
                ofs = 0;
        } else {
                s64 tdata_size, tinitialized_size;
+               u32 decompsz;
 
                /*
                 * Compressed cb, decompress it into the temporary buffer, then
@@ -791,7 +792,10 @@ do_next_cb:
                if (cb_pos + 2 <= cb_end)
                        *(u16*)cb_pos = 0;
                ntfs_log_debug("Successfully read the compression block.\n");
-               if (ntfs_decompress(dest, cb_size, cb, cb_size) < 0) {
+               /* Do not decompress beyond the requested block */
+               to_read = min(count, cb_size - ofs);
+               decompsz = ((ofs + to_read - 1) | (NTFS_SB_SIZE - 1)) + 1;
+               if (ntfs_decompress(dest, decompsz, cb, cb_size) < 0) {
                        err = errno;
                        free(cb);
                        free(dest);
@@ -800,7 +804,6 @@ do_next_cb:
                        errno = err;
                        return -1;
                }
-               to_read = min(count, cb_size - ofs);
                memcpy(b, dest + ofs, to_read);
                total += to_read;
                count -= to_read;
diff --git a/src/add-ons/kernel/file_systems/ntfs/libntfs/device.c 
b/src/add-ons/kernel/file_systems/ntfs/libntfs/device.c
index ef7070b..12ca14d 100644
--- a/src/add-ons/kernel/file_systems/ntfs/libntfs/device.c
+++ b/src/add-ons/kernel/file_systems/ntfs/libntfs/device.c
@@ -1,9 +1,10 @@
 /**
  * device.c - Low level device io functions. Originated from the Linux-NTFS 
project.
  *
- * Copyright (c) 2004-2006 Anton Altaparmakov
+ * Copyright (c) 2004-2013 Anton Altaparmakov
  * Copyright (c) 2004-2006 Szabolcs Szakacsits
  * Copyright (c) 2010      Jean-Pierre Andre
+ * Copyright (c) 2008-2013 Tuxera 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
@@ -67,6 +68,9 @@
 #ifdef HAVE_LINUX_HDREG_H
 #include <linux/hdreg.h>
 #endif
+#ifdef ENABLE_HD
+#include <hd.h>
+#endif
 #ifdef __HAIKU__
 #include <Drivers.h>
 #endif
@@ -131,6 +135,8 @@ struct ntfs_device *ntfs_device_alloc(const char *name, 
const long state,
                dev->d_ops = dops;
                dev->d_state = state;
                dev->d_private = priv_data;
+               dev->d_heads = -1;
+               dev->d_sectors_per_track = -1;
        }
        return dev;
 }
@@ -663,6 +669,132 @@ s64 ntfs_device_partition_start_sector_get(struct 
ntfs_device *dev)
        return -1;
 }
 
+static int ntfs_device_get_geo(struct ntfs_device *dev)
+{
+       int err;
+
+       if (!dev) {
+               errno = EINVAL;
+               return -1;
+       }
+       err = EOPNOTSUPP;
+#ifdef ENABLE_HD
+       {
+               hd_data_t *hddata;
+               hd_t *hd, *devlist, *partlist = NULL;
+               str_list_t *names;
+               hd_res_t *res;
+               const int d_name_len = strlen(dev->d_name) + 1;
+               int done = 0;
+
+               hddata = calloc(1, sizeof(*hddata));
+               if (!hddata) {
+                       err = ENOMEM;
+                       goto skip_hd;
+               }
+               /* List all "disk" class devices on the system. */
+               devlist = hd_list(hddata, hw_disk, 1, NULL);
+               if (!devlist) {
+                       free(hddata);
+                       err = ENOMEM;
+                       goto skip_hd;
+               }
+               /*
+                * Loop over each disk device looking for the device with the
+                * same unix name as @dev.
+                */
+               for (hd = devlist; hd; hd = hd->next) {
+                       if (hd->unix_dev_name && !strncmp(dev->d_name,
+                                       hd->unix_dev_name, d_name_len))
+                               goto got_hd;
+                       if (hd->unix_dev_name2 && !strncmp(dev->d_name,
+                                       hd->unix_dev_name2, d_name_len))
+                               goto got_hd;
+                       for (names = hd->unix_dev_names; names;
+                                       names = names->next) {
+                               if (names->str && !strncmp(dev->d_name,
+                                               names->str, d_name_len))
+                                       goto got_hd;
+                       }
+               }
+               /*
+                * Device was not a whole disk device.  Unless it is a file it
+                * is likely to be a partition device.  List all "partition"
+                * class devices on the system.
+                */
+               partlist = hd_list(hddata, hw_partition, 1, NULL);
+               for (hd = partlist; hd; hd = hd->next) {
+                       if (hd->unix_dev_name && !strncmp(dev->d_name,
+                                       hd->unix_dev_name, d_name_len))
+                               goto got_part_hd;
+                       if (hd->unix_dev_name2 && !strncmp(dev->d_name,
+                                       hd->unix_dev_name2, d_name_len))
+                               goto got_part_hd;
+                       for (names = hd->unix_dev_names; names;
+                                       names = names->next) {
+                               if (names->str && !strncmp(dev->d_name,
+                                               names->str, d_name_len))
+                                       goto got_part_hd;
+                       }
+               }
+               /* Failed to find the device.  Stop trying and clean up. */
+               goto end_hd;
+got_part_hd:
+               /* Get the whole block device the partition device is on. */
+               hd = hd_get_device_by_idx(hddata, hd->attached_to);
+               if (!hd)
+                       goto end_hd;
+got_hd:
+               /*
+                * @hd is now the whole block device either being formatted or
+                * that the partition being formatted is on.
+                *
+                * Loop over each resource of the disk device looking for the
+                * BIOS legacy geometry obtained from EDD which is what Windows
+                * needs to boot.
+                */
+               for (res = hd->res; res; res = res->next) {
+                       /* geotype 3 is BIOS legacy. */
+                       if (res->any.type != res_disk_geo ||
+                                       res->disk_geo.geotype != 3)
+                               continue;
+                       dev->d_heads = res->disk_geo.heads;
+                       dev->d_sectors_per_track = res->disk_geo.sectors;
+                       done = 1;
+               }
+end_hd:
+               if (partlist)
+                       hd_free_hd_list(partlist);
+               hd_free_hd_list(devlist);
+               hd_free_hd_data(hddata);
+               free(hddata);
+               if (done) {
+                       ntfs_log_debug("EDD/BIOD legacy heads = %u, sectors "
+                                       "per track = %u\n", dev->d_heads,
+                                       dev->d_sectors_per_track);
+                       return 0;
+               }
+       }
+skip_hd:
+#endif
+#ifdef HDIO_GETGEO
+       {       struct hd_geometry geo;
+
+               if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
+                       dev->d_heads = geo.heads;
+                       dev->d_sectors_per_track = geo.sectors;
+                       ntfs_log_debug("HDIO_GETGEO heads = %u, sectors per "
+                                       "track = %u\n", dev->d_heads,
+                                       dev->d_sectors_per_track);
+                       return 0;
+               }
+               err = errno;
+       }
+#endif
+       errno = err;
+       return -1;
+}
+
 /**
  * ntfs_device_heads_get - get number of heads of device
  * @dev:               open device
@@ -674,6 +806,7 @@ s64 ntfs_device_partition_start_sector_get(struct 
ntfs_device *dev)
  *     EINVAL          Input parameter error
  *     EOPNOTSUPP      System does not support HDIO_GETGEO ioctl
  *     ENOTTY          @dev is a file or a device not supporting HDIO_GETGEO
+ *     ENOMEM          Not enough memory to complete the request
  */
 int ntfs_device_heads_get(struct ntfs_device *dev)
 {
@@ -681,20 +814,15 @@ int ntfs_device_heads_get(struct ntfs_device *dev)
                errno = EINVAL;
                return -1;
        }
-#ifdef HDIO_GETGEO
-       {       struct hd_geometry geo;
-
-               if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
-                       ntfs_log_debug("HDIO_GETGEO heads = %u (0x%x)\n",
-                                       (unsigned)geo.heads,
-                                       (unsigned)geo.heads);
-                       return geo.heads;
+       if (dev->d_heads == -1) {
+               if (ntfs_device_get_geo(dev) == -1)
+                       return -1;
+               if (dev->d_heads == -1) {
+                       errno = EINVAL;
+                       return -1;
                }
        }
-#else
-       errno = EOPNOTSUPP;
-#endif
-       return -1;
+       return dev->d_heads;
 }
 
 /**
@@ -708,6 +836,7 @@ int ntfs_device_heads_get(struct ntfs_device *dev)
  *     EINVAL          Input parameter error
  *     EOPNOTSUPP      System does not support HDIO_GETGEO ioctl
  *     ENOTTY          @dev is a file or a device not supporting HDIO_GETGEO
+ *     ENOMEM          Not enough memory to complete the request
  */
 int ntfs_device_sectors_per_track_get(struct ntfs_device *dev)
 {
@@ -715,20 +844,15 @@ int ntfs_device_sectors_per_track_get(struct ntfs_device 
*dev)
                errno = EINVAL;
                return -1;
        }
-#ifdef HDIO_GETGEO
-       {       struct hd_geometry geo;
-
-               if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
-                       ntfs_log_debug("HDIO_GETGEO sectors_per_track = %u 
(0x%x)\n",
-                                       (unsigned)geo.sectors,
-                                       (unsigned)geo.sectors);
-                       return geo.sectors;
+       if (dev->d_sectors_per_track == -1) {
+               if (ntfs_device_get_geo(dev) == -1)
+                       return -1;
+               if (dev->d_sectors_per_track == -1) {
+                       errno = EINVAL;
+                       return -1;
                }
        }
-#else
-       errno = EOPNOTSUPP;
-#endif
-       return -1;
+       return dev->d_sectors_per_track;
 }
 
 /**
diff --git a/src/add-ons/kernel/file_systems/ntfs/libntfs/device.h 
b/src/add-ons/kernel/file_systems/ntfs/libntfs/device.h
index ad34ac5..c7cc9b6 100644
--- a/src/add-ons/kernel/file_systems/ntfs/libntfs/device.h
+++ b/src/add-ons/kernel/file_systems/ntfs/libntfs/device.h
@@ -1,7 +1,8 @@
 /*
  * device.h - Exports for low level device io. Originated from the Linux-NTFS 
project.
  *
- * Copyright (c) 2000-2006 Anton Altaparmakov
+ * Copyright (c) 2000-2013 Anton Altaparmakov
+ * Copyright (c) 2008-2013 Tuxera 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
@@ -73,6 +74,11 @@ typedef enum {
  *
  * The ntfs device structure defining all operations needed to access the low
  * level device underlying the ntfs volume.
+ *
+ * Note d_heads and d_sectors_per_track are only set as a result of a call to
+ * either ntfs_device_heads_get() or ntfs_device_sectors_per_track_get() (both
+ * calls will set up both fields or if getting them failed they will be left at
+ * -1).
  */
 struct ntfs_device {
        struct ntfs_device_operations *d_ops;   /* Device operations. */
@@ -80,6 +86,10 @@ struct ntfs_device {
        char *d_name;                           /* Name of device. */
        void *d_private;                        /* Private data used by the
                                                   device operations. */
+       int d_heads;                            /* Disk geometry: number of
+                                                  heads or -1. */
+       int d_sectors_per_track;                /* Disk geometry: number of
+                                                  sectors per track or -1. */
 };
 
 struct stat;
diff --git a/src/add-ons/kernel/file_systems/ntfs/libntfs/device_io.h 
b/src/add-ons/kernel/file_systems/ntfs/libntfs/device_io.h
index 8437cc2..24f8d9b 100644
--- a/src/add-ons/kernel/file_systems/ntfs/libntfs/device_io.h
+++ b/src/add-ons/kernel/file_systems/ntfs/libntfs/device_io.h
@@ -28,12 +28,18 @@
 
 #ifndef NO_NTFS_DEVICE_DEFAULT_IO_OPS
 
-#ifndef __CYGWIN32__
+#if defined(linux) || defined(__uClinux__) || defined(__sun) \
+               || defined(__APPLE__) || defined(__DARWIN__)
+  /* Make sure the presence of <windows.h> means compiling for Windows */
+#undef HAVE_WINDOWS_H
+#endif
+
+#ifndef HAVE_WINDOWS_H
 
-/* Not on Cygwin; use standard Unix style low level device operations. */
+/* Not for Windows use standard Unix style low level device operations. */
 #define ntfs_device_default_io_ops ntfs_device_unix_io_ops
 
-#else /* __CYGWIN32__ */
+#else /* HAVE_WINDOWS_H */
 
 #ifndef HDIO_GETGEO
 #      define HDIO_GETGEO      0x301
@@ -60,10 +66,15 @@ struct hd_geometry {
 #      define BLKBSZSET        0x40041271
 #endif
 
-/* On Cygwin; use Win32 low level device operations. */
+/* On Windows (and Cygwin) : use Win32 low level device operations. */
 #define ntfs_device_default_io_ops ntfs_device_win32_io_ops
 
-#endif /* __CYGWIN32__ */
+/* A few useful functions */
+int ntfs_win32_set_sparse(int);
+int ntfs_win32_ftruncate(int fd, s64 size);
+int ntfs_win32_device_ftruncate(struct ntfs_device*, s64);
+
+#endif /* HAVE_WINDOWS_H */
 
 
 /* Forward declaration. */
diff --git a/src/add-ons/kernel/file_systems/ntfs/libntfs/dir.c 
b/src/add-ons/kernel/file_systems/ntfs/libntfs/dir.c
index d5f08f2..a13b121 100644
--- a/src/add-ons/kernel/file_systems/ntfs/libntfs/dir.c
+++ b/src/add-ons/kernel/file_systems/ntfs/libntfs/dir.c
@@ -1047,6 +1047,9 @@ static int ntfs_filldir(ntfs_inode *dir_ni, s64 *pos, u8 
ivcn_bits,
  * Return the mft reference of the parent directory on success or -1 on error
  * with errno set to the error code.
  */
+#ifndef __HAIKU__
+static
+#endif
 MFT_REF ntfs_mft_get_parent_ref(ntfs_inode *ni)
 {
        MFT_REF mref;
diff --git a/src/add-ons/kernel/file_systems/ntfs/libntfs/dir.h 
b/src/add-ons/kernel/file_systems/ntfs/libntfs/dir.h
index 43308d1..7d196b0 100644
--- a/src/add-ons/kernel/file_systems/ntfs/libntfs/dir.h
+++ b/src/add-ons/kernel/file_systems/ntfs/libntfs/dir.h
@@ -88,8 +88,6 @@ extern int ntfs_delete(ntfs_volume *vol, const char *path,
 extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, const ntfschar *name,
                u8 name_len);
 
-extern MFT_REF ntfs_mft_get_parent_ref(ntfs_inode *ni);
-
 /*
  * File types (adapted from include <linux/fs.h>)
  */
@@ -118,6 +116,10 @@ extern int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos,
 
 ntfs_inode *ntfs_dir_parent_inode(ntfs_inode *ni);
 
+#ifdef __HAIKU__
+MFT_REF ntfs_mft_get_parent_ref(ntfs_inode *ni);
+#endif
+
 int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
                        char *value, size_t size);
 int ntfs_set_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni,
diff --git a/src/add-ons/kernel/file_systems/ntfs/libntfs/logging.c 
b/src/add-ons/kernel/file_systems/ntfs/libntfs/logging.c
index 8102827..76acdbc 100644
--- a/src/add-ons/kernel/file_systems/ntfs/libntfs/logging.c
+++ b/src/add-ons/kernel/file_systems/ntfs/libntfs/logging.c
@@ -188,6 +188,7 @@ u32 ntfs_log_clear_flags(u32 flags)
        return old;
 }
 
+
 /**
  * ntfs_log_get_stream - Default output streams for logging levels
  * @level:     Log level
@@ -277,6 +278,7 @@ static const char * ntfs_log_get_prefix(u32 level)
        return prefix;
 }
 
+
 /**
  * ntfs_log_set_handler - Provide an alternate logging handler
  * @handler:   function to perform the logging
diff --git a/src/add-ons/kernel/file_systems/ntfs/libntfs/reparse.c 
b/src/add-ons/kernel/file_systems/ntfs/libntfs/reparse.c
index dc44bcd..cdabadd 100644
--- a/src/add-ons/kernel/file_systems/ntfs/libntfs/reparse.c
+++ b/src/add-ons/kernel/file_systems/ntfs/libntfs/reparse.c
@@ -3,7 +3,7 @@
  *
  *     This module is part of ntfs-3g library
  *
- * Copyright (c) 2008-2012 Jean-Pierre Andre
+ * Copyright (c) 2008-2013 Jean-Pierre Andre
  *
  * 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
@@ -313,14 +313,14 @@ static char *search_relative(ntfs_inode *ni, ntfschar 
*path, int count)
                if ((count >= (pos + 2))
                    && (path[pos] == const_cpu_to_le16('.'))
                    && (path[pos+1] == const_cpu_to_le16('\\'))) {
-                       path[1] = const_cpu_to_le16('/');
+                       path[pos+1] = const_cpu_to_le16('/');
                        pos += 2;
                } else {
                        if ((count >= (pos + 3))
                            && (path[pos] == const_cpu_to_le16('.'))
                            &&(path[pos+1] == const_cpu_to_le16('.'))
                            && (path[pos+2] == const_cpu_to_le16('\\'))) {
-                               path[2] = const_cpu_to_le16('/');
+                               path[pos+2] = const_cpu_to_le16('/');
                                pos += 3;
                                newni = ntfs_dir_parent_inode(curni);
                                if (curni != ni)
diff --git a/src/add-ons/kernel/file_systems/ntfs/libntfs/security.c 
b/src/add-ons/kernel/file_systems/ntfs/libntfs/security.c
index 2ff3306..8ab23ef 100644
--- a/src/add-ons/kernel/file_systems/ntfs/libntfs/security.c
+++ b/src/add-ons/kernel/file_systems/ntfs/libntfs/security.c
@@ -373,6 +373,8 @@ void ntfs_generate_guid(GUID *guid)
        unsigned int i;
        u8 *p = (u8 *)guid;
 
+       /* this is called at most once from mkntfs */
+       srandom(time((time_t*)NULL) ^ (getpid() << 16));
        for (i = 0; i < sizeof(GUID); i++) {
                p[i] = (u8)(random() & 0xFF);
                if (i == 7)
diff --git a/src/add-ons/kernel/file_systems/ntfs/libntfs/volume.c 
b/src/add-ons/kernel/file_systems/ntfs/libntfs/volume.c
index 6acef48..1cb58db 100644
--- a/src/add-ons/kernel/file_systems/ntfs/libntfs/volume.c
+++ b/src/add-ons/kernel/file_systems/ntfs/libntfs/volume.c
@@ -1433,7 +1433,8 @@ static int ntfs_mntent_check(const char *file, unsigned 
long *mnt_flags)
                err = errno;
                goto exit;
        }
-       if (!(f = setmntent(MOUNTED, "r"))) {
+       f = setmntent("/proc/mounts", "r");
+       if (!f && !(f = setmntent(MOUNTED, "r"))) {
                err = errno;
                goto exit;
        }
diff --git a/src/add-ons/kernel/file_systems/ntfs/libntfs/win32_io.c 
b/src/add-ons/kernel/file_systems/ntfs/libntfs/win32_io.c
index ed9fa52..437a3fc 100644
--- a/src/add-ons/kernel/file_systems/ntfs/libntfs/win32_io.c
+++ b/src/add-ons/kernel/file_systems/ntfs/libntfs/win32_io.c
@@ -6,6 +6,7 @@
  * Copyright (c) 2003-2004 Lode Leroy
  * Copyright (c) 2003-2006 Anton Altaparmakov
  * Copyright (c) 2004-2005 Yuval Fledel
+ * Copyright (c) 2012-2013 Jean-Pierre Andre
  *
  * 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
@@ -26,8 +27,33 @@
 #include "config.h"
 
 #ifdef HAVE_WINDOWS_H
+#define BOOL WINBOOL /* avoid conflicting definitions of BOOL */
 #include <windows.h>
+#undef BOOL
 #endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+/*
+ *             Definitions needed for <winioctl.h>
+ */
+#ifndef _ANONYMOUS_UNION
+#define _ANONYMOUS_UNION
+#define _ANONYMOUS_STRUCT
+typedef unsigned long long DWORD64;
+#endif
+
+typedef struct {
+        DWORD data1;     /* The first eight hexadecimal digits of the GUID. */
+        WORD data2;     /* The first group of four hexadecimal digits. */
+        WORD data3;     /* The second group of four hexadecimal digits. */ 
+        char data4[8];    /* The first two bytes are the third group of four
+                           hexadecimal digits. The remaining six bytes are the
+                           final 12 hexadecimal digits. */
+} GUID;
+
 #include <winioctl.h>
 
 #ifdef HAVE_STDIO_H
@@ -42,6 +68,11 @@
 #ifdef HAVE_FCNTL_H
 #include <fcntl.h>
 #endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#define stat stat64
+#define st_blocks  st_rdev /* emulate st_blocks, missing in Windows */
+#endif
 
 /* Prevent volume.h from being be loaded, as it conflicts with winnt.h. */
 #define _NTFS_VOLUME_H
@@ -51,6 +82,10 @@ typedef struct ntfs_volume ntfs_volume;
 #include "debug.h"
 #include "types.h"
 #include "device.h"
+#include "misc.h"
+
+#define cpu_to_le16(x) (x)
+#define const_cpu_to_le16(x) (x)
 
 #ifndef MAX_PATH
 #define MAX_PATH 1024
@@ -61,10 +96,26 @@ typedef struct ntfs_volume ntfs_volume;
 #define NTFS_BLOCK_SIZE_BITS   9
 #endif
 
+#ifndef INVALID_SET_FILE_POINTER
+#define INVALID_SET_FILE_POINTER ((DWORD)-1)
+#endif
+
 #ifndef IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
 #define IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS 5636096
 #endif
 
+#ifndef IOCTL_DISK_GET_DRIVE_GEOMETRY
+#define IOCTL_DISK_GET_DRIVE_GEOMETRY 0x70000
+#endif
+
+#ifndef IOCTL_GET_DISK_LENGTH_INFO
+#define IOCTL_GET_DISK_LENGTH_INFO 0x7405c
+#endif
+
+#ifndef FSCTL_ALLOW_EXTENDED_DASD_IO
+#define FSCTL_ALLOW_EXTENDED_DASD_IO 0x90083
+#endif
+
 /* Windows 2k+ imports. */
 typedef HANDLE (WINAPI *LPFN_FINDFIRSTVOLUME)(LPTSTR, DWORD);
 typedef BOOL (WINAPI *LPFN_FINDNEXTVOLUME)(HANDLE, LPTSTR, DWORD);
@@ -83,6 +134,146 @@ static LPFN_SETFILEPOINTEREX fnSetFilePointerEx = NULL;
 #define FNPOSTFIX "A"
 #endif
 
+enum { /* see http://msdn.microsoft.com/en-us/library/cc704588(v=prot.10).aspx 
*/
+   STATUS_UNKNOWN = -1,
+   STATUS_SUCCESS =              0x00000000,
+   STATUS_BUFFER_OVERFLOW =      0x80000005,
+   STATUS_INVALID_HANDLE =       0xC0000008,
+   STATUS_INVALID_PARAMETER =    0xC000000D,
+   STATUS_INVALID_DEVICE_REQUEST = 0xC0000010,
+   STATUS_END_OF_FILE =          0xC0000011,
+   STATUS_CONFLICTING_ADDRESSES = 0xC0000018,
+   STATUS_NO_MATCH =             0xC000001E,
+   STATUS_ACCESS_DENIED =        0xC0000022,
+   STATUS_BUFFER_TOO_SMALL =     0xC0000023,
+   STATUS_OBJECT_TYPE_MISMATCH = 0xC0000024,
+   STATUS_FILE_NOT_FOUND =       0xC0000028,
+   STATUS_OBJECT_NAME_INVALID =  0xC0000033,
+   STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034,
+   STATUS_INVALID_PARAMETER_1 =  0xC00000EF,
+   STATUS_IO_DEVICE_ERROR =      0xC0000185,
+   STATUS_GUARD_PAGE_VIOLATION = 0x80000001
+ } ;
+
+typedef u32 NTSTATUS; /* do not let the compiler choose the size */
+#ifdef __x86_64__
+typedef unsigned long long ULONG_PTR; /* an integer the same size as a pointer 
*/
+#else
+typedef unsigned long ULONG_PTR; /* an integer the same size as a pointer */
+#endif
+
+HANDLE get_osfhandle(int); /* from msvcrt.dll */
+
+/*
+ *             A few needed definitions not included in <windows.h>
+ */
+
+typedef struct _IO_STATUS_BLOCK {
+       union {
+               NTSTATUS Status;
+               PVOID    Pointer;
+       };
+       ULONG_PTR Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+typedef struct _UNICODE_STRING {
+       USHORT Length;
+       USHORT MaximumLength;
+#ifdef __x86_64__
+       u32    padding;
+#endif
+       PWSTR  Buffer;
+} UNICODE_STRING, *PUNICODE_STRING;
+
+typedef struct _OBJECT_ATTRIBUTES {
+       ULONG           Length;
+#ifdef __x86_64__
+       u32             padding1;
+       HANDLE          RootDirectory;
+       PUNICODE_STRING ObjectName;
+       ULONG           Attributes;
+       u32             padding2;
+#else
+       HANDLE          RootDirectory;
+       PUNICODE_STRING ObjectName;
+       ULONG           Attributes;
+#endif
+       PVOID           SecurityDescriptor;
+       PVOID           SecurityQualityOfService;
+}  OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
+
+#define FILE_OPEN 1
+#define FILE_CREATE 2
+#define FILE_OVERWRITE 4
+#define FILE_SYNCHRONOUS_IO_ALERT    0x10
+#define FILE_SYNCHRONOUS_IO_NONALERT 0x20
+#define OBJ_CASE_INSENSITIVE 0x40
+
+typedef void (WINAPI *PIO_APC_ROUTINE)(void*, PIO_STATUS_BLOCK, ULONG);
+
+extern WINAPI NTSTATUS NtOpenFile(
+       PHANDLE FileHandle,
+       ACCESS_MASK DesiredAccess,
+       POBJECT_ATTRIBUTES ObjectAttributes,
+       PIO_STATUS_BLOCK IoStatusBlock,
+       ULONG ShareAccess,
+       ULONG OpenOptions
+);
+
+extern WINAPI NTSTATUS NtReadFile(
+       HANDLE FileHandle,
+       HANDLE Event,
+       PIO_APC_ROUTINE ApcRoutine,
+       PVOID ApcContext,
+       PIO_STATUS_BLOCK IoStatusBlock,
+       PVOID Buffer,
+       ULONG Length,
+       PLARGE_INTEGER ByteOffset,
+       PULONG Key
+);
+
+extern WINAPI NTSTATUS NtWriteFile(
+       HANDLE FileHandle,
+       HANDLE Event,
+       PIO_APC_ROUTINE ApcRoutine,
+       PVOID ApcContext,
+       PIO_STATUS_BLOCK IoStatusBlock,
+       LPCVOID Buffer,
+       ULONG Length,
+       PLARGE_INTEGER ByteOffset,
+       PULONG Key
+);
+
+extern NTSTATUS WINAPI NtClose(
+       HANDLE Handle
+);
+
+extern NTSTATUS WINAPI NtDeviceIoControlFile(
+       HANDLE FileHandle,
+       HANDLE Event,
+       PIO_APC_ROUTINE ApcRoutine,
+       PVOID ApcContext,
+       PIO_STATUS_BLOCK IoStatusBlock,
+       ULONG IoControlCode,
+       PVOID InputBuffer,
+       ULONG InputBufferLength,
+       PVOID OutputBuffer,
+       ULONG OutputBufferLength
+);
+
+extern NTSTATUS        WINAPI NtFsControlFile(
+       HANDLE FileHandle,
+       HANDLE Event,
+       PIO_APC_ROUTINE ApcRoutine,
+       PVOID ApcContext,
+       PIO_STATUS_BLOCK IoStatusBlock,
+       ULONG FsControlCode,
+       PVOID InputBuffer,
+       ULONG InputBufferLength,
+       PVOID OutputBuffer,
+       ULONG OutputBufferLength
+);
+
 /**
  * struct win32_fd -
  */
@@ -93,8 +284,11 @@ typedef struct {
        s64 part_length;
        int part_hidden_sectors;
        s64 geo_size, geo_cylinders;
+       s32 geo_sector_size;
+       s64 volume_size;
        DWORD geo_sectors, geo_heads;
        HANDLE vol_handle;
+       BOOL ntdll;
 } win32_fd;
 
 /**
@@ -146,6 +340,26 @@ static int ntfs_w32error_to_errno(unsigned int w32error)
        }
 }
 
+static int ntfs_ntstatus_to_errno(NTSTATUS status)
+{
+       ntfs_log_trace("Converting w32error 0x%x.\n",w32error);
+       switch (status) {
+               case STATUS_INVALID_HANDLE :
+               case STATUS_INVALID_PARAMETER :
+               case STATUS_OBJECT_NAME_INVALID :
+               case STATUS_INVALID_DEVICE_REQUEST :
+                       return (EINVAL);
+               case STATUS_ACCESS_DENIED :
+                       return (EACCES);
+               case STATUS_IO_DEVICE_ERROR :
+               case STATUS_END_OF_FILE :
+                       return (EIO);
+               default:
+                       /* generic message */
+                       return ENOMSG;
+       }
+}
+
 /**
  * libntfs_SetFilePointerEx - emulation for SetFilePointerEx()
  *
@@ -156,10 +370,11 @@ static BOOL WINAPI libntfs_SetFilePointerEx(HANDLE hFile,
                LARGE_INTEGER liDistanceToMove,
                PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod)
 {
-       liDistanceToMove.LowPart = SetFilePointer(hFile,
-                       liDistanceToMove.LowPart, &liDistanceToMove.HighPart,
-                       dwMoveMethod);
-       if (liDistanceToMove.LowPart == INVALID_SET_FILE_POINTER &&
+       liDistanceToMove.u.LowPart = SetFilePointer(hFile,
+                       liDistanceToMove.u.LowPart,
+                       &liDistanceToMove.u.HighPart, dwMoveMethod);
+       SetLastError(NO_ERROR);
+       if (liDistanceToMove.u.LowPart == INVALID_SET_FILE_POINTER &&
                        GetLastError() != NO_ERROR) {
                if (lpNewFilePointer)
                        lpNewFilePointer->QuadPart = -1;
@@ -199,7 +414,7 @@ static void ntfs_device_win32_init_imports(void)
                 * SetFilePointerEx().
                 */
                if (!fnSetFilePointerEx) {
-                       ntfs_log_debug("SetFilePonterEx() not found in "
+                       ntfs_log_debug("SetFilePointerEx() not found in "
                                        "kernel32.dll: Enabling emulation.\n");
                        fnSetFilePointerEx = libntfs_SetFilePointerEx;
                }
@@ -232,13 +447,13 @@ static __inline__ int 
ntfs_device_unix_status_flags_to_win32(int flags)
 
        switch (flags & O_ACCMODE) {
        case O_RDONLY:
-               win_mode = FILE_READ_DATA;
+               win_mode = GENERIC_READ;
                break;
        case O_WRONLY:
-               win_mode = FILE_WRITE_DATA;
+               win_mode = GENERIC_WRITE;
                break;
        case O_RDWR:
-               win_mode = FILE_READ_DATA | FILE_WRITE_DATA;
+               win_mode = GENERIC_READ | GENERIC_WRITE;
                break;
        default:
                /* error */
@@ -267,7 +482,8 @@ static int ntfs_device_win32_simple_open_file(const char 
*filename,
        *handle = CreateFile(filename,
                        ntfs_device_unix_status_flags_to_win32(flags),
                        locking ? 0 : (FILE_SHARE_WRITE | FILE_SHARE_READ),
-                       NULL, OPEN_EXISTING, 0, NULL);
+                       NULL, (flags & O_CREAT ? OPEN_ALWAYS : OPEN_EXISTING),
+                       0, NULL);
        if (*handle == INVALID_HANDLE_VALUE) {
                errno = ntfs_w32error_to_errno(GetLastError());
                ntfs_log_trace("CreateFile(%s) failed.\n", filename);
@@ -321,6 +537,22 @@ static int ntfs_device_win32_unlock(HANDLE handle)
        return 0;
 }
 
+static int ntfs_device_win32_setlock(HANDLE handle, ULONG code)
+{
+       IO_STATUS_BLOCK io_status;
+       NTSTATUS res;
+
+       io_status.Status = STATUS_SUCCESS;
+       io_status.Information = 0;
+       res = NtFsControlFile(handle,(HANDLE)NULL,
+                               (PIO_APC_ROUTINE)NULL,(void*)NULL,
+                               &io_status, code,
+                               (char*)NULL,0,(char*)NULL,0);
+       if (res != STATUS_SUCCESS)
+               errno = ntfs_ntstatus_to_errno(res);
+       return (res == STATUS_SUCCESS ? 0 : -1);
+}
+
 /**
  * ntfs_device_win32_dismount - dismount a volume
  * @handle:    a win32 HANDLE for a volume to dismount
@@ -359,15 +591,18 @@ static int ntfs_device_win32_dismount(HANDLE handle)
  */
 static s64 ntfs_device_win32_getsize(HANDLE handle)
 {
-       DWORD loword, hiword;
+       LONG loword, hiword;
 
-       loword = GetFileSize(handle, &hiword);
-       if (loword == INVALID_FILE_SIZE) {
+       SetLastError(NO_ERROR);
+       hiword = 0;
+       loword = SetFilePointer(handle, 0, &hiword, 2);
+       if ((loword == INVALID_SET_FILE_POINTER)
+           && (GetLastError() != NO_ERROR)) {
                errno = ntfs_w32error_to_errno(GetLastError());
                ntfs_log_trace("Couldn't get file size.\n");
                return -1;
        }
-       return ((s64)hiword << 32) + loword;
+       return ((s64)hiword << 32) + (ULONG)loword;
 }
 
 /**
@@ -467,6 +702,7 @@ static int ntfs_device_win32_getgeo(HANDLE handle, win32_fd 
*fd)
                fd->geo_cylinders = ((DISK_GEOMETRY*)&b)->Cylinders.QuadPart;
                fd->geo_sectors = ((DISK_GEOMETRY*)&b)->SectorsPerTrack;
                fd->geo_size = ((DISK_GEOMETRY_EX*)&b)->DiskSize.QuadPart;
+               fd->geo_sector_size = NTFS_BLOCK_SIZE;
                switch (ddi->DetectionType) {
                case DetectInt13:
                        fd->geo_cylinders = ddi->Int13.MaxCylinders;
@@ -493,6 +729,7 @@ static int ntfs_device_win32_getgeo(HANDLE handle, win32_fd 
*fd)
                fd->geo_size = fd->geo_cylinders * fd->geo_sectors *
                                ((DISK_GEOMETRY*)&b)->TracksPerCylinder *
                                ((DISK_GEOMETRY*)&b)->BytesPerSector;
+               fd->geo_sector_size = ((DISK_GEOMETRY*)&b)->BytesPerSector;
                return 0;
        }
        errno = ntfs_w32error_to_errno(GetLastError());
@@ -500,9 +737,51 @@ static int ntfs_device_win32_getgeo(HANDLE handle, 
win32_fd *fd)
        fd->geo_cylinders = -1;
        fd->geo_sectors = -1;
        fd->geo_size = -1;
+       fd->geo_sector_size = NTFS_BLOCK_SIZE;
        return -1;
 }
 
+static int ntfs_device_win32_getntgeo(HANDLE handle, win32_fd *fd)
+{
+       DISK_GEOMETRY geo;
+       NTSTATUS st;
+       IO_STATUS_BLOCK status;
+       u64 bytes;
+       int res;
+
+       res = -1;
+       fd->geo_cylinders = 0;
+       fd->geo_sectors = 0;
+       fd->geo_size = 1073741824;
+       fd->geo_sectors = fd->geo_size >> 9;
+       fd->geo_sector_size = NTFS_BLOCK_SIZE;
+
+       st = NtDeviceIoControlFile(handle, (HANDLE)NULL,
+                       (PIO_APC_ROUTINE)NULL, (void*)NULL,
+                       &status, IOCTL_DISK_GET_DRIVE_GEOMETRY, (void*)NULL, 0,
+                       (void*)&geo, sizeof(geo));
+       if (st == STATUS_SUCCESS) {
+               /* over-estimate the (rounded) number of cylinders */
+               fd->geo_cylinders = geo.Cylinders.QuadPart + 1;
+               fd->geo_sectors = fd->geo_cylinders
+                               *geo.TracksPerCylinder*geo.SectorsPerTrack;
+               fd->geo_size = fd->geo_sectors*geo.BytesPerSector;
+               fd->geo_sector_size = geo.BytesPerSector;
+               res = 0;
+                       /* try to get the exact sector count */
+               st = NtDeviceIoControlFile(handle, (HANDLE)NULL,
+                               (PIO_APC_ROUTINE)NULL, (void*)NULL,
+                               &status, IOCTL_GET_DISK_LENGTH_INFO,
+                               (void*)NULL, 0,
+                               (void*)&bytes, sizeof(bytes));
+               if (st == STATUS_SUCCESS) {
+                       fd->geo_size = bytes;
+                       fd->geo_sectors = bytes/geo.BytesPerSector;
+               }
+       }
+       return (res);
+}
+
 /**
  * ntfs_device_win32_open_file - open a file via win32 API
  * @filename:  name of the file to open
@@ -516,12 +795,22 @@ static __inline__ int ntfs_device_win32_open_file(char 
*filename, win32_fd *fd,
                int flags)
 {
        HANDLE handle;
+       int mode;
 
        if (ntfs_device_win32_simple_open_file(filename, &handle, flags,
                        FALSE)) {
                /* open error */
                return -1;
        }
+       mode = flags & O_ACCMODE;
+       if ((mode == O_RDWR) || (mode == O_WRONLY)) {
+               DWORD bytes;
+
+               /* try making sparse (but ignore errors) */
+               DeviceIoControl(handle, FSCTL_SET_SPARSE,
+                               (void*)NULL, 0, (void*)NULL, 0,
+                               &bytes, (LPOVERLAPPED)NULL);
+       }
        /* fill fd */
        fd->handle = handle;
        fd->part_start = 0;
@@ -530,6 +819,8 @@ static __inline__ int ntfs_device_win32_open_file(char 
*filename, win32_fd *fd,
        fd->part_hidden_sectors = -1;
        fd->geo_size = -1;      /* used as a marker that this is a file */
        fd->vol_handle = INVALID_HANDLE_VALUE;
+       fd->geo_sector_size = 512;  /* will be adjusted from the boot sector */
+       fd->ntdll = FALSE;
        return 0;
 }
 
@@ -561,6 +852,90 @@ static __inline__ int ntfs_device_win32_open_drive(int 
drive_id, win32_fd *fd,
        if (fd->geo_size == -1)
                fd->geo_size = ntfs_device_win32_getdisklength(handle);
        /* fill fd */
+       fd->ntdll = FALSE;
+       fd->handle = handle;
+       fd->part_start = 0;
+       fd->part_length = fd->geo_size;
+       fd->pos = 0;
+       fd->part_hidden_sectors = -1;
+       fd->vol_handle = INVALID_HANDLE_VALUE;
+       return 0;
+}
+
+/**
+ * ntfs_device_win32_open_lowlevel - open a drive via low level win32 API
+ * @drive_id:  drive to open
+ * @fd:                pointer to win32 file device in which to put the result
+ * @flags:     unix open status flags
+ *
+ * return 0 if o.k.
+ *        -1 if not, and errno set.
+ */
+static __inline__ int ntfs_device_win32_open_lowlevel(int drive_id,
+               win32_fd *fd, int flags)
+{
+       HANDLE handle;
+       NTSTATUS st;
+       ACCESS_MASK access;
+       ULONG share;
+       OBJECT_ATTRIBUTES attr;
+       IO_STATUS_BLOCK io_status;
+       UNICODE_STRING unicode_name;
+       ntfschar unicode_buffer[7];
+       int mode;
+       static const ntfschar unicode_init[] = {
+               const_cpu_to_le16('\\'), const_cpu_to_le16('?'),
+               const_cpu_to_le16('?'), const_cpu_to_le16('\\'),
+               const_cpu_to_le16(' '), const_cpu_to_le16(':'),
+               const_cpu_to_le16(0)
+       };
+
+       memcpy(unicode_buffer, unicode_init, sizeof(unicode_buffer));
+       unicode_buffer[4] = cpu_to_le16(drive_id + 'A');
+       unicode_name.Buffer = unicode_buffer;
+       unicode_name.Length = 6*sizeof(ntfschar);
+       unicode_name.MaximumLength = 6*sizeof(ntfschar);
+
+       attr.Length = sizeof(OBJECT_ATTRIBUTES);
+       attr.RootDirectory = (HANDLE*)NULL;
+       attr.ObjectName = &unicode_name;
+       attr.Attributes = OBJ_CASE_INSENSITIVE;
+       attr.SecurityDescriptor = (void*)NULL;
+       attr.SecurityQualityOfService = (void*)NULL;
+
+       io_status.Status = 0;
+       io_status.Information = 0;
+       mode = flags & O_ACCMODE;
+       share = (mode == O_RDWR ?
+                       0 : FILE_SHARE_READ | FILE_SHARE_WRITE);
+       access = (mode == O_RDWR ?
+                        FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE
+                       : FILE_READ_DATA | SYNCHRONIZE);
+
+       st = NtOpenFile(&handle, access,
+                       &attr, &io_status,
+                       share,
+                       FILE_SYNCHRONOUS_IO_ALERT);
+       if (st != STATUS_SUCCESS) {
+               errno = ntfs_ntstatus_to_errno(st);
+               return (-1);
+       }
+       ntfs_device_win32_setlock(handle,FSCTL_LOCK_VOLUME);
+       /* store the drive geometry */
+       ntfs_device_win32_getntgeo(handle, fd);
+       fd->ntdll = TRUE;
+       /* allow accessing the full partition */
+       st = NtFsControlFile(handle, (HANDLE)NULL,
+                       (PIO_APC_ROUTINE)NULL,
+                       (PVOID)NULL, &io_status,
+                       FSCTL_ALLOW_EXTENDED_DASD_IO,
+                       NULL, 0, NULL, 0);
+       if (st != STATUS_SUCCESS) {
+               errno = ntfs_ntstatus_to_errno(st);
+               NtClose(handle);
+               return (-1);
+       }
+       /* fill fd */
        fd->handle = handle;
        fd->part_start = 0;
        fd->part_length = fd->geo_size;
@@ -694,7 +1069,7 @@ static BOOL ntfs_device_win32_find_partition(HANDLE 
handle, DWORD partition_id,
        do {
                buf_size = sizeof(DRIVE_LAYOUT_INFORMATION) +
                                part_count * sizeof(PARTITION_INFORMATION);
-               drive_layout = malloc(buf_size);
+               drive_layout = (DRIVE_LAYOUT_INFORMATION*)ntfs_malloc(buf_size);
                if (!drive_layout) {
                        errno = ENOMEM;
                        return FALSE;
@@ -775,6 +1150,8 @@ static int ntfs_device_win32_open_partition(int drive_id,
                fd->part_start = part_start;
                fd->part_length = part_length;
                fd->part_hidden_sectors = hidden_sectors;
+               fd->geo_sector_size = 512;
+               fd->ntdll = FALSE;
                tmp = ntfs_device_win32_getntfssize(vol_handle);
                if (tmp > 0)
                        fd->geo_size = tmp;
@@ -837,7 +1214,13 @@ static int ntfs_device_win32_open(struct ntfs_device 
*dev, int flags)
        }
        ntfs_device_win32_init_imports();
        numparams = sscanf(dev->d_name, "/dev/hd%c%u", &drive_char, &part);
-       drive_id = toupper(drive_char) - 'A';
+       if (!numparams
+           && (dev->d_name[1] == ':')
+           && (dev->d_name[2] == '\0')) {
+               drive_char = dev->d_name[0];
+               numparams = 3;
+               drive_id = toupper(drive_char) - 'A';
+       }
        switch (numparams) {
        case 0:
                ntfs_log_debug("win32_open(%s) -> file.\n", dev->d_name);
@@ -854,6 +1237,12 @@ static int ntfs_device_win32_open(struct ntfs_device 
*dev, int flags)
                err = ntfs_device_win32_open_partition(drive_id, part, &fd,
                                flags);
                break;
+       case 3:
+               ntfs_log_debug("win32_open(%s) -> drive %c:\n",
+                               dev->d_name, drive_char);
+               err = ntfs_device_win32_open_lowlevel(drive_id, &fd,
+                               flags);
+               break;
        default:
                ntfs_log_debug("win32_open(%s) -> unknwon file format.\n",
                                dev->d_name);
@@ -866,7 +1255,7 @@ static int ntfs_device_win32_open(struct ntfs_device *dev, 
int flags)
        /* Setup our read-only flag. */
        if ((flags & O_RDWR) != O_RDWR)
                NDevSetReadOnly(dev);
-       dev->d_private = malloc(sizeof(win32_fd));
+       dev->d_private = (win32_fd*)ntfs_malloc(sizeof(win32_fd));
        memcpy(dev->d_private, &fd, sizeof(win32_fd));
        NDevSetOpen(dev);
        NDevClearDirty(dev);
@@ -916,7 +1305,8 @@ static s64 ntfs_device_win32_seek(struct ntfs_device *dev, 
s64 offset,
                errno = EINVAL;
                return -1;
        }
-       if (abs_ofs < 0 || abs_ofs > fd->part_length) {
+       if ((abs_ofs < 0)
+           || (fd->ntdll && (abs_ofs > fd->part_length))) {
                ntfs_log_trace("Seeking outsize seekable area.\n");
                errno = EINVAL;
                return -1;
@@ -937,18 +1327,19 @@ static s64 ntfs_device_win32_seek(struct ntfs_device 
*dev, s64 offset,
  * error returns -1 and errno set.  Transfer starts from position @pos on @fd.
  *
  * Notes:
- *     - @pos, @buf, and @count must be aligned to NTFS_BLOCK_SIZE.
+ *     - @pos, @buf, and @count must be aligned to geo_sector_size
  *     - When dealing with volumes, a single call must not span both volume
  *       and disk extents.
  *     - Does not use/set @fd->pos.
  */
 static s64 ntfs_device_win32_pio(win32_fd *fd, const s64 pos,
-               const s64 count, void *b, const BOOL write)
+               const s64 count, void *rbuf, const void *wbuf)
 {
        LARGE_INTEGER li;
        HANDLE handle;
        DWORD bt;
        BOOL res;
+       s64 bytes;
 
        ntfs_log_trace("pos = 0x%llx, count = 0x%llx, direction = %s.\n",
                        (long long)pos, (long long)count, write ? "write" :
@@ -962,21 +1353,57 @@ static s64 ntfs_device_win32_pio(win32_fd *fd, const s64 
pos,
                handle = fd->handle;
                li.QuadPart += fd->part_start;
        }
-       if (!fnSetFilePointerEx(handle, li, NULL, FILE_BEGIN)) {
-               errno = ntfs_w32error_to_errno(GetLastError());
-               ntfs_log_trace("SetFilePointer failed.\n");
-               return -1;
-       }
-       if (write)
-               res = WriteFile(handle, b, count, &bt, NULL);
-       else
-               res = ReadFile(handle, b, count, &bt, NULL);
-       if (!res) {
-               errno = ntfs_w32error_to_errno(GetLastError());
-               ntfs_log_trace("%sFile() failed.\n", write ? "Write" : "Read");
-               return -1;
+
+       if (fd->ntdll) {
+               IO_STATUS_BLOCK io_status;
+               NTSTATUS res;
+               LARGE_INTEGER offset;
+
+               io_status.Status = STATUS_SUCCESS;
+               io_status.Information = 0;
+               offset.QuadPart = pos;
+               if (wbuf) {
+                       res = NtWriteFile(fd->handle,(HANDLE)NULL,
+                                       (PIO_APC_ROUTINE)NULL,(void*)NULL,
+                                       &io_status, wbuf, count,
+                                       &offset, (PULONG)NULL);
+               } else {
+                       res = NtReadFile(fd->handle,(HANDLE)NULL,
+                                       (PIO_APC_ROUTINE)NULL,(void*)NULL,
+                                       &io_status, rbuf, count,
+                                       &offset, (PULONG)NULL);
+               }
+               if (res == STATUS_SUCCESS) {
+                       bytes = io_status.Information;
+               } else {
+                       bytes = -1;
+                       errno = ntfs_ntstatus_to_errno(res);
+               }
+       } else {
+               if (!fnSetFilePointerEx(handle, li, NULL, FILE_BEGIN)) {
+                       errno = ntfs_w32error_to_errno(GetLastError());
+                       ntfs_log_trace("SetFilePointer failed.\n");
+                       return -1;
+               }
+               if (wbuf)
+                       res = WriteFile(handle, wbuf, count, &bt, NULL);
+               else
+                       res = ReadFile(handle, rbuf, count, &bt, NULL);
+               bytes = bt;
+               if (!res) {
+                       errno = ntfs_w32error_to_errno(GetLastError());
+                       ntfs_log_trace("%sFile() failed.\n", write ?
+                                                       "Write" : "Read");
+                       return -1;
+               }
+               if (rbuf && !pos) {
+                       /* get the sector size from the boot sector */
+                       char *boot = (char*)rbuf;
+                       fd->geo_sector_size = (boot[11] & 255)
+                                               + ((boot[12] & 255) << 8);
+               }
        }
-       return bt;
+       return bytes;
 }
 
 /**
@@ -990,7 +1417,7 @@ static s64 ntfs_device_win32_pio(win32_fd *fd, const s64 
pos,
  * returns -1 and errno set.  Read starts from position @pos.
  *
  * Notes:
- *     - @pos, @buf, and @count must be aligned to NTFS_BLOCK_SIZE.
+ *     - @pos, @buf, and @count must be aligned to geo_sector_size.
  *     - When dealing with volumes, a single call must not span both volume
  *       and disk extents.
  *     - Does not use/set @fd->pos.
@@ -998,7 +1425,7 @@ static s64 ntfs_device_win32_pio(win32_fd *fd, const s64 
pos,
 static inline s64 ntfs_device_win32_pread_simple(win32_fd *fd, const s64 pos,
                const s64 count, void *b)
 {
-       return ntfs_device_win32_pio(fd, pos, count, b, FALSE);
+       return ntfs_device_win32_pio(fd, pos, count, b, (void*)NULL);
 }
 
 /**
@@ -1018,9 +1445,9 @@ static s64 ntfs_device_win32_read(struct ntfs_device 
*dev, void *b, s64 count)
        int old_ofs, ofs;
 
        old_pos = fd->pos;
-       old_ofs = ofs = old_pos & (NTFS_BLOCK_SIZE - 1);
-       to_read = (ofs + count + NTFS_BLOCK_SIZE - 1) &
-                       ~(s64)(NTFS_BLOCK_SIZE - 1);
+       old_ofs = ofs = old_pos & (fd->geo_sector_size - 1);
+       to_read = (ofs + count + fd->geo_sector_size - 1) &
+                       ~(s64)(fd->geo_sector_size - 1);
        /* Impose maximum of 2GB to be on the safe side. */
        if (to_read > 0x80000000) {
                int delta = to_read - count;
@@ -1031,8 +1458,8 @@ static s64 ntfs_device_win32_read(struct ntfs_device 
*dev, void *b, s64 count)
                        "ofs = %i, to_read = 0x%llx.\n", fd, b,
                        (long long)count, (long long)old_pos, ofs,
                        (long long)to_read);
-       if (!((unsigned long)b & (NTFS_BLOCK_SIZE - 1)) && !old_ofs &&
-                       !(count & (NTFS_BLOCK_SIZE - 1)))
+       if (!((unsigned long)b & (fd->geo_sector_size - 1)) && !old_ofs &&
+                       !(count & (fd->geo_sector_size - 1)))
                alignedbuffer = b;
        else {
                alignedbuffer = (BYTE *)VirtualAlloc(NULL, to_read, MEM_COMMIT,
@@ -1047,7 +1474,7 @@ static s64 ntfs_device_win32_read(struct ntfs_device 
*dev, void *b, s64 count)
                s64 vol_to_read = fd->geo_size - old_pos;
                if (count > vol_to_read) {
                        br = ntfs_device_win32_pread_simple(fd,
-                                       old_pos & ~(s64)(NTFS_BLOCK_SIZE - 1),
+                                       old_pos & ~(s64)(fd->geo_sector_size - 
1),
                                        ofs + vol_to_read, alignedbuffer);
                        if (br == -1)
                                goto read_error;
@@ -1058,13 +1485,13 @@ static s64 ntfs_device_win32_read(struct ntfs_device 
*dev, void *b, s64 count)
                        }
                        br -= ofs;
                        fd->pos += br;
-                       ofs = fd->pos & (NTFS_BLOCK_SIZE - 1);
+                       ofs = fd->pos & (fd->geo_sector_size - 1);
                        if (br != vol_to_read)
                                goto read_partial;
                }
        }
        i = ntfs_device_win32_pread_simple(fd,
-                       fd->pos & ~(s64)(NTFS_BLOCK_SIZE - 1), to_read,
+                       fd->pos & ~(s64)(fd->geo_sector_size - 1), to_read,
                        alignedbuffer + br);
        if (i == -1) {
                if (br)
@@ -1115,11 +1542,18 @@ static int ntfs_device_win32_close(struct ntfs_device 
*dev)
                if (!CloseHandle(fd->vol_handle))
                        ntfs_log_trace("CloseHandle() failed for volume.\n");
        }
-       rvl = CloseHandle(fd->handle);
+       if (fd->ntdll) {
+               ntfs_device_win32_setlock(fd->handle,FSCTL_UNLOCK_VOLUME);
+               rvl = NtClose(fd->handle) == STATUS_SUCCESS;
+       } else
+               rvl = CloseHandle(fd->handle);
        free(fd);
        if (!rvl) {
                errno = ntfs_w32error_to_errno(GetLastError());
-               ntfs_log_trace("CloseHandle() failed.\n");
+               if (fd->ntdll)
+                       ntfs_log_trace("NtClose() failed.\n");
+               else
+                       ntfs_log_trace("CloseHandle() failed.\n");
                return -1;
        }
        return 0;
@@ -1174,7 +1608,7 @@ static int ntfs_device_win32_sync(struct ntfs_device *dev)
  * errno set.  Write starts from position @pos.
  *
  * Notes:
- *     - @pos, @buf, and @count must be aligned to NTFS_BLOCK_SIZE.
+ *     - @pos, @buf, and @count must be aligned to geo_sector_size.
  *     - When dealing with volumes, a single call must not span both volume
  *       and disk extents.
  *     - Does not use/set @fd->pos.
@@ -1182,7 +1616,7 @@ static int ntfs_device_win32_sync(struct ntfs_device *dev)
 static inline s64 ntfs_device_win32_pwrite_simple(win32_fd *fd, const s64 pos,
                const s64 count, const void *b)
 {
-       return ntfs_device_win32_pio(fd, pos, count, (void *)b, TRUE);
+       return ntfs_device_win32_pio(fd, pos, count, (void*)NULL, b);
 }
 
 /**
@@ -1203,9 +1637,9 @@ static s64 ntfs_device_win32_write(struct ntfs_device 
*dev, const void *b,
        int old_ofs, ofs;
 
        old_pos = fd->pos;
-       old_ofs = ofs = old_pos & (NTFS_BLOCK_SIZE - 1);
-       to_write = (ofs + count + NTFS_BLOCK_SIZE - 1) &
-                       ~(s64)(NTFS_BLOCK_SIZE - 1);
+       old_ofs = ofs = old_pos & (fd->geo_sector_size - 1);
+       to_write = (ofs + count + fd->geo_sector_size - 1) &
+                       ~(s64)(fd->geo_sector_size - 1);
        /* Impose maximum of 2GB to be on the safe side. */
        if (to_write > 0x80000000) {
                int delta = to_write - count;
@@ -1224,8 +1658,8 @@ static s64 ntfs_device_win32_write(struct ntfs_device 
*dev, const void *b,
        if (!count)
                return 0;
        NDevSetDirty(dev);
-       if (!((unsigned long)b & (NTFS_BLOCK_SIZE - 1)) && !old_ofs &&
-                       !(count & (NTFS_BLOCK_SIZE - 1)))
+       if (!((unsigned long)b & (fd->geo_sector_size - 1)) && !old_ofs &&
+                       !(count & (fd->geo_sector_size - 1)))
                alignedbuffer = (BYTE *)b;
        else {
                s64 end;
@@ -1240,9 +1674,9 @@ static s64 ntfs_device_win32_write(struct ntfs_device 
*dev, const void *b,
                /* Read first sector if start of write not sector aligned. */
                if (ofs) {
                        i = ntfs_device_win32_pread_simple(fd,
-                                       old_pos & ~(s64)(NTFS_BLOCK_SIZE - 1),
-                                       NTFS_BLOCK_SIZE, alignedbuffer);
-                       if (i != NTFS_BLOCK_SIZE) {
+                                       old_pos & ~(s64)(fd->geo_sector_size - 
1),
+                                       fd->geo_sector_size, alignedbuffer);
+                       if (i != fd->geo_sector_size) {
                                if (i >= 0)
                                        errno = EIO;
                                goto write_error;
@@ -1255,13 +1689,13 @@ static s64 ntfs_device_win32_write(struct ntfs_device 
*dev, const void *b,
                 * yet, i.e. the start of the write is sector aligned.
                 */
                end = old_pos + count;
-               if ((end & (NTFS_BLOCK_SIZE - 1)) &&
-                               ((to_write > NTFS_BLOCK_SIZE) || !ofs)) {
+               if ((end & (fd->geo_sector_size - 1)) &&
+                               ((to_write > fd->geo_sector_size) || !ofs)) {
                        i = ntfs_device_win32_pread_simple(fd,
-                                       end & ~(s64)(NTFS_BLOCK_SIZE - 1),
-                                       NTFS_BLOCK_SIZE, alignedbuffer +
-                                       to_write - NTFS_BLOCK_SIZE);
-                       if (i != NTFS_BLOCK_SIZE) {
+                                       end & ~(s64)(fd->geo_sector_size - 1),
+                                       fd->geo_sector_size, alignedbuffer +
+                                       to_write - fd->geo_sector_size);
+                       if (i != fd->geo_sector_size) {
                                if (i >= 0)
                                        errno = EIO;
                                goto write_error;
@@ -1274,7 +1708,7 @@ static s64 ntfs_device_win32_write(struct ntfs_device 
*dev, const void *b,
                s64 vol_to_write = fd->geo_size - old_pos;
                if (count > vol_to_write) {
                        bw = ntfs_device_win32_pwrite_simple(fd,
-                                       old_pos & ~(s64)(NTFS_BLOCK_SIZE - 1),
+                                       old_pos & ~(s64)(fd->geo_sector_size - 
1),
                                        ofs + vol_to_write, alignedbuffer);
                        if (bw == -1)
                                goto write_error;
@@ -1285,13 +1719,13 @@ static s64 ntfs_device_win32_write(struct ntfs_device 
*dev, const void *b,
                        }
                        bw -= ofs;
                        fd->pos += bw;
-                       ofs = fd->pos & (NTFS_BLOCK_SIZE - 1);
+                       ofs = fd->pos & (fd->geo_sector_size - 1);
                        if (bw != vol_to_write)
                                goto write_partial;
                }
        }
        i = ntfs_device_win32_pwrite_simple(fd,
-                       fd->pos & ~(s64)(NTFS_BLOCK_SIZE - 1), to_write,
+                       fd->pos & ~(s64)(fd->geo_sector_size - 1), to_write,
                        alignedbuffer + bw);
        if (i == -1) {
                if (bw)
@@ -1329,19 +1763,22 @@ static int ntfs_device_win32_stat(struct ntfs_device 
*dev, struct stat *buf)
        win32_fd *fd = (win32_fd *)dev->d_private;
        mode_t st_mode;
 
-       switch (GetFileType(fd->handle)) {
-       case FILE_TYPE_CHAR:
-               st_mode = S_IFCHR;
-               break;
-       case FILE_TYPE_DISK:
+       if ((dev->d_name[1] == ':') && (dev->d_name[2] == '\0'))
                st_mode = S_IFBLK;
-               break;
-       case FILE_TYPE_PIPE:
-               st_mode = S_IFIFO;
-               break;
-       default:
-               st_mode = 0;
-       }
+       else
+               switch (GetFileType(fd->handle)) {
+               case FILE_TYPE_CHAR:
+                       st_mode = S_IFCHR;
+                       break;
+               case FILE_TYPE_DISK:
+                       st_mode = S_IFREG;
+                       break;
+               case FILE_TYPE_PIPE:
+                       st_mode = S_IFIFO;
+                       break;
+               default:
+                       st_mode = 0;
+               }
        memset(buf, 0, sizeof(struct stat));
        buf->st_mode = st_mode;
        buf->st_size = fd->part_length;
@@ -1352,6 +1789,7 @@ static int ntfs_device_win32_stat(struct ntfs_device 
*dev, struct stat *buf)
        return 0;
 }
 
+#ifdef HDIO_GETGEO
 /**
  * ntfs_win32_hdio_getgeo - get drive geometry
  * @dev:       ntfs device obtained via ->open
@@ -1373,6 +1811,7 @@ static __inline__ int ntfs_win32_hdio_getgeo(struct 
ntfs_device *dev,
        argp->start = fd->part_hidden_sectors;
        return 0;
 }
+#endif
 
 /**
  * ntfs_win32_blksszget - get block device sector size
@@ -1404,7 +1843,9 @@ static __inline__ int ntfs_win32_blksszget(struct 
ntfs_device *dev,int *argp)
 static int ntfs_device_win32_ioctl(struct ntfs_device *dev, int request,
                void *argp)
 {
+#if defined(BLKGETSIZE) | defined(BLKGETSIZE64)
        win32_fd *fd = (win32_fd *)dev->d_private;
+#endif
 
        ntfs_log_trace("win32_ioctl(%d) called.\n", request);
        switch (request) {
@@ -1454,13 +1895,40 @@ static int ntfs_device_win32_ioctl(struct ntfs_device 
*dev, int request,
 static s64 ntfs_device_win32_pread(struct ntfs_device *dev, void *b,
                s64 count, s64 offset)
 {
-       return ntfs_pread(dev, offset, count, b);
+       s64 got;
+       win32_fd *fd;
+
+               /* read the fast way if sector aligned */
+       fd = (win32_fd*)dev->d_private;
+       if (!((count | offset) & (fd->geo_sector_size - 1))) {
+               got = ntfs_device_win32_pio(fd, offset, count, b, (void*)NULL);
+       } else {
+               if (ntfs_device_win32_seek(dev, offset, 0) == -1)
+                       got = 0;
+               else
+                       got = ntfs_device_win32_read(dev, b, count);
+       }
+
+       return (got);
 }
 
 static s64 ntfs_device_win32_pwrite(struct ntfs_device *dev, const void *b,
                s64 count, s64 offset)
 {
-       return ntfs_pwrite(dev, offset, count, b);
+       s64 put;
+       win32_fd *fd;
+
+               /* write the fast way if sector aligned */
+       fd = (win32_fd*)dev->d_private;
+       if (!((count | offset) & (fd->geo_sector_size - 1))) {
+               put = ntfs_device_win32_pio(fd, offset, count, (void*)NULL, b);
+       } else {
+               if (ntfs_device_win32_seek(dev, offset, 0) == -1)
+                       put = 0;
+               else
+                       put = ntfs_device_win32_write(dev, b, count);
+       }
+       return (put);
 }
 
 struct ntfs_device_operations ntfs_device_win32_io_ops = {
@@ -1475,3 +1943,87 @@ struct ntfs_device_operations ntfs_device_win32_io_ops = 
{
        .stat           = ntfs_device_win32_stat,
        .ioctl          = ntfs_device_win32_ioctl
 };
+
+/*
+ *                     Mark an open file as sparse
+ *
+ *     This is only called by ntfsclone when cloning a volume to a file.
+ *     The argument is the target file, not a volume.
+ *
+ *     Returns 0 if successful.
+ */
+
+int ntfs_win32_set_sparse(int fd)
+{
+       BOOL ok;
+       HANDLE handle;
+       DWORD bytes;   
+
+       handle = get_osfhandle(fd);
+       if (handle == INVALID_HANDLE_VALUE)
+               ok = FALSE;
+       else
+               ok = DeviceIoControl(handle, FSCTL_SET_SPARSE,
+                               (void*)NULL, 0, (void*)NULL, 0,
+                               &bytes, (LPOVERLAPPED)NULL);
+       return (!ok);
+}
+
+/*
+ *                     Resize an open file
+ *
+ *     This is only called by ntfsclone when cloning a volume to a file.
+ *     The argument must designate a file, not a volume.
+ *
+ *     Returns 0 if successful.
+ */
+
+static int win32_ftruncate(HANDLE handle, s64 size)
+{
+       BOOL ok;
+       LONG hsize, lsize;
+       LONG ohsize, olsize;
+
+       if (handle == INVALID_HANDLE_VALUE)
+               ok = FALSE;
+       else {
+               SetLastError(NO_ERROR);
+                       /* save original position */
+               ohsize = 0;
+               olsize = SetFilePointer(handle, 0, &ohsize, 1);
+               hsize = size >> 32;
+               lsize = size & 0xffffffff;
+               ok = (SetFilePointer(handle, lsize, &hsize, 0) == (DWORD)lsize)
+                   && (GetLastError() == NO_ERROR)
+                   && SetEndOfFile(handle);
+                       /* restore original position, even if above failed */
+               SetFilePointer(handle, olsize, &ohsize, 0);
+               if (GetLastError() != NO_ERROR)
+                       ok = FALSE;
+       }
+       if (!ok)
+               errno = EINVAL;
+       return (ok ? 0 : -1);
+}
+
+int ntfs_device_win32_ftruncate(struct ntfs_device *dev, s64 size)
+{
+       win32_fd *fd;
+       int ret;
+
+       ret = -1;
+       fd = (win32_fd*)dev->d_private;
+       if (fd && !fd->ntdll)
+               ret = win32_ftruncate(fd->handle, size);
+       return (ret);
+}
+
+int ntfs_win32_ftruncate(int fd, s64 size)
+{
+       int ret;
+       HANDLE handle;
+
+       handle = get_osfhandle(fd);
+       ret = win32_ftruncate(handle, size);
+       return (ret);
+}


Other related posts:

  • » [haiku-commits] haiku: hrev47115 - src/add-ons/kernel/file_systems/ntfs/libntfs - Gerasim Troeglazov