Package: fusedav
Version: 0.2-3
Severity: normal
Tags: upstream patch
[PATCH] fix truncate (it was completely broken)
dav_truncate(): add braces to prevent early exit,
previously all calls to dav_truncate() were no-ops
file_cache_truncate(): set the fi->modified flag to ensure
file_cache_sync_unlocked() picks up the change.
Additionally, we need to update the fi->present offset
as we no longer have the truncated data cached.
load_up_to_unlocked(): limit retrieval to fi->length. If we
truncate a file locally, we don't want to reload the data on the
server, instead we want to leave holes in the file if we write
beyond the truncation point.
I used the following Ruby test script to test this behavior.
---------------------------- 8< ----------------------------
require 'test/unit'
class TestTruncate < Test::Unit::TestCase
# Ideally this directory should be mounted with the auto_cache
# FUSE mount option
TEST_DIR = ENV["TEST_DIR"] or abort "TEST_DIR env needs to be set"
def test_truncate
Dir.chdir(TEST_DIR) do
File.open("truncate", "w") do |f|
f.write("HELLO WORLD")
end
assert system("sync") # try to work around lack of auto_cache
File.open("truncate", "r+") do |f|
f.sync = true
f.truncate(0)
f.seek(5)
f.write "!"
end
assert system("sync") # try to work around lack of auto_cache
assert_equal "\0\0\0\0\0!", File.read("truncate")
end
end
end
---------------------------- 8< ----------------------------
Usage: TEST_DIR=/path/to/fusedav/mount ruby /path/to/this_script.rb
>From d4b6e7b53634ac2577e64325ffadba2530bb98b8 Mon Sep 17 00:00:00 2001
From: Eric Wong <[email protected]>
Date: Thu, 25 Oct 2012 19:10:42 +0000
Subject: [PATCH 10/13] fix truncate (it was completely broken)
dav_truncate(): add braces to prevent early exit,
previously all calls to dav_truncate() were no-ops
file_cache_truncate(): set the fi->modified flag to ensure
file_cache_sync_unlocked() picks up the change.
Additionally, we need to update the fi->present offset
as we no longer have the truncated data cached.
load_up_to_unlocked(): limit retrieval to fi->length. If we
truncate a file locally, we don't want to reload the data on the
server, instead we want to leave holes in the file if we write
beyond the truncation point.
I used the following Ruby test script to test this behavior.
---------------------------- 8< ----------------------------
require 'test/unit'
class TestTruncate < Test::Unit::TestCase
# Ideally this directory should be mounted with the auto_cache
# FUSE mount option
TEST_DIR = ENV["TEST_DIR"] or abort "TEST_DIR env needs to be set"
def test_truncate
Dir.chdir(TEST_DIR) do
File.open("truncate", "w") do |f|
f.write("HELLO WORLD")
end
assert system("sync") # try to work around lack of auto_cache
File.open("truncate", "r+") do |f|
f.sync = true
f.truncate(0)
f.seek(5)
f.write "!"
end
assert system("sync") # try to work around lack of auto_cache
assert_equal "\0\0\0\0\0!", File.read("truncate")
end
end
end
---------------------------- 8< ----------------------------
Usage: TEST_DIR=/path/to/fusedav/mount ruby /path/to/this_script.rb
---
src/filecache.c | 6 ++++++
src/fusedav.c | 3 ++-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/filecache.c b/src/filecache.c
index 08071fe..f9b4075 100644
--- a/src/filecache.c
+++ b/src/filecache.c
@@ -265,6 +265,9 @@ static int load_up_to_unlocked(struct file_info *fi, off_t
l) {
return -1;
}
+ if (l > fi->length)
+ l = fi->length;
+
if (l > fi->server_length)
l = fi->server_length;
@@ -353,6 +356,9 @@ int file_cache_truncate(void *f, off_t s) {
fi->length = s;
r = ftruncate(fi->fd, fi->length);
+ fi->modified = 1;
+ if (fi->present > s)
+ fi->present = s;
pthread_mutex_unlock(&fi->mutex);
diff --git a/src/fusedav.c b/src/fusedav.c
index 4c95ea3..6a92799 100644
--- a/src/fusedav.c
+++ b/src/fusedav.c
@@ -710,9 +710,10 @@ static int dav_truncate(const char *path, off_t size) {
if (debug)
fprintf(stderr, "truncate(%s, %lu)\n", path, (unsigned long) size);
- if (!(session = session_get(1)))
+ if (!(session = session_get(1))) {
r = -EIO;
goto finish;
+ }
if (!(f = file_cache_get(path))) {
fprintf(stderr, "truncate() called for closed file\n");
--
1.8.0.3.gdd57fab.dirty