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