Package: gvfs-fuse
Version: 1.12.3-1+b1
Severity: critical
Tags: upstream
Justification: causes serious data loss
Dear Maintainer,
* What led up to the situation?
After some of my files got truncated at 4096 bytes when saved in leafpad
over agvfs sftp mount, I did some debug, and found that the bug was
apparently in gvfs fuse sftp module.
* What exactly did you do that was effective?
I wrote a small C soft that could reproduce the bug when trying to write a 5k
txt file over the sftp gvfs mount :
- Mount a sftp location with gvfs : gvfs-mount "sftp://${USER}@localhost"
- compile and run the small piece of software :
- The fwrite() posix call returns a number of bytes of the expected len,
- But the gvfs layer buffers it and does not write the totality of the data
immediatly,
- The software opens the same file in append mode, and that seems to
invalidate the subsequent write calls of the gvfs layer.
- As a result the text file is truncated at 4kbyte on the remote disk
* What outcome did you expect instead?
the text file should weight 5kbyte as "gfvs-fuse also supports exposing the
gvfs mounts to non-gio applications using fuse. "
The bug with leafpad + sftp + gvfs also exist in ubuntu as I found bug report
on launchpad, so it's probably upstream.
I joined the commented C code of my debug case.
I hope it can help a little, and I apologise for my bad English.
Thank you for reading this.
-- System Information:
Debian Release: wheezy/sid
APT prefers testing
APT policy: (550, 'testing'), (550, 'stable'), (500,
'stable-updates'), (500, 'proposed-updates'), (33, 'unstable')
Architecture: amd64 (x86_64)
Kernel: Linux 3.2.0-2-amd64 (SMP w/2 CPU cores)
Locale: LANG=fr_FR.UTF-8, LC_CTYPE=fr_FR.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Versions of packages gvfs-fuse depends on:
ii fuse 2.9.0-2
ii gvfs 1.12.3-1+b1
ii libc6 2.13-33
ii libdbus-1-3 1.6.0-1
ii libfuse2 2.9.0-2
ii libglib2.0-0 2.32.3-1
gvfs-fuse recommends no packages.
gvfs-fuse suggests no packages.
-- no debconf information
/// Filename : write5kfile.c
/// Compile with :
/// gcc `pkg-config --cflags glib-2.0 gtk+-2.0` `pkg-config --libs glib-2.0 gtk+-2.0` write5kfile.c -o write5kfile
#include <gtk/gtk.h>
#include <stdio.h>
#include <string.h>
/// Functions adapted from original leafpad source code
gboolean check_file_writable(gchar *filename)
{
FILE *fp;
if ((fp = fopen(filename, "a")) != NULL) {
fclose(fp);
return TRUE;
}
return FALSE;
}
int save(char* filename)
{
FILE *fp;
gchar *str, *cstr;
gsize len;
gsize written;
/// We want to write this 5k of text
str = g_strnfill(5 * 1024, '*');
len = strlen(str);
fp = fopen(filename, "w");
if (!fp) {
printf("Can't open file to write\n");
return -1;
}
written = fwrite(str, 1, len, fp);
/// The call to fwrite returns written == len == 5120
/// But at first the underlaying gvfs mount only write 4096 bytes :
// [ 7f6343c62500] open("~/.gvfs/${mounted_ssh_dir}/tmp/5k.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
// [ 7f6343c62750] write(3, "********************************"..., 4096) = 4096
/// The soft then open the same file in append mode before the file is closed
/// (indirectly caused by gtk_text_buffer_set_modified(buffer, FALSE); in original leafpad)
check_file_writable(filename);
// [ 7f6343c62500] open("~/.gvfs/${mounted_ssh_dir}/tmp/5k.txt", O_WRONLY|O_CREAT|O_APPEND, 0666) = 4
// [ 7f6343c62690] close(4) = 0
/// Then the underlaying gvfs mount try to write the remaining 1024 bytes, but fails !
// [ 7f6343c62750] write(3, "********************************"..., 1024) = -1 EOPNOTSUPP (Operation not supported)
// [ 7f6343c62690] close(3) = 0
/// The file is then closed
fclose(fp);
g_free(str);
printf("written=%d, expected=%d\n", written, len);
/// As expected the software think all was correctly written
// [ 7f6343c62750] write(1, "written=5120, expected=5120\n", 28written=5120, expected=5120
if (written != len) {
printf("Can't write file\n");
return -1;
}
return 0;
}
int main(int argc, char *argv[])
{
if(argc != 2){
printf("How to use :\n");
printf(" * First mount a sftp with gvfs : \n");
printf(" gvfs-mount \"sftp://${USER}@localhost\"\n");
printf(" * Then run the soft (optionaly with strace) :\n");
printf(" strace -i -e trace=write,open,stat,read,close,signal \\\n");
printf(" %s ~/.gvfs/your_mounted_ssh_dir/tmp/5k.txt\n", argv[0]);
}
else {
char* filename = argv[1];
save(filename);
}
}