1 /**
   2  * device.c - Low level device io functions. Part of the Linux-NTFS project.
   3  *
   4  * Copyright (c) 2004-2006 Anton Altaparmakov
   5  *
   6  * This program/include file is free software; you can redistribute it and/or
   7  * modify it under the terms of the GNU General Public License as published
   8  * by the Free Software Foundation; either version 2 of the License, or
   9  * (at your option) any later version.
  10  *
  11  * This program/include file is distributed in the hope that it will be
  12  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14  * GNU General Public License for more details.
  15  *
  16  * You should have received a copy of the GNU General Public License
  17  * along with this program (in the main directory of the Linux-NTFS
  18  * distribution in the file COPYING); if not, write to the Free Software
  19  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20  */
  21 
  22 #ifdef HAVE_CONFIG_H
  23 #include "config.h"
  24 #endif
  25 
  26 #ifdef HAVE_UNISTD_H
  27 #include <unistd.h>
  28 #endif
  29 #ifdef HAVE_STDLIB_H
  30 #include <stdlib.h>
  31 #endif
  32 #ifdef HAVE_STRING_H
  33 #include <string.h>
  34 #endif
  35 #ifdef HAVE_ERRNO_H
  36 #include <errno.h>
  37 #endif
  38 #ifdef HAVE_STDIO_H
  39 #include <stdio.h>
  40 #endif
  41 #ifdef HAVE_SYS_TYPES_H
  42 #include <sys/types.h>
  43 #endif
  44 #ifdef HAVE_SYS_STAT_H
  45 #include <sys/stat.h>
  46 #endif
  47 #ifdef HAVE_FCNTL_H
  48 #include <fcntl.h>
  49 #endif
  50 #ifdef HAVE_SYS_IOCTL_H
  51 #include <sys/ioctl.h>
  52 #endif
  53 #ifdef HAVE_SYS_PARAM_H
  54 #include <sys/param.h>
  55 #endif
  56 #ifdef HAVE_SYS_MOUNT_H
  57 #include <sys/mount.h>
  58 #endif
  59 #ifdef HAVE_LINUX_FD_H
  60 #include <linux/fd.h>
  61 #endif
  62 #ifdef HAVE_LINUX_HDREG_H
  63 #include <linux/hdreg.h>
  64 #endif
  65 
  66 #include "compat.h"
  67 #include "types.h"
  68 #include "mst.h"
  69 #include "debug.h"
  70 #include "device.h"
  71 #include "logging.h"
  72 
  73 #if defined(linux) && defined(_IO) && !defined(BLKGETSIZE)
  74 #define BLKGETSIZE      _IO(0x12,96)  /* Get device size in 512-byte blocks. */
  75 #endif
  76 #if defined(linux) && defined(_IOR) && !defined(BLKGETSIZE64)
  77 #define BLKGETSIZE64    _IOR(0x12,114,size_t)   /* Get device size in bytes. */
  78 #endif
  79 #if defined(linux) && !defined(HDIO_GETGEO)
  80 #define HDIO_GETGEO     0x0301  /* Get device geometry. */
  81 #endif
  82 #if defined(linux) && defined(_IO) && !defined(BLKSSZGET)
  83 #       define BLKSSZGET _IO(0x12,104) /* Get device sector size in bytes. */
  84 #endif
  85 #if defined(linux) && defined(_IO) && !defined(BLKBSZSET)
  86 #       define BLKBSZSET _IOW(0x12,113,size_t) /* Set device block size in bytes. */
  87 #endif
  88 
  89 /**
  90  * ntfs_device_alloc - allocate an ntfs device structure and pre-initialize it
  91  * @name:       name of the device (must be present)
  92  * @state:      initial device state (usually zero)
  93  * @dops:       ntfs device operations to use with the device (must be present)
  94  * @priv_data:  pointer to private data (optional)
  95  *
  96  * Allocate an ntfs device structure and pre-initialize it with the user-
  97  * specified device operations @dops, device state @state, device name @name,
  98  * and optional private data @priv_data.
  99  *
 100  * Note, @name is copied and can hence be freed after this functions returns.
 101  *
 102  * On success return a pointer to the allocated ntfs device structure and on
 103  * error return NULL with errno set to the error code returned by malloc().
 104  */
 105 struct ntfs_device *ntfs_device_alloc(const char *name, const long state,
 106                 struct ntfs_device_operations *dops, void *priv_data)
 107 {
 108         struct ntfs_device *dev;
 109 
 110         if (!name) {
 111                 errno = EINVAL;
 112                 return NULL;
 113         }
 114 
 115         dev = (struct ntfs_device *)ntfs_malloc(sizeof(struct ntfs_device));
 116         if (dev) {
 117                 if (!(dev->d_name = strdup(name))) {
 118                         int eo = errno;
 119                         free(dev);
 120                         errno = eo;
 121                         return NULL;
 122                 }
 123                 dev->d_ops = dops;
 124                 dev->d_state = state;
 125                 dev->d_private = priv_data;
 126         }
 127         return dev;
 128 }
 129 
 130 /**
 131  * ntfs_device_free - free an ntfs device structure
 132  * @dev:        ntfs device structure to free
 133  *
 134  * Free the ntfs device structure @dev.
 135  *
 136  * Return 0 on success or -1 on error with errno set to the error code. The
 137  * following error codes are defined:
 138  *      EINVAL          Invalid pointer @dev.
 139  *      EBUSY           Device is still open. Close it before freeing it!
 140  */
 141 int ntfs_device_free(struct ntfs_device *dev)
 142 {
 143         if (!dev) {
 144                 errno = EINVAL;
 145                 return -1;
 146         }
 147         if (NDevOpen(dev)) {
 148                 errno = EBUSY;
 149                 return -1;
 150         }
 151         free(dev->d_name);
 152         free(dev);
 153         return 0;
 154 }
 155 
 156 /**
 157  * fake_pread - read operation disguised as pread
 158  * @dev:        device to read from
 159  * @b:          output data buffer
 160  * @count:      number of bytes to read
 161  * @pos:        position in device to read from
 162  *
 163  * Auxiliary function, used when we emulate pread by seek() + a sequence of
 164  * read()s.
 165  */
 166 static s64 fake_pread(struct ntfs_device *dev, void *b, s64 count,
 167                 s64 pos __attribute__((unused)))
 168 {
 169         return dev->d_ops->read(dev, b, count);
 170 }
 171 
 172 /**
 173  * ntfs_pread - positioned read from disk
 174  * @dev:        device to read from
 175  * @pos:        position in device to read from
 176  * @count:      number of bytes to read
 177  * @b:          output data buffer
 178  *
 179  * This function will read @count bytes from device @dev at position @pos into
 180  * the data buffer @b.
 181  *
 182  * On success, return the number of successfully read bytes. If this number is
 183  * lower than @count this means that we have either reached end of file or
 184  * encountered an error during the read so that the read is partial. 0 means
 185  * end of file or nothing to read (@count is 0).
 186  *
 187  * On error and nothing has been read, return -1 with errno set appropriately
 188  * to the return code of either seek, read, or set to EINVAL in case of
 189  * invalid arguments.
 190  */
 191 s64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b)
 192 {
 193         s64 br, total;
 194         struct ntfs_device_operations *dops;
 195         s64 (*_pread)(struct ntfs_device *, void *, s64, s64);
 196 
 197         ntfs_log_trace("Entering for pos 0x%llx, count 0x%llx.\n", pos, count);
 198         if (!b || count < 0 || pos < 0) {
 199                 errno = EINVAL;
 200                 return -1;
 201         }
 202         if (!count)
 203                 return 0;
 204         dops = dev->d_ops;
 205         _pread = dops->pread;
 206         if (!_pread)
 207                 _pread = fake_pread;
 208 seek:
 209         /* Locate to position if pread is to be emulated by seek() + read(). */
 210         if (_pread == fake_pread &&
 211                         dops->seek(dev, pos, SEEK_SET) == (off_t)-1) {
 212                 ntfs_log_perror("ntfs_pread: device seek to 0x%llx returned "
 213                                 "error", pos);
 214                 return -1;
 215         }
 216         /* Read the data. */
 217         for (total = 0; count; count -= br, total += br) {
 218                 br = _pread(dev, (char*)b + total, count, pos + total);
 219                 /* If everything ok, continue. */
 220                 if (br > 0)
 221                         continue;
 222                 /* If EOF or error return number of bytes read. */
 223                 if (!br || total)
 224                         return total;
 225                 /*
 226                  * If pread is not supported by the OS, fall back to emulating
 227                  * it by seek() + read() and set the device pread() pointer to
 228                  * NULL so we automatically use seek() + read() from now on.
 229                  */
 230                 if (errno == ENOSYS && _pread != fake_pread) {
 231                         _pread = fake_pread;
 232                         dops->pread = NULL;
 233                         goto seek;
 234                 }
 235                 /* Nothing read and error, return error status. */
 236                 return br;
 237         }
 238         /* Finally, return the number of bytes read. */
 239         return total;
 240 }
 241 
 242 /**
 243  * fake_pwrite - write operation disguised as pwrite
 244  * @dev:        device to write to
 245  * @b:          input data buffer
 246  * @count:      number of bytes to write
 247  * @pos:        position in device to write to
 248  *
 249  * Auxiliary function, used when we emulate pwrite by seek() + a sequence of
 250  * write()s.
 251  */
 252 static s64 fake_pwrite(struct ntfs_device *dev, const void *b, s64 count,
 253                 s64 pos __attribute__((unused)))
 254 {
 255         return dev->d_ops->write(dev, b, count);
 256 }
 257 
 258 /**
 259  * ntfs_pwrite - positioned write to disk
 260  * @dev:        device to write to
 261  * @pos:        position in file descriptor to write to
 262  * @count:      number of bytes to write
 263  * @b:          data buffer to write to disk
 264  *
 265  * This function will write @count bytes from data buffer @b to the device @dev
 266  * at position @pos.
 267  *
 268  * On success, return the number of successfully written bytes. If this number
 269  * is lower than @count this means that the write has been interrupted in
 270  * flight or that an error was encountered during the write so that the write
 271  * is partial. 0 means nothing was written (also return 0 when @count is 0).
 272  *
 273  * On error and nothing has been written, return -1 with errno set
 274  * appropriately to the return code of either seek, write, or set
 275  * to EINVAL in case of invalid arguments.
 276  */
 277 s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
 278                 const void *b)
 279 {
 280         s64 written, total;
 281         struct ntfs_device_operations *dops;
 282         s64 (*_pwrite)(struct ntfs_device *, const void *, s64, s64);
 283 
 284         ntfs_log_trace("Entering for pos 0x%llx, count 0x%llx.\n", pos, count);
 285         if (!b || count < 0 || pos < 0) {
 286                 errno = EINVAL;
 287                 return -1;
 288         }
 289         if (!count)
 290                 return 0;
 291         if (NDevReadOnly(dev)) {
 292                 errno = EROFS;
 293                 return -1;
 294         }
 295         dops = dev->d_ops;
 296         _pwrite = dops->pwrite;
 297         if (!_pwrite)
 298                 _pwrite = fake_pwrite;
 299 seek:
 300         /*
 301          * Locate to position if pwrite is to be emulated by seek() + write().
 302          */
 303         if (_pwrite == fake_pwrite &&
 304                         dops->seek(dev, pos, SEEK_SET) == (off_t)-1) {
 305                 ntfs_log_perror("ntfs_pwrite: seek to 0x%llx returned error",
 306                                 pos);
 307                 return -1;
 308         }
 309         NDevSetDirty(dev);
 310         /* Write the data. */
 311         for (total = 0; count; count -= written, total += written) {
 312                 written = _pwrite(dev, (const char*)b + total, count,
 313                                 pos + total);
 314                 /* If everything ok, continue. */
 315                 if (written > 0)
 316                         continue;
 317                 /*
 318                  * If nothing written or error return number of bytes written.
 319                  */
 320                 if (!written || total)
 321                         break;
 322                 /*
 323                  * If pwrite is not supported by the OS, fall back to emulating
 324                  * it by seek() + write() and set the device pwrite() pointer
 325                  * to NULL so we automatically use seek() + write() from now
 326                  * on.
 327                  */
 328                 if (errno == ENOSYS && _pwrite != fake_pwrite) {
 329                         _pwrite = fake_pwrite;
 330                         dops->pwrite = NULL;
 331                         goto seek;
 332                 }
 333                 /* Nothing written and error, return error status. */
 334                 return written;
 335         }
 336         /* Finally, return the number of bytes written. */
 337         return total;
 338 }
 339 
 340 /**
 341  * ntfs_mst_pread - multi sector transfer (mst) positioned read
 342  * @dev:        device to read from
 343  * @pos:        position in file descriptor to read from
 344  * @count:      number of blocks to read
 345  * @bksize:     size of each block that needs mst deprotecting
 346  * @b:          output data buffer
 347  *
 348  * Multi sector transfer (mst) positioned read. This function will read @count
 349  * blocks of size @bksize bytes each from device @dev at position @pos into the
 350  * the data buffer @b.
 351  *
 352  * On success, return the number of successfully read blocks. If this number is
 353  * lower than @count this means that we have reached end of file, that the read
 354  * was interrupted, or that an error was encountered during the read so that
 355  * the read is partial. 0 means end of file or nothing was read (also return 0
 356  * when @count or @bksize are 0).
 357  *
 358  * On error and nothing was read, return -1 with errno set appropriately to the
 359  * return code of either seek, read, or set to EINVAL in case of invalid
 360  * arguments.
 361  *
 362  * NOTE: If an incomplete multi sector transfer has been detected the magic
 363  * will have been changed to magic_BAAD but no error will be returned. Thus it
 364  * is possible that we return count blocks as being read but that any number
 365  * (between zero and count!) of these blocks is actually subject to a multi
 366  * sector transfer error. This should be detected by the caller by checking for
 367  * the magic being "BAAD".
 368  */
 369 s64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count,
 370                 const u32 bksize, void *b)
 371 {
 372         s64 br, i;
 373 
 374         if (bksize & (bksize - 1) || bksize % NTFS_BLOCK_SIZE) {
 375                 errno = EINVAL;
 376                 return -1;
 377         }
 378         /* Do the read. */
 379         br = ntfs_pread(dev, pos, count * bksize, b);
 380         if (br < 0)
 381                 return br;
 382         /*
 383          * Apply fixups to successfully read data, disregarding any errors
 384          * returned from the MST fixup function. This is because we want to
 385          * fixup everything possible and we rely on the fact that the "BAAD"
 386          * magic will be detected later on.
 387          */
 388         count = br / bksize;
 389         for (i = 0; i < count; ++i)
 390                 ntfs_mst_post_read_fixup((NTFS_RECORD*)
 391                                 ((u8*)b + i * bksize), bksize);
 392         /* Finally, return the number of complete blocks read. */
 393         return count;
 394 }
 395 
 396 /**
 397  * ntfs_mst_pwrite - multi sector transfer (mst) positioned write
 398  * @dev:        device to write to
 399  * @pos:        position in file descriptor to write to
 400  * @count:      number of blocks to write
 401  * @bksize:     size of each block that needs mst protecting
 402  * @b:          data buffer to write to disk
 403  *
 404  * Multi sector transfer (mst) positioned write. This function will write
 405  * @count blocks of size @bksize bytes each from data buffer @b to the device
 406  * @dev at position @pos.
 407  *
 408  * On success, return the number of successfully written blocks. If this number
 409  * is lower than @count this means that the write has been interrupted or that
 410  * an error was encountered during the write so that the write is partial. 0
 411  * means nothing was written (also return 0 when @count or @bksize are 0).
 412  *
 413  * On error and nothing has been written, return -1 with errno set
 414  * appropriately to the return code of either seek, write, or set
 415  * to EINVAL in case of invalid arguments.
 416  *
 417  * NOTE: We mst protect the data, write it, then mst deprotect it using a quick
 418  * deprotect algorithm (no checking). This saves us from making a copy before
 419  * the write and at the same time causes the usn to be incremented in the
 420  * buffer. This conceptually fits in better with the idea that cached data is
 421  * always deprotected and protection is performed when the data is actually
 422  * going to hit the disk and the cache is immediately deprotected again
 423  * simulating an mst read on the written data. This way cache coherency is
 424  * achieved.
 425  */
 426 s64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
 427                 const u32 bksize, void *b)
 428 {
 429         s64 written, i;
 430 
 431         if (count < 0 || bksize % NTFS_BLOCK_SIZE) {
 432                 errno = EINVAL;
 433                 return -1;
 434         }
 435         if (!count)
 436                 return 0;
 437         /* Prepare data for writing. */
 438         for (i = 0; i < count; ++i) {
 439                 int err;
 440 
 441                 err = ntfs_mst_pre_write_fixup((NTFS_RECORD*)
 442                                 ((u8*)b + i * bksize), bksize);
 443                 if (err < 0) {
 444                         /* Abort write at this position. */
 445                         if (!i)
 446                                 return err;
 447                         count = i;
 448                         break;
 449                 }
 450         }
 451         /* Write the prepared data. */
 452         written = ntfs_pwrite(dev, pos, count * bksize, b);
 453         /* Quickly deprotect the data again. */
 454         for (i = 0; i < count; ++i)
 455                 ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)b + i * bksize));
 456         if (written <= 0)
 457                 return written;
 458         /* Finally, return the number of complete blocks written. */
 459         return written / bksize;
 460 }
 461 
 462 /**
 463  * ntfs_cluster_read - read ntfs clusters
 464  * @vol:        volume to read from
 465  * @lcn:        starting logical cluster number
 466  * @count:      number of clusters to read
 467  * @b:          output data buffer
 468  *
 469  * Read @count ntfs clusters starting at logical cluster number @lcn from
 470  * volume @vol into buffer @b. Return number of clusters read or -1 on error,
 471  * with errno set to the error code.
 472  */
 473 s64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count,
 474                 void *b)
 475 {
 476         s64 br;
 477 
 478         if (!vol || lcn < 0 || count < 0) {
 479                 errno = EINVAL;
 480                 return -1;
 481         }
 482         if (vol->nr_clusters < lcn + count) {
 483                 errno = ESPIPE;
 484                 return -1;
 485         }
 486         br = ntfs_pread(vol->u.dev, lcn << vol->cluster_size_bits,
 487                         count << vol->cluster_size_bits, b);
 488         if (br < 0) {
 489                 ntfs_log_perror("Error reading cluster(s)");
 490                 return br;
 491         }
 492         return br >> vol->cluster_size_bits;
 493 }
 494 
 495 /**
 496  * ntfs_cluster_write - write ntfs clusters
 497  * @vol:        volume to write to
 498  * @lcn:        starting logical cluster number
 499  * @count:      number of clusters to write
 500  * @b:          data buffer to write to disk
 501  *
 502  * Write @count ntfs clusters starting at logical cluster number @lcn from
 503  * buffer @b to volume @vol. Return the number of clusters written or -1 on
 504  * error, with errno set to the error code.
 505  */
 506 s64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn,
 507                 const s64 count, const void *b)
 508 {
 509         s64 bw;
 510 
 511         if (!vol || lcn < 0 || count < 0) {
 512                 errno = EINVAL;
 513                 return -1;
 514         }
 515         if (vol->nr_clusters < lcn + count) {
 516                 errno = ESPIPE;
 517                 return -1;
 518         }
 519         if (!NVolReadOnly(vol))
 520                 bw = ntfs_pwrite(vol->u.dev, lcn << vol->cluster_size_bits,
 521                                 count << vol->cluster_size_bits, b);
 522         else
 523                 bw = count << vol->cluster_size_bits;
 524         if (bw < 0) {
 525                 ntfs_log_perror("Error writing cluster(s)");
 526                 return bw;
 527         }
 528         return bw >> vol->cluster_size_bits;
 529 }
 530 
 531 /**
 532  * ntfs_device_offset_valid - test if a device offset is valid
 533  * @dev:        open device
 534  * @ofs:        offset to test for validity
 535  *
 536  * Test if the offset @ofs is an existing location on the device described
 537  * by the open device structure @dev.
 538  *
 539  * Return 0 if it is valid and -1 if it is not valid.
 540  */
 541 static int ntfs_device_offset_valid(struct ntfs_device *dev, s64 ofs)
 542 {
 543         char ch;
 544 
 545         if (dev->d_ops->seek(dev, ofs, SEEK_SET) >= 0 &&
 546                         dev->d_ops->read(dev, &ch, 1) == 1)
 547                 return 0;
 548         return -1;
 549 }
 550 
 551 /**
 552  * ntfs_device_size_get - return the size of a device in blocks
 553  * @dev:        open device
 554  * @block_size: block size in bytes in which to return the result
 555  *
 556  * Return the number of @block_size sized blocks in the device described by the
 557  * open device @dev.
 558  *
 559  * Adapted from e2fsutils-1.19, Copyright (C) 1995 Theodore Ts'o.
 560  *
 561  * On error return -1 with errno set to the error code.
 562  */
 563 s64 ntfs_device_size_get(struct ntfs_device *dev, int block_size)
 564 {
 565         s64 high, low;
 566 
 567         if (!dev || block_size <= 0 || (block_size - 1) & block_size) {
 568                 errno = EINVAL;
 569                 return -1;
 570         }
 571 #ifdef BLKGETSIZE64
 572         {       u64 size;
 573 
 574                 if (dev->d_ops->ioctl(dev, BLKGETSIZE64, &size) >= 0) {
 575                         ntfs_log_debug("BLKGETSIZE64 nr bytes = %llu (0x%llx)\n",
 576                                         (unsigned long long)size,
 577                                         (unsigned long long)size);
 578                         return (s64)size / block_size;
 579                 }
 580         }
 581 #endif
 582 #ifdef BLKGETSIZE
 583         {       unsigned long size;
 584 
 585                 if (dev->d_ops->ioctl(dev, BLKGETSIZE, &size) >= 0) {
 586                         ntfs_log_debug("BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n",
 587                                         size, size);
 588                         return (s64)size * 512 / block_size;
 589                 }
 590         }
 591 #endif
 592 #ifdef FDGETPRM
 593         {       struct floppy_struct this_floppy;
 594 
 595                 if (dev->d_ops->ioctl(dev, FDGETPRM, &this_floppy) >= 0) {
 596                         ntfs_log_debug("FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n",
 597                                         (unsigned long)this_floppy.size,
 598                                         (unsigned long)this_floppy.size);
 599                         return (s64)this_floppy.size * 512 / block_size;
 600                 }
 601         }
 602 #endif
 603         /*
 604          * We couldn't figure it out by using a specialized ioctl,
 605          * so do binary search to find the size of the device.
 606          */
 607         low = 0LL;
 608         for (high = 1024LL; !ntfs_device_offset_valid(dev, high); high <<= 1)
 609                 low = high;
 610         while (low < high - 1LL) {
 611                 const s64 mid = (low + high) / 2;
 612 
 613                 if (!ntfs_device_offset_valid(dev, mid))
 614                         low = mid;
 615                 else
 616                         high = mid;
 617         }
 618         dev->d_ops->seek(dev, 0LL, SEEK_SET);
 619         return (low + 1LL) / block_size;
 620 }
 621 
 622 /**
 623  * ntfs_device_partition_start_sector_get - get starting sector of a partition
 624  * @dev:        open device
 625  *
 626  * On success, return the starting sector of the partition @dev in the parent
 627  * block device of @dev.  On error return -1 with errno set to the error code.
 628  *
 629  * The following error codes are defined:
 630  *      EINVAL          Input parameter error
 631  *      EOPNOTSUPP      System does not support HDIO_GETGEO ioctl
 632  *      ENOTTY          @dev is a file or a device not supporting HDIO_GETGEO
 633  */
 634 s64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev)
 635 {
 636         if (!dev) {
 637                 errno = EINVAL;
 638                 return -1;
 639         }
 640 #ifdef HDIO_GETGEO
 641         {       struct hd_geometry geo;
 642 
 643                 if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
 644                         ntfs_log_debug("HDIO_GETGEO start_sect = %lu (0x%lx)\n",
 645                                         geo.start, geo.start);
 646                         return geo.start;
 647                 }
 648         }
 649 #else
 650         errno = EOPNOTSUPP;
 651 #endif
 652         return -1;
 653 }
 654 
 655 /**
 656  * ntfs_device_heads_get - get number of heads of device
 657  * @dev:                open device
 658  *
 659  * On success, return the number of heads on the device @dev.  On error return
 660  * -1 with errno set to the error code.
 661  *
 662  * The following error codes are defined:
 663  *      EINVAL          Input parameter error
 664  *      EOPNOTSUPP      System does not support HDIO_GETGEO ioctl
 665  *      ENOTTY          @dev is a file or a device not supporting HDIO_GETGEO
 666  */
 667 int ntfs_device_heads_get(struct ntfs_device *dev)
 668 {
 669         if (!dev) {
 670                 errno = EINVAL;
 671                 return -1;
 672         }
 673 #ifdef HDIO_GETGEO
 674         {       struct hd_geometry geo;
 675 
 676                 if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
 677                         ntfs_log_debug("HDIO_GETGEO heads = %u (0x%x)\n",
 678                                         (unsigned)geo.heads,
 679                                         (unsigned)geo.heads);
 680                         return geo.heads;
 681                 }
 682         }
 683 #else
 684         errno = EOPNOTSUPP;
 685 #endif
 686         return -1;
 687 }
 688 
 689 /**
 690  * ntfs_device_sectors_per_track_get - get number of sectors per track of device
 691  * @dev:                open device
 692  *
 693  * On success, return the number of sectors per track on the device @dev.  On
 694  * error return -1 with errno set to the error code.
 695  *
 696  * The following error codes are defined:
 697  *      EINVAL          Input parameter error
 698  *      EOPNOTSUPP      System does not support HDIO_GETGEO ioctl
 699  *      ENOTTY          @dev is a file or a device not supporting HDIO_GETGEO
 700  */
 701 int ntfs_device_sectors_per_track_get(struct ntfs_device *dev)
 702 {
 703         if (!dev) {
 704                 errno = EINVAL;
 705                 return -1;
 706         }
 707 #ifdef HDIO_GETGEO
 708         {       struct hd_geometry geo;
 709 
 710                 if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) {
 711                         ntfs_log_debug("HDIO_GETGEO sectors_per_track = %u (0x%x)\n",
 712                                         (unsigned)geo.sectors,
 713                                         (unsigned)geo.sectors);
 714                         return geo.sectors;
 715                 }
 716         }
 717 #else
 718         errno = EOPNOTSUPP;
 719 #endif
 720         return -1;
 721 }
 722 
 723 /**
 724  * ntfs_device_sector_size_get - get sector size of a device
 725  * @dev:        open device
 726  *
 727  * On success, return the sector size in bytes of the device @dev.
 728  * On error return -1 with errno set to the error code.
 729  *
 730  * The following error codes are defined:
 731  *      EINVAL          Input parameter error
 732  *      EOPNOTSUPP      System does not support BLKSSZGET ioctl
 733  *      ENOTTY          @dev is a file or a device not supporting BLKSSZGET
 734  */
 735 int ntfs_device_sector_size_get(struct ntfs_device *dev)
 736 {
 737         if (!dev) {
 738                 errno = EINVAL;
 739                 return -1;
 740         }
 741 #ifdef BLKSSZGET
 742         {
 743                 int sect_size = 0;
 744 
 745                 if (!dev->d_ops->ioctl(dev, BLKSSZGET, &sect_size)) {
 746                         ntfs_log_debug("BLKSSZGET sector size = %d bytes\n",
 747                                         sect_size);
 748                         return sect_size;
 749                 }
 750         }
 751 #else
 752         errno = EOPNOTSUPP;
 753 #endif
 754         return -1;
 755 }
 756 
 757 /**
 758  * ntfs_device_block_size_set - set block size of a device
 759  * @dev:        open device
 760  * @block_size: block size to set @dev to
 761  *
 762  * On success, return 0.
 763  * On error return -1 with errno set to the error code.
 764  *
 765  * The following error codes are defined:
 766  *      EINVAL          Input parameter error
 767  *      EOPNOTSUPP      System does not support BLKBSZSET ioctl
 768  *      ENOTTY          @dev is a file or a device not supporting BLKBSZSET
 769  */
 770 int ntfs_device_block_size_set(struct ntfs_device *dev,
 771                 int block_size __attribute__((unused)))
 772 {
 773         if (!dev) {
 774                 errno = EINVAL;
 775                 return -1;
 776         }
 777 #ifdef BLKBSZSET
 778         {
 779                 size_t s_block_size = block_size;
 780                 if (!dev->d_ops->ioctl(dev, BLKBSZSET, &s_block_size)) {
 781                         ntfs_log_debug("Used BLKBSZSET to set block size to "
 782                                         "%d bytes.\n", block_size);
 783                         return 0;
 784                 }
 785                 /* If not a block device, pretend it was successful. */
 786                 if (!NDevBlock(dev))
 787                         return 0;
 788         }
 789 #else
 790         /* If not a block device, pretend it was successful. */
 791         if (!NDevBlock(dev))
 792                 return 0;
 793         errno = EOPNOTSUPP;
 794 #endif
 795         return -1;
 796 }