mirror of
https://github.com/wiidev/usbloadergx.git
synced 2024-11-29 06:34:17 +01:00
64f8406b07
*updated libntfs (write fix) *updated libfat *lots of changes in the startup code, removed almost everything. This might cause problems for some drives at loading the gamelist and needs to be adjusted later but better this time. more cleanup is needed in main.cpp and will come. *using libogc sd/usb for config loading and reload to cIOS afterwards *added missing boothomebrew stuff pune forgot NOTE: From now on we will be doing a lot of revs which we won't be compiling and releasing. This revs are officially not available for public so don't making issues regarding those revs. Those will be closed right away. We need first to cleanup a lot of crap and update loader to new standards before releasing stuff again.
648 lines
17 KiB
C
648 lines
17 KiB
C
/**
|
|
* gekko_io.c - Gekko style disk io functions.
|
|
*
|
|
* Copyright (c) 2009 Rhys "Shareese" Koedijk
|
|
* Copyright (c) 2010 Dimok
|
|
*
|
|
* This program/include file is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as published
|
|
* by the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program/include file is distributed in the hope that it will be
|
|
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#ifdef HAVE_STDLIB_H
|
|
#include <stdlib.h>
|
|
#endif
|
|
#ifdef HAVE_STDIO_H
|
|
#include <stdio.h>
|
|
#endif
|
|
#ifdef HAVE_MATH_H
|
|
#include <math.h>
|
|
#endif
|
|
#ifdef HAVE_STRING_H
|
|
#include <string.h>
|
|
#endif
|
|
#ifdef HAVE_FCNTL_H
|
|
#include <fcntl.h>
|
|
#endif
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#ifdef HAVE_ERRNO_H
|
|
#include <errno.h>
|
|
#endif
|
|
#ifdef HAVE_SYS_STAT_H
|
|
#include <sys/stat.h>
|
|
#endif
|
|
#ifdef HAVE_LIMITS_H
|
|
#include <limits.h>
|
|
#endif
|
|
#ifdef HAVE_LOCALE_H
|
|
#include <locale.h>
|
|
#endif
|
|
|
|
#include "ntfs.h"
|
|
#include "types.h"
|
|
#include "logging.h"
|
|
#include "device_io.h"
|
|
#include "gekko_io.h"
|
|
#include "cache.h"
|
|
#include "device.h"
|
|
#include "bootsect.h"
|
|
|
|
#define DEV_FD(dev) ((gekko_fd *)dev->d_private)
|
|
|
|
/* Prototypes */
|
|
static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s64 count, void *buf);
|
|
static bool ntfs_device_gekko_io_readsectors(struct ntfs_device *dev, sec_t sector, sec_t numSectors, void* buffer);
|
|
static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset, s64 count, const void *buf);
|
|
static bool ntfs_device_gekko_io_writesectors(struct ntfs_device *dev, sec_t sector, sec_t numSectors, const void* buffer);
|
|
|
|
/**
|
|
*
|
|
*/
|
|
static int ntfs_device_gekko_io_open(struct ntfs_device *dev, int flags)
|
|
{
|
|
ntfs_log_trace("dev %p, flags %i\n", dev, flags);
|
|
|
|
// Get the device driver descriptor
|
|
gekko_fd *fd = DEV_FD(dev);
|
|
if (!fd) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
// Get the device interface
|
|
const DISC_INTERFACE* interface = fd->interface;
|
|
if (!interface) {
|
|
errno = ENODEV;
|
|
return -1;
|
|
}
|
|
|
|
// Start the device interface and ensure that it is inserted
|
|
if (!interface->startup()) {
|
|
ntfs_log_perror("device failed to start\n");
|
|
errno = EIO;
|
|
return -1;
|
|
}
|
|
if (!interface->isInserted()) {
|
|
ntfs_log_perror("device media is not inserted\n");
|
|
errno = EIO;
|
|
return -1;
|
|
}
|
|
|
|
// Check that the device isn't already open (used by another volume?)
|
|
if (NDevOpen(dev)) {
|
|
ntfs_log_perror("device is busy (already open)\n");
|
|
errno = EBUSY;
|
|
return -1;
|
|
}
|
|
|
|
// Check that there is a valid NTFS boot sector at the start of the device
|
|
NTFS_BOOT_SECTOR boot;
|
|
if (interface->readSectors(fd->startSector, 1, &boot)) {
|
|
if (!ntfs_boot_sector_is_ntfs(&boot)) {
|
|
errno = EINVALPART;
|
|
return -1;
|
|
}
|
|
} else {
|
|
ntfs_log_perror("read failure @ sector %d\n", fd->startSector);
|
|
errno = EIO;
|
|
return -1;
|
|
}
|
|
|
|
// Parse the boot sector
|
|
fd->hiddenSectors = le32_to_cpu(boot.bpb.hidden_sectors);
|
|
fd->sectorSize = le16_to_cpu(boot.bpb.bytes_per_sector);
|
|
fd->sectorCount = sle64_to_cpu(boot.number_of_sectors);
|
|
fd->pos = 0;
|
|
fd->len = (fd->sectorCount * fd->sectorSize);
|
|
fd->ino = le64_to_cpu(boot.volume_serial_number);
|
|
|
|
// Mark the device as read-only (if required)
|
|
if (flags & O_RDONLY) {
|
|
NDevSetReadOnly(dev);
|
|
}
|
|
|
|
// Create the cache
|
|
fd->cache = _NTFS_cache_constructor(fd->cachePageCount, fd->cachePageSize, interface, fd->startSector + fd->sectorCount, fd->sectorSize);
|
|
|
|
// Mark the device as open
|
|
NDevSetBlock(dev);
|
|
NDevSetOpen(dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
static int ntfs_device_gekko_io_close(struct ntfs_device *dev)
|
|
{
|
|
ntfs_log_trace("dev %p\n", dev);
|
|
|
|
// Get the device driver descriptor
|
|
gekko_fd *fd = DEV_FD(dev);
|
|
if (!fd) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
// Check that the device is actually open
|
|
if (!NDevOpen(dev)) {
|
|
ntfs_log_perror("device is not open\n");
|
|
errno = EIO;
|
|
return -1;
|
|
}
|
|
|
|
// Mark the device as closed
|
|
NDevClearOpen(dev);
|
|
NDevClearBlock(dev);
|
|
|
|
// Flush the device (if dirty and not read-only)
|
|
if (NDevDirty(dev) && !NDevReadOnly(dev)) {
|
|
ntfs_log_debug("device is dirty, will now sync\n");
|
|
|
|
// ...?
|
|
|
|
// Mark the device as clean
|
|
NDevClearDirty(dev);
|
|
|
|
}
|
|
|
|
// Flush and destroy the cache (if required)
|
|
if (fd->cache) {
|
|
_NTFS_cache_flush(fd->cache);
|
|
_NTFS_cache_destructor(fd->cache);
|
|
}
|
|
|
|
// Shutdown the device interface
|
|
/*const DISC_INTERFACE* interface = fd->interface;
|
|
if (interface) {
|
|
interface->shutdown();
|
|
}*/
|
|
|
|
// Free the device driver private data
|
|
ntfs_free(dev->d_private);
|
|
dev->d_private = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
static s64 ntfs_device_gekko_io_seek(struct ntfs_device *dev, s64 offset, int whence)
|
|
{
|
|
ntfs_log_trace("dev %p, offset %Li, whence %i\n", dev, offset, whence);
|
|
|
|
// Get the device driver descriptor
|
|
gekko_fd *fd = DEV_FD(dev);
|
|
if (!fd) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
// Set the current position on the device (in bytes)
|
|
switch(whence) {
|
|
case SEEK_SET: fd->pos = MIN(MAX(offset, 0), fd->len); break;
|
|
case SEEK_CUR: fd->pos = MIN(MAX(fd->pos + offset, 0), fd->len); break;
|
|
case SEEK_END: fd->pos = MIN(MAX(fd->len + offset, 0), fd->len); break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
static s64 ntfs_device_gekko_io_read(struct ntfs_device *dev, void *buf, s64 count)
|
|
{
|
|
return ntfs_device_gekko_io_readbytes(dev, DEV_FD(dev)->pos, count, buf);
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
static s64 ntfs_device_gekko_io_write(struct ntfs_device *dev, const void *buf, s64 count)
|
|
{
|
|
return ntfs_device_gekko_io_writebytes(dev, DEV_FD(dev)->pos, count, buf);
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
static s64 ntfs_device_gekko_io_pread(struct ntfs_device *dev, void *buf, s64 count, s64 offset)
|
|
{
|
|
return ntfs_device_gekko_io_readbytes(dev, offset, count, buf);
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
static s64 ntfs_device_gekko_io_pwrite(struct ntfs_device *dev, const void *buf, s64 count, s64 offset)
|
|
{
|
|
return ntfs_device_gekko_io_writebytes(dev, offset, count, buf);
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
static s64 ntfs_device_gekko_io_readbytes(struct ntfs_device *dev, s64 offset, s64 count, void *buf)
|
|
{
|
|
ntfs_log_trace("dev %p, offset %Li, count %Li\n", dev, offset, count);
|
|
|
|
// Get the device driver descriptor
|
|
gekko_fd *fd = DEV_FD(dev);
|
|
if (!fd) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
// Get the device interface
|
|
const DISC_INTERFACE* interface = fd->interface;
|
|
if (!interface) {
|
|
errno = ENODEV;
|
|
return -1;
|
|
}
|
|
|
|
if(offset < 0)
|
|
{
|
|
errno = EROFS;
|
|
return -1;
|
|
}
|
|
|
|
if(!count)
|
|
return 0;
|
|
|
|
sec_t sec_start = (sec_t) fd->startSector;
|
|
sec_t sec_count = 1;
|
|
u32 buffer_offset = (u32) (offset % fd->sectorSize);
|
|
u8 *buffer = NULL;
|
|
|
|
// Determine the range of sectors required for this read
|
|
if (offset > 0) {
|
|
sec_start += (sec_t) floor((f64) offset / (f64) fd->sectorSize);
|
|
}
|
|
if (buffer_offset+count > fd->sectorSize) {
|
|
sec_count = (sec_t) ceil((f64) (buffer_offset+count) / (f64) fd->sectorSize);
|
|
}
|
|
|
|
// If this read happens to be on the sector boundaries then do the read straight into the destination buffer
|
|
|
|
if((buffer_offset == 0) && (count % fd->sectorSize == 0)) {
|
|
|
|
// Read from the device
|
|
ntfs_log_trace("direct read from sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
|
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buf)) {
|
|
ntfs_log_perror("direct read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
|
errno = EIO;
|
|
return -1;
|
|
}
|
|
|
|
// Else read into a buffer and copy over only what was requested
|
|
}
|
|
else
|
|
{
|
|
|
|
// Allocate a buffer to hold the read data
|
|
buffer = (u8*)ntfs_alloc(sec_count * fd->sectorSize);
|
|
if (!buffer) {
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
|
|
// Read from the device
|
|
ntfs_log_trace("buffered read from sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
|
ntfs_log_trace("count: %d sec_count:%d fd->sectorSize: %d )\n", (u32)count, (u32)sec_count,(u32)fd->sectorSize);
|
|
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, sec_count, buffer)) {
|
|
ntfs_log_perror("buffered read failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
|
ntfs_free(buffer);
|
|
errno = EIO;
|
|
return -1;
|
|
}
|
|
|
|
// Copy what was requested to the destination buffer
|
|
memcpy(buf, buffer + buffer_offset, count);
|
|
ntfs_free(buffer);
|
|
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
static s64 ntfs_device_gekko_io_writebytes(struct ntfs_device *dev, s64 offset, s64 count, const void *buf)
|
|
{
|
|
ntfs_log_trace("dev %p, offset %lli, count %lli\n", dev, offset, count);
|
|
|
|
// Get the device driver descriptor
|
|
gekko_fd *fd = DEV_FD(dev);
|
|
if (!fd) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
// Get the device interface
|
|
const DISC_INTERFACE* interface = fd->interface;
|
|
if (!interface) {
|
|
errno = ENODEV;
|
|
return -1;
|
|
}
|
|
|
|
// Check that the device can be written to
|
|
if (NDevReadOnly(dev)) {
|
|
errno = EROFS;
|
|
return -1;
|
|
}
|
|
|
|
if(count < 0 || offset < 0) {
|
|
errno = EROFS;
|
|
return -1;
|
|
}
|
|
|
|
if(count == 0)
|
|
return 0;
|
|
|
|
sec_t sec_start = (sec_t) fd->startSector;
|
|
sec_t sec_count = 1;
|
|
u32 buffer_offset = (u32) (offset % fd->sectorSize);
|
|
u8 *buffer = NULL;
|
|
|
|
// Determine the range of sectors required for this write
|
|
if (offset > 0) {
|
|
sec_start += (sec_t) floor((f64) offset / (f64) fd->sectorSize);
|
|
}
|
|
if ((buffer_offset+count) > fd->sectorSize) {
|
|
sec_count = (sec_t) ceil((f64) (buffer_offset+count) / (f64) fd->sectorSize);
|
|
}
|
|
|
|
// If this write happens to be on the sector boundaries then do the write straight to disc
|
|
if((buffer_offset == 0) && (count % fd->sectorSize == 0))
|
|
{
|
|
// Write to the device
|
|
ntfs_log_trace("direct write to sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
|
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buf)) {
|
|
ntfs_log_perror("direct write failure @ sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
|
errno = EIO;
|
|
return -1;
|
|
}
|
|
// Else write from a buffer aligned to the sector boundaries
|
|
}
|
|
else
|
|
{
|
|
// Allocate a buffer to hold the write data
|
|
buffer = (u8 *) ntfs_alloc(sec_count * fd->sectorSize);
|
|
if (!buffer) {
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
// Read the first and last sectors of the buffer from disc (if required)
|
|
// NOTE: This is done because the data does not line up with the sector boundaries,
|
|
// we just read in the buffer edges where the data overlaps with the rest of the disc
|
|
if(buffer_offset != 0)
|
|
{
|
|
if (!ntfs_device_gekko_io_readsectors(dev, sec_start, 1, buffer)) {
|
|
ntfs_log_perror("read failure @ sector %d\n", sec_start);
|
|
ntfs_free(buffer);
|
|
errno = EIO;
|
|
return -1;
|
|
}
|
|
}
|
|
if((buffer_offset+count) % fd->sectorSize != 0)
|
|
{
|
|
if (!ntfs_device_gekko_io_readsectors(dev, sec_start + sec_count - 1, 1, buffer + ((sec_count-1) * fd->sectorSize))) {
|
|
ntfs_log_perror("read failure @ sector %d\n", sec_start + sec_count - 1);
|
|
ntfs_free(buffer);
|
|
errno = EIO;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
// Copy the data into the write buffer
|
|
memcpy(buffer + buffer_offset, buf, count);
|
|
|
|
// Write to the device
|
|
ntfs_log_trace("buffered write to sector %d (%d sector(s) long)\n", sec_start, sec_count);
|
|
if (!ntfs_device_gekko_io_writesectors(dev, sec_start, sec_count, buffer)) {
|
|
ntfs_log_perror("buffered write failure @ sector %d\n", sec_start);
|
|
ntfs_free(buffer);
|
|
errno = EIO;
|
|
return -1;
|
|
}
|
|
|
|
// Free the buffer
|
|
ntfs_free(buffer);
|
|
}
|
|
|
|
// Mark the device as dirty (if we actually wrote anything)
|
|
NDevSetDirty(dev);
|
|
|
|
return count;
|
|
}
|
|
|
|
static bool ntfs_device_gekko_io_readsectors(struct ntfs_device *dev, sec_t sector, sec_t numSectors, void* buffer)
|
|
{
|
|
// Get the device driver descriptor
|
|
gekko_fd *fd = DEV_FD(dev);
|
|
if (!fd) {
|
|
errno = EBADF;
|
|
return false;
|
|
}
|
|
// Read the sectors from disc (or cache, if enabled)
|
|
if (fd->cache)
|
|
return _NTFS_cache_readSectors(fd->cache, sector, numSectors, buffer);
|
|
else
|
|
return fd->interface->readSectors(sector, numSectors, buffer);
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool ntfs_device_gekko_io_writesectors(struct ntfs_device *dev, sec_t sector, sec_t numSectors, const void* buffer)
|
|
{
|
|
// Get the device driver descriptor
|
|
gekko_fd *fd = DEV_FD(dev);
|
|
if (!fd) {
|
|
errno = EBADF;
|
|
return false;
|
|
}
|
|
|
|
// Write the sectors to disc (or cache, if enabled)
|
|
if (fd->cache)
|
|
return _NTFS_cache_writeSectors(fd->cache, sector, numSectors, buffer);
|
|
else
|
|
return fd->interface->writeSectors(sector, numSectors, buffer);
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
static int ntfs_device_gekko_io_sync(struct ntfs_device *dev)
|
|
{
|
|
gekko_fd *fd = DEV_FD(dev);
|
|
ntfs_log_trace("dev %p\n", dev);
|
|
|
|
// Check that the device can be written to
|
|
if (NDevReadOnly(dev)) {
|
|
errno = EROFS;
|
|
return -1;
|
|
}
|
|
|
|
// Mark the device as clean
|
|
NDevClearDirty(dev);
|
|
|
|
// Flush any sectors in the disc cache (if required)
|
|
if (fd->cache) {
|
|
if (!_NTFS_cache_flush(fd->cache)) {
|
|
errno = EIO;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
static int ntfs_device_gekko_io_stat(struct ntfs_device *dev, struct stat *buf)
|
|
{
|
|
ntfs_log_trace("dev %p, buf %p\n", dev, buf);
|
|
|
|
// Get the device driver descriptor
|
|
gekko_fd *fd = DEV_FD(dev);
|
|
if (!fd) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
// Short circuit cases were we don't actually have to do anything
|
|
if (!buf)
|
|
return 0;
|
|
|
|
// Build the device mode
|
|
mode_t mode = (S_IFBLK) |
|
|
(S_IRUSR | S_IRGRP | S_IROTH) |
|
|
((!NDevReadOnly(dev)) ? (S_IWUSR | S_IWGRP | S_IWOTH) : 0);
|
|
|
|
// Zero out the stat buffer
|
|
memset(buf, 0, sizeof(struct stat));
|
|
|
|
// Build the device stats
|
|
buf->st_dev = fd->interface->ioType;
|
|
buf->st_ino = fd->ino;
|
|
buf->st_mode = mode;
|
|
buf->st_rdev = fd->interface->ioType;
|
|
buf->st_blksize = fd->sectorSize;
|
|
buf->st_blocks = fd->sectorCount;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
static int ntfs_device_gekko_io_ioctl(struct ntfs_device *dev, int request, void *argp)
|
|
{
|
|
ntfs_log_trace("dev %p, request %i, argp %p\n", dev, request, argp);
|
|
|
|
// Get the device driver descriptor
|
|
gekko_fd *fd = DEV_FD(dev);
|
|
if (!fd) {
|
|
errno = EBADF;
|
|
return -1;
|
|
}
|
|
|
|
// Figure out which i/o control was requested
|
|
switch (request) {
|
|
|
|
// Get block device size (sectors)
|
|
#if defined(BLKGETSIZE)
|
|
case BLKGETSIZE: {
|
|
*(u32*)argp = fd->sectorCount;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
// Get block device size (bytes)
|
|
#if defined(BLKGETSIZE64)
|
|
case BLKGETSIZE64: {
|
|
*(u64*)argp = (fd->sectorCount * fd->sectorSize);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
// Get hard drive geometry
|
|
#if defined(HDIO_GETGEO)
|
|
case HDIO_GETGEO: {
|
|
struct hd_geometry *geo = (struct hd_geometry*)argp;
|
|
geo->sectors = 0;
|
|
geo->heads = 0;
|
|
geo->cylinders = 0;
|
|
geo->start = fd->hiddenSectors;
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
// Get block device sector size (bytes)
|
|
#if defined(BLKSSZGET)
|
|
case BLKSSZGET: {
|
|
*(int*)argp = fd->sectorSize;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
// Set block device block size (bytes)
|
|
#if defined(BLKBSZSET)
|
|
case BLKBSZSET: {
|
|
int sectorSize = *(int*)argp;
|
|
fd->sectorSize = sectorSize;
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
// Unimplemented ioctrl
|
|
default: {
|
|
ntfs_log_perror("Unimplemented ioctrl %i\n", request);
|
|
errno = EOPNOTSUPP;
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Device operations for working with gekko style devices and files.
|
|
*/
|
|
struct ntfs_device_operations ntfs_device_gekko_io_ops = {
|
|
.open = ntfs_device_gekko_io_open,
|
|
.close = ntfs_device_gekko_io_close,
|
|
.seek = ntfs_device_gekko_io_seek,
|
|
.read = ntfs_device_gekko_io_read,
|
|
.write = ntfs_device_gekko_io_write,
|
|
.pread = ntfs_device_gekko_io_pread,
|
|
.pwrite = ntfs_device_gekko_io_pwrite,
|
|
.sync = ntfs_device_gekko_io_sync,
|
|
.stat = ntfs_device_gekko_io_stat,
|
|
.ioctl = ntfs_device_gekko_io_ioctl,
|
|
};
|