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, §_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 }