[PATCH] fuse: Support ftruncate where requested size > current size



When ftruncate is called with a size greater than the current size
of the file, the expected behavior is that the file size increases to
the requested size, and the new space is zero-filled.  SQLite depends
on this behavior when opening a database using 'write-ahead log'
journaling.

Signed-off-by: Jeff Smith <whydoubt yahoo com>
---
On iOS 5, the SQLite database MediaLibrary.sqlite uses write-ahead
logging.  Without this patch, the only way to do anything with the
database (even to dump it) is to copy it from the iPod/iPhone to a
local filesystem, and then work with it.

 client/gvfsfusedaemon.c |   26 ++++++++++++++++----------
 1 file changed, 16 insertions(+), 10 deletions(-)

diff --git a/client/gvfsfusedaemon.c b/client/gvfsfusedaemon.c
index 8cf1c01..9f11678 100644
--- a/client/gvfsfusedaemon.c
+++ b/client/gvfsfusedaemon.c
@@ -1814,6 +1814,7 @@ vfs_rmdir (const gchar *path)
 
 static gboolean
 file_handle_get_size (FileHandle *fh,
+		      GFile *file,
 		      goffset *size)
 {
   GFileInfo *info;
@@ -1822,15 +1823,9 @@ file_handle_get_size (FileHandle *fh,
   if (fh->stream == NULL)
     return FALSE;
   
-  info = NULL;
-  if (fh->op == FILE_OP_READ)
-    info = g_file_input_stream_query_info (fh->stream,
-					   G_FILE_ATTRIBUTE_STANDARD_SIZE,
-					   NULL, NULL);
-  else if (fh->op == FILE_OP_WRITE)
-    info = g_file_output_stream_query_info (fh->stream,
-					    G_FILE_ATTRIBUTE_STANDARD_SIZE,
-					    NULL, NULL);
+  info = g_file_query_info (file,
+			    G_FILE_ATTRIBUTE_STANDARD_SIZE,
+			    0, NULL, NULL);
 
   res = FALSE;
   if (info)
@@ -1891,11 +1886,22 @@ vfs_ftruncate (const gchar *path, off_t size, struct fuse_file_info *fi)
                       fh->stream = NULL;
                     }
                 }
-              else if (file_handle_get_size (fh, &current_size) &&
+              else if (file_handle_get_size (fh, file, &current_size) &&
 		       current_size == size)
 		{
 		  /* Don't have to do anything to succeed */
 		}
+              else if ((current_size < size) && g_seekable_can_seek(G_SEEKABLE(fh->stream)))
+                {
+                  /* If the truncated size is larger than the current size
+                   * then we need to pad out the difference with 0's */
+                  goffset orig_pos = g_seekable_tell (G_SEEKABLE(fh->stream));
+                  gsize buf_size = size - current_size;
+                  gpointer buf = g_malloc0 (buf_size);
+                  write_stream (fh, buf, buf_size, current_size);
+                  g_free (buf);
+                  g_seekable_seek (G_SEEKABLE(fh->stream), orig_pos, G_SEEK_SET, NULL, NULL);
+                }
 	      else
 		{
 		  result = -ENOTSUP;
-- 
1.7.9.5



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]