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
parent
1e625a9563
commit
9442db0d8b
41
configure.ac
41
configure.ac
|
@ -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"])
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 = \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue