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 <normalper...@yhbt.net> 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