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);
  }
}

Reply via email to