SetEndOfFile fix

Guy L. Albertelli galberte at neo.lrun.com
Sat Jan 26 00:48:06 CST 2002


----- Original Message -----
From: "Rein Klazes" <rklazes at xs4all.nl>
To: <wine-patches at winehq.com>
Sent: Sunday, January 20, 2002 2:13 PM
Subject: SetEndOfFile fix


> hi,
>
> This fixes office 97 MSword error (disk full or write protected) when
> saving files on a vfat partition. MSword calls SetEndOfFile() which
> uses ftruncate() that, in Linux, cannot grow files in this filesystem.
>
> BTW. A google search shows that the ftruncate problem has been
> mentioned at least 3 times on c.e.m.w. in the last 6 months Since
> nobody entered a fix, I could be overlooking something...


This was a great catch. It was the reason Scandisk complained about
OutlookExpress's files (see my message from 1/11/2001). However your fix
still fails on my outdated kernel (2.2.12-20). The attached version seems to
work better on this kernel.

Guy
-------------- next part --------------
Index: server/file.c
===================================================================
RCS file: /home/wine/wine/server/file.c,v
retrieving revision 1.53
diff -u -r1.53 file.c
--- server/file.c	2002/01/09 20:30:52	1.53
+++ server/file.c	2002/01/26 03:38:49
@@ -456,6 +456,37 @@
     return 1;
 }
 
+/* wrapper around ftruncate:
+ * ftruncate may fail to grow the size of a file with some OS and filesystem
+ * combinations. Linux and vfat/fat is one example. If this is the case do
+ * a write to grow the file to the desired length.
+ */
+static int _ftruncate ( int fd, off_t length)
+{
+    struct stat st;
+    int ret, ret_errno;
+    char buf[1]={'\0'};
+    off_t oldoff;
+
+    ret_errno = errno;
+    if( fstat( fd, &st ) == -1) return -1;
+    if( st.st_size == length ) return 0;
+    errno = ret_errno;
+
+    /* ftruncate() shouldn't fail when requested to shrink the file */
+    if( st.st_size > length ) {
+	ret = ftruncate( fd, length);
+	return ret;
+    }
+
+    if( (oldoff = lseek( fd, 0, SEEK_CUR)) == -1) return -1;
+    if( lseek( fd, length - 1, SEEK_SET) == -1) return -1;
+    /* write one byte, filepointer is back at the orig. position. */
+    if( write( fd, &buf, 1) == -1) return -1;
+    if( lseek( fd, oldoff, SEEK_SET) == -1) return -1;
+    return 0;
+}
+
 static int truncate_file( handle_t handle )
 {
     struct file *file;
@@ -464,8 +495,9 @@
     if (!(file = get_file_obj( current->process, handle, GENERIC_WRITE )))
         return 0;
     if (((result = lseek( file->obj.fd, 0, SEEK_CUR )) == -1) ||
-        (ftruncate( file->obj.fd, result ) == -1))
+        (_ftruncate( file->obj.fd, result ) == -1))
     {
+	fprintf( stderr, "ftruncate failed\n");
         file_set_error();
         release_object( file );
         return 0;


More information about the wine-devel mailing list