Added use of hd library to get the legacy BIOS geometry

Author: Anton Altaparmakov <anton@tuxera.com>
Date:   Tue Feb 12 10:33:55 2013 +0000

    Modify libntfs-3g to make use of hd library to get the legacy BIOS geometry
    from EDD.  We scan all whole disk devices on the system and check if they
    match the open ntfs device and if not we scan all partition devices on the
    system and check if they match the open ntfs device.

    If we find a partition device to match then we find its parent device again
    using the hd library.

    Once we have the parent of the partition device or we matched a whole disk
    device we get the legacy EDD sectors per track and heads again using the hd
    library.

    Use of the hd library is auto detected (based on finding <hd.h> header file,
    being able to link against libhd and finding the hd_list symbol in libhd.

    Use can also be disabled/enabled/libhd prefix specified at ./configure time.
    See ./configure --help for details.

    Note this obviously requires libhd to be installed.  On Ubuntu 12/04 systems
    the relevant packages needed are libhd-dev and libhd16 (on older Ubuntu
    versions it will be libhdN where N is some number <= 16 but an easy way to
    get the right package is to simply install libhd-dev which by dependency
    pulls in the correct libhdN package) whilst on SLES systems the relevant
    packages needed are hwinfo and hwinfo-devel.
edge.strict_endians
Jean-Pierre André 2013-02-12 15:45:54 +01:00
parent 1e625a9563
commit 9442db0d8b
4 changed files with 201 additions and 28 deletions

View File

@ -2,7 +2,7 @@
# configure.ac - Source file to generate "./configure" to prepare package for
# compilation.
#
# Copyright (c) 2000-2006 Anton Altaparmakov
# Copyright (c) 2000-2013 Anton Altaparmakov
# Copyright (c) 2003 Jan Kratochvil
# Copyright (c) 2005-2009 Szabolcs Szakacsits
# Copyright (C) 2007-2008 Alon Bar-Lev
@ -417,6 +417,43 @@ if test "x$extrapath" != "x"; then
fi
fi
# Specify support for obtaining the correct BIOS legacy geometry needed for
# Windows to boot in CHS mode. We check if hd.h header is present and the hd
# library is present that goes with it and then check if the hd_list() function
# is present and usable.
#
# Using the hd library is enabled by default and can be disabled with the
# --disable-hd option to the configure script.
AC_ARG_WITH(hd, [
--with-hd@<:@=PFX@:>@ use Windows compliant disk geometry, with optional
prefix to hd library and headers @<:@default=detect@:>@
--without-hd do not use Windows compliant disk geometry],
if test "$with_hd" = "yes"; then
extrapath2=default
elif test "$with_hd" = "no"; then
extrapath2=
else
extrapath2=$with_hd
fi,
extrapath2=default
)
if test "x$extrapath2" != "x"; then
if test "x$extrapath2" != "xdefault"; then
LIBNTFS_CPPFLAGS="$LIBNTFS_CPPFLAGS -I$extrapath2/include"
LIBNTFS_LIBS="$LIBNTFS_LIBS -L$extrapath2/lib"
fi
AC_CHECK_HEADER([hd.h],
AC_CHECK_LIB([hd], [hd_list],
AC_DEFINE([ENABLE_HD], 1,
[Define this to 1 if you want to enable use of Windows
compliant disk geometry.])
LIBNTFS_LIBS="$LIBNTFS_LIBS -lhd",
AC_MSG_WARN([ntfsprogs Windows compliant geometry code requires the hd library.]),
),
AC_MSG_WARN([ntfsprogs Windows compliant geometry code requires the hd library.]),
)
fi
# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([ctype.h fcntl.h libgen.h libintl.h limits.h locale.h \
@ -554,6 +591,8 @@ AC_SUBST([LIBFUSE_LITE_CFLAGS])
AC_SUBST([LIBFUSE_LITE_LIBS])
AC_SUBST([MKNTFS_CPPFLAGS])
AC_SUBST([MKNTFS_LIBS])
AC_SUBST([LIBNTFS_CPPFLAGS])
AC_SUBST([LIBNTFS_LIBS])
AC_SUBST([OUTPUT_FORMAT])
AM_CONDITIONAL([FUSE_INTERNAL], [test "${with_fuse}" = "internal"])
AM_CONDITIONAL([GENERATE_LDSCRIPT], [test "${enable_ldscript}" = "yes"])

View File

@ -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;

View File

@ -10,7 +10,8 @@ noinst_LTLIBRARIES = libntfs-3g.la
endif
libntfs_3g_la_CFLAGS = $(AM_CFLAGS) -I$(top_srcdir)/include/ntfs-3g
libntfs_3g_la_CPPFLAGS= $(AM_CPPFLAGS) $(LIBNTFS_CPPFLAGS)
libntfs_3g_la_LIBADD = $(LIBNTFS_LIBS)
libntfs_3g_la_LDFLAGS = -version-info $(LIBNTFS_3G_VERSION) -no-undefined
libntfs_3g_la_SOURCES = \

View File

@ -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
#include "types.h"
#include "mst.h"
@ -128,6 +132,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;
}
@ -642,6 +648,131 @@ 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 *devlist, *partlist, *hd;
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:
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
@ -653,6 +784,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)
{
@ -660,20 +792,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;
}
/**
@ -687,6 +814,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)
{
@ -694,20 +822,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;
}
/**