1*9663SMark.Logan@Sun.COM /** 2*9663SMark.Logan@Sun.COM * unix_io.c - Unix style disk io functions. Part of the Linux-NTFS project. 3*9663SMark.Logan@Sun.COM * 4*9663SMark.Logan@Sun.COM * Copyright (c) 2000-2006 Anton Altaparmakov 5*9663SMark.Logan@Sun.COM * 6*9663SMark.Logan@Sun.COM * This program/include file is free software; you can redistribute it and/or 7*9663SMark.Logan@Sun.COM * modify it under the terms of the GNU General Public License as published 8*9663SMark.Logan@Sun.COM * by the Free Software Foundation; either version 2 of the License, or 9*9663SMark.Logan@Sun.COM * (at your option) any later version. 10*9663SMark.Logan@Sun.COM * 11*9663SMark.Logan@Sun.COM * This program/include file is distributed in the hope that it will be 12*9663SMark.Logan@Sun.COM * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 13*9663SMark.Logan@Sun.COM * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*9663SMark.Logan@Sun.COM * GNU General Public License for more details. 15*9663SMark.Logan@Sun.COM * 16*9663SMark.Logan@Sun.COM * You should have received a copy of the GNU General Public License 17*9663SMark.Logan@Sun.COM * along with this program (in the main directory of the Linux-NTFS 18*9663SMark.Logan@Sun.COM * distribution in the file COPYING); if not, write to the Free Software 19*9663SMark.Logan@Sun.COM * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20*9663SMark.Logan@Sun.COM */ 21*9663SMark.Logan@Sun.COM 22*9663SMark.Logan@Sun.COM #ifdef HAVE_CONFIG_H 23*9663SMark.Logan@Sun.COM #include "config.h" 24*9663SMark.Logan@Sun.COM #endif 25*9663SMark.Logan@Sun.COM 26*9663SMark.Logan@Sun.COM #ifdef HAVE_UNISTD_H 27*9663SMark.Logan@Sun.COM #include <unistd.h> 28*9663SMark.Logan@Sun.COM #endif 29*9663SMark.Logan@Sun.COM #ifdef HAVE_STDLIB_H 30*9663SMark.Logan@Sun.COM #include <stdlib.h> 31*9663SMark.Logan@Sun.COM #endif 32*9663SMark.Logan@Sun.COM #ifdef HAVE_STRING_H 33*9663SMark.Logan@Sun.COM #include <string.h> 34*9663SMark.Logan@Sun.COM #endif 35*9663SMark.Logan@Sun.COM #ifdef HAVE_ERRNO_H 36*9663SMark.Logan@Sun.COM #include <errno.h> 37*9663SMark.Logan@Sun.COM #endif 38*9663SMark.Logan@Sun.COM #ifdef HAVE_STDIO_H 39*9663SMark.Logan@Sun.COM #include <stdio.h> 40*9663SMark.Logan@Sun.COM #endif 41*9663SMark.Logan@Sun.COM #ifdef HAVE_SYS_TYPES_H 42*9663SMark.Logan@Sun.COM #include <sys/types.h> 43*9663SMark.Logan@Sun.COM #endif 44*9663SMark.Logan@Sun.COM #ifdef HAVE_SYS_STAT_H 45*9663SMark.Logan@Sun.COM #include <sys/stat.h> 46*9663SMark.Logan@Sun.COM #endif 47*9663SMark.Logan@Sun.COM #ifdef HAVE_FCNTL_H 48*9663SMark.Logan@Sun.COM #include <fcntl.h> 49*9663SMark.Logan@Sun.COM #endif 50*9663SMark.Logan@Sun.COM #ifdef HAVE_SYS_IOCTL_H 51*9663SMark.Logan@Sun.COM #include <sys/ioctl.h> 52*9663SMark.Logan@Sun.COM #endif 53*9663SMark.Logan@Sun.COM #ifdef HAVE_LINUX_FD_H 54*9663SMark.Logan@Sun.COM #include <linux/fd.h> 55*9663SMark.Logan@Sun.COM #endif 56*9663SMark.Logan@Sun.COM 57*9663SMark.Logan@Sun.COM #include "types.h" 58*9663SMark.Logan@Sun.COM #include "mst.h" 59*9663SMark.Logan@Sun.COM #include "debug.h" 60*9663SMark.Logan@Sun.COM #include "device.h" 61*9663SMark.Logan@Sun.COM #include "logging.h" 62*9663SMark.Logan@Sun.COM 63*9663SMark.Logan@Sun.COM #define DEV_FD(dev) (*(int *)dev->d_private) 64*9663SMark.Logan@Sun.COM 65*9663SMark.Logan@Sun.COM /* Define to nothing if not present on this system. */ 66*9663SMark.Logan@Sun.COM #ifndef O_EXCL 67*9663SMark.Logan@Sun.COM # define O_EXCL 0 68*9663SMark.Logan@Sun.COM #endif 69*9663SMark.Logan@Sun.COM 70*9663SMark.Logan@Sun.COM /** 71*9663SMark.Logan@Sun.COM * ntfs_device_unix_io_open - Open a device and lock it exclusively 72*9663SMark.Logan@Sun.COM * @dev: 73*9663SMark.Logan@Sun.COM * @flags: 74*9663SMark.Logan@Sun.COM * 75*9663SMark.Logan@Sun.COM * Description... 76*9663SMark.Logan@Sun.COM * 77*9663SMark.Logan@Sun.COM * Returns: 78*9663SMark.Logan@Sun.COM */ 79*9663SMark.Logan@Sun.COM static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags) 80*9663SMark.Logan@Sun.COM { 81*9663SMark.Logan@Sun.COM struct flock flk; 82*9663SMark.Logan@Sun.COM struct stat sbuf; 83*9663SMark.Logan@Sun.COM int err; 84*9663SMark.Logan@Sun.COM 85*9663SMark.Logan@Sun.COM if (NDevOpen(dev)) { 86*9663SMark.Logan@Sun.COM errno = EBUSY; 87*9663SMark.Logan@Sun.COM return -1; 88*9663SMark.Logan@Sun.COM } 89*9663SMark.Logan@Sun.COM if (!(dev->d_private = ntfs_malloc(sizeof(int)))) 90*9663SMark.Logan@Sun.COM return -1; 91*9663SMark.Logan@Sun.COM *(int*)dev->d_private = open(dev->d_name, flags); 92*9663SMark.Logan@Sun.COM if (*(int*)dev->d_private == -1) { 93*9663SMark.Logan@Sun.COM err = errno; 94*9663SMark.Logan@Sun.COM goto err_out; 95*9663SMark.Logan@Sun.COM } 96*9663SMark.Logan@Sun.COM /* Setup our read-only flag. */ 97*9663SMark.Logan@Sun.COM if ((flags & O_RDWR) != O_RDWR) 98*9663SMark.Logan@Sun.COM NDevSetReadOnly(dev); 99*9663SMark.Logan@Sun.COM /* Acquire exclusive (mandatory) lock on the whole device. */ 100*9663SMark.Logan@Sun.COM memset(&flk, 0, sizeof(flk)); 101*9663SMark.Logan@Sun.COM if (NDevReadOnly(dev)) 102*9663SMark.Logan@Sun.COM flk.l_type = F_RDLCK; 103*9663SMark.Logan@Sun.COM else 104*9663SMark.Logan@Sun.COM flk.l_type = F_WRLCK; 105*9663SMark.Logan@Sun.COM flk.l_whence = SEEK_SET; 106*9663SMark.Logan@Sun.COM flk.l_start = flk.l_len = 0LL; 107*9663SMark.Logan@Sun.COM if (fcntl(DEV_FD(dev), F_SETLK, &flk)) { 108*9663SMark.Logan@Sun.COM err = errno; 109*9663SMark.Logan@Sun.COM ntfs_log_debug("ntfs_device_unix_io_open: Could not lock %s " 110*9663SMark.Logan@Sun.COM "for %s\n", dev->d_name, NDevReadOnly(dev) ? 111*9663SMark.Logan@Sun.COM "reading" : "writing"); 112*9663SMark.Logan@Sun.COM if (close(DEV_FD(dev))) 113*9663SMark.Logan@Sun.COM ntfs_log_perror("ntfs_device_unix_io_open: Warning: " 114*9663SMark.Logan@Sun.COM "Could not close %s", dev->d_name); 115*9663SMark.Logan@Sun.COM goto err_out; 116*9663SMark.Logan@Sun.COM } 117*9663SMark.Logan@Sun.COM /* Determine if device is a block device or not, ignoring errors. */ 118*9663SMark.Logan@Sun.COM if (!fstat(DEV_FD(dev), &sbuf) && S_ISBLK(sbuf.st_mode)) 119*9663SMark.Logan@Sun.COM NDevSetBlock(dev); 120*9663SMark.Logan@Sun.COM /* Set our open flag. */ 121*9663SMark.Logan@Sun.COM NDevSetOpen(dev); 122*9663SMark.Logan@Sun.COM return 0; 123*9663SMark.Logan@Sun.COM err_out: 124*9663SMark.Logan@Sun.COM free(dev->d_private); 125*9663SMark.Logan@Sun.COM dev->d_private = NULL; 126*9663SMark.Logan@Sun.COM errno = err; 127*9663SMark.Logan@Sun.COM return -1; 128*9663SMark.Logan@Sun.COM } 129*9663SMark.Logan@Sun.COM 130*9663SMark.Logan@Sun.COM /** 131*9663SMark.Logan@Sun.COM * ntfs_device_unix_io_close - Close the device, releasing the lock 132*9663SMark.Logan@Sun.COM * @dev: 133*9663SMark.Logan@Sun.COM * 134*9663SMark.Logan@Sun.COM * Description... 135*9663SMark.Logan@Sun.COM * 136*9663SMark.Logan@Sun.COM * Returns: 137*9663SMark.Logan@Sun.COM */ 138*9663SMark.Logan@Sun.COM static int ntfs_device_unix_io_close(struct ntfs_device *dev) 139*9663SMark.Logan@Sun.COM { 140*9663SMark.Logan@Sun.COM struct flock flk; 141*9663SMark.Logan@Sun.COM 142*9663SMark.Logan@Sun.COM if (!NDevOpen(dev)) { 143*9663SMark.Logan@Sun.COM errno = EBADF; 144*9663SMark.Logan@Sun.COM return -1; 145*9663SMark.Logan@Sun.COM } 146*9663SMark.Logan@Sun.COM if (NDevDirty(dev)) 147*9663SMark.Logan@Sun.COM fsync(DEV_FD(dev)); 148*9663SMark.Logan@Sun.COM /* Release exclusive (mandatory) lock on the whole device. */ 149*9663SMark.Logan@Sun.COM memset(&flk, 0, sizeof(flk)); 150*9663SMark.Logan@Sun.COM flk.l_type = F_UNLCK; 151*9663SMark.Logan@Sun.COM flk.l_whence = SEEK_SET; 152*9663SMark.Logan@Sun.COM flk.l_start = flk.l_len = 0LL; 153*9663SMark.Logan@Sun.COM if (fcntl(DEV_FD(dev), F_SETLK, &flk)) 154*9663SMark.Logan@Sun.COM ntfs_log_perror("ntfs_device_unix_io_close: Warning: Could not " 155*9663SMark.Logan@Sun.COM "unlock %s", dev->d_name); 156*9663SMark.Logan@Sun.COM /* Close the file descriptor and clear our open flag. */ 157*9663SMark.Logan@Sun.COM if (close(DEV_FD(dev))) 158*9663SMark.Logan@Sun.COM return -1; 159*9663SMark.Logan@Sun.COM NDevClearOpen(dev); 160*9663SMark.Logan@Sun.COM free(dev->d_private); 161*9663SMark.Logan@Sun.COM dev->d_private = NULL; 162*9663SMark.Logan@Sun.COM return 0; 163*9663SMark.Logan@Sun.COM } 164*9663SMark.Logan@Sun.COM 165*9663SMark.Logan@Sun.COM /** 166*9663SMark.Logan@Sun.COM * ntfs_device_unix_io_seek - Seek to a place on the device 167*9663SMark.Logan@Sun.COM * @dev: 168*9663SMark.Logan@Sun.COM * @offset: 169*9663SMark.Logan@Sun.COM * @whence: 170*9663SMark.Logan@Sun.COM * 171*9663SMark.Logan@Sun.COM * Description... 172*9663SMark.Logan@Sun.COM * 173*9663SMark.Logan@Sun.COM * Returns: 174*9663SMark.Logan@Sun.COM */ 175*9663SMark.Logan@Sun.COM static s64 ntfs_device_unix_io_seek(struct ntfs_device *dev, s64 offset, 176*9663SMark.Logan@Sun.COM int whence) 177*9663SMark.Logan@Sun.COM { 178*9663SMark.Logan@Sun.COM return lseek(DEV_FD(dev), offset, whence); 179*9663SMark.Logan@Sun.COM } 180*9663SMark.Logan@Sun.COM 181*9663SMark.Logan@Sun.COM /** 182*9663SMark.Logan@Sun.COM * ntfs_device_unix_io_read - Read from the device, from the current location 183*9663SMark.Logan@Sun.COM * @dev: 184*9663SMark.Logan@Sun.COM * @buf: 185*9663SMark.Logan@Sun.COM * @count: 186*9663SMark.Logan@Sun.COM * 187*9663SMark.Logan@Sun.COM * Description... 188*9663SMark.Logan@Sun.COM * 189*9663SMark.Logan@Sun.COM * Returns: 190*9663SMark.Logan@Sun.COM */ 191*9663SMark.Logan@Sun.COM static s64 ntfs_device_unix_io_read(struct ntfs_device *dev, void *buf, 192*9663SMark.Logan@Sun.COM s64 count) 193*9663SMark.Logan@Sun.COM { 194*9663SMark.Logan@Sun.COM return read(DEV_FD(dev), buf, count); 195*9663SMark.Logan@Sun.COM } 196*9663SMark.Logan@Sun.COM 197*9663SMark.Logan@Sun.COM /** 198*9663SMark.Logan@Sun.COM * ntfs_device_unix_io_write - Write to the device, at the current location 199*9663SMark.Logan@Sun.COM * @dev: 200*9663SMark.Logan@Sun.COM * @buf: 201*9663SMark.Logan@Sun.COM * @count: 202*9663SMark.Logan@Sun.COM * 203*9663SMark.Logan@Sun.COM * Description... 204*9663SMark.Logan@Sun.COM * 205*9663SMark.Logan@Sun.COM * Returns: 206*9663SMark.Logan@Sun.COM */ 207*9663SMark.Logan@Sun.COM static s64 ntfs_device_unix_io_write(struct ntfs_device *dev, const void *buf, 208*9663SMark.Logan@Sun.COM s64 count) 209*9663SMark.Logan@Sun.COM { 210*9663SMark.Logan@Sun.COM if (NDevReadOnly(dev)) { 211*9663SMark.Logan@Sun.COM errno = EROFS; 212*9663SMark.Logan@Sun.COM return -1; 213*9663SMark.Logan@Sun.COM } 214*9663SMark.Logan@Sun.COM NDevSetDirty(dev); 215*9663SMark.Logan@Sun.COM return write(DEV_FD(dev), buf, count); 216*9663SMark.Logan@Sun.COM } 217*9663SMark.Logan@Sun.COM 218*9663SMark.Logan@Sun.COM /** 219*9663SMark.Logan@Sun.COM * ntfs_device_unix_io_pread - Perform a positioned read from the device 220*9663SMark.Logan@Sun.COM * @dev: 221*9663SMark.Logan@Sun.COM * @buf: 222*9663SMark.Logan@Sun.COM * @count: 223*9663SMark.Logan@Sun.COM * @offset: 224*9663SMark.Logan@Sun.COM * 225*9663SMark.Logan@Sun.COM * Description... 226*9663SMark.Logan@Sun.COM * 227*9663SMark.Logan@Sun.COM * Returns: 228*9663SMark.Logan@Sun.COM */ 229*9663SMark.Logan@Sun.COM static s64 ntfs_device_unix_io_pread(struct ntfs_device *dev, void *buf, 230*9663SMark.Logan@Sun.COM s64 count, s64 offset) 231*9663SMark.Logan@Sun.COM { 232*9663SMark.Logan@Sun.COM return pread(DEV_FD(dev), buf, count, offset); 233*9663SMark.Logan@Sun.COM } 234*9663SMark.Logan@Sun.COM 235*9663SMark.Logan@Sun.COM /** 236*9663SMark.Logan@Sun.COM * ntfs_device_unix_io_pwrite - Perform a positioned write to the device 237*9663SMark.Logan@Sun.COM * @dev: 238*9663SMark.Logan@Sun.COM * @buf: 239*9663SMark.Logan@Sun.COM * @count: 240*9663SMark.Logan@Sun.COM * @offset: 241*9663SMark.Logan@Sun.COM * 242*9663SMark.Logan@Sun.COM * Description... 243*9663SMark.Logan@Sun.COM * 244*9663SMark.Logan@Sun.COM * Returns: 245*9663SMark.Logan@Sun.COM */ 246*9663SMark.Logan@Sun.COM static s64 ntfs_device_unix_io_pwrite(struct ntfs_device *dev, const void *buf, 247*9663SMark.Logan@Sun.COM s64 count, s64 offset) 248*9663SMark.Logan@Sun.COM { 249*9663SMark.Logan@Sun.COM if (NDevReadOnly(dev)) { 250*9663SMark.Logan@Sun.COM errno = EROFS; 251*9663SMark.Logan@Sun.COM return -1; 252*9663SMark.Logan@Sun.COM } 253*9663SMark.Logan@Sun.COM NDevSetDirty(dev); 254*9663SMark.Logan@Sun.COM return pwrite(DEV_FD(dev), buf, count, offset); 255*9663SMark.Logan@Sun.COM } 256*9663SMark.Logan@Sun.COM 257*9663SMark.Logan@Sun.COM /** 258*9663SMark.Logan@Sun.COM * ntfs_device_unix_io_sync - Flush any buffered changes to the device 259*9663SMark.Logan@Sun.COM * @dev: 260*9663SMark.Logan@Sun.COM * 261*9663SMark.Logan@Sun.COM * Description... 262*9663SMark.Logan@Sun.COM * 263*9663SMark.Logan@Sun.COM * Returns: 264*9663SMark.Logan@Sun.COM */ 265*9663SMark.Logan@Sun.COM static int ntfs_device_unix_io_sync(struct ntfs_device *dev) 266*9663SMark.Logan@Sun.COM { 267*9663SMark.Logan@Sun.COM if (!NDevReadOnly(dev) && NDevDirty(dev)) { 268*9663SMark.Logan@Sun.COM int res = fsync(DEV_FD(dev)); 269*9663SMark.Logan@Sun.COM if (!res) 270*9663SMark.Logan@Sun.COM NDevClearDirty(dev); 271*9663SMark.Logan@Sun.COM return res; 272*9663SMark.Logan@Sun.COM } 273*9663SMark.Logan@Sun.COM return 0; 274*9663SMark.Logan@Sun.COM } 275*9663SMark.Logan@Sun.COM 276*9663SMark.Logan@Sun.COM /** 277*9663SMark.Logan@Sun.COM * ntfs_device_unix_io_stat - Get information about the device 278*9663SMark.Logan@Sun.COM * @dev: 279*9663SMark.Logan@Sun.COM * @buf: 280*9663SMark.Logan@Sun.COM * 281*9663SMark.Logan@Sun.COM * Description... 282*9663SMark.Logan@Sun.COM * 283*9663SMark.Logan@Sun.COM * Returns: 284*9663SMark.Logan@Sun.COM */ 285*9663SMark.Logan@Sun.COM static int ntfs_device_unix_io_stat(struct ntfs_device *dev, struct stat *buf) 286*9663SMark.Logan@Sun.COM { 287*9663SMark.Logan@Sun.COM return fstat(DEV_FD(dev), buf); 288*9663SMark.Logan@Sun.COM } 289*9663SMark.Logan@Sun.COM 290*9663SMark.Logan@Sun.COM /** 291*9663SMark.Logan@Sun.COM * ntfs_device_unix_io_ioctl - Perform an ioctl on the device 292*9663SMark.Logan@Sun.COM * @dev: 293*9663SMark.Logan@Sun.COM * @request: 294*9663SMark.Logan@Sun.COM * @argp: 295*9663SMark.Logan@Sun.COM * 296*9663SMark.Logan@Sun.COM * Description... 297*9663SMark.Logan@Sun.COM * 298*9663SMark.Logan@Sun.COM * Returns: 299*9663SMark.Logan@Sun.COM */ 300*9663SMark.Logan@Sun.COM static int ntfs_device_unix_io_ioctl(struct ntfs_device *dev, int request, 301*9663SMark.Logan@Sun.COM void *argp) 302*9663SMark.Logan@Sun.COM { 303*9663SMark.Logan@Sun.COM return ioctl(DEV_FD(dev), request, argp); 304*9663SMark.Logan@Sun.COM } 305*9663SMark.Logan@Sun.COM 306*9663SMark.Logan@Sun.COM /** 307*9663SMark.Logan@Sun.COM * Device operations for working with unix style devices and files. 308*9663SMark.Logan@Sun.COM */ 309*9663SMark.Logan@Sun.COM struct ntfs_device_operations ntfs_device_unix_io_ops = { 310*9663SMark.Logan@Sun.COM .open = ntfs_device_unix_io_open, 311*9663SMark.Logan@Sun.COM .close = ntfs_device_unix_io_close, 312*9663SMark.Logan@Sun.COM .seek = ntfs_device_unix_io_seek, 313*9663SMark.Logan@Sun.COM .read = ntfs_device_unix_io_read, 314*9663SMark.Logan@Sun.COM .write = ntfs_device_unix_io_write, 315*9663SMark.Logan@Sun.COM .pread = ntfs_device_unix_io_pread, 316*9663SMark.Logan@Sun.COM .pwrite = ntfs_device_unix_io_pwrite, 317*9663SMark.Logan@Sun.COM .sync = ntfs_device_unix_io_sync, 318*9663SMark.Logan@Sun.COM .stat = ntfs_device_unix_io_stat, 319*9663SMark.Logan@Sun.COM .ioctl = ntfs_device_unix_io_ioctl, 320*9663SMark.Logan@Sun.COM }; 321