diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | src/bindfs.1 | 4 | ||||
-rw-r--r-- | src/bindfs.c | 43 | ||||
-rwxr-xr-x | tests/test_block_devices_as_files.rb | 55 |
4 files changed, 104 insertions, 2 deletions
@@ -1,3 +1,7 @@ +2017-04-19 Martin Pärtel <martin dot partel at gmail dot com> + + * Added --block-devices-as-files (issue #53). + 2017-03-14 Martin Pärtel <martin dot partel at gmail dot com> * Added Vagrantfile for FreeBSD 10.3 and fixed build and test suite to diff --git a/src/bindfs.1 b/src/bindfs.1 index e458ecf..2f73d3d 100644 --- a/src/bindfs.1 +++ b/src/bindfs.1 @@ -277,6 +277,10 @@ only if deleting the target succeeded). The default is \fBsymlink-only\fP. Note that deleting files inside symlinked directories is always possible with all settings, including \fBdeny\fP, unless something else protects those files. +.TP +.B \-\-block\-devices\-as\-files, \-o block\-devices\-as\-files +Shows block devices as regular files. + .SH MISCELLANEOUS OPTIONS diff --git a/src/bindfs.c b/src/bindfs.c index cf681dd..f6bbbe4 100644 --- a/src/bindfs.c +++ b/src/bindfs.c @@ -72,6 +72,10 @@ #include <sys/xattr.h> #endif +#ifdef __LINUX__ +#include <linux/fs.h> // For BLKGETSIZE64 +#endif + #include <fuse.h> #include <fuse_opt.h> @@ -164,6 +168,8 @@ static struct Settings { int hide_hard_links; int resolve_symlinks; + int block_devices_as_files; + enum ResolvedSymlinkDeletion { RESOLVED_SYMLINK_DELETION_DENY, RESOLVED_SYMLINK_DELETION_SYMLINK_ONLY, @@ -365,8 +371,34 @@ static int getattr_common(const char *procpath, struct stat *stbuf) } /* Hide hard links */ - if (settings.hide_hard_links) + if (settings.hide_hard_links) { stbuf->st_nlink = 1; + } + + /* Block files as regular files. */ + if (settings.block_devices_as_files && S_ISBLK(stbuf->st_mode)) { + stbuf->st_mode ^= S_IFBLK | S_IFREG; // Flip both bits +#ifdef __LINUX__ + uint64_t size; + ioctl(file, BLKGETSIZE64, &size); + stbuf->st_size = (off_t)size; + if (stbuf->st_size < 0) { // Underflow + return -EOVERFLOW; + } +#else + int fd = open(procpath, O_RDONLY); + if (fd == -1) { + return -errno; + } + off_t size = lseek(fd, 0, SEEK_END); + if (size == (off_t)-1) { + close(fd); + return -errno; + } + stbuf->st_size = size; + close(fd); +#endif + } /* Then permission bits. Symlink permissions don't matter, though. */ if ((stbuf->st_mode & S_IFLNK) != S_IFLNK) { @@ -1436,6 +1468,7 @@ static void print_usage(const char *progname) " --hide-hard-links Always report a hard link count of 1.\n" " --resolve-symlinks Resolve symbolic links.\n" " --resolved-symlink-deletion=... Decide how to delete resolved symlinks.\n" + " --block-devices-as-files Show block devices as regular files.\n" " --multithreaded Enable multithreaded mode. See man page\n" " for security issue with current implementation.\n" "\n" @@ -1477,7 +1510,8 @@ enum OptionKey { OPTKEY_DISABLE_LOCK_FORWARDING, OPTKEY_ENABLE_IOCTL, OPTKEY_HIDE_HARD_LINKS, - OPTKEY_RESOLVE_SYMLINKS + OPTKEY_RESOLVE_SYMLINKS, + OPTKEY_BLOCK_DEVICES_AS_FILES }; static int process_option(void *data, const char *arg, int key, @@ -1570,6 +1604,9 @@ static int process_option(void *data, const char *arg, int key, case OPTKEY_RESOLVE_SYMLINKS: settings.resolve_symlinks = 1; return 0; + case OPTKEY_BLOCK_DEVICES_AS_FILES: + settings.block_devices_as_files = 1; + return 0; case OPTKEY_NONOPTION: if (!settings.mntsrc) { @@ -1901,6 +1938,7 @@ int main(int argc, char *argv[]) OPT2("--hide-hard-links", "hide-hard-links", OPTKEY_HIDE_HARD_LINKS), OPT2("--resolve-symlinks", "resolve-symlinks", OPTKEY_RESOLVE_SYMLINKS), OPT_OFFSET2("--resolved-symlink-deletion=%s", "resolved-symlink-deletion=%s", resolved_symlink_deletion, -1), + OPT2("--block-devices-as-files", "block-devices-as-files", OPTKEY_BLOCK_DEVICES_AS_FILES), OPT2("--realistic-permissions", "realistic-permissions", OPTKEY_REALISTIC_PERMISSIONS), OPT2("--ctime-from-mtime", "ctime-from-mtime", OPTKEY_CTIME_FROM_MTIME), @@ -1949,6 +1987,7 @@ int main(int argc, char *argv[]) settings.hide_hard_links = 0; settings.resolve_symlinks = 0; settings.resolved_symlink_deletion_policy = RESOLVED_SYMLINK_DELETION_SYMLINK_ONLY; + settings.block_devices_as_files = 0; settings.realistic_permissions = 0; settings.ctime_from_mtime = 0; settings.enable_lock_forwarding = 0; diff --git a/tests/test_block_devices_as_files.rb b/tests/test_block_devices_as_files.rb new file mode 100755 index 0000000..29a81ee --- /dev/null +++ b/tests/test_block_devices_as_files.rb @@ -0,0 +1,55 @@ +#!/usr/bin/env ruby +# +# Copyright 2006,2007,2008,2009,2010 Martin Pärtel <martin.partel@gmail.com> +# +# This file is part of bindfs. +# +# bindfs 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. +# +# bindfs 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 bindfs. If not, see <http://www.gnu.org/licenses/>. +# + +# if we are being run by make check it will set srcdir and we should use it +$LOAD_PATH << (ENV['srcdir'] || '.') +require 'common.rb' + +raise "Please run this as root" unless Process.uid == 0 + +if ARGV.include?("-h") || ARGV.include?("--help") || ARGV.length != 1 + puts + puts "Usage: #{$0} /dev/some-block-device" + puts + puts "This test will attempt to read the block device through bindfs." + puts "This is a separate test file because it's nontrivial to set up a" + puts "block device for testing in a non-intrusive and portable way." + puts + exit(1) +end + +device = ARGV[0] + +root_testenv("--block-devices-as-files --resolve-symlinks") do + symlink(device, 'src/devicelink') + + size_through_bindfs = File.size('mnt/devicelink') + measured_size = File.open(device, "r") do |f| + f.seek(0, IO::SEEK_END) + f.tell + end + assert { size_through_bindfs == measured_size } + assert { measured_size >= 512 } + puts "Device size: #{size_through_bindfs}" + + data_read_through_bindfs = File.read('mnt/devicelink', 512) + data_read_directly= File.read(device, 512) + assert { data_read_through_bindfs == data_read_directly } +end |