Compare commits

...

19 Commits

Author SHA1 Message Date
Miklos Szeredi 258c5ff728 new release 2006-01-14 23:02:33 +00:00
Miklos Szeredi 747ffa12f6 fix 2006-01-10 10:54:38 +00:00
Miklos Szeredi bad7f96bad *** empty log message *** 2006-01-09 17:27:28 +00:00
Miklos Szeredi a162ae9bd4 version change 2006-01-09 17:19:39 +00:00
Miklos Szeredi 95116f4b12 doc update 2006-01-09 17:01:21 +00:00
Miklos Szeredi 3f854ace05 fix 2006-01-09 16:51:06 +00:00
Miklos Szeredi 6a6476b52b fix 2006-01-09 10:09:09 +00:00
Miklos Szeredi 57a490e12a fix 2005-12-16 11:15:26 +00:00
Miklos Szeredi eddbd3967b fix 2005-12-09 20:30:32 +00:00
Miklos Szeredi 891a3e5d87 updated to use libfuse's option parsing 2005-12-09 17:43:06 +00:00
Miklos Szeredi 5dd6469a84 fix 2005-11-29 07:04:09 +00:00
Miklos Szeredi aa44e01549 fix 2005-11-23 13:13:42 +00:00
Miklos Szeredi e916cdd633 README update 2005-11-22 11:19:45 +00:00
Miklos Szeredi 0096ea860e README update 2005-11-22 11:19:21 +00:00
Miklos Szeredi 1f3cdff4ed fix 2005-11-16 18:50:55 +00:00
Miklos Szeredi c3b0185deb fix 2005-11-16 18:42:35 +00:00
Miklos Szeredi 7e97377d52 fix 2005-11-16 13:05:23 +00:00
Miklos Szeredi adba209812 fix 2005-11-07 15:51:14 +00:00
Miklos Szeredi 5377a9a571 fix 2005-11-07 15:49:24 +00:00
12 changed files with 1146 additions and 652 deletions
+39 -3
View File
@@ -1,3 +1,39 @@
2006-01-14 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.4
2006-01-09 Miklos Szeredi <miklos@szeredi.hu>
* Added 'transform_symlinks' option to "fix-up" absolute symlinks.
Patch by Paul Jarc
* Add option parsing implementation, so linking with older than
2.5.0 libfuse still works.
2005-12-09 Miklos Szeredi <miklos@szeredi.hu>
* Use new option parsing interface of FUSE
2005-11-28 Miklos Szeredi <miklos@szeredi.hu>
* Set statvfs::f_frsize
2005-11-23 Miklos Szeredi <miklos@szeredi.hu>
* Fix warnings on 64bit systems. Reported by D. R. Evans
2005-11-16 Miklos Szeredi <miklos@szeredi.hu>
* Replace EPROTO with the more portable EIO
* Fix bug in option parsing. Reported by Csaba Henk
2005-10-29 Miklos Szeredi <miklos@szeredi.hu>
* Use FUSE version 25 if available
* Add <sys/socket.h> include. Reported by Csaba Henk
2005-10-29 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.3
@@ -102,7 +138,7 @@
* Added asynchronous writeback (big performance gain) and made
this the default. Can be disabled with '-o sshfs_sync'
2005-02-09 Miklos Szeredi <miklos@szeredi.hu>
* Added option to start arbitary command instead of 'ssh'
@@ -113,7 +149,7 @@
2005-02-08 Miklos Szeredi <miklos@szeredi.hu>
* Add caching of symlinks
* Add support for many ssh options to be passed to ssh
* Port number can now actually be specified with "-o port=PORT",
@@ -129,7 +165,7 @@
Fix PKG_CONFIG_PATH setting in configure.ac (reported by Alpar
Juttner)
2005-01-09 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.0
+7 -2
View File
@@ -1,5 +1,10 @@
## Process this file with automake to produce Makefile.in
bin_PROGRAMS = sshfs
sshfs_SOURCES = sshfs.c cache.c opts.c cache.h opts.h
sshfs_CPPFLAGS = -DFUSE_USE_VERSION=22
if FUSE_OPT_COMPAT
compat_sources = compat/fuse_opt.c compat/fuse_opt.h
endif
sshfs_SOURCES = sshfs.c cache.c cache.h $(compat_sources)
sshfs_CPPFLAGS = -DFUSE_USE_VERSION=25
+13
View File
@@ -1,3 +1,16 @@
What is new in 1.4
------------------
* Updated to version 25 of libfuse API
* This means that the 'cp' of readonly file to sshfs bug is finally
solved (as long as using libfuse 2.5.0 or later *and* Linux 2.6.15
or later)
* Sshfs now works on FreeBSD
* Added option to "transform" absolute symbolic links
What is new in 1.3
------------------
+9 -8
View File
@@ -22,6 +22,13 @@ codebase, so I rewrote it. Features of this implementation are:
- Reconnect on failure
Latest version
==============
The latest version and more information can be found on
http://fuse.sourceforge.net/sshfs.html
How to mount a filesystem
=========================
@@ -63,11 +70,5 @@ installing FUSE, compile sshfs the usual way:
And you are ready to go.
Bugs and feature requests
=========================
Send bug reports to <miklos@szeredi.hu>.
Good luck!
Miklos Szeredi
If checking out from CVS for the first time also do 'autoreconf -i'
before doing './configure'.
+86 -121
View File
@@ -14,17 +14,23 @@
#include <glib.h>
#include <pthread.h>
#include "opts.h"
#define DEFAULT_CACHE_TIMEOUT 20
#define MAX_CACHE_SIZE 10000
#define MIN_CACHE_CLEAN_INTERVAL 5
#define CACHE_CLEAN_INTERVAL 60
static int cache_on = 1;
static unsigned cache_stat_timeout = DEFAULT_CACHE_TIMEOUT;
static unsigned cache_dir_timeout = DEFAULT_CACHE_TIMEOUT;
static unsigned cache_link_timeout = DEFAULT_CACHE_TIMEOUT;
struct cache {
int on;
unsigned stat_timeout;
unsigned dir_timeout;
unsigned link_timeout;
struct fuse_cache_operations *next_oper;
GHashTable *table;
pthread_mutex_t lock;
time_t last_cleaned;
};
static struct cache cache;
struct node {
struct stat stat;
@@ -43,11 +49,6 @@ struct fuse_cache_dirhandle {
GPtrArray *dir;
};
static struct fuse_cache_operations *next_oper;
static GHashTable *cache;
static pthread_mutex_t cache_lock;
static time_t last_cleaned;
static void free_node(gpointer node_)
{
struct node *node = (struct node *) node_;
@@ -67,22 +68,23 @@ static int cache_clean_entry(void *key_, struct node *node, time_t *now)
static void cache_clean(void)
{
time_t now = time(NULL);
if (now > last_cleaned + MIN_CACHE_CLEAN_INTERVAL &&
(g_hash_table_size(cache) > MAX_CACHE_SIZE ||
now > last_cleaned + CACHE_CLEAN_INTERVAL)) {
g_hash_table_foreach_remove(cache, (GHRFunc) cache_clean_entry, &now);
last_cleaned = now;
if (now > cache.last_cleaned + MIN_CACHE_CLEAN_INTERVAL &&
(g_hash_table_size(cache.table) > MAX_CACHE_SIZE ||
now > cache.last_cleaned + CACHE_CLEAN_INTERVAL)) {
g_hash_table_foreach_remove(cache.table,
(GHRFunc) cache_clean_entry, &now);
cache.last_cleaned = now;
}
}
static struct node *cache_lookup(const char *path)
{
return (struct node *) g_hash_table_lookup(cache, path);
return (struct node *) g_hash_table_lookup(cache.table, path);
}
static void cache_purge(const char *path)
{
g_hash_table_remove(cache, path);
g_hash_table_remove(cache.table, path);
}
static void cache_purge_parent(const char *path)
@@ -90,7 +92,7 @@ static void cache_purge_parent(const char *path)
const char *s = strrchr(path, '/');
if (s) {
if (s == path)
g_hash_table_remove(cache, "/");
g_hash_table_remove(cache.table, "/");
else {
char *parent = g_strndup(path, s - path);
cache_purge(parent);
@@ -101,27 +103,27 @@ static void cache_purge_parent(const char *path)
static void cache_invalidate(const char *path)
{
pthread_mutex_lock(&cache_lock);
pthread_mutex_lock(&cache.lock);
cache_purge(path);
pthread_mutex_unlock(&cache_lock);
pthread_mutex_unlock(&cache.lock);
}
static void cache_invalidate_dir(const char *path)
{
pthread_mutex_lock(&cache_lock);
pthread_mutex_lock(&cache.lock);
cache_purge(path);
cache_purge_parent(path);
pthread_mutex_unlock(&cache_lock);
pthread_mutex_unlock(&cache.lock);
}
static void cache_do_rename(const char *from, const char *to)
{
pthread_mutex_lock(&cache_lock);
pthread_mutex_lock(&cache.lock);
cache_purge(from);
cache_purge(to);
cache_purge_parent(from);
cache_purge_parent(to);
pthread_mutex_unlock(&cache_lock);
pthread_mutex_unlock(&cache.lock);
}
static struct node *cache_get(const char *path)
@@ -130,7 +132,7 @@ static struct node *cache_get(const char *path)
if (node == NULL) {
char *pathcopy = g_strdup(path);
node = g_new0(struct node, 1);
g_hash_table_insert(cache, pathcopy, node);
g_hash_table_insert(cache.table, pathcopy, node);
}
return node;
}
@@ -140,15 +142,15 @@ static void cache_add_attr(const char *path, const struct stat *stbuf)
struct node *node;
time_t now;
pthread_mutex_lock(&cache_lock);
pthread_mutex_lock(&cache.lock);
node = cache_get(path);
now = time(NULL);
node->stat = *stbuf;
node->stat_valid = time(NULL) + cache_stat_timeout;
node->stat_valid = time(NULL) + cache.stat_timeout;
if (node->stat_valid > node->valid)
node->valid = node->stat_valid;
cache_clean();
pthread_mutex_unlock(&cache_lock);
pthread_mutex_unlock(&cache.lock);
}
static void cache_add_dir(const char *path, char **dir)
@@ -156,16 +158,16 @@ static void cache_add_dir(const char *path, char **dir)
struct node *node;
time_t now;
pthread_mutex_lock(&cache_lock);
pthread_mutex_lock(&cache.lock);
node = cache_get(path);
now = time(NULL);
g_strfreev(node->dir);
node->dir = dir;
node->dir_valid = time(NULL) + cache_dir_timeout;
node->dir_valid = time(NULL) + cache.dir_timeout;
if (node->dir_valid > node->valid)
node->valid = node->dir_valid;
cache_clean();
pthread_mutex_unlock(&cache_lock);
pthread_mutex_unlock(&cache.lock);
}
static size_t my_strnlen(const char *s, size_t maxsize)
@@ -180,23 +182,23 @@ static void cache_add_link(const char *path, const char *link, size_t size)
struct node *node;
time_t now;
pthread_mutex_lock(&cache_lock);
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->link_valid = time(NULL) + cache_link_timeout;
node->link_valid = time(NULL) + cache.link_timeout;
if (node->link_valid > node->valid)
node->valid = node->link_valid;
cache_clean();
pthread_mutex_unlock(&cache_lock);
pthread_mutex_unlock(&cache.lock);
}
static int cache_get_attr(const char *path, struct stat *stbuf)
{
struct node *node;
int err = -EAGAIN;
pthread_mutex_lock(&cache_lock);
pthread_mutex_lock(&cache.lock);
node = cache_lookup(path);
if (node != NULL) {
time_t now = time(NULL);
@@ -205,7 +207,7 @@ static int cache_get_attr(const char *path, struct stat *stbuf)
err = 0;
}
}
pthread_mutex_unlock(&cache_lock);
pthread_mutex_unlock(&cache.lock);
return err;
}
@@ -213,7 +215,7 @@ static int cache_getattr(const char *path, struct stat *stbuf)
{
int err = cache_get_attr(path, stbuf);
if (err) {
err = next_oper->oper.getattr(path, stbuf);
err = cache.next_oper->oper.getattr(path, stbuf);
if (!err)
cache_add_attr(path, stbuf);
}
@@ -225,19 +227,19 @@ static int cache_readlink(const char *path, char *buf, size_t size)
struct node *node;
int err;
pthread_mutex_lock(&cache_lock);
pthread_mutex_lock(&cache.lock);
node = cache_lookup(path);
if (node != NULL) {
time_t now = time(NULL);
if (node->link_valid - now >= 0) {
strncpy(buf, node->link, size-1);
buf[size-1] = '\0';
pthread_mutex_unlock(&cache_lock);
pthread_mutex_unlock(&cache.lock);
return 0;
}
}
pthread_mutex_unlock(&cache_lock);
err = next_oper->oper.readlink(path, buf, size);
pthread_mutex_unlock(&cache.lock);
err = cache.next_oper->oper.readlink(path, buf, size);
if (!err)
cache_add_link(path, buf, size);
@@ -265,24 +267,24 @@ static int cache_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
char **dir;
struct node *node;
pthread_mutex_lock(&cache_lock);
pthread_mutex_lock(&cache.lock);
node = cache_lookup(path);
if (node != NULL && node->dir != NULL) {
time_t now = time(NULL);
if (node->dir_valid - now >= 0) {
for(dir = node->dir; *dir != NULL; dir++)
filler(h, *dir, 0, 0);
pthread_mutex_unlock(&cache_lock);
pthread_mutex_unlock(&cache.lock);
return 0;
}
}
pthread_mutex_unlock(&cache_lock);
pthread_mutex_unlock(&cache.lock);
ch.path = path;
ch.h = h;
ch.filler = filler;
ch.dir = g_ptr_array_new();
err = next_oper->cache_getdir(path, &ch, cache_dirfill);
err = cache.next_oper->cache_getdir(path, &ch, cache_dirfill);
g_ptr_array_add(ch.dir, NULL);
dir = (char **) ch.dir->pdata;
if (!err)
@@ -306,12 +308,12 @@ static int cache_unity_getdir(const char *path, fuse_dirh_t h,
struct fuse_cache_dirhandle ch;
ch.h = h;
ch.filler = filler;
return next_oper->cache_getdir(path, &ch, cache_unity_dirfill);
return cache.next_oper->cache_getdir(path, &ch, cache_unity_dirfill);
}
static int cache_mknod(const char *path, mode_t mode, dev_t rdev)
{
int err = next_oper->oper.mknod(path, mode, rdev);
int err = cache.next_oper->oper.mknod(path, mode, rdev);
if (!err)
cache_invalidate_dir(path);
return err;
@@ -319,7 +321,7 @@ static int cache_mknod(const char *path, mode_t mode, dev_t rdev)
static int cache_mkdir(const char *path, mode_t mode)
{
int err = next_oper->oper.mkdir(path, mode);
int err = cache.next_oper->oper.mkdir(path, mode);
if (!err)
cache_invalidate_dir(path);
return err;
@@ -327,7 +329,7 @@ static int cache_mkdir(const char *path, mode_t mode)
static int cache_unlink(const char *path)
{
int err = next_oper->oper.unlink(path);
int err = cache.next_oper->oper.unlink(path);
if (!err)
cache_invalidate_dir(path);
return err;
@@ -335,7 +337,7 @@ static int cache_unlink(const char *path)
static int cache_rmdir(const char *path)
{
int err = next_oper->oper.rmdir(path);
int err = cache.next_oper->oper.rmdir(path);
if (!err)
cache_invalidate_dir(path);
return err;
@@ -343,7 +345,7 @@ static int cache_rmdir(const char *path)
static int cache_symlink(const char *from, const char *to)
{
int err = next_oper->oper.symlink(from, to);
int err = cache.next_oper->oper.symlink(from, to);
if (!err)
cache_invalidate_dir(to);
return err;
@@ -351,7 +353,7 @@ static int cache_symlink(const char *from, const char *to)
static int cache_rename(const char *from, const char *to)
{
int err = next_oper->oper.rename(from, to);
int err = cache.next_oper->oper.rename(from, to);
if (!err)
cache_do_rename(from, to);
return err;
@@ -359,7 +361,7 @@ static int cache_rename(const char *from, const char *to)
static int cache_link(const char *from, const char *to)
{
int err = next_oper->oper.link(from, to);
int err = cache.next_oper->oper.link(from, to);
if (!err) {
cache_invalidate(from);
cache_invalidate_dir(to);
@@ -369,7 +371,7 @@ static int cache_link(const char *from, const char *to)
static int cache_chmod(const char *path, mode_t mode)
{
int err = next_oper->oper.chmod(path, mode);
int err = cache.next_oper->oper.chmod(path, mode);
if (!err)
cache_invalidate(path);
return err;
@@ -377,7 +379,7 @@ static int cache_chmod(const char *path, mode_t mode)
static int cache_chown(const char *path, uid_t uid, gid_t gid)
{
int err = next_oper->oper.chown(path, uid, gid);
int err = cache.next_oper->oper.chown(path, uid, gid);
if (!err)
cache_invalidate(path);
return err;
@@ -385,7 +387,7 @@ static int cache_chown(const char *path, uid_t uid, gid_t gid)
static int cache_truncate(const char *path, off_t size)
{
int err = next_oper->oper.truncate(path, size);
int err = cache.next_oper->oper.truncate(path, size);
if (!err)
cache_invalidate(path);
return err;
@@ -393,7 +395,7 @@ static int cache_truncate(const char *path, off_t size)
static int cache_utime(const char *path, struct utimbuf *buf)
{
int err = next_oper->oper.utime(path, buf);
int err = cache.next_oper->oper.utime(path, buf);
if (!err)
cache_invalidate(path);
return err;
@@ -402,7 +404,7 @@ static int cache_utime(const char *path, struct utimbuf *buf)
static int cache_write(const char *path, const char *buf, size_t size,
off_t offset, struct fuse_file_info *fi)
{
int res = next_oper->oper.write(path, buf, size, offset, fi);
int res = cache.next_oper->oper.write(path, buf, size, offset, fi);
if (res >= 0)
cache_invalidate(path);
return res;
@@ -412,7 +414,7 @@ static int cache_write(const char *path, const char *buf, size_t size,
static int cache_create(const char *path, mode_t mode,
struct fuse_file_info *fi)
{
int err = next_oper->oper.create(path, mode, fi);
int err = cache.next_oper->oper.create(path, mode, fi);
if (!err)
cache_invalidate_dir(path);
return err;
@@ -421,7 +423,7 @@ static int cache_create(const char *path, mode_t mode,
static int cache_ftruncate(const char *path, off_t size,
struct fuse_file_info *fi)
{
int err = next_oper->oper.ftruncate(path, size, fi);
int err = cache.next_oper->oper.ftruncate(path, size, fi);
if (!err)
cache_invalidate(path);
return err;
@@ -432,7 +434,7 @@ static int cache_fgetattr(const char *path, struct stat *stbuf,
{
int err = cache_get_attr(path, stbuf);
if (err) {
err = next_oper->oper.fgetattr(path, stbuf, fi);
err = cache.next_oper->oper.fgetattr(path, stbuf, fi);
if (!err)
cache_add_attr(path, stbuf);
}
@@ -481,10 +483,10 @@ static void cache_unity_fill(struct fuse_cache_operations *oper,
struct fuse_operations *cache_init(struct fuse_cache_operations *oper)
{
static struct fuse_operations cache_oper;
next_oper = oper;
cache.next_oper = oper;
cache_unity_fill(oper, &cache_oper);
if (cache_on) {
if (cache.on) {
cache_oper.getattr = oper->oper.getattr ? cache_getattr : NULL;
cache_oper.readlink = oper->oper.readlink ? cache_readlink : NULL;
cache_oper.getdir = oper->cache_getdir ? cache_getdir : NULL;
@@ -505,10 +507,10 @@ struct fuse_operations *cache_init(struct fuse_cache_operations *oper)
cache_oper.ftruncate = oper->oper.ftruncate ? cache_ftruncate : NULL;
cache_oper.fgetattr = oper->oper.fgetattr ? cache_fgetattr : NULL;
#endif
pthread_mutex_init(&cache_lock, NULL);
cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
free_node);
if (cache == NULL) {
pthread_mutex_init(&cache.lock, NULL);
cache.table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
free_node);
if (cache.table == NULL) {
fprintf(stderr, "failed to create cache\n");
return NULL;
}
@@ -516,61 +518,24 @@ struct fuse_operations *cache_init(struct fuse_cache_operations *oper)
return &cache_oper;
}
enum {
COPT_CACHE,
COPT_TIMEOUT,
COPT_STAT_TIMEOUT,
COPT_DIR_TIMEOUT,
COPT_LINK_TIMEOUT,
COPT_LAST /* Last entry in this list! */
static const struct fuse_opt cache_opts[] = {
{ "cache=yes", offsetof(struct cache, on), 1 },
{ "cache=no", offsetof(struct cache, on), 0 },
{ "cache_timeout=%u", offsetof(struct cache, stat_timeout), 0 },
{ "cache_timeout=%u", offsetof(struct cache, dir_timeout), 0 },
{ "cache_timeout=%u", offsetof(struct cache, link_timeout), 0 },
{ "cache_stat_timeout=%u", offsetof(struct cache, stat_timeout), 0 },
{ "cache_dir_timeout=%u", offsetof(struct cache, dir_timeout), 0 },
{ "cache_link_timeout=%u", offsetof(struct cache, link_timeout), 0 },
FUSE_OPT_END
};
static struct opt cache_opts[] = {
[COPT_CACHE] = { .optname = "cache" },
[COPT_TIMEOUT] = { .optname = "cache_timeout" },
[COPT_STAT_TIMEOUT] = { .optname = "cache_stat_timeout" },
[COPT_DIR_TIMEOUT] = { .optname = "cache_dir_timeout" },
[COPT_LINK_TIMEOUT] = { .optname = "cache_link_timeout" },
[COPT_LAST] = { .optname = NULL }
};
static int get_timeout(int sel, unsigned *timeoutp)
int cache_parse_options(struct fuse_args *args)
{
struct opt *o = &cache_opts[sel];
if (!o->present)
return 0;
if (opt_get_unsigned(o, timeoutp) == -1)
return -1;
return 1;
}
cache.stat_timeout = DEFAULT_CACHE_TIMEOUT;
cache.dir_timeout = DEFAULT_CACHE_TIMEOUT;
cache.link_timeout = DEFAULT_CACHE_TIMEOUT;
cache.on = 1;
int cache_parse_options(int *argcp, char *argv[])
{
unsigned timeout;
int res;
process_options(argcp, argv, cache_opts, 1);
if (cache_opts[COPT_CACHE].present) {
char *val = cache_opts[COPT_CACHE].value;
if (!val || !val[0] ||
(strcmp(val, "yes") != 0 && strcmp(val, "no") != 0)) {
fprintf(stderr, "Invalid or missing value for 'cache' option\n");
return -1;
}
if (strcmp(val, "yes") == 0)
cache_on = 1;
else
cache_on = 0;
}
if ((res = get_timeout(COPT_TIMEOUT, &timeout)) == -1)
return -1;
if (res == 1) {
cache_stat_timeout = timeout;
cache_dir_timeout = timeout;
cache_link_timeout = timeout;
}
if(get_timeout(COPT_STAT_TIMEOUT, &cache_stat_timeout) == -1 ||
get_timeout(COPT_DIR_TIMEOUT, &cache_dir_timeout) == -1 ||
get_timeout(COPT_LINK_TIMEOUT, &cache_link_timeout) == -1)
return -1;
return 0;
return fuse_opt_parse(args, &cache, cache_opts, NULL);
}
+2 -2
View File
@@ -7,6 +7,7 @@
*/
#include <fuse.h>
#include <fuse_opt.h>
#ifndef FUSE_VERSION
#define FUSE_VERSION (FUSE_MAJOR_VERSION * 10 + FUSE_MINOR_VERSION)
@@ -19,8 +20,7 @@ typedef int (*fuse_cache_dirfil_t) (fuse_cache_dirh_t h, const char *name,
struct fuse_cache_operations {
struct fuse_operations oper;
int (*cache_getdir) (const char *, fuse_cache_dirh_t, fuse_cache_dirfil_t);
};
struct fuse_operations *cache_init(struct fuse_cache_operations *oper);
int cache_parse_options(int *argcp, char *argv[]);
int cache_parse_options(struct fuse_args *args);
+359
View File
@@ -0,0 +1,359 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU LGPL.
See the file COPYING.LIB
*/
#include "fuse_opt.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
struct fuse_opt_context {
void *data;
const struct fuse_opt *opt;
fuse_opt_proc_t proc;
int argctr;
int argc;
char **argv;
struct fuse_args outargs;
char *opts;
int nonopt;
};
void fuse_opt_free_args(struct fuse_args *args)
{
if (args && args->argv && args->allocated) {
int i;
for (i = 0; i < args->argc; i++)
free(args->argv[i]);
free(args->argv);
args->argv = NULL;
args->allocated = 0;
}
}
static int alloc_failed(void)
{
fprintf(stderr, "fuse: memory allocation failed\n");
return -1;
}
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
{
char **newargv;
char *newarg;
assert(!args->argv || args->allocated);
newargv = realloc(args->argv, (args->argc + 2) * sizeof(char *));
newarg = newargv ? strdup(arg) : NULL;
if (!newargv || !newarg)
return alloc_failed();
args->argv = newargv;
args->allocated = 1;
args->argv[args->argc++] = newarg;
args->argv[args->argc] = NULL;
return 0;
}
static int next_arg(struct fuse_opt_context *ctx, const char *opt)
{
if (ctx->argctr + 1 >= ctx->argc) {
fprintf(stderr, "fuse: missing argument after `%s'\n", opt);
return -1;
}
ctx->argctr++;
return 0;
}
static int add_arg(struct fuse_opt_context *ctx, const char *arg)
{
return fuse_opt_add_arg(&ctx->outargs, arg);
}
int fuse_opt_add_opt(char **opts, const char *opt)
{
char *newopts;
if (!*opts)
newopts = strdup(opt);
else {
unsigned oldlen = strlen(*opts);
newopts = realloc(*opts, oldlen + 1 + strlen(opt) + 1);
if (newopts) {
newopts[oldlen] = ',';
strcpy(newopts + oldlen + 1, opt);
}
}
if (!newopts)
return alloc_failed();
*opts = newopts;
return 0;
}
static int add_opt(struct fuse_opt_context *ctx, const char *opt)
{
return fuse_opt_add_opt(&ctx->opts, opt);
}
static int insert_arg(struct fuse_opt_context *ctx, int pos, const char *arg)
{
assert(pos <= ctx->outargs.argc);
if (add_arg(ctx, arg) == -1)
return -1;
if (pos != ctx->outargs.argc - 1) {
char *newarg = ctx->outargs.argv[ctx->outargs.argc - 1];
memmove(&ctx->outargs.argv[pos + 1], &ctx->outargs.argv[pos],
sizeof(char *) * (ctx->outargs.argc - pos - 1));
ctx->outargs.argv[pos] = newarg;
}
return 0;
}
static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key,
int iso)
{
if (ctx->proc) {
int res = ctx->proc(ctx->data, arg, key, &ctx->outargs);
if (res == -1 || !res)
return res;
}
if (iso)
return add_opt(ctx, arg);
else
return add_arg(ctx, arg);
}
static int match_template(const char *t, const char *arg, unsigned *sepp)
{
int arglen = strlen(arg);
const char *sep = strchr(t, '=');
sep = sep ? sep : strchr(t, ' ');
if (sep && (!sep[1] || sep[1] == '%')) {
int tlen = sep - t;
if (sep[0] == '=')
tlen ++;
if (arglen >= tlen && strncmp(arg, t, tlen) == 0) {
*sepp = sep - t;
return 1;
}
}
if (strcmp(t, arg) == 0) {
*sepp = 0;
return 1;
}
return 0;
}
static const struct fuse_opt *find_opt(const struct fuse_opt *opt,
const char *arg, unsigned *sepp)
{
for (; opt && opt->template; opt++)
if (match_template(opt->template, arg, sepp))
return opt;
return NULL;
}
int fuse_opt_match(const struct fuse_opt *opts, const char *opt)
{
unsigned dummy;
return find_opt(opts, opt, &dummy) ? 1 : 0;
}
static int process_opt_param(void *var, const char *format, const char *param,
const char *arg)
{
assert(format[0] == '%');
if (format[1] == 's') {
char *copy = strdup(param);
if (!copy)
return alloc_failed();
*(char **) var = copy;
} else {
if (sscanf(param, format, var) != 1) {
fprintf(stderr, "fuse: invalid parameter in option `%s'\n", arg);
return -1;
}
}
return 0;
}
static int process_opt(struct fuse_opt_context *ctx,
const struct fuse_opt *opt, unsigned sep,
const char *arg, int iso)
{
if (opt->offset == -1U) {
if (call_proc(ctx, arg, opt->value, iso) == -1)
return -1;
} else {
void *var = ctx->data + opt->offset;
if (sep && opt->template[sep + 1]) {
const char *param = arg + sep;
if (opt->template[sep] == '=')
param ++;
if (process_opt_param(var, opt->template + sep + 1,
param, arg) == -1)
return -1;
} else
*(int *)var = opt->value;
}
return 0;
}
static int process_opt_sep_arg(struct fuse_opt_context *ctx,
const struct fuse_opt *opt, unsigned sep,
const char *arg, int iso)
{
int res;
char *newarg;
char *param;
if (next_arg(ctx, arg) == -1)
return -1;
param = ctx->argv[ctx->argctr];
newarg = malloc(sep + strlen(param) + 1);
if (!newarg)
return alloc_failed();
memcpy(newarg, arg, sep);
strcpy(newarg + sep, param);
res = process_opt(ctx, opt, sep, newarg, iso);
free(newarg);
return res;
}
static int process_gopt(struct fuse_opt_context *ctx, const char *arg, int iso)
{
unsigned sep;
const struct fuse_opt *opt = find_opt(ctx->opt, arg, &sep);
if (opt) {
for (; opt; opt = find_opt(opt + 1, arg, &sep)) {
int res;
if (sep && opt->template[sep] == ' ' && !arg[sep])
res = process_opt_sep_arg(ctx, opt, sep, arg, iso);
else
res = process_opt(ctx, opt, sep, arg, iso);
if (res == -1)
return -1;
}
return 0;
} else
return call_proc(ctx, arg, FUSE_OPT_KEY_OPT, iso);
}
static int process_real_option_group(struct fuse_opt_context *ctx, char *opts)
{
char *sep;
do {
int res;
sep = strchr(opts, ',');
if (sep)
*sep = '\0';
res = process_gopt(ctx, opts, 1);
if (res == -1)
return -1;
opts = sep + 1;
} while (sep);
return 0;
}
static int process_option_group(struct fuse_opt_context *ctx, const char *opts)
{
int res;
char *copy;
const char *sep = strchr(opts, ',');
if (!sep)
return process_gopt(ctx, opts, 1);
copy = strdup(opts);
if (!copy) {
fprintf(stderr, "fuse: memory allocation failed\n");
return -1;
}
res = process_real_option_group(ctx, copy);
free(copy);
return res;
}
static int process_one(struct fuse_opt_context *ctx, const char *arg)
{
if (ctx->nonopt || arg[0] != '-')
return call_proc(ctx, arg, FUSE_OPT_KEY_NONOPT, 0);
else if (arg[1] == 'o') {
if (arg[2])
return process_option_group(ctx, arg + 2);
else {
if (next_arg(ctx, arg) == -1)
return -1;
return process_option_group(ctx, ctx->argv[ctx->argctr]);
}
} else if (arg[1] == '-' && !arg[2]) {
if (add_arg(ctx, arg) == -1)
return -1;
ctx->nonopt = ctx->outargs.argc;
return 0;
} else
return process_gopt(ctx, arg, 0);
}
static int opt_parse(struct fuse_opt_context *ctx)
{
if (ctx->argc) {
if (add_arg(ctx, ctx->argv[0]) == -1)
return -1;
}
for (ctx->argctr = 1; ctx->argctr < ctx->argc; ctx->argctr++)
if (process_one(ctx, ctx->argv[ctx->argctr]) == -1)
return -1;
if (ctx->opts) {
if (insert_arg(ctx, 1, "-o") == -1 ||
insert_arg(ctx, 2, ctx->opts) == -1)
return -1;
}
if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc)
ctx->outargs.argv[--ctx->outargs.argc] = NULL;
return 0;
}
int fuse_opt_parse(struct fuse_args *args, void *data,
const struct fuse_opt opts[], fuse_opt_proc_t proc)
{
int res;
struct fuse_opt_context ctx = {
.data = data,
.opt = opts,
.proc = proc,
};
if (!args || !args->argv || !args->argc)
return 0;
ctx.argc = args->argc;
ctx.argv = args->argv;
res = opt_parse(&ctx);
if (res != -1) {
struct fuse_args tmp = *args;
*args = ctx.outargs;
ctx.outargs = tmp;
}
free(ctx.opts);
fuse_opt_free_args(&ctx.outargs);
return res;
}
+227
View File
@@ -0,0 +1,227 @@
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#ifndef _FUSE_OPT_H_
#define _FUSE_OPT_H_
/* This file defines the option parsing interface of FUSE */
#ifdef __cplusplus
extern "C" {
#endif
/**
* Option description
*
* This structure describes a single option, and and action associated
* with it, in case it matches.
*
* More than one such match may occur, in which case the action for
* each match is executed.
*
* There are three possible actions in case of a match:
*
* i) An integer (int or unsigned) variable determined by 'offset' is
* set to 'value'
*
* ii) The processing function is called, with 'value' as the key
*
* iii) An integer (any) or string (char *) variable determined by
* 'offset' is set to the value of an option parameter
*
* 'offset' should normally be either set to
*
* - 'offsetof(struct foo, member)' actions i) and iii)
*
* - -1 action ii)
*
* The 'offsetof()' macro is defined in the <stddef.h> header.
*
* The template determines which options match, and also have an
* effect on the action. Normally the action is either i) or ii), but
* if a format is present in the template, then action iii) is
* performed.
*
* The types of templates are:
*
* 1) "-x", "-foo", "--foo", "--foo-bar", etc. These match only
* themselves. Invalid values are "--" and anything beginning
* with "-o"
*
* 2) "foo", "foo-bar", etc. These match "-ofoo", "-ofoo-bar" or
* the relevant option in a comma separated option list
*
* 3) "bar=", "--foo=", etc. These are variations of 1) and 2)
* which have a parameter
*
* 4) "bar=%s", "--foo=%lu", etc. Same matching as above but perform
* action iii).
*
* 5) "-x ", etc. Matches either "-xparam" or "-x param" as
* two separate arguments
*
* 6) "-x %s", etc. Combination of 4) and 5)
*
* If the format is "%s", memory is allocated for the string unlike
* with scanf().
*/
struct fuse_opt {
/** Matching template and optional parameter formatting */
const char *template;
/**
* Offset of variable within 'data' parameter of fuse_opt_parse()
* or -1
*/
unsigned long offset;
/**
* Value to set the variable to, or to be passed as 'key' to the
* processing function. Ignored if template a format
*/
int value;
};
/**
* Key option. In case of a match, the processing function will be
* called with the specified key.
*/
#define FUSE_OPT_KEY(template, key) { template, -1U, key }
/**
* Last option. An array of 'struct fuse_opt' must end with a NULL
* template value
*/
#define FUSE_OPT_END { .template = NULL }
/**
* Argument list
*/
struct fuse_args {
/** Argument count */
int argc;
/** Argument vector. NULL terminated */
char **argv;
/** Is 'argv' allocated? */
int allocated;
};
/**
* Initializer for 'struct fuse_args'
*/
#define FUSE_ARGS_INIT(argc, argv) { argc, argv, 0 }
/**
* Key value passed to the processing function if an option did not
* match any templated
*/
#define FUSE_OPT_KEY_OPT -1
/**
* Key value passed to the processing function for all non-options
*
* Non-options are the arguments beginning with a charater other than
* '-' or all arguments after the special '--' option
*/
#define FUSE_OPT_KEY_NONOPT -2
/**
* Processing function
*
* This function is called if
* - option did not match any 'struct fuse_opt'
* - argument is a non-option
* - option did match and offset was set to -1
*
* The 'arg' parameter will always contain the whole argument or
* option including the parameter if exists. A two-argument option
* ("-x foo") is always converted to single arguemnt option of the
* form "-xfoo" before this function is called.
*
* Options of the form '-ofoo' are passed to this function without the
* '-o' prefix.
*
* The return value of this function determines whether this argument
* is to be inserted into the output argument vector, or discarded.
*
* @param data is the user data passed to the fuse_opt_parse() function
* @param arg is the whole argument or option
* @param key determines why the processing function was called
* @param outargs the current output argument list
* @return -1 on error, 0 if arg is to be discarded, 1 if arg should be kept
*/
typedef int (*fuse_opt_proc_t)(void *data, const char *arg, int key,
struct fuse_args *outargs);
/**
* Option parsing function
*
* If 'args' was returned from a previous call to fuse_opt_parse() or
* it was constructed from
*
* A NULL 'args' is equivalent to an empty argument vector
*
* A NULL 'opts' is equivalent to an 'opts' array containing a single
* end marker
*
* A NULL 'proc' is equivalent to a processing function always
* returning '1'
*
* @param args is the input and output argument list
* @param data is the user data
* @param opts is the option description array
* @param proc is the processing function
* @return -1 on error, 0 on success
*/
int fuse_opt_parse(struct fuse_args *args, void *data,
const struct fuse_opt opts[], fuse_opt_proc_t proc);
/**
* Add an option to a comma separated option list
*
* @param opts is a pointer to an option list, may point to a NULL value
* @param opt is the option to add
* @return -1 on allocation error, 0 on success
*/
int fuse_opt_add_opt(char **opts, const char *opt);
/**
* Add an argument to a NULL terminated argument vector
*
* @param args is the structure containing the current argument list
* @param arg is the new argument to add
* @return -1 on allocation error, 0 on success
*/
int fuse_opt_add_arg(struct fuse_args *args, const char *arg);
/**
* Free the contents of argument list
*
* The structure itself is not freed
*
* @param args is the structure containing the argument list
*/
void fuse_opt_free_args(struct fuse_args *args);
/**
* Check if an option matches
*
* @param opts is the option description array
* @param opt is the option to match
* @return 1 if a match is found, 0 if not
*/
int fuse_opt_match(const struct fuse_opt opts[], const char *opt);
#ifdef __cplusplus
}
#endif
#endif /* _FUSE_OPT_H_ */
+7 -1
View File
@@ -1,4 +1,4 @@
AC_INIT(sshfs-fuse, 1.3)
AC_INIT(sshfs-fuse, 1.4)
AM_INIT_AUTOMAKE
AM_CONFIG_HEADER(config.h)
@@ -7,6 +7,12 @@ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
PKG_CHECK_MODULES(SSHFS, [fuse >= 2.2 glib-2.0])
CFLAGS="$CFLAGS -Wall -W -D_REENTRANT $SSHFS_CFLAGS"
LIBS="$SSHFS_LIBS"
have_fuse_opt_parse=no
AC_CHECK_FUNC([fuse_opt_parse], [have_fuse_opt_parse=yes])
if test "$have_fuse_opt_parse" = no; then
CFLAGS="$CFLAGS -Icompat"
fi
AM_CONDITIONAL(FUSE_OPT_COMPAT, test "$have_fuse_opt_parse" = no)
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
-130
View File
@@ -1,130 +0,0 @@
/*
Mount option parsing
Copyright (C) 2004 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#include "opts.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <glib.h>
static int process_option(char *arg, struct opt opts[], int case_sensitive)
{
int i;
char *eq = strchr(arg, '=');
if (eq)
*eq = '\0';
for (i = 0; opts[i].optname != NULL; i++) {
if (case_sensitive) {
if (strcmp(opts[i].optname, arg) == 0)
break;
} else if (strcasecmp(opts[i].optname, arg) == 0)
break;
}
if (opts[i].optname == NULL) {
if (eq)
*eq = '=';
return 0;
}
opts[i].present = 1;
if (eq) {
if (opts[i].value)
g_free(opts[i].value);
opts[i].value = g_strdup(eq+1);
}
return 1;
}
static int process_option_group(char *arg, struct opt opts[],
int case_sensitive)
{
int remove = 1;
char *prevcomma = NULL;
while (1) {
int remove_one;
char *comma = strchr(arg, ',');
if (comma)
*comma = '\0';
remove_one = process_option(arg, opts, case_sensitive);
if (remove_one) {
if (comma)
memmove(arg, comma + 1, strlen(comma + 1) + 1);
} else {
remove = 0;
if (comma)
arg = comma + 1;
}
if (!remove_one && prevcomma)
*prevcomma = ',';
if (!comma)
break;
prevcomma = comma;
}
return remove;
}
void process_options(int *argcp, char *argv[], struct opt opts[],
int case_sensitive)
{
int argctr;
int newargctr;
for (argctr = 1, newargctr = 1; argctr < *argcp; argctr++) {
char *arg = argv[argctr];
int removed = 0;
if (arg[0] == '-' && arg[1] == 'o') {
if (arg[2])
removed = process_option_group(arg+2, opts, case_sensitive);
else {
if (argctr + 1 < *argcp) {
argctr++;
arg = argv[argctr];
removed = process_option_group(arg, opts, case_sensitive);
if (removed)
g_free(argv[argctr-1]);
else if (argctr != newargctr)
argv[newargctr++] = argv[argctr-1];
}
}
}
if (removed)
g_free(arg);
else {
if(argctr != newargctr)
argv[newargctr] = arg;
newargctr++;
}
}
*argcp = newargctr;
}
int opt_get_unsigned(const struct opt *o, unsigned *valp)
{
char *end;
unsigned val;
if (!o->value || !o->value[0]) {
fprintf(stderr, "Missing value for '%s' option\n", o->optname);
return -1;
}
val = strtoul(o->value, &end, 0);
if (end[0]) {
fprintf(stderr, "Invalid value for '%s' option\n", o->optname);
return -1;
}
*valp = val;
return 0;
}
char *opt_get_string(const struct opt *o)
{
if (!o->value || !o->value[0]) {
fprintf(stderr, "Missing value for '%s' option\n", o->optname);
return NULL;
}
return o->value;
}
-20
View File
@@ -1,20 +0,0 @@
/*
Mount option parsing
Copyright (C) 2004 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
struct opt {
const char *optname;
int present;
char *value;
};
void process_options(int *argcp, char *argv[], struct opt opts[],
int case_sensitive);
int opt_get_unsigned(const struct opt *o, unsigned *valp);
char *opt_get_string(const struct opt *o);
+397 -365
View File
File diff suppressed because it is too large Load Diff