示例#1
0
/**
 * ntfs_device_unix_io_open - Open a device and lock it exclusively
 * @dev:
 * @flags:
 *
 * Description...
 *
 * Returns:
 */
static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags)
{
	struct flock flk;
	struct stat sbuf;
	int err;

	if (NDevOpen(dev)) {
		errno = EBUSY;
		return -1;
	}
	if (stat(dev->d_name, &sbuf)) {
		ntfs_log_perror("Failed to access '%s'", dev->d_name);
		return -1;
	}
	if (S_ISBLK(sbuf.st_mode))
		NDevSetBlock(dev);
	
	dev->d_private = ntfs_malloc(sizeof(int));
	if (!dev->d_private)
		return -1;
	/*
	 * Open file for exclusive access if mounting r/w.
	 * Fuseblk takes care about block devices.
	 */ 
	if (!NDevBlock(dev) && (flags & O_RDWR) == O_RDWR)
		flags |= O_EXCL;
	*(int*)dev->d_private = open(dev->d_name, flags);
	if (*(int*)dev->d_private == -1) {
		err = errno;
		goto err_out;
	}
	
	if ((flags & O_RDWR) != O_RDWR)
		NDevSetReadOnly(dev);
	
	memset(&flk, 0, sizeof(flk));
	if (NDevReadOnly(dev))
		flk.l_type = F_RDLCK;
	else
		flk.l_type = F_WRLCK;
	flk.l_whence = SEEK_SET;
	flk.l_start = flk.l_len = 0LL;
	if (fcntl(DEV_FD(dev), F_SETLK, &flk)) {
		err = errno;
		ntfs_log_perror("Failed to %s lock '%s'", NDevReadOnly(dev) ? 
				"read" : "write", dev->d_name);
		if (close(DEV_FD(dev)))
			ntfs_log_perror("Failed to close '%s'", dev->d_name);
		goto err_out;
	}
	
	NDevSetOpen(dev);
	return 0;
err_out:
	free(dev->d_private);
	dev->d_private = NULL;
	errno = err;
	return -1;
}
示例#2
0
/**
 * ntfs_device_unix_io_open - Open a device and lock it exclusively
 * @dev:
 * @flags:
 *
 * Description...
 *
 * Returns:
 */
static int ntfs_device_unix_io_open(struct ntfs_device *dev, int flags)
{
	struct flock flk;
	struct stat sbuf;
	int err;

	if (NDevOpen(dev)) {
		errno = EBUSY;
		return -1;
	}
	if (!(dev->d_private = ntfs_malloc(sizeof(int))))
		return -1;
	*(int*)dev->d_private = open(dev->d_name, flags);
	if (*(int*)dev->d_private == -1) {
		err = errno;
		goto err_out;
	}
	/* Setup our read-only flag. */
	if ((flags & O_RDWR) != O_RDWR)
		NDevSetReadOnly(dev);
	/* Acquire exclusive (mandatory) lock on the whole device. */
	memset(&flk, 0, sizeof(flk));
	if (NDevReadOnly(dev))
		flk.l_type = F_RDLCK;
	else
		flk.l_type = F_WRLCK;
	flk.l_whence = SEEK_SET;
	flk.l_start = flk.l_len = 0LL;
	if (fcntl(DEV_FD(dev), F_SETLK, &flk)) {
		err = errno;
		ntfs_log_debug("ntfs_device_unix_io_open: Could not lock %s "
				"for %s\n", dev->d_name, NDevReadOnly(dev) ?
				"reading" : "writing");
		if (close(DEV_FD(dev)))
			ntfs_log_perror("ntfs_device_unix_io_open: Warning: "
					"Could not close %s", dev->d_name);
		goto err_out;
	}
	/* Determine if device is a block device or not, ignoring errors. */
	if (!fstat(DEV_FD(dev), &sbuf) && S_ISBLK(sbuf.st_mode))
		NDevSetBlock(dev);
	/* Set our open flag. */
	NDevSetOpen(dev);
	return 0;
err_out:
	free(dev->d_private);
	dev->d_private = NULL;
	errno = err;
	return -1;
}
示例#3
0
static int ntfs_device_uefi_io_sync(struct ntfs_device *dev)
{
	struct _uefi_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);
    NDevClearSync(dev);

    // Flush any sectors in the disc cache (if required)
    if (fd->cache) {
        /*if (!_NTFS_cache_flush(fd->cache)) {
            errno = EIO;
            return -1;
        }*/
		ntfs_log_trace("ntfs_device_uefi_io_sync cache enabled?!?!");
    }

    return 0;
}
示例#4
0
/**
 * ntfs_device_unix_io_sync - Flush any buffered changes to the device
 * @dev:
 *
 * Description...
 *
 * Returns:
 */
static int ntfs_device_unix_io_sync(struct ntfs_device *dev)
{
	if (!NDevReadOnly(dev) && NDevDirty(dev)) {
		int res = fsync(DEV_FD(dev));
		if (!res)
			NDevClearDirty(dev);
		return res;
	}
	return 0;
}
示例#5
0
/**
 * ntfs_device_unix_io_pwrite - Perform a positioned write to the device
 * @dev:
 * @buf:
 * @count:
 * @offset:
 *
 * Description...
 *
 * Returns:
 */
static s64 ntfs_device_unix_io_pwrite(struct ntfs_device *dev, const void *buf,
		s64 count, s64 offset)
{
	if (NDevReadOnly(dev)) {
		errno = EROFS;
		return -1;
	}
	NDevSetDirty(dev);
	return pwrite(DEV_FD(dev), buf, count, offset);
}
示例#6
0
static int ntfs_device_uefi_io_close(struct ntfs_device *dev)
{
	struct _uefi_fd *fd = DEV_FD(dev);
    ntfs_log_trace("dev %p\n", dev);

	//AsciiPrint("ntfs_device_uefi_io_close\n\r");
    // Get the device driver descriptor
    
    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;
}
示例#7
0
/**
 * ntfs_device_unix_io_sync - Flush any buffered changes to the device
 * @dev:
 *
 * Description...
 *
 * Returns:
 */
static int ntfs_device_unix_io_sync(struct ntfs_device *dev)
{
	int res = 0;
	
	if (!NDevReadOnly(dev)) {
		res = ntfs_fsync(DEV_FD(dev));
		if (res)
			ntfs_log_perror("Failed to sync device %s", dev->d_name);
		else
			NDevClearDirty(dev);
	}
	return res;
}
/**
 * ntfs_device_unix_io_pwrite - Perform a positioned write to the device
 * @dev:
 * @buf:
 * @count:
 * @offset:
 *
 * Description...
 *
 * Returns:
 */
static s64 ntfs_device_unix_io_pwrite(struct ntfs_device *dev, const void *buf,
		s64 count, s64 offset)
{
	if (NDevReadOnly(dev)) {
		errno = EROFS;
		return -1;
	}
	NDevSetDirty(dev);
	
	if (lseek64(DEV_FD(dev), offset, SEEK_SET) != offset) {
		ntfs_log_perror("seek for pwrite fail");
    }
	return write(DEV_FD(dev), buf, count);
}
示例#9
0
文件: device.c 项目: DonCN/haiku
/**
 * ntfs_pwrite - positioned write to disk
 * @dev:	device to write to
 * @pos:	position in file descriptor to write to
 * @count:	number of bytes to write
 * @b:		data buffer to write to disk
 *
 * This function will write @count bytes from data buffer @b to the device @dev
 * at position @pos.
 *
 * On success, return the number of successfully written bytes. If this number
 * is lower than @count this means that the write has been interrupted in
 * flight or that an error was encountered during the write so that the write
 * is partial. 0 means nothing was written (also return 0 when @count is 0).
 *
 * On error and nothing has been written, return -1 with errno set
 * appropriately to the return code of either seek, write, or set
 * to EINVAL in case of invalid arguments.
 */
s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
		const void *b)
{
	s64 written, total, ret = -1;
	struct ntfs_device_operations *dops;

	ntfs_log_trace("pos %lld, count %lld\n",(long long)pos,(long long)count);

	if (!b || count < 0 || pos < 0) {
		errno = EINVAL;
		goto out;
	}
	if (!count)
		return 0;
	if (NDevReadOnly(dev)) {
		errno = EROFS;
		goto out;
	}
	
	dops = dev->d_ops;

	NDevSetDirty(dev);
	for (total = 0; count; count -= written, total += written) {
		written = dops->pwrite(dev, (const char*)b + total, count,
				       pos + total);
		/* If everything ok, continue. */
		if (written > 0)
			continue;
		/*
		 * If nothing written or error return number of bytes written.
		 */
		if (!written || total)
			break;
		/* Nothing written and error, return error status. */
		total = written;
		break;
	}
	if (NDevSync(dev) && total && dops->sync(dev)) {
		total--; /* on sync error, return partially written */
	}
	ret = total;
out:	
	return ret;
}
示例#10
0
/**
 * ntfs_pwrite - positioned write to disk
 * @dev:	device to write to
 * @pos:	position in file descriptor to write to
 * @count:	number of bytes to write
 * @b:		data buffer to write to disk
 *
 * This function will write @count bytes from data buffer @b to the device @dev
 * at position @pos.
 *
 * On success, return the number of successfully written bytes. If this number
 * is lower than @count this means that the write has been interrupted in
 * flight or that an error was encountered during the write so that the write
 * is partial. 0 means nothing was written (also return 0 when @count is 0).
 *
 * On error and nothing has been written, return -1 with errno set
 * appropriately to the return code of either seek, write, or set
 * to EINVAL in case of invalid arguments.
 */
s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
		const void *b)
{
	s64 written, total;
	struct ntfs_device_operations *dops;

	ntfs_log_trace("Entering for pos 0x%llx, count 0x%llx.\n", pos, count);
	if (!b || count < 0 || pos < 0) {
		errno = EINVAL;
		return -1;
	}
	if (!count)
		return 0;
	if (NDevReadOnly(dev)) {
		errno = EROFS;
		return -1;
	}
	dops = dev->d_ops;
	/* Locate to position. */
	if (dops->seek(dev, pos, SEEK_SET) == (off_t)-1) {
		ntfs_log_perror("ntfs_pwrite: seek to 0x%llx returned error",
				pos);
		return -1;
	}
	NDevSetDirty(dev);
	/* Write the data. */
	for (total = 0; count; count -= written, total += written) {
		written = dops->write(dev, (const char*)b + total, count);
		/* If everything ok, continue. */
		if (written > 0)
			continue;
		/*
		 * If nothing written or error return number of bytes written.
		 */
		if (!written || total)
			break;
		/* Nothing written and error, return error status. */
		return written;
	}
	/* Finally, return the number of bytes written. */
	return total;
}
示例#11
0
/**
 * ntfs_device_uefi_io_pread - Perform a positioned read from the device
 * @dev:
 * @buf:
 * @count:
 * @offset:
 *
 * Description...
 *
 * Returns:
 */
static s64 ntfs_device_uefi_io_pread(struct ntfs_device *dev, void *buf,
                                     s64 count, s64 offset)
{
    EFI_DISK_IO_PROTOCOL *DiskIo;
    NTFS_VOLUME *Volume;

    Volume = (NTFS_VOLUME *) dev->d_private;

    if (NDevReadOnly(dev)) {
        errno = EROFS;
        return -1;
    }

    NDevSetDirty(dev);

    DiskIo = Volume->DiskIo;
    DiskIo->ReadDisk (DiskIo, Volume->MediaId, offset, count, buf);

    return 0;
}
示例#12
0
/**
 * ntfs_device_uefi_io_write - Write to the device, at the current location
 * @dev:
 * @buf:
 * @count:
 *
 * Description...
 *
 * Returns:
 */
static s64 ntfs_device_uefi_io_write(struct ntfs_device *dev, const void *buf,
                                     s64 count)
{
    EFI_DISK_IO_PROTOCOL *DiskIo;
    NTFS_VOLUME *Volume;

    Volume = (NTFS_VOLUME *) dev->d_private;

    if (NDevReadOnly(dev)) {
        errno = EROFS;
        return -1;
    }

    NDevSetDirty(dev);

    DiskIo = Volume->DiskIo;
    DiskIo->WriteDisk (DiskIo, Volume->MediaId, 0, count, buf);

    return 0; //write(DEV_FD(dev), buf, count);
}
示例#13
0
static int ntfs_device_uefi_io_stat(struct ntfs_device *dev, struct stat *buf)
{
	// Get the device driver descriptor
    struct _uefi_fd *fd = DEV_FD(dev);
	mode_t mode;

    ntfs_log_trace("dev %p, buf %p\n", dev, buf);

    
    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 = (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 = 0;//fd->interface->ioType;
    buf->st_ino = fd->ino;
    buf->st_mode = mode;
    buf->st_rdev = 0; //fd->interface->ioType;
    buf->st_blksize = fd->sectorSize;
    buf->st_blocks = fd->sectorCount;

    return 0;
}
示例#14
0
static s64 ntfs_device_uefi_io_writebytes(struct ntfs_device *dev, s64 offset, s64 count, const void *buf)
{
	struct _uefi_fd *fd = DEV_FD(dev);
	sec_t sec_start;
    sec_t sec_count;
    u32 buffer_offset;
    u8 *buffer;

    ntfs_log_trace("dev %p, offset %l, count %l\n", dev, offset, count);

    // Get the device driver descriptor
    
    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_start = (sec_t) fd->startSector;
    sec_count = 1;
    buffer_offset = (u32) (offset % fd->sectorSize);
    buffer = NULL;

    // Determine the range of sectors required for this write
    if (offset > 0) {
        sec_start += (sec_t) offset / fd->sectorSize;
    }
    if ((buffer_offset+count) > fd->sectorSize) {
        sec_count = (sec_t) ((buffer_offset+count) / fd->sectorSize);

		if (((buffer_offset+count) % fd->sectorSize) != 0)
			sec_count++;
    }

    // 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_uefi_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_uefi_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_uefi_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_uefi_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;
}
示例#15
0
/**
 * ntfs_pwrite - positioned write to disk
 * @dev:	device to write to
 * @pos:	position in file descriptor to write to
 * @count:	number of bytes to write
 * @b:		data buffer to write to disk
 *
 * This function will write @count bytes from data buffer @b to the device @dev
 * at position @pos.
 *
 * On success, return the number of successfully written bytes. If this number
 * is lower than @count this means that the write has been interrupted in
 * flight or that an error was encountered during the write so that the write
 * is partial. 0 means nothing was written (also return 0 when @count is 0).
 *
 * On error and nothing has been written, return -1 with errno set
 * appropriately to the return code of either seek, write, or set
 * to EINVAL in case of invalid arguments.
 */
s64 ntfs_pwrite(struct ntfs_device *dev, const s64 pos, s64 count,
		const void *b)
{
	s64 written, total;
	struct ntfs_device_operations *dops;
	s64 (*_pwrite)(struct ntfs_device *, const void *, s64, s64);

	ntfs_log_trace("Entering for pos 0x%llx, count 0x%llx.\n", pos, count);
	if (!b || count < 0 || pos < 0) {
		errno = EINVAL;
		return -1;
	}
	if (!count)
		return 0;
	if (NDevReadOnly(dev)) {
		errno = EROFS;
		return -1;
	}
	dops = dev->d_ops;
	_pwrite = dops->pwrite;
	if (!_pwrite)
		_pwrite = fake_pwrite;
seek:
	/*
	 * Locate to position if pwrite is to be emulated by seek() + write().
	 */
	if (_pwrite == fake_pwrite &&
			dops->seek(dev, pos, SEEK_SET) == (off_t)-1) {
		ntfs_log_perror("ntfs_pwrite: seek to 0x%llx returned error",
				pos);
		return -1;
	}
	NDevSetDirty(dev);
	/* Write the data. */
	for (total = 0; count; count -= written, total += written) {
		written = _pwrite(dev, (const char*)b + total, count,
				pos + total);
		/* If everything ok, continue. */
		if (written > 0)
			continue;
		/*
		 * If nothing written or error return number of bytes written.
		 */
		if (!written || total)
			break;
		/*
		 * If pwrite is not supported by the OS, fall back to emulating
		 * it by seek() + write() and set the device pwrite() pointer
		 * to NULL so we automatically use seek() + write() from now
		 * on.
		 */
		if (errno == ENOSYS && _pwrite != fake_pwrite) {
			_pwrite = fake_pwrite;
			dops->pwrite = NULL;
			goto seek;
		}
		/* Nothing written and error, return error status. */
		return written;
	}
	/* Finally, return the number of bytes written. */
	return total;
}