1987da915Sopenharmony_ci/** 2987da915Sopenharmony_ci * device.c - Low level device io functions. Originated from the Linux-NTFS project. 3987da915Sopenharmony_ci * 4987da915Sopenharmony_ci * Copyright (c) 2004-2013 Anton Altaparmakov 5987da915Sopenharmony_ci * Copyright (c) 2004-2006 Szabolcs Szakacsits 6987da915Sopenharmony_ci * Copyright (c) 2010 Jean-Pierre Andre 7987da915Sopenharmony_ci * Copyright (c) 2008-2013 Tuxera Inc. 8987da915Sopenharmony_ci * 9987da915Sopenharmony_ci * This program/include file is free software; you can redistribute it and/or 10987da915Sopenharmony_ci * modify it under the terms of the GNU General Public License as published 11987da915Sopenharmony_ci * by the Free Software Foundation; either version 2 of the License, or 12987da915Sopenharmony_ci * (at your option) any later version. 13987da915Sopenharmony_ci * 14987da915Sopenharmony_ci * This program/include file is distributed in the hope that it will be 15987da915Sopenharmony_ci * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 16987da915Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17987da915Sopenharmony_ci * GNU General Public License for more details. 18987da915Sopenharmony_ci * 19987da915Sopenharmony_ci * You should have received a copy of the GNU General Public License 20987da915Sopenharmony_ci * along with this program (in the main directory of the NTFS-3G 21987da915Sopenharmony_ci * distribution in the file COPYING); if not, write to the Free Software 22987da915Sopenharmony_ci * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23987da915Sopenharmony_ci */ 24987da915Sopenharmony_ci 25987da915Sopenharmony_ci#ifdef HAVE_CONFIG_H 26987da915Sopenharmony_ci#include "config.h" 27987da915Sopenharmony_ci#endif 28987da915Sopenharmony_ci 29987da915Sopenharmony_ci#ifdef HAVE_UNISTD_H 30987da915Sopenharmony_ci#include <unistd.h> 31987da915Sopenharmony_ci#endif 32987da915Sopenharmony_ci#ifdef HAVE_STDLIB_H 33987da915Sopenharmony_ci#include <stdlib.h> 34987da915Sopenharmony_ci#endif 35987da915Sopenharmony_ci#ifdef HAVE_STRING_H 36987da915Sopenharmony_ci#include <string.h> 37987da915Sopenharmony_ci#endif 38987da915Sopenharmony_ci#ifdef HAVE_ERRNO_H 39987da915Sopenharmony_ci#include <errno.h> 40987da915Sopenharmony_ci#endif 41987da915Sopenharmony_ci#ifdef HAVE_STDIO_H 42987da915Sopenharmony_ci#include <stdio.h> 43987da915Sopenharmony_ci#endif 44987da915Sopenharmony_ci#ifdef HAVE_SYS_TYPES_H 45987da915Sopenharmony_ci#include <sys/types.h> 46987da915Sopenharmony_ci#endif 47987da915Sopenharmony_ci#ifdef HAVE_SYS_STAT_H 48987da915Sopenharmony_ci#include <sys/stat.h> 49987da915Sopenharmony_ci#endif 50987da915Sopenharmony_ci#ifdef HAVE_FCNTL_H 51987da915Sopenharmony_ci#include <fcntl.h> 52987da915Sopenharmony_ci#endif 53987da915Sopenharmony_ci#ifdef HAVE_SYS_IOCTL_H 54987da915Sopenharmony_ci#include <sys/ioctl.h> 55987da915Sopenharmony_ci#endif 56987da915Sopenharmony_ci#ifdef HAVE_SYS_PARAM_H 57987da915Sopenharmony_ci#include <sys/param.h> 58987da915Sopenharmony_ci#endif 59987da915Sopenharmony_ci#ifdef HAVE_SYS_MOUNT_H 60987da915Sopenharmony_ci#include <sys/mount.h> 61987da915Sopenharmony_ci#endif 62987da915Sopenharmony_ci#ifdef HAVE_SYS_DISK_H 63987da915Sopenharmony_ci#include <sys/disk.h> 64987da915Sopenharmony_ci#endif 65987da915Sopenharmony_ci#ifdef HAVE_LINUX_FD_H 66987da915Sopenharmony_ci#include <linux/fd.h> 67987da915Sopenharmony_ci#endif 68987da915Sopenharmony_ci#ifdef HAVE_LINUX_HDREG_H 69987da915Sopenharmony_ci#include <linux/hdreg.h> 70987da915Sopenharmony_ci#endif 71987da915Sopenharmony_ci#ifdef ENABLE_HD 72987da915Sopenharmony_ci#include <hd.h> 73987da915Sopenharmony_ci#endif 74987da915Sopenharmony_ci 75987da915Sopenharmony_ci#include "types.h" 76987da915Sopenharmony_ci#include "mst.h" 77987da915Sopenharmony_ci#include "debug.h" 78987da915Sopenharmony_ci#include "device.h" 79987da915Sopenharmony_ci#include "logging.h" 80987da915Sopenharmony_ci#include "misc.h" 81987da915Sopenharmony_ci 82987da915Sopenharmony_ci#if defined(linux) && defined(_IO) && !defined(BLKGETSIZE) 83987da915Sopenharmony_ci#define BLKGETSIZE _IO(0x12,96) /* Get device size in 512-byte blocks. */ 84987da915Sopenharmony_ci#endif 85987da915Sopenharmony_ci#if defined(linux) && defined(_IOR) && !defined(BLKGETSIZE64) 86987da915Sopenharmony_ci#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* Get device size in bytes. */ 87987da915Sopenharmony_ci#endif 88987da915Sopenharmony_ci#if defined(linux) && !defined(HDIO_GETGEO) 89987da915Sopenharmony_ci#define HDIO_GETGEO 0x0301 /* Get device geometry. */ 90987da915Sopenharmony_ci#endif 91987da915Sopenharmony_ci#if defined(linux) && defined(_IO) && !defined(BLKSSZGET) 92987da915Sopenharmony_ci# define BLKSSZGET _IO(0x12,104) /* Get device sector size in bytes. */ 93987da915Sopenharmony_ci#endif 94987da915Sopenharmony_ci#if defined(linux) && defined(_IO) && !defined(BLKBSZSET) 95987da915Sopenharmony_ci# define BLKBSZSET _IOW(0x12,113,size_t) /* Set device block size in bytes. */ 96987da915Sopenharmony_ci#endif 97987da915Sopenharmony_ci 98987da915Sopenharmony_ci/** 99987da915Sopenharmony_ci * ntfs_device_alloc - allocate an ntfs device structure and pre-initialize it 100987da915Sopenharmony_ci * @name: name of the device (must be present) 101987da915Sopenharmony_ci * @state: initial device state (usually zero) 102987da915Sopenharmony_ci * @dops: ntfs device operations to use with the device (must be present) 103987da915Sopenharmony_ci * @priv_data: pointer to private data (optional) 104987da915Sopenharmony_ci * 105987da915Sopenharmony_ci * Allocate an ntfs device structure and pre-initialize it with the user- 106987da915Sopenharmony_ci * specified device operations @dops, device state @state, device name @name, 107987da915Sopenharmony_ci * and optional private data @priv_data. 108987da915Sopenharmony_ci * 109987da915Sopenharmony_ci * Note, @name is copied and can hence be freed after this functions returns. 110987da915Sopenharmony_ci * 111987da915Sopenharmony_ci * On success return a pointer to the allocated ntfs device structure and on 112987da915Sopenharmony_ci * error return NULL with errno set to the error code returned by ntfs_malloc(). 113987da915Sopenharmony_ci */ 114987da915Sopenharmony_cistruct ntfs_device *ntfs_device_alloc(const char *name, const long state, 115987da915Sopenharmony_ci struct ntfs_device_operations *dops, void *priv_data) 116987da915Sopenharmony_ci{ 117987da915Sopenharmony_ci struct ntfs_device *dev; 118987da915Sopenharmony_ci 119987da915Sopenharmony_ci if (!name) { 120987da915Sopenharmony_ci errno = EINVAL; 121987da915Sopenharmony_ci return NULL; 122987da915Sopenharmony_ci } 123987da915Sopenharmony_ci 124987da915Sopenharmony_ci dev = ntfs_malloc(sizeof(struct ntfs_device)); 125987da915Sopenharmony_ci if (dev) { 126987da915Sopenharmony_ci if (!(dev->d_name = strdup(name))) { 127987da915Sopenharmony_ci int eo = errno; 128987da915Sopenharmony_ci free(dev); 129987da915Sopenharmony_ci errno = eo; 130987da915Sopenharmony_ci return NULL; 131987da915Sopenharmony_ci } 132987da915Sopenharmony_ci dev->d_ops = dops; 133987da915Sopenharmony_ci dev->d_state = state; 134987da915Sopenharmony_ci dev->d_private = priv_data; 135987da915Sopenharmony_ci dev->d_heads = -1; 136987da915Sopenharmony_ci dev->d_sectors_per_track = -1; 137987da915Sopenharmony_ci } 138987da915Sopenharmony_ci return dev; 139987da915Sopenharmony_ci} 140987da915Sopenharmony_ci 141987da915Sopenharmony_ci/** 142987da915Sopenharmony_ci * ntfs_device_free - free an ntfs device structure 143987da915Sopenharmony_ci * @dev: ntfs device structure to free 144987da915Sopenharmony_ci * 145987da915Sopenharmony_ci * Free the ntfs device structure @dev. 146987da915Sopenharmony_ci * 147987da915Sopenharmony_ci * Return 0 on success or -1 on error with errno set to the error code. The 148987da915Sopenharmony_ci * following error codes are defined: 149987da915Sopenharmony_ci * EINVAL Invalid pointer @dev. 150987da915Sopenharmony_ci * EBUSY Device is still open. Close it before freeing it! 151987da915Sopenharmony_ci */ 152987da915Sopenharmony_ciint ntfs_device_free(struct ntfs_device *dev) 153987da915Sopenharmony_ci{ 154987da915Sopenharmony_ci if (!dev) { 155987da915Sopenharmony_ci errno = EINVAL; 156987da915Sopenharmony_ci return -1; 157987da915Sopenharmony_ci } 158987da915Sopenharmony_ci if (NDevOpen(dev)) { 159987da915Sopenharmony_ci errno = EBUSY; 160987da915Sopenharmony_ci return -1; 161987da915Sopenharmony_ci } 162987da915Sopenharmony_ci free(dev->d_name); 163987da915Sopenharmony_ci free(dev); 164987da915Sopenharmony_ci return 0; 165987da915Sopenharmony_ci} 166987da915Sopenharmony_ci 167987da915Sopenharmony_ci/* 168987da915Sopenharmony_ci * Sync the device 169987da915Sopenharmony_ci * 170987da915Sopenharmony_ci * returns zero if successful. 171987da915Sopenharmony_ci */ 172987da915Sopenharmony_ci 173987da915Sopenharmony_ciint ntfs_device_sync(struct ntfs_device *dev) 174987da915Sopenharmony_ci{ 175987da915Sopenharmony_ci int ret; 176987da915Sopenharmony_ci struct ntfs_device_operations *dops; 177987da915Sopenharmony_ci 178987da915Sopenharmony_ci if (NDevDirty(dev)) { 179987da915Sopenharmony_ci dops = dev->d_ops; 180987da915Sopenharmony_ci ret = dops->sync(dev); 181987da915Sopenharmony_ci } else 182987da915Sopenharmony_ci ret = 0; 183987da915Sopenharmony_ci return ret; 184987da915Sopenharmony_ci} 185987da915Sopenharmony_ci 186987da915Sopenharmony_ci/** 187987da915Sopenharmony_ci * ntfs_pread - positioned read from disk 188987da915Sopenharmony_ci * @dev: device to read from 189987da915Sopenharmony_ci * @pos: position in device to read from 190987da915Sopenharmony_ci * @count: number of bytes to read 191987da915Sopenharmony_ci * @b: output data buffer 192987da915Sopenharmony_ci * 193987da915Sopenharmony_ci * This function will read @count bytes from device @dev at position @pos into 194987da915Sopenharmony_ci * the data buffer @b. 195987da915Sopenharmony_ci * 196987da915Sopenharmony_ci * On success, return the number of successfully read bytes. If this number is 197987da915Sopenharmony_ci * lower than @count this means that we have either reached end of file or 198987da915Sopenharmony_ci * encountered an error during the read so that the read is partial. 0 means 199987da915Sopenharmony_ci * end of file or nothing to read (@count is 0). 200987da915Sopenharmony_ci * 201987da915Sopenharmony_ci * On error and nothing has been read, return -1 with errno set appropriately 202987da915Sopenharmony_ci * to the return code of either seek, read, or set to EINVAL in case of 203987da915Sopenharmony_ci * invalid arguments. 204987da915Sopenharmony_ci */ 205987da915Sopenharmony_cis64 ntfs_pread(struct ntfs_device *dev, const s64 pos, s64 count, void *b) 206987da915Sopenharmony_ci{ 207987da915Sopenharmony_ci s64 br, total; 208987da915Sopenharmony_ci struct ntfs_device_operations *dops; 209987da915Sopenharmony_ci 210987da915Sopenharmony_ci ntfs_log_trace("pos %lld, count %lld\n",(long long)pos,(long long)count); 211987da915Sopenharmony_ci 212987da915Sopenharmony_ci if (!b || count < 0 || pos < 0) { 213987da915Sopenharmony_ci errno = EINVAL; 214987da915Sopenharmony_ci return -1; 215987da915Sopenharmony_ci } 216987da915Sopenharmony_ci if (!count) 217987da915Sopenharmony_ci return 0; 218987da915Sopenharmony_ci 219987da915Sopenharmony_ci dops = dev->d_ops; 220987da915Sopenharmony_ci 221987da915Sopenharmony_ci for (total = 0; count; count -= br, total += br) { 222987da915Sopenharmony_ci br = dops->pread(dev, (char*)b + total, count, pos + total); 223987da915Sopenharmony_ci /* If everything ok, continue. */ 224987da915Sopenharmony_ci if (br > 0) 225987da915Sopenharmony_ci continue; 226987da915Sopenharmony_ci /* If EOF or error return number of bytes read. */ 227987da915Sopenharmony_ci if (!br || total) 228987da915Sopenharmony_ci return total; 229987da915Sopenharmony_ci /* Nothing read and error, return error status. */ 230987da915Sopenharmony_ci return br; 231987da915Sopenharmony_ci } 232987da915Sopenharmony_ci /* Finally, return the number of bytes read. */ 233987da915Sopenharmony_ci return total; 234987da915Sopenharmony_ci} 235987da915Sopenharmony_ci 236987da915Sopenharmony_ci/** 237987da915Sopenharmony_ci * ntfs_pwrite - positioned write to disk 238987da915Sopenharmony_ci * @dev: device to write to 239987da915Sopenharmony_ci * @pos: position in file descriptor to write to 240987da915Sopenharmony_ci * @count: number of bytes to write 241987da915Sopenharmony_ci * @b: data buffer to write to disk 242987da915Sopenharmony_ci * 243987da915Sopenharmony_ci * This function will write @count bytes from data buffer @b to the device @dev 244987da915Sopenharmony_ci * at position @pos. 245987da915Sopenharmony_ci * 246987da915Sopenharmony_ci * On success, return the number of successfully written bytes. If this number 247987da915Sopenharmony_ci * is lower than @count this means that the write has been interrupted in 248987da915Sopenharmony_ci * flight or that an error was encountered during the write so that the write 249987da915Sopenharmony_ci * is partial. 0 means nothing was written (also return 0 when @count is 0). 250987da915Sopenharmony_ci * 251987da915Sopenharmony_ci * On error and nothing has been written, return -1 with errno set 252987da915Sopenharmony_ci * appropriately to the return code of either seek, write, or set 253987da915Sopenharmony_ci * to EINVAL in case of invalid arguments. 254987da915Sopenharmony_ci */ 255987da915Sopenharmony_cis64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, 256987da915Sopenharmony_ci const void *b) 257987da915Sopenharmony_ci{ 258987da915Sopenharmony_ci s64 written, total, ret = -1; 259987da915Sopenharmony_ci struct ntfs_device_operations *dops; 260987da915Sopenharmony_ci 261987da915Sopenharmony_ci ntfs_log_trace("pos %lld, count %lld\n",(long long)pos,(long long)count); 262987da915Sopenharmony_ci 263987da915Sopenharmony_ci if (!b || count < 0 || pos < 0) { 264987da915Sopenharmony_ci errno = EINVAL; 265987da915Sopenharmony_ci goto out; 266987da915Sopenharmony_ci } 267987da915Sopenharmony_ci if (!count) 268987da915Sopenharmony_ci return 0; 269987da915Sopenharmony_ci if (NDevReadOnly(dev)) { 270987da915Sopenharmony_ci errno = EROFS; 271987da915Sopenharmony_ci goto out; 272987da915Sopenharmony_ci } 273987da915Sopenharmony_ci 274987da915Sopenharmony_ci dops = dev->d_ops; 275987da915Sopenharmony_ci 276987da915Sopenharmony_ci NDevSetDirty(dev); 277987da915Sopenharmony_ci for (total = 0; count; count -= written, total += written) { 278987da915Sopenharmony_ci written = dops->pwrite(dev, (const char*)b + total, count, 279987da915Sopenharmony_ci pos + total); 280987da915Sopenharmony_ci /* If everything ok, continue. */ 281987da915Sopenharmony_ci if (written > 0) 282987da915Sopenharmony_ci continue; 283987da915Sopenharmony_ci /* 284987da915Sopenharmony_ci * If nothing written or error return number of bytes written. 285987da915Sopenharmony_ci */ 286987da915Sopenharmony_ci if (!written || total) 287987da915Sopenharmony_ci break; 288987da915Sopenharmony_ci /* Nothing written and error, return error status. */ 289987da915Sopenharmony_ci total = written; 290987da915Sopenharmony_ci break; 291987da915Sopenharmony_ci } 292987da915Sopenharmony_ci if (NDevSync(dev) && total && dops->sync(dev)) { 293987da915Sopenharmony_ci total--; /* on sync error, return partially written */ 294987da915Sopenharmony_ci } 295987da915Sopenharmony_ci ret = total; 296987da915Sopenharmony_ciout: 297987da915Sopenharmony_ci return ret; 298987da915Sopenharmony_ci} 299987da915Sopenharmony_ci 300987da915Sopenharmony_ci/** 301987da915Sopenharmony_ci * ntfs_mst_pread - multi sector transfer (mst) positioned read 302987da915Sopenharmony_ci * @dev: device to read from 303987da915Sopenharmony_ci * @pos: position in file descriptor to read from 304987da915Sopenharmony_ci * @count: number of blocks to read 305987da915Sopenharmony_ci * @bksize: size of each block that needs mst deprotecting 306987da915Sopenharmony_ci * @b: output data buffer 307987da915Sopenharmony_ci * 308987da915Sopenharmony_ci * Multi sector transfer (mst) positioned read. This function will read @count 309987da915Sopenharmony_ci * blocks of size @bksize bytes each from device @dev at position @pos into the 310987da915Sopenharmony_ci * the data buffer @b. 311987da915Sopenharmony_ci * 312987da915Sopenharmony_ci * On success, return the number of successfully read blocks. If this number is 313987da915Sopenharmony_ci * lower than @count this means that we have reached end of file, that the read 314987da915Sopenharmony_ci * was interrupted, or that an error was encountered during the read so that 315987da915Sopenharmony_ci * the read is partial. 0 means end of file or nothing was read (also return 0 316987da915Sopenharmony_ci * when @count or @bksize are 0). 317987da915Sopenharmony_ci * 318987da915Sopenharmony_ci * On error and nothing was read, return -1 with errno set appropriately to the 319987da915Sopenharmony_ci * return code of either seek, read, or set to EINVAL in case of invalid 320987da915Sopenharmony_ci * arguments. 321987da915Sopenharmony_ci * 322987da915Sopenharmony_ci * NOTE: If an incomplete multi sector transfer has been detected the magic 323987da915Sopenharmony_ci * will have been changed to magic_BAAD but no error will be returned. Thus it 324987da915Sopenharmony_ci * is possible that we return count blocks as being read but that any number 325987da915Sopenharmony_ci * (between zero and count!) of these blocks is actually subject to a multi 326987da915Sopenharmony_ci * sector transfer error. This should be detected by the caller by checking for 327987da915Sopenharmony_ci * the magic being "BAAD". 328987da915Sopenharmony_ci */ 329987da915Sopenharmony_cis64 ntfs_mst_pread(struct ntfs_device *dev, const s64 pos, s64 count, 330987da915Sopenharmony_ci const u32 bksize, void *b) 331987da915Sopenharmony_ci{ 332987da915Sopenharmony_ci s64 br, i; 333987da915Sopenharmony_ci 334987da915Sopenharmony_ci if (bksize & (bksize - 1) || bksize % NTFS_BLOCK_SIZE) { 335987da915Sopenharmony_ci errno = EINVAL; 336987da915Sopenharmony_ci return -1; 337987da915Sopenharmony_ci } 338987da915Sopenharmony_ci /* Do the read. */ 339987da915Sopenharmony_ci br = ntfs_pread(dev, pos, count * bksize, b); 340987da915Sopenharmony_ci if (br < 0) 341987da915Sopenharmony_ci return br; 342987da915Sopenharmony_ci /* 343987da915Sopenharmony_ci * Apply fixups to successfully read data, disregarding any errors 344987da915Sopenharmony_ci * returned from the MST fixup function. This is because we want to 345987da915Sopenharmony_ci * fixup everything possible and we rely on the fact that the "BAAD" 346987da915Sopenharmony_ci * magic will be detected later on. 347987da915Sopenharmony_ci */ 348987da915Sopenharmony_ci count = br / bksize; 349987da915Sopenharmony_ci for (i = 0; i < count; ++i) 350987da915Sopenharmony_ci ntfs_mst_post_read_fixup((NTFS_RECORD*) 351987da915Sopenharmony_ci ((u8*)b + i * bksize), bksize); 352987da915Sopenharmony_ci /* Finally, return the number of complete blocks read. */ 353987da915Sopenharmony_ci return count; 354987da915Sopenharmony_ci} 355987da915Sopenharmony_ci 356987da915Sopenharmony_ci/** 357987da915Sopenharmony_ci * ntfs_mst_pwrite - multi sector transfer (mst) positioned write 358987da915Sopenharmony_ci * @dev: device to write to 359987da915Sopenharmony_ci * @pos: position in file descriptor to write to 360987da915Sopenharmony_ci * @count: number of blocks to write 361987da915Sopenharmony_ci * @bksize: size of each block that needs mst protecting 362987da915Sopenharmony_ci * @b: data buffer to write to disk 363987da915Sopenharmony_ci * 364987da915Sopenharmony_ci * Multi sector transfer (mst) positioned write. This function will write 365987da915Sopenharmony_ci * @count blocks of size @bksize bytes each from data buffer @b to the device 366987da915Sopenharmony_ci * @dev at position @pos. 367987da915Sopenharmony_ci * 368987da915Sopenharmony_ci * On success, return the number of successfully written blocks. If this number 369987da915Sopenharmony_ci * is lower than @count this means that the write has been interrupted or that 370987da915Sopenharmony_ci * an error was encountered during the write so that the write is partial. 0 371987da915Sopenharmony_ci * means nothing was written (also return 0 when @count or @bksize are 0). 372987da915Sopenharmony_ci * 373987da915Sopenharmony_ci * On error and nothing has been written, return -1 with errno set 374987da915Sopenharmony_ci * appropriately to the return code of either seek, write, or set 375987da915Sopenharmony_ci * to EINVAL in case of invalid arguments. 376987da915Sopenharmony_ci * 377987da915Sopenharmony_ci * NOTE: We mst protect the data, write it, then mst deprotect it using a quick 378987da915Sopenharmony_ci * deprotect algorithm (no checking). This saves us from making a copy before 379987da915Sopenharmony_ci * the write and at the same time causes the usn to be incremented in the 380987da915Sopenharmony_ci * buffer. This conceptually fits in better with the idea that cached data is 381987da915Sopenharmony_ci * always deprotected and protection is performed when the data is actually 382987da915Sopenharmony_ci * going to hit the disk and the cache is immediately deprotected again 383987da915Sopenharmony_ci * simulating an mst read on the written data. This way cache coherency is 384987da915Sopenharmony_ci * achieved. 385987da915Sopenharmony_ci */ 386987da915Sopenharmony_cis64 ntfs_mst_pwrite(struct ntfs_device *dev, const s64 pos, s64 count, 387987da915Sopenharmony_ci const u32 bksize, void *b) 388987da915Sopenharmony_ci{ 389987da915Sopenharmony_ci s64 written, i; 390987da915Sopenharmony_ci 391987da915Sopenharmony_ci if (count < 0 || bksize % NTFS_BLOCK_SIZE) { 392987da915Sopenharmony_ci errno = EINVAL; 393987da915Sopenharmony_ci return -1; 394987da915Sopenharmony_ci } 395987da915Sopenharmony_ci if (!count) 396987da915Sopenharmony_ci return 0; 397987da915Sopenharmony_ci /* Prepare data for writing. */ 398987da915Sopenharmony_ci for (i = 0; i < count; ++i) { 399987da915Sopenharmony_ci int err; 400987da915Sopenharmony_ci 401987da915Sopenharmony_ci err = ntfs_mst_pre_write_fixup((NTFS_RECORD*) 402987da915Sopenharmony_ci ((u8*)b + i * bksize), bksize); 403987da915Sopenharmony_ci if (err < 0) { 404987da915Sopenharmony_ci /* Abort write at this position. */ 405987da915Sopenharmony_ci if (!i) 406987da915Sopenharmony_ci return err; 407987da915Sopenharmony_ci count = i; 408987da915Sopenharmony_ci break; 409987da915Sopenharmony_ci } 410987da915Sopenharmony_ci } 411987da915Sopenharmony_ci /* Write the prepared data. */ 412987da915Sopenharmony_ci written = ntfs_pwrite(dev, pos, count * bksize, b); 413987da915Sopenharmony_ci /* Quickly deprotect the data again. */ 414987da915Sopenharmony_ci for (i = 0; i < count; ++i) 415987da915Sopenharmony_ci ntfs_mst_post_write_fixup((NTFS_RECORD*)((u8*)b + i * bksize)); 416987da915Sopenharmony_ci if (written <= 0) 417987da915Sopenharmony_ci return written; 418987da915Sopenharmony_ci /* Finally, return the number of complete blocks written. */ 419987da915Sopenharmony_ci return written / bksize; 420987da915Sopenharmony_ci} 421987da915Sopenharmony_ci 422987da915Sopenharmony_ci/** 423987da915Sopenharmony_ci * ntfs_cluster_read - read ntfs clusters 424987da915Sopenharmony_ci * @vol: volume to read from 425987da915Sopenharmony_ci * @lcn: starting logical cluster number 426987da915Sopenharmony_ci * @count: number of clusters to read 427987da915Sopenharmony_ci * @b: output data buffer 428987da915Sopenharmony_ci * 429987da915Sopenharmony_ci * Read @count ntfs clusters starting at logical cluster number @lcn from 430987da915Sopenharmony_ci * volume @vol into buffer @b. Return number of clusters read or -1 on error, 431987da915Sopenharmony_ci * with errno set to the error code. 432987da915Sopenharmony_ci */ 433987da915Sopenharmony_cis64 ntfs_cluster_read(const ntfs_volume *vol, const s64 lcn, const s64 count, 434987da915Sopenharmony_ci void *b) 435987da915Sopenharmony_ci{ 436987da915Sopenharmony_ci s64 br; 437987da915Sopenharmony_ci 438987da915Sopenharmony_ci if (!vol || lcn < 0 || count < 0) { 439987da915Sopenharmony_ci errno = EINVAL; 440987da915Sopenharmony_ci return -1; 441987da915Sopenharmony_ci } 442987da915Sopenharmony_ci if (vol->nr_clusters < lcn + count) { 443987da915Sopenharmony_ci errno = ESPIPE; 444987da915Sopenharmony_ci ntfs_log_perror("Trying to read outside of volume " 445987da915Sopenharmony_ci "(%lld < %lld)", (long long)vol->nr_clusters, 446987da915Sopenharmony_ci (long long)lcn + count); 447987da915Sopenharmony_ci return -1; 448987da915Sopenharmony_ci } 449987da915Sopenharmony_ci br = ntfs_pread(vol->dev, lcn << vol->cluster_size_bits, 450987da915Sopenharmony_ci count << vol->cluster_size_bits, b); 451987da915Sopenharmony_ci if (br < 0) { 452987da915Sopenharmony_ci ntfs_log_perror("Error reading cluster(s)"); 453987da915Sopenharmony_ci return br; 454987da915Sopenharmony_ci } 455987da915Sopenharmony_ci return br >> vol->cluster_size_bits; 456987da915Sopenharmony_ci} 457987da915Sopenharmony_ci 458987da915Sopenharmony_ci/** 459987da915Sopenharmony_ci * ntfs_cluster_write - write ntfs clusters 460987da915Sopenharmony_ci * @vol: volume to write to 461987da915Sopenharmony_ci * @lcn: starting logical cluster number 462987da915Sopenharmony_ci * @count: number of clusters to write 463987da915Sopenharmony_ci * @b: data buffer to write to disk 464987da915Sopenharmony_ci * 465987da915Sopenharmony_ci * Write @count ntfs clusters starting at logical cluster number @lcn from 466987da915Sopenharmony_ci * buffer @b to volume @vol. Return the number of clusters written or -1 on 467987da915Sopenharmony_ci * error, with errno set to the error code. 468987da915Sopenharmony_ci */ 469987da915Sopenharmony_cis64 ntfs_cluster_write(const ntfs_volume *vol, const s64 lcn, 470987da915Sopenharmony_ci const s64 count, const void *b) 471987da915Sopenharmony_ci{ 472987da915Sopenharmony_ci s64 bw; 473987da915Sopenharmony_ci 474987da915Sopenharmony_ci if (!vol || lcn < 0 || count < 0) { 475987da915Sopenharmony_ci errno = EINVAL; 476987da915Sopenharmony_ci return -1; 477987da915Sopenharmony_ci } 478987da915Sopenharmony_ci if (vol->nr_clusters < lcn + count) { 479987da915Sopenharmony_ci errno = ESPIPE; 480987da915Sopenharmony_ci ntfs_log_perror("Trying to write outside of volume " 481987da915Sopenharmony_ci "(%lld < %lld)", (long long)vol->nr_clusters, 482987da915Sopenharmony_ci (long long)lcn + count); 483987da915Sopenharmony_ci return -1; 484987da915Sopenharmony_ci } 485987da915Sopenharmony_ci if (!NVolReadOnly(vol)) 486987da915Sopenharmony_ci bw = ntfs_pwrite(vol->dev, lcn << vol->cluster_size_bits, 487987da915Sopenharmony_ci count << vol->cluster_size_bits, b); 488987da915Sopenharmony_ci else 489987da915Sopenharmony_ci bw = count << vol->cluster_size_bits; 490987da915Sopenharmony_ci if (bw < 0) { 491987da915Sopenharmony_ci ntfs_log_perror("Error writing cluster(s)"); 492987da915Sopenharmony_ci return bw; 493987da915Sopenharmony_ci } 494987da915Sopenharmony_ci return bw >> vol->cluster_size_bits; 495987da915Sopenharmony_ci} 496987da915Sopenharmony_ci 497987da915Sopenharmony_ci/** 498987da915Sopenharmony_ci * ntfs_device_offset_valid - test if a device offset is valid 499987da915Sopenharmony_ci * @dev: open device 500987da915Sopenharmony_ci * @ofs: offset to test for validity 501987da915Sopenharmony_ci * 502987da915Sopenharmony_ci * Test if the offset @ofs is an existing location on the device described 503987da915Sopenharmony_ci * by the open device structure @dev. 504987da915Sopenharmony_ci * 505987da915Sopenharmony_ci * Return 0 if it is valid and -1 if it is not valid. 506987da915Sopenharmony_ci */ 507987da915Sopenharmony_cistatic int ntfs_device_offset_valid(struct ntfs_device *dev, s64 ofs) 508987da915Sopenharmony_ci{ 509987da915Sopenharmony_ci char ch; 510987da915Sopenharmony_ci 511987da915Sopenharmony_ci if (dev->d_ops->seek(dev, ofs, SEEK_SET) >= 0 && 512987da915Sopenharmony_ci dev->d_ops->read(dev, &ch, 1) == 1) 513987da915Sopenharmony_ci return 0; 514987da915Sopenharmony_ci return -1; 515987da915Sopenharmony_ci} 516987da915Sopenharmony_ci 517987da915Sopenharmony_ci/** 518987da915Sopenharmony_ci * ntfs_device_size_get - return the size of a device in blocks 519987da915Sopenharmony_ci * @dev: open device 520987da915Sopenharmony_ci * @block_size: block size in bytes in which to return the result 521987da915Sopenharmony_ci * 522987da915Sopenharmony_ci * Return the number of @block_size sized blocks in the device described by the 523987da915Sopenharmony_ci * open device @dev. 524987da915Sopenharmony_ci * 525987da915Sopenharmony_ci * Adapted from e2fsutils-1.19, Copyright (C) 1995 Theodore Ts'o. 526987da915Sopenharmony_ci * 527987da915Sopenharmony_ci * On error return -1 with errno set to the error code. 528987da915Sopenharmony_ci */ 529987da915Sopenharmony_cis64 ntfs_device_size_get(struct ntfs_device *dev, int block_size) 530987da915Sopenharmony_ci{ 531987da915Sopenharmony_ci s64 high, low; 532987da915Sopenharmony_ci 533987da915Sopenharmony_ci if (!dev || block_size <= 0 || (block_size - 1) & block_size) { 534987da915Sopenharmony_ci errno = EINVAL; 535987da915Sopenharmony_ci return -1; 536987da915Sopenharmony_ci } 537987da915Sopenharmony_ci#ifdef BLKGETSIZE64 538987da915Sopenharmony_ci { u64 size; 539987da915Sopenharmony_ci 540987da915Sopenharmony_ci if (dev->d_ops->ioctl(dev, BLKGETSIZE64, &size) >= 0) { 541987da915Sopenharmony_ci ntfs_log_debug("BLKGETSIZE64 nr bytes = %llu (0x%llx)\n", 542987da915Sopenharmony_ci (unsigned long long)size, 543987da915Sopenharmony_ci (unsigned long long)size); 544987da915Sopenharmony_ci return (s64)size / block_size; 545987da915Sopenharmony_ci } 546987da915Sopenharmony_ci } 547987da915Sopenharmony_ci#endif 548987da915Sopenharmony_ci#ifdef BLKGETSIZE 549987da915Sopenharmony_ci { unsigned long size; 550987da915Sopenharmony_ci 551987da915Sopenharmony_ci if (dev->d_ops->ioctl(dev, BLKGETSIZE, &size) >= 0) { 552987da915Sopenharmony_ci ntfs_log_debug("BLKGETSIZE nr 512 byte blocks = %lu (0x%lx)\n", 553987da915Sopenharmony_ci size, size); 554987da915Sopenharmony_ci return (s64)size * 512 / block_size; 555987da915Sopenharmony_ci } 556987da915Sopenharmony_ci } 557987da915Sopenharmony_ci#endif 558987da915Sopenharmony_ci#ifdef FDGETPRM 559987da915Sopenharmony_ci { struct floppy_struct this_floppy; 560987da915Sopenharmony_ci 561987da915Sopenharmony_ci if (dev->d_ops->ioctl(dev, FDGETPRM, &this_floppy) >= 0) { 562987da915Sopenharmony_ci ntfs_log_debug("FDGETPRM nr 512 byte blocks = %lu (0x%lx)\n", 563987da915Sopenharmony_ci (unsigned long)this_floppy.size, 564987da915Sopenharmony_ci (unsigned long)this_floppy.size); 565987da915Sopenharmony_ci return (s64)this_floppy.size * 512 / block_size; 566987da915Sopenharmony_ci } 567987da915Sopenharmony_ci } 568987da915Sopenharmony_ci#endif 569987da915Sopenharmony_ci#ifdef DIOCGMEDIASIZE 570987da915Sopenharmony_ci { 571987da915Sopenharmony_ci /* FreeBSD */ 572987da915Sopenharmony_ci off_t size; 573987da915Sopenharmony_ci 574987da915Sopenharmony_ci if (dev->d_ops->ioctl(dev, DIOCGMEDIASIZE, &size) >= 0) { 575987da915Sopenharmony_ci ntfs_log_debug("DIOCGMEDIASIZE nr bytes = %llu (0x%llx)\n", 576987da915Sopenharmony_ci (unsigned long long)size, 577987da915Sopenharmony_ci (unsigned long long)size); 578987da915Sopenharmony_ci return (s64)size / block_size; 579987da915Sopenharmony_ci } 580987da915Sopenharmony_ci } 581987da915Sopenharmony_ci#endif 582987da915Sopenharmony_ci#ifdef DKIOCGETBLOCKCOUNT 583987da915Sopenharmony_ci { 584987da915Sopenharmony_ci /* Mac OS X */ 585987da915Sopenharmony_ci uint64_t blocks; 586987da915Sopenharmony_ci int sector_size; 587987da915Sopenharmony_ci 588987da915Sopenharmony_ci sector_size = ntfs_device_sector_size_get(dev); 589987da915Sopenharmony_ci if (sector_size >= 0 && dev->d_ops->ioctl(dev, 590987da915Sopenharmony_ci DKIOCGETBLOCKCOUNT, &blocks) >= 0) 591987da915Sopenharmony_ci { 592987da915Sopenharmony_ci ntfs_log_debug("DKIOCGETBLOCKCOUNT nr blocks = %llu (0x%llx)\n", 593987da915Sopenharmony_ci (unsigned long long) blocks, 594987da915Sopenharmony_ci (unsigned long long) blocks); 595987da915Sopenharmony_ci return blocks * sector_size / block_size; 596987da915Sopenharmony_ci } 597987da915Sopenharmony_ci } 598987da915Sopenharmony_ci#endif 599987da915Sopenharmony_ci /* 600987da915Sopenharmony_ci * We couldn't figure it out by using a specialized ioctl, 601987da915Sopenharmony_ci * so do binary search to find the size of the device. 602987da915Sopenharmony_ci */ 603987da915Sopenharmony_ci low = 0LL; 604987da915Sopenharmony_ci for (high = 1024LL; !ntfs_device_offset_valid(dev, high); high <<= 1) 605987da915Sopenharmony_ci low = high; 606987da915Sopenharmony_ci while (low < high - 1LL) { 607987da915Sopenharmony_ci const s64 mid = (low + high) / 2; 608987da915Sopenharmony_ci 609987da915Sopenharmony_ci if (!ntfs_device_offset_valid(dev, mid)) 610987da915Sopenharmony_ci low = mid; 611987da915Sopenharmony_ci else 612987da915Sopenharmony_ci high = mid; 613987da915Sopenharmony_ci } 614987da915Sopenharmony_ci dev->d_ops->seek(dev, 0LL, SEEK_SET); 615987da915Sopenharmony_ci return (low + 1LL) / block_size; 616987da915Sopenharmony_ci} 617987da915Sopenharmony_ci 618987da915Sopenharmony_ci/** 619987da915Sopenharmony_ci * ntfs_device_partition_start_sector_get - get starting sector of a partition 620987da915Sopenharmony_ci * @dev: open device 621987da915Sopenharmony_ci * 622987da915Sopenharmony_ci * On success, return the starting sector of the partition @dev in the parent 623987da915Sopenharmony_ci * block device of @dev. On error return -1 with errno set to the error code. 624987da915Sopenharmony_ci * 625987da915Sopenharmony_ci * The following error codes are defined: 626987da915Sopenharmony_ci * EINVAL Input parameter error 627987da915Sopenharmony_ci * EOPNOTSUPP System does not support HDIO_GETGEO ioctl 628987da915Sopenharmony_ci * ENOTTY @dev is a file or a device not supporting HDIO_GETGEO 629987da915Sopenharmony_ci */ 630987da915Sopenharmony_cis64 ntfs_device_partition_start_sector_get(struct ntfs_device *dev) 631987da915Sopenharmony_ci{ 632987da915Sopenharmony_ci if (!dev) { 633987da915Sopenharmony_ci errno = EINVAL; 634987da915Sopenharmony_ci return -1; 635987da915Sopenharmony_ci } 636987da915Sopenharmony_ci#ifdef HDIO_GETGEO 637987da915Sopenharmony_ci { struct hd_geometry geo; 638987da915Sopenharmony_ci 639987da915Sopenharmony_ci if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) { 640987da915Sopenharmony_ci ntfs_log_debug("HDIO_GETGEO start_sect = %lu (0x%lx)\n", 641987da915Sopenharmony_ci geo.start, geo.start); 642987da915Sopenharmony_ci return geo.start; 643987da915Sopenharmony_ci } 644987da915Sopenharmony_ci } 645987da915Sopenharmony_ci#else 646987da915Sopenharmony_ci errno = EOPNOTSUPP; 647987da915Sopenharmony_ci#endif 648987da915Sopenharmony_ci return -1; 649987da915Sopenharmony_ci} 650987da915Sopenharmony_ci 651987da915Sopenharmony_cistatic int ntfs_device_get_geo(struct ntfs_device *dev) 652987da915Sopenharmony_ci{ 653987da915Sopenharmony_ci int err; 654987da915Sopenharmony_ci 655987da915Sopenharmony_ci if (!dev) { 656987da915Sopenharmony_ci errno = EINVAL; 657987da915Sopenharmony_ci return -1; 658987da915Sopenharmony_ci } 659987da915Sopenharmony_ci err = EOPNOTSUPP; 660987da915Sopenharmony_ci#ifdef ENABLE_HD 661987da915Sopenharmony_ci { 662987da915Sopenharmony_ci hd_data_t *hddata; 663987da915Sopenharmony_ci hd_t *hd, *devlist, *partlist = NULL; 664987da915Sopenharmony_ci str_list_t *names; 665987da915Sopenharmony_ci hd_res_t *res; 666987da915Sopenharmony_ci const int d_name_len = strlen(dev->d_name) + 1; 667987da915Sopenharmony_ci int done = 0; 668987da915Sopenharmony_ci 669987da915Sopenharmony_ci hddata = calloc(1, sizeof(*hddata)); 670987da915Sopenharmony_ci if (!hddata) { 671987da915Sopenharmony_ci err = ENOMEM; 672987da915Sopenharmony_ci goto skip_hd; 673987da915Sopenharmony_ci } 674987da915Sopenharmony_ci /* List all "disk" class devices on the system. */ 675987da915Sopenharmony_ci devlist = hd_list(hddata, hw_disk, 1, NULL); 676987da915Sopenharmony_ci if (!devlist) { 677987da915Sopenharmony_ci free(hddata); 678987da915Sopenharmony_ci err = ENOMEM; 679987da915Sopenharmony_ci goto skip_hd; 680987da915Sopenharmony_ci } 681987da915Sopenharmony_ci /* 682987da915Sopenharmony_ci * Loop over each disk device looking for the device with the 683987da915Sopenharmony_ci * same unix name as @dev. 684987da915Sopenharmony_ci */ 685987da915Sopenharmony_ci for (hd = devlist; hd; hd = hd->next) { 686987da915Sopenharmony_ci if (hd->unix_dev_name && !strncmp(dev->d_name, 687987da915Sopenharmony_ci hd->unix_dev_name, d_name_len)) 688987da915Sopenharmony_ci goto got_hd; 689987da915Sopenharmony_ci if (hd->unix_dev_name2 && !strncmp(dev->d_name, 690987da915Sopenharmony_ci hd->unix_dev_name2, d_name_len)) 691987da915Sopenharmony_ci goto got_hd; 692987da915Sopenharmony_ci for (names = hd->unix_dev_names; names; 693987da915Sopenharmony_ci names = names->next) { 694987da915Sopenharmony_ci if (names->str && !strncmp(dev->d_name, 695987da915Sopenharmony_ci names->str, d_name_len)) 696987da915Sopenharmony_ci goto got_hd; 697987da915Sopenharmony_ci } 698987da915Sopenharmony_ci } 699987da915Sopenharmony_ci /* 700987da915Sopenharmony_ci * Device was not a whole disk device. Unless it is a file it 701987da915Sopenharmony_ci * is likely to be a partition device. List all "partition" 702987da915Sopenharmony_ci * class devices on the system. 703987da915Sopenharmony_ci */ 704987da915Sopenharmony_ci partlist = hd_list(hddata, hw_partition, 1, NULL); 705987da915Sopenharmony_ci for (hd = partlist; hd; hd = hd->next) { 706987da915Sopenharmony_ci if (hd->unix_dev_name && !strncmp(dev->d_name, 707987da915Sopenharmony_ci hd->unix_dev_name, d_name_len)) 708987da915Sopenharmony_ci goto got_part_hd; 709987da915Sopenharmony_ci if (hd->unix_dev_name2 && !strncmp(dev->d_name, 710987da915Sopenharmony_ci hd->unix_dev_name2, d_name_len)) 711987da915Sopenharmony_ci goto got_part_hd; 712987da915Sopenharmony_ci for (names = hd->unix_dev_names; names; 713987da915Sopenharmony_ci names = names->next) { 714987da915Sopenharmony_ci if (names->str && !strncmp(dev->d_name, 715987da915Sopenharmony_ci names->str, d_name_len)) 716987da915Sopenharmony_ci goto got_part_hd; 717987da915Sopenharmony_ci } 718987da915Sopenharmony_ci } 719987da915Sopenharmony_ci /* Failed to find the device. Stop trying and clean up. */ 720987da915Sopenharmony_ci goto end_hd; 721987da915Sopenharmony_cigot_part_hd: 722987da915Sopenharmony_ci /* Get the whole block device the partition device is on. */ 723987da915Sopenharmony_ci hd = hd_get_device_by_idx(hddata, hd->attached_to); 724987da915Sopenharmony_ci if (!hd) 725987da915Sopenharmony_ci goto end_hd; 726987da915Sopenharmony_cigot_hd: 727987da915Sopenharmony_ci /* 728987da915Sopenharmony_ci * @hd is now the whole block device either being formatted or 729987da915Sopenharmony_ci * that the partition being formatted is on. 730987da915Sopenharmony_ci * 731987da915Sopenharmony_ci * Loop over each resource of the disk device looking for the 732987da915Sopenharmony_ci * BIOS legacy geometry obtained from EDD which is what Windows 733987da915Sopenharmony_ci * needs to boot. 734987da915Sopenharmony_ci */ 735987da915Sopenharmony_ci for (res = hd->res; res; res = res->next) { 736987da915Sopenharmony_ci /* geotype 3 is BIOS legacy. */ 737987da915Sopenharmony_ci if (res->any.type != res_disk_geo || 738987da915Sopenharmony_ci res->disk_geo.geotype != 3) 739987da915Sopenharmony_ci continue; 740987da915Sopenharmony_ci dev->d_heads = res->disk_geo.heads; 741987da915Sopenharmony_ci dev->d_sectors_per_track = res->disk_geo.sectors; 742987da915Sopenharmony_ci done = 1; 743987da915Sopenharmony_ci } 744987da915Sopenharmony_ciend_hd: 745987da915Sopenharmony_ci if (partlist) 746987da915Sopenharmony_ci hd_free_hd_list(partlist); 747987da915Sopenharmony_ci hd_free_hd_list(devlist); 748987da915Sopenharmony_ci hd_free_hd_data(hddata); 749987da915Sopenharmony_ci free(hddata); 750987da915Sopenharmony_ci if (done) { 751987da915Sopenharmony_ci ntfs_log_debug("EDD/BIOD legacy heads = %u, sectors " 752987da915Sopenharmony_ci "per track = %u\n", dev->d_heads, 753987da915Sopenharmony_ci dev->d_sectors_per_track); 754987da915Sopenharmony_ci return 0; 755987da915Sopenharmony_ci } 756987da915Sopenharmony_ci } 757987da915Sopenharmony_ciskip_hd: 758987da915Sopenharmony_ci#endif 759987da915Sopenharmony_ci#ifdef HDIO_GETGEO 760987da915Sopenharmony_ci { struct hd_geometry geo; 761987da915Sopenharmony_ci 762987da915Sopenharmony_ci if (!dev->d_ops->ioctl(dev, HDIO_GETGEO, &geo)) { 763987da915Sopenharmony_ci dev->d_heads = geo.heads; 764987da915Sopenharmony_ci dev->d_sectors_per_track = geo.sectors; 765987da915Sopenharmony_ci ntfs_log_debug("HDIO_GETGEO heads = %u, sectors per " 766987da915Sopenharmony_ci "track = %u\n", dev->d_heads, 767987da915Sopenharmony_ci dev->d_sectors_per_track); 768987da915Sopenharmony_ci return 0; 769987da915Sopenharmony_ci } 770987da915Sopenharmony_ci err = errno; 771987da915Sopenharmony_ci } 772987da915Sopenharmony_ci#endif 773987da915Sopenharmony_ci errno = err; 774987da915Sopenharmony_ci return -1; 775987da915Sopenharmony_ci} 776987da915Sopenharmony_ci 777987da915Sopenharmony_ci/** 778987da915Sopenharmony_ci * ntfs_device_heads_get - get number of heads of device 779987da915Sopenharmony_ci * @dev: open device 780987da915Sopenharmony_ci * 781987da915Sopenharmony_ci * On success, return the number of heads on the device @dev. On error return 782987da915Sopenharmony_ci * -1 with errno set to the error code. 783987da915Sopenharmony_ci * 784987da915Sopenharmony_ci * The following error codes are defined: 785987da915Sopenharmony_ci * EINVAL Input parameter error 786987da915Sopenharmony_ci * EOPNOTSUPP System does not support HDIO_GETGEO ioctl 787987da915Sopenharmony_ci * ENOTTY @dev is a file or a device not supporting HDIO_GETGEO 788987da915Sopenharmony_ci * ENOMEM Not enough memory to complete the request 789987da915Sopenharmony_ci */ 790987da915Sopenharmony_ciint ntfs_device_heads_get(struct ntfs_device *dev) 791987da915Sopenharmony_ci{ 792987da915Sopenharmony_ci if (!dev) { 793987da915Sopenharmony_ci errno = EINVAL; 794987da915Sopenharmony_ci return -1; 795987da915Sopenharmony_ci } 796987da915Sopenharmony_ci if (dev->d_heads == -1) { 797987da915Sopenharmony_ci if (ntfs_device_get_geo(dev) == -1) 798987da915Sopenharmony_ci return -1; 799987da915Sopenharmony_ci if (dev->d_heads == -1) { 800987da915Sopenharmony_ci errno = EINVAL; 801987da915Sopenharmony_ci return -1; 802987da915Sopenharmony_ci } 803987da915Sopenharmony_ci } 804987da915Sopenharmony_ci return dev->d_heads; 805987da915Sopenharmony_ci} 806987da915Sopenharmony_ci 807987da915Sopenharmony_ci/** 808987da915Sopenharmony_ci * ntfs_device_sectors_per_track_get - get number of sectors per track of device 809987da915Sopenharmony_ci * @dev: open device 810987da915Sopenharmony_ci * 811987da915Sopenharmony_ci * On success, return the number of sectors per track on the device @dev. On 812987da915Sopenharmony_ci * error return -1 with errno set to the error code. 813987da915Sopenharmony_ci * 814987da915Sopenharmony_ci * The following error codes are defined: 815987da915Sopenharmony_ci * EINVAL Input parameter error 816987da915Sopenharmony_ci * EOPNOTSUPP System does not support HDIO_GETGEO ioctl 817987da915Sopenharmony_ci * ENOTTY @dev is a file or a device not supporting HDIO_GETGEO 818987da915Sopenharmony_ci * ENOMEM Not enough memory to complete the request 819987da915Sopenharmony_ci */ 820987da915Sopenharmony_ciint ntfs_device_sectors_per_track_get(struct ntfs_device *dev) 821987da915Sopenharmony_ci{ 822987da915Sopenharmony_ci if (!dev) { 823987da915Sopenharmony_ci errno = EINVAL; 824987da915Sopenharmony_ci return -1; 825987da915Sopenharmony_ci } 826987da915Sopenharmony_ci if (dev->d_sectors_per_track == -1) { 827987da915Sopenharmony_ci if (ntfs_device_get_geo(dev) == -1) 828987da915Sopenharmony_ci return -1; 829987da915Sopenharmony_ci if (dev->d_sectors_per_track == -1) { 830987da915Sopenharmony_ci errno = EINVAL; 831987da915Sopenharmony_ci return -1; 832987da915Sopenharmony_ci } 833987da915Sopenharmony_ci } 834987da915Sopenharmony_ci return dev->d_sectors_per_track; 835987da915Sopenharmony_ci} 836987da915Sopenharmony_ci 837987da915Sopenharmony_ci/** 838987da915Sopenharmony_ci * ntfs_device_sector_size_get - get sector size of a device 839987da915Sopenharmony_ci * @dev: open device 840987da915Sopenharmony_ci * 841987da915Sopenharmony_ci * On success, return the sector size in bytes of the device @dev. 842987da915Sopenharmony_ci * On error return -1 with errno set to the error code. 843987da915Sopenharmony_ci * 844987da915Sopenharmony_ci * The following error codes are defined: 845987da915Sopenharmony_ci * EINVAL Input parameter error 846987da915Sopenharmony_ci * EOPNOTSUPP System does not support BLKSSZGET ioctl 847987da915Sopenharmony_ci * ENOTTY @dev is a file or a device not supporting BLKSSZGET 848987da915Sopenharmony_ci */ 849987da915Sopenharmony_ciint ntfs_device_sector_size_get(struct ntfs_device *dev) 850987da915Sopenharmony_ci{ 851987da915Sopenharmony_ci if (!dev) { 852987da915Sopenharmony_ci errno = EINVAL; 853987da915Sopenharmony_ci return -1; 854987da915Sopenharmony_ci } 855987da915Sopenharmony_ci#ifdef BLKSSZGET 856987da915Sopenharmony_ci { 857987da915Sopenharmony_ci int sect_size = 0; 858987da915Sopenharmony_ci 859987da915Sopenharmony_ci if (!dev->d_ops->ioctl(dev, BLKSSZGET, §_size)) { 860987da915Sopenharmony_ci ntfs_log_debug("BLKSSZGET sector size = %d bytes\n", 861987da915Sopenharmony_ci sect_size); 862987da915Sopenharmony_ci return sect_size; 863987da915Sopenharmony_ci } 864987da915Sopenharmony_ci } 865987da915Sopenharmony_ci#elif defined(DIOCGSECTORSIZE) 866987da915Sopenharmony_ci { 867987da915Sopenharmony_ci /* FreeBSD */ 868987da915Sopenharmony_ci size_t sect_size = 0; 869987da915Sopenharmony_ci 870987da915Sopenharmony_ci if (!dev->d_ops->ioctl(dev, DIOCGSECTORSIZE, §_size)) { 871987da915Sopenharmony_ci ntfs_log_debug("DIOCGSECTORSIZE sector size = %d bytes\n", 872987da915Sopenharmony_ci (int) sect_size); 873987da915Sopenharmony_ci return sect_size; 874987da915Sopenharmony_ci } 875987da915Sopenharmony_ci } 876987da915Sopenharmony_ci#elif defined(DKIOCGETBLOCKSIZE) 877987da915Sopenharmony_ci { 878987da915Sopenharmony_ci /* Mac OS X */ 879987da915Sopenharmony_ci uint32_t sect_size = 0; 880987da915Sopenharmony_ci 881987da915Sopenharmony_ci if (!dev->d_ops->ioctl(dev, DKIOCGETBLOCKSIZE, §_size)) { 882987da915Sopenharmony_ci ntfs_log_debug("DKIOCGETBLOCKSIZE sector size = %d bytes\n", 883987da915Sopenharmony_ci (int) sect_size); 884987da915Sopenharmony_ci return sect_size; 885987da915Sopenharmony_ci } 886987da915Sopenharmony_ci } 887987da915Sopenharmony_ci#else 888987da915Sopenharmony_ci errno = EOPNOTSUPP; 889987da915Sopenharmony_ci#endif 890987da915Sopenharmony_ci return -1; 891987da915Sopenharmony_ci} 892987da915Sopenharmony_ci 893987da915Sopenharmony_ci/** 894987da915Sopenharmony_ci * ntfs_device_block_size_set - set block size of a device 895987da915Sopenharmony_ci * @dev: open device 896987da915Sopenharmony_ci * @block_size: block size to set @dev to 897987da915Sopenharmony_ci * 898987da915Sopenharmony_ci * On success, return 0. 899987da915Sopenharmony_ci * On error return -1 with errno set to the error code. 900987da915Sopenharmony_ci * 901987da915Sopenharmony_ci * The following error codes are defined: 902987da915Sopenharmony_ci * EINVAL Input parameter error 903987da915Sopenharmony_ci * EOPNOTSUPP System does not support BLKBSZSET ioctl 904987da915Sopenharmony_ci * ENOTTY @dev is a file or a device not supporting BLKBSZSET 905987da915Sopenharmony_ci */ 906987da915Sopenharmony_ciint ntfs_device_block_size_set(struct ntfs_device *dev, 907987da915Sopenharmony_ci int block_size __attribute__((unused))) 908987da915Sopenharmony_ci{ 909987da915Sopenharmony_ci if (!dev) { 910987da915Sopenharmony_ci errno = EINVAL; 911987da915Sopenharmony_ci return -1; 912987da915Sopenharmony_ci } 913987da915Sopenharmony_ci#ifdef BLKBSZSET 914987da915Sopenharmony_ci { 915987da915Sopenharmony_ci size_t s_block_size = block_size; 916987da915Sopenharmony_ci if (!dev->d_ops->ioctl(dev, BLKBSZSET, &s_block_size)) { 917987da915Sopenharmony_ci ntfs_log_debug("Used BLKBSZSET to set block size to " 918987da915Sopenharmony_ci "%d bytes.\n", block_size); 919987da915Sopenharmony_ci return 0; 920987da915Sopenharmony_ci } 921987da915Sopenharmony_ci /* If not a block device, pretend it was successful. */ 922987da915Sopenharmony_ci if (!NDevBlock(dev)) 923987da915Sopenharmony_ci return 0; 924987da915Sopenharmony_ci } 925987da915Sopenharmony_ci#else 926987da915Sopenharmony_ci /* If not a block device, pretend it was successful. */ 927987da915Sopenharmony_ci if (!NDevBlock(dev)) 928987da915Sopenharmony_ci return 0; 929987da915Sopenharmony_ci errno = EOPNOTSUPP; 930987da915Sopenharmony_ci#endif 931987da915Sopenharmony_ci return -1; 932987da915Sopenharmony_ci} 933