/** * 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; }
/** * 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; }
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; }
/** * 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; }
/** * 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); }
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; }
/** * 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); }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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); }
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; }
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; }
/** * 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; }