19663SMark.Logan@Sun.COM /** 29663SMark.Logan@Sun.COM * unix_io.c - Unix style disk io functions. Part of the Linux-NTFS project. 39663SMark.Logan@Sun.COM * 49663SMark.Logan@Sun.COM * Copyright (c) 2000-2006 Anton Altaparmakov 59663SMark.Logan@Sun.COM * 69663SMark.Logan@Sun.COM * This program/include file is free software; you can redistribute it and/or 79663SMark.Logan@Sun.COM * modify it under the terms of the GNU General Public License as published 89663SMark.Logan@Sun.COM * by the Free Software Foundation; either version 2 of the License, or 99663SMark.Logan@Sun.COM * (at your option) any later version. 109663SMark.Logan@Sun.COM * 119663SMark.Logan@Sun.COM * This program/include file is distributed in the hope that it will be 129663SMark.Logan@Sun.COM * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 139663SMark.Logan@Sun.COM * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 149663SMark.Logan@Sun.COM * GNU General Public License for more details. 159663SMark.Logan@Sun.COM * 169663SMark.Logan@Sun.COM * You should have received a copy of the GNU General Public License 179663SMark.Logan@Sun.COM * along with this program (in the main directory of the Linux-NTFS 189663SMark.Logan@Sun.COM * distribution in the file COPYING); if not, write to the Free Software 199663SMark.Logan@Sun.COM * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 209663SMark.Logan@Sun.COM */ 219663SMark.Logan@Sun.COM 229663SMark.Logan@Sun.COM #ifdef HAVE_CONFIG_H 239663SMark.Logan@Sun.COM #include "config.h" 249663SMark.Logan@Sun.COM #endif 259663SMark.Logan@Sun.COM 269663SMark.Logan@Sun.COM #ifdef HAVE_UNISTD_H 279663SMark.Logan@Sun.COM #include <unistd.h> 289663SMark.Logan@Sun.COM #endif 299663SMark.Logan@Sun.COM #ifdef HAVE_STDLIB_H 309663SMark.Logan@Sun.COM #include <stdlib.h> 319663SMark.Logan@Sun.COM #endif 329663SMark.Logan@Sun.COM #ifdef HAVE_STRING_H 339663SMark.Logan@Sun.COM #include <string.h> 349663SMark.Logan@Sun.COM #endif 359663SMark.Logan@Sun.COM #ifdef HAVE_ERRNO_H 369663SMark.Logan@Sun.COM #include <errno.h> 379663SMark.Logan@Sun.COM #endif 389663SMark.Logan@Sun.COM #ifdef HAVE_STDIO_H 399663SMark.Logan@Sun.COM #include <stdio.h> 409663SMark.Logan@Sun.COM #endif 419663SMark.Logan@Sun.COM #ifdef HAVE_SYS_TYPES_H 429663SMark.Logan@Sun.COM #include <sys/types.h> 439663SMark.Logan@Sun.COM #endif 449663SMark.Logan@Sun.COM #ifdef HAVE_SYS_STAT_H 459663SMark.Logan@Sun.COM #include <sys/stat.h> 469663SMark.Logan@Sun.COM #endif 479663SMark.Logan@Sun.COM #ifdef HAVE_FCNTL_H 489663SMark.Logan@Sun.COM #include <fcntl.h> 499663SMark.Logan@Sun.COM #endif 509663SMark.Logan@Sun.COM #ifdef HAVE_SYS_IOCTL_H 519663SMark.Logan@Sun.COM #include <sys/ioctl.h> 529663SMark.Logan@Sun.COM #endif 539663SMark.Logan@Sun.COM #ifdef HAVE_LINUX_FD_H 549663SMark.Logan@Sun.COM #include <linux/fd.h> 559663SMark.Logan@Sun.COM #endif 569663SMark.Logan@Sun.COM 57*10214SMark.Logan@Sun.COM #include "compat.h" 589663SMark.Logan@Sun.COM #include "types.h" 599663SMark.Logan@Sun.COM #include "mst.h" 609663SMark.Logan@Sun.COM #include "debug.h" 619663SMark.Logan@Sun.COM #include "device.h" 629663SMark.Logan@Sun.COM #include "logging.h" 639663SMark.Logan@Sun.COM 649663SMark.Logan@Sun.COM #define DEV_FD(dev) (*(int *)dev->d_private) 659663SMark.Logan@Sun.COM 669663SMark.Logan@Sun.COM /* Define to nothing if not present on this system. */ 679663SMark.Logan@Sun.COM #ifndef O_EXCL 689663SMark.Logan@Sun.COM # define O_EXCL 0 699663SMark.Logan@Sun.COM #endif 709663SMark.Logan@Sun.COM 719663SMark.Logan@Sun.COM /** 729663SMark.Logan@Sun.COM * ntfs_device_unix_io_open - Open a device and lock it exclusively 739663SMark.Logan@Sun.COM * @dev: 749663SMark.Logan@Sun.COM * @flags: 759663SMark.Logan@Sun.COM * 769663SMark.Logan@Sun.COM * Description... 779663SMark.Logan@Sun.COM * 789663SMark.Logan@Sun.COM * Returns: 799663SMark.Logan@Sun.COM */ 809663SMark.Logan@Sun.COM static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags) 819663SMark.Logan@Sun.COM { 829663SMark.Logan@Sun.COM struct flock flk; 839663SMark.Logan@Sun.COM struct stat sbuf; 849663SMark.Logan@Sun.COM int err; 859663SMark.Logan@Sun.COM 869663SMark.Logan@Sun.COM if (NDevOpen(dev)) { 879663SMark.Logan@Sun.COM errno = EBUSY; 889663SMark.Logan@Sun.COM return -1; 899663SMark.Logan@Sun.COM } 909663SMark.Logan@Sun.COM if (!(dev->d_private = ntfs_malloc(sizeof(int)))) 919663SMark.Logan@Sun.COM return -1; 929663SMark.Logan@Sun.COM *(int*)dev->d_private = open(dev->d_name, flags); 939663SMark.Logan@Sun.COM if (*(int*)dev->d_private == -1) { 949663SMark.Logan@Sun.COM err = errno; 959663SMark.Logan@Sun.COM goto err_out; 969663SMark.Logan@Sun.COM } 979663SMark.Logan@Sun.COM /* Setup our read-only flag. */ 989663SMark.Logan@Sun.COM if ((flags & O_RDWR) != O_RDWR) 999663SMark.Logan@Sun.COM NDevSetReadOnly(dev); 1009663SMark.Logan@Sun.COM /* Acquire exclusive (mandatory) lock on the whole device. */ 1019663SMark.Logan@Sun.COM memset(&flk, 0, sizeof(flk)); 1029663SMark.Logan@Sun.COM if (NDevReadOnly(dev)) 1039663SMark.Logan@Sun.COM flk.l_type = F_RDLCK; 1049663SMark.Logan@Sun.COM else 1059663SMark.Logan@Sun.COM flk.l_type = F_WRLCK; 1069663SMark.Logan@Sun.COM flk.l_whence = SEEK_SET; 1079663SMark.Logan@Sun.COM flk.l_start = flk.l_len = 0LL; 1089663SMark.Logan@Sun.COM if (fcntl(DEV_FD(dev), F_SETLK, &flk)) { 1099663SMark.Logan@Sun.COM err = errno; 1109663SMark.Logan@Sun.COM ntfs_log_debug("ntfs_device_unix_io_open: Could not lock %s " 1119663SMark.Logan@Sun.COM "for %s\n", dev->d_name, NDevReadOnly(dev) ? 1129663SMark.Logan@Sun.COM "reading" : "writing"); 1139663SMark.Logan@Sun.COM if (close(DEV_FD(dev))) 1149663SMark.Logan@Sun.COM ntfs_log_perror("ntfs_device_unix_io_open: Warning: " 1159663SMark.Logan@Sun.COM "Could not close %s", dev->d_name); 1169663SMark.Logan@Sun.COM goto err_out; 1179663SMark.Logan@Sun.COM } 1189663SMark.Logan@Sun.COM /* Determine if device is a block device or not, ignoring errors. */ 1199663SMark.Logan@Sun.COM if (!fstat(DEV_FD(dev), &sbuf) && S_ISBLK(sbuf.st_mode)) 1209663SMark.Logan@Sun.COM NDevSetBlock(dev); 1219663SMark.Logan@Sun.COM /* Set our open flag. */ 1229663SMark.Logan@Sun.COM NDevSetOpen(dev); 1239663SMark.Logan@Sun.COM return 0; 1249663SMark.Logan@Sun.COM err_out: 1259663SMark.Logan@Sun.COM free(dev->d_private); 1269663SMark.Logan@Sun.COM dev->d_private = NULL; 1279663SMark.Logan@Sun.COM errno = err; 1289663SMark.Logan@Sun.COM return -1; 1299663SMark.Logan@Sun.COM } 1309663SMark.Logan@Sun.COM 1319663SMark.Logan@Sun.COM /** 1329663SMark.Logan@Sun.COM * ntfs_device_unix_io_close - Close the device, releasing the lock 1339663SMark.Logan@Sun.COM * @dev: 1349663SMark.Logan@Sun.COM * 1359663SMark.Logan@Sun.COM * Description... 1369663SMark.Logan@Sun.COM * 1379663SMark.Logan@Sun.COM * Returns: 1389663SMark.Logan@Sun.COM */ 1399663SMark.Logan@Sun.COM static int ntfs_device_unix_io_close(struct ntfs_device *dev) 1409663SMark.Logan@Sun.COM { 1419663SMark.Logan@Sun.COM struct flock flk; 1429663SMark.Logan@Sun.COM 1439663SMark.Logan@Sun.COM if (!NDevOpen(dev)) { 1449663SMark.Logan@Sun.COM errno = EBADF; 1459663SMark.Logan@Sun.COM return -1; 1469663SMark.Logan@Sun.COM } 1479663SMark.Logan@Sun.COM if (NDevDirty(dev)) 1489663SMark.Logan@Sun.COM fsync(DEV_FD(dev)); 1499663SMark.Logan@Sun.COM /* Release exclusive (mandatory) lock on the whole device. */ 1509663SMark.Logan@Sun.COM memset(&flk, 0, sizeof(flk)); 1519663SMark.Logan@Sun.COM flk.l_type = F_UNLCK; 1529663SMark.Logan@Sun.COM flk.l_whence = SEEK_SET; 1539663SMark.Logan@Sun.COM flk.l_start = flk.l_len = 0LL; 1549663SMark.Logan@Sun.COM if (fcntl(DEV_FD(dev), F_SETLK, &flk)) 1559663SMark.Logan@Sun.COM ntfs_log_perror("ntfs_device_unix_io_close: Warning: Could not " 1569663SMark.Logan@Sun.COM "unlock %s", dev->d_name); 1579663SMark.Logan@Sun.COM /* Close the file descriptor and clear our open flag. */ 1589663SMark.Logan@Sun.COM if (close(DEV_FD(dev))) 1599663SMark.Logan@Sun.COM return -1; 1609663SMark.Logan@Sun.COM NDevClearOpen(dev); 1619663SMark.Logan@Sun.COM free(dev->d_private); 1629663SMark.Logan@Sun.COM dev->d_private = NULL; 1639663SMark.Logan@Sun.COM return 0; 1649663SMark.Logan@Sun.COM } 1659663SMark.Logan@Sun.COM 1669663SMark.Logan@Sun.COM /** 1679663SMark.Logan@Sun.COM * ntfs_device_unix_io_seek - Seek to a place on the device 1689663SMark.Logan@Sun.COM * @dev: 1699663SMark.Logan@Sun.COM * @offset: 1709663SMark.Logan@Sun.COM * @whence: 1719663SMark.Logan@Sun.COM * 1729663SMark.Logan@Sun.COM * Description... 1739663SMark.Logan@Sun.COM * 1749663SMark.Logan@Sun.COM * Returns: 1759663SMark.Logan@Sun.COM */ 1769663SMark.Logan@Sun.COM static s64 ntfs_device_unix_io_seek(struct ntfs_device *dev, s64 offset, 1779663SMark.Logan@Sun.COM int whence) 1789663SMark.Logan@Sun.COM { 1799663SMark.Logan@Sun.COM return lseek(DEV_FD(dev), offset, whence); 1809663SMark.Logan@Sun.COM } 1819663SMark.Logan@Sun.COM 1829663SMark.Logan@Sun.COM /** 1839663SMark.Logan@Sun.COM * ntfs_device_unix_io_read - Read from the device, from the current location 1849663SMark.Logan@Sun.COM * @dev: 1859663SMark.Logan@Sun.COM * @buf: 1869663SMark.Logan@Sun.COM * @count: 1879663SMark.Logan@Sun.COM * 1889663SMark.Logan@Sun.COM * Description... 1899663SMark.Logan@Sun.COM * 1909663SMark.Logan@Sun.COM * Returns: 1919663SMark.Logan@Sun.COM */ 1929663SMark.Logan@Sun.COM static s64 ntfs_device_unix_io_read(struct ntfs_device *dev, void *buf, 1939663SMark.Logan@Sun.COM s64 count) 1949663SMark.Logan@Sun.COM { 1959663SMark.Logan@Sun.COM return read(DEV_FD(dev), buf, count); 1969663SMark.Logan@Sun.COM } 1979663SMark.Logan@Sun.COM 1989663SMark.Logan@Sun.COM /** 1999663SMark.Logan@Sun.COM * ntfs_device_unix_io_write - Write to the device, at the current location 2009663SMark.Logan@Sun.COM * @dev: 2019663SMark.Logan@Sun.COM * @buf: 2029663SMark.Logan@Sun.COM * @count: 2039663SMark.Logan@Sun.COM * 2049663SMark.Logan@Sun.COM * Description... 2059663SMark.Logan@Sun.COM * 2069663SMark.Logan@Sun.COM * Returns: 2079663SMark.Logan@Sun.COM */ 2089663SMark.Logan@Sun.COM static s64 ntfs_device_unix_io_write(struct ntfs_device *dev, const void *buf, 2099663SMark.Logan@Sun.COM s64 count) 2109663SMark.Logan@Sun.COM { 2119663SMark.Logan@Sun.COM if (NDevReadOnly(dev)) { 2129663SMark.Logan@Sun.COM errno = EROFS; 2139663SMark.Logan@Sun.COM return -1; 2149663SMark.Logan@Sun.COM } 2159663SMark.Logan@Sun.COM NDevSetDirty(dev); 2169663SMark.Logan@Sun.COM return write(DEV_FD(dev), buf, count); 2179663SMark.Logan@Sun.COM } 2189663SMark.Logan@Sun.COM 2199663SMark.Logan@Sun.COM /** 2209663SMark.Logan@Sun.COM * ntfs_device_unix_io_pread - Perform a positioned read from the device 2219663SMark.Logan@Sun.COM * @dev: 2229663SMark.Logan@Sun.COM * @buf: 2239663SMark.Logan@Sun.COM * @count: 2249663SMark.Logan@Sun.COM * @offset: 2259663SMark.Logan@Sun.COM * 2269663SMark.Logan@Sun.COM * Description... 2279663SMark.Logan@Sun.COM * 2289663SMark.Logan@Sun.COM * Returns: 2299663SMark.Logan@Sun.COM */ 2309663SMark.Logan@Sun.COM static s64 ntfs_device_unix_io_pread(struct ntfs_device *dev, void *buf, 2319663SMark.Logan@Sun.COM s64 count, s64 offset) 2329663SMark.Logan@Sun.COM { 2339663SMark.Logan@Sun.COM return pread(DEV_FD(dev), buf, count, offset); 2349663SMark.Logan@Sun.COM } 2359663SMark.Logan@Sun.COM 2369663SMark.Logan@Sun.COM /** 2379663SMark.Logan@Sun.COM * ntfs_device_unix_io_pwrite - Perform a positioned write to the device 2389663SMark.Logan@Sun.COM * @dev: 2399663SMark.Logan@Sun.COM * @buf: 2409663SMark.Logan@Sun.COM * @count: 2419663SMark.Logan@Sun.COM * @offset: 2429663SMark.Logan@Sun.COM * 2439663SMark.Logan@Sun.COM * Description... 2449663SMark.Logan@Sun.COM * 2459663SMark.Logan@Sun.COM * Returns: 2469663SMark.Logan@Sun.COM */ 2479663SMark.Logan@Sun.COM static s64 ntfs_device_unix_io_pwrite(struct ntfs_device *dev, const void *buf, 2489663SMark.Logan@Sun.COM s64 count, s64 offset) 2499663SMark.Logan@Sun.COM { 2509663SMark.Logan@Sun.COM if (NDevReadOnly(dev)) { 2519663SMark.Logan@Sun.COM errno = EROFS; 2529663SMark.Logan@Sun.COM return -1; 2539663SMark.Logan@Sun.COM } 2549663SMark.Logan@Sun.COM NDevSetDirty(dev); 2559663SMark.Logan@Sun.COM return pwrite(DEV_FD(dev), buf, count, offset); 2569663SMark.Logan@Sun.COM } 2579663SMark.Logan@Sun.COM 2589663SMark.Logan@Sun.COM /** 2599663SMark.Logan@Sun.COM * ntfs_device_unix_io_sync - Flush any buffered changes to the device 2609663SMark.Logan@Sun.COM * @dev: 2619663SMark.Logan@Sun.COM * 2629663SMark.Logan@Sun.COM * Description... 2639663SMark.Logan@Sun.COM * 2649663SMark.Logan@Sun.COM * Returns: 2659663SMark.Logan@Sun.COM */ 2669663SMark.Logan@Sun.COM static int ntfs_device_unix_io_sync(struct ntfs_device *dev) 2679663SMark.Logan@Sun.COM { 2689663SMark.Logan@Sun.COM if (!NDevReadOnly(dev) && NDevDirty(dev)) { 2699663SMark.Logan@Sun.COM int res = fsync(DEV_FD(dev)); 2709663SMark.Logan@Sun.COM if (!res) 2719663SMark.Logan@Sun.COM NDevClearDirty(dev); 2729663SMark.Logan@Sun.COM return res; 2739663SMark.Logan@Sun.COM } 2749663SMark.Logan@Sun.COM return 0; 2759663SMark.Logan@Sun.COM } 2769663SMark.Logan@Sun.COM 2779663SMark.Logan@Sun.COM /** 2789663SMark.Logan@Sun.COM * ntfs_device_unix_io_stat - Get information about the device 2799663SMark.Logan@Sun.COM * @dev: 2809663SMark.Logan@Sun.COM * @buf: 2819663SMark.Logan@Sun.COM * 2829663SMark.Logan@Sun.COM * Description... 2839663SMark.Logan@Sun.COM * 2849663SMark.Logan@Sun.COM * Returns: 2859663SMark.Logan@Sun.COM */ 2869663SMark.Logan@Sun.COM static int ntfs_device_unix_io_stat(struct ntfs_device *dev, struct stat *buf) 2879663SMark.Logan@Sun.COM { 2889663SMark.Logan@Sun.COM return fstat(DEV_FD(dev), buf); 2899663SMark.Logan@Sun.COM } 2909663SMark.Logan@Sun.COM 2919663SMark.Logan@Sun.COM /** 2929663SMark.Logan@Sun.COM * ntfs_device_unix_io_ioctl - Perform an ioctl on the device 2939663SMark.Logan@Sun.COM * @dev: 2949663SMark.Logan@Sun.COM * @request: 2959663SMark.Logan@Sun.COM * @argp: 2969663SMark.Logan@Sun.COM * 2979663SMark.Logan@Sun.COM * Description... 2989663SMark.Logan@Sun.COM * 2999663SMark.Logan@Sun.COM * Returns: 3009663SMark.Logan@Sun.COM */ 3019663SMark.Logan@Sun.COM static int ntfs_device_unix_io_ioctl(struct ntfs_device *dev, int request, 3029663SMark.Logan@Sun.COM void *argp) 3039663SMark.Logan@Sun.COM { 3049663SMark.Logan@Sun.COM return ioctl(DEV_FD(dev), request, argp); 3059663SMark.Logan@Sun.COM } 3069663SMark.Logan@Sun.COM 3079663SMark.Logan@Sun.COM /** 3089663SMark.Logan@Sun.COM * Device operations for working with unix style devices and files. 3099663SMark.Logan@Sun.COM */ 3109663SMark.Logan@Sun.COM struct ntfs_device_operations ntfs_device_unix_io_ops = { 3119663SMark.Logan@Sun.COM .open = ntfs_device_unix_io_open, 3129663SMark.Logan@Sun.COM .close = ntfs_device_unix_io_close, 3139663SMark.Logan@Sun.COM .seek = ntfs_device_unix_io_seek, 3149663SMark.Logan@Sun.COM .read = ntfs_device_unix_io_read, 3159663SMark.Logan@Sun.COM .write = ntfs_device_unix_io_write, 3169663SMark.Logan@Sun.COM .pread = ntfs_device_unix_io_pread, 3179663SMark.Logan@Sun.COM .pwrite = ntfs_device_unix_io_pwrite, 3189663SMark.Logan@Sun.COM .sync = ntfs_device_unix_io_sync, 3199663SMark.Logan@Sun.COM .stat = ntfs_device_unix_io_stat, 3209663SMark.Logan@Sun.COM .ioctl = ntfs_device_unix_io_ioctl, 3219663SMark.Logan@Sun.COM }; 322