|
|
|
@@ -8,7 +8,6 @@
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
|
#include <bsd/readpassphrase.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
@@ -73,7 +72,7 @@ static int buf_resize(struct buffer *buf, size_t len)
|
|
|
|
|
buf->size = (buf->len + len + 63) & ~31;
|
|
|
|
|
buf->p = (uint8_t *) realloc(buf->p, buf->size);
|
|
|
|
|
if (!buf->p) {
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "ftpfs: memory allocation failed\n");
|
|
|
|
|
fprintf(stderr, "ftpfs: memory allocation failed\n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
@@ -130,8 +129,6 @@ enum {
|
|
|
|
|
|
|
|
|
|
static struct fuse_opt ftpfs_opts[] = {
|
|
|
|
|
FTPFS_OPT("ftpfs_debug=%u", debug, 0),
|
|
|
|
|
FTPFS_OPT("stderr_path=%s", stderr_path, 0),
|
|
|
|
|
FTPFS_OPT("stderr_fd=%u", stderr_fd, 2),
|
|
|
|
|
FTPFS_OPT("transform_symlinks", transform_symlinks, 1),
|
|
|
|
|
FTPFS_OPT("disable_epsv", disable_epsv, 1),
|
|
|
|
|
FTPFS_OPT("enable_epsv", disable_epsv, 0),
|
|
|
|
@@ -177,7 +174,6 @@ static struct fuse_opt ftpfs_opts[] = {
|
|
|
|
|
FTPFS_OPT("codepage=%s", codepage, 0),
|
|
|
|
|
FTPFS_OPT("iocharset=%s", iocharset, 0),
|
|
|
|
|
FTPFS_OPT("nomulticonn", multiconn, 0),
|
|
|
|
|
FTPFS_OPT("exit_after_connect", exit_after_connect, 1),
|
|
|
|
|
|
|
|
|
|
FUSE_OPT_KEY("-h", KEY_HELP),
|
|
|
|
|
FUSE_OPT_KEY("--help", KEY_HELP),
|
|
|
|
@@ -212,7 +208,7 @@ static void cancel_previous_multi()
|
|
|
|
|
CURLMcode curlMCode = curl_multi_remove_handle(ftpfs.multi, ftpfs.connection);
|
|
|
|
|
if (curlMCode != CURLE_OK)
|
|
|
|
|
{
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "curl_multi_remove_handle problem: %d\n", curlMCode);
|
|
|
|
|
fprintf(stderr, "curl_multi_remove_handle problem: %d\n", curlMCode);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
ftpfs.attached_to_multi = 0;
|
|
|
|
@@ -225,12 +221,11 @@ static int op_return(int err, char * operation)
|
|
|
|
|
DEBUG(2, "%s successful\n", operation);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "ftpfs: operation %s failed because %s. inner: %s\n", operation, strerror(-err), error_buf);
|
|
|
|
|
fprintf(stderr, "ftpfs: operation %s failed because %s\n", operation, strerror(-err));
|
|
|
|
|
if (strstr(error_buf, "timed out") != NULL
|
|
|
|
|
|| strstr(error_buf, "timeout") != NULL
|
|
|
|
|
|| strstr(error_buf, "time-out") != NULL) {
|
|
|
|
|
// try to match any curl error which would indiciate that the mount is offline.
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "exiting due to timeout\n");
|
|
|
|
|
fuse_exit(fuse_get_context()->fuse);
|
|
|
|
|
}
|
|
|
|
|
return err;
|
|
|
|
@@ -266,7 +261,7 @@ static size_t read_data(void *ptr, size_t size, size_t nmemb, void *data) {
|
|
|
|
|
do {\
|
|
|
|
|
CURLcode res = curl_easy_setopt(handle, option, __VA_ARGS__);\
|
|
|
|
|
if (res != CURLE_OK) {\
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "Error setting curl option %d: %s\n", option, error_buf);\
|
|
|
|
|
fprintf(stderr, "Error setting curl: %s\n", error_buf);\
|
|
|
|
|
exit(1);\
|
|
|
|
|
}\
|
|
|
|
|
}while(0)
|
|
|
|
@@ -275,10 +270,7 @@ static int ftpfs_readdir(const char* path, void *dbuf, fuse_fill_dir_t filler,
|
|
|
|
|
off_t offset, struct fuse_file_info *fi,
|
|
|
|
|
enum fuse_readdir_flags flags) {
|
|
|
|
|
// N.B.: fuse.h tells us that we can ignore `offset` and pass 0 to the filler where it would expect an offset.
|
|
|
|
|
(void) offset;
|
|
|
|
|
// fuse_cache_dirfil_t handle = (struct dir_handle*) fi->fh; //< set by us in `open`
|
|
|
|
|
(void) fi;
|
|
|
|
|
(void) flags; //< TODO(colin): is this safe to ignore?
|
|
|
|
|
|
|
|
|
|
int err = 0;
|
|
|
|
|
CURLcode curl_res;
|
|
|
|
@@ -310,8 +302,6 @@ static int ftpfs_readdir(const char* path, void *dbuf, fuse_fill_dir_t filler,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int ftpfs_getattr(const char* path, struct stat* sbuf, struct fuse_file_info* fi) {
|
|
|
|
|
(void) fi; //< TODO(colin): is this safe to ignore?
|
|
|
|
|
|
|
|
|
|
int err;
|
|
|
|
|
CURLcode curl_res;
|
|
|
|
|
char* dir_path = get_dir_path(path);
|
|
|
|
@@ -329,15 +319,13 @@ static int ftpfs_getattr(const char* path, struct stat* sbuf, struct fuse_file_i
|
|
|
|
|
|
|
|
|
|
if (curl_res != 0) {
|
|
|
|
|
DEBUG(1, "%s\n", error_buf);
|
|
|
|
|
err = -EIO;
|
|
|
|
|
} else {
|
|
|
|
|
buf_null_terminate(&buf);
|
|
|
|
|
|
|
|
|
|
char* name = strrchr(path, '/');
|
|
|
|
|
++name;
|
|
|
|
|
err = parse_dir((char*)buf.p, dir_path + strlen(ftpfs.host) - 1,
|
|
|
|
|
name, sbuf, NULL, 0, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
buf_null_terminate(&buf);
|
|
|
|
|
|
|
|
|
|
char* name = strrchr(path, '/');
|
|
|
|
|
++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);
|
|
|
|
@@ -360,12 +348,12 @@ static size_t ftpfs_read_chunk(const char* full_path, char* rbuf,
|
|
|
|
|
int err = 0;
|
|
|
|
|
struct ftpfs_file* fh = get_ftpfs_file(fi);
|
|
|
|
|
|
|
|
|
|
DEBUG(2, "ftpfs_read_chunk: %s %p %zu %ld %p %p\n",
|
|
|
|
|
DEBUG(2, "ftpfs_read_chunk: %s %p %zu %lld %p %p\n",
|
|
|
|
|
full_path, rbuf, size, offset, fi, fh);
|
|
|
|
|
|
|
|
|
|
pthread_mutex_lock(&ftpfs.lock);
|
|
|
|
|
|
|
|
|
|
DEBUG(2, "buffer size: %zu %ld\n", fh->buf.len, fh->buf.begin_offset);
|
|
|
|
|
DEBUG(2, "buffer size: %zu %lld\n", fh->buf.len, fh->buf.begin_offset);
|
|
|
|
|
|
|
|
|
|
if ((fh->buf.len < size + offset - fh->buf.begin_offset) ||
|
|
|
|
|
offset < fh->buf.begin_offset ||
|
|
|
|
@@ -377,7 +365,7 @@ static size_t ftpfs_read_chunk(const char* full_path, char* rbuf,
|
|
|
|
|
!check_running()) {
|
|
|
|
|
DEBUG(1, "We need to restart the connection %p\n", ftpfs.connection);
|
|
|
|
|
DEBUG(2, "current_fh=%p fh=%p\n", ftpfs.current_fh, fh);
|
|
|
|
|
DEBUG(2, "buf.begin_offset=%ld offset=%ld\n", fh->buf.begin_offset, offset);
|
|
|
|
|
DEBUG(2, "buf.begin_offset=%lld offset=%lld\n", fh->buf.begin_offset, offset);
|
|
|
|
|
|
|
|
|
|
buf_clear(&fh->buf);
|
|
|
|
|
fh->buf.begin_offset = offset;
|
|
|
|
@@ -396,7 +384,7 @@ static size_t ftpfs_read_chunk(const char* full_path, char* rbuf,
|
|
|
|
|
CURLMcode curlMCode = curl_multi_add_handle(ftpfs.multi, ftpfs.connection);
|
|
|
|
|
if (curlMCode != CURLE_OK)
|
|
|
|
|
{
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "curl_multi_add_handle problem: %d\n", curlMCode);
|
|
|
|
|
fprintf(stderr, "curl_multi_add_handle problem: %d\n", curlMCode);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
ftpfs.attached_to_multi = 1;
|
|
|
|
@@ -526,9 +514,9 @@ int write_thread_ctr = 0;
|
|
|
|
|
|
|
|
|
|
static void *ftpfs_write_thread(void *data) {
|
|
|
|
|
struct ftpfs_file *fh = data;
|
|
|
|
|
//char range[15];
|
|
|
|
|
char range[15];
|
|
|
|
|
|
|
|
|
|
DEBUG(2, "enter streaming write thread #%d path=%s pos=%ld\n", ++write_thread_ctr, fh->full_path, fh->pos);
|
|
|
|
|
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);
|
|
|
|
@@ -579,7 +567,7 @@ static int start_write_thread(struct ftpfs_file *fh)
|
|
|
|
|
{
|
|
|
|
|
if (fh->write_conn != NULL)
|
|
|
|
|
{
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "assert fh->write_conn == NULL failed!\n");
|
|
|
|
|
fprintf(stderr, "assert fh->write_conn == NULL failed!\n");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -593,14 +581,14 @@ static int start_write_thread(struct ftpfs_file *fh)
|
|
|
|
|
|
|
|
|
|
fh->write_conn = curl_easy_init();
|
|
|
|
|
if (fh->write_conn == NULL) {
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "Error initializing libcurl\n");
|
|
|
|
|
fprintf(stderr, "Error initializing libcurl\n");
|
|
|
|
|
return 0;
|
|
|
|
|
} else {
|
|
|
|
|
int err;
|
|
|
|
|
set_common_curl_stuff(fh->write_conn);
|
|
|
|
|
err = pthread_create(&fh->thread_id, NULL, ftpfs_write_thread, fh);
|
|
|
|
|
if (err) {
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "failed to create thread: %s\n", strerror(err));
|
|
|
|
|
fprintf(stderr, "failed to create thread: %s\n", strerror(err));
|
|
|
|
|
/* FIXME: destroy curl_easy */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@@ -648,23 +636,23 @@ static void free_ftpfs_file(struct ftpfs_file *fh) {
|
|
|
|
|
free(fh);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// static int buffer_file(struct ftpfs_file *fh) {
|
|
|
|
|
// // 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_WRITEDATA, &fh->buf);
|
|
|
|
|
// CURLcode curl_res = curl_easy_perform(ftpfs.connection);
|
|
|
|
|
// pthread_mutex_unlock(&ftpfs.lock);
|
|
|
|
|
//
|
|
|
|
|
// if (curl_res != 0) {
|
|
|
|
|
// return -EACCES;
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// return 0;
|
|
|
|
|
// }
|
|
|
|
|
static int buffer_file(struct ftpfs_file *fh) {
|
|
|
|
|
// 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_WRITEDATA, &fh->buf);
|
|
|
|
|
CURLcode curl_res = curl_easy_perform(ftpfs.connection);
|
|
|
|
|
pthread_mutex_unlock(&ftpfs.lock);
|
|
|
|
|
|
|
|
|
|
if (curl_res != 0) {
|
|
|
|
|
return -EACCES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int create_empty_file(const char * path)
|
|
|
|
|
{
|
|
|
|
@@ -766,7 +754,7 @@ static int ftpfs_open_common(const char* path, mode_t mode,
|
|
|
|
|
size_t size = ftpfs_read_chunk(fh->full_path, NULL, 1, 0, fi, 0);
|
|
|
|
|
|
|
|
|
|
if (size == CURLFTPFS_BAD_READ) {
|
|
|
|
|
DEBUG(1, "initial read failed size=%zu\n", size);
|
|
|
|
|
DEBUG(1, "initial read failed size=%d\n", size);
|
|
|
|
|
err = -EACCES;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -853,11 +841,11 @@ static int ftpfs_read(const char* path, char* rbuf, size_t size, off_t offset,
|
|
|
|
|
int ret;
|
|
|
|
|
struct ftpfs_file *fh = get_ftpfs_file(fi);
|
|
|
|
|
|
|
|
|
|
DEBUG(1, "ftpfs_read: %s size=%zu offset=%ld has_write_conn=%d pos=%ld\n", path, size, offset, fh->write_conn!=0, fh->pos);
|
|
|
|
|
DEBUG(1, "ftpfs_read: %s size=%zu offset=%lld has_write_conn=%d pos=%lld\n", path, size, (long long) offset, fh->write_conn!=0, fh->pos);
|
|
|
|
|
|
|
|
|
|
if (fh->pos>0 || fh->write_conn!=NULL)
|
|
|
|
|
{
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "in read/write mode we cannot read from a file that has already been written to\n");
|
|
|
|
|
fprintf(stderr, "in read/write mode we cannot read from a file that has already been written to\n");
|
|
|
|
|
return op_return(-EIO, "ftpfs_read");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -893,7 +881,6 @@ static int ftpfs_mknod(const char* path, mode_t mode, dev_t rdev) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int ftpfs_chmod(const char* path, mode_t mode, struct fuse_file_info* fi) {
|
|
|
|
|
(void) fi; //< TODO(colin): is this safe to ignore?
|
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
|
|
// We can only process a subset of the mode - so strip
|
|
|
|
@@ -935,7 +922,7 @@ static int ftpfs_chmod(const char* path, mode_t mode, struct fuse_file_info* fi)
|
|
|
|
|
static int ftpfs_chown(const char* path, uid_t uid, gid_t gid, struct fuse_file_info* fi) {
|
|
|
|
|
int err = 0;
|
|
|
|
|
|
|
|
|
|
DEBUG(1, "ftpfs_chown: %d %d %p\n", (int)uid, (int)gid, fi);
|
|
|
|
|
DEBUG(1, "ftpfs_chown: %d %d %u\n", (int)uid, (int)gid, fi);
|
|
|
|
|
|
|
|
|
|
struct curl_slist* header = NULL;
|
|
|
|
|
char* full_path = get_dir_path(path);
|
|
|
|
@@ -974,7 +961,7 @@ static int ftpfs_chown(const char* path, uid_t uid, gid_t gid, struct fuse_file_
|
|
|
|
|
|
|
|
|
|
static int ftpfs_ftruncate(const char * path , off_t offset, struct fuse_file_info * fi)
|
|
|
|
|
{
|
|
|
|
|
DEBUG(1, "ftpfs_ftruncate: %s len=%ld\n", path, offset);
|
|
|
|
|
DEBUG(1, "ftpfs_ftruncate: %s len=%lld\n", path, offset);
|
|
|
|
|
struct ftpfs_file *fh = get_ftpfs_file(fi);
|
|
|
|
|
|
|
|
|
|
if (offset == 0)
|
|
|
|
@@ -1003,7 +990,7 @@ static int ftpfs_truncate(const char* path, off_t offset, struct fuse_file_info*
|
|
|
|
|
if (fi)
|
|
|
|
|
return ftpfs_ftruncate(path, offset, fi);
|
|
|
|
|
|
|
|
|
|
DEBUG(1, "ftpfs_truncate: %s len=%ld\n", path, offset);
|
|
|
|
|
DEBUG(1, "ftpfs_truncate: %s len=%lld\n", path, offset);
|
|
|
|
|
/* we can't use ftpfs_mknod here, because we don't know the right permissions */
|
|
|
|
|
if (offset == 0) return op_return(create_empty_file(path), "ftpfs_truncate");
|
|
|
|
|
|
|
|
|
@@ -1021,10 +1008,9 @@ static int ftpfs_truncate(const char* path, off_t offset, struct fuse_file_info*
|
|
|
|
|
return op_return(-EPERM, "ftpfs_truncate");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int ftpfs_utimens(const char* path, const struct timespec* time, struct fuse_file_info* fi) {
|
|
|
|
|
static int ftpfs_utimens(const char* path, struct utimbuf* time, struct fuse_file_info* fi) {
|
|
|
|
|
(void) path;
|
|
|
|
|
(void) time;
|
|
|
|
|
(void) fi;
|
|
|
|
|
return op_return(0, "ftpfs_utimens");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1142,7 +1128,7 @@ static int ftpfs_write(const char *path, const char *wbuf, size_t size,
|
|
|
|
|
(void) path;
|
|
|
|
|
struct ftpfs_file *fh = get_ftpfs_file(fi);
|
|
|
|
|
|
|
|
|
|
DEBUG(1, "ftpfs_write: %s size=%zu offset=%ld has_write_conn=%d pos=%ld\n", path, size, offset, fh->write_conn!=0, fh->pos);
|
|
|
|
|
DEBUG(1, "ftpfs_write: %s size=%zu offset=%lld has_write_conn=%d pos=%lld\n", path, size, (long long) offset, fh->write_conn!=0, fh->pos);
|
|
|
|
|
|
|
|
|
|
if (fh->write_fail_cause != CURLE_OK)
|
|
|
|
|
{
|
|
|
|
@@ -1152,7 +1138,7 @@ static int ftpfs_write(const char *path, const char *wbuf, size_t size,
|
|
|
|
|
|
|
|
|
|
if (!fh->write_conn && fh->pos == 0 && offset == 0)
|
|
|
|
|
{
|
|
|
|
|
DEBUG(1, "ftpfs_write: starting a streaming write at pos=%ld\n", fh->pos);
|
|
|
|
|
DEBUG(1, "ftpfs_write: starting a streaming write at pos=%lld\n", fh->pos);
|
|
|
|
|
|
|
|
|
|
/* check if the file has been truncated to zero or has been newly created */
|
|
|
|
|
if (!fh->write_may_start)
|
|
|
|
@@ -1160,7 +1146,7 @@ static int ftpfs_write(const char *path, const char *wbuf, size_t size,
|
|
|
|
|
long long size = (long long int)test_size(path);
|
|
|
|
|
if (size != 0)
|
|
|
|
|
{
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "ftpfs_write: start writing with no previous truncate not allowed! size check rval=%lld\n", size);
|
|
|
|
|
fprintf(stderr, "ftpfs_write: start writing with no previous truncate not allowed! size check rval=%lld\n", size);
|
|
|
|
|
return op_return(-EIO, "ftpfs_write");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -1177,7 +1163,7 @@ static int ftpfs_write(const char *path, const char *wbuf, size_t size,
|
|
|
|
|
if (!fh->write_conn && fh->pos >0 && offset == fh->pos)
|
|
|
|
|
{
|
|
|
|
|
/* resume a streaming write */
|
|
|
|
|
DEBUG(1, "ftpfs_write: resuming a streaming write at pos=%ld\n", fh->pos);
|
|
|
|
|
DEBUG(1, "ftpfs_write: resuming a streaming write at pos=%lld\n", fh->pos);
|
|
|
|
|
|
|
|
|
|
int success = start_write_thread(fh);
|
|
|
|
|
if (!success)
|
|
|
|
@@ -1229,31 +1215,31 @@ static int ftpfs_flush(const char *path, struct fuse_file_info *fi) {
|
|
|
|
|
int err = 0;
|
|
|
|
|
struct ftpfs_file* fh = get_ftpfs_file(fi);
|
|
|
|
|
|
|
|
|
|
DEBUG(1, "ftpfs_flush: buf.len=%zu buf.pos=%ld write_conn=%d\n", fh->buf.len, fh->pos, fh->write_conn!=0);
|
|
|
|
|
|
|
|
|
|
DEBUG(1, "ftpfs_flush: buf.len=%zu buf.pos=%lld write_conn=%d\n", fh->buf.len, fh->pos, fh->write_conn!=0);
|
|
|
|
|
|
|
|
|
|
if (fh->write_conn) {
|
|
|
|
|
err = finish_write_thread(fh);
|
|
|
|
|
if (err) return op_return(err, "ftpfs_flush");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct stat sbuf;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* check if the resulting file has the correct size
|
|
|
|
|
this is important, because we use APPE for continuing
|
|
|
|
|
writing after a premature flush */
|
|
|
|
|
err = ftpfs_getattr(path, &sbuf, fi);
|
|
|
|
|
if (err) return op_return(err, "ftpfs_flush");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (sbuf.st_size != fh->pos)
|
|
|
|
|
{
|
|
|
|
|
fh->write_fail_cause = -999;
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "ftpfs_flush: check filesize problem: size=%ld expected=%ld\n", sbuf.st_size, fh->pos);
|
|
|
|
|
return op_return(-EIO, "ftpfs_flush");
|
|
|
|
|
fh->write_fail_cause = -999;
|
|
|
|
|
fprintf(stderr, "ftpfs_flush: check filesize problem: size=%lld expected=%lld\n", sbuf.st_size, fh->pos);
|
|
|
|
|
return op_return(-EIO, "ftpfs_flush");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!fh->dirty) return 0;
|
|
|
|
|
|
|
|
|
|
return op_return(-EIO, "ftpfs_flush");
|
|
|
|
@@ -1350,15 +1336,13 @@ static int ftpfs_readlink(const char *path, char *linkbuf, size_t size) {
|
|
|
|
|
|
|
|
|
|
if (curl_res != 0) {
|
|
|
|
|
DEBUG(1, "%s\n", error_buf);
|
|
|
|
|
err = -EIO;
|
|
|
|
|
} else {
|
|
|
|
|
buf_null_terminate(&buf);
|
|
|
|
|
|
|
|
|
|
char* name = strrchr(path, '/');
|
|
|
|
|
++name;
|
|
|
|
|
err = parse_dir((char*)buf.p, dir_path + strlen(ftpfs.host) - 1,
|
|
|
|
|
name, NULL, linkbuf, size, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
buf_null_terminate(&buf);
|
|
|
|
|
|
|
|
|
|
char* name = strrchr(path, '/');
|
|
|
|
|
++name;
|
|
|
|
|
err = parse_dir((char*)buf.p, dir_path + strlen(ftpfs.host) - 1,
|
|
|
|
|
name, NULL, linkbuf, size, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
free(dir_path);
|
|
|
|
|
buf_free(&buf);
|
|
|
|
@@ -1451,7 +1435,7 @@ static int ftpfs_opt_proc(void* data, const char* arg, int key,
|
|
|
|
|
ftpfs.verbose = 1;
|
|
|
|
|
return 0;
|
|
|
|
|
case KEY_VERSION:
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "curlftpfs %s libcurl/%s fuse/%u.%u\n",
|
|
|
|
|
fprintf(stderr, "curlftpfs %s libcurl/%s fuse/%u.%u\n",
|
|
|
|
|
VERSION,
|
|
|
|
|
ftpfs.curl_version->version,
|
|
|
|
|
FUSE_MAJOR_VERSION,
|
|
|
|
@@ -1474,8 +1458,6 @@ static void usage(const char* progname) {
|
|
|
|
|
"\n"
|
|
|
|
|
"FTP options:\n"
|
|
|
|
|
" ftpfs_debug print some debugging information\n"
|
|
|
|
|
" stderr_path=STR log stderr to path\n"
|
|
|
|
|
" stderr_fd=N log stderr to file descriptor\n"
|
|
|
|
|
" transform_symlinks prepend mountpoint to absolute symlink targets\n"
|
|
|
|
|
" disable_epsv use PASV, without trying EPSV first (default)\n"
|
|
|
|
|
" enable_epsv try EPSV before reverting to PASV\n"
|
|
|
|
@@ -1520,7 +1502,6 @@ static void usage(const char* progname) {
|
|
|
|
|
" utf8 try to transfer file list with utf-8 encoding\n"
|
|
|
|
|
" codepage=STR set the codepage the server uses\n"
|
|
|
|
|
" iocharset=STR set the charset used by the client\n"
|
|
|
|
|
" exit_after_connect after connecting to the FTP server, instead of passing control to FUSE, exit\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"CurlFtpFS cache options: \n"
|
|
|
|
|
" cache=yes|no enable/disable cache (default: yes)\n"
|
|
|
|
@@ -1606,7 +1587,7 @@ static void set_common_curl_stuff(CURL* easy) {
|
|
|
|
|
* with version 7.15.4 */
|
|
|
|
|
if (ftpfs.use_ssl > CURLFTPSSL_TRY &&
|
|
|
|
|
ftpfs.curl_version->version_num <= CURLFTPFS_BAD_SSL) {
|
|
|
|
|
dprintf(ftpfs.stderr_fd,
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"WARNING: you are using libcurl %s.\n"
|
|
|
|
|
"This version of libcurl does not respect the mandatory SSL flag.\n"
|
|
|
|
|
"It will try to send the user and password even if the server doesn't support\n"
|
|
|
|
@@ -1616,10 +1597,10 @@ static void set_common_curl_stuff(CURL* easy) {
|
|
|
|
|
int i;
|
|
|
|
|
const int time_to_wait = 10;
|
|
|
|
|
for (i = 0; i < time_to_wait; i++) {
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "%d.. ", time_to_wait - i);
|
|
|
|
|
fprintf(stderr, "%d.. ", time_to_wait - i);
|
|
|
|
|
sleep(1);
|
|
|
|
|
}
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "\n");
|
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
|
}
|
|
|
|
|
curl_easy_setopt_or_die(easy, CURLOPT_FTP_SSL, ftpfs.use_ssl);
|
|
|
|
|
|
|
|
|
@@ -1703,7 +1684,6 @@ static void checkpasswd(const char *kind, /* for what purpose */
|
|
|
|
|
if(!ptr) {
|
|
|
|
|
/* no password present, prompt for one */
|
|
|
|
|
char *passwd;
|
|
|
|
|
char passwd_buf[256];
|
|
|
|
|
char prompt[256];
|
|
|
|
|
size_t passwdlen;
|
|
|
|
|
size_t userlen = strlen(*userpwd);
|
|
|
|
@@ -1715,7 +1695,7 @@ static void checkpasswd(const char *kind, /* for what purpose */
|
|
|
|
|
kind, *userpwd);
|
|
|
|
|
|
|
|
|
|
/* get password */
|
|
|
|
|
passwd = readpassphrase(prompt, passwd_buf, 256, 0 /* flags */);
|
|
|
|
|
passwd = getpass(prompt);
|
|
|
|
|
passwdlen = strlen(passwd);
|
|
|
|
|
|
|
|
|
|
/* extend the allocated memory area to fit the password too */
|
|
|
|
@@ -1756,20 +1736,9 @@ int main(int argc, char** argv) {
|
|
|
|
|
if (fuse_opt_parse(&args, &ftpfs, ftpfs_opts, ftpfs_opt_proc) == -1)
|
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
|
|
if (ftpfs.stderr_path)
|
|
|
|
|
ftpfs.stderr_fd = open(ftpfs.stderr_path, O_RDWR|O_CREAT|O_APPEND, 0644);
|
|
|
|
|
|
|
|
|
|
if (ftpfs.stderr_fd == -1) {
|
|
|
|
|
fprintf(stderr, "failed to open stderr\n");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ftpfs.debug)
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "logging configured\n");
|
|
|
|
|
|
|
|
|
|
if (!ftpfs.host) {
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "missing host\n");
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "see `%s -h' for usage\n", argv[0]);
|
|
|
|
|
fprintf(stderr, "missing host\n");
|
|
|
|
|
fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1783,7 +1752,7 @@ int main(int argc, char** argv) {
|
|
|
|
|
|
|
|
|
|
easy = curl_easy_init();
|
|
|
|
|
if (easy == NULL) {
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "Error initializing libcurl\n");
|
|
|
|
|
fprintf(stderr, "Error initializing libcurl\n");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1795,7 +1764,7 @@ int main(int argc, char** argv) {
|
|
|
|
|
checkpasswd("proxy", &ftpfs.proxy_user);
|
|
|
|
|
|
|
|
|
|
if (ftpfs.transform_symlinks && !ftpfs.mountpoint) {
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "cannot transform symlinks: no mountpoint given\n");
|
|
|
|
|
fprintf(stderr, "cannot transform symlinks: no mountpoint given\n");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
if (!ftpfs.transform_symlinks)
|
|
|
|
@@ -1812,14 +1781,14 @@ int main(int argc, char** argv) {
|
|
|
|
|
curl_easy_setopt_or_die(easy, CURLOPT_NOBODY, ftpfs.safe_nobody);
|
|
|
|
|
curl_res = curl_easy_perform(easy);
|
|
|
|
|
if (curl_res != 0) {
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "Error connecting to ftp: %s\n", error_buf);
|
|
|
|
|
fprintf(stderr, "Error connecting to ftp: %s\n", error_buf);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
curl_easy_setopt_or_die(easy, CURLOPT_NOBODY, 0);
|
|
|
|
|
|
|
|
|
|
ftpfs.multi = curl_multi_init();
|
|
|
|
|
if (ftpfs.multi == NULL) {
|
|
|
|
|
dprintf(ftpfs.stderr_fd, "Error initializing libcurl multi\n");
|
|
|
|
|
fprintf(stderr, "Error initializing libcurl multi\n");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1831,10 +1800,7 @@ int main(int argc, char** argv) {
|
|
|
|
|
fuse_opt_insert_arg(&args, 1, tmp);
|
|
|
|
|
g_free(tmp);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!ftpfs.exit_after_connect) {
|
|
|
|
|
res = curlftpfs_fuse_main(&args);
|
|
|
|
|
}
|
|
|
|
|
res = curlftpfs_fuse_main(&args);
|
|
|
|
|
|
|
|
|
|
cancel_previous_multi();
|
|
|
|
|
curl_multi_cleanup(ftpfs.multi);
|
|
|
|
|