Package: curlftpfs
Version: 0.9.2-9+b1

Hi!

I'm using curlftpfs to backup data off a FTP server. Works mostly,
but it breaks with an I/O error for a directory containins a
single ' ' (space) in its name.

  Seems this bug is known upstream. The `curl` people claim that
curlftpfs supplies a wrong URL
(https://github.com/curl/curl/issues/7621), while a matching bug
report exists for curlftpfs on the SF.net site
(https://sourceforge.net/p/curlftpfs/bugs/74/). While curlftpfs is
_really_ a useful piece of software, it's mostly mature and it seems
there isn't done a whole lot of maintenance these days. Maybe we'd
like to fix this for Debian? I guess it's not even a hard fix...

  There is actually already a fix for a similar issue in
https://github.com/JackSlateur/curlftpfs/commit/85f3a9ef2accb1093f28c424c72068a06182d6f9
where the author seems to have had issues with '%' and "#".

  This is an adopted version, additionally incorporating the space
character (though no other: an useful extension might be stuff like
TABs or '?' or '+' ...)  It's in the "Works for me[tm]" state.

--- ftpfs.c~bak 2022-06-07 12:47:17.662097505 +0200
+++ ftpfs.c     2022-06-07 13:37:03.054256599 +0200
@@ -208,6 +208,54 @@
   ftpfs.attached_to_multi = 0;  
 }
 
+// Code from stackoverflow
+static char *replace (char const * const original, char const * const pattern, 
char const * const replacement) {
+  size_t const replen = strlen(replacement);
+  size_t const patlen = strlen(pattern);
+  size_t const orilen = strlen(original);
+  size_t patcnt = 0;
+  const char *oriptr;
+  const char *patloc;
+
+  // find how many times the pattern occurs in the original string
+  for (oriptr = original; patloc = strstr(oriptr, pattern); oriptr = patloc + 
patlen)
+    patcnt++;
+
+  {
+    // allocate memory for the new string
+    size_t const retlen = orilen + patcnt * (replen - patlen);
+    char * const returned = (char *) malloc( sizeof(char) * (retlen + 1) );
+
+    if (returned != NULL){
+      // copy the original string,
+      // replacing all the instances of the pattern
+      char * retptr = returned;
+      for (oriptr = original; patloc = strstr(oriptr, pattern); oriptr = 
patloc + patlen){
+        size_t const skplen = patloc - oriptr;
+        // copy the section until the occurence of the pattern
+        strncpy(retptr, oriptr, skplen);
+        retptr += skplen;
+        // copy the replacement 
+        strncpy(retptr, replacement, replen);
+        retptr += replen;
+      }
+      // copy the rest of the string.
+      strcpy(retptr, oriptr);
+    }
+    return returned;
+  }
+}
+
+char* urlencode(char const * const original){
+  //Always process % first
+  char *tmp_percent = replace(original, "%", "%25");
+  char *tmpsharp = replace(tmp_percent, "#", "%23");
+  char *tmpspace = replace(tmpsharp, " ", "%20");
+  free(tmp_percent);
+  free(tmpsharp);
+  return tmpspace;
+}
+
 static int op_return(int err, char * operation)
 {
        if(!err)
@@ -247,6 +295,7 @@
 
 #define curl_easy_setopt_or_die(handle, option, ...) \
   do {\
+    if (option == CURLOPT_URL) fprintf (stderr, "Access to: %s\n", 
__VA_ARGS__);\
     CURLcode res = curl_easy_setopt(handle, option, __VA_ARGS__);\
     if (res != CURLE_OK) {\
       fprintf(stderr, "Error setting curl: %s\n", error_buf);\
@@ -254,8 +303,9 @@
     }\
   }while(0)
 
-static int ftpfs_getdir(const char* path, fuse_cache_dirh_t h,
+static int ftpfs_getdir(const char* path_tmp, fuse_cache_dirh_t h,
                         fuse_cache_dirfil_t filler) {
+  char * const path = urlencode(path_tmp);
   int err = 0;
   CURLcode curl_res;
   char* dir_path = get_fulldir_path(path);
@@ -282,10 +332,12 @@
 
   free(dir_path);
   buf_free(&buf);
+  free(path);
   return op_return(err, "ftpfs_getdir");
 }
 
-static int ftpfs_getattr(const char* path, struct stat* sbuf) {
+static int ftpfs_getattr(const char* path_tmp, struct stat* sbuf) {
+  char * const path = urlencode(path_tmp);
   int err;
   CURLcode curl_res;
   char* dir_path = get_dir_path(path);
@@ -306,13 +358,14 @@
   }
   buf_null_terminate(&buf);
 
-  char* name = strrchr(path, '/');
+  char* name = strrchr(path_tmp, '/');
   ++name;
   err = parse_dir((char*)buf.p, dir_path + strlen(ftpfs.host) - 1,
                   name, sbuf, NULL, 0, NULL, NULL); 
 
   free(dir_path);
   buf_free(&buf);
+  free(path);
   if (err) return op_return(-ENOENT, "ftpfs_getattr");
   return 0;
 }
@@ -699,9 +752,9 @@
        return sbuf.st_size;
 }
 
-static int ftpfs_open_common(const char* path, mode_t mode,
+static int ftpfs_open_common(const char* path_tmp, mode_t mode,
                              struct fuse_file_info* fi) {
-       
+  char * const path = urlencode(path_tmp);
   char * flagsAsStr = flags_to_string(fi->flags);
   DEBUG(2, "ftpfs_open_common: %s\n", flagsAsStr);
   int err = 0;
@@ -808,6 +861,7 @@
   if (err)
     free_ftpfs_file(fh);
 
+  free(path);
   g_free(flagsAsStr);
   return op_return(err, "ftpfs_open");
 }
@@ -823,8 +877,9 @@
 }
 #endif
 
-static int ftpfs_read(const char* path, char* rbuf, size_t size, off_t offset,
+static int ftpfs_read(const char* path_tmp, char* rbuf, size_t size, off_t 
offset,
                       struct fuse_file_info* fi) {
+  char * const path = urlencode(path_tmp);
   int ret;
   struct ftpfs_file *fh = get_ftpfs_file(fi);
   
@@ -844,7 +899,8 @@
   } else {
     ret = size_read;
   }
-  
+  free(path);
+
   if (ret<0) op_return(ret, "ftpfs_read");
   return ret;
 }



  Also, I had to s/5/7/ in ./debian/compat to build it. Seems this
package didn't get updates in the last seven years?!

MfG, JBG

-- 

Attachment: signature.asc
Description: PGP signature

Reply via email to