summaryrefslogtreecommitdiff
path: root/net-fs
diff options
context:
space:
mode:
authorSergei Trofimovich <slyfox@gentoo.org>2013-07-25 12:04:15 +0000
committerSergei Trofimovich <slyfox@gentoo.org>2013-07-25 12:04:15 +0000
commitf8dcc7e382dd18c43f24c740abe2db03fb3e50c8 (patch)
tree51997b5d45556120f9fb90d37fa739b0f89ee099 /net-fs
parentFix "invalid mutex directory" error when starting wrt bug #438758. (diff)
downloadhistorical-f8dcc7e382dd18c43f24c740abe2db03fb3e50c8.tar.gz
historical-f8dcc7e382dd18c43f24c740abe2db03fb3e50c8.tar.bz2
historical-f8dcc7e382dd18c43f24c740abe2db03fb3e50c8.zip
Fixed pathname escaping when passed to libcurl (bug #458110 by Jaakko Perttilä). Fix heavily based on patch by jomat <jomat@copete.de>.
Package-Manager: portage-2.2.0_alpha188_p25/cvs/Linux x86_64 Manifest-Sign-Key: 0x611FF3AA
Diffstat (limited to 'net-fs')
-rw-r--r--net-fs/curlftpfs/ChangeLog9
-rw-r--r--net-fs/curlftpfs/Manifest22
-rw-r--r--net-fs/curlftpfs/curlftpfs-0.9.2-r3.ebuild43
-rw-r--r--net-fs/curlftpfs/files/curlftpfs-0.9.2-fix-escaping.patch420
4 files changed, 478 insertions, 16 deletions
diff --git a/net-fs/curlftpfs/ChangeLog b/net-fs/curlftpfs/ChangeLog
index 5ca4a80e650d..73a1aa5ec7c9 100644
--- a/net-fs/curlftpfs/ChangeLog
+++ b/net-fs/curlftpfs/ChangeLog
@@ -1,6 +1,13 @@
# ChangeLog for net-fs/curlftpfs
# Copyright 1999-2013 Gentoo Foundation; Distributed under the GPL v2
-# $Header: /var/cvsroot/gentoo-x86/net-fs/curlftpfs/ChangeLog,v 1.28 2013/06/25 14:49:29 ago Exp $
+# $Header: /var/cvsroot/gentoo-x86/net-fs/curlftpfs/ChangeLog,v 1.29 2013/07/25 12:04:06 slyfox Exp $
+
+*curlftpfs-0.9.2-r3 (25 Jul 2013)
+
+ 25 Jul 2013; Sergei Trofimovich <slyfox@gentoo.org>
+ +curlftpfs-0.9.2-r3.ebuild, +files/curlftpfs-0.9.2-fix-escaping.patch:
+ Fixed pathname escaping when passed to libcurl (bug #458110 by Jaakko
+ Perttilä). Fix heavily based on patch by jomat <jomat@copete.de>.
25 Jun 2013; Agostino Sarubbo <ago@gentoo.org> curlftpfs-0.9.2-r1.ebuild:
Stable for amd64, wrt bug #472040
diff --git a/net-fs/curlftpfs/Manifest b/net-fs/curlftpfs/Manifest
index f9a6b2b32779..d61f9d3946ca 100644
--- a/net-fs/curlftpfs/Manifest
+++ b/net-fs/curlftpfs/Manifest
@@ -1,29 +1,21 @@
-----BEGIN PGP SIGNED MESSAGE-----
-Hash: SHA512
+Hash: SHA256
AUX curlftpfs-0.9.2-64bit_filesize.patch 626 SHA256 95d880b3a43387f5ae6e5b3ed9309060bbdc3757fb7631af50edf386c7a6805c SHA512 3b23ee31c5008fffec3032c9ab440a584d672a3936f8fae943af31e5936964e8b5641f5778f56b5c656e9af26156d0a1f31e49ef8c4eb526ec8a83ff7076fcb7 WHIRLPOOL 26be2399dca4464cb1e8e130bd3cc2a765d1cc9cca5901e52c5f91a7ba56950c4350cae70161c01c12c96f9eeeb4922ca2a8836f4659db93b4d3e37c76438d10
AUX curlftpfs-0.9.2-darwin.patch 516 SHA256 46770b2274a3634e399319e1387d9fd67e56fcd3a85056d5a6d1451cea31b8a4 SHA512 1960dc4b08e8f5e3154ff4cbccf1f48f616d8ac92ed464bf5aac8054c680b2575fc3801a56f309d29e7ef3aa7d611fa8f7a67c73fd5894b8dc5a1cce36ff38f9 WHIRLPOOL 42388c8df3c71ce2fb34676c15149c8cc86dfcae524a7e4a88d6157707502b476d91911b9f273d507287bb6b3111184707813852eef81923e1d2272b7b8bafd7
+AUX curlftpfs-0.9.2-fix-escaping.patch 15764 SHA256 c87c3f3ec9f3399c3850c71342a04a24db46ac3f4179be7792c3079d8f0acdf4 SHA512 3e93eb58ea0f143ae09e6300a411e7cec32b25417e183f68486d796062dbc41c1c9d4824a282840824c07f02a49ec14995dc7eb1d19b77b7ef27e89c26a4c5cf WHIRLPOOL 13922480eb6a53e2f662102aefbdefa7fe0ec0b6f0fcc0bc32fb2d340ee3fb816c03670fe743f74e3c487ede3852fe5b158a69e9bc82b9d60b6262ef8b3a9c94
AUX curlftpfs-0.9.2-memleak-nocache.patch 1810 SHA256 d51e86585061c4dc15145d50d139331d9ae332643332467291e7e7313e3c4e48 SHA512 b53ed1acfea1aa539c0f69ab7dd961a635ded7299500337a7453fa2445e61590ec39a9010ac105d230880b09a90d388b8564295a185e5b44f3398903a6d1d5d4 WHIRLPOOL 8794b31cc4cb6bd75b2f3461d1c82127582d5fb1f78b6621739dfd11eb6e985bc7a0cc69e953a55bfa563411d3cf49305756e7bc479116ccbed3d7cdea1664f1
AUX curlftpfs-0.9.2-memleak.patch 834 SHA256 b81de7d8eac46a390f1baf4071efde62c77148908562ea9a255acc9fd8d35f97 SHA512 dee0eac27bd09208f44d20d3c0627499da0664601abfb0cb5a3a979c988c71713ef00850f2b72e71c38a9dac09698e55cfbc6249bb1e2196a07a783b0fcd49bc WHIRLPOOL 17e3d417734ca610753c2435e736d3d833183b3346873039bc352d9cb36748f792b34e3c46f1609c1d0d94e30db7d702d17a7544a3edef4766fbfdaf918e9130
DIST curlftpfs-0.9.2.tar.gz 365503 SHA256 4eb44739c7078ba0edde177bdd266c4cfb7c621075f47f64c85a06b12b3c6958 SHA512 df07c418d175f766c89525017fc56e79726061eee0c3a6607ded0e1bf24f64f1475ba0e546157b65892194e3c4414c120822bf8fb175437e68366f82de216067 WHIRLPOOL c14686eeadafe2f26f9c79fd44ab0d66403e79ec724d5eae28a8b3838ac676755edc1d86583c4de73486fc0dc5d49eabb2b57f7cb477edaccfab33b2aa9f0931
EBUILD curlftpfs-0.9.2-r1.ebuild 965 SHA256 d431dcbed990c71d57414077a72e3d1484e91f2acbb261b5919f7e4fe104f3e8 SHA512 785bd6517a16562922e5d9df7ab0217d4cb198d4c17ee8a888ad31d28f7df26980eab7f6fdf35cae045f3b9986422e7721cd6cbceefd20c47fc41a85387a4295 WHIRLPOOL 4ada32354e3a9c1fb411ac6def2b0ba0af08a6978e0490560e1d2aeaadc14d854797cbeb3c7e13937c5152eca878a176847ddf24602ad64764704bf00883a59a
EBUILD curlftpfs-0.9.2-r2.ebuild 1090 SHA256 a2c8bea5deb3dbf44bfe003a97413a1d0f929b7045ead605d07d7ac8bf8786b7 SHA512 cf26015119d703035f41eff86c2de089bcbb946c4779170d0088730ec6c302efa25667030ead9fba0a7b5f49765d2ed420a3dd8c549c2f57b9cb7e6de14ed729 WHIRLPOOL 986143108b8a238f1230767a07a8e74b81b4fd698bf9d4acdc743da0e49a919193f3a7532a76b51b0220923cb9e1072e61cf3d7257db345f1607737d69eddefd
-MISC ChangeLog 4286 SHA256 3fb8d31d57cab280116dafca6f1fc2934bee8a9d2e10c2a1f73ca167890fd195 SHA512 18e1f7d81059ca089aa6c1cf97242a3a80e437b8e43615b92f3717a8a1ff6e3d6d42fcdc0115af09e1cbfca5919a3dd9d10ac35e369e1e9dc0f80c24c9e5d3e0 WHIRLPOOL 2d33c99f6f060ca1710aa5d83277a8285e5367c111c80782fcca9db4ad39d4a94d792c6d539860e6e48cd463369d67f16fd2611e26603838db411b98d0b1661b
+EBUILD curlftpfs-0.9.2-r3.ebuild 1115 SHA256 36564f06bbffbd7d50cb5ba407e5a0665d4f8e4b27f996d297928ba7d34a0690 SHA512 6f946efc26e860b4e884b3a910646c4d1483dd0cf8c43bb051a9ac0da68f6a1d726c6d784a303b1e768901385b2ff31c67fac44119c803c5b119b43563958924 WHIRLPOOL 0e5774c7c5e0f322d907d95a64594ebe5207e497e8c6f47409c02f6f81ab08c427f65d84f7c1a017e570106d3efebd14b559baf53d1d88f7b46b38cf74786589
+MISC ChangeLog 4593 SHA256 2e622af5ee739f647bda0cfab5f3932e8eb69ee28f1f2bb9ed2fc0480cd6aaad SHA512 8fa8de127800283aa9bfcd7c90fb2f82a1c66a67afe16765798612bb9d7189fbb350ac8c904009b8b99cab94b3459a6e999777b89833f74e8ef3ff5f7e1fe6e8 WHIRLPOOL 04b8a6844bb6cfe1e64bf88f5ad2c1eca2b53a520880725a3eb13d6c8bd8bcd909f8a850472cdea350de43c151da8057a534bcc38b12b99afe296a788e399823
MISC metadata.xml 265 SHA256 89560d1b083b008e6d38f31d7fa5a97da8890a72e93d0532ac0bbc8b15b2679e SHA512 0048ece4ab8d1dfdfb3be937d2c33d12428d69621bd0c02c21202ef414c4a7c73869c52e333d46b49466abe82af1ef50b0bedb79f648591d1aea82a429d10857 WHIRLPOOL 8ceef3afb2393cefdf25df36e2b42322dcf19181982c228942de02b586984949023c42e7559093211a63edad2491905f47fc47d19ddadba0a4ba669a597b714b
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.20 (GNU/Linux)
-iQIcBAEBCgAGBQJRya38AAoJELp701BxlEWf39EP/3+DWxjHBF7joJ1rIkuesDsK
-85XKgnERww8ZlsO8TOxLtkvH24U+Sxpkp7YYPLbpSpSMS+jzFO5rfwosw4L40r4e
-ZhL4B2dMNyr8s/VjZ0v/GU3Uy6t0jIYmMbns3inFwvnGmw4dDrSDioNEB3FKaon6
-3GO4Op7R5EqxtbS058sovixIl4hqzFaoihFg/MdNOUqxBtqT7zIiiV0p4wWnTLSl
-CzJ7657kcK59QGTh9qg8deszJY7F5UjmPN8m1NS3kk9i6aaad1iqNS7QwuQEd7Pt
-N4TyLLlYfJRD+pstUKW0aRFKbZuKuP8CBX5pPZ4dXGOiYhOQ1PrpfescDaKIHPDG
-q0tbds4X8cBpeyJ3yfF8L8k3ar3RAdeQBWm8KbvWR6oKjp5/TV3Z1SN6opPoF4LK
-/v1OyYiCMBssBVMJMtQ7h5EvYTJUfEXB/9vOhyB7AE2qZvgeKZdJ/0xLT/3Rq/FV
-jjTCvfTh/dPxDMnA9BBciTE6qfXBjbqEv9qnPquXbGpmHuvUxmeTPgz9fem8dE80
-AKAjjKpQPuuxpUDzsX96ghYSqyN2eOSVmaPJjMowPSticVh3KJvZwIcc+4GBge1R
-AMTfowvXkCwYu9ixLYPCUznzHnM4dqXyQo08WvM1386OMexcoEoQJRr6dQD2eA4C
-+1FI8dkcAexHsYuX+9DR
-=yRIp
+iEYEAREIAAYFAlHxE5QACgkQcaHudmEf86odngCghtEZDf6GpnBpxGH5Qr8yt7vI
+UNEAnAoZvUGbv9n8gGdGyyBlsDeLFQCp
+=TBZC
-----END PGP SIGNATURE-----
diff --git a/net-fs/curlftpfs/curlftpfs-0.9.2-r3.ebuild b/net-fs/curlftpfs/curlftpfs-0.9.2-r3.ebuild
new file mode 100644
index 000000000000..3cf92c43afc9
--- /dev/null
+++ b/net-fs/curlftpfs/curlftpfs-0.9.2-r3.ebuild
@@ -0,0 +1,43 @@
+# Copyright 1999-2013 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: /var/cvsroot/gentoo-x86/net-fs/curlftpfs/curlftpfs-0.9.2-r3.ebuild,v 1.1 2013/07/25 12:04:06 slyfox Exp $
+
+EAPI=5
+
+inherit eutils autotools
+
+DESCRIPTION="File system for accessing ftp hosts based on FUSE"
+HOMEPAGE="http://curlftpfs.sourceforge.net/"
+SRC_URI="mirror://sourceforge/${PN}/${P}.tar.gz"
+
+LICENSE="GPL-2"
+SLOT="0"
+KEYWORDS="~amd64 ~arm ~x86 ~amd64-linux ~x86-linux ~x86-macos"
+IUSE=""
+RESTRICT="test" # bug 258460
+
+RDEPEND=">=net-misc/curl-7.17.0
+ >=sys-fs/fuse-2.2
+ >=dev-libs/glib-2.0"
+DEPEND="${RDEPEND}
+ virtual/pkgconfig"
+
+src_prepare() {
+ epatch "${FILESDIR}"/${P}-64bit_filesize.patch
+ epatch "${FILESDIR}"/${PN}-0.9.2-darwin.patch
+ epatch "${FILESDIR}"/${PN}-0.9.2-memleak.patch
+ epatch "${FILESDIR}"/${PN}-0.9.2-memleak-nocache.patch
+ epatch "${FILESDIR}"/${PN}-0.9.2-fix-escaping.patch
+
+ # automake-1.13.1 obsoletes AM_* bit #469818
+ sed -i -e 's/AM_CONFIG_HEADER/AC_CONFIG_HEADERS/' configure.ac || die
+
+ epatch_user
+
+ eautoreconf
+}
+
+src_install() {
+ default
+ dodoc README
+}
diff --git a/net-fs/curlftpfs/files/curlftpfs-0.9.2-fix-escaping.patch b/net-fs/curlftpfs/files/curlftpfs-0.9.2-fix-escaping.patch
new file mode 100644
index 000000000000..29251f993e40
--- /dev/null
+++ b/net-fs/curlftpfs/files/curlftpfs-0.9.2-fix-escaping.patch
@@ -0,0 +1,420 @@
+fix handling of special symbols in file operations.
+
+Path fixes at least following cases:
+ - attempt to enter directory named '#'
+ - attempt to open file named '#'
+ - attempt to dereference link named '#'
+ - attempt to chown file / dir named '#'
+
+The fix is basically following mechanical conversion:
+--- curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, something);
++++ escaped_something = ftpfs.connection, something, 0);
++++ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, something);
+=== curl_easy_perform();
++++ curl_free(escaped_something);
+
+What is not yet converted is ftp hostname.
+
+Reported-by: Jaakko Perttilä
+Gentoo-bug: http://bugs.gentoo.org/458110
+Based-on-patch: https://github.com/jomat/curlftpfs/commit/da20298fd0d0dcefc7d6d69ffecbc5544e783cfe
+Signed-off-by: Sergei Trofimovich <slyfox@gentoo.org>
+diff --git a/ftpfs.c b/ftpfs.c
+index ffd0b28..f21a267 100644
+--- a/ftpfs.c
++++ b/ftpfs.c
+@@ -257,6 +257,7 @@ static int ftpfs_getdir(const char* path, fuse_cache_dirh_t h,
+ int err = 0;
+ CURLcode curl_res;
+ char* dir_path = get_fulldir_path(path);
++ char* dir_path_uri = path_to_uri(dir_path);
+
+ DEBUG(1, "ftpfs_getdir: %s\n", dir_path);
+ struct buffer buf;
+@@ -264,7 +265,7 @@ static int ftpfs_getdir(const char* path, fuse_cache_dirh_t h,
+
+ pthread_mutex_lock(&ftpfs.lock);
+ cancel_previous_multi();
+- curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, dir_path);
++ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, dir_path_uri);
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_WRITEDATA, &buf);
+ curl_res = curl_easy_perform(ftpfs.connection);
+ pthread_mutex_unlock(&ftpfs.lock);
+@@ -278,6 +279,7 @@ static int ftpfs_getdir(const char* path, fuse_cache_dirh_t h,
+ NULL, NULL, NULL, 0, h, filler);
+ }
+
++ free_uri(dir_path_uri);
+ free(dir_path);
+ buf_free(&buf);
+ return op_return(err, "ftpfs_getdir");
+@@ -287,6 +289,7 @@ static int ftpfs_getattr(const char* path, struct stat* sbuf) {
+ int err;
+ CURLcode curl_res;
+ char* dir_path = get_dir_path(path);
++ char* dir_path_uri = path_to_uri(dir_path);
+
+ DEBUG(2, "ftpfs_getattr: %s dir_path=%s\n", path, dir_path);
+ struct buffer buf;
+@@ -294,7 +297,7 @@ static int ftpfs_getattr(const char* path, struct stat* sbuf) {
+
+ pthread_mutex_lock(&ftpfs.lock);
+ cancel_previous_multi();
+- curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, dir_path);
++ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, dir_path_uri);
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_WRITEDATA, &buf);
+ curl_res = curl_easy_perform(ftpfs.connection);
+ pthread_mutex_unlock(&ftpfs.lock);
+@@ -309,6 +312,7 @@ static int ftpfs_getattr(const char* path, struct stat* sbuf) {
+ err = parse_dir((char*)buf.p, dir_path + strlen(ftpfs.host) - 1,
+ name, sbuf, NULL, 0, NULL, NULL);
+
++ free_uri(dir_path_uri);
+ free(dir_path);
+ buf_free(&buf);
+ if (err) return op_return(-ENOENT, "ftpfs_getattr");
+@@ -329,6 +333,7 @@ static size_t ftpfs_read_chunk(const char* full_path, char* rbuf,
+ int running_handles = 0;
+ int err = 0;
+ struct ftpfs_file* fh = get_ftpfs_file(fi);
++ char* full_path_uri = path_to_uri(full_path); /* TODO: optimize bu pushing up conversion to context */
+
+ DEBUG(2, "ftpfs_read_chunk: %s %p %zu %lld %p %p\n",
+ full_path, rbuf, size, offset, fi, fh);
+@@ -355,7 +360,7 @@ static size_t ftpfs_read_chunk(const char* full_path, char* rbuf,
+
+ cancel_previous_multi();
+
+- curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path);
++ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path_uri);
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_WRITEDATA, &fh->buf);
+ if (offset) {
+ char range[15];
+@@ -444,6 +449,7 @@ static size_t ftpfs_read_chunk(const char* full_path, char* rbuf,
+
+ pthread_mutex_unlock(&ftpfs.lock);
+
++ free_uri(full_path_uri);
+ if (err) return CURLFTPFS_BAD_READ;
+ return size;
+ }
+@@ -497,11 +503,12 @@ int write_thread_ctr = 0;
+ static void *ftpfs_write_thread(void *data) {
+ struct ftpfs_file *fh = data;
+ char range[15];
+-
++ char* full_path_uri = path_to_uri(fh->full_path); /* TODO: optimize bu pushing up conversion to context */
++
+ DEBUG(2, "enter streaming write thread #%d path=%s pos=%lld\n", ++write_thread_ctr, fh->full_path, fh->pos);
+
+
+- curl_easy_setopt_or_die(fh->write_conn, CURLOPT_URL, fh->full_path);
++ curl_easy_setopt_or_die(fh->write_conn, CURLOPT_URL, full_path_uri);
+ curl_easy_setopt_or_die(fh->write_conn, CURLOPT_UPLOAD, 1);
+ curl_easy_setopt_or_die(fh->write_conn, CURLOPT_INFILESIZE, (curl_off_t)-1);
+ curl_easy_setopt_or_die(fh->write_conn, CURLOPT_READFUNCTION, write_data_bg);
+@@ -541,6 +548,8 @@ static void *ftpfs_write_thread(void *data) {
+
+ sem_post(&fh->data_written); /* ftpfs_write may return */
+
++ free_uri(full_path_uri);
++
+ return NULL;
+ }
+
+@@ -621,16 +630,19 @@ static void free_ftpfs_file(struct ftpfs_file *fh) {
+ }
+
+ static int buffer_file(struct ftpfs_file *fh) {
++ char* full_path_uri = path_to_uri(fh->full_path); /* TODO: optimize bu pushing up conversion to context */
+ // If we want to write to the file, we have to load it all at once,
+ // modify it in memory and then upload it as a whole as most FTP servers
+ // don't support resume for uploads.
+ pthread_mutex_lock(&ftpfs.lock);
+ cancel_previous_multi();
+- curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, fh->full_path);
++ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path_uri);
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_WRITEDATA, &fh->buf);
+ CURLcode curl_res = curl_easy_perform(ftpfs.connection);
+ pthread_mutex_unlock(&ftpfs.lock);
+
++ free_uri(full_path_uri);
++
+ if (curl_res != 0) {
+ return -EACCES;
+ }
+@@ -643,10 +655,11 @@ static int create_empty_file(const char * path)
+ int err = 0;
+
+ char *full_path = get_full_path(path);
++ char* full_path_uri = path_to_uri(full_path);
+
+ pthread_mutex_lock(&ftpfs.lock);
+ cancel_previous_multi();
+- curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path);
++ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path_uri);
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_INFILESIZE, 0);
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_UPLOAD, 1);
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_READDATA, NULL);
+@@ -656,7 +669,9 @@ static int create_empty_file(const char * path)
+
+ if (curl_res != 0) {
+ err = -EPERM;
+- }
++ }
++
++ free_uri(full_path_uri);
+ free(full_path);
+ return err;
+ }
+@@ -875,6 +890,7 @@ static int ftpfs_chmod(const char* path, mode_t mode) {
+
+ struct curl_slist* header = NULL;
+ char* full_path = get_dir_path(path);
++ char* full_path_uri = path_to_uri(full_path);
+ char* filename = get_file_name(path);
+ char* cmd = g_strdup_printf("SITE CHMOD %.3o %s", mode_c, filename);
+ struct buffer buf;
+@@ -885,7 +901,7 @@ static int ftpfs_chmod(const char* path, mode_t mode) {
+ pthread_mutex_lock(&ftpfs.lock);
+ cancel_previous_multi();
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_POSTQUOTE, header);
+- curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path);
++ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path_uri);
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_WRITEDATA, &buf);
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_NOBODY, ftpfs.safe_nobody);
+ CURLcode curl_res = curl_easy_perform(ftpfs.connection);
+@@ -896,12 +912,13 @@ static int ftpfs_chmod(const char* path, mode_t mode) {
+ if (curl_res != 0) {
+ err = -EPERM;
+ }
+-
++
+ buf_free(&buf);
+ curl_slist_free_all(header);
++ free_uri(full_path_uri);
+ free(full_path);
+ free(filename);
+- free(cmd);
++ free(cmd);
+ return op_return(err, "ftpfs_chmod");
+ }
+
+@@ -912,6 +929,7 @@ static int ftpfs_chown(const char* path, uid_t uid, gid_t gid) {
+
+ struct curl_slist* header = NULL;
+ char* full_path = get_dir_path(path);
++ char* full_path_uri = path_to_uri(full_path);
+ char* filename = get_file_name(path);
+ char* cmd = g_strdup_printf("SITE CHUID %i %s", uid, filename);
+ char* cmd2 = g_strdup_printf("SITE CHGID %i %s", gid, filename);
+@@ -924,7 +942,7 @@ static int ftpfs_chown(const char* path, uid_t uid, gid_t gid) {
+ pthread_mutex_lock(&ftpfs.lock);
+ cancel_previous_multi();
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_POSTQUOTE, header);
+- curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path);
++ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path_uri);
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_WRITEDATA, &buf);
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_NOBODY, ftpfs.safe_nobody);
+ CURLcode curl_res = curl_easy_perform(ftpfs.connection);
+@@ -938,6 +956,7 @@ static int ftpfs_chown(const char* path, uid_t uid, gid_t gid) {
+
+ buf_free(&buf);
+ curl_slist_free_all(header);
++ free_uri(full_path_uri);
+ free(full_path);
+ free(filename);
+ free(cmd);
+@@ -1001,6 +1020,7 @@ static int ftpfs_rmdir(const char* path) {
+ int err = 0;
+ struct curl_slist* header = NULL;
+ char* full_path = get_dir_path(path);
++ char* full_path_uri = path_to_uri(full_path);
+ char* filename = get_file_name(path);
+ char* cmd = g_strdup_printf("RMD %s", filename);
+ struct buffer buf;
+@@ -1014,7 +1034,7 @@ static int ftpfs_rmdir(const char* path) {
+ pthread_mutex_lock(&ftpfs.lock);
+ cancel_previous_multi();
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_POSTQUOTE, header);
+- curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path);
++ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path_uri);
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_WRITEDATA, &buf);
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_NOBODY, ftpfs.safe_nobody);
+ CURLcode curl_res = curl_easy_perform(ftpfs.connection);
+@@ -1028,6 +1048,7 @@ static int ftpfs_rmdir(const char* path) {
+
+ buf_free(&buf);
+ curl_slist_free_all(header);
++ free_uri(full_path_uri);
+ free(full_path);
+ free(filename);
+ free(cmd);
+@@ -1038,6 +1059,7 @@ static int ftpfs_mkdir(const char* path, mode_t mode) {
+ int err = 0;
+ struct curl_slist* header = NULL;
+ char* full_path = get_dir_path(path);
++ char* full_path_uri = path_to_uri(full_path);
+ char* filename = get_file_name(path);
+ char* cmd = g_strdup_printf("MKD %s", filename);
+ struct buffer buf;
+@@ -1048,7 +1070,7 @@ static int ftpfs_mkdir(const char* path, mode_t mode) {
+ pthread_mutex_lock(&ftpfs.lock);
+ cancel_previous_multi();
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_POSTQUOTE, header);
+- curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path);
++ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path_uri);
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_WRITEDATA, &buf);
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_NOBODY, ftpfs.safe_nobody);
+ CURLcode curl_res = curl_easy_perform(ftpfs.connection);
+@@ -1062,6 +1084,7 @@ static int ftpfs_mkdir(const char* path, mode_t mode) {
+
+ buf_free(&buf);
+ curl_slist_free_all(header);
++ free_uri(full_path_uri);
+ free(full_path);
+ free(filename);
+ free(cmd);
+@@ -1076,6 +1099,7 @@ static int ftpfs_unlink(const char* path) {
+ int err = 0;
+ struct curl_slist* header = NULL;
+ char* full_path = get_dir_path(path);
++ char* full_path_uri = path_to_uri(full_path);
+ char* filename = get_file_name(path);
+ char* cmd = g_strdup_printf("DELE %s", filename);
+ struct buffer buf;
+@@ -1086,7 +1110,7 @@ static int ftpfs_unlink(const char* path) {
+ pthread_mutex_lock(&ftpfs.lock);
+ cancel_previous_multi();
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_POSTQUOTE, header);
+- curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path);
++ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path_uri);
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_WRITEDATA, &buf);
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_NOBODY, ftpfs.safe_nobody);
+ CURLcode curl_res = curl_easy_perform(ftpfs.connection);
+@@ -1100,6 +1124,7 @@ static int ftpfs_unlink(const char* path) {
+
+ buf_free(&buf);
+ curl_slist_free_all(header);
++ free_uri(full_path_uri);
+ free(full_path);
+ free(filename);
+ free(cmd);
+@@ -1301,6 +1326,7 @@ static int ftpfs_readlink(const char *path, char *linkbuf, size_t size) {
+ int err;
+ CURLcode curl_res;
+ char* dir_path = get_dir_path(path);
++ char* dir_path_uri = path_to_uri(dir_path);
+
+ DEBUG(2, "dir_path: %s %s\n", path, dir_path);
+ struct buffer buf;
+@@ -1308,7 +1334,7 @@ static int ftpfs_readlink(const char *path, char *linkbuf, size_t size) {
+
+ pthread_mutex_lock(&ftpfs.lock);
+ cancel_previous_multi();
+- curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, dir_path);
++ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, dir_path_uri);
+ curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_WRITEDATA, &buf);
+ curl_res = curl_easy_perform(ftpfs.connection);
+ pthread_mutex_unlock(&ftpfs.lock);
+@@ -1323,6 +1349,7 @@ static int ftpfs_readlink(const char *path, char *linkbuf, size_t size) {
+ err = parse_dir((char*)buf.p, dir_path + strlen(ftpfs.host) - 1,
+ name, NULL, linkbuf, size, NULL, NULL);
+
++ free_uri(dir_path_uri);
+ free(dir_path);
+ buf_free(&buf);
+ if (err) return op_return(-ENOENT, "ftpfs_readlink");
+diff --git a/path_utils.c b/path_utils.c
+index db3d7e4..214b5e6 100644
+--- a/path_utils.c
++++ b/path_utils.c
+@@ -92,3 +92,72 @@ char* get_dir_path(const char* path) {
+
+ return ret;
+ }
++
++/*
++ * the chars not needed to be escaped:
++ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
++ */
++static inline int is_unreserved_rfc3986(char c)
++{
++ int is_locase_alpha = (c >= 'a' && c <= 'z');
++ int is_upcase_alpha = (c >= 'a' && c <= 'z');
++ int is_digit = (c >= '0' && c <= '9');
++ int is_special = c == '-'
++ || c == '.'
++ || c == '_'
++ || c == '~';
++ int is_unreserved = is_locase_alpha
++ || is_upcase_alpha
++ || is_digit
++ || is_special;
++
++ return is_unreserved;
++}
++
++static inline int is_unreserved(char c)
++{
++ return is_unreserved_rfc3986(c) || c == '/';
++}
++
++char* path_to_uri(const char* path)
++{
++ static const char hex[] = "0123456789ABCDEF";
++ size_t path_len = strlen(path);
++ size_t host_len = strlen(ftpfs.host);
++ /* at worst: c -> %XX */
++ char * encoded_path = malloc (3 * path_len + 1);
++ const char * s = path;
++ char * d = encoded_path;
++
++ /*
++ * 'path' is always prefixed with 'ftpfs.host'
++ */
++ memcpy (d, ftpfs.host, host_len);
++ s += host_len;
++ d += host_len;
++
++ for (; *s; ++s)
++ {
++ char c = *s;
++ if (is_unreserved (c))
++ {
++ *d++ = c;
++ }
++ else
++ {
++ unsigned int hi = ((unsigned)c >> 4) & 0xF;
++ unsigned int lo = ((unsigned)c >> 0) & 0xF;
++ *d++ = '%';
++ *d++ = hex[hi];
++ *d++ = hex[lo];
++ }
++ }
++ *d = '\0';
++
++ return encoded_path;
++}
++
++void free_uri(char* path)
++{
++ free(path);
++}
+diff --git a/path_utils.h b/path_utils.h
+index 084ae4d..e3e9bca 100644
+--- a/path_utils.h
++++ b/path_utils.h
+@@ -6,4 +6,11 @@ char* get_full_path(const char* path);
+ char* get_fulldir_path(const char* path);
+ char* get_dir_path(const char* path);
+
++/*
++ * Transforms UNIX path to RFC3986 encoded path
++ * (CURLOPT_URL accepts only such paths)
++ */
++char* path_to_uri(const char* path);
++void free_uri(char* path);
++
+ #endif /* __CURLFTPFS_PATH_UTILS_H__ */