12 Commits

Author SHA1 Message Date
242be02050 path_utils.c: fix mismatched printf specifier 2024-12-27 00:39:59 +00:00
1f737a42fb include some missing includes 2024-12-27 00:38:52 +00:00
8a4635e811 cache.c: fix some compiler warnings 2024-12-27 00:12:06 +00:00
d0affffc5c ftpfs.c: remove unused variable "range" 2024-12-27 00:00:09 +00:00
7b7d769d59 ftpfs_utimens: update for fuse3, which uses timespec instead of utimbuf 2024-12-27 00:00:09 +00:00
2e7b724b2b ftpfs.c: include utime.h for struct utimbuf definition 2024-12-27 00:00:09 +00:00
ed6a9cee3d ftpfs.c: fix several compiler warnings, especially around printf specifiers 2024-12-27 00:00:09 +00:00
761dac3d64 ftpfs_readdir: specify all parameters to filler
else they may be filled with garbage instead
2024-10-23 10:03:00 +00:00
8f2d6449f7 op_return: also log the inner error, since we use that for matching against timeouts 2024-10-12 01:19:23 +00:00
ee70864395 propagate curl errors in ftpfs_getattr,ftpfs_readlink
this should address a hang, where certain timeouts ('server response timeout') wouldn't trigger fuse_exit
2024-10-12 00:55:08 +00:00
ff6f1a45dd new options: stderr_fd, stderr_path
the mount subsystem is screwy and lots of things will eat logs, so it's nice to be able to directly log to a path
2024-10-11 23:58:09 +00:00
a02006d8ec curl_easy_setopt: error path: log the option being set 2024-08-20 09:35:22 +00:00
9 changed files with 130 additions and 99 deletions

View File

@@ -107,6 +107,7 @@ static void cache_invalidate_dir(const char *path)
static void cache_do_rename(const char *from, const char *to, unsigned int flags)
{
(void) flags; //< TODO(colin): is this safe to ignore?
pthread_mutex_lock(&cache.lock);
cache_purge(from);
cache_purge(to);
@@ -129,11 +130,9 @@ static struct node *cache_get(const char *path)
void cache_add_attr(const char *path, const struct stat *stbuf)
{
struct node *node;
time_t now;
pthread_mutex_lock(&cache.lock);
node = cache_get(path);
now = time(NULL);
if (stbuf) {
node->stat = *stbuf;
node->not_found = 0;
@@ -150,11 +149,9 @@ void cache_add_attr(const char *path, const struct stat *stbuf)
void cache_add_dir(const char *path, char **dir)
{
struct node *node;
time_t now;
pthread_mutex_lock(&cache.lock);
node = cache_get(path);
now = time(NULL);
g_strfreev(node->dir);
node->dir = dir;
node->not_found = 0;
@@ -175,11 +172,9 @@ static size_t my_strnlen(const char *s, size_t maxsize)
void cache_add_link(const char *path, const char *link, size_t size)
{
struct node *node;
time_t now;
pthread_mutex_lock(&cache.lock);
node = cache_get(path);
now = time(NULL);
g_free(node->link);
node->link = g_strndup(link, my_strnlen(link, size-1));
node->not_found = 0;
@@ -330,7 +325,7 @@ static int cache_truncate(const char *path, off_t size, struct fuse_file_info *f
return err;
}
static int cache_utimens(const char *path, struct utimbuf *buf, struct fuse_file_info* fi)
static int cache_utimens(const char *path, const struct timespec *buf, struct fuse_file_info* fi)
{
int err = cache.next_oper->oper.utimens(path, buf, fi);
if (!err)

View File

@@ -18,8 +18,6 @@
#define CACHE_CLEAN_INTERVAL 60
typedef struct fuse_cache_dirhandle *fuse_cache_dirh_t;
typedef int (*fuse_cache_dirfil_t) (fuse_cache_dirh_t h, const char *name,
const struct stat *stbuf);
struct fuse_cache_operations {
struct fuse_operations oper;

View File

@@ -12,14 +12,19 @@ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
PKG_CHECK_MODULES(GLIB, [glib-2.0])
PKG_CHECK_MODULES(FUSE, [fuse3 >= 3.16])
PKG_CHECK_MODULES(BSD, [libbsd])
LIBCURL_CHECK_CONFIG([yes], [7.17.0], [], [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
CFLAGS="$CFLAGS -Wall -W -Wno-sign-compare -D_REENTRANT $GLIB_CFLAGS $FUSE_CFLAGS $LIBCURL_CPPFLAGS"
LIBS="$GLIB_LIBS $FUSE_LIBS $LIBCURL"
# _POSIX_C_SOURCE>=200809L causes glibc to provide `dprintf` in stdio.h
# - <https://linux.die.net/man/3/dprintf>
# also used by time.h for strptime
# fuse3 requires _off_t to be 8 bytes, and advises to add _FILE_OFFSET_BITS=64 for 32bit platforms.
CFLAGS="$CFLAGS -Wall -W -Wno-sign-compare -D_REENTRANT -D_POSIX_C_SOURCE=200809L -D_FILE_OFFSET_BITS=64 $BSD_CFLAGS $GLIB_CFLAGS $FUSE_CFLAGS $LIBCURL_CPPFLAGS"
LIBS="$BSD_LIBS $GLIB_LIBS $FUSE_LIBS $LIBCURL"
have_fuse_opt_parse=no
AC_CHECK_FUNC([fuse_opt_parse], [have_fuse_opt_parse=yes])

View File

@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <glib.h>
#include "cache.h"
#include "ftpfs.h"
#include "charset_utils.h"
#include "ftpfs-ls.h"
@@ -190,7 +191,7 @@ static int parse_dir_netware(const char *line,
int parse_dir(const char* list, const char* dir,
const char* name, struct stat* sbuf,
char* linkbuf, int linklen,
void *dbuf, fuse_cache_dirfil_t filler) {
void *dbuf, fuse_fill_dir_t filler) {
char *file;
char *link;
const char *start = list;
@@ -255,7 +256,7 @@ int parse_dir(const char* list, const char* dir,
if (dbuf && filler) {
DEBUG(1, "filler: %s\n", file);
filler(dbuf, file, &stat_buf);
filler(dbuf, file, &stat_buf, 0, 0);
} else {
DEBUG(1, "cache_add_attr: %s\n", full_path);
cache_add_attr(full_path, &stat_buf);

View File

@@ -9,11 +9,11 @@
See the file COPYING.
*/
#include "cache.h"
#include <fuse.h>
int parse_dir(const char* list, const char* dir,
const char* name, struct stat* sbuf,
char* linkbuf, int linklen,
void *dbuf, fuse_cache_dirfil_t filler);
void *dbuf, fuse_fill_dir_t filler);
#endif /* __CURLFTPFS_FTPFS_LS_H__ */

179
ftpfs.c
View File

@@ -8,6 +8,7 @@
#include "config.h"
#include <bsd/readpassphrase.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
@@ -72,7 +73,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) {
fprintf(stderr, "ftpfs: memory allocation failed\n");
dprintf(ftpfs.stderr_fd, "ftpfs: memory allocation failed\n");
return -1;
}
return 0;
@@ -129,6 +130,8 @@ 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),
@@ -209,7 +212,7 @@ static void cancel_previous_multi()
CURLMcode curlMCode = curl_multi_remove_handle(ftpfs.multi, ftpfs.connection);
if (curlMCode != CURLE_OK)
{
fprintf(stderr, "curl_multi_remove_handle problem: %d\n", curlMCode);
dprintf(ftpfs.stderr_fd, "curl_multi_remove_handle problem: %d\n", curlMCode);
exit(1);
}
ftpfs.attached_to_multi = 0;
@@ -222,11 +225,12 @@ static int op_return(int err, char * operation)
DEBUG(2, "%s successful\n", operation);
return 0;
}
fprintf(stderr, "ftpfs: operation %s failed because %s\n", operation, strerror(-err));
dprintf(ftpfs.stderr_fd, "ftpfs: operation %s failed because %s. inner: %s\n", operation, strerror(-err), error_buf);
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;
@@ -262,7 +266,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) {\
fprintf(stderr, "Error setting curl: %s\n", error_buf);\
dprintf(ftpfs.stderr_fd, "Error setting curl option %d: %s\n", option, error_buf);\
exit(1);\
}\
}while(0)
@@ -271,7 +275,10 @@ 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;
@@ -303,6 +310,8 @@ 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);
@@ -320,13 +329,15 @@ static int ftpfs_getattr(const char* path, struct stat* sbuf, struct fuse_file_i
if (curl_res != 0) {
DEBUG(1, "%s\n", error_buf);
}
buf_null_terminate(&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);
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);
@@ -349,12 +360,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 %lld %p %p\n",
DEBUG(2, "ftpfs_read_chunk: %s %p %zu %ld %p %p\n",
full_path, rbuf, size, offset, fi, fh);
pthread_mutex_lock(&ftpfs.lock);
DEBUG(2, "buffer size: %zu %lld\n", fh->buf.len, fh->buf.begin_offset);
DEBUG(2, "buffer size: %zu %ld\n", fh->buf.len, fh->buf.begin_offset);
if ((fh->buf.len < size + offset - fh->buf.begin_offset) ||
offset < fh->buf.begin_offset ||
@@ -366,7 +377,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=%lld offset=%lld\n", fh->buf.begin_offset, offset);
DEBUG(2, "buf.begin_offset=%ld offset=%ld\n", fh->buf.begin_offset, offset);
buf_clear(&fh->buf);
fh->buf.begin_offset = offset;
@@ -385,7 +396,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)
{
fprintf(stderr, "curl_multi_add_handle problem: %d\n", curlMCode);
dprintf(ftpfs.stderr_fd, "curl_multi_add_handle problem: %d\n", curlMCode);
exit(1);
}
ftpfs.attached_to_multi = 1;
@@ -515,9 +526,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=%lld\n", ++write_thread_ctr, fh->full_path, fh->pos);
DEBUG(2, "enter streaming write thread #%d path=%s pos=%ld\n", ++write_thread_ctr, fh->full_path, fh->pos);
curl_easy_setopt_or_die(fh->write_conn, CURLOPT_URL, fh->full_path);
@@ -568,7 +579,7 @@ static int start_write_thread(struct ftpfs_file *fh)
{
if (fh->write_conn != NULL)
{
fprintf(stderr, "assert fh->write_conn == NULL failed!\n");
dprintf(ftpfs.stderr_fd, "assert fh->write_conn == NULL failed!\n");
exit(1);
}
@@ -582,14 +593,14 @@ static int start_write_thread(struct ftpfs_file *fh)
fh->write_conn = curl_easy_init();
if (fh->write_conn == NULL) {
fprintf(stderr, "Error initializing libcurl\n");
dprintf(ftpfs.stderr_fd, "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) {
fprintf(stderr, "failed to create thread: %s\n", strerror(err));
dprintf(ftpfs.stderr_fd, "failed to create thread: %s\n", strerror(err));
/* FIXME: destroy curl_easy */
return 0;
}
@@ -637,23 +648,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)
{
@@ -755,7 +766,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=%d\n", size);
DEBUG(1, "initial read failed size=%zu\n", size);
err = -EACCES;
}
}
@@ -842,11 +853,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=%lld has_write_conn=%d pos=%lld\n", path, size, (long long) offset, fh->write_conn!=0, fh->pos);
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);
if (fh->pos>0 || fh->write_conn!=NULL)
{
fprintf(stderr, "in read/write mode we cannot read from a file that has already been written to\n");
dprintf(ftpfs.stderr_fd, "in read/write mode we cannot read from a file that has already been written to\n");
return op_return(-EIO, "ftpfs_read");
}
@@ -882,6 +893,7 @@ 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
@@ -923,7 +935,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 %u\n", (int)uid, (int)gid, fi);
DEBUG(1, "ftpfs_chown: %d %d %p\n", (int)uid, (int)gid, fi);
struct curl_slist* header = NULL;
char* full_path = get_dir_path(path);
@@ -962,7 +974,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=%lld\n", path, offset);
DEBUG(1, "ftpfs_ftruncate: %s len=%ld\n", path, offset);
struct ftpfs_file *fh = get_ftpfs_file(fi);
if (offset == 0)
@@ -991,7 +1003,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=%lld\n", path, offset);
DEBUG(1, "ftpfs_truncate: %s len=%ld\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");
@@ -1009,9 +1021,10 @@ 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, struct utimbuf* time, struct fuse_file_info* fi) {
static int ftpfs_utimens(const char* path, const struct timespec* time, struct fuse_file_info* fi) {
(void) path;
(void) time;
(void) fi;
return op_return(0, "ftpfs_utimens");
}
@@ -1129,7 +1142,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=%lld has_write_conn=%d pos=%lld\n", path, size, (long long) offset, fh->write_conn!=0, fh->pos);
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);
if (fh->write_fail_cause != CURLE_OK)
{
@@ -1139,7 +1152,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=%lld\n", fh->pos);
DEBUG(1, "ftpfs_write: starting a streaming write at pos=%ld\n", fh->pos);
/* check if the file has been truncated to zero or has been newly created */
if (!fh->write_may_start)
@@ -1147,7 +1160,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)
{
fprintf(stderr, "ftpfs_write: start writing with no previous truncate not allowed! size check rval=%lld\n", size);
dprintf(ftpfs.stderr_fd, "ftpfs_write: start writing with no previous truncate not allowed! size check rval=%lld\n", size);
return op_return(-EIO, "ftpfs_write");
}
}
@@ -1164,7 +1177,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=%lld\n", fh->pos);
DEBUG(1, "ftpfs_write: resuming a streaming write at pos=%ld\n", fh->pos);
int success = start_write_thread(fh);
if (!success)
@@ -1216,31 +1229,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=%lld write_conn=%d\n", fh->buf.len, fh->pos, fh->write_conn!=0);
DEBUG(1, "ftpfs_flush: buf.len=%zu buf.pos=%ld 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;
fprintf(stderr, "ftpfs_flush: check filesize problem: size=%lld expected=%lld\n", sbuf.st_size, fh->pos);
return op_return(-EIO, "ftpfs_flush");
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");
}
return 0;
}
if (!fh->dirty) return 0;
return op_return(-EIO, "ftpfs_flush");
@@ -1337,13 +1350,15 @@ static int ftpfs_readlink(const char *path, char *linkbuf, size_t size) {
if (curl_res != 0) {
DEBUG(1, "%s\n", error_buf);
}
buf_null_terminate(&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);
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);
@@ -1436,7 +1451,7 @@ static int ftpfs_opt_proc(void* data, const char* arg, int key,
ftpfs.verbose = 1;
return 0;
case KEY_VERSION:
fprintf(stderr, "curlftpfs %s libcurl/%s fuse/%u.%u\n",
dprintf(ftpfs.stderr_fd, "curlftpfs %s libcurl/%s fuse/%u.%u\n",
VERSION,
ftpfs.curl_version->version,
FUSE_MAJOR_VERSION,
@@ -1459,6 +1474,8 @@ 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"
@@ -1589,7 +1606,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) {
fprintf(stderr,
dprintf(ftpfs.stderr_fd,
"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"
@@ -1599,10 +1616,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++) {
fprintf(stderr, "%d.. ", time_to_wait - i);
dprintf(ftpfs.stderr_fd, "%d.. ", time_to_wait - i);
sleep(1);
}
fprintf(stderr, "\n");
dprintf(ftpfs.stderr_fd, "\n");
}
curl_easy_setopt_or_die(easy, CURLOPT_FTP_SSL, ftpfs.use_ssl);
@@ -1686,6 +1703,7 @@ 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);
@@ -1697,7 +1715,7 @@ static void checkpasswd(const char *kind, /* for what purpose */
kind, *userpwd);
/* get password */
passwd = getpass(prompt);
passwd = readpassphrase(prompt, passwd_buf, 256, 0 /* flags */);
passwdlen = strlen(passwd);
/* extend the allocated memory area to fit the password too */
@@ -1738,9 +1756,20 @@ 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) {
fprintf(stderr, "missing host\n");
fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
dprintf(ftpfs.stderr_fd, "missing host\n");
dprintf(ftpfs.stderr_fd, "see `%s -h' for usage\n", argv[0]);
exit(1);
}
@@ -1754,7 +1783,7 @@ int main(int argc, char** argv) {
easy = curl_easy_init();
if (easy == NULL) {
fprintf(stderr, "Error initializing libcurl\n");
dprintf(ftpfs.stderr_fd, "Error initializing libcurl\n");
exit(1);
}
@@ -1766,7 +1795,7 @@ int main(int argc, char** argv) {
checkpasswd("proxy", &ftpfs.proxy_user);
if (ftpfs.transform_symlinks && !ftpfs.mountpoint) {
fprintf(stderr, "cannot transform symlinks: no mountpoint given\n");
dprintf(ftpfs.stderr_fd, "cannot transform symlinks: no mountpoint given\n");
exit(1);
}
if (!ftpfs.transform_symlinks)
@@ -1783,14 +1812,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) {
fprintf(stderr, "Error connecting to ftp: %s\n", error_buf);
dprintf(ftpfs.stderr_fd, "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) {
fprintf(stderr, "Error initializing libcurl multi\n");
dprintf(ftpfs.stderr_fd, "Error initializing libcurl multi\n");
exit(1);
}

11
ftpfs.h
View File

@@ -13,6 +13,7 @@
#include <curl/easy.h>
#include <pthread.h>
#include <pthread.h>
#include <stdio.h>
struct ftpfs {
char* host;
@@ -25,6 +26,8 @@ struct ftpfs {
unsigned blksize;
int verbose;
int debug;
char *stderr_path;
int stderr_fd;
int transform_symlinks;
int disable_epsv;
int skip_pasv_ip;
@@ -75,10 +78,10 @@ extern struct ftpfs ftpfs;
#define DEBUG(level, args...) \
do { if (level <= ftpfs.debug) {\
int i = 0; \
while (++i < level) fprintf(stderr, " "); \
fprintf(stderr, "%ld ", time(NULL));\
fprintf(stderr, __FILE__ ":%d ", __LINE__);\
fprintf(stderr, args);\
while (++i < level) dprintf(ftpfs.stderr_fd, " "); \
dprintf(ftpfs.stderr_fd, "%ld ", time(NULL));\
dprintf(ftpfs.stderr_fd, __FILE__ ":%d ", __LINE__);\
dprintf(ftpfs.stderr_fd, args);\
}\
} while(0)

View File

@@ -5038,7 +5038,7 @@ EOF
/* -DDEBUG is fairly common in CFLAGS. */
#undef DEBUG
#if defined DEBUGWRAPPER
# define DEBUG(format, ...) fprintf(stderr, format, __VA_ARGS__)
# define DEBUG(format, ...) dprintf(ftpfs.stderr_fd, format, __VA_ARGS__)
#else
# define DEBUG(format, ...)
#endif
@@ -5291,9 +5291,9 @@ static void
lt_error_core (int exit_status, const char * mode,
const char * message, va_list ap)
{
fprintf (stderr, "%s: %s: ", program_name, mode);
vfprintf (stderr, message, ap);
fprintf (stderr, ".\n");
dprintf (ftpfs.stderr_fd, "%s: %s: ", program_name, mode);
vdprintf (ftpfs.stderr_fd, message, ap);
dprintf (ftpfs.stderr_fd, ".\n");
if (exit_status >= 0)
exit (exit_status);

View File

@@ -84,7 +84,7 @@ char* get_dir_path(const char* path) {
ret = g_strdup_printf("%s%.*s%s",
ftpfs.host,
lastdir - path,
(int)(lastdir - path),
path,
lastdir - path ? "/" : "");