Imported Upstream version 1.5.1
This commit is contained in:
1618
cpp/src/fuse/fuse_adapter.cpp
Normal file
1618
cpp/src/fuse/fuse_adapter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
407
cpp/src/fuse/fuse_operations.cpp
Normal file
407
cpp/src/fuse/fuse_operations.cpp
Normal file
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "fuse/fuse_operations.h"
|
||||
|
||||
#include "fuse/fuse_adapter.h"
|
||||
#include "util/logging.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace xtreemfs::util;
|
||||
|
||||
xtreemfs::FuseAdapter* fuse_adapter = NULL;
|
||||
|
||||
int xtreemfs_fuse_getattr(const char *path, struct stat *statbuf) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "getattr on path " << path << endl;
|
||||
}
|
||||
return fuse_adapter->getattr(path, statbuf);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_readlink(const char *path, char *link, size_t size) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG)
|
||||
<< "xtreemfs_fuse_readlink on path " << path << endl;
|
||||
}
|
||||
return fuse_adapter->readlink(path, link, size);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_mknod(const char *path, mode_t mode, dev_t dev) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_mknod on path "
|
||||
<< path << endl;
|
||||
}
|
||||
return fuse_adapter->mknod(path, mode, dev);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_mkdir(const char *path, mode_t mode) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_mkdir on path "
|
||||
<< path << endl;
|
||||
}
|
||||
return fuse_adapter->mkdir(path, mode);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_unlink(const char *path) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_unlink " << path
|
||||
<< endl;
|
||||
}
|
||||
return fuse_adapter->unlink(path);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_rmdir(const char *path) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_rmdir on path " << path
|
||||
<< endl;
|
||||
}
|
||||
return fuse_adapter->rmdir(path);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_symlink(const char *path, const char *link) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_symlink on path "
|
||||
<< path << endl;
|
||||
}
|
||||
return fuse_adapter->symlink(path, link);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_rename(const char *path, const char *newpath) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG)
|
||||
<< "xtreemfs_fuse_rename on path " << path << " to " << newpath <<
|
||||
endl;
|
||||
}
|
||||
return fuse_adapter->rename(path, newpath);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_link(const char *path, const char *newpath) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG)
|
||||
<< "xtreemfs_fuse_link on path " << path << " " << newpath << endl;
|
||||
}
|
||||
return fuse_adapter->link(path, newpath);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_chmod(const char *path, mode_t mode) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_chmod on path " << path
|
||||
<< endl;
|
||||
}
|
||||
return fuse_adapter->chmod(path, mode);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_lock(const char* path,
|
||||
struct fuse_file_info *fi,
|
||||
int cmd,
|
||||
struct flock* flock_) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
string log_command;
|
||||
switch(cmd) {
|
||||
case F_GETLK:
|
||||
log_command = "check lock";
|
||||
break;
|
||||
case F_SETLK:
|
||||
log_command = "set lock";
|
||||
break;
|
||||
case F_SETLKW:
|
||||
log_command = "set lock and wait";
|
||||
break;
|
||||
default:
|
||||
log_command = "unknown lock command";
|
||||
break;
|
||||
}
|
||||
string log_type;
|
||||
switch(flock_->l_type) {
|
||||
case F_UNLCK:
|
||||
log_type = "unlock";
|
||||
break;
|
||||
case F_RDLCK:
|
||||
log_type = "read lock";
|
||||
break;
|
||||
case F_WRLCK:
|
||||
log_type = "write lock";
|
||||
break;
|
||||
default:
|
||||
log_type = "unknown lock type";
|
||||
break;
|
||||
}
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_lock on path " << path
|
||||
<< " command: " << log_command << " type: " << log_type << " start: "
|
||||
<< flock_->l_start << " length: "<< flock_->l_len << " pid: "
|
||||
<< flock_->l_pid << endl;
|
||||
}
|
||||
return fuse_adapter->lock(path, fi, cmd, flock_);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_chown(const char *path, uid_t uid, gid_t gid) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_chown on path " << path
|
||||
<< endl;
|
||||
}
|
||||
return fuse_adapter->chown(path, uid, gid);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_truncate(const char *path, off_t new_file_size) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG)
|
||||
<< "xtreemfs_fuse_truncate on path " << path
|
||||
<< " size:" << new_file_size << endl;
|
||||
}
|
||||
return fuse_adapter->truncate(path, new_file_size);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_utime(const char *path, struct utimbuf *ubuf) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_utime on path " << path
|
||||
<< endl;
|
||||
}
|
||||
return fuse_adapter->utime(path, ubuf);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_utimens(const char *path, const struct timespec tv[2]) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_utimens on path "
|
||||
<< path << endl;
|
||||
}
|
||||
return fuse_adapter->utimens(path, tv);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_open(const char *path, struct fuse_file_info *fi) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_open on path " << path
|
||||
<< endl;
|
||||
}
|
||||
return fuse_adapter->open(path, fi);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_release(const char *path, struct fuse_file_info *fi) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_release " << path
|
||||
<< endl;
|
||||
}
|
||||
return fuse_adapter->release(path, fi);
|
||||
}
|
||||
|
||||
|
||||
int xtreemfs_fuse_read(
|
||||
const char *path, char *buf,
|
||||
size_t size, off_t offset, struct fuse_file_info *fi) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_read " << path
|
||||
<< " s:" << size << " o:" << offset << endl;
|
||||
}
|
||||
int count = fuse_adapter->read(path, buf, size, offset, fi);
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_read finished " << path
|
||||
<< " s:" << size << " o:" << offset << " r:" << count << endl;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_write(const char *path, const char *buf, size_t size,
|
||||
off_t offset, struct fuse_file_info *fi) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_write " << path
|
||||
<< " s: " << size << " o:" << offset << endl;
|
||||
}
|
||||
int count = fuse_adapter->write(path, buf, size, offset, fi);
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_write finished " << path
|
||||
<< " s:" << size << " o:" << offset << " w:" << count << endl;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_statfs(const char *path, struct statvfs *statv) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_statfs " << path
|
||||
<< endl;
|
||||
}
|
||||
return fuse_adapter->statfs(path, statv);
|
||||
}
|
||||
|
||||
/** Unlink fsync(), flush() requests are NOT initiated from the user.
|
||||
*
|
||||
* Instead, flush() is a Fuse internal mechanism to avoid the problem that
|
||||
* the return value of release() will be ignored.
|
||||
*
|
||||
* Therefore, a flush() will be called by Fuse with every close() executed by
|
||||
* the user. Only errors returned by this flush() operation can be returned
|
||||
* to the close() of the user.
|
||||
*/
|
||||
int xtreemfs_fuse_flush(const char *path, struct fuse_file_info *fi) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_flush " << path
|
||||
<< endl;
|
||||
}
|
||||
return fuse_adapter->flush(path, fi);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_fsync(const char *path, int datasync,
|
||||
struct fuse_file_info *fi) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_fsync " << path
|
||||
<< endl;
|
||||
}
|
||||
|
||||
// We ignore the datasync parameter as all metadata operations are
|
||||
// synchronous and therefore never have to be flushed.
|
||||
return fuse_adapter->flush(path, fi);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_setxattr(
|
||||
const char *path, const char *name,
|
||||
const char *value, size_t size, int flags
|
||||
#ifdef __APPLE__
|
||||
, uint32_t position
|
||||
#endif
|
||||
) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG)
|
||||
<< "xtreemfs_fuse_setxattr " << " " << path << " " << name << endl;
|
||||
}
|
||||
return fuse_adapter->setxattr(path, name, value, size, flags);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_getxattr(
|
||||
const char *path, const char *name, char *value, size_t size
|
||||
#ifdef __APPLE__
|
||||
, uint32_t position
|
||||
#endif
|
||||
) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG)
|
||||
<< "xtreemfs_fuse_getxattr " << " " << path << " " << name << " "
|
||||
<< size << endl;
|
||||
}
|
||||
return fuse_adapter->getxattr(path, name, value, size);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_listxattr(const char *path, char *list, size_t size) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG)
|
||||
<< "xtreemfs_fuse_listxattr " << path << " " << size << endl;
|
||||
}
|
||||
return fuse_adapter->listxattr(path, list, size);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_removexattr(const char *path, const char *name) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG)
|
||||
<< "xtreemfs_fuse_removexattr " << " " << path << " " << name << endl;
|
||||
}
|
||||
return fuse_adapter->removexattr(path, name);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_opendir(const char *path, struct fuse_file_info *fi) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_opendir " << path
|
||||
<< endl;
|
||||
}
|
||||
return fuse_adapter->opendir(path, fi);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_readdir(
|
||||
const char *path, void *buf,
|
||||
fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_readdir " << path
|
||||
<< endl;
|
||||
}
|
||||
return fuse_adapter->readdir(path, buf, filler, offset, fi);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_releasedir(const char *path, struct fuse_file_info *fi) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG) && path != NULL) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_releasedir " << path
|
||||
<< endl;
|
||||
}
|
||||
return fuse_adapter->releasedir(path, fi);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_fsyncdir(
|
||||
const char *path, int datasync, struct fuse_file_info *fi) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_fsyncdir " << path
|
||||
<< endl;
|
||||
}
|
||||
|
||||
// Like fsync, but for directories - not required for XtreemFS.
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *xtreemfs_fuse_init(struct fuse_conn_info *conn) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_init " << endl;
|
||||
}
|
||||
|
||||
// http://sourceforge.net/apps/mediawiki/fuse/index.php?title=Fuse_file_info
|
||||
// TODO(mberlin): Check for valid parameters.
|
||||
conn->async_read = 5;
|
||||
conn->max_readahead = 10 * 128 * 1024;
|
||||
conn->max_write = 128 * 1024;
|
||||
|
||||
#if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8) // NOLINT
|
||||
conn->capable
|
||||
= FUSE_CAP_ASYNC_READ | FUSE_CAP_BIG_WRITES
|
||||
| FUSE_CAP_ATOMIC_O_TRUNC | FUSE_CAP_POSIX_LOCKS;
|
||||
conn->want
|
||||
= FUSE_CAP_ASYNC_READ | FUSE_CAP_BIG_WRITES
|
||||
| FUSE_CAP_ATOMIC_O_TRUNC | FUSE_CAP_POSIX_LOCKS;
|
||||
#endif
|
||||
|
||||
struct fuse_context* context = fuse_get_context();
|
||||
return context->private_data;
|
||||
}
|
||||
|
||||
void xtreemfs_fuse_destroy(void *userdata) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_destroy " << endl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will only be called by Fuse if "-o default_permissions" is not
|
||||
* send to Fuse (for instance before changing the working directory).
|
||||
*
|
||||
* If "-o default_permissions" is enabled, Fuse does determine on its own, based
|
||||
* on the result of the getattr, if the user is allowed to access the directory.
|
||||
*/
|
||||
int xtreemfs_fuse_access(const char *path, int mask) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "xtreemfs_fuse_access " << path
|
||||
<< endl;
|
||||
}
|
||||
return fuse_adapter->access(path, mask);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_create(const char *path, mode_t mode,
|
||||
struct fuse_file_info *fi) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "create on path " << path << endl;
|
||||
}
|
||||
return fuse_adapter->create(path, mode, fi);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_ftruncate(
|
||||
const char *path, off_t new_file_size, struct fuse_file_info *fi) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG)
|
||||
<< "xtreemfs_fuse_ftruncate on path " << path
|
||||
<< " size:" << new_file_size << endl;
|
||||
}
|
||||
return fuse_adapter->ftruncate(path, new_file_size, fi);
|
||||
}
|
||||
|
||||
int xtreemfs_fuse_fgetattr(
|
||||
const char *path, struct stat *statbuf, struct fuse_file_info *fi) {
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "fgetattr on path " << path << endl;
|
||||
}
|
||||
return fuse_adapter->fgetattr(path, statbuf, fi);
|
||||
}
|
||||
261
cpp/src/fuse/fuse_options.cpp
Normal file
261
cpp/src/fuse/fuse_options.cpp
Normal file
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (c) 2011 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "fuse/fuse_options.h"
|
||||
|
||||
#include <csignal>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/program_options/cmdline.hpp>
|
||||
#include <boost/tokenizer.hpp>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "libxtreemfs/helper.h"
|
||||
#include "libxtreemfs/xtreemfs_exception.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace po = boost::program_options;
|
||||
namespace style = boost::program_options::command_line_style;
|
||||
|
||||
namespace xtreemfs {
|
||||
|
||||
FuseOptions::FuseOptions() : Options(), fuse_descriptions_("Fuse Options") {
|
||||
// Overwrite certain members of Options().
|
||||
#ifndef __linux
|
||||
// Interrupting read calls does not work with Linux Fuse.
|
||||
max_read_tries = 0;
|
||||
#endif
|
||||
|
||||
// Never give up to execute a request as we enabled interruption.
|
||||
max_tries = 0;
|
||||
max_write_tries = 0;
|
||||
|
||||
async_writes_max_request_size_kb = 128; // FUSE specific limit.
|
||||
|
||||
// Default Fuse options.
|
||||
#ifdef __APPLE__
|
||||
// We assume that the MacFuse default timeout is 60 seconds on Leopard.
|
||||
daemon_timeout = 60;
|
||||
|
||||
// Always enable xattrs for Mac.
|
||||
enable_xattrs = true;
|
||||
|
||||
// If we are under Leopard or newer, reduce the timeout values.
|
||||
if (GetMacOSXKernelVersion() >= 9) {
|
||||
max_tries = 3;
|
||||
max_read_tries = 3;
|
||||
max_write_tries = 3;
|
||||
|
||||
retry_delay_s = 15;
|
||||
connect_timeout_s = 15;
|
||||
// The detection of a timeout may take twice the time, i.e. up to 18 seconds
|
||||
// resulting in a total time of 3 * 18 (< 60 seconds daemon_timeout default).
|
||||
request_timeout_s = 9;
|
||||
}
|
||||
#else
|
||||
enable_xattrs = false;
|
||||
#endif // __APPLE__
|
||||
foreground = false;
|
||||
use_fuse_permission_checks = true;
|
||||
fuse_permission_checks_explicitly_disabled = false;
|
||||
|
||||
fuse_descriptions_.add_options()
|
||||
("foreground,f", po::value(&foreground)->zero_tokens(),
|
||||
"Do not fork into background.")
|
||||
("fuse_option,o",
|
||||
po::value< vector<string> >(&fuse_options),
|
||||
"Passes -o=<option> to Fuse if not recognized by mount.xtreemfs, "
|
||||
"see 'Alternative Specification of options'.")
|
||||
("no-default-permissions",
|
||||
po::value(&fuse_permission_checks_explicitly_disabled)->zero_tokens(),
|
||||
"Do not pass -o default_permissions to Fuse (disables local Fuse"
|
||||
" permissions checks).");
|
||||
po::options_description fuse_options_information(
|
||||
"ACL and extended attributes Support:\n"
|
||||
" -o xtreemfs_acl Enable the correct evaluation of XtreemFS ACLs.\n"
|
||||
" (Note that you cannot use the system tools getfattr\n"
|
||||
" and setfattr; use 'xtfsutil' instead to set and\n"
|
||||
" retrieve ACLs.)"
|
||||
#ifndef __APPLE__
|
||||
"\n -o user_xattr Enable user defined extended attributes.");
|
||||
#else
|
||||
);
|
||||
#endif // __APPLE__
|
||||
fuse_descriptions_.add(fuse_options_information);
|
||||
|
||||
helptext_usage_ =
|
||||
"mount.xtreemfs: Mounts an XtreemFS Volume.\n"
|
||||
"\n"
|
||||
"Usage: \n"
|
||||
"\tmount.xtreemfs [options] [pbrpc[g|s]://]<dir-host>[:port]/<volume-name>"
|
||||
" <mount point>\n"
|
||||
"\n"
|
||||
" Example: mount.xtreemfs localhost/myVolume ~/xtreemfs\n";
|
||||
}
|
||||
|
||||
void FuseOptions::ParseCommandLine(int argc, char** argv) {
|
||||
// Parse general options and retrieve unregistered options for own parsing.
|
||||
vector<string> options = Options::ParseCommandLine(argc, argv);
|
||||
|
||||
// Read Volume URL and mount point from command line.
|
||||
po::positional_options_description p;
|
||||
p.add("dir_volume_url", 1);
|
||||
p.add("mount_point", 1);
|
||||
po::options_description mount("Mount options");
|
||||
mount.add_options()
|
||||
("dir_volume_url", po::value(&xtreemfs_url), "volume to mount")
|
||||
("mount_point", po::value(&mount_point), "where to mount the volume");
|
||||
|
||||
// Parse command line.
|
||||
po::options_description all_descriptions_;
|
||||
all_descriptions_.add(mount).add(fuse_descriptions_);
|
||||
po::variables_map vm;
|
||||
try {
|
||||
po::store(po::command_line_parser(options)
|
||||
.options(all_descriptions_)
|
||||
.positional(p)
|
||||
.style(style::default_style & ~style::allow_guessing)
|
||||
.run(), vm);
|
||||
po::notify(vm);
|
||||
} catch(const std::exception& e) {
|
||||
// Rethrow boost errors due to invalid command line parameters.
|
||||
throw InvalidCommandLineParametersException(string(e.what()));
|
||||
}
|
||||
|
||||
// Do not check parameters if the help shall be shown.
|
||||
if (show_help || empty_arguments_list || show_version) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Split list of comma separated -o options and add them as extra options.
|
||||
list<string> split_options;
|
||||
for (int i = 0; i < fuse_options.size(); i++) {
|
||||
typedef boost::tokenizer< boost::char_separator<char> > tokenizer;
|
||||
boost::char_separator<char> seperator(",");
|
||||
tokenizer tokens(fuse_options[i], seperator);
|
||||
|
||||
// Check if there are at least two tokens and they have to be split up
|
||||
tokenizer::iterator first_tokens = tokens.begin();
|
||||
if (++first_tokens != tokens.end()) {
|
||||
// Split tokens and add them to a temporary list.
|
||||
for (tokenizer::iterator token = tokens.begin();
|
||||
token != tokens.end();
|
||||
++token) {
|
||||
split_options.push_back(string(*token));
|
||||
}
|
||||
|
||||
// Remove split tokens from fuse_options as they will be readded later.
|
||||
fuse_options.erase(fuse_options.begin() + i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
// Readd split options.
|
||||
for (list<string>::const_iterator iter = split_options.begin();
|
||||
iter != split_options.end();
|
||||
++iter) {
|
||||
fuse_options.push_back(*iter);
|
||||
}
|
||||
|
||||
// Evaluate certain Fuse options.
|
||||
for (int i = 0; i < fuse_options.size(); i++) {
|
||||
if (fuse_options[i] == "acl") {
|
||||
throw InvalidCommandLineParametersException(
|
||||
"The option -o acl is not supported. Specify -o xtreemfs_acl instead."
|
||||
"\n\nWe do not allow -o acl because XtreemFS does not support the "
|
||||
"getfacl and setfacl tools. You have to use 'xtfs_acl' instead "
|
||||
"to set and retrieve ACLs.");
|
||||
}
|
||||
if (fuse_options[i] == "user_xattr") {
|
||||
enable_xattrs = true;
|
||||
// Don't send this option to Fuse.
|
||||
fuse_options.erase(fuse_options.begin() + i);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
if (fuse_options[i] == "xtreemfs_acl") {
|
||||
// Fuse may prevent operations based on the evaluation of stat records
|
||||
// although a user is allowed to due to further ACLs, so we disable this
|
||||
// Fuse feature here.
|
||||
use_fuse_permission_checks = false;
|
||||
// Don't send this option to Fuse.
|
||||
fuse_options.erase(fuse_options.begin() + i);
|
||||
i--;
|
||||
continue;
|
||||
}
|
||||
if (fuse_options[i] == "intr") {
|
||||
// Don't send this option to Fuse.
|
||||
fuse_options.erase(fuse_options.begin() + i);
|
||||
i--;
|
||||
throw InvalidCommandLineParametersException(
|
||||
"The option -o intr will be ignored as command line parameter and"
|
||||
" not passed through to Fuse. Use --interrupt-signal instead.");
|
||||
}
|
||||
if (fuse_options[i].substr(0, 12) == "intr_signal=") {
|
||||
// Don't send this option to Fuse.
|
||||
fuse_options.erase(fuse_options.begin() + i);
|
||||
i--;
|
||||
throw InvalidCommandLineParametersException(
|
||||
"The option -o intr_signal will be ignored as command line "
|
||||
"parameter and not passed through to Fuse. Use --interrupt-signal "
|
||||
"instead.");
|
||||
}
|
||||
if (fuse_options[i] == "_netdev") {
|
||||
// Don't send this option to Fuse, just ignore it, solves issue 276:
|
||||
// https://code.google.com/p/xtreemfs/issues/detail?id=276
|
||||
fuse_options.erase(fuse_options.begin() + i);
|
||||
i--;
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
if (fuse_options[i].substr(0, 15) == "daemon_timeout=") {
|
||||
try {
|
||||
daemon_timeout = boost::lexical_cast<int>(fuse_options[i].substr(15));
|
||||
continue;
|
||||
} catch(const boost::bad_lexical_cast& e) {
|
||||
throw InvalidCommandLineParametersException(
|
||||
"The integer value after daemon_timeout could not be parsed: "
|
||||
+ fuse_options[i].substr(15));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Extract information from command line.
|
||||
Options::ParseURL(kDIR);
|
||||
|
||||
// Check for required parameters.
|
||||
if (service_addresses.empty()) {
|
||||
throw InvalidCommandLineParametersException("missing DIR host.");
|
||||
}
|
||||
if (volume_name.empty()) {
|
||||
throw InvalidCommandLineParametersException("missing volume name.");
|
||||
}
|
||||
if (mount_point.empty()) {
|
||||
throw InvalidCommandLineParametersException("missing mount point.");
|
||||
}
|
||||
}
|
||||
|
||||
std::string FuseOptions::ShowCommandLineUsage() {
|
||||
return helptext_usage_
|
||||
+ "\nFor complete list of options, please specify -h or --help.\n";
|
||||
}
|
||||
|
||||
std::string FuseOptions::ShowCommandLineHelp() {
|
||||
ostringstream stream;
|
||||
// No help text given in descriptions for positional mount options. Instead
|
||||
// the usage is explained here.
|
||||
stream << helptext_usage_
|
||||
<< endl
|
||||
// Descriptions of this class.
|
||||
<< fuse_descriptions_
|
||||
// Descriptions of the general options.
|
||||
<< Options::ShowCommandLineHelp();
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
} // namespace xtreemfs
|
||||
283
cpp/src/fuse/mount.xtreemfs.cpp
Normal file
283
cpp/src/fuse/mount.xtreemfs.cpp
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2011 by Patrick Schaefer, Zuse Institute Berlin
|
||||
* 2011 by Michael Berlin, Zuse Institute Berlin
|
||||
*
|
||||
* Licensed under the BSD License, see LICENSE file for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#define FUSE_USE_VERSION 26
|
||||
|
||||
#include <errno.h>
|
||||
#include <csignal>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fuse.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "util/logging.h"
|
||||
|
||||
#include "fuse/fuse_adapter.h"
|
||||
#include "fuse/fuse_operations.h"
|
||||
#include "fuse/fuse_options.h"
|
||||
#include "libxtreemfs/xtreemfs_exception.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace xtreemfs::util;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Parse command line options.
|
||||
xtreemfs::FuseOptions options;
|
||||
bool invalid_commandline_parameters = false;
|
||||
try {
|
||||
options.ParseCommandLine(argc, argv);
|
||||
} catch(const xtreemfs::XtreemFSException& e) {
|
||||
cout << "Invalid parameters found, error: " << e.what() << endl << endl;
|
||||
invalid_commandline_parameters = true;
|
||||
}
|
||||
// Display help if needed.
|
||||
if (options.empty_arguments_list || invalid_commandline_parameters) {
|
||||
cout << options.ShowCommandLineUsage() << endl;
|
||||
return 1;
|
||||
}
|
||||
if (options.show_help) {
|
||||
cout << options.ShowCommandLineHelp() << endl;
|
||||
return 1;
|
||||
}
|
||||
// Show only the version.
|
||||
if (options.show_version) {
|
||||
cout << options.ShowVersion("mount.xtreemfs") << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// In case of background operation: Fork before threads are created.
|
||||
int fd[2];
|
||||
int kErrorBufferSize = 1024;
|
||||
char error_output[kErrorBufferSize];
|
||||
memset(&error_output, 0, kErrorBufferSize);
|
||||
if (!options.foreground) {
|
||||
if (pipe(fd) < 0) {
|
||||
cerr << "Failed to create pipe. (Needed to send process to background.)";
|
||||
return 2;
|
||||
}
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
cerr << "Failed to fork(). (Needed to send process to background.)";
|
||||
return 3;
|
||||
}
|
||||
// Evaluate pipe from daemonized thread.
|
||||
if (pid > 0) { // Parent
|
||||
// Cleanup the static memory in the parent to pass the valgrind
|
||||
// leak check.
|
||||
google::protobuf::ShutdownProtobufLibrary();
|
||||
|
||||
signal(SIGINT, SIG_IGN); // Ignore interrupt signals in parent.
|
||||
// Close write end.
|
||||
close(fd[1]);
|
||||
fd_set read_fds;
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(fd[0], &read_fds);
|
||||
// Wait until there is something to read at the other end.
|
||||
select(fd[0]+1, &read_fds, NULL, NULL, NULL);
|
||||
int count = read(fd[0], error_output, kErrorBufferSize);
|
||||
if (count == 0) {
|
||||
// No error found, exiting.
|
||||
return 0;
|
||||
} else {
|
||||
printf("mount.xtreemfs failed: %s\n", error_output);
|
||||
return 4;
|
||||
}
|
||||
} else { // Child.
|
||||
// Close read end of pipe.
|
||||
close(fd[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Child only from here.
|
||||
// Run client and open volume.
|
||||
list<char*> required_fuse_options;
|
||||
try {
|
||||
fuse_adapter = new xtreemfs::FuseAdapter(&options);
|
||||
fuse_adapter->Start(&required_fuse_options);
|
||||
} catch(const xtreemfs::XtreemFSException& e) {
|
||||
if (options.foreground) {
|
||||
cerr << "mount.xtreemfs failed: " << e.what() << endl;
|
||||
} else {
|
||||
// Tell parent about error: write error to pipe and exit.
|
||||
write(fd[1], e.what(), min(static_cast<int>(strlen(e.what()) + 1),
|
||||
kErrorBufferSize));
|
||||
}
|
||||
fuse_adapter->Stop();
|
||||
delete fuse_adapter;
|
||||
return 5;
|
||||
}
|
||||
|
||||
// Setup fuse and pass client and volume objects.
|
||||
struct fuse_chan* fuse_channel = NULL;
|
||||
struct fuse* fuse_ = NULL;
|
||||
char* mount_point = NULL;
|
||||
// Fill in operations.
|
||||
struct fuse_operations xtreemfs_fuse_ops = {0};
|
||||
xtreemfs_fuse_ops.getattr = xtreemfs_fuse_getattr;
|
||||
xtreemfs_fuse_ops.readlink = xtreemfs_fuse_readlink;
|
||||
xtreemfs_fuse_ops.mknod = xtreemfs_fuse_mknod;
|
||||
xtreemfs_fuse_ops.mkdir = xtreemfs_fuse_mkdir;
|
||||
xtreemfs_fuse_ops.unlink = xtreemfs_fuse_unlink;
|
||||
xtreemfs_fuse_ops.rmdir = xtreemfs_fuse_rmdir;
|
||||
xtreemfs_fuse_ops.symlink = xtreemfs_fuse_symlink;
|
||||
xtreemfs_fuse_ops.rename = xtreemfs_fuse_rename;
|
||||
xtreemfs_fuse_ops.link = xtreemfs_fuse_link;
|
||||
xtreemfs_fuse_ops.chmod = xtreemfs_fuse_chmod;
|
||||
xtreemfs_fuse_ops.chown = xtreemfs_fuse_chown;
|
||||
xtreemfs_fuse_ops.truncate = xtreemfs_fuse_truncate;
|
||||
xtreemfs_fuse_ops.utime = xtreemfs_fuse_utime;
|
||||
xtreemfs_fuse_ops.open = xtreemfs_fuse_open;
|
||||
xtreemfs_fuse_ops.read = xtreemfs_fuse_read;
|
||||
xtreemfs_fuse_ops.write = xtreemfs_fuse_write;
|
||||
xtreemfs_fuse_ops.statfs = xtreemfs_fuse_statfs;
|
||||
xtreemfs_fuse_ops.flush = xtreemfs_fuse_flush;
|
||||
xtreemfs_fuse_ops.release = xtreemfs_fuse_release;
|
||||
xtreemfs_fuse_ops.fsync = xtreemfs_fuse_fsync;
|
||||
xtreemfs_fuse_ops.setxattr = xtreemfs_fuse_setxattr;
|
||||
xtreemfs_fuse_ops.getxattr = xtreemfs_fuse_getxattr;
|
||||
xtreemfs_fuse_ops.listxattr = xtreemfs_fuse_listxattr;
|
||||
xtreemfs_fuse_ops.removexattr = xtreemfs_fuse_removexattr;
|
||||
xtreemfs_fuse_ops.opendir = xtreemfs_fuse_opendir;
|
||||
xtreemfs_fuse_ops.readdir = xtreemfs_fuse_readdir;
|
||||
xtreemfs_fuse_ops.releasedir = xtreemfs_fuse_releasedir;
|
||||
xtreemfs_fuse_ops.fsyncdir = xtreemfs_fuse_fsyncdir;
|
||||
xtreemfs_fuse_ops.init = xtreemfs_fuse_init;
|
||||
xtreemfs_fuse_ops.destroy = xtreemfs_fuse_destroy;
|
||||
xtreemfs_fuse_ops.access = xtreemfs_fuse_access;
|
||||
xtreemfs_fuse_ops.create = xtreemfs_fuse_create;
|
||||
xtreemfs_fuse_ops.ftruncate = xtreemfs_fuse_ftruncate;
|
||||
xtreemfs_fuse_ops.fgetattr = xtreemfs_fuse_fgetattr;
|
||||
xtreemfs_fuse_ops.lock = xtreemfs_fuse_lock;
|
||||
xtreemfs_fuse_ops.utimens = xtreemfs_fuse_utimens;
|
||||
#if FUSE_MAJOR_VERSION > 2 || ( FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8 ) // NOLINT
|
||||
// We cannot work on unlinked files in case -ohard_remove was specified, so
|
||||
// a null path is not okay.
|
||||
xtreemfs_fuse_ops.flag_nullpath_ok = 0;
|
||||
#endif // >= FUSE 2.8
|
||||
#if FUSE_MAJOR_VERSION > 2 || ( FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 9 ) // NOLINT
|
||||
// We require Fuse to calculate the "path" for all file handle operations.
|
||||
xtreemfs_fuse_ops.flag_nopath = 0;
|
||||
#endif // >= FUSE 2.8
|
||||
|
||||
// Forward args.
|
||||
vector<char*> fuse_opts;
|
||||
// Fuse does not parse the first parameter, thus set it to "mount.xtreemfs".
|
||||
fuse_opts.push_back((strdup("mount.xtreemfs")));
|
||||
for (int i = 0; i < options.fuse_options.size(); i++) {
|
||||
// Prepend "-o" to every Fuse option.
|
||||
fuse_opts.push_back(strdup(
|
||||
(string("-o") + options.fuse_options[i]).c_str()));
|
||||
}
|
||||
for (list<char*>::iterator it = required_fuse_options.begin();
|
||||
it != required_fuse_options.end(); ++it) {
|
||||
fuse_opts.push_back((*it));
|
||||
}
|
||||
struct fuse_args fuse_args = FUSE_ARGS_INIT(
|
||||
static_cast<int>(fuse_opts.size()), &fuse_opts[0]);
|
||||
if (Logging::log->loggingActive(LEVEL_DEBUG)) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "About to call fuse_mount using "
|
||||
<< fuse_opts.size() << " parameters: " << endl;
|
||||
for (int i = 0; i < fuse_opts.size(); i++) {
|
||||
Logging::log->getLog(LEVEL_DEBUG) << "\t" << fuse_opts[i] << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Create Fuse channel (mount_point will be freed by fuse_teardown()).
|
||||
mount_point = strdup(options.mount_point.c_str());
|
||||
|
||||
struct stat mount_point_stat;
|
||||
stat(mount_point, &mount_point_stat);
|
||||
if((mount_point_stat.st_mode & S_IFMT) != S_IFDIR) {
|
||||
cerr << mount_point << " is not a directory." << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Fuse docu: "manually add arguments to the struct fuse_args list"
|
||||
fuse_opt_parse(&fuse_args, NULL, NULL, NULL);
|
||||
fuse_channel = fuse_mount(mount_point, &fuse_args);
|
||||
if (fuse_channel == NULL) {
|
||||
fuse_opt_free_args(&fuse_args);
|
||||
for (int i = 0; i < fuse_opts.size(); i++) {
|
||||
free(fuse_opts[i]);
|
||||
}
|
||||
free(mount_point);
|
||||
// Stop FuseAdapter.
|
||||
fuse_adapter->Stop();
|
||||
delete fuse_adapter;
|
||||
return errno;
|
||||
}
|
||||
// Create Fuse filesystem.
|
||||
fuse_ = fuse_new(
|
||||
fuse_channel,
|
||||
&fuse_args,
|
||||
&xtreemfs_fuse_ops,
|
||||
sizeof(xtreemfs_fuse_ops),
|
||||
NULL);
|
||||
fuse_opt_free_args(&fuse_args);
|
||||
if (fuse_ == NULL) {
|
||||
// Avoid "Transport endpoint is not connected" in case fuse_new failed.
|
||||
fuse_unmount(mount_point, fuse_channel);
|
||||
for (int i = 0; i < fuse_opts.size(); i++) {
|
||||
free(fuse_opts[i]);
|
||||
}
|
||||
free(mount_point);
|
||||
// Stop FuseAdapter.
|
||||
fuse_adapter->Stop();
|
||||
delete fuse_adapter;
|
||||
return errno;
|
||||
}
|
||||
|
||||
// Send to background.
|
||||
if (!options.foreground) {
|
||||
// Close write end of pipe as no error was encountered.
|
||||
close(fd[1]);
|
||||
// Daemonize. (Do everything (except for the fork()), the regular daemon()
|
||||
// would have done, too.)
|
||||
// 1. Change the file mode mask.
|
||||
umask(0);
|
||||
// 2. Create a new SID for the child process.
|
||||
if (setsid() < 0) {
|
||||
return 6;
|
||||
}
|
||||
|
||||
// 3. Change the current working directory. This prevents the current
|
||||
// directory from being locked; hence not being able to remove it.
|
||||
if ((chdir("/")) < 0) {
|
||||
return 7;
|
||||
}
|
||||
// 4. Redirect standard files to /dev/null.
|
||||
freopen( "/dev/null", "r", stdin);
|
||||
freopen( "/dev/null", "w", stdout);
|
||||
freopen( "/dev/null", "w", stderr);
|
||||
}
|
||||
|
||||
// Run fuse.
|
||||
fuse_set_signal_handlers(fuse_get_session(fuse_));
|
||||
fuse_adapter->SetInterruptQueryFunction();
|
||||
fuse_loop_mt(fuse_);
|
||||
// Cleanup
|
||||
fuse_teardown(fuse_, mount_point);
|
||||
for (int i = 0; i < fuse_opts.size(); i++) {
|
||||
free(fuse_opts[i]);
|
||||
}
|
||||
|
||||
// Stop FuseAdapter.
|
||||
fuse_adapter->Stop();
|
||||
delete fuse_adapter;
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user