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