I did an implementation of the truncate function.

Any comments?

--- fusesmb-0.8.5/fusesmb.c     2007-05-31 17:21:05.000000000 -0400
+++ fusesmb-0.8.5-truncate/fusesmb.c    2007-05-31 17:21:05.000000000 -0400
@@ -42,6 +42,7 @@
 #include "hash.h"
 #include "smbctx.h"
 
+#define BKSIZE 4096
 #define MY_MAXPATHLEN (MAXPATHLEN + 256)
 
 /* Mutex for locking the Samba context */
@@ -869,33 +870,219 @@
     return 0;
 }
 
+static int fusesmb_empty(const char *path)
+{
+    SMBCFILE *file;
+    pthread_mutex_lock(&ctx_mutex);
+    if (NULL == (file = ctx->creat(ctx, path, 0666)))
+    {
+        pthread_mutex_unlock(&ctx_mutex);
+        return -errno;
+    }
+#ifdef HAVE_LIBSMBCLIENT_CLOSE_FN
+    ctx->close_fn(ctx, file);
+#else
+    ctx->close(ctx, file);
+#endif
+    pthread_mutex_unlock(&ctx_mutex);
+    return 0;
+
+}
+
 static int fusesmb_truncate(const char *path, off_t size)
 {
 
     //fprintf(stderr, "TRUNCATE %s [%llu]\n", path, size);
-    char smb_path[MY_MAXPATHLEN] = "smb:/";
     if (slashcount(path) <= 3)
         return -EACCES;
 
-    SMBCFILE *file;
+    char smb_path[MY_MAXPATHLEN] = "smb:/";
     strcat(smb_path, stripworkgroup(path));
+    int nb_blocs = 0;
+    int nb_remainder = 0;
+    struct stat stbuf;
+    int i;
+    int ret = 0;
+    struct fuse_file_info fi_smb_path;
+    struct fuse_file_info fi_smb_path_tmp;
+    memset(&fi_smb_path, 0, sizeof(fi_smb_path));
+    memset(&fi_smb_path_tmp, 0, sizeof(fi_smb_path_tmp));
+
+    // If the final size is 0, empty the file
     if (size == 0)
     {
-        pthread_mutex_lock(&ctx_mutex);
-        if (NULL == (file = ctx->creat(ctx, smb_path, 0666)))
+        //fprintf(stderr, "TRUNCATE fusesmb_empty\n");
+        return fusesmb_empty(smb_path);
+    }
+
+    // Get the size of the file to see if we have to shirk or expand,
or leave it untouch
+    if ( (ret =  fusesmb_getattr(path, &stbuf)) < 0 )
+    {
+       return ret;
+    }
+  
+    // The file has the same size as the truncate operation, nothing to do
+    if ( size == stbuf.st_size )
+    {
+        //fprintf(stderr, "TRUNCATE same size, nothing to do\n");
+       return 0;
+    }
+
+    // Expanding with zeros
+    if ( size > stbuf.st_size )
+    {
+        // Chunk of memory for copying the content of the file
+        // If an error occur in the process, this memory will not be freed
+        char *mem = (char *)malloc(BKSIZE);
+
+        //fprintf(stderr, "TRUNCATE expanding\n");
+        // Compute the number of blocs to write
+       off_t offset;
+       off_t fill_length;
+        memset(mem, 0, BKSIZE);
+
+       offset = stbuf.st_size;
+        fill_length = size - stbuf.st_size;
+        nb_blocs = fill_length / BKSIZE;
+        nb_remainder = fill_length % BKSIZE;
+        fi_smb_path.flags = O_WRONLY | O_CREAT;
+
+        for(i=0; i < nb_blocs; i++)
+       {
+            fusesmb_write(smb_path, mem, BKSIZE, offset + i*BKSIZE,
&fi_smb_path);
+        }
+
+        fusesmb_write(smb_path, mem, nb_remainder, offset + i*BKSIZE,
&fi_smb_path);
+
+       free(mem);
+
+        return 0;
+    }
+
+    //fprintf(stderr, "TRUNCATE shrinking\n");
+    // Srinking
+    // The data that is keep is copied to a temp file
+    // and the content is copied back to the original file
+    // size < stbuf.st_size
+   
+    // Chunk of memory for copying the content of the file
+    // If an error occur in the process, this memory will not be freed
+    char *mem = (char *)malloc(BKSIZE);
+
+    // FIXME: Should test if the file exists, there is one chance that this
+    // file is usefull for the user.
+    char smb_path_tmp[MY_MAXPATHLEN] = "smb:/";
+    strcat(smb_path_tmp, stripworkgroup(path));
+    strcat(smb_path_tmp, ".fusesmb_tmp");
+
+    // Compute the number of blocs to copy
+    nb_blocs = size / BKSIZE;
+    nb_remainder = size % BKSIZE;
+    //printf(" nb_bloc=%d\n nb_remainder=%d \n", nb_blocs, nb_remainder);
+    //printf(" path=%s\n",path);
+
+    fi_smb_path.flags     = O_RDONLY;
+    fi_smb_path_tmp.flags = O_WRONLY | O_CREAT;
+
+    // Empty the temp file
+    if ( (ret = fusesmb_empty(smb_path_tmp)) < 0)
+    {
+        return ret;
+    }
+
+    // Copy data to keep
+    for(i=0; i < nb_blocs; i++)
+    {
+        if ( (ret = fusesmb_read(smb_path, mem, BKSIZE, i*BKSIZE,
&fi_smb_path)) < 0)
         {
-            pthread_mutex_unlock(&ctx_mutex);
-            return -errno;
+            free(mem);
+           return ret;
         }
-#ifdef HAVE_LIBSMBCLIENT_CLOSE_FN
-        ctx->close_fn(ctx, file);
-#else
-        ctx->close(ctx, file);
-#endif
+        if ( (ret = fusesmb_write(smb_path_tmp, mem, BKSIZE, i*BKSIZE,
&fi_smb_path_tmp)) < 0)
+        {
+           free(mem);
+           return ret;
+        }
+    }
+
+    if ( (ret = fusesmb_read(smb_path, mem, nb_remainder, i*BKSIZE,
&fi_smb_path)) < 0)
+    {
+        free(mem);
+        return ret;
+    }
+    if ( (ret = fusesmb_write(smb_path_tmp, mem, nb_remainder,
i*BKSIZE, &fi_smb_path_tmp)) < 0)
+    {
+        free(mem);
+        return ret;
+    }
+ 
+    // Initialise variables for the next step
+    memset(mem, 0, BKSIZE);
+    memset(&fi_smb_path, 0, sizeof(fi_smb_path));
+    memset(&fi_smb_path_tmp, 0, sizeof(fi_smb_path_tmp));
+    fi_smb_path.flags     = O_WRONLY | O_CREAT;
+    fi_smb_path_tmp.flags = O_RDONLY;
+   
+    // Empty the source file
+    if ( (ret = fusesmb_empty(smb_path)) < 0)
+    {
+        return ret;
+    }
+
+    // Copy data back
+    // Well, if there is an error here, the file will be lost.
+    for(i=0; i < nb_blocs; i++)
+    {
+        if ( (ret = fusesmb_read(smb_path_tmp, mem, BKSIZE, i*BKSIZE,
&fi_smb_path_tmp)) < 0)
+        {
+            free(mem);
+           return ret;
+        }
+        if ( (ret = fusesmb_write(smb_path, mem, BKSIZE, i*BKSIZE,
&fi_smb_path)) < 0)
+        {
+           free(mem);
+           return ret;
+        }
+    }
+
+    if ( (ret = fusesmb_read(smb_path_tmp, mem, nb_remainder, i*BKSIZE,
&fi_smb_path_tmp)) < 0)
+    {
+        free(mem);
+        return ret;
+    }
+    if ( (ret = fusesmb_write(smb_path, mem, nb_remainder, i*BKSIZE,
&fi_smb_path)) < 0)
+    {
+        free(mem);
+        return ret;
+    }
+
+    free(mem);
+/*
+ * Verify return codes
+ *
+    for(i=0; i < nb_blocs; i++)
+    {
+        fusesmb_read(smb_path_tmp, mem, BKSIZE, i*BKSIZE,
&fi_smb_path_tmp);
+        fusesmb_write(smb_path, mem, BKSIZE, i*BKSIZE, &fi_smb_path);
+    }
+
+    fusesmb_read(smb_path_tmp, mem, nb_remainder, i*BKSIZE,
&fi_smb_path_tmp);
+    fusesmb_write(smb_path, mem, nb_remainder, i*BKSIZE, &fi_smb_path);
+*/
+
+    // clean up
+    // remove temp file
+    pthread_mutex_lock(&ctx_mutex);
+    if (ctx->unlink(ctx, smb_path_tmp) < 0)
+    {
         pthread_mutex_unlock(&ctx_mutex);
-        return 0;
+        return -errno;
     }
-    return -ENOTSUP;
+    pthread_mutex_unlock(&ctx_mutex);
+
+
+    return 0;
+   
 }

-- 
Francis Giraldeau, Ing jr.
Analyste Infrastructure
Directeur Qualité
Téléphone : (819) 780-8955 poste 1111
Sans frais : 1-800-996-8955
Télécopieur : (819) 780-8871

Revolution Linux Inc.
2100 King ouest - bureau 260
Sherbrooke (Québec)
J1J 2E8 CANADA

http://www.revolutionlinux.com

Toutes les opinions et les prises de position exprimees dans ce courriel
sont celles de son auteur et ne representent pas necessairement celles
de Revolution Linux

Any views and opinions expressed in this email are solely those of the
author and do not necessarily represent those of Revolution Linux




Reply via email to