aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/bindfs.c34
-rw-r--r--src/misc.c14
-rwxr-xr-xtests/test_bindfs.rb16
3 files changed, 57 insertions, 7 deletions
diff --git a/src/bindfs.c b/src/bindfs.c
index dc8e25c..22b446e 100644
--- a/src/bindfs.c
+++ b/src/bindfs.c
@@ -1,5 +1,5 @@
/*
- Copyright 2006,2007,2008,2009,2010,2012 Martin Pärtel <martin.partel@gmail.com>
+ Copyright 2006,2007,2008,2009,2010,2012,2019 Martin Pärtel <martin.partel@gmail.com>
This file is part of bindfs.
@@ -615,7 +615,6 @@ static size_t round_up_buffer_size_for_direct_io(size_t size)
}
#endif
-
static void *bindfs_init()
{
assert(settings.permchain != NULL);
@@ -715,7 +714,6 @@ static int bindfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
}
long pc_ret = pathconf(real_path, _PC_NAME_MAX);
- free(real_path);
if (pc_ret < 0) {
DPRINTF("pathconf failed: %s (%d)", strerror(errno), errno);
pc_ret = NAME_MAX;
@@ -725,6 +723,17 @@ static int bindfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
pc_ret = NAME_MAX;
}
+ // Path buffer for resolving symlinks
+ struct memory_block resolve_buf = MEMORY_BLOCK_INITIALIZER;
+ if (settings.resolve_symlinks) {
+ int len = strlen(real_path);
+ append_to_memory_block(&resolve_buf, real_path, len + 1);
+ resolve_buf.ptr[len] = '/';
+ }
+
+ free(real_path);
+ real_path = NULL;
+
int result = 0;
while (1) {
errno = 0;
@@ -741,6 +750,21 @@ static int bindfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
st.st_ino = de->d_ino;
st.st_mode = de->d_type << 12;
+ if (settings.resolve_symlinks && (st.st_mode & S_IFLNK) == S_IFLNK) {
+ int file_len = strlen(de->d_name) + 1; // (include null terminator)
+ append_to_memory_block(&resolve_buf, de->d_name, file_len);
+ char *resolved = realpath(resolve_buf.ptr, NULL);
+ resolve_buf.size -= file_len;
+
+ if (resolved) {
+ if (lstat(resolved, &st) == -1) {
+ result = -errno;
+ break;
+ }
+ free(resolved);
+ }
+ }
+
// See issue #28 for why we pass a 0 offset to `filler` and ignore
// `offset`.
//
@@ -754,6 +778,10 @@ static int bindfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
}
}
+ if (settings.resolve_symlinks) {
+ free_memory_block(&resolve_buf);
+ }
+
closedir(dp);
return result;
}
diff --git a/src/misc.c b/src/misc.c
index eae81f0..dafebed 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -188,10 +188,16 @@ void grow_memory_block(struct memory_block *a, int amount)
a->size += amount;
if (a->size >= a->capacity) {
new_cap = a->capacity;
- if (new_cap == 0) {
- new_cap = 8;
- } else {
- new_cap *= 2;
+ while (new_cap < a->size) {
+ if (new_cap == 0) {
+ new_cap = 8;
+ } else {
+ new_cap *= 2;
+ }
+ if (new_cap < 0) { // Overflow
+ fprintf(stderr, "Memory block too large.");
+ abort();
+ }
}
a->ptr = (char *)realloc(a->ptr, new_cap);
a->capacity = new_cap;
diff --git a/tests/test_bindfs.rb b/tests/test_bindfs.rb
index bfc6d64..1a407a1 100755
--- a/tests/test_bindfs.rb
+++ b/tests/test_bindfs.rb
@@ -635,6 +635,22 @@ nonroot_testenv("--resolve-symlinks --resolved-symlink-deletion=target-first -p
end
end
+testenv("--resolve-symlinks", :title => "resolving broken symlinks") do
+ Dir.chdir 'src' do
+ symlink('dir', 'dirlink')
+ symlink('dir/file', 'filelink')
+ end
+
+ assert { File.lstat('mnt/dirlink').symlink? }
+ assert { File.lstat('mnt/filelink').symlink? }
+
+ File.unlink('mnt/filelink')
+ assert { !File.exist?('mnt/filelink') }
+
+ File.unlink('mnt/dirlink')
+ assert { !File.exist?('mnt/dirlink') }
+end
+
# Issue #28 reproduction attempt.
testenv("", :title => "many files in a directory") do
mkdir('src/dir')