Compare commits

..

71 Commits

Author SHA1 Message Date
Miklos Szeredi 666119d285 fix 2006-03-09 20:03:16 +00:00
Miklos Szeredi f3e8d58bd7 new release 2006-03-09 19:43:13 +00:00
Miklos Szeredi 326ff7f97e fix 2006-03-09 11:25:15 +00:00
Miklos Szeredi 7f4eaea507 fix 2006-03-08 14:32:16 +00:00
Miklos Szeredi 57fc3f4b6a fix 2006-02-24 11:42:40 +00:00
Miklos Szeredi b436754a11 fix 2006-02-23 21:31:41 +00:00
Miklos Szeredi e277fe1ca2 fix 2006-02-23 16:20:55 +00:00
Miklos Szeredi c9c9e9dfbd fix 2006-02-22 16:23:42 +00:00
Miklos Szeredi 3cfb3a6dab new release 2006-02-20 12:11:23 +00:00
Miklos Szeredi 790bb8dd36 fix 2006-02-20 11:44:36 +00:00
Miklos Szeredi accc218cdb revert making rename workaround on by default 2006-02-20 11:32:45 +00:00
Miklos Szeredi 8468900705 fix 2006-02-16 17:02:25 +00:00
Miklos Szeredi b60a970602 fix 2006-02-16 11:51:27 +00:00
Miklos Szeredi 27c1b7b09d fix 2006-02-02 12:07:14 +00:00
Miklos Szeredi 6f0233e11e fix 2006-02-01 15:50:44 +00:00
Miklos Szeredi 89da93d07e fix 2006-01-31 18:34:38 +00:00
Miklos Szeredi cb4239036a fix 2006-01-30 11:05:40 +00:00
Miklos Szeredi 40393a4b0b fix 2006-01-30 09:47:02 +00:00
Miklos Szeredi a6e0d2ddd9 fix 2006-01-27 16:30:55 +00:00
Miklos Szeredi 1cb9aba6ea fix 2006-01-27 12:49:14 +00:00
Miklos Szeredi 3883b4eb0c fix 2006-01-25 14:47:07 +00:00
Miklos Szeredi f1f738d5b8 fix 2006-01-23 17:03:25 +00:00
Miklos Szeredi d2a3ed327e fix 2006-01-20 16:29:23 +00:00
Miklos Szeredi cd6a924cdc fix 2006-01-18 14:05:48 +00:00
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
Miklos Szeredi cea6b546d1 *** empty log message *** 2005-10-29 09:59:28 +00:00
Miklos Szeredi 032d201d02 new release 2005-10-29 09:50:33 +00:00
Miklos Szeredi de2f4aabd1 fix 2005-10-28 12:19:21 +00:00
Miklos Szeredi 642d16587c fix 2005-10-28 12:12:57 +00:00
Miklos Szeredi 8bba944723 fix 2005-10-28 09:41:52 +00:00
Miklos Szeredi ad284c89a7 fix 2005-10-27 16:00:19 +00:00
Miklos Szeredi 9e1c63ecb9 fix 2005-10-26 11:30:51 +00:00
Miklos Szeredi 9f6bf0da77 fix 2005-10-20 10:39:51 +00:00
Miklos Szeredi 81928eda76 fix 2005-10-19 11:41:59 +00:00
Miklos Szeredi 1ff673ab5e fix 2005-10-19 11:38:56 +00:00
Miklos Szeredi 6d0e39592d fix 2005-10-19 11:30:11 +00:00
Miklos Szeredi 0bcb97098a add feature 2005-10-18 15:44:58 +00:00
Miklos Szeredi 8e2bfd7c4b fix 2005-10-17 16:01:45 +00:00
Miklos Szeredi d5f5babffd fix 2005-10-17 15:10:52 +00:00
Miklos Szeredi 42076a8575 whitespace cleanup 2005-10-17 12:58:58 +00:00
Miklos Szeredi 0358c96422 fix 2005-10-17 12:57:52 +00:00
Miklos Szeredi 205f9ac27e revert create method 2005-09-08 15:33:35 +00:00
Miklos Szeredi 95381c9bb4 fix 2005-08-23 15:41:02 +00:00
Miklos Szeredi 42676ca0f6 fix 2005-08-23 15:20:37 +00:00
Miklos Szeredi 5098495dbb ChangeLog fix 2005-08-15 16:16:26 +00:00
Miklos Szeredi adf379b056 fix 2005-08-15 09:07:44 +00:00
Miklos Szeredi 82d15b68d4 release 1.2 2005-08-15 08:58:26 +00:00
Miklos Szeredi 2d959740ea fix 2005-08-13 21:33:42 +00:00
Miklos Szeredi 28495b3bb2 reconnection 2005-08-13 21:17:11 +00:00
Miklos Szeredi 61a154807b fix 2005-05-05 11:55:53 +00:00
Miklos Szeredi c67cf9b98b fix 2005-05-05 11:33:39 +00:00
Miklos Szeredi effd586502 fix 2005-04-13 11:38:40 +00:00
Miklos Szeredi b1ddd5f430 fix 2005-03-08 13:11:12 +00:00
13 changed files with 2358 additions and 669 deletions
+215 -4
View File
@@ -1,3 +1,214 @@
2006-03-09 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.6
2006-03-09 Miklos Szeredi <miklos@szeredi.hu>
* Fix segfault if remote host is down and reconnection is enabled
2006-03-08 Miklos Szeredi <miklos@szeredi.hu>
* Fix bug in symlink transformation. Reported by Ralf Hoffmann
2006-02-24 Miklos Szeredi <miklos@szeredi.hu>
* Add workaround for broken truncate on old sftp servers. Can be
enabled with '-oworkaround=truncate'. Patch from Joseph M Link
2006-02-23 Miklos Szeredi <miklos@szeredi.hu>
* Avoid double memcpy on writes. Patch by Joseph M Link
* More memory copy avoidance
2006-02-22 Miklos Szeredi <miklos@szeredi.hu>
* Add -fPIC to the comile flags of sshnodelay.so. Reported by
Anthony Kolasny
2006-02-20 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.5
2006-02-19 Miklos Szeredi <miklos@szeredi.hu>
* Fix compilation with old FUSE versions. Report by Kurt George
Gjerde
2006-02-16 Miklos Szeredi <miklos@szeredi.hu>
* Block TERM/INT/HUP/QUIT signals in sshfs reading thread, so they
will always be received by the FUSE main thread. Fixes the
"double ^C" problem seen on FreeBSD.
* Use 'auto_cache' option if available, so that file cache is not
thrown away on each open. This should make repeated reading of a
file much much faster.
2006-01-31 Miklos Szeredi <miklos@szeredi.hu>
* Fix problems with nodelay workaround on FreeBSD.
2006-01-30 Miklos Szeredi <miklos@szeredi.hu>
* Fix data consitency bug if readahead is enabled and writes are
intermixed with reads. Solution is far from optimal, since it
will prevent readahead in the above situation. If used with FUSE
>= 2.6.0 with Linux-2.6.X, readahead will be done by the kernel,
and hence there will be no performance penalty. Bug reported and
test program written by Wolfgang Köbler. Further testing on
FreeBSD by Csaba Henk
2006-01-29 Miklos Szeredi <miklos@szeredi.hu>
* Add '-olarge_read' option for Linux-2.4.*. This should
generally improve download performance
2006-01-27 Miklos Szeredi <miklos@szeredi.hu>
* Add workaround (enabled by default) for ssh clients not setting
TCP_NODELAY on the network connection. Currently this is all
known versions of openssh. This may improve download speed in
some circumstances
* Make it possible to idividually disable workarounds with a "no"
prefix
* Change '-otransform_symlinks' not to prefix with the mountpoint
(which is fragile wrt. moving/binding the mount). Rather convert
absolute symlinks to relative if possible. Does not yet work if
base path is itself relative
2006-01-25 Miklos Szeredi <miklos@szeredi.hu>
* Use TCP_NODELAY socket option for direct connection. This may
improve download speed in some circumstances
2006-01-20 Miklos Szeredi <miklos@szeredi.hu>
* Update to fuse API 2.6
* Don't do readahead in sshfs if it's done in kernel
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
2005-10-28 Miklos Szeredi <miklos@szeredi.hu>
* Add atomic create+open and ftruncate operation. This should fix
issues with 'cp' and other programs failing with "Permission
denied". To be effective, needs FUSE version 2.5 and kernel
version 2.6.15 (just a guess, since neither of them is released
yet).
2005-10-27 Miklos Szeredi <miklos@szeredi.hu>
* Add support for SSH protocol version 1. Bug reported by Miklos
Bagi Jr.
2005-10-26 Miklos Szeredi <miklos@szeredi.hu>
* Fix typo (ConnectTimeout -> ConnectionTimeout) in ssh options.
Bug reported by Miklos Bagi Jr.
2005-10-19 Miklos Szeredi <miklos@szeredi.hu>
* GNOME Nautilus fails to copy file to sshfs filesystem, because
FUSE returns zero free space. So instead return huge (999999999
kbytes) amount of free space, yet it should be obvious that the
number is artificial. Bug report by Peter Kronheimer
2005-10-18 Miklos Szeredi <miklos@szeredi.hu>
* Add remote uid detection and translation ('idmap=user' option).
Idea and implementation details worked out by Jean-Marc Valin
2005-10-17 Miklos Szeredi <miklos@szeredi.hu>
* Add one more missing lock.
* Add workaround for failure to rename to an existing file. Based
on patch by Michael Best
2005-10-15 Miklos Szeredi <miklos@szeredi.hu>
* Protect request ID allocation with mutex. Bug report by Tvrtko
Ursulin
2005-08-17 Miklos Szeredi <miklos@szeredi.hu>
* Try to calculate approximate disk usage of files from their
size, so that 'du' returns meaningful results. Problem reported
by Bernd Amend.
2005-08-15 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.2
2005-08-13 Miklos Szeredi <miklos@szeredi.hu>
* Add 'reconnect' option, which tries to reconnect to the server
when the connection is broken. If a password is required for
connection, it is recommended that you install ssh-askpass, and
set the SSH_ASKPASS environment variable (see 'man ssh' for more
details).
2005-05-05 Miklos Szeredi <miklos@szeredi.hu>
* Work around missing truncate() support in some older sftp
servers (only works for zero size truncate). Thanks to Eduard
Czimbalmos for the bug report and help with testing
2005-04-13 Miklos Szeredi <miklos@szeredi.hu>
* Fix compilation with gcc-2.95. Reported by David A. Gershman
2005-03-08 Miklos Szeredi <miklos@szeredi.hu>
* Make it work on server version 2 (e.g. Sun_SSH_1.0.1). Report
and testing by Pieter J. Kersten
2005-03-04 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.1
2005-03-03 Miklos Szeredi <miklos@szeredi.hu>
* Slightly optimize readahead. Still not clever enough to always
@@ -19,7 +230,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'
@@ -30,11 +241,11 @@
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",
bug spotted by Nadia Maksymiw
bug spotted by Andrew Ukrainec
2005-02-07 Miklos Szeredi <miklos@szeredi.hu>
@@ -46,7 +257,7 @@
Fix PKG_CONFIG_PATH setting in configure.ac (reported by Alpar
Juttner)
2005-01-09 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.0
+24 -2
View File
@@ -1,5 +1,27 @@
## 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
sshfs_SOURCES = sshfs.c cache.c cache.h
if FUSE_OPT_COMPAT
sshfs_SOURCES += compat/fuse_opt.c compat/fuse_opt.h
endif
sshfs_LDADD = $(SSHFS_LIBS)
sshfs_CFLAGS = $(SSHFS_CFLAGS)
sshfs_CPPFLAGS = -D_REENTRANT -DFUSE_USE_VERSION=26 -DLIBDIR=\"$(libdir)\"
EXTRA_DIST = sshnodelay.c
CLEANFILES = sshnodelay.so
all-local: sshnodelay.so
install-exec-local: sshnodelay.so
test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)"
$(INSTALL) -m 755 sshnodelay.so "$(DESTDIR)$(libdir)/sshnodelay.so"
uninstall-local:
rm -f "$(DESTDIR)$(libdir)/sshnodelay.so"
sshnodelay.so:
$(CC) -Wall -W -s --shared -fPIC $(sshnodelay_libs) sshnodelay.c -o sshnodelay.so
+52
View File
@@ -1,3 +1,55 @@
What is new in 1.6
------------------
* Workaround for missing truncate operation on old sftp servers
* Bug fixes
What is new in 1.5
------------------
* Improvements to read performance. Now both read and write
throughput should be very close to 'scp'
* If used with FUSE 2.6.0 or later, then perform better data caching.
This should show dramatic speed improvements when a file is opened
more than once
* Bug fixes
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
------------------
* Add workaround for failure to rename to an existing file
* Simple user ID mapping
* Estimate disk usage of files based on size
* Report "infinite" disk space
* Bug fixes
What is new in 1.2
------------------
* Better compatibility with different sftp servers
* Automatic reconnect (optional)
What is new in 1.1
------------------
+12 -9
View File
@@ -11,7 +11,7 @@ The idea of sshfs was taken from the SSHFS filesystem distributed with
LUFS, which I found very useful. There were some limitations of that
codebase, so I rewrote it. Features of this implementation are:
- Based on FUSE (the best userspace filesystem framework for linux ;)
- Based on FUSE (the best userspace filesystem framework for Linux ;)
- Multithreading: more than one request can be on it's way to the
server
@@ -20,6 +20,15 @@ codebase, so I rewrote it. Features of this implementation are:
- Caching directory contents
- 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
=========================
@@ -61,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'.
+144 -129
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);
@@ -99,29 +101,29 @@ static void cache_purge_parent(const char *path)
}
}
static void cache_invalidate(const char *path)
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,25 +132,25 @@ 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;
}
static void cache_add_attr(const char *path, const struct stat *stbuf)
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,38 +182,43 @@ 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_getattr(const char *path, struct stat *stbuf)
static int cache_get_attr(const char *path, struct stat *stbuf)
{
struct node *node;
int err;
pthread_mutex_lock(&cache_lock);
int err = -EAGAIN;
pthread_mutex_lock(&cache.lock);
node = cache_lookup(path);
if (node != NULL) {
time_t now = time(NULL);
if (node->stat_valid - now >= 0) {
*stbuf = node->stat;
pthread_mutex_unlock(&cache_lock);
return 0;
err = 0;
}
}
pthread_mutex_unlock(&cache_lock);
err = next_oper->oper.getattr(path, stbuf);
if (!err)
cache_add_attr(path, stbuf);
pthread_mutex_unlock(&cache.lock);
return err;
}
static int cache_getattr(const char *path, struct stat *stbuf)
{
int err = cache_get_attr(path, stbuf);
if (err) {
err = cache.next_oper->oper.getattr(path, stbuf);
if (!err)
cache_add_attr(path, stbuf);
}
return err;
}
@@ -220,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);
@@ -244,9 +251,9 @@ static int cache_dirfill(fuse_cache_dirh_t ch, const char *name,
{
int err = ch->filler(ch->h, name, 0, 0);
if (!err) {
char *fullpath;
g_ptr_array_add(ch->dir, g_strdup(name));
char *fullpath = g_strdup_printf("%s/%s",
!ch->path[1] ? "" : ch->path, name);
fullpath = g_strdup_printf("%s/%s", !ch->path[1] ? "" : ch->path, name);
cache_add_attr(fullpath, stbuf);
g_free(fullpath);
}
@@ -260,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)
@@ -301,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;
@@ -314,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;
@@ -322,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;
@@ -330,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;
@@ -338,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;
@@ -346,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;
@@ -354,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);
@@ -364,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;
@@ -372,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;
@@ -380,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;
@@ -388,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;
@@ -397,15 +404,50 @@ 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;
}
#if FUSE_VERSION >= 25
static int cache_create(const char *path, mode_t mode,
struct fuse_file_info *fi)
{
int err = cache.next_oper->oper.create(path, mode, fi);
if (!err)
cache_invalidate_dir(path);
return err;
}
static int cache_ftruncate(const char *path, off_t size,
struct fuse_file_info *fi)
{
int err = cache.next_oper->oper.ftruncate(path, size, fi);
if (!err)
cache_invalidate(path);
return err;
}
static int cache_fgetattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi)
{
int err = cache_get_attr(path, stbuf);
if (err) {
err = cache.next_oper->oper.fgetattr(path, stbuf, fi);
if (!err)
cache_add_attr(path, stbuf);
}
return err;
}
#endif
static void cache_unity_fill(struct fuse_cache_operations *oper,
struct fuse_operations *cache_oper)
{
#if FUSE_VERSION >= 23
cache_oper->init = oper->oper.init;
#endif
cache_oper->getattr = oper->oper.getattr;
cache_oper->readlink = oper->oper.readlink;
cache_oper->getdir = cache_unity_getdir;
@@ -431,15 +473,20 @@ static void cache_unity_fill(struct fuse_cache_operations *oper,
cache_oper->getxattr = oper->oper.getxattr;
cache_oper->listxattr = oper->oper.listxattr;
cache_oper->removexattr = oper->oper.removexattr;
#if FUSE_VERSION >= 25
cache_oper->create = oper->oper.create;
cache_oper->ftruncate = oper->oper.ftruncate;
cache_oper->fgetattr = oper->oper.fgetattr;
#endif
}
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;
@@ -455,10 +502,15 @@ struct fuse_operations *cache_init(struct fuse_cache_operations *oper)
cache_oper.truncate = oper->oper.truncate ? cache_truncate : NULL;
cache_oper.utime = oper->oper.utime ? cache_utime : NULL;
cache_oper.write = oper->oper.write ? cache_write : NULL;
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) {
#if FUSE_VERSION >= 25
cache_oper.create = oper->oper.create ? cache_create : NULL;
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.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;
}
@@ -466,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);
}
+8 -2
View File
@@ -7,6 +7,11 @@
*/
#include <fuse.h>
#include <fuse_opt.h>
#ifndef FUSE_VERSION
#define FUSE_VERSION (FUSE_MAJOR_VERSION * 10 + FUSE_MINOR_VERSION)
#endif
typedef struct fuse_cache_dirhandle *fuse_cache_dirh_t;
typedef int (*fuse_cache_dirfil_t) (fuse_cache_dirh_t h, const char *name,
@@ -15,8 +20,9 @@ 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);
void cache_add_attr(const char *path, const struct stat *stbuf);
void cache_invalidate(const char *path);
+364
View File
@@ -0,0 +1,364 @@
/*
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;
}
int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg)
{
assert(pos <= args->argc);
if (fuse_opt_add_arg(args, arg) == -1)
return -1;
if (pos != args->argc - 1) {
char *newarg = args->argv[args->argc - 1];
memmove(&args->argv[pos + 1], &args->argv[pos],
sizeof(char *) * (args->argc - pos - 1));
args->argv[pos] = newarg;
}
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 call_proc(struct fuse_opt_context *ctx, const char *arg, int key,
int iso)
{
if (key == FUSE_OPT_KEY_DISCARD)
return 0;
if (key != FUSE_OPT_KEY_KEEP && 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->templ; opt++)
if (match_template(opt->templ, 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->templ[sep + 1]) {
const char *param = arg + sep;
if (opt->templ[sep] == '=')
param ++;
if (process_opt_param(var, opt->templ + 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->templ[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 (fuse_opt_insert_arg(&ctx->outargs, 1, "-o") == -1 ||
fuse_opt_insert_arg(&ctx->outargs, 2, ctx->opts) == -1)
return -1;
}
if (ctx->nonopt && ctx->nonopt == ctx->outargs.argc) {
free(ctx->outargs.argv[ctx->outargs.argc - 1]);
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;
}
+258
View File
@@ -0,0 +1,258 @@
/*
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 *templ;
/**
* 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 has 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(templ, key) { templ, -1U, key }
/**
* Last option. An array of 'struct fuse_opt' must end with a NULL
* template value
*/
#define FUSE_OPT_END { .templ = 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 template
*/
#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
/**
* Special key value for options to keep
*
* Argument is not passed to processing function, but behave as if the
* processing function returned 1
*/
#define FUSE_OPT_KEY_KEEP -3
/**
* Special key value for options to discard
*
* Argument is not passed to processing function, but behave as if the
* processing function returned zero
*/
#define FUSE_OPT_KEY_DISCARD -4
/**
* 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);
/**
* Add an argument at the specified position in a NULL terminated
* argument vector
*
* Adds the argument to the N-th position. This is useful for adding
* options at the beggining of the array which must not come after the
* special '--' option.
*
* @param args is the structure containing the current argument list
* @param pos is the position at which to add the argument
* @param arg is the new argument to add
* @return -1 on allocation error, 0 on success
*/
int fuse_opt_insert_arg(struct fuse_args *args, int pos, 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_ */
+14 -3
View File
@@ -1,12 +1,23 @@
AC_INIT(sshfs-fuse, 1.1)
AC_INIT(sshfs-fuse, 1.6)
AM_INIT_AUTOMAKE
AM_CONFIG_HEADER(config.h)
AC_PROG_CC
CFLAGS="$CFLAGS -Wall -W"
LIBS=
AC_SEARCH_LIBS(dlsym, [dl])
sshnodelay_libs=$LIBS
AC_SUBST(sshnodelay_libs)
LIBS=
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
-121
View File
@@ -1,121 +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;
}
-18
View File
@@ -1,18 +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);
+1249 -381
View File
File diff suppressed because it is too large Load Diff
+18
View File
@@ -0,0 +1,18 @@
#define _GNU_SOURCE
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
int connect(int sock, const struct sockaddr *addr, socklen_t addrlen)
{
int (*next_connect)(int, const struct sockaddr *, socklen_t) =
dlsym(RTLD_NEXT, "connect");
int res = next_connect(sock, addr, addrlen);
if (!res && addr->sa_family == AF_INET) {
int opt = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
}
return res;
}