Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ config.status

# Binary outputs
cloudfuse
test/specrunner

# Ignore Eclipse files
.cproject
.project

# Misc dev files
TAGS
**/*~

19 changes: 17 additions & 2 deletions Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@ prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = $(DESTDIR)$(exec_prefix)/bin

SOURCES=cloudfsapi.c cloudfuse.c
HEADERS=cloudfsapi.h
SOURCES=cloudfsapi.c cloudfuse.c headerspec.c
HEADERS=cloudfsapi.h headerspec.h

TESTS=test/header01 \
test/header02 \
test/header03 \
test/header04

all: cloudfuse

Expand All @@ -28,6 +33,9 @@ $(bindir):
cloudfuse: $(SOURCES) $(HEADERS)
$(CC) $(CFLAGS) -o cloudfuse $(SOURCES) $(LIBS)

test/specrunner: $(SOURCES) $(HEADERS) test/specrunner.c
$(CC) $(CFLAGS) -o test/specrunner test/specrunner.c headerspec.c cloudfsapi.c $(LIBS)

clean:
/bin/rm -f cloudfuse

Expand All @@ -52,3 +60,10 @@ Makefile: Makefile.in config.status
config.status: configure
./config.status --recheck

tests: test/specrunner
for test in $(TESTS); do \
$$test || exit 1; \
done

etags:
etags $$(ls *.[hc]) /usr/include/fuse/fuse.h /usr/include/fuse/fuse_opt.h /usr/include/curl/curl.h
36 changes: 35 additions & 1 deletion README
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,40 @@ EXAMPLE:
authurl=http://10.10.0.1:5000/v2.0


HEADER SPECIFICATIONS:

The option headers_spec option allows to specify headers to send
when a file is written. A common use is to specify the
Content-Type header. Rackspace's CloudFiles, for example, allows
14 different headers for specifying access controls, content
expiration, and content encoding. Cloudfuse doesn't restrict what
headers can be specified.

The header value is set based on matching a path against a list of
globs. The syntax:

HeaderKey: [!]GlobMatch HeaderValue [, [!]GlobMatch HeaderValue...] [; HeaderKey:...]

Here's an example which sets the Content-Type header:

Content-Type: /foobucket/*.html text/html, "/*/my dir/*.txt" text/plain;

If no pattern matches, then the header is omitted. Note that
double quotes can be used to specify a pattern that has spaces. A
match pattern preceded by ! is negated, so that the header is
applied when the path does not match the glob pattern. Multiple
headers can be specified, separated by semicolon (;) More examples
are available in the test directory.

See 'man 3 fnmatch' for accepted glob patterns.

The path looks like an absolute path beginning at the mount point.
For example, a file "index.html" in bucket "foo" will result in
the string "/foo/index.html" being matched against the glob
pattern (even if the absolute path on your system is actually
/var/www/foo/index.html).


BUGS/SHORTCOMINGS:

* rename() doesn't work on directories (and probably never will).
Expand All @@ -118,7 +152,7 @@ AWESOME CONTRIBUTORS:
* David Brownlee https://github.com/abs0
* Mike Lundy https://github.com/novas0x2a
* justinb https://github.com/justinsb

* Erik Mackdanz http://mackdanz.net

Thanks, and I hope you find it useful.

Expand Down
17 changes: 14 additions & 3 deletions cloudfsapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <libxml/xpathInternals.h>
#include "cloudfsapi.h"
#include "config.h"
#include "headerspec.h"

#define RHEL5_LIBCURL_VERSION 462597
#define RHEL5_CERTIFICATE_FILE "/etc/pki/tls/certs/ca-bundle.crt"
Expand All @@ -31,6 +32,7 @@ static int curl_pool_count = 0;
static int debug = 0;
static int verify_ssl = 1;
static int rhel5_mode = 0;
static header_spec *hspec;

#ifdef HAVE_OPENSSL
#include <openssl/crypto.h>
Expand Down Expand Up @@ -84,9 +86,10 @@ static void return_connection(CURL *curl)
pthread_mutex_unlock(&pool_mut);
}

static void add_header(curl_slist **headers, const char *name,
const char *value)
void add_header(curl_slist **headers, const char *name,
const char *value)
{
debugf("Adding the header %s: %s",name,value);
char x_header[MAX_HEADER_SIZE];
snprintf(x_header, sizeof(x_header), "%s: %s", name, value);
*headers = curl_slist_append(*headers, x_header);
Expand Down Expand Up @@ -249,8 +252,11 @@ int cloudfs_object_read_fp(const char *path, FILE *fp)
fflush(fp);
rewind(fp);
char *encoded = curl_escape(path, 0);
int response = send_request("PUT", encoded, fp, NULL, NULL);
curl_slist *headers = NULL;
add_matching_headers(&headers,hspec,path);
int response = send_request("PUT", encoded, fp, NULL, headers);
curl_free(encoded);
curl_slist_free_all(headers);
return (response >= 200 && response < 300);
}

Expand Down Expand Up @@ -497,6 +503,11 @@ void cloudfs_set_credentials(char *username, char *tenant, char *password,
reconnect_args.use_snet = use_snet;
}

void cloudfs_set_header_spec(header_spec *spec)
{
hspec = spec;
}

int cloudfs_connect()
{
long response = -1;
Expand Down
4 changes: 4 additions & 0 deletions cloudfsapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <curl/curl.h>
#include <curl/easy.h>
#include "headerspec.h"

#define BUFFER_INITIAL_SIZE 4096
#define MAX_HEADER_SIZE 8192
Expand Down Expand Up @@ -38,6 +39,9 @@ off_t cloudfs_file_size(int fd);
void cloudfs_debug(int dbg);
void cloudfs_verify_ssl(int dbg);
void cloudfs_free_dir_list(dir_entry *dir_list);
void cloudfs_set_header_spec(header_spec *spec);
void add_header(curl_slist **headers, const char *name,
const char *value);

void debugf(char *fmt, ...);
#endif
Expand Down
18 changes: 16 additions & 2 deletions cloudfuse.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#include <stddef.h>
#include "cloudfsapi.h"
#include "config.h"

#include "headerspec.h"

#define OPTION_SIZE 1024

Expand Down Expand Up @@ -433,6 +433,7 @@ static struct options {
char region[OPTION_SIZE];
char use_snet[OPTION_SIZE];
char verify_ssl[OPTION_SIZE];
char header_spec[OPTION_SIZE*10];
} options = {
.username = "",
.password = "",
Expand All @@ -442,6 +443,7 @@ static struct options {
.region = "",
.use_snet = "false",
.verify_ssl = "true",
.header_spec = ""
};

int parse_option(void *data, const char *arg, int key, struct fuse_args *outargs)
Expand All @@ -454,7 +456,8 @@ int parse_option(void *data, const char *arg, int key, struct fuse_args *outargs
sscanf(arg, " authurl = %[^\r\n ]", options.authurl) ||
sscanf(arg, " region = %[^\r\n ]", options.region) ||
sscanf(arg, " use_snet = %[^\r\n ]", options.use_snet) ||
sscanf(arg, " verify_ssl = %[^\r\n ]", options.verify_ssl))
sscanf(arg, " verify_ssl = %[^\r\n ]", options.verify_ssl) ||
sscanf(arg, " header_spec = %[^\r\n]", options.header_spec)) // Note spaces permitted
return 0;
if (!strcmp(arg, "-f") || !strcmp(arg, "-d") || !strcmp(arg, "debug"))
cloudfs_debug(1);
Expand Down Expand Up @@ -494,12 +497,21 @@ int main(int argc, char **argv)
fprintf(stderr, " use_snet=[True to use Rackspace ServiceNet for connections]\n");
fprintf(stderr, " cache_timeout=[Seconds for directory caching, default 600]\n");
fprintf(stderr, " verify_ssl=[False to disable SSL cert verification]\n");
fprintf(stderr, " header_spec=[Match specification for writing extra headers, see README]\n");

return 1;
}

cloudfs_init();

header_spec *parsed = NULL;
if(!parse_spec(options.header_spec, &parsed))
{
fprintf(stderr, "Could not parse header spec\n");
return 1;
}
cloudfs_set_header_spec(parsed);

cloudfs_verify_ssl(!strcasecmp(options.verify_ssl, "true"));

cloudfs_set_credentials(options.username, options.tenant, options.password,
Expand Down Expand Up @@ -541,5 +553,7 @@ int main(int argc, char **argv)

pthread_mutex_init(&dmut, NULL);
return fuse_main(args.argc, args.argv, &cfs_oper, &options);

free_spec(parsed);
}

Loading