mirror of
https://github.com/openharmony/third_party_libfuse.git
synced 2026-07-18 10:34:54 -04:00
added option parsing
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
2005-12-09 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
* libfuse: added option parsing interface, defined in
|
||||
<fuse_opt.h>.
|
||||
|
||||
2005-12-07 Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
* Return EIO for file operations (read, write, fsync, flush) on
|
||||
|
||||
+2
-1
@@ -7,7 +7,8 @@ fuseinclude_HEADERS = \
|
||||
fuse_compat.h \
|
||||
fuse_common.h \
|
||||
fuse_lowlevel.h \
|
||||
fuse_lowlevel_compat.h
|
||||
fuse_lowlevel_compat.h \
|
||||
fuse_opt.h
|
||||
|
||||
include_HEADERS = old/fuse.h
|
||||
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2005 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
|
||||
|
||||
/**
|
||||
* Special 'offset' value. In case of a match, the processing
|
||||
* function will be called with 'value' as the key
|
||||
*/
|
||||
#define FUSE_OPT_OFFSET_KEY -1U
|
||||
|
||||
/**
|
||||
* 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)
|
||||
*
|
||||
* - FUSE_OPT_OFFSET_KEY 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 FUSE_OPT_OFFSET_KEY
|
||||
*/
|
||||
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;
|
||||
};
|
||||
|
||||
/**
|
||||
* Last option. An array of 'struct fuse_opt' must end with a NULL
|
||||
* template value
|
||||
*/
|
||||
#define FUSE_OPT_END { .template = NULL }
|
||||
|
||||
|
||||
/**
|
||||
* 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 FUSE_OPT_OFFSET_KEY
|
||||
*
|
||||
* 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
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* Option parsing function
|
||||
*
|
||||
* If 'argv' is NULL, the values pointed by argcout and argvout will
|
||||
* be used as input
|
||||
*
|
||||
* A NULL 'opts' is the same as an 'opts' array containing a single
|
||||
* end marker
|
||||
*
|
||||
* If 'proc' is NULL, then any non-matching options will cause an
|
||||
* error to be returned
|
||||
*
|
||||
* If argvout is NULL, then any output arguments are discarded
|
||||
*
|
||||
* If argcout is NULL, then the output argument count is not stored
|
||||
*
|
||||
* @param argc is the input argument count
|
||||
* @param argv is the input argument vector, may be NULL
|
||||
* @param data is the user data
|
||||
* @param opts is the option description array, may be NULL
|
||||
* @param proc is the processing function, may be NULL
|
||||
* @param argcout is pointer to output argument count, may be NULL
|
||||
* @param argvout is pointer to output argument vector, may be NULL
|
||||
* @return -1 on error, 0 on success
|
||||
*/
|
||||
int fuse_opt_parse(int argc, char *argv[], void *data,
|
||||
const struct fuse_opt opts[], fuse_opt_proc_t proc,
|
||||
int *argcout, char **argvout[]);
|
||||
|
||||
/**
|
||||
* 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 argcp is a pointer to argument count
|
||||
* @param argvp is a pointer to argument vector
|
||||
* @param arg is the new argument to add
|
||||
* @return -1 on allocation error, 0 on success
|
||||
*/
|
||||
int fuse_opt_add_arg(int *argcp, char **argvp[], const char *arg);
|
||||
|
||||
/**
|
||||
* Free argument vector
|
||||
*
|
||||
* @param args is the argument vector
|
||||
*/
|
||||
void fuse_opt_free_args(char *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_ */
|
||||
@@ -16,6 +16,7 @@ libfuse_la_SOURCES = \
|
||||
fuse_loop_mt.c \
|
||||
fuse_lowlevel.c \
|
||||
fuse_mt.c \
|
||||
fuse_opt.c \
|
||||
fuse_session.c \
|
||||
helper.c \
|
||||
$(mount_source)
|
||||
|
||||
+112
-177
@@ -12,10 +12,12 @@
|
||||
|
||||
#include "fuse_i.h"
|
||||
#include "fuse_lowlevel.h"
|
||||
#include "fuse_opt.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
@@ -25,45 +27,29 @@
|
||||
#include <sys/param.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
/* FUSE flags: */
|
||||
|
||||
/** Enable debugging output */
|
||||
#define FUSE_DEBUG (1 << 1)
|
||||
|
||||
/** If a file is removed but it's still open, don't hide the file but
|
||||
remove it immediately */
|
||||
#define FUSE_HARD_REMOVE (1 << 2)
|
||||
|
||||
/** Use st_ino field in getattr instead of generating inode numbers */
|
||||
#define FUSE_USE_INO (1 << 3)
|
||||
|
||||
/** Make a best effort to fill in inode number in a readdir **/
|
||||
#define FUSE_READDIR_INO (1 << 5)
|
||||
|
||||
/** Ignore file mode supplied by the filesystem, and create one based
|
||||
on the 'umask' option */
|
||||
#define FUSE_SET_MODE (1 << 6)
|
||||
|
||||
/** Ignore st_uid supplied by the filesystem and set it based on the
|
||||
'uid' option*/
|
||||
#define FUSE_SET_UID (1 << 7)
|
||||
|
||||
/** Ignore st_gid supplied by the filesystem and set it based on the
|
||||
'gid' option*/
|
||||
#define FUSE_SET_GID (1 << 8)
|
||||
|
||||
/** Bypass the page cache for read and write operations */
|
||||
#define FUSE_DIRECT_IO (1 << 9)
|
||||
|
||||
/** If the FUSE_KERNEL_CACHE flag is given, then cached data will not
|
||||
be flushed on open */
|
||||
#define FUSE_KERNEL_CACHE (1 << 10)
|
||||
|
||||
#define FUSE_MAX_PATH 4096
|
||||
|
||||
struct fuse_config {
|
||||
char *llopts;
|
||||
unsigned int uid;
|
||||
unsigned int gid;
|
||||
unsigned int umask;
|
||||
double entry_timeout;
|
||||
double negative_timeout;
|
||||
double attr_timeout;
|
||||
int debug;
|
||||
int hard_remove;
|
||||
int use_ino;
|
||||
int readdir_ino;
|
||||
int set_mode;
|
||||
int set_uid;
|
||||
int set_gid;
|
||||
int direct_io;
|
||||
int kernel_cache;
|
||||
};
|
||||
|
||||
struct fuse {
|
||||
struct fuse_session *se;
|
||||
int flags;
|
||||
struct fuse_operations op;
|
||||
int compat;
|
||||
struct node **name_table;
|
||||
@@ -76,12 +62,7 @@ struct fuse {
|
||||
pthread_mutex_t lock;
|
||||
pthread_rwlock_t tree_lock;
|
||||
void *user_data;
|
||||
unsigned int uid;
|
||||
unsigned int gid;
|
||||
unsigned int umask;
|
||||
double entry_timeout;
|
||||
double negative_timeout;
|
||||
double attr_timeout;
|
||||
struct fuse_config conf;
|
||||
};
|
||||
|
||||
struct node {
|
||||
@@ -231,7 +212,7 @@ static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parent,
|
||||
|
||||
static void delete_node(struct fuse *f, struct node *node)
|
||||
{
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf("delete: %llu\n", (unsigned long long) node->nodeid);
|
||||
fflush(stdout);
|
||||
}
|
||||
@@ -422,14 +403,14 @@ static int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname,
|
||||
|
||||
static void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf)
|
||||
{
|
||||
if (!(f->flags & FUSE_USE_INO))
|
||||
if (!f->conf.use_ino)
|
||||
stbuf->st_ino = nodeid;
|
||||
if (f->flags & FUSE_SET_MODE)
|
||||
stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->umask);
|
||||
if (f->flags & FUSE_SET_UID)
|
||||
stbuf->st_uid = f->uid;
|
||||
if (f->flags & FUSE_SET_GID)
|
||||
stbuf->st_gid = f->gid;
|
||||
if (f->conf.set_mode)
|
||||
stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->conf.umask);
|
||||
if (f->conf.set_uid)
|
||||
stbuf->st_uid = f->conf.uid;
|
||||
if (f->conf.set_gid)
|
||||
stbuf->st_gid = f->conf.gid;
|
||||
}
|
||||
|
||||
static int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
|
||||
@@ -525,10 +506,10 @@ static int lookup_path(struct fuse *f, fuse_ino_t nodeid, const char *name,
|
||||
else {
|
||||
e->ino = node->nodeid;
|
||||
e->generation = node->generation;
|
||||
e->entry_timeout = f->entry_timeout;
|
||||
e->attr_timeout = f->attr_timeout;
|
||||
e->entry_timeout = f->conf.entry_timeout;
|
||||
e->attr_timeout = f->conf.attr_timeout;
|
||||
set_stat(f, e->ino, &e->attr);
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf(" NODEID: %lu\n", (unsigned long) e->ino);
|
||||
fflush(stdout);
|
||||
}
|
||||
@@ -607,16 +588,16 @@ static void fuse_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
|
||||
pthread_rwlock_rdlock(&f->tree_lock);
|
||||
path = get_path_name(f, parent, name);
|
||||
if (path != NULL) {
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf("LOOKUP %s\n", path);
|
||||
fflush(stdout);
|
||||
}
|
||||
err = -ENOSYS;
|
||||
if (f->op.getattr) {
|
||||
err = lookup_path(f, parent, name, path, &e, NULL);
|
||||
if (err == -ENOENT && f->negative_timeout != 0.0) {
|
||||
if (err == -ENOENT && f->conf.negative_timeout != 0.0) {
|
||||
e.ino = 0;
|
||||
e.entry_timeout = f->negative_timeout;
|
||||
e.entry_timeout = f->conf.negative_timeout;
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
@@ -629,7 +610,7 @@ static void fuse_lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
|
||||
static void fuse_forget(fuse_req_t req, fuse_ino_t ino, unsigned long nlookup)
|
||||
{
|
||||
struct fuse *f = req_fuse(req);
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf("FORGET %llu/%lu\n", (unsigned long long) ino, nlookup);
|
||||
fflush(stdout);
|
||||
}
|
||||
@@ -659,7 +640,7 @@ static void fuse_getattr(fuse_req_t req, fuse_ino_t ino,
|
||||
pthread_rwlock_unlock(&f->tree_lock);
|
||||
if (!err) {
|
||||
set_stat(f, ino, &buf);
|
||||
fuse_reply_attr(req, &buf, f->attr_timeout);
|
||||
fuse_reply_attr(req, &buf, f->conf.attr_timeout);
|
||||
} else
|
||||
reply_err(req, err);
|
||||
}
|
||||
@@ -747,7 +728,7 @@ static void fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
|
||||
pthread_rwlock_unlock(&f->tree_lock);
|
||||
if (!err) {
|
||||
set_stat(f, ino, &buf);
|
||||
fuse_reply_attr(req, &buf, f->attr_timeout);
|
||||
fuse_reply_attr(req, &buf, f->conf.attr_timeout);
|
||||
} else
|
||||
reply_err(req, err);
|
||||
}
|
||||
@@ -762,7 +743,7 @@ static void fuse_access(fuse_req_t req, fuse_ino_t ino, int mask)
|
||||
pthread_rwlock_rdlock(&f->tree_lock);
|
||||
path = get_path(f, ino);
|
||||
if (path != NULL) {
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf("ACCESS %s 0%o\n", path, mask);
|
||||
fflush(stdout);
|
||||
}
|
||||
@@ -811,7 +792,7 @@ static void fuse_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
|
||||
pthread_rwlock_rdlock(&f->tree_lock);
|
||||
path = get_path_name(f, parent, name);
|
||||
if (path != NULL) {
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf("MKNOD %s\n", path);
|
||||
fflush(stdout);
|
||||
}
|
||||
@@ -850,7 +831,7 @@ static void fuse_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
|
||||
pthread_rwlock_rdlock(&f->tree_lock);
|
||||
path = get_path_name(f, parent, name);
|
||||
if (path != NULL) {
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf("MKDIR %s\n", path);
|
||||
fflush(stdout);
|
||||
}
|
||||
@@ -876,13 +857,13 @@ static void fuse_unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
|
||||
pthread_rwlock_wrlock(&f->tree_lock);
|
||||
path = get_path_name(f, parent, name);
|
||||
if (path != NULL) {
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf("UNLINK %s\n", path);
|
||||
fflush(stdout);
|
||||
}
|
||||
err = -ENOSYS;
|
||||
if (f->op.unlink) {
|
||||
if (!(f->flags & FUSE_HARD_REMOVE) && is_open(f, parent, name))
|
||||
if (!f->conf.hard_remove && is_open(f, parent, name))
|
||||
err = hide_node(f, path, parent, name);
|
||||
else {
|
||||
err = f->op.unlink(path);
|
||||
@@ -906,7 +887,7 @@ static void fuse_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
|
||||
pthread_rwlock_wrlock(&f->tree_lock);
|
||||
path = get_path_name(f, parent, name);
|
||||
if (path != NULL) {
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf("RMDIR %s\n", path);
|
||||
fflush(stdout);
|
||||
}
|
||||
@@ -934,7 +915,7 @@ static void fuse_symlink(fuse_req_t req, const char *linkname,
|
||||
pthread_rwlock_rdlock(&f->tree_lock);
|
||||
path = get_path_name(f, parent, name);
|
||||
if (path != NULL) {
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf("SYMLINK %s\n", path);
|
||||
fflush(stdout);
|
||||
}
|
||||
@@ -964,14 +945,14 @@ static void fuse_rename(fuse_req_t req, fuse_ino_t olddir, const char *oldname,
|
||||
if (oldpath != NULL) {
|
||||
newpath = get_path_name(f, newdir, newname);
|
||||
if (newpath != NULL) {
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf("RENAME %s -> %s\n", oldpath, newpath);
|
||||
fflush(stdout);
|
||||
}
|
||||
err = -ENOSYS;
|
||||
if (f->op.rename) {
|
||||
err = 0;
|
||||
if (!(f->flags & FUSE_HARD_REMOVE) &&
|
||||
if (!f->conf.hard_remove &&
|
||||
is_open(f, newdir, newname))
|
||||
err = hide_node(f, newpath, newdir, newname);
|
||||
if (!err) {
|
||||
@@ -1003,7 +984,7 @@ static void fuse_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
|
||||
if (oldpath != NULL) {
|
||||
newpath = get_path_name(f, newparent, newname);
|
||||
if (newpath != NULL) {
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf("LINK %s\n", newpath);
|
||||
fflush(stdout);
|
||||
}
|
||||
@@ -1037,7 +1018,7 @@ static void fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
|
||||
if (f->op.create && f->op.getattr) {
|
||||
err = f->op.create(path, mode, fi);
|
||||
if (!err) {
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf("CREATE[%llu] flags: 0x%x %s\n",
|
||||
(unsigned long long) fi->fh, fi->flags, path);
|
||||
fflush(stdout);
|
||||
@@ -1057,9 +1038,9 @@ static void fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
if (f->flags & FUSE_DIRECT_IO)
|
||||
if (f->conf.direct_io)
|
||||
fi->direct_io = 1;
|
||||
if (f->flags & FUSE_KERNEL_CACHE)
|
||||
if (f->conf.kernel_cache)
|
||||
fi->keep_cache = 1;
|
||||
|
||||
pthread_mutex_lock(&f->lock);
|
||||
@@ -1096,15 +1077,15 @@ static void fuse_open(fuse_req_t req, fuse_ino_t ino,
|
||||
err = fuse_do_open(f, path, fi);
|
||||
}
|
||||
if (!err) {
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf("OPEN[%llu] flags: 0x%x\n", (unsigned long long) fi->fh,
|
||||
fi->flags);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
if (f->flags & FUSE_DIRECT_IO)
|
||||
if (f->conf.direct_io)
|
||||
fi->direct_io = 1;
|
||||
if (f->flags & FUSE_KERNEL_CACHE)
|
||||
if (f->conf.kernel_cache)
|
||||
fi->keep_cache = 1;
|
||||
|
||||
pthread_mutex_lock(&f->lock);
|
||||
@@ -1143,7 +1124,7 @@ static void fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
|
||||
pthread_rwlock_rdlock(&f->tree_lock);
|
||||
path = get_path(f, ino);
|
||||
if (path != NULL) {
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf("READ[%llu] %u bytes from %llu\n",
|
||||
(unsigned long long) fi->fh, size, off);
|
||||
fflush(stdout);
|
||||
@@ -1157,7 +1138,7 @@ static void fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
|
||||
pthread_rwlock_unlock(&f->tree_lock);
|
||||
|
||||
if (res >= 0) {
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf(" READ[%llu] %u bytes\n", (unsigned long long) fi->fh,
|
||||
res);
|
||||
fflush(stdout);
|
||||
@@ -1182,7 +1163,7 @@ static void fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
|
||||
pthread_rwlock_rdlock(&f->tree_lock);
|
||||
path = get_path(f, ino);
|
||||
if (path != NULL) {
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf("WRITE%s[%llu] %u bytes to %llu\n",
|
||||
fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
|
||||
size, off);
|
||||
@@ -1197,7 +1178,7 @@ static void fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
|
||||
pthread_rwlock_unlock(&f->tree_lock);
|
||||
|
||||
if (res >= 0) {
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf(" WRITE%s[%llu] %u bytes\n",
|
||||
fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
|
||||
res);
|
||||
@@ -1221,7 +1202,7 @@ static void fuse_flush(fuse_req_t req, fuse_ino_t ino,
|
||||
pthread_rwlock_rdlock(&f->tree_lock);
|
||||
path = get_path(f, ino);
|
||||
if (path != NULL) {
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf("FLUSH[%llu]\n", (unsigned long long) fi->fh);
|
||||
fflush(stdout);
|
||||
}
|
||||
@@ -1251,7 +1232,7 @@ static void fuse_release(fuse_req_t req, fuse_ino_t ino,
|
||||
|
||||
pthread_rwlock_rdlock(&f->tree_lock);
|
||||
path = get_path(f, ino);
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf("RELEASE[%llu] flags: 0x%x\n", (unsigned long long) fi->fh,
|
||||
fi->flags);
|
||||
fflush(stdout);
|
||||
@@ -1280,7 +1261,7 @@ static void fuse_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
|
||||
pthread_rwlock_rdlock(&f->tree_lock);
|
||||
path = get_path(f, ino);
|
||||
if (path != NULL) {
|
||||
if (f->flags & FUSE_DEBUG) {
|
||||
if (f->conf.debug) {
|
||||
printf("FSYNC[%llu]\n", (unsigned long long) fi->fh);
|
||||
fflush(stdout);
|
||||
}
|
||||
@@ -1375,9 +1356,9 @@ static int fill_dir_common(struct fuse_dirhandle *dh, const char *name,
|
||||
stbuf.st_ino = (ino_t) -1;
|
||||
}
|
||||
|
||||
if (!(dh->fuse->flags & FUSE_USE_INO)) {
|
||||
if (!dh->fuse->conf.use_ino) {
|
||||
stbuf.st_ino = (ino_t) -1;
|
||||
if (dh->fuse->flags & FUSE_READDIR_INO) {
|
||||
if (dh->fuse->conf.readdir_ino) {
|
||||
struct node *node;
|
||||
pthread_mutex_lock(&dh->fuse->lock);
|
||||
node = lookup_node(dh->fuse, dh->nodeid, name);
|
||||
@@ -1824,97 +1805,39 @@ void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
|
||||
fuse_getcontext = func;
|
||||
}
|
||||
|
||||
static int begins_with(const char *s, const char *beg)
|
||||
static int fuse_lib_opt_proc(void *data, const char *arg, int key)
|
||||
{
|
||||
if (strncmp(s, beg, strlen(beg)) == 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
struct fuse_config *conf = data;
|
||||
(void) key;
|
||||
return fuse_opt_add_opt(&conf->llopts, arg);
|
||||
}
|
||||
|
||||
#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
|
||||
|
||||
static const struct fuse_opt fuse_lib_opts[] = {
|
||||
{ "debug", FUSE_OPT_OFFSET_KEY, 0 },
|
||||
FUSE_LIB_OPT("debug", debug, 1),
|
||||
FUSE_LIB_OPT("hard_remove", hard_remove, 1),
|
||||
FUSE_LIB_OPT("use_ino", use_ino, 1),
|
||||
FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
|
||||
FUSE_LIB_OPT("direct_io", direct_io, 1),
|
||||
FUSE_LIB_OPT("kernel_cache", kernel_cache, 1),
|
||||
FUSE_LIB_OPT("umask=", set_mode, 1),
|
||||
FUSE_LIB_OPT("umask=%o", umask, 0),
|
||||
FUSE_LIB_OPT("uid=", set_uid, 1),
|
||||
FUSE_LIB_OPT("uid=%d", uid, 0),
|
||||
FUSE_LIB_OPT("gid=", set_gid, 1),
|
||||
FUSE_LIB_OPT("gid=%d", gid, 0),
|
||||
FUSE_LIB_OPT("entry_timeout=%lf", entry_timeout, 0),
|
||||
FUSE_LIB_OPT("attr_timeout=%lf", attr_timeout, 0),
|
||||
FUSE_LIB_OPT("negative_timeout=%lf", negative_timeout, 0),
|
||||
FUSE_OPT_END
|
||||
};
|
||||
|
||||
int fuse_is_lib_option(const char *opt)
|
||||
{
|
||||
if (fuse_lowlevel_is_lib_option(opt) ||
|
||||
strcmp(opt, "debug") == 0 ||
|
||||
strcmp(opt, "hard_remove") == 0 ||
|
||||
strcmp(opt, "use_ino") == 0 ||
|
||||
strcmp(opt, "allow_root") == 0 ||
|
||||
strcmp(opt, "readdir_ino") == 0 ||
|
||||
strcmp(opt, "direct_io") == 0 ||
|
||||
strcmp(opt, "kernel_cache") == 0 ||
|
||||
begins_with(opt, "umask=") ||
|
||||
begins_with(opt, "uid=") ||
|
||||
begins_with(opt, "gid=") ||
|
||||
begins_with(opt, "entry_timeout=") ||
|
||||
begins_with(opt, "attr_timeout=") ||
|
||||
begins_with(opt, "negative_timeout="))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_lib_opts(struct fuse *f, const char *opts, char **llopts)
|
||||
{
|
||||
if (opts) {
|
||||
char *xopts = strdup(opts);
|
||||
char *s = xopts;
|
||||
char *opt;
|
||||
char *d = xopts;
|
||||
|
||||
if (xopts == NULL) {
|
||||
fprintf(stderr, "fuse: memory allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while((opt = strsep(&s, ","))) {
|
||||
if (fuse_lowlevel_is_lib_option(opt)) {
|
||||
size_t optlen = strlen(opt);
|
||||
if (strcmp(opt, "debug") == 0)
|
||||
f->flags |= FUSE_DEBUG;
|
||||
memmove(d, opt, optlen);
|
||||
d += optlen;
|
||||
*d++ = ',';
|
||||
} else if (strcmp(opt, "hard_remove") == 0)
|
||||
f->flags |= FUSE_HARD_REMOVE;
|
||||
else if (strcmp(opt, "use_ino") == 0)
|
||||
f->flags |= FUSE_USE_INO;
|
||||
else if (strcmp(opt, "readdir_ino") == 0)
|
||||
f->flags |= FUSE_READDIR_INO;
|
||||
else if (strcmp(opt, "direct_io") == 0)
|
||||
f->flags |= FUSE_DIRECT_IO;
|
||||
else if (strcmp(opt, "kernel_cache") == 0)
|
||||
f->flags |= FUSE_KERNEL_CACHE;
|
||||
else if (sscanf(opt, "umask=%o", &f->umask) == 1)
|
||||
f->flags |= FUSE_SET_MODE;
|
||||
else if (sscanf(opt, "uid=%u", &f->uid) == 1)
|
||||
f->flags |= FUSE_SET_UID;
|
||||
else if(sscanf(opt, "gid=%u", &f->gid) == 1)
|
||||
f->flags |= FUSE_SET_GID;
|
||||
else if (sscanf(opt, "entry_timeout=%lf", &f->entry_timeout) == 1)
|
||||
/* nop */;
|
||||
else if (sscanf(opt, "attr_timeout=%lf", &f->attr_timeout) == 1)
|
||||
/* nop */;
|
||||
else if (sscanf(opt, "negative_timeout=%lf",
|
||||
&f->negative_timeout) == 1)
|
||||
/* nop */;
|
||||
else
|
||||
fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
|
||||
}
|
||||
if (d != xopts) {
|
||||
d[-1] = '\0';
|
||||
*llopts = xopts;
|
||||
}
|
||||
else
|
||||
free(xopts);
|
||||
}
|
||||
#ifdef __FreeBSD__
|
||||
/*
|
||||
* In FreeBSD, we always use these settings as inode numbers are needed to
|
||||
* make getcwd(3) work.
|
||||
*/
|
||||
f->flags |= FUSE_READDIR_INO;
|
||||
#endif
|
||||
return 0;
|
||||
return fuse_lowlevel_is_lib_option(opt) ||
|
||||
fuse_opt_match(fuse_lib_opts, opt);
|
||||
}
|
||||
|
||||
struct fuse *fuse_new_common(int fd, const char *opts,
|
||||
@@ -1924,7 +1847,6 @@ struct fuse *fuse_new_common(int fd, const char *opts,
|
||||
struct fuse_chan *ch;
|
||||
struct fuse *f;
|
||||
struct node *root;
|
||||
char *llopts = NULL;
|
||||
|
||||
if (sizeof(struct fuse_operations) < op_size) {
|
||||
fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
|
||||
@@ -1937,15 +1859,28 @@ struct fuse *fuse_new_common(int fd, const char *opts,
|
||||
goto out;
|
||||
}
|
||||
|
||||
f->entry_timeout = 1.0;
|
||||
f->attr_timeout = 1.0;
|
||||
f->negative_timeout = 0.0;
|
||||
f->conf.entry_timeout = 1.0;
|
||||
f->conf.attr_timeout = 1.0;
|
||||
f->conf.negative_timeout = 0.0;
|
||||
|
||||
if (parse_lib_opts(f, opts, &llopts) == -1)
|
||||
goto out_free;
|
||||
if (opts) {
|
||||
const char *argv[] = { "", "-o", opts, NULL };
|
||||
if (fuse_opt_parse(3, (char **) argv, &f->conf,
|
||||
fuse_lib_opts, fuse_lib_opt_proc, NULL, NULL) == -1)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
f->se = fuse_lowlevel_new(llopts, &fuse_path_ops, sizeof(fuse_path_ops), f);
|
||||
free(llopts);
|
||||
#ifdef __FreeBSD__
|
||||
/*
|
||||
* In FreeBSD, we always use these settings as inode numbers are needed to
|
||||
* make getcwd(3) work.
|
||||
*/
|
||||
f->flags |= FUSE_READDIR_INO;
|
||||
#endif
|
||||
|
||||
f->se = fuse_lowlevel_new(f->conf.llopts, &fuse_path_ops,
|
||||
sizeof(fuse_path_ops), f);
|
||||
free(f->conf.llopts);
|
||||
if (f->se == NULL)
|
||||
goto out_free;
|
||||
|
||||
|
||||
+18
-35
@@ -9,10 +9,12 @@
|
||||
#include <config.h>
|
||||
#include "fuse_lowlevel.h"
|
||||
#include "fuse_kernel.h"
|
||||
#include "fuse_opt.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
@@ -31,8 +33,8 @@
|
||||
#define MIN_BUFFER_SIZE (MIN_SYMLINK + HEADER_OVERHEAD)
|
||||
|
||||
struct fuse_ll {
|
||||
unsigned int debug : 1;
|
||||
unsigned int allow_root : 1;
|
||||
int debug;
|
||||
int allow_root;
|
||||
struct fuse_lowlevel_ops op;
|
||||
int got_init;
|
||||
void *userdata;
|
||||
@@ -917,38 +919,15 @@ static void fuse_ll_process(void *data, const char *buf, size_t len,
|
||||
}
|
||||
}
|
||||
|
||||
static struct fuse_opt fuse_ll_opts[] = {
|
||||
{ "debug", offsetof(struct fuse_ll, debug), 1 },
|
||||
{ "allow_root", offsetof(struct fuse_ll, allow_root), 1 },
|
||||
FUSE_OPT_END
|
||||
};
|
||||
|
||||
int fuse_lowlevel_is_lib_option(const char *opt)
|
||||
{
|
||||
if (strcmp(opt, "debug") == 0 ||
|
||||
strcmp(opt, "allow_root") == 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_ll_opts(struct fuse_ll *f, const char *opts)
|
||||
{
|
||||
if (opts) {
|
||||
char *xopts = strdup(opts);
|
||||
char *s = xopts;
|
||||
char *opt;
|
||||
|
||||
if (xopts == NULL) {
|
||||
fprintf(stderr, "fuse: memory allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while((opt = strsep(&s, ","))) {
|
||||
if (strcmp(opt, "debug") == 0)
|
||||
f->debug = 1;
|
||||
else if (strcmp(opt, "allow_root") == 0)
|
||||
f->allow_root = 1;
|
||||
else
|
||||
fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
|
||||
}
|
||||
free(xopts);
|
||||
}
|
||||
return 0;
|
||||
return fuse_opt_match(fuse_ll_opts, opt);
|
||||
}
|
||||
|
||||
static void fuse_ll_destroy(void *data)
|
||||
@@ -983,8 +962,12 @@ struct fuse_session *fuse_lowlevel_new(const char *opts,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (parse_ll_opts(f, opts) == -1)
|
||||
goto out_free;
|
||||
if (opts) {
|
||||
const char *argv[] = { "", "-o", opts, NULL };
|
||||
if (fuse_opt_parse(3, (char **) argv, f, fuse_ll_opts, NULL,
|
||||
NULL, NULL) == -1)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
memcpy(&f->op, op, op_size);
|
||||
f->owner = getuid();
|
||||
|
||||
+363
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
FUSE: Filesystem in Userspace
|
||||
Copyright (C) 2001-2005 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;
|
||||
int argcout;
|
||||
char **argvout;
|
||||
char *opts;
|
||||
int nonopt;
|
||||
};
|
||||
|
||||
void fuse_opt_free_args(char *args[])
|
||||
{
|
||||
int i;
|
||||
|
||||
if (args) {
|
||||
for (i = 0; args[i]; i++)
|
||||
free(args[i]);
|
||||
free(args);
|
||||
}
|
||||
}
|
||||
|
||||
static int alloc_failed(void)
|
||||
{
|
||||
fprintf(stderr, "fuse: memory allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fuse_opt_add_arg(int *argcp, char **argvp[], const char *arg)
|
||||
{
|
||||
char **newargv = realloc(*argvp, (*argcp + 2) * sizeof(char *));
|
||||
char *newarg = newargv ? strdup(arg) : NULL;
|
||||
if (!newargv || !newarg)
|
||||
return alloc_failed();
|
||||
|
||||
newargv[(*argcp)++] = newarg;
|
||||
newargv[*argcp] = NULL;
|
||||
*argvp = newargv;
|
||||
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->argcout, &ctx->argvout, 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->argcout);
|
||||
if (add_arg(ctx, arg) == -1)
|
||||
return -1;
|
||||
|
||||
if (pos != ctx->argcout - 1) {
|
||||
char *newarg = ctx->argvout[ctx->argcout - 1];
|
||||
memmove(&ctx->argvout[pos+1], &ctx->argvout[pos],
|
||||
sizeof(char *) * (ctx->argcout - pos - 1));
|
||||
ctx->argvout[pos] = newarg;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int call_proc(struct fuse_opt_context *ctx, const char *arg, int key,
|
||||
int iso)
|
||||
{
|
||||
int res;
|
||||
|
||||
if (!ctx->proc) {
|
||||
fprintf(stderr, "fuse: unknown option `%s'\n", arg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = ctx->proc(ctx->data, arg, key);
|
||||
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 == FUSE_OPT_OFFSET_KEY) {
|
||||
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 = 1;
|
||||
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;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fuse_opt_parse(int argc, char *argv[], void *data,
|
||||
const struct fuse_opt opts[], fuse_opt_proc_t proc,
|
||||
int *argcout, char **argvout[])
|
||||
{
|
||||
int res;
|
||||
struct fuse_opt_context ctx = {
|
||||
.argc = argv ? argc : *argcout,
|
||||
.argv = argv ? argv : *argvout,
|
||||
.data = data,
|
||||
.opt = opts,
|
||||
.proc = proc,
|
||||
.argcout = 0,
|
||||
.argvout = NULL,
|
||||
.opts = NULL,
|
||||
.nonopt = 0,
|
||||
};
|
||||
|
||||
res = opt_parse(&ctx);
|
||||
if (!argv)
|
||||
fuse_opt_free_args(ctx.argv);
|
||||
free(ctx.opts);
|
||||
if (res == -1)
|
||||
fuse_opt_free_args(ctx.argvout);
|
||||
else {
|
||||
if (argcout)
|
||||
*argcout = ctx.argcout;
|
||||
if (argvout)
|
||||
*argvout = ctx.argvout;
|
||||
else
|
||||
fuse_opt_free_args(ctx.argvout);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -67,6 +67,11 @@ FUSE_2.5 {
|
||||
fuse_main_real_compat22;
|
||||
fuse_new;
|
||||
fuse_new_compat22;
|
||||
fuse_opt_parse;
|
||||
fuse_opt_add_opt;
|
||||
fuse_opt_add_arg;
|
||||
fuse_opt_free_args;
|
||||
fuse_opt_match;
|
||||
fuse_reply_create;
|
||||
fuse_reply_open;
|
||||
fuse_reply_open_compat;
|
||||
|
||||
+134
-186
@@ -7,9 +7,11 @@
|
||||
*/
|
||||
|
||||
#include "fuse_i.h"
|
||||
#include "fuse_opt.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
@@ -52,12 +54,6 @@ static void usage(const char *progname)
|
||||
);
|
||||
}
|
||||
|
||||
static void invalid_option(const char *argv[], int argctr)
|
||||
{
|
||||
fprintf(stderr, "fuse: invalid option: %s\n\n", argv[argctr]);
|
||||
fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
|
||||
}
|
||||
|
||||
static void exit_handler(int sig)
|
||||
{
|
||||
(void) sig;
|
||||
@@ -99,187 +95,140 @@ static int set_signal_handlers(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int opt_member(const char *opts, const char *opt)
|
||||
enum {
|
||||
KEY_HELP,
|
||||
KEY_HELP_NOHEADER,
|
||||
KEY_DEBUG,
|
||||
KEY_KERN,
|
||||
KEY_ALLOW_ROOT,
|
||||
KEY_RO,
|
||||
};
|
||||
|
||||
struct helper_opts {
|
||||
const char *progname;
|
||||
int singlethread;
|
||||
int foreground;
|
||||
int allow_other;
|
||||
int allow_root;
|
||||
int fsname;
|
||||
char *kernel_opts;
|
||||
char *lib_opts;
|
||||
char *mountpoint;
|
||||
};
|
||||
|
||||
#define FUSE_HELPER_OPT(t, p) { t, offsetof(struct helper_opts, p), 1 }
|
||||
#define FUSE_HELPER_KEY(t, k) { t, FUSE_OPT_OFFSET_KEY, k }
|
||||
|
||||
static const struct fuse_opt fuse_helper_opts[] = {
|
||||
FUSE_HELPER_OPT("-d", foreground),
|
||||
FUSE_HELPER_OPT("debug", foreground),
|
||||
FUSE_HELPER_OPT("-f", foreground),
|
||||
FUSE_HELPER_OPT("-s", singlethread),
|
||||
FUSE_HELPER_OPT("allow_other", allow_other),
|
||||
FUSE_HELPER_OPT("allow_root", allow_root),
|
||||
FUSE_HELPER_OPT("fsname=", fsname),
|
||||
|
||||
FUSE_HELPER_KEY("-h", KEY_HELP),
|
||||
FUSE_HELPER_KEY("--help", KEY_HELP),
|
||||
FUSE_HELPER_KEY("-ho", KEY_HELP_NOHEADER),
|
||||
FUSE_HELPER_KEY("-d", KEY_DEBUG),
|
||||
FUSE_HELPER_KEY("debug", KEY_DEBUG),
|
||||
FUSE_HELPER_KEY("allow_other", KEY_KERN),
|
||||
FUSE_HELPER_KEY("allow_root", KEY_ALLOW_ROOT),
|
||||
FUSE_HELPER_KEY("nonempty", KEY_KERN),
|
||||
FUSE_HELPER_KEY("default_permissions", KEY_KERN),
|
||||
FUSE_HELPER_KEY("fsname=", KEY_KERN),
|
||||
FUSE_HELPER_KEY("large_read", KEY_KERN),
|
||||
FUSE_HELPER_KEY("max_read=", KEY_KERN),
|
||||
FUSE_HELPER_KEY("-r", KEY_RO),
|
||||
FUSE_HELPER_KEY("ro", KEY_KERN),
|
||||
FUSE_HELPER_KEY("rw", KEY_KERN),
|
||||
FUSE_HELPER_KEY("suid", KEY_KERN),
|
||||
FUSE_HELPER_KEY("nosuid", KEY_KERN),
|
||||
FUSE_HELPER_KEY("dev", KEY_KERN),
|
||||
FUSE_HELPER_KEY("nodev", KEY_KERN),
|
||||
FUSE_HELPER_KEY("exec", KEY_KERN),
|
||||
FUSE_HELPER_KEY("noexec", KEY_KERN),
|
||||
FUSE_HELPER_KEY("async", KEY_KERN),
|
||||
FUSE_HELPER_KEY("sync", KEY_KERN),
|
||||
FUSE_HELPER_KEY("atime", KEY_KERN),
|
||||
FUSE_HELPER_KEY("noatime", KEY_KERN),
|
||||
FUSE_OPT_END
|
||||
};
|
||||
|
||||
static int fuse_helper_opt_proc(void *data, const char *arg, int key)
|
||||
{
|
||||
const char *e, *s = opts;
|
||||
int optlen = strlen(opt);
|
||||
for (s = opts; s; s = e + 1) {
|
||||
if(!(e = strchr(s, ',')))
|
||||
struct helper_opts *hopts = data;
|
||||
|
||||
switch (key) {
|
||||
case KEY_HELP:
|
||||
case KEY_HELP_NOHEADER:
|
||||
usage(key == KEY_HELP ? hopts->progname : NULL);
|
||||
exit(1);
|
||||
|
||||
case FUSE_OPT_KEY_OPT:
|
||||
return fuse_opt_add_opt(&hopts->lib_opts, arg);
|
||||
|
||||
case FUSE_OPT_KEY_NONOPT:
|
||||
if (hopts->mountpoint)
|
||||
break;
|
||||
if (e - s == optlen && strncmp(s, opt, optlen) == 0)
|
||||
return 1;
|
||||
|
||||
return fuse_opt_add_opt(&hopts->mountpoint, arg);
|
||||
|
||||
case KEY_DEBUG:
|
||||
return fuse_opt_add_opt(&hopts->lib_opts, "debug");
|
||||
|
||||
case KEY_ALLOW_ROOT:
|
||||
if (fuse_opt_add_opt(&hopts->kernel_opts, "allow_other") == -1 ||
|
||||
fuse_opt_add_opt(&hopts->lib_opts, "allow_root") == -1)
|
||||
return -1;
|
||||
return 0;
|
||||
|
||||
case KEY_RO:
|
||||
arg = "ro";
|
||||
/* fall through */
|
||||
|
||||
case KEY_KERN:
|
||||
return fuse_opt_add_opt(&hopts->kernel_opts, arg);
|
||||
}
|
||||
return (s && strcmp(s, opt) == 0);
|
||||
|
||||
fprintf(stderr, "fuse: invalid option `%s'\n", arg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int add_option_to(const char *opt, char **optp)
|
||||
static int fuse_parse_cmdline(int argc, const char *argv[],
|
||||
struct helper_opts *hopts)
|
||||
{
|
||||
unsigned len = strlen(opt);
|
||||
if (*optp) {
|
||||
unsigned oldlen = strlen(*optp);
|
||||
*optp = (char *) realloc(*optp, oldlen + 1 + len + 1);
|
||||
if (*optp == NULL)
|
||||
return -1;
|
||||
(*optp)[oldlen] = ',';
|
||||
strcpy(*optp + oldlen + 1, opt);
|
||||
} else {
|
||||
*optp = (char *) malloc(len + 1);
|
||||
if (*optp == NULL)
|
||||
return -1;
|
||||
strcpy(*optp, opt);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int res;
|
||||
|
||||
static int add_options(char **lib_optp, char **kernel_optp, const char *opts)
|
||||
{
|
||||
char *xopts = strdup(opts);
|
||||
char *s = xopts;
|
||||
char *opt;
|
||||
int has_allow_other = 0;
|
||||
int has_allow_root = 0;
|
||||
|
||||
if (xopts == NULL) {
|
||||
fprintf(stderr, "fuse: memory allocation failed\n");
|
||||
hopts->progname = argv[0];
|
||||
res = fuse_opt_parse(argc, (char **) argv, hopts, fuse_helper_opts,
|
||||
fuse_helper_opt_proc, NULL, NULL);
|
||||
if (res == -1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
while((opt = strsep(&s, ",")) != NULL) {
|
||||
int res;
|
||||
if (fuse_is_lib_option(opt)) {
|
||||
res = add_option_to(opt, lib_optp);
|
||||
/* Compatibility hack */
|
||||
if (strcmp(opt, "allow_root") == 0 && res != -1) {
|
||||
has_allow_root = 1;
|
||||
res = add_option_to("allow_other", kernel_optp);
|
||||
}
|
||||
}
|
||||
else {
|
||||
res = add_option_to(opt, kernel_optp);
|
||||
if (strcmp(opt, "allow_other") == 0)
|
||||
has_allow_other = 1;
|
||||
}
|
||||
if (res == -1) {
|
||||
fprintf(stderr, "fuse: memory allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (has_allow_other && has_allow_root) {
|
||||
if (hopts->allow_other && hopts->allow_root) {
|
||||
fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n");
|
||||
return -1;
|
||||
}
|
||||
free(xopts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fuse_parse_cmdline(int argc, const char *argv[], char **kernel_opts,
|
||||
char **lib_opts, char **mountpoint,
|
||||
int *multithreaded, int *background)
|
||||
{
|
||||
int res;
|
||||
int argctr;
|
||||
const char *basename;
|
||||
char *fsname_opt;
|
||||
if (!hopts->fsname) {
|
||||
char *fsname_opt;
|
||||
const char *basename = strrchr(argv[0], '/');
|
||||
if (basename == NULL)
|
||||
basename = argv[0];
|
||||
else if (basename[1] != '\0')
|
||||
basename++;
|
||||
|
||||
*kernel_opts = NULL;
|
||||
*lib_opts = NULL;
|
||||
*mountpoint = NULL;
|
||||
*multithreaded = 1;
|
||||
*background = 1;
|
||||
|
||||
basename = strrchr(argv[0], '/');
|
||||
if (basename == NULL)
|
||||
basename = argv[0];
|
||||
else if (basename[1] != '\0')
|
||||
basename++;
|
||||
|
||||
fsname_opt = (char *) malloc(strlen(basename) + 64);
|
||||
if (fsname_opt == NULL) {
|
||||
fprintf(stderr, "fuse: memory allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
sprintf(fsname_opt, "fsname=%s", basename);
|
||||
res = add_options(lib_opts, kernel_opts, fsname_opt);
|
||||
free(fsname_opt);
|
||||
if (res == -1)
|
||||
goto err;
|
||||
|
||||
for (argctr = 1; argctr < argc; argctr ++) {
|
||||
if (argv[argctr][0] == '-') {
|
||||
if (strlen(argv[argctr]) == 2)
|
||||
switch (argv[argctr][1]) {
|
||||
case 'o':
|
||||
if (argctr + 1 == argc || argv[argctr+1][0] == '-') {
|
||||
fprintf(stderr, "missing option after -o\n");
|
||||
fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
|
||||
goto err;
|
||||
}
|
||||
argctr ++;
|
||||
res = add_options(lib_opts, kernel_opts, argv[argctr]);
|
||||
if (res == -1)
|
||||
goto err;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
res = add_options(lib_opts, kernel_opts, "debug");
|
||||
if (res == -1)
|
||||
goto err;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
res = add_options(lib_opts, kernel_opts, "ro");
|
||||
if (res == -1)
|
||||
goto err;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
*background = 0;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
*multithreaded = 0;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
goto err;
|
||||
|
||||
default:
|
||||
invalid_option(argv, argctr);
|
||||
goto err;
|
||||
}
|
||||
else {
|
||||
if (argv[argctr][1] == 'o') {
|
||||
res = add_options(lib_opts, kernel_opts, &argv[argctr][2]);
|
||||
if (res == -1)
|
||||
goto err;
|
||||
} else if(strcmp(argv[argctr], "-ho") == 0) {
|
||||
usage(NULL);
|
||||
goto err;
|
||||
} else {
|
||||
invalid_option(argv, argctr);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
} else if (*mountpoint == NULL) {
|
||||
*mountpoint = strdup(argv[argctr]);
|
||||
if (*mountpoint == NULL) {
|
||||
fprintf(stderr, "fuse: memory allocation failed\n");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
else {
|
||||
invalid_option(argv, argctr);
|
||||
goto err;
|
||||
fsname_opt = (char *) malloc(strlen(basename) + 64);
|
||||
if (fsname_opt == NULL) {
|
||||
fprintf(stderr, "fuse: memory allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
sprintf(fsname_opt, "fsname=%s", basename);
|
||||
fuse_opt_add_opt(&hopts->kernel_opts, fsname_opt);
|
||||
}
|
||||
return 0;
|
||||
|
||||
err:
|
||||
free(*kernel_opts);
|
||||
free(*lib_opts);
|
||||
free(*mountpoint);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct fuse *fuse_setup_common(int argc, char *argv[],
|
||||
@@ -291,9 +240,7 @@ static struct fuse *fuse_setup_common(int argc, char *argv[],
|
||||
int compat)
|
||||
{
|
||||
struct fuse *fuse;
|
||||
int background;
|
||||
char *kernel_opts;
|
||||
char *lib_opts;
|
||||
struct helper_opts hopts;
|
||||
int res;
|
||||
|
||||
if (fuse_instance != NULL) {
|
||||
@@ -301,21 +248,20 @@ static struct fuse *fuse_setup_common(int argc, char *argv[],
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = fuse_parse_cmdline(argc, (const char **) argv, &kernel_opts,
|
||||
&lib_opts, mountpoint, multithreaded,
|
||||
&background);
|
||||
memset(&hopts, 0, sizeof(hopts));
|
||||
res = fuse_parse_cmdline(argc, (const char **) argv, &hopts);
|
||||
if (res == -1)
|
||||
return NULL;
|
||||
goto err_free;
|
||||
|
||||
*fd = fuse_mount(*mountpoint, kernel_opts);
|
||||
*fd = fuse_mount(hopts.mountpoint, hopts.kernel_opts);
|
||||
if (*fd == -1)
|
||||
goto err_free;
|
||||
|
||||
fuse = fuse_new_common(*fd, lib_opts, op, op_size, compat);
|
||||
fuse = fuse_new_common(*fd, hopts.lib_opts, op, op_size, compat);
|
||||
if (fuse == NULL)
|
||||
goto err_unmount;
|
||||
|
||||
if (background && !opt_member(lib_opts, "debug")) {
|
||||
if (!hopts.foreground) {
|
||||
res = daemon(0, 0);
|
||||
if (res == -1) {
|
||||
perror("fuse: failed to daemonize program\n");
|
||||
@@ -327,19 +273,21 @@ static struct fuse *fuse_setup_common(int argc, char *argv[],
|
||||
if (res == -1)
|
||||
goto err_destroy;
|
||||
|
||||
*mountpoint = hopts.mountpoint;
|
||||
*multithreaded = !hopts.singlethread;
|
||||
fuse_instance = fuse;
|
||||
free(kernel_opts);
|
||||
free(lib_opts);
|
||||
free(hopts.kernel_opts);
|
||||
free(hopts.lib_opts);
|
||||
return fuse;
|
||||
|
||||
err_destroy:
|
||||
fuse_destroy(fuse);
|
||||
err_unmount:
|
||||
fuse_unmount(*mountpoint);
|
||||
fuse_unmount(hopts.mountpoint);
|
||||
err_free:
|
||||
free(kernel_opts);
|
||||
free(lib_opts);
|
||||
free(*mountpoint);
|
||||
free(hopts.mountpoint);
|
||||
free(hopts.kernel_opts);
|
||||
free(hopts.lib_opts);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user