Add initial support for doing read on demand from FTP servers. This makes us depend on very recent libcurl versions.
This commit is contained in:
@@ -9,7 +9,7 @@ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
|
||||
PKG_CHECK_MODULES(GLIB, [glib-2.0])
|
||||
PKG_CHECK_MODULES(FUSE, [fuse >= 2.2])
|
||||
|
||||
LIBCURL_CHECK_CONFIG([yes], [7.7.2], [], [AC_MSG_ERROR(["libcurl not found"])])
|
||||
LIBCURL_CHECK_CONFIG([yes], [7.15.2], [], [AC_MSG_ERROR(["libcurl not found"])])
|
||||
if test "$libcurl_protocol_FTP" != yes; then
|
||||
AC_MSG_ERROR(["We need libcurl with support for FTP protocol."])
|
||||
fi
|
||||
|
326
ftpfs.c
326
ftpfs.c
@@ -28,6 +28,8 @@
|
||||
#define CURLFTPFS_BAD_NOBODY 0x070f02
|
||||
#define CURLFTPFS_BAD_SSL 0x070f03
|
||||
|
||||
#define CURLFTPFS_BAD_READ ((size_t)-1)
|
||||
|
||||
struct ftpfs ftpfs;
|
||||
static char error_buf[CURL_ERROR_SIZE];
|
||||
|
||||
@@ -35,6 +37,7 @@ struct buffer {
|
||||
uint8_t* p;
|
||||
size_t len;
|
||||
size_t size;
|
||||
off_t begin_offset;
|
||||
};
|
||||
|
||||
static void usage(const char* progname);
|
||||
@@ -50,6 +53,7 @@ static inline void buf_init(struct buffer* buf, size_t size)
|
||||
}
|
||||
} else
|
||||
buf->p = NULL;
|
||||
buf->begin_offset = 0;
|
||||
buf->len = 0;
|
||||
buf->size = size;
|
||||
}
|
||||
@@ -205,6 +209,7 @@ struct ftpfs_file {
|
||||
struct buffer buf;
|
||||
int dirty;
|
||||
int copied;
|
||||
off_t last_offset;
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -302,6 +307,7 @@ static int ftpfs_getdir(const char* path, fuse_cache_dirh_t h,
|
||||
buf_init(&buf, 0);
|
||||
|
||||
pthread_mutex_lock(&ftpfs.lock);
|
||||
curl_multi_remove_handle(ftpfs.multi, ftpfs.connection);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, dir_path);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_WRITEDATA, &buf);
|
||||
curl_res = curl_easy_perform(ftpfs.connection);
|
||||
@@ -348,6 +354,7 @@ static int ftpfs_getattr(const char* path, struct stat* sbuf) {
|
||||
buf_init(&buf, 0);
|
||||
|
||||
pthread_mutex_lock(&ftpfs.lock);
|
||||
curl_multi_remove_handle(ftpfs.multi, ftpfs.connection);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, dir_path);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_WRITEDATA, &buf);
|
||||
curl_res = curl_easy_perform(ftpfs.connection);
|
||||
@@ -368,55 +375,173 @@ static int ftpfs_getattr(const char* path, struct stat* sbuf) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ftpfs_open(const char* path, struct fuse_file_info* fi) {
|
||||
DEBUG("%d\n", fi->flags & O_ACCMODE);
|
||||
if ((fi->flags & O_ACCMODE) == O_RDONLY) {
|
||||
DEBUG("opening %s O_RDONLY\n", path);
|
||||
} else if ((fi->flags & O_ACCMODE) == O_WRONLY) {
|
||||
DEBUG("opening %s O_WRONLY\n", path);
|
||||
} else if ((fi->flags & O_ACCMODE) == O_RDWR) {
|
||||
DEBUG("opening %s O_RDWR\n", path);
|
||||
}
|
||||
|
||||
char *full_path = g_strdup_printf("%s%s", ftpfs.host, path + 1);
|
||||
|
||||
DEBUG("full_path: %s\n", full_path);
|
||||
struct buffer buf;
|
||||
static size_t ftpfs_read_chunk(const char* full_path, char* rbuf,
|
||||
size_t size, off_t offset,
|
||||
struct fuse_file_info* fi,
|
||||
int update_offset) {
|
||||
int running_handles;
|
||||
int err = 0;
|
||||
buf_init(&buf, 0);
|
||||
struct ftpfs_file* fh = (struct ftpfs_file*) (uintptr_t) fi->fh;
|
||||
|
||||
DEBUG("ftpfs_read_chunk: %s %p %d %lld %p\n",
|
||||
full_path, rbuf, size, offset, fi);
|
||||
|
||||
pthread_mutex_lock(&ftpfs.lock);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_WRITEDATA, &buf);
|
||||
CURLcode curl_res = curl_easy_perform(ftpfs.connection);
|
||||
if (curl_res != 0) {
|
||||
err = -EACCES;
|
||||
buf_free(&buf);
|
||||
} else {
|
||||
struct ftpfs_file* fh = (struct ftpfs_file*)
|
||||
malloc(sizeof(struct ftpfs_file));
|
||||
fh->buf = buf;
|
||||
fh->dirty = 0;
|
||||
fh->copied = 0;
|
||||
fi->fh = (unsigned long) fh;
|
||||
|
||||
DEBUG("buffer size: %d\n", fh->buf.len);
|
||||
|
||||
if ((fh->buf.len < size + offset - fh->buf.begin_offset) ||
|
||||
offset < fh->buf.begin_offset ||
|
||||
offset > fh->buf.begin_offset + fh->buf.len) {
|
||||
// We can't answer this from cache
|
||||
curl_multi_perform(ftpfs.multi, &running_handles);
|
||||
|
||||
if (ftpfs.current_fh != fh ||
|
||||
running_handles == 0 ||
|
||||
offset < fh->buf.begin_offset ||
|
||||
offset > fh->buf.begin_offset + fh->buf.len) {
|
||||
DEBUG("We need to restart the connection\n");
|
||||
DEBUG("%p %p\n", ftpfs.current_fh, fh);
|
||||
DEBUG("%d\n", running_handles);
|
||||
DEBUG("%lld %lld\n", fh->last_offset, offset);
|
||||
|
||||
buf_clear(&fh->buf);
|
||||
fh->buf.begin_offset = offset;
|
||||
ftpfs.current_fh = fh;
|
||||
|
||||
curl_multi_remove_handle(ftpfs.multi, ftpfs.connection);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_WRITEDATA, &fh->buf);
|
||||
if (offset) {
|
||||
char range[15];
|
||||
snprintf(range, 15, "%lld-", offset);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_RANGE, range);
|
||||
}
|
||||
curl_multi_add_handle(ftpfs.multi, ftpfs.connection);
|
||||
}
|
||||
|
||||
while(CURLM_CALL_MULTI_PERFORM ==
|
||||
curl_multi_perform(ftpfs.multi, &running_handles));
|
||||
while ((fh->buf.len < size + offset - fh->buf.begin_offset) &&
|
||||
running_handles) {
|
||||
struct timeval timeout;
|
||||
int rc; /* select() return code */
|
||||
|
||||
fd_set fdread;
|
||||
fd_set fdwrite;
|
||||
fd_set fdexcep;
|
||||
int maxfd;
|
||||
|
||||
FD_ZERO(&fdread);
|
||||
FD_ZERO(&fdwrite);
|
||||
FD_ZERO(&fdexcep);
|
||||
|
||||
/* set a suitable timeout to play around with */
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
/* get file descriptors from the transfers */
|
||||
curl_multi_fdset(ftpfs.multi, &fdread, &fdwrite, &fdexcep, &maxfd);
|
||||
|
||||
rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
|
||||
|
||||
switch(rc) {
|
||||
case -1:
|
||||
/* select error */
|
||||
break;
|
||||
case 0:
|
||||
/* timeout, do something else */
|
||||
break;
|
||||
default:
|
||||
/* one or more of curl's file descriptors say there's data to read
|
||||
or write */
|
||||
while(CURLM_CALL_MULTI_PERFORM ==
|
||||
curl_multi_perform(ftpfs.multi, &running_handles));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (running_handles == 0) {
|
||||
int msgs_left = 1;
|
||||
while (msgs_left) {
|
||||
CURLMsg* msg = curl_multi_info_read(ftpfs.multi, &msgs_left);
|
||||
if (msg == NULL ||
|
||||
msg->msg != CURLMSG_DONE ||
|
||||
msg->data.result != CURLE_OK) {
|
||||
err = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t to_copy = fh->buf.len + fh->buf.begin_offset - offset;
|
||||
size = size > to_copy ? to_copy : size;
|
||||
if (rbuf) {
|
||||
memcpy(rbuf, fh->buf.p + offset - fh->buf.begin_offset, size);
|
||||
}
|
||||
|
||||
if (update_offset) {
|
||||
fh->last_offset = offset + size;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&ftpfs.lock);
|
||||
|
||||
free(full_path);
|
||||
if (err) return CURLFTPFS_BAD_READ;
|
||||
return size;
|
||||
}
|
||||
|
||||
static int ftpfs_open(const char* path, struct fuse_file_info* fi) {
|
||||
DEBUG("%d\n", fi->flags & O_ACCMODE);
|
||||
int err = 0;
|
||||
char *full_path = g_strdup_printf("%s%s", ftpfs.host, path + 1);
|
||||
|
||||
struct ftpfs_file* fh =
|
||||
(struct ftpfs_file*) malloc(sizeof(struct ftpfs_file));
|
||||
buf_init(&fh->buf, 0);
|
||||
fh->dirty = 0;
|
||||
fh->copied = 0;
|
||||
fh->last_offset = 0;
|
||||
fi->fh = (unsigned long) fh;
|
||||
|
||||
if ((fi->flags & O_ACCMODE) == O_RDONLY) {
|
||||
// If it's read-only, we can load the file a bit at a time, as necessary.
|
||||
DEBUG("opening %s O_RDONLY\n", path);
|
||||
size_t size = ftpfs_read_chunk(full_path, NULL, 4096, 0, fi, 0);
|
||||
|
||||
if (size == CURLFTPFS_BAD_READ) {
|
||||
err = -EACCES;
|
||||
buf_free(&fh->buf);
|
||||
free(fh);
|
||||
}
|
||||
} else if ((fi->flags & O_ACCMODE) == O_WRONLY ||
|
||||
(fi->flags & O_ACCMODE) == O_RDWR) {
|
||||
// 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.
|
||||
DEBUG("opening %s O_WRONLY or O_RDWR\n", path);
|
||||
pthread_mutex_lock(&ftpfs.lock);
|
||||
curl_multi_remove_handle(ftpfs.multi, ftpfs.connection);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_WRITEDATA, &fh->buf);
|
||||
CURLcode curl_res = curl_easy_perform(ftpfs.connection);
|
||||
pthread_mutex_unlock(&ftpfs.lock);
|
||||
|
||||
if (curl_res != 0) {
|
||||
err = -EACCES;
|
||||
buf_free(&fh->buf);
|
||||
free(fh);
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ftpfs_read(const char* path, char* rbuf, size_t size, off_t offset,
|
||||
struct fuse_file_info* fi) {
|
||||
(void) path;
|
||||
struct ftpfs_file* fh = (struct ftpfs_file*) (uintptr_t) fi->fh;
|
||||
if (offset >= fh->buf.len) return 0;
|
||||
if (size > fh->buf.len - offset) {
|
||||
size = fh->buf.len - offset;
|
||||
}
|
||||
memcpy(rbuf, fh->buf.p + offset, size);
|
||||
|
||||
return size;
|
||||
char *full_path = g_strdup_printf("%s%s", ftpfs.host, path + 1);
|
||||
int ret = ftpfs_read_chunk(full_path, rbuf, size, offset, fi, 1);
|
||||
free(full_path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ftpfs_mknod(const char* path, mode_t mode, dev_t rdev) {
|
||||
@@ -430,6 +555,7 @@ static int ftpfs_mknod(const char* path, mode_t mode, dev_t rdev) {
|
||||
char *full_path = g_strdup_printf("%s%s", ftpfs.host, path + 1);
|
||||
|
||||
pthread_mutex_lock(&ftpfs.lock);
|
||||
curl_multi_remove_handle(ftpfs.multi, ftpfs.connection);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_INFILESIZE, 0);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_UPLOAD, 1);
|
||||
@@ -485,6 +611,7 @@ static int ftpfs_rmdir(const char* path) {
|
||||
header = curl_slist_append(header, cmd);
|
||||
|
||||
pthread_mutex_lock(&ftpfs.lock);
|
||||
curl_multi_remove_handle(ftpfs.multi, ftpfs.connection);
|
||||
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_WRITEDATA, &buf);
|
||||
@@ -517,6 +644,7 @@ static int ftpfs_mkdir(const char* path, mode_t mode) {
|
||||
header = curl_slist_append(header, cmd);
|
||||
|
||||
pthread_mutex_lock(&ftpfs.lock);
|
||||
curl_multi_remove_handle(ftpfs.multi, ftpfs.connection);
|
||||
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_WRITEDATA, &buf);
|
||||
@@ -548,6 +676,7 @@ static int ftpfs_unlink(const char* path) {
|
||||
header = curl_slist_append(header, cmd);
|
||||
|
||||
pthread_mutex_lock(&ftpfs.lock);
|
||||
curl_multi_remove_handle(ftpfs.multi, ftpfs.connection);
|
||||
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_WRITEDATA, &buf);
|
||||
@@ -594,20 +723,21 @@ static int ftpfs_flush(const char *path, struct fuse_file_info *fi) {
|
||||
char* full_path = g_strdup_printf("%s%s", ftpfs.host, path + 1);
|
||||
|
||||
pthread_mutex_lock(&ftpfs.lock);
|
||||
curl_multi_remove_handle(ftpfs.multi, ftpfs.connection);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, full_path);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_INFILESIZE, fh->buf.len);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_UPLOAD, 1);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_READDATA, fh);
|
||||
CURLcode curl_res = curl_easy_perform(ftpfs.connection);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_UPLOAD, 0);
|
||||
|
||||
fh->dirty = 0;
|
||||
pthread_mutex_unlock(&ftpfs.lock);
|
||||
|
||||
if (curl_res != 0) {
|
||||
err = -EPERM;
|
||||
}
|
||||
|
||||
fh->dirty = 0;
|
||||
|
||||
free(full_path);
|
||||
return err;
|
||||
}
|
||||
@@ -621,8 +751,13 @@ static int ftpfs_fsync(const char *path, int isdatasync,
|
||||
static int ftpfs_release(const char* path, struct fuse_file_info* fi) {
|
||||
struct ftpfs_file* fh = (struct ftpfs_file*) (uintptr_t) fi->fh;
|
||||
ftpfs_flush(path, fi);
|
||||
pthread_mutex_lock(&ftpfs.lock);
|
||||
if (ftpfs.current_fh == fh) {
|
||||
ftpfs.current_fh = NULL;
|
||||
}
|
||||
buf_free(&fh->buf);
|
||||
free(fh);
|
||||
pthread_mutex_unlock(&ftpfs.lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -638,6 +773,7 @@ static int ftpfs_rename(const char* from, const char* to) {
|
||||
header = curl_slist_append(header, rnto);
|
||||
|
||||
pthread_mutex_lock(&ftpfs.lock);
|
||||
curl_multi_remove_handle(ftpfs.multi, ftpfs.connection);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_POSTQUOTE, header);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, ftpfs.host);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_WRITEDATA, &buf);
|
||||
@@ -669,6 +805,7 @@ static int ftpfs_readlink(const char *path, char *linkbuf, size_t size) {
|
||||
buf_init(&buf, 0);
|
||||
|
||||
pthread_mutex_lock(&ftpfs.lock);
|
||||
curl_multi_remove_handle(ftpfs.multi, ftpfs.connection);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, dir_path);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_WRITEDATA, &buf);
|
||||
curl_res = curl_easy_perform(ftpfs.connection);
|
||||
@@ -843,43 +980,44 @@ static void usage(const char* progname) {
|
||||
"\n", progname);
|
||||
}
|
||||
|
||||
static void set_common_curl_stuff() {
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_WRITEFUNCTION, read_data);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_READFUNCTION, write_data);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_ERRORBUFFER, error_buf);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_URL, ftpfs.host);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
|
||||
static void set_common_curl_stuff(CURL* easy) {
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_WRITEFUNCTION, read_data);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_READFUNCTION, write_data);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_ERRORBUFFER, error_buf);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_URL, ftpfs.host);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_NOSIGNAL, 1);
|
||||
|
||||
if (ftpfs.verbose) {
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_VERBOSE, TRUE);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_VERBOSE, TRUE);
|
||||
}
|
||||
|
||||
if (ftpfs.disable_epsv) {
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_FTP_USE_EPSV, FALSE);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_FTP_USE_EPSV, FALSE);
|
||||
}
|
||||
|
||||
if (ftpfs.skip_pasv_ip) {
|
||||
#ifdef CURLOPT_FTP_SKIP_PASV_IP
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_FTP_SKIP_PASV_IP, TRUE);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_FTP_SKIP_PASV_IP, TRUE);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ftpfs.ftp_port) {
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_FTPPORT, ftpfs.ftp_port);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_FTPPORT, ftpfs.ftp_port);
|
||||
}
|
||||
|
||||
if (ftpfs.disable_eprt) {
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_FTP_USE_EPRT, FALSE);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_FTP_USE_EPRT, FALSE);
|
||||
}
|
||||
|
||||
if (ftpfs.tcp_nodelay) {
|
||||
#ifdef CURLOPT_TCP_NODELAY
|
||||
/* CURLOPT_TCP_NODELAY is not defined in older versions */
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_TCP_NODELAY, 1);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_TCP_NODELAY, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_CONNECTTIMEOUT, ftpfs.connect_timeout);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_CONNECTTIMEOUT, ftpfs.connect_timeout);
|
||||
|
||||
/* CURLFTPSSL_CONTROL and CURLFTPSSL_ALL should make the connection fail if
|
||||
* the server doesn't support SSL but libcurl only honors this beginning
|
||||
@@ -901,75 +1039,79 @@ static void set_common_curl_stuff() {
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_FTP_SSL, ftpfs.use_ssl);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_FTP_SSL, ftpfs.use_ssl);
|
||||
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_SSLCERT, ftpfs.cert);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_SSLCERTTYPE, ftpfs.cert_type);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_SSLKEY, ftpfs.key);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_SSLKEYTYPE, ftpfs.key_type);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_SSLKEYPASSWD, ftpfs.key_password);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_SSLCERT, ftpfs.cert);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_SSLCERTTYPE, ftpfs.cert_type);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_SSLKEY, ftpfs.key);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_SSLKEYTYPE, ftpfs.key_type);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_SSLKEYPASSWD, ftpfs.key_password);
|
||||
|
||||
if (ftpfs.engine) {
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_SSLENGINE, ftpfs.engine);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_SSLENGINE_DEFAULT, 1);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_SSLENGINE, ftpfs.engine);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_SSLENGINE_DEFAULT, 1);
|
||||
}
|
||||
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_SSL_VERIFYPEER, TRUE);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_SSL_VERIFYPEER, TRUE);
|
||||
if (ftpfs.no_verify_peer) {
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_SSL_VERIFYPEER, FALSE);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_SSL_VERIFYPEER, FALSE);
|
||||
}
|
||||
|
||||
if (ftpfs.cacert || ftpfs.capath) {
|
||||
if (ftpfs.cacert) {
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_CAINFO, ftpfs.cacert);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_CAINFO, ftpfs.cacert);
|
||||
}
|
||||
if (ftpfs.capath) {
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_CAPATH, ftpfs.capath);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_CAPATH, ftpfs.capath);
|
||||
}
|
||||
}
|
||||
|
||||
if (ftpfs.ciphers) {
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_SSL_CIPHER_LIST, ftpfs.ciphers);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_SSL_CIPHER_LIST, ftpfs.ciphers);
|
||||
}
|
||||
|
||||
if (ftpfs.no_verify_hostname) {
|
||||
/* The default is 2 which verifies even the host string. This sets to 1
|
||||
* which means verify the host but not the string. */
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_SSL_VERIFYHOST, 1);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_SSL_VERIFYHOST, 1);
|
||||
}
|
||||
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_INTERFACE, ftpfs.interface);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_KRB4LEVEL, ftpfs.krb4);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_INTERFACE, ftpfs.interface);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_KRB4LEVEL, ftpfs.krb4);
|
||||
|
||||
if (ftpfs.proxy) {
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_PROXY, ftpfs.proxy);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_PROXY, ftpfs.proxy);
|
||||
/* Connection to FTP servers only make sense with a tunnel proxy */
|
||||
}
|
||||
if (ftpfs.proxy || ftpfs.proxytunnel) {
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_HTTPPROXYTUNNEL, TRUE);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_HTTPPROXYTUNNEL, TRUE);
|
||||
}
|
||||
|
||||
if (ftpfs.proxyanyauth) {
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
|
||||
} else if (ftpfs.proxyntlm) {
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
|
||||
} else if (ftpfs.proxydigest) {
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
|
||||
} else if (ftpfs.proxybasic) {
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
|
||||
}
|
||||
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_USERPWD, ftpfs.user);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_PROXYUSERPWD, ftpfs.proxy_user);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_SSLVERSION, ftpfs.ssl_version);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_IPRESOLVE, ftpfs.ip_version);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_USERPWD, ftpfs.user);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_PROXYUSERPWD, ftpfs.proxy_user);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_SSLVERSION, ftpfs.ssl_version);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_IPRESOLVE, ftpfs.ip_version);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int res;
|
||||
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
|
||||
CURLcode curl_res;
|
||||
CURL* easy;
|
||||
|
||||
// Initialize curl library before we are a multithreaded program
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
|
||||
memset(&ftpfs, 0, sizeof(ftpfs));
|
||||
|
||||
ftpfs.curl_version = curl_version_info(CURLVERSION_NOW);
|
||||
@@ -986,8 +1128,8 @@ int main(int argc, char** argv) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ftpfs.connection = curl_easy_init();
|
||||
if (ftpfs.connection == NULL) {
|
||||
easy = curl_easy_init();
|
||||
if (easy == NULL) {
|
||||
fprintf(stderr, "Error initializing libcurl\n");
|
||||
exit(1);
|
||||
}
|
||||
@@ -1009,21 +1151,29 @@ int main(int argc, char** argv) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
set_common_curl_stuff();
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_WRITEDATA, NULL);
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_NOBODY, ftpfs.safe_nobody);
|
||||
curl_res = curl_easy_perform(ftpfs.connection);
|
||||
set_common_curl_stuff(easy);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_WRITEDATA, NULL);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_NOBODY, ftpfs.safe_nobody);
|
||||
curl_res = curl_easy_perform(easy);
|
||||
if (curl_res != 0) {
|
||||
fprintf(stderr, "Error connecting to ftp: %s\n", error_buf);
|
||||
exit(1);
|
||||
}
|
||||
curl_easy_setopt_or_die(ftpfs.connection, CURLOPT_NOBODY, 0);
|
||||
curl_easy_setopt_or_die(easy, CURLOPT_NOBODY, 0);
|
||||
|
||||
ftpfs.multi = curl_multi_init();
|
||||
if (ftpfs.multi == NULL) {
|
||||
fprintf(stderr, "Error initializing libcurl multi\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ftpfs.connection = easy;
|
||||
pthread_mutex_init(&ftpfs.lock, NULL);
|
||||
|
||||
res = fuse_main(args.argc, args.argv, cache_init(&ftpfs_oper));
|
||||
|
||||
curl_easy_cleanup(ftpfs.connection);
|
||||
|
||||
curl_easy_cleanup(easy);
|
||||
curl_global_cleanup();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
3
ftpfs.h
3
ftpfs.h
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <curl/easy.h>
|
||||
#include <pthread.h>
|
||||
#include <glib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
@@ -11,6 +12,8 @@ struct ftpfs {
|
||||
char* mountpoint;
|
||||
pthread_mutex_t lock;
|
||||
CURL* connection;
|
||||
CURLM* multi;
|
||||
struct ftpfs_file* current_fh;
|
||||
unsigned blksize;
|
||||
GHashTable *filetab;
|
||||
int verbose;
|
||||
|
Reference in New Issue
Block a user