NTFS: Update libntfs to 2014.2.15

This commit is contained in:
Gerasim Troeglazov
2014-04-14 11:35:50 +00:00
parent 02cdea9f9d
commit d68289f7ae
14 changed files with 860 additions and 139 deletions
@@ -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)))
@@ -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);
@@ -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;
/**
@@ -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;
@@ -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;
}
/**
@@ -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;
@@ -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
/* Not on Cygwin; use standard Unix style low level device operations. */
#ifndef HAVE_WINDOWS_H
/* 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. */
@@ -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;
@@ -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,
@@ -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
@@ -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)
@@ -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)
@@ -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;
}
File diff suppressed because it is too large Load Diff